reducer.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*
  2. * <<
  3. * Davinci
  4. * ==
  5. * Copyright (C) 2016 - 2017 EDP
  6. * ==
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. * >>
  19. */
  20. import produce from 'immer'
  21. import { LOCATION_CHANGE, LocationChangeAction } from 'connected-react-router'
  22. import { matchDisplaySlidePath } from 'utils/router'
  23. import { ActionTypes } from './constants'
  24. import { ActionTypes as VizActionTypes } from 'containers/Viz/constants'
  25. import { ActionTypes as ViewActionTypes } from '../View/constants'
  26. import { GraphTypes } from './components/constants'
  27. import { fieldGroupedSort } from 'containers/Widget/components/Config/Sort'
  28. import { DisplayActionType } from './actions'
  29. import { VizActionType } from '../Viz/actions'
  30. import { ViewActionType } from '../View/actions'
  31. import { IDisplayState, IDisplaySharePanelState } from './types'
  32. const defaultSharePanelState: IDisplaySharePanelState = {
  33. id: 0,
  34. type: 'display',
  35. title: '',
  36. visible: false
  37. }
  38. export const initialState: IDisplayState = {
  39. currentDisplayShareToken: '',
  40. currentDisplayAuthorizedShareToken: '',
  41. currentDisplayPasswordShareToken: '',
  42. currentDisplayPasswordPassword: '',
  43. sharePanel: defaultSharePanelState,
  44. currentDisplaySelectOptions: {},
  45. currentSlideId: 0,
  46. currentDisplayWidgets: {},
  47. slideLayers: {},
  48. slideLayersInfo: {},
  49. slideLayersOperationInfo: {},
  50. clipboardSlides: [],
  51. clipboardLayers: [],
  52. lastOperationType: null,
  53. lastLayers: [],
  54. editorBaselines: [],
  55. operateItemParams: [],
  56. loading: {
  57. shareToken: false,
  58. slideLayers: false
  59. }
  60. }
  61. const displayReducer = (
  62. state = initialState,
  63. action:
  64. | DisplayActionType
  65. | VizActionType
  66. | ViewActionType
  67. | LocationChangeAction
  68. ) =>
  69. produce(state, (draft: IDisplayState) => {
  70. let slideId: number
  71. let layerId: number
  72. const layersInfo = draft.slideLayersInfo[draft.currentSlideId]
  73. const layersOperationInfo =
  74. draft.slideLayersOperationInfo[draft.currentSlideId]
  75. switch (action.type) {
  76. case VizActionTypes.EDIT_SLIDES_SUCCESS:
  77. draft.lastOperationType = VizActionTypes.EDIT_SLIDES_SUCCESS
  78. break
  79. case ActionTypes.LOAD_SLIDE_DETAIL:
  80. draft.loading.slideLayers = true
  81. break
  82. case ActionTypes.LOAD_SLIDE_DETAIL_SUCCESS:
  83. slideId = action.payload.slideId
  84. if (!draft.currentSlideId) {
  85. draft.currentSlideId = slideId
  86. }
  87. draft.currentDisplaySelectOptions = {}
  88. draft.currentDisplayWidgets = action.payload.widgets.reduce(
  89. (obj, widget) => {
  90. obj[widget.id] = widget
  91. return obj
  92. },
  93. draft.currentDisplayWidgets
  94. )
  95. draft.slideLayers[slideId] = (action.payload.layers || []).reduce(
  96. (obj, layer) => {
  97. obj[layer.id] = layer
  98. return obj
  99. },
  100. {}
  101. )
  102. draft.slideLayersInfo[slideId] = (action.payload.layers || []).reduce(
  103. (obj, layer) => {
  104. obj[layer.id] =
  105. layer.type === GraphTypes.Chart
  106. ? {
  107. datasource: { resultList: [] },
  108. loading: false,
  109. queryConditions: {
  110. tempFilters: [], // @TODO combine widget static filters with local filters
  111. linkageFilters: [],
  112. globalFilters: [],
  113. variables: [],
  114. linkageVariables: [],
  115. globalVariables: [],
  116. pagination: {}
  117. },
  118. interactId: '',
  119. rendered: false,
  120. renderType: 'rerender'
  121. }
  122. : {
  123. loading: false,
  124. datasource: { resultList: [] }
  125. }
  126. return obj
  127. },
  128. {}
  129. )
  130. draft.slideLayersOperationInfo[slideId] = (
  131. action.payload.layers || []
  132. ).reduce((obj, layer) => {
  133. obj[layer.id] = {
  134. selected: false,
  135. dragging: false,
  136. resizing: false,
  137. editing: false
  138. }
  139. return obj
  140. }, {})
  141. draft.editorBaselines = []
  142. break
  143. case ActionTypes.LOAD_SLIDE_DETAIL_FAILURE:
  144. draft.loading.slideLayers = false
  145. break
  146. case ActionTypes.ADD_SLIDE_LAYERS_SUCCESS:
  147. draft.lastOperationType = ActionTypes.ADD_SLIDE_LAYERS_SUCCESS
  148. draft.lastLayers = action.payload.layers
  149. slideId = action.payload.slideId
  150. Object.entries(layersOperationInfo).forEach(
  151. ([id, layerOperationInfo]: [string, any]) => {
  152. draft.slideLayersOperationInfo[slideId][+id] = {
  153. ...layerOperationInfo,
  154. selected: false
  155. }
  156. }
  157. )
  158. draft.slideLayersOperationInfo[slideId] = {
  159. ...layersOperationInfo
  160. }
  161. action.payload.layers.forEach((layer) => {
  162. draft.slideLayers[slideId][layer.id] = layer
  163. draft.slideLayersInfo[slideId][layer.id] =
  164. layer.type === GraphTypes.Chart
  165. ? {
  166. datasource: { resultList: [] },
  167. loading: false,
  168. queryConditions: {
  169. tempFilters: [],
  170. linkageFilters: [],
  171. globalFilters: [],
  172. variables: [],
  173. linkageVariables: [],
  174. globalVariables: []
  175. },
  176. interactId: '',
  177. rendered: false,
  178. renderType: 'rerender'
  179. }
  180. : {
  181. datasource: { resultList: [] },
  182. loading: false
  183. }
  184. draft.slideLayersOperationInfo[slideId][layer.id] = {
  185. selected: true,
  186. resizing: false,
  187. dragging: false,
  188. editing: false
  189. }
  190. if (Array.isArray(action.payload.widgets)) {
  191. action.payload.widgets.forEach((w) => {
  192. draft.currentDisplayWidgets[w.id] = w
  193. })
  194. }
  195. })
  196. break
  197. case ActionTypes.DELETE_SLIDE_LAYERS_SUCCESS:
  198. slideId = action.payload.slideId
  199. draft.lastOperationType = ActionTypes.DELETE_SLIDE_LAYERS_SUCCESS
  200. draft.lastLayers = action.payload.layerIds.map(
  201. (layerId) => draft.slideLayers[slideId][layerId]
  202. )
  203. action.payload.layerIds.forEach((id) => {
  204. delete draft.slideLayers[slideId][id]
  205. delete draft.slideLayersInfo[slideId][id]
  206. delete draft.slideLayersOperationInfo[slideId][id]
  207. })
  208. break
  209. case ActionTypes.LOAD_DISPLAY_PASSWORD_SHARE_LINK_SUCCESS:
  210. draft.currentDisplayPasswordShareToken = action.payload.passwordShareToken
  211. draft.currentDisplayPasswordPassword = action.payload.password
  212. draft.loading.shareToken = false
  213. break
  214. case ActionTypes.EDIT_SLIDE_LAYERS_SUCCESS:
  215. slideId = action.payload.slideId
  216. const lastLayers = []
  217. action.payload.layers.forEach((layer) => {
  218. lastLayers.push(draft.slideLayers[slideId][layer.id])
  219. draft.slideLayers[slideId][layer.id] = layer
  220. if (draft.slideLayersInfo[slideId][layer.id].renderType) {
  221. draft.slideLayersInfo[slideId][layer.id].renderType = 'resize'
  222. draft.slideLayersInfo[slideId][layer.id].datasource = {
  223. ...draft.slideLayersInfo[slideId][layer.id].datasource
  224. }
  225. }
  226. })
  227. draft.lastOperationType = ActionTypes.EDIT_SLIDE_LAYERS_SUCCESS
  228. draft.lastLayers = lastLayers
  229. break
  230. case ActionTypes.CHANGE_LAYER_OPERATION_INFO:
  231. Object.entries(layersOperationInfo).forEach(
  232. ([id, layerOperationInfo]: [string, any]) => {
  233. Object.entries(action.payload.changedInfo).forEach(
  234. ([type, status]: [string, boolean]) => {
  235. if (status) {
  236. return (draft.slideLayersOperationInfo[draft.currentSlideId][
  237. id
  238. ] = {
  239. ...layerOperationInfo,
  240. [type]: +id === action.payload.layerId
  241. })
  242. } else {
  243. return (draft.slideLayersOperationInfo[draft.currentSlideId][
  244. id
  245. ] = {
  246. ...layerOperationInfo,
  247. [type]: status
  248. })
  249. }
  250. }
  251. )
  252. }
  253. )
  254. draft.slideLayersOperationInfo[draft.currentSlideId] = {
  255. ...layersOperationInfo
  256. }
  257. break
  258. case ViewActionTypes.LOAD_VIEW_DATA_FROM_VIZ_ITEM:
  259. if (action.payload.vizType === 'display') {
  260. ;[slideId, layerId] = action.payload.itemId as [number, number]
  261. const layerInfo = draft.slideLayersInfo[slideId][layerId]
  262. layerInfo.loading = true
  263. layerInfo.queryConditions = {
  264. tempFilters: action.payload.requestParams.tempFilters,
  265. linkageFilters: action.payload.requestParams.linkageFilters,
  266. globalFilters: action.payload.requestParams.globalFilters,
  267. variables: action.payload.requestParams.variables,
  268. linkageVariables: action.payload.requestParams.linkageVariables,
  269. globalVariables: action.payload.requestParams.globalVariables
  270. }
  271. }
  272. break
  273. case ViewActionTypes.LOAD_VIEW_DATA_FROM_VIZ_ITEM_SUCCESS:
  274. if (action.payload.vizType === 'display') {
  275. ;[slideId, layerId] = action.payload.itemId as [number, number]
  276. fieldGroupedSort(
  277. action.payload.result.resultList,
  278. action.payload.requestParams.customOrders
  279. )
  280. const layerInfo = draft.slideLayersInfo[slideId][layerId]
  281. layerInfo.loading = false
  282. layerInfo.datasource = action.payload.result
  283. layerInfo.renderType = action.payload.renderType
  284. }
  285. break
  286. case ViewActionTypes.LOAD_VIEW_DATA_FROM_VIZ_ITEM_FAILURE:
  287. if (action.payload.vizType === 'display') {
  288. ;[slideId, layerId] = action.payload.itemId as [number, number]
  289. if (draft.slideLayersInfo[slideId]) {
  290. draft.slideLayersInfo[slideId][layerId].loading = false
  291. }
  292. }
  293. break
  294. case ActionTypes.RESIZE_LAYER_ADJUSTED:
  295. const resizingLayerIds = action.payload.layerIds
  296. resizingLayerIds.forEach((layerId) => {
  297. if (!action.payload.finish) {
  298. draft.slideLayers[draft.currentSlideId][layerId].params.width +=
  299. action.payload.deltaSize.deltaWidth
  300. draft.slideLayers[draft.currentSlideId][layerId].params.height +=
  301. action.payload.deltaSize.deltaHeight
  302. }
  303. if (layersInfo[layerId].renderType) {
  304. layersInfo[layerId].renderType = 'resize'
  305. layersInfo[layerId].datasource = {
  306. ...layersInfo[layerId].datasource
  307. }
  308. }
  309. draft.slideLayersOperationInfo[draft.currentSlideId][
  310. layerId
  311. ].resizing = !action.payload.finish
  312. })
  313. break
  314. case ActionTypes.DRAG_LAYER_ADJUSTED: {
  315. const {
  316. slideSize: { width: slideWidth, height: slideHeight },
  317. layerIds,
  318. deltaPosition
  319. } = action.payload
  320. const isEmpty = draft.operateItemParams.length === 0
  321. layerIds.forEach((layerId) => {
  322. if (isEmpty) {
  323. draft.operateItemParams.push({
  324. ...draft.slideLayers[draft.currentSlideId][layerId]
  325. })
  326. }
  327. const item = draft.operateItemParams.find(
  328. (item) => item.id === layerId
  329. )
  330. if (item) {
  331. item.params.positionX += deltaPosition.deltaX
  332. item.params.positionY += deltaPosition.deltaY
  333. if (item.params.positionX < 0) {
  334. item.params.positionX = 0
  335. } else if (item.params.positionX + item.params.width > slideWidth) {
  336. item.params.positionX = slideWidth - item.params.width
  337. }
  338. if (item.params.positionY < 0) {
  339. item.params.positionY = 0
  340. } else if (
  341. item.params.positionY + item.params.height >
  342. slideHeight
  343. ) {
  344. item.params.positionY = slideHeight - item.params.height
  345. }
  346. draft.slideLayersOperationInfo[draft.currentSlideId][
  347. layerId
  348. ].dragging = true
  349. }
  350. })
  351. break
  352. }
  353. case ActionTypes.SELECT_LAYER:
  354. Object.entries(layersOperationInfo).forEach(
  355. ([id, layerOperationInfo]: [string, any]) => {
  356. if (action.payload.selected && action.payload.exclusive) {
  357. draft.slideLayersOperationInfo[draft.currentSlideId][id] = {
  358. ...layerOperationInfo,
  359. selected: false,
  360. editing: false
  361. }
  362. }
  363. if (+id === action.payload.layerId) {
  364. draft.slideLayersOperationInfo[draft.currentSlideId][id] = {
  365. ...layerOperationInfo,
  366. selected: action.payload.selected
  367. }
  368. }
  369. }
  370. )
  371. draft.slideLayersOperationInfo[draft.currentSlideId] = {
  372. ...layersOperationInfo
  373. }
  374. break
  375. case ActionTypes.CLEAR_LAYERS_OPERATION_INFO:
  376. if (layersOperationInfo) {
  377. Object.values(layersOperationInfo).forEach(
  378. (layerOperationInfo: any) => {
  379. return Object.entries(action.payload.changedInfo).forEach(
  380. ([type, value]: [string, boolean]) => {
  381. layerOperationInfo[type] = value
  382. }
  383. )
  384. }
  385. )
  386. }
  387. break
  388. case ActionTypes.CLEAR_EDITOR_BASELINES:
  389. draft.editorBaselines = []
  390. draft.operateItemParams = []
  391. Object.values(
  392. draft.slideLayersOperationInfo[draft.currentSlideId]
  393. ).forEach((item) => {
  394. item.dragging = false
  395. })
  396. break
  397. case ActionTypes.SHOW_EDITOR_BASELINES:
  398. draft.editorBaselines = action.payload.baselines
  399. break
  400. case ActionTypes.COPY_SLIDE_LAYERS_SUCCESS:
  401. draft.clipboardLayers = action.payload.layers
  402. break
  403. case ActionTypes.LOAD_DISPLAY_SHARE_LINK:
  404. draft.loading.shareToken = true
  405. if (action.payload.params.mode === 'AUTH') {
  406. draft.currentDisplayAuthorizedShareToken = ''
  407. }
  408. break
  409. case ActionTypes.LOAD_DISPLAY_SHARE_LINK_SUCCESS:
  410. draft.currentDisplayShareToken = action.payload.shareToken
  411. draft.loading.shareToken = false
  412. break
  413. case ActionTypes.LOAD_DISPLAY_AUTHORIZED_SHARE_LINK_SUCCESS:
  414. draft.currentDisplayAuthorizedShareToken =
  415. action.payload.authorizedShareToken
  416. draft.loading.shareToken = false
  417. break
  418. case ActionTypes.LOAD_DISPLAY_SHARE_LINK_FAILURE:
  419. draft.loading.shareToken = false
  420. break
  421. case ActionTypes.OPEN_SHARE_PANEL:
  422. draft.sharePanel = {
  423. id: action.payload.id,
  424. type: 'display',
  425. title: action.payload.title,
  426. visible: true
  427. }
  428. break
  429. case ActionTypes.CLOSE_SHARE_PANEL:
  430. draft.sharePanel = defaultSharePanelState
  431. break
  432. case ActionTypes.RESET_DISPLAY_STATE:
  433. return initialState
  434. case LOCATION_CHANGE:
  435. const matchSlide = matchDisplaySlidePath(
  436. action.payload.location.pathname
  437. )
  438. if (matchSlide) {
  439. draft.currentSlideId = +matchSlide.params.slideId || null
  440. } else {
  441. return initialState
  442. }
  443. break
  444. }
  445. })
  446. export { initialState as displayInitialState}
  447. export default displayReducer