From 0fab179f5afd8ae3e2c299cf0f47756c9e2286d9 Mon Sep 17 00:00:00 2001 From: kanlon Date: Fri, 29 Jul 2022 11:11:11 +0800 Subject: [PATCH 001/103] refactor: refactor parseDataProviderConfig method add @Override --- .../datart/server/service/impl/DataProviderServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/datart/server/service/impl/DataProviderServiceImpl.java b/server/src/main/java/datart/server/service/impl/DataProviderServiceImpl.java index 8554e7cb..f85bd4d2 100644 --- a/server/src/main/java/datart/server/service/impl/DataProviderServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/DataProviderServiceImpl.java @@ -140,14 +140,14 @@ public class DataProviderServiceImpl extends BaseService implements DataProvider return dataProviderManager.readTableColumns(parseDataProviderConfig(source), database, table); } - + @Override public DataProviderSource parseDataProviderConfig(Source source) { DataProviderSource providerSource = new DataProviderSource(); try { providerSource.setSourceId(source.getId()); providerSource.setType(source.getType()); providerSource.setName(source.getName()); - Map properties = new HashMap<>(); + Map properties = new HashMap<>(16); if (StringUtils.isNotBlank(source.getConfig())) { properties = objectMapper.readValue(source.getConfig(), HashMap.class); } -- Gitee From b46f7fe9f945ddd0f0a523b3bd7a400eafe20da2 Mon Sep 17 00:00:00 2001 From: kanlon Date: Thu, 4 Aug 2022 20:42:22 +0800 Subject: [PATCH 002/103] fix: import resource problem, when dashboard contain relation --- .../java/datart/server/service/impl/DashboardServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/datart/server/service/impl/DashboardServiceImpl.java b/server/src/main/java/datart/server/service/impl/DashboardServiceImpl.java index b5b9ff23..67480548 100644 --- a/server/src/main/java/datart/server/service/impl/DashboardServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/DashboardServiceImpl.java @@ -518,8 +518,8 @@ public class DashboardServiceImpl extends BaseService implements DashboardServic final Map widgetIdMapping = new HashMap<>(); for (WidgetDetail widget : mainModel.getWidgets()) { String widgetId = UUIDGenerator.generate(); - widget.setId(widgetId); widgetIdMapping.put(widget.getId(), widgetId); + widget.setId(widgetId); } for (WidgetDetail widget : mainModel.getWidgets()) { widget.setDashboardId(newId); @@ -537,6 +537,7 @@ public class DashboardServiceImpl extends BaseService implements DashboardServic } if (widget.getRelations() != null) { for (RelWidgetWidget relation : widget.getRelations()) { + relation.setId(UUIDGenerator.generate()); relation.setSourceId(widgetIdMapping.get(relation.getSourceId())); relation.setTargetId(widgetIdMapping.get(relation.getTargetId())); } -- Gitee From 33ec69aa76ac52c2d5986ccef5f030f4f38ad3b7 Mon Sep 17 00:00:00 2001 From: tianlei Date: Wed, 10 Aug 2022 17:45:34 +0800 Subject: [PATCH 003/103] fix(interaction): fix interaction relation components --- .../Interaction/BoardRelationList.tsx | 44 +++++++++++------- .../Interaction/ChartRelationList.tsx | 44 +++++++++++------- .../Customize/Interaction/ControllerList.tsx | 44 +++++++++++------- .../Customize/Interaction/UrlParamList.tsx | 46 ++++++++++++------- 4 files changed, 110 insertions(+), 68 deletions(-) diff --git a/frontend/src/app/components/FormGenerator/Customize/Interaction/BoardRelationList.tsx b/frontend/src/app/components/FormGenerator/Customize/Interaction/BoardRelationList.tsx index 1b272b24..e56d571d 100644 --- a/frontend/src/app/components/FormGenerator/Customize/Interaction/BoardRelationList.tsx +++ b/frontend/src/app/components/FormGenerator/Customize/Interaction/BoardRelationList.tsx @@ -86,28 +86,38 @@ const BoardRelationList: FC< ); }; - const handleDeleteRelation = index => { - if (index > -1) { + const handleDeleteRelation = id => { + if (id) { const newRelations = updateBy(relations, draft => { - draft?.splice(index, 1); + const index = draft!.findIndex(v => v.id === id); + if (index > -1) { + draft?.splice(index, 1); + } }); onRelationChange(newRelations); } }; - const handleRelationChange = (index, key, value) => { - if (index > -1) { + const handleRelationChange = (id, key, value) => { + if (id) { const newRelations = updateBy(relations, draft => { - draft![index][key] = value; + const config = draft!.find(v => v.id === id); + config && (config[key] = value); }); onRelationChange(newRelations); } }; - const handleRelationTypeChange = (index, value) => { - if (index > -1) { + const handleRelationTypeChange = (id, value) => { + if (id) { const newRelations = updateBy(relations, draft => { - draft![index] = { id: uuidv4(), type: value }; + const index = draft!.findIndex(v => v.id === id); + if (index > -1) { + draft![index] = { + id: uuidv4(), + type: value, + }; + } }); onRelationChange(newRelations); } @@ -122,12 +132,12 @@ const BoardRelationList: FC< title: t('drillThrough.rule.relation.type'), dataIndex: 'type', key: 'type', - render: (value, _, index) => ( + render: (value, record) => ( handleRelationTypeChange(index, e.target.value)} + onChange={e => handleRelationTypeChange(record.id, e.target.value)} > {t('drillThrough.rule.relation.field')} @@ -142,11 +152,11 @@ const BoardRelationList: FC< title: t('drillThrough.rule.relation.source'), dataIndex: 'source', key: 'source', - render: (value, record, index) => ( + render: (value, record) => ( handleRelationChange(index, 'target', value)} + onChange={value => handleRelationChange(record.id, 'target', value)} dropdownMatchSelectWidth={false} > {(isFieldType(record) ? targetFields : targetVariables)?.map(sf => { @@ -175,8 +185,8 @@ const BoardRelationList: FC< { key: 'operation', width: 50, - render: (_1, _2, index) => ( - ), diff --git a/frontend/src/app/components/FormGenerator/Customize/Interaction/ChartRelationList.tsx b/frontend/src/app/components/FormGenerator/Customize/Interaction/ChartRelationList.tsx index dffc6145..b444892b 100644 --- a/frontend/src/app/components/FormGenerator/Customize/Interaction/ChartRelationList.tsx +++ b/frontend/src/app/components/FormGenerator/Customize/Interaction/ChartRelationList.tsx @@ -76,28 +76,38 @@ const ChartRelationList: FC< ); }; - const handleDeleteRelation = index => { - if (index > -1) { + const handleDeleteRelation = id => { + if (id) { const newRelations = updateBy(relations, draft => { - draft?.splice(index, 1); + const index = draft!.findIndex(v => v.id === id); + if (index > -1) { + draft?.splice(index, 1); + } }); onRelationChange(newRelations); } }; - const handleRelationChange = (index, key, value) => { - if (index > -1) { + const handleRelationChange = (id, key, value) => { + if (id) { const newRelations = updateBy(relations, draft => { - draft![index][key] = value; + const config = draft!.find(v => v.id === id); + config && (config[key] = value); }); onRelationChange(newRelations); } }; - const handleRelationTypeChange = (index, value) => { - if (index > -1) { + const handleRelationTypeChange = (id, value) => { + if (id) { const newRelations = updateBy(relations, draft => { - draft![index] = { id: uuidv4(), type: value }; + const index = draft!.findIndex(v => v.id === id); + if (index > -1) { + draft![index] = { + id: uuidv4(), + type: value, + }; + } }); onRelationChange(newRelations); } @@ -112,12 +122,12 @@ const ChartRelationList: FC< title: t('drillThrough.rule.relation.type'), dataIndex: 'type', key: 'type', - render: (value, _, index) => ( + render: (value, record) => ( handleRelationTypeChange(index, e.target.value)} + onChange={e => handleRelationTypeChange(record.id, e.target.value)} > {t('drillThrough.rule.relation.field')} @@ -132,11 +142,11 @@ const ChartRelationList: FC< title: t('drillThrough.rule.relation.source'), dataIndex: 'source', key: 'source', - render: (value, record, index) => ( + render: (value, record) => ( handleRelationChange(index, 'target', value)} + onChange={value => handleRelationChange(record.id, 'target', value)} dropdownMatchSelectWidth={false} > {(isFieldType(record) ? targetFields : targetVariables)?.map(sf => { @@ -165,8 +175,8 @@ const ChartRelationList: FC< { key: 'operation', width: 50, - render: (_1, _2, index) => ( - ), diff --git a/frontend/src/app/components/FormGenerator/Customize/Interaction/ControllerList.tsx b/frontend/src/app/components/FormGenerator/Customize/Interaction/ControllerList.tsx index b58b7568..6a04dbf5 100644 --- a/frontend/src/app/components/FormGenerator/Customize/Interaction/ControllerList.tsx +++ b/frontend/src/app/components/FormGenerator/Customize/Interaction/ControllerList.tsx @@ -66,28 +66,38 @@ const ControllerList: FC< ); }; - const handleDeleteRelation = index => { - if (index > -1) { + const handleDeleteRelation = id => { + if (id) { const newRelations = updateBy(relations, draft => { - draft?.splice(index, 1); + const index = draft!.findIndex(v => v.id === id); + if (index > -1) { + draft?.splice(index, 1); + } }); onRelationChange(newRelations); } }; - const handleRelationChange = (index, key, value) => { - if (index > -1) { + const handleRelationChange = (id, key, value) => { + if (id) { const newRelations = updateBy(relations, draft => { - draft![index][key] = value; + const config = draft!.find(v => v.id === id); + config && (config[key] = value); }); onRelationChange(newRelations); } }; - const handleRelationTypeChange = (index, value) => { - if (index > -1) { + const handleRelationTypeChange = (id, value) => { + if (id) { const newRelations = updateBy(relations, draft => { - draft![index] = { id: uuidv4(), type: value }; + const index = draft!.findIndex(v => v.id === id); + if (index > -1) { + draft![index] = { + id: uuidv4(), + type: value, + }; + } }); onRelationChange(newRelations); } @@ -102,12 +112,12 @@ const ControllerList: FC< title: t('drillThrough.rule.relation.type'), dataIndex: 'type', key: 'type', - render: (value, _, index) => ( + render: (value, record) => ( handleRelationTypeChange(index, e.target.value)} + onChange={e => handleRelationTypeChange(record.id, e.target.value)} > {t('drillThrough.rule.relation.field')} @@ -122,11 +132,11 @@ const ControllerList: FC< title: t('drillThrough.rule.relation.source'), dataIndex: 'source', key: 'source', - render: (value, record, index) => ( + render: (value, record) => ( handleRelationChange(index, 'target', value)} + onChange={value => handleRelationChange(record.id, 'target', value)} dropdownMatchSelectWidth={false} > {controllerNames?.map(name => { @@ -155,8 +165,8 @@ const ControllerList: FC< { key: 'operation', width: 50, - render: (_1, _2, index) => ( - ), diff --git a/frontend/src/app/components/FormGenerator/Customize/Interaction/UrlParamList.tsx b/frontend/src/app/components/FormGenerator/Customize/Interaction/UrlParamList.tsx index fff58d2c..a94c17c2 100644 --- a/frontend/src/app/components/FormGenerator/Customize/Interaction/UrlParamList.tsx +++ b/frontend/src/app/components/FormGenerator/Customize/Interaction/UrlParamList.tsx @@ -48,28 +48,38 @@ const UrlParamList: FC< ); }; - const handleDeleteRelation = index => { - if (index > -1) { + const handleDeleteRelation = id => { + if (id) { const newRelations = updateBy(relations, draft => { - draft?.splice(index, 1); + const index = draft!.findIndex(v => v.id === id); + if (index > -1) { + draft?.splice(index, 1); + } }); onRelationChange(newRelations); } }; - const handleRelationChange = (index, key, value) => { - if (index > -1) { + const handleRelationChange = (id, key, value) => { + if (id) { const newRelations = updateBy(relations, draft => { - draft![index][key] = value; + const config = draft!.find(v => v.id === id); + config && (config[key] = value); }); onRelationChange(newRelations); } }; - const handleRelationTypeChange = (index, value) => { - if (index > -1) { + const handleRelationTypeChange = (id, value) => { + if (id) { const newRelations = updateBy(relations, draft => { - draft![index] = { id: uuidv4(), type: value }; + const index = draft!.findIndex(v => v.id === id); + if (index > -1) { + draft![index] = { + id: uuidv4(), + type: value, + }; + } }); onRelationChange(newRelations); } @@ -84,12 +94,12 @@ const UrlParamList: FC< title: t('drillThrough.rule.relation.type'), dataIndex: 'type', key: 'type', - render: (value, _, index) => ( + render: (value, record) => ( handleRelationTypeChange(index, e.target.value)} + onChange={e => handleRelationTypeChange(record.id, e.target.value)} > {t('drillThrough.rule.relation.field')} @@ -104,11 +114,11 @@ const UrlParamList: FC< title: t('drillThrough.rule.relation.source'), dataIndex: 'source', key: 'source', - render: (value, record, index) => ( + render: (value, record) => ( handleRelationChange(index, 'target', e.target.value)} + onChange={e => + handleRelationChange(record.id, 'target', e.target.value) + } /> ), }, { key: 'operation', width: 50, - render: (_1, _2, index) => ( - ), -- Gitee From c4ad5329a91e27c5084806f73cf53ebc935ede48 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Thu, 11 Aug 2022 21:25:02 +0800 Subject: [PATCH 004/103] fix: issue #1858 --- frontend/src/__tests__/task.test.ts | 9 ++- .../ChartDrill/ChartDrillContextMenu.tsx | 9 ++- .../Interaction/BoardRelationList.tsx | 13 +++- .../Interaction/ChartRelationList.tsx | 13 +++- .../BoardConfig/migrateWidgetChartConfig.ts | 45 +++++++++++++ .../ChartConfig/migrateChartConfig.ts | 67 +++++++++++++++++-- .../__tests__/migrateChartConfig.test.ts | 8 +-- frontend/src/app/migration/constants.ts | 2 + .../DateLevelFieldContainer.tsx | 5 +- .../DateLevelAction/DateLevelMenuItems.tsx | 6 +- .../components/ChartOperationPanel/utils.ts | 17 ++++- .../pages/ChartWorkbenchPage/slice/types.ts | 1 + .../pages/Board/slice/asyncActions.ts | 7 +- .../app/pages/DashBoardPage/utils/widget.ts | 1 - .../utils/__tests__/chartDtoHelper.test.ts | 6 +- frontend/src/app/utils/chartHelper.ts | 8 ++- frontend/src/app/utils/internalChartHelper.ts | 4 ++ frontend/src/globalConstants.ts | 1 + 18 files changed, 190 insertions(+), 32 deletions(-) create mode 100644 frontend/src/app/migration/BoardConfig/migrateWidgetChartConfig.ts diff --git a/frontend/src/__tests__/task.test.ts b/frontend/src/__tests__/task.test.ts index 344ca445..894e8e97 100644 --- a/frontend/src/__tests__/task.test.ts +++ b/frontend/src/__tests__/task.test.ts @@ -111,7 +111,7 @@ describe('Test getQueryData', () => { test('should get Chart Query data has computed', () => { const dataStr = JSON.stringify({ config: - '{"aggregation":true,"chartConfig":{"datas":[{"actions":{"NUMERIC":["aggregate","alias","format","sortable"],"STRING":["alias","sortable"],"DATE":["alias","sortable","dateLevel"]},"label":"mixed","key":"mixed","required":true,"type":"mixed","rows":[{"uid":"8ee5af74-3927-433f-806c-21469eafcdbd","field":"root.birthday","colName":"root.birthday(Year)","type":"DATE","category":"dateLevelComputedField","expression":"AGG_DATE_YEAR([root].[birthday])"},{"uid":"ac82d0ef-b162-4ec3-a534-4c48229c448b","colName":"root.age","type":"STRING","category":"field","children":[]},{"uid":"4090e82e-cc8a-4af1-b664-191a14067549","colName":"viewComputerField_age","type":"NUMERIC","category":"computedField","children":[],"aggregate":"SUM"},{"uid":"52a13c93-a529-4f9b-889c-9ec5c3825a79","colName":"root.salary","type":"NUMERIC","category":"field","children":[],"aggregate":"SUM"}]},{"label":"filter","key":"filter","type":"filter","disableAggregate":true}],"styles":[{"label":"header.title","key":"header","comType":"group","rows":[{"label":"header.open","key":"modal","comType":"group","options":{"type":"modal","modalSize":"middle"},"rows":[{"label":"header.styleAndGroup","key":"tableHeaders","comType":"tableHeader"}]}]},{"label":"column.conditionalStyle","key":"column","comType":"group","rows":[{"label":"column.open","key":"modal","comType":"group","options":{"type":"modal","modalSize":"middle"},"rows":[{"label":"column.list","key":"list","comType":"listTemplate","rows":[],"options":{},"template":{"label":"column.listItem","key":"listItem","comType":"group","rows":[{"label":"column.columnStyle","key":"columnStyle","comType":"group","options":{"expand":true},"rows":[{"label":"column.useColumnWidth","key":"useColumnWidth","default":false,"comType":"checkbox"},{"label":"column.columnWidth","key":"columnWidth","default":100,"options":{"min":0},"watcher":{"deps":["useColumnWidth"]},"comType":"inputNumber"},{"label":"style.align","key":"align","default":"default","comType":"fontAlignment","options":{"translateItemLabel":true,"items":[{"label":"@global@.style.alignDefault","value":"default"},{"label":"viz.common.enum.fontAlignment.left","value":"left"},{"label":"viz.common.enum.fontAlignment.center","value":"center"},{"label":"viz.common.enum.fontAlignment.right","value":"right"}]}}]},{"label":"column.conditionalStyle","key":"conditionalStyle","comType":"group","options":{"expand":true},"rows":[{"label":"column.conditionalStylePanel","key":"conditionalStylePanel","comType":"conditionalStylePanel"}]}]}}]}]},{"label":"style.title","key":"style","comType":"group","rows":[{"label":"style.enableFixedHeader","key":"enableFixedHeader","default":true,"comType":"checkbox","value":true},{"label":"style.enableBorder","key":"enableBorder","default":true,"comType":"checkbox","value":true},{"label":"style.enableRowNumber","key":"enableRowNumber","default":false,"comType":"checkbox","value":false},{"label":"style.leftFixedColumns","key":"leftFixedColumns","default":0,"options":{"min":0},"comType":"inputNumber","value":0},{"label":"style.rightFixedColumns","key":"rightFixedColumns","default":0,"options":{"min":0},"comType":"inputNumber","value":0},{"label":"style.autoMergeFields","key":"autoMergeFields","comType":"select","options":{"mode":"multiple"}},{"label":"style.tableSize","key":"tableSize","default":"small","comType":"select","options":{"translateItemLabel":true,"items":[{"label":"@global@.tableSize.default","value":"default"},{"label":"@global@.tableSize.middle","value":"middle"},{"label":"@global@.tableSize.small","value":"small"}]},"value":"small"}]},{"label":"style.tableHeaderStyle","key":"tableHeaderStyle","comType":"group","rows":[{"label":"common.backgroundColor","key":"bgColor","default":"#f8f9fa","comType":"fontColor","value":"#f8f9fa"},{"label":"style.font","key":"font","comType":"font","default":{"fontFamily":"-apple-system, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"","fontSize":12,"fontWeight":"bold","fontStyle":"normal","color":"#495057"},"value":{"fontFamily":"-apple-system, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"","fontSize":12,"fontWeight":"bold","fontStyle":"normal","color":"#495057"}},{"label":"style.align","key":"align","default":"left","comType":"fontAlignment","value":"left"}]},{"label":"style.tableBodyStyle","key":"tableBodyStyle","comType":"group","rows":[{"label":"style.oddFontColor","key":"oddFontColor","default":"#000","comType":"fontColor","value":"#000"},{"label":"style.oddBgColor","key":"oddBgColor","default":"rgba(0,0,0,0)","comType":"fontColor","value":"rgba(0,0,0,0)"},{"label":"style.evenFontColor","key":"evenFontColor","default":"#000","comType":"fontColor","value":"#000"},{"label":"style.evenBgColor","key":"evenBgColor","default":"rgba(0,0,0,0)","comType":"fontColor","value":"rgba(0,0,0,0)"},{"label":"style.fontSize","key":"fontSize","comType":"fontSize","default":12,"value":12},{"label":"style.fontFamily","key":"fontFamily","comType":"fontFamily","default":"-apple-system, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"","value":"-apple-system, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\""},{"label":"style.fontWeight","key":"fontWeight","comType":"fontWeight","default":"normal","value":"normal"},{"label":"style.fontStyle","key":"fontStyle","comType":"fontStyle","default":"normal","value":"normal"},{"label":"style.align","key":"align","default":"default","comType":"fontAlignment","options":{"translateItemLabel":true,"items":[{"label":"@global@.style.alignDefault","value":"default"},{"label":"viz.common.enum.fontAlignment.left","value":"left"},{"label":"viz.common.enum.fontAlignment.center","value":"center"},{"label":"viz.common.enum.fontAlignment.right","value":"right"}]},"value":"default"}]}],"settings":[{"label":"paging.title","key":"paging","comType":"group","rows":[{"label":"paging.enablePaging","key":"enablePaging","default":true,"comType":"checkbox","options":{"needRefresh":true},"value":true},{"label":"paging.pageSize","key":"pageSize","default":100,"comType":"inputNumber","options":{"needRefresh":true,"step":1,"min":0},"watcher":{"deps":["enablePaging"]},"value":100}]},{"label":"summary.title","key":"summary","comType":"group","rows":[{"label":"summary.aggregateFields","key":"aggregateFields","comType":"select","options":{"mode":"multiple"}},{"label":"common.backgroundColor","key":"summaryBcColor","default":"rgba(0, 0, 0, 0)","comType":"fontColor","value":"rgba(0, 0, 0, 0)"},{"label":"viz.palette.style.font","key":"summaryFont","comType":"font","default":{"fontFamily":"-apple-system, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"","fontSize":"14","fontWeight":"normal","fontStyle":"normal","color":"black"},"value":{"fontFamily":"-apple-system, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"","fontSize":"14","fontWeight":"normal","fontStyle":"normal","color":"black"}}]}],"interactions":[{"label":"drillThrough.title","key":"drillThrough","comType":"checkboxModal","default":false,"options":{"modalSize":"middle"},"rows":[{"label":"drillThrough.title","key":"setting","comType":"interaction.drillThrough"}],"value":false},{"label":"viewDetail.title","key":"viewDetail","comType":"checkboxModal","default":false,"options":{"modalSize":"middle"},"rows":[{"label":"viewDetail.title","key":"setting","comType":"interaction.viewDetail"}],"value":false}],"i18ns":[{"lang":"zh-CN","translation":{"common":{"backgroundColor":"背景颜色"},"header":{"title":"表头分组","open":"打开","styleAndGroup":"表头分组"},"column":{"open":"打开样式设置","list":"字段列表","sortAndFilter":"排序与过滤","enableSort":"开启列排序","basicStyle":"基础样式","useColumnWidth":"启用固定列宽","columnWidth":"列宽","columnStyle":"列样式","columnStylePanel":"列样式配置器","conditionalStyle":"条件样式","conditionalStylePanel":"条件样式配置器","align":"对齐方式","enableFixedCol":"开启固定列宽","fixedColWidth":"固定列宽度设置","font":"字体与样式"},"style":{"title":"表格样式","enableFixedHeader":"固定表头","enableBorder":"显示边框","enableRowNumber":"启用行号","leftFixedColumns":"左侧固定列","rightFixedColumns":"右侧固定列","autoMergeFields":"自动合并列内容","tableSize":"表格大小","tableHeaderStyle":"表头样式","tableBodyStyle":"表体样式","bgColor":"背景颜色","font":"字体","align":"对齐方式","alignDefault":"默认","fontWeight":"字体粗细","fontFamily":"字体","oddBgColor":"奇行背景色","oddFontColor":"奇行字体色","evenBgColor":"偶行背景色","evenFontColor":"偶行字体色","fontSize":"字体大小","fontStyle":"字体样式"},"tableSize":{"default":"默认","middle":"中","small":"小"},"summary":{"title":"数据汇总","aggregateFields":"汇总列"},"paging":{"title":"常规","enablePaging":"启用分页","pageSize":"每页行数"}}},{"lang":"en-US","translation":{"common":{"backgroundColor":"Background Color"},"header":{"title":"Table Header Group","open":"Open","styleAndGroup":"Header Group"},"column":{"open":"Open Style Setting","list":"Field List","sortAndFilter":"Sort and Filter","enableSort":"Enable Sort","basicStyle":"Baisc Style","useColumnWidth":"Use Column Width","columnWidth":"Column Width","columnStyle":"Column Style","columnStylePanel":"Column Style Panel","conditionalStyle":"Conditional Style","conditionalStylePanel":"Conditional Style Panel","align":"Align","enableFixedCol":"Enable Fixed Column","fixedColWidth":"Fixed Column Width","font":"Font and Style"},"style":{"title":"Table Style","enableFixedHeader":"Enable Fixed Header","enableBorder":"Show Border","enableRowNumber":"Enable Row Number","leftFixedColumns":"LeftFixed Columns","rightFixedColumns":"Right Fixed Columns","autoMergeFields":"Auto Merge Column Content","tableSize":"Table Size","tableHeaderStyle":"Table Header Style","tableBodyStyle":"Table Body Style","font":"Font","align":"Align","alignDefault":"Default","fontWeight":"Font Weight","fontFamily":"Font Family","oddBgColor":"Odd Row Background Color","evenBgColor":"Even Row Background Color","oddFontColor":"Odd Row Font Color","evenFontColor":"Even Row Font Color","fontSize":"Font Size","fontStyle":"Font Style"},"tableSize":{"default":"Default","middle":"Middle","small":"Small"},"summary":{"title":"Summary","aggregateFields":"Summary Fields"},"paging":{"title":"Paging","enablePaging":"Enable Paging","pageSize":"Page Size"}}}]},"chartGraphId":"mingxi-table","computedFields":[{"category":"dateLevelComputedField","name":"root.birthday(Year)","type":"DATE","expression":"AGG_DATE_YEAR([root].[birthday])"}]}', + '{"aggregation":true,"chartConfig":{"datas":[{"actions":{"NUMERIC":["aggregate","alias","format","sortable"],"STRING":["alias","sortable"],"DATE":["alias","sortable","dateLevel"]},"label":"mixed","key":"mixed","required":true,"type":"mixed","rows":[{"uid":"8ee5af74-3927-433f-806c-21469eafcdbd","field":"root.birthday","colName":"root.birthday@date_level_delimiter@AGG_DATE_YEAR","type":"DATE","category":"dateLevelComputedField","expression":"AGG_DATE_YEAR([root].[birthday])"},{"uid":"ac82d0ef-b162-4ec3-a534-4c48229c448b","colName":"root.age","type":"STRING","category":"field","children":[]},{"uid":"4090e82e-cc8a-4af1-b664-191a14067549","colName":"viewComputerField_age","type":"NUMERIC","category":"computedField","children":[],"aggregate":"SUM"},{"uid":"52a13c93-a529-4f9b-889c-9ec5c3825a79","colName":"root.salary","type":"NUMERIC","category":"field","children":[],"aggregate":"SUM"}]},{"label":"filter","key":"filter","type":"filter","disableAggregate":true}],"styles":[{"label":"header.title","key":"header","comType":"group","rows":[{"label":"header.open","key":"modal","comType":"group","options":{"type":"modal","modalSize":"middle"},"rows":[{"label":"header.styleAndGroup","key":"tableHeaders","comType":"tableHeader"}]}]},{"label":"column.conditionalStyle","key":"column","comType":"group","rows":[{"label":"column.open","key":"modal","comType":"group","options":{"type":"modal","modalSize":"middle"},"rows":[{"label":"column.list","key":"list","comType":"listTemplate","rows":[],"options":{},"template":{"label":"column.listItem","key":"listItem","comType":"group","rows":[{"label":"column.columnStyle","key":"columnStyle","comType":"group","options":{"expand":true},"rows":[{"label":"column.useColumnWidth","key":"useColumnWidth","default":false,"comType":"checkbox"},{"label":"column.columnWidth","key":"columnWidth","default":100,"options":{"min":0},"watcher":{"deps":["useColumnWidth"]},"comType":"inputNumber"},{"label":"style.align","key":"align","default":"default","comType":"fontAlignment","options":{"translateItemLabel":true,"items":[{"label":"@global@.style.alignDefault","value":"default"},{"label":"viz.common.enum.fontAlignment.left","value":"left"},{"label":"viz.common.enum.fontAlignment.center","value":"center"},{"label":"viz.common.enum.fontAlignment.right","value":"right"}]}}]},{"label":"column.conditionalStyle","key":"conditionalStyle","comType":"group","options":{"expand":true},"rows":[{"label":"column.conditionalStylePanel","key":"conditionalStylePanel","comType":"conditionalStylePanel"}]}]}}]}]},{"label":"style.title","key":"style","comType":"group","rows":[{"label":"style.enableFixedHeader","key":"enableFixedHeader","default":true,"comType":"checkbox","value":true},{"label":"style.enableBorder","key":"enableBorder","default":true,"comType":"checkbox","value":true},{"label":"style.enableRowNumber","key":"enableRowNumber","default":false,"comType":"checkbox","value":false},{"label":"style.leftFixedColumns","key":"leftFixedColumns","default":0,"options":{"min":0},"comType":"inputNumber","value":0},{"label":"style.rightFixedColumns","key":"rightFixedColumns","default":0,"options":{"min":0},"comType":"inputNumber","value":0},{"label":"style.autoMergeFields","key":"autoMergeFields","comType":"select","options":{"mode":"multiple"}},{"label":"style.tableSize","key":"tableSize","default":"small","comType":"select","options":{"translateItemLabel":true,"items":[{"label":"@global@.tableSize.default","value":"default"},{"label":"@global@.tableSize.middle","value":"middle"},{"label":"@global@.tableSize.small","value":"small"}]},"value":"small"}]},{"label":"style.tableHeaderStyle","key":"tableHeaderStyle","comType":"group","rows":[{"label":"common.backgroundColor","key":"bgColor","default":"#f8f9fa","comType":"fontColor","value":"#f8f9fa"},{"label":"style.font","key":"font","comType":"font","default":{"fontFamily":"-apple-system, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"","fontSize":12,"fontWeight":"bold","fontStyle":"normal","color":"#495057"},"value":{"fontFamily":"-apple-system, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"","fontSize":12,"fontWeight":"bold","fontStyle":"normal","color":"#495057"}},{"label":"style.align","key":"align","default":"left","comType":"fontAlignment","value":"left"}]},{"label":"style.tableBodyStyle","key":"tableBodyStyle","comType":"group","rows":[{"label":"style.oddFontColor","key":"oddFontColor","default":"#000","comType":"fontColor","value":"#000"},{"label":"style.oddBgColor","key":"oddBgColor","default":"rgba(0,0,0,0)","comType":"fontColor","value":"rgba(0,0,0,0)"},{"label":"style.evenFontColor","key":"evenFontColor","default":"#000","comType":"fontColor","value":"#000"},{"label":"style.evenBgColor","key":"evenBgColor","default":"rgba(0,0,0,0)","comType":"fontColor","value":"rgba(0,0,0,0)"},{"label":"style.fontSize","key":"fontSize","comType":"fontSize","default":12,"value":12},{"label":"style.fontFamily","key":"fontFamily","comType":"fontFamily","default":"-apple-system, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"","value":"-apple-system, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\""},{"label":"style.fontWeight","key":"fontWeight","comType":"fontWeight","default":"normal","value":"normal"},{"label":"style.fontStyle","key":"fontStyle","comType":"fontStyle","default":"normal","value":"normal"},{"label":"style.align","key":"align","default":"default","comType":"fontAlignment","options":{"translateItemLabel":true,"items":[{"label":"@global@.style.alignDefault","value":"default"},{"label":"viz.common.enum.fontAlignment.left","value":"left"},{"label":"viz.common.enum.fontAlignment.center","value":"center"},{"label":"viz.common.enum.fontAlignment.right","value":"right"}]},"value":"default"}]}],"settings":[{"label":"paging.title","key":"paging","comType":"group","rows":[{"label":"paging.enablePaging","key":"enablePaging","default":true,"comType":"checkbox","options":{"needRefresh":true},"value":true},{"label":"paging.pageSize","key":"pageSize","default":100,"comType":"inputNumber","options":{"needRefresh":true,"step":1,"min":0},"watcher":{"deps":["enablePaging"]},"value":100}]},{"label":"summary.title","key":"summary","comType":"group","rows":[{"label":"summary.aggregateFields","key":"aggregateFields","comType":"select","options":{"mode":"multiple"}},{"label":"common.backgroundColor","key":"summaryBcColor","default":"rgba(0, 0, 0, 0)","comType":"fontColor","value":"rgba(0, 0, 0, 0)"},{"label":"viz.palette.style.font","key":"summaryFont","comType":"font","default":{"fontFamily":"-apple-system, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"","fontSize":"14","fontWeight":"normal","fontStyle":"normal","color":"black"},"value":{"fontFamily":"-apple-system, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"","fontSize":"14","fontWeight":"normal","fontStyle":"normal","color":"black"}}]}],"interactions":[{"label":"drillThrough.title","key":"drillThrough","comType":"checkboxModal","default":false,"options":{"modalSize":"middle"},"rows":[{"label":"drillThrough.title","key":"setting","comType":"interaction.drillThrough"}],"value":false},{"label":"viewDetail.title","key":"viewDetail","comType":"checkboxModal","default":false,"options":{"modalSize":"middle"},"rows":[{"label":"viewDetail.title","key":"setting","comType":"interaction.viewDetail"}],"value":false}],"i18ns":[{"lang":"zh-CN","translation":{"common":{"backgroundColor":"背景颜色"},"header":{"title":"表头分组","open":"打开","styleAndGroup":"表头分组"},"column":{"open":"打开样式设置","list":"字段列表","sortAndFilter":"排序与过滤","enableSort":"开启列排序","basicStyle":"基础样式","useColumnWidth":"启用固定列宽","columnWidth":"列宽","columnStyle":"列样式","columnStylePanel":"列样式配置器","conditionalStyle":"条件样式","conditionalStylePanel":"条件样式配置器","align":"对齐方式","enableFixedCol":"开启固定列宽","fixedColWidth":"固定列宽度设置","font":"字体与样式"},"style":{"title":"表格样式","enableFixedHeader":"固定表头","enableBorder":"显示边框","enableRowNumber":"启用行号","leftFixedColumns":"左侧固定列","rightFixedColumns":"右侧固定列","autoMergeFields":"自动合并列内容","tableSize":"表格大小","tableHeaderStyle":"表头样式","tableBodyStyle":"表体样式","bgColor":"背景颜色","font":"字体","align":"对齐方式","alignDefault":"默认","fontWeight":"字体粗细","fontFamily":"字体","oddBgColor":"奇行背景色","oddFontColor":"奇行字体色","evenBgColor":"偶行背景色","evenFontColor":"偶行字体色","fontSize":"字体大小","fontStyle":"字体样式"},"tableSize":{"default":"默认","middle":"中","small":"小"},"summary":{"title":"数据汇总","aggregateFields":"汇总列"},"paging":{"title":"常规","enablePaging":"启用分页","pageSize":"每页行数"}}},{"lang":"en-US","translation":{"common":{"backgroundColor":"Background Color"},"header":{"title":"Table Header Group","open":"Open","styleAndGroup":"Header Group"},"column":{"open":"Open Style Setting","list":"Field List","sortAndFilter":"Sort and Filter","enableSort":"Enable Sort","basicStyle":"Baisc Style","useColumnWidth":"Use Column Width","columnWidth":"Column Width","columnStyle":"Column Style","columnStylePanel":"Column Style Panel","conditionalStyle":"Conditional Style","conditionalStylePanel":"Conditional Style Panel","align":"Align","enableFixedCol":"Enable Fixed Column","fixedColWidth":"Fixed Column Width","font":"Font and Style"},"style":{"title":"Table Style","enableFixedHeader":"Enable Fixed Header","enableBorder":"Show Border","enableRowNumber":"Enable Row Number","leftFixedColumns":"LeftFixed Columns","rightFixedColumns":"Right Fixed Columns","autoMergeFields":"Auto Merge Column Content","tableSize":"Table Size","tableHeaderStyle":"Table Header Style","tableBodyStyle":"Table Body Style","font":"Font","align":"Align","alignDefault":"Default","fontWeight":"Font Weight","fontFamily":"Font Family","oddBgColor":"Odd Row Background Color","evenBgColor":"Even Row Background Color","oddFontColor":"Odd Row Font Color","evenFontColor":"Even Row Font Color","fontSize":"Font Size","fontStyle":"Font Style"},"tableSize":{"default":"Default","middle":"Middle","small":"Small"},"summary":{"title":"Summary","aggregateFields":"Summary Fields"},"paging":{"title":"Paging","enablePaging":"Enable Paging","pageSize":"Page Size"}}}]},"chartGraphId":"mingxi-table","computedFields":[{"category":"dateLevelComputedField","name":"root.birthday(Year)","type":"DATE","expression":"AGG_DATE_YEAR([root].[birthday])"}]}', createBy: '06b6305528694968bc7085ecdabe4a5a', createTime: '2022-07-25 11:40:30', description: null, @@ -174,7 +174,10 @@ describe('Test getQueryData', () => { }, ], groups: [ - { alias: 'root.birthday(Year)', column: ['root.birthday(Year)'] }, + { + alias: 'root.birthday@date_level_delimiter@AGG_DATE_YEAR', + column: ['root.birthday@date_level_delimiter@AGG_DATE_YEAR'], + }, { alias: 'root.age', column: ['root', 'age'] }, ], filters: [], @@ -182,7 +185,7 @@ describe('Test getQueryData', () => { pageInfo: { countTotal: true, pageSize: 100 }, functionColumns: [ { - alias: 'root.birthday(Year)', + alias: 'root.birthday@date_level_delimiter@AGG_DATE_YEAR', snippet: 'AGG_DATE_YEAR([root].[birthday])', }, { alias: 'viewComputerField_age', snippet: '[root].[age]' }, diff --git a/frontend/src/app/components/ChartDrill/ChartDrillContextMenu.tsx b/frontend/src/app/components/ChartDrill/ChartDrillContextMenu.tsx index ec665e9a..8f11af52 100644 --- a/frontend/src/app/components/ChartDrill/ChartDrillContextMenu.tsx +++ b/frontend/src/app/components/ChartDrill/ChartDrillContextMenu.tsx @@ -28,6 +28,7 @@ import ChartDrillContext from 'app/contexts/ChartDrillContext'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { DrillMode } from 'app/models/ChartDrillOption'; import DateLevelMenuItems from 'app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/DateLevelAction/DateLevelMenuItems'; +import { handleDateLevelsName } from 'app/pages/ChartWorkbenchPage/components/ChartOperationPanel/utils'; import { ChartConfig, ChartDataSectionField } from 'app/types/ChartConfig'; import { ChartDataViewMeta } from 'app/types/ChartDataViewMeta'; import { getRuntimeDateLevelFields } from 'app/utils/chartHelper'; @@ -215,7 +216,13 @@ const ChartDrillContextMenu: FC<{ ) ?.map((v, i) => { return ( - + {(isFieldType(record) ? sourceFields : sourceVariables)?.map(sf => { - return {sf?.name}; + return ( + + {handleDateLevelsName(sf)} + + ); })} ), @@ -167,7 +172,11 @@ const BoardRelationList: FC< dropdownMatchSelectWidth={false} > {(isFieldType(record) ? targetFields : targetVariables)?.map(sf => { - return {sf?.name}; + return ( + + {handleDateLevelsName(sf)} + + ); })} ), diff --git a/frontend/src/app/components/FormGenerator/Customize/Interaction/ChartRelationList.tsx b/frontend/src/app/components/FormGenerator/Customize/Interaction/ChartRelationList.tsx index dffc6145..300e3706 100644 --- a/frontend/src/app/components/FormGenerator/Customize/Interaction/ChartRelationList.tsx +++ b/frontend/src/app/components/FormGenerator/Customize/Interaction/ChartRelationList.tsx @@ -19,6 +19,7 @@ import { Button, Radio, Select, Table } from 'antd'; import { ColumnsType } from 'antd/lib/table'; import useMount from 'app/hooks/useMount'; +import { handleDateLevelsName } from 'app/pages/ChartWorkbenchPage/components/ChartOperationPanel/utils'; import { Variable } from 'app/pages/MainPage/pages/VariablePage/slice/types'; import { ChartDataViewMeta } from 'app/types/ChartDataViewMeta'; import { @@ -140,7 +141,11 @@ const ChartRelationList: FC< dropdownMatchSelectWidth={false} > {(isFieldType(record) ? sourceFields : sourceVariables)?.map(sf => { - return {sf?.name}; + return ( + + {handleDateLevelsName(sf)} + + ); })} ), @@ -157,7 +162,11 @@ const ChartRelationList: FC< dropdownMatchSelectWidth={false} > {(isFieldType(record) ? targetFields : targetVariables)?.map(sf => { - return {sf?.name}; + return ( + + {handleDateLevelsName(sf)} + + ); })} ), diff --git a/frontend/src/app/migration/BoardConfig/migrateWidgetChartConfig.ts b/frontend/src/app/migration/BoardConfig/migrateWidgetChartConfig.ts new file mode 100644 index 00000000..4ad2e215 --- /dev/null +++ b/frontend/src/app/migration/BoardConfig/migrateWidgetChartConfig.ts @@ -0,0 +1,45 @@ +/** + * Datart + * + * Copyright 2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Widget } from 'app/pages/DashBoardPage/types/widgetTypes'; +import { RC2 } from '../ChartConfig/migrateChartConfig'; +import { APP_VERSION_RC_2 } from '../constants'; +import MigrationEvent from '../MigrationEvent'; +import MigrationEventDispatcher from '../MigrationEventDispatcher'; + +const migrateWidgetChartConfig = (widgets: Widget[]): Widget[] => { + if (!Array.isArray(widgets)) { + return []; + } + return widgets + .map(widget => { + if (widget?.config?.content?.dataChart?.config) { + const event_rc_2 = new MigrationEvent(APP_VERSION_RC_2, RC2); + const dispatcher_rc_2 = new MigrationEventDispatcher(event_rc_2); + + widget.config.content.dataChart.config = dispatcher_rc_2.process( + widget.config.content.dataChart.config, + ); + } + + return widget; + }) + .filter(Boolean) as Widget[]; +}; + +export default migrateWidgetChartConfig; diff --git a/frontend/src/app/migration/ChartConfig/migrateChartConfig.ts b/frontend/src/app/migration/ChartConfig/migrateChartConfig.ts index 180ec699..71835247 100644 --- a/frontend/src/app/migration/ChartConfig/migrateChartConfig.ts +++ b/frontend/src/app/migration/ChartConfig/migrateChartConfig.ts @@ -16,7 +16,9 @@ * limitations under the License. */ -import { APP_VERSION_RC_0 } from '../constants'; +import { ChartDataViewFieldCategory } from 'app/constants'; +import { DATE_LEVEL_DELIMITER } from 'globalConstants'; +import { APP_VERSION_RC_0, APP_VERSION_RC_2 } from '../constants'; import MigrationEvent from '../MigrationEvent'; import MigrationEventDispatcher from '../MigrationEventDispatcher'; @@ -45,16 +47,69 @@ export const RC0 = config => { } }; -const migrationViewConfig = (config: string): string => { +export const RC2 = config => { + if (!config) { + return config; + } + try { + if (config?.chartConfig) { + config.chartConfig?.datas.forEach(data => { + data.rows?.forEach(row => { + if ( + row.category === + ChartDataViewFieldCategory.DateLevelComputedField && + !row.colName.includes(DATE_LEVEL_DELIMITER) + ) { + row.colName = + row.field + DATE_LEVEL_DELIMITER + row.expression.split('(')[0]; + } + }); + }); + } + if (config?.computedFields) { + const allRows = config.chartConfig?.datas.flatMap(v => v.rows || []); + config.computedFields = config.computedFields.map(computedField => { + if ( + computedField.category === + ChartDataViewFieldCategory.DateLevelComputedField && + !computedField.name.includes(DATE_LEVEL_DELIMITER) + ) { + const currenrRowFiledForComputed = allRows.find( + row => row.expression === computedField.expression, + ); + return { + ...computedField, + name: + currenrRowFiledForComputed.field + + DATE_LEVEL_DELIMITER + + computedField.expression.split('(')[0], + }; + } + return computedField; + }); + } + + return config; + } catch (error) { + console.error('Migration config Errors | RC.0 | ', error); + return config; + } +}; + +const migrationChartConfig = (config: string): string => { if (!config) { return config; } const chartConfig = JSON.parse(config); - const event2 = new MigrationEvent(APP_VERSION_RC_0, RC0); - const dispatcher = new MigrationEventDispatcher(event2); + const event = new MigrationEvent(APP_VERSION_RC_0, RC0); + const dispatcher = new MigrationEventDispatcher(event); const result = dispatcher.process(chartConfig); - return JSON.stringify(result); + const event2 = new MigrationEvent(APP_VERSION_RC_2, RC2); + const dispatcher2 = new MigrationEventDispatcher(event2); + const result2 = dispatcher2.process(result); + + return JSON.stringify(result2); }; -export default migrationViewConfig; +export default migrationChartConfig; diff --git a/frontend/src/app/migration/__tests__/migrateChartConfig.test.ts b/frontend/src/app/migration/__tests__/migrateChartConfig.test.ts index 92a82358..69be6def 100644 --- a/frontend/src/app/migration/__tests__/migrateChartConfig.test.ts +++ b/frontend/src/app/migration/__tests__/migrateChartConfig.test.ts @@ -16,7 +16,7 @@ * limitations under the License. */ import migrateChartConfig, { RC0 } from '../ChartConfig/migrateChartConfig'; -import { APP_VERSION_RC_0 } from '../constants'; +import { APP_VERSION_RC_0, APP_VERSION_RC_2 } from '../constants'; describe('test RC0 Function ', () => { test('should add name fields for chartConfig computedFields', () => { @@ -59,7 +59,7 @@ describe('test migrateChartConfig ', () => { expect(result).toEqual( JSON.stringify({ computedFields: [{ id: '1', name: '1' }], - version: APP_VERSION_RC_0, + version: APP_VERSION_RC_2, }), ); }); @@ -73,7 +73,7 @@ describe('test migrateChartConfig ', () => { expect(result).toEqual( JSON.stringify({ computedFields: [{ name: '1' }], - version: APP_VERSION_RC_0, + version: APP_VERSION_RC_2, }), ); }); @@ -82,6 +82,6 @@ describe('test migrateChartConfig ', () => { const chartConfig = JSON.stringify({}) as any; const result = migrateChartConfig(chartConfig as any); - expect(result).toEqual(JSON.stringify({ version: APP_VERSION_RC_0 })); + expect(result).toEqual(JSON.stringify({ version: APP_VERSION_RC_2 })); }); }); diff --git a/frontend/src/app/migration/constants.ts b/frontend/src/app/migration/constants.ts index d7ddd869..96bccb89 100644 --- a/frontend/src/app/migration/constants.ts +++ b/frontend/src/app/migration/constants.ts @@ -26,6 +26,7 @@ export const APP_VERSION_BETA_4_1 = '1.0.0-beta.4+1'; export const APP_VERSION_BETA_4_2 = '1.0.0-beta.4+2'; export const APP_VERSION_RC_0 = '1.0.0-RC.0'; export const APP_VERSION_RC_1 = '1.0.0-RC.1'; +export const APP_VERSION_RC_2 = '1.0.0-RC.2'; export const APP_SEMANTIC_VERSIONS = [ APP_VERSION_INIT, @@ -38,6 +39,7 @@ export const APP_SEMANTIC_VERSIONS = [ APP_VERSION_BETA_4_2, APP_VERSION_RC_0, APP_VERSION_RC_1, + APP_VERSION_RC_2, ]; export const APP_CURRENT_VERSION = diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/DateLevelFieldContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/DateLevelFieldContainer.tsx index 9eb46986..ffc194ad 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/DateLevelFieldContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/DateLevelFieldContainer.tsx @@ -7,6 +7,7 @@ import { useDrag } from 'react-dnd'; import styled from 'styled-components/macro'; import { FONT_SIZE_TITLE, INFO } from 'styles/StyleConstants'; import { dateLevelFieldsProps } from '../../../../slice/types'; +import { handleDateLevelsName } from '../../utils'; function DateLevelFieldContainer({ onClearCheckedList, @@ -43,7 +44,9 @@ function DateLevelFieldContainer({ {}

- {folderRole === ColumnRole.Hierarchy ? item?.name : item?.displayName} + {folderRole === ColumnRole.Hierarchy + ? handleDateLevelsName(item) + : item?.displayName}

diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/DateLevelAction/DateLevelMenuItems.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/DateLevelAction/DateLevelMenuItems.tsx index 265faabf..f73e56f6 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/DateLevelAction/DateLevelMenuItems.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/DateLevelAction/DateLevelMenuItems.tsx @@ -26,6 +26,7 @@ import { FieldTemplate } from 'app/pages/ChartWorkbenchPage/components/ChartOper import { ChartDataViewMeta } from 'app/types/ChartDataViewMeta'; import { getAllColumnInMeta } from 'app/utils/chartHelper'; import { updateBy } from 'app/utils/mutation'; +import { DATE_LEVEL_DELIMITER } from 'globalConstants'; import React, { memo, useCallback } from 'react'; import { DATE_LEVELS } from '../../../../../slice/constant'; interface DateLevelMenuItemsProps { @@ -68,7 +69,7 @@ const DateLevelMenuItems = memo( return onChange({ ...config, - colName: `${config.field}(${selectedConfig.colName})`, + colName: selectedConfig.colName, expression: selectedConfig.expression, [RUNTIME_DATE_LEVEL_KEY]: null, }); @@ -125,7 +126,6 @@ const DateLevelMenuItems = memo( const expression = `${item.expression}(${FieldTemplate( row?.path, )})`; - return ( handleChangeFn({ category: ChartDataViewFieldCategory.DateLevelComputedField, - colName: item.name, + colName: row?.name + DATE_LEVEL_DELIMITER + item.expression, expression, }) } diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/utils.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/utils.ts index a3c287e0..97607a90 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/utils.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/utils.ts @@ -22,6 +22,8 @@ import { ColumnRole } from 'app/pages/MainPage/pages/ViewPage/slice/types'; import { ChartDataSectionField } from 'app/types/ChartConfig'; import { ChartDataViewMeta } from 'app/types/ChartDataViewMeta'; import { updateBy } from 'app/utils/mutation'; +import { DATE_LEVEL_DELIMITER } from 'globalConstants'; +import i18n from 'i18next'; import { CloneValueDeep } from 'utils/object'; import { DATE_LEVELS } from '../../slice/constant'; @@ -103,7 +105,7 @@ export const buildDateLevelFields = (args: { availableSourceFunctions.includes(item.expression) ) { return { - name: v.name + `(${item.name})`, + name: v.name + DATE_LEVEL_DELIMITER + item.expression, field: v.name, type: item.type, category: item.category, @@ -217,3 +219,16 @@ export const findSameFieldInView = ( return false; }; + +export const handleDateLevelsName = (col: { + name: string; + category: string; +}): string => { + if (col.category === ChartDataViewFieldCategory.DateLevelComputedField) { + const prefix = 'viz.workbench.dataview.'; + const colList = col.name.split(DATE_LEVEL_DELIMITER); + return `${colList[0]}(${i18n.t(prefix + colList[1])})`; + } else { + return col.name; + } +}; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/slice/types.ts b/frontend/src/app/pages/ChartWorkbenchPage/slice/types.ts index 6170d817..caac5271 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/slice/types.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/slice/types.ts @@ -21,6 +21,7 @@ import ChartDataSetDTO from 'app/types/ChartDataSet'; import ChartDataView from 'app/types/ChartDataView'; import { ChartDataViewMeta } from 'app/types/ChartDataViewMeta'; import { ChartDTO } from 'app/types/ChartDTO'; +import { ChartDataViewFieldCategory } from 'app/constants'; export type ChartConfigPayloadType = { init?: ChartConfig; diff --git a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/asyncActions.ts b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/asyncActions.ts index 0d8841a1..599f9284 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/asyncActions.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/asyncActions.ts @@ -16,6 +16,7 @@ * limitations under the License. */ import { DownloadFileType } from 'app/constants'; +import migrateWidgetChartConfig from 'app/migration/BoardConfig/migrateWidgetChartConfig'; import { migrateWidgets } from 'app/migration/BoardConfig/migrateWidgets'; import { FilterSearchParamsWithMatch } from 'app/pages/MainPage/pages/VizPage/slice/types'; import { mainActions } from 'app/pages/MainPage/slice'; @@ -64,10 +65,10 @@ export const handleServerBoardAction = datacharts, serverViews, ); - const migratedWidgets = migrateWidgets( - serverWidgets, - dashboard.config.type, + const migratedWidgets = migrateWidgetChartConfig( + migrateWidgets(serverWidgets, dashboard.config.type), ); + const { widgetMap, wrappedDataCharts, controllerWidgets } = getWidgetMap( migratedWidgets, dataCharts, diff --git a/frontend/src/app/pages/DashBoardPage/utils/widget.ts b/frontend/src/app/pages/DashBoardPage/utils/widget.ts index 9f64bf2f..d87072ee 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/widget.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/widget.ts @@ -60,7 +60,6 @@ import { } from '../pages/Board/slice/types'; import { StrControlTypes } from '../pages/BoardEditor/components/ControllerWidgetPanel/constants'; import { Widget, WidgetMapping } from '../types/widgetTypes'; - export const VALUE_SPLITTER = '###'; // export const createInitWidgetConfig = (opt: { diff --git a/frontend/src/app/utils/__tests__/chartDtoHelper.test.ts b/frontend/src/app/utils/__tests__/chartDtoHelper.test.ts index 52681d06..daeb4986 100644 --- a/frontend/src/app/utils/__tests__/chartDtoHelper.test.ts +++ b/frontend/src/app/utils/__tests__/chartDtoHelper.test.ts @@ -16,7 +16,7 @@ * limitations under the License. */ -import { APP_VERSION_BETA_4 } from 'app/migration/constants'; +import { APP_VERSION_BETA_4, APP_VERSION_RC_2 } from 'app/migration/constants'; import { buildUpdateChartRequest, convertToChartConfigDTO, @@ -34,7 +34,7 @@ describe('chartDtoHelper Test', () => { }; const dto = convertToChartDto(data); expect(dto).toEqual({ - config: { id: 1, computedFields: [], version: '1.0.0-RC.0' }, + config: { id: 1, computedFields: [], version: APP_VERSION_RC_2 }, view: { meta: [ { @@ -100,7 +100,7 @@ describe('chartDtoHelper Test', () => { type: 'STRING', }, ], - version: '1.0.0-RC.0', + version: APP_VERSION_RC_2, }, view: { meta: [ diff --git a/frontend/src/app/utils/chartHelper.ts b/frontend/src/app/utils/chartHelper.ts index 12443c91..5e4ab458 100644 --- a/frontend/src/app/utils/chartHelper.ts +++ b/frontend/src/app/utils/chartHelper.ts @@ -62,7 +62,11 @@ import ChartMetadata from 'app/types/ChartMetadata'; import { updateBy } from 'app/utils/mutation'; import { ECharts } from 'echarts'; import { ECBasicOption } from 'echarts/types/dist/shared'; -import { NumberUnitKey, NumericUnitDescriptions } from 'globalConstants'; +import { + DATE_LEVEL_DELIMITER, + NumberUnitKey, + NumericUnitDescriptions, +} from 'globalConstants'; import moment from 'moment'; import { Debugger } from 'utils/debugger'; import { @@ -1835,7 +1839,7 @@ export function createDateLevelComputedFieldForConfigComputedFields( DATE_LEVELS.forEach(v => { allDateLevelComputedFields.push({ category: ChartDataViewFieldCategory.DateLevelComputedField, - name: field.name + `(${v.name})`, + name: field.name + DATE_LEVEL_DELIMITER + v.expression, type: field.type, expression: `${v.expression}(${FieldTemplate(field.path)})`, }); diff --git a/frontend/src/app/utils/internalChartHelper.ts b/frontend/src/app/utils/internalChartHelper.ts index b1b5b9a7..7c194acb 100644 --- a/frontend/src/app/utils/internalChartHelper.ts +++ b/frontend/src/app/utils/internalChartHelper.ts @@ -34,6 +34,7 @@ import { DataViewFieldType, } from 'app/constants'; import { ChartDrillOption } from 'app/models/ChartDrillOption'; +import { handleDateLevelsName } from 'app/pages/ChartWorkbenchPage/components/ChartOperationPanel/utils'; import { VariableTypes } from 'app/pages/MainPage/pages/VariablePage/constants'; import { Variable } from 'app/pages/MainPage/pages/VariablePage/slice/types'; import { @@ -342,6 +343,9 @@ export function getColumnRenderOriginName(c?: ChartDataSectionField) { if (c.aggregate) { return `${c.aggregate}(${c.colName})`; } + if (c.category === ChartDataViewFieldCategory.DateLevelComputedField) { + return handleDateLevelsName({ ...c, name: c.colName }); + } return c.colName; } diff --git a/frontend/src/globalConstants.ts b/frontend/src/globalConstants.ts index 511b60bb..bceba21e 100644 --- a/frontend/src/globalConstants.ts +++ b/frontend/src/globalConstants.ts @@ -26,6 +26,7 @@ export const RUNTIME_FILTER_KEY = Symbol('@filters@'); export const BOARD_COPY_CHART_SUFFIX = '_copy'; export const BOARD_SELF_CHART_PREFIX = 'widget_'; export const TABLE_DATA_INDEX = '@datartTableIndex@'; +export const DATE_LEVEL_DELIMITER = '@date_level_delimiter@'; export enum StorageKeys { AuthorizationToken = 'AUTHORIZATION_TOKEN', -- Gitee From a4f0f0df4b23c5857374b5c4525e8f3598bd4f0b Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Fri, 12 Aug 2022 11:04:42 +0800 Subject: [PATCH 005/103] fix: add migrateWidgetChartConfig to DashboardEditor --- .../app/components/ChartDrill/ChartDrillContextMenu.tsx | 7 ++++--- .../DateLevelAction/DateLevelMenuItems.tsx | 6 +++--- .../pages/DashBoardPage/pages/Board/slice/asyncActions.ts | 5 ++--- .../pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts | 2 ++ .../pages/SharePage/Chart/ChartPreviewBoardForShare.tsx | 5 ++++- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/frontend/src/app/components/ChartDrill/ChartDrillContextMenu.tsx b/frontend/src/app/components/ChartDrill/ChartDrillContextMenu.tsx index 8f11af52..2731bc81 100644 --- a/frontend/src/app/components/ChartDrill/ChartDrillContextMenu.tsx +++ b/frontend/src/app/components/ChartDrill/ChartDrillContextMenu.tsx @@ -215,18 +215,19 @@ const ChartDrillContextMenu: FC<{ ].includes(f.category), ) ?.map((v, i) => { + const config = v[RUNTIME_DATE_LEVEL_KEY] || v; return ( diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/DateLevelAction/DateLevelMenuItems.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/DateLevelAction/DateLevelMenuItems.tsx index f73e56f6..bf1ce018 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/DateLevelAction/DateLevelMenuItems.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/DateLevelAction/DateLevelMenuItems.tsx @@ -87,7 +87,7 @@ const DateLevelMenuItems = memo( draft.field = config.colName; draft.category = ChartDataViewFieldCategory.DateLevelComputedField; - draft.colName = `${draft.colName}(${selectedConfig.colName})`; + draft.colName = selectedConfig.colName; draft[RUNTIME_DATE_LEVEL_KEY] = null; }), ); @@ -119,7 +119,6 @@ const DateLevelMenuItems = memo( config.category === ChartDataViewFieldCategory.Field ? config.colName : config.field; - const row = getAllColumnInMeta(metas)?.find( v => v.name === configColName, ); @@ -134,7 +133,8 @@ const DateLevelMenuItems = memo( onClick={() => handleChangeFn({ category: ChartDataViewFieldCategory.DateLevelComputedField, - colName: row?.name + DATE_LEVEL_DELIMITER + item.expression, + colName: + configColName + DATE_LEVEL_DELIMITER + item.expression, expression, }) } diff --git a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/asyncActions.ts b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/asyncActions.ts index 599f9284..5bfd1b8c 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/asyncActions.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/asyncActions.ts @@ -65,9 +65,8 @@ export const handleServerBoardAction = datacharts, serverViews, ); - const migratedWidgets = migrateWidgetChartConfig( - migrateWidgets(serverWidgets, dashboard.config.type), - ); + let migratedWidgets = migrateWidgets(serverWidgets, dashboard.config.type); + migratedWidgets = migrateWidgetChartConfig(migratedWidgets); const { widgetMap, wrappedDataCharts, controllerWidgets } = getWidgetMap( migratedWidgets, diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts index ca9a0fe3..4e8df2fc 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts @@ -1,4 +1,5 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; +import migrateWidgetChartConfig from 'app/migration/BoardConfig/migrateWidgetChartConfig'; import migrateWidgetConfig from 'app/migration/BoardConfig/migrateWidgetConfig'; import { migrateWidgets } from 'app/migration/BoardConfig/migrateWidgets'; import { ChartDataRequestBuilder } from 'app/models/ChartDataRequestBuilder'; @@ -116,6 +117,7 @@ export const fetchEditBoardDetail = createAsyncThunk< ); let migratedWidgets = migrateWidgets(serverWidgets, boardType); migratedWidgets = migrateWidgetConfig(migratedWidgets); + migratedWidgets = migrateWidgetChartConfig(migratedWidgets); const { widgetMap, wrappedDataCharts } = getWidgetMap( migratedWidgets, //todo dataCharts, diff --git a/frontend/src/app/pages/SharePage/Chart/ChartPreviewBoardForShare.tsx b/frontend/src/app/pages/SharePage/Chart/ChartPreviewBoardForShare.tsx index dc98a534..fb287f6f 100644 --- a/frontend/src/app/pages/SharePage/Chart/ChartPreviewBoardForShare.tsx +++ b/frontend/src/app/pages/SharePage/Chart/ChartPreviewBoardForShare.tsx @@ -378,7 +378,10 @@ const ChartPreviewBoardForShare: FC<{ }} >
- + Date: Fri, 12 Aug 2022 16:48:44 +0800 Subject: [PATCH 006/103] fix: oracle adapter bugfix --- .../data/provider/jdbc/adapters/JdbcDataProviderAdapter.java | 2 +- .../data/provider/jdbc/adapters/OracleDataProviderAdapter.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/adapters/JdbcDataProviderAdapter.java b/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/adapters/JdbcDataProviderAdapter.java index 133363b4..b3f6061e 100644 --- a/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/adapters/JdbcDataProviderAdapter.java +++ b/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/adapters/JdbcDataProviderAdapter.java @@ -173,7 +173,7 @@ public class JdbcDataProviderAdapter implements Closeable { try (ResultSet columns = metadata.getColumns(database, null, table, null)) { while (columns.next()) { Column column = readTableColumn(columns); - column.setForeignKeys(importedKeys.get(column.getName())); + column.setForeignKeys(importedKeys.get(column.columnKey())); columnSet.add(column); } } diff --git a/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/adapters/OracleDataProviderAdapter.java b/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/adapters/OracleDataProviderAdapter.java index 81c4dde4..eed05a28 100644 --- a/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/adapters/OracleDataProviderAdapter.java +++ b/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/adapters/OracleDataProviderAdapter.java @@ -53,7 +53,7 @@ public class OracleDataProviderAdapter extends JdbcDataProviderAdapter { Dataframe dataframe = new Dataframe(); List columns = getColumns(rs); int start = 1; - if ("V_R_N".equals(columns.get(0).getName())) { + if ("V_R_N".equals(columns.get(0).columnKey())) { start = 2; columns.remove(0); } -- Gitee From 9e29d1e8acf5d5817a1d89f65b668d79a62653f9 Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Fri, 12 Aug 2022 16:49:42 +0800 Subject: [PATCH 007/103] fix: return auth exception after user password changed --- .../datart/security/manager/shiro/ShiroSecurityManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/src/main/java/datart/security/manager/shiro/ShiroSecurityManager.java b/security/src/main/java/datart/security/manager/shiro/ShiroSecurityManager.java index 998751dd..1a2724e6 100644 --- a/security/src/main/java/datart/security/manager/shiro/ShiroSecurityManager.java +++ b/security/src/main/java/datart/security/manager/shiro/ShiroSecurityManager.java @@ -113,7 +113,7 @@ public class ShiroSecurityManager implements DatartSecurityManager { } if (jwtToken.getPwdHash() != user.getPassword().hashCode()) { - Exceptions.tr(BaseException.class, "login.fail.pwd.hash"); + Exceptions.tr(AuthException.class, "login.fail.pwd.hash"); } PasswordToken passwordToken = new PasswordToken(user.getUsername(), user.getPassword(), System.currentTimeMillis()); -- Gitee From 6896df8f826c712e5229a30713006a800c860c03 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Fri, 12 Aug 2022 16:52:21 +0800 Subject: [PATCH 008/103] fix: Add error message for testing data source connection --- .../SourcePage/SourceDetailPage/index.tsx | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/index.tsx b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/index.tsx index cd81ebe0..692f9ce2 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/index.tsx @@ -45,7 +45,7 @@ import { SPACE_TIMES, } from 'styles/StyleConstants'; import { request2 } from 'utils/request'; -import { uuidv4 } from 'utils/utils'; +import { errorHandle, uuidv4 } from 'utils/utils'; import { selectDataProviderConfigTemplateLoading, selectDataProviderListLoading, @@ -199,12 +199,16 @@ export function SourceDetailPage() { const { type, config } = form.getFieldsValue(); const { name } = dataProviders[type]; setTestLoading(true); - await request2({ - url: '/data-provider/test', - method: 'POST', - data: { name, type, properties: config }, - }); - message.success(t('testSuccess')); + try { + await request2({ + url: '/data-provider/test', + method: 'POST', + data: { name, type, properties: config }, + }); + message.success(t('testSuccess')); + } catch (error) { + errorHandle(error); + } setTestLoading(false); }, [form, dataProviders, t]); @@ -212,21 +216,25 @@ export function SourceDetailPage() { async (config, callback) => { const { name } = dataProviders[providerType]; setTestLoading(true); - const { data } = await request2({ - url: '/data-provider/test', - method: 'POST', - data: { - name, - type: providerType, - properties: - providerType === 'FILE' - ? { path: config.path, format: config.format } - : config, - sourceId: editingSource?.id, - }, - }); + try { + const { data } = await request2({ + url: '/data-provider/test', + method: 'POST', + data: { + name, + type: providerType, + properties: + providerType === 'FILE' + ? { path: config.path, format: config.format } + : config, + sourceId: editingSource?.id, + }, + }); + callback(data); + } catch (error) { + errorHandle(error); + } setTestLoading(false); - callback(data); }, [dataProviders, providerType, editingSource], ); -- Gitee From b399ecb1caa44ecce461d2c300cdfef65fc7fe75 Mon Sep 17 00:00:00 2001 From: xueqiang Date: Fri, 12 Aug 2022 18:00:14 +0800 Subject: [PATCH 009/103] =?UTF-8?q?fix(ArrayConfig.tsx):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8DFILE=E5=92=8CHTTP=E7=B1=BB=E5=9E=8B=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=BA=90=EF=BC=8C=E7=BC=96=E8=BE=91=E8=A1=A8=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E4=B8=94=E4=BF=AE=E6=94=B9=E9=85=8D=E7=BD=AE=E5=90=8E=EF=BC=8C?= =?UTF-8?q?=E4=BC=9A=E6=B7=BB=E5=8A=A0=E4=B8=80=E6=9D=A1=E8=84=8F=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E9=97=AE=E9=A2=98=E3=80=90issue:=20#1878=E3=80=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SourceDetailPage/ConfigComponent/ArrayConfig.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/ArrayConfig.tsx b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/ArrayConfig.tsx index 6cc85a19..153351f8 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/ArrayConfig.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/ArrayConfig.tsx @@ -141,9 +141,7 @@ export function ArrayConfig({ (formValues: SourceFormModel) => { const configRowKey = attr.key; if (value && configRowKey) { - const index = value.findIndex( - o => o[configRowKey] === formValues.config[configRowKey], - ); + const index = value.findIndex(o => o[configRowKey] === editingRowKey); if (index >= 0) { onChange && onChange([ @@ -159,7 +157,7 @@ export function ArrayConfig({ } setFormVisible(false); }, - [attr, value, onChange], + [attr.key, value, editingRowKey, onChange], ); const editConfig = useCallback( -- Gitee From 74095c169518c6658bab3b684ba163678c1d1f42 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Fri, 12 Aug 2022 18:05:50 +0800 Subject: [PATCH 010/103] test: add migrateChartConfig and migrateWidgetChartConfig test --- .../ChartConfig/migrateChartConfig.ts | 11 +- .../__tests__/migrateChartConfig.test.ts | 80 +++++++++++- .../migrateWidgetChartConfig.test.ts | 115 ++++++++++++++++++ 3 files changed, 197 insertions(+), 9 deletions(-) create mode 100644 frontend/src/app/migration/__tests__/migrateWidgetChartConfig.test.ts diff --git a/frontend/src/app/migration/ChartConfig/migrateChartConfig.ts b/frontend/src/app/migration/ChartConfig/migrateChartConfig.ts index 71835247..d0f7b2f4 100644 --- a/frontend/src/app/migration/ChartConfig/migrateChartConfig.ts +++ b/frontend/src/app/migration/ChartConfig/migrateChartConfig.ts @@ -91,7 +91,7 @@ export const RC2 = config => { return config; } catch (error) { - console.error('Migration config Errors | RC.0 | ', error); + console.error('Migration config Errors | RC.2 | ', error); return config; } }; @@ -102,14 +102,11 @@ const migrationChartConfig = (config: string): string => { } const chartConfig = JSON.parse(config); const event = new MigrationEvent(APP_VERSION_RC_0, RC0); - const dispatcher = new MigrationEventDispatcher(event); - const result = dispatcher.process(chartConfig); - const event2 = new MigrationEvent(APP_VERSION_RC_2, RC2); - const dispatcher2 = new MigrationEventDispatcher(event2); - const result2 = dispatcher2.process(result); + const dispatcher = new MigrationEventDispatcher(event, event2); + const result = dispatcher.process(chartConfig); - return JSON.stringify(result2); + return JSON.stringify(result); }; export default migrationChartConfig; diff --git a/frontend/src/app/migration/__tests__/migrateChartConfig.test.ts b/frontend/src/app/migration/__tests__/migrateChartConfig.test.ts index 69be6def..6687835b 100644 --- a/frontend/src/app/migration/__tests__/migrateChartConfig.test.ts +++ b/frontend/src/app/migration/__tests__/migrateChartConfig.test.ts @@ -15,8 +15,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import migrateChartConfig, { RC0 } from '../ChartConfig/migrateChartConfig'; -import { APP_VERSION_RC_0, APP_VERSION_RC_2 } from '../constants'; +import { ChartDataViewFieldCategory } from 'app/constants'; +import { DATE_LEVEL_DELIMITER } from 'globalConstants'; +import migrateChartConfig, { + RC0, + RC2, +} from '../ChartConfig/migrateChartConfig'; +import { APP_VERSION_RC_2 } from '../constants'; describe('test RC0 Function ', () => { test('should add name fields for chartConfig computedFields', () => { @@ -47,9 +52,29 @@ describe('test RC0 Function ', () => { expect(result).toMatchObject({}); }); + test('test chartConfig is null', () => { + const chartConfig = { + computedFields: '1111', + } as any; + const result = RC0(chartConfig as any); + + expect(result).toEqual(chartConfig); + }); + test('test RCO Try Catch function', () => { + const chartConfig = null as any; + const result = RC0(chartConfig as any); + + expect(result).toEqual(null); + }); }); describe('test migrateChartConfig ', () => { + test('test config is null', () => { + const chartConfig: any = null; + const result = migrateChartConfig(chartConfig); + expect(result).toEqual(null); + }); + test('should add name fields for chartConfig computedFields', () => { const chartConfig = JSON.stringify({ computedFields: [{ id: '1' }], @@ -85,3 +110,54 @@ describe('test migrateChartConfig ', () => { expect(result).toEqual(JSON.stringify({ version: APP_VERSION_RC_2 })); }); }); + +describe('test RC2 Function ', () => { + test('test if config if empty', () => { + const config = null; + const result = RC2(config); + expect(result).toEqual(config); + }); + + test('should return correct colName', () => { + const chartConfig = { + chartConfig: { + datas: [ + { + rows: [ + { + category: ChartDataViewFieldCategory.DateLevelComputedField, + colName: 'birthday(Year)', + expression: 'AGG_DATE_YEAR([birthday])', + field: 'birthday', + }, + ], + }, + ], + }, + computedFields: [ + { + category: ChartDataViewFieldCategory.DateLevelComputedField, + expression: 'AGG_DATE_YEAR([birthday])', + name: 'birthday(Year)', + type: 'DATE', + }, + ], + } as any; + const result = RC2(chartConfig as any); + console.log(JSON.stringify(result), 'result'); + expect(result.chartConfig.datas[0].rows[0].colName).toEqual( + 'birthday' + DATE_LEVEL_DELIMITER + 'AGG_DATE_YEAR', + ); + expect(result.computedFields[0].name).toEqual( + 'birthday' + DATE_LEVEL_DELIMITER + 'AGG_DATE_YEAR', + ); + }); + + test('test try catch function', () => { + const chartConfig = { + chartConfig: {}, + } as any; + const result = RC2(chartConfig as any); + expect(result).toEqual(chartConfig); + }); +}); diff --git a/frontend/src/app/migration/__tests__/migrateWidgetChartConfig.test.ts b/frontend/src/app/migration/__tests__/migrateWidgetChartConfig.test.ts new file mode 100644 index 00000000..b4feb0c5 --- /dev/null +++ b/frontend/src/app/migration/__tests__/migrateWidgetChartConfig.test.ts @@ -0,0 +1,115 @@ +/** + * Datart + * + * Copyright 2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChartDataViewFieldCategory } from 'app/constants'; +import { DATE_LEVEL_DELIMITER } from 'globalConstants'; +import migrateWidgetChartConfig from '../BoardConfig/migrateWidgetChartConfig'; + +describe('migrate Widget ChartConfig', () => { + test('should return empty array if widget is empty ', () => { + const widget = []; + + const result = migrateWidgetChartConfig(widget); + expect(result).toEqual([]); + }); + test('should return null if widget is null ', () => { + const widget: any = null; + + const result = migrateWidgetChartConfig(widget); + expect(result).toEqual([]); + }); + + test('should No processing of widgets', () => { + const widget: any = [ + { + config: { + content: { + dataChart: null, + }, + }, + }, + ] as any; + + const result = migrateWidgetChartConfig(widget); + expect(result).toEqual(widget); + }); + + test('should return array if widget is not empty ', () => { + // widget?.config?.content?.dataChart?.config + const widget = [ + { + config: { + content: { + dataChart: { + config: { + chartConfig: { + datas: [ + { + rows: [ + { + category: + ChartDataViewFieldCategory.DateLevelComputedField, + colName: 'birthday(Year)', + expression: 'AGG_DATE_YEAR([birthday])', + field: 'birthday', + }, + ], + }, + ], + }, + computedFields: [ + { + category: ChartDataViewFieldCategory.DateLevelComputedField, + expression: 'AGG_DATE_YEAR([birthday])', + name: 'birthday(Year)', + type: 'DATE', + }, + ], + }, + }, + }, + }, + }, + ] as any; + + const result = migrateWidgetChartConfig(widget); + expect(result[0].config.content.dataChart.config.chartConfig.datas).toEqual( + [ + { + rows: [ + { + category: ChartDataViewFieldCategory.DateLevelComputedField, + colName: 'birthday' + DATE_LEVEL_DELIMITER + 'AGG_DATE_YEAR', + expression: 'AGG_DATE_YEAR([birthday])', + field: 'birthday', + }, + ], + }, + ], + ); + + expect(result[0].config.content.dataChart.config.computedFields).toEqual([ + { + category: ChartDataViewFieldCategory.DateLevelComputedField, + expression: 'AGG_DATE_YEAR([birthday])', + name: 'birthday' + DATE_LEVEL_DELIMITER + 'AGG_DATE_YEAR', + type: 'DATE', + }, + ]); + }); +}); -- Gitee From 95a6c423dd9eefeb0490862f6fdad9c91df4cdc8 Mon Sep 17 00:00:00 2001 From: zhu-mingye <934230207@qq.com> Date: Mon, 15 Aug 2022 12:59:52 +0800 Subject: [PATCH 011/103] =?UTF-8?q?fix:=E7=B3=BB=E7=BB=9F=E5=8F=98?= =?UTF-8?q?=E9=87=8FUSERNAME=E5=92=8CNAME=E5=8F=96=E5=80=BC=E4=B8=80?= =?UTF-8?q?=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datart/server/service/impl/DataProviderServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/datart/server/service/impl/DataProviderServiceImpl.java b/server/src/main/java/datart/server/service/impl/DataProviderServiceImpl.java index 782952d1..5a26cd0c 100644 --- a/server/src/main/java/datart/server/service/impl/DataProviderServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/DataProviderServiceImpl.java @@ -352,7 +352,7 @@ public class DataProviderServiceImpl extends BaseService implements DataProvider variables.add(new ScriptVariable(VARIABLE_NAME, VariableTypeEnum.PERMISSION, ValueType.STRING, - Sets.newHashSet(getCurrentUser().getUsername()), + Sets.newHashSet(getCurrentUser().getName()), false)); variables.add(new ScriptVariable(VARIABLE_EMAIL, VariableTypeEnum.PERMISSION, -- Gitee From aa931bf563c97cc6933860ead6d6b6a6a9b4eb5b Mon Sep 17 00:00:00 2001 From: zhu-mingye <934230207@qq.com> Date: Mon, 15 Aug 2022 13:13:00 +0800 Subject: [PATCH 012/103] fix:push error --- frontend/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index e036d228..a3846d3b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,8 +27,8 @@ "eslint": "eslint --ext js,ts,tsx", "lint": "npm run eslint src", "lint:fix": "npm run eslint --fix src", - "lint:css": "npx stylelint 'src/**/*.css'", - "lint:style": "npx stylelint 'src/**/*.{js,ts,jsx,tsx}'", + "lint:css": "npx stylelint \"src/**/*.css\"", + "lint:style": "npx stylelint \"src/**/*.{js,ts,jsx,tsx}\"", "prettify": "prettier --write src", "prepare": "cd .. && husky install frontend/.husky", "eject": "react-scripts eject", -- Gitee From 1038cd4b36fd66c4e8e2af9c08ff3842987fce57 Mon Sep 17 00:00:00 2001 From: "kaixuan.chen" Date: Mon, 15 Aug 2022 13:59:16 +0800 Subject: [PATCH 013/103] feat: fix parse wrong column type when parse sql for PostgreSQL --- .../data/provider/jdbc/DataTypeUtils.java | 24 ++++++++++++++++++- .../adapters/JdbcDataProviderAdapter.java | 4 ++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/data-providers/data-provider-base/src/main/java/datart/data/provider/jdbc/DataTypeUtils.java b/data-providers/data-provider-base/src/main/java/datart/data/provider/jdbc/DataTypeUtils.java index 53829091..28e606bc 100644 --- a/data-providers/data-provider-base/src/main/java/datart/data/provider/jdbc/DataTypeUtils.java +++ b/data-providers/data-provider-base/src/main/java/datart/data/provider/jdbc/DataTypeUtils.java @@ -17,8 +17,8 @@ */ package datart.data.provider.jdbc; -import datart.core.base.consts.ValueType; import datart.core.base.consts.JavaType; +import datart.core.base.consts.ValueType; import datart.data.provider.calcite.custom.CustomSqlTypeName; import org.apache.calcite.sql.type.SqlTypeFamily; import org.apache.calcite.sql.type.SqlTypeName; @@ -50,6 +50,28 @@ public class DataTypeUtils { } } + + public static ValueType jdbcType2DataType(int jdbcType) { + SqlTypeName sqlTypeName = SqlTypeName.getNameForJdbcType(jdbcType); + SqlTypeFamily family; + if (sqlTypeName == null) { + family = SqlTypeFamily.getFamilyForJdbcType(jdbcType); + } else { + family = sqlTypeName.getFamily(); + } + switch (family) { + case NUMERIC: + return ValueType.NUMERIC; + case DATE: + case TIME: + case TIMESTAMP: + case DATETIME: + return ValueType.DATE; + default: + return ValueType.STRING; + } + } + public static SqlTypeName javaType2SqlType(String javaTypeSimpleName) { JavaType javaType = JavaType.valueOf(javaTypeSimpleName.toUpperCase()); switch (javaType) { diff --git a/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/adapters/JdbcDataProviderAdapter.java b/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/adapters/JdbcDataProviderAdapter.java index 133363b4..d5574a0f 100644 --- a/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/adapters/JdbcDataProviderAdapter.java +++ b/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/adapters/JdbcDataProviderAdapter.java @@ -394,9 +394,9 @@ public class JdbcDataProviderAdapter implements Closeable { protected List getColumns(ResultSet rs) throws SQLException { ArrayList columns = new ArrayList<>(); for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) { - String columnTypeName = rs.getMetaData().getColumnTypeName(i); + int columnType = rs.getMetaData().getColumnType(i); String columnName = rs.getMetaData().getColumnLabel(i); - ValueType valueType = DataTypeUtils.sqlType2DataType(columnTypeName); + ValueType valueType = DataTypeUtils.jdbcType2DataType(columnType); columns.add(Column.of(valueType, columnName)); } return columns; -- Gitee From 0b73a6e808a4de4e2fed9884e28118e9aae94a18 Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Wed, 17 Aug 2022 13:31:34 +0800 Subject: [PATCH 014/103] fix: check child node before delete schedule instance --- .../java/datart/core/mappers/ext/ScheduleMapperExt.java | 5 +++++ .../main/java/datart/server/service/BaseCRUDService.java | 2 +- .../datart/server/service/impl/DatachartServiceImpl.java | 4 ++-- .../datart/server/service/impl/ScheduleServiceImpl.java | 5 +++++ .../java/datart/server/service/impl/ViewServiceImpl.java | 8 ++++---- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/datart/core/mappers/ext/ScheduleMapperExt.java b/core/src/main/java/datart/core/mappers/ext/ScheduleMapperExt.java index 9b0a224d..460c7718 100644 --- a/core/src/main/java/datart/core/mappers/ext/ScheduleMapperExt.java +++ b/core/src/main/java/datart/core/mappers/ext/ScheduleMapperExt.java @@ -20,4 +20,9 @@ public interface ScheduleMapperExt extends ScheduleMapper { }) List selectArchived(String orgId); + @Select({ + "SELECT COUNT(*) FROM `schedule` WHERE parent_id = #{scheduleId} AND `status`!=0" + }) + int checkReference(String scheduleId); + } diff --git a/server/src/main/java/datart/server/service/BaseCRUDService.java b/server/src/main/java/datart/server/service/BaseCRUDService.java index b5ed835c..253b10de 100644 --- a/server/src/main/java/datart/server/service/BaseCRUDService.java +++ b/server/src/main/java/datart/server/service/BaseCRUDService.java @@ -228,7 +228,7 @@ public interface BaseCRUDService { return null; } - default boolean safeDelete(String viewId) { + default boolean safeDelete(String id) { return true; } diff --git a/server/src/main/java/datart/server/service/impl/DatachartServiceImpl.java b/server/src/main/java/datart/server/service/impl/DatachartServiceImpl.java index 258e32a4..f11530ab 100644 --- a/server/src/main/java/datart/server/service/impl/DatachartServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/DatachartServiceImpl.java @@ -303,8 +303,8 @@ public class DatachartServiceImpl extends BaseService implements DatachartServic } @Override - public boolean safeDelete(String datachartId) { - return datachartMapper.countWidgetRels(datachartId) == 0; + public boolean safeDelete(String id) { + return datachartMapper.countWidgetRels(id) == 0; } @Override diff --git a/server/src/main/java/datart/server/service/impl/ScheduleServiceImpl.java b/server/src/main/java/datart/server/service/impl/ScheduleServiceImpl.java index 1c449faa..9b56173c 100644 --- a/server/src/main/java/datart/server/service/impl/ScheduleServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/ScheduleServiceImpl.java @@ -231,6 +231,11 @@ public class ScheduleServiceImpl extends BaseService implements ScheduleService return true; } + @Override + public boolean safeDelete(String id) { + return scheduleMapper.checkReference(id) == 0; + } + @Override public boolean stop(String scheduleId) throws SchedulerException { Schedule schedule = retrieve(scheduleId); diff --git a/server/src/main/java/datart/server/service/impl/ViewServiceImpl.java b/server/src/main/java/datart/server/service/impl/ViewServiceImpl.java index 28cc7586..07f6473e 100644 --- a/server/src/main/java/datart/server/service/impl/ViewServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/ViewServiceImpl.java @@ -400,17 +400,17 @@ public class ViewServiceImpl extends BaseService implements ViewService { } } - public boolean safeDelete(String viewId) { + public boolean safeDelete(String id) { // check children - if (viewMapper.checkReference(viewId) != 0) { + if (viewMapper.checkReference(id) != 0) { return false; } // check charts reference Datachart datachart = new Datachart(); - datachart.setViewId(viewId); + datachart.setViewId(id); //check widget reference RelWidgetElement relWidgetElement = new RelWidgetElement(); - relWidgetElement.setRelId(viewId); + relWidgetElement.setRelId(id); return viewMapper.checkUnique(datachart) && viewMapper.checkUnique(relWidgetElement); } -- Gitee From 762e86d0aae4ec7b6ff1fe3ef0200c724eda8745 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Wed, 17 Aug 2022 14:08:38 +0800 Subject: [PATCH 015/103] fix: add container to wrap title and drag handle, issue #1891 --- .../components/LayerPanel/LayerTreeItem.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LayerPanel/LayerTreeItem.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LayerPanel/LayerTreeItem.tsx index fd16f93e..f3ce7694 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LayerPanel/LayerTreeItem.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LayerPanel/LayerTreeItem.tsx @@ -65,8 +65,10 @@ export const TreeItem: FC<{ node: LayerNode }> = memo(({ node }) => { return ( -

{String(title) || 'untitled-widget'}

- + +

{String(title) || 'untitled-widget'}

+ +
Date: Wed, 17 Aug 2022 14:21:54 +0800 Subject: [PATCH 016/103] fix: schedule create api bugfix --- .../java/datart/server/base/params/ScheduleCreateParam.java | 2 +- .../java/datart/server/controller/ScheduleController.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/datart/server/base/params/ScheduleCreateParam.java b/server/src/main/java/datart/server/base/params/ScheduleCreateParam.java index 71a70e33..43c304cb 100644 --- a/server/src/main/java/datart/server/base/params/ScheduleCreateParam.java +++ b/server/src/main/java/datart/server/base/params/ScheduleCreateParam.java @@ -46,6 +46,6 @@ public class ScheduleCreateParam extends BaseCreateParam { private Boolean isFolder; - private Integer index; + private Double index; } diff --git a/server/src/main/java/datart/server/controller/ScheduleController.java b/server/src/main/java/datart/server/controller/ScheduleController.java index b203b287..93e79186 100644 --- a/server/src/main/java/datart/server/controller/ScheduleController.java +++ b/server/src/main/java/datart/server/controller/ScheduleController.java @@ -86,7 +86,7 @@ public class ScheduleController extends BaseController { @ApiOperation(value = "update a schedule base info") @PutMapping(value = "/{scheduleId}/base") public ResponseData updateScheduleBaseInfo(@PathVariable String scheduleId, - @Validated @RequestBody ScheduleBaseUpdateParam updateParam) { + @Validated @RequestBody ScheduleBaseUpdateParam updateParam) { checkBlank(scheduleId, "scheduleId"); return ResponseData.success(scheduleService.updateBase(updateParam)); } @@ -94,7 +94,7 @@ public class ScheduleController extends BaseController { @ApiOperation(value = "delete a schedule") @DeleteMapping(value = "/{scheduleId}") public ResponseData deleteSchedule(@PathVariable String scheduleId, @RequestParam boolean archive) { - return ResponseData.success(scheduleService.delete(scheduleId, archive)); + return ResponseData.success(scheduleService.delete(scheduleId, archive, true)); } @ApiOperation(value = "execute a schedule") -- Gitee From 4ab1f5bc9319b53b33467131bece8db090a99f3d Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Wed, 17 Aug 2022 14:22:38 +0800 Subject: [PATCH 017/103] fix: source api bugfix --- .../main/java/datart/core/mappers/ext/SourceMapperExt.java | 5 +++++ .../main/java/datart/server/controller/SourceController.java | 2 +- .../java/datart/server/service/impl/SourceServiceImpl.java | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/datart/core/mappers/ext/SourceMapperExt.java b/core/src/main/java/datart/core/mappers/ext/SourceMapperExt.java index 0960360e..5086d648 100644 --- a/core/src/main/java/datart/core/mappers/ext/SourceMapperExt.java +++ b/core/src/main/java/datart/core/mappers/ext/SourceMapperExt.java @@ -38,4 +38,9 @@ public interface SourceMapperExt extends SourceMapper { }) Organization getOrgById(@Param("sourceId") String sourceId); + @Select({ + "SELECT COUNT(*) FROM `source` WHERE parent_id = #{sourceId} AND `status`!=0" + }) + int checkReference(String sourceId); + } diff --git a/server/src/main/java/datart/server/controller/SourceController.java b/server/src/main/java/datart/server/controller/SourceController.java index 2966cfbb..6cb45285 100644 --- a/server/src/main/java/datart/server/controller/SourceController.java +++ b/server/src/main/java/datart/server/controller/SourceController.java @@ -87,7 +87,7 @@ public class SourceController extends BaseController { public ResponseData deleteSource(@PathVariable String sourceId, @RequestParam boolean archive) { checkBlank(sourceId, "sourceId"); - return ResponseData.success(sourceService.delete(sourceId, archive)); + return ResponseData.success(sourceService.delete(sourceId, archive, true)); } @ApiOperation(value = "list archived source") diff --git a/server/src/main/java/datart/server/service/impl/SourceServiceImpl.java b/server/src/main/java/datart/server/service/impl/SourceServiceImpl.java index 51d4d067..834c8666 100644 --- a/server/src/main/java/datart/server/service/impl/SourceServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/SourceServiceImpl.java @@ -425,6 +425,11 @@ public class SourceServiceImpl extends BaseService implements SourceService { sourceSchemasMapper.deleteBySource(source.getId()); } + @Override + public boolean safeDelete(String id) { + return sourceMapper.checkReference(id) == 0; + } + @Override public void deleteStaticFiles(Source source) { fileService.deleteFiles(FileOwner.DATA_SOURCE, source.getId()); -- Gitee From 6314819a2342925244a71079a0f6d0e41d642195 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Wed, 17 Aug 2022 19:25:51 +0800 Subject: [PATCH 018/103] feat: add format for date field in model --- .../ViewConfig/migrationViewModelConfig.ts | 53 ++- .../src/app/pages/MainPage/Navbar/Profile.tsx | 41 ++- .../app/pages/MainPage/Navbar/constants.ts | 337 ++++++++++++++++++ .../DataModelTree/DataModelNode.tsx | 39 +- .../DataModelTree/DataModelTree.tsx | 24 +- .../MainPage/pages/ViewPage/constants.ts | 7 + .../MainPage/pages/ViewPage/slice/types.ts | 2 +- frontend/src/app/slice/types.ts | 1 + frontend/src/globalConstants.ts | 1 + frontend/src/locales/en/translation.json | 3 +- frontend/src/locales/zh/translation.json | 3 +- 11 files changed, 480 insertions(+), 31 deletions(-) create mode 100644 frontend/src/app/pages/MainPage/Navbar/constants.ts diff --git a/frontend/src/app/migration/ViewConfig/migrationViewModelConfig.ts b/frontend/src/app/migration/ViewConfig/migrationViewModelConfig.ts index fd88cbd6..324a7ae5 100644 --- a/frontend/src/app/migration/ViewConfig/migrationViewModelConfig.ts +++ b/frontend/src/app/migration/ViewConfig/migrationViewModelConfig.ts @@ -16,12 +16,17 @@ * limitations under the License. */ +import { DateFormat } from 'app/pages/MainPage/pages/ViewPage/constants'; import { addPathToHierarchyStructureAndChangeName } from 'app/pages/MainPage/pages/ViewPage/utils'; +import { updateBy } from 'app/utils/mutation'; import { CloneValueDeep } from 'utils/object'; -import { APP_VERSION_BETA_2, APP_VERSION_BETA_4 } from '../constants'; +import { + APP_VERSION_BETA_2, + APP_VERSION_BETA_4, + APP_VERSION_RC_2, +} from '../constants'; import MigrationEvent from '../MigrationEvent'; import MigrationEventDispatcher from '../MigrationEventDispatcher'; - /** * Migrate @see View config in beta.2 version * Changes: @@ -31,7 +36,7 @@ import MigrationEventDispatcher from '../MigrationEventDispatcher'; * @param {object} [model] * @return {*} {(object | undefined)} */ -const beta2 = (model?: object): object | undefined => { +const beta2 = model => { const clonedModel = CloneValueDeep(model) || {}; if (model) { Object.keys(clonedModel).forEach(name => { @@ -45,8 +50,8 @@ const beta2 = (model?: object): object | undefined => { return model; }; -const beta4 = obj => { - const { viewType, result } = obj; +const beta4 = view => { + const { viewType, result } = view; try { result.hierarchy = addPathToHierarchyStructureAndChangeName( result.hierarchy, @@ -59,6 +64,25 @@ const beta4 = obj => { } }; +const RC2 = model => { + model.hierarchy = updateBy(model.hierarchy, draft => { + Object.values(draft).forEach((field: any) => { + if (field.children) { + field.children.forEach(child => { + if (!child.dateFormat && child.type === 'DATE') { + child.dateFormat = DateFormat.DateTime; + } + }); + } else { + if (!field.dateFormat && field.type === 'DATE') { + field.dateFormat = DateFormat.DateTime; + } + } + }); + }); + return model; +}; + /** * main entry point of migration * @@ -71,15 +95,24 @@ const beginViewModelMigration = (model: string, viewType): string => { } const modelObj = JSON.parse(model); const event2 = new MigrationEvent(APP_VERSION_BETA_2, beta2); - const dispatcher = new MigrationEventDispatcher(event2); - const result = dispatcher.process(modelObj); - const event4 = new MigrationEvent(APP_VERSION_BETA_4, beta4); + const eventRC2 = new MigrationEvent(APP_VERSION_RC_2, RC2); + + const dispatcher2 = new MigrationEventDispatcher(event2); + const result2 = dispatcher2.process(modelObj); + const dispatcher4 = new MigrationEventDispatcher(event4); - const result4 = dispatcher4.process({ result, viewType }); + const result4 = dispatcher4.process({ + result: result2, + viewType, + }); + + const dispatcherRC2 = new MigrationEventDispatcher(eventRC2); + + const resultRC2 = dispatcherRC2.process(result4); - return JSON.stringify(result4); + return JSON.stringify(resultRC2); }; export default beginViewModelMigration; diff --git a/frontend/src/app/pages/MainPage/Navbar/Profile.tsx b/frontend/src/app/pages/MainPage/Navbar/Profile.tsx index a1b20de8..b6eec4c8 100644 --- a/frontend/src/app/pages/MainPage/Navbar/Profile.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/Profile.tsx @@ -16,7 +16,16 @@ * limitations under the License. */ -import { Button, Form, Input, message, Modal, ModalProps, Upload } from 'antd'; +import { + Button, + Form, + Input, + message, + Modal, + ModalProps, + Select, + Upload, +} from 'antd'; import { Avatar } from 'app/components'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { @@ -24,13 +33,19 @@ import { selectSaveProfileLoading, } from 'app/slice/selectors'; import { saveProfile, updateUser } from 'app/slice/thunks'; -import { BASE_API_URL, BASE_RESOURCE_URL } from 'globalConstants'; +import { + BASE_API_URL, + BASE_RESOURCE_URL, + TIME_ZONE_DELIMITER, +} from 'globalConstants'; import React, { useCallback, useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components/macro'; import { SPACE_LG, SPACE_MD, SPACE_UNIT } from 'styles/StyleConstants'; import { APIResponse } from 'types'; import { getToken } from 'utils/auth'; +import { timezoneList } from './constants'; + const FormItem = Form.Item; export function Profile({ visible, onCancel }: ModalProps) { @@ -99,6 +114,14 @@ export function Profile({ visible, onCancel }: ModalProps) { [dispatch, loggedInUser, onCancel, tg], ); + const formatTimezone = useCallback(zone => { + const ensure2Digits = num => (num > 9 ? `${num}` : `0${num}`); + + return `(${zone.value < 0 ? '-' : '+'}${ensure2Digits( + Math.floor(Math.abs(zone.value)), + )}:${ensure2Digits(Math.abs((zone.value % 1) * 60))}) ${zone.label}`; + }, []); + return ( + + + - ) : null - } - /> + <> + + enableExtraAction ? ( + + ) : null + } + /> + {contextHolder} + ); }, dataConfigSectionComparer, diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetManager/utils/init.ts b/frontend/src/app/pages/DashBoardPage/components/WidgetManager/utils/init.ts index f55e900c..cd09ceae 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetManager/utils/init.ts +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetManager/utils/init.ts @@ -456,7 +456,7 @@ export const initBorderTpl = () => { return borderTpl; }; -// TODO(Stephen): set width/height same as free widget? +// TODO(Stephen): to be check if width/height setting same as free widget? export const initAutoWidgetRect = (): RectConfig => ({ x: 0, y: 0, diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddChart/AddChart.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddChart/AddChart.tsx index 2c835810..d99bb55c 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddChart/AddChart.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddChart/AddChart.tsx @@ -86,7 +86,7 @@ export const AddChart = () => { /> {widgetChartVisible && ( Date: Mon, 22 Aug 2022 15:42:26 +0800 Subject: [PATCH 045/103] refactor: refactor share token style --- .../src/app/pages/SharePage/components/TitleForShare.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/pages/SharePage/components/TitleForShare.tsx b/frontend/src/app/pages/SharePage/components/TitleForShare.tsx index 9ef0c57a..f5d49a83 100644 --- a/frontend/src/app/pages/SharePage/components/TitleForShare.tsx +++ b/frontend/src/app/pages/SharePage/components/TitleForShare.tsx @@ -43,7 +43,7 @@ interface TitleHeaderProps { } const IconStyle = { marginLeft: '20px', - fontSize: 20, + fontSize: 14, cursor: 'pointer', }; @@ -95,6 +95,7 @@ const TitleForShare: FC = memo( ); export default TitleForShare; + const FixedButton = styled.div` position: fixed; top: 8px; @@ -102,7 +103,10 @@ const FixedButton = styled.div` z-index: ${LEVEL_100}; cursor: pointer; `; + const Wrapper = styled.div` + position: fixed; + z-index: ${LEVEL_100}; display: flex; flex-shrink: 0; align-items: center; -- Gitee From f142cdcc617d600292d8b55cf9d9d441987314be Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Mon, 22 Aug 2022 21:21:14 +0800 Subject: [PATCH 046/103] feat: add dropDownTree controller for dashboard --- frontend/package-lock.json | 8 + frontend/src/app/constants.ts | 1 + .../ChartConfig/migrateChartConfig.ts | 8 +- .../components/WidgetManager/index.tsx | 2 + .../components/WidgetMapper/WidgetMapper.tsx | 1 + .../Controller/TreeController.tsx | 95 +++++++++ .../ControllerWidget/ControllerWidgetCore.tsx | 22 ++- .../ControllerWidget/config/dropDownTree.ts | 133 +++++++++++++ .../src/app/pages/DashBoardPage/constants.ts | 5 + .../DashBoardPage/pages/Board/slice/thunk.ts | 6 + .../AddControler/AddControler.tsx | 11 +- .../ValuesSetter/TreeSetter/TreeSetter.tsx | 54 ++++++ .../ValuesSetter/TreeSetter/index.tsx | 20 ++ .../ValuesOptionsSetter.tsx | 181 ++++++++++++++---- .../ControllerWidgetPanel/constants.ts | 1 + .../ControllerWidgetPanel/index.tsx | 1 + .../components/ControllerWidgetPanel/types.ts | 2 + .../pages/BoardEditor/slice/thunk.ts | 4 + .../app/pages/DashBoardPage/utils/widget.ts | 26 +++ frontend/src/app/types/ChartConfig.ts | 1 + frontend/src/locales/en/translation.json | 6 +- frontend/src/locales/zh/translation.json | 6 +- 22 files changed, 545 insertions(+), 49 deletions(-) create mode 100644 frontend/src/app/pages/DashBoardPage/components/Widgets/ControllerWidget/Controller/TreeController.tsx create mode 100644 frontend/src/app/pages/DashBoardPage/components/Widgets/ControllerWidget/config/dropDownTree.ts create mode 100644 frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TreeSetter/TreeSetter.tsx create mode 100644 frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TreeSetter/index.tsx diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8486a934..e2c190cf 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -6084,6 +6084,8 @@ }, "node_modules/antd-theme-generator/node_modules/har-validator/node_modules/fast-deep-equal": { "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==", "inBundle": true, "license": "MIT", "optional": true @@ -6325,6 +6327,8 @@ }, "node_modules/antd-theme-generator/node_modules/minimist": { "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "inBundle": true, "license": "MIT", "optional": true @@ -35056,6 +35060,8 @@ }, "fast-deep-equal": { "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==", "bundled": true, "optional": true } @@ -35234,6 +35240,8 @@ }, "minimist": { "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "bundled": true, "optional": true }, diff --git a/frontend/src/app/constants.ts b/frontend/src/app/constants.ts index 3eda9355..67a5169d 100644 --- a/frontend/src/app/constants.ts +++ b/frontend/src/app/constants.ts @@ -27,6 +27,7 @@ export enum TenantManagementMode { export enum ControllerFacadeTypes { DropdownList = 'dropdownList', MultiDropdownList = 'multiDropdownList', + DropDownTree = 'dropDownTree', RadioGroup = 'radioGroup', CheckboxGroup = 'checkboxGroup', diff --git a/frontend/src/app/migration/ChartConfig/migrateChartConfig.ts b/frontend/src/app/migration/ChartConfig/migrateChartConfig.ts index d0f7b2f4..e361f374 100644 --- a/frontend/src/app/migration/ChartConfig/migrateChartConfig.ts +++ b/frontend/src/app/migration/ChartConfig/migrateChartConfig.ts @@ -60,8 +60,9 @@ export const RC2 = config => { ChartDataViewFieldCategory.DateLevelComputedField && !row.colName.includes(DATE_LEVEL_DELIMITER) ) { + const field = row.field || row.id?.split('(')?.[0]; row.colName = - row.field + DATE_LEVEL_DELIMITER + row.expression.split('(')[0]; + field + DATE_LEVEL_DELIMITER + row.expression.split('(')[0]; } }); }); @@ -77,10 +78,13 @@ export const RC2 = config => { const currenrRowFiledForComputed = allRows.find( row => row.expression === computedField.expression, ); + const field = + currenrRowFiledForComputed?.field || + currenrRowFiledForComputed?.id?.split('(')?.[0]; return { ...computedField, name: - currenrRowFiledForComputed.field + + field + DATE_LEVEL_DELIMITER + computedField.expression.split('(')[0], }; diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetManager/index.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetManager/index.tsx index 54b5f11a..cd3397c9 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetManager/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetManager/index.tsx @@ -18,6 +18,7 @@ import type { WidgetProto } from '../../types/widgetTypes'; import checkboxGroupProto from '../Widgets/ControllerWidget/config/checkboxGroup'; import dropdownListProto from '../Widgets/ControllerWidget/config/dropdownList'; +import dropDownTree from '../Widgets/ControllerWidget/config/dropDownTree'; import multiDropdownListProto from '../Widgets/ControllerWidget/config/multiDropdownList'; import radioGroupProto from '../Widgets/ControllerWidget/config/radioGroup'; import rangeTimeProto from '../Widgets/ControllerWidget/config/rangeTimeProto'; @@ -56,6 +57,7 @@ const protoList: WidgetProto[] = [ radioGroupProto, textProto, timeProto, + dropDownTree, rangeTimeProto, rangeValueProto, valueProto, diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetMapper/WidgetMapper.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetMapper/WidgetMapper.tsx index e1a405f2..6cad8b5d 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetMapper/WidgetMapper.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetMapper/WidgetMapper.tsx @@ -84,6 +84,7 @@ export const WidgetMapper: React.FC<{ case ORIGINAL_TYPE_MAP.rangeValue: case ORIGINAL_TYPE_MAP.value: case ORIGINAL_TYPE_MAP.slider: + case ORIGINAL_TYPE_MAP.dropDownTree: return ( void; + label?: React.ReactNode; + name?: string; + required?: boolean; + parentField?: string; +} + +export const TreeControllerForm: React.FC = memo( + ({ label, name, required, ...rest }) => { + return ( + + + + ); + }, +); +export const TreeSelectController: React.FC = memo( + ({ options, onChange, value, parentField }) => { + const t = useI18NPrefix(`viz.common.enum.controllerPlaceHolders`); + return ( + + {options?.map(item => ( + + {item.children?.map(children => { + return ( + + ); + })} + + ))} + + ); + }, +); +const StyledTreeSelect = styled(TreeSelect)` + display: block; + + &.ant-select .ant-select-selector { + background-color: transparent !important; + /* border: none; */ + } +`; diff --git a/frontend/src/app/pages/DashBoardPage/components/Widgets/ControllerWidget/ControllerWidgetCore.tsx b/frontend/src/app/pages/DashBoardPage/components/Widgets/ControllerWidget/ControllerWidgetCore.tsx index 97899932..33b2b209 100644 --- a/frontend/src/app/pages/DashBoardPage/components/Widgets/ControllerWidget/ControllerWidgetCore.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/Widgets/ControllerWidget/ControllerWidgetCore.tsx @@ -31,6 +31,7 @@ import produce from 'immer'; import React, { memo, useCallback, useContext, useMemo } from 'react'; import styled from 'styled-components/macro'; import { isEmpty } from 'utils/object'; +import { convertToTreeData } from '../../../utils/widget'; import { WidgetActionContext } from '../../ActionProvider/WidgetActionProvider'; import { WidgetTitle } from '../../WidgetComponents/WidgetTitle'; import { getWidgetTitle } from '../../WidgetManager/utils/utils'; @@ -46,6 +47,7 @@ import { SelectControllerForm } from './Controller/SelectController'; import { SlideControllerForm } from './Controller/SliderController'; import { TextControllerForm } from './Controller/TextController'; import { TimeControllerForm } from './Controller/TimeController'; +import { TreeControllerForm } from './Controller/TreeController'; export const ControllerWidgetCore: React.FC<{}> = memo(() => { const widget = useContext(WidgetContext); @@ -72,6 +74,7 @@ export const ControllerWidgetCore: React.FC<{}> = memo(() => { controllerValues, valueOptions, valueOptionType, + parentField, // sqlOperator, } = useMemo(() => config as ControllerConfig, [config]); const title = getWidgetTitle(widget.config.customConfig.props); @@ -100,7 +103,11 @@ export const ControllerWidgetCore: React.FC<{}> = memo(() => { }, [title]); const optionRows = useMemo(() => { const dataRows = dataset?.rows || []; + if (valueOptionType === 'common') { + if (parentField) { + return convertToTreeData(dataRows); + } return dataRows.map(ele => { const item: RelationFilterValue = { key: ele?.[0], @@ -114,7 +121,7 @@ export const ControllerWidgetCore: React.FC<{}> = memo(() => { } else { return []; } - }, [dataset?.rows, valueOptionType, valueOptions]); + }, [dataset?.rows, valueOptionType, valueOptions, parentField]); const onControllerChange = useCallback(() => { form.submit(); @@ -349,6 +356,18 @@ export const ControllerWidgetCore: React.FC<{}> = memo(() => { /> ); + case ControllerFacadeTypes.DropDownTree: + form.setFieldsValue({ value: controllerValues }); + return ( + + ); + default: break; } @@ -361,6 +380,7 @@ export const ControllerWidgetCore: React.FC<{}> = memo(() => { leftControlLabel, config, controllerDate, + parentField, onRangeTimeChange, onTimeChange, ]); diff --git a/frontend/src/app/pages/DashBoardPage/components/Widgets/ControllerWidget/config/dropDownTree.ts b/frontend/src/app/pages/DashBoardPage/components/Widgets/ControllerWidget/config/dropDownTree.ts new file mode 100644 index 00000000..cef2193c --- /dev/null +++ b/frontend/src/app/pages/DashBoardPage/components/Widgets/ControllerWidget/config/dropDownTree.ts @@ -0,0 +1,133 @@ +/** + * Datart + * + * Copyright 2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ORIGINAL_TYPE_MAP } from 'app/pages/DashBoardPage/constants'; +import { + WidgetMeta, + WidgetProto, + WidgetToolkit, +} from 'app/pages/DashBoardPage/types/widgetTypes'; +import { WHITE } from 'styles/StyleConstants'; +import { controlWidgetTpl, getControlDropDownList } from '.'; +import { + ImmediateQueryI18N, + initBackgroundTpl, + initBorderTpl, + initLoopFetchTpl, + initPaddingTpl, + initWidgetName, + LoopFetchI18N, + PaddingI18N, + TitleI18N, +} from '../../../WidgetManager/utils/init'; + +const NameI18N = { + zh: '下拉树', + en: 'Dropdown tree', +}; +export const widgetMeta: WidgetMeta = { + icon: 'control-widget', + originalType: ORIGINAL_TYPE_MAP.dropDownTree, + canWrapped: true, + controllable: true, + linkable: false, + canFullScreen: false, + singleton: false, + + i18ns: [ + { + lang: 'zh-CN', + translation: { + desc: '', + widgetName: NameI18N.zh, + action: {}, + title: TitleI18N.zh, + immediateQuery: ImmediateQueryI18N.zh, + background: { backgroundGroup: '背景' }, + padding: PaddingI18N.zh, + loopFetch: LoopFetchI18N.zh, + border: { borderGroup: '边框' }, + }, + }, + { + lang: 'en-US', + translation: { + desc: '', + widgetName: NameI18N.en, + action: {}, + title: TitleI18N.en, + immediateQuery: ImmediateQueryI18N.en, + background: { backgroundGroup: 'Background' }, + padding: PaddingI18N.en, + loopFetch: LoopFetchI18N.en, + border: { borderGroup: 'Border' }, + }, + }, + ], +}; + +export const widgetToolkit: WidgetToolkit = { + create: opt => { + const widget = controlWidgetTpl(opt); + widget.id = widgetMeta.originalType + widget.id; + widget.config.originalType = widgetMeta.originalType; + widget.config.rect.height = 40; + const addProps = [ + { ...initBackgroundTpl(WHITE) }, + { ...initPaddingTpl() }, + { ...initBorderTpl() }, + { ...initLoopFetchTpl() }, + ]; + widget.config.customConfig.props?.forEach(ele => { + if (ele.key === 'titleGroup') { + ele.rows?.forEach(row => { + if (row.key === 'showTitle') { + row.value = true; + } + }); + } + }); + widget.config.customConfig.props = + widget.config.customConfig.props?.concat(addProps); + return widget; + }, + getName(key) { + return initWidgetName(NameI18N, key); + }, + getDropDownList(...arg) { + return getControlDropDownList(true); + }, + edit() {}, + save() {}, + // lock() {}, + // unlock() {}, + // copy() {}, + // paste() {}, + // delete() {}, + // changeTitle() {}, + // getMeta() {}, + // getWidgetName() {}, + // // +}; + +const dropDownTree: WidgetProto = { + originalType: widgetMeta.originalType, + meta: widgetMeta, + toolkit: widgetToolkit, +}; +export default dropDownTree; diff --git a/frontend/src/app/pages/DashBoardPage/constants.ts b/frontend/src/app/pages/DashBoardPage/constants.ts index 2083ba89..b2b93442 100644 --- a/frontend/src/app/pages/DashBoardPage/constants.ts +++ b/frontend/src/app/pages/DashBoardPage/constants.ts @@ -98,6 +98,7 @@ export const ORIGINAL_TYPE_MAP = { rangeValue: ControllerFacadeTypes.RangeValue, value: ControllerFacadeTypes.Value, slider: ControllerFacadeTypes.Slider, + dropDownTree: ControllerFacadeTypes.DropDownTree, // custom: 'custom', TODO: }; @@ -287,6 +288,10 @@ export const SQL_OPERATOR_OPTIONS_TYPES = { FilterSqlOperator.LessThanOrEqual, FilterSqlOperator.GreaterThanOrEqual, ], + [ControllerFacadeTypes.DropDownTree]: [ + FilterSqlOperator.In, + FilterSqlOperator.NotIn, + ], }; export const WIDGET_TITLE_ALIGN_OPTIONS = [ diff --git a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/thunk.ts b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/thunk.ts index c3a32b69..4b09050c 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/thunk.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/thunk.ts @@ -494,10 +494,16 @@ export const getControllerOptions = createAsyncThunk< const [viewId, ...columns] = config.assistViewFields; + const parentField = config?.parentField; + const executeToken = executeTokenMap?.[viewId]; const view = viewMap[viewId]; if (!view) return null; + if (parentField) { + columns.push(parentField); + } + const requestParams = getControlOptionQueryParams({ view, columns: columns, diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControler/AddControler.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControler/AddControler.tsx index cabcfec9..969e21b0 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControler/AddControler.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControler/AddControler.tsx @@ -80,12 +80,11 @@ export const AddController: React.FC = () => { // type: ControllerFacadeTypes.RadioGroup, // disabled: false, // }, - // { - // name: '多选下拉树', - // icon: '', - // type: ControllerFacadeTypes.RadioGroup, - // disabled: false, - // }, + { + name: '多选下拉树', + icon: '', + type: ControllerFacadeTypes.DropDownTree, + }, ]; const dateControllers: ButtonItemType[] = [ { diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TreeSetter/TreeSetter.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TreeSetter/TreeSetter.tsx new file mode 100644 index 00000000..c4960e8f --- /dev/null +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TreeSetter/TreeSetter.tsx @@ -0,0 +1,54 @@ +/** + * Datart + * + * Copyright 2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Select } from 'antd'; +import styled from 'styled-components/macro'; + +export interface TreeSetterProps { + onChange?: (value: string) => void; + value?: string; + style: object; + viewFieldList; +} + +function TreeSetter({ + viewFieldList, + value: val, + style, + onChange, +}: TreeSetterProps) { + return ( + + ))} - + {item.children?.map(children => { + return ( + + + {children.label || children.key} + + {children.key} +
+ } + > + ); + })} + + ))} + + ) : ( + + )} )} {getOptionType() === 'custom' && ( diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/constants.ts b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/constants.ts index 7f8d3a0c..6b1c2c19 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/constants.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/constants.ts @@ -57,4 +57,5 @@ export const HasOptionsControlTypes = [ ControllerFacadeTypes.MultiDropdownList, ControllerFacadeTypes.RadioGroup, ControllerFacadeTypes.CheckboxGroup, + ControllerFacadeTypes.DropDownTree, ]; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/index.tsx index 2f8c1c5b..f6a7a41f 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/index.tsx @@ -220,6 +220,7 @@ const ControllerWidgetPanel: React.FC = memo( config: postControlConfig(config, controllerType!), }; const viewIds = getViewIdsInControlConfig(config); + let newWidget = widgetManagerInstance.toolkit(controllerType).create({ boardType, name: name, diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/types.ts b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/types.ts index 449783bb..edc542f9 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/types.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/types.ts @@ -23,6 +23,7 @@ export interface ControlOption { variables?: { [viewId: string]: string; }; + children?: ControlOption[]; } export interface VisibilityCondition { dependentControllerId: string; @@ -40,6 +41,7 @@ export interface ControllerConfig { canChangeSqlOperator?: boolean; // 是否显示 sqlOperator 切换 assistViewFields?: string[]; //辅助添加view字段 controllerDate?: ControllerDate; //存储时间 + parentField?: string; //父节点字段 minValue?: number; // slider min maxValue?: number; // slider max diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts index 4e8df2fc..824c35a9 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts @@ -674,11 +674,15 @@ export const getEditControllerOptions = createAsyncThunk< if (!Array.isArray(config.assistViewFields)) return null; if (config.assistViewFields.length < 2) return null; + const parentField = config?.parentField; const boardState = rootState.board as BoardState; const viewMap = boardState.viewMap; const [viewId, ...columns] = config.assistViewFields; const view = viewMap[viewId]; if (!view) return null; + if (parentField) { + columns.push(parentField); + } const requestParams = getControlOptionQueryParams({ view, columns: columns, diff --git a/frontend/src/app/pages/DashBoardPage/utils/widget.ts b/frontend/src/app/pages/DashBoardPage/utils/widget.ts index d87072ee..4334c8d8 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/widget.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/widget.ts @@ -25,6 +25,7 @@ import { } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import { FilterSearchParamsWithMatch } from 'app/pages/MainPage/pages/VizPage/slice/types'; import { ChartsEventData } from 'app/types/Chart'; +import { RelationFilterValue } from 'app/types/ChartConfig'; import ChartDataView from 'app/types/ChartDataView'; import { View } from 'app/types/View'; import { @@ -60,6 +61,7 @@ import { } from '../pages/Board/slice/types'; import { StrControlTypes } from '../pages/BoardEditor/components/ControllerWidgetPanel/constants'; import { Widget, WidgetMapping } from '../types/widgetTypes'; + export const VALUE_SPLITTER = '###'; // export const createInitWidgetConfig = (opt: { @@ -777,3 +779,27 @@ export function cloneWidgets(args: { newWidgets, }; } + +export const convertToTreeData = collection => { + const treeNode: { [key: string]: RelationFilterValue } = {}; + + collection.forEach(ele => { + const parentTitle = ele[ele.length - 1]; + if (!treeNode[parentTitle]) { + treeNode[parentTitle] = { + key: parentTitle, + label: parentTitle, + children: [], + }; + } + treeNode[parentTitle]['children'] = [ + ...(treeNode[parentTitle]['children'] as []), + { + key: ele?.[0], + label: ele.length > 2 ? ele?.[1] : '', + }, + ]; + }); + + return Object.values(treeNode); +}; diff --git a/frontend/src/app/types/ChartConfig.ts b/frontend/src/app/types/ChartConfig.ts index 61201ebb..e55a3e1f 100644 --- a/frontend/src/app/types/ChartConfig.ts +++ b/frontend/src/app/types/ChartConfig.ts @@ -97,6 +97,7 @@ export type RelationFilterValue = { index?: number; isSelected?: boolean; children?: RelationFilterValue[]; + selectable?: boolean; }; export type AggregateLimit = Pick; diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index d6cb6eb6..882628d6 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -382,7 +382,8 @@ "value": "Value", "time": "Time", "slider": "Slider", - "rangeSlider": "Range Slider" + "rangeSlider": "Range Slider", + "dropDownTree": "Dropdown tree" }, "controllerPlaceHolders": { "multiSelectController": "Select ..", @@ -390,7 +391,8 @@ "rangeNumberControllerMin": "Min", "rangeNumberControllerMax": "Max", "selectController": "Select ..", - "textController": "Enter text" + "textController": "Enter text", + "treeSelectController": "Select .." }, "controllerVisibilityTypes": { "hide": "Hide", diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 9bf46b52..8b53f187 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -382,7 +382,8 @@ "value": "数值", "time": "日期", "slider": "滑块", - "rangeSlider": "范围滑块" + "rangeSlider": "范围滑块", + "dropDownTree": "下拉树" }, "controllerPlaceHolders": { "multiSelectController": "请选择", @@ -390,7 +391,8 @@ "rangeNumberControllerMin": "最小值", "rangeNumberControllerMax": "最大值", "selectController": "请选择", - "textController": "请输入" + "textController": "请输入", + "treeSelectController": "请选择" }, "controllerVisibilityTypes": { "hide": "隐藏", -- Gitee From 002c0d0070ffcdf7017b45172799fe6ea38fe9c7 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Tue, 23 Aug 2022 10:44:27 +0800 Subject: [PATCH 047/103] fix: add i18n for tree controller --- .../Widgets/ControllerWidget/Controller/TreeController.tsx | 2 +- .../components/BoardToolBar/AddControler/AddControler.tsx | 1 - .../ControllerConfig/ValuesSetter/TreeSetter/TreeSetter.tsx | 4 +++- frontend/src/app/pages/DashBoardPage/utils/widget.ts | 2 +- frontend/src/locales/en/translation.json | 3 ++- frontend/src/locales/zh/translation.json | 3 ++- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/Widgets/ControllerWidget/Controller/TreeController.tsx b/frontend/src/app/pages/DashBoardPage/components/Widgets/ControllerWidget/Controller/TreeController.tsx index 15e7bb64..a9d675ff 100644 --- a/frontend/src/app/pages/DashBoardPage/components/Widgets/ControllerWidget/Controller/TreeController.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/Widgets/ControllerWidget/Controller/TreeController.tsx @@ -75,7 +75,7 @@ export const TreeSelectController: React.FC = memo( ); })} diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControler/AddControler.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControler/AddControler.tsx index 969e21b0..41f33bfa 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControler/AddControler.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControler/AddControler.tsx @@ -81,7 +81,6 @@ export const AddController: React.FC = () => { // disabled: false, // }, { - name: '多选下拉树', icon: '', type: ControllerFacadeTypes.DropDownTree, }, diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TreeSetter/TreeSetter.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TreeSetter/TreeSetter.tsx index c4960e8f..4ad40da2 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TreeSetter/TreeSetter.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TreeSetter/TreeSetter.tsx @@ -17,6 +17,7 @@ */ import { Select } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import styled from 'styled-components/macro'; export interface TreeSetterProps { @@ -32,13 +33,14 @@ function TreeSetter({ style, onChange, }: TreeSetterProps) { + const tc = useI18NPrefix(`viz.control`); return ( ), diff --git a/frontend/src/app/components/FormGenerator/Customize/Interaction/UrlParamList.tsx b/frontend/src/app/components/FormGenerator/Customize/Interaction/UrlParamList.tsx index a94c17c2..c1ac6f2f 100644 --- a/frontend/src/app/components/FormGenerator/Customize/Interaction/UrlParamList.tsx +++ b/frontend/src/app/components/FormGenerator/Customize/Interaction/UrlParamList.tsx @@ -18,6 +18,7 @@ import { Button, Input, Radio, Select, Table } from 'antd'; import { ColumnsType } from 'antd/lib/table'; +import { handleDateLevelsName } from 'app/pages/ChartWorkbenchPage/components/ChartOperationPanel/utils'; import { ChartDataViewMeta } from 'app/types/ChartDataViewMeta'; import { updateBy } from 'app/utils/mutation'; import { FC } from 'react'; @@ -122,7 +123,11 @@ const UrlParamList: FC< dropdownMatchSelectWidth={false} > {(isFieldType(record) ? sourceFields : sourceVariables)?.map(sf => { - return {sf?.name}; + return ( + + {handleDateLevelsName(sf)} + + ); })} ), -- Gitee From 30e5a1fe341e46e439e41d1163e12acf6355c31c Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Tue, 23 Aug 2022 15:04:02 +0800 Subject: [PATCH 052/103] fix: fix null exception when name variable is null --- .../datart/server/service/impl/DataProviderServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/datart/server/service/impl/DataProviderServiceImpl.java b/server/src/main/java/datart/server/service/impl/DataProviderServiceImpl.java index 9d5e5b97..45255be9 100644 --- a/server/src/main/java/datart/server/service/impl/DataProviderServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/DataProviderServiceImpl.java @@ -352,7 +352,7 @@ public class DataProviderServiceImpl extends BaseService implements DataProvider variables.add(new ScriptVariable(VARIABLE_NAME, VariableTypeEnum.PERMISSION, ValueType.STRING, - Sets.newHashSet(getCurrentUser().getName()), + getCurrentUser().getName() == null ? Collections.emptySet() : Sets.newHashSet(getCurrentUser().getName()), false)); variables.add(new ScriptVariable(VARIABLE_EMAIL, VariableTypeEnum.PERMISSION, -- Gitee From 01e5f8ae2cef538382ce8d64f9fe99de4107541c Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Tue, 23 Aug 2022 15:11:24 +0800 Subject: [PATCH 053/103] fix: change initvalue function --- .../ValuesOptionsSetter/ValuesOptionsSetter.tsx | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/ValuesOptionsSetter.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/ValuesOptionsSetter.tsx index 3c76e7a8..179e38eb 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/ValuesOptionsSetter.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/ValuesOptionsSetter.tsx @@ -247,7 +247,7 @@ const ValuesOptionsSetter: FC<{ ); const onInitOptions = useCallback( - async (value: string[], parentField: string) => { + async (value: string[], parentField?: string) => { const [viewId, ...columns] = value; const { option: options, dataView } = await getViewOption(viewId); if (parentField) { @@ -283,12 +283,7 @@ const ValuesOptionsSetter: FC<{ const assistViewFields = config?.assistViewFields; const parentField = config?.parentField; - if ( - assistViewFields && - assistViewFields[0] && - assistViewFields[1] && - parentField - ) { + if (assistViewFields && assistViewFields[0] && assistViewFields[1]) { onInitOptions(assistViewFields, parentField); } }, [form, getControllerConfig, onInitOptions]); @@ -308,7 +303,7 @@ const ValuesOptionsSetter: FC<{ }, }); - onViewFieldChange(config.assistViewFields || [], ''); + onViewFieldChange(config.assistViewFields || []); }, [getControllerConfig, form, onViewFieldChange], ); -- Gitee From 6fb9bd7d0f1ad155e6d7b260a57217b9f1687db0 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Tue, 23 Aug 2022 15:12:41 +0800 Subject: [PATCH 054/103] fix: add init TreeController Config --- .../BoardEditor/components/ControllerWidgetPanel/utils.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/utils.ts b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/utils.ts index 210e2147..8413cc2a 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/utils.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/utils.ts @@ -168,6 +168,8 @@ export const getInitWidgetController = ( type: ControllerFacadeTypes = ControllerFacadeTypes.DropdownList, ) => { switch (type) { + case ControllerFacadeTypes.DropDownTree: + return getDropdownTreeControllerConfig(); case ControllerFacadeTypes.MultiDropdownList: return getMultiDropdownListControllerConfig(); case ControllerFacadeTypes.Time: @@ -284,6 +286,12 @@ export const getRangeValueControllerConfig = () => { return config; }; +export const getDropdownTreeControllerConfig = () => { + const config = getInitControllerConfig(); + config.sqlOperator = FilterSqlOperator.In; + return config; +}; + export const filterValueTypeByControl = ( controlType: ControllerFacadeTypes, valueType: any, -- Gitee From ff631bf4b443f3a15fd1f480b8543b044da4351b Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Tue, 23 Aug 2022 15:13:36 +0800 Subject: [PATCH 055/103] fix: change file name OtherSet.tsx to OtherSetter --- .../RadioStyle/RadioStyleForm.tsx | 0 .../RadioStyle/RadioStyleSet.tsx | 0 .../SliderStyle/SliderMarks.tsx | 0 .../SliderStyle/SliderStep.tsx | 0 .../SqlOperator/SqlOperatorForm.tsx | 1 + .../SqlOperator/SqlOperatorSet.tsx | 0 .../{OtherSet.tsx => OtherSetter}/SqlOperator/index.tsx | 0 .../ControllerWidgetPanel/ControllerConfig/index.tsx | 8 ++++---- 8 files changed, 5 insertions(+), 4 deletions(-) rename frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/{OtherSet.tsx => OtherSetter}/RadioStyle/RadioStyleForm.tsx (100%) rename frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/{OtherSet.tsx => OtherSetter}/RadioStyle/RadioStyleSet.tsx (100%) rename frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/{OtherSet.tsx => OtherSetter}/SliderStyle/SliderMarks.tsx (100%) rename frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/{OtherSet.tsx => OtherSetter}/SliderStyle/SliderStep.tsx (100%) rename frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/{OtherSet.tsx => OtherSetter}/SqlOperator/SqlOperatorForm.tsx (97%) rename frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/{OtherSet.tsx => OtherSetter}/SqlOperator/SqlOperatorSet.tsx (100%) rename frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/{OtherSet.tsx => OtherSetter}/SqlOperator/index.tsx (100%) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/RadioStyle/RadioStyleForm.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/RadioStyle/RadioStyleForm.tsx similarity index 100% rename from frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/RadioStyle/RadioStyleForm.tsx rename to frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/RadioStyle/RadioStyleForm.tsx diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/RadioStyle/RadioStyleSet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/RadioStyle/RadioStyleSet.tsx similarity index 100% rename from frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/RadioStyle/RadioStyleSet.tsx rename to frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/RadioStyle/RadioStyleSet.tsx diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/SliderStyle/SliderMarks.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/SliderStyle/SliderMarks.tsx similarity index 100% rename from frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/SliderStyle/SliderMarks.tsx rename to frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/SliderStyle/SliderMarks.tsx diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/SliderStyle/SliderStep.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/SliderStyle/SliderStep.tsx similarity index 100% rename from frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/SliderStyle/SliderStep.tsx rename to frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/SliderStyle/SliderStep.tsx diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/SqlOperator/SqlOperatorForm.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/SqlOperator/SqlOperatorForm.tsx similarity index 97% rename from frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/SqlOperator/SqlOperatorForm.tsx rename to frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/SqlOperator/SqlOperatorForm.tsx index 48ef72b0..b71583e5 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/SqlOperator/SqlOperatorForm.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/SqlOperator/SqlOperatorForm.tsx @@ -23,6 +23,7 @@ export interface SqlOperatorFormProps extends FormItemProps { } export const SqlOperatorForm: React.FC = memo( ({ options, ...rest }) => { + console.log(rest, 'rest'); return ( diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/SqlOperator/SqlOperatorSet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/SqlOperator/SqlOperatorSet.tsx similarity index 100% rename from frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/SqlOperator/SqlOperatorSet.tsx rename to frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/SqlOperator/SqlOperatorSet.tsx diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/SqlOperator/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/SqlOperator/index.tsx similarity index 100% rename from frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSet.tsx/SqlOperator/index.tsx rename to frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/OtherSetter/SqlOperator/index.tsx diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/index.tsx index 35de05a9..a1926c97 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/index.tsx @@ -27,10 +27,10 @@ import ChartDataView from 'app/types/ChartDataView'; import React, { memo, useMemo } from 'react'; import styled from 'styled-components/macro'; import ControllerVisibility from './ControllerVisibility'; -import { RadioStyleForm } from './OtherSet.tsx/RadioStyle/RadioStyleForm'; -import { SliderMarks } from './OtherSet.tsx/SliderStyle/SliderMarks'; -import { SliderStep } from './OtherSet.tsx/SliderStyle/SliderStep'; -import { SqlOperator } from './OtherSet.tsx/SqlOperator'; +import { RadioStyleForm } from './OtherSetter/RadioStyle/RadioStyleForm'; +import { SliderMarks } from './OtherSetter/SliderStyle/SliderMarks'; +import { SliderStep } from './OtherSetter/SliderStyle/SliderStep'; +import { SqlOperator } from './OtherSetter/SqlOperator'; import { ValuesSetter } from './ValuesSetter/ValuesSetter'; export const ControllerValuesName = ['config', 'controllerValues']; -- Gitee From 095129e32564f7443a3df3fdea0d639e21d335b2 Mon Sep 17 00:00:00 2001 From: tianlei Date: Wed, 17 Aug 2022 12:59:35 +0800 Subject: [PATCH 056/103] refactor(permission): refactor schedule permission --- .../Main/PermissionForm/index.tsx | 8 +- .../pages/PermissionPage/slice/index.tsx | 21 +- .../pages/SchedulePage/EditorPage/index.tsx | 103 +++- .../MainPage/pages/SchedulePage/SaveForm.tsx | 158 ++++++ .../pages/SchedulePage/SaveFormContext.ts | 118 +++++ .../pages/SchedulePage/Sidebar/Recycle.tsx | 184 ++++++- .../SchedulePage/Sidebar/ScheduleList.tsx | 495 ++++++++++++------ .../pages/SchedulePage/Sidebar/index.tsx | 263 +++++++--- .../MainPage/pages/SchedulePage/constants.ts | 3 + .../MainPage/pages/SchedulePage/index.tsx | 29 +- .../pages/SchedulePage/slice/index.ts | 27 +- .../pages/SchedulePage/slice/selectors.ts | 36 ++ .../pages/SchedulePage/slice/thunks.ts | 48 +- .../pages/SchedulePage/slice/types.ts | 59 ++- .../MainPage/pages/SchedulePage/types.ts | 4 +- .../MainPage/pages/SchedulePage/utils.ts | 8 + frontend/src/locales/en/translation.json | 10 +- frontend/src/locales/zh/translation.json | 10 +- frontend/src/utils/utils.ts | 4 +- 19 files changed, 1224 insertions(+), 364 deletions(-) create mode 100644 frontend/src/app/pages/MainPage/pages/SchedulePage/SaveForm.tsx create mode 100644 frontend/src/app/pages/MainPage/pages/SchedulePage/SaveFormContext.ts diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/index.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/index.tsx index 9aef40b2..1c89a44a 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/index.tsx @@ -307,9 +307,11 @@ export const PermissionForm = memo( /> )} {viewpoint === Viewpoints.Subject && - ![ResourceTypes.Viz, ResourceTypes.View].includes( - dataSourceType as ResourceTypes, - ) && ( + ![ + ResourceTypes.Viz, + ResourceTypes.View, + ResourceTypes.Schedule, + ].includes(dataSourceType as ResourceTypes) && ( { + const root = generateRootNode(ResourceTypes.Schedule); state.scheduleListLoading = false; - state.schedules = action.payload.map(({ id, name }) => ({ - id, - name, - type: ResourceTypes.Schedule, - parentId: null, - index: null, - isFolder: false, - permissionArray: getDefaultPermissionArray(), - })); + state.schedules = [root].concat( + action.payload.map(({ id, name, parentId, index, isFolder }) => ({ + id, + name, + index, + type: root.type, + parentId: parentId === null ? root.id : parentId, + isFolder, + permissionArray: getDefaultPermissionArray(), + })), + ); }); builder.addCase(getSchedules.rejected, state => { state.scheduleListLoading = false; diff --git a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/index.tsx b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/index.tsx index 037b7a96..304d8e6d 100644 --- a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/index.tsx @@ -11,19 +11,30 @@ import { import { DetailPageHeader } from 'app/components/DetailPageHeader'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { getFolders } from 'app/pages/MainPage/pages/VizPage/slice/thunks'; -import { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import { CommonFormTypes } from 'globalConstants'; +import { + FC, + useCallback, + useContext, + useEffect, + useMemo, + useState, +} from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useRouteMatch } from 'react-router-dom'; import styled from 'styled-components/macro'; import { BORDER_RADIUS, SPACE_LG, SPACE_SM } from 'styles/StyleConstants'; +import { getInsertedNodeIndex } from 'utils/utils'; import { DEFAULT_VALUES, FileTypes, JobTypes, TimeModes } from '../constants'; import { useToScheduleDetails } from '../hooks'; +import { SaveFormContext } from '../SaveFormContext'; import { useScheduleSlice } from '../slice'; import { selectDeleteLoading, selectEditingSchedule, selectSaveLoading, selectScheduleDetailLoading, + selectSchedules, selectUnarchiveLoading, } from '../slice/selectors'; import { @@ -63,6 +74,8 @@ export const EditorPage: FC = () => { const saveLoading = useSelector(selectSaveLoading); const unarchiveLoading = useSelector(selectUnarchiveLoading); const deleteLoading = useSelector(selectDeleteLoading); + const schedules = useSelector(selectSchedules); + const { showSaveForm } = useContext(SaveFormContext); const { toDetails } = useToScheduleDetails(); const isArchived = editingSchedule?.status === 0; const t = useI18NPrefix('main.pages.schedulePage.sidebar.editorPage.index'); @@ -84,18 +97,31 @@ export const EditorPage: FC = () => { message.error(t('tickToSendContent')); return; } - const params = toScheduleSubmitParams(values, orgId); + let index = getInsertedNodeIndex(values, schedules); + const params = toScheduleSubmitParams( + { ...values, index, parentId: editingSchedule?.parentId || null }, + orgId, + ); if (isAdd) { - dispatch( - addSchedule({ - params, - resolve: (id: string) => { - message.success(t('addSuccess')); - toDetails(orgId, id); - refreshScheduleList(); - }, - }), - ); + showSaveForm({ + type: CommonFormTypes.Add, + visible: true, + simple: true, + parentIdLabel: t('parent'), + onSave: (val, onClose) => { + dispatch( + addSchedule({ + params: { ...params, parentId: val.parentId }, + resolve: (id: string) => { + message.success(t('addSuccess')); + toDetails(orgId, id); + refreshScheduleList(); + onClose(); + }, + }), + ); + }, + }); } else { dispatch( editSchedule({ @@ -112,13 +138,16 @@ export const EditorPage: FC = () => { }); }, [ form, + schedules, + editingSchedule?.parentId, + editingSchedule?.id, orgId, isAdd, t, + showSaveForm, dispatch, toDetails, refreshScheduleList, - editingSchedule?.id, ]); const onResetForm = useCallback(() => { @@ -190,16 +219,38 @@ export const EditorPage: FC = () => { ); const unarchive = useCallback(() => { - dispatch( - unarchiveSchedule({ - id: editingSchedule!.id, - resolve: () => { - message.success(t('restoredSuccess')); - toDetails(orgId); - }, - }), - ); - }, [dispatch, toDetails, orgId, editingSchedule, t]); + if (unarchiveLoading) return; + const { id, name } = editingSchedule!; + showSaveForm({ + type: CommonFormTypes.Edit, + visible: true, + simple: false, + initialValues: { id, name, parentId: null }, + parentIdLabel: t('parent'), + onSave: (values, onClose) => { + let index = getInsertedNodeIndex(values, schedules); + dispatch( + unarchiveSchedule({ + schedule: { ...values, id, index }, + resolve: () => { + message.success(t('restoredSuccess')); + toDetails(orgId); + onClose(); + }, + }), + ); + }, + }); + }, [ + unarchiveLoading, + editingSchedule, + showSaveForm, + t, + schedules, + dispatch, + toDetails, + orgId, + ]); const del = useCallback( archive => () => { @@ -244,9 +295,9 @@ export const EditorPage: FC = () => { actions={ isArchived ? ( <> - - - + - + - - - + + + + + + ); } diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/slice/index.ts b/frontend/src/app/pages/MainPage/pages/SourcePage/slice/index.ts index 5c81f528..eb200231 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/slice/index.ts +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/slice/index.ts @@ -27,6 +27,7 @@ import { getSources, syncSourceSchema, unarchiveSource, + updateSourceBase, } from './thunks'; import { SourceState } from './types'; @@ -41,6 +42,7 @@ export const initialState: SourceState = { unarchiveSourceLoading: false, deleteSourceLoading: false, syncSourceSchemaLoading: false, + updateLoading: false, }; const slice = createSlice({ @@ -58,7 +60,7 @@ const slice = createSlice({ }); builder.addCase(getSources.fulfilled, (state, action) => { state.sourceListLoading = false; - state.sources = action.payload; + state.sources = action.payload.map(v => ({ ...v, deleteLoading: false })); }); builder.addCase(getSources.rejected, state => { state.sourceListLoading = false; @@ -70,7 +72,10 @@ const slice = createSlice({ }); builder.addCase(getArchivedSources.fulfilled, (state, action) => { state.archivedListLoading = false; - state.archived = action.payload; + state.archived = action.payload.map(v => ({ + ...v, + deleteLoading: false, + })); }); builder.addCase(getArchivedSources.rejected, state => { state.archivedListLoading = false; @@ -83,7 +88,9 @@ const slice = createSlice({ builder.addCase(getSource.fulfilled, (state, action) => { state.sourceDetailLoading = false; state.sources = state.sources.map(s => - s.id === action.payload.id ? action.payload : s, + s.id === action.payload.id + ? { ...action.payload, deleteLoading: false } + : s, ); state.editingSource = action.payload.id; }); @@ -97,7 +104,7 @@ const slice = createSlice({ }); builder.addCase(addSource.fulfilled, (state, action) => { state.saveSourceLoading = false; - state.sources.unshift(action.payload); + state.sources.unshift({ ...action.payload, deleteLoading: false }); }); builder.addCase(addSource.rejected, state => { state.saveSourceLoading = false; @@ -110,7 +117,9 @@ const slice = createSlice({ builder.addCase(editSource.fulfilled, (state, action) => { state.saveSourceLoading = false; state.sources = state.sources.map(s => - s.id === action.payload.id ? action.payload : s, + s.id === action.payload.id + ? { ...action.payload, deleteLoading: false } + : s, ); }); builder.addCase(editSource.rejected, state => { @@ -123,7 +132,9 @@ const slice = createSlice({ }); builder.addCase(unarchiveSource.fulfilled, (state, action) => { state.unarchiveSourceLoading = false; - state.archived = state.archived.filter(s => s.id !== action.meta.arg.id); + state.archived = state.archived.filter( + s => s.id !== action.meta.arg.source.id, + ); }); builder.addCase(unarchiveSource.rejected, state => { state.unarchiveSourceLoading = false; @@ -135,13 +146,8 @@ const slice = createSlice({ }); builder.addCase(deleteSource.fulfilled, (state, action) => { state.deleteSourceLoading = false; - if (action.meta.arg.archive) { - state.sources = state.sources.filter(s => s.id !== action.meta.arg.id); - } else { - state.archived = state.archived.filter( - s => s.id !== action.meta.arg.id, - ); - } + state.sources = state.sources.filter(s => s.id !== action.meta.arg.id); + state.archived = state.archived.filter(s => s.id !== action.meta.arg.id); }); builder.addCase(deleteSource.rejected, state => { state.deleteSourceLoading = false; @@ -157,6 +163,27 @@ const slice = createSlice({ builder.addCase(syncSourceSchema.rejected, state => { state.syncSourceSchemaLoading = false; }); + + // updateSourceBase + builder.addCase(updateSourceBase.pending, state => { + state.updateLoading = true; + }); + builder.addCase(updateSourceBase.fulfilled, (state, action) => { + state.updateLoading = false; + state.sources = state.sources.map(v => + v.id === action.payload.id + ? { + ...v, + ...action.payload, + parentId: action.payload.parentId || null, + deleteLoading: false, + } + : v, + ); + }); + builder.addCase(updateSourceBase.rejected, state => { + state.updateLoading = false; + }); }, }); diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/slice/selectors.ts b/frontend/src/app/pages/MainPage/pages/SourcePage/slice/selectors.ts index c026ba09..f08a5e71 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/slice/selectors.ts +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/slice/selectors.ts @@ -18,7 +18,10 @@ import { createSelector } from '@reduxjs/toolkit'; import { RootState } from 'types'; +import { listToTree } from 'utils/utils'; import { initialState } from '.'; +import { ResourceTypes } from '../../PermissionPage/constants'; +import { SelectSourceFolderTreeProps, SelectSourceTreeProps } from './types'; const selectDomain = (state: RootState) => state.source || initialState; @@ -27,6 +30,36 @@ export const selectSources = createSelector( sourceState => sourceState.sources, ); +export const makeSelectSourceTree = () => + createSelector( + [ + selectSources, + (_, props: SelectSourceTreeProps) => props.getIcon, + (_, props: SelectSourceTreeProps) => props.getDisabled, + ], + (sources, getIcon, getDisabled) => + listToTree(sources, null, [ResourceTypes.Source], { + getIcon, + getDisabled, + }), + ); + +export const makeSelectSourceFolderTree = () => + createSelector( + [ + selectSources, + (_, props: SelectSourceFolderTreeProps) => props.id, + (_, props: SelectSourceFolderTreeProps) => props.getDisabled, + ], + (sources, id, getDisabled) => + listToTree( + sources && sources.filter(v => v.isFolder && v.id !== id), + null, + [ResourceTypes.Source], + { getDisabled }, + ), + ); + export const selectArchived = createSelector( [selectDomain], sourceState => sourceState.archived, diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/slice/thunks.ts b/frontend/src/app/pages/MainPage/pages/SourcePage/slice/thunks.ts index 41fcb686..d560158a 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/slice/thunks.ts +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/slice/thunks.ts @@ -17,22 +17,22 @@ */ import { createAsyncThunk } from '@reduxjs/toolkit'; -import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; -import { getLoggedInUserPermissions } from 'app/pages/MainPage/slice/thunks'; import { RootState } from 'types'; import { request2 } from 'utils/request'; import { - AddSourceParams, DeleteSourceParams, EditSourceParams, - Source, + SourceBase, + SourceParamsResolve, + SourceSimple, UnarchiveSourceParams, + UpdateSourceBaseParams, } from './types'; -export const getSources = createAsyncThunk( +export const getSources = createAsyncThunk( 'source/getSources', async orgId => { - const { data } = await request2({ + const { data } = await request2({ url: '/sources', method: 'GET', params: { orgId }, @@ -41,10 +41,10 @@ export const getSources = createAsyncThunk( }, ); -export const getArchivedSources = createAsyncThunk( +export const getArchivedSources = createAsyncThunk( 'source/getArchivedSources', async orgId => { - const { data } = await request2({ + const { data } = await request2({ url: '/sources/archived', method: 'GET', params: { orgId }, @@ -53,34 +53,30 @@ export const getArchivedSources = createAsyncThunk( }, ); -export const getSource = createAsyncThunk( +export const getSource = createAsyncThunk( 'source/getSource', async id => { - const { data } = await request2(`/sources/${id}`); + const { data } = await request2(`/sources/${id}`); return data; }, ); export const addSource = createAsyncThunk< - Source, - AddSourceParams, + SourceSimple, + SourceParamsResolve, { state: RootState } >('source/addSource', async ({ source, resolve }, { getState, dispatch }) => { - const { data } = await request2({ + const { data } = await request2({ url: '/sources', method: 'POST', data: source, }); - // FIXME 拥有Read权限等级的扁平结构资源新增后需要更新权限字典;后续如改造为目录结构则删除该逻辑 - const orgId = selectOrgId(getState()); - await dispatch(getLoggedInUserPermissions(orgId)); - resolve(data.id); return data; }); -export const editSource = createAsyncThunk( +export const editSource = createAsyncThunk( 'source/editSource', async ({ source, resolve, reject }) => { await request2( @@ -103,10 +99,11 @@ export const editSource = createAsyncThunk( export const unarchiveSource = createAsyncThunk( 'source/unarchiveSource', - async ({ id, resolve }) => { + async ({ source, resolve }) => { await request2({ - url: `/sources/unarchive/${id}`, + url: `/sources/unarchive/${source.id}`, method: 'PUT', + params: source, }); resolve(); return null; @@ -136,3 +133,16 @@ export const syncSourceSchema = createAsyncThunk( return data; }, ); + +export const updateSourceBase = createAsyncThunk< + SourceBase, + UpdateSourceBaseParams +>('source/updateSourceBase', async ({ source, resolve }) => { + await request2({ + url: `/sources/${source.id}/base`, + method: 'PUT', + data: source, + }); + resolve(); + return source; +}); diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/slice/types.ts b/frontend/src/app/pages/MainPage/pages/SourcePage/slice/types.ts index 32a0ee89..6c077dc5 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/slice/types.ts +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/slice/types.ts @@ -16,9 +16,12 @@ * limitations under the License. */ +import { TreeNodeProps } from 'antd'; +import { ReactElement } from 'react'; + export interface SourceState { - sources: Source[]; - archived: Source[]; + sources: SourceSimpleViewModel[]; + archived: SourceSimpleViewModel[]; editingSource: string; sourceListLoading: boolean; archivedListLoading: boolean; @@ -27,40 +30,90 @@ export interface SourceState { unarchiveSourceLoading: boolean; deleteSourceLoading: boolean; syncSourceSchemaLoading: boolean; + updateLoading: boolean; } export interface Source { config: string; - createBy: string; - createTime: string; + createBy?: string; + createTime?: string; id: string; name: string; orgId: string; - status: number; + status?: number; type: string; - updateBy: string; - updateTime: string; - schemaUpdateDate: string; + index: number | null; + updateBy?: string; + updateTime?: string; + permission?: number; + schemaUpdateDate?: string; +} + +export interface SelectSourceTreeProps { + getIcon: ( + o: SourceSimpleViewModel, + ) => ReactElement | ((props: TreeNodeProps) => ReactElement) | undefined; + getDisabled: (o: SourceSimpleViewModel) => boolean; } -export interface SourceFormModel extends Pick { +export interface SelectSourceFolderTreeProps { id?: string; + getDisabled: (o: SourceSimpleViewModel, path: string[]) => boolean; +} + +export interface UpdateSourceBaseParams { + source: SourceBase; + resolve: () => void; +} + +export interface SourceBase { + id: string; + name: string; + parentId: string | null; + index: number | null; +} + +export interface SourceSimple extends Source { + isFolder: boolean; + parentId: string | null; +} + +export interface SourceSimpleViewModel extends SourceSimple { + deleteLoading: boolean; +} + +export interface SourceFormModel + extends Pick< + SourceSimple, + 'isFolder' | 'name' | 'type' | 'parentId' | 'orgId' | 'index' + > { config: object; } export interface AddSourceParams { - source: Pick; + config: string; + parentId: string | null; + index: number | null; + orgId: string; + isFolder: boolean; + id?: string | undefined; + name: string; + type?: string; +} + +export interface SourceParamsResolve { + source: AddSourceParams; resolve: (redirectId: string) => void; } export interface EditSourceParams { - source: Source; + source: SourceSimple; resolve: () => void; reject?: () => void; } export interface UnarchiveSourceParams { - id: string; + source: SourceBase; resolve: () => void; } diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/utils.ts b/frontend/src/app/pages/MainPage/pages/SourcePage/utils.ts index d2bcae9a..de28d61e 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/utils.ts +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/utils.ts @@ -18,18 +18,10 @@ import { PermissionLevels, ResourceTypes } from '../PermissionPage/constants'; -export function allowCreateSource() { +export function allowManageSource(path: string[]) { return { module: ResourceTypes.Source, - id: ResourceTypes.Source, - level: PermissionLevels.Create, - }; -} - -export function allowManageSource(id?: string) { - return { - module: ResourceTypes.Source, - id, + path, level: PermissionLevels.Manage, }; } diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index abe14a8b..39c1ef40 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -1366,7 +1366,16 @@ "sidebar": { "title": "Sources", "add": "Create Source", - "recycle": "Recycle" + "recycle": "Recycle", + "addFolder": "Create Folder", + "parent": "Parent", + "success": "Success", + "delete": "Delete", + "moveToTrash": "Move to recycle bin", + "restoredSuccess": "Restored successfully", + "restore": "Restore", + "sureToDelete": "Confirm delete?", + "addSuccess": "Add Success" }, "form": { "name": "Name", @@ -1380,6 +1389,12 @@ "editConfig": "Edit Configuration", "duplicate": "Duplicate Key", "duplicateName": "Duplicate Name" + }, + "saveForm": { + "name": "Name", + "folder": "Folder", + "root": "Root", + "title": "Sources" } }, "schedule": { diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 2f4bb721..5bfb9ea8 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -1365,7 +1365,16 @@ "sidebar": { "title": "数据源列表", "add": "新建数据源", - "recycle": "回收站" + "addFolder": "新建目录", + "recycle": "回收站", + "parent": "所属目录", + "success": "成功", + "delete": "删除", + "moveToTrash": "移至回收站", + "addSuccess": "新增成功", + "restoredSuccess": "还原成功", + "restore": "还原", + "sureToDelete": "确定删除?" }, "form": { "name": "名称", @@ -1379,6 +1388,12 @@ "editConfig": "编辑配置", "duplicateKey": "Key不能重复", "duplicateName": "名称重复" + }, + "saveForm": { + "name": "名称", + "folder": "目录", + "root": "根目录", + "title": "数据源" } }, "schedule": { -- Gitee From f92695b65e5d79337f3b31a05cb2fe11344e04ef Mon Sep 17 00:00:00 2001 From: tianlei Date: Tue, 23 Aug 2022 17:04:54 +0800 Subject: [PATCH 086/103] feat:(Source) add source expanded --- .../pages/SourcePage/Sidebar/SourceList.tsx | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/SourceList.tsx b/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/SourceList.tsx index 2ddd5e05..4b9d8410 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/SourceList.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/SourceList.tsx @@ -31,7 +31,7 @@ import { selectPermissionMap, } from 'app/pages/MainPage/slice/selectors'; import { CommonFormTypes } from 'globalConstants'; -import { memo, useCallback, useContext, useEffect } from 'react'; +import { memo, useCallback, useContext, useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router'; import { errorHandle, onDropTreeFn, stopPPG, uuidv4 } from 'utils/utils'; @@ -64,6 +64,7 @@ export const SourceList = memo(({ sourceId, list }: SourceListProps) => { const { showSaveForm } = useContext(SaveFormContext); const isOwner = useSelector(selectIsOrgOwner); const permissionMap = useSelector(selectPermissionMap); + const [expandedKeys, setExpandedKeys] = useState([]); useEffect(() => { dispatch(getSources(orgId)); @@ -260,15 +261,6 @@ export const SourceList = memo(({ sourceId, list }: SourceListProps) => { ], ); - const treeSelect = useCallback( - (_, { node }) => { - if (!node.isFolder && node.id !== sourceId) { - history.push(`/organizations/${orgId}/sources/${node.id}`); - } - }, - [history, orgId, sourceId], - ); - const onDrop = info => { onDropTreeFn({ info, @@ -289,14 +281,36 @@ export const SourceList = memo(({ sourceId, list }: SourceListProps) => { }); }; + const menuSelect = useCallback( + (_, { node }) => { + if (node.type === 'FOLDER') { + if (expandedKeys?.includes(node.key)) { + setExpandedKeys(expandedKeys.filter(k => k !== node.key)); + } else { + setExpandedKeys([node.key].concat(expandedKeys)); + } + } else { + history.push(`/organizations/${orgId}/sources/${node.id}`); + } + }, + [expandedKeys, history, orgId], + ); + + const handleExpandTreeNode = expandedKeys => { + setExpandedKeys(expandedKeys); + }; + return ( ); }); -- Gitee From 929c5f0a07cb3f8f66887da2369261432cf78f33 Mon Sep 17 00:00:00 2001 From: tianlei Date: Thu, 25 Aug 2022 17:43:09 +0800 Subject: [PATCH 087/103] refactor(permission): refactor viz story board and source tree list --- .../Main/PermissionForm/PermissionTable.tsx | 24 +- .../Main/PermissionForm/PrivilegeSetting.tsx | 32 ++- .../Main/PermissionForm/VizPermissionForm.tsx | 58 ++--- .../Main/PermissionForm/index.tsx | 46 +--- .../Main/PermissionForm/utils.ts | 24 +- .../pages/PermissionPage/constants.ts | 11 + .../pages/PermissionPage/slice/index.tsx | 24 +- .../MainPage/pages/PermissionPage/utils.ts | 22 +- .../pages/SourcePage/Sidebar/Recycle.tsx | 29 +-- .../pages/SourcePage/Sidebar/index.tsx | 3 - .../pages/ViewPage/Sidebar/Recycle.tsx | 29 +-- .../MainPage/pages/ViewPage/Sidebar/index.tsx | 3 - .../pages/MainPage/pages/VizPage/SaveForm.tsx | 35 ++- .../pages/VizPage/Sidebar/Folders/index.tsx | 33 ++- .../pages/VizPage/Sidebar/Recycle.tsx | 175 +++++--------- .../VizPage/Sidebar/Storyboards/List.tsx | 219 +++++++++++------- .../VizPage/Sidebar/Storyboards/index.tsx | 150 ++++++++---- .../MainPage/pages/VizPage/slice/index.ts | 52 +++-- .../MainPage/pages/VizPage/slice/selectors.ts | 109 +++++++-- .../MainPage/pages/VizPage/slice/thunks.ts | 60 ++--- .../MainPage/pages/VizPage/slice/types.ts | 53 ++++- frontend/src/locales/en/translation.json | 12 + frontend/src/locales/zh/translation.json | 12 + 23 files changed, 705 insertions(+), 510 deletions(-) diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/PermissionTable.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/PermissionTable.tsx index da1f01bd..58e71fc2 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/PermissionTable.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/PermissionTable.tsx @@ -28,6 +28,7 @@ import { ResourceTypes, SubjectTypes, Viewpoints, + VizResourceSubTypes, } from '../../constants'; import { DataSourceTreeNode, @@ -41,6 +42,7 @@ interface PermissionTableProps { viewpoint: Viewpoints; viewpointType: ResourceTypes | SubjectTypes; dataSourceType: ResourceTypes | SubjectTypes; + vizSubTypes?: VizResourceSubTypes; dataSource: DataSourceViewModel[] | undefined; resourceLoading: boolean; privileges: Privilege[] | undefined; @@ -63,6 +65,7 @@ export const PermissionTable = memo( resourceLoading, privileges, onPrivilegeChange, + vizSubTypes, }: PermissionTableProps) => { const t = useI18NPrefix('permission'); @@ -79,11 +82,19 @@ export const PermissionTable = memo( viewpoint, viewpointType, dataSourceType, + vizSubTypes, ); } else { return []; } - }, [viewpoint, viewpointType, dataSourceType, dataSource, privileges]); + }, [ + viewpoint, + viewpointType, + dataSourceType, + dataSource, + privileges, + vizSubTypes, + ]); const { filteredData, @@ -122,6 +133,7 @@ export const PermissionTable = memo( viewpoint, viewpointType, dataSourceType, + vizSubTypes, ), render: (_, record) => ( ), }, ]; return columns; - }, [viewpoint, viewpointType, dataSourceType, privilegeChange, t]); + }, [ + viewpoint, + viewpointType, + dataSourceType, + privilegeChange, + t, + vizSubTypes, + ]); return ( <> diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/PrivilegeSetting.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/PrivilegeSetting.tsx index 07a8d842..413bff0c 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/PrivilegeSetting.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/PrivilegeSetting.tsx @@ -25,6 +25,7 @@ import { RESOURCE_TYPE_PERMISSION_MAPPING, SubjectTypes, Viewpoints, + VizResourceSubTypes, } from '../../constants'; import { DataSourceTreeNode } from '../../slice/types'; import { getDefaultPermissionArray } from '../../utils'; @@ -35,6 +36,7 @@ interface PrivilegeSettingProps { viewpoint: Viewpoints; viewpointType: ResourceTypes | SubjectTypes; dataSourceType: ResourceTypes | SubjectTypes; + vizSubTypes?: VizResourceSubTypes; onChange: ( record: DataSourceTreeNode, newPermissionArray: PermissionLevels[], @@ -49,10 +51,11 @@ export const PrivilegeSetting = memo( viewpoint, viewpointType, dataSourceType, + vizSubTypes, onChange, }: PrivilegeSettingProps) => { const [values, setValues] = useState( - getDefaultPermissionArray(), + getDefaultPermissionArray(vizSubTypes), ); const t = useI18NPrefix('permission'); @@ -78,18 +81,25 @@ export const PrivilegeSetting = memo( useEffect(() => { setValues(record.permissionArray); }, [record]); - return ( - {RESOURCE_TYPE_PERMISSION_MAPPING[resourceType!].map((level, index) => ( - - {t(`privilegeLabel.${resourceType!.toLowerCase()}.${index}`)} - - ))} + {RESOURCE_TYPE_PERMISSION_MAPPING[ + resourceType! + (vizSubTypes || '') + ].map((level, index) => { + return ( + + {t( + `privilegeLabel.${( + resourceType! + (vizSubTypes || '') + ).toLowerCase()}.${index}`, + )} + + ); + })} ); }, diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/VizPermissionForm.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/VizPermissionForm.tsx index a73d9688..a02096a9 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/VizPermissionForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/VizPermissionForm.tsx @@ -80,7 +80,9 @@ export const VizPermissionForm = memo( storyboardListLoading, permissionLoading, }: PermissionFormProps) => { - const [vizType, setVizType] = useState<'folder' | 'persentation'>('folder'); + const [vizType, setVizType] = useState( + VizResourceSubTypes.Folder, + ); const dispatch = useDispatch(); const selectPrivileges = useMemo(makeSelectPrivileges, []); const privileges = useSelector(state => @@ -101,6 +103,7 @@ export const VizPermissionForm = memo( viewpoint, viewpointType, dataSourceType, + vizType, ); } else { return []; @@ -112,24 +115,21 @@ export const VizPermissionForm = memo( folders, storyboards, privileges, + vizType, ]); const vizTypeChange = useCallback(e => { setVizType(e.target.value); }, []); - const { moduleEnabled, storyboardCreateEnabled } = useMemo(() => { + const { moduleEnabled } = useMemo(() => { let moduleEnabled = PermissionLevels.Disable; - let storyboardCreateEnabled = PermissionLevels.Disable; privileges?.forEach(({ resourceId, permission }) => { if (resourceId === '*') { moduleEnabled = permission; } - if (resourceId === VizResourceSubTypes.Storyboard) { - storyboardCreateEnabled = permission; - } }); - return { moduleEnabled, storyboardCreateEnabled }; + return { moduleEnabled }; }, [privileges]); const independentPermissionChange = useCallback( @@ -306,28 +306,6 @@ export const VizPermissionForm = memo( ], [t], ); - const createPermissionValues = useMemo( - () => [ - { - text: t( - `createPermissionLabel.${ - PermissionLevels[PermissionLevels.Disable] - }`, - ), - value: PermissionLevels.Disable, - }, - { - text: t( - `createPermissionLabel.${ - PermissionLevels[PermissionLevels.Create] - }`, - ), - value: PermissionLevels.Create, - }, - ], - [t], - ); - return ( @@ -345,8 +323,10 @@ export const VizPermissionForm = memo( /> - {t('folder')} - {t('presentation')} + {t('folder')} + + {t('presentation')} + - {vizType === 'persentation' && ( - - )} { + const { moduleEnabled } = useMemo(() => { let moduleEnabled = PermissionLevels.Disable; - let createEnabled = PermissionLevels.Disable; privileges?.forEach(({ resourceId, permission }) => { if (resourceId === '*') { moduleEnabled = permission; } - if (resourceId === dataSourceType) { - createEnabled = permission; - } }); - return { moduleEnabled, createEnabled }; - }, [privileges, dataSourceType]); + return { moduleEnabled }; + }, [privileges]); const independentPermissionChange = useCallback( resourceId => e => { @@ -267,27 +263,6 @@ export const PermissionForm = memo( ], [t], ); - const createPermissionValues = useMemo( - () => [ - { - text: t( - `createPermissionLabel.${ - PermissionLevels[PermissionLevels.Disable] - }`, - ), - value: PermissionLevels.Disable, - }, - { - text: t( - `createPermissionLabel.${ - PermissionLevels[PermissionLevels.Create] - }`, - ), - value: PermissionLevels.Create, - }, - ], - [t], - ); return ( @@ -306,21 +281,6 @@ export const PermissionForm = memo( onChange={independentPermissionChange('*')} /> )} - {viewpoint === Viewpoints.Subject && - ![ - ResourceTypes.Viz, - ResourceTypes.View, - ResourceTypes.Schedule, - ].includes(dataSourceType as ResourceTypes) && ( - - )} { - if ((permission & (p as PermissionLevels)) === p) { - permissionViewModel.push(p); - } else { - permissionViewModel.push(PermissionLevels.Disable); - } - }); + RESOURCE_TYPE_PERMISSION_MAPPING[resourceType + (vizSubTypes || '')].forEach( + p => { + if ((permission & (p as PermissionLevels)) === p) { + permissionViewModel.push(p); + } else { + permissionViewModel.push(PermissionLevels.Disable); + } + }, + ); return permissionViewModel; } @@ -267,9 +273,13 @@ export function getPrivilegeSettingWidth( viewpoint: Viewpoints, viewpointType: SubjectTypes | ResourceTypes, dataSourceType: SubjectTypes | ResourceTypes, + vizSubTypes?: VizResourceSubTypes, ) { switch (getPrivilegeSettingType(viewpoint, viewpointType, dataSourceType)) { case ResourceTypes.Viz: + if (vizSubTypes === VizResourceSubTypes.Storyboard) { + return 3 * 80 + 40; + } return 4 * 80 + 40; case ResourceTypes.Schedule: return 1 * 80 + 40; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/constants.ts b/frontend/src/app/pages/MainPage/pages/PermissionPage/constants.ts index 058026a7..9a03faf3 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/constants.ts +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/constants.ts @@ -62,6 +62,17 @@ export const RESOURCE_TYPE_PERMISSION_MAPPING = { PermissionLevels.Share, PermissionLevels.Create, ], + [ResourceTypes.Viz + VizResourceSubTypes.Folder]: [ + PermissionLevels.Read, + PermissionLevels.Download, + PermissionLevels.Share, + PermissionLevels.Create, + ], + [ResourceTypes.Viz + VizResourceSubTypes.Storyboard]: [ + PermissionLevels.Read, + PermissionLevels.Share, + PermissionLevels.Create, + ], [ResourceTypes.View]: [PermissionLevels.Read, PermissionLevels.Create], [ResourceTypes.Source]: [PermissionLevels.Read, PermissionLevels.Create], [ResourceTypes.Schedule]: [PermissionLevels.Create], diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/index.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/index.tsx index cdb264e5..b5443b3e 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/index.tsx @@ -215,16 +215,22 @@ const slice = createSlice({ state.storyboardListLoading = true; }); builder.addCase(getStoryboards.fulfilled, (state, action) => { + const root = generateRootNode( + ResourceTypes.Viz, + VizResourceSubTypes.Storyboard, + ); state.storyboardListLoading = false; - state.storyboards = action.payload.map(({ id, name }) => ({ - id, - name, - type: ResourceTypes.Viz, - parentId: null, - index: null, - isFolder: false, - permissionArray: getDefaultPermissionArray(), - })); + state.storyboards = [root].concat( + action.payload.map(({ id, name, parentId, index, isFolder }) => ({ + id, + name, + type: root.type, + parentId: parentId === null ? root.id : parentId, + index, + isFolder, + permissionArray: getDefaultPermissionArray(), + })), + ); }); builder.addCase(getStoryboards.rejected, state => { state.storyboardListLoading = false; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/utils.ts b/frontend/src/app/pages/MainPage/pages/PermissionPage/utils.ts index d3ca0331..6ab6549b 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/utils.ts +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/utils.ts @@ -25,13 +25,19 @@ import { } from './constants'; import { DataSourceViewModel } from './slice/types'; -export function getDefaultPermissionArray() { - return [ - PermissionLevels.Disable, - PermissionLevels.Disable, - PermissionLevels.Disable, - PermissionLevels.Disable, - ]; +export function getDefaultPermissionArray(vizSubTypes?: VizResourceSubTypes) { + return vizSubTypes !== VizResourceSubTypes.Storyboard + ? [ + PermissionLevels.Disable, + PermissionLevels.Disable, + PermissionLevels.Disable, + PermissionLevels.Disable, + ] + : [ + PermissionLevels.Disable, + PermissionLevels.Disable, + PermissionLevels.Disable, + ]; } export function generateRootNode( @@ -45,7 +51,7 @@ export function generateRootNode( parentId: null, index: null, isFolder: true, - permissionArray: getDefaultPermissionArray(), + permissionArray: getDefaultPermissionArray(vizId), }; } diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/Recycle.tsx b/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/Recycle.tsx index b5abeb19..eb908c58 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/Recycle.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/Recycle.tsx @@ -27,18 +27,12 @@ import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { selectIsOrgOwner, selectOrgId, - selectPermissionMap, } from 'app/pages/MainPage/slice/selectors'; import { CommonFormTypes } from 'globalConstants'; import { memo, useCallback, useContext, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router'; -import { getInsertedNodeIndex, getPath, stopPPG } from 'utils/utils'; -import { getCascadeAccess } from '../../../Access'; -import { - PermissionLevels, - ResourceTypes, -} from '../../PermissionPage/constants'; +import { getInsertedNodeIndex, stopPPG } from 'utils/utils'; import { SaveFormContext } from '../SaveFormContext'; import { selectArchivedListLoading } from '../slice/selectors'; import { @@ -65,7 +59,6 @@ export const Recycle = memo(({ sourceId, list }: RecycleProps) => { const t = useI18NPrefix('source.sidebar'); const { showSaveForm } = useContext(SaveFormContext); const isOwner = useSelector(selectIsOrgOwner); - const permissionMap = useSelector(selectPermissionMap); useEffect(() => { dispatch(getArchivedSources(orgId)); @@ -144,25 +137,11 @@ export const Recycle = memo(({ sourceId, list }: RecycleProps) => { ); const renderTreeTitle = useCallback( - ({ key, title, parentId }) => { - const path = list - ? getPath( - list as Array<{ id: string; parentId: string }>, - { id: key, parentId }, - ResourceTypes.Schedule, - ) - : []; - const allowManage = getCascadeAccess( - isOwner, - permissionMap, - ResourceTypes.Schedule, - path, - PermissionLevels.Manage, - ); + ({ key, title }) => { return (

{`${title}`}

- {allowManage && ( + {isOwner && ( {
); }, - [list, isOwner, permissionMap, moreMenuClick, t, del], + [isOwner, moreMenuClick, t, del], ); return ( diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/index.tsx b/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/index.tsx index 54d6fd2d..dde92a59 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/index.tsx @@ -17,10 +17,8 @@ */ import { DeleteOutlined, - FileOutlined, FolderFilled, FolderOpenFilled, - FolderOutlined, } from '@ant-design/icons'; import { message } from 'antd'; import { ListNav, ListPane, ListTitle } from 'app/components'; @@ -95,7 +93,6 @@ export const Sidebar = memo(() => { key: id, title: name, parentId, - icon: isFolder ? : , isFolder, disabled: deleteLoading, })), diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/Recycle.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/Recycle.tsx index a6a427ad..590e7885 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/Recycle.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/Recycle.tsx @@ -24,21 +24,15 @@ import { import { Menu, message, Popconfirm, TreeDataNode } from 'antd'; import { MenuListItem, Popup, Tree, TreeTitle } from 'app/components'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; -import { getCascadeAccess } from 'app/pages/MainPage/Access'; import { selectIsOrgOwner, selectOrgId, - selectPermissionMap, } from 'app/pages/MainPage/slice/selectors'; import { CommonFormTypes } from 'globalConstants'; import { memo, useCallback, useContext, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; -import { getInsertedNodeIndex, getPath, stopPPG } from 'utils/utils'; -import { - PermissionLevels, - ResourceTypes, -} from '../../PermissionPage/constants'; +import { getInsertedNodeIndex, stopPPG } from 'utils/utils'; import { SaveFormContext } from '../SaveFormContext'; import { selectArchivedListLoading, @@ -65,7 +59,6 @@ export const Recycle = memo(({ list }: RecycleProps) => { const currentEditingViewKey = useSelector(selectCurrentEditingViewKey); const views = useSelector(selectViews); const isOwner = useSelector(selectIsOrgOwner); - const permissionMap = useSelector(selectPermissionMap); const t = useI18NPrefix('view.saveForm'); const tg = useI18NPrefix('global'); @@ -137,25 +130,11 @@ export const Recycle = memo(({ list }: RecycleProps) => { ); const renderTreeTitle = useCallback( - ({ key, title, parentId }) => { - const path = views - ? getPath( - views as Array<{ id: string; parentId: string }>, - { id: key, parentId }, - ResourceTypes.View, - ) - : []; - const allowManage = getCascadeAccess( - isOwner, - permissionMap, - ResourceTypes.View, - path, - PermissionLevels.Manage, - ); + ({ key, title }) => { return (

{`${title}`}

- {allowManage && ( + {isOwner && ( {
); }, - [moreMenuClick, del, views, isOwner, permissionMap, tg], + [moreMenuClick, del, isOwner, tg], ); const treeSelect = useCallback( diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/index.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/index.tsx index f0f76be3..ec2b2f51 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/index.tsx @@ -19,10 +19,8 @@ import { CodeFilled, DeleteOutlined, - FileOutlined, FolderFilled, FolderOpenFilled, - FolderOutlined, MenuFoldOutlined, MenuUnfoldOutlined, } from '@ant-design/icons'; @@ -95,7 +93,6 @@ export const Sidebar = memo( key: id, title: name, parentId, - icon: isFolder ? : , isFolder, disabled: deleteLoading, })), diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx index 1a5542fb..8159ab58 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx @@ -12,6 +12,7 @@ import { import { useCallback, useContext, useEffect, useMemo, useRef } from 'react'; import { useSelector } from 'react-redux'; import styled from 'styled-components/macro'; +import { APP_CURRENT_VERSION } from '../../../../migration/constants'; import { getCascadeAccess } from '../../Access'; import { selectIsOrgOwner, @@ -22,6 +23,7 @@ import { PermissionLevels, ResourceTypes } from '../PermissionPage/constants'; import { FileUpload } from '../ResourceMigrationPage/FileUpload'; import { SaveFormContext } from './SaveFormContext'; import { + makeSelectStoryboradFolderTree, makeSelectVizFolderTree, selectSaveFolderLoading, selectSaveStoryboardLoading, @@ -40,6 +42,10 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { onAfterClose, } = useContext(SaveFormContext); const selectVizFolderTree = useMemo(makeSelectVizFolderTree, []); + const selectStoryboradFolderTree = useMemo( + makeSelectStoryboradFolderTree, + [], + ); const saveFolderLoading = useSelector(selectSaveFolderLoading); const saveStoryboardLoading = useSelector(selectSaveStoryboardLoading); const orgId = useSelector(selectOrgId); @@ -61,13 +67,22 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { [isOwner, permissionMap], ); - const treeData = useSelector(state => + const folderTreeData = useSelector(state => selectVizFolderTree(state, { id: initialValues?.id, getDisabled }), ); + const storyboardTreeData = useSelector(state => + selectStoryboradFolderTree(state, { id: initialValues?.id, getDisabled }), + ); const save = useCallback( values => { - onSave(values, onCancel); + onSave( + { + ...values, + config: { version: APP_CURRENT_VERSION, ...values.config }, + }, + onCancel, + ); }, [onSave, onCancel], ); @@ -132,7 +147,7 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { const data = { name: value, orgId, - vizType: 'FOLDER', + vizType, parentId: parentId || null, }; return fetchCheckName('viz', data); @@ -191,7 +206,19 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { { + formRef.current?.validateFields(); + }} + /> + + )} + {vizType === 'STORYBOARD' && ( + + { formRef.current?.validateFields(); diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/index.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/index.tsx index 6af1e23f..3a5405fa 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/index.tsx @@ -18,17 +18,17 @@ import { SPACE_XS } from 'styles/StyleConstants'; import { useAddViz } from '../../hooks/useAddViz'; import { SaveFormContext } from '../../SaveFormContext'; import { + makeSelectArchivedDashboardsTree, + makeSelectArchivedDatachartsTree, makeSelectVizTree, selectArchivedDashboardLoading, - selectArchivedDashboards, selectArchivedDatachartLoading, - selectArchivedDatacharts, } from '../../slice/selectors'; import { getArchivedDashboards, getArchivedDatacharts, } from '../../slice/thunks'; -import { FolderViewModel } from '../../slice/types'; +import { ArchivedViz, FolderViewModel } from '../../slice/types'; import { Recycle } from '../Recycle'; import { FolderTree } from './FolderTree'; @@ -70,8 +70,27 @@ export const Folders = memo( useDebouncedSearch(treeData, (keywords, d) => d.title.toLowerCase().includes(keywords.toLowerCase()), ); - const archivedDatacharts = useSelector(selectArchivedDatacharts); - const archivedDashboards = useSelector(selectArchivedDashboards); + + const selectArchivedDatachartsTree = useMemo( + makeSelectArchivedDatachartsTree, + [], + ); + const selectArchivedDashboardsTree = useMemo( + makeSelectArchivedDashboardsTree, + [], + ); + + const getArchivedDisabled = useCallback( + ({ deleteLoading }: ArchivedViz) => deleteLoading, + [], + ); + + const archivedDatachartsTreeData = useSelector(state => + selectArchivedDatachartsTree(state, { getDisabled: getArchivedDisabled }), + ); + const archivedDashboardsTreeData = useSelector(state => + selectArchivedDashboardsTree(state, { getDisabled: getArchivedDisabled }), + ); const archivedDataChartLoading = useSelector( selectArchivedDatachartLoading, ); @@ -80,8 +99,8 @@ export const Folders = memo( ); const { filteredData: filteredListData, debouncedSearch: listSearch } = useDebouncedSearch( - archivedDatacharts.concat(archivedDashboards), - (keywords, d) => d.name.toLowerCase().includes(keywords.toLowerCase()), + (archivedDatachartsTreeData || []).concat(archivedDashboardsTreeData), + (keywords, d) => d.title.toLowerCase().includes(keywords.toLowerCase()), ); const recycleInit = useCallback(() => { diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Recycle.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Recycle.tsx index 4f8674a3..883b8315 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Recycle.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Recycle.tsx @@ -1,39 +1,26 @@ import { DeleteOutlined, - LoadingOutlined, MoreOutlined, ReloadOutlined, } from '@ant-design/icons'; -import { Button, List, Menu, message, Popconfirm } from 'antd'; -import { ListItem, MenuListItem, Popup } from 'app/components'; +import { Menu, message, Popconfirm, TreeDataNode } from 'antd'; +import { MenuListItem, Popup, Tree, TreeTitle } from 'app/components'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; -import { calcAc, getCascadeAccess } from 'app/pages/MainPage/Access'; -import { - selectIsOrgOwner, - selectPermissionMap, -} from 'app/pages/MainPage/slice/selectors'; -import classnames from 'classnames'; +import { selectIsOrgOwner } from 'app/pages/MainPage/slice/selectors'; import { CommonFormTypes } from 'globalConstants'; import { memo, useCallback, useContext, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; -import styled from 'styled-components/macro'; -import { getInsertedNodeIndex, getPath, stopPPG } from 'utils/utils'; -import { - PermissionLevels, - ResourceTypes, - VizResourceSubTypes, -} from '../../PermissionPage/constants'; +import { getInsertedNodeIndex, stopPPG } from 'utils/utils'; import { SaveFormContext } from '../SaveFormContext'; import { selectVizs } from '../slice/selectors'; import { deleteViz, removeTab, unarchiveViz } from '../slice/thunks'; -import { ArchivedViz } from '../slice/types'; interface RecycleProps { type: 'viz' | 'storyboard'; orgId: string; selectedId?: string; - list?: ArchivedViz[]; + list?: TreeDataNode[]; listLoading: boolean; onInit: () => void; } @@ -45,7 +32,6 @@ export const Recycle = memo( const { showSaveForm } = useContext(SaveFormContext); const vizs = useSelector(selectVizs); const isOwner = useSelector(selectIsOrgOwner); - const permissionMap = useSelector(selectPermissionMap); const tg = useI18NPrefix('global'); useEffect(() => { @@ -120,105 +106,68 @@ export const Recycle = memo( [dispatch, showSaveForm, redirect, vizs, tg], ); - const toDetail = useCallback( - id => () => { - history.push(`/organizations/${orgId}/vizs/${id}`); + const treeSelect = useCallback( + (_, { node }) => { + if (node.id !== selectedId) { + history.push(`/organizations/${orgId}/vizs/${node.id}`); + } }, - [history, orgId], + [history, orgId, selectedId], ); - return ( - - }} - renderItem={({ id, name, vizType, loading }) => { - let allowManage = false; - if (type === 'viz') { - const viz = vizs.find(v => v.id === id); - const path = viz - ? getPath( - vizs as Array<{ id: string; parentId: string }>, - { id, parentId: viz.parentId }, - VizResourceSubTypes.Folder, - ) - : [id]; - allowManage = getCascadeAccess( - isOwner, - permissionMap, - ResourceTypes.View, - path, - PermissionLevels.Manage, - ); - } else { - allowManage = !!calcAc( - isOwner, - permissionMap, - ResourceTypes.Viz, - PermissionLevels.Manage, - id, - ); - } - return ( - - } - > - {tg('button.restore')} - - } - > - - {tg('button.delete')} - - - - } + const renderTreeTitle = useCallback( + ({ key, title, vizType }) => { + return ( + +

{`${title}`}

+ {isOwner && ( + + } + > + {tg('button.restore')} + + } > - - - - - + + + + + ) : ( + <> + ) ) : ( <> )} - ) : ( + ) : isOwner ? ( <>
+ ) : ( + <> ) } /> -- Gitee From 6737fea0f6a20595e410136551f2d849bd0da20e Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 9 Sep 2022 11:17:09 +0800 Subject: [PATCH 100/103] fix: should keep global controller filter when cancel link, issue #1980 --- .../pages/DashBoardPage/actions/widgetAction.ts | 9 ++++----- .../DashBoardPage/pages/Board/slice/thunk.ts | 5 ++++- .../DashBoardPage/pages/Board/slice/types.ts | 1 + .../pages/BoardEditor/slice/actions/actions.ts | 16 ++++++++++++---- .../pages/BoardEditor/slice/thunk.ts | 14 ++++++++++++-- 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/actions/widgetAction.ts b/frontend/src/app/pages/DashBoardPage/actions/widgetAction.ts index 8450a469..e3ab79b9 100644 --- a/frontend/src/app/pages/DashBoardPage/actions/widgetAction.ts +++ b/frontend/src/app/pages/DashBoardPage/actions/widgetAction.ts @@ -304,11 +304,10 @@ export const widgetLinkEventAction = sourceWidgetId: widget.id, widgetId: targetWidget.id, option: widgetInfo, - extraFilters: isUnSelectedAll - ? controllerFilters || [] - : (clickFilters || []) - .concat(controllerFilters || []) - .concat(sourceLinkAndControllerFilterByRule || []), + extraFilters: controllerFilters, + tempFilters: isUnSelectedAll + ? [] + : (clickFilters || []).concat(sourceLinkAndControllerFilterByRule), variableParams: isUnSelectedAll ? variableParams || {} : Object.assign( diff --git a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/thunk.ts b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/thunk.ts index b04f7a78..a434bd9d 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/thunk.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/thunk.ts @@ -224,6 +224,7 @@ export const syncBoardWidgetChartDataAsync = createAsyncThunk< widgetId: string; option?: getDataOption; extraFilters?: PendingChartDataRequestFilter[]; + tempFilters?: PendingChartDataRequestFilter[]; variableParams?: Record; } & { executeToken?: any; @@ -238,6 +239,7 @@ export const syncBoardWidgetChartDataAsync = createAsyncThunk< widgetId, option, extraFilters, + tempFilters, variableParams, executeToken, }, @@ -273,7 +275,7 @@ export const syncBoardWidgetChartDataAsync = createAsyncThunk< ) .addVariableParams(variableParams) .addExtraSorters(option?.sorters as any[]) - .addRuntimeFilters(extraFilters) + .addRuntimeFilters((extraFilters || []).concat(tempFilters || [])) .addDrillOption(drillOption) .build(); @@ -295,6 +297,7 @@ export const syncBoardWidgetChartDataAsync = createAsyncThunk< linkInfo: { sourceWidgetId, filters: extraFilters, + tempFilters: tempFilters, variables: variableParams, }, }), diff --git a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/types.ts b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/types.ts index a12692dc..c1a8fa7f 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/types.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/types.ts @@ -445,5 +445,6 @@ export type WidgetErrorType = 'request' | 'interaction'; export type WidgetLinkInfo = { sourceWidgetId?: string; filters?: PendingChartDataRequestFilter[]; + tempFilters?: PendingChartDataRequestFilter[]; variables?: Record; }; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/actions/actions.ts b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/actions/actions.ts index 5e36f5c5..4c3c5402 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/actions/actions.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/actions/actions.ts @@ -438,13 +438,17 @@ export const widgetClearLinkageAction = const linkTargetWidgets = Object.values(boardWidgetInfoRecord || {}).filter( widgetInfo => widgetInfo?.linkInfo?.sourceWidgetId === id, ); - linkTargetWidgets.forEach(targetWidget => { + linkTargetWidgets.forEach(widgetInfo => { + const filters = widgetInfo?.linkInfo?.filters || []; + const variables = widgetInfo?.linkInfo?.variables; dispatch( syncBoardWidgetChartDataAsync({ boardId: dashboardId, sourceWidgetId: '', - widgetId: targetWidget.id, + widgetId: widgetInfo.id, executeToken, + extraFilters: filters, + variableParams: variables, }), ); }); @@ -475,12 +479,16 @@ export const editorWidgetClearLinkageAction = const linkTargetWidgets = Object.values(boardWidgetInfoRecord || {}).filter( widgetInfo => widgetInfo?.linkInfo?.sourceWidgetId === id, ); - linkTargetWidgets.forEach(targetWidget => { + linkTargetWidgets.forEach(widgetInfo => { + const filters = widgetInfo?.linkInfo?.filters || []; + const variables = widgetInfo?.linkInfo?.variables; dispatch( syncEditBoardWidgetChartDataAsync({ boardId: dashboardId, sourceWidgetId: '', - widgetId: targetWidget.id, + widgetId: widgetInfo.id, + extraFilters: filters, + variableParams: variables, }), ); }); diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts index 6d5565fd..5f7dbecc 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts @@ -452,13 +452,22 @@ export const syncEditBoardWidgetChartDataAsync = createAsyncThunk< widgetId: string; option?: getDataOption; extraFilters?: PendingChartDataRequestFilter[]; + tempFilters?: PendingChartDataRequestFilter[]; variableParams?: Record; }, { state: RootState } >( 'board/syncEditBoardWidgetChartDataAsync', async ( - { boardId, sourceWidgetId, widgetId, option, extraFilters, variableParams }, + { + boardId, + sourceWidgetId, + widgetId, + option, + extraFilters, + tempFilters, + variableParams, + }, { getState, dispatch }, ) => { const boardState = getState() as { board: BoardState }; @@ -492,7 +501,7 @@ export const syncEditBoardWidgetChartDataAsync = createAsyncThunk< ) .addVariableParams(variableParams) .addExtraSorters(option?.sorters as any[]) - .addRuntimeFilters(extraFilters) + .addRuntimeFilters((extraFilters || []).concat(tempFilters || [])) .addDrillOption(drillOption) .build(); @@ -536,6 +545,7 @@ export const syncEditBoardWidgetChartDataAsync = createAsyncThunk< linkInfo: { sourceWidgetId, filters: extraFilters, + tempFilters: tempFilters, variables: variableParams, }, }), -- Gitee From bc2bd4807978d9928eb5ca22885ded0697bdcd81 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 9 Sep 2022 12:21:46 +0800 Subject: [PATCH 101/103] fix: fix paging event triggger other events, issue #1986 --- .../DashBoardPage/actions/widgetAction.ts | 23 +------------------ .../DataChartWidget/DataChartWidgetCore.tsx | 10 +++++++- .../ChartPreview/ChartPreviewBoard.tsx | 23 ++++++++++++------- .../Chart/ChartPreviewBoardForShare.tsx | 22 ++++++++++-------- 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/actions/widgetAction.ts b/frontend/src/app/pages/DashBoardPage/actions/widgetAction.ts index e3ab79b9..4769db87 100644 --- a/frontend/src/app/pages/DashBoardPage/actions/widgetAction.ts +++ b/frontend/src/app/pages/DashBoardPage/actions/widgetAction.ts @@ -445,34 +445,13 @@ export const widgetChartClickAction = history: any; }) => dispatch => { - const { boardId, editing, renderMode, widget, params, history } = obj; + const { boardId, editing, renderMode, widget, params } = obj; //is tableChart tablePagingAndSortEventListener(params, p => { dispatch( tableChartClickAction(boardId, editing, renderMode, widget, params), ); }); - // jump - const jumpConfig = widget.config?.jumpConfig; - if (jumpConfig && jumpConfig.open) { - dispatch( - widgetClickJumpAction({ - renderMode, - widget, - params, - history, - }), - ); - return; - } - // linkage - const linkageConfig = widget.config.linkageConfig; - if (linkageConfig?.open && widget.relations.length) { - dispatch( - widgetClickLinkageAction(boardId, editing, renderMode, widget, params), - ); - return; - } }; export const widgetLinkEventActionCreator = diff --git a/frontend/src/app/pages/DashBoardPage/components/Widgets/DataChartWidget/DataChartWidgetCore.tsx b/frontend/src/app/pages/DashBoardPage/components/Widgets/DataChartWidget/DataChartWidgetCore.tsx index 0d97e53a..80e10c27 100644 --- a/frontend/src/app/pages/DashBoardPage/components/Widgets/DataChartWidget/DataChartWidgetCore.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/Widgets/DataChartWidget/DataChartWidgetCore.tsx @@ -23,6 +23,7 @@ import { InteractionMouseEvent } from 'app/components/FormGenerator/constants'; import { ChartDataSectionType, ChartDataViewFieldCategory, + ChartInteractionEvent, } from 'app/constants'; import ChartDrillContext from 'app/contexts/ChartDrillContext'; import { useCacheWidthHeight } from 'app/hooks/useCacheWidthHeight'; @@ -455,6 +456,14 @@ export const DataChartWidgetCore: React.FC<{}> = memo(() => { if (!params) { return; } + + if ( + params?.interactionType === ChartInteractionEvent.PagingOrSort + ) { + onWidgetChartClick(widgetRef.current, params); + return; + } + handleDrillThroughEvent( buildDrillThroughEventParams( params, @@ -481,7 +490,6 @@ export const DataChartWidgetCore: React.FC<{}> = memo(() => { chartSelectionEventListener(params, p => { changeSelectedItems(dispatch, renderMode, p, wid); }); - onWidgetChartClick(widgetRef.current, params); }, }, { diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreviewBoard.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreviewBoard.tsx index 257c13dd..0a6bd31c 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreviewBoard.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreviewBoard.tsx @@ -23,6 +23,7 @@ import ChartDrillPaths from 'app/components/ChartDrill/ChartDrillPaths'; import { ChartIFrameContainer } from 'app/components/ChartIFrameContainer'; import { InteractionMouseEvent } from 'app/components/FormGenerator/constants'; import { VizHeader } from 'app/components/VizHeader'; +import { ChartInteractionEvent } from 'app/constants'; import ChartDrillContext from 'app/contexts/ChartDrillContext'; import { useCacheWidthHeight } from 'app/hooks/useCacheWidthHeight'; import useChartInteractions from 'app/hooks/useChartInteractions'; @@ -384,6 +385,20 @@ const ChartPreviewBoard: FC<{ { name: 'click', callback: param => { + if ( + param?.interactionType === ChartInteractionEvent.PagingOrSort + ) { + tablePagingAndSortEventListener(param, p => { + dispatch( + fetchDataSetByPreviewChartAction({ + ...p, + backendChartId, + }), + ); + }); + return; + } + handleDrillThroughEvent( buildDrillThroughEventParams(param, InteractionMouseEvent.Left), ); @@ -394,14 +409,6 @@ const ChartPreviewBoard: FC<{ drillOptionRef.current = p; handleDrillOptionChange?.(p); }); - tablePagingAndSortEventListener(param, p => { - dispatch( - fetchDataSetByPreviewChartAction({ - ...p, - backendChartId, - }), - ); - }); pivotTableDrillEventListener(param, p => { handleDrillOptionChange(p); }); diff --git a/frontend/src/app/pages/SharePage/Chart/ChartPreviewBoardForShare.tsx b/frontend/src/app/pages/SharePage/Chart/ChartPreviewBoardForShare.tsx index fb287f6f..03aec2bb 100644 --- a/frontend/src/app/pages/SharePage/Chart/ChartPreviewBoardForShare.tsx +++ b/frontend/src/app/pages/SharePage/Chart/ChartPreviewBoardForShare.tsx @@ -21,6 +21,7 @@ import ChartDrillContextMenu from 'app/components/ChartDrill/ChartDrillContextMe import ChartDrillPaths from 'app/components/ChartDrill/ChartDrillPaths'; import { ChartIFrameContainer } from 'app/components/ChartIFrameContainer'; import { InteractionMouseEvent } from 'app/components/FormGenerator/constants'; +import { ChartInteractionEvent } from 'app/constants'; import useChartInteractions from 'app/hooks/useChartInteractions'; import useDebouncedLoadingStatus from 'app/hooks/useDebouncedLoadingStatus'; import useMount from 'app/hooks/useMount'; @@ -278,6 +279,18 @@ const ChartPreviewBoardForShare: FC<{ { name: 'click', callback: param => { + if (param?.interactionType === ChartInteractionEvent.PagingOrSort) { + tablePagingAndSortEventListener(param, p => { + dispatch( + fetchShareDataSetByPreviewChartAction({ + ...p, + preview: chartPreview!, + filterSearchParams, + }), + ); + }); + return; + } handleDrillThroughEvent( buildDrillThroughEventParams(param, InteractionMouseEvent.Left), ); @@ -288,15 +301,6 @@ const ChartPreviewBoardForShare: FC<{ drillOptionRef.current = p; handleDrillOptionChange?.(p); }); - tablePagingAndSortEventListener(param, p => { - dispatch( - fetchShareDataSetByPreviewChartAction({ - ...p, - preview: chartPreview!, - filterSearchParams, - }), - ); - }); pivotTableDrillEventListener(param, p => { handleDrillOptionChange(p); }); -- Gitee From 0cc5e9a72faf71251471bbbfe0e162148d55b939 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 9 Sep 2022 13:28:18 +0800 Subject: [PATCH 102/103] fix: add runtime filters when table paging, issue #1986 --- frontend/src/app/pages/DashBoardPage/utils/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/pages/DashBoardPage/utils/index.ts b/frontend/src/app/pages/DashBoardPage/utils/index.ts index 553f2263..438d66cb 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/index.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/index.ts @@ -112,9 +112,10 @@ export const getDataChartRequestParams = (obj: { dataChart: DataChart; view: ChartDataView; drillOption?: ChartDrillOption; + tempFilters?: PendingChartDataRequestFilter[]; option; }) => { - const { dataChart, view, option, drillOption } = obj; + const { dataChart, view, option, drillOption, tempFilters } = obj; const migratedChartConfig = migrateChartConfig( CloneValueDeep(dataChart?.config) as ChartDetailConfigDTO, ); @@ -137,6 +138,7 @@ export const getDataChartRequestParams = (obj: { let requestParams = builder .addExtraSorters((option?.sorters as any) || []) .addDrillOption(drillOption) + .addRuntimeFilters(tempFilters || []) .build(); return requestParams; }; @@ -438,6 +440,7 @@ export const getChartWidgetRequestParams = (obj: { view: chartDataView, option: option, drillOption, + tempFilters: widgetInfo?.linkInfo?.tempFilters, }); const { filterParams, variableParams } = getTheWidgetFiltersAndParams({ -- Gitee From 976bbdc7d78f74d7fca6fe2fabfefa020fcb3dac Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 9 Sep 2022 14:31:23 +0800 Subject: [PATCH 103/103] fix: should not invoke drag end event if not drag itself --- .../pages/BoardEditor/FreeEditor/WidgetOfFreeEdit.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/FreeEditor/WidgetOfFreeEdit.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/FreeEditor/WidgetOfFreeEdit.tsx index a79f83ff..e89bb301 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/FreeEditor/WidgetOfFreeEdit.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/FreeEditor/WidgetOfFreeEdit.tsx @@ -80,13 +80,16 @@ export const WidgetOfFreeEdit: React.FC<{}> = () => { [widget.id], ); const moveEnd = useCallback(() => { + if (!selectedIds.includes(widget.id)) { + return; + } const nextRect = { ...widget.config.rect, x: Number(curXY[0].toFixed(1)), y: Number(curXY[1].toFixed(1)), }; onEditFreeWidgetRect(nextRect, widget.id, false); - }, [curXY, onEditFreeWidgetRect, widget.config.rect, widget.id]); + }, [curXY, onEditFreeWidgetRect, selectedIds, widget.config.rect, widget.id]); useEffect(() => { widgetMove.on(move); widgetMoveEnd.on(moveEnd); -- Gitee