sagas.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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 { call, put, all, takeLatest, takeEvery } from 'redux-saga/effects'
  21. import { ActionTypes } from './constants'
  22. import { ViewActions, ViewActionType } from './actions'
  23. import omit from 'lodash/omit'
  24. import axios, { AxiosResponse, AxiosError, CancelTokenSource } from 'axios'
  25. import request, { IDavinciResponse } from 'utils/request'
  26. import api from 'utils/api'
  27. import { errorHandler, getErrorMessage } from 'utils/util'
  28. import { IViewBase, IView, IExecuteSqlResponse, IViewVariable } from './types'
  29. import { EExecuteType } from './Editor'
  30. export function* getViews (action: ViewActionType) {
  31. if (action.type !== ActionTypes.LOAD_VIEWS) { return }
  32. const { payload } = action
  33. const { viewsLoaded, loadViewsFail } = ViewActions
  34. let views: IViewBase[]
  35. try {
  36. const asyncData = yield call(request, `${api.view}?projectId=${payload.projectId}&parentId=${payload.parentId}`)
  37. views = asyncData.payload
  38. yield put(viewsLoaded(views))
  39. } catch (err) {
  40. yield put(loadViewsFail())
  41. errorHandler(err)
  42. } finally {
  43. if (payload.resolve) {
  44. payload.resolve(views)
  45. }
  46. }
  47. }
  48. export function* getViewsDetail (action: ViewActionType) {
  49. if (action.type !== ActionTypes.LOAD_VIEWS_DETAIL) { return }
  50. const { payload } = action
  51. const { viewsDetailLoaded, loadViewsDetailFail } = ViewActions
  52. const { viewIds, resolve, isEditing } = payload
  53. try {
  54. // @FIXME make it be a single request
  55. const asyncData = yield all(viewIds.map((viewId) => (call(request, `${api.view}/${viewId}`))))
  56. const views: IView[] = asyncData.map((item) => item.payload)
  57. yield put(viewsDetailLoaded(views, isEditing))
  58. if (resolve) { resolve(views) }
  59. } catch (err) {
  60. yield put(loadViewsDetailFail())
  61. errorHandler(err)
  62. }
  63. }
  64. export function* addView (action: ViewActionType) {
  65. if (action.type !== ActionTypes.ADD_VIEW) { return }
  66. const { payload } = action
  67. const { view, resolve } = payload
  68. const { viewAdded, addViewFail } = ViewActions
  69. try {
  70. const asyncData = yield call(request, {
  71. method: 'post',
  72. url: api.view,
  73. data: view
  74. })
  75. yield put(viewAdded(asyncData.payload))
  76. resolve()
  77. } catch (err) {
  78. yield put(addViewFail())
  79. errorHandler(err)
  80. }
  81. }
  82. export function* editView (action: ViewActionType) {
  83. if (action.type !== ActionTypes.EDIT_VIEW) { return }
  84. const { payload } = action
  85. const { view, resolve } = payload
  86. const { viewEdited, editViewFail } = ViewActions
  87. try {
  88. yield call(request, {
  89. method: 'put',
  90. url: `${api.view}/${view.id}`,
  91. data: view
  92. })
  93. yield put(viewEdited(view))
  94. resolve()
  95. } catch (err) {
  96. yield put(editViewFail())
  97. errorHandler(err)
  98. }
  99. }
  100. export function* deleteView (action: ViewActionType) {
  101. if (action.type !== ActionTypes.DELETE_VIEW) { return }
  102. const { payload } = action
  103. const { viewDeleted, deleteViewFail } = ViewActions
  104. try {
  105. yield call(request, {
  106. method: 'delete',
  107. url: `${api.view}/${payload.id}`
  108. })
  109. yield put(viewDeleted(payload.id))
  110. payload.resolve(payload.id)
  111. } catch (err) {
  112. yield put(deleteViewFail())
  113. errorHandler(err)
  114. }
  115. }
  116. export function* copyView (action: ViewActionType) {
  117. if (action.type !== ActionTypes.COPY_VIEW) { return }
  118. const { view, resolve } = action.payload
  119. const { viewCopied, copyViewFail } = ViewActions
  120. try {
  121. const fromViewResponse = yield call(request, `${api.view}/${view.id}`)
  122. const fromView = fromViewResponse.payload
  123. const copyView: IView = { ...fromView, name: view.name, description: view.description }
  124. const asyncData = yield call(request, {
  125. method: 'post',
  126. url: api.view,
  127. data: copyView
  128. })
  129. yield put(viewCopied(fromView.id, asyncData.payload))
  130. resolve()
  131. } catch (err) {
  132. yield put(copyViewFail())
  133. errorHandler(err)
  134. }
  135. }
  136. let cancelTokenSource = null as CancelTokenSource
  137. export function* executeSql (action: ViewActionType) {
  138. if (action.type !== ActionTypes.EXECUTE_SQL) { return }
  139. const { sqlExecuted, executeSqlFail, executeSqlCancel, setIsLastExecuteWholeSql } = ViewActions
  140. if (cancelTokenSource) {
  141. cancelTokenSource.cancel('cancel execute')
  142. yield put(executeSqlCancel())
  143. return cancelTokenSource = null
  144. }
  145. cancelTokenSource = axios.CancelToken.source()
  146. const { params, exeType } = action.payload
  147. const { variables, ...rest } = params
  148. const omitKeys: Array<keyof IViewVariable> = ['key', 'alias', 'fromService']
  149. const variableParam = variables.map((v) => omit(v, omitKeys))
  150. try {
  151. const asyncData: IDavinciResponse<IExecuteSqlResponse> = yield call(request, {
  152. method: 'post',
  153. url: `${api.view}/executesql`,
  154. data: {
  155. ...rest,
  156. variables: variableParam
  157. },
  158. cancelToken: cancelTokenSource.token
  159. })
  160. yield put(sqlExecuted(asyncData))
  161. const isLastExecuteWholeSql = exeType === EExecuteType.whole ? true : false
  162. yield put(setIsLastExecuteWholeSql(isLastExecuteWholeSql))
  163. cancelTokenSource = null
  164. } catch (err) {
  165. const { response } = err as AxiosError
  166. const { data } = response as AxiosResponse<IDavinciResponse<any>>
  167. yield put(executeSqlFail(data.header))
  168. cancelTokenSource = null
  169. }
  170. }
  171. /** View sagas for external usages */
  172. export function* getViewData (action: ViewActionType) {
  173. if (action.type !== ActionTypes.LOAD_VIEW_DATA) { return }
  174. const { id, requestParams, resolve, reject } = action.payload
  175. const { viewDataLoaded, loadViewDataFail } = ViewActions
  176. try {
  177. const asyncData = yield call(request, {
  178. method: 'post',
  179. url: `${api.view}/${id}/getdata`,
  180. data: requestParams
  181. })
  182. yield put(viewDataLoaded())
  183. asyncData.payload.resultList = asyncData.payload.resultList || []
  184. resolve(asyncData.payload)
  185. } catch (err) {
  186. const { response } = err as AxiosError
  187. const { data } = response as AxiosResponse<IDavinciResponse<any>>
  188. yield put(loadViewDataFail(err))
  189. reject(data.header)
  190. }
  191. }
  192. export function* getSelectOptions (action: ViewActionType) {
  193. if (action.type !== ActionTypes.LOAD_SELECT_OPTIONS) {
  194. return
  195. }
  196. const { selectOptionsLoaded, loadSelectOptionsFail } = ViewActions
  197. try {
  198. const {
  199. controlKey,
  200. requestParams,
  201. itemId,
  202. cancelTokenSource
  203. } = action.payload
  204. const requests = Object.entries(requestParams).map(([viewId, params]) => {
  205. const { columns, filters, variables, cache, expired } = params
  206. return call(request, {
  207. method: 'post',
  208. url: `${api.view}/${viewId}/getdistinctvalue`,
  209. data: {
  210. columns,
  211. filters,
  212. params: variables,
  213. cache,
  214. expired
  215. },
  216. cancelToken: cancelTokenSource.token
  217. })
  218. })
  219. const results: Array<IDavinciResponse<object[]>> = yield all(requests)
  220. yield put(selectOptionsLoaded(
  221. controlKey,
  222. results.reduce((arr, result) => arr.concat(result.payload), []),
  223. itemId
  224. ))
  225. } catch (err) {
  226. yield put(loadSelectOptionsFail(err))
  227. }
  228. }
  229. export function* getColumnDistinctValue(action: ViewActionType) {
  230. if (action.type !== ActionTypes.LOAD_COLUMN_DISTINCT_VALUE) {
  231. return
  232. }
  233. const { paramsByViewId, callback } = action.payload
  234. try {
  235. const requests = Object.entries(paramsByViewId).map(([viewId, params]) => {
  236. return call(request, {
  237. method: 'post',
  238. url: `${api.view}/${viewId}/getdistinctvalue`,
  239. data: {
  240. ...params,
  241. cache: false,
  242. expired: 0,
  243. columns: params.columns
  244. }
  245. })
  246. })
  247. const results: Array<IDavinciResponse<object[]>> = yield all(requests)
  248. callback(results.reduce((arr, result) => arr.concat(result.payload), []))
  249. } catch (err) {
  250. callback()
  251. errorHandler(err)
  252. }
  253. }
  254. export function* getViewDataFromVizItem (action: ViewActionType) {
  255. if (action.type !== ActionTypes.LOAD_VIEW_DATA_FROM_VIZ_ITEM) { return }
  256. const { renderType, itemId, viewId, requestParams, vizType, cancelTokenSource } = action.payload
  257. const { viewDataFromVizItemLoaded, loadViewDataFromVizItemFail } = ViewActions
  258. const {
  259. filters,
  260. tempFilters, // @TODO combine widget static filters with local filters
  261. linkageFilters,
  262. globalFilters,
  263. variables,
  264. linkageVariables,
  265. globalVariables,
  266. pagination,
  267. drillStatus,
  268. groups,
  269. ...rest
  270. } = requestParams
  271. const { pageSize, pageNo } = pagination || { pageSize: 0, pageNo: 0 }
  272. let searchFilters = filters.concat(tempFilters).concat(linkageFilters).concat(globalFilters)
  273. if (drillStatus && drillStatus.filters) {
  274. searchFilters = searchFilters.concat(drillStatus.filters) // 改成 drillStatus.filters
  275. }
  276. try {
  277. const asyncData = yield call(request, {
  278. method: 'post',
  279. url: `${api.view}/${viewId}/getdata`,
  280. data: {
  281. ...omit(rest, 'customOrders'),
  282. groups: drillStatus && drillStatus.groups ? drillStatus.groups : groups,
  283. filters: searchFilters,
  284. params: variables.concat(linkageVariables).concat(globalVariables),
  285. pageSize,
  286. pageNo
  287. },
  288. cancelToken: cancelTokenSource.token
  289. })
  290. asyncData.payload = asyncData.payload || {}
  291. const { payload } = asyncData
  292. payload.resultList = payload.resultList || []
  293. yield put(viewDataFromVizItemLoaded(renderType, itemId, requestParams, asyncData.payload, vizType, action.statistic))
  294. } catch (err) {
  295. yield put(loadViewDataFromVizItemFail(itemId, vizType, getErrorMessage(err)))
  296. }
  297. }
  298. /** */
  299. /** View sagas for fetch external authorization variables values */
  300. export function* getDacChannels (action: ViewActionType) {
  301. if (action.type !== ActionTypes.LOAD_DAC_CHANNELS) { return }
  302. const { dacChannelsLoaded, loadDacChannelsFail } = ViewActions
  303. try {
  304. const asyncData = yield call(request, `${api.view}/dac/channels`)
  305. const channels = asyncData.payload
  306. yield put(dacChannelsLoaded(channels))
  307. } catch (err) {
  308. yield put(loadDacChannelsFail())
  309. errorHandler(err)
  310. }
  311. }
  312. export function* getDacTenants (action: ViewActionType) {
  313. if (action.type !== ActionTypes.LOAD_DAC_TENANTS) { return }
  314. const { dacTenantsLoaded, loadDacTenantsFail } = ViewActions
  315. const { channelName } = action.payload
  316. try {
  317. const asyncData = yield call(request, `${api.view}/dac/${channelName}/tenants`)
  318. const tenants = asyncData.payload
  319. yield put(dacTenantsLoaded(tenants))
  320. } catch (err) {
  321. yield put(loadDacTenantsFail())
  322. errorHandler(err)
  323. }
  324. }
  325. export function* getDacBizs (action: ViewActionType) {
  326. if (action.type !== ActionTypes.LOAD_DAC_BIZS) { return }
  327. const { dacBizsLoaded, loadDacBizsFail } = ViewActions
  328. const { channelName, tenantId } = action.payload
  329. try {
  330. const asyncData = yield call(request, `${api.view}/dac/${channelName}/tenants/${tenantId}/bizs`)
  331. const bizs = asyncData.payload
  332. yield put(dacBizsLoaded(bizs))
  333. } catch (err) {
  334. yield put(loadDacBizsFail())
  335. errorHandler(err)
  336. }
  337. }
  338. /** */
  339. export default function* rootViewSaga () {
  340. yield all([
  341. takeLatest(ActionTypes.LOAD_VIEWS, getViews),
  342. takeEvery(ActionTypes.LOAD_VIEWS_DETAIL, getViewsDetail),
  343. takeLatest(ActionTypes.ADD_VIEW, addView),
  344. takeEvery(ActionTypes.EDIT_VIEW, editView),
  345. takeEvery(ActionTypes.DELETE_VIEW, deleteView),
  346. takeEvery(ActionTypes.COPY_VIEW, copyView),
  347. takeLatest(ActionTypes.EXECUTE_SQL, executeSql),
  348. takeEvery(ActionTypes.LOAD_VIEW_DATA, getViewData),
  349. takeEvery(ActionTypes.LOAD_SELECT_OPTIONS, getSelectOptions),
  350. takeEvery(ActionTypes.LOAD_COLUMN_DISTINCT_VALUE, getColumnDistinctValue),
  351. takeEvery(ActionTypes.LOAD_VIEW_DATA_FROM_VIZ_ITEM, getViewDataFromVizItem),
  352. takeEvery(ActionTypes.LOAD_DAC_CHANNELS, getDacChannels),
  353. takeEvery(ActionTypes.LOAD_DAC_TENANTS, getDacTenants),
  354. takeEvery(ActionTypes.LOAD_DAC_BIZS, getDacBizs)
  355. ])
  356. }