edit.jsx 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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 { 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 './edit.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.refs.body && this.refs.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', () => {
  48. this.setState({
  49. show: true,
  50. is_add: true
  51. })
  52. setTimeout(() => {
  53. this.tryToFocus()
  54. }, 100)
  55. })
  56. Agent.on('edit_hosts', (hosts) => {
  57. this.current_hosts = hosts
  58. let include = hosts.include || []
  59. include = Array.from(new Set(include))
  60. this.setState({
  61. id: hosts.id,
  62. show: true,
  63. is_add: false,
  64. where: hosts.where || 'local',
  65. title: hosts.title || '',
  66. url: hosts.url || '',
  67. last_refresh: hosts.last_refresh || null,
  68. refresh_interval: hosts.refresh_interval || 0,
  69. include
  70. })
  71. setTimeout(() => {
  72. this.tryToFocus()
  73. }, 100)
  74. })
  75. Agent.on('list_updated', list => {
  76. let hosts = list.find(i => i.id === this.state.id)
  77. if (hosts) {
  78. this.current_hosts = hosts
  79. this.setState({last_refresh: hosts.last_refresh})
  80. setTimeout(() => this.setState({is_loading: false}), 500)
  81. }
  82. })
  83. Agent.on('refresh_end', (id) => {
  84. if (this.state.is_loading) {
  85. this.setState({
  86. is_loading: false
  87. })
  88. if (id && id === this.current_hosts.id) {
  89. this.setState({
  90. last_refresh: this.current_hosts.last_refresh
  91. })
  92. }
  93. }
  94. })
  95. }
  96. onOK () {
  97. this.setState({
  98. title: (this.state.title || '').replace(/^\s+|\s+$/g, ''),
  99. url: (this.state.url || '').replace(/^\s+|\s+$/g, '')
  100. })
  101. if (this.state.title === '') {
  102. this.refs.title.focus()
  103. return false
  104. }
  105. if (this.state.where === 'remote' && this.state.url === '') {
  106. this.refs.url.focus()
  107. return false
  108. }
  109. let new_id = makeId()
  110. let data = Object.assign({}, this.current_hosts, this.state,
  111. this.state.is_add ? {
  112. id: new_id,
  113. content: `# ${this.state.title}`,
  114. on: false
  115. } : {})
  116. if (!data.id) data.id = new_id
  117. if (this.state.is_add) {
  118. this.props.justAdd(new_id)
  119. }
  120. delete data['is_add']
  121. Agent.emit('update_hosts', data)
  122. this.setState({
  123. show: false
  124. })
  125. this.clear()
  126. }
  127. onCancel () {
  128. this.setState({
  129. show: false
  130. })
  131. this.clear()
  132. }
  133. confirmDel () {
  134. let {lang} = this.props
  135. if (!confirm(lang.confirm_del)) return
  136. Agent.emit('del_hosts', this.current_hosts)
  137. this.setState({
  138. show: false
  139. })
  140. this.clear()
  141. }
  142. updateInclude (include) {
  143. this.setState({include})
  144. }
  145. getRefreshOptions () {
  146. let {lang} = this.props
  147. let k = [
  148. [0, `${lang.never}`],
  149. [1, `1 ${lang.hour}`],
  150. [24, `24 ${lang.hours}`],
  151. [168, `7 ${lang.days}`]
  152. ]
  153. if (Agent.IS_DEV) {
  154. k.splice(1, 0, [0.002778, `10s (for DEV)`]) // dev test only
  155. }
  156. return k.map(([v, n], idx) => {
  157. return (
  158. <Option value={v} key={idx}>{n}</Option>
  159. )
  160. })
  161. }
  162. getEditOperations () {
  163. if (this.state.is_add) return null
  164. let {lang} = this.props
  165. return (
  166. <div>
  167. <div className="ln">
  168. <a href="#" className="del"
  169. onClick={this.confirmDel.bind(this)}
  170. >
  171. <i className="iconfont icon-delete"/>
  172. <span>{lang.del_hosts}</span>
  173. </a>
  174. </div>
  175. </div>
  176. )
  177. }
  178. refresh () {
  179. if (this.state.is_loading) return
  180. Agent.emit('check_hosts_refresh', this.current_hosts)
  181. this.setState({
  182. is_loading: true
  183. })
  184. }
  185. renderGroup () {
  186. if (this.state.where !== 'group') return null
  187. return <Group
  188. list={this.props.list}
  189. include={this.state.include}
  190. updateInclude={this.updateInclude.bind(this)}
  191. />
  192. }
  193. renderRemoteInputs () {
  194. if (this.state.where !== 'remote') return null
  195. let {lang} = this.props
  196. return (
  197. <div className="remote-ipts">
  198. <div className="ln">
  199. <div className="title">{lang.url}</div>
  200. <div className="cnt">
  201. <Input
  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()) || (e.keyCode === 27 && this.onCancel())}
  207. />
  208. </div>
  209. </div>
  210. <div className="ln">
  211. <div className="title">{lang.auto_refresh}</div>
  212. <div className="cnt">
  213. <Select
  214. value={this.state.refresh_interval}
  215. style={{width: 120}}
  216. onChange={v => this.setState({refresh_interval: parseFloat(v) || 0})}
  217. >
  218. {this.getRefreshOptions()}
  219. </Select>
  220. <Icon
  221. type="reload"
  222. className={classnames({
  223. 'iconfont': 1,
  224. 'icon-refresh': 1,
  225. 'invisible': !this.current_hosts || this.state.url !== this.current_hosts.url,
  226. 'loading': this.state.is_loading
  227. })}
  228. title={lang.refresh}
  229. onClick={() => this.refresh()}
  230. />
  231. <span className="last-refresh">
  232. {lang.last_refresh}
  233. {this.state.last_refresh || 'N/A'}
  234. </span>
  235. </div>
  236. </div>
  237. </div>
  238. )
  239. }
  240. body () {
  241. let {lang} = this.props
  242. return (
  243. <div ref="body">
  244. <div className="ln">
  245. <RadioGroup onChange={e => this.setState({where: e.target.value})} value={this.state.where}>
  246. <RadioButton value="local"><Icon type="file-text" /> {lang.where_local}</RadioButton>
  247. <RadioButton value="remote"><Icon type="global" /> {lang.where_remote}</RadioButton>
  248. <RadioButton value="group"><Icon type="copy" /> {lang.where_group}</RadioButton>
  249. </RadioGroup>
  250. </div>
  251. <div className="ln">
  252. <div className="title">{lang.hosts_title}</div>
  253. <div className="cnt">
  254. <Input
  255. ref="title"
  256. value={this.state.title}
  257. onChange={(e) => this.setState({title: e.target.value})}
  258. onKeyDown={(e) => (e.keyCode === 13 && this.onOK() || e.keyCode === 27 && this.onCancel())}
  259. />
  260. </div>
  261. </div>
  262. {this.renderRemoteInputs()}
  263. {this.renderGroup()}
  264. {this.getEditOperations()}
  265. </div>
  266. )
  267. }
  268. render () {
  269. let {lang} = this.props
  270. return (
  271. <MyFrame
  272. show={this.state.show}
  273. title={lang[this.state.is_add ? 'add_hosts' : 'edit_hosts']}
  274. body={this.body()}
  275. onOK={() => this.onOK()}
  276. onCancel={() => this.onCancel()}
  277. lang={this.props.lang}
  278. />
  279. )
  280. }
  281. }