edit.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /**
  2. * @author oldj
  3. * @blog https://oldj.net
  4. */
  5. 'use strict'
  6. import React from 'react'
  7. import MyFrame from './frame'
  8. import classnames from 'classnames'
  9. import Group from './group'
  10. import Agent from '../Agent'
  11. import makeId from '../../app/libs/make-id'
  12. import './edit.less'
  13. export default class EditPrompt extends React.Component {
  14. constructor (props) {
  15. super(props)
  16. this.state = {
  17. show: false,
  18. is_add: true,
  19. where: 'local',
  20. title: '',
  21. url: '',
  22. last_refresh: null,
  23. refresh_interval: 0,
  24. is_loading: false,
  25. include: []
  26. }
  27. this.current_hosts = null
  28. }
  29. tryToFocus () {
  30. let el = this.refs.body && this.refs.body.querySelector('input[type=text]')
  31. el && el.focus()
  32. }
  33. clear () {
  34. this.setState({
  35. where: 'local',
  36. title: '',
  37. url: '',
  38. last_refresh: null,
  39. refresh_interval: 0
  40. })
  41. }
  42. componentDidMount () {
  43. Agent.on('add_hosts', () => {
  44. this.setState({
  45. show: true,
  46. is_add: true
  47. })
  48. setTimeout(() => {
  49. this.tryToFocus()
  50. }, 100)
  51. })
  52. Agent.on('edit_hosts', (hosts) => {
  53. this.current_hosts = hosts
  54. let include = hosts.include || []
  55. include = Array.from(new Set(include))
  56. this.setState({
  57. id: hosts.id,
  58. show: true,
  59. is_add: false,
  60. where: hosts.where || 'local',
  61. title: hosts.title || '',
  62. url: hosts.url || '',
  63. last_refresh: hosts.last_refresh || null,
  64. refresh_interval: hosts.refresh_interval || 0,
  65. include
  66. })
  67. setTimeout(() => {
  68. this.tryToFocus()
  69. }, 100)
  70. })
  71. Agent.on('loading_done', (old_hosts, data) => {
  72. if (old_hosts === this.current_hosts) {
  73. this.setState({
  74. last_refresh: data.last_refresh,
  75. is_loading: false
  76. })
  77. Agent.emit('host_refreshed', data, this.current_hosts)
  78. }
  79. })
  80. Agent.on('list_updated', list => {
  81. let hosts = list.find(i => i.id === this.state.id)
  82. if (hosts) {
  83. this.setState({
  84. last_refresh: hosts.last_refresh
  85. })
  86. }
  87. })
  88. }
  89. onOK () {
  90. this.setState({
  91. title: (this.state.title || '').replace(/^\s+|\s+$/g, ''),
  92. url: (this.state.url || '').replace(/^\s+|\s+$/g, '')
  93. })
  94. if (this.state.title === '') {
  95. this.refs.title.focus()
  96. return false
  97. }
  98. if (this.state.where === 'remote' && this.state.url === '') {
  99. this.refs.url.focus()
  100. return false
  101. }
  102. let new_id = makeId()
  103. let data = Object.assign({}, this.current_hosts, this.state,
  104. this.state.is_add ? {
  105. id: new_id,
  106. content: `# ${this.state.title}`,
  107. on: false
  108. } : {})
  109. if (!data.id) data.id = new_id
  110. if (this.state.is_add) {
  111. this.props.justAdd(new_id)
  112. }
  113. delete data['is_add']
  114. Agent.emit('update_hosts', data)
  115. this.setState({
  116. show: false
  117. })
  118. this.clear()
  119. }
  120. onCancel () {
  121. this.setState({
  122. show: false
  123. })
  124. this.clear()
  125. }
  126. confirmDel () {
  127. let {lang} = this.props
  128. if (!confirm(lang.confirm_del)) return
  129. Agent.emit('del_hosts', this.current_hosts)
  130. this.setState({
  131. show: false
  132. })
  133. this.clear()
  134. }
  135. updateInclude (include) {
  136. this.setState({include})
  137. }
  138. getRefreshOptions () {
  139. let {lang} = this.props
  140. let k = [
  141. [0, `${lang.never}`],
  142. [1, `1 ${lang.hour}`],
  143. [24, `24 ${lang.hours}`],
  144. [168, `7 ${lang.days}`]
  145. ]
  146. if (Agent.IS_DEV) {
  147. k.splice(1, 0, [0.002778, `10s (for DEV)`]) // dev test only
  148. }
  149. return k.map(([v, n], idx) => {
  150. return (
  151. <option value={v} key={idx}>{n}</option>
  152. )
  153. })
  154. }
  155. getEditOperations () {
  156. if (this.state.is_add) return null
  157. let {lang} = this.props
  158. return (
  159. <div>
  160. <div className="ln">
  161. <a href="#" className="del"
  162. onClick={this.confirmDel.bind(this)}
  163. >
  164. <i className="iconfont icon-delete"/>
  165. <span>{lang.del_hosts}</span>
  166. </a>
  167. </div>
  168. </div>
  169. )
  170. }
  171. refresh () {
  172. if (this.state.is_loading) return
  173. Agent.emit('check_hosts_refresh', this.current_hosts)
  174. this.setState({
  175. is_loading: true
  176. }, () => {
  177. setTimeout(() => {
  178. this.setState({
  179. is_loading: false
  180. })
  181. }, 1000)
  182. })
  183. }
  184. renderGroup () {
  185. if (this.state.where !== 'group') return null
  186. return <Group
  187. list={this.props.list}
  188. include={this.state.include}
  189. updateInclude={this.updateInclude.bind(this)}
  190. />
  191. }
  192. renderRemoteInputs () {
  193. if (this.state.where !== 'remote') return null
  194. let {lang} = this.props
  195. return (
  196. <div className="remote-ipts">
  197. <div className="ln">
  198. <div className="title">{lang.url}</div>
  199. <div className="cnt">
  200. <input
  201. type="text"
  202. ref="url"
  203. value={this.state.url}
  204. placeholder="http://"
  205. onChange={(e) => this.setState({url: e.target.value})}
  206. onKeyDown={(e) => (e.keyCode === 13 && this.onOK()) ||
  207. (e.keyCode === 27 && this.onCancel())}
  208. />
  209. </div>
  210. </div>
  211. <div className="ln">
  212. <div className="title">{lang.auto_refresh}</div>
  213. <div className="cnt">
  214. <select
  215. value={this.state.refresh_interval}
  216. onChange={(e) => this.setState(
  217. {refresh_interval: parseFloat(e.target.value) || 0})}
  218. >
  219. {this.getRefreshOptions()}
  220. </select>
  221. <i
  222. className={classnames({
  223. iconfont: 1,
  224. 'icon-refresh': 1,
  225. 'invisible': !this.current_hosts ||
  226. this.state.url !== this.current_hosts.url,
  227. 'loading': this.state.is_loading
  228. })}
  229. title={lang.refresh}
  230. onClick={() => this.refresh()}
  231. />
  232. <span className="last-refresh">
  233. {lang.last_refresh}
  234. {this.state.last_refresh || 'N/A'}
  235. </span>
  236. </div>
  237. </div>
  238. </div>
  239. )
  240. }
  241. body () {
  242. let {lang} = this.props
  243. return (
  244. <div ref="body">
  245. <div className="ln">
  246. <input id="ipt-local" type="radio" name="where" value="local"
  247. checked={this.state.where === 'local'}
  248. onChange={(e) => this.setState({where: e.target.value})}
  249. />
  250. <label htmlFor="ipt-local">{lang.where_local}</label>
  251. <input id="ipt-remote" type="radio" name="where" value="remote"
  252. checked={this.state.where === 'remote'}
  253. onChange={(e) => this.setState({where: e.target.value})}
  254. />
  255. <label htmlFor="ipt-remote">{lang.where_remote}</label>
  256. <input id="ipt-group" type="radio" name="where" value="group"
  257. checked={this.state.where === 'group'}
  258. onChange={(e) => this.setState({where: e.target.value})}
  259. />
  260. <label htmlFor="ipt-group">{lang.where_group}</label>
  261. </div>
  262. <div className="ln">
  263. <div className="title">{lang.host_title}</div>
  264. <div className="cnt">
  265. <input
  266. type="text"
  267. ref="title"
  268. name="text"
  269. value={this.state.title}
  270. onChange={(e) => this.setState({title: e.target.value})}
  271. onKeyDown={(e) => (e.keyCode === 13 && this.onOK() ||
  272. e.keyCode === 27 && this.onCancel())}
  273. />
  274. </div>
  275. </div>
  276. {this.renderRemoteInputs()}
  277. {this.renderGroup()}
  278. {this.getEditOperations()}
  279. </div>
  280. )
  281. }
  282. render () {
  283. let {lang} = this.props
  284. return (
  285. <MyFrame
  286. show={this.state.show}
  287. head={lang[this.state.is_add ? 'add_hosts' : 'edit_hosts']}
  288. body={this.body()}
  289. onOK={() => this.onOK()}
  290. onCancel={() => this.onCancel()}
  291. lang={this.props.lang}
  292. />
  293. )
  294. }
  295. }