edit.jsx 7.7 KB

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