EditPrompt.jsx 7.9 KB

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