From 2f9ff754f716c124b8880bcf728bb388c6652571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=BB=A7=E6=83=B3?= <154263362@qq.com> Date: Sat, 4 Dec 2021 17:14:18 +0800 Subject: [PATCH 001/348] jump_url --- frontend/craco.config.js | 4 ++-- .../BoardEditor/components/SettingJumpModal/index.tsx | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/frontend/craco.config.js b/frontend/craco.config.js index c75f1ce8e..3982fe3e0 100644 --- a/frontend/craco.config.js +++ b/frontend/craco.config.js @@ -146,10 +146,10 @@ module.exports = { hot: true, proxy: { '/api/v1': { - target: 'http://localhost:8080/', + target: 'http://192.168.50.29:8083/', }, '/resources': { - target: 'http://localhost:8080/', + target: 'http://192.168.50.29:8083/', }, }, historyApiFallback: { diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx index 1b31aa7a6..05213f717 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx @@ -150,6 +150,15 @@ export const SettingJumpModal: FC = ({ onCancel={handleClose} >
+ + + Date: Sun, 5 Dec 2021 14:42:21 +0800 Subject: [PATCH 002/348] =?UTF-8?q?=E8=B7=B3=E8=BD=AC=E6=94=AF=E6=8C=81=20?= =?UTF-8?q?URL=20=E8=B7=B3=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WidgetProvider/WidgetMethodProvider.tsx | 14 ++- .../DashBoardPage/pages/Board/slice/types.ts | 3 + .../components/SettingJumpModal/index.tsx | 94 +++++++++++++------ 3 files changed, 80 insertions(+), 31 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx index 0aaf207f3..105183027 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx @@ -299,10 +299,12 @@ export const WidgetMethodProvider: FC<{ widgetId: string }> = ({ (values: { widget: Widget; params: ChartMouseEventParams }) => { const { widget, params } = values; const jumpConfig = widget.config?.jumpConfig; + const targetType = jumpConfig?.targetType || 1; + const httpUrl = jumpConfig?.httpUrl || ''; + const queryName = jumpConfig?.queryName || ''; const targetId = jumpConfig?.target?.relId; const jumpFieldName: string = jumpConfig?.field?.jumpFieldName || ''; - - if (typeof jumpConfig?.filter === 'object') { + if (typeof jumpConfig?.filter === 'object' && targetType === 1) { const searchParamsStr = urlSearchTransfer.toUrlString({ [jumpConfig?.filter?.filterId]: (params?.data?.rowData?.[jumpFieldName] as string) || '', @@ -312,6 +314,14 @@ export const WidgetMethodProvider: FC<{ widgetId: string }> = ({ `/organizations/${orgId}/vizs/${targetId}?${searchParamsStr}`, ); } + } else if (targetType === 2) { + let url; + if (httpUrl.indexOf('?') > -1) { + url = `${httpUrl}&${queryName}=${params?.data?.rowData?.[jumpFieldName]}`; + } else { + url = `${httpUrl}?${queryName}=${params?.data?.rowData?.[jumpFieldName]}`; + } + window.location.href = url; } }, [history, orgId], 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 4a2e17581..8d0aa9081 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/types.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/types.ts @@ -161,6 +161,9 @@ export interface JumpConfigField { } export interface JumpConfig { open: boolean; + targetType: number; + httpUrl: string; + queryName: string; field: JumpConfigField; target: JumpConfigTarget; filter: JumpConfigFilter; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx index 05213f717..e30440869 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx @@ -4,7 +4,7 @@ import { FolderOpenFilled, FundFilled, } from '@ant-design/icons'; -import { Form, Modal, ModalProps } from 'antd'; +import { Form, Input, Modal, ModalProps, Select } from 'antd'; import { BoardContext } from 'app/pages/DashBoardPage/contexts/BoardContext'; import { selectDataChartById } from 'app/pages/DashBoardPage/pages/Board/slice/selector'; import { BoardState } from 'app/pages/DashBoardPage/pages/Board/slice/types'; @@ -33,6 +33,7 @@ const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 18 }, }; +const { Option } = Select; interface SettingJumpModalProps extends ModalProps {} export const SettingJumpModal: FC = ({ children, @@ -88,8 +89,11 @@ export const SettingJumpModal: FC = ({ useEffect(() => { const _jumpConfig = curJumpWidget?.config?.jumpConfig; setVisible(jumpVisible); + setTargetType(_jumpConfig?.targetType || 1); if (jumpVisible && _jumpConfig) { - onGetController(curJumpWidget?.config?.jumpConfig?.target); + if (curJumpWidget?.config?.jumpConfig?.targetType === 1) { + onGetController(curJumpWidget?.config?.jumpConfig?.target); + } form.setFieldsValue(_jumpConfig); } }, [jumpVisible, curJumpWidget, form, onGetController]); @@ -99,6 +103,7 @@ export const SettingJumpModal: FC = ({ const dataChart = useSelector((state: { board: BoardState }) => selectDataChartById(state, curJumpWidget?.datachartId), ); + const [targetType, setTargetType] = useState(1); const chartGroupColumns = useMemo(() => { if (!dataChart) { return []; @@ -114,6 +119,14 @@ export const SettingJumpModal: FC = ({ }, [form, onGetController], ); + const onTargetTypeChange = useCallback( + value => { + setTargetType(value); + form.setFieldsValue({ filter: undefined }); + onGetController(value); + }, + [form, onGetController], + ); const handleClose = useCallback(() => { dispatch( editDashBoardInfoActions.changeJumpPanel({ @@ -152,24 +165,46 @@ export const SettingJumpModal: FC = ({ - - - - + + {targetType === 1 && ( + + + + )} + + {targetType === 2 && ( + + + + )} + {targetType === 2 && ( + + + + )} {chartGroupColumns?.length > 1 && ( = ({ > )} - - - - + {targetType === 1 && ( + + + + )} ); From fb7233a2b40204a981aeb3093f4ab8c59eb2ad15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=BB=A7=E6=83=B3?= <154263362@qq.com> Date: Sun, 5 Dec 2021 15:17:03 +0800 Subject: [PATCH 003/348] =?UTF-8?q?=E4=BF=AE=E6=94=B9lable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/BoardEditor/components/SettingJumpModal/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx index e30440869..f736283e2 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx @@ -191,16 +191,16 @@ export const SettingJumpModal: FC = ({ )} {targetType === 2 && ( From 2b4617d0c70acb1a5a95360a079d5f52d47d78ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=BB=A7=E6=83=B3?= <154263362@qq.com> Date: Sun, 5 Dec 2021 15:37:28 +0800 Subject: [PATCH 004/348] =?UTF-8?q?=E8=BF=98=E5=8E=9F=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/craco.config.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/frontend/craco.config.js b/frontend/craco.config.js index 3982fe3e0..6b1b071fd 100644 --- a/frontend/craco.config.js +++ b/frontend/craco.config.js @@ -3,6 +3,7 @@ const fs = require('fs'); const CracoLessPlugin = require('craco-less'); const WebpackBar = require('webpackbar'); const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); +// const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); const { when, whenDev, @@ -56,7 +57,11 @@ module.exports = { ], webpack: { alias: {}, - plugins: [new WebpackBar(), new MonacoWebpackPlugin({ languages: [''] })], + plugins: [ + new WebpackBar(), + new MonacoWebpackPlugin({ languages: [''] }), + // new BundleAnalyzerPlugin(), + ], configure: (webpackConfig, { env, paths }) => { // paths.appPath='public' // paths.appBuild = 'dist'; // 配合输出打包修改文件目录 @@ -146,10 +151,10 @@ module.exports = { hot: true, proxy: { '/api/v1': { - target: 'http://192.168.50.29:8083/', + target: 'http://localhost:8080/', }, '/resources': { - target: 'http://192.168.50.29:8083/', + target: 'http://localhost:8080/', }, }, historyApiFallback: { From 87c6c3637e649eadabaf05d1ca28df52036144ba Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Tue, 7 Dec 2021 10:48:16 +0800 Subject: [PATCH 005/348] fix: change jump for http url --- .../WidgetProvider/WidgetMethodProvider.tsx | 2 +- .../DashBoardPage/pages/Board/slice/types.ts | 2 +- .../components/SettingJumpModal/config.ts | 22 ++++++++++ .../components/SettingJumpModal/index.tsx | 44 ++++++++++--------- 4 files changed, 48 insertions(+), 22 deletions(-) create mode 100644 frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx index 105183027..cc5554728 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx @@ -314,7 +314,7 @@ export const WidgetMethodProvider: FC<{ widgetId: string }> = ({ `/organizations/${orgId}/vizs/${targetId}?${searchParamsStr}`, ); } - } else if (targetType === 2) { + } else if (targetType === 'HTTP') { let url; if (httpUrl.indexOf('?') > -1) { url = `${httpUrl}&${queryName}=${params?.data?.rowData?.[jumpFieldName]}`; 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 8d0aa9081..0b5ddde0e 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/types.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/types.ts @@ -161,7 +161,7 @@ export interface JumpConfigField { } export interface JumpConfig { open: boolean; - targetType: number; + targetType: string; httpUrl: string; queryName: string; field: JumpConfigField; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts new file mode 100644 index 000000000..9ef304fd3 --- /dev/null +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts @@ -0,0 +1,22 @@ +/** + * 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. + */ + +export const jumpTypes: { name: string; value: string }[] = [ + { value: 'DASHBOARD_DATACHART', name: '仪表盘&数据图表' }, + { value: 'HTTP', name: 'HTTP URL ' }, +]; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx index f736283e2..63e9d3d9a 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx @@ -24,6 +24,7 @@ import { import { useDispatch, useSelector } from 'react-redux'; import { editBoardStackActions, editDashBoardInfoActions } from '../../slice'; import { selectJumpPanel, selectSortAllWidgets } from '../../slice/selectors'; +import { jumpTypes } from './config'; import { SelectJumpFields } from './FieldsSelect'; import { FilterSelect } from './FilterSelect'; import { fetchGlobalControllerOptions } from './service'; @@ -89,9 +90,11 @@ export const SettingJumpModal: FC = ({ useEffect(() => { const _jumpConfig = curJumpWidget?.config?.jumpConfig; setVisible(jumpVisible); - setTargetType(_jumpConfig?.targetType || 1); + setTargetType(_jumpConfig?.targetType || jumpTypes[0].value); if (jumpVisible && _jumpConfig) { - if (curJumpWidget?.config?.jumpConfig?.targetType === 1) { + if ( + curJumpWidget?.config?.jumpConfig?.targetType === 'DASHBOARD_DATACHART' + ) { onGetController(curJumpWidget?.config?.jumpConfig?.target); } form.setFieldsValue(_jumpConfig); @@ -103,7 +106,7 @@ export const SettingJumpModal: FC = ({ const dataChart = useSelector((state: { board: BoardState }) => selectDataChartById(state, curJumpWidget?.datachartId), ); - const [targetType, setTargetType] = useState(1); + const [targetType, setTargetType] = useState(jumpTypes[0].value); const chartGroupColumns = useMemo(() => { if (!dataChart) { return []; @@ -119,14 +122,11 @@ export const SettingJumpModal: FC = ({ }, [form, onGetController], ); - const onTargetTypeChange = useCallback( - value => { - setTargetType(value); - form.setFieldsValue({ filter: undefined }); - onGetController(value); - }, - [form, onGetController], - ); + const onTargetTypeChange = useCallback(value => { + setTargetType(value); + // form.setFieldsValue({ filter: undefined }); + // onGetController(value); + }, []); const handleClose = useCallback(() => { dispatch( editDashBoardInfoActions.changeJumpPanel({ @@ -166,14 +166,18 @@ export const SettingJumpModal: FC = ({ - + {jumpTypes.map(({ name, value }) => ( + + ))} - {targetType === 1 && ( + {targetType === 'DASHBOARD_DATACHART' && ( = ({ )} - {targetType === 2 && ( + {targetType === 'HTTP' && ( - + )} - {targetType === 2 && ( + {targetType === 'HTTP' && ( - + )} {chartGroupColumns?.length > 1 && ( @@ -216,7 +220,7 @@ export const SettingJumpModal: FC = ({ >
)} - {targetType === 1 && ( + {targetType === 'DASHBOARD_DATACHART' && ( Date: Tue, 7 Dec 2021 11:25:45 +0800 Subject: [PATCH 006/348] fix: change targetType defaultValue --- .../components/WidgetProvider/WidgetMethodProvider.tsx | 8 ++++++-- .../BoardEditor/components/SettingJumpModal/index.tsx | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx index 7303e97ea..3df16e6bc 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx @@ -42,6 +42,7 @@ import { WidgetContentChartType, WidgetType, } from '../../pages/Board/slice/types'; +import { jumpTypes } from '../../pages/BoardEditor/components/SettingJumpModal/config'; import { editBoardStackActions, editDashBoardInfoActions, @@ -304,12 +305,15 @@ export const WidgetMethodProvider: FC<{ widgetId: string }> = ({ (values: { widget: Widget; params: ChartMouseEventParams }) => { const { widget, params } = values; const jumpConfig = widget.config?.jumpConfig; - const targetType = jumpConfig?.targetType || 1; + const targetType = jumpConfig?.targetType || jumpTypes[0].value; const httpUrl = jumpConfig?.httpUrl || ''; const queryName = jumpConfig?.queryName || ''; const targetId = jumpConfig?.target?.relId; const jumpFieldName: string = jumpConfig?.field?.jumpFieldName || ''; - if (typeof jumpConfig?.filter === 'object' && targetType === 1) { + if ( + typeof jumpConfig?.filter === 'object' && + targetType === 'DASHBOARD_DATACHART' + ) { const searchParamsStr = urlSearchTransfer.toUrlString({ [jumpConfig?.filter?.filterId]: (params?.data?.rowData?.[jumpFieldName] as string) || '', diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx index 336cfd965..f7d3d6bef 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx @@ -206,7 +206,7 @@ export const SettingJumpModal: FC = ({ name="queryName" rules={[{ required: true, message: 'URL参数名称不能为空' }]} > - + )} {chartGroupColumns?.length > 1 && ( From 9b326fef606f67453a0f3a210d092364b85b7fd7 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Mon, 6 Dec 2021 12:43:08 +0800 Subject: [PATCH 007/348] feat(table): adjust mingxi table to table --- .../MixedTypeSection.tsx | 5 +- .../MingXiTableChart/MingXiTableChart.tsx | 5 +- .../ChartGraph/MingXiTableChart/config.ts | 411 ++++++++++++++++++ 3 files changed, 418 insertions(+), 3 deletions(-) create mode 100644 frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/MixedTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/MixedTypeSection.tsx index 992b24715..abf879f1a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/MixedTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/MixedTypeSection.tsx @@ -17,8 +17,8 @@ */ import { ChartDataSectionFieldActionType } from 'app/types/ChartConfig'; -import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { ChartDataConfigSectionProps } from 'app/types/ChartDataConfigSection'; +import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { FC, memo } from 'react'; import BaseDataConfigSection from './BaseDataConfigSection'; import { dataConfigSectionComparer } from './utils'; @@ -32,12 +32,15 @@ const MixedTypeSection: FC = memo( [ChartDataViewFieldType.NUMERIC]: [ ChartDataSectionFieldActionType.Alias, ChartDataSectionFieldActionType.Format, + ChartDataSectionFieldActionType.Sortable, ], [ChartDataViewFieldType.STRING]: [ ChartDataSectionFieldActionType.Alias, + ChartDataSectionFieldActionType.Sortable, ], [ChartDataViewFieldType.DATE]: [ ChartDataSectionFieldActionType.Alias, + ChartDataSectionFieldActionType.Sortable, ], }, }, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/MingXiTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/MingXiTableChart.tsx index 122abe902..1e211d190 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/MingXiTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/MingXiTableChart.tsx @@ -17,14 +17,15 @@ */ import BasicTableChart from '../BasicTableChart'; - +import Config from './config'; class MingXiTableChart extends BasicTableChart { chart: any = null; + config = Config; constructor() { super({ id: 'mingxi-table', - name: '明细表', + name: '表格', icon: 'mingxibiao', }); } diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts new file mode 100644 index 000000000..1d5ca9c6d --- /dev/null +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts @@ -0,0 +1,411 @@ +/** + * 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 { ChartConfig } from 'app/types/ChartConfig'; + +const config: ChartConfig = { + datas: [ + { + label: 'mixed', + key: 'mixed', + required: true, + type: 'mixed', + }, + { + label: 'filter', + key: 'filter', + type: 'filter', + }, + ], + 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.title', + 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: { + getItems: cols => { + const columns = (cols || []) + .filter(col => + ['aggregate', 'group', 'mixed'].includes(col.type), + ) + .reduce((acc, cur) => acc.concat(cur.rows || []), []) + .map(c => ({ + key: c.uid, + value: c.uid, + label: + c.label || c.aggregate + ? `${c.aggregate}(${c.colName})` + : c.colName, + })); + return columns; + }, + }, + template: { + label: 'column.listItem', + key: 'listItem', + comType: 'group', + rows: [ + { + label: 'column.sortAndFilter', + key: 'sortAndFilter', + comType: 'group', + options: { expand: true }, + rows: [ + { + label: 'column.enableSort', + key: 'enableSort', + comType: 'checkbox', + }, + ], + }, + { + label: 'column.basicStyle', + key: 'basicStyle', + comType: 'group', + options: { expand: true }, + rows: [ + { + label: 'column.backgroundColor', + key: 'backgroundColor', + comType: 'fontColor', + }, + { + label: 'column.align', + key: 'align', + default: 'left', + comType: 'select', + options: { + items: [ + { label: '左对齐', value: 'left' }, + { label: '居中对齐', value: 'center' }, + { label: '右对齐', value: 'right' }, + ], + }, + }, + { + label: 'column.enableFixedCol', + key: 'enableFixedCol', + comType: 'switch', + rows: [ + { + label: 'column.fixedColWidth', + key: 'fixedColWidth', + default: 100, + comType: 'inputNumber', + }, + ], + }, + { + label: 'font', + key: 'font', + comType: 'font', + default: { + fontFamily: 'PingFang SC', + fontSize: '12', + fontWeight: 'normal', + fontStyle: 'normal', + color: 'black', + }, + }, + ], + }, + { + label: 'column.conditionStyle', + key: 'conditionStyle', + comType: 'group', + options: { expand: true }, + rows: [], + }, + ], + }, + }, + ], + }, + ], + }, + { + label: 'style.title', + key: 'style', + comType: 'group', + rows: [ + { + label: 'style.enableFixedHeader', + key: 'enableFixedHeader', + default: true, + comType: 'checkbox', + }, + { + label: 'style.enableBorder', + key: 'enableBorder', + default: true, + comType: 'checkbox', + }, + { + label: 'style.leftFixedColumns', + key: 'leftFixedColumns', + comType: 'select', + options: { + mode: 'multiple', + getItems: cols => { + const columns = (cols || []) + .filter(col => + ['aggregate', 'group', 'mixed'].includes(col.type), + ) + .reduce((acc, cur) => acc.concat(cur.rows || []), []) + .map(c => ({ + key: c.uid, + value: c.uid, + label: + c.label || c.aggregate + ? `${c.aggregate}(${c.colName})` + : c.colName, + })); + return columns; + }, + }, + }, + { + label: 'style.rightFixedColumns', + key: 'rightFixedColumns', + comType: 'select', + options: { + mode: 'multiple', + getItems: cols => { + const columns = (cols || []) + .filter(col => + ['aggregate', 'group', 'mixed'].includes(col.type), + ) + .reduce((acc, cur) => acc.concat(cur.rows || []), []) + .map(c => ({ + key: c.uid, + value: c.uid, + label: + c.label || c.aggregate + ? `${c.aggregate}(${c.colName})` + : c.colName, + })); + return columns; + }, + }, + }, + ], + }, + { + label: 'data.title', + key: 'data', + comType: 'group', + rows: [ + { + label: 'data.tableSize', + key: 'tableSize', + default: 'default', + comType: 'select', + options: { + items: [ + { label: '默认', value: 'default' }, + { label: '中', value: 'middle' }, + { label: '小', value: 'small' }, + ], + }, + }, + ], + }, + ], + settings: [ + { + label: 'cache.title', + key: 'cache', + comType: 'group', + rows: [ + { + label: 'cache.title', + key: 'panel', + comType: 'cache', + }, + ], + }, + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.enablePaging', + key: 'enablePaging', + default: true, + comType: 'checkbox', + options: { + needRefresh: true, + }, + }, + { + label: 'paging.pageSize', + key: 'pageSize', + default: 10, + comType: 'select', + options: { + needRefresh: true, + items: [ + { label: '5', value: 5 }, + { label: '10', value: 10 }, + { label: '20', value: 20 }, + { label: '30', value: 30 }, + { label: '40', value: 40 }, + { label: '50', value: 50 }, + { label: '100', value: 100 }, + ], + }, + watcher: { + deps: ['enablePaging'], + action: props => { + return { + disabled: !props.enablePaging, + }; + }, + }, + }, + ], + }, + ], + i18ns: [ + { + lang: 'zh-CN', + translation: { + header: { + title: '表头样式与分组', + open: '打开表头样式与分组', + styleAndGroup: '表头样式与分组', + }, + column: { + title: '表格数据列', + open: '打开列设置', + list: '字段列表', + sortAndFilter: '排序与过滤', + enableSort: '开启列排序', + basicStyle: '基础样式', + conditionStyle: '条件样式', + backgroundColor: '背景颜色', + align: '对齐方式', + enableFixedCol: '开启固定列宽', + fixedColWidth: '固定列宽度设置', + font: '字体与样式', + }, + style: { + title: '表格样式', + enableFixedHeader: '固定表头', + enableBorder: '显示边框', + leftFixedColumns: '左侧固定列', + rightFixedColumns: '右侧固定列', + }, + data: { + title: '表格数据控制', + tableSize: '表格大小', + autoMerge: '自动合并相同内容', + enableRaw: '使用原始数据', + }, + cache: { + title: '数据处理', + }, + paging: { + title: '分页设置', + enablePaging: '启用分页', + pageSize: '分页大小', + }, + }, + }, + { + lang: 'en-US', + translation: { + header: { + title: 'Title', + open: 'Open Table Header and Group', + styleAndGroup: 'Style and Group', + }, + column: { + title: 'Table Data Column', + open: 'Open Column Setting', + list: 'Field List', + sortAndFilter: 'Sort and Filter', + enableSort: 'Enable Sort', + basicStyle: 'Baisc Style', + conditionStyle: 'Condition Style', + backgroundColor: 'Background Color', + 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', + leftFixedColumns: 'Left Fixed Columns', + rightFixedColumns: 'Right Fixed Columns', + }, + data: { + title: 'Table Data Setting', + tableSize: 'Table Size', + autoMerge: 'Auto Merge', + enableRaw: 'Enable Raw Data', + }, + cache: { + title: 'Data Process', + }, + paging: { + title: 'Paging', + enablePaging: 'Enable Paging', + pageSize: 'Page Size', + }, + }, + }, + ], +}; + +export default config; From 0f0aad2a9ccd5b17e3f7873048e1b9c4bde10be0 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 7 Dec 2021 11:32:28 +0800 Subject: [PATCH 008/348] refactor(chart): add non iframe container for internal global component --- .../BasicTableChart/BasicTableChart.tsx | 39 ++----- .../FenZuTableChart/FenZuTableChart.tsx | 1 - .../MingXiTableChart/MingXiTableChart.tsx | 2 +- .../ReChartsChart/ReChartsChart.tsx | 23 ++-- .../components/ChartGraph/ReactChart.ts | 37 +++++-- .../ReactVizXYPlotChart.tsx | 24 ++--- ...eChartAdapter.tsx => AntdTableWrapper.tsx} | 6 +- .../ChartTools/ChartIFrameContainer.tsx | 100 ++++++++++-------- .../ChartIFrameContainerDispatcher.tsx | 2 +- ...artAdapter.ts => ReactLifecycleAdapter.ts} | 18 ++-- .../components/ChartTools/index.ts | 2 +- .../pages/ChartWorkbenchPage/models/Chart.ts | 1 + .../models/ChartEventBroker.ts | 3 +- .../ChartPreview/ChartPreviewBoard.tsx | 2 +- .../SharePage/ChartPreviewBoardForShare.tsx | 2 +- 15 files changed, 143 insertions(+), 119 deletions(-) rename frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/{AntdTableChartAdapter.tsx => AntdTableWrapper.tsx} (84%) rename frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/{ReactChartAdapter.ts => ReactLifecycleAdapter.ts} (79%) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx index 41cf0b041..9c65ebe88 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx @@ -29,21 +29,23 @@ import { import { toFormattedValue } from 'app/utils/number'; import { Omit } from 'utils/object'; import { v4 as uuidv4 } from 'uuid'; -import AntdTableChartAdapter from '../../ChartTools/AntdTableChartAdapter'; +import AntdTableWrapper from '../../ChartTools/AntdTableWrapper'; import Config from './config'; class BasicTableChart extends ReactChart { + _useIFrame = false; isISOContainer = 'react-table'; config = Config; protected isAutoMerge = false; tableOptions = { dataset: {}, config: {} }; constructor(props?) { - super( - props?.id || 'react-table', - props?.name || '表格', - props?.icon || 'table', - ); + super(AntdTableWrapper, { + id: props?.id || 'react-table', + name: props?.name || '表格', + icon: props?.icon || 'table', + }); + this.meta.requirements = props?.requirements || [ { group: [0, 999], @@ -52,43 +54,24 @@ class BasicTableChart extends ReactChart { ]; } - onMount(options, context): void { - if (options.containerId === undefined || !context.document) { - return; - } - - this.getInstance().init(AntdTableChartAdapter); - this.getInstance().mounted( - context.document.getElementById(options.containerId), - options, - context, - ); - } - onUpdated(options, context): void { this.tableOptions = options; if (!this.isMatchRequirement(options.config)) { - this.getInstance()?.unmount(); + this.adapter?.unmount(); return; } - this.getInstance()?.updated( + this.adapter?.updated( this.getOptions(context, options.dataset, options.config), context, ); } - onUnMount(): void { - this.getInstance()?.unmount(); - } - - onResize(opt: any, context): void { + public onResize(options, context?): void { this.onUpdated(this.tableOptions, context); } - getTableY() {} - getOptions(context, dataset?: ChartDataset, config?: ChartConfig) { if (!dataset || !config) { return { locale: { emptyText: ' ' } }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx index 7d5d67b95..9fe7beda3 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx @@ -26,7 +26,6 @@ import BasicTableChart from '../BasicTableChart'; import Config from './config'; class FenZuTableChart extends BasicTableChart { - chart: any = null; config = Config; isAutoMerge = true; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/MingXiTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/MingXiTableChart.tsx index 1e211d190..ba0ad3ec9 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/MingXiTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/MingXiTableChart.tsx @@ -18,8 +18,8 @@ import BasicTableChart from '../BasicTableChart'; import Config from './config'; + class MingXiTableChart extends BasicTableChart { - chart: any = null; config = Config; constructor() { diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReChartsChart/ReChartsChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReChartsChart/ReChartsChart.tsx index fac68f71e..0b6fb5f72 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReChartsChart/ReChartsChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReChartsChart/ReChartsChart.tsx @@ -21,10 +21,6 @@ import Config from './config'; import ReChartPie from './ReChartPie'; class ReChartsChart extends ReactChart { - constructor() { - super('rechart-chart', 'React ReChart Chart', 'preview'); - } - isISOContainer = 'react-rechart-chart'; config = Config; dependency = [ @@ -34,20 +30,21 @@ class ReChartsChart extends ReactChart { 'https://unpkg.com/recharts@2.0.8/umd/Recharts.min.js', ]; + constructor() { + super(ReChartPie, { + id: 'rechart-chart', + name: 'React ReChart Chart', + icon: 'preview', + }); + } + onMount(options, context): void { const { Surface, Pie } = context.window.Recharts; - this.getInstance().init(ReChartPie); - this.getInstance().registerImportDependenies({ Surface, Pie }); - this.getInstance().mounted( - context.document.getElementById(options.containerId), - ); + this.adapter.registerImportDependenies({ Surface, Pie }); + this.adapter.mounted(context.document.getElementById(options.containerId)); } onUpdated({ config }: { config: any }): void {} - - onUnMount(): void { - // this.getWrapper().unmount(); - } } export default ReChartsChart; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactChart.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactChart.ts index 010336ef3..62213bab3 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactChart.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactChart.ts @@ -17,16 +17,41 @@ */ import Chart from '../../../../models/Chart'; -import ReactChartAdapter from '../ChartTools/ReactChartAdapter'; +import ReactLifecycleAdapter from '../ChartTools/ReactLifecycleAdapter'; export default class ReactChart extends Chart { - adapter = new ReactChartAdapter(); + private _adapter; - init(component) { - this.adapter.init(component); + constructor(wrapper, props) { + super( + props?.id || 'react-table', + props?.name || '表格', + props?.icon || 'table', + ); + this._adapter = new ReactLifecycleAdapter(wrapper); } - getInstance() { - return this.adapter; + get adapter() { + if (!this._adapter) { + throw new Error( + 'should be register component by initAdapter before in used', + ); + } + return this._adapter; + } + + public onMount(options, context?): void { + if (options.containerId === undefined || !context.document) { + return; + } + this.adapter?.mounted( + context.document.getElementById(options.containerId), + options, + context, + ); + } + + public onUnMount(options, context?): void { + this.adapter?.unmount(); } } diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactVizXYPlotChart/ReactVizXYPlotChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactVizXYPlotChart/ReactVizXYPlotChart.tsx index f833e6d71..36c018b52 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactVizXYPlotChart/ReactVizXYPlotChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactVizXYPlotChart/ReactVizXYPlotChart.tsx @@ -21,10 +21,6 @@ import Config from './config'; import ReactXYPlot from './ReactVizXYPlot'; class ReactVizXYPlotChart extends ReactChart { - constructor() { - super('reactviz-xyplot-chart', 'ReactViz XYPlot Chart', 'star'); - } - isISOContainer = 'reactviz-container'; config = Config; dependency = [ @@ -32,30 +28,34 @@ class ReactVizXYPlotChart extends ReactChart { 'https://unpkg.com/react-vis/dist/dist.min.js', ]; + constructor() { + super(ReactXYPlot, { + id: 'reactviz-xyplot-chart', + name: 'ReactViz XYPlot Chart', + icon: 'star', + }); + } + onMount(options, context): void { if (!context.window.reactVis) { return; } const { XYPlot, XAxis, YAxis, HorizontalGridLines, LineSeries } = context.window.reactVis; - this.getInstance().init(ReactXYPlot); - this.getInstance().registerImportDependenies({ + this.adapter.init(ReactXYPlot); + this.adapter.registerImportDependenies({ XYPlot, XAxis, YAxis, HorizontalGridLines, LineSeries, }); - this.getInstance().mounted( - context.document.getElementById(options.containerId), - ); + this.adapter.mounted(context.document.getElementById(options.containerId)); } onUpdated(props): void { - // this.getWrapper().updated(props); + // this.adapter.updated(props); } - - onUnMount(): void {} } export default ReactVizXYPlotChart; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/AntdTableChartAdapter.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/AntdTableWrapper.tsx similarity index 84% rename from frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/AntdTableChartAdapter.tsx rename to frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/AntdTableWrapper.tsx index cc8961daa..168d702f4 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/AntdTableChartAdapter.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/AntdTableWrapper.tsx @@ -19,8 +19,8 @@ import { Table } from 'antd'; import { FC, memo } from 'react'; -const AntdTableChartAdapter: FC<{ dataSource: []; columns: [] }> = memo( - ({ dataSource, columns, ...rest }) => { +const AntdTableWrapper: FC<{ dataSource: []; columns: [] }> = memo( + ({ dataSource, columns, children, ...rest }) => { return ( = memo( }, ); -export default AntdTableChartAdapter; +export default AntdTableWrapper; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx index 3ccc253a6..759604911 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx @@ -23,8 +23,6 @@ import Frame, { FrameContextConsumer } from 'react-frame-component'; import styled, { StyleSheetManager } from 'styled-components/macro'; import { isEmpty } from 'utils/object'; import ChartLifecycleAdapter from './ChartLifecycleAdapter'; -// eslint-disable-next-line import/no-webpack-loader-syntax -const antdStyles = require('!!css-loader!antd/dist/antd.min.css'); const ChartIFrameContainer: React.FC<{ dataset: any; @@ -33,9 +31,6 @@ const ChartIFrameContainer: React.FC<{ containerId?: string; style?; }> = props => { - // Note: manually add table css style in iframe - const isTable = props.chart?.isISOContainer === 'react-table'; - const transformToSafeCSSProps = style => { if (isNaN(style?.width) || isEmpty(style?.width)) { style.width = 0; @@ -46,44 +41,63 @@ const ChartIFrameContainer: React.FC<{ return style; }; - return ( - - - - - } - > - - {frameContext => ( - - - - - - )} - - - ); + const render = () => { + if (!props?.chart?._useIFrame) { + return ( +
+ +
+ ); + } + + return ( + + + + } + > + + {frameContext => ( + + + + + + )} + + + ); + }; + + return render(); }; export default ChartIFrameContainer; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx index 719a689e6..257f3156e 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx @@ -79,7 +79,7 @@ class ChartIFrameContainerDispatcher { if (!this.chartContainerMap.has(containerId)) { const newContainer = style => (chart, dataset, config) => { return ( - void; mounted: (container, options?, context?) => any; updated: (options: any, context?) => any; @@ -27,11 +27,17 @@ interface ReactChartAdapterProps { resize: (opt: any) => void; } -export default class ReactChartAdapter implements ReactChartAdapterProps { +export default class ReactLifecycleAdapter + implements ReactLifecycleAdapterProps +{ private domContainer; private reactComponent; private externalLibs; + constructor(componentWrapper) { + this.reactComponent = componentWrapper; + } + public init(component) { this.reactComponent = component; } @@ -43,14 +49,14 @@ export default class ReactChartAdapter implements ReactChartAdapterProps { public mounted(container, options?, context?) { this.domContainer = container; return ReactDom.render( - React.createElement(this.getComponent(), options), + React.createElement(this.getComponent(), options, context), this.domContainer, ); } public updated(options, context?) { return ReactDom.render( - React.createElement(this.getComponent(), options), + React.createElement(this.getComponent(), options, context), this.domContainer, ); } @@ -59,9 +65,9 @@ export default class ReactChartAdapter implements ReactChartAdapterProps { ReactDom.unmountComponentAtNode(this.domContainer); } - public resize(opt: any) { + public resize(options, context?) { return ReactDom.render( - React.createElement(this.getComponent(), opt), + React.createElement(this.getComponent(), options, context), this.domContainer, ); } diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/index.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/index.ts index 63bdc3cb4..4d542b67f 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/index.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/index.ts @@ -22,7 +22,7 @@ import ChartIFrameContainerResourceLoader from './ChartIFrameContainerResourceLo import ChartPluginLoader from './ChartPluginLoader'; const ChartTools = { - ChartIFrame: ChartIFrameContainer, + ChartIFrameContainer, ChartPluginLoader, ChartIFrameContainerDispatcher, ChartIFrameContainerResourceLoader, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/Chart.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/Chart.ts index 1cd78c42a..f31966804 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/Chart.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/Chart.ts @@ -38,6 +38,7 @@ class Chart extends DatartChartBase { dependency: string[] = []; isISOContainer: boolean | string = false; + _useIFrame: boolean = true; _state: ChartStatus = 'init'; _stateHistory: ChartStatus[] = []; _hooks?: ChartEventBroker; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts index 4d50a05fc..4472df649 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts @@ -28,7 +28,6 @@ type BrokerContext = { type HooksEvent = 'mounted' | 'updated' | 'resize' | 'unmount'; -// TODO(Stephen): remove to Chart Tool Folder class ChartEventBroker { private _listeners: Map = new Map(); private _chart?: Chart; @@ -83,7 +82,7 @@ class ChartEventBroker { } } - private safeInvoke(event, options, context) { + private safeInvoke(event: HooksEvent, options: any, context?: BrokerContext) { try { this._listeners.get(event)?.call?.(this._chart, options, context); } catch (e) { 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 588a4d78d..ee16d6412 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreviewBoard.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreviewBoard.tsx @@ -258,7 +258,7 @@ const ChartPreviewBoard: FC<{ onChange={handleFilterChange} /> -
- Date: Tue, 7 Dec 2021 11:44:38 +0800 Subject: [PATCH 009/348] chore: fix some code --- .../components/BoardProvider/BoardActionProvider.tsx | 2 +- .../WidgetCore/ControllerWIdget/ControllerWidgetCore.tsx | 2 +- .../pages/DashBoardPage/contexts/BoardActionContext.ts | 2 +- .../components/ControllerWidgetPanel/index.tsx | 2 +- frontend/src/app/pages/DashBoardPage/utils/index.ts | 8 ++++---- frontend/src/app/pages/DashBoardPage/utils/widget.ts | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/BoardProvider/BoardActionProvider.tsx b/frontend/src/app/pages/DashBoardPage/components/BoardProvider/BoardActionProvider.tsx index 8547b7616..c18ec240f 100644 --- a/frontend/src/app/pages/DashBoardPage/components/BoardProvider/BoardActionProvider.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/BoardProvider/BoardActionProvider.tsx @@ -75,7 +75,7 @@ export const BoardActionProvider: FC<{ id: string }> = ({ dispatch(resetControllerAction({ boardId, renderMode })); } }, 500), - refreshWidgetsByFilter: debounce((widget: Widget) => { + refreshWidgetsByController: debounce((widget: Widget) => { if (hasQueryControl) { return; } diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ControllerWIdget/ControllerWidgetCore.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ControllerWIdget/ControllerWidgetCore.tsx index 2dbfdcb03..da71ade23 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ControllerWIdget/ControllerWidgetCore.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ControllerWIdget/ControllerWidgetCore.tsx @@ -62,7 +62,7 @@ export const ControllerWidgetCore: React.FC<{}> = memo(() => { const { data: { rows }, } = useContext(WidgetDataContext); - const { widgetUpdate, refreshWidgetsByFilter } = + const { widgetUpdate, refreshWidgetsByController: refreshWidgetsByFilter } = useContext(BoardActionContext); const { config, type: facadeType } = useMemo( diff --git a/frontend/src/app/pages/DashBoardPage/contexts/BoardActionContext.ts b/frontend/src/app/pages/DashBoardPage/contexts/BoardActionContext.ts index 6cce6a5f8..ef6e24c62 100644 --- a/frontend/src/app/pages/DashBoardPage/contexts/BoardActionContext.ts +++ b/frontend/src/app/pages/DashBoardPage/contexts/BoardActionContext.ts @@ -20,7 +20,7 @@ import { createContext } from 'react'; import { Widget } from '../pages/Board/slice/types'; export interface BoardActionContextProps { widgetUpdate: (widget: Widget) => void; - refreshWidgetsByFilter: (widget: Widget) => void; + refreshWidgetsByController: (widget: Widget) => void; updateBoard?: (callback: () => void) => void; onGenerateShareLink?: (date, usePwd) => any; onBoardToDownLoad: () => any; 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 370523724..20f44085d 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 @@ -75,7 +75,7 @@ const FilterWidgetPanel: React.FC = memo(props => { const { type, widgetId, controllerType } = useSelector(selectControllerPanel); const { boardId, boardType, queryVariables } = useContext(BoardContext); - const { refreshWidgetsByFilter } = useContext(BoardActionContext); + const { refreshWidgetsByController: refreshWidgetsByFilter } = useContext(BoardActionContext); const allWidgets = useSelector(selectSortAllWidgets); const widgets = useMemo( () => getCanLinkControlWidgets(allWidgets), diff --git a/frontend/src/app/pages/DashBoardPage/utils/index.ts b/frontend/src/app/pages/DashBoardPage/utils/index.ts index 0caab3afc..28c0ae2ee 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/index.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/index.ts @@ -52,10 +52,10 @@ export const convertImageUrl = (urlKey: string = ''): string => { * 将当前前端渲染环境 id 替换掉原有的id ,原来的和当前的相等不受影响 */ export const adaptBoardImageUrl = (url: string = '', curBoardId: string) => { - // // url=resources/image/dashboard/3062ff86cdcb47b3bba75565b3f2991d/2e1cac3a-600c-4636-b858-cbcb07f4a3b3 - const spliter = '/image/dashboard/'; - if (url.includes(spliter)) { - const originalBoardId = url.split(spliter)[1].split('/')[0]; + // // url=resources/image/dashboard/boardIdXXXXXXX/fileIDxxxxxxxxx + const splitter = '/image/dashboard/'; + if (url.includes(splitter)) { + const originalBoardId = url.split(splitter)[1].split('/')[0]; url.replace(originalBoardId, curBoardId); return url; } diff --git a/frontend/src/app/pages/DashBoardPage/utils/widget.ts b/frontend/src/app/pages/DashBoardPage/utils/widget.ts index 266d25edc..c14f03d17 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/widget.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/widget.ts @@ -491,8 +491,8 @@ export const getWidgetMapByServer = ( // 根据 url参数修改filter 默认值 if (filterSearchParams) { const paramsKey = Object.keys(filterSearchParams); - const macthKey = isMatchByName ? widget.config.name : widget.id; - if (paramsKey.includes(macthKey)) { + const matchKey = isMatchByName ? widget.config.name : widget.id; + if (paramsKey.includes(matchKey)) { const _value = isMatchByName ? filterSearchParams[widget.config.name] : filterSearchParams[widget.id]; From 34ee60a350b71f3c37b5d81b5065a2c9e4ddcdbf Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Tue, 7 Dec 2021 12:09:29 +0800 Subject: [PATCH 010/348] style: Modify variable name --- .../WidgetProvider/WidgetMethodProvider.tsx | 5 +---- .../components/SettingJumpModal/config.ts | 4 ++-- .../components/SettingJumpModal/index.tsx | 17 +++++++---------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx index 3df16e6bc..c1aec590c 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx @@ -310,10 +310,7 @@ export const WidgetMethodProvider: FC<{ widgetId: string }> = ({ const queryName = jumpConfig?.queryName || ''; const targetId = jumpConfig?.target?.relId; const jumpFieldName: string = jumpConfig?.field?.jumpFieldName || ''; - if ( - typeof jumpConfig?.filter === 'object' && - targetType === 'DASHBOARD_DATACHART' - ) { + if (typeof jumpConfig?.filter === 'object' && targetType === 'INTERNAL') { const searchParamsStr = urlSearchTransfer.toUrlString({ [jumpConfig?.filter?.filterId]: (params?.data?.rowData?.[jumpFieldName] as string) || '', diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts index 9ef304fd3..98b1e12eb 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts @@ -17,6 +17,6 @@ */ export const jumpTypes: { name: string; value: string }[] = [ - { value: 'DASHBOARD_DATACHART', name: '仪表盘&数据图表' }, - { value: 'HTTP', name: 'HTTP URL ' }, + { value: 'INTERNAL', name: '仪表盘 / 数据图表' }, + { value: 'HTTP', name: 'URL ' }, ]; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx index f7d3d6bef..c092cdc7a 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx @@ -92,9 +92,7 @@ export const SettingJumpModal: FC = ({ setVisible(jumpVisible); setTargetType(_jumpConfig?.targetType || jumpTypes[0].value); if (jumpVisible && _jumpConfig) { - if ( - curJumpWidget?.config?.jumpConfig?.targetType === 'DASHBOARD_DATACHART' - ) { + if (curJumpWidget?.config?.jumpConfig?.targetType === 'INTERNAL') { onGetController(curJumpWidget?.config?.jumpConfig?.target); } form.setFieldsValue(_jumpConfig); @@ -152,7 +150,6 @@ export const SettingJumpModal: FC = ({ }, [dispatch, curJumpWidget, handleClose, chartGroupColumns], ); - return ( = ({ - {targetType === 'DASHBOARD_DATACHART' && ( + {targetType === 'INTERNAL' && ( = ({ {targetType === 'HTTP' && ( @@ -206,7 +203,7 @@ export const SettingJumpModal: FC = ({ name="queryName" rules={[{ required: true, message: 'URL参数名称不能为空' }]} > - + )} {chartGroupColumns?.length > 1 && ( @@ -221,7 +218,7 @@ export const SettingJumpModal: FC = ({ > )} - {targetType === 'DASHBOARD_DATACHART' && ( + {targetType === 'INTERNAL' && ( Date: Tue, 7 Dec 2021 12:20:50 +0800 Subject: [PATCH 011/348] fix(chart): fix table height issue --- .../ChartGraph/BasicTableChart/BasicTableChart.tsx | 5 ++--- .../ChartGraph/FenZuTableChart/FenZuTableChart.tsx | 5 ++--- .../components/ChartTools/ChartLifecycleAdapter.tsx | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx index 9c65ebe88..6ac8094f3 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx @@ -77,7 +77,6 @@ class BasicTableChart extends ReactChart { return { locale: { emptyText: ' ' } }; } - const { clientWidth, clientHeight } = context.document.documentElement; const dataConfigs = config.datas || []; const styleConfigs = config.styles || []; const settingConfigs = config.settings || []; @@ -121,8 +120,8 @@ class BasicTableChart extends ReactChart { ...this.getAntdTableStyleOptions( styleConfigs, dataset, - clientWidth, - clientHeight, + null, + context?.height, tablePagination, ), }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx index 9fe7beda3..a6e7f5302 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx @@ -43,7 +43,6 @@ class FenZuTableChart extends BasicTableChart { return { locale: { emptyText: ' ' } }; } - const { clientWidth, clientHeight } = context.document.documentElement; const dataConfigs = config.datas || []; const styleConfigs = config.styles || []; const settingConfigs = config.settings || []; @@ -74,8 +73,8 @@ class FenZuTableChart extends BasicTableChart { ...this.getAntdTableStyleOptions( styleConfigs, dataset, - clientWidth, - clientHeight, + null, + context?.height, tablePagination, ), }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx index 7db8a1889..0eecf05b2 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx @@ -112,7 +112,7 @@ const ChartLifecycleAdapter: React.FC<{ dataset, config, }, - { document, window }, + { document, window, width: style?.width, height: style?.height }, ); }, [config, dataset, containerStatus, document, window]); From f7c4ed6fffe8f4d51539f21354499631a6e2fa1b Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Tue, 7 Dec 2021 12:29:28 +0800 Subject: [PATCH 012/348] style: http ==> URL --- .../WidgetProvider/WidgetMethodProvider.tsx | 14 +++++++------- .../pages/DashBoardPage/pages/Board/slice/types.ts | 2 +- .../components/SettingJumpModal/config.ts | 2 +- .../components/SettingJumpModal/index.tsx | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx index c1aec590c..a998a4f75 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx @@ -306,7 +306,7 @@ export const WidgetMethodProvider: FC<{ widgetId: string }> = ({ const { widget, params } = values; const jumpConfig = widget.config?.jumpConfig; const targetType = jumpConfig?.targetType || jumpTypes[0].value; - const httpUrl = jumpConfig?.httpUrl || ''; + const URL = jumpConfig?.URL || ''; const queryName = jumpConfig?.queryName || ''; const targetId = jumpConfig?.target?.relId; const jumpFieldName: string = jumpConfig?.field?.jumpFieldName || ''; @@ -320,14 +320,14 @@ export const WidgetMethodProvider: FC<{ widgetId: string }> = ({ `/organizations/${orgId}/vizs/${targetId}?${searchParamsStr}`, ); } - } else if (targetType === 'HTTP') { - let url; - if (httpUrl.indexOf('?') > -1) { - url = `${httpUrl}&${queryName}=${params?.data?.rowData?.[jumpFieldName]}`; + } else if (targetType === 'URL') { + let jumpUrl; + if (URL.indexOf('?') > -1) { + jumpUrl = `${URL}&${queryName}=${params?.data?.rowData?.[jumpFieldName]}`; } else { - url = `${httpUrl}?${queryName}=${params?.data?.rowData?.[jumpFieldName]}`; + jumpUrl = `${URL}?${queryName}=${params?.data?.rowData?.[jumpFieldName]}`; } - window.location.href = url; + window.location.href = jumpUrl; } }, [history, orgId], 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 0b5ddde0e..d6f22167a 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/types.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/types.ts @@ -162,7 +162,7 @@ export interface JumpConfigField { export interface JumpConfig { open: boolean; targetType: string; - httpUrl: string; + URL: string; queryName: string; field: JumpConfigField; target: JumpConfigTarget; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts index 98b1e12eb..4c1cf89f4 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts @@ -18,5 +18,5 @@ export const jumpTypes: { name: string; value: string }[] = [ { value: 'INTERNAL', name: '仪表盘 / 数据图表' }, - { value: 'HTTP', name: 'URL ' }, + { value: 'URL', name: 'URL' }, ]; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx index c092cdc7a..9f9ffb315 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx @@ -188,16 +188,16 @@ export const SettingJumpModal: FC = ({ )} - {targetType === 'HTTP' && ( + {targetType === 'URL' && ( )} - {targetType === 'HTTP' && ( + {targetType === 'URL' && ( Date: Tue, 7 Dec 2021 14:30:43 +0800 Subject: [PATCH 013/348] feat(chart): add disableAggregate to disable auto aggregate both for section and action --- .../FilterTypeSection.tsx | 3 +- .../ChartDraggableTargetContainer.tsx | 41 +++++++++++-------- .../FilterAction/FilterAction.tsx | 1 + .../FilterControlPanel/FilterControlPanel.tsx | 3 ++ .../ChartGraph/MingXiTableChart/config.ts | 2 + .../models/ChartHttpRequest.ts | 3 +- frontend/src/app/types/ChartConfig.ts | 1 + frontend/src/app/utils/chartHelper.ts | 6 ++- 8 files changed, 39 insertions(+), 21 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/FilterTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/FilterTypeSection.tsx index 053e0e5ac..546155786 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/FilterTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/FilterTypeSection.tsx @@ -24,8 +24,8 @@ import { ChartDataSectionConfig, ChartDataSectionFieldActionType, } from 'app/types/ChartConfig'; -import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { ChartDataConfigSectionProps } from 'app/types/ChartDataConfigSection'; +import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { FC, memo, useState } from 'react'; import { CloneValueDeep } from 'utils/object'; import BaseDataConfigSection from './BaseDataConfigSection'; @@ -39,6 +39,7 @@ const FilterTypeSection: FC = memo( const extendedConfig = Object.assign( { allowSameField: true, + disableAggregate: false, }, { actions: { diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx index 55d448af1..5fef018f1 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx @@ -155,27 +155,32 @@ export const ChartDraggableTargetContainer: FC = currentConfig?.type === ChartDataSectionType.SIZE || currentConfig?.type === ChartDataSectionType.INFO ) { + if (currentConfig.disableAggregate) { + return; + } if ( - item.category !== + item.category === (ChartDataViewFieldCategory.AggregateComputedField as string) ) { - let aggType: string = ''; - if (currentConfig?.actions instanceof Array) { - currentConfig?.actions?.find( - type => - type === ChartDataSectionFieldActionType.Aggregate || - type === ChartDataSectionFieldActionType.AggregateLimit, - ); - } else if (currentConfig?.actions instanceof Object) { - aggType = currentConfig?.actions?.[item?.type]?.find( - type => - type === ChartDataSectionFieldActionType.Aggregate || - type === ChartDataSectionFieldActionType.AggregateLimit, - ); - } - if (aggType) { - return AggregateFieldSubAggregateType?.[aggType]?.[0]; - } + return; + } + + let aggType: string = ''; + if (currentConfig?.actions instanceof Array) { + currentConfig?.actions?.find( + type => + type === ChartDataSectionFieldActionType.Aggregate || + type === ChartDataSectionFieldActionType.AggregateLimit, + ); + } else if (currentConfig?.actions instanceof Object) { + aggType = currentConfig?.actions?.[item?.type]?.find( + type => + type === ChartDataSectionFieldActionType.Aggregate || + type === ChartDataSectionFieldActionType.AggregateLimit, + ); + } + if (aggType) { + return AggregateFieldSubAggregateType?.[aggType]?.[0]; } } }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterAction/FilterAction.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterAction/FilterAction.tsx index 37483db53..d2c6156c5 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterAction/FilterAction.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterAction/FilterAction.tsx @@ -39,6 +39,7 @@ const FilterAction: FC<{ // TODO: tobe implement to get fields return await Promise.resolve(['a', 'b', 'c'].map(f => `${fieldId}-${f}`)); }; + return ( { + if (Boolean(dataConfig?.disableAggregate)) { + return AggregateFieldActionType.NONE; + } if (config.aggregate) { return config.aggregate; } else if ( diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts index 1d5ca9c6d..424dbfad0 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts @@ -25,11 +25,13 @@ const config: ChartConfig = { key: 'mixed', required: true, type: 'mixed', + disableAggregate: true, }, { label: 'filter', key: 'filter', type: 'filter', + disableAggregate: true, }, ], styles: [ diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts index 717fe4785..59a0bc8b1 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts @@ -212,7 +212,8 @@ export class ChartDataRequestBuilder { } if ( cur.type === ChartDataSectionType.GROUP || - cur.type === ChartDataSectionType.AGGREGATE + cur.type === ChartDataSectionType.AGGREGATE || + cur.type === ChartDataSectionType.MIXED ) { return acc.concat(cur.rows); } diff --git a/frontend/src/app/types/ChartConfig.ts b/frontend/src/app/types/ChartConfig.ts index 9e86ca901..74957143c 100644 --- a/frontend/src/app/types/ChartConfig.ts +++ b/frontend/src/app/types/ChartConfig.ts @@ -262,6 +262,7 @@ export type ChartDataSectionConfig = ChartConfigBase & { rows?: ChartDataSectionField[]; actions?: Array> | object; limit?: null | number | string | number[] | string[]; + disableAggregate?: boolean; // Question: keep field's filter relation for filter arrangement feature fieldRelation?: FilterCondition; diff --git a/frontend/src/app/utils/chartHelper.ts b/frontend/src/app/utils/chartHelper.ts index d6a2c270e..729838a7a 100644 --- a/frontend/src/app/utils/chartHelper.ts +++ b/frontend/src/app/utils/chartHelper.ts @@ -18,6 +18,7 @@ import echartsDefaultTheme from 'app/assets/theme/echarts_default_theme.json'; import { + AggregateFieldActionType, ChartConfig, ChartDataSectionConfig, ChartDataSectionField, @@ -431,11 +432,14 @@ export function getValueByColumnKey(col?: { aggregate?; colName: string }) { export function getColumnRenderName(c?: ChartDataSectionField) { if (!c) { - return 'unkonwn name'; + return '[unkonwn]'; } if (c.alias?.name) { return c.alias.name; } + if (c.aggregate === AggregateFieldActionType.NONE) { + return c.colName; + } if (c.aggregate) { return `${c.aggregate}(${c.colName})`; } From 792fb88efc7ed140065dedc987c08d5e51d90b90 Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Tue, 7 Dec 2021 15:29:44 +0800 Subject: [PATCH 014/348] fix: support sql any join fix: file provider value parse error --- data-providers/src/main/java/codegen/Parser.jj | 4 ++-- .../main/java/datart/data/provider/DefaultDataProvider.java | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/data-providers/src/main/java/codegen/Parser.jj b/data-providers/src/main/java/codegen/Parser.jj index c9090f9a5..16490394a 100644 --- a/data-providers/src/main/java/codegen/Parser.jj +++ b/data-providers/src/main/java/codegen/Parser.jj @@ -1847,9 +1847,9 @@ SqlLiteral JoinType() : | { joinType = JoinType.INNER; } | - [ ] { joinType = JoinType.LEFT; } + [ || ] { joinType = JoinType.LEFT; } | - [ ] { joinType = JoinType.RIGHT; } + [ || ] { joinType = JoinType.RIGHT; } | [ ] { joinType = JoinType.FULL; } | diff --git a/data-providers/src/main/java/datart/data/provider/DefaultDataProvider.java b/data-providers/src/main/java/datart/data/provider/DefaultDataProvider.java index cdcc488bb..adf125811 100644 --- a/data-providers/src/main/java/datart/data/provider/DefaultDataProvider.java +++ b/data-providers/src/main/java/datart/data/provider/DefaultDataProvider.java @@ -195,7 +195,7 @@ protected List> parseValues(List> values, List return values; } if (values.get(0).size() != columns.size()) { - Exceptions.msg( "message.provider.default.schema", values.get(0).size() + ":" + columns.size()); + Exceptions.msg("message.provider.default.schema", values.get(0).size() + ":" + columns.size()); } values.parallelStream().forEach(vals -> { for (int i = 0; i < vals.size(); i++) { @@ -216,8 +216,10 @@ protected List> parseValues(List> values, List val = null; } else if (NumberUtils.isDigits(val.toString())) { val = Long.parseLong(val.toString()); - } else { + } else if (NumberUtils.isNumber(val.toString())) { val = Double.parseDouble(val.toString()); + } else { + val = null; } break; default: From e9d9817e51a3698ad16210f0dc4491df92b469fd Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Tue, 7 Dec 2021 15:48:56 +0800 Subject: [PATCH 015/348] fix: set h2 case insensitive --- .../src/main/java/datart/data/provider/local/LocalDB.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/data-providers/src/main/java/datart/data/provider/local/LocalDB.java b/data-providers/src/main/java/datart/data/provider/local/LocalDB.java index 549c77fe9..60cdcf191 100644 --- a/data-providers/src/main/java/datart/data/provider/local/LocalDB.java +++ b/data-providers/src/main/java/datart/data/provider/local/LocalDB.java @@ -51,7 +51,9 @@ @Slf4j public class LocalDB { - private static final String MEM_URL = "jdbc:h2:mem:/LOG=0;DATABASE_TO_UPPER=false;CACHE_SIZE=65536;LOCK_MODE=0;UNDO_LOG=0"; + private static final String MEM_URL = "jdbc:h2:mem:/"; + + private static final String H2_PARAM = ";LOG=0;DATABASE_TO_UPPER=false;MODE=MySQL;CASE_INSENSITIVE_IDENTIFIERS=TRUE;CACHE_SIZE=65536;LOCK_MODE=0;UNDO_LOG=0"; private static String fileUrl; @@ -318,7 +320,7 @@ private static void insertTableData(Dataframe dataframe, Connection connection) } private static Connection getConnection(boolean persistent, String database) throws SQLException { - String url = persistent ? getDatabaseUrl(database) : MEM_URL; + String url = persistent ? getDatabaseUrl(database) : MEM_URL + H2_PARAM; return DriverManager.getConnection(url); } @@ -375,7 +377,7 @@ private static String getDatabaseUrl(String database) { } else { database = toDatabase(database); } - return fileUrl = String.format("jdbc:h2:file:%s/%s;LOG=0;DATABASE_TO_UPPER=false;CACHE_SIZE=65536;LOCK_MODE=0;UNDO_LOG=0", getDbFileBasePath(), database); + return fileUrl = String.format("jdbc:h2:file:%s/%s" + H2_PARAM, getDbFileBasePath(), database); } private static String getDbFileBasePath() { From e94c53e05089aad8f85b3f9c2927f0944150d407 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 7 Dec 2021 16:37:48 +0800 Subject: [PATCH 016/348] fix(chart): fix table chart refresh issue on preview --- .../ChartTools/ChartIFrameContainer.tsx | 32 +++++----- .../ChartIFrameContainerDispatcher.tsx | 19 +++--- .../WidgetCore/DataChartWidget/index.tsx | 3 +- .../ChartPreview/ChartPreviewBoard.tsx | 62 +++++++++++-------- .../ControllerPanel/ControllerPanel.tsx | 53 +++++++++------- .../SharePage/ChartPreviewBoardForShare.tsx | 5 +- 6 files changed, 101 insertions(+), 73 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx index 759604911..c24c58fa9 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx @@ -18,27 +18,29 @@ import Chart from 'app/pages/ChartWorkbenchPage/models/Chart'; import { ChartConfig } from 'app/types/ChartConfig'; -import React from 'react'; +import { FC, memo } from 'react'; import Frame, { FrameContextConsumer } from 'react-frame-component'; import styled, { StyleSheetManager } from 'styled-components/macro'; import { isEmpty } from 'utils/object'; import ChartLifecycleAdapter from './ChartLifecycleAdapter'; -const ChartIFrameContainer: React.FC<{ +const ChartIFrameContainer: FC<{ dataset: any; chart: Chart; config: ChartConfig; containerId?: string; - style?; -}> = props => { - const transformToSafeCSSProps = style => { - if (isNaN(style?.width) || isEmpty(style?.width)) { - style.width = 0; + width?: any; + height?: any; +}> = memo(props => { + const transformToSafeCSSProps = (width, height) => { + let newStyle = { width, height }; + if (isNaN(newStyle?.width) || isEmpty(newStyle?.width)) { + newStyle.width = 0; } - if (isNaN(style?.height) || isEmpty(style?.height)) { - style.height = 0; + if (isNaN(newStyle?.height) || isEmpty(newStyle?.height)) { + newStyle.height = 0; } - return style; + return newStyle; }; const render = () => { @@ -47,13 +49,13 @@ const ChartIFrameContainer: React.FC<{
); @@ -64,7 +66,7 @@ const ChartIFrameContainer: React.FC<{ id={`chart-iframe-root-${props.containerId}`} key={props.containerId} frameBorder={0} - style={{ ...props?.style, width: '100%', height: '100%' }} + style={{ width: '100%', height: '100%' }} head={ <> diff --git a/frontend/src/app/pages/MainPage/Navbar/index.tsx b/frontend/src/app/pages/MainPage/Navbar/index.tsx index dcda81448..28851e1eb 100644 --- a/frontend/src/app/pages/MainPage/Navbar/index.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/index.tsx @@ -7,6 +7,7 @@ import { SafetyCertificateFilled, SettingFilled, SettingOutlined, + SwapOutlined, UserOutlined, } from '@ant-design/icons'; import { List, Menu, Tooltip } from 'antd'; @@ -24,6 +25,7 @@ import { logout } from 'app/slice/thunks'; import { downloadFile } from 'app/utils/fetch'; import { BASE_RESOURCE_URL } from 'globalConstants'; import React, { cloneElement, useCallback, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; import { NavLink, useHistory, useRouteMatch } from 'react-router-dom'; import styled from 'styled-components/macro'; @@ -63,6 +65,7 @@ export function Navbar() { const matchModules = useRouteMatch<{ moduleName: string }>( '/organizations/:orgId/:moduleName', ); + const { i18n } = useTranslation(); const brandClick = useCallback(() => { history.push('/'); @@ -183,11 +186,17 @@ export function Navbar() { case 'password': setModifyPasswordVisible(true); break; + case 'zh': + i18n.changeLanguage('zh'); + break; + case 'en': + i18n.changeLanguage('en'); + break; default: break; } }, - [dispatch, history], + [dispatch, history, i18n], ); const onSetPolling = useCallback( @@ -272,6 +281,15 @@ export function Navbar() { >

修改密码

+ + } + key="language" + title="切换语言" + > + 中文 + English + } diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 59b7bf89c..414411bcd 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -416,5 +416,12 @@ "password": "Password", "pleaseInputPassword": "please input password" } + }, + "components":{ + "colorPicker":{ + "more":"More", + "ok": "OK", + "cancel": "Cancel" + } } } diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 5964b9572..a848d9798 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -411,5 +411,12 @@ "password": "密码", "pleaseInputPassword": "请输入密码" } + }, + "components":{ + "colorPicker":{ + "more":"更多", + "ok": "确认", + "cancel": "取消" + } } } From face5006ba545f3967c0a2d9625b3ac3f116a688 Mon Sep 17 00:00:00 2001 From: tianlei Date: Thu, 23 Dec 2021 10:44:50 +0800 Subject: [PATCH 167/348] fix:(Chart)fix richtext init image --- .../ChartTools/ChartRichTextAdapter.tsx | 151 +++++++++--------- 1 file changed, 79 insertions(+), 72 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartRichTextAdapter.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartRichTextAdapter.tsx index 0b7328548..2a5f4a16a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartRichTextAdapter.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartRichTextAdapter.tsx @@ -104,7 +104,7 @@ const ChartRichTextAdapter: FC<{ setQuillValue(contents); contents && debouncedDataChange(JSON.stringify(contents)); } - }, [onChange]); + }, [debouncedDataChange]); useEffect(() => { if (typeof quillValue !== 'string') { @@ -112,15 +112,17 @@ const ChartRichTextAdapter: FC<{ const ops = quill.ops?.concat().map(item => { let insert = item.insert; if (typeof insert !== 'string') { - const name = insert?.calcfield?.name; - const config = name - ? dataList.find(items => items.name === name) - : null; - insert = config?.value || ''; + if (insert.hasOwnProperty('calcfield')) { + const name = insert.calcfield?.name; + const config = name + ? dataList.find(items => items.name === name) + : null; + insert = config?.value || ''; + } } return { ...item, insert }; }); - setTranslate(ops?.length ? { ...quill, ops }: ''); + setTranslate(ops?.length ? { ...quill, ops } : ''); } else { setTranslate(quillValue); } @@ -137,7 +139,7 @@ const ChartRichTextAdapter: FC<{ (!isEditing || visible) && ( () => { - if (quillEditRef.current) { - const quill = quillEditRef.current.getEditor(); - if (field) { - const text = `[${field.name}]`; - quill.getModule('calcfield').insertItem( - { - denotationChar: '', - id: field.id, - name: field.name, - value: field.value, - text, - }, - true, - ); - setImmediate(() => { - setQuillValue(quillEditRef.current?.getEditor().getContents() || ''); - }); + const selectField = useCallback( + (field: any) => () => { + if (quillEditRef.current) { + const quill = quillEditRef.current.getEditor(); + if (field) { + const text = `[${field.name}]`; + quill.getModule('calcfield').insertItem( + { + denotationChar: '', + id: field.id, + name: field.name, + value: field.value, + text, + }, + true, + ); + setImmediate(() => { + setQuillValue( + quillEditRef.current?.getEditor().getContents() || '', + ); + }); + } } - } - }; - - const fieldItems = dataList?.length ? ( - - {dataList.map(fieldName => ( - - {fieldName.name} - - ))} - - ) : ( - - 暂无可用字段 - + }, + [quillEditRef], ); + const fieldItems = useMemo(() => { + return dataList?.length ? ( + + {dataList.map(fieldName => ( + + {fieldName.name} + + ))} + + ) : ( + + 暂无可用字段 + + ); + }, [dataList, selectField]); + const toolbar = useMemo( () => (
@@ -303,28 +312,9 @@ const ChartRichTextAdapter: FC<{ 预览 - { - setVisible(false); - }} - > - {reactQuillView} - ), - [ - visible, - setVisible, - reactQuillView, - quillModules, - quillValue, - quillChange, - isEditing, - ], + [quillModules, quillValue, isEditing, toolbar, quillChange], ); const ssp = e => { @@ -333,27 +323,44 @@ const ChartRichTextAdapter: FC<{ return ( - {quillModules && reactQuillEdit} - {quillModules && reactQuillView} + + {quillModules && reactQuillEdit} + {quillModules && !isEditing && reactQuillView} + + { + setVisible(false); + }} + > + {isEditing && reactQuillView} + ); }); export default ChartRichTextAdapter; -const TextWrap = styled.div` - position: relative; +const QuillBox = styled.div` width: 100%; height: 100%; - overflow: hidden; - + flex-direction: column; + display: flex; .react-quill { - width: 100%; - height: calc(100% - 90px); + flex: 1; + overflow-y: auto; } - - & .rich-text-modal { - width: 900px; + .react-quill-view { + flex: 1; + overflow-y: auto; } +`; +const TextWrap = styled.div` + width: 100%; + height: 100%; & .ql-snow { border: none; From af35b121543a59901647eda95a748df31e86469e Mon Sep 17 00:00:00 2001 From: tianlei Date: Thu, 23 Dec 2021 10:45:17 +0800 Subject: [PATCH 168/348] fix:(Chart)fix chart style --- .../ChartTools/ChartIFrameContainer.tsx | 13 +++++++------ .../WidgetCore/DataChartWidget/index.tsx | 16 ++++++++-------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx index 8401fc492..f210efa5d 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx @@ -74,12 +74,13 @@ const ChartIFrameContainer: FC<{ <> } diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx index ac05022b1..2f4b59ac2 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx @@ -142,18 +142,18 @@ export const DataChartWidget: React.FC = memo(() => { }, [cacheH, cacheW, chart, dataChart, dataset, widgetId]); return ( - {chartFrame} + {chartFrame} ); }); +const ChartFrameBox = styled.div` + position: absolute; + height: 100%; + width: 100%; + overflow: hidden; +`; const Wrap = styled.div` display: flex; flex: 1; - width: 100%; - height: 100%; - overflow: hidden; - & div { - max-width: 100%; - max-height: 100%; - } + position: relative; `; From 2a535dc3d5a8f8b9fb90b372f2c7c4b52a89c459 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Thu, 23 Dec 2021 12:00:41 +0800 Subject: [PATCH 169/348] feact: globalization --- .../pages/MainPage/Navbar/ModifyPassword.tsx | 22 +++-- .../MainPage/Navbar/OrganizationList.tsx | 4 +- .../src/app/pages/MainPage/Navbar/Profile.tsx | 2 + .../src/app/pages/MainPage/Navbar/index.tsx | 29 +++--- .../app/pages/MainPage/OrganizationForm.tsx | 14 +-- frontend/src/locales/en/translation.json | 57 ++++++++++-- frontend/src/locales/zh/translation.json | 92 ++++++++++++++----- 7 files changed, 166 insertions(+), 54 deletions(-) diff --git a/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx b/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx index e8a964b43..906cfb115 100644 --- a/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx @@ -1,5 +1,6 @@ import { Button, Form, Input, message, Modal } from 'antd'; import { RULES } from 'app/constants'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { selectLoggedInUser, selectModifyPasswordLoading, @@ -21,6 +22,7 @@ export const ModifyPassword: FC = ({ const loggedInUser = useSelector(selectLoggedInUser); const loading = useSelector(selectModifyPasswordLoading); const [form] = Form.useForm(); + const t = useI18NPrefix('main.nav.accout.changePassword'); const reset = useCallback(() => { form.resetFields(); @@ -38,7 +40,7 @@ export const ModifyPassword: FC = ({ modifyAccountPassword({ params, resolve: () => { - message.success('修改成功'); + message.success(t('success')); onCancel(); }, }), @@ -53,7 +55,7 @@ export const ModifyPassword: FC = ({ return ( = ({ wrapperCol={{ span: 12 }} onFinish={formSubmit} > - + - + = ({ diff --git a/frontend/src/app/pages/MainPage/Navbar/OrganizationList.tsx b/frontend/src/app/pages/MainPage/Navbar/OrganizationList.tsx index c97123192..12cde2864 100644 --- a/frontend/src/app/pages/MainPage/Navbar/OrganizationList.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/OrganizationList.tsx @@ -5,6 +5,7 @@ import { } from '@ant-design/icons'; import { Menu } from 'antd'; import { Avatar, MenuListItem, ToolbarButton } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { selectOrganizationListLoading, selectOrganizations, @@ -33,6 +34,7 @@ export function OrganizationList() { const organizations = useSelector(selectOrganizations); const orgId = useSelector(selectOrgId); const listLoading = useSelector(selectOrganizationListLoading); + const t = useI18NPrefix('main'); const showForm = useCallback(() => { setFormVisible(true); @@ -95,7 +97,7 @@ export function OrganizationList() { return ( - <h2>组织列表</h2> + <h2>{t('nav.organization.organizationList')}</h2> <ToolbarButton size="small" icon={<PlusOutlined />} diff --git a/frontend/src/app/pages/MainPage/Navbar/Profile.tsx b/frontend/src/app/pages/MainPage/Navbar/Profile.tsx index abe854928..9cbf4988d 100644 --- a/frontend/src/app/pages/MainPage/Navbar/Profile.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/Profile.tsx @@ -1,5 +1,6 @@ import { Button, Form, Input, message, Modal, ModalProps, Upload } from 'antd'; import { Avatar } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { selectLoggedInUser, selectSaveProfileLoading, @@ -21,6 +22,7 @@ export function Profile({ visible, onCancel }: ModalProps) { const loading = useSelector(selectSaveProfileLoading); const [saveDisabled, setSaveDisabled] = useState(true); const [form] = Form.useForm(); + const t = useI18NPrefix('main.nav'); const reset = useCallback(() => { form.resetFields(); diff --git a/frontend/src/app/pages/MainPage/Navbar/index.tsx b/frontend/src/app/pages/MainPage/Navbar/index.tsx index 28851e1eb..143346eb3 100644 --- a/frontend/src/app/pages/MainPage/Navbar/index.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/index.tsx @@ -13,6 +13,7 @@ import { import { List, Menu, Tooltip } from 'antd'; import logo from 'app/assets/images/logo.svg'; import { Avatar, MenuListItem, Popup } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { selectCurrentOrganization, selectDownloadPolling, @@ -66,7 +67,7 @@ export function Navbar() { '/organizations/:orgId/:moduleName', ); const { i18n } = useTranslation(); - + const t = useI18NPrefix('main'); const brandClick = useCallback(() => { history.push('/'); }, [history]); @@ -91,13 +92,13 @@ export function Navbar() { () => [ { name: 'variables', - title: '公共变量设置', + title: t('subNavs.variables.title'), icon: <FunctionOutlined />, module: ResourceTypes.Manager, }, { name: 'orgSettings', - title: '组织设置', + title: t('subNavs.orgSettings.title'), icon: <SettingOutlined />, module: ResourceTypes.Manager, }, @@ -109,31 +110,31 @@ export function Navbar() { () => [ { name: 'vizs', - title: '可视化', + title: t('nav.vizs'), icon: <i className="iconfont icon-xietongzhihuidaping" />, module: ResourceTypes.Viz, }, { name: 'views', - title: '数据视图', + title: t('nav.views'), icon: <i className="iconfont icon-24gf-table" />, module: ResourceTypes.View, }, { name: 'sources', - title: '数据源', + title: t('nav.sources'), icon: <i className="iconfont icon-shujukupeizhi" />, module: ResourceTypes.Source, }, { name: 'schedules', - title: '定时任务', + title: t('nav.schedules'), icon: <i className="iconfont icon-fasongyoujian" />, module: ResourceTypes.Schedule, }, { name: 'members', - title: '成员与角色', + title: t('nav.members'), icon: <i className="iconfont icon-users1" />, isActive: (_, location) => !!location.pathname.match( @@ -143,13 +144,13 @@ export function Navbar() { }, { name: 'permissions', - title: '权限', + title: t('nav.permissions'), icon: <SafetyCertificateFilled />, module: ResourceTypes.Manager, }, { name: 'toSub', - title: '设置', + title: t('nav.settings'), icon: <SettingFilled />, isActive: (_, location) => { const reg = new RegExp( @@ -273,19 +274,19 @@ export function Navbar() { key="profile" prefix={<ProfileOutlined className="icon" />} > - <p>账号设置</p> + <p>{t('nav.accout.accountSettings.title')}</p> </MenuListItem> <MenuListItem key="password" prefix={<FormOutlined className="icon" />} > - <p>修改密码</p> + <p>{t('nav.accout.changePassword.title')}</p> </MenuListItem> <Menu.SubMenu icon={<SwapOutlined className="icon" />} key="language" - title="切换语言" + title={t('nav.accout.switchLanguage.title')} > <Menu.Item key="zh">中文</Menu.Item> <Menu.Item key="en">English</Menu.Item> @@ -294,7 +295,7 @@ export function Navbar() { key="logout" prefix={<ExportOutlined className="icon" />} > - <p>退出登录</p> + <p>{t('nav.accout.logout.title')}</p> </MenuListItem> </Menu> } diff --git a/frontend/src/app/pages/MainPage/OrganizationForm.tsx b/frontend/src/app/pages/MainPage/OrganizationForm.tsx index fd834a615..2e789bc37 100644 --- a/frontend/src/app/pages/MainPage/OrganizationForm.tsx +++ b/frontend/src/app/pages/MainPage/OrganizationForm.tsx @@ -7,6 +7,7 @@ import { useHistory } from 'react-router'; import { request } from 'utils/request'; import { selectSaveOrganizationLoading } from './slice/selectors'; import { addOrganization } from './slice/thunks'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; const FormItem = Form.Item; interface OrganizationFormProps extends Omit<ModalProps, 'onCancel'> { @@ -18,6 +19,7 @@ export function OrganizationForm({ visible, onCancel }: OrganizationFormProps) { const history = useHistory(); const loading = useSelector(selectSaveOrganizationLoading); const [form] = Form.useForm(); + const t = useI18NPrefix('main.nav.organization'); const formSubmit = useCallback( values => { @@ -44,9 +46,9 @@ export function OrganizationForm({ visible, onCancel }: OrganizationFormProps) { return ( <Modal - title="创建组织" + title={t('organizationCreate')} visible={visible} - okText="保存并进入" + okText={t('saveDndEnter')} confirmLoading={loading} onOk={save} onCancel={onCancel} @@ -61,9 +63,9 @@ export function OrganizationForm({ visible, onCancel }: OrganizationFormProps) { > <FormItem name="name" - label="名称" + label={t('organizationName')} rules={[ - { required: true, message: '名称不能为空' }, + { required: true, message: t('nameIsEmptyPrompt') }, { validator: debounce((_, value) => { return request({ @@ -72,7 +74,7 @@ export function OrganizationForm({ visible, onCancel }: OrganizationFormProps) { params: { name: value }, }).then( () => Promise.resolve(), - () => Promise.reject(new Error('名称重复')), + () => Promise.reject(new Error(t('duplicateNamePrompt'))), ); }, DEFAULT_DEBOUNCE_WAIT), }, @@ -80,7 +82,7 @@ export function OrganizationForm({ visible, onCancel }: OrganizationFormProps) { > <Input /> </FormItem> - <FormItem name="description" label="描述"> + <FormItem name="description" label={t('organizationDescription')}> <Input.TextArea autoSize={{ minRows: 4, maxRows: 8 }} /> </FormItem> </Form> diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 414411bcd..50816b0b4 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -1,8 +1,58 @@ { "main": { "nav": { + "vizs": "可视化", + "views": "数据视图", + "sources": "数据源", + "schedules": "定时任务", + "members": "成员与角色", + "permissions": "权限", + "settings": "设置", "download": { "title": "Download List" + }, + "organization": { + "organizationList": "组织列表", + "organizationCreate": "创建组织", + "organizationName": "名称", + "nameIsEmptyPrompt": "名称不能为空", + "duplicateNamePrompt": "名称重复", + "organizationDescription": "描述", + "cancel": "取消", + "saveDndEnter": "保存并进入" + }, + "accout": { + "accountSettings": { + "title": "账号设置", + "clickUpload": "点击上传", + "userName": "用户名", + "email": "邮箱", + "name": "姓名", + "department": "部门", + "save": "保存" + }, + "changePassword": { + "title": "修改密码", + "oldPassword": "旧密码", + "newPassword": "新密码", + "confirmPassword": "确定新密码", + "success": "修改成功", + "save":"保存" + }, + "switchLanguage": { + "title": "切换语言" + }, + "logout": { + "title": "退出登录" + } + } + }, + "subNavs": { + "variables": { + "title": "公共变量设置" + }, + "orgSettings": { + "title": "组织设置" } } }, @@ -377,11 +427,6 @@ "published":"Published", "unpublished":"Unpublished", "archived":"Archived", - - - - - "share": { "link": "Link", "password": "Password", @@ -424,4 +469,4 @@ "cancel": "Cancel" } } -} +} \ No newline at end of file diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index a848d9798..905e64f23 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -1,8 +1,58 @@ { "main": { "nav": { + "vizs": "可视化", + "views": "数据视图", + "sources": "数据源", + "schedules": "定时任务", + "members": "成员与角色", + "permissions": "权限", + "settings": "设置", "download": { "title": "下载列表" + }, + "organization": { + "organizationList": "组织列表", + "organizationCreate": "创建组织", + "organizationName": "名称", + "nameIsEmptyPrompt": "名称不能为空", + "duplicateNamePrompt": "名称重复", + "organizationDescription": "描述", + "cancel": "取消", + "saveDndEnter": "保存并进入" + }, + "accout": { + "accountSettings": { + "title": "账号设置", + "clickUpload": "点击上传", + "userName": "用户名", + "email": "邮箱", + "name": "姓名", + "department": "部门", + "save": "保存" + }, + "changePassword": { + "title": "修改密码", + "oldPassword": "旧密码", + "newPassword": "新密码", + "confirmPassword": "确定新密码", + "success": "修改成功", + "save":"保存" + }, + "switchLanguage": { + "title": "切换语言" + }, + "logout": { + "title": "退出登录" + } + } + }, + "subNavs": { + "variables": { + "title": "公共变量设置" + }, + "orgSettings": { + "title": "组织设置" } } }, @@ -40,7 +90,7 @@ "controllerFacadeTypes": { "dropdownList": "下拉列表", "radioGroup": "单选按钮", - "checkboxGroup":"多选框", + "checkboxGroup": "多选框", "multiDropdownList": "多选下拉列表", "rangeTime": "日期范围", "rangeValue": "数值范围", @@ -368,15 +418,15 @@ "confirm": "请确认", "ok": "确认", "cancel": "取消", - "save":"保存" - }, + "save": "保存" + }, "edit": "编辑", "run": "运行", "publish": "发布", "cancelPublish": "取消发布", - "published":"已发布", - "unpublished":"未发布", - "archived":"已归档", + "published": "已发布", + "unpublished": "未发布", + "archived": "已归档", "share": { "link": "链接", "password": "密码", @@ -387,17 +437,17 @@ "downloadData": "下载数据" } }, - "board":{ - "action":{ - "dataChart":"数据图表", - "media":"媒体组件", - "container":"容器", - "controller":"控制器", - "undo":"撤销", - "redo":"重做", - "delete":"删除", - "copy":"复制", - "paste":"粘贴" + "board": { + "action": { + "dataChart": "数据图表", + "media": "媒体组件", + "container": "容器", + "controller": "控制器", + "undo": "撤销", + "redo": "重做", + "delete": "删除", + "copy": "复制", + "paste": "粘贴" } } }, @@ -412,11 +462,11 @@ "pleaseInputPassword": "请输入密码" } }, - "components":{ - "colorPicker":{ - "more":"更多", + "components": { + "colorPicker": { + "more": "更多", "ok": "确认", "cancel": "取消" } } -} +} \ No newline at end of file From b361807809c5325f4c0d0d9f095bbe7482576194 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Thu, 23 Dec 2021 12:58:09 +0800 Subject: [PATCH 170/348] feat(chart): support real relative dates --- .../src/app/components/From/FormItemEx.tsx | 4 + .../ChartFieldAction/AliasAction.tsx | 3 - .../DateConditionConfiguration.tsx | 53 +++++--- .../FilterFacadeConfiguration.tsx | 9 +- .../MannualRangeTimeSelector.tsx | 14 +- .../ManualSingleTimeSelector.tsx | 46 ++++--- .../RecommendRangeTimeSelector.tsx | 34 ++--- .../RelativeTimeSelector.tsx | 48 ++++--- .../models/ChartFilterCondition.ts | 5 +- .../models/ChartHttpRequest.ts | 124 +++++++++++------- .../ControllerWIdget/ControllerWidgetCore.tsx | 8 +- .../ValuesSetter/TimeSetter/TimeSetter.tsx | 32 ++--- .../components/ControllerWidgetPanel/types.ts | 4 +- .../components/ControllerWidgetPanel/utils.ts | 8 +- .../app/pages/DashBoardPage/utils/index.ts | 6 +- .../components/MultiDropdownListFilter.tsx | 2 +- .../components/RangTimeFilter.tsx | 1 + frontend/src/app/types/ChartConfig.ts | 22 +++- frontend/src/app/types/FilterControlPanel.ts | 7 +- frontend/src/app/utils/time.ts | 19 +-- 20 files changed, 272 insertions(+), 177 deletions(-) diff --git a/frontend/src/app/components/From/FormItemEx.tsx b/frontend/src/app/components/From/FormItemEx.tsx index ab326cdb9..2672671b2 100644 --- a/frontend/src/app/components/From/FormItemEx.tsx +++ b/frontend/src/app/components/From/FormItemEx.tsx @@ -38,4 +38,8 @@ const StyledFromItemEx = styled(Form.Item)` .ant-form-item-explain { padding-left: 10px; } + + .ant-form-item-control-input { + width: 100%; + } `; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/AliasAction.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/AliasAction.tsx index 3029effa6..8a087f6d7 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/AliasAction.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/AliasAction.tsx @@ -76,7 +76,4 @@ export default AliasAction; const StyledAliasAction = styled(Space)` width: 100%; - .ant-form-item-control-input { - width: 100%; - } `; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/DateConditionConfiguration.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/DateConditionConfiguration.tsx index 07cdde075..d7c750759 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/DateConditionConfiguration.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/DateConditionConfiguration.tsx @@ -18,7 +18,9 @@ import { Tabs } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; -import { FC, memo } from 'react'; +import { TimeFilterSubType } from 'app/types/FilterControlPanel'; +import { FC, memo, useState } from 'react'; +import styled from 'styled-components/macro'; import ChartFilterCondition from '../../../../../models/ChartFilterCondition'; import TimeSelector from '../../ChartTimeSelector'; @@ -29,27 +31,40 @@ const DateConditionConfiguration: FC< } & I18NComponentProps > = memo(({ i18nPrefix, condition, onChange: onConditionChange }) => { const t = useI18NPrefix(i18nPrefix); + const [subType, setSubType] = useState( + () => condition?.subType || TimeFilterSubType.Recommend, + ); + + const handleConditionChanged = filter => { + onConditionChange?.(Object.assign(filter, { subType })); + }; return ( - <div> - <Tabs> - <Tabs.TabPane tab={t('recommend')} key="1"> - <TimeSelector.RecommendRangeTimeSelector - i18nPrefix={i18nPrefix} - condition={condition} - onConditionChange={onConditionChange} - /> - </Tabs.TabPane> - <Tabs.TabPane tab={t('manual')} key="2"> - <TimeSelector.MannualRangeTimeSelector - i18nPrefix={i18nPrefix} - condition={condition} - onFilterChange={onConditionChange} - /> - </Tabs.TabPane> - </Tabs> - </div> + <StyledDateConditionConfiguration activeKey={subType} onChange={setSubType}> + <Tabs.TabPane tab={t('recommend')} key={TimeFilterSubType.Recommend}> + <TimeSelector.RecommendRangeTimeSelector + i18nPrefix={i18nPrefix} + condition={condition} + onConditionChange={handleConditionChanged} + /> + </Tabs.TabPane> + <Tabs.TabPane tab={t('manual')} key={TimeFilterSubType.Manual}> + <TimeSelector.MannualRangeTimeSelector + i18nPrefix={i18nPrefix} + condition={condition} + onFilterChange={handleConditionChanged} + /> + </Tabs.TabPane> + </StyledDateConditionConfiguration> ); }); export default DateConditionConfiguration; + +const StyledDateConditionConfiguration = styled(Tabs)` + width: 100%; + + .ant-tabs-content-holder { + margin: 10px 0; + } +`; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterFacadeConfiguration.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterFacadeConfiguration.tsx index 8f8522d0b..d18b7e2e1 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterFacadeConfiguration.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterFacadeConfiguration.tsx @@ -18,12 +18,9 @@ import { InputNumber, Row, Select, Space } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; -import { - FilterConditionType, - FilterFacade, -} from 'app/types/ChartConfig'; -import { ChartDataViewFieldCategory } from 'app/types/ChartDataView'; import ChartFilterCondition from 'app/pages/ChartWorkbenchPage/models/ChartFilterCondition'; +import { FilterConditionType, FilterFacade } from 'app/types/ChartConfig'; +import { ChartDataViewFieldCategory } from 'app/types/ChartDataView'; import { ControllerFacadeTypes, ControllerRadioFacadeTypes, @@ -72,7 +69,7 @@ const getFacadeOptions = (condition, category) => { case FilterConditionType.Value: return [ControllerFacadeTypes.Value]; case FilterConditionType.RangeTime: - case FilterConditionType.RelativeTime: + case FilterConditionType.RelativeTime: // TODO(Stephen): to be new Range time component for both manual and recomend return [ControllerFacadeTypes.RangeTime]; case FilterConditionType.Tree: return [ControllerFacadeTypes.Tree]; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/MannualRangeTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/MannualRangeTimeSelector.tsx index 06ef747eb..5c4561c6d 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/MannualRangeTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/MannualRangeTimeSelector.tsx @@ -19,11 +19,7 @@ import { Row, Space } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import TimeConfigContext from 'app/pages/ChartWorkbenchPage/contexts/TimeConfigContext'; -import { - FilterCondition, - FilterConditionType, -} from 'app/types/ChartConfig'; -import moment from 'moment'; +import { FilterCondition, FilterConditionType } from 'app/types/ChartConfig'; import { FC, memo, useContext, useState } from 'react'; import ChartFilterCondition, { ConditionBuilder, @@ -40,8 +36,8 @@ const MannualRangeTimeSelector: FC< const { format } = useContext(TimeConfigContext); const [timeRange, setTimeRange] = useState(() => { if (condition?.type === FilterConditionType.RangeTime) { - const startTime = moment(condition?.value?.[0]); - const endTime = moment(condition?.value?.[1]); + const startTime = condition?.value?.[0]; + const endTime = condition?.value?.[1]; return [startTime, endTime]; } return []; @@ -52,7 +48,7 @@ const MannualRangeTimeSelector: FC< setTimeRange(timeRange); const filterRow = new ConditionBuilder(condition) - .setValue((timeRange || []).map(d => d.toString())) + .setValue(timeRange || []) .asRangeTime(); onFilterChange && onFilterChange(filterRow); }; @@ -66,11 +62,13 @@ const MannualRangeTimeSelector: FC< </Row> <Space direction="vertical" size={12}> <ManualSingleTimeSelector + time={timeRange?.[0] as any} isStart={true} i18nPrefix={i18nPrefix} onTimeChange={handleTimeChange(0)} /> <ManualSingleTimeSelector + time={timeRange?.[1] as any} isStart={false} i18nPrefix={i18nPrefix} onTimeChange={handleTimeChange(1)} diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ManualSingleTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ManualSingleTimeSelector.tsx index b30e54bcf..9291faf9c 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ManualSingleTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ManualSingleTimeSelector.tsx @@ -18,41 +18,53 @@ import { DatePicker, Select, Space } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; -import { RelativeOrExactTime } from 'app/types/FilterControlPanel'; -import { Moment } from 'moment'; +import { TimeFilterConditionValue } from 'app/types/ChartConfig'; +import { TimeFilterValueCategory } from 'app/types/FilterControlPanel'; +import { formatTime } from 'app/utils/time'; +import { FILTER_TIME_FORMATTER_IN_QUERY } from 'globalConstants'; +import moment from 'moment'; import { FC, memo, useState } from 'react'; import styled from 'styled-components/macro'; import RelativeTimeSelector from './RelativeTimeSelector'; const ManualSingleTimeSelector: FC< { - isStart?: boolean; - time?: Moment; - onTimeChange: (time: Moment) => void; + time?: TimeFilterConditionValue; + isStart: boolean; + onTimeChange: (time) => void; } & I18NComponentProps -> = memo(({ isStart, i18nPrefix, time, onTimeChange }) => { +> = memo(({ time, isStart, i18nPrefix, onTimeChange }) => { const t = useI18NPrefix(i18nPrefix); - const [type, setType] = useState(RelativeOrExactTime.Exact); + const [type, setType] = useState(() => { + return typeof time === 'string' + ? TimeFilterValueCategory.Exact + : TimeFilterValueCategory.Relative; + }); const handleTimeChange = time => { onTimeChange?.(time); }; + const handleMomentTimeChange = momentTime => { + const timeStr = formatTime(momentTime, FILTER_TIME_FORMATTER_IN_QUERY); + onTimeChange?.(timeStr); + }; + const renderTimeSelector = type => { switch (type) { - case RelativeOrExactTime.Exact: + case TimeFilterValueCategory.Exact: return ( <DatePicker showTime - value={time} - onChange={handleTimeChange} + value={moment(time as string)} + onChange={handleMomentTimeChange} placeholder={t('pleaseSelect')} /> ); - case RelativeOrExactTime.Relative: + case TimeFilterValueCategory.Relative: return ( <RelativeTimeSelector - isStart={isStart} + time={time} i18nPrefix={i18nPrefix} onChange={handleTimeChange} /> @@ -63,11 +75,11 @@ const ManualSingleTimeSelector: FC< return ( <StyledManualSingleTimeSelector> <Select value={type} onChange={value => setType(value)}> - <Select.Option value={RelativeOrExactTime.Exact}> - {t(RelativeOrExactTime.Exact)} + <Select.Option value={TimeFilterValueCategory.Exact}> + {t(TimeFilterValueCategory.Exact)} </Select.Option> - <Select.Option value={RelativeOrExactTime.Relative}> - {t(RelativeOrExactTime.Relative)} + <Select.Option value={TimeFilterValueCategory.Relative}> + {t(TimeFilterValueCategory.Relative)} </Select.Option> </Select> {isStart ? `${t('startTime')} : ` : `${t('endTime')} : `} @@ -79,7 +91,7 @@ const ManualSingleTimeSelector: FC< export default ManualSingleTimeSelector; const StyledManualSingleTimeSelector = styled(Space)` - & .ant-select { + & > .ant-select { width: 80px; } `; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx index 174b60b1e..a9acd3199 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx @@ -20,9 +20,9 @@ import { Radio, Row, Space } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import TimeConfigContext from 'app/pages/ChartWorkbenchPage/contexts/TimeConfigContext'; import { FilterCondition } from 'app/types/ChartConfig'; -import { convertRelativeTimeRange } from 'app/utils/time'; +import { formatTime, recommendTimeRangeConverter } from 'app/utils/time'; import { RECOMMEND_TIME } from 'globalConstants'; -import { FC, memo, useContext, useState } from 'react'; +import { FC, memo, useContext, useMemo, useState } from 'react'; import ChartFilterCondition, { ConditionBuilder, } from '../../../../models/ChartFilterCondition'; @@ -35,29 +35,31 @@ const RecommendRangeTimeSelector: FC< > = memo(({ i18nPrefix, condition, onConditionChange }) => { const t = useI18NPrefix(i18nPrefix); const { format } = useContext(TimeConfigContext); - const [timeRange, setTimeRange] = useState<string[]>([]); - const [relativeTime, setRelativeTime] = useState<string | undefined>(); - - const handleChange = relativeTime => { - const timeRange = convertRelativeTimeRange(relativeTime); - setTimeRange(timeRange); + const [recommend, setRecommend] = useState<string | undefined>(() => + String(condition?.value), + ); - setRelativeTime(relativeTime); + const handleChange = recommendTime => { + setRecommend(recommendTime); const filter = new ConditionBuilder(condition) - .setValue(timeRange) - .asRangeTime(); + .setValue(recommendTime) + .asRecommendTime(); onConditionChange?.(filter); }; + const rangeTimes = useMemo(() => { + return recommendTimeRangeConverter(recommend); + }, [recommend]); + return ( - <div> + <> <Row> - {/* {`${t('currentTime')} : ${timeRange + {`${t('currentTime')} : ${rangeTimes ?.map(t => formatTime(t, format)) - .join(' - ')}`} */} + .join(' - ')}`} </Row> <Radio.Group - value={relativeTime} + value={recommend} onChange={e => handleChange(e.target?.value)} > <Space direction="vertical"> @@ -87,7 +89,7 @@ const RecommendRangeTimeSelector: FC< </Radio> </Space> </Radio.Group> - </div> + </> ); }); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RelativeTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RelativeTimeSelector.tsx index 226aa5309..6b2815037 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RelativeTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RelativeTimeSelector.tsx @@ -18,29 +18,37 @@ import { InputNumber, Select, Space } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; -import { getTime } from 'app/utils/time'; +import { TimeFilterConditionValue } from 'app/types/ChartConfig'; import { TIME_DIRECTION, TIME_UNIT_OPTIONS } from 'globalConstants'; import { unitOfTime } from 'moment'; import { FC, memo, useState } from 'react'; import styled from 'styled-components/macro'; + const RelativeTimeSelector: FC< { - isStart?: boolean; + time?: TimeFilterConditionValue; onChange: (time) => void; } & I18NComponentProps -> = memo(({ isStart, i18nPrefix, onChange }) => { +> = memo(({ time, i18nPrefix, onChange }) => { const t = useI18NPrefix(i18nPrefix); - const [amount, setAmount] = useState(0); - const [unit, setUnit] = useState<unitOfTime.DurationConstructor>('d'); - const [direction, setDirection] = useState('-'); + const [amount, setAmount] = useState(() => (time as any)?.amount || 1); + const [unit, setUnit] = useState<unitOfTime.DurationConstructor>( + () => (time as any)?.unit || 'd', + ); + const [direction, setDirection] = useState( + () => (time as any)?.direction || '-', + ); const handleTimeChange = ( unit: unitOfTime.DurationConstructor, amount: number, direction: string, ) => { - const time = getTime(+(direction + amount), unit)(unit, isStart); - onChange?.(time); + onChange?.({ + unit, + amount, + direction, + }); }; const handleUnitChange = (newUnit: unitOfTime.DurationConstructor) => { @@ -60,19 +68,23 @@ const RelativeTimeSelector: FC< return ( <StyledRelativeTimeSelector> - <InputNumber - defaultValue={amount} - step={1} - min={0} - onChange={handleAmountChange} - /> - <Select defaultValue={unit} onChange={handleUnitChange}> - {TIME_UNIT_OPTIONS.map(item => ( + <Select defaultValue={direction} onChange={handleDirectionChange}> + {TIME_DIRECTION.map(item => ( <Select.Option value={item.value}>{t(item.name)}</Select.Option> ))} </Select> - <Select defaultValue={direction} onChange={handleDirectionChange}> - {TIME_DIRECTION.map(item => ( + {TIME_DIRECTION.filter(d => d.name !== 'current').find( + d => d.value === direction, + ) && ( + <InputNumber + defaultValue={amount} + step={1} + min={1} + onChange={handleAmountChange} + /> + )} + <Select defaultValue={unit} onChange={handleUnitChange}> + {TIME_UNIT_OPTIONS.map(item => ( <Select.Option value={item.value}>{t(item.name)}</Select.Option> ))} </Select> diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartFilterCondition.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartFilterCondition.ts index 409278085..283023f2d 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartFilterCondition.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartFilterCondition.ts @@ -28,6 +28,7 @@ class ChartFilterCondition implements FilterCondition { type = FilterConditionType.Filter; value?; visualType = ''; + subType; operator?: string; children?: ChartFilterCondition[]; @@ -37,6 +38,7 @@ class ChartFilterCondition implements FilterCondition { this.type = condition.type || this.type; this.value = condition.value; this.visualType = condition.visualType; + this.subType = condition.subType; this.operator = condition.operator; this.children = (condition.children || []).map( child => new ChartFilterCondition(child), @@ -107,6 +109,7 @@ export class ConditionBuilder { if (condition) { this.condition.name = condition.name; this.condition.visualType = condition.visualType; + this.condition.subType = condition.subType; this.condition.type = condition.type; this.condition.value = condition.value; this.condition.operator = condition.operator; @@ -162,7 +165,7 @@ export class ConditionBuilder { return this.condition; } - asRelativeTime(name?, sqlType?) { + asRecommendTime(name?, sqlType?) { this.condition.type = FilterConditionType.RelativeTime; this.condition.operator = FilterSqlOperator.Equal; this.condition.name = name || this.condition.name; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts index 2d6786e8a..bb77b8d75 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts @@ -17,8 +17,13 @@ */ import { ChartDatasetPageInfo } from 'app/types/ChartDataset'; +import { TimeFilterSubType } from 'app/types/FilterControlPanel'; import { getStyleValue } from 'app/utils/chartHelper'; -import { formatTime } from 'app/utils/time'; +import { + formatTime, + getTime, + recommendTimeRangeConverter, +} from 'app/utils/time'; import { FILTER_TIME_FORMATTER_IN_QUERY } from 'globalConstants'; import { isEmptyArray, IsKeyIn } from 'utils/object'; import { @@ -155,60 +160,83 @@ export class ChartDataRequestBuilder { }) .map(col => col); - const _transformToRequest = (fields: ChartDataSectionField[]) => { - const _convertTime = (visualType, value) => { - if (visualType !== 'DATE') { - return value; - } - return formatTime(value, FILTER_TIME_FORMATTER_IN_QUERY); - }; + return this.normalizeFilters(fields); + } - const convertValues = (field: ChartDataSectionField) => { - if (Array.isArray(field.filter?.condition?.value)) { - return field.filter?.condition?.value - .map(v => { - if (IsKeyIn(v as FilterValueOption, 'key')) { - const listItem = v as FilterValueOption; - if (!listItem.isSelected) { - return undefined; - } - return { - value: listItem.key, - valueType: field.type, - }; + private normalizeFilters = (fields: ChartDataSectionField[]) => { + const _timeConverter = (visualType, subType, value) => { + if (visualType !== 'DATE') { + return value; + } + if (typeof value === 'object') { + const time = getTime(+(value.direction + value.amount), value.unit)( + value.unit, + value.isStart, + ); + return formatTime(time, FILTER_TIME_FORMATTER_IN_QUERY); + } + return formatTime(value, FILTER_TIME_FORMATTER_IN_QUERY); + }; + + const _transformFieldValues = (field: ChartDataSectionField) => { + const conditionValue = field.filter?.condition?.value; + if (!conditionValue) { + return null; + } + if (Array.isArray(conditionValue)) { + return conditionValue + .map(v => { + if (IsKeyIn(v as FilterValueOption, 'key')) { + const listItem = v as FilterValueOption; + if (!listItem.isSelected) { + return undefined; } return { - value: _convertTime(field.filter?.condition?.visualType, v), + value: listItem.key, valueType: field.type, }; - }) - .filter(Boolean) as any[]; - } - const v = field.filter?.condition?.value; - if (!v) { - return null; - } - return [ - { - value: _convertTime(field.filter?.condition?.visualType, v), - valueType: field.type, - }, - ]; - }; - - return fields.map(field => ({ - aggOperator: - field.aggregate === AggregateFieldActionType.NONE - ? null - : field.aggregate, - column: field.colName, - sqlOperator: field.filter?.condition?.operator!, - values: convertValues(field) || [], - })); + } else { + return { + value: _timeConverter( + field.filter?.condition?.visualType, + field.filter?.condition?.subType, + v, + ), + valueType: field.type, + }; + } + }) + .filter(Boolean) as any[]; + } + if (field?.filter?.condition?.subType === TimeFilterSubType.Recommend) { + const timeRange = recommendTimeRangeConverter(conditionValue); + return (timeRange || []).map(t => ({ + value: t, + valueType: field.type, + })); + } + return [ + { + value: _timeConverter( + field.filter?.condition?.visualType, + field.filter?.condition?.subType, + conditionValue, + ), + valueType: field.type, + }, + ]; }; - return _transformToRequest(fields); - } + return fields.map(field => ({ + aggOperator: + field.aggregate === AggregateFieldActionType.NONE + ? null + : field.aggregate, + column: field.colName, + sqlOperator: field.filter?.condition?.operator!, + values: _transformFieldValues(field) || [], + })); + }; private buildOrders() { const sortColumns = this.chartDataConfigs diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ControllerWIdget/ControllerWidgetCore.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ControllerWIdget/ControllerWidgetCore.tsx index 8eb03e988..3923a51bf 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ControllerWIdget/ControllerWidgetCore.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ControllerWIdget/ControllerWidgetCore.tsx @@ -31,7 +31,7 @@ import { getControllerDateValues } from 'app/pages/DashBoardPage/utils'; import { FilterValueOption } from 'app/types/ChartConfig'; import { ControllerFacadeTypes, - RelativeOrExactTime, + TimeFilterValueCategory, } from 'app/types/FilterControlPanel'; import produce from 'immer'; import React, { @@ -159,11 +159,11 @@ export const ControllerWidgetCore: React.FC<{}> = memo(() => { const nextFilterDate: ControllerDate = { ...controllerDate!, startTime: { - relativeOrExact: RelativeOrExactTime.Exact, + relativeOrExact: TimeFilterValueCategory.Exact, exactValue: timeValues?.[0], }, endTime: { - relativeOrExact: RelativeOrExactTime.Exact, + relativeOrExact: TimeFilterValueCategory.Exact, exactValue: timeValues?.[1], }, }; @@ -183,7 +183,7 @@ export const ControllerWidgetCore: React.FC<{}> = memo(() => { const nextFilterDate: ControllerDate = { ...controllerDate!, startTime: { - relativeOrExact: RelativeOrExactTime.Exact, + relativeOrExact: TimeFilterValueCategory.Exact, exactValue: value, }, }; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TimeSetter/TimeSetter.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TimeSetter/TimeSetter.tsx index 7ccd2e573..2e296c331 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TimeSetter/TimeSetter.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TimeSetter/TimeSetter.tsx @@ -19,7 +19,7 @@ import { Form, FormInstance, Select } from 'antd'; import { ControllerWidgetContent } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import { ControllerFacadeTypes, - RelativeOrExactTime, + TimeFilterValueCategory, } from 'app/types/FilterControlPanel'; import produce from 'immer'; import React, { useCallback } from 'react'; @@ -74,7 +74,7 @@ export const TimeSetter: React.FC<{ if (!date) { return false; } - if (date.relativeOrExact === RelativeOrExactTime.Exact) { + if (date.relativeOrExact === TimeFilterValueCategory.Exact) { return date.exactValue; } else { return date.relativeValue; @@ -97,8 +97,8 @@ export const TimeSetter: React.FC<{ }; const onStartRelativeChange = useCallback( value => { - const valueType: RelativeOrExactTime = value; - if (valueType === RelativeOrExactTime.Relative) { + const valueType: TimeFilterValueCategory = value; + if (valueType === TimeFilterValueCategory.Relative) { const startTime = getControllerConfig()?.controllerDate?.startTime; if (startTime?.relativeValue) { } else { @@ -128,8 +128,8 @@ export const TimeSetter: React.FC<{ const onEndRelativeChange = useCallback( value => { - const valueType: RelativeOrExactTime = value; - if (valueType === RelativeOrExactTime.Relative) { + const valueType: TimeFilterValueCategory = value; + if (valueType === TimeFilterValueCategory.Relative) { const endTime = getControllerConfig()?.controllerDate?.endTime; if (endTime?.relativeValue) { } else { @@ -167,14 +167,14 @@ export const TimeSetter: React.FC<{ > <Select style={{ width: '100px' }} onChange={onChange}> <Select.Option - key={RelativeOrExactTime.Exact} - value={RelativeOrExactTime.Exact} + key={TimeFilterValueCategory.Exact} + value={TimeFilterValueCategory.Exact} > {'固定值'} </Select.Option> <Select.Option - key={RelativeOrExactTime.Relative} - value={RelativeOrExactTime.Relative} + key={TimeFilterValueCategory.Relative} + value={TimeFilterValueCategory.Relative} > {'相对值'} </Select.Option> @@ -226,11 +226,11 @@ export const TimeSetter: React.FC<{ > {renderROE(StartTimeROEName, onStartRelativeChange)} - {getStartRelativeOrExact() === RelativeOrExactTime.Exact && + {getStartRelativeOrExact() === TimeFilterValueCategory.Exact && renderExact(StartTimeExactName, getPickerType)} {getStartRelativeOrExact() === - RelativeOrExactTime.Relative && ( + TimeFilterValueCategory.Relative && ( <RelativeTimeSetter relativeName={StartTimeRelativeName} /> )} </Form.Item> @@ -245,10 +245,10 @@ export const TimeSetter: React.FC<{ > <Form.Item label={'默认值-起始'} shouldUpdate> {renderROE(StartTimeROEName, onStartRelativeChange)} - {getStartRelativeOrExact() === RelativeOrExactTime.Exact && + {getStartRelativeOrExact() === TimeFilterValueCategory.Exact && renderExact(StartTimeExactName, getPickerType)} {getStartRelativeOrExact() === - RelativeOrExactTime.Relative && ( + TimeFilterValueCategory.Relative && ( <RelativeTimeSetter relativeName={StartTimeRelativeName} /> )} </Form.Item> @@ -259,10 +259,10 @@ export const TimeSetter: React.FC<{ > {renderROE(EndTimeROEName, onEndRelativeChange)} - {getEndRelativeOrExact() === RelativeOrExactTime.Exact && + {getEndRelativeOrExact() === TimeFilterValueCategory.Exact && renderExact(EndTimeExactName, getPickerType)} - {getEndRelativeOrExact() === RelativeOrExactTime.Relative && ( + {getEndRelativeOrExact() === TimeFilterValueCategory.Relative && ( <RelativeTimeSetter relativeName={EndTimeRelativeName} /> )} </Form.Item> 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 76a59ba8b..7c227818c 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 @@ -5,7 +5,7 @@ import { } from 'app/pages/DashBoardPage/constants'; import { FilterValueOption } from 'app/types/ChartConfig'; import { ChartDataViewFieldType } from 'app/types/ChartDataView'; -import { RelativeOrExactTime } from 'app/types/FilterControlPanel'; +import { TimeFilterValueCategory } from 'app/types/FilterControlPanel'; import { FilterSqlOperator } from 'globalConstants'; import { Moment, unitOfTime } from 'moment'; import { VariableValueTypes } from '../../../../../MainPage/pages/VariablePage/constants'; @@ -80,7 +80,7 @@ export const PickerTypeOptions = [ ]; export interface ControllerDateType { - relativeOrExact: RelativeOrExactTime; + relativeOrExact: TimeFilterValueCategory; relativeValue?: RelativeDate; exactValue?: Moment | string | null; } 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 38a9f9b83..0523b2924 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 @@ -31,7 +31,7 @@ import { import { ControllerFacadeTypes, ControllerFacadeTypes as Opt, - RelativeOrExactTime, + TimeFilterValueCategory, } from 'app/types/FilterControlPanel'; import moment, { Moment } from 'moment'; import { FilterSqlOperator } from '../../../../../../../globalConstants'; @@ -202,7 +202,7 @@ export const getTimeControllerConfig = () => { config.controllerDate = { pickerType: 'date', startTime: { - relativeOrExact: RelativeOrExactTime.Exact, + relativeOrExact: TimeFilterValueCategory.Exact, exactValue: null, }, }; @@ -214,11 +214,11 @@ export const getRangeTimeControllerConfig = () => { config.controllerDate = { pickerType: 'date', startTime: { - relativeOrExact: RelativeOrExactTime.Exact, + relativeOrExact: TimeFilterValueCategory.Exact, exactValue: null, }, endTime: { - relativeOrExact: RelativeOrExactTime.Exact, + relativeOrExact: TimeFilterValueCategory.Exact, exactValue: null, }, }; diff --git a/frontend/src/app/pages/DashBoardPage/utils/index.ts b/frontend/src/app/pages/DashBoardPage/utils/index.ts index 18cc4c91a..1e0ca0e69 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/index.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/index.ts @@ -14,7 +14,7 @@ import ChartDataView, { } from 'app/types/ChartDataView'; import { ControllerFacadeTypes, - RelativeOrExactTime, + TimeFilterValueCategory, } from 'app/types/FilterControlPanel'; import { getTime } from 'app/utils/time'; import { FilterSqlOperator } from 'globalConstants'; @@ -273,7 +273,7 @@ export const getControllerDateValues = (obj: { }) => { const { endTime, startTime, pickerType } = obj.filterDate; let timeValues: [string, string] = ['', '']; - if (startTime.relativeOrExact === RelativeOrExactTime.Exact) { + if (startTime.relativeOrExact === TimeFilterValueCategory.Exact) { timeValues[0] = startTime.exactValue as string; } else { const { amount, unit, direction } = startTime.relativeValue!; @@ -281,7 +281,7 @@ export const getControllerDateValues = (obj: { timeValues[0] = time.format(DEFAULT_VALUE_DATE_FORMAT); } if (endTime) { - if (endTime.relativeOrExact === RelativeOrExactTime.Exact) { + if (endTime.relativeOrExact === TimeFilterValueCategory.Exact) { timeValues[1] = endTime.exactValue as string; if (obj.execute) { timeValues[1] = adjustRangeDataEndValue( diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/MultiDropdownListFilter.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/MultiDropdownListFilter.tsx index 700679438..43f4a874c 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/MultiDropdownListFilter.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/MultiDropdownListFilter.tsx @@ -64,7 +64,7 @@ const MultiDropdownListFilter: FC<PresentControllerFilterProps> = memo( multiple treeCheckable treeDefaultExpandAll - value={selectedNodes} + value={selectedNodes as any} onChange={handleSelectedChange} > {originalNodes?.map((n: FilterValueOption) => { diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangTimeFilter.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangTimeFilter.tsx index 1e2924211..bf03d23c1 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangTimeFilter.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangTimeFilter.tsx @@ -22,6 +22,7 @@ import moment from 'moment'; import { FC, memo, useState } from 'react'; import { PresentControllerFilterProps } from '.'; +// TODO(Stephen): to be use relative time const RangTimeFilter: FC<PresentControllerFilterProps> = memo( ({ condition, onConditionChange }) => { const [timeRange, setTimeRange] = useState<string[]>(() => { diff --git a/frontend/src/app/types/ChartConfig.ts b/frontend/src/app/types/ChartConfig.ts index 62999ffef..3b5f78803 100644 --- a/frontend/src/app/types/ChartConfig.ts +++ b/frontend/src/app/types/ChartConfig.ts @@ -19,8 +19,13 @@ import { ControllerFacadeTypes, ControllerVisibilityTypes, + TimeFilterSubType, } from 'app/types/FilterControlPanel'; -import { FilterSqlOperator, NumberUnitKey } from 'globalConstants'; +import { + FilterSqlOperator, + NumberUnitKey, + RECOMMEND_TIME, +} from 'globalConstants'; import { ValueOf } from 'types'; import { ChartDataViewFieldCategory, @@ -86,8 +91,10 @@ export type FilterCondition = { | number | [number, number] | string[] - | Array<FilterValueOption>; + | Array<FilterValueOption> + | TimeFilterConditionValue; visualType: string; + subType?: TimeFilterSubType | string; operator?: | string | Lowercase<keyof typeof FilterRelationType> @@ -95,6 +102,17 @@ export type FilterCondition = { children?: FilterCondition[]; }; +export type TimeFilterConditionValue = + | string + | string[] + | Lowercase<keyof typeof RECOMMEND_TIME> + | Array<{ + unit; + amount; + direction?: string; + }>; + +// TODO(Stephen): to be rename to `RelationFilterValue` export type FilterValueOption = { key: string; label: string; diff --git a/frontend/src/app/types/FilterControlPanel.ts b/frontend/src/app/types/FilterControlPanel.ts index 5534e3dc2..73147e0f2 100644 --- a/frontend/src/app/types/FilterControlPanel.ts +++ b/frontend/src/app/types/FilterControlPanel.ts @@ -36,11 +36,16 @@ export enum ControllerRadioFacadeTypes { Button = 'button', } -export enum RelativeOrExactTime { +export enum TimeFilterValueCategory { Relative = 'relative', Exact = 'exact', } +export enum TimeFilterSubType { + Recommend = 'recommend', + Manual = 'manual', +} + export enum ControllerVisibilityTypes { Hide = 'hide', Show = 'show', diff --git a/frontend/src/app/utils/time.ts b/frontend/src/app/utils/time.ts index 72d162dbe..93713cc25 100644 --- a/frontend/src/app/utils/time.ts +++ b/frontend/src/app/utils/time.ts @@ -20,10 +20,13 @@ import { DEFAULT_VALUE_DATE_FORMAT } from 'app/pages/MainPage/pages/VariablePage import { RECOMMEND_TIME } from 'globalConstants'; import moment, { Moment, unitOfTime } from 'moment'; -export function getTimeRange(amount?, unit?): (unitTime) => [string, string] { +export function getTimeRange( + amount?: [number, number], + unit?, +): (unitTime) => [string, string] { return unitOfTime => { - const startTime = moment().add(amount, unit).startOf(unitOfTime); - const endTime = moment().add(amount, unit).endOf(unitOfTime); + const startTime = moment().add(amount?.[0], unit).startOf(unitOfTime); + const endTime = moment().add(amount?.[1], unit).endOf(unitOfTime); return [ startTime.format(DEFAULT_VALUE_DATE_FORMAT), endTime.format(DEFAULT_VALUE_DATE_FORMAT), @@ -47,25 +50,25 @@ export function formatTime(time: string | Moment, format): string { return moment(time).format(format); } -export function convertRelativeTimeRange(relativeTimeRange) { +export function recommendTimeRangeConverter(relativeTimeRange) { let timeRange = getTimeRange()('d'); switch (relativeTimeRange) { case RECOMMEND_TIME.TODAY: break; case RECOMMEND_TIME.YESTERDAY: - timeRange = getTimeRange(-1, 'd')('d'); + timeRange = getTimeRange([-1, 0], 'd')('d'); break; case RECOMMEND_TIME.THISWEEK: timeRange = getTimeRange()('w'); break; case RECOMMEND_TIME.LAST_7_DAYS: - timeRange = getTimeRange(-7, 'd')('d'); + timeRange = getTimeRange([-7, 0], 'd')('d'); break; case RECOMMEND_TIME.LAST_30_DAYS: - timeRange = getTimeRange(-30, 'd')('d'); + timeRange = getTimeRange([-30, 0], 'd')('d'); break; case RECOMMEND_TIME.LAST_90_DAYS: - timeRange = getTimeRange(-90, 'd')('d'); + timeRange = getTimeRange([-90, 0], 'd')('d'); break; case RECOMMEND_TIME.LAST_1_MONTH: timeRange = getTimeRange()('M'); From 06bd092cb31530b1b6db86b59a090f2de837da2a Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Thu, 23 Dec 2021 13:09:25 +0800 Subject: [PATCH 171/348] refactor(chart): rename date filter value --- .../src/app/components/DragSortEditTable.tsx | 8 ++++---- .../app/hooks/useFetchFilterDataByCondtion.ts | 4 ++-- .../CategoryConditionConfiguration.tsx | 18 +++++++++--------- .../CategoryConditionEditableTable.tsx | 16 ++++++++-------- .../models/ChartHttpRequest.ts | 6 +++--- .../ControllerWIdget/ControllerWidgetCore.tsx | 4 ++-- .../ValuesOptionsSetter/CustomOptions.tsx | 18 +++++++++--------- .../ValuesOptionsSetter.tsx | 6 +++--- .../components/ControllerWidgetPanel/types.ts | 4 ++-- .../components/DropdownListFilter.tsx | 10 +++++----- .../components/MultiDropdownListFilter.tsx | 14 +++++++------- .../components/RadioGroupFilter.tsx | 12 ++++++------ frontend/src/app/types/ChartConfig.ts | 6 +++--- 13 files changed, 63 insertions(+), 63 deletions(-) diff --git a/frontend/src/app/components/DragSortEditTable.tsx b/frontend/src/app/components/DragSortEditTable.tsx index dfbc3ea86..e8696c7a8 100644 --- a/frontend/src/app/components/DragSortEditTable.tsx +++ b/frontend/src/app/components/DragSortEditTable.tsx @@ -18,7 +18,7 @@ import { Form, Input, Table, TableProps } from 'antd'; import { FormInstance } from 'antd/lib/form'; -import { FilterValueOption } from 'app/types/ChartConfig'; +import { RelationFilterValue } from 'app/types/ChartConfig'; import { createContext, useCallback, @@ -36,9 +36,9 @@ interface EditableCellProps { title: React.ReactNode; editable: boolean; children: React.ReactNode; - dataIndex: keyof FilterValueOption; - record: FilterValueOption; - handleSave: (record: FilterValueOption) => void; + dataIndex: keyof RelationFilterValue; + record: RelationFilterValue; + handleSave: (record: RelationFilterValue) => void; } interface EditableRowProps { diff --git a/frontend/src/app/hooks/useFetchFilterDataByCondtion.ts b/frontend/src/app/hooks/useFetchFilterDataByCondtion.ts index ae4dc42b0..192cbcbd7 100644 --- a/frontend/src/app/hooks/useFetchFilterDataByCondtion.ts +++ b/frontend/src/app/hooks/useFetchFilterDataByCondtion.ts @@ -19,7 +19,7 @@ import { FilterCondition, FilterConditionType, - FilterValueOption, + RelationFilterValue, } from 'app/types/ChartConfig'; import { BackendChart } from 'app/pages/ChartWorkbenchPage/slice/workbenchSlice'; import { getDistinctFields } from 'app/utils/fetch'; @@ -28,7 +28,7 @@ import useMount from './useMount'; export const useFetchFilterDataByCondtion = ( viewId?: string, condition?: FilterCondition, - onFinish?: (datas: FilterValueOption[]) => void, + onFinish?: (datas: RelationFilterValue[]) => void, view?: BackendChart['view'], ) => { useMount(() => { diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx index 5373370b8..3b46ed26c 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx @@ -19,7 +19,7 @@ import { Button, Row, Select, Space, Tabs, Transfer, Tree } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import useMount from 'app/hooks/useMount'; -import { FilterConditionType, FilterValueOption } from 'app/types/ChartConfig'; +import { FilterConditionType, RelationFilterValue } from 'app/types/ChartConfig'; import ChartDataView from 'app/types/ChartDataView'; import { getDistinctFields } from 'app/utils/fetch'; import { FilterSqlOperator } from 'globalConstants'; @@ -69,12 +69,12 @@ const CategoryConditionConfiguration: FC< if (Array.isArray(condition?.value)) { const firstValues = (condition?.value as [])?.filter(n => { - if (IsKeyIn(n as FilterValueOption, 'key')) { - return (n as FilterValueOption).isSelected; + if (IsKeyIn(n as RelationFilterValue, 'key')) { + return (n as RelationFilterValue).isSelected; } return false; }) || []; - values = firstValues?.map((n: FilterValueOption) => n.key); + values = firstValues?.map((n: RelationFilterValue) => n.key); } } return values || []; @@ -82,8 +82,8 @@ const CategoryConditionConfiguration: FC< const [selectedKeys, setSelectedKeys] = useState<string[]>([]); const [isTree, setIsTree] = useState(isTreeModel(condition?.value)); const [treeOptions, setTreeOptions] = useState<string[]>([]); - const [listDatas, setListDatas] = useState<FilterValueOption[]>([]); - const [treeDatas, setTreeDatas] = useState<FilterValueOption[]>([]); + const [listDatas, setListDatas] = useState<RelationFilterValue[]>([]); + const [treeDatas, setTreeDatas] = useState<RelationFilterValue[]>([]); useMount(() => { if (curTab === FilterConditionType.List) { @@ -109,7 +109,7 @@ const CategoryConditionConfiguration: FC< }; const setListSelctedState = ( - list?: FilterValueOption[], + list?: RelationFilterValue[], keys?: string[], ) => { return (list || []).map(c => @@ -118,7 +118,7 @@ const CategoryConditionConfiguration: FC< }; const setTreeCheckableState = ( - treeList?: FilterValueOption[], + treeList?: RelationFilterValue[], keys?: string[], ) => { return (treeList || []).map(c => { @@ -230,7 +230,7 @@ const CategoryConditionConfiguration: FC< children: assocaiteChildren, }; }) - .filter(i => Boolean(i)) as FilterValueOption[]; + .filter(i => Boolean(i)) as RelationFilterValue[]; return treeNodes; }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionEditableTable.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionEditableTable.tsx index d2364921a..064efaab0 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionEditableTable.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionEditableTable.tsx @@ -19,7 +19,7 @@ import { Button, Space } from 'antd'; import DragSortEditTable from 'app/components/DragSortEditTable'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; -import { FilterValueOption } from 'app/types/ChartConfig'; +import { RelationFilterValue } from 'app/types/ChartConfig'; import ChartDataView from 'app/types/ChartDataView'; import ChartFilterCondition, { ConditionBuilder, @@ -44,12 +44,12 @@ const CategoryConditionEditableTable: FC< fetchDataByField, }) => { const t = useI18NPrefix(i18nPrefix); - const [rows, setRows] = useState<FilterValueOption[]>([]); + const [rows, setRows] = useState<RelationFilterValue[]>([]); const [showPopover, setShowPopover] = useState(false); useEffect(() => { if (Array.isArray(condition?.value)) { - setRows(condition?.value as FilterValueOption[]); + setRows(condition?.value as RelationFilterValue[]); } else { setRows([]); } @@ -78,7 +78,7 @@ const CategoryConditionEditableTable: FC< title: t('tableHeaderAction'), dataIndex: 'action', width: 80, - render: (_, record: FilterValueOption) => ( + render: (_, record: RelationFilterValue) => ( <Space> {!record.isSelected && ( <a @@ -118,7 +118,7 @@ const CategoryConditionEditableTable: FC< } return { ...col, - onCell: (record: FilterValueOption) => ({ + onCell: (record: RelationFilterValue) => ({ record, editable: col.editable, dataIndex: col.dataIndex, @@ -144,7 +144,7 @@ const CategoryConditionEditableTable: FC< const handleAdd = () => { const newKey = rows?.length + 1; - const newRow: FilterValueOption = { + const newRow: RelationFilterValue = { key: String(newKey), label: String(newKey), isSelected: false, @@ -153,7 +153,7 @@ const CategoryConditionEditableTable: FC< handleFilterConditionChange(currentRows); }; - const handleRowStateUpdate = (row: FilterValueOption) => { + const handleRowStateUpdate = (row: RelationFilterValue) => { const oldRowIndex = rows.findIndex(r => r.index === row.index); rows.splice(oldRowIndex, 1, row); handleFilterConditionChange(rows); @@ -216,7 +216,7 @@ const CategoryConditionEditableTable: FC< dataSource={rows} size="small" bordered - rowKey={(r: FilterValueOption) => `${r.key}-${r.label}`} + rowKey={(r: RelationFilterValue) => `${r.key}-${r.label}`} columns={columnsWithCell} pagination={false} // onMoveRowEnd={onMoveRowEnd} diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts index bb77b8d75..74a0b94a5 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts @@ -32,7 +32,7 @@ import { ChartDataSectionField, ChartDataSectionType, ChartStyleSectionConfig, - FilterValueOption, + RelationFilterValue, SortActionType, } from '../../../types/ChartConfig'; import ChartDataView from '../../../types/ChartDataView'; @@ -186,8 +186,8 @@ export class ChartDataRequestBuilder { if (Array.isArray(conditionValue)) { return conditionValue .map(v => { - if (IsKeyIn(v as FilterValueOption, 'key')) { - const listItem = v as FilterValueOption; + if (IsKeyIn(v as RelationFilterValue, 'key')) { + const listItem = v as RelationFilterValue; if (!listItem.isSelected) { return undefined; } diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ControllerWIdget/ControllerWidgetCore.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ControllerWIdget/ControllerWidgetCore.tsx index 3923a51bf..83e5eadc8 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ControllerWIdget/ControllerWidgetCore.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ControllerWIdget/ControllerWidgetCore.tsx @@ -28,7 +28,7 @@ import { ControlOption, } from 'app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/types'; import { getControllerDateValues } from 'app/pages/DashBoardPage/utils'; -import { FilterValueOption } from 'app/types/ChartConfig'; +import { RelationFilterValue } from 'app/types/ChartConfig'; import { ControllerFacadeTypes, TimeFilterValueCategory, @@ -104,7 +104,7 @@ export const ControllerWidgetCore: React.FC<{}> = memo(() => { const dataRows = rows?.flat(2) || []; if (valueOptionType === 'common') { return dataRows.map(ele => { - const item: FilterValueOption = { + const item: RelationFilterValue = { key: ele, label: ele, // children? diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/CustomOptions.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/CustomOptions.tsx index 286c375f7..40d783b88 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/CustomOptions.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/CustomOptions.tsx @@ -17,21 +17,21 @@ */ import { Button, FormInstance, Space } from 'antd'; import { DragSortEditTable } from 'app/components/DragSortEditTable'; -import { FilterValueOption } from 'app/types/ChartConfig'; +import { RelationFilterValue } from 'app/types/ChartConfig'; import React, { memo, useCallback, useEffect, useState } from 'react'; import styled from 'styled-components/macro'; import { ControllerConfig } from '../../../types'; export interface CustomOptionsProps { form: FormInstance<{ config: ControllerConfig }> | undefined; - fieldRowData: FilterValueOption[]; + fieldRowData: RelationFilterValue[]; getControllerConfig: () => ControllerConfig; } export const CustomOptions: React.FC<CustomOptionsProps> = memo( ({ fieldRowData, form, getControllerConfig }) => { - const [rows, setRows] = useState<FilterValueOption[]>([]); + const [rows, setRows] = useState<RelationFilterValue[]>([]); const onChangeFilterOptions = useCallback( - (rows: FilterValueOption[]) => { + (rows: RelationFilterValue[]) => { setRows(rows); const config = getControllerConfig(); const valueOptions = [...rows.slice()]; @@ -51,7 +51,7 @@ export const CustomOptions: React.FC<CustomOptionsProps> = memo( }, [form, getControllerConfig]); const handleRowStateUpdate = useCallback( - (row: FilterValueOption) => { + (row: RelationFilterValue) => { const newRows = [...rows]; const targetIndex = newRows.findIndex(r => r.index === row.index); newRows.splice(targetIndex, 1, row); @@ -62,7 +62,7 @@ export const CustomOptions: React.FC<CustomOptionsProps> = memo( const handleAdd = useCallback(() => { const newKey = rows?.length || 0; - const newRow: FilterValueOption = { + const newRow: RelationFilterValue = { index: newKey, key: String(newKey), label: String(newKey), @@ -103,7 +103,7 @@ export const CustomOptions: React.FC<CustomOptionsProps> = memo( title: '操作', dataIndex: 'action', width: '30%', - render: (_, record: FilterValueOption) => ( + render: (_, record: RelationFilterValue) => ( <Space> <a href="#!" @@ -132,7 +132,7 @@ export const CustomOptions: React.FC<CustomOptionsProps> = memo( } return { ...col, - onCell: (record: FilterValueOption) => ({ + onCell: (record: RelationFilterValue) => ({ record, editable: col.editable, dataIndex: col.dataIndex, @@ -166,7 +166,7 @@ export const CustomOptions: React.FC<CustomOptionsProps> = memo( dataSource={rows} size="small" bordered - rowKey={(r: FilterValueOption) => `${r.key}-${r.label}`} + rowKey={(r: RelationFilterValue) => `${r.key}-${r.label}`} columns={columnsWithCell} pagination={false} onRow={(_, index) => 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 125ae799a..40ff32f1a 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 @@ -21,7 +21,7 @@ import { OPERATOR_TYPE_OPTION, ValueOptionType, } from 'app/pages/DashBoardPage/constants'; -import { FilterValueOption } from 'app/types/ChartConfig'; +import { RelationFilterValue } from 'app/types/ChartConfig'; import ChartDataView from 'app/types/ChartDataView'; import { ControllerFacadeTypes } from 'app/types/FilterControlPanel'; import { getDistinctFields } from 'app/utils/fetch'; @@ -36,7 +36,7 @@ const ValuesOptionsSetter: FC<{ form: FormInstance<{ config: ControllerConfig }> | undefined; viewMap: Record<string, ChartDataView>; }> = memo(({ form, viewMap, controllerType }) => { - const [optionValues, setOptionValues] = useState<FilterValueOption[]>([]); + const [optionValues, setOptionValues] = useState<RelationFilterValue[]>([]); const [targetKeys, setTargetKeys] = useState<string[]>([]); const getControllerConfig = useCallback(() => { @@ -78,7 +78,7 @@ const ValuesOptionsSetter: FC<{ const items: string[] = (collection || []).flatMap(c => c); const uniqueKeys = Array.from(new Set(items)); return uniqueKeys.map((ele, index) => { - const item: FilterValueOption = { + const item: RelationFilterValue = { index: index, key: ele, label: ele, 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 7c227818c..aa46ad0bd 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 @@ -3,7 +3,7 @@ import { ControllerVisibleType, ValueOptionType, } from 'app/pages/DashBoardPage/constants'; -import { FilterValueOption } from 'app/types/ChartConfig'; +import { RelationFilterValue } from 'app/types/ChartConfig'; import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { TimeFilterValueCategory } from 'app/types/FilterControlPanel'; import { FilterSqlOperator } from 'globalConstants'; @@ -34,7 +34,7 @@ export interface ControllerConfig { valueOptionType: ValueOptionType; // visibility: ControllerVisibility; sqlOperator: FilterSqlOperator; - valueOptions: FilterValueOption[]; + valueOptions: RelationFilterValue[]; controllerValues: any[]; required: boolean; // 是否允许空值 canChangeSqlOperator?: boolean; // 是否显示 sqlOperator 切换 diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/DropdownListFilter.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/DropdownListFilter.tsx index bd3816403..22eaf4300 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/DropdownListFilter.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/DropdownListFilter.tsx @@ -18,7 +18,7 @@ import { Select } from 'antd'; import useFetchFilterDataByCondtion from 'app/hooks/useFetchFilterDataByCondtion'; -import { FilterValueOption } from 'app/types/ChartConfig'; +import { RelationFilterValue } from 'app/types/ChartConfig'; import { updateBy } from 'app/utils/mutation'; import { FC, memo, useState } from 'react'; import styled from 'styled-components/macro'; @@ -27,14 +27,14 @@ import { PresentControllerFilterProps } from '.'; const DropdownListFilter: FC<PresentControllerFilterProps> = memo( ({ viewId, view, condition, onConditionChange }) => { - const [originalNodes, setOriginalNodes] = useState<FilterValueOption[]>( - condition?.value as FilterValueOption[], + const [originalNodes, setOriginalNodes] = useState<RelationFilterValue[]>( + condition?.value as RelationFilterValue[], ); const [selectedNode, setSelectedNode] = useState<string>(() => { if (Array.isArray(condition?.value)) { const firstValue = (condition?.value as [])?.find(n => { - if (IsKeyIn(n as FilterValueOption, 'key')) { - return (n as FilterValueOption).isSelected; + if (IsKeyIn(n as RelationFilterValue, 'key')) { + return (n as RelationFilterValue).isSelected; } return false; }); diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/MultiDropdownListFilter.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/MultiDropdownListFilter.tsx index 43f4a874c..77094b054 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/MultiDropdownListFilter.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/MultiDropdownListFilter.tsx @@ -18,7 +18,7 @@ import { TreeSelect } from 'antd'; import useFetchFilterDataByCondtion from 'app/hooks/useFetchFilterDataByCondtion'; -import { FilterValueOption } from 'app/types/ChartConfig'; +import { RelationFilterValue } from 'app/types/ChartConfig'; import { updateBy } from 'app/utils/mutation'; import { FC, memo, useMemo, useState } from 'react'; import styled from 'styled-components/macro'; @@ -27,8 +27,8 @@ import { PresentControllerFilterProps } from '.'; const MultiDropdownListFilter: FC<PresentControllerFilterProps> = memo( ({ viewId, view, condition, onConditionChange }) => { - const [originalNodes, setOriginalNodes] = useState<FilterValueOption[]>( - condition?.value as FilterValueOption[], + const [originalNodes, setOriginalNodes] = useState<RelationFilterValue[]>( + condition?.value as RelationFilterValue[], ); useFetchFilterDataByCondtion(viewId, condition, setOriginalNodes, view); @@ -45,12 +45,12 @@ const MultiDropdownListFilter: FC<PresentControllerFilterProps> = memo( if (typeof item === 'object') { const firstValues = (condition?.value as [])?.filter(n => { - if (IsKeyIn(n as FilterValueOption, 'key')) { - return (n as FilterValueOption).isSelected; + if (IsKeyIn(n as RelationFilterValue, 'key')) { + return (n as RelationFilterValue).isSelected; } return false; }) || []; - return firstValues?.map((n: FilterValueOption) => n.key); + return firstValues?.map((n: RelationFilterValue) => n.key); } else { return condition?.value || []; } @@ -67,7 +67,7 @@ const MultiDropdownListFilter: FC<PresentControllerFilterProps> = memo( value={selectedNodes as any} onChange={handleSelectedChange} > - {originalNodes?.map((n: FilterValueOption) => { + {originalNodes?.map((n: RelationFilterValue) => { return ( <TreeSelect.TreeNode key={n.key} value={n.key} title={n.label} /> ); diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RadioGroupFilter.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RadioGroupFilter.tsx index 758f9b04f..b6c6d5a01 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RadioGroupFilter.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RadioGroupFilter.tsx @@ -18,7 +18,7 @@ import { Radio } from 'antd'; import useFetchFilterDataByCondtion from 'app/hooks/useFetchFilterDataByCondtion'; -import { FilterValueOption } from 'app/types/ChartConfig'; +import { RelationFilterValue } from 'app/types/ChartConfig'; import { ControllerRadioFacadeTypes } from 'app/types/FilterControlPanel'; import { updateBy } from 'app/utils/mutation'; import { FC, memo, useState } from 'react'; @@ -27,14 +27,14 @@ import { PresentControllerFilterProps } from '.'; const RadioGroupFilter: FC<PresentControllerFilterProps> = memo( ({ viewId, view, condition, options, onConditionChange }) => { - const [originalNodes, setOriginalNodes] = useState<FilterValueOption[]>( - condition?.value as FilterValueOption[], + const [originalNodes, setOriginalNodes] = useState<RelationFilterValue[]>( + condition?.value as RelationFilterValue[], ); const [selectedNode, setSelectedNode] = useState<string>(() => { if (Array.isArray(condition?.value)) { const firstValue = (condition?.value as [])?.find(n => { - if (IsKeyIn(n as FilterValueOption, 'key')) { - return (n as FilterValueOption).isSelected; + if (IsKeyIn(n as RelationFilterValue, 'key')) { + return (n as RelationFilterValue).isSelected; } return false; }); @@ -58,7 +58,7 @@ const RadioGroupFilter: FC<PresentControllerFilterProps> = memo( }; const renderChildrenByRadioType = type => { - const _getProps = (n: FilterValueOption) => ({ + const _getProps = (n: RelationFilterValue) => ({ key: n.key, value: n.key, checked: n.key === selectedNode, diff --git a/frontend/src/app/types/ChartConfig.ts b/frontend/src/app/types/ChartConfig.ts index 3b5f78803..ac2db5045 100644 --- a/frontend/src/app/types/ChartConfig.ts +++ b/frontend/src/app/types/ChartConfig.ts @@ -91,7 +91,7 @@ export type FilterCondition = { | number | [number, number] | string[] - | Array<FilterValueOption> + | Array<RelationFilterValue> | TimeFilterConditionValue; visualType: string; subType?: TimeFilterSubType | string; @@ -113,12 +113,12 @@ export type TimeFilterConditionValue = }>; // TODO(Stephen): to be rename to `RelationFilterValue` -export type FilterValueOption = { +export type RelationFilterValue = { key: string; label: string; index?: number; isSelected?: boolean; - children?: FilterValueOption[]; + children?: RelationFilterValue[]; }; export const FilterRelationType = { From e210676b914c02e174e9f3576c657cae9d356645 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Thu, 23 Dec 2021 14:38:00 +0800 Subject: [PATCH 172/348] fix(chart): should save default time value when time category changed or created --- .../ChartTimeSelector/ExactTimeSelector.tsx | 57 +++++++++++++++++++ .../ManualSingleTimeSelector.tsx | 29 ++++------ .../RelativeTimeSelector.tsx | 8 ++- frontend/src/app/types/ChartConfig.ts | 1 - 4 files changed, 75 insertions(+), 20 deletions(-) create mode 100644 frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ExactTimeSelector.tsx diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ExactTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ExactTimeSelector.tsx new file mode 100644 index 000000000..b7c0722c7 --- /dev/null +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ExactTimeSelector.tsx @@ -0,0 +1,57 @@ +/** + * 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 { DatePicker } from 'antd'; +import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; +import { TimeFilterConditionValue } from 'app/types/ChartConfig'; +import { formatTime } from 'app/utils/time'; +import { FILTER_TIME_FORMATTER_IN_QUERY } from 'globalConstants'; +import moment from 'moment'; +import { FC, memo, useEffect } from 'react'; + +const ExactTimeSelector: FC< + { + time?: TimeFilterConditionValue; + onChange: (time) => void; + } & I18NComponentProps +> = memo(({ time, i18nPrefix, onChange }) => { + const t = useI18NPrefix(i18nPrefix); + + useEffect(() => { + if (!time) { + console.log(`handleMomentTimeChange ---> `, time); + handleMomentTimeChange(moment()); + } + }, [time]); + + const handleMomentTimeChange = momentTime => { + const timeStr = formatTime(momentTime, FILTER_TIME_FORMATTER_IN_QUERY); + onChange?.(timeStr); + }; + + return ( + <DatePicker + showTime + value={moment(time as string)} + onChange={handleMomentTimeChange} + placeholder={t('pleaseSelect')} + /> + ); +}); + +export default ExactTimeSelector; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ManualSingleTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ManualSingleTimeSelector.tsx index 9291faf9c..64cf83b04 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ManualSingleTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ManualSingleTimeSelector.tsx @@ -16,15 +16,13 @@ * limitations under the License. */ -import { DatePicker, Select, Space } from 'antd'; +import { Select, Space } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import { TimeFilterConditionValue } from 'app/types/ChartConfig'; import { TimeFilterValueCategory } from 'app/types/FilterControlPanel'; -import { formatTime } from 'app/utils/time'; -import { FILTER_TIME_FORMATTER_IN_QUERY } from 'globalConstants'; -import moment from 'moment'; import { FC, memo, useState } from 'react'; import styled from 'styled-components/macro'; +import ExactTimeSelector from './ExactTimeSelector'; import RelativeTimeSelector from './RelativeTimeSelector'; const ManualSingleTimeSelector: FC< @@ -41,24 +39,19 @@ const ManualSingleTimeSelector: FC< : TimeFilterValueCategory.Relative; }); - const handleTimeChange = time => { - onTimeChange?.(time); - }; - - const handleMomentTimeChange = momentTime => { - const timeStr = formatTime(momentTime, FILTER_TIME_FORMATTER_IN_QUERY); - onTimeChange?.(timeStr); + const handleTimeCategoryChange = type => { + setType(type); + onTimeChange?.(null); }; const renderTimeSelector = type => { switch (type) { case TimeFilterValueCategory.Exact: return ( - <DatePicker - showTime - value={moment(time as string)} - onChange={handleMomentTimeChange} - placeholder={t('pleaseSelect')} + <ExactTimeSelector + time={time} + i18nPrefix={i18nPrefix} + onChange={onTimeChange} /> ); case TimeFilterValueCategory.Relative: @@ -66,7 +59,7 @@ const ManualSingleTimeSelector: FC< <RelativeTimeSelector time={time} i18nPrefix={i18nPrefix} - onChange={handleTimeChange} + onChange={onTimeChange} /> ); } @@ -74,7 +67,7 @@ const ManualSingleTimeSelector: FC< return ( <StyledManualSingleTimeSelector> - <Select value={type} onChange={value => setType(value)}> + <Select value={type} onChange={handleTimeCategoryChange}> <Select.Option value={TimeFilterValueCategory.Exact}> {t(TimeFilterValueCategory.Exact)} </Select.Option> diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RelativeTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RelativeTimeSelector.tsx index 6b2815037..2a77cc26c 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RelativeTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RelativeTimeSelector.tsx @@ -21,7 +21,7 @@ import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import { TimeFilterConditionValue } from 'app/types/ChartConfig'; import { TIME_DIRECTION, TIME_UNIT_OPTIONS } from 'globalConstants'; import { unitOfTime } from 'moment'; -import { FC, memo, useState } from 'react'; +import { FC, memo, useEffect, useState } from 'react'; import styled from 'styled-components/macro'; const RelativeTimeSelector: FC< @@ -39,6 +39,12 @@ const RelativeTimeSelector: FC< () => (time as any)?.direction || '-', ); + useEffect(() => { + if (!time) { + handleTimeChange('d', 1, '-'); + } + }, [time]); + const handleTimeChange = ( unit: unitOfTime.DurationConstructor, amount: number, diff --git a/frontend/src/app/types/ChartConfig.ts b/frontend/src/app/types/ChartConfig.ts index ac2db5045..6012b7647 100644 --- a/frontend/src/app/types/ChartConfig.ts +++ b/frontend/src/app/types/ChartConfig.ts @@ -112,7 +112,6 @@ export type TimeFilterConditionValue = direction?: string; }>; -// TODO(Stephen): to be rename to `RelationFilterValue` export type RelationFilterValue = { key: string; label: string; From 7db0395f26a7428444961eb50a8b0b6180d1a106 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Thu, 23 Dec 2021 15:08:40 +0800 Subject: [PATCH 173/348] style: color ==> primary --- .../components/ColorPicker/SingleColorSelection.tsx | 4 ++-- .../components/ColorPicker/ThemeColorSelection.tsx | 11 ++++++----- frontend/src/app/pages/MainPage/OrganizationForm.tsx | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/frontend/src/app/components/ColorPicker/SingleColorSelection.tsx b/frontend/src/app/components/ColorPicker/SingleColorSelection.tsx index 3a9473e5a..5053d3dce 100644 --- a/frontend/src/app/components/ColorPicker/SingleColorSelection.tsx +++ b/frontend/src/app/components/ColorPicker/SingleColorSelection.tsx @@ -138,7 +138,7 @@ const ColorBlock = styled.span<{ color: string }>` opacity: 0.7; } &.active { - border: 1px solid ${p => p.theme.blue}; + border: 1px solid ${p => p.theme.primary}; } `; @@ -157,6 +157,6 @@ const MoreColor = styled.div` font-size: ${FONT_SIZE_BODY}; color: ${G80}; &:hover { - color: ${p => p.theme.blue}; + color: ${p => p.theme.primary}; } `; diff --git a/frontend/src/app/components/ColorPicker/ThemeColorSelection.tsx b/frontend/src/app/components/ColorPicker/ThemeColorSelection.tsx index 57a5f0884..ae0e861a7 100644 --- a/frontend/src/app/components/ColorPicker/ThemeColorSelection.tsx +++ b/frontend/src/app/components/ColorPicker/ThemeColorSelection.tsx @@ -15,10 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @param callbackFn 回调函数返回一个颜色数组 - * @param children 点击弹出按钮的文字 支持文字和html类型 - */ + import { List, Popover } from 'antd'; import { colorThemes } from 'app/assets/theme/colorsConfig'; import React, { useState } from 'react'; @@ -27,6 +24,10 @@ import styled from 'styled-components/macro'; import { FONT_SIZE_BODY, G10, SPACE_TIMES } from 'styles/StyleConstants'; import { themeColorPropTypes } from './slice/types'; +/** + * @param callbackFn 回调函数返回一个颜色数组 + * @param children 点击弹出按钮的文字 支持文字和html类型 + */ function ThemeColorSelection({ children, callbackFn }: themeColorPropTypes) { const [switchStatus, setSwitchStatus] = useState(false); const [colors] = useState(colorThemes); @@ -89,7 +90,7 @@ const ChooseThemeSpan = styled.div` display: inline-block; width: max-content; &:hover { - color: ${p => p.theme.blue}; + color: ${p => p.theme.primary}; } `; const ColorWrapAlert = styled.div` diff --git a/frontend/src/app/pages/MainPage/OrganizationForm.tsx b/frontend/src/app/pages/MainPage/OrganizationForm.tsx index 2e789bc37..796b8dca9 100644 --- a/frontend/src/app/pages/MainPage/OrganizationForm.tsx +++ b/frontend/src/app/pages/MainPage/OrganizationForm.tsx @@ -1,4 +1,5 @@ import { Form, Input, Modal, ModalProps } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import debounce from 'debounce-promise'; import { DEFAULT_DEBOUNCE_WAIT } from 'globalConstants'; import React, { useCallback } from 'react'; @@ -7,7 +8,6 @@ import { useHistory } from 'react-router'; import { request } from 'utils/request'; import { selectSaveOrganizationLoading } from './slice/selectors'; import { addOrganization } from './slice/thunks'; -import useI18NPrefix from 'app/hooks/useI18NPrefix'; const FormItem = Form.Item; interface OrganizationFormProps extends Omit<ModalProps, 'onCancel'> { From 73969b972faa91db1a6bf60a27614d9ec4d1d371 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Thu, 23 Dec 2021 15:19:15 +0800 Subject: [PATCH 174/348] feat(chart): show filter current range time --- .../ChartTimeSelector/CurrentRangeTime.tsx | 34 ++++++++ .../MannualRangeTimeSelector.tsx | 36 ++++++--- .../RecommendRangeTimeSelector.tsx | 77 ++++++++++--------- .../models/ChartHttpRequest.ts | 2 +- 4 files changed, 99 insertions(+), 50 deletions(-) create mode 100644 frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/CurrentRangeTime.tsx diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/CurrentRangeTime.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/CurrentRangeTime.tsx new file mode 100644 index 000000000..92bea649f --- /dev/null +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/CurrentRangeTime.tsx @@ -0,0 +1,34 @@ +/** + * 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 { DatePicker } from 'antd'; +import moment from 'moment'; +import { FC, memo } from 'react'; +const { RangePicker } = DatePicker; + +const CurrentRangeTime: FC<{ times?: [string, string] }> = memo(({ times }) => { + return ( + <RangePicker + showTime + disabled + value={[moment(times?.[0]), moment(times?.[1])]} + /> + ); +}); + +export default CurrentRangeTime; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/MannualRangeTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/MannualRangeTimeSelector.tsx index 5c4561c6d..d327243e7 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/MannualRangeTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/MannualRangeTimeSelector.tsx @@ -20,10 +20,13 @@ import { Row, Space } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import TimeConfigContext from 'app/pages/ChartWorkbenchPage/contexts/TimeConfigContext'; import { FilterCondition, FilterConditionType } from 'app/types/ChartConfig'; +import { formatTime, getTime } from 'app/utils/time'; +import { FILTER_TIME_FORMATTER_IN_QUERY } from 'globalConstants'; import { FC, memo, useContext, useState } from 'react'; import ChartFilterCondition, { ConditionBuilder, } from '../../../../models/ChartFilterCondition'; +import CurrentRangeTime from './CurrentRangeTime'; import ManualSingleTimeSelector from './ManualSingleTimeSelector'; const MannualRangeTimeSelector: FC< @@ -34,7 +37,7 @@ const MannualRangeTimeSelector: FC< > = memo(({ i18nPrefix, condition, onFilterChange }) => { const t = useI18NPrefix(i18nPrefix); const { format } = useContext(TimeConfigContext); - const [timeRange, setTimeRange] = useState(() => { + const [rangeTimes, setRangeTimes] = useState(() => { if (condition?.type === FilterConditionType.RangeTime) { const startTime = condition?.value?.[0]; const endTime = condition?.value?.[1]; @@ -44,31 +47,42 @@ const MannualRangeTimeSelector: FC< }); const handleTimeChange = index => time => { - timeRange[index] = time; - setTimeRange(timeRange); + rangeTimes[index] = time; + setRangeTimes(rangeTimes); const filterRow = new ConditionBuilder(condition) - .setValue(timeRange || []) + .setValue(rangeTimes || []) .asRangeTime(); onFilterChange && onFilterChange(filterRow); }; + const getRangeStringTimes = () => { + return (rangeTimes || []).map(t => { + if (Boolean(t) && typeof t === 'object' && 'unit' in t) { + const time = getTime(+(t.direction + t.amount), t.unit)( + t.unit, + t.isStart, + ); + return formatTime(time, FILTER_TIME_FORMATTER_IN_QUERY); + } + return t; + }); + }; + return ( <div> - <Row> - {/* {`${t('currentTime')} : ${timeRange - ?.map(time => formatTime(time, format)) - ?.join(' - ')}`} */} - </Row> <Space direction="vertical" size={12}> + <Row> + <CurrentRangeTime times={getRangeStringTimes() as any} /> + </Row> <ManualSingleTimeSelector - time={timeRange?.[0] as any} + time={rangeTimes?.[0] as any} isStart={true} i18nPrefix={i18nPrefix} onTimeChange={handleTimeChange(0)} /> <ManualSingleTimeSelector - time={timeRange?.[1] as any} + time={rangeTimes?.[1] as any} isStart={false} i18nPrefix={i18nPrefix} onTimeChange={handleTimeChange(1)} diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx index a9acd3199..1d7ae3418 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx @@ -16,16 +16,17 @@ * limitations under the License. */ -import { Radio, Row, Space } from 'antd'; +import { Radio, Space } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import TimeConfigContext from 'app/pages/ChartWorkbenchPage/contexts/TimeConfigContext'; import { FilterCondition } from 'app/types/ChartConfig'; -import { formatTime, recommendTimeRangeConverter } from 'app/utils/time'; +import { recommendTimeRangeConverter } from 'app/utils/time'; import { RECOMMEND_TIME } from 'globalConstants'; import { FC, memo, useContext, useMemo, useState } from 'react'; import ChartFilterCondition, { ConditionBuilder, } from '../../../../models/ChartFilterCondition'; +import CurrentRangeTime from './CurrentRangeTime'; const RecommendRangeTimeSelector: FC< { @@ -53,42 +54,42 @@ const RecommendRangeTimeSelector: FC< return ( <> - <Row> - {`${t('currentTime')} : ${rangeTimes - ?.map(t => formatTime(t, format)) - .join(' - ')}`} - </Row> - <Radio.Group - value={recommend} - onChange={e => handleChange(e.target?.value)} - > - <Space direction="vertical"> - <Radio value={RECOMMEND_TIME.TODAY}>{t(RECOMMEND_TIME.TODAY)}</Radio> - <Radio value={RECOMMEND_TIME.YESTERDAY}> - {t(RECOMMEND_TIME.YESTERDAY)} - </Radio> - <Radio value={RECOMMEND_TIME.THISWEEK}> - {t(RECOMMEND_TIME.THISWEEK)} - </Radio> - </Space> - <Space direction="vertical"> - <Radio value={RECOMMEND_TIME.LAST_7_DAYS}> - {t(RECOMMEND_TIME.LAST_7_DAYS)} - </Radio> - <Radio value={RECOMMEND_TIME.LAST_30_DAYS}> - {t(RECOMMEND_TIME.LAST_30_DAYS)} - </Radio> - <Radio value={RECOMMEND_TIME.LAST_90_DAYS}> - {t(RECOMMEND_TIME.LAST_90_DAYS)} - </Radio> - <Radio value={RECOMMEND_TIME.LAST_1_MONTH}> - {t(RECOMMEND_TIME.LAST_1_MONTH)} - </Radio> - <Radio value={RECOMMEND_TIME.LAST_1_YEAR}> - {t(RECOMMEND_TIME.LAST_1_YEAR)} - </Radio> - </Space> - </Radio.Group> + <Space direction="vertical"> + <CurrentRangeTime times={rangeTimes} /> + <Radio.Group + value={recommend} + onChange={e => handleChange(e.target?.value)} + > + <Space direction="vertical"> + <Radio value={RECOMMEND_TIME.TODAY}> + {t(RECOMMEND_TIME.TODAY)} + </Radio> + <Radio value={RECOMMEND_TIME.YESTERDAY}> + {t(RECOMMEND_TIME.YESTERDAY)} + </Radio> + <Radio value={RECOMMEND_TIME.THISWEEK}> + {t(RECOMMEND_TIME.THISWEEK)} + </Radio> + </Space> + <Space direction="vertical"> + <Radio value={RECOMMEND_TIME.LAST_7_DAYS}> + {t(RECOMMEND_TIME.LAST_7_DAYS)} + </Radio> + <Radio value={RECOMMEND_TIME.LAST_30_DAYS}> + {t(RECOMMEND_TIME.LAST_30_DAYS)} + </Radio> + <Radio value={RECOMMEND_TIME.LAST_90_DAYS}> + {t(RECOMMEND_TIME.LAST_90_DAYS)} + </Radio> + <Radio value={RECOMMEND_TIME.LAST_1_MONTH}> + {t(RECOMMEND_TIME.LAST_1_MONTH)} + </Radio> + <Radio value={RECOMMEND_TIME.LAST_1_YEAR}> + {t(RECOMMEND_TIME.LAST_1_YEAR)} + </Radio> + </Space> + </Radio.Group> + </Space> </> ); }); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts index 74a0b94a5..2bb4798d2 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts @@ -168,7 +168,7 @@ export class ChartDataRequestBuilder { if (visualType !== 'DATE') { return value; } - if (typeof value === 'object') { + if (Boolean(value) && typeof value === 'object' && 'unit' in value) { const time = getTime(+(value.direction + value.amount), value.unit)( value.unit, value.isStart, From 79b02f9d17682b7c2321e5a1b894c702ea29cb65 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Tue, 21 Dec 2021 15:46:10 +0800 Subject: [PATCH 175/348] feat: add en on Board --- .../BoardToolBar/AddControl/AddControlBtn.tsx | 48 +++++++------- .../components/BoardToolBar/ToolBarItem.tsx | 22 +++---- frontend/src/locales/en/translation.json | 62 ++++++++++++------ frontend/src/locales/zh/translation.json | 63 +++++++++++++------ 4 files changed, 120 insertions(+), 75 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControl/AddControlBtn.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControl/AddControlBtn.tsx index cbd60f466..389f1b535 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControl/AddControlBtn.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControl/AddControlBtn.tsx @@ -29,13 +29,16 @@ import { BoardToolBarContext } from '../context/BoardToolBarContext'; import { WithTipButton } from '../ToolBarItem'; export interface AddControlBtnProps {} export interface ButtonItemType<T> { - name: string; + name?: string; icon: any; type: T; disabled?: boolean; } export const AddControlBtn: React.FC<AddControlBtnProps> = () => { const t = useI18NPrefix(`viz.board.action`); + const tFilterName = useI18NPrefix(`viz.common.enum.controllerFacadeTypes`); + const tType = useI18NPrefix(`viz.board.controlTypes`); + const { boardId, boardType, showLabel } = useContext(BoardToolBarContext); const dispatch = useDispatch(); const { config: boardConfig } = useContext(BoardConfigContext); @@ -51,27 +54,22 @@ export const AddControlBtn: React.FC<AddControlBtnProps> = () => { }; const conventionalControllers: ButtonItemType<ControllerFacadeTypes>[] = [ { - name: '单选下拉菜单', icon: '', type: ControllerFacadeTypes.DropdownList, }, { - name: '多选下拉菜单', icon: '', type: ControllerFacadeTypes.MultiDropdownList, }, { - name: '单选按钮', icon: '', type: ControllerFacadeTypes.RadioGroup, }, { - name: '多选框', icon: '', type: ControllerFacadeTypes.CheckboxGroup, }, { - name: '文本', icon: '', type: ControllerFacadeTypes.Text, }, @@ -88,31 +86,26 @@ export const AddControlBtn: React.FC<AddControlBtnProps> = () => { // disabled: false, // }, ]; - const dateControllers = [ + const dateControllers: ButtonItemType<ControllerFacadeTypes>[] = [ { - name: '日期范围', icon: '', type: ControllerFacadeTypes.RangeTime, }, { - name: '日期', icon: '', type: ControllerFacadeTypes.Time, }, ]; - const numericalControllers = [ + const numericalControllers: ButtonItemType<ControllerFacadeTypes>[] = [ { - name: '数值范围', icon: '', type: ControllerFacadeTypes.RangeValue, }, { - name: '数值', icon: '', type: ControllerFacadeTypes.Value, }, { - name: '滑块', icon: '', type: ControllerFacadeTypes.Slider, }, @@ -142,28 +135,37 @@ export const AddControlBtn: React.FC<AddControlBtnProps> = () => { }; const controlerItems = ( <Menu onClick={onAddControler}> - <Menu.ItemGroup key="conventionalControllers" title={renderTitle('常规')}> - {conventionalControllers.map(({ name, icon, type }) => ( + <Menu.ItemGroup + key="conventionalControllers" + title={renderTitle(tType('common'))} + > + {conventionalControllers.map(({ icon, type }) => ( <Menu.Item key={type} icon={icon}> - {name} + {tFilterName(type)} </Menu.Item> ))} </Menu.ItemGroup> - <Menu.ItemGroup key="dateControllers" title={renderTitle('日期')}> - {dateControllers.map(({ name, icon, type }) => ( + <Menu.ItemGroup key="dateControllers" title={renderTitle(tType('date'))}> + {dateControllers.map(({ icon, type }) => ( <Menu.Item key={type} icon={icon}> - {name} + {tFilterName(type)} </Menu.Item> ))} </Menu.ItemGroup> - <Menu.ItemGroup key="numericalControllers" title={renderTitle('数值')}> - {numericalControllers.map(({ name, icon, type }) => ( + <Menu.ItemGroup + key="numericalControllers" + title={renderTitle(tType('numeric'))} + > + {numericalControllers.map(({ icon, type }) => ( <Menu.Item key={type} icon={icon}> - {name} + {tFilterName(type)} </Menu.Item> ))} </Menu.ItemGroup> - <Menu.ItemGroup key="buttonControllers" title={renderTitle('按钮')}> + <Menu.ItemGroup + key="buttonControllers" + title={renderTitle(tType('button'))} + > {buttonControllers.map(({ name, icon, type, disabled }) => ( <Menu.Item key={type} icon={icon} disabled={disabled}> {name} diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/ToolBarItem.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/ToolBarItem.tsx index dff7b8694..4e9587f24 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/ToolBarItem.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/ToolBarItem.tsx @@ -217,27 +217,27 @@ export const MediaWidgetDropdown: React.FC<ToolBtnProps> = props => { type TinyWidgetItems = { name: string; icon: string; type: LightWidgetType }; const mediaWidgetTypes: TinyWidgetItems[] = [ { - name: '图片', + name: t('image'), icon: '', type: 'image', }, { - name: '富文本', + name: t('richText'), icon: '', type: 'richText', }, { - name: '时间器', + name: t('timer'), icon: '', type: 'timer', }, { - name: 'iframe', + name: t('iFrame'), icon: '', type: 'iframe', }, { - name: '视频', + name: t('richText'), icon: '', type: 'video', }, @@ -286,14 +286,12 @@ export const ContainerWidgetDropdown: React.FC<ToolBtnProps> = props => { ); type ContainerWidgetItems = { name: string; - title: string; icon: string; type: LightWidgetType; }; const containerWidgetTypes: ContainerWidgetItems[] = [ { - name: 'tabs', - title: '标签页', + name: t('tab'), icon: '', type: 'tab', }, @@ -306,8 +304,8 @@ export const ContainerWidgetDropdown: React.FC<ToolBtnProps> = props => { const containerWidgetItems = ( <Menu onClick={onSelectContainerWidget}> - {containerWidgetTypes.map(({ name, title, type }) => ( - <Menu.Item key={type}>{title}</Menu.Item> + {containerWidgetTypes.map(({ name, type }) => ( + <Menu.Item key={type}>{name}</Menu.Item> ))} </Menu> ); @@ -350,12 +348,12 @@ export const ChartWidgetDropdown: React.FC<ChartWidgetDropdownProps> = ); const addChartTypes = [ { - name: '添加已有数据图表', + name: t('addDataChartFormList'), icon: '', type: 'select', }, { - name: '新建数据图表', + name: t('createDataChartInBoard'), icon: '', type: 'create', }, diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index dffaae7f7..87524b211 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -198,17 +198,11 @@ "goBack": "Back", "run": "Run", "save": "Save", - "saveToDashboard": "Save to Dashboard", - "login": "Login", - "lang": { - "zh": "ZH", - "en": "EN" - }, + + "format": { "local": "local", - "date": "date", - "ll": "LL", - "lll": "LLL" + "date": "date" } }, "dataview": { @@ -438,17 +432,45 @@ "downloadData": "Download Data" } }, - "board": { - "action": { - "dataChart": "DataChart", - "media": "Media", - "container": "Container", - "controller": "Controller", - "undo": "Undo", - "redo": "Redo", - "delete": "Delete", - "copy": "Copy", - "paste": "Paste" + "board":{ + "action":{ + "dataChart":"DataChart", + "addDataChartFormList":"Add DataChart Form List", + "createDataChartInBoard":"Create DataChart In Board", + + "media":"Media", + "image":"Image", + "richText":"Rich Text", + "timer":"Timer", + "iFrame":"iFrame", + "video":"Video", + + "container":"Container", + "tab":"Tab", + + "controller":"Controller", + "undo":"Undo", + "redo":"Redo", + "delete":"Delete", + "copy":"Copy", + "paste":"Paste" + }, + "controlTypes":{ + "common":"Common", + "date":"Date", + "numeric":"Numeric", + "button":"Button" + } + + }, + "widget":{ + "type":{ + "chart":"Chart", + "media":"Media", + "container":"Container", + "controller":"Controller", + "query":"Query", + "reset":"Reset" } } }, diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index e50c2022c..dc911c8aa 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -199,17 +199,10 @@ "goBack": "返回", "run": "执行", "save": "保存", - "saveToDashboard": "保存到仪表盘", - "login": "登陆", - "lang": { - "zh": "中文", - "en": "英文" - }, + "format": { "local": "本地", - "date": "日期", - "ll": "LL", - "lll": "LLL" + "date": "日期" } }, "dataview": { @@ -438,17 +431,47 @@ "downloadData": "下载数据" } }, - "board": { - "action": { - "dataChart": "数据图表", - "media": "媒体组件", - "container": "容器", - "controller": "控制器", - "undo": "撤销", - "redo": "重做", - "delete": "删除", - "copy": "复制", - "paste": "粘贴" + "board":{ + "action":{ + "dataChart":"数据图表", + "addDataChartFormList":"添加已有数据图表", + "createDataChartInBoard":"新建数据图表", + + "media":"媒体组件", + "image":"图片", + "richText":"富文本", + "timer":"计时器", + "iFrame":"iFrame", + "video":"视频", + + + "container":"容器", + "tab":"标签页", + "轮播图":"", + + "controller":"控制器", + + "undo":"撤销", + "redo":"重做", + "delete":"删除", + "copy":"复制", + "paste":"粘贴" + }, + "controlTypes":{ + "common":"常规", + "date":"日期", + "numeric":"数值", + "button":"按钮" + } + }, + "widget":{ + "type":{ + "chart":"数据图表", + "media":"媒体", + "container":"容器", + "controller":"控制器", + "query":"查询", + "reset":"重置" } } }, From 4042487089d7aa402c2b6158897d25d4bbb37d2d Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 23 Dec 2021 16:45:18 +0800 Subject: [PATCH 176/348] fix: handleRowStateUpdate #368 --- .../CategoryConditionEditableTable.tsx | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionEditableTable.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionEditableTable.tsx index f3ad433cf..b78b705f8 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionEditableTable.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionEditableTable.tsx @@ -84,9 +84,7 @@ const CategoryConditionEditableTable: FC< <a href="#!" onClick={() => - handleRowStateUpdate( - Object.assign(record, { isSelected: true }), - ) + handleRowStateUpdate({ ...record, isSelected: true }) } > {t('setDefault')} @@ -96,9 +94,7 @@ const CategoryConditionEditableTable: FC< <a href="#!" onClick={() => - handleRowStateUpdate( - Object.assign(record, { isSelected: false }), - ) + handleRowStateUpdate({ ...record, isSelected: false }) } > {t('setUnDefault')} @@ -154,9 +150,10 @@ const CategoryConditionEditableTable: FC< }; const handleRowStateUpdate = (row: RelationFilterValue) => { - const oldRowIndex = rows.findIndex(r => r.index === row.index); - rows.splice(oldRowIndex, 1, row); - handleFilterConditionChange(rows); + const newRows = [...rows]; + const targetIndex = newRows.findIndex(r => r.index === row.index); + newRows.splice(targetIndex, 1, row); + handleFilterConditionChange(newRows); }; const handleFetchDataFromField = field => async () => { @@ -181,23 +178,23 @@ const CategoryConditionEditableTable: FC< ); const fetchNewDataset = async (viewId, colName) => { - const feildDataset = await getDistinctFields( + const fieldDataset = await getDistinctFields( viewId, colName, undefined, undefined, ); - return feildDataset; + return fieldDataset; }; - const convertToList = (collection, selecteKeys) => { + const convertToList = (collection, selectedKeys) => { const items: string[] = (collection || []).flatMap(c => c); const uniqueKeys = Array.from(new Set(items)); return uniqueKeys.map((item, index) => ({ index: index, key: item, label: item, - isSelected: selecteKeys.includes(item), + isSelected: selectedKeys.includes(item), })); }; From b1433c65cb462e7c61640e551f7f35e6a8d4147f Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Thu, 23 Dec 2021 16:45:51 +0800 Subject: [PATCH 177/348] feat: support select from a function as table --- data-providers/src/main/java/codegen/Parser.jj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/data-providers/src/main/java/codegen/Parser.jj b/data-providers/src/main/java/codegen/Parser.jj index 16490394a..99043f31a 100644 --- a/data-providers/src/main/java/codegen/Parser.jj +++ b/data-providers/src/main/java/codegen/Parser.jj @@ -2071,6 +2071,10 @@ SqlNode TableRef2(boolean lateral) : } { ( + // datart: function as table + LOOKAHEAD(256,TableFunctionCall(getPos())) + tableRef = TableFunctionCall(getPos()) + | LOOKAHEAD(2) tableRef = TableRefWithHintsOpt() [ @@ -2133,6 +2137,7 @@ SqlNode TableRef2(boolean lateral) : } | tableRef = ExtendedTableRef() + ) [ tableRef = Pivot(tableRef) From 4ac534d41c19b11e2670cec8072c6179ac3d1645 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 23 Dec 2021 16:48:38 +0800 Subject: [PATCH 178/348] fix: change some spell --- .../demo-custom-line-chart.js | 2 +- .../demo-d3js-scatter-chart.js | 2 +- .../{BaiscSelector.tsx => BasicSelector.tsx} | 4 +-- .../components/FormGenerator/Basic/index.ts | 3 +- .../FormGenerator/Layout/ItemLayout.tsx | 6 ++-- .../CategoryConditionConfiguration.tsx | 28 ++++++++++--------- .../SortAction/SortAction.tsx | 4 +-- .../BasicBarChart/BasicBarChart.tsx | 8 +++--- .../BasicDoubleYChart/BasicDoubleYChart.tsx | 4 +-- .../BasicFunnelChart/BasicFunnelChart.tsx | 4 +-- .../BasicGaugeChart/BasicGaugeChart.tsx | 4 +-- .../BasicLineChart/BasicLineChart.ts | 4 +-- .../BasicOutlineMapChart.tsx | 4 +-- .../BasicPieChart/BasicPieChart.tsx | 4 +-- .../BasicRichText/BasicRichText.tsx | 4 +-- .../BasicScatterChart/BasicScatterChart.tsx | 4 +-- .../BasicTableChart/BasicTableChart.tsx | 4 +-- .../FenZuTableChart/FenZuTableChart.tsx | 4 +-- .../PivotSheetChart/PivotSheetChart.tsx | 4 +-- .../ChartGraph/ScoreChart/ScoreChart.tsx | 4 +-- .../WaterfallChart/WaterfallChart.tsx | 4 +-- .../WordCloudChart/WordCloudChart.tsx | 4 +-- .../ChartIFrameContainerResourceLoader.ts | 2 +- .../ChartTools/ChartLifecycleAdapter.tsx | 2 +- .../pages/MainPage/Navbar/ModifyPassword.tsx | 2 +- .../src/app/pages/MainPage/Navbar/index.tsx | 8 +++--- frontend/src/app/utils/chartHelper.ts | 6 ++-- frontend/src/locales/en/translation.json | 2 +- frontend/src/locales/zh/translation.json | 2 +- 29 files changed, 69 insertions(+), 68 deletions(-) rename frontend/src/app/components/FormGenerator/Basic/{BaiscSelector.tsx => BasicSelector.tsx} (97%) diff --git a/frontend/public/custom-chart-plugins/demo-custom-line-chart.js b/frontend/public/custom-chart-plugins/demo-custom-line-chart.js index e6eb2303b..1fb9a6883 100644 --- a/frontend/public/custom-chart-plugins/demo-custom-line-chart.js +++ b/frontend/public/custom-chart-plugins/demo-custom-line-chart.js @@ -532,7 +532,7 @@ function DemoCustomLineChart({ dHelper }) { .filter(c => c.type === 'aggregate') .flatMap(config => config.rows || []); - const objDataColumns = dHelper.transfromToObjectArray( + const objDataColumns = dHelper.transformToObjectArray( dataset.rows, dataset.columns, ); diff --git a/frontend/public/custom-chart-plugins/demo-d3js-scatter-chart.js b/frontend/public/custom-chart-plugins/demo-d3js-scatter-chart.js index 650ad9466..4bb6532fe 100644 --- a/frontend/public/custom-chart-plugins/demo-d3js-scatter-chart.js +++ b/frontend/public/custom-chart-plugins/demo-d3js-scatter-chart.js @@ -173,7 +173,7 @@ function D3JSScatterChart({ dHelper }) { .flatMap(config => config.rows || []); // 数据转换,根据Datart提供了Helper转换工具 - const objDataColumns = dHelper.transfromToObjectArray( + const objDataColumns = dHelper.transformToObjectArray( dataset.rows, dataset.columns, ); diff --git a/frontend/src/app/components/FormGenerator/Basic/BaiscSelector.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx similarity index 97% rename from frontend/src/app/components/FormGenerator/Basic/BaiscSelector.tsx rename to frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx index c22384ae2..d45ce9da7 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BaiscSelector.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx @@ -26,7 +26,7 @@ import { ItemLayoutProps } from '../types'; import { itemLayoutComparer } from '../utils'; import { BW } from './components/BasicWrapper'; -const BaiscSelector: FC<ItemLayoutProps<ChartStyleSectionConfig>> = memo( +const BasicSelector: FC<ItemLayoutProps<ChartStyleSectionConfig>> = memo( ({ ancestors, translate: t = title => title, @@ -93,7 +93,7 @@ const BaiscSelector: FC<ItemLayoutProps<ChartStyleSectionConfig>> = memo( itemLayoutComparer, ); -export default BaiscSelector; +export default BasicSelector; const Wrapper = styled(BW)` .ant-select { diff --git a/frontend/src/app/components/FormGenerator/Basic/index.ts b/frontend/src/app/components/FormGenerator/Basic/index.ts index d7a7fd385..b99a8fe4b 100644 --- a/frontend/src/app/components/FormGenerator/Basic/index.ts +++ b/frontend/src/app/components/FormGenerator/Basic/index.ts @@ -15,8 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -export { default as BaiscSelector } from './BaiscSelector'; export { default as BasicCheckbox } from './BasicCheckbox'; export { default as BasicColorSelector } from './BasicColorSelector'; export { default as BasicFont } from './BasicFont'; @@ -27,6 +25,7 @@ export { default as BasicInputNumber } from './BasicInputNumber'; export { default as BasicInputPercentage } from './BasicInputPercentage'; export { default as BasicLine } from './BasicLine'; export { default as BasicMarginWidth } from './BasicMarginWidth'; +export { default as BasicSelector } from './BasicSelector'; export { default as BasicSlider } from './BasicSlider'; export { default as BasicSwitch } from './BasicSwitch'; export { default as BasicText } from './BasicText'; diff --git a/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx b/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx index 8878595c5..f08a60851 100644 --- a/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx +++ b/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx @@ -32,8 +32,6 @@ import { } from 'utils/object'; import { GroupLayout } from '.'; import { - BaiscSelector, - BasicCheckbox, BasicColorSelector, BasicFont, BasicFontFamilySelector, @@ -43,11 +41,13 @@ import { BasicInputPercentage, BasicLine, BasicMarginWidth, + BasicSelector, BasicSlider, BasicSwitch, BasicText, BasicUnControlledTabPanel, } from '../Basic'; +import BasicCheckbox from '../Basic/BasicCheckbox'; import { ConditionStylePanel, DataCachePanel, @@ -128,7 +128,7 @@ const ItemLayout: FC<FormGeneratorLayoutProps<ChartStyleSectionConfig>> = memo( case ChartStyleSectionComponentType.INPUT: return <BasicInput {...props} />; case ChartStyleSectionComponentType.SELECT: - return <BaiscSelector {...props} />; + return <BasicSelector {...props} />; case ChartStyleSectionComponentType.TABS: return <BasicUnControlledTabPanel {...props} />; case ChartStyleSectionComponentType.FONT: diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx index 3b46ed26c..e4f26b78e 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx @@ -19,7 +19,10 @@ import { Button, Row, Select, Space, Tabs, Transfer, Tree } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import useMount from 'app/hooks/useMount'; -import { FilterConditionType, RelationFilterValue } from 'app/types/ChartConfig'; +import { + FilterConditionType, + RelationFilterValue, +} from 'app/types/ChartConfig'; import ChartDataView from 'app/types/ChartDataView'; import { getDistinctFields } from 'app/utils/fetch'; import { FilterSqlOperator } from 'globalConstants'; @@ -30,7 +33,6 @@ import ChartFilterCondition, { ConditionBuilder, } from '../../../../../models/ChartFilterCondition'; import CategoryConditionEditableTable from './CategoryConditionEditableTable'; -// import CategoryConditionEditableTable from './CategoryConditionEditableTableBak'; import CategoryConditionRelationSelector from './CategoryConditionRelationSelector'; const CategoryConditionConfiguration: FC< @@ -99,16 +101,16 @@ const CategoryConditionConfiguration: FC< selectedKeys.indexOf(eventKey) !== -1; const fetchNewDataset = async (viewId, colName) => { - const feildDataset = await getDistinctFields( + const fieldDataset = await getDistinctFields( viewId, colName, undefined, undefined, ); - return feildDataset; + return fieldDataset; }; - const setListSelctedState = ( + const setListSelectedState = ( list?: RelationFilterValue[], keys?: string[], ) => { @@ -129,7 +131,7 @@ const CategoryConditionConfiguration: FC< }; const handleGeneralListChange = async selectedKeys => { - const items = setListSelctedState(listDatas, selectedKeys); + const items = setListSelectedState(listDatas, selectedKeys); setTargetKeys(selectedKeys); setListDatas(items); @@ -185,17 +187,17 @@ const CategoryConditionConfiguration: FC< }); }; - const convertToList = (collection, selecteKeys) => { + const convertToList = (collection, selectedKeys) => { const items: string[] = (collection || []).flatMap(c => c); const uniqueKeys = Array.from(new Set(items)); return uniqueKeys.map(item => ({ key: item, label: item, - isSelected: selecteKeys.includes(item), + isSelected: selectedKeys.includes(item), })); }; - const convertToTree = (collection, selecteKeys) => { + const convertToTree = (collection, selectedKeys) => { const associateField = treeOptions?.[0]; const labelField = treeOptions?.[1]; @@ -212,22 +214,22 @@ const CategoryConditionConfiguration: FC< if (!associateItem) { return null; } - const assocaiteChildren = collection + const associateChildren = collection .filter(c => c[associateField] === key) .map(c => { const itemKey = c[labelField]; return { key: itemKey, label: itemKey, - isSelected: isChecked(selecteKeys, itemKey), + isSelected: isChecked(selectedKeys, itemKey), }; }); const itemKey = associateItem?.[colName]; return { key: itemKey, label: itemKey, - isSelected: isChecked(selecteKeys, itemKey), - children: assocaiteChildren, + isSelected: isChecked(selectedKeys, itemKey), + children: associateChildren, }; }) .filter(i => Boolean(i)) as RelationFilterValue[]; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/SortAction/SortAction.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/SortAction/SortAction.tsx index 688b52e3f..996b3effc 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/SortAction/SortAction.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/SortAction/SortAction.tsx @@ -24,7 +24,7 @@ import { ChartDataSectionField, SortActionType } from 'app/types/ChartConfig'; import ChartDataset from 'app/types/ChartDataset'; import { getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { updateBy } from 'app/utils/mutation'; import { FC, useState } from 'react'; @@ -47,7 +47,7 @@ const SortAction: FC<{ const t = useI18NPrefix(`viz.palette.data.actions`); const [direction, setDirection] = useState(config?.sort?.type); const [sortValue, setSortValue] = useState(() => { - const objDataColumns = transfromToObjectArray( + const objDataColumns = transformToObjectArray( dataset?.rows, dataset?.columns, ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/BasicBarChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/BasicBarChart.tsx index d6f0f69e4..d48f3afd0 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/BasicBarChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/BasicBarChart.tsx @@ -34,7 +34,7 @@ import { getSeriesTooltips4Rectangular2, getStyleValueByGroup, getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { toExponential, @@ -120,7 +120,7 @@ class BasicBarChart extends Chart { .filter(c => c.type === ChartDataSectionType.INFO) .flatMap(config => config.rows || []); - const objDataColumns = transfromToObjectArray( + const objDataColumns = transformToObjectArray( dataset.rows, dataset.columns, ); @@ -162,7 +162,7 @@ class BasicBarChart extends Chart { return { tooltip: { trigger: 'item', - formatter: this.getTooltipFormmaterFunc( + formatter: this.getTooltipFormatterFunc( styleConfigs, groupConfigs, aggregateConfigs, @@ -580,7 +580,7 @@ class BasicBarChart extends Chart { return `${label}: ${value}`; } - getTooltipFormmaterFunc( + getTooltipFormatterFunc( styleConfigs, groupConfigs, aggregateConfigs, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicDoubleYChart/BasicDoubleYChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicDoubleYChart/BasicDoubleYChart.tsx index 927fd857a..d9986b0cf 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicDoubleYChart/BasicDoubleYChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicDoubleYChart/BasicDoubleYChart.tsx @@ -36,7 +36,7 @@ import { getSplitLine, getStyleValueByGroup, getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { toFormattedValue } from 'app/utils/number'; import { init } from 'echarts'; @@ -95,7 +95,7 @@ class BasicDoubleYChart extends Chart { const styleConfigs = config.styles || []; const settingConfigs = config.settings; - const objDataColumns = transfromToObjectArray( + const objDataColumns = transformToObjectArray( dataset.rows, dataset.columns, ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx index 824730a12..715f06bdf 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx @@ -30,7 +30,7 @@ import { getSeriesTooltips4Scatter, getStyleValueByGroup, getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { toFormattedValue } from 'app/utils/number'; import { init } from 'echarts'; @@ -99,7 +99,7 @@ class BasicFunnelChart extends Chart { .filter(c => c.type === ChartDataSectionType.INFO) .flatMap(config => config.rows || []); - const objDataColumns = transfromToObjectArray( + const objDataColumns = transformToObjectArray( dataset.rows, dataset.columns, ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/BasicGaugeChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/BasicGaugeChart.tsx index 2b508b45e..ee5d3a879 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/BasicGaugeChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/BasicGaugeChart.tsx @@ -23,7 +23,7 @@ import { getColumnRenderName, getStyleValueByGroup, getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { toFormattedValue } from 'app/utils/number'; import { init } from 'echarts'; @@ -90,7 +90,7 @@ class BasicGaugeChart extends Chart { const aggregateConfigs = dataConfigs .filter(c => c.type === ChartDataSectionType.AGGREGATE) .flatMap(config => config.rows || []); - const dataColumns = transfromToObjectArray(dataset.rows, dataset.columns); + const dataColumns = transformToObjectArray(dataset.rows, dataset.columns); const series = this.getSeries( styleConfigs, dataColumns, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicLineChart/BasicLineChart.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicLineChart/BasicLineChart.ts index 7cc79e541..c09c099ff 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicLineChart/BasicLineChart.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicLineChart/BasicLineChart.ts @@ -39,7 +39,7 @@ import { getSplitLine, getStyleValueByGroup, getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { toExponential, @@ -124,7 +124,7 @@ class BasicLineChart extends Chart { .filter(c => c.type === ChartDataSectionType.INFO) .flatMap(config => config.rows || []); - const objDataColumns = transfromToObjectArray( + const objDataColumns = transformToObjectArray( dataset.rows, dataset.columns, ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicOutlineMapChart/BasicOutlineMapChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicOutlineMapChart/BasicOutlineMapChart.tsx index 9f52baa24..ba0227a48 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicOutlineMapChart/BasicOutlineMapChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicOutlineMapChart/BasicOutlineMapChart.tsx @@ -26,7 +26,7 @@ import { getSeriesTooltips4Polar2, getStyleValueByGroup, getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { init, registerMap } from 'echarts'; import Config from './config'; @@ -110,7 +110,7 @@ class BasicOutlineMapChart extends Chart { this.registerGeoMap(styleConfigs); - const objDataColumns = transfromToObjectArray( + const objDataColumns = transformToObjectArray( dataset.rows, dataset.columns, ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx index 008520bd6..6703a64c2 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx @@ -31,7 +31,7 @@ import { getSeriesTooltips4Polar2, getStyleValueByGroup, getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { init } from 'echarts'; import Config from './config'; @@ -89,7 +89,7 @@ class BasicPieChart extends Chart { } getOptions(dataset: ChartDataset, config: ChartConfig) { - const dataColumns = transfromToObjectArray(dataset.rows, dataset.columns); + const dataColumns = transformToObjectArray(dataset.rows, dataset.columns); const styleConfigs = config.styles; const dataConfigs = config.datas || []; const groupConfigs = dataConfigs diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/BasicRichText.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/BasicRichText.tsx index f4ceaadad..22e34559b 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/BasicRichText.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/BasicRichText.tsx @@ -25,7 +25,7 @@ import { getCustomSortableColumns, getStyleValueByGroup, getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { toFormattedValue } from 'app/utils/number'; import Config from './config'; @@ -93,7 +93,7 @@ class BasicRichText extends ReactChart { const aggregateConfigs = dataConfigs .filter(c => c.type === ChartDataSectionType.AGGREGATE) .flatMap(config => config.rows || []); - const objDataColumns = transfromToObjectArray( + const objDataColumns = transformToObjectArray( dataset.rows, dataset.columns, ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/BasicScatterChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/BasicScatterChart.tsx index 36a6ebe86..ed2910390 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/BasicScatterChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/BasicScatterChart.tsx @@ -28,7 +28,7 @@ import { getSeriesTooltips4Scatter, getStyleValueByGroup, getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { init } from 'echarts'; import Config from './config'; @@ -84,7 +84,7 @@ class BasicScatterChart extends Chart { } getOptions(dataset: ChartDataset, config: ChartConfig) { - const objDataColumns = transfromToObjectArray( + const objDataColumns = transformToObjectArray( dataset.rows, dataset.columns, ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx index 5e11f84ab..723daca49 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx @@ -25,7 +25,7 @@ import { getCustomSortableColumns, getUnusedHeaderRows, getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { toFormattedValue } from 'app/utils/number'; import { isEmptyArray, Omit } from 'utils/object'; @@ -91,7 +91,7 @@ class BasicTableChart extends ReactChart { const styleConfigs = config.styles || []; const settingConfigs = config.settings || []; - const objDataColumns = transfromToObjectArray( + const objDataColumns = transformToObjectArray( dataset.rows, dataset.columns, ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx index e038da39b..e6b572c01 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx @@ -20,7 +20,7 @@ import { ChartConfig, ChartDataSectionType } from 'app/types/ChartConfig'; import ChartDataset from 'app/types/ChartDataset'; import { getCustomSortableColumns, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import BasicTableChart from '../BasicTableChart'; import Config from './config'; @@ -46,7 +46,7 @@ class FenZuTableChart extends BasicTableChart { const dataConfigs = config.datas || []; const styleConfigs = config.styles || []; const settingConfigs = config.settings || []; - const objDataColumns = transfromToObjectArray( + const objDataColumns = transformToObjectArray( dataset.rows, dataset.columns, ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/PivotSheetChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/PivotSheetChart.tsx index 83d6f3318..636c57e50 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/PivotSheetChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/PivotSheetChart.tsx @@ -26,7 +26,7 @@ import { getColumnRenderName, getCustomSortableColumns, getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { isNumber, toFormattedValue } from 'app/utils/number'; import groupBy from 'lodash/groupBy'; @@ -80,7 +80,7 @@ class PivotSheetChart extends ReactChart { const dataConfigs = config.datas || []; const styleConfigs = config.styles || []; const settingConfigs = config.settings || []; - const objDataColumns = transfromToObjectArray( + const objDataColumns = transformToObjectArray( dataset.rows, dataset.columns, ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScoreChart/ScoreChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScoreChart/ScoreChart.tsx index 6b418ee0c..5b58f69a4 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScoreChart/ScoreChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScoreChart/ScoreChart.tsx @@ -22,7 +22,7 @@ import ChartDataset from 'app/types/ChartDataset'; import { getStyleValueByGroup, getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { toFormattedValue } from 'app/utils/number'; import { init } from 'echarts'; @@ -99,7 +99,7 @@ class ScoreChart extends Chart { .filter(c => c.type === ChartDataSectionType.AGGREGATE) .flatMap(config => config.rows || []); - const objDataColumns = transfromToObjectArray( + const objDataColumns = transformToObjectArray( dataset.rows, dataset.columns, ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WaterfallChart/WaterfallChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WaterfallChart/WaterfallChart.tsx index 4cc4e918d..7639e10aa 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WaterfallChart/WaterfallChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WaterfallChart/WaterfallChart.tsx @@ -24,7 +24,7 @@ import { getCustomSortableColumns, getStyleValueByGroup, getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { toFormattedValue } from 'app/utils/number'; import { init } from 'echarts'; @@ -90,7 +90,7 @@ class WaterfallChart extends Chart { .filter(c => c.type === ChartDataSectionType.AGGREGATE) .flatMap(config => config.rows || []); - const objDataColumns = transfromToObjectArray( + const objDataColumns = transformToObjectArray( dataset.rows, dataset.columns, ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WordCloudChart/WordCloudChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WordCloudChart/WordCloudChart.tsx index a8d0b7118..a1ba6e134 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WordCloudChart/WordCloudChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WordCloudChart/WordCloudChart.tsx @@ -23,7 +23,7 @@ import { getDefaultThemeColor, getStyleValueByGroup, getValueByColumnKey, - transfromToObjectArray, + transformToObjectArray, } from 'app/utils/chartHelper'; import { init } from 'echarts'; import 'echarts-wordcloud'; @@ -93,7 +93,7 @@ class WordCloudChart extends Chart { .filter(c => c.type === ChartDataSectionType.AGGREGATE) .flatMap(config => config.rows || []); - const objDataColumns = transfromToObjectArray( + const objDataColumns = transformToObjectArray( dataset.rows, dataset.columns, ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerResourceLoader.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerResourceLoader.ts index 8b595505d..5fb643327 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerResourceLoader.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerResourceLoader.ts @@ -21,7 +21,7 @@ import { loadScript } from '../../../../../../../utils/resource'; class ChartIFrameContainerResourceLoader { private resources: string[] = []; - laodResource(doc, deps?: string[]): Promise<any[]> { + loadResource(doc, deps?: string[]): Promise<any[]> { const unloadedDeps = (deps || []).filter(d => !this.resources.includes(d)); return this.loadDependencies(doc, unloadedDeps); } diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx index e2e457e77..b507da840 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx @@ -66,7 +66,7 @@ const ChartLifecycleAdapter: React.FC<{ setContainerStatus(ContainerStatus.LOADING); (async () => { chartResourceLoader - .laodResource(document, chart?.getDependencies?.()) + .loadResource(document, chart?.getDependencies?.()) .then(_ => { chart.init(config); const newBrokerRef = new ChartEventBroker(); diff --git a/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx b/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx index 906cfb115..e8a139f03 100644 --- a/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx @@ -22,7 +22,7 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ const loggedInUser = useSelector(selectLoggedInUser); const loading = useSelector(selectModifyPasswordLoading); const [form] = Form.useForm(); - const t = useI18NPrefix('main.nav.accout.changePassword'); + const t = useI18NPrefix('main.nav.account.changePassword'); const reset = useCallback(() => { form.resetFields(); diff --git a/frontend/src/app/pages/MainPage/Navbar/index.tsx b/frontend/src/app/pages/MainPage/Navbar/index.tsx index 143346eb3..1d6d33b4e 100644 --- a/frontend/src/app/pages/MainPage/Navbar/index.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/index.tsx @@ -274,19 +274,19 @@ export function Navbar() { key="profile" prefix={<ProfileOutlined className="icon" />} > - <p>{t('nav.accout.accountSettings.title')}</p> + <p>{t('nav.account.accountSettings.title')}</p> </MenuListItem> <MenuListItem key="password" prefix={<FormOutlined className="icon" />} > - <p>{t('nav.accout.changePassword.title')}</p> + <p>{t('nav.account.changePassword.title')}</p> </MenuListItem> <Menu.SubMenu icon={<SwapOutlined className="icon" />} key="language" - title={t('nav.accout.switchLanguage.title')} + title={t('nav.account.switchLanguage.title')} > <Menu.Item key="zh">中文</Menu.Item> <Menu.Item key="en">English</Menu.Item> @@ -295,7 +295,7 @@ export function Navbar() { key="logout" prefix={<ExportOutlined className="icon" />} > - <p>{t('nav.accout.logout.title')}</p> + <p>{t('nav.account.logout.title')}</p> </MenuListItem> </Menu> } diff --git a/frontend/src/app/utils/chartHelper.ts b/frontend/src/app/utils/chartHelper.ts index c4c4e43fe..945d5fc75 100644 --- a/frontend/src/app/utils/chartHelper.ts +++ b/frontend/src/app/utils/chartHelper.ts @@ -401,7 +401,7 @@ export function getNameTextStyle(fontFamily, fontSize, color) { }; } -export function transfromToObjectArray( +export function transformToObjectArray( columns?: string[][], metas?: ChartDatasetMeta[], ) { @@ -434,7 +434,7 @@ export function getValueByColumnKey(col?: { aggregate?; colName: string }) { export function getColumnRenderOriginName(c?: ChartDataSectionField) { if (!c) { - return '[unkonwn]'; + return '[unknown]'; } if (c.aggregate === AggregateFieldActionType.NONE) { return c.colName; @@ -447,7 +447,7 @@ export function getColumnRenderOriginName(c?: ChartDataSectionField) { export function getColumnRenderName(c?: ChartDataSectionField) { if (!c) { - return '[unkonwn]'; + return '[unknown]'; } if (c.alias?.name) { return c.alias.name; diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 87524b211..626456081 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -21,7 +21,7 @@ "cancel": "取消", "saveDndEnter": "保存并进入" }, - "accout": { + "account": { "accountSettings": { "title": "账号设置", "clickUpload": "点击上传", diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index dc911c8aa..e15b0884b 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -21,7 +21,7 @@ "cancel": "取消", "saveDndEnter": "保存并进入" }, - "accout": { + "account": { "accountSettings": { "title": "账号设置", "clickUpload": "点击上传", From de2c20f02565a54fc5239cad430cd81071c68766 Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Thu, 23 Dec 2021 16:53:14 +0800 Subject: [PATCH 179/348] fix: org check name bug --- .../DataProviderExecuteOptimizer.java | 22 +++++++++++-------- .../server/service/BaseCRUDService.java | 3 +++ .../datart/server/service/VizCRUDService.java | 3 ++- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/data-providers/src/main/java/datart/data/provider/optimize/DataProviderExecuteOptimizer.java b/data-providers/src/main/java/datart/data/provider/optimize/DataProviderExecuteOptimizer.java index a77163580..a5991ebac 100644 --- a/data-providers/src/main/java/datart/data/provider/optimize/DataProviderExecuteOptimizer.java +++ b/data-providers/src/main/java/datart/data/provider/optimize/DataProviderExecuteOptimizer.java @@ -54,20 +54,24 @@ public Dataframe runOptimize(String queryKey, DataProviderSource source, QuerySc } } - public Dataframe getFromCache(String queryKey) { - Cache cache = CacheFactory.getCache(); - if (cache != null) { - return cache.get(queryKey); - } else { - return null; + try { + Cache cache = CacheFactory.getCache(); + if (cache != null) { + return cache.get(queryKey); + } + } catch (Exception e) { } + return null; } public void setCache(String queryKey, Dataframe dataframe, int cacheExpires) { - Cache cache = CacheFactory.getCache(); - if (cache != null) { - cache.put(queryKey, dataframe, cacheExpires); + try { + Cache cache = CacheFactory.getCache(); + if (cache != null) { + cache.put(queryKey, dataframe, cacheExpires); + } + } catch (Exception e) { } } diff --git a/server/src/main/java/datart/server/service/BaseCRUDService.java b/server/src/main/java/datart/server/service/BaseCRUDService.java index 577b19862..3c1626155 100644 --- a/server/src/main/java/datart/server/service/BaseCRUDService.java +++ b/server/src/main/java/datart/server/service/BaseCRUDService.java @@ -153,6 +153,9 @@ default void grantDefaultPermission(E entity) { } default boolean checkUnique(BaseEntity entity) { + if (!getDefaultMapper().checkUnique(entity)) { + Exceptions.tr(BaseException.class, "error.param.exists.name"); + } return true; } diff --git a/server/src/main/java/datart/server/service/VizCRUDService.java b/server/src/main/java/datart/server/service/VizCRUDService.java index ae6dce4f8..15552db3c 100644 --- a/server/src/main/java/datart/server/service/VizCRUDService.java +++ b/server/src/main/java/datart/server/service/VizCRUDService.java @@ -27,7 +27,8 @@ default E create(BaseCreateParam createParam) { requirePermission(instance, Const.CREATE); - checkUnique(instance); +// checkUnique(instance); + E e = BaseCRUDService.super.create(vizCreateParam); getRoleService().grantPermission(vizCreateParam.getPermissions()); From 5f84eaefb96c1fad1245cdb6785c29084f79ab27 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 23 Dec 2021 17:03:29 +0800 Subject: [PATCH 180/348] fix: view has no variables in addVariablesToBoard --- frontend/src/app/pages/DashBoardPage/pages/BoardEditor/index.tsx | 1 - .../DashBoardPage/pages/BoardEditor/slice/actions/actions.ts | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/index.tsx index 73a727100..07d5efc05 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/index.tsx @@ -72,7 +72,6 @@ export const BoardEditor: React.FC<{ dispatch(editHasChartWidget({ widgetId, dataChart, view })); onCloseChartEditor(); dispatch(addVariablesToBoard(view.variables)); - // todo view.variables save on board }, [boardChartEditorProps?.widgetId, dispatch, onCloseChartEditor], ); 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 56f84d82d..303263349 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 @@ -264,6 +264,7 @@ export const closeLinkageAction = (widget: Widget) => (dispatch, getState) => { export const addVariablesToBoard = (variables: Variable[]) => (dispatch, getState) => { + if (!variables) return; if (!variables.length) return; const addedViewId = variables[0].viewId; if (!addedViewId) return; From f75535b044da98c8e905dd24e9678d385c54d680 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 23 Dec 2021 17:07:22 +0800 Subject: [PATCH 181/348] fix: BasicCheckbox path --- frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx b/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx index f08a60851..11ccb2ca1 100644 --- a/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx +++ b/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx @@ -32,6 +32,7 @@ import { } from 'utils/object'; import { GroupLayout } from '.'; import { + BasicCheckbox, BasicColorSelector, BasicFont, BasicFontFamilySelector, @@ -47,7 +48,6 @@ import { BasicText, BasicUnControlledTabPanel, } from '../Basic'; -import BasicCheckbox from '../Basic/BasicCheckbox'; import { ConditionStylePanel, DataCachePanel, From 2b8f8a9969077ada45fbb3717e7fa020dd53f613 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Thu, 23 Dec 2021 17:20:52 +0800 Subject: [PATCH 182/348] refactor(chart): auto reset filter facade --- .../DateConditionConfiguration.tsx | 55 +++++++++++++++---- .../FilterFacadeConfiguration.tsx | 7 ++- .../ChartTimeSelector/ExactTimeSelector.tsx | 9 +-- .../MannualRangeTimeSelector.tsx | 13 ++--- .../RecommendRangeTimeSelector.tsx | 48 +++++++--------- .../RelativeTimeSelector.tsx | 8 +-- .../models/ChartFilterCondition.ts | 5 +- .../models/ChartHttpRequest.ts | 15 ++--- frontend/src/app/types/ChartConfig.ts | 6 +- frontend/src/app/types/FilterControlPanel.ts | 6 +- frontend/src/locales/en/translation.json | 1 + frontend/src/locales/zh/translation.json | 41 +++++++------- 12 files changed, 108 insertions(+), 106 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/DateConditionConfiguration.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/DateConditionConfiguration.tsx index d7c750759..8fcb7b9e7 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/DateConditionConfiguration.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/DateConditionConfiguration.tsx @@ -18,10 +18,18 @@ import { Tabs } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; -import { TimeFilterSubType } from 'app/types/FilterControlPanel'; +import { FilterConditionType } from 'app/types/ChartConfig'; +import { formatTime } from 'app/utils/time'; +import { + FILTER_TIME_FORMATTER_IN_QUERY, + RECOMMEND_TIME, +} from 'globalConstants'; +import moment from 'moment'; import { FC, memo, useState } from 'react'; import styled from 'styled-components/macro'; -import ChartFilterCondition from '../../../../../models/ChartFilterCondition'; +import ChartFilterCondition, { + ConditionBuilder, +} from '../../../../../models/ChartFilterCondition'; import TimeSelector from '../../ChartTimeSelector'; const DateConditionConfiguration: FC< @@ -31,28 +39,52 @@ const DateConditionConfiguration: FC< } & I18NComponentProps > = memo(({ i18nPrefix, condition, onChange: onConditionChange }) => { const t = useI18NPrefix(i18nPrefix); - const [subType, setSubType] = useState( - () => condition?.subType || TimeFilterSubType.Recommend, + const [type, setType] = useState<string>(() => + condition?.type === FilterConditionType.RangeTime + ? String(FilterConditionType.RangeTime) + : String(FilterConditionType.RecommendTime), ); - const handleConditionChanged = filter => { - onConditionChange?.(Object.assign(filter, { subType })); + const clearFilterWhenTypeChange = (type: string) => { + setType(type); + const conditionType = Number(type); + if (conditionType === FilterConditionType.RecommendTime) { + const filter = new ConditionBuilder(condition) + .setValue(RECOMMEND_TIME.TODAY) + .asRecommendTime(); + onConditionChange?.(filter); + } else if (conditionType === FilterConditionType.RangeTime) { + const filterRow = new ConditionBuilder(condition) + .setValue([ + formatTime(moment(), FILTER_TIME_FORMATTER_IN_QUERY), + formatTime(moment(), FILTER_TIME_FORMATTER_IN_QUERY), + ]) + .asRangeTime(); + onConditionChange?.(filterRow); + } }; return ( - <StyledDateConditionConfiguration activeKey={subType} onChange={setSubType}> - <Tabs.TabPane tab={t('recommend')} key={TimeFilterSubType.Recommend}> + <StyledDateConditionConfiguration + activeKey={type} + onChange={clearFilterWhenTypeChange} + destroyInactiveTabPane={true} + > + <Tabs.TabPane + tab={t('recommend')} + key={FilterConditionType.RecommendTime} + > <TimeSelector.RecommendRangeTimeSelector i18nPrefix={i18nPrefix} condition={condition} - onConditionChange={handleConditionChanged} + onConditionChange={onConditionChange} /> </Tabs.TabPane> - <Tabs.TabPane tab={t('manual')} key={TimeFilterSubType.Manual}> + <Tabs.TabPane tab={t('manual')} key={FilterConditionType.RangeTime}> <TimeSelector.MannualRangeTimeSelector i18nPrefix={i18nPrefix} condition={condition} - onFilterChange={handleConditionChanged} + onConditionChange={onConditionChange} /> </Tabs.TabPane> </StyledDateConditionConfiguration> @@ -63,6 +95,7 @@ export default DateConditionConfiguration; const StyledDateConditionConfiguration = styled(Tabs)` width: 100%; + padding: 0 !important; .ant-tabs-content-holder { margin: 10px 0; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterFacadeConfiguration.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterFacadeConfiguration.tsx index d18b7e2e1..c23339e1d 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterFacadeConfiguration.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterFacadeConfiguration.tsx @@ -69,8 +69,9 @@ const getFacadeOptions = (condition, category) => { case FilterConditionType.Value: return [ControllerFacadeTypes.Value]; case FilterConditionType.RangeTime: - case FilterConditionType.RelativeTime: // TODO(Stephen): to be new Range time component for both manual and recomend return [ControllerFacadeTypes.RangeTime]; + case FilterConditionType.RecommendTime: + return [ControllerFacadeTypes.RecommendTime]; case FilterConditionType.Tree: return [ControllerFacadeTypes.Tree]; } @@ -130,6 +131,10 @@ const FilterFacadeConfiguration: FC< !facades.includes(currentFacade as ControllerFacadeTypes) ) { setCurrentFacade(undefined); + handleFacadeChange(undefined); + } else if (!currentFacade) { + setCurrentFacade(facades?.[0]); + handleFacadeChange(facades?.[0]); } }, [condition, category, currentFacade]); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ExactTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ExactTimeSelector.tsx index b7c0722c7..7d04187c4 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ExactTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ExactTimeSelector.tsx @@ -22,7 +22,7 @@ import { TimeFilterConditionValue } from 'app/types/ChartConfig'; import { formatTime } from 'app/utils/time'; import { FILTER_TIME_FORMATTER_IN_QUERY } from 'globalConstants'; import moment from 'moment'; -import { FC, memo, useEffect } from 'react'; +import { FC, memo } from 'react'; const ExactTimeSelector: FC< { @@ -32,13 +32,6 @@ const ExactTimeSelector: FC< > = memo(({ time, i18nPrefix, onChange }) => { const t = useI18NPrefix(i18nPrefix); - useEffect(() => { - if (!time) { - console.log(`handleMomentTimeChange ---> `, time); - handleMomentTimeChange(moment()); - } - }, [time]); - const handleMomentTimeChange = momentTime => { const timeStr = formatTime(momentTime, FILTER_TIME_FORMATTER_IN_QUERY); onChange?.(timeStr); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/MannualRangeTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/MannualRangeTimeSelector.tsx index d327243e7..303ced8ad 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/MannualRangeTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/MannualRangeTimeSelector.tsx @@ -17,12 +17,11 @@ */ import { Row, Space } from 'antd'; -import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; -import TimeConfigContext from 'app/pages/ChartWorkbenchPage/contexts/TimeConfigContext'; +import { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import { FilterCondition, FilterConditionType } from 'app/types/ChartConfig'; import { formatTime, getTime } from 'app/utils/time'; import { FILTER_TIME_FORMATTER_IN_QUERY } from 'globalConstants'; -import { FC, memo, useContext, useState } from 'react'; +import { FC, memo, useState } from 'react'; import ChartFilterCondition, { ConditionBuilder, } from '../../../../models/ChartFilterCondition'; @@ -32,11 +31,9 @@ import ManualSingleTimeSelector from './ManualSingleTimeSelector'; const MannualRangeTimeSelector: FC< { condition?: FilterCondition; - onFilterChange: (filter: ChartFilterCondition) => void; + onConditionChange: (filter: ChartFilterCondition) => void; } & I18NComponentProps -> = memo(({ i18nPrefix, condition, onFilterChange }) => { - const t = useI18NPrefix(i18nPrefix); - const { format } = useContext(TimeConfigContext); +> = memo(({ i18nPrefix, condition, onConditionChange }) => { const [rangeTimes, setRangeTimes] = useState(() => { if (condition?.type === FilterConditionType.RangeTime) { const startTime = condition?.value?.[0]; @@ -53,7 +50,7 @@ const MannualRangeTimeSelector: FC< const filterRow = new ConditionBuilder(condition) .setValue(rangeTimes || []) .asRangeTime(); - onFilterChange && onFilterChange(filterRow); + onConditionChange?.(filterRow); }; const getRangeStringTimes = () => { diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx index 1d7ae3418..f464da166 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx @@ -18,11 +18,10 @@ import { Radio, Space } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; -import TimeConfigContext from 'app/pages/ChartWorkbenchPage/contexts/TimeConfigContext'; import { FilterCondition } from 'app/types/ChartConfig'; import { recommendTimeRangeConverter } from 'app/utils/time'; import { RECOMMEND_TIME } from 'globalConstants'; -import { FC, memo, useContext, useMemo, useState } from 'react'; +import { FC, memo, useMemo, useState } from 'react'; import ChartFilterCondition, { ConditionBuilder, } from '../../../../models/ChartFilterCondition'; @@ -35,9 +34,8 @@ const RecommendRangeTimeSelector: FC< } & I18NComponentProps > = memo(({ i18nPrefix, condition, onConditionChange }) => { const t = useI18NPrefix(i18nPrefix); - const { format } = useContext(TimeConfigContext); - const [recommend, setRecommend] = useState<string | undefined>(() => - String(condition?.value), + const [recommend, setRecommend] = useState<string | undefined>( + condition?.value as string, ); const handleChange = recommendTime => { @@ -61,32 +59,24 @@ const RecommendRangeTimeSelector: FC< onChange={e => handleChange(e.target?.value)} > <Space direction="vertical"> - <Radio value={RECOMMEND_TIME.TODAY}> - {t(RECOMMEND_TIME.TODAY)} - </Radio> - <Radio value={RECOMMEND_TIME.YESTERDAY}> - {t(RECOMMEND_TIME.YESTERDAY)} - </Radio> - <Radio value={RECOMMEND_TIME.THISWEEK}> - {t(RECOMMEND_TIME.THISWEEK)} - </Radio> + {[ + RECOMMEND_TIME.TODAY, + RECOMMEND_TIME.YESTERDAY, + RECOMMEND_TIME.THISWEEK, + ].map(time => ( + <Radio value={time}>{t(time)}</Radio> + ))} </Space> <Space direction="vertical"> - <Radio value={RECOMMEND_TIME.LAST_7_DAYS}> - {t(RECOMMEND_TIME.LAST_7_DAYS)} - </Radio> - <Radio value={RECOMMEND_TIME.LAST_30_DAYS}> - {t(RECOMMEND_TIME.LAST_30_DAYS)} - </Radio> - <Radio value={RECOMMEND_TIME.LAST_90_DAYS}> - {t(RECOMMEND_TIME.LAST_90_DAYS)} - </Radio> - <Radio value={RECOMMEND_TIME.LAST_1_MONTH}> - {t(RECOMMEND_TIME.LAST_1_MONTH)} - </Radio> - <Radio value={RECOMMEND_TIME.LAST_1_YEAR}> - {t(RECOMMEND_TIME.LAST_1_YEAR)} - </Radio> + {[ + RECOMMEND_TIME.LAST_7_DAYS, + RECOMMEND_TIME.LAST_30_DAYS, + RECOMMEND_TIME.LAST_90_DAYS, + RECOMMEND_TIME.LAST_1_MONTH, + RECOMMEND_TIME.LAST_1_YEAR, + ].map(time => ( + <Radio value={time}>{t(time)}</Radio> + ))} </Space> </Radio.Group> </Space> diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RelativeTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RelativeTimeSelector.tsx index 2a77cc26c..6b2815037 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RelativeTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RelativeTimeSelector.tsx @@ -21,7 +21,7 @@ import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import { TimeFilterConditionValue } from 'app/types/ChartConfig'; import { TIME_DIRECTION, TIME_UNIT_OPTIONS } from 'globalConstants'; import { unitOfTime } from 'moment'; -import { FC, memo, useEffect, useState } from 'react'; +import { FC, memo, useState } from 'react'; import styled from 'styled-components/macro'; const RelativeTimeSelector: FC< @@ -39,12 +39,6 @@ const RelativeTimeSelector: FC< () => (time as any)?.direction || '-', ); - useEffect(() => { - if (!time) { - handleTimeChange('d', 1, '-'); - } - }, [time]); - const handleTimeChange = ( unit: unitOfTime.DurationConstructor, amount: number, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartFilterCondition.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartFilterCondition.ts index 283023f2d..d62ead2e4 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartFilterCondition.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartFilterCondition.ts @@ -28,7 +28,6 @@ class ChartFilterCondition implements FilterCondition { type = FilterConditionType.Filter; value?; visualType = ''; - subType; operator?: string; children?: ChartFilterCondition[]; @@ -38,7 +37,6 @@ class ChartFilterCondition implements FilterCondition { this.type = condition.type || this.type; this.value = condition.value; this.visualType = condition.visualType; - this.subType = condition.subType; this.operator = condition.operator; this.children = (condition.children || []).map( child => new ChartFilterCondition(child), @@ -109,7 +107,6 @@ export class ConditionBuilder { if (condition) { this.condition.name = condition.name; this.condition.visualType = condition.visualType; - this.condition.subType = condition.subType; this.condition.type = condition.type; this.condition.value = condition.value; this.condition.operator = condition.operator; @@ -166,7 +163,7 @@ export class ConditionBuilder { } asRecommendTime(name?, sqlType?) { - this.condition.type = FilterConditionType.RelativeTime; + this.condition.type = FilterConditionType.RecommendTime; this.condition.operator = FilterSqlOperator.Equal; this.condition.name = name || this.condition.name; this.condition.visualType = sqlType || this.condition.visualType; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts index 2bb4798d2..b6546ad36 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts @@ -17,7 +17,6 @@ */ import { ChartDatasetPageInfo } from 'app/types/ChartDataset'; -import { TimeFilterSubType } from 'app/types/FilterControlPanel'; import { getStyleValue } from 'app/utils/chartHelper'; import { formatTime, @@ -32,6 +31,7 @@ import { ChartDataSectionField, ChartDataSectionType, ChartStyleSectionConfig, + FilterConditionType, RelationFilterValue, SortActionType, } from '../../../types/ChartConfig'; @@ -164,7 +164,7 @@ export class ChartDataRequestBuilder { } private normalizeFilters = (fields: ChartDataSectionField[]) => { - const _timeConverter = (visualType, subType, value) => { + const _timeConverter = (visualType, value) => { if (visualType !== 'DATE') { return value; } @@ -197,18 +197,16 @@ export class ChartDataRequestBuilder { }; } else { return { - value: _timeConverter( - field.filter?.condition?.visualType, - field.filter?.condition?.subType, - v, - ), + value: _timeConverter(field.filter?.condition?.visualType, v), valueType: field.type, }; } }) .filter(Boolean) as any[]; } - if (field?.filter?.condition?.subType === TimeFilterSubType.Recommend) { + if ( + field?.filter?.condition?.type === FilterConditionType.RecommendTime + ) { const timeRange = recommendTimeRangeConverter(conditionValue); return (timeRange || []).map(t => ({ value: t, @@ -219,7 +217,6 @@ export class ChartDataRequestBuilder { { value: _timeConverter( field.filter?.condition?.visualType, - field.filter?.condition?.subType, conditionValue, ), valueType: field.type, diff --git a/frontend/src/app/types/ChartConfig.ts b/frontend/src/app/types/ChartConfig.ts index 6012b7647..8ba15a928 100644 --- a/frontend/src/app/types/ChartConfig.ts +++ b/frontend/src/app/types/ChartConfig.ts @@ -19,7 +19,6 @@ import { ControllerFacadeTypes, ControllerVisibilityTypes, - TimeFilterSubType, } from 'app/types/FilterControlPanel'; import { FilterSqlOperator, @@ -94,7 +93,6 @@ export type FilterCondition = { | Array<RelationFilterValue> | TimeFilterConditionValue; visualType: string; - subType?: TimeFilterSubType | string; operator?: | string | Lowercase<keyof typeof FilterRelationType> @@ -135,7 +133,7 @@ export enum FilterConditionType { RangeValue = 1 << 4, Value = 1 << 5, RangeTime = 1 << 6, - RelativeTime = 1 << 7, + RecommendTime = 1 << 7, Time = 1 << 8, Tree = 1 << 9, @@ -146,7 +144,7 @@ export enum FilterConditionType { RangeValue | Value | RangeTime | - RelativeTime | + RecommendTime | Time | Tree, Relation = 1 << 50, diff --git a/frontend/src/app/types/FilterControlPanel.ts b/frontend/src/app/types/FilterControlPanel.ts index 73147e0f2..04890b939 100644 --- a/frontend/src/app/types/FilterControlPanel.ts +++ b/frontend/src/app/types/FilterControlPanel.ts @@ -22,6 +22,7 @@ export enum ControllerFacadeTypes { CheckboxGroup = 'checkboxGroup', MultiDropdownList = 'multiDropdownList', RangeTime = 'rangeTime', + RecommendTime = 'recommendTime', RangeValue = 'rangeValue', Text = 'text', Tree = 'tree', @@ -41,11 +42,6 @@ export enum TimeFilterValueCategory { Exact = 'exact', } -export enum TimeFilterSubType { - Recommend = 'recommend', - Manual = 'manual', -} - export enum ControllerVisibilityTypes { Hide = 'hide', Show = 'show', diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 24c25d5dd..589a55c40 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -43,6 +43,7 @@ "checkboxGroup": "Checkbox Group", "multiDropdownList": "multiple Dropdown List", "rangeTime": "Range Time", + "recommendTime": "Recommend Time", "rangeValue": "Range Value", "text": "Text", "tree": "Tree", diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index cda237631..c4fbf3c07 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -40,9 +40,10 @@ "controllerFacadeTypes": { "dropdownList": "下拉列表", "radioGroup": "单选按钮", - "checkboxGroup":"多选框", + "checkboxGroup": "多选框", "multiDropdownList": "多选下拉列表", "rangeTime": "日期范围", + "recommendTime": "推荐时间", "rangeValue": "数值范围", "text": "文本", "tree": "下拉树列表", @@ -369,15 +370,15 @@ "confirm": "请确认", "ok": "确认", "cancel": "取消", - "save":"保存" - }, + "save": "保存" + }, "edit": "编辑", "run": "运行", "publish": "发布", "cancelPublish": "取消发布", - "published":"已发布", - "unpublished":"未发布", - "archived":"已归档", + "published": "已发布", + "unpublished": "未发布", + "archived": "已归档", "share": { "link": "链接", "password": "密码", @@ -388,17 +389,17 @@ "downloadData": "下载数据" } }, - "board":{ - "action":{ - "dataChart":"数据图表", - "media":"媒体组件", - "container":"容器", - "controller":"控制器", - "undo":"撤销", - "redo":"重做", - "delete":"删除", - "copy":"复制", - "paste":"粘贴" + "board": { + "action": { + "dataChart": "数据图表", + "media": "媒体组件", + "container": "容器", + "controller": "控制器", + "undo": "撤销", + "redo": "重做", + "delete": "删除", + "copy": "复制", + "paste": "粘贴" } } }, @@ -413,9 +414,9 @@ "pleaseInputPassword": "请输入密码" } }, - "components":{ - "colorPicker":{ - "more":"更多", + "components": { + "colorPicker": { + "more": "更多", "ok": "确认", "cancel": "取消" } From 9523cbcdec1bef63580d2979711ac8e1c3819c1a Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Thu, 23 Dec 2021 17:23:33 +0800 Subject: [PATCH 183/348] fix:create permission bug fix --- .../java/datart/server/service/impl/ScheduleServiceImpl.java | 2 +- .../main/java/datart/server/service/impl/SourceServiceImpl.java | 2 +- .../java/datart/server/service/impl/StoryboardServiceImpl.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 55a16be83..bf758f896 100644 --- a/server/src/main/java/datart/server/service/impl/ScheduleServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/ScheduleServiceImpl.java @@ -93,7 +93,7 @@ public void requirePermission(Schedule schedule, int permission) { } private boolean hasPermission(Role role, Schedule schedule, int permission) { - if (schedule.getId() == null || rrrMapper.countRolePermission(schedule.getId(), role.getId()) == 0) { + if (schedule.getId() == null || (permission & Const.CREATE) == permission) { return securityManager.hasPermission(PermissionHelper.schedulePermission(schedule.getOrgId(), role.getId(), ResourceType.SCHEDULE.name(), permission)); } else { return securityManager.hasPermission(PermissionHelper.schedulePermission(schedule.getOrgId(), role.getId(), schedule.getId(), permission)); 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 86ae33c65..8979d2c5b 100644 --- a/server/src/main/java/datart/server/service/impl/SourceServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/SourceServiceImpl.java @@ -103,7 +103,7 @@ public void requirePermission(Source source, int permission) { } private boolean hasPermission(Role role, Source source, int permission) { - if (source.getId() == null || rrrMapper.countRolePermission(source.getId(), role.getId()) == 0) { + if (source.getId() == null || (permission & Const.CREATE) == permission) { return securityManager.hasPermission(PermissionHelper.sourcePermission(source.getOrgId(), role.getId(), ResourceType.SOURCE.name(), permission)); } else { return securityManager.hasPermission(PermissionHelper.sourcePermission(source.getOrgId(), role.getId(), source.getId(), permission)); diff --git a/server/src/main/java/datart/server/service/impl/StoryboardServiceImpl.java b/server/src/main/java/datart/server/service/impl/StoryboardServiceImpl.java index 561eba09c..6c8f8eee9 100644 --- a/server/src/main/java/datart/server/service/impl/StoryboardServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/StoryboardServiceImpl.java @@ -120,7 +120,7 @@ public void requirePermission(Storyboard storyboard, int permission) { } private boolean hasPermission(Role role, Storyboard storyboard, int permission) { - if (storyboard.getId() == null || rrrMapper.countRolePermission(storyboard.getId(), role.getId()) == 0) { + if (storyboard.getId() == null || (permission & Const.CREATE) == permission) { return securityManager.hasPermission(PermissionHelper.vizPermission(storyboard.getOrgId(), role.getId(), ResourceType.STORYBOARD.name(), permission)); } else { return securityManager.hasPermission(PermissionHelper.vizPermission(storyboard.getOrgId(), role.getId(), storyboard.getId(), permission)); From 9f7bd8ac3aa762583866093f06aefe3be1dac112 Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Thu, 23 Dec 2021 17:26:09 +0800 Subject: [PATCH 184/348] refactor:(Chart)refactor settings pageSize --- .../demo-custom-line-chart.js | 24 +++++-- .../demo-d3js-scatter-chart.js | 20 ++++++ .../ChartGraph/BasicAreaChart/config.ts | 20 ++++++ .../ChartGraph/BasicBarChart/config.ts | 29 +++++---- .../ChartGraph/BasicDoubleYChart/config.ts | 29 +++++---- .../ChartGraph/BasicFunnelChart/config.ts | 19 +++--- .../ChartGraph/BasicGaugeChart/config.ts | 21 ++++++- .../ChartGraph/BasicLineChart/config.ts | 29 +++++---- .../ChartGraph/BasicOutlineMapChart/config.ts | 20 ++++++ .../ChartGraph/BasicPieChart/config.ts | 19 +++--- .../ChartGraph/BasicRadarChart/config.ts | 29 +++++---- .../ChartGraph/BasicRichText/config.ts | 21 ++++++- .../ChartGraph/BasicScatterChart/config.ts | 29 +++++---- .../ChartGraph/ChartJSChart/config.ts | 20 ++++++ .../ChartGraph/ClusterBarChart/config.ts | 31 ++++++---- .../ChartGraph/ClusterColumnChart/config.ts | 31 ++++++---- .../ChartGraph/D3USMapChart/config.ts | 20 ++++++ .../ChartGraph/FenZuTableChart/config.ts | 24 +++---- .../ChartGraph/MingXiTableChart/config.ts | 62 +++++++++---------- .../NormalOutlineMapChart/config.ts | 20 ++++++ .../PercentageStackBarChart/config.ts | 29 +++++---- .../PercentageStackColumnChart/config.ts | 29 +++++---- .../ChartGraph/PivotSheetChart/config.ts | 60 ++++++------------ .../ChartGraph/ReChartsChart/config.ts | 20 ++++++ .../ChartGraph/ReactVizXYPlotChart/config.ts | 20 ++++++ .../ChartGraph/RephaelPaperChart/config.ts | 20 ++++++ .../ScatterOutlineMapChart/config.ts | 20 ++++++ .../ChartGraph/ScoreChart/config.ts | 20 ++++++ .../ChartGraph/StackBarChart/config.ts | 29 +++++---- .../ChartGraph/StackColumnChart/config.ts | 29 +++++---- .../ChartGraph/WaterfallChart/config.ts | 29 +++++---- .../ChartGraph/WordCloudChart/config.ts | 20 ++++++ .../models/ChartHttpRequest.ts | 11 +--- frontend/src/locales/zh/translation.json | 4 ++ 34 files changed, 587 insertions(+), 270 deletions(-) diff --git a/frontend/public/custom-chart-plugins/demo-custom-line-chart.js b/frontend/public/custom-chart-plugins/demo-custom-line-chart.js index e6eb2303b..084766ffa 100644 --- a/frontend/public/custom-chart-plugins/demo-custom-line-chart.js +++ b/frontend/public/custom-chart-plugins/demo-custom-line-chart.js @@ -410,7 +410,26 @@ function DemoCustomLineChart({ dHelper }) { ], }, ], - settings: [], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', @@ -472,9 +491,6 @@ function DemoCustomLineChart({ dHelper }) { title: '参考线', open: '点击参考线配置', }, - cache: { - title: '数据处理', - }, }, }, ], diff --git a/frontend/public/custom-chart-plugins/demo-d3js-scatter-chart.js b/frontend/public/custom-chart-plugins/demo-d3js-scatter-chart.js index 650ad9466..bf6ef8609 100644 --- a/frontend/public/custom-chart-plugins/demo-d3js-scatter-chart.js +++ b/frontend/public/custom-chart-plugins/demo-d3js-scatter-chart.js @@ -47,6 +47,26 @@ function D3JSScatterChart({ dHelper }) { ], }, ], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicAreaChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicAreaChart/config.ts index 88a853b10..d9fac9092 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicAreaChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicAreaChart/config.ts @@ -94,6 +94,26 @@ const config: ChartConfig = { ], }, ], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/config.ts index 0a171ad76..90bc04aa4 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/config.ts @@ -502,27 +502,33 @@ const config: ChartConfig = { ], settings: [ { - label: 'reference.title', - key: 'reference', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'reference.open', - key: 'panel', - comType: 'reference', - options: { type: 'modal' }, + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, { - label: 'cache.title', - key: 'cache', + label: 'reference.title', + key: 'reference', comType: 'group', rows: [ { - label: 'cache.title', + label: 'reference.open', key: 'panel', - comType: 'cache', + comType: 'reference', + options: { type: 'modal' }, }, ], }, @@ -597,9 +603,6 @@ const config: ChartConfig = { title: '参考线', open: '点击参考线配置', }, - cache: { - title: '数据处理', - }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicDoubleYChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicDoubleYChart/config.ts index 3f1c90142..262bda483 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicDoubleYChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicDoubleYChart/config.ts @@ -387,27 +387,33 @@ const config: ChartConfig = { ], settings: [ { - label: 'reference.title', - key: 'reference', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'reference.open', - key: 'panel', - comType: 'reference', - options: { type: 'modal' }, + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, { - label: 'cache.title', - key: 'cache', + label: 'reference.title', + key: 'reference', comType: 'group', rows: [ { - label: 'cache.title', + label: 'reference.open', key: 'panel', - comType: 'cache', + comType: 'reference', + options: { type: 'modal' }, }, ], }, @@ -475,9 +481,6 @@ const config: ChartConfig = { title: '参考线', open: '点击参考线配置', }, - cache: { - title: '数据处理', - }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/config.ts index 5e172089f..6cf514c02 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/config.ts @@ -239,14 +239,20 @@ const config: ChartConfig = { ], settings: [ { - label: 'cache.title', - key: 'cache', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'cache.title', - key: 'panel', - comType: 'cache', + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, @@ -287,9 +293,6 @@ const config: ChartConfig = { color: '颜色', colorize: '配色', }, - cache: { - title: '数据处理', - }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/config.ts index d951fe04a..574706ee5 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/config.ts @@ -344,7 +344,26 @@ const config: ChartConfig = { ], }, ], - settings: [], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicLineChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicLineChart/config.ts index 7c0671543..709e613e9 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicLineChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicLineChart/config.ts @@ -424,27 +424,33 @@ const config: ChartConfig = { ], settings: [ { - label: 'reference.title', - key: 'reference', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'reference.open', - key: 'panel', - comType: 'reference', - options: { type: 'modal' }, + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, { - label: 'cache.title', - key: 'cache', + label: 'reference.title', + key: 'reference', comType: 'group', rows: [ { - label: 'cache.title', + label: 'reference.open', key: 'panel', - comType: 'cache', + comType: 'reference', + options: { type: 'modal' }, }, ], }, @@ -510,9 +516,6 @@ const config: ChartConfig = { title: '参考线', open: '点击参考线配置', }, - cache: { - title: '数据处理', - }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicOutlineMapChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicOutlineMapChart/config.ts index 932dcacf2..65aa8fbce 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicOutlineMapChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicOutlineMapChart/config.ts @@ -217,6 +217,26 @@ const config: ChartConfig = { ], }, ], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts index 24c3e4f53..bfcb60db0 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts @@ -199,14 +199,20 @@ const config: ChartConfig = { ], settings: [ { - label: 'cache.title', - key: 'cache', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'cache.title', - key: 'panel', - comType: 'cache', + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, @@ -245,9 +251,6 @@ const config: ChartConfig = { title: '参考线', open: '点击参考线配置', }, - cache: { - title: '数据处理', - }, tooltip: { title: '提示信息', showPercentage: '增加百分比显示', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRadarChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRadarChart/config.ts index 7db180c0b..14a329c37 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRadarChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRadarChart/config.ts @@ -505,27 +505,33 @@ const config: ChartConfig = { ], settings: [ { - label: 'reference.title', - key: 'reference', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'reference.open', - key: 'panel', - comType: 'reference', - options: { type: 'modal' }, + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, { - label: 'cache.title', - key: 'cache', + label: 'reference.title', + key: 'reference', comType: 'group', rows: [ { - label: 'cache.title', + label: 'reference.open', key: 'panel', - comType: 'cache', + comType: 'reference', + options: { type: 'modal' }, }, ], }, @@ -600,9 +606,6 @@ const config: ChartConfig = { title: '参考线', open: '点击参考线配置', }, - cache: { - title: '数据处理', - }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/config.ts index eba640060..1e92a9ab3 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/config.ts @@ -57,7 +57,26 @@ const config: ChartConfig = { ], }, ], - settings: [], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/config.ts index de0807450..c6d098c1f 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/config.ts @@ -460,27 +460,33 @@ const config: ChartConfig = { ], settings: [ { - label: 'reference.title', - key: 'reference', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'reference.open', - key: 'panel', - comType: 'reference', - options: { type: 'modal' }, + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, { - label: 'cache.title', - key: 'cache', + label: 'reference.title', + key: 'reference', comType: 'group', rows: [ { - label: 'cache.title', + label: 'reference.open', key: 'panel', - comType: 'cache', + comType: 'reference', + options: { type: 'modal' }, }, ], }, @@ -546,9 +552,6 @@ const config: ChartConfig = { title: '参考线', open: '点击参考线配置', }, - cache: { - title: '数据处理', - }, scatter: { title: '散点图配置', cycleRatio: '气泡大像素比', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ChartJSChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ChartJSChart/config.ts index 11c8d3026..f6864d5c0 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ChartJSChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ChartJSChart/config.ts @@ -98,6 +98,26 @@ const config: ChartConfig = { ], }, ], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterBarChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterBarChart/config.ts index 19657173e..a02b4471a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterBarChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterBarChart/config.ts @@ -436,27 +436,33 @@ const config: ChartConfig = { ], settings: [ { - label: 'reference.title', - key: 'reference', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'reference.open', - key: 'panel', - comType: 'reference', - options: { type: 'modal' }, + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, { - label: 'cache.title', - key: 'cache', + label: 'reference.title', + key: 'reference', comType: 'group', rows: [ { - label: 'cache.title', + label: 'reference.open', key: 'panel', - comType: 'cache', + comType: 'reference', + options: { type: 'modal' }, }, ], }, @@ -531,8 +537,9 @@ const config: ChartConfig = { title: '参考线', open: '点击参考线配置', }, - cache: { - title: '数据处理', + paging: { + title: '常规', + pageSize: '总行数', }, }, }, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterColumnChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterColumnChart/config.ts index 19657173e..a02b4471a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterColumnChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterColumnChart/config.ts @@ -436,27 +436,33 @@ const config: ChartConfig = { ], settings: [ { - label: 'reference.title', - key: 'reference', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'reference.open', - key: 'panel', - comType: 'reference', - options: { type: 'modal' }, + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, { - label: 'cache.title', - key: 'cache', + label: 'reference.title', + key: 'reference', comType: 'group', rows: [ { - label: 'cache.title', + label: 'reference.open', key: 'panel', - comType: 'cache', + comType: 'reference', + options: { type: 'modal' }, }, ], }, @@ -531,8 +537,9 @@ const config: ChartConfig = { title: '参考线', open: '点击参考线配置', }, - cache: { - title: '数据处理', + paging: { + title: '常规', + pageSize: '总行数', }, }, }, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/D3USMapChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/D3USMapChart/config.ts index a34d17741..3c4230fd6 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/D3USMapChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/D3USMapChart/config.ts @@ -86,6 +86,26 @@ const config: ChartConfig = { ], }, ], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/config.ts index 461737f2e..7d9575526 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/config.ts @@ -194,14 +194,20 @@ const config: ChartConfig = { ], settings: [ { - label: 'cache.title', - key: 'cache', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'cache.title', - key: 'panel', - comType: 'cache', + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, @@ -243,13 +249,9 @@ const config: ChartConfig = { autoMerge: '自动合并相同内容', enableRaw: '使用原始数据', }, - cache: { - title: '数据处理', - }, paging: { - title: '分页设置', - enablePaging: '启用分页', - pageSize: '分页大小', + title: '常规', + pageSize: '总行数', }, }, }, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts index e59701932..4c66dce27 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts @@ -302,36 +302,6 @@ const config: ChartConfig = { }, ], settings: [ - { - label: 'summary.title', - key: 'summary', - comType: 'group', - rows: [ - { - label: 'summary.aggregateFields', - key: 'aggregateFields', - comType: 'select', - options: { - mode: 'multiple', - getItems: cols => { - const columns = (cols || []) - .filter(col => ['mixed'].includes(col.type)) - .reduce((acc, cur) => acc.concat(cur.rows || []), []) - .filter(c => c.type === 'NUMERIC') - .map(c => ({ - key: c.uid, - value: c.uid, - label: - c.label || c.aggregate - ? `${c.aggregate}(${c.colName})` - : c.colName, - })); - return columns; - }, - }, - }, - ], - }, { label: 'paging.title', key: 'paging', @@ -368,6 +338,36 @@ const config: ChartConfig = { }, ], }, + { + label: 'summary.title', + key: 'summary', + comType: 'group', + rows: [ + { + label: 'summary.aggregateFields', + key: 'aggregateFields', + comType: 'select', + options: { + mode: 'multiple', + getItems: cols => { + const columns = (cols || []) + .filter(col => ['mixed'].includes(col.type)) + .reduce((acc, cur) => acc.concat(cur.rows || []), []) + .filter(c => c.type === 'NUMERIC') + .map(c => ({ + key: c.uid, + value: c.uid, + label: + c.label || c.aggregate + ? `${c.aggregate}(${c.colName})` + : c.colName, + })); + return columns; + }, + }, + }, + ], + }, ], i18ns: [ { @@ -412,7 +412,7 @@ const config: ChartConfig = { aggregateFields: '汇总列', }, paging: { - title: '分页设置', + title: '常规', enablePaging: '启用分页', pageSize: '分页大小', }, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/NormalOutlineMapChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/NormalOutlineMapChart/config.ts index 4b47a11ef..44db0abd6 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/NormalOutlineMapChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/NormalOutlineMapChart/config.ts @@ -217,6 +217,26 @@ const config: ChartConfig = { ], }, ], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackBarChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackBarChart/config.ts index 6bf100a04..43baa55dc 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackBarChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackBarChart/config.ts @@ -430,27 +430,33 @@ const config: ChartConfig = { ], settings: [ { - label: 'reference.title', - key: 'reference', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'reference.open', - key: 'panel', - comType: 'reference', - options: { type: 'modal' }, + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, { - label: 'cache.title', - key: 'cache', + label: 'reference.title', + key: 'reference', comType: 'group', rows: [ { - label: 'cache.title', + label: 'reference.open', key: 'panel', - comType: 'cache', + comType: 'reference', + options: { type: 'modal' }, }, ], }, @@ -525,9 +531,6 @@ const config: ChartConfig = { title: '参考线', open: '点击参考线配置', }, - cache: { - title: '数据处理', - }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackColumnChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackColumnChart/config.ts index 6bf100a04..43baa55dc 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackColumnChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackColumnChart/config.ts @@ -430,27 +430,33 @@ const config: ChartConfig = { ], settings: [ { - label: 'reference.title', - key: 'reference', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'reference.open', - key: 'panel', - comType: 'reference', - options: { type: 'modal' }, + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, { - label: 'cache.title', - key: 'cache', + label: 'reference.title', + key: 'reference', comType: 'group', rows: [ { - label: 'cache.title', + label: 'reference.open', key: 'panel', - comType: 'cache', + comType: 'reference', + options: { type: 'modal' }, }, ], }, @@ -525,9 +531,6 @@ const config: ChartConfig = { title: '参考线', open: '点击参考线配置', }, - cache: { - title: '数据处理', - }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts index 757d30458..f9e965342 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts @@ -237,6 +237,24 @@ const config: ChartConfig = { }, ], settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, { label: 'summary.rowSummary', key: 'rowSummary', @@ -280,42 +298,6 @@ const config: ChartConfig = { }, ], }, - { - label: 'paging.title', - key: 'paging', - comType: 'group', - rows: [ - { - label: 'paging.enablePaging', - key: 'enablePaging', - default: true, - comType: 'checkbox', - options: { - needRefresh: true, - }, - }, - - { - label: 'paging.pageSize', - key: 'pageSize', - default: 2000, - comType: 'inputNumber', - options: { - needRefresh: true, - step: 1, - min: 0, - }, - watcher: { - deps: ['enablePaging'], - action: props => { - return { - disabled: !props.enablePaging, - }; - }, - }, - }, - ], - }, ], i18ns: [ { @@ -351,11 +333,6 @@ const config: ChartConfig = { subTotalPosition: '小计位置', aggregateFields: '汇总列', }, - paging: { - title: '分页设置', - enablePaging: '启用分页', - pageSize: '分页大小', - }, }, }, { @@ -393,7 +370,6 @@ const config: ChartConfig = { }, paging: { title: 'Paging', - enablePaging: 'Enable Paging', pageSize: 'Page Size', }, }, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReChartsChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReChartsChart/config.ts index 11c8d3026..f6864d5c0 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReChartsChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReChartsChart/config.ts @@ -98,6 +98,26 @@ const config: ChartConfig = { ], }, ], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactVizXYPlotChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactVizXYPlotChart/config.ts index 9571bdb37..702af2fad 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactVizXYPlotChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactVizXYPlotChart/config.ts @@ -99,6 +99,26 @@ const config: ChartConfig = { ], }, ], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/RephaelPaperChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/RephaelPaperChart/config.ts index 11c8d3026..f6864d5c0 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/RephaelPaperChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/RephaelPaperChart/config.ts @@ -98,6 +98,26 @@ const config: ChartConfig = { ], }, ], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScatterOutlineMapChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScatterOutlineMapChart/config.ts index 56bc4bd93..1b63bacb3 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScatterOutlineMapChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScatterOutlineMapChart/config.ts @@ -228,6 +228,26 @@ const config: ChartConfig = { ], }, ], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScoreChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScoreChart/config.ts index 45994c7b4..891aa79a7 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScoreChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScoreChart/config.ts @@ -248,6 +248,26 @@ const config: ChartConfig = { ], }, ], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackBarChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackBarChart/config.ts index 6bf100a04..43baa55dc 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackBarChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackBarChart/config.ts @@ -430,27 +430,33 @@ const config: ChartConfig = { ], settings: [ { - label: 'reference.title', - key: 'reference', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'reference.open', - key: 'panel', - comType: 'reference', - options: { type: 'modal' }, + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, { - label: 'cache.title', - key: 'cache', + label: 'reference.title', + key: 'reference', comType: 'group', rows: [ { - label: 'cache.title', + label: 'reference.open', key: 'panel', - comType: 'cache', + comType: 'reference', + options: { type: 'modal' }, }, ], }, @@ -525,9 +531,6 @@ const config: ChartConfig = { title: '参考线', open: '点击参考线配置', }, - cache: { - title: '数据处理', - }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackColumnChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackColumnChart/config.ts index 6bf100a04..43baa55dc 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackColumnChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackColumnChart/config.ts @@ -430,27 +430,33 @@ const config: ChartConfig = { ], settings: [ { - label: 'reference.title', - key: 'reference', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'reference.open', - key: 'panel', - comType: 'reference', - options: { type: 'modal' }, + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, { - label: 'cache.title', - key: 'cache', + label: 'reference.title', + key: 'reference', comType: 'group', rows: [ { - label: 'cache.title', + label: 'reference.open', key: 'panel', - comType: 'cache', + comType: 'reference', + options: { type: 'modal' }, }, ], }, @@ -525,9 +531,6 @@ const config: ChartConfig = { title: '参考线', open: '点击参考线配置', }, - cache: { - title: '数据处理', - }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WaterfallChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WaterfallChart/config.ts index 317c60e10..80838285a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WaterfallChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WaterfallChart/config.ts @@ -395,27 +395,33 @@ const config: ChartConfig = { ], settings: [ { - label: 'reference.title', - key: 'reference', + label: 'paging.title', + key: 'paging', comType: 'group', rows: [ { - label: 'reference.open', - key: 'panel', - comType: 'reference', - options: { type: 'modal' }, + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, }, ], }, { - label: 'cache.title', - key: 'cache', + label: 'reference.title', + key: 'reference', comType: 'group', rows: [ { - label: 'cache.title', + label: 'reference.open', key: 'panel', - comType: 'cache', + comType: 'reference', + options: { type: 'modal' }, }, ], }, @@ -471,9 +477,6 @@ const config: ChartConfig = { title: '参考线', open: '点击参考线配置', }, - cache: { - title: '数据处理', - }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WordCloudChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WordCloudChart/config.ts index 0488d172c..47b5b632c 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WordCloudChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WordCloudChart/config.ts @@ -217,6 +217,26 @@ const config: ChartConfig = { ], }, ], + settings: [ + { + label: 'paging.title', + key: 'paging', + comType: 'group', + rows: [ + { + label: 'paging.pageSize', + key: 'pageSize', + default: 1000, + comType: 'inputNumber', + options: { + needRefresh: true, + step: 1, + min: 0, + }, + }, + ], + }, + ], i18ns: [ { lang: 'zh-CN', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts index 2bb4798d2..ec57734f9 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts @@ -285,19 +285,10 @@ export class ChartDataRequestBuilder { private buildPageInfo() { const settingStyles = this.charSettingConfigs; - const enablePaging = getStyleValue(settingStyles, [ - 'paging', - 'enablePaging', - ]); const pageSize = getStyleValue(settingStyles, ['paging', 'pageSize']); - if (!enablePaging) { - return { - pageSize: Number.MAX_SAFE_INTEGER, - }; - } return { pageNo: this.pageInfo?.pageNo, - pageSize: pageSize || 10, + pageSize: pageSize || 1000, }; } diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index e50c2022c..58588b16b 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -396,6 +396,10 @@ "opacity": "透明度", "backgroundColor": "背景颜色", "borderStyle": "边框样式" + }, + "paging": { + "title": "常规", + "pageSize": "总行数" } }, "present": { From 838509817f2960f430482e123bb7ea516ba6a04c Mon Sep 17 00:00:00 2001 From: "jin.gao" <jin.gao@mobilemd.cn> Date: Thu, 23 Dec 2021 17:31:48 +0800 Subject: [PATCH 185/348] =?UTF-8?q?fix:=20widget=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E9=80=8F=E4=BC=A0=E6=96=B9=E5=BC=8F=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BasicTableChart/BasicTableChart.tsx | 18 ++++++-------- .../FenZuTableChart/FenZuTableChart.tsx | 5 ++-- .../ChartTools/ChartIFrameContainer.tsx | 7 +++--- .../ChartTools/ChartLifecycleAdapter.tsx | 11 ++++----- .../WidgetCore/DataChartWidget/index.tsx | 24 +++++++++++++++++-- 5 files changed, 39 insertions(+), 26 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx index 553c2e95f..1fabcfb56 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx @@ -17,7 +17,6 @@ */ import ReactChart from 'app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactChart'; -import { WidgetContextProps } from 'app/pages/DashBoardPage/contexts/WidgetContext'; import { ChartConfig } from 'app/types/ChartConfig'; import ChartDataset from 'app/types/ChartDataset'; import { ChartDataViewFieldType } from 'app/types/ChartDataView'; @@ -79,7 +78,7 @@ class BasicTableChart extends ReactChart { context, options.dataset, options.config, - options.content, + options.widgetSpecialConfig, ), context, ); @@ -93,7 +92,7 @@ class BasicTableChart extends ReactChart { context, dataset?: ChartDataset, config?: ChartConfig, - content?: WidgetContextProps, + widgetSpecialConfig?: any, ) { if (!dataset || !config) { return { locale: { emptyText: ' ' } }; @@ -150,7 +149,7 @@ class BasicTableChart extends ReactChart { tableColumns, aggregateConfigs, ), - components: this.getTableComponents(styleConfigs, content), + components: this.getTableComponents(styleConfigs, widgetSpecialConfig), ...this.getAntdTableStyleOptions( styleConfigs, dataset, @@ -305,11 +304,8 @@ class BasicTableChart extends ReactChart { }); } - getTableComponents(styleConfigs, content?: WidgetContextProps) { - const linkRelations = content?.relations - .filter(re => re.config.type === 'widgetToWidget') - .map(item => item.config.widgetToWidget?.triggerColumn); - const jumpFieldName = content?.config.jumpConfig?.field?.jumpFieldName; + getTableComponents(styleConfigs, widgetSpecialConfig) { + const { linkFields, jumpField } = widgetSpecialConfig; const tableHeaders = this.getStyleValue(styleConfigs, [ 'header', @@ -400,8 +396,8 @@ class BasicTableChart extends ReactChart { <TableComponentsTd {...rest} style={Object.assign(style || {}, conditionalCellStyle)} - isLinkCell={linkRelations?.includes(dataIndex)} - isJumpCell={jumpFieldName === dataIndex} + isLinkCell={linkFields?.includes(dataIndex)} + isJumpCell={jumpField === dataIndex} /> ); }, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx index 24990d39e..a110d77a4 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx @@ -16,7 +16,6 @@ * limitations under the License. */ -import { WidgetContextProps } from 'app/pages/DashBoardPage/contexts/WidgetContext'; import { ChartConfig, ChartDataSectionType } from 'app/types/ChartConfig'; import ChartDataset from 'app/types/ChartDataset'; import { @@ -43,7 +42,7 @@ class FenZuTableChart extends BasicTableChart { context, dataset?: ChartDataset, config?: ChartConfig, - content?: WidgetContextProps, + widgetSpecialConfig?: any, ) { if (!dataset || !config) { return { locale: { emptyText: ' ' } }; @@ -76,7 +75,7 @@ class FenZuTableChart extends BasicTableChart { dataColumns, ), summaryFn: undefined as any, - components: this.getTableComponents(styleConfigs, content), + components: this.getTableComponents(styleConfigs, widgetSpecialConfig), ...this.getAntdTableStyleOptions( styleConfigs, dataset, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx index a78902cde..9dda2d789 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx @@ -21,7 +21,6 @@ import { FrameContextConsumer, } from 'app/components/ReactFrameComponent'; import Chart from 'app/pages/ChartWorkbenchPage/models/Chart'; -import { WidgetContextProps } from 'app/pages/DashBoardPage/contexts/WidgetContext'; import { ChartConfig } from 'app/types/ChartConfig'; import { FC, memo } from 'react'; import styled, { StyleSheetManager } from 'styled-components/macro'; @@ -35,7 +34,7 @@ const ChartIFrameContainer: FC<{ containerId?: string; width?: any; height?: any; - content?: WidgetContextProps; + widgetSpecialConfig?: any; }> = memo(props => { const transformToSafeCSSProps = (width, height) => { let newStyle = { width, height }; @@ -61,7 +60,7 @@ const ChartIFrameContainer: FC<{ chart={props.chart} config={props.config} style={transformToSafeCSSProps(props?.width, props?.height)} - content={props.content} + widgetSpecialConfig={props.widgetSpecialConfig} /> </div> ); @@ -96,7 +95,7 @@ const ChartIFrameContainer: FC<{ chart={props.chart} config={props.config} style={transformToSafeCSSProps(props?.width, props?.height)} - content={props.content} + widgetSpecialConfig={props.widgetSpecialConfig} /> </StyledChartLifecycleAdapter> </StyleSheetManager> diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx index 94a16abb3..b4f4979ca 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx @@ -22,7 +22,6 @@ import { useFrame } from 'app/components/ReactFrameComponent'; import useMount from 'app/hooks/useMount'; import Chart from 'app/pages/ChartWorkbenchPage/models/Chart'; import ChartEventBroker from 'app/pages/ChartWorkbenchPage/models/ChartEventBroker'; -import { WidgetContextProps } from 'app/pages/DashBoardPage/contexts/WidgetContext'; import { ChartConfig } from 'app/types/ChartConfig'; import { ChartLifecycle } from 'app/types/ChartLifecycle'; import React, { CSSProperties, useEffect, useRef, useState } from 'react'; @@ -42,8 +41,8 @@ const ChartLifecycleAdapter: React.FC<{ chart: Chart; config: ChartConfig; style: CSSProperties; - content?: WidgetContextProps; -}> = ({ dataset, chart, config, style, content }) => { + widgetSpecialConfig?: any; +}> = ({ dataset, chart, config, style, widgetSpecialConfig }) => { const [chartResourceLoader, setChartResourceLoader] = useState( () => new ChartIFrameContainerResourceLoader(), ); @@ -75,7 +74,7 @@ const ChartLifecycleAdapter: React.FC<{ newBrokerRef.register(chart); newBrokerRef.publish( ChartLifecycle.MOUNTED, - { containerId, dataset, config, content }, + { containerId, dataset, config, widgetSpecialConfig }, { document, window, @@ -113,11 +112,11 @@ const ChartLifecycleAdapter: React.FC<{ { dataset, config, - content, + widgetSpecialConfig, }, { document, window, width: style?.width, height: style?.height }, ); - }, [config, dataset, content, containerStatus, document, window]); + }, [config, dataset, widgetSpecialConfig, containerStatus, document, window]); // when chart size change useEffect(() => { diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx index af0593015..42c0d6ef7 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx @@ -87,6 +87,18 @@ export const DataChartWidget: React.FC<DataChartWidgetProps> = memo(() => { } }, [chartClick, dataChart]); + const widgetSpecialConfig = useMemo(() => { + const linkFields = widget?.relations + .filter(re => re.config.type === 'widgetToWidget') + .map(item => item.config.widgetToWidget?.triggerColumn); + const jumpField = widget?.config.jumpConfig?.field?.jumpFieldName; + + return { + linkFields, + jumpField, + }; + }, [widget]); + const onResize = useCallback(() => {}, []); const { @@ -134,13 +146,21 @@ export const DataChartWidget: React.FC<DataChartWidgetProps> = memo(() => { width={cacheW} height={cacheH} containerId={widgetId} - content={widget} + widgetSpecialConfig={widgetSpecialConfig} /> ); } catch (error) { return <span>has err in {`<ChartIFrameContainer>`}</span>; } - }, [cacheH, cacheW, chart, dataChart, dataset, widgetId]); + }, [ + cacheH, + cacheW, + chart, + dataChart, + dataset, + widgetSpecialConfig, + widgetId, + ]); return ( <Wrap className="widget-chart" ref={ref}> {chartFrame} From e8a327448b4942905f1d7bfbb438bc320a6e1c44 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 23 Dec 2021 17:52:22 +0800 Subject: [PATCH 186/348] fix: compatibly legacyName transfromToObjectArray --- frontend/src/app/utils/chartHelper.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/frontend/src/app/utils/chartHelper.ts b/frontend/src/app/utils/chartHelper.ts index 945d5fc75..2c1943270 100644 --- a/frontend/src/app/utils/chartHelper.ts +++ b/frontend/src/app/utils/chartHelper.ts @@ -421,6 +421,30 @@ export function transformToObjectArray( return objCol; }); } +// TODO delete this function #migration +export function transfromToObjectArray( + columns?: string[][], + metas?: ChartDatasetMeta[], +) { + console.warn( + 'This method `transfromToObjectArray` will be deprecated and can be replaced by `transformToObjectArray`', + ); + if (!columns || !metas) { + return []; + } + return columns.map((col, index) => { + let objCol = { + id: index, + }; + for (let i = 0; i < metas.length; i++) { + const key = metas?.[i]?.name; + if (!!key) { + objCol[key] = col[i]; + } + } + return objCol; + }); +} export function getValueByColumnKey(col?: { aggregate?; colName: string }) { if (!col) { From a4b52b22aa398eb31848f481852bbc97ec0fe9dc Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Thu, 23 Dec 2021 18:37:11 +0800 Subject: [PATCH 187/348] refactor(chart): show new range time filter --- .../ManualSingleTimeSelector.tsx | 11 ++- .../models/ChartHttpRequest.ts | 1 - .../ControllerPanel/ControllerPanel.tsx | 2 +- .../components/RangTimeFilter.tsx | 53 -------------- .../components/RangeTimeFilter.tsx | 69 +++++++++++++++++++ .../ControllerPanel/components/index.ts | 4 +- 6 files changed, 82 insertions(+), 58 deletions(-) delete mode 100644 frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangTimeFilter.tsx create mode 100644 frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangeTimeFilter.tsx diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ManualSingleTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ManualSingleTimeSelector.tsx index 64cf83b04..ad67d633b 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ManualSingleTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ManualSingleTimeSelector.tsx @@ -20,6 +20,9 @@ import { Select, Space } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import { TimeFilterConditionValue } from 'app/types/ChartConfig'; import { TimeFilterValueCategory } from 'app/types/FilterControlPanel'; +import { formatTime } from 'app/utils/time'; +import { FILTER_TIME_FORMATTER_IN_QUERY } from 'globalConstants'; +import moment from 'moment'; import { FC, memo, useState } from 'react'; import styled from 'styled-components/macro'; import ExactTimeSelector from './ExactTimeSelector'; @@ -41,7 +44,13 @@ const ManualSingleTimeSelector: FC< const handleTimeCategoryChange = type => { setType(type); - onTimeChange?.(null); + if (type === TimeFilterValueCategory.Exact) { + onTimeChange?.(formatTime(moment(), FILTER_TIME_FORMATTER_IN_QUERY)); + } else if (type === TimeFilterValueCategory.Relative) { + onTimeChange?.({ unit: 'd', amount: 1, direction: '-' }); + } else { + onTimeChange?.(null); + } }; const renderTimeSelector = type => { diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts index b6546ad36..8469b0b84 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts @@ -159,7 +159,6 @@ export class ChartDataRequestBuilder { return true; }) .map(col => col); - return this.normalizeFilters(fields); } diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/ControllerPanel.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/ControllerPanel.tsx index e5b057e25..1816bac66 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/ControllerPanel.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/ControllerPanel.tsx @@ -130,7 +130,7 @@ const ControllerPanel: FC<{ case ControllerFacadeTypes.MultiDropdownList: return <Filters.MultiDropdownListFilter {...props} />; case ControllerFacadeTypes.RangeTime: - return <Filters.RangTimeFilter {...props} />; + return <Filters.RangeTimeFilter {...props} />; case ControllerFacadeTypes.RangeValue: return <Filters.RangValueFilter {...props} />; case ControllerFacadeTypes.Text: diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangTimeFilter.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangTimeFilter.tsx deleted file mode 100644 index bf03d23c1..000000000 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangTimeFilter.tsx +++ /dev/null @@ -1,53 +0,0 @@ -/** - * 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 { DatePicker } from 'antd'; -import { updateBy } from 'app/utils/mutation'; -import moment from 'moment'; -import { FC, memo, useState } from 'react'; -import { PresentControllerFilterProps } from '.'; - -// TODO(Stephen): to be use relative time -const RangTimeFilter: FC<PresentControllerFilterProps> = memo( - ({ condition, onConditionChange }) => { - const [timeRange, setTimeRange] = useState<string[]>(() => { - if (Array.isArray(condition?.value)) { - return condition?.value as string[]; - } - return []; - }); - - const handleDateChange = (times: any) => { - const newCondition = updateBy(condition!, draft => { - draft.value = (times || []).map(d => d.toString()); - }); - onConditionChange(newCondition); - setTimeRange(newCondition.value as string[]); - }; - - return ( - <DatePicker.RangePicker - showTime - value={[moment(timeRange?.[0]), moment(timeRange?.[1])]} - onChange={handleDateChange} - /> - ); - }, -); - -export default RangTimeFilter; diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangeTimeFilter.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangeTimeFilter.tsx new file mode 100644 index 000000000..f7d3adfb2 --- /dev/null +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangeTimeFilter.tsx @@ -0,0 +1,69 @@ +/** + * 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 { Space } from 'antd'; +import TimeSelector from 'app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector'; +import { ConditionBuilder } from 'app/pages/ChartWorkbenchPage/models/ChartFilterCondition'; +import { FilterConditionType } from 'app/types/ChartConfig'; +import { FC, memo, useState } from 'react'; +import { PresentControllerFilterProps } from '.'; + +const RangeTimeFilter: FC<PresentControllerFilterProps> = memo( + ({ condition, onConditionChange }) => { + const dateI18NPrefix = 'viz.common.filter.date'; + const [rangeTimes, setRangeTimes] = useState(() => { + if (condition?.type === FilterConditionType.RangeTime) { + const startTime = condition?.value?.[0]; + const endTime = condition?.value?.[1]; + return [startTime, endTime]; + } + return []; + }); + + const handleTimeChange = index => time => { + rangeTimes[index] = time; + setRangeTimes(rangeTimes); + + const filterRow = new ConditionBuilder(condition) + .setValue(rangeTimes || []) + .asRangeTime(); + onConditionChange?.(filterRow); + }; + + return ( + <div> + <Space direction="vertical" size={12}> + <TimeSelector.ManualSingleTimeSelector + i18nPrefix={dateI18NPrefix} + time={rangeTimes?.[0] as any} + isStart={true} + onTimeChange={handleTimeChange(0)} + /> + <TimeSelector.ManualSingleTimeSelector + i18nPrefix={dateI18NPrefix} + time={rangeTimes?.[1] as any} + isStart={false} + onTimeChange={handleTimeChange(1)} + /> + </Space> + </div> + ); + }, +); + +export default RangeTimeFilter; diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/index.ts b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/index.ts index 2c5566cd5..ec9e4046e 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/index.ts +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/index.ts @@ -21,7 +21,7 @@ import { FilterCondition } from 'app/types/ChartConfig'; import DropdownListFilter from './DropdownListFilter'; import MultiDropdownListFilter from './MultiDropdownListFilter'; import RadioGroupFilter from './RadioGroupFilter'; -import RangTimeFilter from './RangTimeFilter'; +import RangeTimeFilter from './RangeTimeFilter'; import RangValueFilter from './RangValueFilter'; import SliderFilter from './SliderFilter'; import TextFilter from './TextFilter'; @@ -41,7 +41,7 @@ const Filters = { DropdownListFilter, MultiDropdownListFilter, RadioGroupFilter, - RangTimeFilter, + RangeTimeFilter, RangValueFilter, SliderFilter, TextFilter, From f6a94e36b23a066e04f93bb38d25b5afa00ddd9a Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Thu, 23 Dec 2021 18:58:32 +0800 Subject: [PATCH 188/348] refactor(chart): add recommend time preview filter --- .../ControllerPanel/ControllerPanel.tsx | 2 ++ .../components/RangeTimeFilter.tsx | 6 ++-- .../components/RecommendTimeFilter.tsx | 36 +++++++++++++++++++ .../ControllerPanel/components/index.ts | 2 ++ 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RecommendTimeFilter.tsx diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/ControllerPanel.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/ControllerPanel.tsx index 1816bac66..70e7005b1 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/ControllerPanel.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/ControllerPanel.tsx @@ -131,6 +131,8 @@ const ControllerPanel: FC<{ return <Filters.MultiDropdownListFilter {...props} />; case ControllerFacadeTypes.RangeTime: return <Filters.RangeTimeFilter {...props} />; + case ControllerFacadeTypes.RecommendTime: + return <Filters.RecommendTimeFilter {...props} />; case ControllerFacadeTypes.RangeValue: return <Filters.RangValueFilter {...props} />; case ControllerFacadeTypes.Text: diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangeTimeFilter.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangeTimeFilter.tsx index f7d3adfb2..128655ed0 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangeTimeFilter.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangeTimeFilter.tsx @@ -25,7 +25,7 @@ import { PresentControllerFilterProps } from '.'; const RangeTimeFilter: FC<PresentControllerFilterProps> = memo( ({ condition, onConditionChange }) => { - const dateI18NPrefix = 'viz.common.filter.date'; + const i18NPrefix = 'viz.common.filter.date'; const [rangeTimes, setRangeTimes] = useState(() => { if (condition?.type === FilterConditionType.RangeTime) { const startTime = condition?.value?.[0]; @@ -49,13 +49,13 @@ const RangeTimeFilter: FC<PresentControllerFilterProps> = memo( <div> <Space direction="vertical" size={12}> <TimeSelector.ManualSingleTimeSelector - i18nPrefix={dateI18NPrefix} + i18nPrefix={i18NPrefix} time={rangeTimes?.[0] as any} isStart={true} onTimeChange={handleTimeChange(0)} /> <TimeSelector.ManualSingleTimeSelector - i18nPrefix={dateI18NPrefix} + i18nPrefix={i18NPrefix} time={rangeTimes?.[1] as any} isStart={false} onTimeChange={handleTimeChange(1)} diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RecommendTimeFilter.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RecommendTimeFilter.tsx new file mode 100644 index 000000000..ceb649748 --- /dev/null +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RecommendTimeFilter.tsx @@ -0,0 +1,36 @@ +/** + * 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 TimeSelector from 'app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector'; +import { FC, memo } from 'react'; +import { PresentControllerFilterProps } from '.'; + +const RecommendTimeFilter: FC<PresentControllerFilterProps> = memo( + ({ condition, onConditionChange }) => { + const i18NPrefix = 'viz.common.filter.date'; + return ( + <TimeSelector.RecommendRangeTimeSelector + i18nPrefix={i18NPrefix} + condition={condition} + onConditionChange={onConditionChange} + /> + ); + }, +); + +export default RecommendTimeFilter; diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/index.ts b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/index.ts index ec9e4046e..16fe7434d 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/index.ts +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/index.ts @@ -23,6 +23,7 @@ import MultiDropdownListFilter from './MultiDropdownListFilter'; import RadioGroupFilter from './RadioGroupFilter'; import RangeTimeFilter from './RangeTimeFilter'; import RangValueFilter from './RangValueFilter'; +import RecommendTimeFilter from './RecommendTimeFilter'; import SliderFilter from './SliderFilter'; import TextFilter from './TextFilter'; import TimeFilter from './TimeFilter'; @@ -42,6 +43,7 @@ const Filters = { MultiDropdownListFilter, RadioGroupFilter, RangeTimeFilter, + RecommendTimeFilter, RangValueFilter, SliderFilter, TextFilter, From 299c9200985ab4781ca3c9cf136ba1c70e3cdadb Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Thu, 23 Dec 2021 19:46:30 +0800 Subject: [PATCH 189/348] feat(chart): add date time pick filter --- .../FilterFacadeConfiguration.tsx | 4 +- .../ChartTimeSelector/CurrentRangeTime.tsx | 19 ++--- .../components/ChartTimeSelector/index.ts | 2 + .../ControllerPanel/ControllerPanel.tsx | 6 +- .../components/RangeTimePickerFilter.tsx | 75 +++++++++++++++++++ .../ControllerPanel/components/index.ts | 2 + frontend/src/app/types/FilterControlPanel.ts | 1 + frontend/src/locales/en/translation.json | 7 +- frontend/src/locales/zh/translation.json | 1 + 9 files changed, 99 insertions(+), 18 deletions(-) create mode 100644 frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangeTimePickerFilter.tsx diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterFacadeConfiguration.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterFacadeConfiguration.tsx index c23339e1d..0965af7b7 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterFacadeConfiguration.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterFacadeConfiguration.tsx @@ -69,9 +69,9 @@ const getFacadeOptions = (condition, category) => { case FilterConditionType.Value: return [ControllerFacadeTypes.Value]; case FilterConditionType.RangeTime: - return [ControllerFacadeTypes.RangeTime]; + return [ControllerFacadeTypes.RangeTimePicker]; case FilterConditionType.RecommendTime: - return [ControllerFacadeTypes.RecommendTime]; + return [ControllerFacadeTypes.RangeTimePicker]; case FilterConditionType.Tree: return [ControllerFacadeTypes.Tree]; } diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/CurrentRangeTime.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/CurrentRangeTime.tsx index 92bea649f..ad31a32c6 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/CurrentRangeTime.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/CurrentRangeTime.tsx @@ -21,14 +21,15 @@ import moment from 'moment'; import { FC, memo } from 'react'; const { RangePicker } = DatePicker; -const CurrentRangeTime: FC<{ times?: [string, string] }> = memo(({ times }) => { - return ( - <RangePicker - showTime - disabled - value={[moment(times?.[0]), moment(times?.[1])]} - /> - ); -}); +const CurrentRangeTime: FC<{ times?: [string, string]; disabled?: boolean }> = + memo(({ times, disabled = true }) => { + return ( + <RangePicker + showTime + disabled={disabled} + value={[moment(times?.[0]), moment(times?.[1])]} + /> + ); + }); export default CurrentRangeTime; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/index.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/index.ts index a308ceb63..58212ab6a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/index.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/index.ts @@ -16,6 +16,7 @@ * limitations under the License. */ +import CurrentRangeTime from './CurrentRangeTime'; import MannualRangeTimeSelector from './MannualRangeTimeSelector'; import ManualSingleTimeSelector from './ManualSingleTimeSelector'; import RecommendRangeTimeSelector from './RecommendRangeTimeSelector'; @@ -24,6 +25,7 @@ const TimeSelector = { MannualRangeTimeSelector, ManualSingleTimeSelector, RecommendRangeTimeSelector, + CurrentRangeTime, }; export default TimeSelector; diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/ControllerPanel.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/ControllerPanel.tsx index 70e7005b1..7203aec68 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/ControllerPanel.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/ControllerPanel.tsx @@ -129,10 +129,8 @@ const ControllerPanel: FC<{ return <Filters.DropdownListFilter {...props} />; case ControllerFacadeTypes.MultiDropdownList: return <Filters.MultiDropdownListFilter {...props} />; - case ControllerFacadeTypes.RangeTime: - return <Filters.RangeTimeFilter {...props} />; - case ControllerFacadeTypes.RecommendTime: - return <Filters.RecommendTimeFilter {...props} />; + case ControllerFacadeTypes.RangeTimePicker: + return <Filters.RangeTimePickerFilter {...props} />; case ControllerFacadeTypes.RangeValue: return <Filters.RangValueFilter {...props} />; case ControllerFacadeTypes.Text: diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangeTimePickerFilter.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangeTimePickerFilter.tsx new file mode 100644 index 000000000..cdd53284a --- /dev/null +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/RangeTimePickerFilter.tsx @@ -0,0 +1,75 @@ +/** + * 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 { DatePicker } from 'antd'; +import { ConditionBuilder } from 'app/pages/ChartWorkbenchPage/models/ChartFilterCondition'; +import { FilterConditionType } from 'app/types/ChartConfig'; +import { + formatTime, + getTime, + recommendTimeRangeConverter, +} from 'app/utils/time'; +import { FILTER_TIME_FORMATTER_IN_QUERY } from 'globalConstants'; +import moment from 'moment'; +import { FC, memo, useMemo } from 'react'; +import { PresentControllerFilterProps } from '.'; +const { RangePicker } = DatePicker; + +const toMoment = t => { + if (!t) { + return moment(); + } + if (Boolean(t) && typeof t === 'object' && 'unit' in t) { + const time = getTime(+(t.direction + t.amount), t.unit)(t.unit, t.isStart); + return moment(formatTime(time, FILTER_TIME_FORMATTER_IN_QUERY)); + } + return moment(t); +}; + +const RangeTimePickerFilter: FC<PresentControllerFilterProps> = memo( + ({ condition, onConditionChange }) => { + const handleTimeChange = (moments, dateStrings) => { + const filterRow = new ConditionBuilder(condition) + .setValue(dateStrings) + .asRangeTime(); + onConditionChange?.(filterRow); + }; + + const rangeTimes = useMemo(() => { + if (condition?.type === FilterConditionType.RangeTime) { + const startTime = toMoment(condition?.value?.[0]); + const endTime = toMoment(condition?.value?.[1]); + return [startTime, endTime]; + } + if (condition?.type === FilterConditionType.RecommendTime) { + return recommendTimeRangeConverter(condition?.value)?.map(toMoment); + } + return [moment(), moment()]; + }, [condition?.type, condition?.value]); + + return ( + <RangePicker + showTime + value={rangeTimes as any} + onChange={handleTimeChange} + /> + ); + }, +); + +export default RangeTimePickerFilter; diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/index.ts b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/index.ts index 16fe7434d..3c1d24bb2 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/index.ts +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/components/ControllerPanel/components/index.ts @@ -22,6 +22,7 @@ import DropdownListFilter from './DropdownListFilter'; import MultiDropdownListFilter from './MultiDropdownListFilter'; import RadioGroupFilter from './RadioGroupFilter'; import RangeTimeFilter from './RangeTimeFilter'; +import RangeTimePickerFilter from './RangeTimePickerFilter'; import RangValueFilter from './RangValueFilter'; import RecommendTimeFilter from './RecommendTimeFilter'; import SliderFilter from './SliderFilter'; @@ -43,6 +44,7 @@ const Filters = { MultiDropdownListFilter, RadioGroupFilter, RangeTimeFilter, + RangeTimePickerFilter, RecommendTimeFilter, RangValueFilter, SliderFilter, diff --git a/frontend/src/app/types/FilterControlPanel.ts b/frontend/src/app/types/FilterControlPanel.ts index 04890b939..0dea30b8c 100644 --- a/frontend/src/app/types/FilterControlPanel.ts +++ b/frontend/src/app/types/FilterControlPanel.ts @@ -22,6 +22,7 @@ export enum ControllerFacadeTypes { CheckboxGroup = 'checkboxGroup', MultiDropdownList = 'multiDropdownList', RangeTime = 'rangeTime', + RangeTimePicker = 'rangeTimePicker', RecommendTime = 'recommendTime', RangeValue = 'rangeValue', Text = 'text', diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 589a55c40..042dbcc7b 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -43,6 +43,7 @@ "checkboxGroup": "Checkbox Group", "multiDropdownList": "multiple Dropdown List", "rangeTime": "Range Time", + "rangeTimePicker": "Range Time", "recommendTime": "Recommend Time", "rangeValue": "Range Value", "text": "Text", @@ -415,9 +416,9 @@ "pleaseInputPassword": "please input password" } }, - "components":{ - "colorPicker":{ - "more":"More", + "components": { + "colorPicker": { + "more": "More", "ok": "OK", "cancel": "Cancel" } diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index c4fbf3c07..94cda6d76 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -43,6 +43,7 @@ "checkboxGroup": "多选框", "multiDropdownList": "多选下拉列表", "rangeTime": "日期范围", + "rangeTimePicker": "日期范围", "recommendTime": "推荐时间", "rangeValue": "数值范围", "text": "文本", From 1e41ba9a0ffbb28bd3a3506968f243947d621e9f Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Thu, 23 Dec 2021 19:51:13 +0800 Subject: [PATCH 190/348] refactor:(Chart) delete DataCachePanel --- .../Customize/DataCachePanel.tsx | 87 ------------------- .../FormGenerator/Customize/index.ts | 1 - .../FormGenerator/Layout/ItemLayout.tsx | 3 - .../ChartGraph/BasicTableChart/config.ts | 18 ---- frontend/src/app/types/ChartConfig.ts | 1 - 5 files changed, 110 deletions(-) delete mode 100644 frontend/src/app/components/FormGenerator/Customize/DataCachePanel.tsx diff --git a/frontend/src/app/components/FormGenerator/Customize/DataCachePanel.tsx b/frontend/src/app/components/FormGenerator/Customize/DataCachePanel.tsx deleted file mode 100644 index f6cb5f3f1..000000000 --- a/frontend/src/app/components/FormGenerator/Customize/DataCachePanel.tsx +++ /dev/null @@ -1,87 +0,0 @@ -/** - * 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 { ChartStyleSectionConfig } from 'app/types/ChartConfig'; -import { updateByKey } from 'app/utils/mutation'; -import { FC, memo, useEffect } from 'react'; -import { CloneValueDeep, mergeDefaultToValue } from 'utils/object'; -import { GroupLayout } from '../Layout'; -import { GroupLayoutMode, ItemLayoutProps } from '../types'; -import { itemLayoutComparer } from '../utils'; - -const defaultRows = [ - { - label: 'displayCount', - key: 'displayCount', - default: 10, - comType: 'inputNumber', - }, - { - label: 'autoLoad', - key: 'autoLoad', - default: true, - comType: 'switch', - }, - { - label: 'enableRaw', - key: 'enableRaw', - default: false, - comType: 'switch', - }, -]; - -const DataCachePanel: FC<ItemLayoutProps<ChartStyleSectionConfig>> = memo( - ({ - ancestors, - translate: t = title => title, - data: row, - dataConfigs, - onChange, - }) => { - useEffect(() => { - if (!row.rows || row.rows.length === 0) { - onChange?.( - ancestors, - updateByKey( - row, - 'rows', - mergeDefaultToValue(CloneValueDeep(defaultRows)), - ), - ); - } - }, [row]); - - const handleOnChange = (ancestors, value) => { - onChange?.(ancestors, value, true); - }; - - return ( - <GroupLayout - ancestors={ancestors} - mode={GroupLayoutMode.INNER} - data={row} - translate={t} - dataConfigs={dataConfigs} - onChange={handleOnChange} - /> - ); - }, - itemLayoutComparer, -); - -export default DataCachePanel; diff --git a/frontend/src/app/components/FormGenerator/Customize/index.ts b/frontend/src/app/components/FormGenerator/Customize/index.ts index 8640715e2..b27e87a06 100644 --- a/frontend/src/app/components/FormGenerator/Customize/index.ts +++ b/frontend/src/app/components/FormGenerator/Customize/index.ts @@ -17,7 +17,6 @@ */ export { default as ConditionStylePanel } from './ConditionStylePanel'; -export { default as DataCachePanel } from './DataCachePanel'; export { default as DataReferencePanel } from './DataReferencePanel'; export { default as ListTemplatePanel } from './ListTemplatePanel'; export { default as UnControlledTableHeaderPanel } from './UnControlledTableHeaderPanel'; diff --git a/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx b/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx index 8878595c5..9445b26f7 100644 --- a/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx +++ b/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx @@ -50,7 +50,6 @@ import { } from '../Basic'; import { ConditionStylePanel, - DataCachePanel, DataReferencePanel, ListTemplatePanel, UnControlledTableHeaderPanel, @@ -151,8 +150,6 @@ const ItemLayout: FC<FormGeneratorLayoutProps<ChartStyleSectionConfig>> = memo( return <ListTemplatePanel {...props} />; case ChartStyleSectionComponentType.LINE: return <BasicLine {...props} />; - case ChartStyleSectionComponentType.CACHE: - return <DataCachePanel {...props} />; case ChartStyleSectionComponentType.REFERENCE: return <DataReferencePanel {...props} />; case ChartStyleSectionComponentType.TABLEHEADER: diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/config.ts index 95f16318e..e990157fe 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/config.ts @@ -203,18 +203,6 @@ const config: ChartConfig = { }, ], settings: [ - { - label: 'cache.title', - key: 'cache', - comType: 'group', - rows: [ - { - label: 'cache.title', - key: 'panel', - comType: 'cache', - }, - ], - }, { label: 'paging.title', key: 'paging', @@ -294,9 +282,6 @@ const config: ChartConfig = { autoMerge: '自动合并相同内容', enableRaw: '使用原始数据', }, - cache: { - title: '数据处理', - }, paging: { title: '分页设置', enablePaging: '启用分页', @@ -340,9 +325,6 @@ const config: ChartConfig = { autoMerge: 'Auto Merge', enableRaw: 'Enable Raw Data', }, - cache: { - title: 'Data Process', - }, paging: { title: 'Paging', enablePaging: 'Enable Paging', diff --git a/frontend/src/app/types/ChartConfig.ts b/frontend/src/app/types/ChartConfig.ts index 6012b7647..15db1d1b6 100644 --- a/frontend/src/app/types/ChartConfig.ts +++ b/frontend/src/app/types/ChartConfig.ts @@ -196,7 +196,6 @@ export const ChartStyleSectionComponentType = { INPUTPERCENTAGE: 'inputPercentage', SLIDER: 'slider', GROUP: 'group', - CACHE: 'cache', REFERENCE: 'reference', TABS: 'tabs', LISTTEMPLATE: 'listTemplate', From c9a359c77c2fa874d58ecfc875c73de3eb875783 Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Thu, 23 Dec 2021 19:52:44 +0800 Subject: [PATCH 191/348] fix:(Chart) fix tableChart enablePaging --- .../app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts index ec57734f9..1fc9ae870 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts @@ -286,7 +286,12 @@ export class ChartDataRequestBuilder { private buildPageInfo() { const settingStyles = this.charSettingConfigs; const pageSize = getStyleValue(settingStyles, ['paging', 'pageSize']); + const enablePaging = getStyleValue(settingStyles, [ + 'paging', + 'enablePaging', + ]); return { + countTotal: !!enablePaging, pageNo: this.pageInfo?.pageNo, pageSize: pageSize || 1000, }; From f693bc6e1c829fa26436b6195bbdeeac354f5ef2 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 24 Dec 2021 10:45:04 +0800 Subject: [PATCH 192/348] fix(chart): shoudl not clear all string filter datas issue #423 --- .../CategoryConditionConfiguration.tsx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx index 3b46ed26c..f15c80e79 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx @@ -19,7 +19,10 @@ import { Button, Row, Select, Space, Tabs, Transfer, Tree } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import useMount from 'app/hooks/useMount'; -import { FilterConditionType, RelationFilterValue } from 'app/types/ChartConfig'; +import { + FilterConditionType, + RelationFilterValue, +} from 'app/types/ChartConfig'; import ChartDataView from 'app/types/ChartDataView'; import { getDistinctFields } from 'app/utils/fetch'; import { FilterSqlOperator } from 'globalConstants'; @@ -30,7 +33,6 @@ import ChartFilterCondition, { ConditionBuilder, } from '../../../../../models/ChartFilterCondition'; import CategoryConditionEditableTable from './CategoryConditionEditableTable'; -// import CategoryConditionEditableTable from './CategoryConditionEditableTableBak'; import CategoryConditionRelationSelector from './CategoryConditionRelationSelector'; const CategoryConditionConfiguration: FC< @@ -91,6 +93,8 @@ const CategoryConditionConfiguration: FC< } }); + console.log(`condition ---> `, condition); + const getDataOptionFields = () => { return dataView?.meta || []; }; @@ -175,12 +179,6 @@ const CategoryConditionConfiguration: FC< // setListDatas(convertToList(dataset?.columns, selectedKeys)); } else { setListDatas(convertToList(dataset?.rows, selectedKeys)); - setTargetKeys([]); - const filter = new ConditionBuilder(condition) - .setOperator(FilterSqlOperator.In) - .setValue([]) - .asGeneral(); - onConditionChange(filter); } }); }; From da33395ecb5448c58669951f25419a21654bc5ae Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 24 Dec 2021 10:51:14 +0800 Subject: [PATCH 193/348] refactor(chart): move antd table wrapper into basic table chart --- .../BasicTableChart}/AntdTableWrapper.tsx | 0 .../components/ChartGraph/BasicTableChart/BasicTableChart.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/{ChartTools => ChartGraph/BasicTableChart}/AntdTableWrapper.tsx (100%) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/AntdTableWrapper.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/AntdTableWrapper.tsx similarity index 100% rename from frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/AntdTableWrapper.tsx rename to frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/AntdTableWrapper.tsx diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx index 5e11f84ab..a1adf3d01 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx @@ -30,7 +30,7 @@ import { import { toFormattedValue } from 'app/utils/number'; import { isEmptyArray, Omit } from 'utils/object'; import { v4 as uuidv4 } from 'uuid'; -import AntdTableWrapper from '../../ChartTools/AntdTableWrapper'; +import AntdTableWrapper from './AntdTableWrapper'; import { getCustomBodyCellStyle, getCustomBodyRowStyle, From 6416fbd0e0c53c4e9fa94a33beadd1ac280d15c6 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Fri, 24 Dec 2021 11:28:42 +0800 Subject: [PATCH 194/348] style: format json code --- frontend/src/locales/en/translation.json | 70 ++++++++++------------ frontend/src/locales/zh/translation.json | 74 +++++++++++------------- 2 files changed, 66 insertions(+), 78 deletions(-) diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 626456081..5abdd64a3 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -198,8 +198,6 @@ "goBack": "Back", "run": "Run", "save": "Save", - - "format": { "local": "local", "date": "date" @@ -432,45 +430,41 @@ "downloadData": "Download Data" } }, - "board":{ - "action":{ - "dataChart":"DataChart", - "addDataChartFormList":"Add DataChart Form List", - "createDataChartInBoard":"Create DataChart In Board", - - "media":"Media", - "image":"Image", - "richText":"Rich Text", - "timer":"Timer", - "iFrame":"iFrame", - "video":"Video", - - "container":"Container", - "tab":"Tab", - - "controller":"Controller", - "undo":"Undo", - "redo":"Redo", - "delete":"Delete", - "copy":"Copy", - "paste":"Paste" + "board": { + "action": { + "dataChart": "DataChart", + "addDataChartFormList": "Add DataChart Form List", + "createDataChartInBoard": "Create DataChart In Board", + "media": "Media", + "image": "Image", + "richText": "Rich Text", + "timer": "Timer", + "iFrame": "iFrame", + "video": "Video", + "container": "Container", + "tab": "Tab", + "controller": "Controller", + "undo": "Undo", + "redo": "Redo", + "delete": "Delete", + "copy": "Copy", + "paste": "Paste" }, - "controlTypes":{ - "common":"Common", - "date":"Date", - "numeric":"Numeric", - "button":"Button" + "controlTypes": { + "common": "Common", + "date": "Date", + "numeric": "Numeric", + "button": "Button" } - }, - "widget":{ - "type":{ - "chart":"Chart", - "media":"Media", - "container":"Container", - "controller":"Controller", - "query":"Query", - "reset":"Reset" + "widget": { + "type": { + "chart": "Chart", + "media": "Media", + "container": "Container", + "controller": "Controller", + "query": "Query", + "reset": "Reset" } } }, diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 7d12b9621..f027ee3fa 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -37,7 +37,7 @@ "newPassword": "新密码", "confirmPassword": "确定新密码", "success": "修改成功", - "save":"保存" + "save": "保存" }, "switchLanguage": { "title": "切换语言" @@ -199,7 +199,6 @@ "goBack": "返回", "run": "执行", "save": "保存", - "format": { "local": "本地", "date": "日期" @@ -435,47 +434,42 @@ "downloadData": "下载数据" } }, - "board":{ - "action":{ - "dataChart":"数据图表", - "addDataChartFormList":"添加已有数据图表", - "createDataChartInBoard":"新建数据图表", - - "media":"媒体组件", - "image":"图片", - "richText":"富文本", - "timer":"计时器", - "iFrame":"iFrame", - "video":"视频", - - - "container":"容器", - "tab":"标签页", - "轮播图":"", - - "controller":"控制器", - - "undo":"撤销", - "redo":"重做", - "delete":"删除", - "copy":"复制", - "paste":"粘贴" + "board": { + "action": { + "dataChart": "数据图表", + "addDataChartFormList": "添加已有数据图表", + "createDataChartInBoard": "新建数据图表", + "media": "媒体组件", + "image": "图片", + "richText": "富文本", + "timer": "计时器", + "iFrame": "iFrame", + "video": "视频", + "container": "容器", + "tab": "标签页", + "轮播图": "", + "controller": "控制器", + "undo": "撤销", + "redo": "重做", + "delete": "删除", + "copy": "复制", + "paste": "粘贴" }, - "controlTypes":{ - "common":"常规", - "date":"日期", - "numeric":"数值", - "button":"按钮" + "controlTypes": { + "common": "常规", + "date": "日期", + "numeric": "数值", + "button": "按钮" } }, - "widget":{ - "type":{ - "chart":"数据图表", - "media":"媒体", - "container":"容器", - "controller":"控制器", - "query":"查询", - "reset":"重置" + "widget": { + "type": { + "chart": "数据图表", + "media": "媒体", + "container": "容器", + "controller": "控制器", + "query": "查询", + "reset": "重置" } } }, From da6295a0cabfd0c60a6c1ce3b48c54d66f20599c Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Fri, 24 Dec 2021 11:56:10 +0800 Subject: [PATCH 195/348] chore: remove incorrect comments --- frontend/src/app/pages/ActivePage/Loadable.tsx | 3 --- frontend/src/app/pages/AuthorizationPage/Loadable.tsx | 3 --- frontend/src/app/pages/ForgetPasswordPage/Loadable.tsx | 3 --- frontend/src/app/pages/LoginPage/Loadable.tsx | 3 --- frontend/src/app/pages/MainPage/Loadable.tsx | 3 --- frontend/src/app/pages/RegisterPage/Loadable.tsx | 3 --- frontend/src/app/pages/SharePage/Loadable.tsx | 3 --- 7 files changed, 21 deletions(-) diff --git a/frontend/src/app/pages/ActivePage/Loadable.tsx b/frontend/src/app/pages/ActivePage/Loadable.tsx index 205f3aa05..af9b98fc0 100644 --- a/frontend/src/app/pages/ActivePage/Loadable.tsx +++ b/frontend/src/app/pages/ActivePage/Loadable.tsx @@ -15,9 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * Asynchronously loads the component for NotFoundPage - */ import { defaultLazyLoad } from 'utils/loadable'; diff --git a/frontend/src/app/pages/AuthorizationPage/Loadable.tsx b/frontend/src/app/pages/AuthorizationPage/Loadable.tsx index 252622fab..aeb3fe23a 100644 --- a/frontend/src/app/pages/AuthorizationPage/Loadable.tsx +++ b/frontend/src/app/pages/AuthorizationPage/Loadable.tsx @@ -15,9 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * Asynchronously loads the component for NotFoundPage - */ import { defaultLazyLoad } from 'utils/loadable'; diff --git a/frontend/src/app/pages/ForgetPasswordPage/Loadable.tsx b/frontend/src/app/pages/ForgetPasswordPage/Loadable.tsx index 5198635b9..ba1e2bdab 100644 --- a/frontend/src/app/pages/ForgetPasswordPage/Loadable.tsx +++ b/frontend/src/app/pages/ForgetPasswordPage/Loadable.tsx @@ -15,9 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * Asynchronously loads the component for NotFoundPage - */ import { defaultLazyLoad } from 'utils/loadable'; diff --git a/frontend/src/app/pages/LoginPage/Loadable.tsx b/frontend/src/app/pages/LoginPage/Loadable.tsx index 0c71ae061..c026aa0ce 100644 --- a/frontend/src/app/pages/LoginPage/Loadable.tsx +++ b/frontend/src/app/pages/LoginPage/Loadable.tsx @@ -15,9 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * Asynchronously loads the component for NotFoundPage - */ import { defaultLazyLoad } from 'utils/loadable'; diff --git a/frontend/src/app/pages/MainPage/Loadable.tsx b/frontend/src/app/pages/MainPage/Loadable.tsx index 7276ef68f..6b5e7ce8d 100644 --- a/frontend/src/app/pages/MainPage/Loadable.tsx +++ b/frontend/src/app/pages/MainPage/Loadable.tsx @@ -15,9 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * Asynchronously loads the component for NotFoundPage - */ import { defaultLazyLoad } from 'utils/loadable'; diff --git a/frontend/src/app/pages/RegisterPage/Loadable.tsx b/frontend/src/app/pages/RegisterPage/Loadable.tsx index eda1906f8..66bffe11e 100644 --- a/frontend/src/app/pages/RegisterPage/Loadable.tsx +++ b/frontend/src/app/pages/RegisterPage/Loadable.tsx @@ -15,9 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * Asynchronously loads the component for NotFoundPage - */ import { defaultLazyLoad } from 'utils/loadable'; diff --git a/frontend/src/app/pages/SharePage/Loadable.tsx b/frontend/src/app/pages/SharePage/Loadable.tsx index 193a7a6c0..c8bafda8f 100644 --- a/frontend/src/app/pages/SharePage/Loadable.tsx +++ b/frontend/src/app/pages/SharePage/Loadable.tsx @@ -15,9 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * Asynchronously loads the component for NotFoundPage - */ import { defaultLazyLoad } from 'utils/loadable'; From ee3e37ec5af8396f35574e787d4aa289dd0db73b Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Fri, 24 Dec 2021 11:59:03 +0800 Subject: [PATCH 196/348] fix: sql builder bugfix --- .../core/data/provider/QueryScript.java | 3 +-- .../core/data/provider/ScriptVariable.java | 12 ++++++++++ .../provider/calcite/SqlVariableVisitor.java | 1 - .../data/provider/jdbc/SqlScriptRender.java | 9 +++---- .../data/provider/script/ScriptRender.java | 13 ---------- .../provider/script/VariablePlaceholder.java | 4 ++-- .../service/impl/FolderServiceImpl.java | 24 +++++++++++++++---- .../service/impl/SourceServiceImpl.java | 2 +- 8 files changed, 39 insertions(+), 29 deletions(-) diff --git a/core/src/main/java/datart/core/data/provider/QueryScript.java b/core/src/main/java/datart/core/data/provider/QueryScript.java index a99dd530f..4d7ba6ccf 100644 --- a/core/src/main/java/datart/core/data/provider/QueryScript.java +++ b/core/src/main/java/datart/core/data/provider/QueryScript.java @@ -45,11 +45,10 @@ public class QueryScript implements Serializable { private List<ScriptVariable> variables; - private Map<String,Column> schema; + private Map<String, Column> schema; public String toQueryKey() { return 'Q' + DigestUtils.md5Hex(JSON.toJSONString(this)); } - } \ No newline at end of file diff --git a/core/src/main/java/datart/core/data/provider/ScriptVariable.java b/core/src/main/java/datart/core/data/provider/ScriptVariable.java index 115055757..8727aa158 100644 --- a/core/src/main/java/datart/core/data/provider/ScriptVariable.java +++ b/core/src/main/java/datart/core/data/provider/ScriptVariable.java @@ -18,10 +18,12 @@ package datart.core.data.provider; +import datart.core.base.consts.Const; import datart.core.base.consts.ValueType; import datart.core.base.consts.VariableTypeEnum; import lombok.Data; import lombok.EqualsAndHashCode; +import org.apache.commons.lang3.StringUtils; import java.util.Set; @@ -35,6 +37,8 @@ public class ScriptVariable extends TypedValue { private Set<String> values; + private String nameWithQuote; + private boolean expression; @Override @@ -56,4 +60,12 @@ public ScriptVariable(String name, VariableTypeEnum type, ValueType valueType, S this.expression = expression; } + public String getNameWithQuote() { + if (nameWithQuote != null) { + return nameWithQuote; + } + nameWithQuote = StringUtils.prependIfMissing(name, Const.DEFAULT_VARIABLE_QUOTE); + nameWithQuote = StringUtils.appendIfMissing(nameWithQuote, Const.DEFAULT_VARIABLE_QUOTE); + return nameWithQuote; + } } \ No newline at end of file diff --git a/data-providers/src/main/java/datart/data/provider/calcite/SqlVariableVisitor.java b/data-providers/src/main/java/datart/data/provider/calcite/SqlVariableVisitor.java index c55cc8a93..d9f3e5d29 100644 --- a/data-providers/src/main/java/datart/data/provider/calcite/SqlVariableVisitor.java +++ b/data-providers/src/main/java/datart/data/provider/calcite/SqlVariableVisitor.java @@ -107,7 +107,6 @@ private VariablePlaceholder createVariablePlaceholder(SqlCall sqlCall, String va return new TrueVariablePlaceholder(originalSqlFragment); } - variable.setName(variableName); if (VariableTypeEnum.PERMISSION.equals(variable.getType())) { return new PermissionVariablePlaceholder(variable, sqlDialect, sqlCall, originalSqlFragment); } else { diff --git a/data-providers/src/main/java/datart/data/provider/jdbc/SqlScriptRender.java b/data-providers/src/main/java/datart/data/provider/jdbc/SqlScriptRender.java index e716e7a44..104d951fd 100644 --- a/data-providers/src/main/java/datart/data/provider/jdbc/SqlScriptRender.java +++ b/data-providers/src/main/java/datart/data/provider/jdbc/SqlScriptRender.java @@ -29,7 +29,6 @@ import datart.data.provider.calcite.SqlValidateUtils; import datart.data.provider.calcite.SqlParserUtils; import datart.data.provider.calcite.SqlVariableVisitor; -import datart.data.provider.calcite.parser.impl.SqlParserImpl; import datart.data.provider.freemarker.FreemarkerContext; import datart.data.provider.local.LocalDB; import datart.data.provider.script.ReplacementPair; @@ -37,12 +36,9 @@ import datart.data.provider.script.VariablePlaceholder; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; -import org.apache.calcite.config.Lex; import org.apache.calcite.sql.SqlDialect; import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.parser.SqlParseException; -import org.apache.calcite.sql.parser.SqlParser; -import org.apache.calcite.sql.validate.SqlConformanceEnum; import org.apache.commons.lang3.CharUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.util.CollectionUtils; @@ -85,7 +81,7 @@ public String replaceVariables(String selectSql) { Map<String, ScriptVariable> variableMap = queryScript.getVariables() .stream() - .collect(Collectors.toMap(v -> getVariablePattern(v.getName()), variable -> variable)); + .collect(Collectors.toMap(ScriptVariable::getNameWithQuote, variable -> variable)); String srcSql = selectSql; SqlNode sqlNode = null; try { @@ -119,6 +115,7 @@ public String render(boolean withExecuteParam, boolean withPage, boolean onlySel return variable.getValues().iterator().next(); } else return variable.getValues(); })); + String script1 = queryScript.getScript(); script = FreemarkerContext.process(queryScript.getScript(), dataMap); // 替换脚本中的表达式类型变量 @@ -128,7 +125,7 @@ public String render(boolean withExecuteParam, boolean withPage, boolean onlySel if (size != 1) { Exceptions.tr(DataProviderException.class, "message.provider.variable.expression.size", size + ":" + variable.getValues()); } - script = script.replace(getVariablePattern(variable.getName()), Iterables.get(variable.getValues(), 0)); + script = script.replace(variable.getNameWithQuote(), Iterables.get(variable.getValues(), 0)); } } diff --git a/data-providers/src/main/java/datart/data/provider/script/ScriptRender.java b/data-providers/src/main/java/datart/data/provider/script/ScriptRender.java index 52a38590f..dc1b0ff36 100644 --- a/data-providers/src/main/java/datart/data/provider/script/ScriptRender.java +++ b/data-providers/src/main/java/datart/data/provider/script/ScriptRender.java @@ -52,17 +52,4 @@ public ScriptRender(QueryScript queryScript, ExecuteParam executeParam, String v this.variableQuote = variableQuote; } - protected String getVariablePattern(String variableName) { - variableName = StringUtils.prependIfMissing(variableName, variableQuote); - variableName = StringUtils.appendIfMissing(variableName, variableQuote); - return variableName; - } - -// private String variableValueString(ScriptVariable variable) { -// if (variable == null || CollectionUtils.isEmpty(variable.getValues())) { -// return ""; -// } else { -// return String.join(",", variable.getValues()); -// } -// } } \ No newline at end of file diff --git a/data-providers/src/main/java/datart/data/provider/script/VariablePlaceholder.java b/data-providers/src/main/java/datart/data/provider/script/VariablePlaceholder.java index f37cd51b9..c0fe4b7e8 100644 --- a/data-providers/src/main/java/datart/data/provider/script/VariablePlaceholder.java +++ b/data-providers/src/main/java/datart/data/provider/script/VariablePlaceholder.java @@ -144,13 +144,13 @@ protected void replaceVariable(SqlCall sqlCall) { } else if (sqlNode instanceof SqlLiteral) { // pass } else if (sqlNode instanceof SqlIdentifier) { - if (sqlNode.toString().equals(variable.getName())) { + if (sqlNode.toString().equals(variable.getNameWithQuote())) { sqlCall.setOperand(i, SqlNodeUtils.toSingleSqlLiteral(variable, sqlNode.getParserPosition())); } } else if (sqlNode instanceof SqlNodeList) { SqlNodeList nodeList = (SqlNodeList) sqlNode; List<SqlNode> otherNodes = Arrays.stream(nodeList.toArray()) - .filter(node -> !node.toString().equals(variable.getName())) + .filter(node -> !node.toString().equals(variable.getNameWithQuote())) .collect(Collectors.toList()); if (otherNodes.size() == nodeList.size()) { diff --git a/server/src/main/java/datart/server/service/impl/FolderServiceImpl.java b/server/src/main/java/datart/server/service/impl/FolderServiceImpl.java index ae1890550..a5cefa907 100644 --- a/server/src/main/java/datart/server/service/impl/FolderServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/FolderServiceImpl.java @@ -22,7 +22,9 @@ import datart.core.common.UUIDGenerator; import datart.core.entity.*; import datart.core.mappers.ext.*; +import datart.security.base.PermissionInfo; import datart.security.base.ResourceType; +import datart.security.base.SubjectType; import datart.security.exception.PermissionDeniedException; import datart.security.manager.shiro.ShiroSecurityManager; import datart.security.util.PermissionHelper; @@ -37,10 +39,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; @Service @@ -244,6 +243,7 @@ public Folder create(BaseCreateParam createParam) { if (!CollectionUtils.isEmpty(folderCreate.getPermissions())) { roleService.grantPermission(folderCreate.getPermissions()); } + grantDefaultPermission(folder); folderMapper.insert(folder); return folder; } @@ -265,4 +265,20 @@ private boolean hasReadPermission(Folder folder) { } return false; } + + @Override + @Transactional + public void grantDefaultPermission(Folder folder) { + if (securityManager.isOrgOwner(folder.getOrgId())) { + return; + } + PermissionInfo permissionInfo = new PermissionInfo(); + permissionInfo.setOrgId(folder.getOrgId()); + permissionInfo.setSubjectType(SubjectType.USER); + permissionInfo.setSubjectId(getCurrentUser().getId()); + permissionInfo.setResourceType(ResourceType.FOLDER); + permissionInfo.setResourceId(folder.getId()); + permissionInfo.setPermission(Const.CREATE); + roleService.grantPermission(Collections.singletonList(permissionInfo)); + } } 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 8979d2c5b..cb4734472 100644 --- a/server/src/main/java/datart/server/service/impl/SourceServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/SourceServiceImpl.java @@ -159,7 +159,7 @@ public void grantDefaultPermission(Source source) { permissionInfo.setSubjectId(getCurrentUser().getId()); permissionInfo.setResourceType(ResourceType.SOURCE); permissionInfo.setResourceId(source.getId()); - permissionInfo.setPermission(Const.MANAGE); + permissionInfo.setPermission(Const.CREATE); roleService.grantPermission(Collections.singletonList(permissionInfo)); } From 51e4ef2e9a48045993db40c6e2a007c9c3474087 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 24 Dec 2021 12:05:11 +0800 Subject: [PATCH 197/348] refactor(chart): remove logs --- .../FilterControlPanel/CategoryConditionConfiguration.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx index 1cea3bdfc..dd3977641 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionConfiguration.tsx @@ -93,8 +93,6 @@ const CategoryConditionConfiguration: FC< } }); - console.log(`condition ---> `, condition); - const getDataOptionFields = () => { return dataView?.meta || []; }; From 4e18afd07674272f66c4fd8d9b7c602cfe8b6de7 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 24 Dec 2021 12:16:01 +0800 Subject: [PATCH 198/348] refactor(chart): remove no used codes --- .../app/components/FormGenerator/Layout/ItemLayout.tsx | 1 + frontend/src/app/hooks/useMount.ts | 1 + frontend/src/app/hooks/useStateModal.tsx | 10 +--------- .../CategoryConditionEditableTable.tsx | 3 --- .../FilterVisibilityConfiguration.tsx | 5 +---- .../ChartWorkbenchPage/models/ChartEventBroker.ts | 1 + 6 files changed, 5 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx b/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx index 757ebb08a..1518273e2 100644 --- a/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx +++ b/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx @@ -97,6 +97,7 @@ const ItemLayout: FC<FormGeneratorLayoutProps<ChartStyleSectionConfig>> = memo( }); onChange?.(ancestors, newData); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [dependency]); const handleDataChange = ( diff --git a/frontend/src/app/hooks/useMount.ts b/frontend/src/app/hooks/useMount.ts index 12dabc7b7..2e1be0b4d 100644 --- a/frontend/src/app/hooks/useMount.ts +++ b/frontend/src/app/hooks/useMount.ts @@ -24,6 +24,7 @@ const useMount = (fn?: () => void, dispose?: () => void) => { return () => { dispose?.(); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); }; diff --git a/frontend/src/app/hooks/useStateModal.tsx b/frontend/src/app/hooks/useStateModal.tsx index d21d81b49..8b8e293bf 100644 --- a/frontend/src/app/hooks/useStateModal.tsx +++ b/frontend/src/app/hooks/useStateModal.tsx @@ -18,7 +18,6 @@ import { Form, Modal } from 'antd'; import { useRef } from 'react'; -import useI18NPrefix from './useI18NPrefix'; export interface IStateModalContentProps { onChange: (o: any) => void; @@ -38,14 +37,7 @@ const defaultBodyStyle: React.CSSProperties = { overflowX: 'auto', }; -function useStateModal({ - i18nPrefix, - initState, -}: { - i18nPrefix?: string; - initState?: any; -}) { - const t = useI18NPrefix(i18nPrefix); +function useStateModal({ initState }: { initState?: any }) { const [form] = Form.useForm(); const [modal, contextHolder] = Modal.useModal(); const okCallbackRef = useRef<Function>(); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionEditableTable.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionEditableTable.tsx index b78b705f8..ef6a7ba5a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionEditableTable.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/CategoryConditionEditableTable.tsx @@ -45,7 +45,6 @@ const CategoryConditionEditableTable: FC< }) => { const t = useI18NPrefix(i18nPrefix); const [rows, setRows] = useState<RelationFilterValue[]>([]); - const [showPopover, setShowPopover] = useState(false); useEffect(() => { if (Array.isArray(condition?.value)) { @@ -157,7 +156,6 @@ const CategoryConditionEditableTable: FC< }; const handleFetchDataFromField = field => async () => { - setShowPopover(false); if (fetchDataByField) { const dataset = await fetchNewDataset(dataView?.id!, field); const newRows = convertToList(dataset?.rows, []); @@ -216,7 +214,6 @@ const CategoryConditionEditableTable: FC< rowKey={(r: RelationFilterValue) => `${r.key}-${r.label}`} columns={columnsWithCell} pagination={false} - // onMoveRowEnd={onMoveRowEnd} onRow={(_, index) => ({ index, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterVisibilityConfiguration.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterVisibilityConfiguration.tsx index 122a3f80c..adf857386 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterVisibilityConfiguration.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterVisibilityConfiguration.tsx @@ -18,10 +18,7 @@ import { Input, Radio, Row, Select, Space } from 'antd'; import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; -import { - ChartDataSectionField, - FilterVisibility, -} from 'app/types/ChartConfig'; +import { ChartDataSectionField, FilterVisibility } from 'app/types/ChartConfig'; import { ControllerVisibilityTypes } from 'app/types/FilterControlPanel'; import { FilterSqlOperator } from 'globalConstants'; import { FC, memo, useState } from 'react'; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts index 4472df649..fb257cecf 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts @@ -48,6 +48,7 @@ class ChartEventBroker { if (!this._listeners.has(event) || !this._listeners.get(event)) { return; } + this.invokeEvent(event, options, context); } From 4ea1f9d95304bb3e7f37cbf413c48caf94dd1241 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Fri, 24 Dec 2021 12:16:06 +0800 Subject: [PATCH 199/348] fix(Source): create button does not display when have create permission --- frontend/src/app/pages/MainPage/Access.tsx | 8 +- .../SourcePage/SourceDetailPage/index.tsx | 194 +++++++++--------- .../MainPage/pages/SourcePage/slice/thunks.ts | 43 ++-- .../MainPage/pages/VizPage/slice/thunks.ts | 15 +- 4 files changed, 136 insertions(+), 124 deletions(-) diff --git a/frontend/src/app/pages/MainPage/Access.tsx b/frontend/src/app/pages/MainPage/Access.tsx index 260b23f0f..bc4e027c5 100644 --- a/frontend/src/app/pages/MainPage/Access.tsx +++ b/frontend/src/app/pages/MainPage/Access.tsx @@ -31,13 +31,7 @@ export function Access({ return null; } - const isAuthorized = isOwner - ? true - : type === 'module' - ? permissionMap[module]['*'] >= level - : id - ? permissionMap[module][id] >= level - : false; + const isAuthorized = calcAc(isOwner, permissionMap, module, level, id, type); return ( <AuthorizedComponent authority={isAuthorized} denied={denied}> 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 b5af995ea..b2b8a2096 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/index.tsx @@ -1,16 +1,8 @@ import { LoadingOutlined } from '@ant-design/icons'; -import { - Button, - Card, - Form, - Input, - message, - Popconfirm, - Select, - Space, -} from 'antd'; +import { Button, Card, Form, Input, message, Popconfirm, Select } from 'antd'; +import { Authorized, EmptyFiller } from 'app/components'; import { DetailPageHeader } from 'app/components/DetailPageHeader'; -import { Access, useAccess } from 'app/pages/MainPage/Access'; +import { useAccess } from 'app/pages/MainPage/Access'; import debounce from 'debounce-promise'; import { CommonFormTypes, @@ -52,7 +44,7 @@ import { unarchiveSource, } from '../slice/thunks'; import { Source, SourceFormModel } from '../slice/types'; -import { allowManageSource } from '../utils'; +import { allowCreateSource, allowManageSource } from '../utils'; import { ConfigComponent } from './ConfigComponent'; export function SourceDetailPage() { @@ -76,7 +68,10 @@ export function SourceDetailPage() { const { sourceId } = params; const [form] = Form.useForm<SourceFormModel>(); const isArchived = editingSource?.status === 0; - const allowManage = useAccess(allowManageSource(editingSource?.id)); + const allowCreate = + useAccess(allowCreateSource())(true) && sourceId === 'add'; + const allowManage = + useAccess(allowManageSource(sourceId))(true) && sourceId !== 'add'; const config = useMemo( () => dataProviders[providerType]?.config, @@ -290,13 +285,16 @@ export function SourceDetailPage() { ); return ( - <Wrapper> - <DetailPageHeader - title={`${titleLabelPrefix}数据源`} - actions={ - <Access {...allowManageSource(editingSource?.id)}> - {!isArchived ? ( - <Space> + <Authorized + authority={allowCreate || allowManage} + denied={<EmptyFiller title="您没有权限访问该页面" />} + > + <Wrapper> + <DetailPageHeader + title={`${titleLabelPrefix}数据源`} + actions={ + !isArchived ? ( + <> <Button type="primary" loading={saveSourceLoading} @@ -311,9 +309,9 @@ export function SourceDetailPage() { </Button> </Popconfirm> )} - </Space> + </> ) : ( - <Space> + <> <Popconfirm title="确定还原?" onConfirm={unarchive}> <Button loading={unarchiveSourceLoading}>还原</Button> </Popconfirm> @@ -322,85 +320,85 @@ export function SourceDetailPage() { 删除 </Button> </Popconfirm> - </Space> - )} - </Access> - } - /> - <Content> - <Card bordered={false}> - <Form - name="source_form_" - className="detailForm" - form={form} - labelAlign="left" - labelCol={{ offset: 1, span: 5 }} - wrapperCol={{ span: 8 }} - onFinish={formSubmit} - > - <Form.Item - name="name" - label="名称" - validateFirst - rules={[ - { required: true, message: '名称不能为空' }, - { - validator: debounce((_, value) => { - if (value === editingSource?.name) { - return Promise.resolve(); - } - return request({ - url: `/sources/check/name`, - method: 'POST', - params: { name: value, orgId }, - }).then( - () => Promise.resolve(), - () => Promise.reject(new Error('名称重复')), - ); - }, DEFAULT_DEBOUNCE_WAIT), - }, - ]} - > - <Input disabled={isArchived} /> - </Form.Item> - <Form.Item - name="type" - label="类型" - rules={[{ required: true, message: '类型为必选项' }]} + </> + ) + } + /> + <Content> + <Card bordered={false}> + <Form + name="source_form_" + className="detailForm" + form={form} + labelAlign="left" + labelCol={{ offset: 1, span: 5 }} + wrapperCol={{ span: 8 }} + onFinish={formSubmit} > - <Select - loading={dataProviderListLoading} - disabled={isArchived} - onChange={dataProviderChange} + <Form.Item + name="name" + label="名称" + validateFirst + rules={[ + { required: true, message: '名称不能为空' }, + { + validator: debounce((_, value) => { + if (value === editingSource?.name) { + return Promise.resolve(); + } + return request({ + url: `/sources/check/name`, + method: 'POST', + params: { name: value, orgId }, + }).then( + () => Promise.resolve(), + () => Promise.reject(new Error('名称重复')), + ); + }, DEFAULT_DEBOUNCE_WAIT), + }, + ]} > - {Object.keys(dataProviders).map(key => ( - <Select.Option key={key} value={key}> - {key} - </Select.Option> - ))} - </Select> - </Form.Item> - {dataProviderConfigTemplateLoading && <LoadingOutlined />} - - {(providerType !== 'FILE' || formType === CommonFormTypes.Edit) && - config?.attributes.map(attr => ( - <ConfigComponent - key={`${providerType}_${attr.name}`} - attr={attr} - form={form} - sourceId={editingSource?.id} - testLoading={testLoading} + <Input disabled={isArchived} /> + </Form.Item> + <Form.Item + name="type" + label="类型" + rules={[{ required: true, message: '类型为必选项' }]} + > + <Select + loading={dataProviderListLoading} disabled={isArchived} - allowManage={allowManage(true)} - onTest={test} - onSubFormTest={subFormTest} - onDbTypeChange={dbTypeChange} - /> - ))} - </Form> - </Card> - </Content> - </Wrapper> + onChange={dataProviderChange} + > + {Object.keys(dataProviders).map(key => ( + <Select.Option key={key} value={key}> + {key} + </Select.Option> + ))} + </Select> + </Form.Item> + {dataProviderConfigTemplateLoading && <LoadingOutlined />} + + {(providerType !== 'FILE' || formType === CommonFormTypes.Edit) && + config?.attributes.map(attr => ( + <ConfigComponent + key={`${providerType}_${attr.name}`} + attr={attr} + form={form} + sourceId={editingSource?.id} + testLoading={testLoading} + disabled={isArchived} + allowManage={allowManage} + onTest={test} + onSubFormTest={subFormTest} + onDbTypeChange={dbTypeChange} + /> + ))} + </Form> + </Card> + </Content> + </Wrapper> + </Authorized> ); } 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 f58c83693..77d7fce3b 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/slice/thunks.ts +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/slice/thunks.ts @@ -1,4 +1,7 @@ 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 { request } from 'utils/request'; import { errorHandle } from 'utils/utils'; import { @@ -56,23 +59,29 @@ export const getSource = createAsyncThunk<Source, string>( }, ); -export const addSource = createAsyncThunk<Source, AddSourceParams>( - 'source/addSource', - async ({ source, resolve }) => { - try { - const { data } = await request<Source>({ - url: '/sources', - method: 'POST', - data: source, - }); - resolve(data.id); - return data; - } catch (error) { - errorHandle(error); - throw error; - } - }, -); +export const addSource = createAsyncThunk< + Source, + AddSourceParams, + { state: RootState } +>('source/addSource', async ({ source, resolve }, { getState, dispatch }) => { + try { + const { data } = await request<Source>({ + url: '/sources', + method: 'POST', + data: source, + }); + + // FIXME 拥有Read权限等级的扁平结构资源新增后需要更新权限字典;后续如改造为目录结构则删除该逻辑 + const orgId = selectOrgId(getState()); + await dispatch(getLoggedInUserPermissions(orgId)); + + resolve(data.id); + return data; + } catch (error) { + errorHandle(error); + throw error; + } +}); export const editSource = createAsyncThunk<Source, EditSourceParams>( 'source/editSource', diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/slice/thunks.ts b/frontend/src/app/pages/MainPage/pages/VizPage/slice/thunks.ts index f046a10d7..5a429f8b9 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/slice/thunks.ts +++ b/frontend/src/app/pages/MainPage/pages/VizPage/slice/thunks.ts @@ -5,6 +5,8 @@ import { Dashboard, DataChart, } from 'app/pages/DashBoardPage/pages/Board/slice/types'; +import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; +import { getLoggedInUserPermissions } from 'app/pages/MainPage/slice/thunks'; import { StoryBoard } from 'app/pages/StoryBoardPage/slice/types'; import { RootState } from 'types'; import { request } from 'utils/request'; @@ -102,15 +104,24 @@ export const getArchivedStoryboards = createAsyncThunk<StoryBoard[], string>( }, ); -export const addStoryboard = createAsyncThunk<Storyboard, AddStoryboardParams>( +export const addStoryboard = createAsyncThunk< + Storyboard, + AddStoryboardParams, + { state: RootState } +>( 'viz/addStoryboard', - async ({ storyboard, resolve }) => { + async ({ storyboard, resolve }, { getState, dispatch }) => { try { const { data } = await request<Storyboard>({ url: `/viz/storyboards`, method: 'POST', data: storyboard, }); + + // FIXME 拥有Read权限等级的扁平结构资源新增后需要更新权限字典;后续如改造为目录结构则删除该逻辑 + const orgId = selectOrgId(getState()); + await dispatch(getLoggedInUserPermissions(orgId)); + resolve(); return data; } catch (error) { From 1370bb89e2f678e3990964a69eed9d0af3f283bd Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Fri, 24 Dec 2021 11:40:34 +0800 Subject: [PATCH 200/348] fix:(Chart) fix map tooltip --- frontend/src/app/utils/chartHelper.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/utils/chartHelper.ts b/frontend/src/app/utils/chartHelper.ts index 2c1943270..2f96cadd6 100644 --- a/frontend/src/app/utils/chartHelper.ts +++ b/frontend/src/app/utils/chartHelper.ts @@ -688,7 +688,13 @@ export function getSeriesTooltips4Polar2( .concat(aggConfigs || []) .concat(sizeConfigs || []) .concat(infoConfigs || []) - .map(config => valueFormatter(config, row?.[getValueByColumnKey(config)])); + .map(config => { + const value = + row?.[getValueByColumnKey(config)] !== void 0 + ? row?.[getValueByColumnKey(config)] + : '-'; + return valueFormatter(config, value); + }); return tooltips.join('<br />'); } From 16e05b0522a044be7e780589438a52a3145e7dcf Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Fri, 24 Dec 2021 12:15:58 +0800 Subject: [PATCH 201/348] fix:(Schedules) fix schedules webHookUrl --- frontend/src/app/pages/MainPage/pages/SchedulePage/utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/app/pages/MainPage/pages/SchedulePage/utils.ts b/frontend/src/app/pages/MainPage/pages/SchedulePage/utils.ts index 0e9183e23..46b6db614 100644 --- a/frontend/src/app/pages/MainPage/pages/SchedulePage/utils.ts +++ b/frontend/src/app/pages/MainPage/pages/SchedulePage/utils.ts @@ -143,6 +143,7 @@ export const toEchoFormValues = ({ cc: configObj?.cc || '', bcc: configObj?.bcc || '', type: configObj?.attachments || [], + webHookUrl: configObj?.webHookUrl || '', demoContent, folderContent, setCronExpressionManually, From 727376f1fa0feff06245944cb4cd2cade821c832 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Fri, 24 Dec 2021 12:43:45 +0800 Subject: [PATCH 202/348] fix: lock ant-design/pro-table version with antd --- frontend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/package.json b/frontend/package.json index 41a671ab4..3b32bf6a3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -83,7 +83,7 @@ }, "dependencies": { "@ant-design/icons": "^4.5.0", - "@ant-design/pro-table": "^2.54.4", + "@ant-design/pro-table": "2.60.1", "@antv/s2": "^1.3.0", "@antv/s2-react": "^1.3.0", "@dinero.js/currencies": "^2.0.0-alpha.8", From 4dd6ce86eac47d0b7f9d2bc03ddd82069276f9e9 Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Fri, 24 Dec 2021 12:46:35 +0800 Subject: [PATCH 203/348] style:(Chart) style toFormattedValue --- frontend/src/app/utils/chartHelper.ts | 8 +------- frontend/src/app/utils/number.ts | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/frontend/src/app/utils/chartHelper.ts b/frontend/src/app/utils/chartHelper.ts index 2f96cadd6..2c1943270 100644 --- a/frontend/src/app/utils/chartHelper.ts +++ b/frontend/src/app/utils/chartHelper.ts @@ -688,13 +688,7 @@ export function getSeriesTooltips4Polar2( .concat(aggConfigs || []) .concat(sizeConfigs || []) .concat(infoConfigs || []) - .map(config => { - const value = - row?.[getValueByColumnKey(config)] !== void 0 - ? row?.[getValueByColumnKey(config)] - : '-'; - return valueFormatter(config, value); - }); + .map(config => valueFormatter(config, row?.[getValueByColumnKey(config)])); return tooltips.join('<br />'); } diff --git a/frontend/src/app/utils/number.ts b/frontend/src/app/utils/number.ts index e3134e37f..e7f544c34 100644 --- a/frontend/src/app/utils/number.ts +++ b/frontend/src/app/utils/number.ts @@ -74,7 +74,7 @@ export function toFormattedValue( format?: IFieldFormatConfig, ) { if (value === null || value === undefined) { - return value; + return '-'; } if (!format || format.type === FieldFormatType.DEFAULT) { From 3a3b7638ff0ec81ec3f0664adc4fed6acf77a635 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 24 Dec 2021 13:58:02 +0800 Subject: [PATCH 204/348] perf(tool): add debugger tool --- .../models/ChartEventBroker.ts | 5 ++- frontend/src/index.tsx | 2 + frontend/src/utils/debugger.ts | 44 +++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 frontend/src/utils/debugger.ts diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts index fb257cecf..9b6623eeb 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts @@ -17,6 +17,7 @@ */ import { ChartLifecycle } from 'app/types/ChartLifecycle'; +import { Debugger } from 'utils/debugger'; import Chart from './Chart'; type BrokerContext = { @@ -85,7 +86,9 @@ class ChartEventBroker { private safeInvoke(event: HooksEvent, options: any, context?: BrokerContext) { try { - this._listeners.get(event)?.call?.(this._chart, options, context); + Debugger.instance.measure(`ChartEventBroker | ${event} `, () => { + this._listeners.get(event)?.call?.(this._chart, options, context); + }); } catch (e) { console.error(`ChartEventBroker | ${event} exception ----> `, e); } finally { diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 8ea201464..a41dfe3be 100755 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -14,8 +14,10 @@ import { HelmetProvider } from 'react-helmet-async'; import { Provider } from 'react-redux'; import { configureAppStore } from 'redux/configureStore'; import { ThemeProvider } from 'styles/theme/ThemeProvider'; +import { Debugger } from 'utils/debugger'; import './locales/i18n'; +Debugger.instance.setEnable(true); export const store = configureAppStore(); const MOUNT_NODE = document.getElementById('root') as HTMLElement; /** diff --git a/frontend/src/utils/debugger.ts b/frontend/src/utils/debugger.ts new file mode 100644 index 000000000..c43942b99 --- /dev/null +++ b/frontend/src/utils/debugger.ts @@ -0,0 +1,44 @@ +/** + * 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. + */ + +export class Debugger { + private static _instance: Debugger; + private _enableDebug = false; + + public static get instance() { + if (!Debugger._instance) { + Debugger._instance = new Debugger(); + } + return Debugger._instance; + } + + public setEnable(enable?: boolean) { + this._enableDebug = !!enable; + } + + public measure(info: string, fn) { + if (!this._enableDebug) { + return fn(); + } + + const start = performance.now(); + fn(); + const end = performance.now(); + console.info(`Performance - ${info} - `, `${end - start} ms`); + } +} From 87224565224fe82004d37fc5380c66e0721fe4ef Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 24 Dec 2021 14:05:32 +0800 Subject: [PATCH 205/348] perf(tool): only enable performance log in development mode --- frontend/src/index.tsx | 73 +++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index a41dfe3be..a5f90987c 100755 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -17,46 +17,47 @@ import { ThemeProvider } from 'styles/theme/ThemeProvider'; import { Debugger } from 'utils/debugger'; import './locales/i18n'; -Debugger.instance.setEnable(true); -export const store = configureAppStore(); const MOUNT_NODE = document.getElementById('root') as HTMLElement; -/** - * hot-key [control,shift,command,c] - */ +const IS_DEVELOPMENT = process.env.NODE_ENV === 'development'; +const InspectorWrapper = IS_DEVELOPMENT ? Inspector : React.Fragment; +Debugger.instance.setEnable(IS_DEVELOPMENT); +export const store = configureAppStore(); const MainApp = <App />; -const InspectorWrapper = - process.env.NODE_ENV === 'development' ? Inspector : React.Fragment; -ChartManager.instance() - .load() - .catch(err => console.error('Fail to load customize charts with ', err)) - .finally(() => { - ReactDOM.render( - <InspectorWrapper> - <Provider store={store}> - <ThemeProvider> - <ConfigProvider locale={zh_CN}> - <HelmetProvider> - <React.StrictMode>{MainApp}</React.StrictMode> - </HelmetProvider> - </ConfigProvider> - </ThemeProvider> - </Provider> - </InspectorWrapper>, - MOUNT_NODE, - ); +Debugger.instance.measure('Main App', () => { + ChartManager.instance() + .load() + .catch(err => console.error('Fail to load customize charts with ', err)) + .finally(() => { + ReactDOM.render( + <InspectorWrapper> + <Provider store={store}> + <ThemeProvider> + <ConfigProvider locale={zh_CN}> + <HelmetProvider> + <React.StrictMode>{MainApp}</React.StrictMode> + </HelmetProvider> + </ConfigProvider> + </ThemeProvider> + </Provider> + </InspectorWrapper>, + MOUNT_NODE, + ); - // Hot reloadable translation json files - if (module.hot) { - module.hot.accept(['./locales/i18n'], () => { - // No need to render the App again because i18next works with the hooks - }); - } + // Hot reloadable translation json files + if (module.hot) { + module.hot.accept(['./locales/i18n'], () => { + // No need to render the App again because i18next works with the hooks + }); + } - if (process.env.NODE_ENV === 'production') { - if (typeof (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__ === 'object') { - (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = () => void 0; + if (!IS_DEVELOPMENT) { + if ( + typeof (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__ === 'object' + ) { + (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = () => void 0; + } } - } - }); + }); +}); From d3427ca0d7891615af42a59545a86b6ae0a01080 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 24 Dec 2021 15:06:32 +0800 Subject: [PATCH 206/348] fix(chart): fix mixed group section sql params issue --- .../BasicTableChart/BasicTableChart.tsx | 3 ++- .../models/ChartHttpRequest.ts | 19 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx index e7ebb248f..6cb74cfcc 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx @@ -305,7 +305,8 @@ class BasicTableChart extends ReactChart { } getTableComponents(styleConfigs, widgetSpecialConfig) { - const { linkFields, jumpField } = widgetSpecialConfig; + const linkFields = widgetSpecialConfig?.linkFields; + const jumpField = widgetSpecialConfig?.jumpField; const tableHeaders = this.getStyleValue(styleConfigs, [ 'header', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts index 12a117f0b..d00f8c169 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts @@ -35,9 +35,7 @@ import { RelationFilterValue, SortActionType, } from '../../../types/ChartConfig'; -import ChartDataView, { - ChartDataViewFieldType, -} from '../../../types/ChartDataView'; +import ChartDataView from '../../../types/ChartDataView'; export type ChartRequest = { viewId: string; @@ -362,13 +360,14 @@ export class ChartDataRequestBuilder { ) { return acc.concat(cur.rows); } - if (cur.type === ChartDataSectionType.MIXED) { - return acc.concat( - cur.rows.filter( - ({ type }) => type === ChartDataViewFieldType.STRING, - ), - ); - } + // TODO(TMGigGoup): Mixed Section类型为什么需要加入到sql请求的group中? + // if (cur.type === ChartDataSectionType.MIXED) { + // return acc.concat( + // cur.rows.filter( + // ({ type }) => type === ChartDataViewFieldType.STRING, + // ), + // ); + // } return acc; }, [], From ef0e10c969eb53c32b90a9e34d9613283ec6c1e7 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 24 Dec 2021 15:09:20 +0800 Subject: [PATCH 207/348] perf(app): remove app performance logs --- frontend/src/index.tsx | 62 ++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index a5f90987c..992ca14cd 100755 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -25,39 +25,35 @@ Debugger.instance.setEnable(IS_DEVELOPMENT); export const store = configureAppStore(); const MainApp = <App />; -Debugger.instance.measure('Main App', () => { - ChartManager.instance() - .load() - .catch(err => console.error('Fail to load customize charts with ', err)) - .finally(() => { - ReactDOM.render( - <InspectorWrapper> - <Provider store={store}> - <ThemeProvider> - <ConfigProvider locale={zh_CN}> - <HelmetProvider> - <React.StrictMode>{MainApp}</React.StrictMode> - </HelmetProvider> - </ConfigProvider> - </ThemeProvider> - </Provider> - </InspectorWrapper>, - MOUNT_NODE, - ); +ChartManager.instance() + .load() + .catch(err => console.error('Fail to load customize charts with ', err)) + .finally(() => { + ReactDOM.render( + <InspectorWrapper> + <Provider store={store}> + <ThemeProvider> + <ConfigProvider locale={zh_CN}> + <HelmetProvider> + <React.StrictMode>{MainApp}</React.StrictMode> + </HelmetProvider> + </ConfigProvider> + </ThemeProvider> + </Provider> + </InspectorWrapper>, + MOUNT_NODE, + ); - // Hot reloadable translation json files - if (module.hot) { - module.hot.accept(['./locales/i18n'], () => { - // No need to render the App again because i18next works with the hooks - }); - } + // Hot reloadable translation json files + if (module.hot) { + module.hot.accept(['./locales/i18n'], () => { + // No need to render the App again because i18next works with the hooks + }); + } - if (!IS_DEVELOPMENT) { - if ( - typeof (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__ === 'object' - ) { - (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = () => void 0; - } + if (!IS_DEVELOPMENT) { + if (typeof (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__ === 'object') { + (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = () => void 0; } - }); -}); + } + }); From 14f40bcde482c5a8b4b9bee24e41f049a62ec56d Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 24 Dec 2021 15:13:13 +0800 Subject: [PATCH 208/348] refactor(chart): fix typo --- .../src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts index d00f8c169..2e9b88277 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts @@ -360,7 +360,7 @@ export class ChartDataRequestBuilder { ) { return acc.concat(cur.rows); } - // TODO(TMGigGoup): Mixed Section类型为什么需要加入到sql请求的group中? + // TODO(TMBigGroup): Mixed Section类型为什么需要加入到sql请求的group中? // if (cur.type === ChartDataSectionType.MIXED) { // return acc.concat( // cur.rows.filter( From d998fcccfeadc5619af657f223fddb28415439b2 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 24 Dec 2021 15:37:58 +0800 Subject: [PATCH 209/348] perf(tool): support async type of function for performance log --- .../src/app/pages/ChartWorkbenchPage/models/ChartManager.ts | 5 ++++- frontend/src/utils/debugger.ts | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartManager.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartManager.ts index 20592472a..861a13bbc 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartManager.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartManager.ts @@ -19,6 +19,7 @@ import WidgetPlugins from 'app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph'; import ChartTools from 'app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools'; import { getChartPluginPaths } from 'app/utils/fetch'; +import { Debugger } from 'utils/debugger'; import { CloneValueDeep } from 'utils/object'; import Chart from './Chart'; @@ -68,7 +69,9 @@ class ChartManager { return; } const pluginsPaths = await getChartPluginPaths(); - return await this._loadCustomizeCharts(pluginsPaths); + await Debugger.instance.measure('Plugin Charts | ', async () => { + await this._loadCustomizeCharts(pluginsPaths); + }); } public getAllCharts(): Chart[] { diff --git a/frontend/src/utils/debugger.ts b/frontend/src/utils/debugger.ts index c43942b99..3727e32e1 100644 --- a/frontend/src/utils/debugger.ts +++ b/frontend/src/utils/debugger.ts @@ -31,13 +31,13 @@ export class Debugger { this._enableDebug = !!enable; } - public measure(info: string, fn) { + public async measure(info: string, fn: VoidFunction) { if (!this._enableDebug) { - return fn(); + return await fn(); } const start = performance.now(); - fn(); + await fn(); const end = performance.now(); console.info(`Performance - ${info} - `, `${end - start} ms`); } From 1891e02a3846c058a98d492e372d7fd7afbb19a4 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Fri, 24 Dec 2021 15:48:32 +0800 Subject: [PATCH 210/348] chore: del useless props --- .../components/SlideSetting/SettingItem/NameSet.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/NameSet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/NameSet.tsx index 5a0e26622..e6aa57649 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/NameSet.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/NameSet.tsx @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Checkbox, Form, FormInstance, Input } from 'antd'; +import { Checkbox, Form, Input } from 'antd'; import BasicFont from 'app/components/FormGenerator/Basic/BasicFont'; import { WIDGET_TITLE_ALIGN_OPTIONS } from 'app/pages/DashBoardPage/constants'; import { WidgetNameConfig } from 'app/pages/DashBoardPage/pages/Board/slice/types'; @@ -33,9 +33,7 @@ const FONT_DATA = { export const NameSet: FC<{ config: WidgetNameConfig; - form: FormInstance; - onForceUpdate: () => void; -}> = memo(({ config, onForceUpdate, form }) => { +}> = memo(({ config }) => { const fontData = useMemo(() => { const data = { ...FONT_DATA, From 13b63d9a403f68b02f7a835aa4417885e6e0998f Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Fri, 24 Dec 2021 16:02:25 +0800 Subject: [PATCH 211/348] refactor: board and widget image setter --- .../components/SlideSetting/BoardSetting.tsx | 20 ++-- .../SettingItem/BackgroundSet.tsx | 12 +- .../SettingItem/BasicSet/ImageUpload.tsx | 113 +++++++----------- .../components/SlideSetting/WidgetSetting.tsx | 20 +--- 4 files changed, 58 insertions(+), 107 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/BoardSetting.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/BoardSetting.tsx index b46022ca6..9a9cac0ea 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/BoardSetting.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/BoardSetting.tsx @@ -48,7 +48,7 @@ export const BoardSetting: FC = memo(() => { useEffect(() => { cacheValue.current = { backgroundColor: config.background.color, - backgroundImage: [config.background.image], + backgroundImage: config.background.image, scaleMode: config.scaleMode, boardWidth: config.width, boardHeight: config.height, @@ -57,7 +57,7 @@ export const BoardSetting: FC = memo(() => { paddingW: config.containerPadding[0], paddingH: config.containerPadding[1], rowHeight: config.rowHeight, - initialQuery: config.initialQuery=== false ? false : true, // TODO migration 如果initialQuery的值为undefined默认为true 兼容旧的仪表盘没有initialQuery参数的问题 + initialQuery: config.initialQuery === false ? false : true, // TODO migration 如果initialQuery的值为undefined默认为true 兼容旧的仪表盘没有initialQuery参数的问题 }; form.setFieldsValue({ ...cacheValue.current }); }, [config, form]); @@ -65,9 +65,10 @@ export const BoardSetting: FC = memo(() => { const onUpdate = useCallback( (newValues, config: DashboardConfig) => { const value = { ...cacheValue.current, ...newValues }; + const nextConf = produce(config, draft => { draft.background.color = getRGBAColor(value.backgroundColor); - draft.background.image = value.backgroundImage[0]; + draft.background.image = value.backgroundImage; draft.scaleMode = value.scaleMode; draft.width = value.boardWidth; draft.height = value.boardHeight; @@ -76,16 +77,13 @@ export const BoardSetting: FC = memo(() => { draft.containerPadding[0] = value.paddingW; draft.containerPadding[1] = value.paddingH; draft.rowHeight = value.rowHeight; - draft.initialQuery= value.initialQuery; + draft.initialQuery = value.initialQuery; }); dispatch(editBoardStackActions.updateBoardConfig(nextConf)); }, [dispatch], ); - const onForceUpdate = useCallback(() => { - const values = form.getFieldsValue(); - onUpdate(values, config); - }, [config, form, onUpdate]); + const throttledUpdate = useRef( throttle((allValue, config) => onUpdate(allValue, config), 1000), ); @@ -140,11 +138,7 @@ export const BoardSetting: FC = memo(() => { )} <Panel header="背景设计" key="background" forceRender> <Group> - <BackgroundSet - onForceUpdate={onForceUpdate} - background={config.background} - form={form} - /> + <BackgroundSet background={config.background} /> </Group> </Panel> <Panel header="查询配置" key="initialQuery" forceRender> diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BackgroundSet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BackgroundSet.tsx index 274d22757..cb11bc8d3 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BackgroundSet.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BackgroundSet.tsx @@ -15,26 +15,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Form, FormInstance } from 'antd'; +import { Form } from 'antd'; import { BackgroundConfig } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import React, { FC, memo } from 'react'; import ColorSet from './BasicSet/ColorSet'; -import ImageUpload from './BasicSet/ImageUpload'; +import { ImageUpload } from './BasicSet/ImageUpload'; export const BackgroundSet: FC<{ - form: FormInstance; - onForceUpdate: () => void; background: BackgroundConfig; -}> = memo(({ form, background, onForceUpdate }) => { +}> = memo(({ background }) => { return ( <> <Form.Item label="背景颜色"> <ColorSet filedName={'backgroundColor'} filedValue={background.color} /> </Form.Item> <ImageUpload - form={form} - onForceUpdate={onForceUpdate} filedName={'backgroundImage'} - filedValue={background.image as string} + value={background.image as string} /> </> ); diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ImageUpload.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ImageUpload.tsx index a5cd0dfac..c0796be63 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ImageUpload.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ImageUpload.tsx @@ -16,7 +16,7 @@ * limitations under the License. */ import { DeleteOutlined } from '@ant-design/icons'; -import { Form, FormInstance, Upload } from 'antd'; +import { Form, Upload } from 'antd'; import { BoardContext } from 'app/pages/DashBoardPage/contexts/BoardContext'; import { convertImageUrl } from 'app/pages/DashBoardPage/utils'; import React, { useCallback, useContext } from 'react'; @@ -25,49 +25,43 @@ import styled from 'styled-components/macro'; import { uploadBoardImage } from '../../../../slice/thunk'; export interface ImageUploadProps { - form: FormInstance; filedName: string; - onForceUpdate: () => void; - filedValue: string; + + value: string; } -const ImageUpload: React.FC<ImageUploadProps> = ({ - form, +export const ImageUpload: React.FC<ImageUploadProps> = ({ filedName, - filedValue, - onForceUpdate, + value, }) => { + return ( + <Wrapper> + <Form.Item name={filedName} label="背景图片" preserve> + <UploadDragger value={value} /> + </Form.Item> + </Wrapper> + ); +}; +export const UploadDragger: React.FC<{ + value: string; + onChange?: any; +}> = ({ value, onChange }) => { const dispatch = useDispatch(); const { boardId } = useContext(BoardContext); - const onChange = useCallback( - value => { - form.setFieldsValue({ - [filedName]: [value], - }); - onForceUpdate(); - }, - [filedName, form, onForceUpdate], - ); const beforeUpload = useCallback( async info => { - // const reader = new FileReader(); - // reader.readAsDataURL(info); - // reader.onload = () => { - // const urlIndex = `${STORAGE_IMAGE_KEY_PREFIX}${info.name || info.uid}`; - // if (reader.result) { - // localStorage.setItem(urlIndex, reader.result as string); - // onChange(urlIndex); - // } - // }; const formData = new FormData(); formData.append('file', info); - dispatch( + await dispatch( uploadBoardImage({ boardId, formData: formData, resolve: onChange }), ); return false; }, [boardId, dispatch, onChange], ); + const getImageError = useCallback(() => { + onChange(''); + }, [onChange]); const delImageUrl = useCallback( e => { e.stopPropagation(); @@ -75,52 +69,30 @@ const ImageUpload: React.FC<ImageUploadProps> = ({ }, [onChange], ); - const normFile = (e: any) => { - if (Array.isArray(e)) { - return e; - } - return e && e.fileList; - }; - const getImageError = useCallback(() => { - onChange(''); - }, [onChange]); return ( - <Wrapper> - <Form.Item - name={filedName} - label="背景图片" - valuePropName="fileList" - getValueFromEvent={normFile} - preserve - > - <Upload.Dragger - name={'upload-image'} - className="imageUpload" - beforeUpload={beforeUpload} - multiple={false} - > - {filedValue ? ( - <div className="image-box"> - <img - className="image" - src={convertImageUrl(filedValue)} - alt="" - onError={getImageError} - /> - <DeleteOutlined className="del-button" onClick={delImageUrl} /> - </div> - ) : ( - <Placeholder>点击上传</Placeholder> - )} - </Upload.Dragger> - </Form.Item> - </Wrapper> + <StyleUpload + name={'upload-image'} + className="imageUpload" + beforeUpload={beforeUpload} + multiple={false} + > + {value ? ( + <div className="image-box"> + <img + className="image" + src={convertImageUrl(value)} + alt="" + onError={getImageError} + /> + <DeleteOutlined className="del-button" onClick={delImageUrl} /> + </div> + ) : ( + <Placeholder>点击上传</Placeholder> + )} + </StyleUpload> ); }; - -export default ImageUpload; - -const Wrapper = styled.div` +const StyleUpload = styled(Upload.Dragger)` .ant-upload-list { display: none; } @@ -155,6 +127,7 @@ const Wrapper = styled.div` height: auto; } `; +const Wrapper = styled.div``; const Placeholder = styled.p` color: ${p => p.theme.textColorLight}; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/WidgetSetting.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/WidgetSetting.tsx index b7a4f0da7..84c4073be 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/WidgetSetting.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/WidgetSetting.tsx @@ -54,7 +54,7 @@ export const WidgetSetting: FC = memo(() => { name: config.name, nameConfig: config.nameConfig, backgroundColor: config.background.color, - backgroundImage: [config.background.image], + backgroundImage: config.background.image, border: config.border, rect: config.rect, autoUpdate: config.autoUpdate || false, @@ -79,7 +79,7 @@ export const WidgetSetting: FC = memo(() => { draft.name = value.name; draft.nameConfig = value.nameConfig; draft.background.color = getRGBAColor(value.backgroundColor); - draft.background.image = value.backgroundImage[0]; + draft.background.image = value.backgroundImage; draft.border = value.border; draft.rect = value.rect; draft.padding = value.padding; @@ -105,10 +105,6 @@ export const WidgetSetting: FC = memo(() => { }, [throttledUpdate, widget], ); - const onForceUpdate = useCallback(() => { - const values = form.getFieldsValue(); - onUpdate(values, widget); - }, [form, onUpdate, widget]); return ( <SettingPanel title="组件设计"> @@ -125,11 +121,7 @@ export const WidgetSetting: FC = memo(() => { > <Panel header="组件标题" key="name" forceRender> <Group> - <NameSet - form={form} - onForceUpdate={onForceUpdate} - config={config.nameConfig} - /> + <NameSet config={config.nameConfig} /> </Group> </Panel> {boardType === 'free' && ( @@ -150,11 +142,7 @@ export const WidgetSetting: FC = memo(() => { )} <Panel header="背景" key="background" forceRender> <Group> - <BackgroundSet - onForceUpdate={onForceUpdate} - background={config.background} - form={form} - /> + <BackgroundSet background={config.background} /> </Group> </Panel> <Panel header="内边距" key="padding" forceRender> From 0306d7d5a55522b941e4f55a104bfa785ccd86ee Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Fri, 24 Dec 2021 16:43:13 +0800 Subject: [PATCH 212/348] refactor: edit imageWdget #190 --- .../MediaWidget/ImageWidget/index.tsx | 60 ++++++++++++------- .../WidgetCore/MediaWidget/index.tsx | 2 +- .../SettingItem/BasicSet/ImageUpload.tsx | 10 ++-- 3 files changed, 44 insertions(+), 28 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/MediaWidget/ImageWidget/index.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/MediaWidget/ImageWidget/index.tsx index 6b459466b..b6c2c89bf 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/MediaWidget/ImageWidget/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/MediaWidget/ImageWidget/index.tsx @@ -15,27 +15,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { Empty } from 'antd'; +import { BoardActionContext } from 'app/pages/DashBoardPage/contexts/BoardActionContext'; +import { WidgetContext } from 'app/pages/DashBoardPage/contexts/WidgetContext'; +import { WidgetInfoContext } from 'app/pages/DashBoardPage/contexts/WidgetInfoContext'; import useClientRect from 'app/pages/DashBoardPage/hooks/useClientRect'; -import { - MediaWidgetContent, - Widget, - WidgetInfo, -} from 'app/pages/DashBoardPage/pages/Board/slice/types'; -import { convertImageUrl } from 'app/pages/DashBoardPage/utils'; -import React, { useMemo } from 'react'; +import { MediaWidgetContent } from 'app/pages/DashBoardPage/pages/Board/slice/types'; +import { UploadDragger } from 'app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ImageUpload'; +import produce from 'immer'; +import React, { useCallback, useContext, useMemo } from 'react'; import styled from 'styled-components/macro'; -export interface ImageWidgetProps { - widgetConfig: Widget; - widgetInfo: WidgetInfo; -} const widgetSize: React.CSSProperties = { width: '100%', height: '100%', }; -const ImageWidget: React.FC<ImageWidgetProps> = ({ widgetConfig }) => { - const { imageConfig } = widgetConfig.config.content as MediaWidgetContent; - +const ImageWidget: React.FC<{}> = () => { + const widget = useContext(WidgetContext); + const { editing } = useContext(WidgetInfoContext); + const { widgetUpdate } = useContext(BoardActionContext); + const { imageConfig } = widget.config.content as MediaWidgetContent; + const widgetBgImage = widget.config.background.image; const [rect, refDom] = useClientRect<HTMLDivElement>(32); const widthBigger = useMemo(() => { @@ -53,21 +53,37 @@ const ImageWidget: React.FC<ImageWidgetProps> = ({ widgetConfig }) => { height: 'auto', }; }, [widthBigger]); + const onChange = useCallback( + value => { + const nextWidget = produce(widget, draft => { + draft.config.background.image = value; + }); + widgetUpdate(nextWidget); + }, + [widget, widgetUpdate], + ); const imageSize = useMemo(() => { return imageConfig?.type === 'IMAGE_RATIO' ? imageRatioCss : widgetSize; }, [imageRatioCss, imageConfig?.type]); - - return ( - <Wrap ref={refDom}> - {imageConfig?.src && ( - <img style={imageSize} src={convertImageUrl(imageConfig?.src)} alt="" /> - )} - </Wrap> - ); + const renderImage = useMemo(() => { + return editing ? ( + <UploadDragger value={widgetBgImage} onChange={onChange} /> + ) : widgetBgImage ? null : ( + <Empty description="" /> + ); + }, [editing, onChange, widgetBgImage]); + return <Wrap ref={refDom}>{renderImage}</Wrap>; }; export default ImageWidget; const Wrap = styled.div` + display: flex; + align-items: center; + justify-content: center; width: 100%; height: 100%; + + .ant-upload-list { + display: none; + } `; diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/MediaWidget/index.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/MediaWidget/index.tsx index 41a0b92ed..76671c8da 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/MediaWidget/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/MediaWidget/index.tsx @@ -33,7 +33,7 @@ export const MediaWidget: React.FC<{}> = memo(() => { case 'richText': return <RichTextWidget widgetConfig={widget} widgetInfo={widgetInfo} />; case 'image': - return <ImageWidget widgetConfig={widget} widgetInfo={widgetInfo} />; + return <ImageWidget />; case 'video': return <VideoWidget />; case 'iframe': diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ImageUpload.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ImageUpload.tsx index c0796be63..f2a19a9b2 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ImageUpload.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ImageUpload.tsx @@ -93,10 +93,6 @@ export const UploadDragger: React.FC<{ ); }; const StyleUpload = styled(Upload.Dragger)` - .ant-upload-list { - display: none; - } - .imageUpload { display: block; } @@ -127,7 +123,11 @@ const StyleUpload = styled(Upload.Dragger)` height: auto; } `; -const Wrapper = styled.div``; +const Wrapper = styled.div` + .ant-upload-list { + display: none; + } +`; const Placeholder = styled.p` color: ${p => p.theme.textColorLight}; From df92df41c6e67c0ad5327dbcd64385c5e23aba77 Mon Sep 17 00:00:00 2001 From: "jin.gao" <jin.gao@mobilemd.cn> Date: Fri, 24 Dec 2021 17:01:32 +0800 Subject: [PATCH 213/348] fix: chartGroupColumns problem Pr #451 --- .../ChartWorkbenchPage/models/ChartHttpRequest.ts | 8 -------- .../components/SettingJumpModal/index.tsx | 14 +++++--------- .../src/app/pages/DashBoardPage/utils/index.ts | 6 +++++- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts index 2e9b88277..dfa51e880 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts @@ -360,14 +360,6 @@ export class ChartDataRequestBuilder { ) { return acc.concat(cur.rows); } - // TODO(TMBigGroup): Mixed Section类型为什么需要加入到sql请求的group中? - // if (cur.type === ChartDataSectionType.MIXED) { - // return acc.concat( - // cur.rows.filter( - // ({ type }) => type === ChartDataViewFieldType.STRING, - // ), - // ); - // } return acc; }, [], diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx index 9f9ffb315..b50dbe6e0 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx @@ -8,7 +8,7 @@ import { Form, Input, Modal, ModalProps, Select } from 'antd'; import { BoardContext } from 'app/pages/DashBoardPage/contexts/BoardContext'; import { selectDataChartById } from 'app/pages/DashBoardPage/pages/Board/slice/selector'; import { BoardState } from 'app/pages/DashBoardPage/pages/Board/slice/types'; -import { getChartDataRequestBuilder } from 'app/pages/DashBoardPage/utils'; +import { getChartGroupColumns } from 'app/pages/DashBoardPage/utils'; import { convertToWidgetMap } from 'app/pages/DashBoardPage/utils/widget'; import { makeSelectVizTree } from 'app/pages/MainPage/pages/VizPage/slice/selectors'; import { Folder } from 'app/pages/MainPage/pages/VizPage/slice/types'; @@ -105,14 +105,10 @@ export const SettingJumpModal: FC<SettingJumpModalProps> = ({ selectDataChartById(state, curJumpWidget?.datachartId), ); const [targetType, setTargetType] = useState(jumpTypes[0].value); - const chartGroupColumns = useMemo(() => { - if (!dataChart) { - return []; - } - const builder = getChartDataRequestBuilder(dataChart); - let groupColumns = builder.buildGroupColumns(); - return groupColumns; - }, [dataChart]); + const chartGroupColumns = useMemo( + () => getChartGroupColumns(dataChart), + [dataChart], + ); const onTargetChange = useCallback( value => { form.setFieldsValue({ filter: undefined }); diff --git a/frontend/src/app/pages/DashBoardPage/utils/index.ts b/frontend/src/app/pages/DashBoardPage/utils/index.ts index 1e0ca0e69..5e82d54c2 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/index.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/index.ts @@ -98,7 +98,6 @@ export const getChartGroupColumns = (dataChart: DataChart) => { const chartDataConfigs = dataChart?.config?.chartConfig?.datas; if (!chartDataConfigs) return [] as ChartDataSectionField[]; const groupTypes = [ChartDataSectionType.GROUP, ChartDataSectionType.COLOR]; - // ChartDataSectionType.MIXED ?? const groupColumns = chartDataConfigs.reduce<ChartDataSectionField[]>( (acc, cur) => { if (!cur.rows) { @@ -107,6 +106,11 @@ export const getChartGroupColumns = (dataChart: DataChart) => { if (groupTypes.includes(cur.type as any)) { return acc.concat(cur.rows); } + if (cur.type === ChartDataSectionType.MIXED) { + return acc.concat( + cur.rows.filter(({ type }) => type === ChartDataViewFieldType.STRING), + ); + } return acc; }, [], From 924bcaca1b228ec041582adb7f578fb09ec3bc31 Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Fri, 24 Dec 2021 17:07:17 +0800 Subject: [PATCH 214/348] fix:(Chart)funnel sort data --- .../BasicFunnelChart/BasicFunnelChart.tsx | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx index 715f06bdf..f23f3c717 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx @@ -103,12 +103,29 @@ class BasicFunnelChart extends Chart { dataset.rows, dataset.columns, ); + let dataList = objDataColumns; + let aggregateList = aggregateConfigs; + if (!groupConfigs.length) { + aggregateList = aggregateConfigs.sort((a, b) => { + return ( + objDataColumns[0][getValueByColumnKey(b)] - + objDataColumns[0][getValueByColumnKey(a)] + ); + }); + } else { + dataList = objDataColumns.sort((a, b) => { + return ( + b[getValueByColumnKey(aggregateConfigs[0])] - + a[getValueByColumnKey(aggregateConfigs[0])] + ); + }); + } const series = this.getSeries( styleConfigs, - aggregateConfigs, + aggregateList, groupConfigs, - objDataColumns, + dataList, infoConfigs, ); From 53af74fdabdc5c336d6d317a3b1eccbcae3e2a75 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 24 Dec 2021 17:11:18 +0800 Subject: [PATCH 215/348] refactor(chart): remove document.write --- .../components/ReactFrameComponent/Frame.jsx | 16 +++++++++------- .../BasicTableChart/BasicTableChart.tsx | 18 +++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/components/ReactFrameComponent/Frame.jsx b/frontend/src/app/components/ReactFrameComponent/Frame.jsx index 6f806709d..aa451612c 100644 --- a/frontend/src/app/components/ReactFrameComponent/Frame.jsx +++ b/frontend/src/app/components/ReactFrameComponent/Frame.jsx @@ -53,7 +53,7 @@ export class Frame extends Component { } getDoc() { - return this.nodeRef.current ? this.nodeRef.current.contentDocument : null; // eslint-disable-line + return this.nodeRef.current ? this.nodeRef.current.contentDocument : null; // eslint-disable-line } getMountTarget() { @@ -61,7 +61,7 @@ export class Frame extends Component { if (this.props.mountTarget) { return doc.querySelector(this.props.mountTarget); } - return doc.body.children[0]; + return doc.body; } setRef = node => { @@ -69,9 +69,6 @@ export class Frame extends Component { if (!this.nodeRef.current?.contentWindow) { return; } - this.nodeRef.current.contentWindow.document.write( - '<!DOCTYPE html><html><head></head><body><div class="frame-root"></div></body></html>', - ); }; handleLoad = () => { @@ -110,17 +107,22 @@ export class Frame extends Component { render() { const props = { ...this.props, - // srcDoc: this.props.initialContent, children: undefined, // The iframe isn't ready so we drop children from props here. #12, #17 }; delete props.head; + /** + * Because ios wechat browser issue which not support srcDoc props + * we remove this props and also to avoid performance issue with + * document.write function, but still PR will be welcom! + */ + delete props.srcDoc; delete props.mountTarget; delete props.contentDidMount; delete props.contentDidUpdate; return ( <iframe - title={'title'} + title={props?.id} {...props} ref={this.setRef} onLoad={this.handleLoad} diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx index 6cb74cfcc..d6209c393 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx @@ -251,16 +251,16 @@ class BasicTableChart extends ReactChart { let width = this.getTextWidth( context, text, - bodyFont.fontWeight, - bodyFont.fontSize, - bodyFont.fontFamily, + bodyFont?.fontWeight, + bodyFont?.fontSize, + bodyFont?.fontFamily, ); const headerWidth = this.getTextWidth( context, header?.label || header?.colName, - headerFont.fontWeight, - headerFont.fontSize, - headerFont.fontFamily, + headerFont?.fontWeight, + headerFont?.fontSize, + headerFont?.fontFamily, ); const sorterIconWidth = 12; return Math.max(width, headerWidth + sorterIconWidth); @@ -274,9 +274,9 @@ class BasicTableChart extends ReactChart { return this.getTextWidth( context, maxContent, - bodyFont.fontWeight, - bodyFont.fontSize, - bodyFont.fontFamily, + bodyFont?.fontWeight, + bodyFont?.fontSize, + bodyFont?.fontFamily, ); }; From 23a4f3fcbe5abedb628835d2b7c135134e36efd8 Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Fri, 24 Dec 2021 17:18:38 +0800 Subject: [PATCH 216/348] style:(Chart)style funnel data --- .../BasicFunnelChart/BasicFunnelChart.tsx | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx index f23f3c717..3980e6e54 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx @@ -103,23 +103,22 @@ class BasicFunnelChart extends Chart { dataset.rows, dataset.columns, ); - let dataList = objDataColumns; - let aggregateList = aggregateConfigs; - if (!groupConfigs.length) { - aggregateList = aggregateConfigs.sort((a, b) => { - return ( - objDataColumns[0][getValueByColumnKey(b)] - - objDataColumns[0][getValueByColumnKey(a)] - ); - }); - } else { - dataList = objDataColumns.sort((a, b) => { - return ( - b[getValueByColumnKey(aggregateConfigs[0])] - - a[getValueByColumnKey(aggregateConfigs[0])] - ); - }); - } + const dataList = !groupConfigs.length + ? objDataColumns + : objDataColumns.sort((a, b) => { + return ( + b[getValueByColumnKey(aggregateConfigs[0])] - + a[getValueByColumnKey(aggregateConfigs[0])] + ); + }); + const aggregateList = !groupConfigs.length + ? aggregateConfigs.sort((a, b) => { + return ( + objDataColumns[0][getValueByColumnKey(b)] - + objDataColumns[0][getValueByColumnKey(a)] + ); + }) + : aggregateConfigs; const series = this.getSeries( styleConfigs, @@ -132,7 +131,7 @@ class BasicFunnelChart extends Chart { return { tooltip: this.getFunnelChartTooltip( groupConfigs, - aggregateConfigs, + aggregateList, infoConfigs, ), legend: this.getLegendStyle(styleConfigs), From 1ff0323c65a2023ab961a0b6352e7385d8b4849b Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 24 Dec 2021 17:34:05 +0800 Subject: [PATCH 217/348] fix(chart): fix typo --- frontend/src/app/components/ReactFrameComponent/Frame.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/components/ReactFrameComponent/Frame.jsx b/frontend/src/app/components/ReactFrameComponent/Frame.jsx index aa451612c..4e412c5c2 100644 --- a/frontend/src/app/components/ReactFrameComponent/Frame.jsx +++ b/frontend/src/app/components/ReactFrameComponent/Frame.jsx @@ -114,7 +114,7 @@ export class Frame extends Component { /** * Because ios wechat browser issue which not support srcDoc props * we remove this props and also to avoid performance issue with - * document.write function, but still PR will be welcom! + * document.write function, but PR is still welcome! */ delete props.srcDoc; delete props.mountTarget; From e99205c8b6415eb5dfc7f9e1989793d88e223f89 Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Fri, 24 Dec 2021 17:36:46 +0800 Subject: [PATCH 218/348] style:(Chart)style funnel data --- .../BasicFunnelChart/BasicFunnelChart.tsx | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx index 3980e6e54..c566059a0 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx @@ -105,19 +105,17 @@ class BasicFunnelChart extends Chart { ); const dataList = !groupConfigs.length ? objDataColumns - : objDataColumns.sort((a, b) => { - return ( - b[getValueByColumnKey(aggregateConfigs[0])] - - a[getValueByColumnKey(aggregateConfigs[0])] - ); - }); + : objDataColumns?.sort( + (a, b) => + b?.[getValueByColumnKey(aggregateConfigs[0])] - + a?.[getValueByColumnKey(aggregateConfigs[0])], + ); const aggregateList = !groupConfigs.length - ? aggregateConfigs.sort((a, b) => { - return ( - objDataColumns[0][getValueByColumnKey(b)] - - objDataColumns[0][getValueByColumnKey(a)] - ); - }) + ? aggregateConfigs?.sort( + (a, b) => + objDataColumns?.[0]?.[getValueByColumnKey(b)] - + objDataColumns?.[0]?.[getValueByColumnKey(a)], + ) : aggregateConfigs; const series = this.getSeries( From 41c1dce34773f2fae8eb2f10102ccad2e225489a Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Fri, 24 Dec 2021 17:57:34 +0800 Subject: [PATCH 219/348] fix(chart): disable measure log when use --- .../ChartWorkbenchPage/models/ChartEventBroker.ts | 10 +++++++--- frontend/src/utils/debugger.ts | 8 ++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts index 9b6623eeb..88f272918 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts @@ -86,9 +86,13 @@ class ChartEventBroker { private safeInvoke(event: HooksEvent, options: any, context?: BrokerContext) { try { - Debugger.instance.measure(`ChartEventBroker | ${event} `, () => { - this._listeners.get(event)?.call?.(this._chart, options, context); - }); + Debugger.instance.measure( + `ChartEventBroker | ${event} `, + () => { + this._listeners.get(event)?.call?.(this._chart, options, context); + }, + false, + ); } catch (e) { console.error(`ChartEventBroker | ${event} exception ----> `, e); } finally { diff --git a/frontend/src/utils/debugger.ts b/frontend/src/utils/debugger.ts index 3727e32e1..e65abc14f 100644 --- a/frontend/src/utils/debugger.ts +++ b/frontend/src/utils/debugger.ts @@ -31,8 +31,12 @@ export class Debugger { this._enableDebug = !!enable; } - public async measure(info: string, fn: VoidFunction) { - if (!this._enableDebug) { + public async measure( + info: string, + fn: VoidFunction, + forceEnable: boolean = true, + ) { + if (!this._enableDebug || !forceEnable) { return await fn(); } From 93b518c443d0cd76341d19a6a93c1bfe926031fc Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Fri, 24 Dec 2021 19:28:34 +0800 Subject: [PATCH 220/348] refactor:(Chart) refactor rich env status --- .../ChartGraph/BasicRichText/BasicRichText.tsx | 14 ++++++++++---- .../components/ChartPresentWrapper.tsx | 2 +- .../ChartTools/ChartIFrameContainerDispatcher.tsx | 1 + 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/BasicRichText.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/BasicRichText.tsx index 22e34559b..7d1d52b9a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/BasicRichText.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/BasicRichText.tsx @@ -35,7 +35,12 @@ class BasicRichText extends ReactChart { isISOContainer = 'react-rich-text'; config = Config; protected isAutoMerge = false; - richTextOptions = { dataset: {}, config: {}, containerId: '' }; + richTextOptions = { + dataset: {}, + config: {}, + containerId: '', + widgetSpecialConfig: { env: '' }, + }; constructor(props?) { super(ChartRichTextAdapter, { @@ -52,6 +57,7 @@ class BasicRichText extends ReactChart { } onMount(options, context): void { + console.log(context); if (options.containerId === undefined || !context.document) { return; } @@ -81,9 +87,9 @@ class BasicRichText extends ReactChart { } getOptions(context, dataset?: ChartDataset, config?: ChartConfig) { - const { containerId } = this.richTextOptions; + const { containerId, widgetSpecialConfig } = this.richTextOptions; if (!dataset || !config || !containerId) { - return { dataList: [], id: '', isEditing: !!config?.env }; + return { dataList: [], id: '', isEditing: !!widgetSpecialConfig?.env }; } const dataConfigs = config.datas || []; const stylesConfigs = config.styles || []; @@ -115,7 +121,7 @@ class BasicRichText extends ReactChart { dataList, initContent, id: containerId, - isEditing: !!config?.env, + isEditing: !!widgetSpecialConfig?.env, ...this.getOnChange(), }; } diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartPresentWrapper.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartPresentWrapper.tsx index 543835929..b1276e398 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartPresentWrapper.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartPresentWrapper.tsx @@ -41,7 +41,7 @@ const ChartPresentWrapper: FC<{ <ChartPresentPanel chart={chart} dataset={dataset} - chartConfig={{ ...chartConfig, env: 'workbench' }} + chartConfig={chartConfig} /> </StyledChartPresentWrapper> ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx index 7f0492672..5e96a0ed4 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx @@ -88,6 +88,7 @@ class ChartIFrameContainerDispatcher { key={containerId} width={style?.width} height={style?.height} + widgetSpecialConfig={{ env: 'workbench' }} /> </div> ); From cf8ecf253a07b4122484b842326691c0c18d4cb8 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Fri, 24 Dec 2021 14:27:39 +0800 Subject: [PATCH 221/348] chore: improve account menu style --- .../src/app/components/Popup/MenuListItem.tsx | 56 +++++++++++++++---- .../src/app/pages/MainPage/Navbar/index.tsx | 25 +++++---- frontend/src/locales/en/translation.json | 8 +-- 3 files changed, 61 insertions(+), 28 deletions(-) diff --git a/frontend/src/app/components/Popup/MenuListItem.tsx b/frontend/src/app/components/Popup/MenuListItem.tsx index a943f91d2..62c518892 100644 --- a/frontend/src/app/components/Popup/MenuListItem.tsx +++ b/frontend/src/app/components/Popup/MenuListItem.tsx @@ -1,5 +1,5 @@ import { Menu, MenuItemProps } from 'antd'; -import React, { cloneElement, ReactElement } from 'react'; +import React, { cloneElement, ReactElement, ReactNode } from 'react'; import styled, { css } from 'styled-components/macro'; import { LINE_HEIGHT_HEADING, SPACE, SPACE_XS } from 'styles/StyleConstants'; import { mergeClassNames } from 'utils/utils'; @@ -10,36 +10,68 @@ const WrapperStyle = css` &.selected { background-color: ${p => p.theme.emphasisBackground}; } + + .ant-dropdown-menu-submenu-title { + line-height: ${LINE_HEIGHT_HEADING}; + } `; interface MenuListItemProps extends Omit<MenuItemProps, 'prefix'> { prefix?: ReactElement; suffix?: ReactElement; + sub?: boolean; } export function MenuListItem({ prefix, suffix, + sub, ...menuProps }: MenuListItemProps) { - return ( + return sub ? ( + <Menu.SubMenu + css={WrapperStyle} + {...menuProps} + title={ + <ListItem prefix={prefix} suffix={suffix}> + {menuProps.title} + </ListItem> + } + > + {menuProps.children} + </Menu.SubMenu> + ) : ( <Menu.Item css={WrapperStyle} {...menuProps}> - <ListItem> - {prefix && - cloneElement(prefix, { - className: mergeClassNames(prefix.props.className, 'prefix'), - })} + <ListItem prefix={prefix} suffix={suffix}> {menuProps.children} - {suffix && - cloneElement(suffix, { - className: mergeClassNames(suffix.props.className, 'suffix'), - })} </ListItem> </Menu.Item> ); } -const ListItem = styled.div` +interface ListItemProps { + prefix?: ReactElement; + suffix?: ReactElement; + children?: ReactNode; +} + +function ListItem({ prefix, suffix, children }: ListItemProps) { + return ( + <StyledListItem> + {prefix && + cloneElement(prefix, { + className: mergeClassNames(prefix.props.className, 'prefix'), + })} + {children} + {suffix && + cloneElement(suffix, { + className: mergeClassNames(suffix.props.className, 'suffix'), + })} + </StyledListItem> + ); +} + +const StyledListItem = styled.div` display: flex; align-items: center; diff --git a/frontend/src/app/pages/MainPage/Navbar/index.tsx b/frontend/src/app/pages/MainPage/Navbar/index.tsx index 1d6d33b4e..7fc30beb4 100644 --- a/frontend/src/app/pages/MainPage/Navbar/index.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/index.tsx @@ -3,11 +3,11 @@ import { ExportOutlined, FormOutlined, FunctionOutlined, + GlobalOutlined, ProfileOutlined, SafetyCertificateFilled, SettingFilled, SettingOutlined, - SwapOutlined, UserOutlined, } from '@ant-design/icons'; import { List, Menu, Tooltip } from 'antd'; @@ -103,7 +103,7 @@ export function Navbar() { module: ResourceTypes.Manager, }, ], - [], + [t], ); const navs = useMemo( @@ -163,7 +163,7 @@ export function Navbar() { module: ResourceTypes.Manager, }, ], - [subNavs], + [subNavs, t], ); const showSubNav = useMemo( @@ -270,6 +270,16 @@ export function Navbar() { selectable={false} onClick={userMenuSelect} > + <MenuListItem + key="language" + prefix={<GlobalOutlined className="icon" />} + title={<p>{t('nav.account.switchLanguage.title')}</p>} + sub + > + <MenuListItem key="zh">中文</MenuListItem> + <MenuListItem key="en">English</MenuListItem> + </MenuListItem> + <Menu.Divider /> <MenuListItem key="profile" prefix={<ProfileOutlined className="icon" />} @@ -282,15 +292,6 @@ export function Navbar() { > <p>{t('nav.account.changePassword.title')}</p> </MenuListItem> - - <Menu.SubMenu - icon={<SwapOutlined className="icon" />} - key="language" - title={t('nav.account.switchLanguage.title')} - > - <Menu.Item key="zh">中文</Menu.Item> - <Menu.Item key="en">English</Menu.Item> - </Menu.SubMenu> <MenuListItem key="logout" prefix={<ExportOutlined className="icon" />} diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 16116135b..5ac035c27 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -23,7 +23,7 @@ }, "account": { "accountSettings": { - "title": "账号设置", + "title": "Profile", "clickUpload": "点击上传", "userName": "用户名", "email": "邮箱", @@ -32,7 +32,7 @@ "save": "保存" }, "changePassword": { - "title": "修改密码", + "title": "Password", "oldPassword": "旧密码", "newPassword": "新密码", "confirmPassword": "确定新密码", @@ -40,10 +40,10 @@ "save": "保存" }, "switchLanguage": { - "title": "切换语言" + "title": "language" }, "logout": { - "title": "退出登录" + "title": "Logout" } } }, From 7638d37fa909c7bb73957d98d5c978e6d17c89f1 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Sun, 26 Dec 2021 18:28:16 +0800 Subject: [PATCH 222/348] refactor(Variable): variable name duplicate check --- frontend/src/app/components/ListItem.tsx | 5 -- .../pages/VariablePage/VariableForm.tsx | 57 ++++++++++--------- .../ViewPage/Main/Properties/Variables.tsx | 44 +++++++++++--- 3 files changed, 66 insertions(+), 40 deletions(-) diff --git a/frontend/src/app/components/ListItem.tsx b/frontend/src/app/components/ListItem.tsx index cf79298a9..40d21fd9d 100644 --- a/frontend/src/app/components/ListItem.tsx +++ b/frontend/src/app/components/ListItem.tsx @@ -47,11 +47,6 @@ const StyledItem = styled(Item)` color: ${p => p.theme.textColorSnd}; text-overflow: ellipsis; white-space: nowrap; - - > span { - margin-right: ${SPACE_XS}; - color: ${p => p.theme.textColorDisabled}; - } } &.with-avatar { diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx index 410fc45ea..8c87ca3b3 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx @@ -3,7 +3,7 @@ import { ModalForm, ModalFormProps } from 'app/components'; import debounce from 'debounce-promise'; import { DEFAULT_DEBOUNCE_WAIT } from 'globalConstants'; import moment from 'moment'; -import { memo, useCallback, useEffect, useRef, useState } from 'react'; +import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { SPACE_XS } from 'styles/StyleConstants'; import { request } from 'utils/request'; import { errorHandle } from 'utils/utils'; @@ -97,6 +97,35 @@ export const VariableForm = memo( formRef.current?.setFieldsValue({ defaultValue: [] }); }, []); + const nameValidator = useMemo( + () => + scope === VariableScopes.Private + ? (_, value) => { + if (value === editingVariable?.name) { + return Promise.resolve(); + } + if (variables?.find(({ name }) => name === value)) { + return Promise.reject(new Error('名称重复')); + } else { + return Promise.resolve(); + } + } + : debounce((_, value) => { + if (!value || value === editingVariable?.name) { + return Promise.resolve(); + } + return request({ + url: `/variables/check/name`, + method: 'POST', + params: { name: value, orgId }, + }).then( + () => Promise.resolve(), + () => Promise.reject(new Error('名称重复')), + ); + }, DEFAULT_DEBOUNCE_WAIT), + [scope, editingVariable?.name, variables, orgId], + ); + return ( <ModalForm {...modalProps} @@ -118,31 +147,7 @@ export const VariableForm = memo( rules={[ { required: true, message: '名称不能为空' }, { - validator: debounce((_, value) => { - if (!value || value === editingVariable?.name) { - return Promise.resolve(); - } - return request({ - url: `/variables/check/name`, - method: 'POST', - params: { name: value, orgId }, - }).then( - () => Promise.resolve(), - () => Promise.reject(new Error('名称重复')), - ); - }, DEFAULT_DEBOUNCE_WAIT), - }, - { - validator: (_, value) => { - if (value === editingVariable?.name) { - return Promise.resolve(); - } - if (variables?.find(({ name }) => name === value)) { - return Promise.reject(new Error('名称重复')); - } else { - return Promise.resolve(); - } - }, + validator: nameValidator, }, ]} > diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx index 2547a1dd4..325531005 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx @@ -23,6 +23,7 @@ import { SubjectForm } from 'app/pages/MainPage/pages/VariablePage/SubjectForm'; import { VariableFormModel } from 'app/pages/MainPage/pages/VariablePage/types'; import { VariableForm } from 'app/pages/MainPage/pages/VariablePage/VariableForm'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; +import classnames from 'classnames'; import { CommonFormTypes } from 'globalConstants'; import { Moment } from 'moment'; import { @@ -37,7 +38,7 @@ import { import { monaco } from 'react-monaco-editor'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components/macro'; -import { SPACE_MD, SPACE_TIMES } from 'styles/StyleConstants'; +import { SPACE_MD, SPACE_TIMES, SPACE_XS } from 'styles/StyleConstants'; import { errorHandle } from 'utils/utils'; import { v4 as uuidv4 } from 'uuid'; import { selectVariables } from '../../../VariablePage/slice/selectors'; @@ -256,14 +257,22 @@ export const Variables = memo(() => { [dispatch, actions, editingVariable, variables], ); - const renderTitleText = useCallback(item => { - return ( - <> - {item.relVariableSubjects ? '' : <span>[公共]</span>} - {item.name} - </> - ); - }, []); + const renderTitleText = useCallback( + item => { + const isPrivate = !!item.relVariableSubjects; + const isDuplicate = isPrivate + ? publicVariables.some(v => v.name === item.name) + : variables.some(v => v.name === item.name); + return ( + <ListItemTitle className={classnames({ duplicate: isDuplicate })}> + {!isPrivate && <span className="prefix">[公共]</span>} + {item.name} + {isDuplicate && <span className="suffix">重复</span>} + </ListItemTitle> + ); + }, + [variables, publicVariables], + ); const titleProps = useMemo( () => ({ @@ -345,6 +354,7 @@ export const Variables = memo(() => { scope={VariableScopes.Private} orgId={orgId} editingVariable={editingVariable} + variables={variables} visible={formVisible} title="变量" type={formType} @@ -391,3 +401,19 @@ const ListWrapper = styled.div` color: ${p => p.theme.warning}; } `; + +const ListItemTitle = styled.div` + &.duplicate { + color: ${p => p.theme.highlight}; + } + + .prefix { + margin-right: ${SPACE_XS}; + color: ${p => p.theme.textColorDisabled}; + } + + .suffix { + margin-left: ${SPACE_XS}; + color: ${p => p.theme.highlight}; + } +`; From 8b98388d0e88a80d8c111a8161f42a9dd6e2bce2 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Sun, 26 Dec 2021 19:04:52 +0800 Subject: [PATCH 223/348] fix: unique key warning --- .../ChartOperationPanel/components/ChartGraphPanel.tsx | 1 + .../components/ChartTools/ChartIFrameContainerDispatcher.tsx | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraphPanel.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraphPanel.tsx index 07c05fe42..a3a6181dc 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraphPanel.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraphPanel.tsx @@ -153,6 +153,7 @@ const ChartGraphPanel: FC<{ return ( <Popconfirm + key={c?.meta?.id} title={t('confirm', undefined, { name: c.meta?.name })} onConfirm={handleChartChange(c?.meta?.id)} okText={t('ok')} diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx index 5e96a0ed4..06a56197f 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx @@ -79,13 +79,12 @@ class ChartIFrameContainerDispatcher { if (!this.chartContainerMap.has(containerId)) { const newContainer = style => (chart, dataset, config) => { return ( - <div style={style}> + <div key={containerId} style={style}> <ChartTools.ChartIFrameContainer dataset={dataset} chart={chart} config={config} containerId={containerId} - key={containerId} width={style?.width} height={style?.height} widgetSpecialConfig={{ env: 'workbench' }} From 6db95df79347e5f231ceb99428898eb970f0e6b8 Mon Sep 17 00:00:00 2001 From: francis <francis.xjl@qq.com> Date: Mon, 27 Dec 2021 08:28:35 +0800 Subject: [PATCH 224/348] https://github.com/running-elephant/datart/issues/459 make page editable after click folder. --- .../ValuesSetter/ValuesOptionsSetter/AssistViewFields.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/AssistViewFields.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/AssistViewFields.tsx index 10d224328..e8d1d9748 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/AssistViewFields.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/AssistViewFields.tsx @@ -104,7 +104,7 @@ export const AssistViewFields: React.FC<AssistViewFieldsProps> = memo( targetOption.loading = true; const data = await getViewData(targetOption.value); - if (!data) return; + if (!data || !data.model) return; // make page can edit after click folder const model = JSON.parse(data.model); const children: CascaderOptionType[] = Object.keys(model).map(key => { return { From 5528c9f30273658f147bd06440fcf4e81f16ccb1 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Mon, 27 Dec 2021 10:20:08 +0800 Subject: [PATCH 225/348] fix(View): schema table name sorted by a-z --- .../MainPage/pages/ViewPage/Main/Properties/Resource.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx index 69b1e1351..366951762 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx @@ -98,7 +98,13 @@ export const Resource = memo(() => { actions.addTables({ sourceId, databaseName: database, - tables: data, + tables: data.sort((a, b) => + a.toLowerCase() < b.toLowerCase() + ? -1 + : a.toLowerCase() > b.toLowerCase() + ? 1 + : 0, + ), }), ); resolve(); From ab5ba487526360303d2d9275bfc02b5433e35099 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Sat, 25 Dec 2021 22:26:21 +0800 Subject: [PATCH 226/348] feat(widget): add renderErrorIcon --- .../components/WidgetToolBar/index.tsx | 16 +++++++- .../DashBoardPage/pages/Board/slice/index.ts | 11 ++++++ .../DashBoardPage/pages/Board/slice/thunk.ts | 37 ++++++++++++++++++- .../DashBoardPage/pages/Board/slice/types.ts | 1 + .../pages/BoardEditor/slice/index.ts | 11 ++++++ .../pages/BoardEditor/slice/thunk.ts | 20 +++++++++- 6 files changed, 91 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/index.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/index.tsx index bde7fb63b..90bac7618 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/index.tsx @@ -20,11 +20,12 @@ import { ClockCircleOutlined, LinkOutlined, SyncOutlined, + WarningTwoTone, } from '@ant-design/icons'; import { Space, Tooltip } from 'antd'; import React, { FC, useContext } from 'react'; import styled from 'styled-components'; -import { PRIMARY } from 'styles/StyleConstants'; +import { ERROR, PRIMARY } from 'styles/StyleConstants'; import { BoardContext } from '../../contexts/BoardContext'; import { WidgetContext } from '../../contexts/WidgetContext'; import { WidgetInfoContext } from '../../contexts/WidgetInfoContext'; @@ -36,7 +37,8 @@ interface WidgetToolBarProps {} const WidgetToolBar: FC<WidgetToolBarProps> = () => { const { boardType, editing: boardEditing } = useContext(BoardContext); - const { loading, inLinking, rendered } = useContext(WidgetInfoContext); + const { loading, inLinking, rendered, errInfo } = + useContext(WidgetInfoContext); const widget = useContext(WidgetContext); const { onClearLinkage } = useContext(WidgetMethodContext); const ssp = e => { @@ -77,6 +79,14 @@ const WidgetToolBar: FC<WidgetToolBarProps> = () => { ) : null; } }; + const renderErrorIcon = (errInfo?: string) => { + if (!errInfo) return null; + return ( + <Tooltip title={errInfo}> + <WarningTwoTone twoToneColor={ERROR} /> + </Tooltip> + ); + }; const renderWidgetAction = () => { const widgetType = widget.config.type; const hideTypes: WidgetType[] = ['query', 'reset', 'controller']; @@ -85,9 +95,11 @@ const WidgetToolBar: FC<WidgetToolBarProps> = () => { } return <WidgetActionDropdown widget={widget} />; }; + return ( <StyleWrap onClick={ssp} className="widget-tool-bar"> <Space> + {renderErrorIcon(errInfo)} {renderedIcon()} {loadingIcon()} {linkageIcon()} diff --git a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/index.ts b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/index.ts index 53df1189e..b2621c7a9 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/index.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/index.ts @@ -238,6 +238,17 @@ const boardSlice = createSlice({ pageNo: 1, }; }, + setWidgetErrInfo( + state, + action: PayloadAction<{ + boardId: string; + widgetId: string; + errInfo?: string; + }>, + ) { + const { boardId, widgetId, errInfo } = action.payload; + state.widgetInfoRecord[boardId][widgetId].errInfo = errInfo; + }, resetControlWidgets( state, action: PayloadAction<{ 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 3ebaaa5e4..d053b0d1f 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/thunk.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/thunk.ts @@ -265,8 +265,28 @@ export const getChartWidgetDataAsync = createAsyncThunk< pageInfo: widgetData.pageInfo, }), ); + dispatch( + boardActions.setWidgetErrInfo({ + boardId, + widgetId, + errInfo: undefined, + }), + ); } catch (error) { - errorHandle(error); + dispatch( + boardActions.setWidgetErrInfo({ + boardId, + widgetId, + errInfo: (error as any)?.message as any, + }), + ); + dispatch( + boardActions.setWidgetData({ + id: widgetId, + columns: [], + rows: [], + } as WidgetData), + ); } dispatch( boardActions.addFetchedItem({ @@ -344,8 +364,21 @@ export const getControllerOptions = createAsyncThunk< widgetData = { ...data, id: widget.id }; dispatch(boardActions.setWidgetData(widgetData as WidgetData)); } + dispatch( + boardActions.setWidgetErrInfo({ + boardId, + widgetId, + errInfo: undefined, + }), + ); } catch (error) { - errorHandle(error); + dispatch( + boardActions.setWidgetErrInfo({ + boardId, + widgetId, + errInfo: (error as any)?.message as any, + }), + ); } dispatch( boardActions.addFetchedItem({ 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 2591867e3..05f4007a7 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/types.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/types.ts @@ -189,6 +189,7 @@ export interface WidgetInfo { inLinking: boolean; //是否在触发联动 selected: boolean; pageInfo: Partial<PageInfo>; + errInfo?: string; selectItems?: string[]; parameters?: any; } diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/index.ts b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/index.ts index 4297fa5c7..7529a0fe0 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/index.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/index.ts @@ -235,6 +235,17 @@ const widgetInfoRecordSlice = createSlice({ const { widgetId, pageInfo } = action.payload; state[widgetId].pageInfo = pageInfo || { pageNo: 1 }; }, + setWidgetErrInfo( + state, + action: PayloadAction<{ + boardId?: string; + widgetId: string; + errInfo?: string; + }>, + ) { + const { widgetId, errInfo } = action.payload; + state[widgetId].errInfo = errInfo; + }, }, extraReducers: builder => { builder.addCase(getEditChartWidgetDataAsync.pending, (state, action) => { 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 99952f674..22fdbcefe 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts @@ -514,8 +514,26 @@ export const getEditChartWidgetDataAsync = createAsyncThunk< pageInfo: data.pageInfo, }), ); + dispatch( + editWidgetInfoActions.setWidgetErrInfo({ + widgetId, + errInfo: undefined, + }), + ); } catch (error) { - errorHandle(error); + dispatch( + editWidgetInfoActions.setWidgetErrInfo({ + widgetId, + errInfo: (error as any)?.message as any, + }), + ); + dispatch( + editWidgetDataActions.setWidgetData({ + id: widgetId, + columns: [], + rows: [], + } as WidgetData), + ); } return null; }, From c910be4a1c8ef854a0588321741865d5222f08c7 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Mon, 27 Dec 2021 11:23:19 +0800 Subject: [PATCH 227/348] refactor: renderErrorIcon in a box --- .../components/WidgetToolBar/index.tsx | 12 +++++++++++- .../DashBoardPage/pages/Board/slice/thunk.ts | 7 ++++--- frontend/src/utils/utils.ts | 17 +++++++++++++++-- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/index.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/index.tsx index 90bac7618..f2c3829c7 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/index.tsx @@ -81,8 +81,18 @@ const WidgetToolBar: FC<WidgetToolBarProps> = () => { }; const renderErrorIcon = (errInfo?: string) => { if (!errInfo) return null; + const renderTitle = errInfo => { + if (typeof errInfo !== 'string') return 'object'; + return ( + <div + style={{ maxHeight: '200px', maxWidth: '400px', overflow: 'auto' }} + > + {errInfo} + </div> + ); + }; return ( - <Tooltip title={errInfo}> + <Tooltip title={renderTitle(errInfo)}> <WarningTwoTone twoToneColor={ERROR} /> </Tooltip> ); 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 d053b0d1f..8037f9f30 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/thunk.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/thunk.ts @@ -13,7 +13,7 @@ import { ExecuteToken, ShareVizInfo } from 'app/pages/SharePage/slice/types'; import ChartDataset from 'app/types/ChartDataset'; import { RootState } from 'types'; import { request } from 'utils/request'; -import { errorHandle } from 'utils/utils'; +import { errorHandle, getErrorMessage } from 'utils/utils'; import { boardActions } from '.'; import { getChartWidgetRequestParams } from '../../../utils'; import { handleServerBoardAction } from './asyncActions'; @@ -277,9 +277,10 @@ export const getChartWidgetDataAsync = createAsyncThunk< boardActions.setWidgetErrInfo({ boardId, widgetId, - errInfo: (error as any)?.message as any, + errInfo: getErrorMessage(error), }), ); + dispatch( boardActions.setWidgetData({ id: widgetId, @@ -376,7 +377,7 @@ export const getControllerOptions = createAsyncThunk< boardActions.setWidgetErrInfo({ boardId, widgetId, - errInfo: (error as any)?.message as any, + errInfo: getErrorMessage(error), }), ); } diff --git a/frontend/src/utils/utils.ts b/frontend/src/utils/utils.ts index a51096634..1855a9311 100644 --- a/frontend/src/utils/utils.ts +++ b/frontend/src/utils/utils.ts @@ -32,7 +32,20 @@ export function errorHandle(error) { } return error; } - +export function getErrorMessage(error) { + if (error?.response) { + const { response } = error as AxiosError; + switch (response?.status) { + case 401: + message.error({ key: '401', content: '未登录或会话过期,请重新登录' }); + removeToken(); + return '401'; + default: + return response?.data.message || error.message; + } + } + return error?.message; +} export function reduxActionErrorHandler(errorAction) { if (errorAction?.payload) { message.error(errorAction?.payload); @@ -180,7 +193,7 @@ export const onDropTreeFn = ({ info, treeData, callback }) => { } else { //中间 if (!dropArr[dropIndex].index && !dropArr[dropIndex + 1].index) { - index = dropArr[dropArr.length-1].index + 1; + index = dropArr[dropArr.length - 1].index + 1; } else { index = (dropArr[dropIndex].index + dropArr[dropIndex + 1].index) / 2; } From 11f558d38aa7ad2b2fc21dec14701201671a67bd Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Mon, 27 Dec 2021 12:38:49 +0800 Subject: [PATCH 228/348] feat: add aggregation switch --- frontend/src/app/components/ChartEditor.tsx | 26 ++++++++ .../src/app/hooks/useFieldActionModal.tsx | 4 ++ .../ChartHeaderPanel/ChartHeaderPanel.tsx | 65 +++++++++++++------ .../components/AggregationOperationMenu.tsx | 51 +++++++++++++++ .../ChartConfigPanel/ChartDataConfigPanel.tsx | 6 +- .../AggregateTypeSection.tsx | 13 ++-- .../FilterTypeSection.tsx | 8 ++- .../GroupTypeSection.tsx | 2 +- .../InfoTypeSection.tsx | 15 +++-- .../MixedTypeSection.tsx | 12 +++- .../SizeTypeSection.tsx | 11 +++- .../ChartDataConfigSection/utils.ts | 25 ++++++- .../ChartDraggableTargetContainer.tsx | 44 ++++++++++++- .../FilterAction/FilterAction.tsx | 37 ++++++----- .../FilterControlPanel/FilterControlPanel.tsx | 4 +- .../ChartGraph/MingXiTableChart/config.ts | 1 - .../components/ChartGraphPanel.tsx | 1 + .../ChartWorkbench/ChartWorkbench.tsx | 61 +++++++++-------- .../contexts/ChartAggregationContext.ts | 27 ++++++++ .../models/ChartHttpRequest.ts | 24 ++++++- .../slice/workbenchSlice.ts | 18 ++++- .../DashBoardPage/pages/Board/slice/types.ts | 1 + .../BoardEditor/slice/actions/actions.ts | 2 +- .../app/pages/DashBoardPage/utils/index.ts | 5 ++ .../ChartPreview/ChartPreviewBoard.tsx | 4 ++ .../MainPage/pages/VizPage/slice/thunks.ts | 2 + .../SharePage/ChartPreviewBoardForShare.tsx | 3 + .../src/app/pages/SharePage/slice/thunks.ts | 2 + .../src/app/types/ChartDataConfigSection.ts | 1 + frontend/src/app/utils/mutation.ts | 1 - frontend/src/locales/zh/translation.json | 8 ++- frontend/src/utils/utils.ts | 2 +- 32 files changed, 390 insertions(+), 96 deletions(-) create mode 100644 frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/components/AggregationOperationMenu.tsx create mode 100644 frontend/src/app/pages/ChartWorkbenchPage/contexts/ChartAggregationContext.ts diff --git a/frontend/src/app/components/ChartEditor.tsx b/frontend/src/app/components/ChartEditor.tsx index 334278d0d..3d69367d3 100644 --- a/frontend/src/app/components/ChartEditor.tsx +++ b/frontend/src/app/components/ChartEditor.tsx @@ -169,6 +169,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ setChart(currentChart); let clonedState = CloneValueDeep(currentChart.config); + dispatch(workbenchSlice.actions.updateShadowChartConfig({})); dispatch( workbenchSlice.actions.updateChartConfig({ type: ChartConfigReducerActionType.INIT, @@ -186,6 +187,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ chartConfig: chartConfig!, chartGraphId: chart?.meta.id!, computedFields: dataview?.computedFields || [], + aggregation: backendChart?.config?.aggregation, }; const dataChart: DataChart = { @@ -207,6 +209,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ dataview, onSaveInWidget, orgId, + backendChart?.config?.aggregation, ]); const saveChart = useCallback(async () => { @@ -219,6 +222,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ chartId: dataChartId, index: 0, parentId: 0, + aggregation: backendChart?.config?.aggregation, }), ); onSaveInDataChart?.(orgId, dataChartId); @@ -239,6 +243,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ chartId: dataChartId, index: 0, parentId: 0, + aggregation: backendChart?.config?.aggregation, }), ); saveToWidget(); @@ -260,6 +265,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ orgId, chartType, saveToWidget, + backendChart?.config?.aggregation, ]); const registerChartEvents = chart => { @@ -293,6 +299,24 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ ]); }; + const handleAggregationState = state => { + const currentChart = ChartManager.instance().getById(chart?.meta?.id); + registerChartEvents(currentChart); + let clonedState = CloneValueDeep(currentChart?.config); + + dispatch(actions.updateChartAggregation(state)); + dispatch(workbenchSlice.actions.updateShadowChartConfig({})); + dispatch( + workbenchSlice.actions.updateChartConfig({ + type: ChartConfigReducerActionType.INIT, + payload: { + init: { + ...clonedState, + }, + }, + }), + ); + }; return ( <StyledChartWorkbenchPage> <ChartWorkbench @@ -302,7 +326,9 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ onGoBack: () => { onClose?.(); }, + onChangeAggregation: handleAggregationState, }} + aggregation={backendChart?.config?.aggregation} chart={chart} dataset={dataset} dataview={dataview} diff --git a/frontend/src/app/hooks/useFieldActionModal.tsx b/frontend/src/app/hooks/useFieldActionModal.tsx index 0c25d5920..21b584d5c 100644 --- a/frontend/src/app/hooks/useFieldActionModal.tsx +++ b/frontend/src/app/hooks/useFieldActionModal.tsx @@ -39,6 +39,7 @@ function useFieldActionModal({ i18nPrefix }: I18NComponentProps) { dataView?: ChartDataView, dataConfig?: ChartDataSectionConfig, onChange?, + aggregation?: boolean, ) => { if (!config) { return null; @@ -50,6 +51,7 @@ function useFieldActionModal({ i18nPrefix }: I18NComponentProps) { dataView, dataConfig, onConfigChange: onChange, + aggregation, }; switch (actionType) { @@ -91,6 +93,7 @@ function useFieldActionModal({ i18nPrefix }: I18NComponentProps) { dataset?: ChartDataset, dataView?: ChartDataView, modalSize?: string, + aggregation?: boolean, ) => { const currentConfig = dataConfig.rows?.find(c => c.uid === columnUid); let _modalSize = StateModalSize.MIDDLE; @@ -110,6 +113,7 @@ function useFieldActionModal({ i18nPrefix }: I18NComponentProps) { dataView, dataConfig, onChange, + aggregation, ), onOk: handleOk(onConfigChange, columnUid), maskClosable: true, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/ChartHeaderPanel.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/ChartHeaderPanel.tsx index e7424f8c6..8a80cb85f 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/ChartHeaderPanel.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/ChartHeaderPanel.tsx @@ -16,8 +16,8 @@ * limitations under the License. */ -import { LeftOutlined } from '@ant-design/icons'; -import { Button, Space } from 'antd'; +import { LeftOutlined, MoreOutlined } from '@ant-design/icons'; +import { Button, Dropdown, Space } from 'antd'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { FC, memo } from 'react'; import styled from 'styled-components/macro'; @@ -30,30 +30,55 @@ import { SPACE_TIMES, SPACE_XS, } from 'styles/StyleConstants'; +import AggregationOperationMenu from './components/AggregationOperationMenu'; const ChartHeaderPanel: FC<{ chartName?: string; onSaveChart?: () => void; onGoBack?: () => void; -}> = memo(({ chartName, onSaveChart, onGoBack }) => { - const t = useI18NPrefix(`viz.workbench.header`); + onChangeAggregation?: (state: boolean) => void; + aggregation?: boolean; +}> = memo( + ({ + chartName, + onSaveChart, + onGoBack, + onChangeAggregation, + aggregation = true, + }) => { + const t = useI18NPrefix(`viz.workbench.header`); - return ( - <Wrapper> - {onGoBack && ( - <GoBack> - <LeftOutlined onClick={onGoBack} /> - </GoBack> - )} - <h1>{chartName}</h1> - <Space> - <Button type="primary" onClick={onSaveChart}> - {t('save')} - </Button> - </Space> - </Wrapper> - ); -}); + const getOverlays = () => { + return ( + <AggregationOperationMenu + defaultValue={aggregation} + onChangeAggregation={e => { + onChangeAggregation?.(e); + }} + ></AggregationOperationMenu> + ); + }; + + return ( + <Wrapper> + {onGoBack && ( + <GoBack> + <LeftOutlined onClick={onGoBack} /> + </GoBack> + )} + <h1>{chartName}</h1> + <Space> + <Button type="primary" onClick={onSaveChart}> + {t('save')} + </Button> + <Dropdown key="more" trigger={['click']} overlay={getOverlays()}> + <Button icon={<MoreOutlined />} /> + </Dropdown> + </Space> + </Wrapper> + ); + }, +); export default ChartHeaderPanel; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/components/AggregationOperationMenu.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/components/AggregationOperationMenu.tsx new file mode 100644 index 000000000..10861a40c --- /dev/null +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/components/AggregationOperationMenu.tsx @@ -0,0 +1,51 @@ +/** + * 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 { Menu, Modal, Switch } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; +import { FC, memo, useMemo } from 'react'; + +const AggregationOperationMenu: FC<{ + defaultValue: boolean; + onChangeAggregation: (value: boolean) => void; +}> = memo(({ defaultValue, onChangeAggregation }) => { + const checkedValue = useMemo(() => defaultValue, [defaultValue]); + const t = useI18NPrefix(`viz.workbench.header`); + + const onChange = value => { + Modal.confirm({ + icon: <></>, + content: t('aggregationSwitchTip'), + okText: checkedValue ? t('close') : t('open'), + // cancelText: t('close'), + onOk() { + onChangeAggregation(value); + }, + }); + }; + return ( + <Menu selectedKeys={[]}> + <Menu.Item key={0}> + {t('aggregationSwitch')}{' '} + <Switch checked={checkedValue} onChange={onChange} /> + </Menu.Item> + </Menu> + ); +}); + +export default AggregationOperationMenu; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartConfigPanel/ChartDataConfigPanel.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartConfigPanel/ChartDataConfigPanel.tsx index ac27df688..901d8ac5d 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartConfigPanel/ChartDataConfigPanel.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartConfigPanel/ChartDataConfigPanel.tsx @@ -21,9 +21,10 @@ import { ChartDataSectionConfig, ChartDataSectionType, } from 'app/types/ChartConfig'; -import { FC, memo } from 'react'; +import { FC, memo, useContext } from 'react'; import styled from 'styled-components/macro'; import { SPACE_XS } from 'styles/StyleConstants'; +import ChartAggregationContext from '../../../../contexts/ChartAggregationContext'; import PaletteDataConfig from '../ChartDataConfigSection'; const ChartDataConfigPanel: FC<{ @@ -36,6 +37,7 @@ const ChartDataConfigPanel: FC<{ }> = memo( ({ dataConfigs, onChange }) => { const translate = useI18NPrefix(`viz.palette.data`); + const { aggregation } = useContext(ChartAggregationContext); const getSectionComponent = (config, index) => { const props = { @@ -43,10 +45,12 @@ const ChartDataConfigPanel: FC<{ ancestors: [index], config, translate, + aggregation, onConfigChanged: (ancestors, config, needRefresh?: boolean) => { onChange?.(ancestors, config, needRefresh); }, }; + switch (props.config?.type) { case ChartDataSectionType.GROUP: return <PaletteDataConfig.GroupTypeSection {...props} />; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/AggregateTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/AggregateTypeSection.tsx index 232e8b911..0ffaa02b2 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/AggregateTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/AggregateTypeSection.tsx @@ -17,15 +17,15 @@ */ import { ChartDataSectionFieldActionType } from 'app/types/ChartConfig'; -import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { ChartDataConfigSectionProps } from 'app/types/ChartDataConfigSection'; +import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { FC, memo } from 'react'; import BaseDataConfigSection from './BaseDataConfigSection'; -import { dataConfigSectionComparer } from './utils'; +import { dataConfigSectionComparer, handleDefaultConfig } from './utils'; const AggregateTypeSection: FC<ChartDataConfigSectionProps> = memo( - ({ config, ...rest }) => { - const defaultConfig = Object.assign( + ({ config, aggregation, ...rest }) => { + let defaultConfig = Object.assign( { allowSameField: true, }, @@ -49,6 +49,11 @@ const AggregateTypeSection: FC<ChartDataConfigSectionProps> = memo( }, config, ); + + if (aggregation === false) { + defaultConfig = handleDefaultConfig(defaultConfig); + } + return <BaseDataConfigSection {...rest} config={defaultConfig} />; }, dataConfigSectionComparer, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/FilterTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/FilterTypeSection.tsx index 7f9c63348..384162e79 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/FilterTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/FilterTypeSection.tsx @@ -32,7 +32,13 @@ import BaseDataConfigSection from './BaseDataConfigSection'; import { dataConfigSectionComparer } from './utils'; const FilterTypeSection: FC<ChartDataConfigSectionProps> = memo( - ({ ancestors, config, translate = title => title, onConfigChanged }) => { + ({ + ancestors, + config, + translate = title => title, + onConfigChanged, + aggregation, + }) => { const [currentConfig, setCurrentConfig] = useState(config); const [originalConfig, setOriginalConfig] = useState(config); const [enableExtraAction] = useState(false); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/GroupTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/GroupTypeSection.tsx index 6e843da09..4c4e3a0e6 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/GroupTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/GroupTypeSection.tsx @@ -17,8 +17,8 @@ */ import { ChartDataSectionFieldActionType } from 'app/types/ChartConfig'; -import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { ChartDataConfigSectionProps } from 'app/types/ChartDataConfigSection'; +import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { FC, memo } from 'react'; import BaseDataConfigSection from './BaseDataConfigSection'; import { dataConfigSectionComparer } from './utils'; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/InfoTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/InfoTypeSection.tsx index b810e6941..887b6d9cd 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/InfoTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/InfoTypeSection.tsx @@ -17,15 +17,15 @@ */ import { ChartDataSectionFieldActionType } from 'app/types/ChartConfig'; -import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { ChartDataConfigSectionProps } from 'app/types/ChartDataConfigSection'; +import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { FC, memo } from 'react'; import BaseDataConfigSection from './BaseDataConfigSection'; -import { dataConfigSectionComparer } from './utils'; +import { dataConfigSectionComparer, handleDefaultConfig } from './utils'; const InfoTypeSection: FC<ChartDataConfigSectionProps> = memo( - ({ config, ...rest }) => { - const defaultConfig = Object.assign( + ({ config, aggregation, ...rest }) => { + let defaultConfig = Object.assign( { allowSameField: true, }, @@ -33,13 +33,18 @@ const InfoTypeSection: FC<ChartDataConfigSectionProps> = memo( actions: { [ChartDataViewFieldType.NUMERIC]: [ ChartDataSectionFieldActionType.Aggregate, - ChartDataSectionFieldActionType.Alias, ChartDataSectionFieldActionType.Format, + ChartDataSectionFieldActionType.Alias, ], }, }, config, ); + + if (aggregation === false) { + defaultConfig = handleDefaultConfig(defaultConfig); + } + return <BaseDataConfigSection {...rest} config={defaultConfig} />; }, dataConfigSectionComparer, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/MixedTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/MixedTypeSection.tsx index abf879f1a..d6589c118 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/MixedTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/MixedTypeSection.tsx @@ -21,15 +21,16 @@ import { ChartDataConfigSectionProps } from 'app/types/ChartDataConfigSection'; import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { FC, memo } from 'react'; import BaseDataConfigSection from './BaseDataConfigSection'; -import { dataConfigSectionComparer } from './utils'; +import { dataConfigSectionComparer, handleDefaultConfig } from './utils'; const MixedTypeSection: FC<ChartDataConfigSectionProps> = memo( - ({ config, ...rest }) => { - const defaultConfig = Object.assign( + ({ config, aggregation, ...rest }) => { + let defaultConfig = Object.assign( {}, { actions: { [ChartDataViewFieldType.NUMERIC]: [ + ChartDataSectionFieldActionType.Aggregate, ChartDataSectionFieldActionType.Alias, ChartDataSectionFieldActionType.Format, ChartDataSectionFieldActionType.Sortable, @@ -46,6 +47,11 @@ const MixedTypeSection: FC<ChartDataConfigSectionProps> = memo( }, config, ); + + if (aggregation === false) { + defaultConfig = handleDefaultConfig(defaultConfig); + } + return <BaseDataConfigSection {...rest} config={defaultConfig} />; }, dataConfigSectionComparer, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/SizeTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/SizeTypeSection.tsx index ff871bf01..c20c96a35 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/SizeTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/SizeTypeSection.tsx @@ -21,11 +21,11 @@ import { ChartDataConfigSectionProps } from 'app/types/ChartDataConfigSection'; import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { FC, memo } from 'react'; import BaseDataConfigSection from './BaseDataConfigSection'; -import { dataConfigSectionComparer } from './utils'; +import { dataConfigSectionComparer, handleDefaultConfig } from './utils'; const SizeTypeSection: FC<ChartDataConfigSectionProps> = memo( - ({ config, ...rest }) => { - const defaultConfig = Object.assign( + ({ config, aggregation, ...rest }) => { + let defaultConfig = Object.assign( {}, { actions: { @@ -38,6 +38,11 @@ const SizeTypeSection: FC<ChartDataConfigSectionProps> = memo( }, config, ); + + if (aggregation === false) { + defaultConfig = handleDefaultConfig(defaultConfig); + } + return <BaseDataConfigSection {...rest} config={defaultConfig} />; }, dataConfigSectionComparer, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/utils.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/utils.ts index 427f0a938..8df78060e 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/utils.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/utils.ts @@ -16,7 +16,10 @@ * limitations under the License. */ +import { ChartDataSectionFieldActionType } from 'app/types/ChartConfig'; import { ChartDataConfigSectionProps } from 'app/types/ChartDataConfigSection'; +import produce from 'immer'; +import { CloneValueDeep } from 'utils/object'; export function dataConfigSectionComparer( prevProps: ChartDataConfigSectionProps, @@ -24,9 +27,29 @@ export function dataConfigSectionComparer( ) { if ( prevProps.translate !== nextProps.translate || - prevProps.config !== nextProps.config + prevProps.config !== nextProps.config || + prevProps.aggregation !== nextProps.aggregation ) { return false; } return true; } + +export function handleDefaultConfig(defaultConfig): any { + const nextConfig = produce(defaultConfig, draft => { + let _actions = {}; + + draft.rows?.forEach((row, i) => { + draft.rows[i].aggregate = undefined; + }); + + for (let key in draft.actions) { + _actions[key] = draft.actions[key].filter( + v => v !== 'aggregate' && v !== 'aggregateLimit', + ); + } + + draft.actions = _actions; + }); + return nextConfig; +} diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx index 5915e3767..65679bc33 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx @@ -55,6 +55,7 @@ import { } from 'styles/StyleConstants'; import { ValueOf } from 'types'; import { v4 as uuidv4 } from 'uuid'; +import ChartAggregationContext from '../../../../contexts/ChartAggregationContext'; import ChartDataConfigSectionActionMenu from './ChartDataConfigSectionActionMenu'; import VizDraggableItem from './ChartDraggableElement'; @@ -76,6 +77,7 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = const [showModal, contextHolder] = useFieldActionModal({ i18nPrefix: 'viz.palette.data.enum.actionType', }); + const { aggregation } = useContext(ChartAggregationContext); const [{ isOver, canDrop }, drop] = useDrop( () => ({ @@ -156,6 +158,37 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = return { delete: needDelete }; }, canDrop: (item: ChartDataSectionField, monitor) => { + let items = Array.isArray(item) ? item : [item]; + + if (aggregation === false) { + let status = false; + let { type } = currentConfig; + + if ( + (type === 'color' || type === 'group') && + items.every(v => v.type === 'DATA' || v.type === 'STRING') + ) { + status = true; + } + + if ( + (type === 'aggregate' || type === 'size' || type === 'info') && + items.every(v => v.type === 'NUMERIC') + ) { + status = true; + } + + if (type === 'mixed') { + status = true; + } + + if (type === 'filter') { + status = true; + } + + return status; + } + if ( Array.isArray(item) && typeof currentConfig.actions === 'object' && @@ -182,7 +215,6 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = return true; } - let items = [item]; if ( monitor.getItemType() === CHART_DRAG_ELEMENT_TYPE.DATASET_GROUP_COLUMNS @@ -209,7 +241,8 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = if ( currentConfig?.type === ChartDataSectionType.AGGREGATE || currentConfig?.type === ChartDataSectionType.SIZE || - currentConfig?.type === ChartDataSectionType.INFO + currentConfig?.type === ChartDataSectionType.INFO || + currentConfig?.type === ChartDataSectionType.MIXED ) { if (currentConfig.disableAggregate) { return; @@ -305,7 +338,11 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = {currentConfig?.actions && ( <DownOutlined style={{ marginRight: '10px' }} /> )} - <span>{getColumnRenderName(columnConfig)}</span> + <span> + {aggregation + ? getColumnRenderName(columnConfig) + : columnConfig.colName} + </span> <div style={{ display: 'inline-block', marginLeft: '5px' }}> {enableActionsIcons(columnConfig)} </div> @@ -348,6 +385,7 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = dataset, dataView, modalSize, + aggregation, ); }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterAction/FilterAction.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterAction/FilterAction.tsx index d2c6156c5..eeb83212e 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterAction/FilterAction.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterAction/FilterAction.tsx @@ -30,26 +30,29 @@ const FilterAction: FC<{ dataset?: ChartDataset; dataView?: ChartDataView; dataConfig?: ChartDataSectionConfig; + aggregation?: boolean; onConfigChange: ( config: ChartDataSectionField, needRefresh?: boolean, ) => void; -}> = memo(({ config, dataset, dataView, dataConfig, onConfigChange }) => { - const handleFetchDataFromField = async fieldId => { - // TODO: tobe implement to get fields - return await Promise.resolve(['a', 'b', 'c'].map(f => `${fieldId}-${f}`)); - }; - - return ( - <FilterControllPanel - config={config} - dataset={dataset} - dataConfig={dataConfig} - dataView={dataView} - onConfigChange={onConfigChange} - fetchDataByField={handleFetchDataFromField} - /> - ); -}); +}> = memo( + ({ config, dataset, dataView, dataConfig, onConfigChange, aggregation }) => { + const handleFetchDataFromField = async fieldId => { + // TODO: tobe implement to get fields + return await Promise.resolve(['a', 'b', 'c'].map(f => `${fieldId}-${f}`)); + }; + return ( + <FilterControllPanel + aggregation={aggregation} + config={config} + dataset={dataset} + dataConfig={dataConfig} + dataView={dataView} + onConfigChange={onConfigChange} + fetchDataByField={handleFetchDataFromField} + /> + ); + }, +); export default FilterAction; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterControlPanel.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterControlPanel.tsx index 3e26b85bd..38954f059 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterControlPanel.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterControlPanel.tsx @@ -50,6 +50,7 @@ const FilterControllPanel: FC< dataset?: ChartDataset; dataView?: ChartDataView; dataConfig?: ChartDataSectionConfig; + aggregation?: boolean; onConfigChange: ( config: ChartDataSectionField, needRefresh?: boolean, @@ -63,6 +64,7 @@ const FilterControllPanel: FC< dataView, i18nPrefix, dataConfig, + aggregation = true, onConfigChange, fetchDataByField, }) => { @@ -220,7 +222,7 @@ const FilterControllPanel: FC< > <Input onChange={e => handleNameChange(e.target?.value)} /> </FormItemEx> - {config.category === ChartDataViewFieldCategory.Field && ( + {config.category === ChartDataViewFieldCategory.Field && aggregation && ( <FormItemEx {...formItemStyles} label={t('filterAggregate')} diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts index e59701932..46629b561 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts @@ -25,7 +25,6 @@ const config: ChartConfig = { key: 'mixed', required: true, type: 'mixed', - disableAggregate: true, }, { label: 'filter', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraphPanel.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraphPanel.tsx index 07c05fe42..e6d6f4455 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraphPanel.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraphPanel.tsx @@ -61,6 +61,7 @@ const ChartGraphPanel: FC<{ const handleChartChange = useCallback( chartId => () => { const chart = chartManager.getById(chartId); + if (!!chart) { onChartChange(chart); } diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartWorkbench/ChartWorkbench.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartWorkbench/ChartWorkbench.tsx index 83f5e6f35..dfc851997 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartWorkbench/ChartWorkbench.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartWorkbench/ChartWorkbench.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ +import ChartAggregationContext from 'app/pages/ChartWorkbenchPage/contexts/ChartAggregationContext'; import ChartDatasetContext from 'app/pages/ChartWorkbenchPage/contexts/ChartDatasetContext'; import ChartDataViewContext from 'app/pages/ChartWorkbenchPage/contexts/ChartDataViewContext'; import TimeConfigContext from 'app/pages/ChartWorkbenchPage/contexts/TimeConfigContext'; @@ -38,10 +39,12 @@ const ChartWorkbench: FC<{ dataview?: ChartDataView; chartConfig?: ChartConfig; chart?: Chart; + aggregation?: boolean; header?: { name?: string; onSaveChart?: () => void; onGoBack?: () => void; + onChangeAggregation?: (state: boolean) => void; }; onChartChange: (c: Chart) => void; onChartConfigChange: (type, payload) => void; @@ -52,6 +55,7 @@ const ChartWorkbench: FC<{ dataview, chartConfig, chart, + aggregation, header, onChartChange, onChartConfigChange, @@ -59,34 +63,37 @@ const ChartWorkbench: FC<{ }) => { const language = useSelector(languageSelector); const dateFormat = useSelector(dateFormatSelector); - return ( - <ChartDatasetContext.Provider value={{ dataset: dataset }}> - <ChartDataViewContext.Provider value={{ dataView: dataview }}> - <TimeConfigContext.Provider - value={{ locale: language, format: dateFormat }} - > - <StyledChartWorkbench> - {header && ( - <ChartHeaderPanel - chartName={header?.name} - onGoBack={header?.onGoBack} - onSaveChart={header?.onSaveChart} - /> - )} - <StyledChartOperationPanel> - <ChartOperationPanel - chart={chart} - chartConfig={chartConfig} - onChartChange={onChartChange} - onChartConfigChange={onChartConfigChange} - onDataViewChange={onDataViewChange} - /> - </StyledChartOperationPanel> - </StyledChartWorkbench> - </TimeConfigContext.Provider> - </ChartDataViewContext.Provider> - </ChartDatasetContext.Provider> + <ChartAggregationContext.Provider value={{ aggregation }}> + <ChartDatasetContext.Provider value={{ dataset: dataset }}> + <ChartDataViewContext.Provider value={{ dataView: dataview }}> + <TimeConfigContext.Provider + value={{ locale: language, format: dateFormat }} + > + <StyledChartWorkbench> + {header && ( + <ChartHeaderPanel + chartName={header?.name} + onGoBack={header?.onGoBack} + onSaveChart={header?.onSaveChart} + onChangeAggregation={header?.onChangeAggregation} + aggregation={aggregation} + /> + )} + <StyledChartOperationPanel> + <ChartOperationPanel + chart={chart} + chartConfig={chartConfig} + onChartChange={onChartChange} + onChartConfigChange={onChartConfigChange} + onDataViewChange={onDataViewChange} + /> + </StyledChartOperationPanel> + </StyledChartWorkbench> + </TimeConfigContext.Provider> + </ChartDataViewContext.Provider> + </ChartDatasetContext.Provider> + </ChartAggregationContext.Provider> ); }, (prev, next) => diff --git a/frontend/src/app/pages/ChartWorkbenchPage/contexts/ChartAggregationContext.ts b/frontend/src/app/pages/ChartWorkbenchPage/contexts/ChartAggregationContext.ts new file mode 100644 index 000000000..42f99f573 --- /dev/null +++ b/frontend/src/app/pages/ChartWorkbenchPage/contexts/ChartAggregationContext.ts @@ -0,0 +1,27 @@ +/** + * 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 { createContext } from 'react'; + +const ChartAggregationContext = createContext<{ + aggregation: boolean | undefined; +}>({ + aggregation: true, +}); + +export default ChartAggregationContext; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts index 2bb4798d2..a458ebe95 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts @@ -96,7 +96,7 @@ export class ChartDataRequestBuilder { pageInfo: ChartDatasetPageInfo; dataView: ChartDataView; script: boolean; - + aggregation?: boolean; private extraSorters: ChartRequest['orders'] = []; constructor( @@ -105,12 +105,14 @@ export class ChartDataRequestBuilder { settingConfigs?: ChartStyleSectionConfig[], pageInfo?: ChartDatasetPageInfo, script?: boolean, + aggregation?: boolean, ) { this.dataView = dataView; this.chartDataConfigs = dataConfigs || []; this.charSettingConfigs = settingConfigs || []; this.pageInfo = pageInfo || {}; this.script = script || false; + this.aggregation = aggregation; } private buildAggregators() { @@ -119,6 +121,9 @@ export class ChartDataRequestBuilder { if (!cur.rows) { return acc; } + if (this.aggregation === false) { + return acc; + } if ( cur.type === ChartDataSectionType.AGGREGATE || cur.type === ChartDataSectionType.SIZE || @@ -320,6 +325,20 @@ export class ChartDataRequestBuilder { if (!cur.rows) { return acc; } + + if (this.aggregation === false) { + if ( + cur.type === ChartDataSectionType.GROUP || + cur.type === ChartDataSectionType.COLOR || + cur.type === ChartDataSectionType.AGGREGATE || + cur.type === ChartDataSectionType.SIZE || + cur.type === ChartDataSectionType.INFO || + cur.type === ChartDataSectionType.MIXED + ) { + return acc.concat(cur.rows); + } + } + if (cur.type === ChartDataSectionType.MIXED) { return acc.concat(cur.rows); } @@ -362,6 +381,9 @@ export class ChartDataRequestBuilder { if (!cur.rows) { return acc; } + if (this.aggregation === false) { + return acc; + } if ( cur.type === ChartDataSectionType.GROUP || cur.type === ChartDataSectionType.COLOR diff --git a/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts b/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts index eba6b854c..e9da680fb 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts @@ -72,6 +72,7 @@ export type BackendChartConfig = { chartConfig: string; chartGraphId: string; computedFields: ChartDataViewMeta[]; + aggregation: boolean; }; export type WorkbenchState = { @@ -255,9 +256,11 @@ export const refreshDatasetAction = createAsyncThunk( try { const state = thunkAPI.getState() as any; const workbenchState = state.workbench as typeof initState; + if (!workbenchState.currentDataView?.id) { return; } + const builder = new ChartDataRequestBuilder( { ...workbenchState.currentDataView, @@ -266,6 +269,7 @@ export const refreshDatasetAction = createAsyncThunk( workbenchState.chartConfig?.settings, arg?.pageInfo, true, + workbenchState.backendChart?.config?.aggregation, ); const requestParams = builder .addExtraSorters(arg?.sorter ? [arg?.sorter as any] : []) @@ -328,7 +332,7 @@ export const fetchChartAction = createAsyncThunk( export const updateChartAction = createAsyncThunk( 'workbench/updateChartAction', async ( - arg: { name; viewId; graphId; chartId; index; parentId }, + arg: { name; viewId; graphId; chartId; index; parentId; aggregation }, thunkAPI, ) => { try { @@ -336,6 +340,7 @@ export const updateChartAction = createAsyncThunk( const workbenchState = state.workbench as typeof initState; const stringConfig = JSON.stringify({ + aggregation: arg.aggregation, chartConfig: workbenchState.chartConfig, chartGraphId: arg.graphId, computedFields: workbenchState.currentDataView?.computedFields || [], @@ -436,6 +441,7 @@ const workbenchSlice = createSlice({ return state; } }; + state.chartConfig = chartConfigReducer(state.chartConfig!, { type: action.payload.type, payload: action.payload.payload, @@ -450,6 +456,11 @@ const workbenchSlice = createSlice({ computedFields: action.payload, } as ChartDataView; }, + updateChartAggregation: (state, action: PayloadAction<boolean>) => { + if (state.backendChart) { + state.backendChart.config.aggregation = action.payload; + } + }, resetWorkbenchState: (state, action) => { return initState; }, @@ -485,10 +496,13 @@ const workbenchSlice = createSlice({ return; } - const backendChartConfig = + let backendChartConfig = typeof payload.config === 'string' ? JSON.parse(payload.config) : CloneValueDeep(payload.config); + backendChartConfig = backendChartConfig || {}; + backendChartConfig.aggregation = + backendChartConfig?.aggregation === undefined ? true : false; state.backendChart = { ...payload, config: backendChartConfig, 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 2591867e3..507e3f6bd 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/Board/slice/types.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/Board/slice/types.ts @@ -404,6 +404,7 @@ export interface DataChart { status: any; } export interface DataChartConfig { + aggregation: boolean | undefined; chartConfig: ChartConfig; chartGraphId: string; computedFields: any[]; 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 56f84d82d..7188b3be6 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 @@ -264,7 +264,7 @@ export const closeLinkageAction = (widget: Widget) => (dispatch, getState) => { export const addVariablesToBoard = (variables: Variable[]) => (dispatch, getState) => { - if (!variables.length) return; + if (!variables?.length) return; const addedViewId = variables[0].viewId; if (!addedViewId) return; diff --git a/frontend/src/app/pages/DashBoardPage/utils/index.ts b/frontend/src/app/pages/DashBoardPage/utils/index.ts index 1e0ca0e69..e6e4578c8 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/index.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/index.ts @@ -84,6 +84,9 @@ export const getChartDataRequestBuilder = (dataChart: DataChart) => { } as any, dataChart?.config?.chartConfig?.datas, dataChart?.config?.chartConfig?.settings, + {}, + false, + dataChart?.config?.aggregation, ); return builder; }; @@ -391,10 +394,12 @@ export const getChartWidgetRequestParams = (obj: { return null; } const chartDataView = viewMap[dataChart?.viewId]; + if (!chartDataView) { errorHandle(`can\`t find View ${dataChart?.viewId}`); return null; } + const builder = getChartDataRequestBuilder(dataChart); let requestParams = builder .addExtraSorters((option?.sorters as any) || []) 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 26ad7b905..48a7fe453 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreviewBoard.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreviewBoard.tsx @@ -191,6 +191,7 @@ const ChartPreviewBoard: FC<{ if (!chartPreview) { return; } + const builder = new ChartDataRequestBuilder( { id: chartPreview?.backendChart?.viewId, @@ -199,6 +200,9 @@ const ChartPreviewBoard: FC<{ } as any, chartPreview?.chartConfig?.datas, chartPreview?.chartConfig?.settings, + {}, + false, + chartPreview?.backendChart?.config?.aggregation, ); dispatch( makeDownloadDataTask({ diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/slice/thunks.ts b/frontend/src/app/pages/MainPage/pages/VizPage/slice/thunks.ts index f046a10d7..08947d104 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/slice/thunks.ts +++ b/frontend/src/app/pages/MainPage/pages/VizPage/slice/thunks.ts @@ -319,6 +319,8 @@ export const fetchDataSetByPreviewChartAction = createAsyncThunk( arg.chartPreview?.chartConfig?.datas, arg.chartPreview?.chartConfig?.settings, arg.pageInfo, + false, + arg.chartPreview?.backendChart?.config?.aggregation, ); const response = await request({ method: 'POST', diff --git a/frontend/src/app/pages/SharePage/ChartPreviewBoardForShare.tsx b/frontend/src/app/pages/SharePage/ChartPreviewBoardForShare.tsx index d8d5f7298..65bffa946 100644 --- a/frontend/src/app/pages/SharePage/ChartPreviewBoardForShare.tsx +++ b/frontend/src/app/pages/SharePage/ChartPreviewBoardForShare.tsx @@ -131,6 +131,9 @@ const ChartPreviewBoardForShare: FC<{ } as any, chartPreview?.chartConfig?.datas, chartPreview?.chartConfig?.settings, + {}, + false, + chartPreview?.backendChart?.config?.aggregation, ); const downloadParams = [builder.build()]; const fileName = chartPreview?.backendChart?.name || 'chart'; diff --git a/frontend/src/app/pages/SharePage/slice/thunks.ts b/frontend/src/app/pages/SharePage/slice/thunks.ts index 6948c6f9c..5480eccc9 100644 --- a/frontend/src/app/pages/SharePage/slice/thunks.ts +++ b/frontend/src/app/pages/SharePage/slice/thunks.ts @@ -142,6 +142,8 @@ export const fetchShareDataSetByPreviewChartAction = createAsyncThunk( args.preview?.chartConfig?.datas, args.preview?.chartConfig?.settings, args.pageInfo, + false, + args.preview?.backendChart?.config?.aggregation, ); const response = await request({ method: 'POST', diff --git a/frontend/src/app/types/ChartDataConfigSection.ts b/frontend/src/app/types/ChartDataConfigSection.ts index fe54f5a83..bec5a2047 100644 --- a/frontend/src/app/types/ChartDataConfigSection.ts +++ b/frontend/src/app/types/ChartDataConfigSection.ts @@ -28,6 +28,7 @@ export interface ChartDataConfigSectionProps { category?: Lowercase<keyof typeof ChartDataViewFieldCategory>; extra?: () => ReactNode; translate?: (title: string) => string; + aggregation?: boolean; onConfigChanged: ( ancestors: number[], config: ChartDataSectionConfig, diff --git a/frontend/src/app/utils/mutation.ts b/frontend/src/app/utils/mutation.ts index 36db26d08..1f941a5c4 100644 --- a/frontend/src/app/utils/mutation.ts +++ b/frontend/src/app/utils/mutation.ts @@ -58,7 +58,6 @@ export function updateCollectionByAction<T extends ChartStyleSectionConfig>( ) { const value = action.value; const keys = [...action.ancestors]; - const nextState = produce(base, draft => { const index = keys.shift() as number; if (index !== undefined) { diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index e50c2022c..0fa9276b9 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -37,7 +37,7 @@ "newPassword": "新密码", "confirmPassword": "确定新密码", "success": "修改成功", - "save":"保存" + "save": "保存" }, "switchLanguage": { "title": "切换语言" @@ -201,6 +201,10 @@ "save": "保存", "saveToDashboard": "保存到仪表盘", "login": "登陆", + "aggregationSwitch": "聚合开关", + "aggregationSwitchTip": "开启/关闭聚合会清空全部图表配置,确认开启/关闭?", + "open": "开启", + "close": "关闭", "lang": { "zh": "中文", "en": "英文" @@ -470,4 +474,4 @@ "cancel": "取消" } } -} \ No newline at end of file +} diff --git a/frontend/src/utils/utils.ts b/frontend/src/utils/utils.ts index a51096634..df9ca9dcd 100644 --- a/frontend/src/utils/utils.ts +++ b/frontend/src/utils/utils.ts @@ -180,7 +180,7 @@ export const onDropTreeFn = ({ info, treeData, callback }) => { } else { //中间 if (!dropArr[dropIndex].index && !dropArr[dropIndex + 1].index) { - index = dropArr[dropArr.length-1].index + 1; + index = dropArr[dropArr.length - 1].index + 1; } else { index = (dropArr[dropIndex].index + dropArr[dropIndex + 1].index) / 2; } From 157e17bce75a3b51f936d27ec74b983a7769b9dd Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Mon, 27 Dec 2021 13:14:38 +0800 Subject: [PATCH 229/348] chore: adjust widget toolbar icon style --- .../components/WidgetToolBar/index.tsx | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/index.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/index.tsx index f2c3829c7..5ad62c426 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/index.tsx @@ -22,7 +22,7 @@ import { SyncOutlined, WarningTwoTone, } from '@ant-design/icons'; -import { Space, Tooltip } from 'antd'; +import { Button, Space, Tooltip } from 'antd'; import React, { FC, useContext } from 'react'; import styled from 'styled-components'; import { ERROR, PRIMARY } from 'styles/StyleConstants'; @@ -51,7 +51,10 @@ const WidgetToolBar: FC<WidgetToolBarProps> = () => { if (!showTypes.includes(widgetType)) return null; return rendered ? null : ( <Tooltip title="等待加载"> - <ClockCircleOutlined style={{ color: PRIMARY }} /> + <Button + icon={<ClockCircleOutlined style={{ color: PRIMARY }} />} + type="link" + /> </Tooltip> ); }; @@ -59,7 +62,12 @@ const WidgetToolBar: FC<WidgetToolBarProps> = () => { const widgetType = widget.config.type; const showTypes: WidgetType[] = ['chart', 'controller']; if (!showTypes.includes(widgetType)) return null; - return loading ? <SyncOutlined spin style={{ color: PRIMARY }} /> : null; + return loading ? ( + <Button + icon={<SyncOutlined spin style={{ color: PRIMARY }} />} + type="link" + /> + ) : null; }; const linkageIcon = () => { if (inLinking) { @@ -74,7 +82,10 @@ const WidgetToolBar: FC<WidgetToolBarProps> = () => { } else { return widget.config?.linkageConfig?.open ? ( <Tooltip title="点击图表可联动"> - <LinkOutlined style={{ color: PRIMARY }} /> + <Button + icon={<LinkOutlined style={{ color: PRIMARY }} />} + type="link" + /> </Tooltip> ) : null; } @@ -93,7 +104,10 @@ const WidgetToolBar: FC<WidgetToolBarProps> = () => { }; return ( <Tooltip title={renderTitle(errInfo)}> - <WarningTwoTone twoToneColor={ERROR} /> + <StyledErrorIcon + icon={<WarningTwoTone twoToneColor={ERROR} />} + type="link" + /> </Tooltip> ); }; @@ -108,7 +122,7 @@ const WidgetToolBar: FC<WidgetToolBarProps> = () => { return ( <StyleWrap onClick={ssp} className="widget-tool-bar"> - <Space> + <Space size={0}> {renderErrorIcon(errInfo)} {renderedIcon()} {loadingIcon()} @@ -132,3 +146,12 @@ const StyleWrap = styled.div` visibility: hidden; } `; + +const StyledErrorIcon = styled(Button)` + background: ${p => p.theme.componentBackground}; + + &:hover, + &:focus { + background: ${p => p.theme.componentBackground}; + } +`; From 0e9cdbba97704fc6913ba13f7bd0a0163cca08ce Mon Sep 17 00:00:00 2001 From: "jin.gao" <jin.gao@mobilemd.cn> Date: Mon, 27 Dec 2021 15:22:07 +0800 Subject: [PATCH 230/348] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dtable=E8=B7=B3?= =?UTF-8?q?=E8=BD=AC=E8=81=94=E5=8A=A8css=E6=A0=B7=E5=BC=8F=E6=9C=AA?= =?UTF-8?q?=E8=BF=9B=E8=A1=8Copen=E5=88=A4=E6=96=AD=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WidgetCore/DataChartWidget/index.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx index 4fad46d09..d6c2fef94 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx @@ -88,10 +88,17 @@ export const DataChartWidget: React.FC<DataChartWidgetProps> = memo(() => { }, [chartClick, dataChart]); const widgetSpecialConfig = useMemo(() => { - const linkFields = widget?.relations - .filter(re => re.config.type === 'widgetToWidget') - .map(item => item.config.widgetToWidget?.triggerColumn); - const jumpField = widget?.config.jumpConfig?.field?.jumpFieldName; + let linkFields: string[] = []; + let jumpField: string = ''; + const { jumpConfig, linkageConfig } = widget.config; + if (linkageConfig?.open) { + linkFields = widget?.relations + .filter(re => re.config.type === 'widgetToWidget') + .map(item => item.config.widgetToWidget?.triggerColumn as string); + } + if (jumpConfig?.open) { + jumpField = jumpConfig?.field?.jumpFieldName as string; + } return { linkFields, From c663b8fb6f11d35d1d9659f09833a271e5732649 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Mon, 27 Dec 2021 19:51:56 +0800 Subject: [PATCH 231/348] refactor(chart): optimise chart onResize event --- .../ChartOperationPanel.tsx | 7 + .../BasicTableChart/BasicTableChart.tsx | 48 ++--- .../FenZuTableChart/FenZuTableChart.tsx | 4 +- .../ChartPresentPanel/ChartPresentPanel.tsx | 178 +++++++++--------- .../components/ChartPresentWrapper.tsx | 68 +++++-- .../ChartIFrameContainerDispatcher.tsx | 5 +- frontend/src/app/utils/chartHelper.ts | 30 +-- 7 files changed, 184 insertions(+), 156 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/ChartOperationPanel.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/ChartOperationPanel.tsx index e6b75cba2..1ccf37347 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/ChartOperationPanel.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/ChartOperationPanel.tsx @@ -51,6 +51,7 @@ const ChartOperationPanel: FC<{ const [layout, setLayout] = useState<Model>(() => Model.fromJson(layoutCnofig), ); + const layoutFactory = node => { var component = node.getComponent(); if (component === LayoutComponentType.VIEW) { @@ -72,6 +73,12 @@ const ChartOperationPanel: FC<{ if (component === LayoutComponentType.PRESENT) { return ( <ChartPresentWrapper + containerHeight={ + layout.getNodeById('present-wrapper').getRect().height + } + containerWidth={ + layout.getNodeById('present-wrapper').getRect().width + } chart={chart} dataset={dataset} chartConfig={chartConfig} diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx index d6209c393..aff6ffa4d 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx @@ -46,7 +46,8 @@ class BasicTableChart extends ReactChart { dataColumnWidths = {}; tablePadding = 16; tableCellBorder = 1; - tableOptions = { dataset: {}, config: {} }; + cachedAntTableOptions = {}; + cachedDatartConfig: ChartConfig = {}; showSummaryRow = false; rowNumberUniqKey = `@datart@rowNumberKey`; @@ -66,26 +67,33 @@ class BasicTableChart extends ReactChart { } onUpdated(options, context): void { - this.tableOptions = options; - if (!this.isMatchRequirement(options.config)) { this.adapter?.unmount(); return; } - this.adapter?.updated( - this.getOptions( - context, - options.dataset, - options.config, - options.widgetSpecialConfig, - ), + const tableOptions = this.getOptions( context, + options.dataset, + options.config, + options.widgetSpecialConfig, ); + this.cachedAntTableOptions = tableOptions; + this.cachedDatartConfig = options.config; + this.adapter?.updated(tableOptions, context); } public onResize(options, context?): void { - this.onUpdated(this.tableOptions, context); + this.adapter?.updated( + Object.assign(this.cachedAntTableOptions, { + ...this.getAntdTableStyleOptions( + this.cachedDatartConfig?.styles, + this.cachedDatartConfig?.settings!, + context?.height, + ), + }), + context, + ); } getOptions( @@ -152,10 +160,8 @@ class BasicTableChart extends ReactChart { components: this.getTableComponents(styleConfigs, widgetSpecialConfig), ...this.getAntdTableStyleOptions( styleConfigs, - dataset, - null, + settingConfigs, context?.height, - tablePagination, ), onChange: (pagination, filters, sorter, extra) => { if (extra?.action === 'sort' || extra?.action === 'paginate') { @@ -612,13 +618,11 @@ class BasicTableChart extends ReactChart { }; } - getAntdTableStyleOptions( - styleConfigs, - dataset: ChartDataset, - width, - height, - tablePagination, - ) { + getAntdTableStyleOptions(styleConfigs?, settingConfigs?, height?) { + const enablePaging = this.getStyleValue(settingConfigs, [ + 'paging', + 'enablePaging', + ]); const showTableBorder = this.getStyleValue(styleConfigs, [ 'style', 'enableBorder', @@ -661,7 +665,7 @@ class BasicTableChart extends ReactChart { (this.showSummaryRow ? SUMMRAY_ROW_HEIGHT[tableSize] : 0) - HEADER_HEIGHT[tableSize] * _getMaxHeaderHierarchy(tableHeaderStyles) - - (tablePagination ? PAGINATION_HEIGHT[tableSize] : 0), + (enablePaging ? PAGINATION_HEIGHT[tableSize] : 0), }), bordered: !!showTableBorder, size: tableSize, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx index ce3ea754f..90a648beb 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx @@ -78,10 +78,8 @@ class FenZuTableChart extends BasicTableChart { components: this.getTableComponents(styleConfigs, widgetSpecialConfig), ...this.getAntdTableStyleOptions( styleConfigs, - dataset, - null, + settingConfigs, context?.height, - tablePagination, ), onChange: () => {}, }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartPresentPanel/ChartPresentPanel.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartPresentPanel/ChartPresentPanel.tsx index 388e49973..7e1de891e 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartPresentPanel/ChartPresentPanel.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartPresentPanel/ChartPresentPanel.tsx @@ -19,14 +19,14 @@ import { Table } from 'antd'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; import useMount from 'app/hooks/useMount'; -import useResizeObserver from 'app/hooks/useResizeObserver'; import ChartTools from 'app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools'; import Chart from 'app/pages/ChartWorkbenchPage/models/Chart'; import { ChartConfig } from 'app/types/ChartConfig'; import ChartDataset from 'app/types/ChartDataset'; -import { FC, memo, useRef, useState } from 'react'; +import { FC, memo, useState } from 'react'; import styled from 'styled-components/macro'; import { BORDER_RADIUS, SPACE_LG, SPACE_MD } from 'styles/StyleConstants'; +import { Debugger } from 'utils/debugger'; import Chart404Graph from './components/Chart404Graph'; import ChartTypeSelector, { ChartPresentType, @@ -35,106 +35,104 @@ import ChartTypeSelector, { const CHART_TYPE_SELECTOR_HEIGHT_OFFSET = 50; const ChartPresentPanel: FC<{ + containerHeight?: number; + containerWidth?: number; chart?: Chart; dataset?: ChartDataset; chartConfig?: ChartConfig; -}> = memo(({ chart, dataset, chartConfig }) => { - const translate = useI18NPrefix(`viz.palette.present`); - const [chartType, setChartType] = useState(ChartPresentType.GRAPH); - const panelRef = useRef<{ offsetWidth; offsetHeight }>(null); - const [chartDispatcher] = useState(() => - ChartTools.ChartIFrameContainerDispatcher.instance(), - ); - - useMount(undefined, () => { - console.debug('Disposing - Chart Container'); - ChartTools.ChartIFrameContainerDispatcher.dispose(); - }); - - const { ref: graphRef } = useResizeObserver<HTMLDivElement>({ - refreshMode: 'debounce', - refreshRate: 10, - }); - - const renderGraph = (containerId, chart?: Chart, chartConfig?, style?) => { - if (!chart?.isMatchRequirement(chartConfig)) { - return <Chart404Graph chart={chart} chartConfig={chartConfig} />; - } - return ( - !!chart && - chartDispatcher.getContainers( - containerId, - chart, - dataset, - chartConfig!, - style, - ) - ); - }; - - const renderReusableChartContainer = () => { - const style = { - width: panelRef.current?.offsetWidth, - height: - (panelRef.current?.offsetHeight || CHART_TYPE_SELECTOR_HEIGHT_OFFSET) - - CHART_TYPE_SELECTOR_HEIGHT_OFFSET, // TODO(Stephen): calculate when change chart +}> = memo( + ({ containerHeight, containerWidth, chart, dataset, chartConfig }) => { + const translate = useI18NPrefix(`viz.palette.present`); + const chartDispatcher = + ChartTools.ChartIFrameContainerDispatcher.instance(); + const [chartType, setChartType] = useState(ChartPresentType.GRAPH); + + useMount(undefined, () => { + Debugger.instance.measure(`ChartPresentPanel | Dispose Event`, () => { + ChartTools.ChartIFrameContainerDispatcher.dispose(); + }); + }); + + const renderGraph = (containerId, chart?: Chart, chartConfig?, style?) => { + if (!chart?.isMatchRequirement(chartConfig)) { + return <Chart404Graph chart={chart} chartConfig={chartConfig} />; + } + return ( + !!chart && + chartDispatcher.getContainers( + containerId, + chart, + dataset, + chartConfig!, + style, + ) + ); }; - const containerId = chart?.isISOContainer - ? (chart?.isISOContainer as string) - : 'container-1'; + const renderReusableChartContainer = () => { + const style = { + width: containerWidth, + height: + (containerHeight || CHART_TYPE_SELECTOR_HEIGHT_OFFSET) - + CHART_TYPE_SELECTOR_HEIGHT_OFFSET, + }; + + const containerId = chart?.isISOContainer + ? (chart?.isISOContainer as string) + : 'container-1'; + + return ( + <> + {ChartPresentType.GRAPH === chartType && ( + <div style={{ height: '100%' }}> + {renderGraph(containerId, chart, chartConfig, style)} + </div> + )} + {ChartPresentType.RAW === chartType && ( + <TableWrapper> + <Table + size="small" + dataSource={dataset?.rows} + columns={dataset?.columns?.map((col, index) => ({ + key: col.name, + title: col.name, + dataIndex: index, + }))} + bordered + /> + </TableWrapper> + )} + {ChartPresentType.SQL === chartType && ( + <SqlWrapper> + <code>{dataset?.script}</code> + </SqlWrapper> + )} + </> + ); + }; - return ( - <> - {ChartPresentType.GRAPH === chartType && ( - <div style={{ height: '100%' }} ref={graphRef}> - {renderGraph(containerId, chart, chartConfig, style)} - </div> - )} - {ChartPresentType.RAW === chartType && ( - <TableWrapper> - <Table - size="small" - dataSource={dataset?.rows} - columns={dataset?.columns?.map((col, index) => ({ - key: col.name, - title: col.name, - dataIndex: index, - }))} - bordered - /> - </TableWrapper> - )} - {ChartPresentType.SQL === chartType && ( - <SqlWrapper> - <code>{dataset?.script}</code> - </SqlWrapper> - )} - </> - ); - }; + const renderChartTypeSelector = () => { + return ( + <ChartTypeSelector + type={chartType} + onChange={setChartType} + translate={translate} + /> + ); + }; - const renderChartTypeSelector = () => { return ( - <ChartTypeSelector - type={chartType} - onChange={setChartType} - translate={translate} - /> + <StyledChartPresentPanel> + {renderChartTypeSelector()} + {renderReusableChartContainer()} + </StyledChartPresentPanel> ); - }; - - return ( - <StyledChartPresentPanel ref={panelRef}> - {renderChartTypeSelector()} - {renderReusableChartContainer()} - </StyledChartPresentPanel> - ); -}); + }, +); export default ChartPresentPanel; -const StyledChartPresentPanel = styled.div<{ ref }>` +const StyledChartPresentPanel = styled.div` display: flex; flex: 1; flex-direction: column; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartPresentWrapper.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartPresentWrapper.tsx index b1276e398..86d98c7b5 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartPresentWrapper.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartPresentWrapper.tsx @@ -16,43 +16,73 @@ * limitations under the License. */ +import useResizeObserver from 'app/hooks/useResizeObserver'; import Chart from 'app/pages/ChartWorkbenchPage/models/Chart'; import { ChartConfig } from 'app/types/ChartConfig'; import ChartDataset from 'app/types/ChartDataset'; -import { FC } from 'react'; +import { FC, memo, useMemo } from 'react'; import styled from 'styled-components/macro'; import { SPACE_MD } from 'styles/StyleConstants'; import ChartGraphPanel from './ChartGraphPanel'; import ChartPresentPanel from './ChartPresentPanel'; const ChartPresentWrapper: FC<{ + containerHeight?: number; + containerWidth?: number; chart?: Chart; dataset?: ChartDataset; chartConfig?: ChartConfig; onChartChange: (c: Chart) => void; -}> = ({ chart, dataset, chartConfig, onChartChange }) => { - return ( - <StyledChartPresentWrapper> - <ChartGraphPanel - chart={chart} - chartConfig={chartConfig} - onChartChange={onChartChange} - /> - <ChartPresentPanel - chart={chart} - dataset={dataset} - chartConfig={chartConfig} - /> - </StyledChartPresentWrapper> - ); -}; +}> = memo( + ({ + containerHeight, + containerWidth, + chart, + dataset, + chartConfig, + onChartChange, + }) => { + const { ref: ChartGraphPanelRef } = useResizeObserver<any>({ + refreshMode: 'debounce', + refreshRate: 500, + }); + + const borderWidth = useMemo(() => { + return +SPACE_MD.replace('px', ''); + }, []); + + return ( + <StyledChartPresentWrapper borderWidth={borderWidth}> + <div ref={ChartGraphPanelRef}> + <ChartGraphPanel + chart={chart} + chartConfig={chartConfig} + onChartChange={onChartChange} + /> + </div> + <ChartPresentPanel + containerHeight={ + (containerHeight || 0) - + borderWidth - + (ChartGraphPanelRef?.current?.offsetHeight || 0) + } + containerWidth={(containerWidth || 0) - borderWidth} + chart={chart} + dataset={dataset} + chartConfig={chartConfig} + /> + </StyledChartPresentWrapper> + ); + }, +); export default ChartPresentWrapper; -const StyledChartPresentWrapper = styled.div` +const StyledChartPresentWrapper = styled.div<{ borderWidth }>` display: flex; flex-direction: column; height: 100%; - padding: ${SPACE_MD} ${SPACE_MD} ${SPACE_MD} 0; + padding: ${p => p.borderWidth}px ${p => p.borderWidth}px + ${p => p.borderWidth}px 0; background-color: ${p => p.theme.bodyBackground}; `; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx index 06a56197f..106845458 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx @@ -29,6 +29,7 @@ class ChartIFrameContainerDispatcher { private currentContainerId = DEFAULT_CONTAINER_ID; private chartContainerMap = new Map<string, Function>(); private chartMetadataMap = new Map<string, [Chart, any, any]>(); + private editorEnv = { env: 'workbench' }; public static instance(): ChartIFrameContainerDispatcher { if (!this.dispatcher) { @@ -87,7 +88,7 @@ class ChartIFrameContainerDispatcher { containerId={containerId} width={style?.width} height={style?.height} - widgetSpecialConfig={{ env: 'workbench' }} + widgetSpecialConfig={this.editorEnv} /> </div> ); @@ -108,7 +109,7 @@ class ChartIFrameContainerDispatcher { ...style, transform: 'translate(-9999px, -9999px)', position: 'absolute', - }; /* TODO: visibilty: 'collapse' */ + }; } } diff --git a/frontend/src/app/utils/chartHelper.ts b/frontend/src/app/utils/chartHelper.ts index 2c1943270..66e8fbc8f 100644 --- a/frontend/src/app/utils/chartHelper.ts +++ b/frontend/src/app/utils/chartHelper.ts @@ -408,19 +408,23 @@ export function transformToObjectArray( if (!columns || !metas) { return []; } - return columns.map((col, index) => { + + const result: any[] = Array.apply(null, Array(columns.length)); + for (let j = 0; j < result.length; j++) { let objCol = { - id: index, + id: j, }; for (let i = 0; i < metas.length; i++) { const key = metas?.[i]?.name; if (!!key) { - objCol[key] = col[i]; + objCol[key] = columns[j][i]; } } - return objCol; - }); + result[j] = objCol; + } + return result; } + // TODO delete this function #migration export function transfromToObjectArray( columns?: string[][], @@ -429,21 +433,7 @@ export function transfromToObjectArray( console.warn( 'This method `transfromToObjectArray` will be deprecated and can be replaced by `transformToObjectArray`', ); - if (!columns || !metas) { - return []; - } - return columns.map((col, index) => { - let objCol = { - id: index, - }; - for (let i = 0; i < metas.length; i++) { - const key = metas?.[i]?.name; - if (!!key) { - objCol[key] = col[i]; - } - } - return objCol; - }); + return transformToObjectArray(columns, metas); } export function getValueByColumnKey(col?: { aggregate?; colName: string }) { From 700f59e04c00cb7be5f953c051f3b1e1a14ee70a Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Tue, 28 Dec 2021 10:27:38 +0800 Subject: [PATCH 232/348] chore: ByReference lodash --- frontend/src/app/migration/alpha3.ts | 2 +- .../components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx | 2 +- .../components/BoardProvider/BoardActionProvider.tsx | 2 +- .../pages/BoardEditor/components/SlideSetting/BoardSetting.tsx | 2 +- .../pages/BoardEditor/components/SlideSetting/WidgetSetting.tsx | 2 +- frontend/src/app/utils/number.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/app/migration/alpha3.ts b/frontend/src/app/migration/alpha3.ts index e58203885..d8b809c68 100644 --- a/frontend/src/app/migration/alpha3.ts +++ b/frontend/src/app/migration/alpha3.ts @@ -17,7 +17,7 @@ */ import { ChartConfig } from 'app/types/ChartConfig'; -import { isUndefined } from 'lodash'; +import isUndefined from 'lodash/isUndefined'; export const hasWrongDimensionName = (config?: ChartConfig) => { if (!config) { diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx index c566059a0..fad73fee6 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/BasicFunnelChart.tsx @@ -34,7 +34,7 @@ import { } from 'app/utils/chartHelper'; import { toFormattedValue } from 'app/utils/number'; import { init } from 'echarts'; -import { isEmpty } from 'lodash'; +import isEmpty from 'lodash/isEmpty'; import Config from './config'; class BasicFunnelChart extends Chart { diff --git a/frontend/src/app/pages/DashBoardPage/components/BoardProvider/BoardActionProvider.tsx b/frontend/src/app/pages/DashBoardPage/components/BoardProvider/BoardActionProvider.tsx index ff54fb477..5a3763d59 100644 --- a/frontend/src/app/pages/DashBoardPage/components/BoardProvider/BoardActionProvider.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/BoardProvider/BoardActionProvider.tsx @@ -18,7 +18,7 @@ import { PageInfo } from 'app/pages/MainPage/pages/ViewPage/slice/types'; import { generateShareLinkAsync } from 'app/utils/fetch'; -import { debounce } from 'lodash'; +import debounce from 'lodash/debounce'; import React, { FC, useContext } from 'react'; import { useDispatch } from 'react-redux'; import { diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/BoardSetting.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/BoardSetting.tsx index 9a9cac0ea..dfaf893ad 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/BoardSetting.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/BoardSetting.tsx @@ -21,7 +21,7 @@ import { BoardContext } from 'app/pages/DashBoardPage/contexts/BoardContext'; import { DashboardConfig } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import { getRGBAColor } from 'app/pages/DashBoardPage/utils'; import produce from 'immer'; -import { throttle } from 'lodash'; +import throttle from 'lodash/throttle'; import React, { FC, memo, diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/WidgetSetting.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/WidgetSetting.tsx index 84c4073be..dcb26dafa 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/WidgetSetting.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/WidgetSetting.tsx @@ -21,7 +21,7 @@ import { WidgetContext } from 'app/pages/DashBoardPage/contexts/WidgetContext'; import { Widget } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import { getRGBAColor } from 'app/pages/DashBoardPage/utils'; import produce from 'immer'; -import { throttle } from 'lodash'; +import throttle from 'lodash/throttle'; import React, { FC, memo, diff --git a/frontend/src/app/utils/number.ts b/frontend/src/app/utils/number.ts index e7f544c34..1a6be61de 100644 --- a/frontend/src/app/utils/number.ts +++ b/frontend/src/app/utils/number.ts @@ -19,7 +19,7 @@ import { FieldFormatType, IFieldFormatConfig } from 'app/types/ChartConfig'; import { dinero } from 'dinero.js'; import { NumberUnitKey, NumericUnitDescriptions } from 'globalConstants'; -import { isFinite } from 'lodash'; +import isFinite from 'lodash/isFinite'; import moment from 'moment'; import { isEmpty, pipe } from 'utils/object'; import { getCurrency, intlFormat } from './currency'; From 71f08f5b78413e501be7ed245897f4e74d5007d3 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Tue, 28 Dec 2021 10:30:22 +0800 Subject: [PATCH 233/348] chore: uuidv4 by reference --- frontend/src/app/components/Configuration.tsx | 2 +- .../FormGenerator/Basic/BasicUnControlledTabPanel.tsx | 2 +- .../Customize/ConditionStylePanel/ConditionalStylePanel.tsx | 2 +- .../components/ChartDraggable/ChartDraggableTargetContainer.tsx | 2 +- .../components/ChartGraph/BasicTableChart/BasicTableChart.tsx | 2 +- .../components/ChartTools/ChartLifecycleAdapter.tsx | 2 +- .../components/WidgetCore/ContainerWidget/TabWidget/index.tsx | 2 +- .../pages/BoardEditor/components/BoardToolBar/AddChartBtn.tsx | 2 +- .../DashBoardPage/pages/BoardEditor/slice/actions/actions.ts | 2 +- .../app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts | 2 +- frontend/src/app/pages/DashBoardPage/utils/widget.ts | 2 +- .../pages/DashBoardPage/utils/widgetToolKit/controller/index.ts | 2 +- .../SourcePage/SourceDetailPage/ConfigComponent/Properties.tsx | 2 +- .../app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx | 2 +- .../app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx | 2 +- .../pages/ViewPage/Main/Properties/ColumnPermissions.tsx | 2 +- .../pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx | 2 +- .../src/app/pages/MainPage/pages/ViewPage/Sidebar/index.tsx | 2 +- .../pages/MainPage/pages/ViewPage/components/SchemaTable.tsx | 2 +- frontend/src/app/pages/MainPage/pages/VizPage/slice/index.ts | 2 +- frontend/src/app/pages/SharePage/SharePage.tsx | 2 +- .../pages/SharePage/StoryPlayerForShare/StoryPlayerForShare.tsx | 2 +- frontend/src/app/pages/StoryBoardPage/Editor/index.tsx | 2 +- frontend/src/app/pages/StoryBoardPage/Player/index.tsx | 2 +- 24 files changed, 24 insertions(+), 24 deletions(-) diff --git a/frontend/src/app/components/Configuration.tsx b/frontend/src/app/components/Configuration.tsx index e21bff043..838644404 100644 --- a/frontend/src/app/components/Configuration.tsx +++ b/frontend/src/app/components/Configuration.tsx @@ -1,7 +1,7 @@ import { EditableProTable, ProColumns } from '@ant-design/pro-table'; import { useCallback, useMemo, useState } from 'react'; import { css } from 'styled-components/macro'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; const tableStyle = css` .ant-card-body { diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicUnControlledTabPanel.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicUnControlledTabPanel.tsx index e5ed5366d..9e0f54813 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicUnControlledTabPanel.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicUnControlledTabPanel.tsx @@ -33,7 +33,7 @@ import { isEmpty, resetValue, } from 'utils/object'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import GroupLayout from '../Layout/GroupLayout'; import { GroupLayoutMode, ItemLayoutProps } from '../types'; import { itemLayoutComparer } from '../utils'; diff --git a/frontend/src/app/components/FormGenerator/Customize/ConditionStylePanel/ConditionalStylePanel.tsx b/frontend/src/app/components/FormGenerator/Customize/ConditionStylePanel/ConditionalStylePanel.tsx index c65088137..dad921d35 100644 --- a/frontend/src/app/components/FormGenerator/Customize/ConditionStylePanel/ConditionalStylePanel.tsx +++ b/frontend/src/app/components/FormGenerator/Customize/ConditionStylePanel/ConditionalStylePanel.tsx @@ -22,7 +22,7 @@ import { ChartStyleSectionConfig } from 'app/types/ChartConfig'; import { FC, memo, useState } from 'react'; import styled from 'styled-components/macro'; import { CloneValueDeep } from 'utils/object'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { ItemLayoutProps } from '../../types'; import { itemLayoutComparer } from '../../utils'; import AddModal from './add'; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx index 5915e3767..41c2e6128 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx @@ -54,7 +54,7 @@ import { SPACE_SM, } from 'styles/StyleConstants'; import { ValueOf } from 'types'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import ChartDataConfigSectionActionMenu from './ChartDataConfigSectionActionMenu'; import VizDraggableItem from './ChartDraggableElement'; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx index aff6ffa4d..e7900aaa4 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx @@ -29,7 +29,7 @@ import { } from 'app/utils/chartHelper'; import { toFormattedValue } from 'app/utils/number'; import { isEmptyArray, Omit } from 'utils/object'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import AntdTableWrapper from './AntdTableWrapper'; import { getCustomBodyCellStyle, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx index c2dc3be1d..b8d45a26a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx @@ -26,7 +26,7 @@ import { ChartConfig } from 'app/types/ChartConfig'; import { ChartLifecycle } from 'app/types/ChartLifecycle'; import React, { CSSProperties, useEffect, useRef, useState } from 'react'; import styled from 'styled-components/macro'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import ChartIFrameContainerResourceLoader from './ChartIFrameContainerResourceLoader'; enum ContainerStatus { diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ContainerWidget/TabWidget/index.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ContainerWidget/TabWidget/index.tsx index 2e99692cc..81ae6e55f 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ContainerWidget/TabWidget/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ContainerWidget/TabWidget/index.tsx @@ -23,7 +23,7 @@ import React, { useCallback, useContext, useState } from 'react'; import { useDispatch } from 'react-redux'; import styled from 'styled-components/macro'; import { PRIMARY } from 'styles/StyleConstants'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { BoardContext } from '../../../../contexts/BoardContext'; import { editBoardStackActions } from '../../../../pages/BoardEditor/slice'; import { WidgetAllProvider } from '../../../WidgetProvider/WidgetAllProvider'; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddChartBtn.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddChartBtn.tsx index 331897142..a86bf8a20 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddChartBtn.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddChartBtn.tsx @@ -26,7 +26,7 @@ import { selectVizs } from 'app/pages/MainPage/pages/VizPage/slice/selectors'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import React, { useCallback, useContext, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { addDataChartWidgets, addWrapChartWidget } from '../../slice/thunk'; import ChartSelectModalModal from '../ChartSelectModal'; import { ChartWidgetDropdown, ToolBtnProps } from './ToolBarItem'; 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 303263349..172ebc7c8 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 @@ -37,7 +37,7 @@ import ChartDataView, { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { ControllerFacadeTypes } from 'app/types/FilterControlPanel'; import produce from 'immer'; import { RootState } from 'types'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { editBoardStackActions, editDashBoardInfoActions } from '..'; import { BoardType } from '../../../Board/slice/types'; import { ControllerConfig } from '../../components/ControllerWidgetPanel/types'; 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 22fdbcefe..3983a1557 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts @@ -38,7 +38,7 @@ import { RootState } from 'types'; import { CloneValueDeep } from 'utils/object'; import { request } from 'utils/request'; import { errorHandle } from 'utils/utils'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { editBoardStackActions, editDashBoardInfoActions, diff --git a/frontend/src/app/pages/DashBoardPage/utils/widget.ts b/frontend/src/app/pages/DashBoardPage/utils/widget.ts index 7443f7c2f..b85a008d7 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/widget.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/widget.ts @@ -24,7 +24,7 @@ import produce from 'immer'; import { DeltaStatic } from 'quill'; import { CSSProperties } from 'react'; import { FONT_FAMILY, G90, WHITE } from 'styles/StyleConstants'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { convertImageUrl, fillPx } from '.'; import { AutoBoardWidgetBackgroundDefault, diff --git a/frontend/src/app/pages/DashBoardPage/utils/widgetToolKit/controller/index.ts b/frontend/src/app/pages/DashBoardPage/utils/widgetToolKit/controller/index.ts index e398463c0..6445eb8e8 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/widgetToolKit/controller/index.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/widgetToolKit/controller/index.ts @@ -27,7 +27,7 @@ import { import { RelatedWidgetItem } from 'app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/RelatedWidgets'; import { ControllerConfig } from 'app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/types'; import { ControllerFacadeTypes } from 'app/types/FilterControlPanel'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { createInitWidgetConfig, createWidget } from '../../widget'; export const createControllerWidget = (opt: { boardId: string; diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/Properties.tsx b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/Properties.tsx index 3b91d29c8..7f2892a6e 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/Properties.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/Properties.tsx @@ -4,7 +4,7 @@ import { Configuration } from 'app/components'; import { useCallback, useMemo } from 'react'; import styled from 'styled-components'; import { LINE_HEIGHT_BODY } from 'styles/StyleConstants'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; interface Property { key: string; diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx index d3e39e77d..31344bfe6 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx @@ -4,7 +4,7 @@ import { Key, memo, useCallback, useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import styled from 'styled-components/macro'; import { SPACE_XS } from 'styles/StyleConstants'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { selectMemberListLoading, selectMembers, diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx index a38bbf81c..d8a4acc9f 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx @@ -10,7 +10,7 @@ import { memo, useCallback, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components/macro'; import { FONT_FAMILY, FONT_SIZE_BASE } from 'styles/StyleConstants'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { selectRoles } from '../../../MemberPage/slice/selectors'; import { SubjectTypes } from '../../../PermissionPage/constants'; import { SchemaTable } from '../../components/SchemaTable'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx index 0c7ae6348..7d2afbacb 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx @@ -12,7 +12,7 @@ import { SPACE_XS, WARNING, } from 'styles/StyleConstants'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { selectRoles } from '../../../MemberPage/slice/selectors'; import { SubjectTypes } from '../../../PermissionPage/constants'; import { ViewStatus, ViewViewModelStages } from '../../constants'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx index 325531005..7a80fa155 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx @@ -40,7 +40,7 @@ import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components/macro'; import { SPACE_MD, SPACE_TIMES, SPACE_XS } from 'styles/StyleConstants'; import { errorHandle } from 'utils/utils'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { selectVariables } from '../../../VariablePage/slice/selectors'; import { getVariables } from '../../../VariablePage/slice/thunks'; import { ViewViewModelStages } from '../../constants'; 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 3a55924a6..146b3cb40 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/index.tsx @@ -16,7 +16,7 @@ import { useHistory } from 'react-router-dom'; import styled from 'styled-components/macro'; import { SPACE_XS } from 'styles/StyleConstants'; import { getInsertedNodeIndex } from 'utils/utils'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { UNPERSISTED_ID_PREFIX } from '../constants'; import { SaveFormContext } from '../SaveFormContext'; import { diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx index 328b4435c..5f7d3fab9 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx @@ -14,7 +14,7 @@ import { SPACE_XS, WARNING, } from 'styles/StyleConstants'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { ColumnCategories, ColumnTypes, diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/slice/index.ts b/frontend/src/app/pages/MainPage/pages/VizPage/slice/index.ts index 2acfd822e..faf054b3b 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/slice/index.ts +++ b/frontend/src/app/pages/MainPage/pages/VizPage/slice/index.ts @@ -4,7 +4,7 @@ import { useInjectReducer } from 'utils/@reduxjs/injectReducer'; import { isMySliceAction } from 'utils/@reduxjs/toolkit'; import { CloneValueDeep } from 'utils/object'; import { reduxActionErrorHandler } from 'utils/utils'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { addStoryboard, addViz, diff --git a/frontend/src/app/pages/SharePage/SharePage.tsx b/frontend/src/app/pages/SharePage/SharePage.tsx index 234a46985..3e69b772c 100644 --- a/frontend/src/app/pages/SharePage/SharePage.tsx +++ b/frontend/src/app/pages/SharePage/SharePage.tsx @@ -24,7 +24,7 @@ import { useCallback, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useLocation } from 'react-router-dom'; import persistence from 'utils/persistence'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import ChartRequest from '../ChartWorkbenchPage/models/ChartHttpRequest'; import { useBoardSlice } from '../DashBoardPage/pages/Board/slice'; import { selectShareBoard } from '../DashBoardPage/pages/Board/slice/selector'; diff --git a/frontend/src/app/pages/SharePage/StoryPlayerForShare/StoryPlayerForShare.tsx b/frontend/src/app/pages/SharePage/StoryPlayerForShare/StoryPlayerForShare.tsx index 0d3b7ee6d..0b5509fc2 100644 --- a/frontend/src/app/pages/SharePage/StoryPlayerForShare/StoryPlayerForShare.tsx +++ b/frontend/src/app/pages/SharePage/StoryPlayerForShare/StoryPlayerForShare.tsx @@ -33,7 +33,7 @@ import Reveal from 'reveal.js'; import 'reveal.js/dist/reveal.css'; import RevealZoom from 'reveal.js/plugin/zoom/plugin'; import styled from 'styled-components/macro'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import { storyActions } from '../../StoryBoardPage/slice'; import { makeSelectStoryPagesById } from '../../StoryBoardPage/slice/selectors'; import { getPageContentDetail } from '../../StoryBoardPage/slice/thunks'; diff --git a/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx b/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx index 4c2689412..a283a2916 100644 --- a/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx +++ b/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx @@ -36,7 +36,7 @@ import RevealZoom from 'reveal.js/plugin/zoom/plugin'; import styled from 'styled-components/macro'; import { SPACE_MD } from 'styles/StyleConstants'; import { dispatchResize } from 'utils/utils'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import PageThumbnailList from '../components/PageThumbnailList'; import StoryPageItem from '../components/StoryPageItem'; import { storyActions } from '../slice'; diff --git a/frontend/src/app/pages/StoryBoardPage/Player/index.tsx b/frontend/src/app/pages/StoryBoardPage/Player/index.tsx index dabe74004..f12f56166 100644 --- a/frontend/src/app/pages/StoryBoardPage/Player/index.tsx +++ b/frontend/src/app/pages/StoryBoardPage/Player/index.tsx @@ -33,7 +33,7 @@ import Reveal from 'reveal.js'; import 'reveal.js/dist/reveal.css'; import RevealZoom from 'reveal.js/plugin/zoom/plugin'; import styled from 'styled-components/macro'; -import { v4 as uuidv4 } from 'uuid'; +import uuidv4 from 'uuid/dist/v4'; import StoryPageItem from '../components/StoryPageItem'; import { storyActions } from '../slice'; import { From 1a43bcbfe2711c8f9327c0a6feb7081f6793efb4 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 28 Dec 2021 10:39:12 +0800 Subject: [PATCH 234/348] refactor(chart): fetch plugins chart when authed router without block requests --- frontend/src/app/pages/MainPage/index.tsx | 4 ++ .../src/app/pages/SharePage/SharePage.tsx | 5 ++ frontend/src/app/share.tsx | 2 + frontend/src/index.tsx | 56 +++++++++---------- frontend/src/share.tsx | 55 +++++++++--------- 5 files changed, 61 insertions(+), 61 deletions(-) diff --git a/frontend/src/app/pages/MainPage/index.tsx b/frontend/src/app/pages/MainPage/index.tsx index 5ac02e53b..1f3fdc43c 100644 --- a/frontend/src/app/pages/MainPage/index.tsx +++ b/frontend/src/app/pages/MainPage/index.tsx @@ -9,6 +9,7 @@ import { useRouteMatch, } from 'react-router'; import styled from 'styled-components/macro'; +import ChartManager from '../ChartWorkbenchPage/models/ChartManager'; import { NotFoundPage } from '../NotFoundPage'; import { AccessRoute } from './AccessRoute'; import { Background } from './Background'; @@ -49,6 +50,9 @@ export function MainPage() { // loaded first time useEffect(() => { + ChartManager.instance() + .load() + .catch(err => console.error('Fail to load customize charts with ', err)); dispatch(getUserSettings(organizationMatch?.params.orgId)); dispatch(getDataProviders()); return () => { diff --git a/frontend/src/app/pages/SharePage/SharePage.tsx b/frontend/src/app/pages/SharePage/SharePage.tsx index 234a46985..0327244d3 100644 --- a/frontend/src/app/pages/SharePage/SharePage.tsx +++ b/frontend/src/app/pages/SharePage/SharePage.tsx @@ -26,6 +26,7 @@ import { useLocation } from 'react-router-dom'; import persistence from 'utils/persistence'; import { v4 as uuidv4 } from 'uuid'; import ChartRequest from '../ChartWorkbenchPage/models/ChartHttpRequest'; +import ChartManager from '../ChartWorkbenchPage/models/ChartManager'; import { useBoardSlice } from '../DashBoardPage/pages/Board/slice'; import { selectShareBoard } from '../DashBoardPage/pages/Board/slice/selector'; import { VizRenderMode } from '../DashBoardPage/pages/Board/slice/types'; @@ -85,6 +86,10 @@ export function SharePage() { }, [search]); useMount(() => { + ChartManager.instance() + .load() + .catch(err => console.error('Fail to load customize charts with ', err)); + if (Boolean(usePassword)) { const previousPassword = persistence.session.get(shareToken); if (previousPassword) { diff --git a/frontend/src/app/share.tsx b/frontend/src/app/share.tsx index 998261ff6..97d4a826c 100644 --- a/frontend/src/app/share.tsx +++ b/frontend/src/app/share.tsx @@ -23,7 +23,9 @@ import { useTranslation } from 'react-i18next'; import { BrowserRouter } from 'react-router-dom'; import { GlobalStyle, OverriddenStyle } from 'styles/globalStyles'; import { LazySharePage } from './pages/SharePage/Loadable'; + registerTheme('default', echartsDefaultTheme); + export function Share() { const { i18n } = useTranslation(); diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 992ca14cd..9b1235ae0 100755 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -3,7 +3,6 @@ import 'antd/dist/antd.less'; import zh_CN from 'antd/lib/locale/zh_CN'; import { App } from 'app'; import 'app/assets/fonts/iconfont.css'; -import ChartManager from 'app/pages/ChartWorkbenchPage/models/ChartManager'; import 'core-js/features/string/replace-all'; import React from 'react'; import 'react-app-polyfill/ie11'; @@ -25,35 +24,30 @@ Debugger.instance.setEnable(IS_DEVELOPMENT); export const store = configureAppStore(); const MainApp = <App />; -ChartManager.instance() - .load() - .catch(err => console.error('Fail to load customize charts with ', err)) - .finally(() => { - ReactDOM.render( - <InspectorWrapper> - <Provider store={store}> - <ThemeProvider> - <ConfigProvider locale={zh_CN}> - <HelmetProvider> - <React.StrictMode>{MainApp}</React.StrictMode> - </HelmetProvider> - </ConfigProvider> - </ThemeProvider> - </Provider> - </InspectorWrapper>, - MOUNT_NODE, - ); +ReactDOM.render( + <InspectorWrapper> + <Provider store={store}> + <ThemeProvider> + <ConfigProvider locale={zh_CN}> + <HelmetProvider> + <React.StrictMode>{MainApp}</React.StrictMode> + </HelmetProvider> + </ConfigProvider> + </ThemeProvider> + </Provider> + </InspectorWrapper>, + MOUNT_NODE, +); - // Hot reloadable translation json files - if (module.hot) { - module.hot.accept(['./locales/i18n'], () => { - // No need to render the App again because i18next works with the hooks - }); - } - - if (!IS_DEVELOPMENT) { - if (typeof (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__ === 'object') { - (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = () => void 0; - } - } +// Hot reloadable translation json files +if (module.hot) { + module.hot.accept(['./locales/i18n'], () => { + // No need to render the App again because i18next works with the hooks }); +} + +if (!IS_DEVELOPMENT) { + if (typeof (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__ === 'object') { + (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = () => void 0; + } +} diff --git a/frontend/src/share.tsx b/frontend/src/share.tsx index 1437d609c..6561ebda6 100644 --- a/frontend/src/share.tsx +++ b/frontend/src/share.tsx @@ -2,7 +2,6 @@ import { ConfigProvider } from 'antd'; import 'antd/dist/antd.less'; import zh_CN from 'antd/lib/locale/zh_CN'; import 'app/assets/fonts/iconfont.css'; -import ChartManager from 'app/pages/ChartWorkbenchPage/models/ChartManager'; import { Share } from 'app/share'; import React from 'react'; import 'react-app-polyfill/ie11'; @@ -25,35 +24,31 @@ const MainApp = <Share />; const InspectorWrapper = process.env.NODE_ENV === 'development' ? Inspector : React.Fragment; -ChartManager.instance() - .load() - .catch(err => console.error('Fail to load customize charts with ', err)) - .finally(() => { - ReactDOM.render( - <InspectorWrapper> - <Provider store={store}> - <ThemeProvider> - <ConfigProvider locale={zh_CN}> - <HelmetProvider> - <React.StrictMode>{MainApp}</React.StrictMode> - </HelmetProvider> - </ConfigProvider> - </ThemeProvider> - </Provider> - </InspectorWrapper>, - MOUNT_NODE, - ); - // Hot reloadable translation json files - if (module.hot) { - module.hot.accept(['./locales/i18n'], () => { - // No need to render the App again because i18next works with the hooks - }); - } +ReactDOM.render( + <InspectorWrapper> + <Provider store={store}> + <ThemeProvider> + <ConfigProvider locale={zh_CN}> + <HelmetProvider> + <React.StrictMode>{MainApp}</React.StrictMode> + </HelmetProvider> + </ConfigProvider> + </ThemeProvider> + </Provider> + </InspectorWrapper>, + MOUNT_NODE, +); - if (process.env.NODE_ENV === 'production') { - if (typeof (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__ === 'object') { - (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = () => void 0; - } - } +// Hot reloadable translation json files +if (module.hot) { + module.hot.accept(['./locales/i18n'], () => { + // No need to render the App again because i18next works with the hooks }); +} + +if (process.env.NODE_ENV === 'production') { + if (typeof (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__ === 'object') { + (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = () => void 0; + } +} From 6f5b095636e4b1609d7a26798c169238a2bf8ae5 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Tue, 28 Dec 2021 10:48:09 +0800 Subject: [PATCH 235/348] refactor: import uuidv4 --- frontend/src/app/components/Configuration.tsx | 2 +- .../src/app/components/FormGenerator/Basic/BasicInput.tsx | 4 +++- .../FormGenerator/Basic/BasicUnControlledTabPanel.tsx | 2 +- .../Customize/ConditionStylePanel/ConditionalStylePanel.tsx | 2 +- .../ChartDraggable/ChartDraggableTargetContainer.tsx | 2 +- .../components/ChartGraph/BasicTableChart/BasicTableChart.tsx | 2 +- .../components/ChartTools/ChartLifecycleAdapter.tsx | 2 +- .../components/WidgetCore/ContainerWidget/TabWidget/index.tsx | 2 +- .../pages/BoardEditor/components/BoardToolBar/AddChartBtn.tsx | 2 +- .../DashBoardPage/pages/BoardEditor/slice/actions/actions.ts | 2 +- .../app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts | 3 +-- frontend/src/app/pages/DashBoardPage/utils/widget.ts | 2 +- .../DashBoardPage/utils/widgetToolKit/controller/index.ts | 2 +- .../SourceDetailPage/ConfigComponent/Properties.tsx | 2 +- .../pages/MainPage/pages/VariablePage/SubjectForm/index.tsx | 2 +- .../pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx | 2 +- .../pages/ViewPage/Main/Properties/ColumnPermissions.tsx | 2 +- .../MainPage/pages/ViewPage/Main/Properties/Variables.tsx | 3 +-- .../src/app/pages/MainPage/pages/ViewPage/Sidebar/index.tsx | 3 +-- .../pages/MainPage/pages/ViewPage/components/SchemaTable.tsx | 2 +- frontend/src/app/pages/MainPage/pages/VizPage/slice/index.ts | 3 +-- frontend/src/app/pages/SharePage/SharePage.tsx | 2 +- .../SharePage/StoryPlayerForShare/StoryPlayerForShare.tsx | 2 +- frontend/src/app/pages/StoryBoardPage/Editor/index.tsx | 3 +-- frontend/src/app/pages/StoryBoardPage/Player/index.tsx | 2 +- frontend/src/utils/utils.ts | 1 + 26 files changed, 28 insertions(+), 30 deletions(-) diff --git a/frontend/src/app/components/Configuration.tsx b/frontend/src/app/components/Configuration.tsx index 838644404..4a816a40a 100644 --- a/frontend/src/app/components/Configuration.tsx +++ b/frontend/src/app/components/Configuration.tsx @@ -1,7 +1,7 @@ import { EditableProTable, ProColumns } from '@ant-design/pro-table'; import { useCallback, useMemo, useState } from 'react'; import { css } from 'styled-components/macro'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; const tableStyle = css` .ant-card-body { diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicInput.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicInput.tsx index 613f9f0bb..a5039586f 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicInput.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicInput.tsx @@ -43,7 +43,9 @@ const BasicInput: FC<ItemLayoutProps<ChartStyleSectionConfig>> = memo( {...rest} {...options} onChange={value => { - const newCache = Object.assign({}, cache, { value: value.target?.value }); + const newCache = Object.assign({}, cache, { + value: value.target?.value, + }); setCache(newCache); debouncedDataChange(newCache.value); }} diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicUnControlledTabPanel.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicUnControlledTabPanel.tsx index 9e0f54813..40ad11f91 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicUnControlledTabPanel.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicUnControlledTabPanel.tsx @@ -33,7 +33,7 @@ import { isEmpty, resetValue, } from 'utils/object'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import GroupLayout from '../Layout/GroupLayout'; import { GroupLayoutMode, ItemLayoutProps } from '../types'; import { itemLayoutComparer } from '../utils'; diff --git a/frontend/src/app/components/FormGenerator/Customize/ConditionStylePanel/ConditionalStylePanel.tsx b/frontend/src/app/components/FormGenerator/Customize/ConditionStylePanel/ConditionalStylePanel.tsx index dad921d35..9d33faf5c 100644 --- a/frontend/src/app/components/FormGenerator/Customize/ConditionStylePanel/ConditionalStylePanel.tsx +++ b/frontend/src/app/components/FormGenerator/Customize/ConditionStylePanel/ConditionalStylePanel.tsx @@ -22,7 +22,7 @@ import { ChartStyleSectionConfig } from 'app/types/ChartConfig'; import { FC, memo, useState } from 'react'; import styled from 'styled-components/macro'; import { CloneValueDeep } from 'utils/object'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import { ItemLayoutProps } from '../../types'; import { itemLayoutComparer } from '../../utils'; import AddModal from './add'; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx index 41c2e6128..607758c74 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx @@ -54,7 +54,7 @@ import { SPACE_SM, } from 'styles/StyleConstants'; import { ValueOf } from 'types'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import ChartDataConfigSectionActionMenu from './ChartDataConfigSectionActionMenu'; import VizDraggableItem from './ChartDraggableElement'; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx index e7900aaa4..88ec32748 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx @@ -29,7 +29,7 @@ import { } from 'app/utils/chartHelper'; import { toFormattedValue } from 'app/utils/number'; import { isEmptyArray, Omit } from 'utils/object'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import AntdTableWrapper from './AntdTableWrapper'; import { getCustomBodyCellStyle, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx index b8d45a26a..fa98c6a8e 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx @@ -26,7 +26,7 @@ import { ChartConfig } from 'app/types/ChartConfig'; import { ChartLifecycle } from 'app/types/ChartLifecycle'; import React, { CSSProperties, useEffect, useRef, useState } from 'react'; import styled from 'styled-components/macro'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import ChartIFrameContainerResourceLoader from './ChartIFrameContainerResourceLoader'; enum ContainerStatus { diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ContainerWidget/TabWidget/index.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ContainerWidget/TabWidget/index.tsx index 81ae6e55f..f898e2a35 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ContainerWidget/TabWidget/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/ContainerWidget/TabWidget/index.tsx @@ -23,7 +23,7 @@ import React, { useCallback, useContext, useState } from 'react'; import { useDispatch } from 'react-redux'; import styled from 'styled-components/macro'; import { PRIMARY } from 'styles/StyleConstants'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import { BoardContext } from '../../../../contexts/BoardContext'; import { editBoardStackActions } from '../../../../pages/BoardEditor/slice'; import { WidgetAllProvider } from '../../../WidgetProvider/WidgetAllProvider'; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddChartBtn.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddChartBtn.tsx index a86bf8a20..242c35b21 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddChartBtn.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddChartBtn.tsx @@ -26,7 +26,7 @@ import { selectVizs } from 'app/pages/MainPage/pages/VizPage/slice/selectors'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import React, { useCallback, useContext, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import { addDataChartWidgets, addWrapChartWidget } from '../../slice/thunk'; import ChartSelectModalModal from '../ChartSelectModal'; import { ChartWidgetDropdown, ToolBtnProps } from './ToolBarItem'; 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 172ebc7c8..25c1cfb65 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 @@ -37,7 +37,7 @@ import ChartDataView, { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { ControllerFacadeTypes } from 'app/types/FilterControlPanel'; import produce from 'immer'; import { RootState } from 'types'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import { editBoardStackActions, editDashBoardInfoActions } from '..'; import { BoardType } from '../../../Board/slice/types'; import { ControllerConfig } from '../../components/ControllerWidgetPanel/types'; 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 3983a1557..2bb565192 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts @@ -37,8 +37,7 @@ import { ActionCreators } from 'redux-undo'; import { RootState } from 'types'; import { CloneValueDeep } from 'utils/object'; import { request } from 'utils/request'; -import { errorHandle } from 'utils/utils'; -import uuidv4 from 'uuid/dist/v4'; +import { errorHandle, uuidv4 } from 'utils/utils'; import { editBoardStackActions, editDashBoardInfoActions, diff --git a/frontend/src/app/pages/DashBoardPage/utils/widget.ts b/frontend/src/app/pages/DashBoardPage/utils/widget.ts index b85a008d7..8f40e352d 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/widget.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/widget.ts @@ -24,7 +24,7 @@ import produce from 'immer'; import { DeltaStatic } from 'quill'; import { CSSProperties } from 'react'; import { FONT_FAMILY, G90, WHITE } from 'styles/StyleConstants'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import { convertImageUrl, fillPx } from '.'; import { AutoBoardWidgetBackgroundDefault, diff --git a/frontend/src/app/pages/DashBoardPage/utils/widgetToolKit/controller/index.ts b/frontend/src/app/pages/DashBoardPage/utils/widgetToolKit/controller/index.ts index 6445eb8e8..466d6b13f 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/widgetToolKit/controller/index.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/widgetToolKit/controller/index.ts @@ -27,7 +27,7 @@ import { import { RelatedWidgetItem } from 'app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/RelatedWidgets'; import { ControllerConfig } from 'app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/types'; import { ControllerFacadeTypes } from 'app/types/FilterControlPanel'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import { createInitWidgetConfig, createWidget } from '../../widget'; export const createControllerWidget = (opt: { boardId: string; diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/Properties.tsx b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/Properties.tsx index 7f2892a6e..71a9ba483 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/Properties.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/Properties.tsx @@ -4,7 +4,7 @@ import { Configuration } from 'app/components'; import { useCallback, useMemo } from 'react'; import styled from 'styled-components'; import { LINE_HEIGHT_BODY } from 'styles/StyleConstants'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; interface Property { key: string; diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx index 31344bfe6..cc09e9cc8 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx @@ -4,7 +4,7 @@ import { Key, memo, useCallback, useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import styled from 'styled-components/macro'; import { SPACE_XS } from 'styles/StyleConstants'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import { selectMemberListLoading, selectMembers, diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx index d8a4acc9f..ee93c912f 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx @@ -10,7 +10,7 @@ import { memo, useCallback, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components/macro'; import { FONT_FAMILY, FONT_SIZE_BASE } from 'styles/StyleConstants'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import { selectRoles } from '../../../MemberPage/slice/selectors'; import { SubjectTypes } from '../../../PermissionPage/constants'; import { SchemaTable } from '../../components/SchemaTable'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx index 7d2afbacb..6f56cc466 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx @@ -12,7 +12,7 @@ import { SPACE_XS, WARNING, } from 'styles/StyleConstants'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import { selectRoles } from '../../../MemberPage/slice/selectors'; import { SubjectTypes } from '../../../PermissionPage/constants'; import { ViewStatus, ViewViewModelStages } from '../../constants'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx index 7a80fa155..eb491e6df 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx @@ -39,8 +39,7 @@ import { monaco } from 'react-monaco-editor'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components/macro'; import { SPACE_MD, SPACE_TIMES, SPACE_XS } from 'styles/StyleConstants'; -import { errorHandle } from 'utils/utils'; -import uuidv4 from 'uuid/dist/v4'; +import { errorHandle, uuidv4 } from 'utils/utils'; import { selectVariables } from '../../../VariablePage/slice/selectors'; import { getVariables } from '../../../VariablePage/slice/thunks'; import { ViewViewModelStages } from '../../constants'; 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 146b3cb40..4dd4d3278 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/index.tsx @@ -15,8 +15,7 @@ import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; import styled from 'styled-components/macro'; import { SPACE_XS } from 'styles/StyleConstants'; -import { getInsertedNodeIndex } from 'utils/utils'; -import uuidv4 from 'uuid/dist/v4'; +import { getInsertedNodeIndex, uuidv4 } from 'utils/utils'; import { UNPERSISTED_ID_PREFIX } from '../constants'; import { SaveFormContext } from '../SaveFormContext'; import { diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx index 5f7d3fab9..83404a9ac 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx @@ -14,7 +14,7 @@ import { SPACE_XS, WARNING, } from 'styles/StyleConstants'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import { ColumnCategories, ColumnTypes, diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/slice/index.ts b/frontend/src/app/pages/MainPage/pages/VizPage/slice/index.ts index faf054b3b..81cba38c6 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/slice/index.ts +++ b/frontend/src/app/pages/MainPage/pages/VizPage/slice/index.ts @@ -3,8 +3,7 @@ import { ChartDataSectionType } from 'app/types/ChartConfig'; import { useInjectReducer } from 'utils/@reduxjs/injectReducer'; import { isMySliceAction } from 'utils/@reduxjs/toolkit'; import { CloneValueDeep } from 'utils/object'; -import { reduxActionErrorHandler } from 'utils/utils'; -import uuidv4 from 'uuid/dist/v4'; +import { reduxActionErrorHandler, uuidv4 } from 'utils/utils'; import { addStoryboard, addViz, diff --git a/frontend/src/app/pages/SharePage/SharePage.tsx b/frontend/src/app/pages/SharePage/SharePage.tsx index 3e69b772c..d3fcad847 100644 --- a/frontend/src/app/pages/SharePage/SharePage.tsx +++ b/frontend/src/app/pages/SharePage/SharePage.tsx @@ -24,7 +24,7 @@ import { useCallback, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useLocation } from 'react-router-dom'; import persistence from 'utils/persistence'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import ChartRequest from '../ChartWorkbenchPage/models/ChartHttpRequest'; import { useBoardSlice } from '../DashBoardPage/pages/Board/slice'; import { selectShareBoard } from '../DashBoardPage/pages/Board/slice/selector'; diff --git a/frontend/src/app/pages/SharePage/StoryPlayerForShare/StoryPlayerForShare.tsx b/frontend/src/app/pages/SharePage/StoryPlayerForShare/StoryPlayerForShare.tsx index 0b5509fc2..11a72a408 100644 --- a/frontend/src/app/pages/SharePage/StoryPlayerForShare/StoryPlayerForShare.tsx +++ b/frontend/src/app/pages/SharePage/StoryPlayerForShare/StoryPlayerForShare.tsx @@ -33,7 +33,7 @@ import Reveal from 'reveal.js'; import 'reveal.js/dist/reveal.css'; import RevealZoom from 'reveal.js/plugin/zoom/plugin'; import styled from 'styled-components/macro'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import { storyActions } from '../../StoryBoardPage/slice'; import { makeSelectStoryPagesById } from '../../StoryBoardPage/slice/selectors'; import { getPageContentDetail } from '../../StoryBoardPage/slice/thunks'; diff --git a/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx b/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx index a283a2916..6fa1567e0 100644 --- a/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx +++ b/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx @@ -35,8 +35,7 @@ import 'reveal.js/dist/reveal.css'; import RevealZoom from 'reveal.js/plugin/zoom/plugin'; import styled from 'styled-components/macro'; import { SPACE_MD } from 'styles/StyleConstants'; -import { dispatchResize } from 'utils/utils'; -import uuidv4 from 'uuid/dist/v4'; +import { dispatchResize, uuidv4 } from 'utils/utils'; import PageThumbnailList from '../components/PageThumbnailList'; import StoryPageItem from '../components/StoryPageItem'; import { storyActions } from '../slice'; diff --git a/frontend/src/app/pages/StoryBoardPage/Player/index.tsx b/frontend/src/app/pages/StoryBoardPage/Player/index.tsx index f12f56166..134776d7d 100644 --- a/frontend/src/app/pages/StoryBoardPage/Player/index.tsx +++ b/frontend/src/app/pages/StoryBoardPage/Player/index.tsx @@ -33,7 +33,7 @@ import Reveal from 'reveal.js'; import 'reveal.js/dist/reveal.css'; import RevealZoom from 'reveal.js/plugin/zoom/plugin'; import styled from 'styled-components/macro'; -import uuidv4 from 'uuid/dist/v4'; +import { uuidv4 } from 'utils/utils'; import StoryPageItem from '../components/StoryPageItem'; import { storyActions } from '../slice'; import { diff --git a/frontend/src/utils/utils.ts b/frontend/src/utils/utils.ts index 1855a9311..eea6e57cd 100644 --- a/frontend/src/utils/utils.ts +++ b/frontend/src/utils/utils.ts @@ -10,6 +10,7 @@ import { import { APIResponse } from 'types'; import { SaveFormModel } from '../app/pages/MainPage/pages/VizPage/SaveFormContext'; import { removeToken } from './auth'; +export { default as uuidv4 } from 'uuid/dist/v4'; export function errorHandle(error) { if (error?.response) { From a4acecb44e9e2e2413ed9c989addc670f4800c3c Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Tue, 28 Dec 2021 10:49:52 +0800 Subject: [PATCH 236/348] style: eslint no-restricted-imports [lodash,uuid] --- frontend/.eslintrc.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index 1b2d2016b..420ad9f53 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -10,6 +10,21 @@ module.exports = { plugins: ['prettier'], rules: { 'prettier/prettier': ['error', prettierOptions], + 'no-restricted-imports': [ + 'error', + { + paths: [ + { + name: 'lodash', + message: 'suggest import xxx from `lodash/xxx`', + }, + { + name: 'uuid', + message: 'suggest import xxx from `uuid/dist/xxx`', + }, + ], + }, + ], }, parserOptions: { ecmaVersion: 2018, From 8c3f4e11adbe6b14f40cd0b07ece0b002fde3ba3 Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Tue, 28 Dec 2021 12:06:56 +0800 Subject: [PATCH 237/348] fix: datetime parse error in impala --- core/pom.xml | 64 ++++++++++--------- .../java/datart/core/base/consts/Const.java | 3 +- .../dialect/ImpalaSqlDialectSupport.java | 6 ++ .../data/provider/jdbc/SqlScriptRender.java | 2 - 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 08241e2d0..35a87ce37 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -157,39 +157,45 @@ <build> <plugins> <!--MyBatis generator--> +<!-- <plugin>--> +<!-- <groupId>org.mybatis.generator</groupId>--> +<!-- <artifactId>mybatis-generator-maven-plugin</artifactId>--> +<!-- <version>1.4.0</version>--> +<!-- <configuration>--> +<!-- <configurationFile>src/main/resources/mybatis-generator/generatorConfig.xml</configurationFile>--> +<!-- <verbose>true</verbose>--> +<!-- <overwrite>true</overwrite>--> +<!-- <includeAllDependencies>true</includeAllDependencies>--> +<!-- </configuration>--> +<!-- <executions>--> +<!-- <execution>--> +<!-- <id>Generate MyBatis Artifacts</id>--> +<!-- <goals>--> +<!-- <goal>generate</goal>--> +<!-- </goals>--> +<!-- <phase>install</phase>--> +<!-- </execution>--> +<!-- </executions>--> +<!-- <dependencies>--> +<!-- <dependency>--> +<!-- <groupId>mysql</groupId>--> +<!-- <artifactId>mysql-connector-java</artifactId>--> +<!-- <version>5.1.49</version>--> +<!-- </dependency>--> +<!-- <dependency>--> +<!-- <groupId>datart</groupId>--> +<!-- <artifactId>datart-core</artifactId>--> +<!-- <version>${project.version}</version>--> +<!-- </dependency>--> +<!-- </dependencies>--> +<!-- </plugin>--> <plugin> - <groupId>org.mybatis.generator</groupId> - <artifactId>mybatis-generator-maven-plugin</artifactId> - <version>1.4.0</version> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> <configuration> - <configurationFile>src/main/resources/mybatis-generator/generatorConfig.xml</configurationFile> - <verbose>true</verbose> - <overwrite>true</overwrite> - <includeAllDependencies>true</includeAllDependencies> + <parameters>true</parameters> </configuration> - <executions> - <execution> - <id>Generate MyBatis Artifacts</id> - <goals> - <goal>generate</goal> - </goals> - <phase>install</phase> - </execution> - </executions> - <dependencies> - <dependency> - <groupId>mysql</groupId> - <artifactId>mysql-connector-java</artifactId> - <version>5.1.49</version> - </dependency> - <dependency> - <groupId>datart</groupId> - <artifactId>datart-core</artifactId> - <version>${project.version}</version> - </dependency> - </dependencies> </plugin> - </plugins> </build> diff --git a/core/src/main/java/datart/core/base/consts/Const.java b/core/src/main/java/datart/core/base/consts/Const.java index 6c3ee8837..708b92985 100644 --- a/core/src/main/java/datart/core/base/consts/Const.java +++ b/core/src/main/java/datart/core/base/consts/Const.java @@ -45,7 +45,8 @@ public class Const { */ //默认的变量引用符号 public static final String DEFAULT_VARIABLE_QUOTE = "$"; - + //变量匹配符 + public static final String VARIABLE_EXP = "\\$\\w+\\$"; /** * 权限变量 */ diff --git a/data-providers/src/main/java/datart/data/provider/calcite/dialect/ImpalaSqlDialectSupport.java b/data-providers/src/main/java/datart/data/provider/calcite/dialect/ImpalaSqlDialectSupport.java index b9d8a735e..7ebf4d4df 100644 --- a/data-providers/src/main/java/datart/data/provider/calcite/dialect/ImpalaSqlDialectSupport.java +++ b/data-providers/src/main/java/datart/data/provider/calcite/dialect/ImpalaSqlDialectSupport.java @@ -19,6 +19,7 @@ package datart.data.provider.calcite.dialect; import datart.data.provider.jdbc.JdbcDriverInfo; +import org.apache.calcite.sql.SqlAbstractDateTimeLiteral; import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.SqlWriter; @@ -32,4 +33,9 @@ public ImpalaSqlDialectSupport(JdbcDriverInfo driverInfo) { public void unparseOffsetFetch(SqlWriter writer, SqlNode offset, SqlNode fetch) { super.unparseFetchUsingLimit(writer, offset, fetch); } + + @Override + public void unparseDateTimeLiteral(SqlWriter writer, SqlAbstractDateTimeLiteral literal, int leftPrec, int rightPrec) { + writer.literal("'" + literal.toFormattedString() + "'"); + } } diff --git a/data-providers/src/main/java/datart/data/provider/jdbc/SqlScriptRender.java b/data-providers/src/main/java/datart/data/provider/jdbc/SqlScriptRender.java index 104d951fd..49309352d 100644 --- a/data-providers/src/main/java/datart/data/provider/jdbc/SqlScriptRender.java +++ b/data-providers/src/main/java/datart/data/provider/jdbc/SqlScriptRender.java @@ -115,7 +115,6 @@ public String render(boolean withExecuteParam, boolean withPage, boolean onlySel return variable.getValues().iterator().next(); } else return variable.getValues(); })); - String script1 = queryScript.getScript(); script = FreemarkerContext.process(queryScript.getScript(), dataMap); // 替换脚本中的表达式类型变量 @@ -129,7 +128,6 @@ public String render(boolean withExecuteParam, boolean withPage, boolean onlySel } } - // find select sql final String selectSql0 = findSelectSql(script); if (StringUtils.isEmpty(selectSql0)) { From 1df898a40e3a0e6f8121dc4cb444af6534eb0493 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 28 Dec 2021 13:04:16 +0800 Subject: [PATCH 238/348] feat(chart): add config placeholder when drag section field item --- .../ChartDraggable/ChartDraggableTargetContainer.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx index 5915e3767..0f18bc9a1 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx @@ -56,7 +56,7 @@ import { import { ValueOf } from 'types'; import { v4 as uuidv4 } from 'uuid'; import ChartDataConfigSectionActionMenu from './ChartDataConfigSectionActionMenu'; -import VizDraggableItem from './ChartDraggableElement'; +import ChartDraggableElement from './ChartDraggableElement'; type DragItem = { index?: number; @@ -243,8 +243,7 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = const onDraggableItemMove = (dragIndex: number, hoverIndex: number) => { const draggedItem = currentConfig.rows?.[dragIndex]; - - if (draggedItem && !currentConfig?.rows?.length) { + if (draggedItem) { const newCurrentConfig = updateBy(currentConfig, draft => { const columns = draft.rows || []; columns.splice(dragIndex, 1); @@ -282,7 +281,7 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = return currentConfig.rows?.map((columnConfig, index) => { return ( - <VizDraggableItem + <ChartDraggableElement key={columnConfig.uid} id={columnConfig.uid} index={index} @@ -315,7 +314,7 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = }} moveCard={onDraggableItemMove} onDelete={handleOnDeleteItem(columnConfig.uid)} - ></VizDraggableItem> + ></ChartDraggableElement> ); }); }; From 00cb406460b0313fd06b8b1733451c13e7ef8ed1 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 28 Dec 2021 15:44:55 +0800 Subject: [PATCH 239/348] refactor(chart): add options data on resize event --- .../ChartTools/ChartLifecycleAdapter.tsx | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx index c2dc3be1d..e2e685b80 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx @@ -55,7 +55,10 @@ const ChartLifecycleAdapter: React.FC<{ setChartResourceLoader(new ChartIFrameContainerResourceLoader()); }); - // when chart change + /** + * Chart Mount Event + * Dependency: 'chart?.meta?.id', 'eventBrokerRef' + */ useEffect(() => { if (!chart || !document || !window || !config) { return; @@ -94,9 +97,12 @@ const ChartLifecycleAdapter: React.FC<{ setContainerStatus(ContainerStatus.INIT); eventBrokerRef?.current?.publish(ChartLifecycle.UNMOUNTED, {}); }; - }, [chart?.meta?.name, eventBrokerRef]); + }, [chart?.meta?.id, eventBrokerRef]); - // when chart config or dataset change + /** + * Chart Update Event + * Dependency: 'config', 'dataset', 'widgetSpecialConfig', 'containerStatus', 'document', 'window' + */ useEffect(() => { if ( !document || @@ -114,19 +120,37 @@ const ChartLifecycleAdapter: React.FC<{ config, widgetSpecialConfig, }, - { document, window, width: style?.width, height: style?.height }, + { + document, + window, + width: style?.width, + height: style?.height, + }, ); }, [config, dataset, widgetSpecialConfig, containerStatus, document, window]); - // when chart size change + /** + * Chart Resize Event + * Dependency: 'style.width', 'style.height', 'document', 'window' + */ useEffect(() => { - if (!style.width || !style.height) { + if ( + !document || + !window || + !config || + !dataset || + containerStatus !== ContainerStatus.SUCCESS + ) { return; } eventBrokerRef.current?.publish( ChartLifecycle.RESIZE, - {}, + { + dataset, + config, + widgetSpecialConfig, + }, { document, window, From 0f6c59e420036ff1cc589550e6366bf41bb7bbda Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Tue, 28 Dec 2021 15:48:52 +0800 Subject: [PATCH 240/348] fix: Modify the drag and drop judgment logic text: Add translation --- frontend/src/app/components/ChartEditor.tsx | 4 +- .../src/app/components/ListTitle/index.tsx | 7 +- .../src/app/hooks/useFieldActionModal.tsx | 2 +- .../ChartHeaderPanel/ChartHeaderPanel.tsx | 73 ++--- .../components/AggregationOperationMenu.tsx | 4 +- .../AggregateTypeSection.tsx | 2 +- .../ColorTypeSection.tsx | 10 +- .../GroupTypeSection.tsx | 9 +- .../InfoTypeSection.tsx | 2 +- .../MixedTypeSection.tsx | 2 +- .../SizeTypeSection.tsx | 2 +- .../ChartDataConfigSection/utils.ts | 13 +- .../ChartDraggableTargetContainer.tsx | 29 -- .../AggregationColorizeAction.tsx | 7 +- .../components/ChartGraphPanel.tsx | 18 +- .../ChartWorkbench/ChartWorkbench.tsx | 1 - .../VizPage/Sidebar/Folders/FolderTree.tsx | 31 +- .../pages/VizPage/Sidebar/Folders/index.tsx | 290 +++++++++--------- .../pages/VizPage/Sidebar/Recycle.tsx | 16 +- .../VizPage/Sidebar/Storyboards/index.tsx | 188 ++++++------ .../MainPage/pages/VizPage/Sidebar/index.tsx | 10 +- .../pages/MainPage/pages/VizPage/index.tsx | 2 +- frontend/src/locales/en/translation.json | 41 ++- frontend/src/locales/zh/translation.json | 39 ++- 24 files changed, 440 insertions(+), 362 deletions(-) diff --git a/frontend/src/app/components/ChartEditor.tsx b/frontend/src/app/components/ChartEditor.tsx index 3d69367d3..87b14c091 100644 --- a/frontend/src/app/components/ChartEditor.tsx +++ b/frontend/src/app/components/ChartEditor.tsx @@ -130,7 +130,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ setChart(currentChart); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [backendChart]); + }, [backendChart?.config]); const handleChartChange = (c: Chart) => { registerChartEvents(c); @@ -302,6 +302,8 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ const handleAggregationState = state => { const currentChart = ChartManager.instance().getById(chart?.meta?.id); registerChartEvents(currentChart); + setChart(currentChart); + let clonedState = CloneValueDeep(currentChart?.config); dispatch(actions.updateChartAggregation(state)); diff --git a/frontend/src/app/components/ListTitle/index.tsx b/frontend/src/app/components/ListTitle/index.tsx index ed9c30825..b7dfc41eb 100644 --- a/frontend/src/app/components/ListTitle/index.tsx +++ b/frontend/src/app/components/ListTitle/index.tsx @@ -1,6 +1,7 @@ import { LeftOutlined, MoreOutlined, SearchOutlined } from '@ant-design/icons'; import { Input, Menu, Space, Tooltip } from 'antd'; import { MenuListItem, Popup, ToolbarButton } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { ReactElement, useCallback, useState } from 'react'; import styled from 'styled-components/macro'; import { @@ -60,7 +61,7 @@ export function ListTitle({ onNext, }: ListTitleProps) { const [searchbarVisible, setSearchbarVisible] = useState(false); - + const t = useI18NPrefix('components.listTitle'); const toggleSearchbar = useCallback(() => { setSearchbarVisible(!searchbarVisible); }, [searchbarVisible]); @@ -88,7 +89,7 @@ export function ListTitle({ {subTitle && <h5>{subTitle}</h5>} <Space size={SPACE_UNIT}> {search && ( - <Tooltip title="搜索" placement="bottom"> + <Tooltip title={t('search')} placement="bottom"> <ToolbarButton size="small" icon={<SearchOutlined />} @@ -129,7 +130,7 @@ export function ListTitle({ <Input className="search-input" prefix={<SearchOutlined className="icon" />} - placeholder="搜索名称关键字" + placeholder={t('searchValue')} bordered={false} onChange={onSearch} /> diff --git a/frontend/src/app/hooks/useFieldActionModal.tsx b/frontend/src/app/hooks/useFieldActionModal.tsx index 21b584d5c..f85bc9316 100644 --- a/frontend/src/app/hooks/useFieldActionModal.tsx +++ b/frontend/src/app/hooks/useFieldActionModal.tsx @@ -52,8 +52,8 @@ function useFieldActionModal({ i18nPrefix }: I18NComponentProps) { dataConfig, onConfigChange: onChange, aggregation, + i18nPrefix, }; - switch (actionType) { case ChartDataSectionFieldActionType.Sortable: return <FieldActions.SortAction {...props} />; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/ChartHeaderPanel.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/ChartHeaderPanel.tsx index 8a80cb85f..683a77e4a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/ChartHeaderPanel.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/ChartHeaderPanel.tsx @@ -19,7 +19,7 @@ import { LeftOutlined, MoreOutlined } from '@ant-design/icons'; import { Button, Dropdown, Space } from 'antd'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; -import { FC, memo } from 'react'; +import { FC, memo, useCallback, useContext } from 'react'; import styled from 'styled-components/macro'; import { FONT_SIZE_ICON_SM, @@ -30,6 +30,7 @@ import { SPACE_TIMES, SPACE_XS, } from 'styles/StyleConstants'; +import ChartAggregationContext from '../../contexts/ChartAggregationContext'; import AggregationOperationMenu from './components/AggregationOperationMenu'; const ChartHeaderPanel: FC<{ @@ -37,48 +38,40 @@ const ChartHeaderPanel: FC<{ onSaveChart?: () => void; onGoBack?: () => void; onChangeAggregation?: (state: boolean) => void; - aggregation?: boolean; -}> = memo( - ({ - chartName, - onSaveChart, - onGoBack, - onChangeAggregation, - aggregation = true, - }) => { - const t = useI18NPrefix(`viz.workbench.header`); - - const getOverlays = () => { - return ( - <AggregationOperationMenu - defaultValue={aggregation} - onChangeAggregation={e => { - onChangeAggregation?.(e); - }} - ></AggregationOperationMenu> - ); - }; +}> = memo(({ chartName, onSaveChart, onGoBack, onChangeAggregation }) => { + const t = useI18NPrefix(`viz.workbench.header`); + const { aggregation } = useContext(ChartAggregationContext); + const getOverlays = useCallback(() => { return ( - <Wrapper> - {onGoBack && ( - <GoBack> - <LeftOutlined onClick={onGoBack} /> - </GoBack> - )} - <h1>{chartName}</h1> - <Space> - <Button type="primary" onClick={onSaveChart}> - {t('save')} - </Button> - <Dropdown key="more" trigger={['click']} overlay={getOverlays()}> - <Button icon={<MoreOutlined />} /> - </Dropdown> - </Space> - </Wrapper> + <AggregationOperationMenu + defaultValue={aggregation} + onChangeAggregation={e => { + onChangeAggregation?.(e); + }} + ></AggregationOperationMenu> ); - }, -); + }, [aggregation, onChangeAggregation]); + + return ( + <Wrapper> + {onGoBack && ( + <GoBack> + <LeftOutlined onClick={onGoBack} /> + </GoBack> + )} + <h1>{chartName}</h1> + <Space> + <Button type="primary" onClick={onSaveChart}> + {t('save')} + </Button> + <Dropdown key="more" trigger={['click']} overlay={getOverlays()}> + <Button icon={<MoreOutlined />} /> + </Dropdown> + </Space> + </Wrapper> + ); +}); export default ChartHeaderPanel; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/components/AggregationOperationMenu.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/components/AggregationOperationMenu.tsx index 10861a40c..69a125cf0 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/components/AggregationOperationMenu.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartHeaderPanel/components/AggregationOperationMenu.tsx @@ -21,9 +21,9 @@ import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { FC, memo, useMemo } from 'react'; const AggregationOperationMenu: FC<{ - defaultValue: boolean; + defaultValue?: boolean; onChangeAggregation: (value: boolean) => void; -}> = memo(({ defaultValue, onChangeAggregation }) => { +}> = memo(({ defaultValue = true, onChangeAggregation }) => { const checkedValue = useMemo(() => defaultValue, [defaultValue]); const t = useI18NPrefix(`viz.workbench.header`); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/AggregateTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/AggregateTypeSection.tsx index 0ffaa02b2..ba187adc2 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/AggregateTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/AggregateTypeSection.tsx @@ -51,7 +51,7 @@ const AggregateTypeSection: FC<ChartDataConfigSectionProps> = memo( ); if (aggregation === false) { - defaultConfig = handleDefaultConfig(defaultConfig); + defaultConfig = handleDefaultConfig(defaultConfig, config.type); } return <BaseDataConfigSection {...rest} config={defaultConfig} />; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/ColorTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/ColorTypeSection.tsx index f31b8e56b..4111ac83a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/ColorTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/ColorTypeSection.tsx @@ -21,11 +21,11 @@ import { ChartDataConfigSectionProps } from 'app/types/ChartDataConfigSection'; import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { FC, memo } from 'react'; import BaseDataConfigSection from './BaseDataConfigSection'; -import { dataConfigSectionComparer } from './utils'; +import { dataConfigSectionComparer, handleDefaultConfig } from './utils'; const ColorTypeSection: FC<ChartDataConfigSectionProps> = memo( - ({ config, ...rest }) => { - const defaultConfig = Object.assign( + ({ config, aggregation, ...rest }) => { + let defaultConfig = Object.assign( {}, { actions: { @@ -37,7 +37,9 @@ const ColorTypeSection: FC<ChartDataConfigSectionProps> = memo( }, config, ); - + if (aggregation === false) { + defaultConfig = handleDefaultConfig(defaultConfig, config.type); + } return <BaseDataConfigSection {...rest} config={defaultConfig} />; }, dataConfigSectionComparer, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/GroupTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/GroupTypeSection.tsx index 4c4e3a0e6..8d25a2140 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/GroupTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/GroupTypeSection.tsx @@ -21,11 +21,11 @@ import { ChartDataConfigSectionProps } from 'app/types/ChartDataConfigSection'; import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { FC, memo } from 'react'; import BaseDataConfigSection from './BaseDataConfigSection'; -import { dataConfigSectionComparer } from './utils'; +import { dataConfigSectionComparer, handleDefaultConfig } from './utils'; const GroupTypeSection: FC<ChartDataConfigSectionProps> = memo( - ({ config, ...rest }) => { - const defaultConfig = Object.assign( + ({ config, aggregation, ...rest }) => { + let defaultConfig = Object.assign( {}, { actions: { @@ -45,6 +45,9 @@ const GroupTypeSection: FC<ChartDataConfigSectionProps> = memo( }, config, ); + if (aggregation === false) { + defaultConfig = handleDefaultConfig(defaultConfig, config.type); + } return <BaseDataConfigSection {...rest} config={defaultConfig} />; }, dataConfigSectionComparer, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/InfoTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/InfoTypeSection.tsx index 887b6d9cd..fa4e9ab7c 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/InfoTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/InfoTypeSection.tsx @@ -42,7 +42,7 @@ const InfoTypeSection: FC<ChartDataConfigSectionProps> = memo( ); if (aggregation === false) { - defaultConfig = handleDefaultConfig(defaultConfig); + defaultConfig = handleDefaultConfig(defaultConfig, config.type); } return <BaseDataConfigSection {...rest} config={defaultConfig} />; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/MixedTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/MixedTypeSection.tsx index d6589c118..4663053e9 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/MixedTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/MixedTypeSection.tsx @@ -49,7 +49,7 @@ const MixedTypeSection: FC<ChartDataConfigSectionProps> = memo( ); if (aggregation === false) { - defaultConfig = handleDefaultConfig(defaultConfig); + defaultConfig = handleDefaultConfig(defaultConfig, config.type); } return <BaseDataConfigSection {...rest} config={defaultConfig} />; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/SizeTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/SizeTypeSection.tsx index c20c96a35..80945cd9e 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/SizeTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/SizeTypeSection.tsx @@ -40,7 +40,7 @@ const SizeTypeSection: FC<ChartDataConfigSectionProps> = memo( ); if (aggregation === false) { - defaultConfig = handleDefaultConfig(defaultConfig); + defaultConfig = handleDefaultConfig(defaultConfig, config.type); } return <BaseDataConfigSection {...rest} config={defaultConfig} />; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/utils.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/utils.ts index 8df78060e..c24dd9075 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/utils.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/utils.ts @@ -16,11 +16,9 @@ * limitations under the License. */ -import { ChartDataSectionFieldActionType } from 'app/types/ChartConfig'; +import { ChartDataSectionType } from 'app/types/ChartConfig'; import { ChartDataConfigSectionProps } from 'app/types/ChartDataConfigSection'; import produce from 'immer'; -import { CloneValueDeep } from 'utils/object'; - export function dataConfigSectionComparer( prevProps: ChartDataConfigSectionProps, nextProps: ChartDataConfigSectionProps, @@ -35,14 +33,19 @@ export function dataConfigSectionComparer( return true; } -export function handleDefaultConfig(defaultConfig): any { +export function handleDefaultConfig(defaultConfig, configType): any { const nextConfig = produce(defaultConfig, draft => { let _actions = {}; draft.rows?.forEach((row, i) => { draft.rows[i].aggregate = undefined; }); - + if (configType === ChartDataSectionType.AGGREGATE) { + delete draft.actions.STRING; + } + if (configType === ChartDataSectionType.GROUP) { + delete draft.actions.NUMERIC; + } for (let key in draft.actions) { _actions[key] = draft.actions[key].filter( v => v !== 'aggregate' && v !== 'aggregateLimit', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx index 65679bc33..1db758985 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx @@ -160,35 +160,6 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = canDrop: (item: ChartDataSectionField, monitor) => { let items = Array.isArray(item) ? item : [item]; - if (aggregation === false) { - let status = false; - let { type } = currentConfig; - - if ( - (type === 'color' || type === 'group') && - items.every(v => v.type === 'DATA' || v.type === 'STRING') - ) { - status = true; - } - - if ( - (type === 'aggregate' || type === 'size' || type === 'info') && - items.every(v => v.type === 'NUMERIC') - ) { - status = true; - } - - if (type === 'mixed') { - status = true; - } - - if (type === 'filter') { - status = true; - } - - return status; - } - if ( Array.isArray(item) && typeof currentConfig.actions === 'object' && diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/AggregationColorizeAction.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/AggregationColorizeAction.tsx index 0656cffc5..608e34c07 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/AggregationColorizeAction.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/AggregationColorizeAction.tsx @@ -23,6 +23,7 @@ import { ThemeColorSelection, } from 'app/components/ColorPicker'; import { ColorTag } from 'app/components/ReactColorPicker'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { ChartDataSectionField } from 'app/types/ChartConfig'; import ChartDataset from 'app/types/ChartDataset'; import { updateBy } from 'app/utils/mutation'; @@ -37,7 +38,8 @@ const AggregationColorizeAction: FC<{ config: ChartDataSectionField, needRefresh?: boolean, ) => void; -}> = memo(({ config, dataset, onConfigChange }) => { + i18nPrefix?: string; +}> = memo(({ config, dataset, onConfigChange, i18nPrefix }) => { const actionNeedNewRequest = true; const [themeColors, setThemeColors] = useState(Theme.color); const [colors, setColors] = useState<{ key: string; value: string }[]>( @@ -45,6 +47,7 @@ const AggregationColorizeAction: FC<{ ); const [selectColor, setSelectColor] = useState(colors[0]); const [selColorBoxStatus, setSelColorBoxStatus] = useState(false); + const t = useI18NPrefix(i18nPrefix); const handleColorChange = value => { if (selectColor) { @@ -105,7 +108,7 @@ const AggregationColorizeAction: FC<{ return ( <> <ThemeColorSelection callbackFn={selectThemeColorFn}> - 选择主题 + {t('chooseTheme')} </ThemeColorSelection> <Row> <Col span={24}> diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraphPanel.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraphPanel.tsx index c57e41f81..fc84e3107 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraphPanel.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraphPanel.tsx @@ -16,7 +16,7 @@ * limitations under the License. */ -import { Popconfirm, Tooltip } from 'antd'; +import { Tooltip } from 'antd'; import { IW } from 'app/components'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; import Chart from 'app/pages/ChartWorkbenchPage/models/Chart'; @@ -148,21 +148,7 @@ const ChartGraphPanel: FC<{ }; return allCharts.map(c => { - if (c?.meta?.id !== 'mingxi-table') { - return _getChartIcon(c, handleChartChange(c?.meta?.id)); - } - - return ( - <Popconfirm - key={c?.meta?.id} - title={t('confirm', undefined, { name: c.meta?.name })} - onConfirm={handleChartChange(c?.meta?.id)} - okText={t('ok')} - cancelText={t('cancel')} - > - {_getChartIcon(c)} - </Popconfirm> - ); + return _getChartIcon(c, handleChartChange(c?.meta?.id)); }); }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartWorkbench/ChartWorkbench.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartWorkbench/ChartWorkbench.tsx index dfc851997..539a9ae13 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartWorkbench/ChartWorkbench.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartWorkbench/ChartWorkbench.tsx @@ -77,7 +77,6 @@ const ChartWorkbench: FC<{ onGoBack={header?.onGoBack} onSaveChart={header?.onSaveChart} onChangeAggregation={header?.onChangeAggregation} - aggregation={aggregation} /> )} <StyledChartOperationPanel> diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/FolderTree.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/FolderTree.tsx index bee1ef7e0..f4c2800c2 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/FolderTree.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/FolderTree.tsx @@ -1,6 +1,7 @@ import { DeleteOutlined, EditOutlined, MoreOutlined } from '@ant-design/icons'; import { Menu, message, Popconfirm } from 'antd'; import { MenuListItem, Popup, Tree, TreeTitle } from 'app/components'; +import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import { CascadeAccess } from 'app/pages/MainPage/Access'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import { LocalTreeDataNode } from 'app/pages/MainPage/slice/types'; @@ -22,18 +23,24 @@ import { getFolders, removeTab, } from '../../slice/thunks'; -interface FolderTreeProps { + +interface FolderTreeProps extends I18NComponentProps { selectedId?: string; treeData?: LocalTreeDataNode[]; } -export function FolderTree({ selectedId, treeData }: FolderTreeProps) { +export function FolderTree({ + selectedId, + treeData, + i18nPrefix, +}: FolderTreeProps) { const dispatch = useDispatch(); const history = useHistory(); const orgId = useSelector(selectOrgId); const loading = useSelector(selectVizListLoading); const vizsData = useSelector(selectVizs); const { showSaveForm } = useContext(SaveFormContext); + const t = useI18NPrefix(i18nPrefix); useEffect(() => { dispatch(getFolders(orgId)); @@ -64,12 +71,12 @@ export function FolderTree({ selectedId, treeData }: FolderTreeProps) { () => { let id = folderId; let archive = false; - let msg = '成功删除'; + let msg = t('folders.folderTree.successDeleted'); if (['DASHBOARD', 'DATACHART'].includes(relType)) { id = relId; archive = true; - msg = '成功移至回收站'; + msg = t('folders.folderTree.successRecycle'); } dispatch( deleteViz({ @@ -82,7 +89,7 @@ export function FolderTree({ selectedId, treeData }: FolderTreeProps) { }), ); }, - [dispatch, redirect], + [dispatch, redirect, t], ); const moreMenuClick = useCallback( @@ -147,19 +154,23 @@ export function FolderTree({ selectedId, treeData }: FolderTreeProps) { key="info" prefix={<EditOutlined className="icon" />} > - 基本信息 + {t('folders.folderTree.info')} </MenuListItem> <MenuListItem key="delete" prefix={<DeleteOutlined className="icon" />} > <Popconfirm - title={`确定${ - node.relType === 'FOLDER' ? '删除' : '移至回收站' + title={`${ + node.relType === 'FOLDER' + ? t('folders.folderTree.confirmDelete') + : t('folders.folderTree.sureMoveRecycleBin') }?`} onConfirm={archiveViz(node)} > - {node.relType === 'FOLDER' ? '删除' : '移至回收站'} + {node.relType === 'FOLDER' + ? t('folders.folderTree.delete') + : t('folders.folderTree.moveToTrash')} </Popconfirm> </MenuListItem> </Menu> @@ -173,7 +184,7 @@ export function FolderTree({ selectedId, treeData }: FolderTreeProps) { </TreeTitle> ); }, - [moreMenuClick, archiveViz], + [moreMenuClick, archiveViz, t], ); const onDrop = info => { 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 5a016f570..ff0211562 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 @@ -7,6 +7,7 @@ import { } from '@ant-design/icons'; import { ListNav, ListPane, ListTitle } from 'app/components'; import { useDebouncedSearch } from 'app/hooks/useDebouncedSearch'; +import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import { BoardTypeMap } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import { getInitBoardConfig } from 'app/pages/DashBoardPage/utils/board'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; @@ -33,161 +34,176 @@ import { import { FolderViewModel, VizType } from '../../slice/types'; import { Recycle } from '../Recycle'; import { FolderTree } from './FolderTree'; -interface FoldersProps { + +interface FoldersProps extends I18NComponentProps { selectedId?: string; className?: string; } -export const Folders = memo(({ selectedId, className }: FoldersProps) => { - const dispatch = useDispatch(); - const orgId = useSelector(selectOrgId); - const { showSaveForm } = useContext(SaveFormContext); - const selectVizTree = useMemo(makeSelectVizTree, []); - const vizsData = useSelector(selectVizs); - const getInitValues = useCallback((relType: VizType) => { - if (relType === 'DASHBOARD') { - return { - name: '', - boardType: BoardTypeMap.auto, - } as SaveFormModel; - } - return undefined; - }, []); +export const Folders = memo( + ({ selectedId, className, i18nPrefix }: FoldersProps) => { + const dispatch = useDispatch(); + const orgId = useSelector(selectOrgId); + const { showSaveForm } = useContext(SaveFormContext); + const selectVizTree = useMemo(makeSelectVizTree, []); + const vizsData = useSelector(selectVizs); + const t = useI18NPrefix(i18nPrefix); + const getInitValues = useCallback((relType: VizType) => { + if (relType === 'DASHBOARD') { + return { + name: '', + boardType: BoardTypeMap.auto, + } as SaveFormModel; + } + return undefined; + }, []); - const updateValue = useCallback((relType: VizType, values: SaveFormModel) => { - const dataValues = values; - if (relType === 'DASHBOARD') { - dataValues.config = JSON.stringify( - getInitBoardConfig(values.boardType || BoardTypeMap.auto), - ); - } - return dataValues; - }, []); + const updateValue = useCallback( + (relType: VizType, values: SaveFormModel) => { + const dataValues = values; + if (relType === 'DASHBOARD') { + dataValues.config = JSON.stringify( + getInitBoardConfig(values.boardType || BoardTypeMap.auto), + ); + } + return dataValues; + }, + [], + ); - const getIcon = useCallback(({ relType }: FolderViewModel) => { - switch (relType) { - case 'DASHBOARD': - return <FundFilled />; - case 'DATACHART': - return <BarChartOutlined />; - default: - return p => (p.expanded ? <FolderOpenFilled /> : <FolderFilled />); - } - }, []); - const getDisabled = useCallback( - ({ deleteLoading }: FolderViewModel) => deleteLoading, - [], - ); + const getIcon = useCallback(({ relType }: FolderViewModel) => { + switch (relType) { + case 'DASHBOARD': + return <FundFilled />; + case 'DATACHART': + return <BarChartOutlined />; + default: + return p => (p.expanded ? <FolderOpenFilled /> : <FolderFilled />); + } + }, []); + const getDisabled = useCallback( + ({ deleteLoading }: FolderViewModel) => deleteLoading, + [], + ); - const treeData = useSelector(state => - selectVizTree(state, { getIcon, getDisabled }), - ); - const { filteredData: filteredTreeData, debouncedSearch: treeSearch } = - useDebouncedSearch(treeData, (keywords, d) => - d.title.toLowerCase().includes(keywords.toLowerCase()), + const treeData = useSelector(state => + selectVizTree(state, { getIcon, getDisabled }), ); - const archivedDatacharts = useSelector(selectArchivedDatacharts); - const archivedDashboards = useSelector(selectArchivedDashboards); - const archivedDatachartloading = useSelector(selectArchivedDatachartLoading); - const archivedDashboardloading = useSelector(selectArchivedDashboardLoading); - const { filteredData: filteredListData, debouncedSearch: listSearch } = - useDebouncedSearch( - archivedDatacharts.concat(archivedDashboards), - (keywords, d) => d.name.toLowerCase().includes(keywords.toLowerCase()), + const { filteredData: filteredTreeData, debouncedSearch: treeSearch } = + useDebouncedSearch(treeData, (keywords, d) => + d.title.toLowerCase().includes(keywords.toLowerCase()), + ); + const archivedDatacharts = useSelector(selectArchivedDatacharts); + const archivedDashboards = useSelector(selectArchivedDashboards); + const archivedDatachartloading = useSelector( + selectArchivedDatachartLoading, + ); + const archivedDashboardloading = useSelector( + selectArchivedDashboardLoading, ); + const { filteredData: filteredListData, debouncedSearch: listSearch } = + useDebouncedSearch( + archivedDatacharts.concat(archivedDashboards), + (keywords, d) => d.name.toLowerCase().includes(keywords.toLowerCase()), + ); - const recycleInit = useCallback(() => { - dispatch(getArchivedDatacharts(orgId)); - dispatch(getArchivedDashboards(orgId)); - }, [dispatch, orgId]); + const recycleInit = useCallback(() => { + dispatch(getArchivedDatacharts(orgId)); + dispatch(getArchivedDashboards(orgId)); + }, [dispatch, orgId]); - const add = useCallback( - ({ key }) => { - showSaveForm({ - vizType: key, - type: CommonFormTypes.Add, - visible: true, - initialValues: getInitValues(key), - onSave: (values, onClose) => { - const dataValues = updateValue(key, values); + const add = useCallback( + ({ key }) => { + showSaveForm({ + vizType: key, + type: CommonFormTypes.Add, + visible: true, + initialValues: getInitValues(key), + onSave: (values, onClose) => { + const dataValues = updateValue(key, values); - let index = getInsertedNodeIndex(values, vizsData); + let index = getInsertedNodeIndex(values, vizsData); - dispatch( - addViz({ - viz: { ...dataValues, orgId: orgId, index: index }, - type: key, - resolve: onClose, - }), - ); - }, - }); - }, - [showSaveForm, getInitValues, updateValue, dispatch, orgId, vizsData], - ); + dispatch( + addViz({ + viz: { ...dataValues, orgId: orgId, index: index }, + type: key, + resolve: onClose, + }), + ); + }, + }); + }, + [showSaveForm, getInitValues, updateValue, dispatch, orgId, vizsData], + ); - const titles = useMemo( - () => [ - { - subTitle: '仪表板 & 数据图表', - add: { - items: [ - { key: 'DASHBOARD', text: '新建仪表板' }, - { key: 'DATACHART', text: '新建数据图表' }, - { key: 'FOLDER', text: '新建目录' }, - ], - callback: add, - }, - more: { - items: [ - { - key: 'recycle', - text: '回收站', - prefix: <DeleteOutlined className="icon" />, + const titles = useMemo( + () => [ + { + subTitle: t('folders.folderTitle'), + add: { + items: [ + { key: 'DASHBOARD', text: t('folders.dashboard') }, + { key: 'DATACHART', text: t('folders.dataChart') }, + { key: 'FOLDER', text: t('folders.folder') }, + ], + callback: add, + }, + more: { + items: [ + { + key: 'recycle', + text: t('folders.recycle'), + prefix: <DeleteOutlined className="icon" />, + }, + ], + callback: (key, _, onNext) => { + switch (key) { + case 'recycle': + onNext(); + break; + } }, - ], - callback: (key, _, onNext) => { - switch (key) { - case 'recycle': - onNext(); - break; - } }, + search: true, + onSearch: treeSearch, }, - search: true, - onSearch: treeSearch, - }, - { - key: 'recycle', - subTitle: '回收站', - back: true, - search: true, - onSearch: listSearch, - }, - ], - [add, treeSearch, listSearch], - ); + { + key: 'recycle', + subTitle: t('folders.recycle'), + back: true, + search: true, + onSearch: listSearch, + }, + ], + [add, treeSearch, listSearch, t], + ); - return ( - <Wrapper className={className} defaultActiveKey="list"> - <ListPane key="list"> - <ListTitle {...titles[0]} /> - <FolderTree treeData={filteredTreeData} selectedId={selectedId} /> - </ListPane> - <ListPane key="recycle"> - <ListTitle {...titles[1]} /> - <Recycle - type="viz" - orgId={orgId} - list={filteredListData} - listLoading={archivedDashboardloading || archivedDatachartloading} - selectedId={selectedId} - onInit={recycleInit} - /> - </ListPane> - </Wrapper> - ); -}); + return ( + <Wrapper className={className} defaultActiveKey="list"> + <ListPane key="list"> + <ListTitle {...titles[0]} /> + <FolderTree + treeData={filteredTreeData} + selectedId={selectedId} + i18nPrefix={i18nPrefix} + /> + </ListPane> + <ListPane key="recycle"> + <ListTitle {...titles[1]} /> + <Recycle + type="viz" + orgId={orgId} + list={filteredListData} + listLoading={archivedDashboardloading || archivedDatachartloading} + selectedId={selectedId} + onInit={recycleInit} + /> + </ListPane> + </Wrapper> + ); + }, +); const Wrapper = styled(ListNav)` display: flex; 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 1f91717dd..e9c0e86f6 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Recycle.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Recycle.tsx @@ -6,6 +6,7 @@ import { } from '@ant-design/icons'; import { Button, List, Menu, message, Popconfirm } from 'antd'; import { ListItem, MenuListItem, Popup } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { calcAc, getCascadeAccess } from 'app/pages/MainPage/Access'; import { selectIsOrgOwner, @@ -45,6 +46,7 @@ export const Recycle = memo( const vizs = useSelector(selectVizs); const isOwner = useSelector(selectIsOrgOwner); const permissionMap = useSelector(selectPermissionMap); + const t = useI18NPrefix('viz.sideBar.recycle'); useEffect(() => { onInit(); @@ -69,13 +71,13 @@ export const Recycle = memo( params: { id, archive: false }, type, resolve: () => { - message.success('删除成功'); + message.success(t('successDeleted')); dispatch(removeTab({ id, resolve: redirect })); }, }), ); }, - [dispatch, redirect], + [dispatch, redirect, t], ); const moreMenuClick = useCallback( @@ -102,7 +104,7 @@ export const Recycle = memo( index, }, resolve: () => { - message.success('还原成功'); + message.success(t('successRestored')); dispatch(removeTab({ id, resolve: redirect })); onClose(); }, @@ -115,7 +117,7 @@ export const Recycle = memo( break; } }, - [dispatch, showSaveForm, redirect, vizs], + [dispatch, showSaveForm, redirect, vizs, t], ); const toDetail = useCallback( @@ -180,17 +182,17 @@ export const Recycle = memo( key="reset" prefix={<ReloadOutlined className="icon" />} > - 还原 + {t('reduction')} </MenuListItem> <MenuListItem key="delelte" prefix={<DeleteOutlined className="icon" />} > <Popconfirm - title="确认删除?" + title={t('confirmDeletion') + '?'} onConfirm={del(id, vizType)} > - 删除 + {t('delete')} </Popconfirm> </MenuListItem> </Menu> diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Storyboards/index.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Storyboards/index.tsx index ce0818aef..8de2fd442 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Storyboards/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Storyboards/index.tsx @@ -1,6 +1,7 @@ import { DeleteOutlined, PlusOutlined } from '@ant-design/icons'; import { ListNav, ListPane, ListTitle } from 'app/components'; import { useDebouncedSearch } from 'app/hooks/useDebouncedSearch'; +import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import { useAccess } from 'app/pages/MainPage/Access'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import { CommonFormTypes } from 'globalConstants'; @@ -19,110 +20,117 @@ import { allowCreateStoryboard } from '../../utils'; import { Recycle } from '../Recycle'; import { List } from './List'; -interface FoldersProps { +interface FoldersProps extends I18NComponentProps { selectedId?: string; className?: string; } -export const Storyboards = memo(({ selectedId, className }: FoldersProps) => { - const dispatch = useDispatch(); - const orgId = useSelector(selectOrgId); - const { showSaveForm } = useContext(SaveFormContext); - const list = useSelector(selectStoryboards); - const allowCreate = useAccess(allowCreateStoryboard()); +export const Storyboards = memo( + ({ selectedId, className, i18nPrefix }: FoldersProps) => { + const dispatch = useDispatch(); + const orgId = useSelector(selectOrgId); + const { showSaveForm } = useContext(SaveFormContext); + const list = useSelector(selectStoryboards); + const allowCreate = useAccess(allowCreateStoryboard()); + const t = useI18NPrefix(i18nPrefix); - const { filteredData: filteredListData, debouncedSearch: listSearch } = - useDebouncedSearch(list, (keywords, d) => - d.name.toLowerCase().includes(keywords.toLowerCase()), - ); - const archived = useSelector(selectArchivedStoryboards); - const archivedListLoading = useSelector(selectArchivedStoryboardLoading); - const { filteredData: filteredRecycleData, debouncedSearch: recycleSearch } = - useDebouncedSearch(archived, (keywords, d) => + const { filteredData: filteredListData, debouncedSearch: listSearch } = + useDebouncedSearch(list, (keywords, d) => + d.name.toLowerCase().includes(keywords.toLowerCase()), + ); + const archived = useSelector(selectArchivedStoryboards); + const archivedListLoading = useSelector(selectArchivedStoryboardLoading); + const { + filteredData: filteredRecycleData, + debouncedSearch: recycleSearch, + } = useDebouncedSearch(archived, (keywords, d) => d.name.toLowerCase().includes(keywords.toLowerCase()), ); - const recycleInit = useCallback(() => { - dispatch(getArchivedStoryboards(orgId)); - }, [dispatch, orgId]); + const recycleInit = useCallback(() => { + dispatch(getArchivedStoryboards(orgId)); + }, [dispatch, orgId]); - const add = useCallback(() => { - showSaveForm({ - vizType: 'STORYBOARD', - type: CommonFormTypes.Add, - visible: true, - onSave: (values, onClose) => { - dispatch( - addStoryboard({ - storyboard: { name: values.name, orgId }, - resolve: onClose, - }), - ); - }, - }); - }, [showSaveForm, dispatch, orgId]); + const add = useCallback(() => { + showSaveForm({ + vizType: 'STORYBOARD', + type: CommonFormTypes.Add, + visible: true, + onSave: (values, onClose) => { + dispatch( + addStoryboard({ + storyboard: { name: values.name, orgId }, + resolve: onClose, + }), + ); + }, + }); + }, [showSaveForm, dispatch, orgId]); - const titles = useMemo( - () => [ - { - subTitle: '故事板列表', - search: true, - ...allowCreate({ - add: { - items: [{ key: 'STORYBOARD', text: '新建故事板' }], - icon: <PlusOutlined />, - callback: add, - }, - }), - more: { - items: [ - { - key: 'recycle', - text: '回收站', - prefix: <DeleteOutlined className="icon" />, + const titles = useMemo( + () => [ + { + subTitle: t('storyBoards.storyBoardsList'), + search: true, + ...allowCreate({ + add: { + items: [ + { key: 'STORYBOARD', text: t('storyBoards.newStoryBoards') }, + ], + icon: <PlusOutlined />, + callback: add, + }, + }), + more: { + items: [ + { + key: 'recycle', + text: t('storyBoards.recycle'), + prefix: <DeleteOutlined className="icon" />, + }, + ], + callback: (key, _, onNext) => { + switch (key) { + case 'recycle': + onNext(); + break; + } }, - ], - callback: (key, _, onNext) => { - switch (key) { - case 'recycle': - onNext(); - break; - } }, + onSearch: listSearch, + }, + { + key: 'recycle', + subTitle: t('storyBoards.recycle'), + back: true, + search: true, + onSearch: recycleSearch, }, - onSearch: listSearch, - }, - { - key: 'recycle', - subTitle: '回收站', - back: true, - search: true, - onSearch: recycleSearch, - }, - ], - [add, allowCreate, listSearch, recycleSearch], - ); + ], + [add, allowCreate, listSearch, recycleSearch, t], + ); - return ( - <Wrapper className={className} defaultActiveKey="list"> - <ListPane key="list"> - <ListTitle {...titles[0]} /> - <List list={filteredListData} selectedId={selectedId} /> - </ListPane> - <ListPane key="recycle"> - <ListTitle {...titles[1]} /> - <Recycle - type="storyboard" - orgId={orgId} - list={filteredRecycleData} - listLoading={archivedListLoading} - selectedId={selectedId} - onInit={recycleInit} - /> - </ListPane> - </Wrapper> - ); -}); + return ( + <Wrapper className={className} defaultActiveKey="list"> + <ListPane key="list"> + <ListTitle {...titles[0]} /> + <List list={filteredListData} selectedId={selectedId} /> + </ListPane> + <ListPane key="recycle"> + <ListTitle {...titles[1]} /> + <Recycle + type="storyboard" + orgId={orgId} + list={filteredRecycleData} + listLoading={archivedListLoading} + selectedId={selectedId} + onInit={recycleInit} + /> + </ListPane> + </Wrapper> + ); + }, +); const Wrapper = styled(ListNav)` display: flex; diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/index.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/index.tsx index 3cfc6e66b..ba6479600 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/index.tsx @@ -3,6 +3,7 @@ import { FundProjectionScreenOutlined, } from '@ant-design/icons'; import { ListSwitch } from 'app/components'; +import useI18NPrefix, { I18NComponentProps } from 'app/hooks/useI18NPrefix'; import classnames from 'classnames'; import { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; @@ -14,7 +15,7 @@ import { Folder } from '../slice/types'; import { Folders } from './Folders'; import { Storyboards } from './Storyboards'; -export const Sidebar = memo(() => { +export const Sidebar = memo(({ i18nPrefix }: I18NComponentProps) => { const [selectedKey, setSelectedKey] = useState('folder'); const vizs = useSelector(selectVizs); const storyboards = useSelector(selectStoryboards); @@ -22,6 +23,7 @@ export const Sidebar = memo(() => { '/organizations/:orgId/vizs/:vizId', ); const vizId = matchDetail?.params.vizId; + const t = useI18NPrefix(i18nPrefix); const selectedFolderId = useMemo(() => { if (vizId && vizs) { const viz = vizs.find(({ relId }) => relId === vizId); @@ -42,11 +44,11 @@ export const Sidebar = memo(() => { const listTitles = useMemo( () => [ - { key: 'folder', icon: <FolderAddFilled />, text: '目录' }, + { key: 'folder', icon: <FolderAddFilled />, text: t('folder') }, { key: 'presentation', icon: <FundProjectionScreenOutlined />, - text: '演示', + text: t('presentation'), }, ], [], @@ -65,11 +67,13 @@ export const Sidebar = memo(() => { /> <Folders selectedId={selectedFolderId} + i18nPrefix={i18nPrefix} className={classnames({ hidden: selectedKey !== 'folder' })} /> <Storyboards selectedId={vizId} className={classnames({ hidden: selectedKey !== 'presentation' })} + i18nPrefix={i18nPrefix} /> </Wrapper> ); diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx index 8ae35611a..0755c8c43 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx @@ -43,7 +43,7 @@ export function VizPage() { onDragEnd={siderDragEnd} className="datart-split" > - <Sidebar /> + <Sidebar i18nPrefix={'viz.sideBar'} /> <Main /> <SaveForm width={400} diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 54312f896..bf493f9ce 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -369,7 +369,8 @@ "colorize": "colorize", "colorRange": "colorize", "colorSingle": "colorize", - "size": "size" + "size": "size", + "chooseTheme": "Choose theme" } } }, @@ -483,6 +484,38 @@ "query": "Query", "reset": "Reset" } + }, + "sideBar": { + "folder": "目录", + "presentation": "演示", + "folders": { + "folderTitle": "仪表板 & 数据图表", + "dashboard": "新建仪表板", + "dataChart": "新建数据图表", + "folder": "新建目录", + "recycle": "回收站", + "folderTree": { + "successDeleted": "成功删除", + "successRecycle": "成功移至回收站", + "info": "基本信息", + "delete": "删除", + "moveToTrash": "移至回收站", + "confirmDelete": "确定删除", + "sureMoveRecycleBin": "确定移至回收站" + } + }, + "storyBoards": { + "storyBoardsList": "故事板列表", + "newStoryBoards": "新建故事板", + "recycle": "回收站" + }, + "recycle": { + "successDeleted": "删除成功", + "successRestored": "还原成功", + "reduction": "还原", + "confirmDeletion": "确认删除", + "delete": "删除" + } } }, "share": { @@ -501,6 +534,10 @@ "more": "More", "ok": "OK", "cancel": "Cancel" + }, + "listTitle": { + "search": "Search", + "searchValue": "Search name keywords" } } -} \ No newline at end of file +} diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 599b7acd6..398ae4155 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -369,7 +369,8 @@ "colorize": "着色", "colorRange": "着色", "colorSingle": "着色", - "size": "大小" + "size": "大小", + "chooseTheme": "选择主题" } } }, @@ -483,6 +484,38 @@ "query": "查询", "reset": "重置" } + }, + "sideBar": { + "folder": "目录", + "presentation": "演示", + "folders": { + "folderTitle": "仪表板 & 数据图表", + "dashboard": "新建仪表板", + "dataChart": "新建数据图表", + "folder": "新建目录", + "recycle": "回收站", + "folderTree": { + "successDeleted": "成功删除", + "successRecycle": "成功移至回收站", + "info": "基本信息", + "delete": "删除", + "moveToTrash": "移至回收站", + "confirmDelete": "确定删除", + "sureMoveRecycleBin": "确定移至回收站" + } + }, + "storyBoards": { + "storyBoardsList": "故事板列表", + "newStoryBoards": "新建故事板", + "recycle": "回收站" + }, + "recycle": { + "successDeleted": "删除成功", + "successRestored": "还原成功", + "reduction": "还原", + "confirmDeletion": "确认删除", + "delete": "删除" + } } }, "share": { @@ -501,6 +534,10 @@ "more": "更多", "ok": "确认", "cancel": "取消" + }, + "listTitle": { + "search": "搜索", + "searchValue": "搜索名称关键字" } } } From 40acffa3be24ca213a1470fc910c8ed648eddd2b Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Tue, 28 Dec 2021 15:55:40 +0800 Subject: [PATCH 241/348] feat: Remove prompt when switching chart types --- frontend/src/app/components/ChartEditor.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/components/ChartEditor.tsx b/frontend/src/app/components/ChartEditor.tsx index 87b14c091..86c8edd85 100644 --- a/frontend/src/app/components/ChartEditor.tsx +++ b/frontend/src/app/components/ChartEditor.tsx @@ -130,7 +130,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ setChart(currentChart); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [backendChart?.config]); + }, [backendChart?.config.chartGraphId]); const handleChartChange = (c: Chart) => { registerChartEvents(c); From bcb06b5a4463f89700f6fb600f2ce559a7d2f08c Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Mon, 27 Dec 2021 17:46:34 +0800 Subject: [PATCH 242/348] fix:(SaveForm) fix check name errer message --- .../components/ChartGraph/BasicRichText/BasicRichText.tsx | 1 - .../MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx | 3 ++- frontend/src/app/pages/MainPage/pages/OrgSettingPage/index.tsx | 3 ++- .../pages/MainPage/pages/SourcePage/SourceDetailPage/index.tsx | 3 ++- .../src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx | 3 ++- frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx | 3 ++- frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx | 3 ++- 7 files changed, 12 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/BasicRichText.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/BasicRichText.tsx index 7d1d52b9a..bdfa09ebe 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/BasicRichText.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicRichText/BasicRichText.tsx @@ -57,7 +57,6 @@ class BasicRichText extends ReactChart { } onMount(options, context): void { - console.log(context); if (options.containerId === undefined || !context.document) { return; } diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx index 959e4c3db..8c53781dd 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx @@ -180,7 +180,8 @@ export function RoleDetailPage() { params: { name: value, orgId }, }).then( () => Promise.resolve(), - () => Promise.reject(new Error('名称重复')), + (err: any) => + Promise.reject(new Error(err.response.data.message)), ); }, DEFAULT_DEBOUNCE_WAIT), }, diff --git a/frontend/src/app/pages/MainPage/pages/OrgSettingPage/index.tsx b/frontend/src/app/pages/MainPage/pages/OrgSettingPage/index.tsx index a9a67b326..c3e58f0d9 100644 --- a/frontend/src/app/pages/MainPage/pages/OrgSettingPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/OrgSettingPage/index.tsx @@ -128,7 +128,8 @@ export function OrgSettingPage() { params: { name: value }, }).then( () => Promise.resolve(), - () => Promise.reject(new Error('名称重复')), + (err: any) => + Promise.reject(new Error(err.response.data.message)), ); }, DEFAULT_DEBOUNCE_WAIT), }, 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 b2b8a2096..3a3dcd9e6 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/index.tsx @@ -352,7 +352,8 @@ export function SourceDetailPage() { params: { name: value, orgId }, }).then( () => Promise.resolve(), - () => Promise.reject(new Error('名称重复')), + (err: any) => + Promise.reject(new Error(err.response.data.message)), ); }, DEFAULT_DEBOUNCE_WAIT), }, diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx index 8c87ca3b3..4d11f6334 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx @@ -120,7 +120,8 @@ export const VariableForm = memo( params: { name: value, orgId }, }).then( () => Promise.resolve(), - () => Promise.reject(new Error('名称重复')), + (err: any) => + Promise.reject(new Error(err.response.data.message)), ); }, DEFAULT_DEBOUNCE_WAIT), [scope, editingVariable?.name, variables, orgId], diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx index a4043b392..199f63a2f 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx @@ -139,7 +139,8 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { params: { name: value, orgId, parentId: parentId || null }, }).then( () => Promise.resolve(), - () => Promise.reject(new Error('名称重复')), + (err: any) => + Promise.reject(new Error(err.response.data.message)), ); }, DEFAULT_DEBOUNCE_WAIT), }, diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx index 35e2e5ad1..bb262994d 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx @@ -119,7 +119,8 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { }, }).then( () => Promise.resolve(), - () => Promise.reject(new Error('名称重复')), + (err: any) => + Promise.reject(new Error(err.response.data.message)), ); }, DEFAULT_DEBOUNCE_WAIT), }, From 3f298ebec780e857fcdaa39ae7634b2a14b87fad Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Mon, 27 Dec 2021 17:57:06 +0800 Subject: [PATCH 243/348] fix:(Chart) fix pie tooltip and label --- .../BasicPieChart/BasicPieChart.tsx | 107 +++++++++++++----- .../ChartGraph/BasicPieChart/config.ts | 21 ++++ 2 files changed, 102 insertions(+), 26 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx index 6703a64c2..c94f7b853 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx @@ -21,18 +21,18 @@ import { ChartConfig, ChartDataSectionField, ChartDataSectionType, - ChartStyleSectionConfig, } from 'app/types/ChartConfig'; import ChartDataset from 'app/types/ChartDataset'; import { getColumnRenderName, getExtraSeriesDataFormat, getExtraSeriesRowData, - getSeriesTooltips4Polar2, getStyleValueByGroup, getValueByColumnKey, transformToObjectArray, + valueFormatter, } from 'app/utils/chartHelper'; +import { toFormattedValue } from 'app/utils/number'; import { init } from 'echarts'; import Config from './config'; @@ -107,6 +107,7 @@ class BasicPieChart extends Chart { dataColumns, groupConfigs, aggregateConfigs, + infoConfigs, ); return { @@ -124,18 +125,27 @@ class BasicPieChart extends Chart { }; } - private getSeries(styleConfigs, dataColumns, groupConfigs, aggregateConfigs) { + private getSeries( + styleConfigs, + dataColumns, + groupConfigs, + aggregateConfigs, + infoConfigs, + ) { if (!groupConfigs?.length) { const dc = dataColumns?.[0]; return { ...this.getBarSeiesImpl(styleConfigs), data: aggregateConfigs.map(config => { return { - ...getExtraSeriesRowData(dc), - ...getExtraSeriesDataFormat(config?.format), + ...config, name: getColumnRenderName(config), - value: dc[getValueByColumnKey(config)], + value: [config] + .concat(infoConfigs) + .map(config => dc?.[getValueByColumnKey(config)]), itemStyle: this.getDataItemStyle(config, groupConfigs, dc), + ...getExtraSeriesRowData(dc), + ...getExtraSeriesDataFormat(config?.format), }; }), }; @@ -148,11 +158,14 @@ class BasicPieChart extends Chart { name: getColumnRenderName(config), data: dataColumns.map(dc => { return { - ...getExtraSeriesRowData(dc), - ...getExtraSeriesDataFormat(config?.format), + ...config, name: groupedConfigNames.map(config => dc[config]).join('-'), - value: dc[getValueByColumnKey(config)], + value: aggregateConfigs + .concat(infoConfigs) + .map(config => dc?.[getValueByColumnKey(config)]), itemStyle: this.getDataItemStyle(config, groupConfigs, dc), + ...getExtraSeriesRowData(dc), + ...getExtraSeriesDataFormat(config?.format), }; }), }; @@ -258,7 +271,29 @@ class BasicPieChart extends Chart { const show = getStyleValueByGroup(styles, 'label', 'showLabel'); const position = getStyleValueByGroup(styles, 'label', 'position'); const font = getStyleValueByGroup(styles, 'label', 'font'); - return { show, position, ...font, formatter: '{b}: {d}%' }; + const formatter = this.getLabelFormatter(styles); + return { show, position, ...font, formatter }; + } + + getLabelFormatter(styles) { + const showValue = getStyleValueByGroup(styles, 'label', 'showValue'); + const showPercent = getStyleValueByGroup(styles, 'label', 'showPercent'); + const showName = getStyleValueByGroup(styles, 'label', 'showName'); + return seriesParams => { + if (seriesParams.componentType !== 'series') { + return seriesParams.name; + } + const data = seriesParams?.data || {}; + return `${showName ? seriesParams?.name + ': ' : ''}${ + showValue ? toFormattedValue(seriesParams?.value[0], data?.format) : '' + }${ + showPercent && showValue + ? '(' + seriesParams?.percent + '%)' + : showPercent + ? seriesParams?.percent + '%' + : '' + }`; + }; } getSeriesStyle(styles) { @@ -269,15 +304,6 @@ class BasicPieChart extends Chart { return { radius: radiusValue, roseType: this.isRose }; } - getStyleValueByGroup( - styles: ChartStyleSectionConfig[], - groupPath: string, - childPath: string, - ) { - const childPaths = childPath.split('.'); - return this.getStyleValue(styles, [groupPath, ...childPaths]); - } - getTooltipFormmaterFunc( styleConfigs, groupConfigs, @@ -289,14 +315,43 @@ class BasicPieChart extends Chart { if (seriesParams.componentType !== 'series') { return seriesParams.name; } - return getSeriesTooltips4Polar2( - seriesParams, - groupConfigs, - [], - aggregateConfigs, - infoConfigs, - [], + const showPercentage = getStyleValueByGroup( + styleConfigs, + 'tooltip', + 'showPercentage', ); + const { data, value, percent } = seriesParams; + if (!groupConfigs?.length) { + const tooltip = [data] + .concat(infoConfigs) + .map((config, index) => valueFormatter(config, value?.[index])); + if (showPercentage) { + tooltip[0] += '(' + percent + '%)'; + } + return tooltip.join('<br />'); + } + let tooltip = aggregateConfigs + .concat(infoConfigs) + .map((config, index) => valueFormatter(config, value?.[index])); + const infoTotal = infoConfigs.map(info => { + let total = 0; + dataColumns.map(dc => { + total += dc?.[getValueByColumnKey(info)]; + }); + return total; + }); + if (showPercentage) { + tooltip = tooltip.map((item, index) => { + if (!index) { + return (item += '(' + percent + '%)'); + } + const percentNum = + (value?.[aggregateConfigs?.length] / infoTotal?.[index - 1]) * + 100 || 0; + return (item += '(' + percentNum.toFixed(2) + '%)'); + }); + } + return tooltip.join('<br />'); }; } } diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts index bfcb60db0..ccdd4c288 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts @@ -87,6 +87,24 @@ const config: ChartConfig = { color: '#495057', }, }, + { + label: 'label.showName', + key: 'showName', + default: true, + comType: 'checkbox', + }, + { + label: 'label.showValue', + key: 'showValue', + default: false, + comType: 'checkbox', + }, + { + label: 'label.showPercent', + key: 'showPercent', + default: true, + comType: 'checkbox', + }, ], }, { @@ -239,6 +257,9 @@ const config: ChartConfig = { title: '标签', showLabel: '显示标签', position: '位置', + showName: '维度值', + showPercent: '百分比', + showValue: '指标值', }, legend: { title: '图例', From b0c169848ad947e1db5ceac743ffd39b33d0516a Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Mon, 27 Dec 2021 18:27:04 +0800 Subject: [PATCH 244/348] fix:(Chart) fix pie tooltip --- .../BasicPieChart/BasicPieChart.tsx | 52 +++++++++---------- .../ChartGraph/BasicPieChart/config.ts | 13 ----- 2 files changed, 25 insertions(+), 40 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx index c94f7b853..e5d98dcf7 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx @@ -112,7 +112,7 @@ class BasicPieChart extends Chart { return { tooltip: { - formatter: this.getTooltipFormmaterFunc( + formatter: this.getTooltipFormatterFunc( styleConfigs, groupConfigs, aggregateConfigs, @@ -284,15 +284,22 @@ class BasicPieChart extends Chart { return seriesParams.name; } const data = seriesParams?.data || {}; - return `${showName ? seriesParams?.name + ': ' : ''}${ - showValue ? toFormattedValue(seriesParams?.value[0], data?.format) : '' - }${ - showPercent && showValue - ? '(' + seriesParams?.percent + '%)' - : showPercent - ? seriesParams?.percent + '%' - : '' - }`; + let labelValue = ''; + if (showName) { + labelValue = seriesParams?.name; + } + if (showName && (showValue || showPercent)) { + labelValue += ': '; + } + if (showValue) { + labelValue += toFormattedValue(seriesParams?.value[0], data?.format); + } + if (showPercent && showValue) { + labelValue += '(' + seriesParams?.percent + '%)'; + } else if (showPercent) { + labelValue += seriesParams?.percent + '%'; + } + return labelValue; }; } @@ -304,7 +311,7 @@ class BasicPieChart extends Chart { return { radius: radiusValue, roseType: this.isRose }; } - getTooltipFormmaterFunc( + getTooltipFormatterFunc( styleConfigs, groupConfigs, aggregateConfigs, @@ -315,24 +322,14 @@ class BasicPieChart extends Chart { if (seriesParams.componentType !== 'series') { return seriesParams.name; } - const showPercentage = getStyleValueByGroup( - styleConfigs, - 'tooltip', - 'showPercentage', - ); const { data, value, percent } = seriesParams; if (!groupConfigs?.length) { const tooltip = [data] .concat(infoConfigs) .map((config, index) => valueFormatter(config, value?.[index])); - if (showPercentage) { - tooltip[0] += '(' + percent + '%)'; - } + tooltip[0] += '(' + percent + '%)'; return tooltip.join('<br />'); } - let tooltip = aggregateConfigs - .concat(infoConfigs) - .map((config, index) => valueFormatter(config, value?.[index])); const infoTotal = infoConfigs.map(info => { let total = 0; dataColumns.map(dc => { @@ -340,17 +337,18 @@ class BasicPieChart extends Chart { }); return total; }); - if (showPercentage) { - tooltip = tooltip.map((item, index) => { + let tooltip = aggregateConfigs + .concat(infoConfigs) + .map((config, index) => { + let tooltipValue = valueFormatter(config, value?.[index]); if (!index) { - return (item += '(' + percent + '%)'); + return (tooltipValue += '(' + percent + '%)'); } const percentNum = (value?.[aggregateConfigs?.length] / infoTotal?.[index - 1]) * 100 || 0; - return (item += '(' + percentNum.toFixed(2) + '%)'); + return (tooltipValue += '(' + percentNum.toFixed(2) + '%)'); }); - } return tooltip.join('<br />'); }; } diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts index ccdd4c288..df9ae1f2f 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts @@ -201,19 +201,6 @@ const config: ChartConfig = { }, ], }, - { - label: 'tooltip.title', - key: 'tooltip', - comType: 'group', - rows: [ - { - label: 'tooltip.showPercentage', - key: 'showPercentage', - default: false, - comType: 'checkbox', - }, - ], - }, ], settings: [ { From d90499bed37cfb7c984b02d289e9bb15ecba2dfd Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Tue, 28 Dec 2021 16:12:42 +0800 Subject: [PATCH 245/348] fix:(Chart)fix filtered resource function --- frontend/src/app/hooks/useDebouncedSearch.ts | 10 +++++- frontend/src/app/hooks/useSearchAndExpand.ts | 8 ++--- .../ViewPage/Main/Properties/Resource.tsx | 11 +++--- frontend/src/utils/utils.ts | 35 +++++++++++++++++++ 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/frontend/src/app/hooks/useDebouncedSearch.ts b/frontend/src/app/hooks/useDebouncedSearch.ts index 6d887cedf..9a4a00b45 100644 --- a/frontend/src/app/hooks/useDebouncedSearch.ts +++ b/frontend/src/app/hooks/useDebouncedSearch.ts @@ -19,7 +19,7 @@ import { DEFAULT_DEBOUNCE_WAIT } from 'globalConstants'; import debounce from 'lodash/debounce'; import { useMemo, useState } from 'react'; -import { filterListOrTree } from 'utils/utils'; +import { filteredResourceTree, filterListOrTree } from 'utils/utils'; export function useDebouncedSearch<T>( dataSource: T[] | undefined, @@ -36,6 +36,13 @@ export function useDebouncedSearch<T>( [dataSource, keywords, filterFunc], ); + const filteredResource = useMemo( + () => + dataSource && keywords.trim() + ? filteredResourceTree(dataSource, keywords, filterFunc) + : dataSource, + [dataSource, keywords, filterFunc], + ); const debouncedSearch = useMemo(() => { const search = e => { setKeywords(e.target.value); @@ -47,5 +54,6 @@ export function useDebouncedSearch<T>( keywords, filteredData, debouncedSearch, + filteredResource, }; } diff --git a/frontend/src/app/hooks/useSearchAndExpand.ts b/frontend/src/app/hooks/useSearchAndExpand.ts index a86e3cc84..05df62d8c 100644 --- a/frontend/src/app/hooks/useSearchAndExpand.ts +++ b/frontend/src/app/hooks/useSearchAndExpand.ts @@ -29,11 +29,8 @@ export function useSearchAndExpand<T extends TreeDataNode>( ) { const [expandedRowKeys, setExpandedRowKeys] = useState<string[]>([]); - const { keywords, filteredData, debouncedSearch } = useDebouncedSearch( - dataSource, - filterFunc, - wait, - ); + const { keywords, filteredData, debouncedSearch, filteredResource } = + useDebouncedSearch(dataSource, filterFunc, wait); const filteredExpandedRowKeys = useMemo( () => @@ -55,5 +52,6 @@ export function useSearchAndExpand<T extends TreeDataNode>( onExpand, debouncedSearch, setExpandedRowKeys, + filteredResource, }; } diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx index 366951762..e56731e1e 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx @@ -43,11 +43,12 @@ export const Resource = memo(() => { selectDataProviderDatabaseListLoading, ); - const { filteredData, expandedRowKeys, onExpand, debouncedSearch } = + const { filteredResource, onExpand, debouncedSearch, expandedRowKeys } = useSearchAndExpand(databases, (keywords, data) => - (data.title as string).includes(keywords), + !data.children?.find(({ isLeaf }) => isLeaf) || !data.isLeaf + ? (data.title as string).includes(keywords) + : false, ); - useEffect(() => { if (sourceId && !databases) { dispatch(getDataProviderDatabases(sourceId)); @@ -155,12 +156,12 @@ export const Resource = memo(() => { <TreeWrapper> <Tree className="medium" - treeData={filteredData} + treeData={filteredResource} loadData={loadData} loading={databaseListLoading} icon={renderIcon} selectable={false} - expandedKeys={expandedRowKeys} + defaultExpandedKeys={expandedRowKeys} onExpand={onExpand} /> </TreeWrapper> diff --git a/frontend/src/utils/utils.ts b/frontend/src/utils/utils.ts index eea6e57cd..854ea7199 100644 --- a/frontend/src/utils/utils.ts +++ b/frontend/src/utils/utils.ts @@ -255,6 +255,41 @@ export function filterListOrTree<T extends { children?: T[] }>( : dataSource; } +export function filteredResourceTree<T extends { children?: T[]; value?: T[] }>( + dataSource: T[], + keywords: string, + filterFunc: (keywords: string, data: T) => boolean, +) { + return keywords + ? dataSource.reduce<T[]>((filtered, d) => { + const isMatch = filterFunc(keywords, d); + let isChildrenMatch; + if (!d.children?.find(v => (v as any).isLeaf) && d.children) { + isChildrenMatch = filteredResourceTree( + d.children, + keywords, + filterFunc, + ); + } + if (!isChildrenMatch?.length && d.children?.length) { + isChildrenMatch = + d.children?.find((item: any) => item?.title?.includes(keywords)) && + d.children; + } + if (isMatch || (isChildrenMatch && isChildrenMatch.length > 0)) { + filtered.push({ + ...d, + children: + isChildrenMatch && isChildrenMatch.length > 0 + ? isChildrenMatch + : d.children, + }); + } + return filtered; + }, []) + : dataSource; +} + export function getExpandedKeys<T extends TreeDataNode>(nodes: T[]) { return nodes.reduce<string[]>((keys, { key, children }) => { if (Array.isArray(children) && children.length) { From 40d5633214ebf0447aee1c405eef3dbfdbb14e1e Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Tue, 28 Dec 2021 16:31:10 +0800 Subject: [PATCH 246/348] style:(Chart) change pie labelFormatter function --- .../BasicPieChart/BasicPieChart.tsx | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx index e5d98dcf7..3b40c2809 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx @@ -284,22 +284,17 @@ class BasicPieChart extends Chart { return seriesParams.name; } const data = seriesParams?.data || {}; - let labelValue = ''; - if (showName) { - labelValue = seriesParams?.name; - } - if (showName && (showValue || showPercent)) { - labelValue += ': '; - } - if (showValue) { - labelValue += toFormattedValue(seriesParams?.value[0], data?.format); - } - if (showPercent && showValue) { - labelValue += '(' + seriesParams?.percent + '%)'; - } else if (showPercent) { - labelValue += seriesParams?.percent + '%'; - } - return labelValue; + return `${showName ? seriesParams?.name : ''}${ + showName && (showValue || showPercent) ? ': ' : '' + }${ + showValue ? toFormattedValue(seriesParams?.value[0], data?.format) : '' + }${ + showPercent && showValue + ? '(' + seriesParams?.percent + '%)' + : showPercent + ? seriesParams?.percent + '%' + : '' + }`; }; } From 655452e5db61b5a648abc99f127f546c81cead85 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 28 Dec 2021 17:27:31 +0800 Subject: [PATCH 247/348] refactor(chart): fix duplicate events in chart container --- frontend/src/app/components/ChartEditor.tsx | 8 ++- .../ChartTools/ChartIFrameContainer.tsx | 3 ++ .../ChartIFrameContainerDispatcher.tsx | 15 +++--- .../ChartTools/ChartLifecycleAdapter.tsx | 52 +++++++++++++------ frontend/src/app/utils/chartHelper.ts | 12 ++++- 5 files changed, 63 insertions(+), 27 deletions(-) diff --git a/frontend/src/app/components/ChartEditor.tsx b/frontend/src/app/components/ChartEditor.tsx index 334278d0d..69d149b97 100644 --- a/frontend/src/app/components/ChartEditor.tsx +++ b/frontend/src/app/components/ChartEditor.tsx @@ -87,8 +87,12 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ useMount( () => { - const currentChart = ChartManager.instance().getDefaultChart(); - handleChartChange(currentChart); + if (!dataChartId && !originChart) { + // Note: add default chart if new to editor + const currentChart = ChartManager.instance().getDefaultChart(); + handleChartChange(currentChart); + } + if (container === 'dataChart') { dispatch( initWorkbenchAction({ diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx index 62d436445..8bff6b5d0 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer.tsx @@ -34,6 +34,7 @@ const ChartIFrameContainer: FC<{ containerId?: string; width?: any; height?: any; + isShown?: boolean; widgetSpecialConfig?: any; }> = memo(props => { const transformToSafeCSSProps = (width, height) => { @@ -61,6 +62,7 @@ const ChartIFrameContainer: FC<{ config={props.config} style={transformToSafeCSSProps(props?.width, props?.height)} widgetSpecialConfig={props.widgetSpecialConfig} + isShown={props.isShown} /> </div> ); @@ -97,6 +99,7 @@ const ChartIFrameContainer: FC<{ config={props.config} style={transformToSafeCSSProps(props?.width, props?.height)} widgetSpecialConfig={props.widgetSpecialConfig} + isShown={props.isShown} /> </StyledChartLifecycleAdapter> </StyleSheetManager> diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx index 106845458..523f7b69e 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainerDispatcher.tsx @@ -20,7 +20,7 @@ import Chart from 'app/pages/ChartWorkbenchPage/models/Chart'; import { ChartConfig } from 'app/types/ChartConfig'; import ChartDataset from 'app/types/ChartDataset'; import { CSSProperties } from 'styled-components'; -import ChartTools from '.'; +import ChartIFrameContainer from './ChartIFrameContainer'; const DEFAULT_CONTAINER_ID = 'frame-container-1'; @@ -54,11 +54,13 @@ class ChartIFrameContainerDispatcher { this.switchContainer(containerId, chart, dataset, config); const renders: Function[] = []; this.chartContainerMap.forEach((chartRenderer: Function, key) => { + const isShown = key === this.currentContainerId; renders.push( chartRenderer .call( Object.create(null), - this.getVisibilityStyle(key === this.currentContainerId, style), + this.getVisibilityStyle(isShown, style), + isShown, ) .apply(Object.create(null), this.chartMetadataMap.get(key)), ); @@ -78,10 +80,10 @@ class ChartIFrameContainerDispatcher { private createNewIfNotExist(containerId: string) { if (!this.chartContainerMap.has(containerId)) { - const newContainer = style => (chart, dataset, config) => { + const newContainer = (style, isShown) => (chart, dataset, config) => { return ( <div key={containerId} style={style}> - <ChartTools.ChartIFrameContainer + <ChartIFrameContainer dataset={dataset} chart={chart} config={config} @@ -89,6 +91,7 @@ class ChartIFrameContainerDispatcher { width={style?.width} height={style?.height} widgetSpecialConfig={this.editorEnv} + isShown={isShown} /> </div> ); @@ -98,8 +101,8 @@ class ChartIFrameContainerDispatcher { this.currentContainerId = containerId; } - private getVisibilityStyle(isShow, style?: CSSProperties) { - return isShow + private getVisibilityStyle(isShown, style?: CSSProperties) { + return isShown ? { ...style, transform: 'none', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx index 0aa5eba71..4f353a7d3 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartLifecycleAdapter.tsx @@ -19,7 +19,6 @@ import { LoadingOutlined } from '@ant-design/icons'; import { Spin } from 'antd'; import { useFrame } from 'app/components/ReactFrameComponent'; -import useMount from 'app/hooks/useMount'; import Chart from 'app/pages/ChartWorkbenchPage/models/Chart'; import ChartEventBroker from 'app/pages/ChartWorkbenchPage/models/ChartEventBroker'; import { ChartConfig } from 'app/types/ChartConfig'; @@ -41,9 +40,17 @@ const ChartLifecycleAdapter: React.FC<{ chart: Chart; config: ChartConfig; style: CSSProperties; + isShown?: boolean; widgetSpecialConfig?: any; -}> = ({ dataset, chart, config, style, widgetSpecialConfig }) => { - const [chartResourceLoader, setChartResourceLoader] = useState( +}> = ({ + dataset, + chart, + config, + style, + isShown = true, + widgetSpecialConfig, +}) => { + const [chartResourceLoader] = useState( () => new ChartIFrameContainerResourceLoader(), ); const [containerStatus, setContainerStatus] = useState(ContainerStatus.INIT); @@ -51,19 +58,19 @@ const ChartLifecycleAdapter: React.FC<{ const [containerId] = useState(() => uuidv4()); const eventBrokerRef = useRef<ChartEventBroker>(); - useMount(() => { - setChartResourceLoader(new ChartIFrameContainerResourceLoader()); - }); - /** * Chart Mount Event - * Dependency: 'chart?.meta?.id', 'eventBrokerRef' + * Dependency: 'chart?.meta?.id', 'eventBrokerRef', 'isShown' */ useEffect(() => { - if (!chart || !document || !window || !config) { - return; - } - if (containerStatus === ContainerStatus.LOADING) { + if ( + !isShown || + !chart || + !document || + !window || + !config || + containerStatus === ContainerStatus.LOADING + ) { return; } @@ -96,15 +103,17 @@ const ChartLifecycleAdapter: React.FC<{ return function cleanup() { setContainerStatus(ContainerStatus.INIT); eventBrokerRef?.current?.publish(ChartLifecycle.UNMOUNTED, {}); + eventBrokerRef?.current?.dispose(); }; - }, [chart?.meta?.id, eventBrokerRef]); + }, [chart?.meta?.id, eventBrokerRef, isShown]); /** * Chart Update Event - * Dependency: 'config', 'dataset', 'widgetSpecialConfig', 'containerStatus', 'document', 'window' + * Dependency: 'config', 'dataset', 'widgetSpecialConfig', 'containerStatus', 'document', 'window', 'isShown' */ useEffect(() => { if ( + !isShown || !document || !window || !config || @@ -127,14 +136,23 @@ const ChartLifecycleAdapter: React.FC<{ height: style?.height, }, ); - }, [config, dataset, widgetSpecialConfig, containerStatus, document, window]); + }, [ + config, + dataset, + widgetSpecialConfig, + containerStatus, + document, + window, + isShown, + ]); /** * Chart Resize Event - * Dependency: 'style.width', 'style.height', 'document', 'window' + * Dependency: 'style.width', 'style.height', 'document', 'window', 'isShown' */ useEffect(() => { if ( + !isShown || !document || !window || !config || @@ -158,7 +176,7 @@ const ChartLifecycleAdapter: React.FC<{ height: style?.height, }, ); - }, [style.width, style.height, document, window]); + }, [style.width, style.height, document, window, isShown]); return ( <Spin diff --git a/frontend/src/app/utils/chartHelper.ts b/frontend/src/app/utils/chartHelper.ts index 66e8fbc8f..01aca6c7a 100644 --- a/frontend/src/app/utils/chartHelper.ts +++ b/frontend/src/app/utils/chartHelper.ts @@ -410,11 +410,11 @@ export function transformToObjectArray( } const result: any[] = Array.apply(null, Array(columns.length)); - for (let j = 0; j < result.length; j++) { + for (let j = 0, outterLength = result.length; j < outterLength; j++) { let objCol = { id: j, }; - for (let i = 0; i < metas.length; i++) { + for (let i = 0, innerLength = metas.length; i < innerLength; i++) { const key = metas?.[i]?.name; if (!!key) { objCol[key] = columns[j][i]; @@ -426,6 +426,14 @@ export function transformToObjectArray( } // TODO delete this function #migration +/** + * @deprecated please use new method transformToObjectArray instead + * @see transformToObjectArray + * @export + * @param {string[][]} [columns] + * @param {ChartDatasetMeta[]} [metas] + * @return {*} + */ export function transfromToObjectArray( columns?: string[][], metas?: ChartDatasetMeta[], From 02a468b03d13be645f13c2c1f2631d038af01c38 Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Wed, 29 Dec 2021 11:20:29 +0800 Subject: [PATCH 248/348] fix:(Resource) fix filterListOrTree function --- frontend/src/app/hooks/useDebouncedSearch.ts | 15 ++---- frontend/src/app/hooks/useSearchAndExpand.ts | 10 ++-- .../ViewPage/Main/Properties/Resource.tsx | 12 ++--- frontend/src/utils/utils.ts | 47 +++++-------------- 4 files changed, 28 insertions(+), 56 deletions(-) diff --git a/frontend/src/app/hooks/useDebouncedSearch.ts b/frontend/src/app/hooks/useDebouncedSearch.ts index 9a4a00b45..85eba7220 100644 --- a/frontend/src/app/hooks/useDebouncedSearch.ts +++ b/frontend/src/app/hooks/useDebouncedSearch.ts @@ -19,11 +19,12 @@ import { DEFAULT_DEBOUNCE_WAIT } from 'globalConstants'; import debounce from 'lodash/debounce'; import { useMemo, useState } from 'react'; -import { filteredResourceTree, filterListOrTree } from 'utils/utils'; +import { filterListOrTree } from 'utils/utils'; export function useDebouncedSearch<T>( dataSource: T[] | undefined, filterFunc: (keywords: string, data: T) => boolean, + filterLeaf?: boolean, wait: number = DEFAULT_DEBOUNCE_WAIT, ) { const [keywords, setKeywords] = useState(''); @@ -31,18 +32,11 @@ export function useDebouncedSearch<T>( const filteredData = useMemo( () => dataSource && keywords.trim() - ? filterListOrTree(dataSource, keywords, filterFunc) + ? filterListOrTree(dataSource, keywords, filterFunc, filterLeaf) : dataSource, - [dataSource, keywords, filterFunc], + [dataSource, keywords, filterFunc, filterLeaf], ); - const filteredResource = useMemo( - () => - dataSource && keywords.trim() - ? filteredResourceTree(dataSource, keywords, filterFunc) - : dataSource, - [dataSource, keywords, filterFunc], - ); const debouncedSearch = useMemo(() => { const search = e => { setKeywords(e.target.value); @@ -54,6 +48,5 @@ export function useDebouncedSearch<T>( keywords, filteredData, debouncedSearch, - filteredResource, }; } diff --git a/frontend/src/app/hooks/useSearchAndExpand.ts b/frontend/src/app/hooks/useSearchAndExpand.ts index 05df62d8c..80d11085a 100644 --- a/frontend/src/app/hooks/useSearchAndExpand.ts +++ b/frontend/src/app/hooks/useSearchAndExpand.ts @@ -25,12 +25,17 @@ import { useDebouncedSearch } from './useDebouncedSearch'; export function useSearchAndExpand<T extends TreeDataNode>( dataSource: T[] | undefined, filterFunc: (keywords: string, data: T) => boolean, + filterLeaf: boolean = false, wait: number = DEFAULT_DEBOUNCE_WAIT, ) { const [expandedRowKeys, setExpandedRowKeys] = useState<string[]>([]); - const { keywords, filteredData, debouncedSearch, filteredResource } = - useDebouncedSearch(dataSource, filterFunc, wait); + const { keywords, filteredData, debouncedSearch } = useDebouncedSearch( + dataSource, + filterFunc, + filterLeaf, + wait, + ); const filteredExpandedRowKeys = useMemo( () => @@ -52,6 +57,5 @@ export function useSearchAndExpand<T extends TreeDataNode>( onExpand, debouncedSearch, setExpandedRowKeys, - filteredResource, }; } diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx index e56731e1e..a7a9164e8 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx @@ -43,11 +43,11 @@ export const Resource = memo(() => { selectDataProviderDatabaseListLoading, ); - const { filteredResource, onExpand, debouncedSearch, expandedRowKeys } = - useSearchAndExpand(databases, (keywords, data) => - !data.children?.find(({ isLeaf }) => isLeaf) || !data.isLeaf - ? (data.title as string).includes(keywords) - : false, + const { filteredData, onExpand, debouncedSearch, expandedRowKeys } = + useSearchAndExpand( + databases, + (keywords, data) => (data.title as string).includes(keywords), + true, ); useEffect(() => { if (sourceId && !databases) { @@ -156,7 +156,7 @@ export const Resource = memo(() => { <TreeWrapper> <Tree className="medium" - treeData={filteredResource} + treeData={filteredData} loadData={loadData} loading={databaseListLoading} icon={renderIcon} diff --git a/frontend/src/utils/utils.ts b/frontend/src/utils/utils.ts index 854ea7199..fc702cee2 100644 --- a/frontend/src/utils/utils.ts +++ b/frontend/src/utils/utils.ts @@ -241,49 +241,24 @@ export function filterListOrTree<T extends { children?: T[] }>( dataSource: T[], keywords: string, filterFunc: (keywords: string, data: T) => boolean, + filterLeaf?: boolean, // 是否展示所有叶子节点 ) { return keywords ? dataSource.reduce<T[]>((filtered, d) => { const isMatch = filterFunc(keywords, d); - const isChildrenMatch = - d.children && filterListOrTree(d.children, keywords, filterFunc); - if (isMatch || (isChildrenMatch && isChildrenMatch.length > 0)) { - filtered.push({ ...d, children: isChildrenMatch }); - } - return filtered; - }, []) - : dataSource; -} - -export function filteredResourceTree<T extends { children?: T[]; value?: T[] }>( - dataSource: T[], - keywords: string, - filterFunc: (keywords: string, data: T) => boolean, -) { - return keywords - ? dataSource.reduce<T[]>((filtered, d) => { - const isMatch = filterFunc(keywords, d); - let isChildrenMatch; - if (!d.children?.find(v => (v as any).isLeaf) && d.children) { - isChildrenMatch = filteredResourceTree( - d.children, - keywords, - filterFunc, - ); - } - if (!isChildrenMatch?.length && d.children?.length) { + let isChildrenMatch: T[] | undefined; + if (filterLeaf && d.children?.every(c => (c as any).isLeaf)) { isChildrenMatch = - d.children?.find((item: any) => item?.title?.includes(keywords)) && - d.children; + isMatch || d.children.some(c => filterFunc(keywords, c)) + ? d.children + : void 0; + } else { + isChildrenMatch = + d.children && + filterListOrTree(d.children, keywords, filterFunc, filterLeaf); } if (isMatch || (isChildrenMatch && isChildrenMatch.length > 0)) { - filtered.push({ - ...d, - children: - isChildrenMatch && isChildrenMatch.length > 0 - ? isChildrenMatch - : d.children, - }); + filtered.push({ ...d, children: isChildrenMatch }); } return filtered; }, []) From dc7ecc511b633b65cec93c0541427afb6e4e340c Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Wed, 29 Dec 2021 11:54:00 +0800 Subject: [PATCH 249/348] chore: login page i18n support --- frontend/src/app/LoginAuthRoute.tsx | 18 ++++ frontend/src/app/constants.ts | 39 --------- frontend/src/app/index.tsx | 22 +++-- .../ForgetPasswordForm/CheckCodeForm.tsx | 71 +++++++++++----- .../ForgetPasswordForm/ResetPasswordForm.tsx | 85 +++++++++++++------ .../ForgetPasswordForm/index.tsx | 23 ++++- .../app/pages/ForgetPasswordPage/constants.ts | 22 ++++- .../app/pages/ForgetPasswordPage/index.tsx | 18 ++++ .../app/pages/ForgetPasswordPage/service.ts | 18 ++++ .../src/app/pages/ForgetPasswordPage/types.ts | 18 ++++ .../src/app/pages/LoginPage/LoginForm.tsx | 41 ++++++--- frontend/src/app/pages/LoginPage/index.tsx | 18 ++++ .../pages/MainPage/Navbar/ModifyPassword.tsx | 42 ++++++--- .../src/app/pages/MainPage/Navbar/Profile.tsx | 18 ++-- .../src/app/pages/MainPage/Navbar/index.tsx | 2 +- .../app/pages/RegisterPage/RegisterForm.tsx | 54 +++++++----- .../app/pages/RegisterPage/SendEmailTips.tsx | 61 ++++++++++--- frontend/src/app/pages/RegisterPage/index.tsx | 26 +++++- .../src/app/pages/RegisterPage/service.ts | 18 ++++ frontend/src/app/slice/index.ts | 18 ++++ frontend/src/app/slice/selectors.ts | 18 ++++ frontend/src/app/slice/thunks.ts | 18 ++++ frontend/src/app/slice/types.ts | 17 ++++ frontend/src/app/utils/history.ts | 18 ++++ frontend/src/app/utils/internalChartHelper.ts | 18 ++++ frontend/src/locales/en/translation.json | 83 +++++++++++++++--- frontend/src/locales/zh/translation.json | 59 ++++++++++++- frontend/src/utils/validators.ts | 46 ++++++++++ 28 files changed, 735 insertions(+), 174 deletions(-) delete mode 100644 frontend/src/app/constants.ts create mode 100644 frontend/src/utils/validators.ts diff --git a/frontend/src/app/LoginAuthRoute.tsx b/frontend/src/app/LoginAuthRoute.tsx index 8214d0df5..3dcaf77f1 100644 --- a/frontend/src/app/LoginAuthRoute.tsx +++ b/frontend/src/app/LoginAuthRoute.tsx @@ -1,3 +1,21 @@ +/** + * 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 { AuthorizedRoute } from 'app/components'; import { getToken } from 'utils/auth'; import { LazyMainPage } from './pages/MainPage/Loadable'; diff --git a/frontend/src/app/constants.ts b/frontend/src/app/constants.ts deleted file mode 100644 index 6e94ac58a..000000000 --- a/frontend/src/app/constants.ts +++ /dev/null @@ -1,39 +0,0 @@ -const REGS = { - password: /^[0-9a-zA-Z][0-9a-zA-Z_]{5,19}$/, -}; -export const RULES = { - password: [ - { - required: true, - message: '密码不能为空', - }, - { - validator(_, value) { - if (value && !REGS.password.test(value)) { - return Promise.reject(new Error('由6-20位字母、数字、下划线组成')); - } - return Promise.resolve(); - }, - }, - ], - getConfirmRule: (filed = 'newPassword') => { - return [ - { required: true, message: '密码不能为空' }, - ({ getFieldValue }) => { - return { - validator(_, value) { - if (value && !REGS.password.test(value)) { - return Promise.reject( - new Error('由6-20位字母、数字、下划线组成'), - ); - } - if (value && getFieldValue(filed) !== value) { - return Promise.reject(new Error('两次输入的密码不一致')); - } - return Promise.resolve(); - }, - }; - }, - ]; - }, -}; diff --git a/frontend/src/app/index.tsx b/frontend/src/app/index.tsx index 39744cf16..ed28067e6 100644 --- a/frontend/src/app/index.tsx +++ b/frontend/src/app/index.tsx @@ -1,9 +1,19 @@ /** + * Datart * - * App + * Copyright 2021 * - * This component is the skeleton around the actual pages, and should only - * contain code that should be seen on all pages. (e.g. navigation bar) + * 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 { message } from 'antd'; @@ -17,6 +27,7 @@ import { useDispatch } from 'react-redux'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { GlobalStyle, OverriddenStyle } from 'styles/globalStyles'; import { getToken } from 'utils/auth'; +import useI18NPrefix from './hooks/useI18NPrefix'; import { LoginAuthRoute } from './LoginAuthRoute'; import { LazyActivePage } from './pages/ActivePage/Loadable'; import { LazyAuthorizationPage } from './pages/AuthorizationPage/Loadable'; @@ -32,6 +43,7 @@ export function App() { const dispatch = useDispatch(); const { i18n } = useTranslation(); const logged = !!getToken(); + const t = useI18NPrefix('global'); useAppSlice(); useLayoutEffect(() => { @@ -39,11 +51,11 @@ export function App() { dispatch(setLoggedInUser()); } else { if (localStorage.getItem(StorageKeys.LoggedInUser)) { - message.warning('会话过期,请重新登录'); + message.warning(t('tokenExpired')); } dispatch(logout()); } - }, [dispatch, logged]); + }, [dispatch, t, logged]); useEffect(() => { dispatch(getSystemInfo()); diff --git a/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/CheckCodeForm.tsx b/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/CheckCodeForm.tsx index 7b8a6c57b..41dfc63c8 100644 --- a/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/CheckCodeForm.tsx +++ b/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/CheckCodeForm.tsx @@ -1,8 +1,27 @@ +/** + * 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 { Button, Form, Input, Radio } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { FC, useCallback, useMemo, useState } from 'react'; import styled from 'styled-components'; import { SPACE_LG } from 'styles/StyleConstants'; -import { FindWays, FIND_WAY_OPTIONS } from '../constants'; +import { FindWays } from '../constants'; import { captchaforResetPassword } from '../service'; import { CaptchaParams } from '../types'; @@ -15,9 +34,13 @@ export const CheckCodeForm: FC<CheckCodeFormProps> = ({ onNextStep }) => { const [token, setToken] = useState<string>(); const [ticket, setTicket] = useState(''); const [submitLoading, setSubmitLoading] = useState(false); + const t = useI18NPrefix('forgotPassword'); + const tg = useI18NPrefix('global.validation'); + const initialValues = useMemo(() => { return { type: FindWays.Email }; }, []); + const onFinish = useCallback((values: CaptchaParams) => { setSubmitLoading(true); captchaforResetPassword(values) @@ -28,9 +51,8 @@ export const CheckCodeForm: FC<CheckCodeFormProps> = ({ onNextStep }) => { .finally(() => { setSubmitLoading(false); }); - // setToken('token-----------'); - // setTicket(values?.principal); }, []); + const isEmail = useMemo(() => { return type === FindWays.Email; }, [type]); @@ -45,6 +67,16 @@ export const CheckCodeForm: FC<CheckCodeFormProps> = ({ onNextStep }) => { }, [form], ); + + const typeOptions = useMemo( + () => + Object.values(FindWays).map(w => ({ + label: t(w.toLowerCase()), + value: w, + })), + [t], + ); + const ticketFormItem = useMemo(() => { return isEmail ? ( <Form.Item @@ -52,15 +84,15 @@ export const CheckCodeForm: FC<CheckCodeFormProps> = ({ onNextStep }) => { rules={[ { required: true, - message: '请输入邮箱', + message: `${t('email')}${tg('required')}`, }, { type: 'email', - message: '邮箱格式不正确', + message: t('emailInvalid'), }, ]} > - <Input size="large" placeholder="请输入邮箱" /> + <Input size="large" placeholder={t('enterEmail')} /> </Form.Item> ) : ( <Form.Item @@ -68,14 +100,15 @@ export const CheckCodeForm: FC<CheckCodeFormProps> = ({ onNextStep }) => { rules={[ { required: true, - message: '请输入用户名', + message: `${t('username')}${tg('required')}`, }, ]} > - <Input size="large" placeholder="请输入用户名" /> + <Input size="large" placeholder={t('enterUsername')} /> </Form.Item> ); - }, [isEmail]); + }, [isEmail, t, tg]); + const goNext = useCallback(() => { onNextStep(token as string); }, [onNextStep, token]); @@ -84,31 +117,29 @@ export const CheckCodeForm: FC<CheckCodeFormProps> = ({ onNextStep }) => { () => token && token.length ? ( <TipsWrapper> - 一封确认信已经发到 + {t('desc1')} {type === FindWays.UserName ? ( <> <b>{ticket}</b> - <span> 所关联的邮箱</span> + <span>{t('desc2')}</span> </> ) : ( <b>{ticket}</b> )} - ,请前往该邮箱获取验证码,然后点击下一步重置密码。 + {t('desc3')} </TipsWrapper> ) : ( <></> ), - [ticket, type, token], + [ticket, type, token, t], ); + return ( <Form initialValues={initialValues} onFinish={onFinish} form={form}> - <Form.Item - name="type" - rules={[{ required: true, message: '找回方式不能为空' }]} - > + <Form.Item name="type"> <Radio.Group size="large" - options={FIND_WAY_OPTIONS} + options={typeOptions} onChange={onTypeChange} /> </Form.Item> @@ -118,7 +149,7 @@ export const CheckCodeForm: FC<CheckCodeFormProps> = ({ onNextStep }) => { <> {tips} <BigButton type="primary" onClick={goNext} size="large"> - 下一步 + {t('nextStep')} </BigButton> </> ) : ( @@ -128,7 +159,7 @@ export const CheckCodeForm: FC<CheckCodeFormProps> = ({ onNextStep }) => { htmlType="submit" size="large" > - 确定 + {t('send')} </BigButton> )} </Form.Item> diff --git a/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/ResetPasswordForm.tsx b/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/ResetPasswordForm.tsx index 60d1b98d2..0a997eeb1 100644 --- a/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/ResetPasswordForm.tsx +++ b/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/ResetPasswordForm.tsx @@ -1,8 +1,31 @@ +/** + * 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 { Button, Form, Input, message } from 'antd'; -import { RULES } from 'app/constants'; -import { FC, useCallback, useMemo, useState } from 'react'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; +import { FC, useCallback, useState } from 'react'; import { useHistory } from 'react-router'; +import { + getConfirmPasswordValidator, + getPasswordValidator, +} from 'utils/validators'; import { resetPassword } from '../service'; + interface ResetPasswordFormProps { token: string; } @@ -10,17 +33,9 @@ export const ResetPasswordForm: FC<ResetPasswordFormProps> = ({ token }) => { const [form] = Form.useForm(); const history = useHistory(); const [submiting, setSubmiting] = useState(false); + const t = useI18NPrefix('forgotPassword'); + const tg = useI18NPrefix('global.validation'); - const checkPasswordConfirm = useCallback( - (_, value, callBack) => { - if (value && value !== form.getFieldValue('newPassword')) { - return Promise.reject('两次输入的密码不一致'); - } else { - return Promise.resolve(); - } - }, - [form], - ); const onFinish = useCallback( values => { setSubmiting(true); @@ -32,7 +47,7 @@ export const ResetPasswordForm: FC<ResetPasswordFormProps> = ({ token }) => { resetPassword(params) .then(res => { if (res) { - message.success('重置密码成功'); + message.success(t('resetSuccess')); history.replace('/login'); } }) @@ -40,27 +55,49 @@ export const ResetPasswordForm: FC<ResetPasswordFormProps> = ({ token }) => { setSubmiting(false); }); }, - [token, history], + [token, history, t], ); - const confirmPasswordRule = useMemo(() => { - return RULES.getConfirmRule('newPassword'); - }, []); + return ( <Form form={form} onFinish={onFinish} size="large"> - <Form.Item name="newPassword" rules={RULES.password}> - <Input.Password placeholder="请输入新密码" /> + <Form.Item + name="newPassword" + rules={[ + { + required: true, + message: `${t('password')}${tg('required')}`, + }, + { validator: getPasswordValidator(tg('invalidPassword')) }, + ]} + > + <Input.Password placeholder={t('enterNewPassword')} /> </Form.Item> - <Form.Item name="confirmPassword" rules={confirmPasswordRule}> - <Input.Password placeholder="请确认新密码" /> + <Form.Item + name="confirmPassword" + rules={[ + { + required: true, + message: `${t('password')}${tg('required')}`, + }, + getConfirmPasswordValidator( + 'newPassword', + tg('invalidPassword'), + tg('passwordNotMatch'), + ), + ]} + > + <Input.Password placeholder={t('confirmNewPassword')} /> </Form.Item> <Form.Item name="verifyCode" - rules={[{ required: true, message: '验证码不能为空' }]} + rules={[ + { required: true, message: `${t('verifyCode')}${tg('required')}` }, + ]} > - <Input placeholder="请输入验证码" /> + <Input placeholder={t('verifyCode')} /> </Form.Item> <Button htmlType="submit" loading={submiting} type="primary" block> - 重置密码 + {t('reset')} </Button> </Form> ); diff --git a/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/index.tsx b/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/index.tsx index d4a33cef7..55f52079d 100644 --- a/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/index.tsx +++ b/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/index.tsx @@ -1,13 +1,34 @@ +/** + * 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 { AuthForm } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { useCallback, useState } from 'react'; import { Link } from 'react-router-dom'; import styled from 'styled-components/macro'; import { LINE_HEIGHT_ICON_LG } from 'styles/StyleConstants'; import { CheckCodeForm } from './CheckCodeForm'; import { ResetPasswordForm } from './ResetPasswordForm'; + export function ForgetPasswordForm() { const [isCheckForm, setIsCheckForm] = useState(true); const [token, setToken] = useState(''); + const t = useI18NPrefix('forgotPassword'); const onNextStep = useCallback((token: string) => { setIsCheckForm(false); @@ -20,7 +41,7 @@ export function ForgetPasswordForm() { ) : ( <ResetPasswordForm token={token} /> )} - <LinkButton to="/login">返回登录页</LinkButton> + <LinkButton to="/login">{t('return')}</LinkButton> </AuthForm> ); } diff --git a/frontend/src/app/pages/ForgetPasswordPage/constants.ts b/frontend/src/app/pages/ForgetPasswordPage/constants.ts index fe8a05be8..ef2308863 100644 --- a/frontend/src/app/pages/ForgetPasswordPage/constants.ts +++ b/frontend/src/app/pages/ForgetPasswordPage/constants.ts @@ -1,8 +1,22 @@ +/** + * 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. + */ + export enum FindWays { Email = 'EMAIL', UserName = 'USERNAME', } -export const FIND_WAY_OPTIONS = [ - { label: '邮箱', value: FindWays.Email }, - { label: '用户名', value: FindWays.UserName }, -]; diff --git a/frontend/src/app/pages/ForgetPasswordPage/index.tsx b/frontend/src/app/pages/ForgetPasswordPage/index.tsx index 4871b0e11..3c1f34869 100644 --- a/frontend/src/app/pages/ForgetPasswordPage/index.tsx +++ b/frontend/src/app/pages/ForgetPasswordPage/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Brand } from 'app/components/Brand'; import React from 'react'; import styled from 'styled-components/macro'; diff --git a/frontend/src/app/pages/ForgetPasswordPage/service.ts b/frontend/src/app/pages/ForgetPasswordPage/service.ts index cd4fab933..6f548e23a 100644 --- a/frontend/src/app/pages/ForgetPasswordPage/service.ts +++ b/frontend/src/app/pages/ForgetPasswordPage/service.ts @@ -1,3 +1,21 @@ +/** + * 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 { request } from 'utils/request'; import { errorHandle } from 'utils/utils'; import { CaptchaParams, ResetPasswordParams } from './types'; diff --git a/frontend/src/app/pages/ForgetPasswordPage/types.ts b/frontend/src/app/pages/ForgetPasswordPage/types.ts index f46d39f34..70947351b 100644 --- a/frontend/src/app/pages/ForgetPasswordPage/types.ts +++ b/frontend/src/app/pages/ForgetPasswordPage/types.ts @@ -1,3 +1,21 @@ +/** + * 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 { FindWays } from './constants'; export interface CaptchaParams { diff --git a/frontend/src/app/pages/LoginPage/LoginForm.tsx b/frontend/src/app/pages/LoginPage/LoginForm.tsx index 64735311a..666247151 100644 --- a/frontend/src/app/pages/LoginPage/LoginForm.tsx +++ b/frontend/src/app/pages/LoginPage/LoginForm.tsx @@ -1,5 +1,24 @@ +/** + * 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 { Button, Form, Input } from 'antd'; import { AuthForm } from 'app/components'; +import usePrefixI18N from 'app/hooks/useI18NPrefix'; import { selectLoggedInUser, selectLoginLoading } from 'app/slice/selectors'; import { login } from 'app/slice/thunks'; import React, { useCallback, useState } from 'react'; @@ -21,6 +40,8 @@ export function LoginForm() { const loggedInUser = useSelector(selectLoggedInUser); const [form] = Form.useForm(); const logged = !!getToken(); + const t = usePrefixI18N('login'); + const tg = usePrefixI18N('global'); const toApp = useCallback(() => { history.replace('/'); @@ -48,13 +69,13 @@ export function LoginForm() { <AuthForm> {logged && !switchUser ? ( <> - <h2>账号已登录</h2> + <h2>{t('alreadyLoggedIn')}</h2> <UserPanel onClick={toApp}> <p>{loggedInUser?.username}</p> - <span>点击进入系统</span> + <span>{t('enter')}</span> </UserPanel> <Button type="link" size="large" block onClick={onSwitch}> - 切换用户 + {t('switch')} </Button> </> ) : ( @@ -64,22 +85,22 @@ export function LoginForm() { rules={[ { required: true, - message: '用户名或邮箱不能为空', + message: `${t('username')}${tg('required')}`, }, ]} > - <Input placeholder="用户名 / 邮箱" size="large" /> + <Input placeholder={t('username')} size="large" /> </Form.Item> <Form.Item name="password" rules={[ { required: true, - message: '密码不能为空', + message: `${t('password')}${tg('required')}`, }, ]} > - <Input placeholder="密码" type="password" size="large" /> + <Input placeholder={t('password')} type="password" size="large" /> </Form.Item> <Form.Item className="last" shouldUpdate> {() => ( @@ -96,13 +117,13 @@ export function LoginForm() { } block > - 登录 + {t('login')} </Button> )} </Form.Item> <Links> - <LinkButton to="/forgetPassword">忘记密码</LinkButton> - <LinkButton to="/register">注册账号</LinkButton> + <LinkButton to="/forgetPassword">{t('forgotPassword')}</LinkButton> + <LinkButton to="/register">{t('register')}</LinkButton> </Links> </Form> )} diff --git a/frontend/src/app/pages/LoginPage/index.tsx b/frontend/src/app/pages/LoginPage/index.tsx index 09030c5bf..ce5eccb4f 100644 --- a/frontend/src/app/pages/LoginPage/index.tsx +++ b/frontend/src/app/pages/LoginPage/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Brand } from 'app/components/Brand'; import { Version } from 'app/components/Version'; import { selectVersion } from 'app/slice/selectors'; diff --git a/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx b/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx index e8a139f03..a0ec3aa5a 100644 --- a/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx @@ -1,5 +1,4 @@ import { Button, Form, Input, message, Modal } from 'antd'; -import { RULES } from 'app/constants'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { selectLoggedInUser, @@ -7,8 +6,12 @@ import { } from 'app/slice/selectors'; import { modifyAccountPassword } from 'app/slice/thunks'; import { ModifyUserPassword } from 'app/slice/types'; -import { FC, useCallback, useEffect, useMemo } from 'react'; +import { FC, useCallback, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; +import { + getConfirmPasswordValidator, + getPasswordValidator, +} from 'utils/validators'; const FormItem = Form.Item; interface ModifyPasswordProps { visible: boolean; @@ -23,6 +26,7 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ const loading = useSelector(selectModifyPasswordLoading); const [form] = Form.useForm(); const t = useI18NPrefix('main.nav.account.changePassword'); + const tg = useI18NPrefix('global.validation'); const reset = useCallback(() => { form.resetFields(); @@ -46,13 +50,9 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ }), ); }, - [dispatch, onCancel], + [dispatch, onCancel, t], ); - const confirmRule = useMemo(() => { - return RULES.getConfirmRule('newPassword'); - }, []); - return ( <Modal title={t('title')} @@ -71,14 +71,26 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ <FormItem label={t('oldPassword')} name="oldPassword" - rules={RULES.password} + rules={[ + { + required: true, + message: `${t('password')}${tg('required')}`, + }, + { validator: getPasswordValidator(tg('invalidPassword')) }, + ]} > <Input.Password type="password" /> </FormItem> <FormItem label={t('newPassword')} name="newPassword" - rules={RULES.password} + rules={[ + { + required: true, + message: `${t('password')}${tg('required')}`, + }, + { validator: getPasswordValidator(tg('invalidPassword')) }, + ]} > <Input.Password type="password" /> </FormItem> @@ -86,7 +98,17 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ label={t('confirmPassword')} name="confirmPassword" dependencies={['newPassword']} - rules={confirmRule} + rules={[ + { + required: true, + message: `${t('password')}${tg('required')}`, + }, + getConfirmPasswordValidator( + 'newPassword', + tg('invalidPassword'), + tg('passwordNotMatch'), + ), + ]} > <Input.Password type="password" placeholder="" /> </FormItem> diff --git a/frontend/src/app/pages/MainPage/Navbar/Profile.tsx b/frontend/src/app/pages/MainPage/Navbar/Profile.tsx index 9cbf4988d..c68cb49fd 100644 --- a/frontend/src/app/pages/MainPage/Navbar/Profile.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/Profile.tsx @@ -22,7 +22,7 @@ export function Profile({ visible, onCancel }: ModalProps) { const loading = useSelector(selectSaveProfileLoading); const [saveDisabled, setSaveDisabled] = useState(true); const [form] = Form.useForm(); - const t = useI18NPrefix('main.nav'); + const t = useI18NPrefix('main.nav.account.profile'); const reset = useCallback(() => { form.resetFields(); @@ -82,7 +82,7 @@ export function Profile({ visible, onCancel }: ModalProps) { return ( <Modal - title="账号设置" + title={t('title')} footer={false} visible={visible} onCancel={onCancel} @@ -105,7 +105,7 @@ export function Profile({ visible, onCancel }: ModalProps) { onChange={avatarChange} > <Button type="link" loading={avatarLoading}> - 点击上传 + {t('clickUpload')} </Button> </Upload> </AvatarUpload> @@ -117,12 +117,12 @@ export function Profile({ visible, onCancel }: ModalProps) { onValuesChange={formChange} onFinish={formSubmit} > - <FormItem label="用户名">{loggedInUser?.username}</FormItem> - <FormItem label="邮箱">{loggedInUser?.email}</FormItem> - <FormItem label="姓名" name="name"> - <Input placeholder="" /> + <FormItem label={t('username')}>{loggedInUser?.username}</FormItem> + <FormItem label={t('email')}>{loggedInUser?.email}</FormItem> + <FormItem label={t('name')} name="name"> + <Input /> </FormItem> - <FormItem label="部门" name="department"> + <FormItem label={t('department')} name="department"> <Input /> </FormItem> <Form.Item wrapperCol={{ offset: 7, span: 12 }}> @@ -133,7 +133,7 @@ export function Profile({ visible, onCancel }: ModalProps) { disabled={saveDisabled} block > - 保存 + {t('save')} </Button> </Form.Item> </Form> diff --git a/frontend/src/app/pages/MainPage/Navbar/index.tsx b/frontend/src/app/pages/MainPage/Navbar/index.tsx index 7fc30beb4..4988adb21 100644 --- a/frontend/src/app/pages/MainPage/Navbar/index.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/index.tsx @@ -284,7 +284,7 @@ export function Navbar() { key="profile" prefix={<ProfileOutlined className="icon" />} > - <p>{t('nav.account.accountSettings.title')}</p> + <p>{t('nav.account.profile.title')}</p> </MenuListItem> <MenuListItem key="password" diff --git a/frontend/src/app/pages/RegisterPage/RegisterForm.tsx b/frontend/src/app/pages/RegisterPage/RegisterForm.tsx index 8c0f460a6..0398ea10b 100644 --- a/frontend/src/app/pages/RegisterPage/RegisterForm.tsx +++ b/frontend/src/app/pages/RegisterPage/RegisterForm.tsx @@ -1,5 +1,24 @@ +/** + * 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 { Button, Form, Input, message } from 'antd'; import { AuthForm } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { selectRegisterLoading } from 'app/slice/selectors'; import { register } from 'app/slice/thunks'; import React, { FC, useCallback } from 'react'; @@ -7,6 +26,8 @@ import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; import styled from 'styled-components/macro'; import { LINE_HEIGHT_ICON_LG } from 'styles/StyleConstants'; +import { getPasswordValidator } from 'utils/validators'; + interface RegisterFormProps { onRegisterSuccess: (email: string) => void; } @@ -15,6 +36,8 @@ export const RegisterForm: FC<RegisterFormProps> = ({ onRegisterSuccess }) => { const history = useHistory(); const loading = useSelector(selectRegisterLoading); const [form] = Form.useForm(); + const t = useI18NPrefix('register'); + const tg = useI18NPrefix('global.validation'); const onRegister = useCallback( values => { @@ -22,14 +45,14 @@ export const RegisterForm: FC<RegisterFormProps> = ({ onRegisterSuccess }) => { register({ data: values, resolve: () => { - message.success('注册成功'); + message.success(t('registrationSuccess')); form.resetFields(); onRegisterSuccess(values.email); }, }), ); }, - [dispatch, form, onRegisterSuccess], + [dispatch, form, onRegisterSuccess, t], ); const toLogin = useCallback(() => { @@ -44,44 +67,36 @@ export const RegisterForm: FC<RegisterFormProps> = ({ onRegisterSuccess }) => { rules={[ { required: true, - message: '用户名不能为空', + message: `${t('username')}${tg('required')}`, }, ]} > - <Input placeholder="用户名" size="large" /> + <Input placeholder={t('username')} size="large" /> </Form.Item> <Form.Item name="email" rules={[ { required: true, - message: '邮箱不能为空', + message: `${t('email')}${tg('required')}`, }, ]} > - <Input placeholder="邮箱" type="email" size="large" /> + <Input placeholder={t('email')} type="email" size="large" /> </Form.Item> <Form.Item name="password" rules={[ { required: true, - message: '密码不能为空', + message: `${t('password')}${tg('required')}`, }, { - validator(_, value) { - if ( - !value || - (value.trim().length >= 6 && value.trim().length <= 20) - ) { - return Promise.resolve(); - } - return Promise.reject(new Error('密码长度为6-20位')); - }, + validator: getPasswordValidator(tg('invalidPassword')), }, ]} > - <Input.Password placeholder="密码" size="large" /> + <Input.Password placeholder={t('password')} size="large" /> </Form.Item> <Form.Item className="last" shouldUpdate> {() => ( @@ -98,12 +113,13 @@ export const RegisterForm: FC<RegisterFormProps> = ({ onRegisterSuccess }) => { } block > - 注册 + {t('register')} </Button> )} </Form.Item> <Links> - 已有账号,<LinkButton onClick={toLogin}>点击登录</LinkButton> + {t('desc1')} + <LinkButton onClick={toLogin}>{t('login')}</LinkButton> </Links> </Form> </AuthForm> diff --git a/frontend/src/app/pages/RegisterPage/SendEmailTips.tsx b/frontend/src/app/pages/RegisterPage/SendEmailTips.tsx index 027662d9c..1286c743d 100644 --- a/frontend/src/app/pages/RegisterPage/SendEmailTips.tsx +++ b/frontend/src/app/pages/RegisterPage/SendEmailTips.tsx @@ -1,7 +1,28 @@ +/** + * 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 { LeftCircleOutlined } from '@ant-design/icons'; import { Button } from 'antd'; import { AuthForm } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { FC, useCallback } from 'react'; +import styled from 'styled-components/macro'; +import { SPACE_XS } from 'styles/StyleConstants'; interface SendEmailTipsProps { email: string; @@ -15,6 +36,7 @@ export const SendEmailTips: FC<SendEmailTipsProps> = ({ onBack, onSendEmailAgain, }) => { + const t = useI18NPrefix('register'); const toEmailWebsite = useCallback(() => { if (email) { const suffix = email.split('@')[1]; @@ -25,28 +47,39 @@ export const SendEmailTips: FC<SendEmailTipsProps> = ({ return ( <AuthForm> - <h1>请查收电子邮件</h1> - <p> - 我们向 <b>{email}</b> 发送了一封电子邮件,请 - <b> - <span onClick={toEmailWebsite}>前往</span> - </b> - 电子邮件中确认。 - </p> - <p> - 没收到? - <Button type="link" loading={loading} onClick={onSendEmailAgain}> - 重新发送电子邮件 + <h1>{t('tipTitle')}</h1> + <Content> + {t('tipDesc1')} + <b>{email}</b> + {t('tipDesc2')} + <Button type="link" size="small" onClick={toEmailWebsite}> + {t('toMailbox')} + </Button> + {t('tipDesc3')} + </Content> + <Content> + {t('tipDesc4')} + <Button + type="link" + size="small" + loading={loading} + onClick={onSendEmailAgain} + > + {t('resend')} </Button> - </p> + </Content> <Button size="large" style={{ width: '100%' }} type="primary" onClick={onBack} > - <LeftCircleOutlined /> 返回上一步 + <LeftCircleOutlined /> {t('back')} </Button> </AuthForm> ); }; + +const Content = styled.p` + margin: ${SPACE_XS} 0; +`; diff --git a/frontend/src/app/pages/RegisterPage/index.tsx b/frontend/src/app/pages/RegisterPage/index.tsx index 3a393f823..0f2e99443 100644 --- a/frontend/src/app/pages/RegisterPage/index.tsx +++ b/frontend/src/app/pages/RegisterPage/index.tsx @@ -1,5 +1,24 @@ +/** + * 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 { message } from 'antd'; import { Brand } from 'app/components/Brand'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { useCallback, useState } from 'react'; import styled from 'styled-components/macro'; import { RegisterForm } from './RegisterForm'; @@ -10,6 +29,8 @@ export function RegisterPage() { const [isRegister, setIsRegister] = useState(true); const [email, setEmail] = useState<string>(''); const [sendEmailLoading, setSendEmailLoading] = useState(false); + const t = useI18NPrefix('register'); + const onRegisterSuccess = useCallback((email: string) => { setEmail(email); setIsRegister(false); @@ -22,12 +43,13 @@ export function RegisterPage() { sendEmail(email) .then(() => { setSendEmailLoading(false); - message.success('发送成功'); + message.success(t('sendSuccess')); }) .catch(() => { setSendEmailLoading(false); }); - }, [email]); + }, [email, t]); + return ( <Wrapper> <Brand /> diff --git a/frontend/src/app/pages/RegisterPage/service.ts b/frontend/src/app/pages/RegisterPage/service.ts index fa72488d7..225843e1b 100644 --- a/frontend/src/app/pages/RegisterPage/service.ts +++ b/frontend/src/app/pages/RegisterPage/service.ts @@ -1,3 +1,21 @@ +/** + * 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 { request } from 'utils/request'; import { errorHandle } from 'utils/utils'; export const sendEmail = async usernameOrEmail => { diff --git a/frontend/src/app/slice/index.ts b/frontend/src/app/slice/index.ts index 7a9c7e62d..afb850a50 100644 --- a/frontend/src/app/slice/index.ts +++ b/frontend/src/app/slice/index.ts @@ -1,3 +1,21 @@ +/** + * 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 { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { useInjectReducer } from 'utils/@reduxjs/injectReducer'; import { diff --git a/frontend/src/app/slice/selectors.ts b/frontend/src/app/slice/selectors.ts index ceb569a70..523febb24 100644 --- a/frontend/src/app/slice/selectors.ts +++ b/frontend/src/app/slice/selectors.ts @@ -1,3 +1,21 @@ +/** + * 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 { createSelector } from '@reduxjs/toolkit'; import { RootState } from 'types'; import { initialState } from '.'; diff --git a/frontend/src/app/slice/thunks.ts b/frontend/src/app/slice/thunks.ts index 8f0c2e954..7cfd30842 100644 --- a/frontend/src/app/slice/thunks.ts +++ b/frontend/src/app/slice/thunks.ts @@ -1,3 +1,21 @@ +/** + * 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 { createAsyncThunk } from '@reduxjs/toolkit'; import { StorageKeys } from 'globalConstants'; import { removeToken, setToken, setTokenExpiration } from 'utils/auth'; diff --git a/frontend/src/app/slice/types.ts b/frontend/src/app/slice/types.ts index 8751c3c17..7810f5583 100644 --- a/frontend/src/app/slice/types.ts +++ b/frontend/src/app/slice/types.ts @@ -1,3 +1,20 @@ +/** + * 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. + */ export interface AppState { loggedInUser: null | User; systemInfo: null | SystemInfo; diff --git a/frontend/src/app/utils/history.ts b/frontend/src/app/utils/history.ts index ee3abb793..1cc814309 100644 --- a/frontend/src/app/utils/history.ts +++ b/frontend/src/app/utils/history.ts @@ -1,3 +1,21 @@ +/** + * 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 { createBrowserHistory } from 'history'; const history = createBrowserHistory(); export default history; diff --git a/frontend/src/app/utils/internalChartHelper.ts b/frontend/src/app/utils/internalChartHelper.ts index f74985abf..555a1b4fa 100644 --- a/frontend/src/app/utils/internalChartHelper.ts +++ b/frontend/src/app/utils/internalChartHelper.ts @@ -1,3 +1,21 @@ +/** + * 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 { ChartConfig, ChartDataSectionType } from 'app/types/ChartConfig'; import { curry, pipe } from 'utils/object'; import { diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index bf493f9ce..41b2b4b08 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -1,13 +1,68 @@ { + "global": { + "tokenExpired": "Token expired, please log in", + "validation": { + "required": " is required", + "invalidPassword": "Password must be 6-20 characters", + "passwordNotMatch": "Password and confirm password does not match" + } + }, + "login": { + "username": "Username / Email", + "password": "Password", + "login": "Log in", + "register": "Sign up for an account", + "forgotPassword": "Can't log in?", + "alreadyLoggedIn": "Your account is already logged in", + "enter": "Click to enter", + "switch": "Switch accounts" + }, + "register": { + "sendSuccess": "Email sent successfully", + "username": "Username", + "email": "Email", + "password": "Password", + "register": "Register", + "desc1": "Already have an account? ", + "login": "Log In", + "tipTitle": "Check your email", + "tipDesc1": "We have sent you email to ", + "tipDesc2": ". Please", + "toMailbox": "click the link ", + "tipDesc3": "to confirm and activate your account.", + "tipDesc4": "Didn't receive?", + "resend": "Click to resend email", + "back": "Go back", + "registrationSuccess": "Registration Success" + }, + "forgotPassword": { + "return": "Return to log in", + "email": "Email", + "enterEmail": "Enter email", + "emailInvalid": "Invalid email address", + "username": "Username", + "enterUsername": "Enter username", + "nextStep": "Next Step", + "send": "Send verification code", + "desc1": "A confirmation email has been sent to ", + "desc2": "'s mailbox", + "desc3": ", please go to the mailbox to get the verification code, and then click next to reset the password.", + "password": "Password", + "enterNewPassword": "Enter new password", + "confirmNewPassword": "Confirm new password", + "verifyCode": "Verification code", + "reset": "Reset password", + "resetSuccess": "Your password has been successfully reset" + }, "main": { "nav": { - "vizs": "可视化", - "views": "数据视图", - "sources": "数据源", - "schedules": "定时任务", - "members": "成员与角色", - "permissions": "权限", - "settings": "设置", + "vizs": "Vizs", + "views": "Views", + "sources": "Sources", + "schedules": "Schedules", + "members": "Members", + "permissions": "Permissions", + "settings": "Settings", "download": { "title": "Download List" }, @@ -22,14 +77,14 @@ "saveDndEnter": "保存并进入" }, "account": { - "accountSettings": { + "profile": { "title": "Profile", - "clickUpload": "点击上传", - "userName": "用户名", - "email": "邮箱", - "name": "姓名", - "department": "部门", - "save": "保存" + "clickUpload": "Click to upload", + "username": "Username", + "email": "Email", + "name": "Name", + "department": "Department", + "save": "Save" }, "changePassword": { "title": "Password", diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 398ae4155..ab6914794 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -1,4 +1,59 @@ { + "global": { + "tokenExpired": "会话过期,请重新登录", + "validation": { + "required": "不能为空", + "invalidPassword": "密码长度为6-20位", + "passwordNotMatch": "两次输入的密码不一致" + } + }, + "login": { + "username": "用户名 / 邮箱", + "password": "密码", + "login": "登录", + "register": "注册新账号", + "forgotPassword": "忘记密码?", + "alreadyLoggedIn": "账号已登录", + "enter": "点击进入", + "switch": "切换账号" + }, + "register": { + "sendSuccess": "发送成功", + "username": "用户名", + "email": "邮箱", + "password": "密码", + "register": "注册", + "desc1": "已有账号?", + "login": "点击登录", + "tipTitle": "请查收电子邮件", + "tipDesc1": "我们向 ", + "tipDesc2": " 发送了一封电子邮件,请", + "toMailbox": "前往邮箱", + "tipDesc3": "确认与激活账号。", + "tipDesc4": "没有收到?", + "resend": "重新发送电子邮件", + "back": "返回上一步", + "registrationSuccess": "注册成功" + }, + "forgotPassword": { + "return": "返回登录", + "email": "邮箱", + "enterEmail": "输入邮箱", + "emailInvalid": "邮箱格式不正确", + "username": "用户名", + "enterUsername": "输入用户名", + "nextStep": "下一步", + "send": "发送验证码", + "desc1": "一封确认信已经发到 ", + "desc2": " 所关联的邮箱", + "desc3": ",请前往该邮箱获取验证码,然后点击下一步重置密码。", + "password": "密码", + "enterNewPassword": "输入新密码", + "confirmNewPassword": "确认新密码", + "verifyCode": "验证码", + "reset": "重置密码", + "resetSuccess": "重置密码成功" + }, "main": { "nav": { "vizs": "可视化", @@ -22,10 +77,10 @@ "saveDndEnter": "保存并进入" }, "account": { - "accountSettings": { + "profile": { "title": "账号设置", "clickUpload": "点击上传", - "userName": "用户名", + "username": "用户名", "email": "邮箱", "name": "姓名", "department": "部门", diff --git a/frontend/src/utils/validators.ts b/frontend/src/utils/validators.ts new file mode 100644 index 000000000..611d72b7c --- /dev/null +++ b/frontend/src/utils/validators.ts @@ -0,0 +1,46 @@ +/** + * 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. + */ + +export function getPasswordValidator(errorMessage: string) { + return function (_, value: string) { + if (value && (value.trim().length < 6 || value.trim().length > 20)) { + return Promise.reject(new Error(errorMessage)); + } + return Promise.resolve(); + }; +} + +export function getConfirmPasswordValidator( + field: string, + errorMessage: string, + confirmErrorMessage: string, +) { + return function ({ getFieldValue }) { + return { + validator(_, value: string) { + if (value && (value.trim().length < 6 || value.trim().length > 20)) { + return Promise.reject(new Error(errorMessage)); + } + if (value && getFieldValue(field) !== value) { + return Promise.reject(new Error(confirmErrorMessage)); + } + return Promise.resolve(); + }, + }; + }; +} From 510ce8b1d28bc77e7fd3e555d74e7444a44b8fee Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Wed, 29 Dec 2021 12:07:01 +0800 Subject: [PATCH 250/348] style:(Resource) change useSearchAndExpand and useDebouncedSearch function --- frontend/src/app/hooks/useDebouncedSearch.ts | 3 +-- frontend/src/app/hooks/useSearchAndExpand.ts | 4 ++-- .../MainPage/pages/ViewPage/Main/Properties/Resource.tsx | 2 ++ 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/hooks/useDebouncedSearch.ts b/frontend/src/app/hooks/useDebouncedSearch.ts index 85eba7220..dd380a6e3 100644 --- a/frontend/src/app/hooks/useDebouncedSearch.ts +++ b/frontend/src/app/hooks/useDebouncedSearch.ts @@ -24,11 +24,10 @@ import { filterListOrTree } from 'utils/utils'; export function useDebouncedSearch<T>( dataSource: T[] | undefined, filterFunc: (keywords: string, data: T) => boolean, - filterLeaf?: boolean, wait: number = DEFAULT_DEBOUNCE_WAIT, + filterLeaf: boolean = false, ) { const [keywords, setKeywords] = useState(''); - const filteredData = useMemo( () => dataSource && keywords.trim() diff --git a/frontend/src/app/hooks/useSearchAndExpand.ts b/frontend/src/app/hooks/useSearchAndExpand.ts index 80d11085a..0c63abef7 100644 --- a/frontend/src/app/hooks/useSearchAndExpand.ts +++ b/frontend/src/app/hooks/useSearchAndExpand.ts @@ -25,16 +25,16 @@ import { useDebouncedSearch } from './useDebouncedSearch'; export function useSearchAndExpand<T extends TreeDataNode>( dataSource: T[] | undefined, filterFunc: (keywords: string, data: T) => boolean, - filterLeaf: boolean = false, wait: number = DEFAULT_DEBOUNCE_WAIT, + filterLeaf: boolean = false, ) { const [expandedRowKeys, setExpandedRowKeys] = useState<string[]>([]); const { keywords, filteredData, debouncedSearch } = useDebouncedSearch( dataSource, filterFunc, - filterLeaf, wait, + filterLeaf, ); const filteredExpandedRowKeys = useMemo( diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx index a7a9164e8..3b126e0ea 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx @@ -11,6 +11,7 @@ import { ListTitle, Tree } from 'app/components'; import { useSearchAndExpand } from 'app/hooks/useSearchAndExpand'; import { selectDataProviderDatabaseListLoading } from 'app/pages/MainPage/slice/selectors'; import { getDataProviderDatabases } from 'app/pages/MainPage/slice/thunks'; +import { DEFAULT_DEBOUNCE_WAIT } from 'globalConstants'; import { memo, useCallback, useContext, useEffect } from 'react'; import { monaco } from 'react-monaco-editor'; import { useDispatch, useSelector } from 'react-redux'; @@ -47,6 +48,7 @@ export const Resource = memo(() => { useSearchAndExpand( databases, (keywords, data) => (data.title as string).includes(keywords), + DEFAULT_DEBOUNCE_WAIT, true, ); useEffect(() => { From 0a7511d2ce7bf0818e571779ef9824c0efbe816c Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Tue, 28 Dec 2021 15:00:34 +0800 Subject: [PATCH 251/348] build: add rollup board,chart --- frontend/.babelrc | 26 ++ frontend/.gitignore | 2 + frontend/package.json | 14 +- frontend/rollup.config.js | 41 +++ .../pages/BoardEditor/slice/thunk.ts | 6 +- .../app/pages/DashBoardPage/utils/board.ts | 1 - .../app/pages/DashBoardPage/utils/index.ts | 5 +- .../app/pages/DashBoardPage/utils/widget.ts | 290 +++++++++--------- frontend/src/app/types/ChartDataView.ts | 1 - frontend/src/globalConstants.ts | 5 - frontend/src/task.ts | 108 ++++++- 11 files changed, 333 insertions(+), 166 deletions(-) create mode 100644 frontend/.babelrc create mode 100644 frontend/rollup.config.js diff --git a/frontend/.babelrc b/frontend/.babelrc new file mode 100644 index 000000000..e194a3306 --- /dev/null +++ b/frontend/.babelrc @@ -0,0 +1,26 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + // 避免转换成 CommonJS + "modules": false, + // 使用 loose 模式,避免产生副作用 + "loose": true + } + ], + ["@babel/preset-typeScript"], + + ], + "plugins": [ + "@babel/plugin-external-helpers", + [ + // 开启 babel 各依赖联动,由此插件负责自动导入 helper 辅助函数,从而形成沙箱 polyfill + "@babel/plugin-transform-runtime", + { + "corejs": { "version": 3, "proposals": true }, + "useESModules": true // 关闭 esm 转化,交由 rollup 处理,同上防止冲突 + } + ] + ] + } \ No newline at end of file diff --git a/frontend/.gitignore b/frontend/.gitignore index 978b23d43..ca2ab7ebe 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -31,3 +31,5 @@ yarn-error.log* # vscode .vscode + +/public/task diff --git a/frontend/package.json b/frontend/package.json index 3b32bf6a3..089a22968 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,7 +16,7 @@ "scripts": { "analyze": "craco build && source-map-explorer 'build/static/js/*.js'", "start": "craco start", - "build": "cross-env GENERATE_SOURCEMAP=false craco build", + "build": "cross-env GENERATE_SOURCEMAP=false && npm run rollup && craco build", "test": "craco test", "test:coverage": "npm run test -- --watchAll=false --coverage", "checkTs": "tsc --noEmit", @@ -26,7 +26,8 @@ "lint:css": "stylelint src/**/*.{less,css}", "prettify": "prettier --write src", "prepare": "cd .. && husky install frontend/.husky", - "eject": "react-scripts eject" + "eject": "react-scripts eject", + "rollup": "rollup -c" }, "eslintConfig": { "extends": [ @@ -134,9 +135,17 @@ "uuid": "^8.3.2" }, "devDependencies": { + "@babel/core": "^7.15.8", + "@babel/preset-env": "^7.15.8", "@commitlint/cli": "^12.0.1", "@commitlint/config-conventional": "^12.0.1", "@craco/craco": "^6.1.1", + "@rollup/plugin-babel": "^5.3.0", + "@rollup/plugin-commonjs": "^21.0.1", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^13.0.6", + "@rollup/plugin-replace": "^2.4.2", + "@rollup/plugin-typescript": "^8.3.0", "@testing-library/jest-dom": "^5.11.9", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^12.8.0", @@ -172,6 +181,7 @@ "prettier-plugin-organize-imports": "^2.3.3", "react-scripts": "4.0.3", "react-test-renderer": "^17.0.1", + "rollup": "^2.62.0", "serve": "^11.3.2", "source-map-explorer": "^2.5.2", "styled-components": "^5.3.0", diff --git a/frontend/rollup.config.js b/frontend/rollup.config.js new file mode 100644 index 000000000..3ad090bb6 --- /dev/null +++ b/frontend/rollup.config.js @@ -0,0 +1,41 @@ +/* eslint-disable import/no-anonymous-default-export */ + +import { babel } from '@rollup/plugin-babel'; +import commonjs from '@rollup/plugin-commonjs'; +import json from '@rollup/plugin-json'; +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import replace from '@rollup/plugin-replace'; +import typescript from '@rollup/plugin-typescript'; +import path from 'path'; +export default { + input: 'src/task.ts', // 打包入口 + output: { + // 打包出口 + name: 'getQueryData', // namespace + file: path.resolve(__dirname, 'public/task/index.js'), // 最终打包出来的文件路径和文件名 + format: 'umd', // umd/amd/cjs/iife + }, + plugins: [ + json(), + nodeResolve({ + extensions: ['.js', '.ts'], + }), + // 解析TypeScript + typescript({ + tsconfig: path.resolve(__dirname, 'tsconfig.json'), + }), + // 将 CommonJS 转换成 ES2015 模块供 Rollup 处理 + commonjs(), + // es6--> es5 + babel({ + babelHelpers: 'runtime', + exclude: 'node_modules/**', + presets: [['@babel/preset-env', { modules: false }]], + comments: false, + }), + replace({ + 'console.log': '//console.log', + // 'new Map': '', + }), + ], +}; 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 2bb565192..514296da9 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts @@ -27,6 +27,7 @@ import { createWidgetInfo, createWidgetInfoMap, getWidgetInfoMapByServer, + getWidgetMapByServer, } from 'app/pages/DashBoardPage/utils/widget'; import { getControlOptionQueryParams } from 'app/pages/DashBoardPage/utils/widgetToolKit/chart'; import { widgetToolKit } from 'app/pages/DashBoardPage/utils/widgetToolKit/widgetToolKit'; @@ -46,10 +47,7 @@ import { } from '.'; import { BoardInfo, BoardType, ServerDashboard } from '../../Board/slice/types'; import { getDataChartMap } from './../../../utils/board'; -import { - getWidgetMapByServer, - updateWidgetsRect, -} from './../../../utils/widget'; +import { updateWidgetsRect } from './../../../utils/widget'; import { addVariablesToBoard } from './actions/actions'; import { boardInfoState, diff --git a/frontend/src/app/pages/DashBoardPage/utils/board.ts b/frontend/src/app/pages/DashBoardPage/utils/board.ts index 6717993f9..dc76da961 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/board.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/board.ts @@ -28,7 +28,6 @@ import { } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import { View } from 'app/pages/MainPage/pages/ViewPage/slice/types'; import { ChartDataView } from 'app/types/ChartDataView'; -// import { dataChartServerModel } from 'app/pages/MainPage/pages/VizPage/slice/types'; import { transformMeta } from 'app/utils/chartHelper'; import { AutoBoardWidgetBackgroundDefault, diff --git a/frontend/src/app/pages/DashBoardPage/utils/index.ts b/frontend/src/app/pages/DashBoardPage/utils/index.ts index 696d47a3c..968ea69f9 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/index.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/index.ts @@ -19,7 +19,6 @@ import { import { getTime } from 'app/utils/time'; import { FilterSqlOperator } from 'globalConstants'; import moment from 'moment'; -import { errorHandle } from 'utils/utils'; import { STORAGE_IMAGE_KEY_PREFIX } from '../constants'; import { BoardLinkFilter, @@ -394,13 +393,13 @@ export const getChartWidgetRequestParams = (obj: { if (!curWidget.datachartId) return null; const dataChart = dataChartMap[curWidget.datachartId]; if (!dataChart) { - errorHandle(`can\`t find Chart ${curWidget.datachartId}`); + // errorHandle(`can\`t find Chart ${curWidget.datachartId}`); return null; } const chartDataView = viewMap[dataChart?.viewId]; if (!chartDataView) { - errorHandle(`can\`t find View ${dataChart?.viewId}`); + // errorHandle(`can\`t find View ${dataChart?.viewId}`); return null; } diff --git a/frontend/src/app/pages/DashBoardPage/utils/widget.ts b/frontend/src/app/pages/DashBoardPage/utils/widget.ts index 8f40e352d..e196cc239 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/widget.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/widget.ts @@ -15,7 +15,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { WidgetType } from 'app/pages/DashBoardPage/pages/Board/slice/types'; +import { + ContainerItem, + WidgetType, +} from 'app/pages/DashBoardPage/pages/Board/slice/types'; import { FilterSearchParamsWithMatch } from 'app/pages/MainPage/pages/VizPage/slice/types'; import ChartDataView from 'app/types/ChartDataView'; import { ControllerFacadeTypes } from 'app/types/FilterControlPanel'; @@ -24,7 +27,6 @@ import produce from 'immer'; import { DeltaStatic } from 'quill'; import { CSSProperties } from 'react'; import { FONT_FAMILY, G90, WHITE } from 'styles/StyleConstants'; -import { uuidv4 } from 'utils/utils'; import { convertImageUrl, fillPx } from '.'; import { AutoBoardWidgetBackgroundDefault, @@ -38,7 +40,6 @@ import { BoardType, BorderConfig, ChartWidgetContent, - ContainerItem, ContainerWidgetContent, ContainerWidgetType, ControllerWidgetContent, @@ -97,7 +98,7 @@ export const createControllerWidget = (opt: { boardType: boardType, }); - const widgetId = relations[0]?.sourceId || uuidv4(); + const widgetId = relations[0]?.sourceId || String(Math.random()); const widget: Widget = createWidget({ id: widgetId, dashboardId: boardId, @@ -204,7 +205,7 @@ export const createWidget = (option: { relations?: Relation[]; }) => { const widget: Widget = { - id: option.id || uuidv4(), + id: option.id || String(Math.random()), dashboardId: option.dashboardId, config: option.config, datachartId: option.datachartId || '', @@ -394,145 +395,6 @@ export const createMediaContent = (type: MediaWidgetType) => { return content; }; -// TODO chart widget -export const getWidgetMapByServer = ( - widgets: ServerWidget[], - dataCharts: DataChart[], - filterSearchParamsMap?: FilterSearchParamsWithMatch, -) => { - const filterSearchParams = filterSearchParamsMap?.params, - isMatchByName = filterSearchParamsMap?.isMatchByName; - const dataChartMap = dataCharts.reduce((acc, cur) => { - acc[cur.id] = cur; - return acc; - }, {} as Record<string, DataChart>); - const widgetMap = widgets.reduce((acc, cur) => { - const viewIds = cur.datachartId - ? [dataChartMap[cur.datachartId].viewId] - : cur.viewIds; - try { - let widget: Widget = { - ...cur, - config: JSON.parse(cur.config), - relations: convertWidgetRelationsToObj(cur.relations), - viewIds, - }; - // TODO migration about font 5 --xld - widget.config.nameConfig = { - ...fontDefault, - ...widget.config.nameConfig, - }; - // TODO migration about filter --xld - if ((widget.config.type as any) !== 'filter') { - acc[cur.id] = widget; - } - return acc; - } catch (error) { - return acc; - } - }, {} as Record<string, Widget>); - - const wrappedDataCharts: DataChart[] = []; - const controllerWidgets: Widget[] = []; // use for reset button - const widgetList = Object.values(widgetMap); - - // 处理 widget包含关系 containerWidget 被包含的 widget.parentId 不为空 - widgetList - .filter(w => w.parentId) - .forEach(widget => { - const parentWidgetId = widget.parentId!; - const childTabId = widget.config.tabId as string; - const curItem = ( - widgetMap[parentWidgetId].config.content as ContainerWidgetContent - ).itemMap[childTabId]; - if (curItem) { - curItem.childWidgetId = widget.id; - curItem.name = widget.config.name; - } else { - let newItem: ContainerItem = { - tabId: childTabId, - name: widget.config.name, - childWidgetId: widget.id, - }; - ( - widgetMap[parentWidgetId].config.content as ContainerWidgetContent - ).itemMap[childTabId] = newItem; - } - }); - - // 处理 controller config visibility依赖关系 id, url参数修改filter - widgetList - .filter(w => w.config.type === 'controller') - .forEach(widget => { - const content = widget.config.content as ControllerWidgetContent; - // 根据 url参数修改filter 默认值 - if (filterSearchParams) { - const paramsKey = Object.keys(filterSearchParams); - const matchKey = isMatchByName ? widget.config.name : widget.id; - if (paramsKey.includes(matchKey)) { - const _value = isMatchByName - ? filterSearchParams[widget.config.name] - : filterSearchParams[widget.id]; - switch (content?.type) { - case ControllerFacadeTypes.RangeTime: - if ( - content.config.controllerDate && - content.config.controllerDate?.startTime && - content.config.controllerDate?.endTime - ) { - content.config.controllerDate.startTime.exactValue = - _value?.[0]; - content.config.controllerDate.endTime.exactValue = _value?.[0]; - } - break; - default: - content.config.controllerValues = _value || []; - break; - } - } - } - - // 通过widget.relation 那里面的 targetId确定 关联controllerWidget 的真实ID - const { visibilityType: visibility, condition } = - content.config.visibility; - const { relations } = widget; - if (visibility === 'condition' && condition) { - const dependentFilterId = relations - .filter(re => re.config.type === 'controlToControl') - .map(re => re.targetId)?.[0]; - if (dependentFilterId) { - condition.dependentControllerId = dependentFilterId; - } - } - - //处理 assistViewFields 旧数据 assistViewFields 是 string 类型 alpha.3版本之后 使用数组存储的 后续版本稳定之后 可以移除此逻辑 - // TODO migration << - if (typeof content?.config?.assistViewFields === 'string') { - content.config.assistViewFields = ( - content.config.assistViewFields as string - ).split(VALUE_SPLITTER); - } - // TODO migration >> --xld - - controllerWidgets.push(widget); - }); - - // 处理 自有 chart widgetControl - widgetList - .filter(w => w.config.content.type === 'widgetChart') - .forEach(widget => { - let content = widget.config.content as ChartWidgetContent; - widget.datachartId = content.dataChart?.id || ''; - wrappedDataCharts.push(content.dataChart!); - delete content.dataChart; - }); - - return { - widgetMap, - wrappedDataCharts, - controllerWidgets, - }; -}; export const getWidgetInfoMapByServer = (widgetMap: Record<string, Widget>) => { const widgetInfoMap = {}; Object.values(widgetMap).forEach(item => { @@ -921,3 +783,143 @@ export const getLinkedColumn = ( '' ); }; + +// TODO chart widget +export const getWidgetMapByServer = ( + widgets: ServerWidget[], + dataCharts: DataChart[], + filterSearchParamsMap?: FilterSearchParamsWithMatch, +) => { + const filterSearchParams = filterSearchParamsMap?.params, + isMatchByName = filterSearchParamsMap?.isMatchByName; + const dataChartMap = dataCharts.reduce((acc, cur) => { + acc[cur.id] = cur; + return acc; + }, {} as Record<string, DataChart>); + const widgetMap = widgets.reduce((acc, cur) => { + const viewIds = cur.datachartId + ? [dataChartMap[cur.datachartId].viewId] + : cur.viewIds; + try { + let widget: Widget = { + ...cur, + config: JSON.parse(cur.config), + relations: convertWidgetRelationsToObj(cur.relations), + viewIds, + }; + // TODO migration about font 5 --xld + widget.config.nameConfig = { + ...fontDefault, + ...widget.config.nameConfig, + }; + // TODO migration about filter --xld + if ((widget.config.type as any) !== 'filter') { + acc[cur.id] = widget; + } + return acc; + } catch (error) { + return acc; + } + }, {} as Record<string, Widget>); + + const wrappedDataCharts: DataChart[] = []; + const controllerWidgets: Widget[] = []; // use for reset button + const widgetList = Object.values(widgetMap); + + // 处理 widget包含关系 containerWidget 被包含的 widget.parentId 不为空 + widgetList + .filter(w => w.parentId) + .forEach(widget => { + const parentWidgetId = widget.parentId!; + const childTabId = widget.config.tabId as string; + const curItem = ( + widgetMap[parentWidgetId].config.content as ContainerWidgetContent + ).itemMap[childTabId]; + if (curItem) { + curItem.childWidgetId = widget.id; + curItem.name = widget.config.name; + } else { + let newItem: ContainerItem = { + tabId: childTabId, + name: widget.config.name, + childWidgetId: widget.id, + }; + ( + widgetMap[parentWidgetId].config.content as ContainerWidgetContent + ).itemMap[childTabId] = newItem; + } + }); + + // 处理 controller config visibility依赖关系 id, url参数修改filter + widgetList + .filter(w => w.config.type === 'controller') + .forEach(widget => { + const content = widget.config.content as ControllerWidgetContent; + // 根据 url参数修改filter 默认值 + if (filterSearchParams) { + const paramsKey = Object.keys(filterSearchParams); + const matchKey = isMatchByName ? widget.config.name : widget.id; + if (paramsKey.includes(matchKey)) { + const _value = isMatchByName + ? filterSearchParams[widget.config.name] + : filterSearchParams[widget.id]; + switch (content?.type) { + case ControllerFacadeTypes.RangeTime: + if ( + content.config.controllerDate && + content.config.controllerDate?.startTime && + content.config.controllerDate?.endTime + ) { + content.config.controllerDate.startTime.exactValue = + _value?.[0]; + content.config.controllerDate.endTime.exactValue = _value?.[0]; + } + break; + default: + content.config.controllerValues = _value || []; + break; + } + } + } + + // 通过widget.relation 那里面的 targetId确定 关联controllerWidget 的真实ID + const { visibilityType: visibility, condition } = + content.config.visibility; + const { relations } = widget; + if (visibility === 'condition' && condition) { + const dependentFilterId = relations + .filter(re => re.config.type === 'controlToControl') + .map(re => re.targetId)?.[0]; + if (dependentFilterId) { + condition.dependentControllerId = dependentFilterId; + } + } + + //处理 assistViewFields 旧数据 assistViewFields 是 string 类型 alpha.3版本之后 使用数组存储的 后续版本稳定之后 可以移除此逻辑 + // TODO migration << + if (typeof content?.config?.assistViewFields === 'string') { + content.config.assistViewFields = ( + content.config.assistViewFields as string + ).split(VALUE_SPLITTER); + } + // TODO migration >> --xld + + controllerWidgets.push(widget); + }); + + // 处理 自有 chart widgetControl + widgetList + .filter(w => w.config.content.type === 'widgetChart') + .forEach(widget => { + let content = widget.config.content as ChartWidgetContent; + widget.datachartId = content.dataChart?.id || ''; + wrappedDataCharts.push(content.dataChart!); + delete content.dataChart; + }); + + return { + widgetMap, + wrappedDataCharts, + controllerWidgets, + }; +}; diff --git a/frontend/src/app/types/ChartDataView.ts b/frontend/src/app/types/ChartDataView.ts index a100a0d94..0bb605a07 100644 --- a/frontend/src/app/types/ChartDataView.ts +++ b/frontend/src/app/types/ChartDataView.ts @@ -45,7 +45,6 @@ export type ChartDataViewMeta = { export type ChartDataView = View & { meta?: ChartDataViewMeta[]; computedFields?: ChartDataViewMeta[]; - // view?: { config?: string }; }; export default ChartDataView; diff --git a/frontend/src/globalConstants.ts b/frontend/src/globalConstants.ts index 98592b243..db6d6d474 100644 --- a/frontend/src/globalConstants.ts +++ b/frontend/src/globalConstants.ts @@ -147,11 +147,6 @@ export enum FilterSqlOperator { GreaterThanOrEqual = 'GTE', } -export const ResizeEvent = new Event('resize', { - bubbles: false, - cancelable: true, -}); - export const FILTER_TIME_FORMATTER_IN_QUERY = 'yyyy-MM-DD HH:mm:ss'; export const CONTROLLER_WIDTH_OPTIONS = [ diff --git a/frontend/src/task.ts b/frontend/src/task.ts index 8c44e6896..f58de2b31 100644 --- a/frontend/src/task.ts +++ b/frontend/src/task.ts @@ -1,9 +1,105 @@ /** + + * 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. + */ + +/* eslint-disable prettier/prettier */ + +import 'react-app-polyfill/stable'; +import { ChartDataRequestBuilder } from 'app/pages/ChartWorkbenchPage/models/ChartHttpRequest'; +import { + BackendChart, + BackendChartConfig, +} from 'app/pages/ChartWorkbenchPage/slice/workbenchSlice'; +import { + DataChart, + ServerDashboard, +} from 'app/pages/DashBoardPage/pages/Board/slice/types'; +import { getBoardChartRequests } from 'app/pages/DashBoardPage/utils'; +import { + getChartDataView, + getDashBoardByResBoard, + getDataChartsByServer, +} from 'app/pages/DashBoardPage/utils/board'; +import { getWidgetMapByServer } from 'app/pages/DashBoardPage/utils/widget'; +import { ChartConfig } from 'app/types/ChartConfig'; +// import 'react-app-polyfill/stable'; +// import 'core-js/stable/map'; +// need polyfill [Object.values,Array.prototype.find,new Map] +/** + * @param '' - * @description 'server 定时任务 调用' - */ -const runTask = (params: any) => { - const a = 3; - return a; + * @description 'server task 定时任务 调用' + */ +const getBoardQueryData = (dataStr: string) => { + var data = JSON.parse(dataStr) as ServerDashboard; + + // const renderMode: VizRenderMode = 'schedule'; + const dashboard = getDashBoardByResBoard(data); + const { datacharts, views: serverViews, widgets: serverWidgets } = data; + + const dataCharts: DataChart[] = getDataChartsByServer(datacharts); + const { widgetMap, wrappedDataCharts } = getWidgetMapByServer( + serverWidgets, + dataCharts, + ); + + const allDataCharts: DataChart[] = dataCharts.concat(wrappedDataCharts); + const viewViews = getChartDataView(serverViews, allDataCharts); + + const viewMap = viewViews.reduce((obj, view) => { + obj[view.id] = view; + return obj; + }, {}); + + const dataChartMap = allDataCharts.reduce((obj, dataChart) => { + obj[dataChart.id] = dataChart; + return obj; + }, {}); + let downloadParams = getBoardChartRequests({ + widgetMap, + viewMap, + dataChartMap, + }); + let fileName = dashboard.name; + return JSON.stringify({ downloadParams, fileName }); +}; +const getChartQueryData = (dataStr: string) => { + // see handleCreateDownloadDataTask + const data: BackendChart = JSON.parse(dataStr); + const dataConfig: BackendChartConfig = JSON.parse(data.config as any); + const chartConfig: ChartConfig = dataConfig.chartConfig as ChartConfig; + const builder = new ChartDataRequestBuilder( + { + id: data.viewId, + computedFields: dataConfig.computedFields || [], + } as any, + chartConfig?.datas, + chartConfig?.settings, + ); + let downloadParams = [builder.build()]; + let fileName = data?.name || 'chart'; + return JSON.stringify({ downloadParams, fileName }); +}; +const getQueryData = (type: 'chart' | 'board', dataStr: string) => { + if (type === 'board') { + return getBoardQueryData(dataStr); + } else { + return getChartQueryData(dataStr); + } }; -export default runTask; +export default getQueryData; From e093ce4bdbfd48d841859bb87ca479325fe493fd Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Wed, 29 Dec 2021 12:12:15 +0800 Subject: [PATCH 252/348] chore: some code import --- .../app/pages/DashBoardPage/utils/widget.ts | 5 ++-- .../pages/MainPage/pages/VizPage/index.tsx | 2 +- .../app/pages/StoryBoardPage/Editor/index.tsx | 3 ++- .../pages/StoryBoardPage/Preview/Preview.tsx | 2 +- frontend/src/app/utils/dispatchResize.ts | 26 +++++++++++++++++++ frontend/src/utils/utils.ts | 10 +------ 6 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 frontend/src/app/utils/dispatchResize.ts diff --git a/frontend/src/app/pages/DashBoardPage/utils/widget.ts b/frontend/src/app/pages/DashBoardPage/utils/widget.ts index e196cc239..f65933aba 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/widget.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/widget.ts @@ -27,6 +27,7 @@ import produce from 'immer'; import { DeltaStatic } from 'quill'; import { CSSProperties } from 'react'; import { FONT_FAMILY, G90, WHITE } from 'styles/StyleConstants'; +import { uuidv4 } from 'utils/utils'; import { convertImageUrl, fillPx } from '.'; import { AutoBoardWidgetBackgroundDefault, @@ -98,7 +99,7 @@ export const createControllerWidget = (opt: { boardType: boardType, }); - const widgetId = relations[0]?.sourceId || String(Math.random()); + const widgetId = relations[0]?.sourceId || uuidv4(); const widget: Widget = createWidget({ id: widgetId, dashboardId: boardId, @@ -205,7 +206,7 @@ export const createWidget = (option: { relations?: Relation[]; }) => { const widget: Widget = { - id: option.id || String(Math.random()), + id: option.id || uuidv4(), dashboardId: option.dashboardId, config: option.config, datachartId: option.datachartId || '', diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx index 0755c8c43..8f1df04cb 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx @@ -3,10 +3,10 @@ import { useSplitSizes } from 'app/hooks/useSplitSizes'; import { useBoardSlice } from 'app/pages/DashBoardPage/pages/Board/slice'; import { useEditBoardSlice } from 'app/pages/DashBoardPage/pages/BoardEditor/slice'; import { useStoryBoardSlice } from 'app/pages/StoryBoardPage/slice'; +import { dispatchResize } from 'app/utils/dispatchResize'; import React, { useCallback } from 'react'; import { useRouteMatch } from 'react-router-dom'; import styled from 'styled-components/macro'; -import { dispatchResize } from 'utils/utils'; import { Main } from './Main'; import { SaveForm } from './SaveForm'; import { SaveFormContext, useSaveFormContext } from './SaveFormContext'; diff --git a/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx b/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx index 6fa1567e0..967ac8934 100644 --- a/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx +++ b/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx @@ -19,6 +19,7 @@ import { Layout, Modal } from 'antd'; import { Split } from 'app/components'; import { useSplitSizes } from 'app/hooks/useSplitSizes'; import { StoryContext } from 'app/pages/StoryBoardPage/contexts/StoryContext'; +import { dispatchResize } from 'app/utils/dispatchResize'; import React, { memo, useCallback, @@ -35,7 +36,7 @@ import 'reveal.js/dist/reveal.css'; import RevealZoom from 'reveal.js/plugin/zoom/plugin'; import styled from 'styled-components/macro'; import { SPACE_MD } from 'styles/StyleConstants'; -import { dispatchResize, uuidv4 } from 'utils/utils'; +import { uuidv4 } from 'utils/utils'; import PageThumbnailList from '../components/PageThumbnailList'; import StoryPageItem from '../components/StoryPageItem'; import { storyActions } from '../slice'; diff --git a/frontend/src/app/pages/StoryBoardPage/Preview/Preview.tsx b/frontend/src/app/pages/StoryBoardPage/Preview/Preview.tsx index 5decfabe9..b680a744e 100644 --- a/frontend/src/app/pages/StoryBoardPage/Preview/Preview.tsx +++ b/frontend/src/app/pages/StoryBoardPage/Preview/Preview.tsx @@ -22,6 +22,7 @@ import { vizActions } from 'app/pages/MainPage/pages/VizPage/slice'; import { selectPublishLoading } from 'app/pages/MainPage/pages/VizPage/slice/selectors'; import { publishViz } from 'app/pages/MainPage/pages/VizPage/slice/thunks'; import { StoryContext } from 'app/pages/StoryBoardPage/contexts/StoryContext'; +import { dispatchResize } from 'app/utils/dispatchResize'; import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; @@ -29,7 +30,6 @@ import { useDispatch, useSelector } from 'react-redux'; import 'reveal.js/dist/reveal.css'; import styled from 'styled-components/macro'; import { SPACE_MD } from 'styles/StyleConstants'; -import { dispatchResize } from 'utils/utils'; import PageThumbnailList from '../components/PageThumbnailList'; import StoryHeader from '../components/StoryHeader'; import StoryPageItem from '../components/StoryPageItem'; diff --git a/frontend/src/app/utils/dispatchResize.ts b/frontend/src/app/utils/dispatchResize.ts new file mode 100644 index 000000000..5bc484d67 --- /dev/null +++ b/frontend/src/app/utils/dispatchResize.ts @@ -0,0 +1,26 @@ +/** + * 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. + */ + +export const ResizeEvent = new Event('resize', { + bubbles: false, + cancelable: true, +}); + +export const dispatchResize = () => { + window.dispatchEvent(ResizeEvent); +}; diff --git a/frontend/src/utils/utils.ts b/frontend/src/utils/utils.ts index fc702cee2..c8f6ad7d5 100644 --- a/frontend/src/utils/utils.ts +++ b/frontend/src/utils/utils.ts @@ -10,7 +10,7 @@ import { import { APIResponse } from 'types'; import { SaveFormModel } from '../app/pages/MainPage/pages/VizPage/SaveFormContext'; import { removeToken } from './auth'; -export { default as uuidv4 } from 'uuid/dist/v4'; +export { default as uuidv4 } from 'uuid/dist/esm-browser/v4'; export function errorHandle(error) { if (error?.response) { @@ -349,11 +349,3 @@ export function fastDeleteArrayElement(arr: any[], index: number) { arr.pop(); } -export const ResizeEvent = new Event('resize', { - bubbles: false, - cancelable: true, -}); - -export const dispatchResize = () => { - window.dispatchEvent(ResizeEvent); -}; From 5633a91272a2fbab0c3b7a8b64417b57da8ffa91 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Wed, 29 Dec 2021 12:13:12 +0800 Subject: [PATCH 253/348] chore: add cleanup --- frontend/.babelrc | 5 +---- frontend/package.json | 1 + frontend/rollup.config.js | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/frontend/.babelrc b/frontend/.babelrc index e194a3306..50144f1f2 100644 --- a/frontend/.babelrc +++ b/frontend/.babelrc @@ -8,9 +8,7 @@ // 使用 loose 模式,避免产生副作用 "loose": true } - ], - ["@babel/preset-typeScript"], - + ] ], "plugins": [ "@babel/plugin-external-helpers", @@ -18,7 +16,6 @@ // 开启 babel 各依赖联动,由此插件负责自动导入 helper 辅助函数,从而形成沙箱 polyfill "@babel/plugin-transform-runtime", { - "corejs": { "version": 3, "proposals": true }, "useESModules": true // 关闭 esm 转化,交由 rollup 处理,同上防止冲突 } ] diff --git a/frontend/package.json b/frontend/package.json index 089a22968..ae074e5eb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -182,6 +182,7 @@ "react-scripts": "4.0.3", "react-test-renderer": "^17.0.1", "rollup": "^2.62.0", + "rollup-plugin-cleanup": "^3.2.1", "serve": "^11.3.2", "source-map-explorer": "^2.5.2", "styled-components": "^5.3.0", diff --git a/frontend/rollup.config.js b/frontend/rollup.config.js index 3ad090bb6..30e83916e 100644 --- a/frontend/rollup.config.js +++ b/frontend/rollup.config.js @@ -1,5 +1,4 @@ /* eslint-disable import/no-anonymous-default-export */ - import { babel } from '@rollup/plugin-babel'; import commonjs from '@rollup/plugin-commonjs'; import json from '@rollup/plugin-json'; @@ -7,6 +6,7 @@ import { nodeResolve } from '@rollup/plugin-node-resolve'; import replace from '@rollup/plugin-replace'; import typescript from '@rollup/plugin-typescript'; import path from 'path'; +import cleanup from 'rollup-plugin-cleanup'; export default { input: 'src/task.ts', // 打包入口 output: { @@ -33,9 +33,9 @@ export default { presets: [['@babel/preset-env', { modules: false }]], comments: false, }), + cleanup(), replace({ 'console.log': '//console.log', - // 'new Map': '', }), ], }; From e3ca20ea4d0a95c73bf06e5552fb253393285b62 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Wed, 29 Dec 2021 12:35:30 +0800 Subject: [PATCH 254/348] fix: add ChartDataRequestBuilder aggregation --- frontend/src/task.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/task.ts b/frontend/src/task.ts index f58de2b31..26828d1d5 100644 --- a/frontend/src/task.ts +++ b/frontend/src/task.ts @@ -90,6 +90,9 @@ const getChartQueryData = (dataStr: string) => { } as any, chartConfig?.datas, chartConfig?.settings, + {}, + false, + dataConfig?.aggregation, ); let downloadParams = [builder.build()]; let fileName = data?.name || 'chart'; From d506d3c2a17c02faef09a16082c8c33ac676ec6f Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Wed, 29 Dec 2021 12:54:57 +0800 Subject: [PATCH 255/348] fix:(Chart)add pie migration --- .../components/ChartGraph/BasicPieChart/BasicPieChart.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx index 3b40c2809..8292c7b8f 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx @@ -284,6 +284,14 @@ class BasicPieChart extends Chart { return seriesParams.name; } const data = seriesParams?.data || {}; + + //处理 label 旧数据中没有 showValue, showPercent, showName 数据 alpha.3版本之后是 boolean 类型 后续版本稳定之后 可以移除此逻辑 + // TODO migration << + if (showName === null || showPercent === null || showValue === null) { + return `${seriesParams?.name}: ${seriesParams?.percent + '%'}`; + } + // TODO migration >> --xld + return `${showName ? seriesParams?.name : ''}${ showName && (showValue || showPercent) ? ': ' : '' }${ From 7598069b4f518d33023768fac9017d114eb76ffe Mon Sep 17 00:00:00 2001 From: "jin.gao" <jin.gao@mobilemd.cn> Date: Wed, 29 Dec 2021 14:08:23 +0800 Subject: [PATCH 256/348] =?UTF-8?q?fix:=20=E6=96=B0=E5=A2=9E=E2=80=9C?= =?UTF-8?q?=E5=90=8D=E7=A7=B0=E2=80=9D=E6=95=88=E9=AA=8C=E8=A1=A8=E6=84=8F?= =?UTF-8?q?=E4=B8=8D=E6=98=8E.=20issue=20#482?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx | 3 +++ .../src/app/pages/MainPage/pages/VizPage/SaveForm.tsx | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx index 199f63a2f..c05fd4457 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx @@ -153,6 +153,9 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { placeholder="根目录" treeData={folderTree || []} allowClear + onChange={() => { + formRef.current?.validateFields(); + }} /> </Form.Item> {!simple && ( diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx index bb262994d..0bd6e37ef 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx @@ -143,7 +143,14 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { )} {vizType !== 'STORYBOARD' && ( <Form.Item name="parentId" label="所属目录"> - <TreeSelect placeholder="根目录" treeData={treeData} allowClear /> + <TreeSelect + placeholder="根目录" + treeData={treeData} + allowClear + onChange={() => { + formRef.current?.validateFields(); + }} + /> </Form.Item> )} </ModalForm> From 95bcafc6882d4a0cba7ba9acd58af9a65941f4f7 Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Wed, 29 Dec 2021 14:32:30 +0800 Subject: [PATCH 257/348] feat:support i18n for data source config template --- .../core/data/provider/DataProvider.java | 5 +++- .../provider/DataProviderConfigTemplate.java | 4 ++- .../data/provider/FileDataProvider.java | 22 +++++++++++--- .../main/resources/file-data-provider.json | 14 ++------- .../data/provider/HttpDataProvider.java | 25 +++++++++++++--- .../main/resources/http-data-provider.json | 9 ++---- .../data/provider/JdbcDataProvider.java | 19 ++++++++++++ .../jdbc/DataSourceFactoryDruidImpl.java | 1 - .../main/resources/jdbc-data-provider.json | 21 ++++--------- .../datart/data/provider/ProviderManager.java | 17 ++++++++++- .../resources/i18n/datart_i18n.properties | 30 +++++++++++++++++++ .../i18n/datart_i18n_en_US.properties | 30 +++++++++++++++++++ .../i18n/datart_i18n_zh_CN.properties | 30 +++++++++++++++++++ 13 files changed, 180 insertions(+), 47 deletions(-) diff --git a/core/src/main/java/datart/core/data/provider/DataProvider.java b/core/src/main/java/datart/core/data/provider/DataProvider.java index 0fd475333..4bd59da3e 100644 --- a/core/src/main/java/datart/core/data/provider/DataProvider.java +++ b/core/src/main/java/datart/core/data/provider/DataProvider.java @@ -26,7 +26,6 @@ import java.io.InputStream; import java.sql.SQLException; import java.util.Collections; -import java.util.List; import java.util.Set; public abstract class DataProvider extends AutoCloseBean { @@ -76,6 +75,9 @@ public DataProviderConfigTemplate getConfigTemplate() throws IOException { } } + public abstract String getConfigDisplayName(String name); + + public abstract String getConfigDescription(String name); public abstract Dataframe execute(DataProviderSource config, QueryScript script, ExecuteParam executeParam) throws Exception; @@ -119,4 +121,5 @@ public Set<StdSqlOperator> supportedStdFunctions(DataProviderSource source) { public void resetSource(DataProviderSource source) { } + } \ No newline at end of file diff --git a/core/src/main/java/datart/core/data/provider/DataProviderConfigTemplate.java b/core/src/main/java/datart/core/data/provider/DataProviderConfigTemplate.java index 9fd98f7fb..01b60dcdc 100644 --- a/core/src/main/java/datart/core/data/provider/DataProviderConfigTemplate.java +++ b/core/src/main/java/datart/core/data/provider/DataProviderConfigTemplate.java @@ -29,6 +29,8 @@ public class DataProviderConfigTemplate implements Serializable { private String name; + private String displayName; + private List<Attribute> attributes; @Data @@ -52,7 +54,7 @@ public static class Attribute implements Serializable { private List<Object> options; - private Object children; + private List<Attribute> children; } diff --git a/data-providers/file-data-provider/src/main/java/datart/data/provider/FileDataProvider.java b/data-providers/file-data-provider/src/main/java/datart/data/provider/FileDataProvider.java index c3fb8b576..8b11daae1 100644 --- a/data-providers/file-data-provider/src/main/java/datart/data/provider/FileDataProvider.java +++ b/data-providers/file-data-provider/src/main/java/datart/data/provider/FileDataProvider.java @@ -21,10 +21,7 @@ import datart.core.base.consts.ValueType; import datart.core.base.exception.BaseException; import datart.core.base.exception.Exceptions; -import datart.core.common.CSVParse; -import datart.core.common.FileUtils; -import datart.core.common.POIUtils; -import datart.core.common.UUIDGenerator; +import datart.core.common.*; import datart.core.data.provider.Column; import datart.core.data.provider.DataProviderSource; import datart.core.data.provider.Dataframe; @@ -46,6 +43,23 @@ public class FileDataProvider extends DefaultDataProvider { public static final String FILE_PATH = "path"; + private static final String I18N_PREFIX = "config.template.file."; + + @Override + public String getConfigDisplayName(String name) { + return MessageResolver.getMessage(I18N_PREFIX + name); + } + + @Override + public String getConfigDescription(String name) { + String message = MessageResolver.getMessage(I18N_PREFIX + name + ".desc"); + if (message.startsWith(I18N_PREFIX)) { + return null; + } else { + return message; + } + } + @Override public List<Dataframe> loadFullDataFromSource(DataProviderSource config) throws Exception { Map<String, Object> properties = config.getProperties(); diff --git a/data-providers/file-data-provider/src/main/resources/file-data-provider.json b/data-providers/file-data-provider/src/main/resources/file-data-provider.json index b468bd49b..33a0530bc 100644 --- a/data-providers/file-data-provider/src/main/resources/file-data-provider.json +++ b/data-providers/file-data-provider/src/main/resources/file-data-provider.json @@ -20,19 +20,11 @@ "required": true, "defaultValue": "", "type": "string", - "description": "文件格式,目前支持excel 和 csv。", "options": [ "XLSX", "CSV" ] }, - { - "name": "path", - "required": true, - "defaultValue": "", - "type": "string", - "description": "文件路径,上传后自动生成" - }, { "name": "columns", "defaultValue": "", @@ -44,15 +36,13 @@ "name": "cacheEnable", "required": false, "defaultValue": true, - "type": "bool", - "description": "是否开启本地缓存。开启后,文件解析结果将被缓存。" + "type": "bool" }, { "name": "cacheTimeout", "required": false, "type": "string", - "defaultValue": "30", - "description": "缓存超时时间(分钟)" + "defaultValue": "30" } ] } \ No newline at end of file diff --git a/data-providers/http-data-provider/src/main/java/datart/data/provider/HttpDataProvider.java b/data-providers/http-data-provider/src/main/java/datart/data/provider/HttpDataProvider.java index 22933a477..1e55b0a27 100644 --- a/data-providers/http-data-provider/src/main/java/datart/data/provider/HttpDataProvider.java +++ b/data-providers/http-data-provider/src/main/java/datart/data/provider/HttpDataProvider.java @@ -20,7 +20,9 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import datart.core.common.MessageResolver; import datart.core.common.UUIDGenerator; +import datart.core.data.provider.DataProviderConfigTemplate; import datart.core.data.provider.DataProviderSource; import datart.core.data.provider.Dataframe; import lombok.extern.slf4j.Slf4j; @@ -29,11 +31,9 @@ import org.springframework.util.CollectionUtils; import java.io.IOException; +import java.io.InputStream; import java.net.URISyntaxException; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import java.util.*; @Slf4j public class HttpDataProvider extends DefaultDataProvider { @@ -64,6 +64,8 @@ public class HttpDataProvider extends DefaultDataProvider { private static final String CONTENT_TYPE = "contentType"; + private static final String I18N_PREFIX = "config.template.http."; + private final static ObjectMapper MAPPER; static { @@ -102,6 +104,21 @@ public String getConfigFile() { return "http-data-provider.json"; } + @Override + public String getConfigDisplayName(String name) { + return MessageResolver.getMessage(I18N_PREFIX + name); + } + + @Override + public String getConfigDescription(String name) { + String message = MessageResolver.getMessage(I18N_PREFIX + name + ".desc"); + if (message.startsWith(I18N_PREFIX)) { + return null; + } else { + return message; + } + } + private HttpRequestParam convert2RequestParam(Map<String, Object> schema) throws ClassNotFoundException { HttpRequestParam httpRequestParam = new HttpRequestParam(); diff --git a/data-providers/http-data-provider/src/main/resources/http-data-provider.json b/data-providers/http-data-provider/src/main/resources/http-data-provider.json index a589800a5..65f65bd24 100644 --- a/data-providers/http-data-provider/src/main/resources/http-data-provider.json +++ b/data-providers/http-data-provider/src/main/resources/http-data-provider.json @@ -29,7 +29,6 @@ { "name": "property", "defaultValue": "", - "description": "Http返回结果中,JSON数组的属性名称。嵌套结构用 . 隔开。如 data.list", "type": "string" }, { @@ -50,13 +49,11 @@ { "name": "timeout", "defaultValue": 0, - "description": "请求超时时间", "type": "number" }, { "name": "responseParser", "defaultValue": "", - "description": "请求结果解析器,自定义解析器时,指定解析器的全类名", "type": "string" }, { @@ -82,15 +79,13 @@ "name": "cacheEnable", "required": false, "defaultValue": true, - "type": "bool", - "description": "是否开启本地缓存。开启后,HTTP请求结果将会缓存到服务端。" + "type": "bool" }, { "name": "cacheTimeout", "required": false, "type": "string", - "defaultValue": "5", - "description": "缓存超时时间(分钟)" + "defaultValue": "5" } ] } \ No newline at end of file diff --git a/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/JdbcDataProvider.java b/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/JdbcDataProvider.java index e0f83fd54..239141e99 100644 --- a/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/JdbcDataProvider.java +++ b/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/JdbcDataProvider.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategy; import datart.core.base.exception.Exceptions; import datart.core.common.FileUtils; +import datart.core.common.MessageResolver; import datart.core.data.provider.*; import datart.data.provider.base.DataProviderException; import datart.data.provider.jdbc.JdbcDriverInfo; @@ -48,6 +49,8 @@ public class JdbcDataProvider extends DataProvider { public static final String DRIVER_CLASS = "driverClass"; + private static final String I18N_PREFIX = "config.template.jdbc."; + /** * 获取连接时最大等待时间(毫秒) */ @@ -157,6 +160,7 @@ public boolean validateFunction(DataProviderSource source, String snippet) { public DataProviderConfigTemplate getConfigTemplate() throws IOException { DataProviderConfigTemplate configTemplate = super.getConfigTemplate(); for (DataProviderConfigTemplate.Attribute attribute : configTemplate.getAttributes()) { + attribute.setDisplayName(MessageResolver.getMessage("config.template.jdbc." + attribute.getName())); if (attribute.getName().equals("dbType")) { List<JdbcDriverInfo> jdbcDriverInfos = ProviderFactory.loadDriverInfoFromResource(); List<Object> dbInfos = jdbcDriverInfos.stream().map(info -> { @@ -172,6 +176,21 @@ public DataProviderConfigTemplate getConfigTemplate() throws IOException { return configTemplate; } + @Override + public String getConfigDisplayName(String name) { + return MessageResolver.getMessage(I18N_PREFIX + name); + } + + @Override + public String getConfigDescription(String name) { + String message = MessageResolver.getMessage(I18N_PREFIX + name + ".desc"); + if (message.startsWith(I18N_PREFIX)) { + return null; + } else { + return message; + } + } + @Override public void close() throws IOException { diff --git a/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/DataSourceFactoryDruidImpl.java b/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/DataSourceFactoryDruidImpl.java index 00c200fc9..791b17d7e 100644 --- a/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/DataSourceFactoryDruidImpl.java +++ b/data-providers/jdbc-data-provider/src/main/java/datart/data/provider/jdbc/DataSourceFactoryDruidImpl.java @@ -46,7 +46,6 @@ public void destroy(DataSource dataSource) { private Properties configDataSource(JdbcProperties properties) { Properties pro = new Properties(); - //connect params pro.setProperty(DruidDataSourceFactory.PROP_DRIVERCLASSNAME, properties.getDriverClass()); pro.setProperty(DruidDataSourceFactory.PROP_URL, properties.getUrl()); diff --git a/data-providers/jdbc-data-provider/src/main/resources/jdbc-data-provider.json b/data-providers/jdbc-data-provider/src/main/resources/jdbc-data-provider.json index 7d5bdce45..6595cea12 100644 --- a/data-providers/jdbc-data-provider/src/main/resources/jdbc-data-provider.json +++ b/data-providers/jdbc-data-provider/src/main/resources/jdbc-data-provider.json @@ -1,28 +1,19 @@ { "type": "JDBC", "name": "jdbc-data-provider", - "syntax": { - "name": "SQL", - "keywords": [ - "SELECT", - "FROM", - "JOIN" - ] - }, "attributes": [ { + "code": "dbType", "name": "dbType", "type": "string", "required": true, - "defaultValue": "", - "description": "database type" + "defaultValue": "" }, { "name": "url", "type": "string", "required": true, - "defaultValue": "", - "description": "connect url" + "defaultValue": "" }, { "name": "user", @@ -45,15 +36,13 @@ "name": "serverAggregate", "type": "bool", "required": false, - "defaultValue": false, - "description": "是否开启服务端聚合" + "defaultValue": false }, { "name": "properties", "type": "object", "required": false, - "defaultValue": "", - "description": "Druid连接池其它配置参数" + "defaultValue": "" } ] } \ No newline at end of file diff --git a/data-providers/src/main/java/datart/data/provider/ProviderManager.java b/data-providers/src/main/java/datart/data/provider/ProviderManager.java index 896bf7043..c8ee2673c 100644 --- a/data-providers/src/main/java/datart/data/provider/ProviderManager.java +++ b/data-providers/src/main/java/datart/data/provider/ProviderManager.java @@ -19,6 +19,7 @@ package datart.data.provider; import datart.core.base.exception.Exceptions; +import datart.core.common.MessageResolver; import datart.core.data.provider.*; import datart.data.provider.optimize.DataProviderExecuteOptimizer; import lombok.extern.slf4j.Slf4j; @@ -53,7 +54,21 @@ public List<DataProviderInfo> getSupportedDataProviders() { @Override public DataProviderConfigTemplate getSourceConfigTemplate(String type) throws IOException { - return getDataProviderService(type).getConfigTemplate(); + DataProvider providerService = getDataProviderService(type); + DataProviderConfigTemplate configTemplate = providerService.getConfigTemplate(); + if (!CollectionUtils.isEmpty(configTemplate.getAttributes())) { + for (DataProviderConfigTemplate.Attribute attribute : configTemplate.getAttributes()) { + attribute.setDisplayName(providerService.getConfigDisplayName(attribute.getName())); + attribute.setDescription(providerService.getConfigDescription(attribute.getName())); + if (!CollectionUtils.isEmpty(attribute.getChildren())) { + for (DataProviderConfigTemplate.Attribute child : attribute.getChildren()) { + child.setDisplayName(providerService.getConfigDisplayName(child.getName())); + child.setDescription(providerService.getConfigDescription(child.getName())); + } + } + } + } + return configTemplate; } @Override diff --git a/server/src/main/resources/i18n/datart_i18n.properties b/server/src/main/resources/i18n/datart_i18n.properties index d73637bcb..303135efe 100644 --- a/server/src/main/resources/i18n/datart_i18n.properties +++ b/server/src/main/resources/i18n/datart_i18n.properties @@ -82,6 +82,36 @@ base.exists={0} 已存在 base.resource= base.resource.name=名称 base.not.found={0} 未找到 +config.template.jdbc.dbType=数据库类型 +config.template.jdbc.url=连接地址 +config.template.jdbc.user=用户 +config.template.jdbc.password=密码 +config.template.jdbc.driverClass=驱动类 +config.template.jdbc.serverAggregate=开启服务端聚合 +config.template.jdbc.properties=连接池参数 +config.template.http.url=地址 +config.template.http.schemas=表 +config.template.http.tableName=表名 +config.template.http.method=请求方式 +config.template.http.property=解析字段 +config.template.http.columns=列 +config.template.http.username=用户名 +config.template.http.password=密码 +config.template.http.timeout=超时时间 +config.template.http.responseParser=结果解析器 +config.template.http.headers=请求头 +config.template.http.queryParam=路径参数 +config.template.http.body=请求体 +config.template.http.contentType=contentType +config.template.http.cacheEnable=启用缓存 +config.template.http.cacheTimeout=缓存时间(分钟) +config.template.http.property.desc=Http返回结果中,JSON数组的属性名称。嵌套结构用 `.` 隔开。如 data.list +config.template.file.schemas=表 +config.template.file.tableName=表名 +config.template.file.format=文件格式 +config.template.file.columns=列 +config.template.file.cacheEnable=是否开启缓存 +config.template.file.cacheTimeout=缓存超时 diff --git a/server/src/main/resources/i18n/datart_i18n_en_US.properties b/server/src/main/resources/i18n/datart_i18n_en_US.properties index 12a7cd83d..6d941f5a2 100644 --- a/server/src/main/resources/i18n/datart_i18n_en_US.properties +++ b/server/src/main/resources/i18n/datart_i18n_en_US.properties @@ -81,4 +81,34 @@ resource.organization.owner=At least one organization owner must exist! base.resource.name=name base.exists={0} already exists base.not.found={0} not found +config.template.jdbc.dbType=database type +config.template.jdbc.url=connection url +config.template.jdbc.user=user +config.template.jdbc.password=password +config.template.jdbc.driverClass=driver class +config.template.jdbc.serverAggregate=serverAggregate +config.template.jdbc.properties=properties +config.template.http.url=url +config.template.http.schemas=schemas +config.template.http.tableName=tableName +config.template.http.method=method +config.template.http.property=property +config.template.http.columns=columns +config.template.http.username=username +config.template.http.password=password +config.template.http.timeout=timeout +config.template.http.responseParser=responseParser +config.template.http.headers=headers +config.template.http.queryParam=queryParam +config.template.http.body=body +config.template.http.contentType=contentType +config.template.http.cacheEnable=cacheEnable +config.template.http.cacheTimeout=cacheTimeout +config.template.http.property.desc=The property name of the JSON array in the result. Nested structures are separated by `.` . Such as the data.list +config.template.file.schemas=schemas +config.template.file.tableName=tableName +config.template.file.format=format +config.template.file.columns=columns +config.template.file.cacheEnable=cacheEnable +config.template.file.cacheTimeout=cacheTimeout diff --git a/server/src/main/resources/i18n/datart_i18n_zh_CN.properties b/server/src/main/resources/i18n/datart_i18n_zh_CN.properties index 17a7ee291..a4c1ed770 100644 --- a/server/src/main/resources/i18n/datart_i18n_zh_CN.properties +++ b/server/src/main/resources/i18n/datart_i18n_zh_CN.properties @@ -81,4 +81,34 @@ resource.organization.owner=组织必须有至少一个管理员 base.resource.name=名称 base.not.found={0} 未找到 base.exists={0} 已存在 +config.template.jdbc.dbType=数据库类型 +config.template.jdbc.url=连接地址 +config.template.jdbc.user=用户 +config.template.jdbc.password=密码 +config.template.jdbc.driverClass=驱动类 +config.template.jdbc.serverAggregate=开启服务端聚合 +config.template.jdbc.properties=连接池参数 +config.template.http.url=地址 +config.template.http.schemas=表 +config.template.http.tableName=表名 +config.template.http.method=请求方式 +config.template.http.property=解析字段 +config.template.http.columns=列 +config.template.http.username=用户名 +config.template.http.password=密码 +config.template.http.timeout=超时时间 +config.template.http.responseParser=结果解析器 +config.template.http.headers=请求头 +config.template.http.queryParam=路径参数 +config.template.http.body=请求体 +config.template.http.contentType=contentType +config.template.http.cacheEnable=启用缓存 +config.template.http.cacheTimeout=缓存时间(分钟) +config.template.http.property.desc=Http返回结果中,JSON数组的属性名称。嵌套结构用 `.` 隔开。如 data.list +config.template.file.schemas=表 +config.template.file.tableName=表名 +config.template.file.format=文件格式 +config.template.file.columns=列 +config.template.file.cacheEnable=是否开启缓存 +config.template.file.cacheTimeout=缓存超时 From 3047519b21a12751bf074f78548f128d72cdeff6 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Wed, 29 Dec 2021 15:18:26 +0800 Subject: [PATCH 258/348] chore: main pages i18n support --- frontend/src/app/index.tsx | 46 +++++++++++-------- .../ForgetPasswordForm/CheckCodeForm.tsx | 8 ++-- .../ForgetPasswordForm/ResetPasswordForm.tsx | 14 +++--- .../src/app/pages/LoginPage/LoginForm.tsx | 6 +-- frontend/src/app/pages/MainPage/Access.tsx | 18 ++++++++ .../src/app/pages/MainPage/AccessRoute.tsx | 18 ++++++++ .../src/app/pages/MainPage/Background.tsx | 26 +++++++++-- .../Navbar/DownloadListPopup/DownloadList.tsx | 37 ++++++++++----- .../Navbar/DownloadListPopup/index.tsx | 20 +++++++- .../Navbar/DownloadListPopup/types.ts | 18 ++++++++ .../pages/MainPage/Navbar/ModifyPassword.tsx | 39 ++++++++++++---- .../MainPage/Navbar/OrganizationList.tsx | 22 ++++++++- .../src/app/pages/MainPage/Navbar/Profile.tsx | 23 +++++++++- .../src/app/pages/MainPage/Navbar/index.tsx | 30 ++++++++++-- .../src/app/pages/MainPage/Navbar/service.ts | 20 +++++++- .../app/pages/MainPage/OrganizationForm.tsx | 35 ++++++++++---- frontend/src/app/pages/MainPage/constants.ts | 18 ++++++++ frontend/src/app/pages/MainPage/index.tsx | 18 ++++++++ .../MemberPage/pages/RoleDetailPage/index.tsx | 2 +- .../MainPage/pages/OrgSettingPage/index.tsx | 3 +- .../SourcePage/SourceDetailPage/index.tsx | 2 +- .../pages/VariablePage/VariableForm.tsx | 3 +- .../MainPage/pages/ViewPage/SaveForm.tsx | 3 +- .../pages/MainPage/pages/VizPage/SaveForm.tsx | 3 +- .../src/app/pages/MainPage/slice/index.ts | 20 +++++++- .../src/app/pages/MainPage/slice/selectors.ts | 18 ++++++++ .../src/app/pages/MainPage/slice/thunks.ts | 20 +++++++- .../src/app/pages/MainPage/slice/types.ts | 22 ++++++++- .../src/app/pages/MainPage/slice/utils.ts | 18 ++++++++ .../app/pages/RegisterPage/RegisterForm.tsx | 10 ++-- frontend/src/app/utils/fetch.ts | 2 +- frontend/src/index.tsx | 13 ++---- frontend/src/locales/en/translation.json | 39 ++++++++++------ frontend/src/locales/i18n.ts | 7 +++ frontend/src/locales/zh/translation.json | 33 ++++++++----- 35 files changed, 503 insertions(+), 131 deletions(-) diff --git a/frontend/src/app/index.tsx b/frontend/src/app/index.tsx index ed28067e6..07a06e458 100644 --- a/frontend/src/app/index.tsx +++ b/frontend/src/app/index.tsx @@ -16,10 +16,11 @@ * limitations under the License. */ -import { message } from 'antd'; +import { ConfigProvider, message } from 'antd'; import echartsDefaultTheme from 'app/assets/theme/echarts_default_theme.json'; import { registerTheme } from 'echarts'; import { StorageKeys } from 'globalConstants'; +import { antdLocales } from 'locales/i18n'; import { useEffect, useLayoutEffect } from 'react'; import { Helmet } from 'react-helmet-async'; import { useTranslation } from 'react-i18next'; @@ -62,24 +63,29 @@ export function App() { }, [dispatch]); return ( - <BrowserRouter> - <Helmet - titleTemplate="%s - Datart" - defaultTitle="Datart" - htmlAttributes={{ lang: i18n.language }} - > - <meta name="description" content="Data Art" /> - </Helmet> - <Switch> - <Route path="/login" component={LazyLoginPage} /> - <Route path="/register" component={LazyRegisterPage} /> - <Route path="/active" component={LazyActivePage} /> - <Route path="/forgetPassword" component={LazyForgetPasswordPage} /> - <Route path="/authorization/:token" component={LazyAuthorizationPage} /> - <LoginAuthRoute /> - </Switch> - <GlobalStyle /> - <OverriddenStyle /> - </BrowserRouter> + <ConfigProvider locale={antdLocales[i18n.language]}> + <BrowserRouter> + <Helmet + titleTemplate="%s - Datart" + defaultTitle="Datart" + htmlAttributes={{ lang: i18n.language }} + > + <meta name="description" content="Data Art" /> + </Helmet> + <Switch> + <Route path="/login" component={LazyLoginPage} /> + <Route path="/register" component={LazyRegisterPage} /> + <Route path="/active" component={LazyActivePage} /> + <Route path="/forgetPassword" component={LazyForgetPasswordPage} /> + <Route + path="/authorization/:token" + component={LazyAuthorizationPage} + /> + <LoginAuthRoute /> + </Switch> + <GlobalStyle /> + <OverriddenStyle /> + </BrowserRouter> + </ConfigProvider> ); } diff --git a/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/CheckCodeForm.tsx b/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/CheckCodeForm.tsx index 41dfc63c8..0ed7d0fca 100644 --- a/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/CheckCodeForm.tsx +++ b/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/CheckCodeForm.tsx @@ -35,7 +35,7 @@ export const CheckCodeForm: FC<CheckCodeFormProps> = ({ onNextStep }) => { const [ticket, setTicket] = useState(''); const [submitLoading, setSubmitLoading] = useState(false); const t = useI18NPrefix('forgotPassword'); - const tg = useI18NPrefix('global.validation'); + const tgv = useI18NPrefix('global.validation'); const initialValues = useMemo(() => { return { type: FindWays.Email }; @@ -84,7 +84,7 @@ export const CheckCodeForm: FC<CheckCodeFormProps> = ({ onNextStep }) => { rules={[ { required: true, - message: `${t('email')}${tg('required')}`, + message: `${t('email')}${tgv('required')}`, }, { type: 'email', @@ -100,14 +100,14 @@ export const CheckCodeForm: FC<CheckCodeFormProps> = ({ onNextStep }) => { rules={[ { required: true, - message: `${t('username')}${tg('required')}`, + message: `${t('username')}${tgv('required')}`, }, ]} > <Input size="large" placeholder={t('enterUsername')} /> </Form.Item> ); - }, [isEmail, t, tg]); + }, [isEmail, t, tgv]); const goNext = useCallback(() => { onNextStep(token as string); diff --git a/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/ResetPasswordForm.tsx b/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/ResetPasswordForm.tsx index 0a997eeb1..e3509b705 100644 --- a/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/ResetPasswordForm.tsx +++ b/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/ResetPasswordForm.tsx @@ -34,7 +34,7 @@ export const ResetPasswordForm: FC<ResetPasswordFormProps> = ({ token }) => { const history = useHistory(); const [submiting, setSubmiting] = useState(false); const t = useI18NPrefix('forgotPassword'); - const tg = useI18NPrefix('global.validation'); + const tgv = useI18NPrefix('global.validation'); const onFinish = useCallback( values => { @@ -65,9 +65,9 @@ export const ResetPasswordForm: FC<ResetPasswordFormProps> = ({ token }) => { rules={[ { required: true, - message: `${t('password')}${tg('required')}`, + message: `${t('password')}${tgv('required')}`, }, - { validator: getPasswordValidator(tg('invalidPassword')) }, + { validator: getPasswordValidator(tgv('invalidPassword')) }, ]} > <Input.Password placeholder={t('enterNewPassword')} /> @@ -77,12 +77,12 @@ export const ResetPasswordForm: FC<ResetPasswordFormProps> = ({ token }) => { rules={[ { required: true, - message: `${t('password')}${tg('required')}`, + message: `${t('password')}${tgv('required')}`, }, getConfirmPasswordValidator( 'newPassword', - tg('invalidPassword'), - tg('passwordNotMatch'), + tgv('invalidPassword'), + tgv('passwordNotMatch'), ), ]} > @@ -91,7 +91,7 @@ export const ResetPasswordForm: FC<ResetPasswordFormProps> = ({ token }) => { <Form.Item name="verifyCode" rules={[ - { required: true, message: `${t('verifyCode')}${tg('required')}` }, + { required: true, message: `${t('verifyCode')}${tgv('required')}` }, ]} > <Input placeholder={t('verifyCode')} /> diff --git a/frontend/src/app/pages/LoginPage/LoginForm.tsx b/frontend/src/app/pages/LoginPage/LoginForm.tsx index 666247151..d84415e5f 100644 --- a/frontend/src/app/pages/LoginPage/LoginForm.tsx +++ b/frontend/src/app/pages/LoginPage/LoginForm.tsx @@ -41,7 +41,7 @@ export function LoginForm() { const [form] = Form.useForm(); const logged = !!getToken(); const t = usePrefixI18N('login'); - const tg = usePrefixI18N('global'); + const tgv = usePrefixI18N('global.validation'); const toApp = useCallback(() => { history.replace('/'); @@ -85,7 +85,7 @@ export function LoginForm() { rules={[ { required: true, - message: `${t('username')}${tg('required')}`, + message: `${t('username')}${tgv('required')}`, }, ]} > @@ -96,7 +96,7 @@ export function LoginForm() { rules={[ { required: true, - message: `${t('password')}${tg('required')}`, + message: `${t('password')}${tgv('required')}`, }, ]} > diff --git a/frontend/src/app/pages/MainPage/Access.tsx b/frontend/src/app/pages/MainPage/Access.tsx index bc4e027c5..794fd08eb 100644 --- a/frontend/src/app/pages/MainPage/Access.tsx +++ b/frontend/src/app/pages/MainPage/Access.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Authorized as AuthorizedComponent } from 'app/components'; import { ReactElement } from 'react'; import { useSelector } from 'react-redux'; diff --git a/frontend/src/app/pages/MainPage/AccessRoute.tsx b/frontend/src/app/pages/MainPage/AccessRoute.tsx index af565d95b..bbba6c030 100644 --- a/frontend/src/app/pages/MainPage/AccessRoute.tsx +++ b/frontend/src/app/pages/MainPage/AccessRoute.tsx @@ -1,3 +1,21 @@ +/** + * 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 React from 'react'; import { Redirect } from 'react-router-dom'; import { Access, AccessProps } from './Access'; diff --git a/frontend/src/app/pages/MainPage/Background.tsx b/frontend/src/app/pages/MainPage/Background.tsx index 59216906c..a5006dcf7 100644 --- a/frontend/src/app/pages/MainPage/Background.tsx +++ b/frontend/src/app/pages/MainPage/Background.tsx @@ -1,8 +1,27 @@ +/** + * 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 { AppstoreAddOutlined, ReloadOutlined, SettingOutlined, } from '@ant-design/icons'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { useCallback, useState } from 'react'; import { useSelector } from 'react-redux'; import styled, { keyframes } from 'styled-components/macro'; @@ -26,6 +45,7 @@ export function Background() { const organizations = useSelector(selectOrganizations); const userSettingLoading = useSelector(selectUserSettingLoading); const error = useSelector(selectInitializationError); + const t = useI18NPrefix('main.background'); const showForm = useCallback(() => { setFormVisible(true); @@ -42,14 +62,14 @@ export function Background() { content = ( <Hint> <SettingOutlined className="img loading" /> - <p>应用配置加载中…</p> + <p>{t('loading')}</p> </Hint> ); } else if (error) { content = ( <Hint> <ReloadOutlined className="img" /> - <p>初始化错误,请刷新页面重试</p> + <p>{t('initError')}</p> </Hint> ); } else if ( @@ -61,7 +81,7 @@ export function Background() { <> <Hint className="add" onClick={showForm}> <AppstoreAddOutlined className="img" /> - <p>未加入任何组织,点击创建</p> + <p>{t('createOrg')}</p> </Hint> <OrganizationForm visible={formVisible} onCancel={hideForm} /> </> diff --git a/frontend/src/app/pages/MainPage/Navbar/DownloadListPopup/DownloadList.tsx b/frontend/src/app/pages/MainPage/Navbar/DownloadListPopup/DownloadList.tsx index 802a2f26f..34a37adcf 100644 --- a/frontend/src/app/pages/MainPage/Navbar/DownloadListPopup/DownloadList.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/DownloadListPopup/DownloadList.tsx @@ -1,3 +1,21 @@ +/** + * 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 { List, Tag } from 'antd'; import { ListItem } from 'app/components'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; @@ -16,16 +34,11 @@ import { } from 'styles/StyleConstants'; import { DownloadTask, DownloadTaskState } from '../../slice/types'; import { DownloadListProps } from './types'; -const DOWNLOAD_STATUS_TAGS = { - [DownloadTaskState.CREATE]: '处理中', - [DownloadTaskState.DOWNLOADED]: '已下载', - [DownloadTaskState.FINISH]: '完成', - [DownloadTaskState.FAILED]: '失败', -}; + const DOWNLOAD_STATUS_COLORS = { - [DownloadTaskState.CREATE]: INFO, + [DownloadTaskState.CREATED]: INFO, [DownloadTaskState.DOWNLOADED]: G50, - [DownloadTaskState.FINISH]: SUCCESS, + [DownloadTaskState.DONE]: SUCCESS, [DownloadTaskState.FAILED]: ERROR, }; @@ -38,19 +51,20 @@ const DownloadFileItem: FC<DownloadFileItemProps> = ({ ...restProps }) => { const { name, status } = restProps; + const t = useI18NPrefix('main.nav.download.status'); const { color, tagName, titleClasses } = useMemo(() => { const titleClasses = ['download-file-name']; if (status === DownloadTaskState.DOWNLOADED) { titleClasses.push('downloaded'); - } else if (status === DownloadTaskState.FINISH) { + } else if (status === DownloadTaskState.DONE) { titleClasses.push('finished'); } return { color: DOWNLOAD_STATUS_COLORS[status], - tagName: DOWNLOAD_STATUS_TAGS[status], + tagName: t(DownloadTaskState[status].toLowerCase()), titleClasses: titleClasses.join(' '), }; - }, [status]); + }, [status, t]); return ( <DownloadFileItemWrapper> <span className={titleClasses} onClick={() => onDownloadFile(restProps)}> @@ -147,7 +161,6 @@ const DownloadFileItemWrapper = styled.div` } } .ant-tag { - width: 56px; margin: 0; text-align: center; } diff --git a/frontend/src/app/pages/MainPage/Navbar/DownloadListPopup/index.tsx b/frontend/src/app/pages/MainPage/Navbar/DownloadListPopup/index.tsx index ab4bc49cb..f9461e268 100644 --- a/frontend/src/app/pages/MainPage/Navbar/DownloadListPopup/index.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/DownloadListPopup/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { CloudDownloadOutlined } from '@ant-design/icons'; import { Badge, Tooltip, TooltipProps } from 'antd'; import { Popup } from 'app/components'; @@ -26,7 +44,7 @@ export const DownloadListPopup: FC<DownloadListPopupProps> = ({ const t = useI18NPrefix('main.nav'); const downloadableNum = useMemo(() => { - return (tasks || []).filter(v => v.status === DownloadTaskState.FINISH) + return (tasks || []).filter(v => v.status === DownloadTaskState.DONE) .length; }, [tasks]); diff --git a/frontend/src/app/pages/MainPage/Navbar/DownloadListPopup/types.ts b/frontend/src/app/pages/MainPage/Navbar/DownloadListPopup/types.ts index 40f285ee9..f31c44716 100644 --- a/frontend/src/app/pages/MainPage/Navbar/DownloadListPopup/types.ts +++ b/frontend/src/app/pages/MainPage/Navbar/DownloadListPopup/types.ts @@ -1,3 +1,21 @@ +/** + * 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 { DownloadTask } from '../../slice/types'; type OnDownloadFileType<T = DownloadTask> = (item: T) => void; export interface DownloadListProps<T = DownloadTask> { diff --git a/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx b/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx index a0ec3aa5a..576280b71 100644 --- a/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Button, Form, Input, message, Modal } from 'antd'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { @@ -26,7 +44,8 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ const loading = useSelector(selectModifyPasswordLoading); const [form] = Form.useForm(); const t = useI18NPrefix('main.nav.account.changePassword'); - const tg = useI18NPrefix('global.validation'); + const tgo = useI18NPrefix('global.operation'); + const tgv = useI18NPrefix('global.validation'); const reset = useCallback(() => { form.resetFields(); @@ -44,13 +63,13 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ modifyAccountPassword({ params, resolve: () => { - message.success(t('success')); + message.success(tgo('updateSuccess')); onCancel(); }, }), ); }, - [dispatch, onCancel, t], + [dispatch, onCancel, tgo], ); return ( @@ -74,9 +93,9 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ rules={[ { required: true, - message: `${t('password')}${tg('required')}`, + message: `${t('oldPassword')}${tgv('required')}`, }, - { validator: getPasswordValidator(tg('invalidPassword')) }, + { validator: getPasswordValidator(tgv('invalidPassword')) }, ]} > <Input.Password type="password" /> @@ -87,9 +106,9 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ rules={[ { required: true, - message: `${t('password')}${tg('required')}`, + message: `${t('newPassword')}${tgv('required')}`, }, - { validator: getPasswordValidator(tg('invalidPassword')) }, + { validator: getPasswordValidator(tgv('invalidPassword')) }, ]} > <Input.Password type="password" /> @@ -101,12 +120,12 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ rules={[ { required: true, - message: `${t('password')}${tg('required')}`, + message: `${t('confirmPassword')}${tgv('required')}`, }, getConfirmPasswordValidator( 'newPassword', - tg('invalidPassword'), - tg('passwordNotMatch'), + tgv('invalidPassword'), + tgv('passwordNotMatch'), ), ]} > diff --git a/frontend/src/app/pages/MainPage/Navbar/OrganizationList.tsx b/frontend/src/app/pages/MainPage/Navbar/OrganizationList.tsx index 12cde2864..872f85dbc 100644 --- a/frontend/src/app/pages/MainPage/Navbar/OrganizationList.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/OrganizationList.tsx @@ -1,3 +1,21 @@ +/** + * 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 { CheckOutlined, LoadingOutlined, @@ -34,7 +52,7 @@ export function OrganizationList() { const organizations = useSelector(selectOrganizations); const orgId = useSelector(selectOrgId); const listLoading = useSelector(selectOrganizationListLoading); - const t = useI18NPrefix('main'); + const t = useI18NPrefix('main.nav.organization'); const showForm = useCallback(() => { setFormVisible(true); @@ -97,7 +115,7 @@ export function OrganizationList() { return ( <Wrapper> <Title> - <h2>{t('nav.organization.organizationList')}</h2> + <h2>{t('title')}</h2> <ToolbarButton size="small" icon={<PlusOutlined />} diff --git a/frontend/src/app/pages/MainPage/Navbar/Profile.tsx b/frontend/src/app/pages/MainPage/Navbar/Profile.tsx index c68cb49fd..cbfb29fe6 100644 --- a/frontend/src/app/pages/MainPage/Navbar/Profile.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/Profile.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Button, Form, Input, message, Modal, ModalProps, Upload } from 'antd'; import { Avatar } from 'app/components'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; @@ -23,6 +41,7 @@ export function Profile({ visible, onCancel }: ModalProps) { const [saveDisabled, setSaveDisabled] = useState(true); const [form] = Form.useForm(); const t = useI18NPrefix('main.nav.account.profile'); + const tgo = useI18NPrefix('global.operation'); const reset = useCallback(() => { form.resetFields(); @@ -71,13 +90,13 @@ export function Profile({ visible, onCancel }: ModalProps) { email: loggedInUser!.email, }, resolve: () => { - message.success('修改成功'); + message.success(tgo('updateSuccess')); onCancel && onCancel(null as any); }, }), ); }, - [dispatch, loggedInUser, onCancel], + [dispatch, loggedInUser, onCancel, tgo], ); return ( diff --git a/frontend/src/app/pages/MainPage/Navbar/index.tsx b/frontend/src/app/pages/MainPage/Navbar/index.tsx index 4988adb21..c70b7b496 100644 --- a/frontend/src/app/pages/MainPage/Navbar/index.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { BankFilled, ExportOutlined, @@ -256,11 +274,13 @@ export function Navbar() { onVisibleChange={organizationListVisibleChange} > <li> - <Avatar - src={`${BASE_RESOURCE_URL}${currentOrganization?.avatar}`} - > - <BankFilled /> - </Avatar> + <Tooltip title={t('nav.organization.title')} placement="right"> + <Avatar + src={`${BASE_RESOURCE_URL}${currentOrganization?.avatar}`} + > + <BankFilled /> + </Avatar> + </Tooltip> </li> </Popup> <Popup diff --git a/frontend/src/app/pages/MainPage/Navbar/service.ts b/frontend/src/app/pages/MainPage/Navbar/service.ts index 9ad7f663c..dd2e26a50 100644 --- a/frontend/src/app/pages/MainPage/Navbar/service.ts +++ b/frontend/src/app/pages/MainPage/Navbar/service.ts @@ -1,3 +1,21 @@ +/** + * 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 { request } from 'utils/request'; import { errorHandle } from 'utils/utils'; import { DownloadTask, DownloadTaskState } from '../slice/types'; @@ -9,7 +27,7 @@ export const loadTasks = async () => { method: 'GET', }); const isNeedStopPolling = !(data || []).some( - v => v.status === DownloadTaskState.CREATE, + v => v.status === DownloadTaskState.CREATED, ); return { isNeedStopPolling, diff --git a/frontend/src/app/pages/MainPage/OrganizationForm.tsx b/frontend/src/app/pages/MainPage/OrganizationForm.tsx index 796b8dca9..2adf4c22f 100644 --- a/frontend/src/app/pages/MainPage/OrganizationForm.tsx +++ b/frontend/src/app/pages/MainPage/OrganizationForm.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Form, Input, Modal, ModalProps } from 'antd'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; import debounce from 'debounce-promise'; @@ -20,6 +38,7 @@ export function OrganizationForm({ visible, onCancel }: OrganizationFormProps) { const loading = useSelector(selectSaveOrganizationLoading); const [form] = Form.useForm(); const t = useI18NPrefix('main.nav.organization'); + const tgv = useI18NPrefix('global.validation'); const formSubmit = useCallback( values => { @@ -46,9 +65,9 @@ export function OrganizationForm({ visible, onCancel }: OrganizationFormProps) { return ( <Modal - title={t('organizationCreate')} + title={t('create')} visible={visible} - okText={t('saveDndEnter')} + okText={t('save')} confirmLoading={loading} onOk={save} onCancel={onCancel} @@ -56,16 +75,16 @@ export function OrganizationForm({ visible, onCancel }: OrganizationFormProps) { > <Form form={form} - labelCol={{ span: 4 }} + labelCol={{ span: 6 }} labelAlign="left" - wrapperCol={{ span: 18 }} + wrapperCol={{ span: 16 }} onFinish={formSubmit} > <FormItem name="name" - label={t('organizationName')} + label={t('name')} rules={[ - { required: true, message: t('nameIsEmptyPrompt') }, + { required: true, message: `${t('name')}${tgv('required')}` }, { validator: debounce((_, value) => { return request({ @@ -74,7 +93,7 @@ export function OrganizationForm({ visible, onCancel }: OrganizationFormProps) { params: { name: value }, }).then( () => Promise.resolve(), - () => Promise.reject(new Error(t('duplicateNamePrompt'))), + err => Promise.reject(new Error(err.response.data.message)), ); }, DEFAULT_DEBOUNCE_WAIT), }, @@ -82,7 +101,7 @@ export function OrganizationForm({ visible, onCancel }: OrganizationFormProps) { > <Input /> </FormItem> - <FormItem name="description" label={t('organizationDescription')}> + <FormItem name="description" label={t('desc')}> <Input.TextArea autoSize={{ minRows: 4, maxRows: 8 }} /> </FormItem> </Form> diff --git a/frontend/src/app/pages/MainPage/constants.ts b/frontend/src/app/pages/MainPage/constants.ts index 2d4b385c2..100bc5632 100644 --- a/frontend/src/app/pages/MainPage/constants.ts +++ b/frontend/src/app/pages/MainPage/constants.ts @@ -1,3 +1,21 @@ +/** + * 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. + */ + export enum UserSettingTypes { LastVisitedOrganization = 'LAST_VISITED_ORGANIZATION', } diff --git a/frontend/src/app/pages/MainPage/index.tsx b/frontend/src/app/pages/MainPage/index.tsx index 1f3fdc43c..94f35823f 100644 --- a/frontend/src/app/pages/MainPage/index.tsx +++ b/frontend/src/app/pages/MainPage/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { useAppSlice } from 'app/slice'; import React, { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx index 8c53781dd..3e16fcdbc 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx @@ -180,7 +180,7 @@ export function RoleDetailPage() { params: { name: value, orgId }, }).then( () => Promise.resolve(), - (err: any) => + err => Promise.reject(new Error(err.response.data.message)), ); }, DEFAULT_DEBOUNCE_WAIT), diff --git a/frontend/src/app/pages/MainPage/pages/OrgSettingPage/index.tsx b/frontend/src/app/pages/MainPage/pages/OrgSettingPage/index.tsx index c3e58f0d9..f97c6a1ff 100644 --- a/frontend/src/app/pages/MainPage/pages/OrgSettingPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/OrgSettingPage/index.tsx @@ -128,8 +128,7 @@ export function OrgSettingPage() { params: { name: value }, }).then( () => Promise.resolve(), - (err: any) => - Promise.reject(new Error(err.response.data.message)), + err => Promise.reject(new Error(err.response.data.message)), ); }, DEFAULT_DEBOUNCE_WAIT), }, 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 3a3dcd9e6..2a3c09163 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/index.tsx @@ -352,7 +352,7 @@ export function SourceDetailPage() { params: { name: value, orgId }, }).then( () => Promise.resolve(), - (err: any) => + err => Promise.reject(new Error(err.response.data.message)), ); }, DEFAULT_DEBOUNCE_WAIT), diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx index 4d11f6334..f865ae193 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx @@ -120,8 +120,7 @@ export const VariableForm = memo( params: { name: value, orgId }, }).then( () => Promise.resolve(), - (err: any) => - Promise.reject(new Error(err.response.data.message)), + err => Promise.reject(new Error(err.response.data.message)), ); }, DEFAULT_DEBOUNCE_WAIT), [scope, editingVariable?.name, variables, orgId], diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx index 199f63a2f..348ca65cb 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx @@ -139,8 +139,7 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { params: { name: value, orgId, parentId: parentId || null }, }).then( () => Promise.resolve(), - (err: any) => - Promise.reject(new Error(err.response.data.message)), + err => Promise.reject(new Error(err.response.data.message)), ); }, DEFAULT_DEBOUNCE_WAIT), }, diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx index bb262994d..473a7a0b6 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx @@ -119,8 +119,7 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { }, }).then( () => Promise.resolve(), - (err: any) => - Promise.reject(new Error(err.response.data.message)), + err => Promise.reject(new Error(err.response.data.message)), ); }, DEFAULT_DEBOUNCE_WAIT), }, diff --git a/frontend/src/app/pages/MainPage/slice/index.ts b/frontend/src/app/pages/MainPage/slice/index.ts index 669f625eb..08108c091 100644 --- a/frontend/src/app/pages/MainPage/slice/index.ts +++ b/frontend/src/app/pages/MainPage/slice/index.ts @@ -1,3 +1,21 @@ +/** + * 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 { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { useInjectReducer } from 'utils/@reduxjs/injectReducer'; import { ResourceTypes } from '../pages/PermissionPage/constants'; @@ -77,7 +95,7 @@ const slice = createSlice({ ) { let newDownloadStatus = payload?.newStatus; const _isNotPendingDownload = status => - status !== DownloadTaskState.CREATE; + status !== DownloadTaskState.CREATED; if (!newDownloadStatus) { const originTasks = state.downloadManagement?.tasks || []; const newTasks = payload?.newTasks || []; diff --git a/frontend/src/app/pages/MainPage/slice/selectors.ts b/frontend/src/app/pages/MainPage/slice/selectors.ts index 4cc6cf15e..cef15d82d 100644 --- a/frontend/src/app/pages/MainPage/slice/selectors.ts +++ b/frontend/src/app/pages/MainPage/slice/selectors.ts @@ -1,3 +1,21 @@ +/** + * 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 { createSelector } from '@reduxjs/toolkit'; import { RootState } from 'types'; import { initialState } from '.'; diff --git a/frontend/src/app/pages/MainPage/slice/thunks.ts b/frontend/src/app/pages/MainPage/slice/thunks.ts index 09904eb2d..40817f7be 100644 --- a/frontend/src/app/pages/MainPage/slice/thunks.ts +++ b/frontend/src/app/pages/MainPage/slice/thunks.ts @@ -1,3 +1,21 @@ +/** + * 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 { createAsyncThunk } from '@reduxjs/toolkit'; import { selectLoggedInUser } from 'app/slice/selectors'; import { RootState } from 'types'; @@ -259,7 +277,7 @@ export const fetchDownloadTasks = createAsyncThunk( }); dispatch(mainActions.setDownloadManagement({ newTasks: data })); const isNeedClear = !(data || []).some( - v => v.status === DownloadTaskState.CREATE, + v => v.status === DownloadTaskState.CREATED, ); payload?.resolve?.(isNeedClear); } catch (error) { diff --git a/frontend/src/app/pages/MainPage/slice/types.ts b/frontend/src/app/pages/MainPage/slice/types.ts index e1081c62f..baa7c7172 100644 --- a/frontend/src/app/pages/MainPage/slice/types.ts +++ b/frontend/src/app/pages/MainPage/slice/types.ts @@ -1,3 +1,21 @@ +/** + * 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 { TreeDataNode } from 'antd'; import { UserSettingTypes } from '../constants'; import { PermissionLevels } from '../pages/PermissionPage/constants'; @@ -125,8 +143,8 @@ export enum DownloadManagementStatus { } export enum DownloadTaskState { - CREATE = 0, - FINISH = 1, + CREATED = 0, + DONE = 1, DOWNLOADED = 2, FAILED = -1, } diff --git a/frontend/src/app/pages/MainPage/slice/utils.ts b/frontend/src/app/pages/MainPage/slice/utils.ts index fd94625c4..ab25b9f1c 100644 --- a/frontend/src/app/pages/MainPage/slice/utils.ts +++ b/frontend/src/app/pages/MainPage/slice/utils.ts @@ -1,3 +1,21 @@ +/** + * 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 { request } from 'utils/request'; import { UserSettingTypes } from '../constants'; import { UserSetting } from './types'; diff --git a/frontend/src/app/pages/RegisterPage/RegisterForm.tsx b/frontend/src/app/pages/RegisterPage/RegisterForm.tsx index 0398ea10b..03ed8642f 100644 --- a/frontend/src/app/pages/RegisterPage/RegisterForm.tsx +++ b/frontend/src/app/pages/RegisterPage/RegisterForm.tsx @@ -37,7 +37,7 @@ export const RegisterForm: FC<RegisterFormProps> = ({ onRegisterSuccess }) => { const loading = useSelector(selectRegisterLoading); const [form] = Form.useForm(); const t = useI18NPrefix('register'); - const tg = useI18NPrefix('global.validation'); + const tgv = useI18NPrefix('global.validation'); const onRegister = useCallback( values => { @@ -67,7 +67,7 @@ export const RegisterForm: FC<RegisterFormProps> = ({ onRegisterSuccess }) => { rules={[ { required: true, - message: `${t('username')}${tg('required')}`, + message: `${t('username')}${tgv('required')}`, }, ]} > @@ -78,7 +78,7 @@ export const RegisterForm: FC<RegisterFormProps> = ({ onRegisterSuccess }) => { rules={[ { required: true, - message: `${t('email')}${tg('required')}`, + message: `${t('email')}${tgv('required')}`, }, ]} > @@ -89,10 +89,10 @@ export const RegisterForm: FC<RegisterFormProps> = ({ onRegisterSuccess }) => { rules={[ { required: true, - message: `${t('password')}${tg('required')}`, + message: `${t('password')}${tgv('required')}`, }, { - validator: getPasswordValidator(tg('invalidPassword')), + validator: getPasswordValidator(tgv('invalidPassword')), }, ]} > diff --git a/frontend/src/app/utils/fetch.ts b/frontend/src/app/utils/fetch.ts index 1b7c31db5..f3ebdc6b5 100644 --- a/frontend/src/app/utils/fetch.ts +++ b/frontend/src/app/utils/fetch.ts @@ -230,7 +230,7 @@ export async function loadShareTask(params) { params, }); const isNeedStopPolling = !(data || []).some( - v => v.status === DownloadTaskState.CREATE, + v => v.status === DownloadTaskState.CREATED, ); return { isNeedStopPolling, diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 9b1235ae0..0eca9bae8 100755 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -1,6 +1,4 @@ -import { ConfigProvider } from 'antd'; import 'antd/dist/antd.less'; -import zh_CN from 'antd/lib/locale/zh_CN'; import { App } from 'app'; import 'app/assets/fonts/iconfont.css'; import 'core-js/features/string/replace-all'; @@ -22,17 +20,16 @@ const InspectorWrapper = IS_DEVELOPMENT ? Inspector : React.Fragment; Debugger.instance.setEnable(IS_DEVELOPMENT); export const store = configureAppStore(); -const MainApp = <App />; ReactDOM.render( <InspectorWrapper> <Provider store={store}> <ThemeProvider> - <ConfigProvider locale={zh_CN}> - <HelmetProvider> - <React.StrictMode>{MainApp}</React.StrictMode> - </HelmetProvider> - </ConfigProvider> + <HelmetProvider> + <React.StrictMode> + <App /> + </React.StrictMode> + </HelmetProvider> </ThemeProvider> </Provider> </InspectorWrapper>, diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 41b2b4b08..2f682fd94 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -1,6 +1,10 @@ { "global": { "tokenExpired": "Token expired, please log in", + "operation": { + "updateSuccess": "Update Successful", + "deleteSuccess": "Delete Successful" + }, "validation": { "required": " is required", "invalidPassword": "Password must be 6-20 characters", @@ -64,17 +68,20 @@ "permissions": "Permissions", "settings": "Settings", "download": { - "title": "Download List" + "title": "Download List", + "status": { + "created": "Processing", + "downloaded": "Downloaded", + "done": "Done", + "failed": "Failed" + } }, "organization": { - "organizationList": "组织列表", - "organizationCreate": "创建组织", - "organizationName": "名称", - "nameIsEmptyPrompt": "名称不能为空", - "duplicateNamePrompt": "名称重复", - "organizationDescription": "描述", - "cancel": "取消", - "saveDndEnter": "保存并进入" + "title": "Organizations", + "create": "Create organization", + "name": "Name", + "desc": "Description", + "save": "Save and enter" }, "account": { "profile": { @@ -88,11 +95,10 @@ }, "changePassword": { "title": "Password", - "oldPassword": "旧密码", - "newPassword": "新密码", - "confirmPassword": "确定新密码", - "success": "修改成功", - "save": "保存" + "oldPassword": "Password", + "newPassword": "New password", + "confirmPassword": "Confirm password", + "save": "Save" }, "switchLanguage": { "title": "language" @@ -109,6 +115,11 @@ "orgSettings": { "title": "组织设置" } + }, + "background": { + "loading": "Loading...", + "initError": "Initialization error, please refresh the page and try again", + "createOrg": "You have not joined any organization, click to create" } }, "viz": { diff --git a/frontend/src/locales/i18n.ts b/frontend/src/locales/i18n.ts index db341b868..4c1120612 100644 --- a/frontend/src/locales/i18n.ts +++ b/frontend/src/locales/i18n.ts @@ -1,3 +1,5 @@ +import en_US from 'antd/lib/locale/en_US'; +import zh_CN from 'antd/lib/locale/zh_CN'; import i18next from 'i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; import { initReactI18next } from 'react-i18next'; @@ -40,3 +42,8 @@ export const i18n = i18next escapeValue: false, // not needed for react as it escapes by default }, }); + +export const antdLocales = { + en: en_US, + zh: zh_CN, +}; diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index ab6914794..03107ed20 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -1,6 +1,10 @@ { "global": { "tokenExpired": "会话过期,请重新登录", + "operation": { + "updateSuccess": "修改成功", + "deleteSuccess": "删除成功" + }, "validation": { "required": "不能为空", "invalidPassword": "密码长度为6-20位", @@ -64,17 +68,20 @@ "permissions": "权限", "settings": "设置", "download": { - "title": "下载列表" + "title": "下载列表", + "status": { + "created": "处理中", + "downloaded": "已下载", + "done": "已完成", + "failed": "已失败" + } }, "organization": { - "organizationList": "组织列表", - "organizationCreate": "创建组织", - "organizationName": "名称", - "nameIsEmptyPrompt": "名称不能为空", - "duplicateNamePrompt": "名称重复", - "organizationDescription": "描述", - "cancel": "取消", - "saveDndEnter": "保存并进入" + "title": "组织列表", + "create": "创建组织", + "name": "名称", + "desc": "描述", + "save": "保存并进入" }, "account": { "profile": { @@ -88,10 +95,9 @@ }, "changePassword": { "title": "修改密码", - "oldPassword": "旧密码", + "oldPassword": "密码", "newPassword": "新密码", "confirmPassword": "确定新密码", - "success": "修改成功", "save": "保存" }, "switchLanguage": { @@ -109,6 +115,11 @@ "orgSettings": { "title": "组织设置" } + }, + "background": { + "loading": "应用配置加载中…", + "initError": "初始化错误,请刷新页面重试", + "createOrg": "未加入任何组织,点击创建" } }, "viz": { From dd86127c32edeb8ef71d7fd49f5fa80fd5fd7c73 Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Wed, 29 Dec 2021 15:22:46 +0800 Subject: [PATCH 259/348] fix:(Chart)fix pie migration --- .../components/ChartGraph/BasicPieChart/BasicPieChart.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx index 8292c7b8f..1fa4cc66d 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/BasicPieChart.tsx @@ -286,11 +286,11 @@ class BasicPieChart extends Chart { const data = seriesParams?.data || {}; //处理 label 旧数据中没有 showValue, showPercent, showName 数据 alpha.3版本之后是 boolean 类型 后续版本稳定之后 可以移除此逻辑 - // TODO migration << + // TODO migration start if (showName === null || showPercent === null || showValue === null) { return `${seriesParams?.name}: ${seriesParams?.percent + '%'}`; } - // TODO migration >> --xld + // TODO migration end --tl return `${showName ? seriesParams?.name : ''}${ showName && (showValue || showPercent) ? ': ' : '' From 1301c9a6407e4922c1540631ee84dae7355c7cd9 Mon Sep 17 00:00:00 2001 From: "jin.gao" <jin.gao@mobilemd.cn> Date: Wed, 29 Dec 2021 15:26:57 +0800 Subject: [PATCH 260/348] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=97=AA?= =?UTF-8?q?=E7=83=81404=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/app/pages/MainPage/index.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/pages/MainPage/index.tsx b/frontend/src/app/pages/MainPage/index.tsx index 94f35823f..22ba21736 100644 --- a/frontend/src/app/pages/MainPage/index.tsx +++ b/frontend/src/app/pages/MainPage/index.tsx @@ -86,11 +86,11 @@ export function MainPage() { } }, [dispatch, vizActions, viewActions, orgId]); - useEffect(() => { - if (isExact && orgId) { - history.push(`/organizations/${orgId}`); - } - }, [isExact, orgId, history]); + // useEffect(() => { + // if (isExact && orgId) { + // history.push(`/organizations/${orgId}`); + // } + // }, [isExact, orgId, history]); return ( <AppContainer> @@ -98,6 +98,11 @@ export function MainPage() { <Navbar /> {orgId && ( <Switch> + {orgId ? ( + <Route path="/" exact> + <Redirect to={`/organizations/${orgId}`} /> + </Route> + ) : null} <Route path="/confirminvite" component={ConfirmInvitePage} /> <Route path="/organizations/:orgId" exact> <Redirect From 5425d8b0780070bbf294aaa11911840a0f86bf1e Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Wed, 29 Dec 2021 15:04:24 +0800 Subject: [PATCH 261/348] refactor(chart): should not delete config fields when user drop outside section --- .../ChartDraggable/ChartDraggableElement.tsx | 49 +++++++------- .../ChartDraggableTargetContainer.tsx | 66 +++++++++---------- frontend/src/globalConstants.ts | 2 +- 3 files changed, 58 insertions(+), 59 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableElement.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableElement.tsx index f6f9efb53..a1c96de9a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableElement.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableElement.tsx @@ -21,24 +21,24 @@ import { ChartDataSectionField } from 'app/types/ChartConfig'; import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { XYCoord } from 'dnd-core'; import { CHART_DRAG_ELEMENT_TYPE } from 'globalConstants'; -import { forwardRef, useImperativeHandle, useRef } from 'react'; +import { forwardRef,useImperativeHandle,useRef } from 'react'; import { - ConnectDragSource, - ConnectDropTarget, - DragSource, - DragSourceConnector, - DragSourceMonitor, - DropTarget, - DropTargetConnector, - DropTargetMonitor, +ConnectDragSource, +ConnectDropTarget, +DragSource, +DragSourceConnector, +DragSourceMonitor, +DropTarget, +DropTargetConnector, +DropTargetMonitor } from 'react-dnd'; import styled from 'styled-components/macro'; import { - BORDER_RADIUS, - FONT_SIZE_SUBTITLE, - SPACE, - SPACE_MD, - SPACE_XS, +BORDER_RADIUS, +FONT_SIZE_SUBTITLE, +SPACE, +SPACE_MD, +SPACE_XS } from 'styles/StyleConstants'; interface ChartDraggableElementObject { @@ -54,7 +54,11 @@ interface ChartDraggableElementProps { config: ChartDataSectionField; connectDragSource: ConnectDragSource; connectDropTarget: ConnectDropTarget; - moveCard: (dragIndex: number, hoverIndex: number) => void; + moveCard: ( + dragIndex: number, + hoverIndex: number, + config?: ChartDataSectionField, + ) => void; onDelete: () => void; } @@ -65,7 +69,7 @@ interface ChartDraggableElementInstance { const ChartDraggableElement = forwardRef< HTMLDivElement, ChartDraggableElementProps ->(function Card( +>(function ChartDraggableElement( { content, isDragging, @@ -104,7 +108,7 @@ const ChartDraggableElement = forwardRef< }); export default DropTarget( - CHART_DRAG_ELEMENT_TYPE.DATA_CONFIG_COLUMN, + [CHART_DRAG_ELEMENT_TYPE.DATA_CONFIG_COLUMN], { hover( props: ChartDraggableElementProps, @@ -120,7 +124,9 @@ export default DropTarget( return null; } - const dragIndex = monitor.getItem<ChartDraggableElementObject>().index; + const dragItem = monitor.getItem<ChartDraggableElementObject>(); + + const dragIndex = dragItem.index; const hoverIndex = props.index; // Don't replace items with themselves @@ -179,9 +185,8 @@ export default DropTarget( }), endDrag: (props, monitor) => { const dropResult = monitor.getDropResult(); - if (!monitor.didDrop() && !dropResult) { - props?.onDelete(); - } else if (monitor.didDrop() && !!dropResult?.delete) { + // NOTE: delete item when user did drop, if cancel should not delete anything + if (monitor.didDrop() && !!dropResult?.delete) { props?.onDelete(); } }, @@ -205,7 +210,7 @@ const StyledChartDraggableElement = styled.div<{ background: ${p => p.type === ChartDataViewFieldType.NUMERIC ? p.theme.success : p.theme.info}; border-radius: ${BORDER_RADIUS}; - opacity: ${p => (p.isDragging ? 0 : 1)}; + opacity: ${p => (p.isDragging ? 0.2 : 1)}; `; const Content = styled.div` diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx index 3b6674d10..e69a5565a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx @@ -80,19 +80,13 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = const [{ isOver, canDrop }, drop] = useDrop( () => ({ accept: [ - CHART_DRAG_ELEMENT_TYPE.DATASET_GROUP_COLUMNS, CHART_DRAG_ELEMENT_TYPE.DATASET_COLUMN, CHART_DRAG_ELEMENT_TYPE.DATA_CONFIG_COLUMN, ], drop(item: ChartDataSectionField & DragItem, monitor) { let items = Array.isArray(item) ? item : [item]; let needDelete = true; - if ( - monitor.getItemType() === - CHART_DRAG_ELEMENT_TYPE.DATASET_GROUP_COLUMNS - ) { - items = item as any; - } + if ( monitor.getItemType() === CHART_DRAG_ELEMENT_TYPE.DATASET_COLUMN ) { @@ -107,13 +101,7 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = aggregate: getDefaultAggregate(item), })), ); - const newCurrentConfig = updateByKey( - currentConfig, - 'rows', - currentColumns, - ); - setCurrentConfig(newCurrentConfig); - onConfigChanged?.(ancestors, newCurrentConfig, true); + updateCurrentConfigColumns(currentConfig, currentColumns, true); } else if ( monitor.getItemType() === CHART_DRAG_ELEMENT_TYPE.DATA_CONFIG_COLUMN ) { @@ -121,6 +109,7 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = r => r.uid === item.uid, ); if (originItemIndex > -1) { + needDelete = false; const currentColumns = updateBy( currentConfig?.rows || [], draft => { @@ -128,14 +117,7 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = return draft.splice(item?.index!, 0, item); }, ); - const newCurrentConfig = updateByKey( - currentConfig, - 'rows', - currentColumns, - ); - needDelete = false; - setCurrentConfig(newCurrentConfig); - onConfigChanged?.(ancestors, newCurrentConfig, false); + updateCurrentConfigColumns(currentConfig, currentColumns); } else { const currentColumns = updateBy( currentConfig?.rows || [], @@ -143,13 +125,7 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = return draft.splice(item?.index!, 0, item); }, ); - const newCurrentConfig = updateByKey( - currentConfig, - 'rows', - currentColumns, - ); - setCurrentConfig(newCurrentConfig); - onConfigChanged?.(ancestors, newCurrentConfig, false); + updateCurrentConfigColumns(currentConfig, currentColumns); } } @@ -183,13 +159,6 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = } let items = [item]; - if ( - monitor.getItemType() === - CHART_DRAG_ELEMENT_TYPE.DATASET_GROUP_COLUMNS - ) { - items = item as any; - } - const exists = currentConfig.rows?.map(col => col.colName); return items.every(i => !exists?.includes(i.colName)); }, @@ -205,6 +174,16 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = setCurrentConfig(config); }, [config]); + const updateCurrentConfigColumns = ( + currentConfig, + newColumns, + refreshDataset = false, + ) => { + const newCurrentConfig = updateByKey(currentConfig, 'rows', newColumns); + setCurrentConfig(newCurrentConfig); + onConfigChanged?.(ancestors, newCurrentConfig, refreshDataset); + }; + const getDefaultAggregate = item => { if ( currentConfig?.type === ChartDataSectionType.AGGREGATE || @@ -250,6 +229,21 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = columns.splice(hoverIndex, 0, draggedItem); }); setCurrentConfig(newCurrentConfig); + } else { + // const placeholder = { + // uid: CHARTCONFIG_FIELD_PLACEHOLDER_UID, + // colName: 'Placeholder', + // category: 'field', + // type: 'STRING', + // } as any; + // const newCurrentConfig = updateBy(currentConfig, draft => { + // const columns = draft.rows || []; + // if (dragIndex) { + // columns.splice(dragIndex, 1); + // } + // columns.splice(hoverIndex, 0, placeholder); + // }); + // setCurrentConfig(newCurrentConfig); } }; diff --git a/frontend/src/globalConstants.ts b/frontend/src/globalConstants.ts index 98592b243..8b5a1f705 100644 --- a/frontend/src/globalConstants.ts +++ b/frontend/src/globalConstants.ts @@ -19,6 +19,7 @@ import { FONT_FAMILY } from 'styles/StyleConstants'; export const DATARTSEPERATOR = '@datart@'; +export const CHARTCONFIG_FIELD_PLACEHOLDER_UID = '@placeholder@'; export enum StorageKeys { AuthorizationToken = 'AUTHORIZATION_TOKEN', @@ -92,7 +93,6 @@ export const CHART_LINE_WIDTH = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; export const CHART_DRAG_ELEMENT_TYPE = { DATA_CONFIG_COLUMN: 'data_config_column', DATASET_COLUMN: 'dataset_column', - DATASET_GROUP_COLUMNS: 'dataset_group_columns', }; export const TIME_UNIT_OPTIONS = [ From 71620615330e5e6b8fd78253544140ba3adc2354 Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Wed, 29 Dec 2021 15:49:59 +0800 Subject: [PATCH 262/348] feat:schedule support excel attachment --- .../datart/core/common/JavascriptUtils.java | 16 +++-- .../datart/server/service/ScheduleJob.java | 64 +++++++++++++++---- .../service/impl/DownloadServiceImpl.java | 1 + .../server/service/impl/WeChartJob.java | 3 + 4 files changed, 67 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/datart/core/common/JavascriptUtils.java b/core/src/main/java/datart/core/common/JavascriptUtils.java index 8eb370d56..89e2f6b9c 100644 --- a/core/src/main/java/datart/core/common/JavascriptUtils.java +++ b/core/src/main/java/datart/core/common/JavascriptUtils.java @@ -18,13 +18,14 @@ package datart.core.common; -import datart.core.base.exception.BaseException; import datart.core.base.exception.Exceptions; import jdk.nashorn.api.scripting.NashornScriptEngineFactory; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; +import javax.script.ScriptException; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -36,7 +37,14 @@ public class JavascriptUtils { engineFactory = new NashornScriptEngineFactory(); } - public static Object invoke(String path, String functionName, Object... args) throws Exception { + public static Object invoke(Invocable invocable, String functionName, Object... args) throws Exception { + if (invocable != null) { + return invocable.invokeFunction(functionName, args); + } + return null; + } + + public static Invocable load(String path) throws IOException, ScriptException { InputStream stream = JavascriptUtils.class.getClassLoader().getResourceAsStream(path); if (stream == null) { Exceptions.notFound(path); @@ -45,10 +53,10 @@ public static Object invoke(String path, String functionName, Object... args) th ScriptEngine engine = engineFactory.getScriptEngine(); engine.eval(reader); if (engine instanceof Invocable) { - Invocable invocable = (Invocable) engine; - return invocable.invokeFunction(functionName, args); + return (Invocable) engine; } return null; } } + } diff --git a/server/src/main/java/datart/server/service/ScheduleJob.java b/server/src/main/java/datart/server/service/ScheduleJob.java index bca4e87dd..6ab08bed7 100644 --- a/server/src/main/java/datart/server/service/ScheduleJob.java +++ b/server/src/main/java/datart/server/service/ScheduleJob.java @@ -3,8 +3,10 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import datart.core.base.PageInfo; import datart.core.base.consts.AttachmentType; import datart.core.base.consts.FileOwner; +import datart.core.base.exception.Exceptions; import datart.core.common.*; import datart.core.data.provider.Dataframe; import datart.core.entity.Folder; @@ -17,7 +19,10 @@ import datart.security.base.PasswordToken; import datart.security.base.ResourceType; import datart.security.manager.DatartSecurityManager; +import datart.server.base.dto.DashboardDetail; +import datart.server.base.dto.DatachartDetail; import datart.server.base.dto.ScheduleJobConfig; +import datart.server.base.params.DownloadCreateParam; import datart.server.base.params.ShareCreateParam; import datart.server.base.params.ShareToken; import datart.server.base.params.ViewExecuteParam; @@ -29,6 +34,8 @@ import org.quartz.JobExecutionContext; import org.springframework.util.CollectionUtils; +import javax.script.Invocable; +import javax.script.ScriptException; import java.io.Closeable; import java.io.File; import java.io.IOException; @@ -45,6 +52,8 @@ public abstract class ScheduleJob implements Job, Closeable { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + public Invocable parser; + static { OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } @@ -61,6 +70,8 @@ public abstract class ScheduleJob implements Job, Closeable { protected final List<File> attachments = new LinkedList<>(); + protected final VizService vizService; + public ScheduleJob() { scheduleLogMapper = Application.getBean(ScheduleLogMapperExt.class); @@ -69,6 +80,8 @@ public ScheduleJob() { securityManager = Application.getBean(DatartSecurityManager.class); + vizService = Application.getBean(VizService.class); + } @Override @@ -115,10 +128,16 @@ public void doGetData() throws Exception { for (ScheduleJobConfig.VizContent vizContent : config.getVizContents()) { Folder folder = folderService.retrieve(vizContent.getVizId()); - - if (config.getAttachments().contains(AttachmentType.EXCEL)) { - ViewExecuteParam viewExecuteParam = parseExecuteParam(); - downloadExcel(viewExecuteParam); + DownloadCreateParam downloadCreateParam; + if (ResourceType.DATACHART.name().equals(folder.getRelType())) { + DatachartDetail datachart = vizService.getDatachart(folder.getRelId()); + downloadCreateParam = parseExecuteParam("chart", OBJECT_MAPPER.writeValueAsString(datachart)); + } else { + DashboardDetail dashboard = vizService.getDashboard(folder.getRelId()); + downloadCreateParam = parseExecuteParam("board", OBJECT_MAPPER.writeValueAsString(dashboard)); + } + if (config.getAttachments().contains(AttachmentType.EXCEL) || true) { + downloadExcel(downloadCreateParam); } if (config.getAttachments().contains(AttachmentType.IMAGE)) { @@ -148,11 +167,17 @@ private void insertLog(Date start, Date end, String scheduleId, int status, Stri scheduleLogMapper.insert(scheduleLog); } - private void downloadExcel(ViewExecuteParam viewExecuteParam) throws Exception { + private void downloadExcel(DownloadCreateParam downloadParams) throws Exception { DataProviderService dataProviderService = Application.getBean(DataProviderService.class); - Dataframe dataframe = dataProviderService.execute(viewExecuteParam); Workbook workbook = POIUtils.createEmpty(); - POIUtils.withSheet(workbook, "sheet0", dataframe); + for (int i = 0; i < downloadParams.getDownloadParams().size(); i++) { + ViewExecuteParam viewExecuteParam = downloadParams.getDownloadParams().get(i); + viewExecuteParam.setPageInfo(PageInfo.builder().pageNo(1) + .pageSize(Integer.MAX_VALUE).build()); + String vizName = viewExecuteParam.getVizName(); + Dataframe dataframe = dataProviderService.execute(downloadParams.getDownloadParams().get(i)); + POIUtils.withSheet(workbook, StringUtils.isEmpty(vizName) ? "Sheet" + i : vizName, dataframe); + } File tempFile = File.createTempFile(UUIDGenerator.generate(), ".xlsx"); POIUtils.save(workbook, tempFile.getPath(), true); attachments.add(tempFile); @@ -173,21 +198,34 @@ private void downloadImage(ResourceType vizType, String vizId, int imageWidth) t String path = FileUtils.concatPath(Application.getFileBasePath(), FileOwner.SCHEDULE.getPath(), schedule.getId()); - File file = WebUtils.screenShot2File(url, path,imageWidth); - -// ImageUtils.resize(file.getPath(), imageWidth * 1.0, null); + File file = WebUtils.screenShot2File(url, path, imageWidth); attachments.add(file); } - private ViewExecuteParam parseExecuteParam() { - return new ViewExecuteParam(); + private DownloadCreateParam parseExecuteParam(String type, String json) throws ScriptException, NoSuchMethodException, JsonProcessingException { + Invocable parser = getParser(); + if (parser == null) { + Exceptions.msg("param parser load error"); + } + Object result = parser.invokeFunction("getQueryData", type, json); + return OBJECT_MAPPER.readValue(result.toString(), DownloadCreateParam.class); + } + + private synchronized Invocable getParser() { + if (parser == null) { + try { + parser = JavascriptUtils.load("javascript/parser.js"); + } catch (Exception e) { + Exceptions.e(e); + } + } + return parser; } @Override public void close() throws IOException { - try { securityManager.logoutCurrent(); } catch (Exception e) { diff --git a/server/src/main/java/datart/server/service/impl/DownloadServiceImpl.java b/server/src/main/java/datart/server/service/impl/DownloadServiceImpl.java index 753a64c28..442b65492 100644 --- a/server/src/main/java/datart/server/service/impl/DownloadServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/DownloadServiceImpl.java @@ -145,4 +145,5 @@ public Download downloadFile(String downloadId) { downloadMapper.updateByPrimaryKey(download); return download; } + } diff --git a/server/src/main/java/datart/server/service/impl/WeChartJob.java b/server/src/main/java/datart/server/service/impl/WeChartJob.java index 1385482bc..da738e480 100644 --- a/server/src/main/java/datart/server/service/impl/WeChartJob.java +++ b/server/src/main/java/datart/server/service/impl/WeChartJob.java @@ -32,6 +32,9 @@ @Slf4j public class WeChartJob extends ScheduleJob { + public WeChartJob() { + } + @Override public void doSend() throws Exception { From 6e41dc5c06bc23f3da475d34ead2d6a02bad44e0 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Wed, 29 Dec 2021 16:00:39 +0800 Subject: [PATCH 263/348] feat: Component replacement ReactColorPicker ==> ColorPicker --- frontend/src/app/components/ChartEditor.tsx | 2 +- .../ColorPicker/ChromeColorPicker.tsx | 8 +-- .../ColorPicker/ColorPickerPopover.tsx | 54 ++++++++++++++ .../ColorTag.tsx | 0 .../ColorPicker/SingleColorSelection.tsx | 20 +++--- .../src/app/components/ColorPicker/index.tsx | 9 ++- .../app/components/ColorPicker/slice/types.ts | 2 +- .../Basic/BasicColorSelector.tsx | 3 +- .../FormGenerator/Basic/BasicFont.tsx | 2 +- .../FormGenerator/Basic/BasicLine.tsx | 2 +- .../Customize/ConditionStylePanel/add.tsx | 3 +- .../FormGenerator/Layout/ItemLayout.tsx | 1 + .../ReactColorPicker/ColorPanel.tsx | 35 --------- .../ReactColorPicker/ColorPickerPopover.tsx | 71 ------------------- .../app/components/ReactColorPicker/index.tsx | 4 -- .../ChartDataConfigSection/utils.ts | 3 + .../ChartDraggableSourceContainer.tsx | 4 +- .../AggregationColorizeAction.tsx | 6 +- .../ChartFieldAction/ColorizeRangeAction.tsx | 28 ++++++-- .../ChartFieldAction/ColorizeSingleAction.tsx | 2 +- .../RecommendRangeTimeSelector.tsx | 12 ++-- .../SettingItem/BasicSet/ColorSet.tsx | 4 +- frontend/src/styles/globalStyles.ts | 2 +- 23 files changed, 126 insertions(+), 151 deletions(-) create mode 100644 frontend/src/app/components/ColorPicker/ColorPickerPopover.tsx rename frontend/src/app/components/{ReactColorPicker => ColorPicker}/ColorTag.tsx (100%) delete mode 100644 frontend/src/app/components/ReactColorPicker/ColorPanel.tsx delete mode 100644 frontend/src/app/components/ReactColorPicker/ColorPickerPopover.tsx delete mode 100644 frontend/src/app/components/ReactColorPicker/index.tsx diff --git a/frontend/src/app/components/ChartEditor.tsx b/frontend/src/app/components/ChartEditor.tsx index 86c8edd85..5133601d4 100644 --- a/frontend/src/app/components/ChartEditor.tsx +++ b/frontend/src/app/components/ChartEditor.tsx @@ -130,7 +130,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ setChart(currentChart); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [backendChart?.config.chartGraphId]); + }, [backendChart?.config?.chartGraphId]); const handleChartChange = (c: Chart) => { registerChartEvents(c); diff --git a/frontend/src/app/components/ColorPicker/ChromeColorPicker.tsx b/frontend/src/app/components/ColorPicker/ChromeColorPicker.tsx index c0fb83b08..d5d48fdae 100644 --- a/frontend/src/app/components/ColorPicker/ChromeColorPicker.tsx +++ b/frontend/src/app/components/ColorPicker/ChromeColorPicker.tsx @@ -31,11 +31,11 @@ const toChangeValue = (data: ColorResult) => { /** * 单色选择组件 - * @param onOk + * @param onChange * @param color * @returns 返回一个新的颜色值 */ -function ChromeColorPicker({ color, onOk }: colorSelectionPropTypes) { +function ChromeColorPicker({ color, onChange }: colorSelectionPropTypes) { const [selectColor, setSelectColor] = useState<any>(color); const t = useI18NPrefix('components.colorPicker'); @@ -52,7 +52,7 @@ function ChromeColorPicker({ color, onOk }: colorSelectionPropTypes) { <Button size="middle" onClick={() => { - onOk?.(false); + onChange?.(false); }} > {t('cancel')} @@ -61,7 +61,7 @@ function ChromeColorPicker({ color, onOk }: colorSelectionPropTypes) { type="primary" size="middle" onClick={() => { - onOk?.(selectColor); + onChange?.(selectColor); }} > {t('ok')} diff --git a/frontend/src/app/components/ColorPicker/ColorPickerPopover.tsx b/frontend/src/app/components/ColorPicker/ColorPickerPopover.tsx new file mode 100644 index 000000000..2ab262b93 --- /dev/null +++ b/frontend/src/app/components/ColorPicker/ColorPickerPopover.tsx @@ -0,0 +1,54 @@ +import { Popover, PopoverProps } from 'antd'; +import { FC, useCallback, useMemo, useState } from 'react'; +import { SketchPickerProps } from 'react-color'; +import { ColorPicker } from './ColorTag'; +import SingleColorSelection from './SingleColorSelection'; + +interface ColorPickerPopoverProps { + popoverProps?: PopoverProps; + defaultValue?: string; + onSubmit?: (color) => void; + onChange?: (color) => void; + colorPickerClass?: string; + colors?: SketchPickerProps['presetColors']; +} +export const ColorPickerPopover: FC<ColorPickerPopoverProps> = ({ + children, + defaultValue, + popoverProps, + onSubmit, + onChange, + colorPickerClass, +}) => { + const [visible, setVisible] = useState(false); + const [color] = useState<string | undefined>(defaultValue); + + const onCancel = useCallback(() => { + setVisible(false); + }, []); + const onColorChange = useCallback( + color => { + onSubmit?.(color); + onChange?.(color); + onCancel(); + }, + [onSubmit, onCancel, onChange], + ); + const _popoverProps = useMemo(() => { + return typeof popoverProps === 'object' ? popoverProps : {}; + }, [popoverProps]); + return ( + <Popover + {..._popoverProps} + visible={visible} + onVisibleChange={setVisible} + content={<SingleColorSelection color={color} onChange={onColorChange} />} + trigger="click" + placement="right" + > + {children || ( + <ColorPicker color={defaultValue} className={colorPickerClass} /> + )} + </Popover> + ); +}; diff --git a/frontend/src/app/components/ReactColorPicker/ColorTag.tsx b/frontend/src/app/components/ColorPicker/ColorTag.tsx similarity index 100% rename from frontend/src/app/components/ReactColorPicker/ColorTag.tsx rename to frontend/src/app/components/ColorPicker/ColorTag.tsx diff --git a/frontend/src/app/components/ColorPicker/SingleColorSelection.tsx b/frontend/src/app/components/ColorPicker/SingleColorSelection.tsx index 5053d3dce..09614e3ba 100644 --- a/frontend/src/app/components/ColorPicker/SingleColorSelection.tsx +++ b/frontend/src/app/components/ColorPicker/SingleColorSelection.tsx @@ -16,12 +16,6 @@ * limitations under the License. */ -/** - * 单色选择组件 - * @param onOk - * @param color - * @returns 返回一个新的颜色值 - */ import { Popover } from 'antd'; import { defaultPalette, defaultThemes } from 'app/assets/theme/colorsConfig'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; @@ -38,7 +32,13 @@ import { import ChromeColorPicker from './ChromeColorPicker'; import { colorSelectionPropTypes } from './slice/types'; -function SingleColorSelection({ color, onOk }: colorSelectionPropTypes) { +/** + * 单色选择组件 + * @param onChange + * @param color + * @returns 返回一个新的颜色值 + */ +function SingleColorSelection({ color, onChange }: colorSelectionPropTypes) { const [moreStatus, setMoreStatus] = useState(false); const [selectColor, setSelectColor] = useState(color); const t = useI18NPrefix('components.colorPicker'); @@ -47,13 +47,13 @@ function SingleColorSelection({ color, onOk }: colorSelectionPropTypes) { const moreCallBackFn = value => { if (value) { setSelectColor(value); - onOk?.(value); + onChange?.(value); } setMoreStatus(false); }; const selectColorFn = (color: string) => { setSelectColor(color); - onOk?.(color); + onChange?.(color); }; return ( <ColorWrap> @@ -92,7 +92,7 @@ function SingleColorSelection({ color, onOk }: colorSelectionPropTypes) { trigger="click" placement="bottom" autoAdjustOverflow - content={<ChromeColorPicker color={color} onOk={moreCallBackFn} />} + content={<ChromeColorPicker color={color} onChange={moreCallBackFn} />} > <MoreColor onClick={() => { diff --git a/frontend/src/app/components/ColorPicker/index.tsx b/frontend/src/app/components/ColorPicker/index.tsx index 52ed8b651..e98c9046a 100644 --- a/frontend/src/app/components/ColorPicker/index.tsx +++ b/frontend/src/app/components/ColorPicker/index.tsx @@ -15,7 +15,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { ColorPickerPopover } from './ColorPickerPopover'; +import { ColorTag } from './ColorTag'; import SingleColorSelection from './SingleColorSelection'; import ThemeColorSelection from './ThemeColorSelection'; -export { SingleColorSelection, ThemeColorSelection }; +export { + SingleColorSelection, + ThemeColorSelection, + ColorTag, + ColorPickerPopover, +}; diff --git a/frontend/src/app/components/ColorPicker/slice/types.ts b/frontend/src/app/components/ColorPicker/slice/types.ts index e9cc8334f..f240fca44 100644 --- a/frontend/src/app/components/ColorPicker/slice/types.ts +++ b/frontend/src/app/components/ColorPicker/slice/types.ts @@ -2,7 +2,7 @@ import { ReactNode } from 'react'; export interface colorSelectionPropTypes { color?: string; - onOk?: (color) => void; + onChange?: (color) => void; } export interface themeColorPropTypes { children: ReactNode; diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicColorSelector.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicColorSelector.tsx index 09ff779aa..501ec5bf0 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicColorSelector.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicColorSelector.tsx @@ -17,7 +17,7 @@ */ import { Col, Row } from 'antd'; -import { ColorPickerPopover } from 'app/components/ReactColorPicker'; +import { ColorPickerPopover } from 'app/components/ColorPicker'; import { ChartStyleSectionConfig } from 'app/types/ChartConfig'; import { FC, memo } from 'react'; import styled from 'styled-components/macro'; @@ -85,4 +85,5 @@ const StyledColor = styled.div` height: 24px; background-color: ${props => props.color}; border: ${props => (props.color === 'transparent' ? '1px solid red' : '0px')}; + cursor: pointer; `; diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicFont.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicFont.tsx index 5b2744a2d..c69f59536 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicFont.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicFont.tsx @@ -17,7 +17,7 @@ */ import { Select } from 'antd'; -import { ColorPickerPopover } from 'app/components/ReactColorPicker'; +import { ColorPickerPopover } from 'app/components/ColorPicker'; import { ChartStyleSectionConfig } from 'app/types/ChartConfig'; import { updateByKey } from 'app/utils/mutation'; import { diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicLine.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicLine.tsx index 6b37edd90..63544b932 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicLine.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicLine.tsx @@ -17,7 +17,7 @@ */ import { Select } from 'antd'; -import { ColorPickerPopover } from 'app/components/ReactColorPicker'; +import { ColorPickerPopover } from 'app/components/ColorPicker'; import { ChartStyleSectionConfig } from 'app/types/ChartConfig'; import { updateByKey } from 'app/utils/mutation'; import { CHART_LINE_STYLES, CHART_LINE_WIDTH } from 'globalConstants'; diff --git a/frontend/src/app/components/FormGenerator/Customize/ConditionStylePanel/add.tsx b/frontend/src/app/components/FormGenerator/Customize/ConditionStylePanel/add.tsx index cbfd29418..f9394bde6 100644 --- a/frontend/src/app/components/FormGenerator/Customize/ConditionStylePanel/add.tsx +++ b/frontend/src/app/components/FormGenerator/Customize/ConditionStylePanel/add.tsx @@ -1,5 +1,5 @@ import { Col, Form, Input, InputNumber, Modal, Radio, Row, Select } from 'antd'; -import { ColorPickerPopover } from 'app/components/ReactColorPicker'; +import { ColorPickerPopover } from 'app/components/ColorPicker'; import { ColumnTypes } from 'app/pages/MainPage/pages/ViewPage/constants'; import { memo, useEffect, useState } from 'react'; import styled from 'styled-components'; @@ -279,6 +279,7 @@ const StyledColor = styled.div` height: 16px; background-color: ${props => props.color}; position: relative; + cursor: pointer; ::after { position: absolute; top: -7px; diff --git a/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx b/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx index 1518273e2..8dc9b5a5b 100644 --- a/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx +++ b/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx @@ -120,6 +120,7 @@ const ItemLayout: FC<FormGeneratorLayoutProps<ChartStyleSectionConfig>> = memo( dataConfigs, context, }; + switch (data.comType) { case ChartStyleSectionComponentType.CHECKBOX: return <BasicCheckbox {...props} />; diff --git a/frontend/src/app/components/ReactColorPicker/ColorPanel.tsx b/frontend/src/app/components/ReactColorPicker/ColorPanel.tsx deleted file mode 100644 index e69f9ce0a..000000000 --- a/frontend/src/app/components/ReactColorPicker/ColorPanel.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { FC, useCallback } from 'react'; -import { ColorResult, SketchPicker, SketchPickerProps } from 'react-color'; -import styled from 'styled-components/macro'; -type ValueType = string | undefined; -export interface ColorPanelProps { - value?: ValueType; - onChange?: (value: ValueType, colorResult?: ColorResult) => void; - colors?: SketchPickerProps['presetColors']; -} -const toChangeValue = (data: ColorResult) => { - const { r, g, b, a } = data.rgb; - return `rgba(${r}, ${g}, ${b}, ${a})`; -}; -export const ReactColorPicker: FC<ColorPanelProps> = ({ value, onChange }) => { - const onChangeComplete = useCallback( - v => { - const rgbaValue = toChangeValue(v); - onChange?.(rgbaValue, v); - }, - [onChange], - ); - - return ( - <SketchPickerPanel color={value} onChangeComplete={onChangeComplete} /> - ); -}; - -const SketchPickerPanel = styled(SketchPicker)` - width: 260px !important; - padding: 0 !important; - border-radius: 0 !important; - box-shadow: none !important; -`; - -export type { ColorResult } from 'react-color'; diff --git a/frontend/src/app/components/ReactColorPicker/ColorPickerPopover.tsx b/frontend/src/app/components/ReactColorPicker/ColorPickerPopover.tsx deleted file mode 100644 index cced4054c..000000000 --- a/frontend/src/app/components/ReactColorPicker/ColorPickerPopover.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { Button, Popover, PopoverProps, Row } from 'antd'; -import { FC, useCallback, useEffect, useMemo, useState } from 'react'; -import styled from 'styled-components/macro'; -import { SPACE_MD } from 'styles/StyleConstants'; -import { ColorPanelProps, ColorResult, ReactColorPicker } from './ColorPanel'; -import { ColorPicker } from './ColorTag'; - -interface ColorPickerPopoverProps extends ColorPanelProps { - popoverProps?: PopoverProps; - defaultValue?: string; - onSubmit?: ColorPanelProps['onChange']; - colorPickerClass?: string; -} -export const ColorPickerPopover: FC<Omit<ColorPickerPopoverProps, 'onChange'>> = - ({ children, defaultValue, popoverProps, onSubmit, colorPickerClass }) => { - const [visible, setVisible] = useState(false); - const [color, setColor] = useState<string | undefined>(defaultValue); - const [colorResult, setColorResult] = useState<ColorResult>(); - - useEffect(() => { - if (visible) { - setColor(defaultValue); - } - }, [visible, defaultValue]); - const onCancel = useCallback(() => { - setVisible(false); - }, []); - const onSure = useCallback(() => { - onSubmit?.(color, colorResult); - onCancel(); - }, [onSubmit, color, colorResult, onCancel]); - const onColorChange = useCallback((color, result) => { - setColor(color); - setColorResult(result); - }, []); - const _popoverProps = useMemo(() => { - return typeof popoverProps === 'object' ? popoverProps : {}; - }, [popoverProps]); - return ( - <Popover - {..._popoverProps} - visible={visible} - onVisibleChange={setVisible} - content={ - <ContentWrapper> - <ReactColorPicker value={color} onChange={onColorChange} /> - <Row justify="end"> - <Button size="small" onClick={onCancel}> - 取消 - </Button> - <Button size="small" type="primary" onClick={onSure}> - 确定 - </Button> - </Row> - </ContentWrapper> - } - trigger="click" - placement="right" - > - {children || ( - <ColorPicker color={defaultValue} className={colorPickerClass} /> - )} - </Popover> - ); - }; - -const ContentWrapper = styled.div` - .ant-btn-primary { - margin-left: ${SPACE_MD}; - } -`; diff --git a/frontend/src/app/components/ReactColorPicker/index.tsx b/frontend/src/app/components/ReactColorPicker/index.tsx deleted file mode 100644 index 489d25afb..000000000 --- a/frontend/src/app/components/ReactColorPicker/index.tsx +++ /dev/null @@ -1,4 +0,0 @@ -import { ReactColorPicker } from './ColorPanel'; -import { ColorPickerPopover } from './ColorPickerPopover'; -import { ColorTag } from './ColorTag'; -export { ReactColorPicker, ColorPickerPopover, ColorTag }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/utils.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/utils.ts index c24dd9075..c9e660438 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/utils.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/utils.ts @@ -40,12 +40,15 @@ export function handleDefaultConfig(defaultConfig, configType): any { draft.rows?.forEach((row, i) => { draft.rows[i].aggregate = undefined; }); + if (configType === ChartDataSectionType.AGGREGATE) { delete draft.actions.STRING; } + if (configType === ChartDataSectionType.GROUP) { delete draft.actions.NUMERIC; } + for (let key in draft.actions) { _actions[key] = draft.actions[key].filter( v => v !== 'aggregate' && v !== 'aggregateLimit', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableSourceContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableSourceContainer.tsx index 20aafbd68..eb4f019b9 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableSourceContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableSourceContainer.tsx @@ -91,7 +91,7 @@ export const ChartDraggableSourceContainer: FC< const styleClasses: Array<string> = useMemo(() => { let styleArr: Array<string> = []; if (isActive) { - styleArr.push('containerActive'); + styleArr.push('container-active'); } return styleArr; }, [isActive]); @@ -199,7 +199,7 @@ const Container = styled.div` font-weight: ${FONT_WEIGHT_MEDIUM}; color: ${p => p.theme.textColorSnd}; cursor: pointer; - &.containerActive { + &.container-active { background-color: #f8f9fa; } > p { diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/AggregationColorizeAction.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/AggregationColorizeAction.tsx index 608e34c07..525c2b103 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/AggregationColorizeAction.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/AggregationColorizeAction.tsx @@ -19,10 +19,10 @@ import { Col, Popover, Row } from 'antd'; import Theme from 'app/assets/theme/echarts_default_theme.json'; import { + ColorTag, SingleColorSelection, ThemeColorSelection, } from 'app/components/ColorPicker'; -import { ColorTag } from 'app/components/ReactColorPicker'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { ChartDataSectionField } from 'app/types/ChartConfig'; import ChartDataset from 'app/types/ChartDataset'; @@ -120,11 +120,11 @@ const AggregationColorizeAction: FC<{ visible={selColorBoxStatus} trigger="click" placement="bottomRight" - overlayClassName="AggregationColorPopover" + overlayClassName="aggregation-colorpopover" content={ <SingleColorSelection color={selectColor.value} - onOk={handleColorChange} + onChange={handleColorChange} /> } ></Popover> diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/ColorizeRangeAction.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/ColorizeRangeAction.tsx index 0b15d4dcb..404f85e9e 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/ColorizeRangeAction.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/ColorizeRangeAction.tsx @@ -17,8 +17,9 @@ */ import { Checkbox, Col, Row } from 'antd'; +import { ColorPickerPopover } from 'app/components/ColorPicker'; +import { ColorPicker } from 'app/components/ColorPicker/ColorTag'; import { FormItemEx } from 'app/components/From'; -import { ReactColorPicker } from 'app/components/ReactColorPicker'; import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { ChartDataSectionField } from 'app/types/ChartConfig'; import ChartDataset from 'app/types/ChartDataset'; @@ -79,13 +80,15 @@ const ColorizeRangeAction: FC<{ name="StartColor" rules={[{ required: true }]} initialValue={colorRange?.start} + className="form-item-ex" > - <ReactColorPicker - value={colorRange?.start} + <ColorPickerPopover onChange={v => { handleColorRangeChange(v, colorRange?.end); }} - /> + > + <ColorPicker className="ColorPicker" color={colorRange?.start} /> + </ColorPickerPopover> </FormItemEx> </Row> </Col> @@ -96,13 +99,15 @@ const ColorizeRangeAction: FC<{ name="EndColor" rules={[{ required: true }]} initialValue={colorRange?.end} + className="form-item-ex" > - <ReactColorPicker - value={colorRange?.end} + <ColorPickerPopover onChange={v => { handleColorRangeChange(colorRange?.start, v); }} - /> + > + <ColorPicker className="ColorPicker" color={colorRange?.end} /> + </ColorPickerPopover> </FormItemEx> </Row> </Col> @@ -114,4 +119,13 @@ export default ColorizeRangeAction; const StyledColorizeRangeAction = styled(Row)` justify-content: center; + .ColorPicker { + border: 1px solid ${p => p.theme.borderColorBase}; + } + .form-item-ex { + width: 100%; + .ant-form-item-control-input { + width: auto; + } + } `; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/ColorizeSingleAction.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/ColorizeSingleAction.tsx index cec87af5e..479dd19e7 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/ColorizeSingleAction.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/ColorizeSingleAction.tsx @@ -77,7 +77,7 @@ const ColorizeSingleAction: FC<{ <Row align="middle"> <SingleColorSelection color={colorRange?.start} - onOk={handleColorChange} + onChange={handleColorChange} /> </Row> </Col> diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx index f464da166..a5df50a9c 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/RecommendRangeTimeSelector.tsx @@ -58,16 +58,18 @@ const RecommendRangeTimeSelector: FC< value={recommend} onChange={e => handleChange(e.target?.value)} > - <Space direction="vertical"> + <Space direction="vertical" key={'smallRange'}> {[ RECOMMEND_TIME.TODAY, RECOMMEND_TIME.YESTERDAY, RECOMMEND_TIME.THISWEEK, ].map(time => ( - <Radio value={time}>{t(time)}</Radio> + <Radio key={time} value={time}> + {t(time)} + </Radio> ))} </Space> - <Space direction="vertical"> + <Space direction="vertical" key={'wideRange'}> {[ RECOMMEND_TIME.LAST_7_DAYS, RECOMMEND_TIME.LAST_30_DAYS, @@ -75,7 +77,9 @@ const RecommendRangeTimeSelector: FC< RECOMMEND_TIME.LAST_1_MONTH, RECOMMEND_TIME.LAST_1_YEAR, ].map(time => ( - <Radio value={time}>{t(time)}</Radio> + <Radio key={time} value={time}> + {t(time)} + </Radio> ))} </Space> </Radio.Group> diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ColorSet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ColorSet.tsx index 18d3c062d..35323fa13 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ColorSet.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ColorSet.tsx @@ -17,7 +17,7 @@ */ import { BgColorsOutlined } from '@ant-design/icons'; import { Form, Popover } from 'antd'; -import { ReactColorPicker } from 'app/components/ReactColorPicker'; +import { SingleColorSelection } from 'app/components/ColorPicker'; import { NamePath } from 'rc-field-form/lib/interface'; import React, { FC, memo } from 'react'; import styled from 'styled-components/macro'; @@ -27,7 +27,7 @@ export const ColorSet: FC<{ }> = memo(({ filedValue, filedName }) => { const widgetContent = ( <Form.Item noStyle name={filedName} preserve> - <ReactColorPicker value={filedValue} /> + <SingleColorSelection color={filedValue} /> </Form.Item> ); return ( diff --git a/frontend/src/styles/globalStyles.ts b/frontend/src/styles/globalStyles.ts index 556d3adba..6fa174706 100644 --- a/frontend/src/styles/globalStyles.ts +++ b/frontend/src/styles/globalStyles.ts @@ -187,7 +187,7 @@ export const OverriddenStyle = createGlobalStyle` .datart-data-section-dropdown { z-index: ${MODAL_LEVEL - 1}; } - .AggregationColorPopover{ + .aggregation-colorpopover{ .ant-popover-arrow{ display:none; } From 64b9ff825d206dab7fce642f95c6fe62b85538d6 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Wed, 29 Dec 2021 16:06:36 +0800 Subject: [PATCH 264/348] fix(chart): make action synchronous --- .../pages/ChartWorkbenchPage/models/ChartEventBroker.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts index 88f272918..4b1e2858a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts @@ -84,9 +84,13 @@ class ChartEventBroker { } } - private safeInvoke(event: HooksEvent, options: any, context?: BrokerContext) { + private async safeInvoke( + event: HooksEvent, + options: any, + context?: BrokerContext, + ) { try { - Debugger.instance.measure( + await Debugger.instance.measure( `ChartEventBroker | ${event} `, () => { this._listeners.get(event)?.call?.(this._chart, options, context); From 860af12e38e9828e6b8ecaa01732c113ed30e5ca Mon Sep 17 00:00:00 2001 From: tianlei <qxqzx13@126.com> Date: Wed, 29 Dec 2021 17:12:46 +0800 Subject: [PATCH 265/348] fix:(SQLEditor) init editorCompletionItemProvider --- .../app/pages/MainPage/pages/ViewPage/Main/Editor/SQLEditor.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/SQLEditor.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/SQLEditor.tsx index 05f9edcb8..5c3b3f801 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/SQLEditor.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/SQLEditor.tsx @@ -110,6 +110,7 @@ export const SQLEditor = memo(() => { dispatch( getEditorProvideCompletionItems({ resolve: getItems => { + editorCompletionItemProviderRef?.current?.dispose(); const providerRef = editor.languages.registerCompletionItemProvider( 'sql', { From f15cfa4b7c4ef75532e4ecf15e364a00e61e6db7 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Wed, 29 Dec 2021 17:12:50 +0800 Subject: [PATCH 266/348] style(chart): format import --- .../ChartDraggable/ChartDraggableElement.tsx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableElement.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableElement.tsx index a1c96de9a..8fc580780 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableElement.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableElement.tsx @@ -21,24 +21,24 @@ import { ChartDataSectionField } from 'app/types/ChartConfig'; import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { XYCoord } from 'dnd-core'; import { CHART_DRAG_ELEMENT_TYPE } from 'globalConstants'; -import { forwardRef,useImperativeHandle,useRef } from 'react'; +import { forwardRef, useImperativeHandle, useRef } from 'react'; import { -ConnectDragSource, -ConnectDropTarget, -DragSource, -DragSourceConnector, -DragSourceMonitor, -DropTarget, -DropTargetConnector, -DropTargetMonitor + ConnectDragSource, + ConnectDropTarget, + DragSource, + DragSourceConnector, + DragSourceMonitor, + DropTarget, + DropTargetConnector, + DropTargetMonitor, } from 'react-dnd'; import styled from 'styled-components/macro'; import { -BORDER_RADIUS, -FONT_SIZE_SUBTITLE, -SPACE, -SPACE_MD, -SPACE_XS + BORDER_RADIUS, + FONT_SIZE_SUBTITLE, + SPACE, + SPACE_MD, + SPACE_XS, } from 'styles/StyleConstants'; interface ChartDraggableElementObject { From 1bee541c9530be7a84484b70f0d624d386c44425 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Wed, 29 Dec 2021 17:39:41 +0800 Subject: [PATCH 267/348] revert(chart): should keep delete field when drag out of section --- .../components/ChartDraggable/ChartDraggableElement.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableElement.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableElement.tsx index 8fc580780..dc224b288 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableElement.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableElement.tsx @@ -185,8 +185,9 @@ export default DropTarget( }), endDrag: (props, monitor) => { const dropResult = monitor.getDropResult(); - // NOTE: delete item when user did drop, if cancel should not delete anything - if (monitor.didDrop() && !!dropResult?.delete) { + if (!monitor.didDrop() && !dropResult) { + props?.onDelete(); + } else if (monitor.didDrop() && !!dropResult?.delete) { props?.onDelete(); } }, From f522bf0ea9120a7d5e22630ca0f9774a81776f4f Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Wed, 29 Dec 2021 17:46:36 +0800 Subject: [PATCH 268/348] fix: thymeleaf i18n bug fix --- .../java/datart/server/config/WebMvcConfig.java | 4 +--- .../server/service/impl/MailServiceImpl.java | 14 ++++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/server/src/main/java/datart/server/config/WebMvcConfig.java b/server/src/main/java/datart/server/config/WebMvcConfig.java index c349ce558..2530fdf36 100644 --- a/server/src/main/java/datart/server/config/WebMvcConfig.java +++ b/server/src/main/java/datart/server/config/WebMvcConfig.java @@ -31,8 +31,6 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; - import java.util.List; @Configuration @@ -51,7 +49,7 @@ public WebMvcConfig(LoginInterceptor loginInterceptor) { public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor).addPathPatterns(getPathPrefix() + "/**"); //i18n locale interceptor - registry.addInterceptor(new LocaleChangeInterceptor()); +// registry.addInterceptor(new LocaleChangeInterceptor()); registry.addInterceptor(new BasicValidRequestInterceptor()).addPathPatterns("/**"); } diff --git a/server/src/main/java/datart/server/service/impl/MailServiceImpl.java b/server/src/main/java/datart/server/service/impl/MailServiceImpl.java index b64845965..591d443f8 100644 --- a/server/src/main/java/datart/server/service/impl/MailServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/MailServiceImpl.java @@ -34,12 +34,15 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Component; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; +import org.thymeleaf.spring5.messageresolver.SpringMessageResolver; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; @@ -91,7 +94,10 @@ public class MailServiceImpl extends BaseService implements MailService { @Value("${spring.mail.senderName:Datart}") private String senderName; - public MailServiceImpl(TemplateEngine templateEngine) { + public MailServiceImpl(TemplateEngine templateEngine,MessageSource messageSource) { + SpringMessageResolver springMessageResolver = new SpringMessageResolver(); + springMessageResolver.setMessageSource(messageSource); + templateEngine.setMessageResolver(springMessageResolver); this.templateEngine = templateEngine; } @@ -140,7 +146,7 @@ public void sendVerifyCode(User user) throws UnsupportedEncodingException, Messa } private MimeMessage createVerifyCodeMimeMessage(User user) throws UnsupportedEncodingException, MessagingException { - Context context = new Context(); + Context context = new Context(LocaleContextHolder.getLocale()); context.setVariable(VERIFY_CODE, user.getPassword()); context.setVariable(MESSAGE, getMessages("message.user.reset.password.mail.message", user.getUsername(), SecurityUtils.VERIFY_CODE_TIMEOUT_MIN)); String mailContent = templateEngine.process(FIND_PASSWORD_TEMPLATE, context); @@ -155,7 +161,7 @@ private MimeMessage createInviteMimeMessage(User user, Organization org) throws inviteToken.setInviter(getCurrentUser().getUsername()); String tokenString = JwtUtils.toJwtString(inviteToken); - Context context = new Context(); + Context context = new Context(LocaleContextHolder.getLocale()); context.setVariable(TOKEN_KEY, tokenString); context.setVariable(USERNAME_KEY, user.getUsername()); context.setVariable(INVITER, inviteToken.getInviter()); @@ -174,7 +180,7 @@ private MimeMessage createActiveMimeMessage(User user) throws MessagingException passwordToken.setCreateTime(System.currentTimeMillis()); String tokenString = JwtUtils.toJwtString(passwordToken); - Context context = new Context(); + Context context = new Context(LocaleContextHolder.getLocale()); context.setVariable(USERNAME_KEY, user.getUsername()); context.setVariable(TOKEN_KEY, tokenString); String activeUrl = Application.getWebRootURL() + "/active"; From a6ef5070433b4284ed32225c3bd2440fb90c218e Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Wed, 29 Dec 2021 15:15:15 +0800 Subject: [PATCH 269/348] feat: add widget.ation i18n --- .../WidgetToolBar/WidgetActionDropdown.tsx | 27 ++++++++++--------- frontend/src/locales/en/translation.json | 13 ++++++++- frontend/src/locales/zh/translation.json | 13 ++++++++- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/WidgetActionDropdown.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/WidgetActionDropdown.tsx index 74904c2ce..e951ff04c 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/WidgetActionDropdown.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetToolBar/WidgetActionDropdown.tsx @@ -27,6 +27,7 @@ import { SyncOutlined, } from '@ant-design/icons'; import { Button, Dropdown, Menu } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { memo, useCallback, useContext, useMemo } from 'react'; import { BoardContext } from '../../contexts/BoardContext'; import { WidgetChartContext } from '../../contexts/WidgetChartContext'; @@ -47,69 +48,69 @@ export const WidgetActionDropdown: React.FC<WidgetActionDropdownProps> = memo( const { editing: boardEditing } = useContext(BoardContext); const { onWidgetAction } = useContext(WidgetMethodContext); const dataChart = useContext(WidgetChartContext)!; - + const t = useI18NPrefix(`viz.widget.action`); const menuClick = useCallback( ({ key }) => { onWidgetAction(key, widget); }, [onWidgetAction, widget], ); - const getAllList = () => { + const getAllList = useCallback(() => { const allWidgetActionList: WidgetActionListItem<widgetActionType>[] = [ { key: 'refresh', - label: '同步数据', + label: t('refresh'), icon: <SyncOutlined />, }, { key: 'fullScreen', - label: '全屏', + label: t('fullScreen'), icon: <FullscreenOutlined />, }, { key: 'edit', - label: '编辑', + label: t('edit'), icon: <EditOutlined />, }, { key: 'delete', - label: '删除', + label: t('delete'), icon: <DeleteOutlined />, danger: true, }, { key: 'info', - label: '信息', + label: t('info'), icon: <InfoOutlined />, }, { key: 'makeLinkage', - label: '联动设置', + label: t('makeLinkage'), icon: <LinkOutlined />, divider: true, }, { key: 'closeLinkage', - label: '关闭联动', + label: t('closeLinkage'), icon: <CloseCircleOutlined />, danger: true, }, { key: 'makeJump', - label: '跳转设置', + label: t('makeJump'), icon: <BranchesOutlined />, divider: true, }, { key: 'closeJump', - label: '关闭跳转', + label: t('closeJump'), icon: <CloseCircleOutlined />, danger: true, }, ]; return allWidgetActionList; - }; + }, [t]); const actionList = useMemo(() => { return ( getWidgetActionList({ @@ -119,7 +120,7 @@ export const WidgetActionDropdown: React.FC<WidgetActionDropdownProps> = memo( chartGraphId: dataChart?.config.chartGraphId, }) || [] ); - }, [boardEditing, dataChart?.config.chartGraphId, widget]); + }, [boardEditing, dataChart?.config.chartGraphId, getAllList, widget]); const dropdownList = useMemo(() => { const menuItems = actionList.map(item => { return ( diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 2f682fd94..260fd9546 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -549,6 +549,17 @@ "controller": "Controller", "query": "Query", "reset": "Reset" + }, + "action": { + "refresh": "Refresh", + "fullScreen": "FullScreen", + "edit": "Edit", + "delete": "Delete", + "info": "Info", + "makeLinkage": "Set Linkage", + "closeLinkage": "Close Linkage", + "makeJump": "Set Jump", + "closeJump": "Close Jump" } }, "sideBar": { @@ -606,4 +617,4 @@ "searchValue": "Search name keywords" } } -} +} \ No newline at end of file diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 03107ed20..e2fa4d2b1 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -549,6 +549,17 @@ "controller": "控制器", "query": "查询", "reset": "重置" + }, + "action": { + "refresh": "同步数据", + "fullScreen": "全屏", + "edit": "编辑", + "delete": "删除", + "info": "基本信息", + "makeLinkage": "联动设置", + "closeLinkage": "关闭联动", + "makeJump": "跳转设置", + "closeJump": "关闭跳转" } }, "sideBar": { @@ -606,4 +617,4 @@ "searchValue": "搜索名称关键字" } } -} +} \ No newline at end of file From 06b19daf81a9fc98aa49e874491e8a8e2fff3ae0 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Wed, 29 Dec 2021 18:00:15 +0800 Subject: [PATCH 270/348] chore: add board i18n --- .../MediaWidget/ImageWidget/index.tsx | 11 +++- .../src/app/pages/DashBoardPage/constants.ts | 30 +++++----- .../components/SlideSetting/BoardSetting.tsx | 54 ++++++++++++----- .../SettingItem/AutoUpdateSet.tsx | 6 +- .../SettingItem/BackgroundSet.tsx | 6 +- .../SettingItem/BasicSet/ImageUpload.tsx | 14 +++-- .../SlideSetting/SettingItem/BorderSet.tsx | 13 +++-- .../SettingItem/InitialQuerySet.tsx | 34 +++++------ .../SlideSetting/SettingItem/NameSet.tsx | 8 ++- .../SlideSetting/SettingItem/PaddingSet.tsx | 10 ++-- .../SlideSetting/SettingItem/ScaleModeSet.tsx | 9 +-- .../components/SlideSetting/WidgetSetting.tsx | 40 ++++++++----- .../ChartPreview/ChartPreviewBoard.tsx | 1 - frontend/src/locales/en/translation.json | 58 +++++++++++++++++++ frontend/src/locales/zh/translation.json | 57 ++++++++++++++++++ 15 files changed, 264 insertions(+), 87 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/MediaWidget/ImageWidget/index.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/MediaWidget/ImageWidget/index.tsx index b6c2c89bf..19e8592b5 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/MediaWidget/ImageWidget/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/MediaWidget/ImageWidget/index.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ import { Empty } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { BoardActionContext } from 'app/pages/DashBoardPage/contexts/BoardActionContext'; import { WidgetContext } from 'app/pages/DashBoardPage/contexts/WidgetContext'; import { WidgetInfoContext } from 'app/pages/DashBoardPage/contexts/WidgetInfoContext'; @@ -37,7 +38,7 @@ const ImageWidget: React.FC<{}> = () => { const { imageConfig } = widget.config.content as MediaWidgetContent; const widgetBgImage = widget.config.background.image; const [rect, refDom] = useClientRect<HTMLDivElement>(32); - + const t = useI18NPrefix(`viz.board.setting`); const widthBigger = useMemo(() => { return rect.width >= rect.height; }, [rect]); @@ -67,11 +68,15 @@ const ImageWidget: React.FC<{}> = () => { }, [imageRatioCss, imageConfig?.type]); const renderImage = useMemo(() => { return editing ? ( - <UploadDragger value={widgetBgImage} onChange={onChange} /> + <UploadDragger + value={widgetBgImage} + onChange={onChange} + placeholder={t('uploadTip')} + /> ) : widgetBgImage ? null : ( <Empty description="" /> ); - }, [editing, onChange, widgetBgImage]); + }, [editing, onChange, t, widgetBgImage]); return <Wrap ref={refDom}>{renderImage}</Wrap>; }; export default ImageWidget; diff --git a/frontend/src/app/pages/DashBoardPage/constants.ts b/frontend/src/app/pages/DashBoardPage/constants.ts index 9c09c1529..c47670c9c 100644 --- a/frontend/src/app/pages/DashBoardPage/constants.ts +++ b/frontend/src/app/pages/DashBoardPage/constants.ts @@ -97,11 +97,11 @@ export const TEXT_ALIGN_ENUM = strEnumType(['left', 'center', 'right']); export type TextAlignType = keyof typeof TEXT_ALIGN_ENUM; export const BORDER_STYLE_ENUM = strEnumType([ + 'none', 'solid', 'dashed', 'dotted', 'double', - 'none', 'hidden', 'ridge', 'groove', @@ -111,16 +111,16 @@ export const BORDER_STYLE_ENUM = strEnumType([ export type BorderStyleType = keyof typeof BORDER_STYLE_ENUM; export const BORDER_STYLE_OPTIONS = [ - { name: '无', value: BORDER_STYLE_ENUM.none }, - { name: '实线', value: BORDER_STYLE_ENUM.solid }, - { name: '虚线', value: BORDER_STYLE_ENUM.dashed }, - { name: '点线', value: BORDER_STYLE_ENUM.dotted }, - { name: '双线', value: BORDER_STYLE_ENUM.double }, - { name: '隐藏', value: BORDER_STYLE_ENUM.hidden }, - { name: '凹槽', value: BORDER_STYLE_ENUM.groove }, - { name: '垄状', value: BORDER_STYLE_ENUM.ridge }, - { name: 'inset', value: BORDER_STYLE_ENUM.inset }, - { name: 'outset', value: BORDER_STYLE_ENUM.outset }, + { value: BORDER_STYLE_ENUM.none }, + { value: BORDER_STYLE_ENUM.solid }, + { value: BORDER_STYLE_ENUM.dashed }, + { value: BORDER_STYLE_ENUM.dotted }, + { value: BORDER_STYLE_ENUM.double }, + { value: BORDER_STYLE_ENUM.hidden }, + { value: BORDER_STYLE_ENUM.groove }, + { value: BORDER_STYLE_ENUM.ridge }, + { value: BORDER_STYLE_ENUM.inset }, + { value: BORDER_STYLE_ENUM.outset }, ]; export const SCALE_MODE_ENUM = strEnumType([ @@ -132,10 +132,10 @@ export const SCALE_MODE_ENUM = strEnumType([ export type ScaleModeType = keyof typeof SCALE_MODE_ENUM; export const SCALE_MODE__OPTIONS = [ - { name: '等比宽度缩放', value: SCALE_MODE_ENUM.scaleWidth }, - { name: '等比高度缩放', value: SCALE_MODE_ENUM.scaleHeight }, - { name: '全屏铺满', value: SCALE_MODE_ENUM.scaleFull }, - { name: '实际尺寸', value: SCALE_MODE_ENUM.noScale }, + { value: SCALE_MODE_ENUM.scaleWidth }, + { value: SCALE_MODE_ENUM.scaleHeight }, + { value: SCALE_MODE_ENUM.scaleFull }, + { value: SCALE_MODE_ENUM.noScale }, ]; export const enum ValueOptionTypes { diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/BoardSetting.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/BoardSetting.tsx index dfaf893ad..6d968080b 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/BoardSetting.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/BoardSetting.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ import { Collapse, Form } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { BoardConfigContext } from 'app/pages/DashBoardPage/contexts/BoardConfigContext'; import { BoardContext } from 'app/pages/DashBoardPage/contexts/BoardContext'; import { DashboardConfig } from 'app/pages/DashBoardPage/pages/Board/slice/types'; @@ -40,6 +41,7 @@ import { Group, SettingPanel } from './SettingPanel'; const { Panel } = Collapse; export const BoardSetting: FC = memo(() => { + const t = useI18NPrefix(`viz.board.setting`); const dispatch = useDispatch(); const { boardType } = useContext(BoardContext); const { config } = useContext(BoardConfigContext); @@ -95,7 +97,7 @@ export const BoardSetting: FC = memo(() => { ); return ( - <SettingPanel title="面板设计"> + <SettingPanel title={`${t('board')} ${t('setting')}`}> <Form form={form} name="auto-board-from" @@ -110,40 +112,64 @@ export const BoardSetting: FC = memo(() => { > {boardType === 'auto' && ( <> - <Panel header="面板属性" key="autoSize" forceRender> + <Panel header={`${t('baseProperty')}`} key="autoSize" forceRender> <Group> - <NumberSet label={'画布边距-上下'} name="paddingH" /> - <NumberSet label={'画布边距-左右'} name="paddingW" /> - <NumberSet label={'组件间距-上下'} name="marginH" /> - <NumberSet label={'组件间距-左右'} name="marginW" /> - <NumberSet label={'组件高度'} name="rowHeight" /> + <NumberSet + label={`${t('board')} ${t('marginTB')}`} + name="paddingH" + /> + <NumberSet + label={`${t('board')} ${t('marginLR')}`} + name="paddingW" + /> + <NumberSet + label={`${t('widget')} ${t('paddingTB')}`} + name="marginH" + /> + <NumberSet + label={`${t('widget')} ${t('paddingLR')}`} + name="marginW" + /> + <NumberSet + label={`${t('widget')} ${t('rowHeight')}`} + name="rowHeight" + /> </Group> </Panel> </> )} {boardType === 'free' && ( <> - <Panel header="面板尺寸" key="freeSize" forceRender> + <Panel header={t('size')} key="freeSize" forceRender> <Group> - <NumberSet label={'宽度(像素)'} name={'boardWidth'} /> - <NumberSet label={'高度(像素)'} name={'boardHeight'} /> + <NumberSet + label={`${t('width')} ( ${t('px')} )`} + name={'boardWidth'} + /> + <NumberSet + label={`${t('height')} ( ${t('px')} )`} + name={'boardHeight'} + /> </Group> </Panel> - <Panel header="缩放模式" key="scale" forceRender> + <Panel header={t('scaleMode')} key="scale" forceRender> <Group> <ScaleModeSet scaleMode={config.scaleMode} /> </Group> </Panel> </> )} - <Panel header="背景设计" key="background" forceRender> + <Panel header={t('background')} key="background" forceRender> <Group> <BackgroundSet background={config.background} /> </Group> </Panel> - <Panel header="查询配置" key="initialQuery" forceRender> + <Panel header={t('queryMode')} key="initialQuery" forceRender> <Group> - <InitialQuerySet name="initialQuery"></InitialQuerySet> + <InitialQuerySet + name="initialQuery" + label={t('openInitQuery')} + ></InitialQuerySet> </Group> </Panel> </Collapse> diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/AutoUpdateSet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/AutoUpdateSet.tsx index 98e5a3c78..273ed4f44 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/AutoUpdateSet.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/AutoUpdateSet.tsx @@ -16,16 +16,18 @@ * limitations under the License. */ import { Checkbox, Form } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { FC } from 'react'; import NumberSet from './BasicSet/NumberSet'; export const AutoUpdateSet: FC = () => { + const t = useI18NPrefix(`viz.board.setting`); return ( <> <Form.Item valuePropName="checked" name="autoUpdate"> - <Checkbox>定时同步数据</Checkbox> + <Checkbox>{t('openAutoUpdate')}</Checkbox> </Form.Item> <Form.Item preserve name="frequency"> - <NumberSet label={'定时同步频率(秒)'} name={'frequency'} /> + <NumberSet label={t('frequency')} name={'frequency'} /> </Form.Item> </> ); diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BackgroundSet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BackgroundSet.tsx index cb11bc8d3..3f8cac562 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BackgroundSet.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BackgroundSet.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ import { Form } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { BackgroundConfig } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import React, { FC, memo } from 'react'; import ColorSet from './BasicSet/ColorSet'; @@ -23,14 +24,17 @@ import { ImageUpload } from './BasicSet/ImageUpload'; export const BackgroundSet: FC<{ background: BackgroundConfig; }> = memo(({ background }) => { + const t = useI18NPrefix(`viz.board.setting`); return ( <> - <Form.Item label="背景颜色"> + <Form.Item label={t('color')}> <ColorSet filedName={'backgroundColor'} filedValue={background.color} /> </Form.Item> <ImageUpload filedName={'backgroundImage'} value={background.image as string} + label={t('image')} + placeholder={t('uploadTip')} /> </> ); diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ImageUpload.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ImageUpload.tsx index f2a19a9b2..0b66ada65 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ImageUpload.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ImageUpload.tsx @@ -26,17 +26,20 @@ import { uploadBoardImage } from '../../../../slice/thunk'; export interface ImageUploadProps { filedName: string; - value: string; + label: string; + placeholder: string; } export const ImageUpload: React.FC<ImageUploadProps> = ({ filedName, value, + label, + placeholder, }) => { return ( <Wrapper> - <Form.Item name={filedName} label="背景图片" preserve> - <UploadDragger value={value} /> + <Form.Item name={filedName} label={label} preserve> + <UploadDragger value={value} placeholder={placeholder} /> </Form.Item> </Wrapper> ); @@ -44,7 +47,8 @@ export const ImageUpload: React.FC<ImageUploadProps> = ({ export const UploadDragger: React.FC<{ value: string; onChange?: any; -}> = ({ value, onChange }) => { + placeholder: string; +}> = ({ value, onChange, placeholder }) => { const dispatch = useDispatch(); const { boardId } = useContext(BoardContext); @@ -87,7 +91,7 @@ export const UploadDragger: React.FC<{ <DeleteOutlined className="del-button" onClick={delImageUrl} /> </div> ) : ( - <Placeholder>点击上传</Placeholder> + <Placeholder>{placeholder}</Placeholder> )} </StyleUpload> ); diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BorderSet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BorderSet.tsx index 40be61a61..a23f51325 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BorderSet.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BorderSet.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ import { Form, InputNumber, Select } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { BORDER_STYLE_OPTIONS } from 'app/pages/DashBoardPage/constants'; import { BorderConfig } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import React, { FC, memo } from 'react'; @@ -23,26 +24,28 @@ import ColorSet from './BasicSet/ColorSet'; export const BorderSet: FC<{ border: BorderConfig; }> = memo(({ border }) => { + const t = useI18NPrefix(`viz.board.setting`); + const tLine = useI18NPrefix(`viz.lineOptions`); return ( <> {/* <ItemLabel> 边框颜色: </ItemLabel> */} - <Form.Item label="边框颜色" name={['border', 'color']}> + <Form.Item label={t('color')} name={['border', 'color']}> <ColorSet filedName={['border', 'color']} filedValue={border.color} /> </Form.Item> - <Form.Item label="边框粗细" name={['border', 'width']}> + <Form.Item label={t('width')} name={['border', 'width']}> <InputNumber /> </Form.Item> - <Form.Item label="边框样式" name={['border', 'style']}> + <Form.Item label={t('style')} name={['border', 'style']}> <Select> {BORDER_STYLE_OPTIONS.map(item => ( <Select.Option key={item.value} value={item.value}> - {item.name} + {tLine(item.value)} </Select.Option> ))} </Select> </Form.Item> - <Form.Item label="边框圆角" name={['border', 'radius']}> + <Form.Item label={t('radius')} name={['border', 'radius']}> <InputNumber /> </Form.Item> </> diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/InitialQuerySet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/InitialQuerySet.tsx index 8999b796c..5e0bf33b0 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/InitialQuerySet.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/InitialQuerySet.tsx @@ -15,20 +15,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import { Form, Checkbox } from 'antd'; - import { NamePath } from 'rc-field-form/lib/interface'; - import React, { FC, memo } from 'react'; - export const InitialQuerySet: FC<{ - name: NamePath; - }> = memo(({ name}) => { - return ( - <> - <Form.Item valuePropName="checked" name={name}> - <Checkbox>初始化自动查询</Checkbox> - </Form.Item> - </> - ); - }); - - export default InitialQuerySet; - \ No newline at end of file +import { Checkbox, Form } from 'antd'; +import { NamePath } from 'rc-field-form/lib/interface'; +import React, { FC, memo } from 'react'; +export const InitialQuerySet: FC<{ + name: NamePath; + label: string; +}> = memo(({ name, label }) => { + return ( + <> + <Form.Item valuePropName="checked" name={name}> + <Checkbox>{label}</Checkbox> + </Form.Item> + </> + ); +}); + +export default InitialQuerySet; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/NameSet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/NameSet.tsx index e6aa57649..56c0052d0 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/NameSet.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/NameSet.tsx @@ -17,6 +17,7 @@ */ import { Checkbox, Form, Input } from 'antd'; import BasicFont from 'app/components/FormGenerator/Basic/BasicFont'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { WIDGET_TITLE_ALIGN_OPTIONS } from 'app/pages/DashBoardPage/constants'; import { WidgetNameConfig } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import { fontDefault } from 'app/pages/DashBoardPage/utils/widget'; @@ -34,6 +35,7 @@ const FONT_DATA = { export const NameSet: FC<{ config: WidgetNameConfig; }> = memo(({ config }) => { + const t = useI18NPrefix(`viz.board.setting`); const fontData = useMemo(() => { const data = { ...FONT_DATA, @@ -49,13 +51,13 @@ export const NameSet: FC<{ return ( <> - <Form.Item label="名称" preserve name="name"> + <Form.Item label={t('title')} preserve name="name"> <Input placeholder="fill a name" /> </Form.Item> <Form.Item valuePropName="checked" name={['nameConfig', 'show']}> - <Checkbox>显示标题</Checkbox> + <Checkbox>{t('showTitle')} </Checkbox> </Form.Item> - <Form.Item label="对齐方式"> + <Form.Item label={t('align')}> <SelectSet name={['nameConfig', 'textAlign']} options={WIDGET_TITLE_ALIGN_OPTIONS} diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/PaddingSet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/PaddingSet.tsx index 5f53c7f4c..16a88a708 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/PaddingSet.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/PaddingSet.tsx @@ -16,20 +16,22 @@ * limitations under the License. */ import { Form, InputNumber } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { FC, memo } from 'react'; export const PaddingSet: FC<{}> = memo(() => { + const t = useI18NPrefix(`viz.board.setting`); return ( <> - <Form.Item label="上内距" name={['padding', 'top']}> + <Form.Item label={t('paddingTop')} name={['padding', 'top']}> <InputNumber /> </Form.Item> - <Form.Item label="右内距" name={['padding', 'right']}> + <Form.Item label={t('paddingRight')} name={['padding', 'right']}> <InputNumber /> </Form.Item> - <Form.Item label="下内距" name={['padding', 'bottom']}> + <Form.Item label={t('paddingBottom')} name={['padding', 'bottom']}> <InputNumber /> </Form.Item> - <Form.Item label="左内距" name={['padding', 'left']}> + <Form.Item label={t('paddingLeft')} name={['padding', 'left']}> <InputNumber /> </Form.Item> </> diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/ScaleModeSet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/ScaleModeSet.tsx index 58d1b7ecd..55911da55 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/ScaleModeSet.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/ScaleModeSet.tsx @@ -16,21 +16,23 @@ * limitations under the License. */ import { Form, Select } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { ScaleModeType, SCALE_MODE__OPTIONS, } from 'app/pages/DashBoardPage/constants'; import React, { FC, memo } from 'react'; -import styled from 'styled-components/macro'; export const ScaleModeSet: FC<{ scaleMode: ScaleModeType; }> = memo(({ scaleMode }) => { + const t = useI18NPrefix(`viz.board.setting`); + const tScale = useI18NPrefix(`viz.scaleMode`); return ( - <Form.Item label="缩放模式" name="scaleMode"> + <Form.Item label={t('scaleMode')} name="scaleMode"> <Select style={{ width: '100%' }}> {SCALE_MODE__OPTIONS.map(item => ( <Select.Option key={item.value} value={item.value}> - {item.name} + {tScale(item.value)} </Select.Option> ))} </Select> @@ -39,4 +41,3 @@ export const ScaleModeSet: FC<{ }); export default ScaleModeSet; -const StyledWrap = styled.div``; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/WidgetSetting.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/WidgetSetting.tsx index dcb26dafa..b9bedf5e4 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/WidgetSetting.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/WidgetSetting.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ import { Collapse, Form } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { BoardContext } from 'app/pages/DashBoardPage/contexts/BoardContext'; import { WidgetContext } from 'app/pages/DashBoardPage/contexts/WidgetContext'; import { Widget } from 'app/pages/DashBoardPage/pages/Board/slice/types'; @@ -43,6 +44,7 @@ import { WidgetNameList } from './WidgetList/WidgetNameList'; const { Panel } = Collapse; export const WidgetSetting: FC = memo(() => { + const t = useI18NPrefix(`viz.board.setting`); const dispatch = useDispatch(); const { boardType } = useContext(BoardContext); const widget = useContext(WidgetContext); @@ -107,7 +109,7 @@ export const WidgetSetting: FC = memo(() => { ); return ( - <SettingPanel title="组件设计"> + <SettingPanel title={`${t('widget')} ${t('setting')}`}> <Form form={form} layout="vertical" @@ -119,48 +121,60 @@ export const WidgetSetting: FC = memo(() => { className="datart-config-panel" ghost > - <Panel header="组件标题" key="name" forceRender> + <Panel header={t('title')} key="name" forceRender> <Group> <NameSet config={config.nameConfig} /> </Group> </Panel> {boardType === 'free' && ( <> - <Panel header="组件位置" key="position" forceRender> + <Panel header={t('position')} key="position" forceRender> <Group> - <NumberSet label={'x轴位置(像素)'} name={['rect', 'x']} /> - <NumberSet label={'y轴位置(像素)'} name={['rect', 'y']} /> + <NumberSet + label={t('xAxis') + ` (${t('px')})`} + name={['rect', 'x']} + /> + <NumberSet + label={t('yAxis') + ` (${t('px')})`} + name={['rect', 'y']} + /> </Group> </Panel> - <Panel header="组件尺寸" key="size" forceRender> + <Panel header={t('size')} key="size" forceRender> <Group> - <NumberSet label={'宽度(像素)'} name={['rect', 'width']} /> - <NumberSet label={'高度(像素)'} name={['rect', 'height']} /> + <NumberSet + label={t('width') + ` (${t('px')})`} + name={['rect', 'width']} + /> + <NumberSet + label={t('height') + ` (${t('px')})`} + name={['rect', 'height']} + /> </Group> </Panel> </> )} - <Panel header="背景" key="background" forceRender> + <Panel header={t('background')} key="background" forceRender> <Group> <BackgroundSet background={config.background} /> </Group> </Panel> - <Panel header="内边距" key="padding" forceRender> + <Panel header={t('padding')} key="padding" forceRender> <Group> <PaddingSet /> </Group> </Panel> - <Panel header="边框" key="border" forceRender> + <Panel header={t('border')} key="border" forceRender> <Group> <BorderSet border={config.border} /> </Group> </Panel> - <Panel header="定时同步数据" key="autUpdate" forceRender> + <Panel header={t('autoUpdate')} key="autoUpdate" forceRender> <Group> <AutoUpdateSet /> </Group> </Panel> - <Panel header="所有组件" key="widgetList"> + <Panel header={t('widgetList')} key="widgetList"> <Group> <WidgetNameList /> </Group> 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 48a7fe453..f967e5021 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreviewBoard.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreviewBoard.tsx @@ -24,7 +24,6 @@ import Chart from 'app/pages/ChartWorkbenchPage/models/Chart'; import { ChartDataRequestBuilder } from 'app/pages/ChartWorkbenchPage/models/ChartHttpRequest'; import ChartManager from 'app/pages/ChartWorkbenchPage/models/ChartManager'; import { useMainSlice } from 'app/pages/MainPage/slice'; -// import { makeDownloadDataTask } from 'app/pages/MainPage/slice/thunks'; import { generateShareLinkAsync, makeDownloadDataTask } from 'app/utils/fetch'; import { FC, memo, useCallback, useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 260fd9546..6c36abf6e 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -539,6 +539,46 @@ "date": "Date", "numeric": "Numeric", "button": "Button" + }, + "setting": { + "setting": "Setting", + "board": "Board", + "widget": "Widget", + "widgetList": "Widget List", + "title": "Title", + "align": "Align", + "showTitle": "Show Title", + "position": "Position", + "xAxis": "xAxis", + "yAxis": "yAxis", + "size": "Size", + "px": "px", + "width": "Width", + "height": "Height", + "background": "Background", + "color": "Color", + "image": "Image", + "uploadTip": "click to Upload", + "padding": "padding", + "paddingTop": "padding Top", + "paddingRight": "padding Right", + "paddingBottom": "padding Bottom", + "paddingLeft": "padding Left", + "border": "Border", + "style": "Style", + "radius": "Radius", + "autoUpdate": "Auto Refresh", + "openAutoUpdate": "open Refresh", + "frequency": "frequency (s)", + "baseProperty": "Base Property", + "marginTB": "Margin-TB", + "marginLR": "Margin-LR", + "paddingTB": "Margin-TB", + "paddingLR": "Margin-LR", + "rowHeight": "rowHeight", + "scaleMode": "scale Mode", + "queryMode": "query Mode", + "openInitQuery": "open Init Query" } }, "widget": { @@ -593,6 +633,24 @@ "confirmDeletion": "确认删除", "delete": "删除" } + }, + "lineOptions": { + "none": "none", + "solid": "solid", + "dashed": "dashed", + "dotted": "dotted", + "double": "double", + "hidden": "hidden", + "ridge": "ridge", + "groove": "groove", + "inset": "inset", + "outset": "outset" + }, + "scaleMode": { + "scaleWidth": "scaleWidth", + "scaleHeight": "scaleHeight", + "scaleFull": "scaleFull", + "noScale": "noScale" } }, "share": { diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index e2fa4d2b1..c579e7372 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -539,6 +539,45 @@ "date": "日期", "numeric": "数值", "button": "按钮" + }, + "setting": { + "setting": "设置", + "board": "面板", + "widget": "组件", + "widgetList": "组件列表", + "title": "标题", + "showTitle": "显示标题", + "position": "位置", + "xAxis": "x轴", + "yAxis": "y轴", + "size": "尺寸", + "px": "像素", + "width": "宽", + "height": "高", + "background": "背景", + "color": "颜色", + "image": "图片", + "uploadTip": "点击上传", + "padding": "内边距", + "paddingTop": "上边距", + "paddingRight": "右边距", + "paddingBottom": "下边距", + "paddingLeft": "左边距", + "border": "边框", + "style": "样式", + "radius": "圆角", + "autoUpdate": "自动刷新数据", + "openAutoUpdate": "开启", + "frequency": "定时同步频率(秒)", + "baseProperty": "基本属性", + "marginTB": "上下外边距", + "marginLR": "左右外边距", + "paddingTB": "上下内边距", + "paddingLR": "左右内边距", + "rowHeight": "行高", + "scaleMode": "缩放模式", + "queryMode": "查询模式", + "openInitQuery": "开启初始化查询" } }, "widget": { @@ -593,6 +632,24 @@ "confirmDeletion": "确认删除", "delete": "删除" } + }, + "lineOptions": { + "none": "无", + "solid": "实线", + "dashed": "虚线", + "dotted": "点线", + "double": "双线", + "hidden": "隐藏", + "ridge": "垄状", + "groove": "凹槽", + "inset": "内凹", + "outset": "外凸" + }, + "scaleMode": { + "scaleWidth": "等比宽度缩放", + "scaleHeight": "等比高度缩放", + "scaleFull": "全屏铺满", + "noScale": "实际尺寸" } }, "share": { From cd6c5a0a9365c530818213334a5ccbd8bc9a6c9f Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Wed, 29 Dec 2021 18:11:57 +0800 Subject: [PATCH 271/348] feat: return view details after create a view --- .../java/datart/server/service/impl/ViewServiceImpl.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) 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 42125ab1d..23c075a15 100644 --- a/server/src/main/java/datart/server/service/impl/ViewServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/ViewServiceImpl.java @@ -97,12 +97,7 @@ public View create(BaseCreateParam createParam) { rscMapper.batchInsert(columnPermission); } - ViewDetailDTO viewDetailDTO = new ViewDetailDTO(view); - viewDetailDTO.setRelVariableSubjects(Collections.emptyList()); - viewDetailDTO.setRelSubjectColumns(Collections.emptyList()); - viewDetailDTO.setVariables(Collections.emptyList()); - - return viewDetailDTO; + return getViewDetail(view.getId()); } @Override From 24703e25af94698fe7e26c227f9cdcbeae46ba3d Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Wed, 29 Dec 2021 18:16:58 +0800 Subject: [PATCH 272/348] fix: schedule bug fix --- server/src/main/java/datart/server/service/ScheduleJob.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/datart/server/service/ScheduleJob.java b/server/src/main/java/datart/server/service/ScheduleJob.java index 6ab08bed7..466aa0885 100644 --- a/server/src/main/java/datart/server/service/ScheduleJob.java +++ b/server/src/main/java/datart/server/service/ScheduleJob.java @@ -136,7 +136,7 @@ public void doGetData() throws Exception { DashboardDetail dashboard = vizService.getDashboard(folder.getRelId()); downloadCreateParam = parseExecuteParam("board", OBJECT_MAPPER.writeValueAsString(dashboard)); } - if (config.getAttachments().contains(AttachmentType.EXCEL) || true) { + if (config.getAttachments().contains(AttachmentType.EXCEL)) { downloadExcel(downloadCreateParam); } From 1afd9e65a01347887953cee8a88ce5c8ba8f8f2d Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Wed, 29 Dec 2021 18:19:32 +0800 Subject: [PATCH 273/348] feat(Excel): send Excel to Email --- frontend/src/app/pages/MainPage/pages/SchedulePage/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/pages/MainPage/pages/SchedulePage/constants.ts b/frontend/src/app/pages/MainPage/pages/SchedulePage/constants.ts index a62e2cddb..c99df17f7 100644 --- a/frontend/src/app/pages/MainPage/pages/SchedulePage/constants.ts +++ b/frontend/src/app/pages/MainPage/pages/SchedulePage/constants.ts @@ -13,7 +13,7 @@ export const JOB_TYPES_OPTIONS = [ { label: '微信', value: JobTypes.WeChart }, ]; export const FILE_TYPE_OPTIONS = [ - // { label: 'Excel', value: FileTypes.Excel }, + { label: 'Excel', value: FileTypes.Excel }, { label: '图片', value: FileTypes.Image }, ]; export const WECHART_FILE_TYPE_OPTIONS = [ From c4493e46cdaee96c3b88bd12bfd015f7b653aa70 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Wed, 29 Dec 2021 18:47:47 +0800 Subject: [PATCH 274/348] fix: Modify the initialization logic of the aggregation switch --- .../src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts b/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts index e9da680fb..8677ebb7e 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts @@ -501,8 +501,9 @@ const workbenchSlice = createSlice({ ? JSON.parse(payload.config) : CloneValueDeep(payload.config); backendChartConfig = backendChartConfig || {}; - backendChartConfig.aggregation = - backendChartConfig?.aggregation === undefined ? true : false; + if (backendChartConfig?.aggregation === undefined) { + backendChartConfig.aggregation = true; + } state.backendChart = { ...payload, config: backendChartConfig, From df8f7307a3ebb6e4eacbdba6b3ce188227866c33 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Wed, 29 Dec 2021 19:34:09 +0800 Subject: [PATCH 275/348] chore: source page i18n support --- frontend/src/app/components/ModalForm.tsx | 6 +- .../ForgetPasswordForm/CheckCodeForm.tsx | 8 +- .../ForgetPasswordForm/ResetPasswordForm.tsx | 17 +-- .../src/app/pages/LoginPage/LoginForm.tsx | 6 +- .../pages/MainPage/Navbar/ModifyPassword.tsx | 27 ++--- .../src/app/pages/MainPage/Navbar/Profile.tsx | 8 +- .../app/pages/MainPage/OrganizationForm.tsx | 7 +- frontend/src/app/pages/MainPage/index.tsx | 2 +- .../MemberPage/pages/RoleDetailPage/index.tsx | 10 +- .../pages/SourcePage/Sidebar/Recycle.tsx | 18 ++++ .../pages/SourcePage/Sidebar/SourceList.tsx | 18 ++++ .../pages/SourcePage/Sidebar/index.tsx | 31 +++++- .../ConfigComponent/ArrayConfig.tsx | 37 +++++-- .../ConfigComponent/FileUpload.tsx | 24 ++++- .../ConfigComponent/Properties.tsx | 37 +++++-- .../ConfigComponent/SchemaComponent.tsx | 18 ++++ .../ConfigComponent/index.tsx | 30 +++++- .../SourcePage/SourceDetailPage/index.tsx | 102 ++++++++++++------ .../SourcePage/SourceDetailPage/types.ts | 18 ++++ .../pages/MainPage/pages/SourcePage/index.tsx | 18 ++++ .../MainPage/pages/SourcePage/slice/index.ts | 18 ++++ .../pages/SourcePage/slice/selectors.ts | 18 ++++ .../MainPage/pages/SourcePage/slice/thunks.ts | 18 ++++ .../MainPage/pages/SourcePage/slice/types.ts | 18 ++++ .../pages/MainPage/pages/SourcePage/utils.ts | 18 ++++ .../app/pages/RegisterPage/RegisterForm.tsx | 10 +- frontend/src/globalConstants.ts | 5 - frontend/src/locales/en/translation.json | 57 ++++++++-- frontend/src/locales/i18n.ts | 2 +- frontend/src/locales/zh/translation.json | 63 +++++++++-- 30 files changed, 545 insertions(+), 124 deletions(-) diff --git a/frontend/src/app/components/ModalForm.tsx b/frontend/src/app/components/ModalForm.tsx index 6f8b193f7..49bea9a8a 100644 --- a/frontend/src/app/components/ModalForm.tsx +++ b/frontend/src/app/components/ModalForm.tsx @@ -1,5 +1,6 @@ import { Form, FormProps, Modal, ModalProps } from 'antd'; -import { CommonFormTypes, COMMON_FORM_TITLE_PREFIX } from 'globalConstants'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; +import { CommonFormTypes } from 'globalConstants'; import { forwardRef, ReactNode, useCallback, useImperativeHandle } from 'react'; export interface ModalFormProps extends ModalProps { @@ -15,6 +16,7 @@ export const ModalForm = forwardRef( ref, ) => { const [form] = Form.useForm(); + const tg = useI18NPrefix('global'); useImperativeHandle(ref, () => form); const onOk = useCallback(() => { @@ -29,7 +31,7 @@ export const ModalForm = forwardRef( return ( <Modal {...rest} - title={`${type ? COMMON_FORM_TITLE_PREFIX[type] : ''}${rest.title}`} + title={`${type ? tg(`modal.title.${type}`) : ''}${rest.title}`} onOk={onOk} afterClose={onAfterClose} > diff --git a/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/CheckCodeForm.tsx b/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/CheckCodeForm.tsx index 0ed7d0fca..9873adc40 100644 --- a/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/CheckCodeForm.tsx +++ b/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/CheckCodeForm.tsx @@ -35,7 +35,7 @@ export const CheckCodeForm: FC<CheckCodeFormProps> = ({ onNextStep }) => { const [ticket, setTicket] = useState(''); const [submitLoading, setSubmitLoading] = useState(false); const t = useI18NPrefix('forgotPassword'); - const tgv = useI18NPrefix('global.validation'); + const tg = useI18NPrefix('global'); const initialValues = useMemo(() => { return { type: FindWays.Email }; @@ -84,7 +84,7 @@ export const CheckCodeForm: FC<CheckCodeFormProps> = ({ onNextStep }) => { rules={[ { required: true, - message: `${t('email')}${tgv('required')}`, + message: `${t('email')}${tg('validation.required')}`, }, { type: 'email', @@ -100,14 +100,14 @@ export const CheckCodeForm: FC<CheckCodeFormProps> = ({ onNextStep }) => { rules={[ { required: true, - message: `${t('username')}${tgv('required')}`, + message: `${t('username')}${tg('validation.required')}`, }, ]} > <Input size="large" placeholder={t('enterUsername')} /> </Form.Item> ); - }, [isEmail, t, tgv]); + }, [isEmail, t, tg]); const goNext = useCallback(() => { onNextStep(token as string); diff --git a/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/ResetPasswordForm.tsx b/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/ResetPasswordForm.tsx index e3509b705..4f99578d2 100644 --- a/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/ResetPasswordForm.tsx +++ b/frontend/src/app/pages/ForgetPasswordPage/ForgetPasswordForm/ResetPasswordForm.tsx @@ -34,7 +34,7 @@ export const ResetPasswordForm: FC<ResetPasswordFormProps> = ({ token }) => { const history = useHistory(); const [submiting, setSubmiting] = useState(false); const t = useI18NPrefix('forgotPassword'); - const tgv = useI18NPrefix('global.validation'); + const tg = useI18NPrefix('global'); const onFinish = useCallback( values => { @@ -65,9 +65,9 @@ export const ResetPasswordForm: FC<ResetPasswordFormProps> = ({ token }) => { rules={[ { required: true, - message: `${t('password')}${tgv('required')}`, + message: `${t('password')}${tg('validation.required')}`, }, - { validator: getPasswordValidator(tgv('invalidPassword')) }, + { validator: getPasswordValidator(tg('validation.invalidPassword')) }, ]} > <Input.Password placeholder={t('enterNewPassword')} /> @@ -77,12 +77,12 @@ export const ResetPasswordForm: FC<ResetPasswordFormProps> = ({ token }) => { rules={[ { required: true, - message: `${t('password')}${tgv('required')}`, + message: `${t('password')}${tg('validation.required')}`, }, getConfirmPasswordValidator( 'newPassword', - tgv('invalidPassword'), - tgv('passwordNotMatch'), + tg('validation.invalidPassword'), + tg('validation.passwordNotMatch'), ), ]} > @@ -91,7 +91,10 @@ export const ResetPasswordForm: FC<ResetPasswordFormProps> = ({ token }) => { <Form.Item name="verifyCode" rules={[ - { required: true, message: `${t('verifyCode')}${tgv('required')}` }, + { + required: true, + message: `${t('verifyCode')}${tg('validation.required')}`, + }, ]} > <Input placeholder={t('verifyCode')} /> diff --git a/frontend/src/app/pages/LoginPage/LoginForm.tsx b/frontend/src/app/pages/LoginPage/LoginForm.tsx index d84415e5f..b0a389cc2 100644 --- a/frontend/src/app/pages/LoginPage/LoginForm.tsx +++ b/frontend/src/app/pages/LoginPage/LoginForm.tsx @@ -41,7 +41,7 @@ export function LoginForm() { const [form] = Form.useForm(); const logged = !!getToken(); const t = usePrefixI18N('login'); - const tgv = usePrefixI18N('global.validation'); + const tg = usePrefixI18N('global'); const toApp = useCallback(() => { history.replace('/'); @@ -85,7 +85,7 @@ export function LoginForm() { rules={[ { required: true, - message: `${t('username')}${tgv('required')}`, + message: `${t('username')}${tg('validation.required')}`, }, ]} > @@ -96,7 +96,7 @@ export function LoginForm() { rules={[ { required: true, - message: `${t('password')}${tgv('required')}`, + message: `${t('password')}${tg('validation.required')}`, }, ]} > diff --git a/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx b/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx index 576280b71..378d24a1b 100644 --- a/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/ModifyPassword.tsx @@ -44,8 +44,7 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ const loading = useSelector(selectModifyPasswordLoading); const [form] = Form.useForm(); const t = useI18NPrefix('main.nav.account.changePassword'); - const tgo = useI18NPrefix('global.operation'); - const tgv = useI18NPrefix('global.validation'); + const tg = useI18NPrefix('global'); const reset = useCallback(() => { form.resetFields(); @@ -63,13 +62,13 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ modifyAccountPassword({ params, resolve: () => { - message.success(tgo('updateSuccess')); + message.success(tg('operation.updateSuccess')); onCancel(); }, }), ); }, - [dispatch, onCancel, tgo], + [dispatch, onCancel, tg], ); return ( @@ -93,9 +92,11 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ rules={[ { required: true, - message: `${t('oldPassword')}${tgv('required')}`, + message: `${t('oldPassword')}${tg('validation.required')}`, + }, + { + validator: getPasswordValidator(tg('validation.invalidPassword')), }, - { validator: getPasswordValidator(tgv('invalidPassword')) }, ]} > <Input.Password type="password" /> @@ -106,9 +107,11 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ rules={[ { required: true, - message: `${t('newPassword')}${tgv('required')}`, + message: `${t('newPassword')}${tg('validation.required')}`, + }, + { + validator: getPasswordValidator(tg('validation.invalidPassword')), }, - { validator: getPasswordValidator(tgv('invalidPassword')) }, ]} > <Input.Password type="password" /> @@ -120,12 +123,12 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ rules={[ { required: true, - message: `${t('confirmPassword')}${tgv('required')}`, + message: `${t('confirmPassword')}${tg('validation.required')}`, }, getConfirmPasswordValidator( 'newPassword', - tgv('invalidPassword'), - tgv('passwordNotMatch'), + tg('validation.invalidPassword'), + tg('validation.passwordNotMatch'), ), ]} > @@ -133,7 +136,7 @@ export const ModifyPassword: FC<ModifyPasswordProps> = ({ </FormItem> <Form.Item wrapperCol={{ offset: 7, span: 12 }}> <Button type="primary" htmlType="submit" loading={loading} block> - {t('save')} + {tg('button.save')} </Button> </Form.Item> </Form> diff --git a/frontend/src/app/pages/MainPage/Navbar/Profile.tsx b/frontend/src/app/pages/MainPage/Navbar/Profile.tsx index cbfb29fe6..d2199598d 100644 --- a/frontend/src/app/pages/MainPage/Navbar/Profile.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/Profile.tsx @@ -41,7 +41,7 @@ export function Profile({ visible, onCancel }: ModalProps) { const [saveDisabled, setSaveDisabled] = useState(true); const [form] = Form.useForm(); const t = useI18NPrefix('main.nav.account.profile'); - const tgo = useI18NPrefix('global.operation'); + const tg = useI18NPrefix('global'); const reset = useCallback(() => { form.resetFields(); @@ -90,13 +90,13 @@ export function Profile({ visible, onCancel }: ModalProps) { email: loggedInUser!.email, }, resolve: () => { - message.success(tgo('updateSuccess')); + message.success(tg('operation.updateSuccess')); onCancel && onCancel(null as any); }, }), ); }, - [dispatch, loggedInUser, onCancel, tgo], + [dispatch, loggedInUser, onCancel, tg], ); return ( @@ -152,7 +152,7 @@ export function Profile({ visible, onCancel }: ModalProps) { disabled={saveDisabled} block > - {t('save')} + {tg('button.save')} </Button> </Form.Item> </Form> diff --git a/frontend/src/app/pages/MainPage/OrganizationForm.tsx b/frontend/src/app/pages/MainPage/OrganizationForm.tsx index 2adf4c22f..5bfdd9e26 100644 --- a/frontend/src/app/pages/MainPage/OrganizationForm.tsx +++ b/frontend/src/app/pages/MainPage/OrganizationForm.tsx @@ -38,7 +38,7 @@ export function OrganizationForm({ visible, onCancel }: OrganizationFormProps) { const loading = useSelector(selectSaveOrganizationLoading); const [form] = Form.useForm(); const t = useI18NPrefix('main.nav.organization'); - const tgv = useI18NPrefix('global.validation'); + const tg = useI18NPrefix('global'); const formSubmit = useCallback( values => { @@ -84,7 +84,10 @@ export function OrganizationForm({ visible, onCancel }: OrganizationFormProps) { name="name" label={t('name')} rules={[ - { required: true, message: `${t('name')}${tgv('required')}` }, + { + required: true, + message: `${t('name')}${tg('validation.required')}`, + }, { validator: debounce((_, value) => { return request({ diff --git a/frontend/src/app/pages/MainPage/index.tsx b/frontend/src/app/pages/MainPage/index.tsx index 22ba21736..8f5e09379 100644 --- a/frontend/src/app/pages/MainPage/index.tsx +++ b/frontend/src/app/pages/MainPage/index.tsx @@ -17,7 +17,7 @@ */ import { useAppSlice } from 'app/slice'; -import React, { useEffect } from 'react'; +import React, { useEffect, useLayoutEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Redirect, diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx index 3e16fcdbc..ece607c4c 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx @@ -2,11 +2,7 @@ import { Button, Card, Form, Input, message, Popconfirm } from 'antd'; import { DetailPageHeader } from 'app/components/DetailPageHeader'; import { User } from 'app/slice/types'; import debounce from 'debounce-promise'; -import { - CommonFormTypes, - COMMON_FORM_TITLE_PREFIX, - DEFAULT_DEBOUNCE_WAIT, -} from 'globalConstants'; +import { CommonFormTypes, DEFAULT_DEBOUNCE_WAIT } from 'globalConstants'; import React, { useCallback, useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory, useRouteMatch } from 'react-router-dom'; @@ -27,6 +23,7 @@ import { editRole, getRoleMembers, } from '../../slice/thunks'; +import useI18NPrefix from 'app/hooks/useI18NPrefix' import { Role } from '../../slice/types'; import { MemberForm } from './MemberForm'; import { MemberTable } from './MemberTable'; @@ -45,6 +42,7 @@ export function RoleDetailPage() { const editingRole = useSelector(selectEditingRole); const getRoleMembersLoading = useSelector(selectGetRoleMembersLoading); const saveRoleLoading = useSelector(selectSaveRoleLoading); + const tg = useI18NPrefix('global'); const { params } = useRouteMatch<{ roleId: string }>(); const { roleId } = params; const [form] = Form.useForm<Pick<Role, 'name' | 'description'>>(); @@ -135,7 +133,7 @@ export function RoleDetailPage() { return ( <Wrapper> <DetailPageHeader - title={`${COMMON_FORM_TITLE_PREFIX[formType]}角色`} + title={`${tg(`modal.title.${formType}`)}角色`} actions={ <> <Button 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 bb66d2646..355affc69 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/Recycle.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/Recycle.tsx @@ -1,3 +1,21 @@ +/** + * 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 { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import classnames from 'classnames'; import { memo, useCallback, useEffect } from 'react'; 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 a7436acc7..60ee0596c 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/SourceList.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/SourceList.tsx @@ -1,3 +1,21 @@ +/** + * 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 { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import classnames from 'classnames'; import React, { memo, useCallback, useEffect } from 'react'; 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 0adba6bed..02dc4f4be 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/index.tsx @@ -1,6 +1,25 @@ +/** + * 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 { DeleteOutlined } from '@ant-design/icons'; import { ListNav, ListPane, ListTitle } from 'app/components'; import { useDebouncedSearch } from 'app/hooks/useDebouncedSearch'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { useAccess } from 'app/pages/MainPage/Access'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import { memo, useCallback, useMemo } from 'react'; @@ -33,6 +52,8 @@ export const Sidebar = memo(() => { '/organizations/:orgId/sources/:sourceId', ); const sourceId = matchSourceDetail?.params.sourceId; + const t = useI18NPrefix('source.sidebar'); + const tg = useI18NPrefix('global'); const allowCreate = useAccess(allowCreateSource()); const { filteredData: sourceList, debouncedSearch: listSearch } = @@ -60,17 +81,17 @@ export const Sidebar = memo(() => { () => [ { key: 'list', - title: '数据源列表', + title: t('title'), search: true, onSearch: listSearch, ...allowCreate({ - add: { items: [{ key: 'add', text: '新建数据源' }], callback: toAdd }, + add: { items: [{ key: 'add', text: t('add') }], callback: toAdd }, }), more: { items: [ { key: 'recycle', - text: '回收站', + text: tg('title.recycle'), prefix: <DeleteOutlined className="icon" />, }, ], @@ -79,13 +100,13 @@ export const Sidebar = memo(() => { }, { key: 'recycle', - title: '回收站', + title: tg('title.recycle'), back: true, search: true, onSearch: archivedSearch, }, ], - [toAdd, moreMenuClick, listSearch, archivedSearch, allowCreate], + [toAdd, moreMenuClick, listSearch, archivedSearch, allowCreate, t, tg], ); return ( 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 a450c1a4e..893758dfa 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 @@ -1,3 +1,21 @@ +/** + * 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 { PlusOutlined } from '@ant-design/icons'; import { Button, @@ -7,6 +25,7 @@ import { Table, TableColumnProps, } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { ModalForm } from 'app/components'; import { Model, @@ -54,6 +73,8 @@ export function ArrayConfig({ const [editingRowKey, setEditingRowKey] = useState(''); const [schemaDataSource, setSchemaDataSource] = useState<object[]>([]); const formRef = useRef<FormInstance<SourceFormModel>>(); + const t = useI18NPrefix('source'); + const tg = useI18NPrefix('global'); const showForm = useCallback(() => { setFormVisible(true); @@ -174,39 +195,39 @@ export function ArrayConfig({ () => [ { title: attr.key, dataIndex: attr.key }, { - title: '操作', + title: tg('title.action'), align: 'center', width: 120, render: (_, record) => ( <Space> <ActionButton - key="view" + key="edit" type="link" onClick={editConfig(record[attr.key!])} > - 查看 + {tg('button.edit')} </ActionButton> {allowManage && ( <Popconfirm key="del" - title="确认删除?" + title={tg('operation.deleteConfirm')} onConfirm={delConfig(record[attr.key!])} > - <ActionButton type="link">删除</ActionButton> + <ActionButton type="link">{tg('button.delete')}</ActionButton> </Popconfirm> )} </Space> ), }, ], - [attr, editConfig, delConfig, allowManage], + [attr, editConfig, delConfig, allowManage, tg], ); return ( <Wrapper> {allowManage && !disabled && ( <AddButton type="link" icon={<PlusOutlined />} onClick={showForm}> - 新增配置 + {t('form.addConfig')} </AddButton> )} <Table @@ -218,7 +239,7 @@ export function ArrayConfig({ bordered /> <ModalForm - title={`${attr.name}配置编辑`} + title={t('form.editConfig')} visible={formVisible} width={SPACE_TIMES(240)} formProps={{ diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/FileUpload.tsx b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/FileUpload.tsx index 692da232a..6ec49ba02 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/FileUpload.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/FileUpload.tsx @@ -1,5 +1,24 @@ +/** + * 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 { UploadOutlined } from '@ant-design/icons'; import { Button, Form, FormInstance, Input, Upload } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { BASE_API_URL } from 'globalConstants'; import { useCallback, useState } from 'react'; import { APIResponse } from 'types'; @@ -19,6 +38,7 @@ export function FileUpload({ onTest, }: FileUploadProps) { const [uploadFileLoading, setUploadFileLoading] = useState(false); + const t = useI18NPrefix('source'); const normFile = useCallback(e => { if (Array.isArray(e)) { @@ -50,7 +70,7 @@ export function FileUpload({ return ( <> <Form.Item - label="文件" + label={t('form.file')} valuePropName="fileList" getValueFromEvent={normFile} > @@ -66,7 +86,7 @@ export function FileUpload({ icon={<UploadOutlined />} loading={uploadFileLoading || loading} > - 选择文件 + {t('form.selectFile')} </Button> </Upload> </Form.Item> diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/Properties.tsx b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/Properties.tsx index 71a9ba483..1f35c7308 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/Properties.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/Properties.tsx @@ -1,6 +1,25 @@ +/** + * 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 { ProColumnType } from '@ant-design/pro-table'; import { Button } from 'antd'; import { Configuration } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { useCallback, useMemo } from 'react'; import styled from 'styled-components'; import { LINE_HEIGHT_BODY } from 'styles/StyleConstants'; @@ -28,6 +47,9 @@ export function Properties({ allowManage, onChange, }: PropertiesProps) { + const t = useI18NPrefix('source'); + const tg = useI18NPrefix('global'); + const tableDataSource = useMemo( () => valueProp @@ -57,7 +79,7 @@ export function Properties({ dataIndex: 'key', formItemProps: (_, { rowIndex }) => ({ rules: [ - { required: true, message: 'Key不能为空' }, + { required: true, message: `Key${tg('validation.required')}` }, { validator: (_, val) => { if (!valueProp) { @@ -70,9 +92,8 @@ export function Properties({ ) { return Promise.resolve(); } - return Promise.reject(new Error('Key重复')); + return Promise.reject(new Error(t('form.duplicateKey'))); }, - message: 'Key不能重复', }, ], }), @@ -82,7 +103,7 @@ export function Properties({ dataIndex: 'value', }, { - title: '操作', + title: tg('title.action'), valueType: 'option', width: 160, render: (_, record, __, action) => [ @@ -94,7 +115,7 @@ export function Properties({ action?.startEditable?.(record.id); }} > - 编辑 + {tg('button.edit')} </ActionButton>, <ActionButton key="delete" @@ -112,17 +133,17 @@ export function Properties({ ); }} > - 删除 + {tg('button.delete')} </ActionButton>, ], }, ], - [disabled, allowManage, valueProp, tableDataSource, onChange], + [disabled, allowManage, valueProp, tableDataSource, onChange, t, tg], ); return ( <Configuration columns={columns} - creatorButtonText="新增配置项" + creatorButtonText={t('form.addProperty')} value={tableDataSource} disabled={disabled || !allowManage} onChange={change} diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/SchemaComponent.tsx b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/SchemaComponent.tsx index 5b9619102..9e167ac55 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/SchemaComponent.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/SchemaComponent.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Empty } from 'antd'; import { SchemaTable } from 'app/pages/MainPage/pages/ViewPage/components/SchemaTable'; import { Schema } from 'app/pages/MainPage/pages/ViewPage/slice/types'; diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/index.tsx b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/index.tsx index 47fab41f2..24bb898b9 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/ConfigComponent/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Button, Form, @@ -8,6 +26,7 @@ import { Select, Switch, } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { QueryResult } from 'app/pages/MainPage/pages/ViewPage/slice/types'; import { DataProviderAttribute } from 'app/pages/MainPage/slice/types'; import { Rule } from 'rc-field-form/lib/interface'; @@ -52,6 +71,8 @@ export function ConfigComponent({ const { name, description, required, defaultValue, type, options } = attr; let component: ReactElement | null = null; let extraFormItemProps: Partial<FormItemProps> = {}; + const t = useI18NPrefix('source'); + const tg = useI18NPrefix('global'); switch (name) { case 'url': @@ -64,7 +85,7 @@ export function ConfigComponent({ loading={testLoading} onClick={onTest} > - 测试连接 + {t('form.test')} </Button> } disabled={disabled} @@ -170,7 +191,10 @@ export function ConfigComponent({ let rules: Rule[] = []; if (required) { - rules.push({ required: true, message: `${name}不能为空` }); + rules.push({ + required: true, + message: `${name}${tg('validation.required')}`, + }); } if (subFormRowKey === name) { @@ -179,7 +203,7 @@ export function ConfigComponent({ const valid = subFormRowKeyValidator && subFormRowKeyValidator(value); return valid ? Promise.resolve() - : Promise.reject(new Error('名称重复')); + : Promise.reject(new Error(t('form.duplicateName'))); }, }); } 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 2a3c09163..ad6a0ae22 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/index.tsx @@ -1,14 +1,29 @@ +/** + * 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 { LoadingOutlined } from '@ant-design/icons'; import { Button, Card, Form, Input, message, Popconfirm, Select } from 'antd'; import { Authorized, EmptyFiller } from 'app/components'; import { DetailPageHeader } from 'app/components/DetailPageHeader'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { useAccess } from 'app/pages/MainPage/Access'; import debounce from 'debounce-promise'; -import { - CommonFormTypes, - COMMON_FORM_TITLE_PREFIX, - DEFAULT_DEBOUNCE_WAIT, -} from 'globalConstants'; +import { CommonFormTypes, DEFAULT_DEBOUNCE_WAIT } from 'globalConstants'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory, useRouteMatch } from 'react-router-dom'; @@ -67,6 +82,8 @@ export function SourceDetailPage() { const { params } = useRouteMatch<{ sourceId: string }>(); const { sourceId } = params; const [form] = Form.useForm<SourceFormModel>(); + const t = useI18NPrefix('source'); + const tg = useI18NPrefix('global'); const isArchived = editingSource?.status === 0; const allowCreate = useAccess(allowCreateSource())(true) && sourceId === 'add'; @@ -101,11 +118,11 @@ export function SourceDetailPage() { setProviderType(type); form.setFieldsValue({ name, type, config: JSON.parse(config) }); } catch (error) { - message.error('配置解析错误'); + message.error(tg('operation.parseError')); throw error; } } - }, [form, editingSource]); + }, [form, editingSource, tg]); useEffect(() => { if ( @@ -167,14 +184,14 @@ export function SourceDetailPage() { method: 'POST', data: { name, type, properties: config }, }); - message.success('测试成功'); + message.success(t('testSuccess')); } catch (error) { errorHandle(error); throw error; } finally { setTestLoading(false); } - }, [form, dataProviders]); + }, [form, dataProviders, t]); const subFormTest = useCallback( async (config, callback) => { @@ -223,7 +240,7 @@ export function SourceDetailPage() { addSource({ source: { ...rest, orgId, config: configStr }, resolve: id => { - message.success('新建成功'); + message.success(t('createSuccess')); history.push(`/organizations/${orgId}/sources/${id}`); }, }), @@ -239,7 +256,7 @@ export function SourceDetailPage() { config: configStr, }, resolve: () => { - message.success('修改成功'); + message.success(tg('operation.updateSuccess')); }, }), ); @@ -248,7 +265,7 @@ export function SourceDetailPage() { break; } }, - [dispatch, history, orgId, editingSource, formType], + [dispatch, history, orgId, editingSource, formType, t, tg], ); const del = useCallback( @@ -258,13 +275,17 @@ export function SourceDetailPage() { id: editingSource!.id, archive, resolve: () => { - message.success(`成功${archive ? '移至回收站' : '删除'}`); + message.success( + archive + ? tg('operation.archiveSuccess') + : tg('operation.deleteSuccess'), + ); history.replace(`/organizations/${orgId}/sources`); }, }), ); }, - [dispatch, history, orgId, editingSource], + [dispatch, history, orgId, editingSource, tg], ); const unarchive = useCallback(() => { @@ -272,26 +293,26 @@ export function SourceDetailPage() { unarchiveSource({ id: editingSource!.id, resolve: () => { - message.success('还原成功'); + message.success(tg('operation.restoreSuccess')); history.replace(`/organizations/${orgId}/sources`); }, }), ); - }, [dispatch, history, orgId, editingSource]); + }, [dispatch, history, orgId, editingSource, tg]); const titleLabelPrefix = useMemo( - () => (isArchived ? '已归档' : COMMON_FORM_TITLE_PREFIX[formType]), - [isArchived, formType], + () => (isArchived ? t('archived') : tg(`modal.title.${formType}`)), + [isArchived, formType, t, tg], ); return ( <Authorized authority={allowCreate || allowManage} - denied={<EmptyFiller title="您没有权限访问该页面" />} + denied={<EmptyFiller title={t('noPermission')} />} > <Wrapper> <DetailPageHeader - title={`${titleLabelPrefix}数据源`} + title={`${titleLabelPrefix}${t('source')}`} actions={ !isArchived ? ( <> @@ -300,24 +321,35 @@ export function SourceDetailPage() { loading={saveSourceLoading} onClick={form.submit} > - 保存 + {tg('button.save')} </Button> {formType === CommonFormTypes.Edit && ( - <Popconfirm title="确定移至回收站?" onConfirm={del(true)}> + <Popconfirm + title={tg('operation.archiveConfirm')} + onConfirm={del(true)} + > <Button loading={deleteSourceLoading} danger> - 移至回收站 + {tg('button.archive')} </Button> </Popconfirm> )} </> ) : ( <> - <Popconfirm title="确定还原?" onConfirm={unarchive}> - <Button loading={unarchiveSourceLoading}>还原</Button> + <Popconfirm + title={tg('operation.restoreConfirm')} + onConfirm={unarchive} + > + <Button loading={unarchiveSourceLoading}> + {tg('button.restore')} + </Button> </Popconfirm> - <Popconfirm title="确认删除?" onConfirm={del(false)}> + <Popconfirm + title={tg('operation.deleteConfirm')} + onConfirm={del(false)} + > <Button loading={deleteSourceLoading} danger> - 删除 + {tg('button.delete')} </Button> </Popconfirm> </> @@ -337,10 +369,13 @@ export function SourceDetailPage() { > <Form.Item name="name" - label="名称" + label={t('form.name')} validateFirst rules={[ - { required: true, message: '名称不能为空' }, + { + required: true, + message: `${t('form.name')}${tg('validation.required')}`, + }, { validator: debounce((_, value) => { if (value === editingSource?.name) { @@ -363,8 +398,13 @@ export function SourceDetailPage() { </Form.Item> <Form.Item name="type" - label="类型" - rules={[{ required: true, message: '类型为必选项' }]} + label={t('type')} + rules={[ + { + required: true, + message: `${t('type')}${tg('validation.required')}`, + }, + ]} > <Select loading={dataProviderListLoading} diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/types.ts b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/types.ts index 579dbd636..9696829e2 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/types.ts +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/SourceDetailPage/types.ts @@ -1,3 +1,21 @@ +/** + * 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 { Schema } from 'app/pages/MainPage/pages/ViewPage/slice/types'; export interface HttpSourceConfig { diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/index.tsx b/frontend/src/app/pages/MainPage/pages/SourcePage/index.tsx index 0844572c4..627549721 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 React from 'react'; import { Route } from 'react-router-dom'; import styled from 'styled-components/macro'; 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 56591ed6d..385515a3a 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/slice/index.ts +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/slice/index.ts @@ -1,3 +1,21 @@ +/** + * 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 { createSlice } from '@reduxjs/toolkit'; import { useInjectReducer } from 'utils/@reduxjs/injectReducer'; import { 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 151053372..04effa454 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/slice/selectors.ts +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/slice/selectors.ts @@ -1,3 +1,21 @@ +/** + * 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 { createSelector } from '@reduxjs/toolkit'; import { RootState } from 'types'; import { initialState } from '.'; 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 77d7fce3b..51f591dc6 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/slice/thunks.ts +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/slice/thunks.ts @@ -1,3 +1,21 @@ +/** + * 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 { createAsyncThunk } from '@reduxjs/toolkit'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import { getLoggedInUserPermissions } from 'app/pages/MainPage/slice/thunks'; 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 250efd7b1..d43f4a481 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/slice/types.ts +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/slice/types.ts @@ -1,3 +1,21 @@ +/** + * 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. + */ + export interface SourceState { sources: Source[]; archived: Source[]; diff --git a/frontend/src/app/pages/MainPage/pages/SourcePage/utils.ts b/frontend/src/app/pages/MainPage/pages/SourcePage/utils.ts index 550d04ae7..d2bcae9a5 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/utils.ts +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/utils.ts @@ -1,3 +1,21 @@ +/** + * 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 { PermissionLevels, ResourceTypes } from '../PermissionPage/constants'; export function allowCreateSource() { diff --git a/frontend/src/app/pages/RegisterPage/RegisterForm.tsx b/frontend/src/app/pages/RegisterPage/RegisterForm.tsx index 03ed8642f..aded7c21c 100644 --- a/frontend/src/app/pages/RegisterPage/RegisterForm.tsx +++ b/frontend/src/app/pages/RegisterPage/RegisterForm.tsx @@ -37,7 +37,7 @@ export const RegisterForm: FC<RegisterFormProps> = ({ onRegisterSuccess }) => { const loading = useSelector(selectRegisterLoading); const [form] = Form.useForm(); const t = useI18NPrefix('register'); - const tgv = useI18NPrefix('global.validation'); + const tg = useI18NPrefix('global'); const onRegister = useCallback( values => { @@ -67,7 +67,7 @@ export const RegisterForm: FC<RegisterFormProps> = ({ onRegisterSuccess }) => { rules={[ { required: true, - message: `${t('username')}${tgv('required')}`, + message: `${t('username')}${tg('validation.required')}`, }, ]} > @@ -78,7 +78,7 @@ export const RegisterForm: FC<RegisterFormProps> = ({ onRegisterSuccess }) => { rules={[ { required: true, - message: `${t('email')}${tgv('required')}`, + message: `${t('email')}${tg('validation.required')}`, }, ]} > @@ -89,10 +89,10 @@ export const RegisterForm: FC<RegisterFormProps> = ({ onRegisterSuccess }) => { rules={[ { required: true, - message: `${t('password')}${tgv('required')}`, + message: `${t('password')}${tg('validation.required')}`, }, { - validator: getPasswordValidator(tgv('invalidPassword')), + validator: getPasswordValidator(tg('validation.invalidPassword')), }, ]} > diff --git a/frontend/src/globalConstants.ts b/frontend/src/globalConstants.ts index 325ed3463..0679cf935 100644 --- a/frontend/src/globalConstants.ts +++ b/frontend/src/globalConstants.ts @@ -38,11 +38,6 @@ export enum CommonFormTypes { export const TITLE_SUFFIX = ['archived', 'unpublished']; -export const COMMON_FORM_TITLE_PREFIX = { - [CommonFormTypes.Add]: '新建', - [CommonFormTypes.Edit]: '编辑', -}; - export const DEFAULT_DEBOUNCE_WAIT = 300; export const FONT_SIZES = [ diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 6c36abf6e..cdfb2e4d2 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -1,14 +1,37 @@ { "global": { "tokenExpired": "Token expired, please log in", + "title": { + "action": "Action", + "recycle": "Recycle" + }, + "button": { + "save": "Save", + "edit": "Edit", + "archive": "Archive", + "restore": "Restore", + "delete": "Delete" + }, "operation": { - "updateSuccess": "Update Successful", - "deleteSuccess": "Delete Successful" + "archiveConfirm": "Archive confirm", + "restoreConfirm": "Restore confirm", + "deleteConfirm": "Delete confirm", + "updateSuccess": "Update successful", + "deleteSuccess": "Delete successful", + "archiveSuccess": "Archive successful", + "restoreSuccess": "Restore successful", + "parseError": "Configuration parse error" }, "validation": { "required": " is required", "invalidPassword": "Password must be 6-20 characters", "passwordNotMatch": "Password and confirm password does not match" + }, + "modal": { + "title": { + "add": "Create ", + "edit": "Edit " + } } }, "login": { @@ -90,15 +113,13 @@ "username": "Username", "email": "Email", "name": "Name", - "department": "Department", - "save": "Save" + "department": "Department" }, "changePassword": { "title": "Password", "oldPassword": "Password", "newPassword": "New password", - "confirmPassword": "Confirm password", - "save": "Save" + "confirmPassword": "Confirm password" }, "switchLanguage": { "title": "language" @@ -653,6 +674,30 @@ "noScale": "noScale" } }, + "source": { + "source": "Source", + "testSuccess": "Test connection succeeded", + "createSuccess": "Source created successfully", + "archived": "Archived ", + "noPermission": "You do not have permission to access this page", + "sidebar": { + "title": "Source List", + "add": "Create source" + }, + "form": { + "name": "Name", + "type": "Type", + "test": "Test connection", + "file": "File", + "selectFile": "Select file", + "addProperty": "Add property", + "editProperty": "Edit property", + "addConfig": "Add configuration", + "editConfig": "Edit configuration", + "duplicate": "Duplicate key", + "duplicateName": "Duplicate Name" + } + }, "share": { "common": { "confirm": "Please Confirm", diff --git a/frontend/src/locales/i18n.ts b/frontend/src/locales/i18n.ts index 4c1120612..e46d99414 100644 --- a/frontend/src/locales/i18n.ts +++ b/frontend/src/locales/i18n.ts @@ -32,7 +32,7 @@ export const i18n = i18next // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ - lng: 'zh', + lng: 'en', resources: translationsJson, fallbackLng: 'en', debug: diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index c579e7372..8757d4c78 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -1,14 +1,37 @@ { "global": { "tokenExpired": "会话过期,请重新登录", + "title": { + "action": "操作", + "recycle": "回收站" + }, + "button": { + "save": "保存", + "edit": "编辑", + "archive": "移至回收站", + "restore": "还原", + "delete": "删除" + }, "operation": { + "archiveConfirm": "确定移至回收站?", + "restoreConfirm": "确定还原?", + "deleteConfirm": "确定删除?", "updateSuccess": "修改成功", - "deleteSuccess": "删除成功" + "deleteSuccess": "删除成功", + "archiveSuccess": "成功移至回收站", + "restoreSuccess": "还原成功", + "parseError": "配置解析错误" }, "validation": { "required": "不能为空", "invalidPassword": "密码长度为6-20位", "passwordNotMatch": "两次输入的密码不一致" + }, + "modal": { + "title": { + "add": "新建", + "edit": "编辑" + } } }, "login": { @@ -78,7 +101,7 @@ }, "organization": { "title": "组织列表", - "create": "创建组织", + "create": "新建组织", "name": "名称", "desc": "描述", "save": "保存并进入" @@ -90,15 +113,13 @@ "username": "用户名", "email": "邮箱", "name": "姓名", - "department": "部门", - "save": "保存" + "department": "部门" }, "changePassword": { "title": "修改密码", "oldPassword": "密码", "newPassword": "新密码", - "confirmPassword": "确定新密码", - "save": "保存" + "confirmPassword": "确定新密码" }, "switchLanguage": { "title": "切换语言" @@ -119,7 +140,7 @@ "background": { "loading": "应用配置加载中…", "initError": "初始化错误,请刷新页面重试", - "createOrg": "未加入任何组织,点击创建" + "createOrg": "未加入任何组织,点击新建" } }, "viz": { @@ -283,8 +304,8 @@ } }, "dataview": { - "createComputedFields": "创建计算字段", - "createVariableFields": "创建查询变量", + "createComputedFields": "新建计算字段", + "createVariableFields": "新建查询变量", "fieldName": "名称", "type": "类型", "field": "字段", @@ -652,6 +673,30 @@ "noScale": "实际尺寸" } }, + "source": { + "source": "数据源", + "testSuccess": "测试连接成功", + "createSuccess": "新建数据源成功", + "archived": "已归档", + "noPermission": "您没有权限访问该页面", + "sidebar": { + "title": "数据源列表", + "add": "新建数据源" + }, + "form": { + "name": "名称", + "type": "类型", + "test": "测试连接", + "file": "文件", + "selectFile": "选择文件", + "addProperty": "新增配置项", + "editProperty": "编辑配置项", + "addConfig": "新增配置", + "editConfig": "编辑配置", + "duplicateKey": "Key不能重复", + "duplicateName": "名称重复" + } + }, "share": { "common": { "confirm": "请确认", From 2ebea164a8ebb53457f4108c4206ea69179aef84 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Wed, 29 Dec 2021 19:42:50 +0800 Subject: [PATCH 276/348] feat: add widget i18n --- frontend/src/locales/en/translation.json | 11 ++++++++++- frontend/src/locales/zh/translation.json | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index cdfb2e4d2..611c97124 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -603,13 +603,22 @@ } }, "widget": { + "widget": "Widget", "type": { "chart": "Chart", + "widgetChart": "privateChart", + "dataChart": "publicChart", "media": "Media", "container": "Container", "controller": "Controller", "query": "Query", - "reset": "Reset" + "reset": "Reset", + "image": "Image", + "richText": "Rich Text", + "timer": "Timer", + "iFrame": "iFrame", + "video": "Video", + "tab": "Tab" }, "action": { "refresh": "Refresh", diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 8757d4c78..fbeb6f045 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -602,13 +602,22 @@ } }, "widget": { + "widget": "组件", "type": { "chart": "数据图表", + "widgetChart": "私有图表", + "dataChart": "公共图表", "media": "媒体", "container": "容器", "controller": "控制器", "query": "查询", - "reset": "重置" + "reset": "重置", + "image": "图片", + "richText": "富文本", + "timer": "时间器", + "iFrame": "iFrame", + "video": "视频", + "tab": "Tab" }, "action": { "refresh": "同步数据", From 3774d76fdc30d43f1b1ada6e15bf771fe97a5ff2 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Wed, 29 Dec 2021 19:45:25 +0800 Subject: [PATCH 277/348] chore: cleanup code --- frontend/src/app/pages/MainPage/index.tsx | 26 +++++------------------ 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/frontend/src/app/pages/MainPage/index.tsx b/frontend/src/app/pages/MainPage/index.tsx index 8f5e09379..767f654bf 100644 --- a/frontend/src/app/pages/MainPage/index.tsx +++ b/frontend/src/app/pages/MainPage/index.tsx @@ -17,15 +17,9 @@ */ import { useAppSlice } from 'app/slice'; -import React, { useEffect, useLayoutEffect } from 'react'; +import React, { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { - Redirect, - Route, - Switch, - useHistory, - useRouteMatch, -} from 'react-router'; +import { Redirect, Route, Switch, useRouteMatch } from 'react-router'; import styled from 'styled-components/macro'; import ChartManager from '../ChartWorkbenchPage/models/ChartManager'; import { NotFoundPage } from '../NotFoundPage'; @@ -59,11 +53,9 @@ export function MainPage() { const { actions: vizActions } = useVizSlice(); const { actions: viewActions } = useViewSlice(); const dispatch = useDispatch(); - const history = useHistory(); const organizationMatch = useRouteMatch<MainPageRouteParams>( '/organizations/:orgId', ); - const { isExact } = useRouteMatch(); const orgId = useSelector(selectOrgId); // loaded first time @@ -86,23 +78,15 @@ export function MainPage() { } }, [dispatch, vizActions, viewActions, orgId]); - // useEffect(() => { - // if (isExact && orgId) { - // history.push(`/organizations/${orgId}`); - // } - // }, [isExact, orgId, history]); - return ( <AppContainer> <Background /> <Navbar /> {orgId && ( <Switch> - {orgId ? ( - <Route path="/" exact> - <Redirect to={`/organizations/${orgId}`} /> - </Route> - ) : null} + <Route path="/" exact> + <Redirect to={`/organizations/${orgId}`} /> + </Route> <Route path="/confirminvite" component={ConfirmInvitePage} /> <Route path="/organizations/:orgId" exact> <Redirect From 4c13159f413ebc972d487f38a1812be8c6f50bcf Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Wed, 29 Dec 2021 19:43:29 +0800 Subject: [PATCH 278/348] refactor: add widget show type name --- .../components/BoardToolBar/ToolBarItem.tsx | 2 +- .../slice/childSlice/stackSlice.ts | 3 ++- .../app/pages/DashBoardPage/utils/index.ts | 24 ++++++++++++++++++- .../app/pages/DashBoardPage/utils/widget.ts | 2 +- frontend/src/locales/i18n.ts | 2 +- 5 files changed, 28 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/ToolBarItem.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/ToolBarItem.tsx index 4e9587f24..ad407d846 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/ToolBarItem.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/ToolBarItem.tsx @@ -237,7 +237,7 @@ export const MediaWidgetDropdown: React.FC<ToolBtnProps> = props => { type: 'iframe', }, { - name: t('richText'), + name: t('video'), icon: '', type: 'video', }, diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/childSlice/stackSlice.ts b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/childSlice/stackSlice.ts index 8989c219a..299c11c1d 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/childSlice/stackSlice.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/childSlice/stackSlice.ts @@ -26,6 +26,7 @@ import { Widget, WidgetConf, } from 'app/pages/DashBoardPage/pages/Board/slice/types'; +import { getDefaultWidgetName } from 'app/pages/DashBoardPage/utils'; import { Variable } from 'app/pages/MainPage/pages/VariablePage/slice/types'; import produce from 'immer'; import { Layout } from 'react-grid-layout'; @@ -76,7 +77,7 @@ export const editBoardStackSlice = createSlice({ const widget = produce(ele, draft => { draft.config.index = maxWidgetIndex; draft.config.name = - ele.config.name || `${ele.config.type}未命名组件_${maxWidgetIndex}`; + ele.config.name || getDefaultWidgetName(ele, maxWidgetIndex); }); state.widgetRecord[widget.id] = widget; }); diff --git a/frontend/src/app/pages/DashBoardPage/utils/index.ts b/frontend/src/app/pages/DashBoardPage/utils/index.ts index 968ea69f9..646583fb8 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/index.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/index.ts @@ -18,6 +18,7 @@ import { } from 'app/types/FilterControlPanel'; import { getTime } from 'app/utils/time'; import { FilterSqlOperator } from 'globalConstants'; +import i18next from 'i18next'; import moment from 'moment'; import { STORAGE_IMAGE_KEY_PREFIX } from '../constants'; import { @@ -35,7 +36,6 @@ import { import { ChartRequestFilter } from './../../ChartWorkbenchPage/models/ChartHttpRequest'; import { PickerType } from './../pages/BoardEditor/components/ControllerWidgetPanel/types'; import { getLinkedColumn } from './widget'; - export const convertImageUrl = (urlKey: string = ''): string => { if (urlKey.startsWith(STORAGE_IMAGE_KEY_PREFIX)) { return localStorage.getItem(urlKey) || ''; @@ -476,3 +476,25 @@ export const getDistinctFiltersByColumn = (filter: ChartRequestFilter[]) => { return Object.values(filterMap); }; + +export const getDefaultWidgetName = (widget: Widget, index: number) => { + const widgetType = widget.config.type; + const subWidgetType = widget.config.content.type; + const typeTitle = i18next.t(`viz.widget.type.${widgetType}`); + const subTypeTitle = i18next.t(`viz.widget.type.${subWidgetType}`); + switch (widgetType) { + case 'chart': + return `${subTypeTitle}_${index}`; + case 'container': + return `${subTypeTitle}_${index}`; + case 'controller': + return `${subTypeTitle}_${index}`; + case 'media': + return `${subTypeTitle}_${index}`; + case 'query': + case 'reset': + return `${typeTitle}`; + default: + return `xxx${index}`; + } +}; diff --git a/frontend/src/app/pages/DashBoardPage/utils/widget.ts b/frontend/src/app/pages/DashBoardPage/utils/widget.ts index f65933aba..2401eee61 100644 --- a/frontend/src/app/pages/DashBoardPage/utils/widget.ts +++ b/frontend/src/app/pages/DashBoardPage/utils/widget.ts @@ -145,7 +145,7 @@ export const createContainerWidget = (opt: { export const createControlBtn = (opt: BtnActionParams) => { const content = { type: opt.type }; const widgetConf = createInitWidgetConfig({ - name: opt.type === 'query' ? '查询' : '重置', + name: '', type: opt.type as WidgetType, content: content, boardType: opt.boardType, diff --git a/frontend/src/locales/i18n.ts b/frontend/src/locales/i18n.ts index e46d99414..4c1120612 100644 --- a/frontend/src/locales/i18n.ts +++ b/frontend/src/locales/i18n.ts @@ -32,7 +32,7 @@ export const i18n = i18next // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ - lng: 'en', + lng: 'zh', resources: translationsJson, fallbackLng: 'en', debug: From 651c5cf5bcefe292f0c1c7cc778e1fe725666e6c Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Wed, 29 Dec 2021 20:29:17 +0800 Subject: [PATCH 279/348] fix(chart): fix debugger tool async issue --- .../ChartWorkbenchPage/models/ChartEventBroker.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts index 4b1e2858a..0b6e8c1bc 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts @@ -90,13 +90,14 @@ class ChartEventBroker { context?: BrokerContext, ) { try { - await Debugger.instance.measure( - `ChartEventBroker | ${event} `, - () => { - this._listeners.get(event)?.call?.(this._chart, options, context); - }, - false, - ); + // await Debugger.instance.measure( + // `ChartEventBroker | ${event} `, + // () => { + // this._listeners.get(event)?.call?.(this._chart, options, context); + // }, + // false, + // ); + this._listeners.get(event)?.call?.(this._chart, options, context); } catch (e) { console.error(`ChartEventBroker | ${event} exception ----> `, e); } finally { From af8c7a7425a185d933fabf9d07b711d1301263e2 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Wed, 29 Dec 2021 20:41:08 +0800 Subject: [PATCH 280/348] chore: viz sidebar i18n support --- .../pages/SourcePage/Sidebar/index.tsx | 7 ++- .../VizPage/Sidebar/Folders/FolderTree.tsx | 19 +++---- .../pages/VizPage/Sidebar/Recycle.tsx | 16 +++--- .../VizPage/Sidebar/Storyboards/List.tsx | 12 +++-- .../VizPage/Sidebar/Storyboards/index.tsx | 10 ++-- .../pages/MainPage/pages/VizPage/index.tsx | 2 +- frontend/src/locales/en/translation.json | 51 +++++++------------ frontend/src/locales/zh/translation.json | 37 ++++---------- 8 files changed, 62 insertions(+), 92 deletions(-) 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 02dc4f4be..b1aa8b3ff 100644 --- a/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SourcePage/Sidebar/index.tsx @@ -53,7 +53,6 @@ export const Sidebar = memo(() => { ); const sourceId = matchSourceDetail?.params.sourceId; const t = useI18NPrefix('source.sidebar'); - const tg = useI18NPrefix('global'); const allowCreate = useAccess(allowCreateSource()); const { filteredData: sourceList, debouncedSearch: listSearch } = @@ -91,7 +90,7 @@ export const Sidebar = memo(() => { items: [ { key: 'recycle', - text: tg('title.recycle'), + text: t('recycle'), prefix: <DeleteOutlined className="icon" />, }, ], @@ -100,13 +99,13 @@ export const Sidebar = memo(() => { }, { key: 'recycle', - title: tg('title.recycle'), + title: t('recycle'), back: true, search: true, onSearch: archivedSearch, }, ], - [toAdd, moreMenuClick, listSearch, archivedSearch, allowCreate, t, tg], + [toAdd, moreMenuClick, listSearch, archivedSearch, allowCreate, t], ); return ( diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/FolderTree.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/FolderTree.tsx index f4c2800c2..c1d905808 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/FolderTree.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/FolderTree.tsx @@ -41,6 +41,7 @@ export function FolderTree({ const vizsData = useSelector(selectVizs); const { showSaveForm } = useContext(SaveFormContext); const t = useI18NPrefix(i18nPrefix); + const tg = useI18NPrefix('global'); useEffect(() => { dispatch(getFolders(orgId)); @@ -71,12 +72,12 @@ export function FolderTree({ () => { let id = folderId; let archive = false; - let msg = t('folders.folderTree.successDeleted'); + let msg = tg('operation.deleteSuccess'); if (['DASHBOARD', 'DATACHART'].includes(relType)) { id = relId; archive = true; - msg = t('folders.folderTree.successRecycle'); + msg = tg('operation.archiveSuccess'); } dispatch( deleteViz({ @@ -89,7 +90,7 @@ export function FolderTree({ }), ); }, - [dispatch, redirect, t], + [dispatch, redirect, tg], ); const moreMenuClick = useCallback( @@ -154,7 +155,7 @@ export function FolderTree({ key="info" prefix={<EditOutlined className="icon" />} > - {t('folders.folderTree.info')} + {tg('button.info')} </MenuListItem> <MenuListItem key="delete" @@ -163,14 +164,14 @@ export function FolderTree({ <Popconfirm title={`${ node.relType === 'FOLDER' - ? t('folders.folderTree.confirmDelete') - : t('folders.folderTree.sureMoveRecycleBin') + ? tg('operation.deleteConfirm') + : tg('operation.archiveConfirm') }?`} onConfirm={archiveViz(node)} > {node.relType === 'FOLDER' - ? t('folders.folderTree.delete') - : t('folders.folderTree.moveToTrash')} + ? tg('button.delete') + : tg('button.archive')} </Popconfirm> </MenuListItem> </Menu> @@ -184,7 +185,7 @@ export function FolderTree({ </TreeTitle> ); }, - [moreMenuClick, archiveViz, t], + [moreMenuClick, archiveViz, t, tg], ); const onDrop = info => { 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 e9c0e86f6..4f8674a38 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Recycle.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Recycle.tsx @@ -46,7 +46,7 @@ export const Recycle = memo( const vizs = useSelector(selectVizs); const isOwner = useSelector(selectIsOrgOwner); const permissionMap = useSelector(selectPermissionMap); - const t = useI18NPrefix('viz.sideBar.recycle'); + const tg = useI18NPrefix('global'); useEffect(() => { onInit(); @@ -71,13 +71,13 @@ export const Recycle = memo( params: { id, archive: false }, type, resolve: () => { - message.success(t('successDeleted')); + message.success(tg('operation.deleteSuccess')); dispatch(removeTab({ id, resolve: redirect })); }, }), ); }, - [dispatch, redirect, t], + [dispatch, redirect, tg], ); const moreMenuClick = useCallback( @@ -104,7 +104,7 @@ export const Recycle = memo( index, }, resolve: () => { - message.success(t('successRestored')); + message.success(tg('operation.restoreSuccess')); dispatch(removeTab({ id, resolve: redirect })); onClose(); }, @@ -117,7 +117,7 @@ export const Recycle = memo( break; } }, - [dispatch, showSaveForm, redirect, vizs, t], + [dispatch, showSaveForm, redirect, vizs, tg], ); const toDetail = useCallback( @@ -182,17 +182,17 @@ export const Recycle = memo( key="reset" prefix={<ReloadOutlined className="icon" />} > - {t('reduction')} + {tg('button.restore')} </MenuListItem> <MenuListItem key="delelte" prefix={<DeleteOutlined className="icon" />} > <Popconfirm - title={t('confirmDeletion') + '?'} + title={tg('operation.deleteConfirm')} onConfirm={del(id, vizType)} > - {t('delete')} + {tg('button.delete')} </Popconfirm> </MenuListItem> </Menu> diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Storyboards/List.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Storyboards/List.tsx index 6e6055649..7f5061b1d 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Storyboards/List.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Storyboards/List.tsx @@ -6,6 +6,7 @@ import { } from '@ant-design/icons'; import { Button, List as ListComponent, Menu, message, Popconfirm } from 'antd'; import { ListItem, MenuListItem, Popup } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { Access } from 'app/pages/MainPage/Access'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import classNames from 'classnames'; @@ -37,6 +38,7 @@ export const List = memo(({ list, selectedId }: StoryboardListProps) => { const listLoading = useSelector(selectStoryboardListLoading); const orgId = useSelector(selectOrgId); const { showSaveForm } = useContext(SaveFormContext); + const tg = useI18NPrefix('global'); useEffect(() => { dispatch(getStoryboards(orgId)); @@ -67,13 +69,13 @@ export const List = memo(({ list, selectedId }: StoryboardListProps) => { params: { id, archive: true }, type: 'STORYBOARD', resolve: () => { - message.success('成功移至回收站'); + message.success(tg('operation.archiveSuccess')); dispatch(removeTab({ id, resolve: redirect })); }, }), ); }, - [dispatch, redirect], + [dispatch, redirect, tg], ); const moreMenuClick = useCallback( @@ -128,17 +130,17 @@ export const List = memo(({ list, selectedId }: StoryboardListProps) => { key="info" prefix={<EditOutlined className="icon" />} > - 基本信息 + {tg('button.info')} </MenuListItem> <MenuListItem key="delete" prefix={<DeleteOutlined className="icon" />} > <Popconfirm - title={`确定移至回收站?`} + title={tg('operation.archiveConfirm')} onConfirm={archiveStoryboard(s.id)} > - 移至回收站 + {tg('button.archive')} </Popconfirm> </MenuListItem> </Menu> diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Storyboards/index.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Storyboards/index.tsx index 8de2fd442..2dce5efe5 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Storyboards/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Storyboards/index.tsx @@ -70,13 +70,11 @@ export const Storyboards = memo( const titles = useMemo( () => [ { - subTitle: t('storyBoards.storyBoardsList'), + subTitle: t('storyboards.title'), search: true, ...allowCreate({ add: { - items: [ - { key: 'STORYBOARD', text: t('storyBoards.newStoryBoards') }, - ], + items: [{ key: 'STORYBOARD', text: t('storyboards.add') }], icon: <PlusOutlined />, callback: add, }, @@ -85,7 +83,7 @@ export const Storyboards = memo( items: [ { key: 'recycle', - text: t('storyBoards.recycle'), + text: t('storyboards.recycle'), prefix: <DeleteOutlined className="icon" />, }, ], @@ -101,7 +99,7 @@ export const Storyboards = memo( }, { key: 'recycle', - subTitle: t('storyBoards.recycle'), + subTitle: t('storyboards.recycle'), back: true, search: true, onSearch: recycleSearch, diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx index 8f1df04cb..423e1ca32 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx @@ -43,7 +43,7 @@ export function VizPage() { onDragEnd={siderDragEnd} className="datart-split" > - <Sidebar i18nPrefix={'viz.sideBar'} /> + <Sidebar i18nPrefix={'viz.sidebar'} /> <Main /> <SaveForm width={400} diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index cdfb2e4d2..a80dcaf0b 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -2,15 +2,15 @@ "global": { "tokenExpired": "Token expired, please log in", "title": { - "action": "Action", - "recycle": "Recycle" + "action": "Action" }, "button": { "save": "Save", "edit": "Edit", "archive": "Archive", "restore": "Restore", - "delete": "Delete" + "delete": "Delete", + "info": "Info" }, "operation": { "archiveConfirm": "Archive confirm", @@ -623,36 +623,20 @@ "closeJump": "Close Jump" } }, - "sideBar": { - "folder": "目录", - "presentation": "演示", + "sidebar": { + "folder": "Folder", + "presentation": "Presentation", "folders": { - "folderTitle": "仪表板 & 数据图表", - "dashboard": "新建仪表板", - "dataChart": "新建数据图表", - "folder": "新建目录", - "recycle": "回收站", - "folderTree": { - "successDeleted": "成功删除", - "successRecycle": "成功移至回收站", - "info": "基本信息", - "delete": "删除", - "moveToTrash": "移至回收站", - "confirmDelete": "确定删除", - "sureMoveRecycleBin": "确定移至回收站" - } + "folderTitle": "Dashboards & Datacharts", + "dashboard": "Create dashboard", + "dataChart": "Create datachart", + "folder": "Create folder", + "recycle": "Recycle" }, - "storyBoards": { - "storyBoardsList": "故事板列表", - "newStoryBoards": "新建故事板", - "recycle": "回收站" - }, - "recycle": { - "successDeleted": "删除成功", - "successRestored": "还原成功", - "reduction": "还原", - "confirmDeletion": "确认删除", - "delete": "删除" + "storyboards": { + "title": "Storyboards", + "add": "Create storyboard", + "recycle": "Recycle" } }, "lineOptions": { @@ -682,7 +666,8 @@ "noPermission": "You do not have permission to access this page", "sidebar": { "title": "Source List", - "add": "Create source" + "add": "Create source", + "recycle": "Recycle" }, "form": { "name": "Name", @@ -720,4 +705,4 @@ "searchValue": "Search name keywords" } } -} \ No newline at end of file +} diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 8757d4c78..f957a370c 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -2,15 +2,15 @@ "global": { "tokenExpired": "会话过期,请重新登录", "title": { - "action": "操作", - "recycle": "回收站" + "action": "操作" }, "button": { "save": "保存", "edit": "编辑", "archive": "移至回收站", "restore": "还原", - "delete": "删除" + "delete": "删除", + "info": "基本信息" }, "operation": { "archiveConfirm": "确定移至回收站?", @@ -622,7 +622,7 @@ "closeJump": "关闭跳转" } }, - "sideBar": { + "sidebar": { "folder": "目录", "presentation": "演示", "folders": { @@ -630,28 +630,12 @@ "dashboard": "新建仪表板", "dataChart": "新建数据图表", "folder": "新建目录", - "recycle": "回收站", - "folderTree": { - "successDeleted": "成功删除", - "successRecycle": "成功移至回收站", - "info": "基本信息", - "delete": "删除", - "moveToTrash": "移至回收站", - "confirmDelete": "确定删除", - "sureMoveRecycleBin": "确定移至回收站" - } - }, - "storyBoards": { - "storyBoardsList": "故事板列表", - "newStoryBoards": "新建故事板", "recycle": "回收站" }, - "recycle": { - "successDeleted": "删除成功", - "successRestored": "还原成功", - "reduction": "还原", - "confirmDeletion": "确认删除", - "delete": "删除" + "storyboards": { + "title": "故事板列表", + "add": "新建故事板", + "recycle": "回收站" } }, "lineOptions": { @@ -681,7 +665,8 @@ "noPermission": "您没有权限访问该页面", "sidebar": { "title": "数据源列表", - "add": "新建数据源" + "add": "新建数据源", + "recycle": "回收站" }, "form": { "name": "名称", @@ -719,4 +704,4 @@ "searchValue": "搜索名称关键字" } } -} \ No newline at end of file +} From ad98c47fbfe5e5547c8cd90e7e42fb6ef78fe270 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Thu, 30 Dec 2021 00:12:25 +0800 Subject: [PATCH 281/348] chore: adjust siderbar title style --- frontend/src/app/components/ListTitle/index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/src/app/components/ListTitle/index.tsx b/frontend/src/app/components/ListTitle/index.tsx index b7dfc41eb..8e097f5bd 100644 --- a/frontend/src/app/components/ListTitle/index.tsx +++ b/frontend/src/app/components/ListTitle/index.tsx @@ -158,17 +158,23 @@ const Title = styled.div` h3 { flex: 1; + overflow: hidden; padding: ${SPACE_MD} 0; font-size: ${FONT_SIZE_TITLE}; font-weight: ${FONT_WEIGHT_MEDIUM}; + text-overflow: ellipsis; + white-space: nowrap; } h5 { flex: 1; + overflow: hidden; padding: ${SPACE_XS} 0; font-size: ${FONT_SIZE_SUBTITLE}; font-weight: ${FONT_WEIGHT_MEDIUM}; color: ${p => p.theme.textColorLight}; + text-overflow: ellipsis; + white-space: nowrap; } .back { From 9b0bd480a04ff0a31d3bbcc4e6a15e7536b00031 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Thu, 30 Dec 2021 00:17:06 +0800 Subject: [PATCH 282/348] chore: add copyright to view pages --- .../MainPage/pages/ViewPage/Container.tsx | 18 ++++++++++++++++++ .../MainPage/pages/ViewPage/EditorContext.ts | 18 ++++++++++++++++++ .../pages/ViewPage/Main/Editor/SQLEditor.tsx | 18 ++++++++++++++++++ .../pages/ViewPage/Main/Editor/Toolbar.tsx | 18 ++++++++++++++++++ .../pages/ViewPage/Main/Editor/index.tsx | 18 ++++++++++++++++++ .../pages/ViewPage/Main/Outputs/Error.tsx | 18 ++++++++++++++++++ .../pages/ViewPage/Main/Outputs/Results.tsx | 18 ++++++++++++++++++ .../pages/ViewPage/Main/Outputs/index.tsx | 18 ++++++++++++++++++ .../Main/Properties/ColumnPermissions.tsx | 18 ++++++++++++++++++ .../ViewPage/Main/Properties/Resource.tsx | 18 ++++++++++++++++++ .../ViewPage/Main/Properties/Variables.tsx | 18 ++++++++++++++++++ .../ViewPage/Main/Properties/VerticalTabs.tsx | 18 ++++++++++++++++++ .../pages/ViewPage/Main/Properties/index.tsx | 18 ++++++++++++++++++ .../MainPage/pages/ViewPage/Main/Tabs.tsx | 18 ++++++++++++++++++ .../pages/ViewPage/Main/Workbench.tsx | 18 ++++++++++++++++++ .../MainPage/pages/ViewPage/Main/index.tsx | 18 ++++++++++++++++++ .../MainPage/pages/ViewPage/SaveForm.tsx | 18 ++++++++++++++++++ .../pages/ViewPage/SaveFormContext.ts | 18 ++++++++++++++++++ .../pages/ViewPage/Sidebar/FolderTree.tsx | 18 ++++++++++++++++++ .../pages/ViewPage/Sidebar/Recycle.tsx | 18 ++++++++++++++++++ .../MainPage/pages/ViewPage/Sidebar/index.tsx | 18 ++++++++++++++++++ .../pages/ViewPage/components/SchemaTable.tsx | 18 ++++++++++++++++++ .../MainPage/pages/ViewPage/constants.ts | 18 ++++++++++++++++++ .../pages/MainPage/pages/ViewPage/index.tsx | 18 ++++++++++++++++++ .../MainPage/pages/ViewPage/slice/index.ts | 18 ++++++++++++++++++ .../pages/ViewPage/slice/selectors.ts | 18 ++++++++++++++++++ .../MainPage/pages/ViewPage/slice/thunks.ts | 18 ++++++++++++++++++ .../MainPage/pages/ViewPage/slice/types.ts | 18 ++++++++++++++++++ .../pages/MainPage/pages/ViewPage/utils.tsx | 19 ++++++++++++++++++- 29 files changed, 522 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Container.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Container.tsx index adb87b04d..4cca642df 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Container.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Container.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Split } from 'app/components'; import { useSplitSizes } from 'app/hooks/useSplitSizes'; import React, { useCallback, useContext } from 'react'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/EditorContext.ts b/frontend/src/app/pages/MainPage/pages/ViewPage/EditorContext.ts index d04ca4afb..97371a08b 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/EditorContext.ts +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/EditorContext.ts @@ -1,3 +1,21 @@ +/** + * 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 { createContext, MutableRefObject, diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/SQLEditor.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/SQLEditor.tsx index 5c3b3f801..fba374530 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/SQLEditor.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/SQLEditor.tsx @@ -1,3 +1,21 @@ +/** + * 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 classnames from 'classnames'; import { CommonFormTypes } from 'globalConstants'; import debounce from 'lodash/debounce'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/Toolbar.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/Toolbar.tsx index 8afdde047..f5d230d13 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/Toolbar.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/Toolbar.tsx @@ -1,3 +1,21 @@ +/** + * 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 { AlignCenterOutlined, CaretRightOutlined, diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/index.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/index.tsx index bb95bbbdb..9014e7ee3 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 React, { memo } from 'react'; import styled from 'styled-components/macro'; import { SQLEditor } from './SQLEditor'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Error.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Error.tsx index 7131bb993..8120deb6d 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Error.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Error.tsx @@ -1,3 +1,21 @@ +/** + * 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 { InfoCircleOutlined } from '@ant-design/icons'; import React, { memo } from 'react'; import { useSelector } from 'react-redux'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx index ee93c912f..3da0fe1f6 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx @@ -1,3 +1,21 @@ +/** + * 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 { CaretRightOutlined, EyeInvisibleOutlined, diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/index.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/index.tsx index 63fc3aa35..d66f17038 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Spin } from 'antd'; import useResizeObserver from 'app/hooks/useResizeObserver'; import { transparentize } from 'polished'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx index 6f56cc466..97ccbe8d4 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx @@ -1,3 +1,21 @@ +/** + * 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 { LoadingOutlined, SearchOutlined } from '@ant-design/icons'; import { Button, Col, Input, List, Row } from 'antd'; import { ListItem, ListTitle, Popup, Tree } from 'app/components'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx index 3b126e0ea..79cc2d0e9 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx @@ -1,3 +1,21 @@ +/** + * 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 { CalendarOutlined, DatabaseOutlined, diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx index eb491e6df..3f1bfc9db 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx @@ -1,3 +1,21 @@ +/** + * 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 { DeleteOutlined, EditOutlined, diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/VerticalTabs.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/VerticalTabs.tsx index d62afba56..5c1963696 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/VerticalTabs.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/VerticalTabs.tsx @@ -1,3 +1,21 @@ +/** + * 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 classnames from 'classnames'; import { cloneElement, memo, ReactElement, useCallback, useState } from 'react'; import styled from 'styled-components/macro'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/index.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/index.tsx index e8984cf02..ca9d447c7 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { DatabaseOutlined, FunctionOutlined, diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Tabs.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Tabs.tsx index 26c8839d9..fa24ae0ed 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Tabs.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Tabs.tsx @@ -1,3 +1,21 @@ +/** + * 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 { CloseOutlined, InfoCircleOutlined, diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Workbench.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Workbench.tsx index 50a2877b4..f4c17d6eb 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Workbench.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Workbench.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Split } from 'app/components'; import { useCascadeAccess } from 'app/pages/MainPage/Access'; import React, { diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/index.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/index.tsx index 8dffb846e..80a345aa6 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { EmptyFiller } from 'app/components'; import React, { memo, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx index e18decc1d..15942c280 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx @@ -1,3 +1,21 @@ +/** + * 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 { DoubleRightOutlined } from '@ant-design/icons'; import { Button, diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/SaveFormContext.ts b/frontend/src/app/pages/MainPage/pages/ViewPage/SaveFormContext.ts index fd80f0b49..03e073635 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/SaveFormContext.ts +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/SaveFormContext.ts @@ -1,3 +1,21 @@ +/** + * 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 { CommonFormTypes } from 'globalConstants'; import { createContext, useCallback, useMemo, useState } from 'react'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/FolderTree.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/FolderTree.tsx index 47837d414..77ffb4548 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/FolderTree.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/FolderTree.tsx @@ -1,3 +1,21 @@ +/** + * 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 { DeleteOutlined, EditOutlined, MoreOutlined } from '@ant-design/icons'; import { Menu, message, Popconfirm, TreeDataNode } from 'antd'; import { MenuListItem, Popup, Tree, TreeTitle } from 'app/components'; 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 b7b16b1dc..217e1931f 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/Recycle.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/Recycle.tsx @@ -1,3 +1,21 @@ +/** + * 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 { DeleteOutlined, MoreOutlined, 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 4dd4d3278..d8735b394 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { CodeFilled, DeleteOutlined, diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx index 83404a9ac..5c8980262 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx @@ -1,3 +1,21 @@ +/** + * 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 { CalendarOutlined, FieldStringOutlined, diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/constants.ts b/frontend/src/app/pages/MainPage/pages/ViewPage/constants.ts index 7288b488c..ae1e827dc 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/constants.ts +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/constants.ts @@ -1,3 +1,21 @@ +/** + * 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. + */ + export enum ColumnTypes { String = 'STRING', Number = 'NUMERIC', diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/index.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/index.tsx index 6e579721b..8254e9527 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { useSourceSlice } from '../SourcePage/slice'; import { Container } from './Container'; import { EditorContext, useEditorContext } from './EditorContext'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/slice/index.ts b/frontend/src/app/pages/MainPage/pages/ViewPage/slice/index.ts index 022536739..0a0f43bab 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/slice/index.ts +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/slice/index.ts @@ -1,3 +1,21 @@ +/** + * 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 { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { getDataProviderDatabases } from 'app/pages/MainPage/slice/thunks'; import { useInjectReducer } from 'utils/@reduxjs/injectReducer'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/slice/selectors.ts b/frontend/src/app/pages/MainPage/pages/ViewPage/slice/selectors.ts index 951172f31..319d7255e 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/slice/selectors.ts +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/slice/selectors.ts @@ -1,3 +1,21 @@ +/** + * 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 { createSelector } from '@reduxjs/toolkit'; import { RootState } from 'types'; import { listToTree } from 'utils/utils'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/slice/thunks.ts b/frontend/src/app/pages/MainPage/pages/ViewPage/slice/thunks.ts index 17755f4b8..2565b6166 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/slice/thunks.ts +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/slice/thunks.ts @@ -1,3 +1,21 @@ +/** + * 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 { createAsyncThunk } from '@reduxjs/toolkit'; import sqlReservedWords from 'app/assets/javascripts/sqlReservedWords'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/slice/types.ts b/frontend/src/app/pages/MainPage/pages/ViewPage/slice/types.ts index 65b6397ca..31ad1e9e1 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/slice/types.ts +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/slice/types.ts @@ -1,3 +1,21 @@ +/** + * 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 { TreeDataNode, TreeNodeProps } from 'antd'; import { ReactElement } from 'react'; import { SubjectTypes } from '../../PermissionPage/constants'; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/utils.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/utils.tsx index c3d45bff9..a896d8c7a 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/utils.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/utils.tsx @@ -1,9 +1,26 @@ +/** + * 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 { FONT_WEIGHT_MEDIUM, SPACE_UNIT } from 'styles/StyleConstants'; import { getDiffParams, getTextWidth } from 'utils/utils'; import { ColumnCategories, DEFAULT_PREVIEW_SIZE, - MAX_RESULT_TABLE_COLUMN_WIDTH, UNPERSISTED_ID_PREFIX, ViewViewModelStages, } from './constants'; From 7ca75396b349cf58e4bfc7a601b59e187ac8b35a Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Thu, 30 Dec 2021 10:44:21 +0800 Subject: [PATCH 283/348] fix(chart): fix chart config default value after change view --- frontend/src/app/components/ChartEditor.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/components/ChartEditor.tsx b/frontend/src/app/components/ChartEditor.tsx index 8b8c0d3db..ea161c57d 100644 --- a/frontend/src/app/components/ChartEditor.tsx +++ b/frontend/src/app/components/ChartEditor.tsx @@ -171,7 +171,12 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ const currentChart = ChartManager.instance().getDefaultChart(); registerChartEvents(currentChart); setChart(currentChart); - let clonedState = CloneValueDeep(currentChart.config); + + let targetChartConfig = CloneValueDeep(currentChart.config); + const finalChartConfig = transferChartConfigs( + targetChartConfig, + targetChartConfig, + ); dispatch(workbenchSlice.actions.updateShadowChartConfig({})); dispatch( @@ -179,7 +184,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ type: ChartConfigReducerActionType.INIT, payload: { init: { - ...clonedState, + ...finalChartConfig, }, }, }), From 5e74d51b66d3f9b709eab02db89fe145b9dbfce6 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Thu, 30 Dec 2021 10:47:18 +0800 Subject: [PATCH 284/348] refactor(chart): remove duplicate deconstruct --- frontend/src/app/components/ChartEditor.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/components/ChartEditor.tsx b/frontend/src/app/components/ChartEditor.tsx index ea161c57d..a2f14f1aa 100644 --- a/frontend/src/app/components/ChartEditor.tsx +++ b/frontend/src/app/components/ChartEditor.tsx @@ -183,9 +183,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ workbenchSlice.actions.updateChartConfig({ type: ChartConfigReducerActionType.INIT, payload: { - init: { - ...finalChartConfig, - }, + init: finalChartConfig, }, }), ); @@ -313,7 +311,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ registerChartEvents(currentChart); setChart(currentChart); - let clonedState = CloneValueDeep(currentChart?.config); + let finalChartConfig = CloneValueDeep(currentChart?.config); dispatch(actions.updateChartAggregation(state)); dispatch(workbenchSlice.actions.updateShadowChartConfig({})); @@ -321,9 +319,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ workbenchSlice.actions.updateChartConfig({ type: ChartConfigReducerActionType.INIT, payload: { - init: { - ...clonedState, - }, + init: finalChartConfig, }, }), ); From 4548eae70ec2efc35e672972b1fbfdae76c97833 Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Thu, 30 Dec 2021 12:54:34 +0800 Subject: [PATCH 285/348] fix: function column parse bug fix --- bin/h2/datart.demo.mv.db | Bin 118784 -> 81920 bytes .../calcite/SqlFunctionRegisterVisitor.java | 20 ++++++++++++------ pom.xml | 7 ++++++ server/pom.xml | 20 ++++++++++++++++++ 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/bin/h2/datart.demo.mv.db b/bin/h2/datart.demo.mv.db index de2611c3d7ce5e7b270da192270615d36a3fc22f..4eec49f80758280a47d40874c6f1265d5443e4c2 100644 GIT binary patch delta 7954 zcmeHMYiu0V6`nix8fQb47~6R5JnYzzxXxnFoyYFZ5|t!i;UpMrw>&}v@jMeJ_Bu`M zC_-xN(g3NTZSa7mMJ126s;C4~lSQ?vN>xOwmKIeFYK1DbA|lO?iat<(6@K(_=00X- zz2g9m)Jin_=iW1W=bn4!p8K8e+%tRThS}NFrh%fIHOD8d14Wy*pBa11DPl>Ivev%o z(t)BYXRUF^C>8OuT^pJ~a>t!1YoBwdXt)I_Zz*#6obkfSxmD@)*EmB*-EPNai;=VA zPN|sBP8bJ^ISZPj#k_7y*^+Z~s)+O1gT`Lxa1k5XLz9zJMa8sW!C1+;s+pY{n+Oar zEnQNb>=EbC;jzh5(Q$oa2tC}F76hSNc&tW5f^ho<LC{A@TlbB1q+Q<9k;!zWT2ojM zT4!3P%YVLjtQ8$D?|=6n4d{ciF}{5bYVcpqp!?H@2COb5V4<Pjzto00{fSmIfbQ^r z(27pi{kjJU4Wf@$!}Bk+q58Vho9KgJ;4APT7}ypJ#Ib>^QN4It_IIv9+4OTemw%ef zp7v22y2U&5^gi@^f5#fs*ZPw!!8?QZjoiKGz6bB^AAzO9uYAucZ}^$>=#<~T7Ja2| zWGI}tpAI-a_?A#dt!_N|0I{~|<>yG-eBvR}wyYka?K2l?`%fxotdS<~4t!T<?dNw~ z5}Jg1;u^iS#yXD8JC1h&AGzriqP}BmY&$J~cm#DK%RhS_Wx5qjt==wE)3ic%x-@;* zvDx<d_ylTP;Y6EgYd(4jH6qZ`nMIcO*Ut8F#SA8sB&A~S^9Hu!lND^;W%Aak2e?nz zk$c$LgJY#TC#OqOMagH&2hH?oV2!w=?0xOEwN!0hF$)Q5lhs59IOV@@sugQ%CWqxR zdSRkQ9D2Nb@Wo}Q-mC*p@6B1|FP?I0Mbq~F^sRNGC42SXJ}*9U*F4&Yeu~6B>*jyn zjV>VZ(Z}b%+=HG+HKUeT{=-X8q8U@nSvRs{AS-U65DJ<l8KF>6B{>vyDHNdRs!H@v z{2eR)jvc*&Wjh>pKO8;@htq)o1Nn3ch~W|x#kC?Kr>N0-WWA7scj$M8^{Ded+KAFf zbgnS7_rA}~-v55wZ0b(TY$i~%nLy2E0yUcm+-&|2v4;uNY$i~%xeyME%%*=avzb86 zW&$;v3Dj&V$kc3&cvG+q>N(>#wR0VH8)9G>p;!dJiebB&WO?WM?)7FnQr^G&ZfFTT zR;Lcj@Y8EJ*>WrYvXuvgcx*Vm6M*FBV7mI{0Z?uc8doAg^V>1H<+BA<))X~gNd5B7 z?|$&RzSN10Fygr2Q&5=|gwcluLE9qSyc<9T+Li)<3bdIw07Rf|-3*`-w66r9GAq<P zbW?i(Dl^M3rN1w<SAz=Xpd#~*!aFMOgb0-5Px8D|;2oWJ4Bjz$$AV5BM7dtaCcrgU z1zcXPa|6Sz!4Ji)2wLny2rU4D5wvh*bg+N%b(Harbv2IC@P+}#SXfh8R0FpSeia*L z+O}iFkj->)E&<tasNTUI>S+`m+1uOIGsASjtTdFW3sokdT3iJ|W=VDRYA{tJm2#5B z3V^9^{}6SDi?F!CGB-E~<K$3AVH~s@TBX58f_5d+t|Vz!Ih31O|MC-P{o;!Nd`Mgb zSNhRD0esjno`jpu!y&{b?_k&Z#dls$*m*1V*~uDkA<tu6<amx2eF!bs`LvT`rmOxt zPoU1waP9*70vFH|T)>LyBD!TuGOJx6a(Yl2+5aMsr+HXOUBET5L)HSZ^u1?q9#Hgz zeFv4M9NYImR;yL!BXjeF94vPVe5+leWEuB)%llV%%Yb4e>~DPXk7i%NZ+Hs9$JLoK z&7153g5!PjQ|+K4Y5QWIjHpmtU8=T6kL=Nz3WKT0SExwZrP!22g{EM;T7?m*FqjIH zsW2*3&|Rs3A1gK`QIX5(PPGa%Qem=Pv6u>33Ut(S(DUBw$qXna-IGdHv8jow7^jQ* zyA`Rjs@NgSoU|3OnaIq^v@OmK%kO9@QC#`APa5rru`Lhj6O2bPW<q%+6aFiNY9{27 zj44qb$%KzZsF+IygbK?5FhDw)C0Ai~GqG`u&|dRG7?uYM;RIq)L)w)DYM2YrQT4X| zacen!c~3psKEHnlT9eukV|)>di%6nu!<oWzoFwjYC3X}|LK1O2$p&4N7+5SS@X$=x z5b)C|G((21MRC`a2zl)9=m@Ceap4z)7;c9C&{DI_M^b-D$~GNN-`s$-rB8>X&AY8L z<ByI&hPaeWQ>w@`WAW>&Jbv+fkg;o)4g$F@T!mcIls1M~v2+l^;H#){EXMTdwa56_ z5oa*C^H8vq4TK?j-%*I~)e<g5SVrwenCSwtA#uflA`l0b>{<apU*{&*xe2+8i8=0d zZW7)tUgsu@T#0N;jNt4lISM>HRzWNZ@00DkVL_P5vtU(AZZurXV9BZoR=zQX*50Z> zD6h)Zf~XYbqAsqCO0UzXwB;J2l975dib_rtj9651r64M0KG8wLUq6K!MTq#LUqU@D z<?>6Q4i&e(uxSfJC3r{VC?rso&-TB)>^A03k!ysbaLk<wrek4AkGs=us9*4EM|FY0 zfM81t4E$OIo9t%73eqjC<QLMPDC2eIc!6OrDKKn?Td|<P04*snK)ay8u#XlPO0>Xm zg%%iY3<?YnrtS&v-r5uI-VSa5adiRWGA%&NEi6E6TUdaAfk6RcZeampTUda2tEvF; zBrQOkTBHE+D=0vm69@046^NAy6^N(l>6;ZA&j2Tc&(ZYmZ%Nzyv#*o3W!FjCzOjn5 zncJzHIXl-JTo!Ih_3YdwH1o^Cq|?WbA%<gkEFJM<mf8YagRC$qdyZv+Br60Q;RT5( z2m&5)XLB5qZ>A&mMyecR^f)Ymok6*(@<d!+z5Bm7g-j>*hhIfKK(hlJ9=Hk)e++|M z3`e{ssE!QfXmw=xJ0D&h**(IlBag0OWdh?kFB6P5#q)J~hGmshN0<Ph1&JXOAX9^C z1QXzzhzq<-!2gNAW5?fdqIa<Dgu{ZY7L)1-odIrTg6aqpWKtbrf=a3*Ovsb!2o+eF zfC-S9tFEYEQISPO6%|bo&}+^Wp-os(GA5kfv6Af^?NxOu&A;7^zK6vBuky*p7}WC< S8?Rp5P)@dF$>iYyrT+uhH5Il1 literal 118784 zcmeHwZHyepbzpCcEy<)PiMBo{S|6j)7b!1SU0wY#vz8?;cZcMV`=!|>MJdRQdZv4* zjh4Ig>@F=ChdTrIkDQZB6v2TN=Mu=VbNLhGek8#mxl5qr?u`54J12n=C_gU9A#f5L z;N(XT!%mR9d-c^_Rns%wOAbX+?1iA7W>vp>{p!`L_g=kz@6@z2*;(K0zA=s2b!F}I z@iek+d$Rlb&c++l9e=XhkHhUannpns#D0W2PIt1m*}oWWPov4paer%VbA$Bjt;gHl z*W><ljH6B*_Po7D`Bze)q(Di5k^&_KN(z(|C@D}<prk-afsz6x1xgCs02DY?+W$Ae zER-me6euZBQlO+jNr93AB?U?floTi_P*R|zKuLjXO96h!Z}T7kXL3E>fK&a8;iYLm zfXkcHA%p^43NOT4)9z${b8~yz=|Xe>{NbM6ncQBx7*F?l^}q{*G!_7!SlgK0+}YTk zwky}_k3<(7Gv@D^FtBl8&nt7`cG%xufdGVPXFZ->-`U!Z`{!2Yk1o$5AJ>8ax!6ap zZN2yPul@Z8&sjhD3_SlO<G&lXPZ-7|{C@2L!+6#(9{5+^rPl{veV1Mje*bNHeW-me zyM71mq5s6My>tJ;qX!QitlSRNnsRJ<!GT5Y;{6-p#dvCMBZ}Xga_e`|yX~;E9#7fw zjc*v%qkE=|`;9y4OiYC}@govHV)3I#K_fa2V#6VR=dgdo?BcSE$1Xm*1ng2{mpZ$I z?9ySEF1tkR60=M1oe9PyVU05h3MiMr|JN?Z3&0|Qjcj_eO!)-bCH@I|kzgPcat;EX zvTcNYiGynO8tP8&Z0u~s(aiQa9#s;C2~)xFDN}t@;1mg*FvSV@m*XTOWXt%_*p`j> zO<-h4W9*Jg@KPAN7CE&ZM+^A87JEH^5X&gVGLo?ThQKmbme*AxSsO%B!ipdX%P|~8 zGER|<B_tD4_5_kl2o%8*=rzem>FT6pLPC}iGFpkq7?|*0ie*p2@_w>{rZ+Fe8>{_r zV=L@#L(tLIBlKU{x<ZHtDhb~4lvZbCE7n?l_AFb!$jxr$<9Z`oMfjA!N`)MZe72^w z1`1a7QLPTdZ_%(VF)n|W;q2(NQXs>+81<}9EA?5OR%)wGE45XpRbUwAYkL-rilN9% zCR^E?__lI~l{-(l3zR!WCM!*W0wi$d#{yruQ-IXurkW$8T)&%c06QDe=KSV`DWu*y zcaVK`%EA0v=hu*5JGawz-i&Sb&lvG5e;mjBzQ?XE@8|M=clp12HUk&2OK+lMy2x~0 z)AdcaX1d`-*K}jk?U^1jJ$E89y<j3Xec$whyBsFD9o%zk$&J_PhRID0cb)X6m)zL4 z)3b5XQkS3U%FlGuXOI&~-LP#Z&=9t}U0XoI$VoB4xK~Ti!9KQAbey{D-zC%+K*tr* zOKeb%*q@k;g)WJP1N#%K8YZrYj14<M#zr7*SD_@m5*gbO+Z8IjU8OQsU@7#lFhj;l zXb~(saW7+2?W8iclZ9nh>;$lhf;zanonT;7rQ4OdsY+-OETuhG+WNaGmfb8Y%dMZ# z?rOIFa#MxCWn~LOx5%b?&-3M`dP8ig1NQf25l?TY@$_Nnxt&gg$8SmR<>UKY;xj9X z+y8ZH|HCH3bbRD#I({T95tr|h$Oe-x=tzzLUlQD7$DTO=&VU2JE#v_3e7Ek^vGv_w zefu9$2f%lz1K{WvzyWaHFpe6=eSdi$T#p$O-}`{x-~ao6M6VCn%k26dx&MMO@xyl> z9ESto_VA8##)AV6fR4@W{*EJlVDZBhKfLSX68I%y*b0|`t9b;5THjaT4S=svupfo~ zph?@osfr+b2Y!*G*U{Ztxz2%IIJ>wiSOhu1BXwN}+I7T-HyuhlPzZ;6E^2foBGlDY zz^+hK<s}$}o={CG?P3?(1MYy1o6rt0NzoHN3!p9gE~r}+Js+^6&H!+MP(P5+ra@CD ze@;(BvM$u=LNvq@l3x=O>~bU{ilm>=&<}v-grM9b<uMNsqhsKJyNY6p04Q@=3C~nS zFhw}faLr;qiGbk!Nc^4e3fw%78w{dq(KTPj&0(l9VT&ASW2gyf>vNkVV$LZKwgTpL zB~;6vS}&bifRbQVs(ZJpx@Wnix_2X}do|Oq-{mkF<G8&V_)z!_2v2ZY@SD0zoEH2B zwj^;wWhnSiM2q|khzHRPIdS?7+(_LpLTNXQ0FZ!&9h_o--5znMuyJsJT>_fPACThU zL*c3)+_<o&y0Tx=*S&|lmHX>-@1gpv?mbkW)xC$2GOq4D<gI*M-P5W*t9x42XLX}6 zmd6crPpjIhds@|2omRY+;T-6+Qd@Oe#rvo?e0{UiihBx%I^9$_I^EP~b-JmoI^B3H z$6u$L@@!3~o7$?=t@o(p>#yl_LpEz>4*Qx;IK&R!rhzu(nD8+QD)Gi@-tG=k+x4+J z?!yu)`cRJCs811=8}(UH8udw08ud9*8ucl0i4*-EzuW+B$PHk?{!Z+F>3jN)U5~mb z3de3iSGfJ39PJ7_?n=*Z1@_8e?fB8A5Q+JJ*m(XnbAq1B8}$mk-u~{N)9bzm{^H=l zC#;7oWEc<q>xb}d2My$4*YgAGPU~aVUTdFqm$l!z+q%cP*E(Q*-1>xdpLM_Wfc2nt z5ZnomSDrq<(pas`wi+|5jrQ@g&H1^CW7`MzR4di}4*TcI*_B4C(mYXFTw1L(&No+9 zS1Q$NWo2f5werj}l~Xe-r^t0?ZlSq&V9yhk%KmRn@F!<yW=}QdDyuWc=Npyk^4a6_ z&DrWy^`+M8tL@|SOUK)*t>(#-jn+!_@Luw|)fLjey*RVbs8-I+v}RAuv<@T3K0?P{ zJUc%>$@=l<w4Q+Z(4Hq-OJ|o;pjllhMsqW(Gt~<Dx%bF{Jx{{hyjSFHW@qLbi*qx( ze-rUwfmab-8F~px2%b*?o?kW#P<^(ww0L7tonq8Dzuao9tTdMvM^DjebD`0Gb!oBD zZqB7WYcTC|jT19xfg=f%5Q;nv6#3mf1t@Z&*#efkQbuenuC`uLkg0n^c~Ir+EEW`e zU4UDgiz}-$i?fXajKg0MXa}s*JlR|XGQnDw))QNIgu26eEVr6Vt>)@0)k@ams~|qo z`9S^v2~NXe&v<=#*7(vUJ+odvqib`ey|}bE3;&&MwO}SB3{-~Tpj(ZX&Ne`NwOftZ zrE`rIyi6iw)CUL$Jp&x{d$$$fAcFB+V|AuEziT-*ge=<Z3?qrwZLYC0+iEVas;kJ; z7KcRU+4-3jAfX~{9nxO|40N75+af|-A=qHA;j=N=_v|u=+D4nnTWK1!o}=eX>r7`t z5#Wbm65lE?hx1FbXLdb%<ROiGu0%b;L`Pu!pDwb2EYH9;o5&$p0n58ar-<+%I6VtE z{aF#5s8l#R-)OZ#)W8DY<tDug2?dO}+J?P<_DmDDrx9XE^Z_B%Xq}sx9}rjM1wREZ z_{}1_;YxF1dA@PQ!e0<vTR~T+g|r&Wpp3O=m(CJ_mMyM%pP@t$S`rX)MZ8@DHcSl~ zq17bN>Yt13lY~~SrDXx`in(*F#9CQxwJBC8l}sLTRAJ7kk@R(T(HH0Ug;_{&AbVrh zMkTty&_lY+FD;%-!0>s>fRuIvP{X^;HD(iF@VmJ%Gk+Ld^c6RgGD&ZMncw^P($aha zToT+F*rr`2nj;kl!h}bG3BPU?5Ytzxrd^Yjdi^%<#m4#7Hqq)-S(z~dpjMwN+EZ5W zGC&C$vb`YHoCcLW(R1~cWl3YG4d@jBskN%Ug0`W9O{KPH;3do=Z6~Jcbw>Av<_e`8 z*_~Qo#=_E=AF?I~)rqOf<NIIdeA--`Yn+#?+SGPM7{tcXqSQt$-jsP|J9n~DO&E#) zX6i4ji|1fn{8i3I7IwSw)>eCc^Mcr)*P>KtVUUFyO(FQaKe9tV-rC&hcjNZ<TbE+B zX9hi!-Z{f^JO^QF=!t&t%|*3BQ~}_Uh2_JN7R$AL${0x_keg|gm8@pI1w=djki=9E zN?{^}_S_5P{(g?eAB9`5cQ(U*RFK-li<;8V@dmBK&HjaU4(+;|8@;s)Kn_^<{8hGJ z-?`Y?2-ns%;2AT-;+)%^x6-Z|Y{7exZ(YVt_nk`-B-b3kAOlz4a|9N|Y9)&+f3~-_ z!|k0d@-mCB$SWKrD}v7Y0a(+sL)J8#8-!hLJxg3r<?}}v=;OdZzmua(0VTrj>+luN z*cd2^x4QkcON_C_hD<pvgTR;9;?E7RTSmW<D<${Hhr*SV89xEc*cif$eCiPP2DmX{ zsj8S?!jAV9;B0>cEQz!42hRS}oSi7z{M^R+W;i~{cq!a|J(XF*^!oL1Yr8GRZs$l2 zE<N*wU2!p!AzqO)sO;#{NNjs_+8=<KIyGe46ZjCZqfb^s@oLhmN@o5+n67W+OjmDn zJpxUD8}&Im&{(#ye!Q;f6j}Qr>7`?nA)qdW{di-$NKblR3YN_hoIf-a^NiB|AkhBU z5ZVj*U(*OLXqO0o!#ME6edPEB&SDN(pR^vf9<d&^9<wUe<5tyr!g|tr%6i&*#yV^r zv7WU)WldT~ttsm{%Z5{!Jr9k*fKdbC`Y;SQxyY;^0yrmzyh%bX_&RhLsH6|&p-%!2 zeJ_WH*4H-PD9AyBlb^LpvL;`w6ux$M`nt}eb%@`*v?lbtaVe0A%Ag96tJbNAn4w(w zFi`u~bDVO78@J-^?X`^yTLr0}wT)*iCRHn^6O++PRzoS$kBneAzI0sh%qXUi`Vz?k z0``3rNbrLkhJ&ZWjkV7+Eq+|0E4)lTt4?>CVY-u|Xi2*GHQr4!lyyZRA%1ki=dz77 zsJ!T`D$g&S%*TNI|CnR_kmcFmT#wtr>MO{G^ch{KYs*%EEF#jAz8d3ZxLymcfJ<@z z;@TF;@}GIam2R(z<0E5Q#>ogDvdu(UpaSc8VaNu;rx3Z|%2O6}22WJQe3M=2aR7RD z7*OGASc@QYK@q^|19X$B0`OPzfD<M`u5QC+;w`{az9QH^0Rx;FGJp_qx;~x-nX@4Q zNrDRgJV(wYAgH&dn4lwF2NsXM$jIW&S%~B0b+KoExDEiy%um70HHXX`Clzva^GBn5 zRnU~o+tVWeCaXhN(RG0G${;7qzfnNqZtZk_BJOUtyPNAf7dMJ-{lXF)C9nkK9F7p( zRB4+f04auTS(py)llo4iv1l<NdL0?-Fz~_B5XKTVx~p3ZgbxH6lX+CE^&<dwn4A<( z5;3V;0@;w$C#al!7Jv_vlcFmXlb&uJj0T^`Npj|zXDtv=bU|H#7MHb+Ym6h->L`Z) zh{(1{n9i4mu%M7_p00ThA-^Kyj*j4MzTJ6Q3P8rR%BuYoaL3Q*I7SJ2m&5)VNgyPa zN<sB9d90uuE7&bp++7aWcXaQ*tXHeX;t1DN)|o{yCpQqj9mTzHXMG!}N6``fZf$uK zV|~T4$h4k|d&UZ=uym(>4w&xz5N?*H7I|43V$y+&vFhP!@=q|&WaG90{<$IWh42H( z>Sbw&39J-+`bhPNVLW`={+-*NFf3#_7Pef=vwSPCYF6Evwmxk=Z+*sk!Ftg;X3bc~ ztyyc%YFH<%lh!G#X`QytSo79`wP-C_%hpR)%UU7cAOzUHnu9G9)meJy2z(P+?Z9e$ zKgZWVR^#W^q6_hMJ6?}3f~&3ITI3JqEHMH;cX^Rc!{AWH!9c3{A*5mtBQHzC(_gI0 zM<UGP0?g$RFd6By)Vxfn3DG@(+ZqBlp&9bB^o9YzNq@@TK1}Ct6`xM_aKYK+C&9yJ zfeSeBo)AXK=_TApB!-1(g>(u7Aj`0wEEybmSxOJ5f_R^5(w$PJHUe;hFY>e09UXAe zodT`{xxbyKwS$>ekirENn|$ZHx|B%#ZN@gFxUcfg35)F(H?pqIc{A6!N7-;1xaEZ* ztCQ<J{(wG3Cs|f=J`GT&hd`ln!ynL{7>q<pJP*wE*Ex|;TRi<^K?cj`o&qeWF<6G5 zjby94OhX6QY5RcovANL(&pdeUn3GK~AfzhH<W@K@>%+Mo#0?AyN03~c@kUgzr;tH| zR_O@sthmNgY}FLdi&XP=EV!koJBopnAt=_i+WdfPAa+6`IzLvEBP*m<{kT&MqXl1l z23E}RAuC3#J6-Eb`CndpF94+cBUE44@g!jB<PkmKMOcY{m$R#ihj$Tul{}KOSyJ{d z#QFK1#9WZ6(w5~#SdNe!0$_*@`54e~nEoRnk9=MGOd4q@S~a<a7bWzZ0eb#+&bG;R z@Uh9YjK!|Yv4QBgELkXcS7Ps!SCqx1QTHa;9tCd*qfxx8woZ=&SL7U$`?{trW>a3J zv%m#k$>W0U&Hh_ALX6$5Hpz1^$#XfvST}sOq{)&ex&agYojmbLo+Y_y3a<EctUOa= z(7e3DU;|l%P(|?s&}gW=lF$P1L%wdxQS{mCR@GM_^6?}9J~@Q=;&qU(+d(o+(Tj@P zQvhyu1UNu2&}|<b7?<2ln95(yao!RCU%^?7FAhenYI2i6%U4@3g<D&n+k{BmL<DDr z6X|-X5O9((&loDB*RIT`T&tt7Yf!>-h&;-`^?G>mP6M0#an6dTZsJ{ru+V36w55dg z6ILj?-ZO|du;$OeTFN^~40P*IdsW5DJ`be&a*mZJ9C-y-RhHhOt*Xoe!HoCMSPmK_ zRg20v2c(|pd<UO=PB_Glh&Q^hM{E-%SB>J9*2Q|*iS?MUjQ7&q<iY?Q7VRS&t0M;A zm5w)L1#9HJ9;<f&czpEU-*!--yDw5EmG}O|5wOGoX`owm5-7o_WLsQ<rSeZXn-A$< zaGB)u_O8TyfmN4!B@@|17EA_zvM7FLit+8?;$}oRTlQ8AehN~IsdmMuA1Mz-M&K_e zZ$aZ{8TdKJIT+}E1;&%|s(5L{sz{gw1-e<y0VO@CcGrSc@uQp&BH<Tj8B=mL(By-b zJk45cj>3u0DOudPbn|m7wF6dQHisQO$;3o~ZWfDqsmk5RNuqK7)Y<(eB=9i~nAw$n zmg%>b?U~tGNR~3JQ%ih)$+`jD{;6l4m@trW;LiP(j@`uploG(G*K?h2r{=mL$n~fm z)oM_?AbL59FK#}wRaue(Z4G1J7r*-A7ykBJ_Zj;uI1a*krykYoA$B1LUk%$qjO||7 zu_0@x9m9Br@m}-75jx@>@POa-1Kjg$NKNb_C#<=Uzu!SMHx8Vz9>w_}0c+n2x{)6S z^*D0<9`1xTlv8jz7(*UdKqMbV@&*(?`}9|zod7cDKL?4G;Lkq&YoB8M^Dtrk-#dN5 z7Vi(+W(4nA>)LQdu>*OoJrD5qp=MCvbe#M-$;UFkhxYzwzKVAB{%3y8;qRZrKkWU# za%SZP`u=;1%v~N&E-bZ9wwGRBY_!r}1vpWCWy7BT#TR$;4hQGIc#QN<$7JvJoAb+y z^xf{tr+SO5reoxjzy9`Aw|k1*?tlJCCwvmwPolTH#mk-bxyzSh^zym+H#Zj}@1?l= zdh3nF^Uv9R{08cuyYSiG?8b$qQx}2@>vJ^}eU>Bw+x2q%nfVWvD9RR~+zX&cQ5-s6 z43$EB96C-=i=$qE{4TVi{FnN1nyuqpbEUZo8B1VpW)_>T&XBY-`K(MA)53kryJ5aB zExb+BmqXpMPrQAI<~=J^zYO{x^4@uD9O=vV{inu?@t8<oUKh#A>m8n>yxtW*L`Ac@ zsAyL2@upDZIuDWf7Xc>}NzX%(^gQ%LA7A`nMb|#`%4q+Nr+Ti7RNf)Y^qdw(lk+?) zMaZ(!pt~fOw^|e}aJyKfJtxIJvTLNJ`St;kG~IK8T~c&LPeeTwJz67;WyTi8W*|W= z`I8HJ1-(u!Ni+`F**zQ&<QcE0#b)4VirudW+9kzi^7D+df`n-SH<7(t;22O86&z)x z2n8Ld9u4A{mPV_~rDjB$ad?E~La!Ia5mKIONzen4K36I!WcMJ&Yg$qWZoNU=(%N!> zMoK@C<GwCx%RzYtR=aUT9(hK<4CF)_c@;T<O(DX`HRTf46E)=!q-LjuC3BI>V7*|F z_2hXZ*kRuhluRoK)zeyX@G~WyNO2#E@&KahMKR=9dUh!9L^H<=-eVM0c~8QMAnAf; zI559}M3OX9E)yWuM~FD@vDBO+%LM4_L!^*TaAZ6vuVEP}f}<DVK|+R7odqNjQt)6X z<R7mLSpdmF9;{{Xpc~q9@kLO_ok0RRDFJ2im&~##WPoZ#d5|E-X1T7dV$f8{pHdi1 z!m1Dj<w6EYVK7n10IC@7W}z@F^^#ll3^^!GEWt9c<BWMuOB#f7NrQxxqNG7#QIpDQ zm^pR9K$3Ivr!b?06+yD*LJiu13Xy4bgHWz+kRT~)+3Zf_451`rN(D&?D}rP_h%=D% zQ>K(_;CzMedQdEv?I^62YPw*cB%M^Yf|Z8Qmo=0+QAAHYLq29>m1+urKq?T+!VtG+ zVTju{Uwz&<XwW*pyneC6lxT+)6n0oaVTTnIc344ShZPidSV3Wj6%=+@L1Bj#6n0oa zVTTnIc344ShZPidSQ%pm8S|>iY*frf#k`G;irJ``7fxlV<sCf*dW|K#=dF4Ubl%Fc z!#jFfdgWOtmBZX{=XfEmx(pfXY3X?@gN*f5@oKA{Dqd~XbH%Hzda`)l%H9|2+2Yk_ zby}&dI;~X5I;}#vumA`vl~!u2PAj!lr&UM`rcSdrvSp&XI^k46I^on-op8LB4dd#B zQ=iodr?%>ZQ(FfJXBfB7|Jct!fib$=Fk3yCtscx)4`!<ev(<yy>cMRFV77WNTRm)P zxNP;fZ1uQo^|);HxV#HnJuX|bE*sTlqq=NVmyPPOQC&8w%SLtCs4g3o!GZ#^q{O+$ zM)laJ9vjtTqk6n28`Wc@dNo?CjQyL>FU)dhEp^%+(*Jkp|GV`6N-+*k=edr|k)F<T zYOBt3YOBs>yp^$vr?Z**tj=a?tIlRBWSz~_XLUB~BxODp!b{4#>nx{?0(GU-wW=0g z(dnkP>U2}fvgmYEpVjH6KC9DBEz6?QP2mL44b?YNpVjH6KC9D8Ez6?QN^R9?rMBv{ zQj4wVv{GAjT9qYT;%T<EUR_C-T24uqnkN@#(dXz!Ea@`wt<DFax>5NU)BpEa`Ef=r z#H*I`J6_+M-__-w4lkh2+8jq|Q=mA!oI3BxE1~l{1twOYU|vt1^~4HHtiZ$yo|qR@ zXV19`o-UH{bd~X3Wdv6l!Bs|ZYx1<~BEgk)5U3ca3LDQv*hIdGY9^|isAHnYM6ro_ zrsJ57XF9&=1g29nozQeTrW2V?Y&ty?BNIC&c1`RV#>5{+4;Y6G<y{m?ddhox%6obW zT|MPJJ!N)0g_52!g0GC=D<k*{C4B{^ufPnH*@2T15==71W-d@*1`3{mG9Q5gv!=kT zDKKl8YKv36pcCB^$qj6Y$#1BFMGf1j%}epdYCqiABJqx!8(Sv!O<Xf^-Nd1ZyC#lI z+%sL<bRE;hrt6t*V7hhF?U-)YbR*NVP0uksY<iyQ`KDK!@F&~}ZvqazCf@Dc4eO9$ z!*y5o^6Uojm*98&CHNgD48P;k$?rIs_#G!bzvE<Lca8$nQJ^@Syu4>kMpNmC6*RE| z5-Wq_x(tLf2!rn`AfZegWdhcwypE@g<|#nDU;<C{Ok|q~naDAbYa&={fr&yBbxp@M z9W()}3Y(5=I(5_OPQX0cCdLymnSqHrCWeD{^R=INv@CgbBb2=IO+UEHfhvY@xaHuU z3pEe<jn^SX2Kh}5f)>)7UUEa7tx)rjcdN_KbmeEd=`+ZQq;A-@6KDwA;M^6^Fa&!f z7+~D1r8hn%brSiY4x9$x<#0C}_<o_JTKQK}prk-afvcqetN$m}-%AbyYm>e8cpJWF z?oWq7r`C0%?)VGo@%n!Qwa97xzbmLZF0fZhijN;{29Xp1{F3ogGyrDu3x=_LE)9Tz z`-$ivy+8Q<x9Rnv_Py--9k_>f^ZTv)4o)6Cbnr3R0gjnRDwZ`^SJ8P`Ezv2a*Z799 zXUY1{#(g3HCam$Gl#YmL=^$#KF?Sha&NIaCnDY!V=NV$oGsK){h<V5mbDkmQvO~;e zhnUL_F_#@;E<40rc8Iy`Q12aa)>IRP$l2Lq8lK|Uz^svun|%4aDJw*U?T6U!NpS+1 zF)1CCo`1n{RZ@cdr#Vhgot>S3IofgO@bfPiTRZn+$6m?_Vm<KSWJ^CXl(2z;Q*6Zf zHMBEq3I_s^TKDV_E-7+97~cWNL`n1xt8wp%c$qXxK}JqKTrUshZp}lv+n>7a4r8)B zB_L-EK06pFj|XDN^&t)<%i{s=6ZXsF0pejHRn5za@0xpdmlfY-Kk&`q{x=st)`XyI z*~6xI>3qe*<|~dlU-8BHii^-!G+m`BP=ExA(=Jd34-_DZv$E#MDA(_%9>SfCXmft^ z!W6oL`l}qwuXTP6`L%QVjo{Bp{Z}`$GmGoa#F<5sicTpLcyn@(%1q8p!Aw50|0Vld zvY=D@KkC3|+_pD<Lt5DXB1X2$%`wUTC#DV!j)drQ8g`giJR%m>?M#v^T+`gdsVAmi zM-Fwp2FO$U|I5t&fB#DC|NF;c|No73$hd!${VzNM&h>Ew{G9FxV4>utA7Ep4b7y0F z+P<Ov06!~SCL+kbqq$5v;224rI1cmST!HUyz-y8Q)+_G3(lK!>Iwr19lwfK9PkDNn zTWSB7_J5xwik&XQ1IH5{*g>WJ&yTYd)4jC+W7F-K9x^?50>Z$8iP-c@`(Fy{x{<s` zH?#ep+TV%&kEQefxZCaY?BE)h(A@tZK0l49ZNblhnGFH?XvEjB;(L1(P7+Vtv=h;& zE*$h!7l0q8E&%yE(lO&t&i@Y^kKab}ejJ70_1Eb2_Fs6EUiUp%Ie731C^`#anh*W! zho+zcEd-#so*!6uS|79aTKlZKto_#A);-p})&c9|)+em{toyA8tOu=wP;BJ!%G2jp z8mkqSD71b2Y;%6D;@I|qJ=IEezr*u~o?U6QD$Nr#cXZ=?b7gg<Qms~2X69Eb&pcB( zHM4SxTxaGMnu`aZU|wbaw{p@zzSLTMwS9bk>3EyxDq0cg+g4^zK~9mynT1B0)e||8 zAzn+7CvqIAJpuEfJx{il&Mv1wv$|4@pql1PwL*T9JWr%n-+M*gW_D)2u{bx=+Vz`= z2ep^Z!cTN%=p`f}cs>PqemN&07^V7bYiaSuqB_N>aelc4Ijtav%;+g16^YufE-g0N z&AGH^O)DWlDDpH=<acut2U3chXtsdmu9OiQi>s|y6lCh&P#zpBw>B3c8`$D(qX6UZ zR|MJt>oiYh<bh}Fj!<`4kL6Z#snuM4C9^y#%}bWf2Pr_JE!fkr*fU-~BMl<ynYCCm zx;9tZi%W~M@ZZ^13uZ#XATz^atMSs=28geAt1-KDuF-;*5m`Wy`T*e|Ql9bma&nbZ z4k8%OHCAVu^SfUCL&%aryeyJv-R2rAv#sVb$;6btnB!@SgJ<j`BhNx6Cm^9BZE1fE zFwlAKY-<L}r>Ag%V1vDe&&FWiv&*D#ahu6oX&SViqvuTPOlLw7;D=!n-{Sk&><rmm zDy!s0D%E8u2j85nPF3j~&M(cL+4by^hcxoJ(hfwJ=m?De(?vFr<r&y!6FCGcV0qW* zh)r=6s}P)?1)Tn@2u@TgoSkp9+H8UII<!SM>0L-Dno<mAXZB1Jwx<zdNb~_2)@YrZ znI8~W<ONAF%5N6g4Of~A%kzyZ7XE_Z+6uZlEu__0Zp^H<XP3?rftD?<d7q&~;A@=L z?-Os=fDKcFMrbt&wEE{F`y`=NYiU`4yJGGfE3sBqTWyLJq~8`Y#6#Knb(6l3#kg=^ zNK>5G7iJ;Bfo!c=8<pq+Ll5af5~?O(_&jAmO1lB5;oasMvk5Tx-CUTNKaB8X#Z|XC z&L>H4fSKR>_|npR0$dPB+dnzrw5vpOtt(-|qrik;&q;_*#q^b`Y1d?>Ucb$I5vujH ziB_k|$_#!1wfbDqp0a|M0ZPy?U)d8qS6^9{G=|!M#sH97tLiIg8#>rjYI_D=!YtBu zVroHUbYEz$P|A_rsRd>%ERFdgYjRMXn1ZywuXA;xxj5H2FX<8KwurEv-CSedYTCCt zS*a$B#DB959M;8iurB^8XCn){T`1zTixO0%GC?ZUGP3tWjke95emBlY;GaRyq<2n= zX^v-Z?EujaqAf_){{>LkXBL(ZOIqxeSIdod`XTu|c2EivDYWNaAourkH2x%Ovv67D zyf$$prqs@=P*Na?yvVvOC4%36edl6lW3ZG;#tgBKy4zP>cm2xgetq)E7fkPd0M_)d zQaNmH5Z2SXOI#r5c>g#s(C_3ZQzRR3_jO1JJT?Z}RmlQTTp>|whEyXcxl*byGR}$| zL%EWQpiclZHim34eCiO^YXnFvRTc9~<k@`%I9pFoFT>(IKtSCOoc*UcJ5jXxxsCPB zFd7?UUkbNhPi5yYy?#C1f<mEu>~>DAOs<%6k(krDSPAwF@tReANS}A1>CkC^0A?z` zdL`DYuZg#YqUR|VWV#-N>H0>_bnzOW+^GLBwz0u7O<DUP>7`?nv8xp?IYCo&fMv4; z9-oF{o>AH#1ls4+HpF@@H$l5Z_#4K7AMQI0$1iXebIAIn^|1Ab^{DljRk0qos@4<M zlh#w#)7CTAVe5$Xto12t(mHBQS<hKEDf#};2n-lC5Y{WdB^YpWky$?ka83*n9tpXS ztJi%?KqY->k&#aV4}C9(ht}6N-YB@-2PZ#km1Ir6SSft%?)3FyPg)14+_Wb2ym2Xz zy0bG~ZpucgVNy)YP%eBJsQv3XPB|ivcUe6xYa7p4OsZB+CnlqptcFsg9~r@LY-Hr> zh0)ZPNEQ&V@1sD1ALK9`JRNSVeV%FY;}Ts(tMw_0mZXapo8~LtO)^Y0MIj-6bi(Jd zjWnpd=<2^bzjQJm1M>f4j`c&9XCG>ow}sVLbn%mCbfK;-76EdgpNuJ&0ZCttaWh=6 z1y_Jxi%vssoa?<9BYem<6J>!4tmlOx8wj0tC>!d6D{pC0@_S_PM3r}@`^e(}^z1O8 z!qq?k>rRtQ!07`Ncol%Zk_VhH337ECZX|fhS7c9p0tPrUWB?)JbbUMvGG{{qk^~j} zd5)Y*Ku~W@F+o?TQf7gLI8I&{d-f%;E8+ncM8?WiBwOb0O+;JH5~9rf6wF*+*-lqC ze>A!)Wjmi90Wet|x{9s?lvf5hVg8K*5_fB-^AmA*yWQPf-?_N4RZ!*%OK_BeA|U68 zX3<TRwi){p!>}z2)4_dG--)tCZH{er9U1E|@WIj$ksxezSGO1l9|$rg^Qc(sM*!?F zIVqkbVp6vRvLUBWP&xT503RkNMOP{&J>5DO4L*^R<jghCS|FgPkh%gbE^8at7^jH* z`-sT4Ntn)IWym=hkf&?jL&&elxT7O@n{RhsmI9D5t+HxA1>EuTIgU|+o~QyVmP%1k z7xvf4C%yx!qsAeE)5j(5Xr1HKLp7|FaK3$T6|VKIxUE$-7S)QimoLWpW7&U;3un4h zKL<>AewaW_rxtlx8sZ?!RFi*#c_s>%4e-wmfuFJj^0G9<1QzcIuD0|MQnvHq)Aq02 z_Jm;}%dxQKTAt-wfmO5W*0l9$>v`)l)(h5))-h|wI&RHcb5_GTVV$&2SxxJ-b;g>v z7OX{U$y&BvvRc*(@dhEl_SGD0nW)avJ4fJ~$Z7{x<NG<j2C^DisnT}59$$<%ik?^S zhjNw}0Z;K6rJayY!{AWH!9c2ERan`>$jj33^cSo0kqEQ60CRZ=`32U<%Tn_)p(aH4 z0B&mt+=OPx%hDSL04Mz^d;2h*zg2uX*~0}TYg%`B)I>pj%M0=L(7EE`K)8=Y?O-~E z0gz?bPL>Rgyey@MQ$f5>HR(>NQX2s{!58^i>W&UL=}rOHf!yED)7rtzDoEi1icS6* zvbvN={B4G5rMRy|;7-n-brb9Aoa=I(dz1~Qfm?EFeES3X6rE&Q&G|GynI5vn$rK@f zKzCv=5-IUKFxOw_L_%#r!pvx=FoWfDPXQLx7%aojMiP%-rXd@PuaJ0}0qtXRqYa*U z@Z6E_I#Z<y%BN*=E1Z}0;am^g21CL?Bo}AA5f$tyWYC~hnqzO~cpQX?>ys>I1AY#T z79X-}kK>k}?kJ)>Lr|=3wfUJ41mLjQ%<8of#cvKq((uvr<4yqpC5%DW-DhCM93Qe` zxV_=)T3^cl^4fa=AmtyS`nrxM0ZSERq6fSPEAj7gc2)84E~2lJM}{djDg7WsBs%~~ z<^23kVlFb4<waPIknsj!Ku95-kz+u|Vfv4RJo0tzGihAkyg;;ME~SW8K<GIG^!)9d zZIkWb1vk!oxt6imbvZT=lb9t71@B69PkBXIOxi-vH~b`!*GDP{-q07iwoZ=&SL7U$ z`?{trW>a3Jv%m#k$>W0U&Hh`R&9FbdNRq5s)#qw+qqlZ}EreZ3^N-FX&%q?m<p^Wl z@Y#|kOP=TkO!Rm1#3y-{B-|>v;?uG6ObubENos~O7=O&IzL6_f;tDDrPXLXE+A9ey z06*mGrW{3|y>3-~6(S!`0^pNFh%a6T`MMn>!xX)!xIG2nW=DVn1Owgn(SdQv-Gr(9 z<s9c7@&6T^#rWc2)T*`?3AB9iekt7A`rIZ+iDUw^!ijXfG((tY43*JqSLRc$)uD=* z9OYB(tlMN6xLyx0-f3WyKh9b4)J?q05ElAOj<%Gre!>bxgNrhVC#wx~&7Xm_ly{OC z=+>e3s*0C=9!T}&94k*a@(Ql10y|vhfndh_XDkP8eX3ei#yKE$jORP}<a5Fy-(bWW zUDzY2COp&<S%=J#dQ4cxdueX+JP(L$tm@j4q_*v9`!A+8UXRtg06ac=?{7OO(A^g) zlgfMl;s{vcfHcspIti3uRI)8D!BY9BoXv;yFStzdd3#r4zQC$Wy^@J+8WM89)$OlQ zP6tzrOZ<zQ5#emvTOlbVqqhZZ&F+d%ua7NqjXV??fxnz`1&yC&;O89YV4(XI7*EQp z;-wL*B4H8~=w>wsl=Pt5T?<ylk8(nYgkO9wNl8=9*+7#ITJkh&u{jDSKBr{ysVgP| zZ)9$zI>8Fe=CGqDnV2Zh&0;YxRk<5ENi@!%I=$b71U|+A^OZUHOsK!T!ks9y>pNT9 zaetY9d)c0uorPp6!#cIZ=a;M-z&&<q?>!R+hQq~du;*6ik1o$5AJ>8a!ti_u5x3s^ z`q%#cgXgTDd<LHHH-GrVgn^6$ckZur>@E(VrW{7Sp6hfwHP;PcUx?~at=6+~^l}tm z+<a!MvLprS8pggae)YvK{Oz~yGxk?-9E9~wJ*wA3?8dfT!*&p3yBBtB&+XVy*AV{R zYku<x9q|r$!0-A2?s>N7yDoCV8f5c^giSR!4xF$a#rYrsYu^jHksk*2ICA|S?u0hf z)pI%+N1+FZ<ikkbfZ}JL{_e9AFirW-L1HHOvrq5&6ziXd3G4sf>2KQN{bAdU;9YB7 z8?GpJLeKR)z}xRdcHnfJ{5i?TGQWrR{%5|6cJ=;e_Bj0gbNGk7|5whu{Q`aey+!6O zk0%$FS|{5}FE2J)>8}EusJ^mc&%giTZr<VG{0GNK|8z|DZofJIQ;YQ7?#icni>#(& z<eRMi_Efifirnsh{z)f%64_6px4gy6o%OlPmt*wux%oFY7bEYbxchqRjm7iN*?s&5 z>Yuyt+1~8Ng{4y$f(z?&H57f8Bof>8a{QSEYl)(40m{9g)~m;%<Hb-i(#N6W1hqKo z1<3D08_IvFAE((q&NWw>tB~;o=4NKG`RWWwTa(YqbTKV7mv_T_Ut0JdG=DnePy57s zP(KZ>_x<I4v_2ZGp9c5$|NbA*e}BMUX4m)F{e!pv$yoBITl>zuFfxC-Bl4%?>ytnI zm-6zb%lWtMtE{2Mv*<$#y@7n(ILWF9^#U`hm<_9`HWa;GmsBf+oKj*fH+y+a$zG1e zm%TitmXf{v8zP;0nsRYH-k65ccyL0y5WYE`K`oXD@d^qduqiA?HMv$onPUA`OtEel zw{0%J4AsQtdXx^U6zQ-^kq)aA>99(X4yzRDuu72*s}$+5N|6q$6zQ-^kq)aA>99(X z4yzRDuu73mkBU_W8MFG7n2n0rsF=60Q8618`;QQZ!8A)8?C4p_Yf5WPE6>DRS%G+` zp54kIV_R#j%aAe3Ze@_MGqP2$^u!_aXWfy{dfBZUXT36+3R$O>+N#q^eP5kcA)^Mv z8LDS8<51L!Q(JXfsjWJ#LRzYc&#x^L-PH-F0@4Ymw(5lAt&DK4PB`^hop5TaPB^u7 zfN+K}@vWEt4J<dx{xSW3PcHk4c#SJYTg0<r^Sip-)8XZ|SexT0Z3+~J7vJJNdD$g? zr@+Jt6wIq{v7T6gi4~Yw!4vcHTkJVk!P7-Do~|;UtBl|(Be=>4ZcR>}u2b2S`34dR ztL*8S2%E?^QO!hk6Lm}!nJ6|<&vYEq@l3}zoxpTzrW2Y@$8;joiA|?xVq{{+#IA`w zn8iPQ<v$vS4CP%EN_xtBddhox3SB+rJw0W1JcW{;GJ>y+;435e3MG97rmw&Zl-U7m zfymb>HgkajGf?mhl=%o0m^B4vO@Ud%tQZ^A4<sIyeRMduSqLvBzoD=oRYs;ZFU1?H z{cvN8oEdIzY?;_Mam~ba6Ne`5nm96X&vb3mbxaqVu4lS|>DEoRW4c|_h3x6J={cr{ zP0uqu-}Gt|{)9W>O@QGy@$QfP2Uv%4X*iBHlL|<^<1fM6IAQpmQlt)XGVwM}dVa^r z#O@pgrlUY{IC*)`nvAB>5i4k71teAm$4Z)g&L9lFtAKQUc{Js9JY_Ub0Roxo@kGx= zwuz95922=Fg0&WyC^S*mbZpZ>6R@hV>A0p-H=XVT%%g2$JOPs#n7CtNa5kBX|Kfj_ zRR&qnL0+5?^SW|4X7%N8k6m4xU-`eg{NFvB6)lX|r8fb~0hz9Ay1wbwOgEf>#gScQ zfF)OV++Gbz4)7bWLBiyw?%Gar1Gb#FfnPlrr!Dd`k^BsJ7{xQliKT8Bp|k}f7+gTZ z4o)$^Zm*l5g9GfQ(42bB7tc7jS932-d90WZQ&xR`Vb#`e-2%S@`S+9j|E`q(zZb#m z*brPl?mtog&l4r$Sp{@nM63?h_?y$n@kIdukCy=SMgD(Q^xOmIbXo#1c0pxNUIQLU zs=tpJdy@bEys><3js+(E0*(dTLdOE&d#`(SY<>Ix{_H=9V}UPCM9i;t%rGuXezl{= zjEV1kK>cXhezjx9ZEya`0|$>DJan)k+ku#^lvq{@TxA=v<*mXu4D0vz{E6|vh`NNS zUrjjJ+|t3uDl6SQ4mRPOluC#e^k*Ril|5NWPnWOfE_mbM54I0!J;N!G&z+IflSS9} zfOFDKm%Jk_`J2Ms_BG)X)XSg<pP(OrQ!}lxh&<U%d1VDsMiEf1nNqp}Z%tR=?eh~G za2i9m0L(mln0fXv^Xy^f*~84UhnZ&&GtVAoo;}Pwd(3U;GS8mNJbNzl?77Ud=khMh zv*$A1%w?mxY*d$xdY#HZQZo2;x;@>x$|BV1E~`PpH)O)Q8Ogp+Uw0kyR%TZFy6aGV zR(Bn$&+1OCSROafomy(E?sHXJb)PG5WjF`An^kSq-K=Fb$Z=JJe2gA!>}*7v^P3l@ z^f~IdvcprKBS&u3rwGf9x+7d^)R|dn)OlHH)LGdDKhA6S_(nzXuPN>*UvVY*iU-P9 zoK9uEKj!ASVz-Xz*AutM&F0x*#y%Ja#IwV0T+ekyJ-9Oe|B0EiQ1?%Ye@{{|=0uo^ zy#DYReEPvo#-{_KUzz_O^4y6C@4=w&GXFoVA6CiAoV2^>?lS*>R<e)+Up9zPaOvxW zk}I#AD`{AHng3tfTFU(Yq&{Kt!2~Mv|0~SVhooc!pQ~hi_eY}(%KZPFTxI_MOr0So zzfY32MrdS(68#kWiiryTGXH;>{~ykdQ)xfaNK(EKzR~ml^Yee{{9QUZ@2$t%@R3`8 zI_%VI*r|^{06?7o2jcwSn`Ebl7sE@_K0E)1$b-p^_|5HU<ZH);5j4RcmX8YqyMv?j zEHIGH0>^y(Um@rJ$BfgvKBxa*-+ntir#Jp5JEwo&FkU;Ke*cntPXE4PKG`}rj&u4u z?!EnKh<@W|@L^3H#@pgY#yP!c^286nJh?AV?#q+=>4?fNKlz&HI-cCWE20V{;ZB6B zlOR`vz^XK=;Oc{}24V`lR1nK?Sl<+w`CRO?sIQUVK<Rsd2n7?NBM}Q7QT77A7jyzC zbcF2<16cYgmaxMl(PCxf!>t+lV7|8ZM0r}pqK<ixF%K@rA9fJ(N9MGODXMUE<z~kY z=!d4|`TsQk?nFOp?kTYkI^B3Hk6+N^CX{DudfbHCs>e<A9+kc}tm$X+$Y#w9>6(5h zk63K%H2=~?J>S<y>L9gUAFDk7kEeK0jS_#Xd?phpK?H&FbxNQF9|Q^z<*S^UBZoBC z@1`FpiLeZ$-tzA<9Lz+fQ|H%^Upwpr4Bm`y6p701f64w%?EfJB0H6c$r`WAW<F=qH z!v3!b`yVuC`Zau}{SU@GBqZIM7CIk%KQd_lqqy5m6*@Ul!ML$!_J3p7_W$?(Ubg@L zfZG34;7izz{SW=k<<>)EvH#z{{YS<_S8M+ZM*#awfCYIX7V?Ss9SiwHEaVfhkWa)y zJ`oG~L@eYJv5-&1LOu}-G({}X6tO^4!~#tb3p7PN5rz(d^PTn0?i;`(gpq>8){!lp zGDn7zBSX-x4B@X!#-a~doJJ-=>Bt!~ZsZXD(h+cVj(}ek?h0v_WV@93J|jc8=>Cf0 zzH8>6AfLJfbT1q5R|M(yCcC#wf5olpuh{nsrN5%|SJ*bXn(wCN=vuB=6MqG%nIn7_ zW&A(SMpN4VG{i#iMH&AOUukeV|K_y+h1CQ{?1}wflkESf)5TuBH*O0$vH$DB{s)6i zxBsCCnFs&?YhHB#FrlR!`UKc<<Mb`+(uvNP(P#Gm+^+5azx~?JN$3CXGy5OD(|_&N z;^+TU#|-mdwhoQM{=f6m$4){1B5uH6>G^+R|BD~&Gs)5sFkODjpXTN$zvZ7UBLY~U zOy}l{2)Icc0STJYuD)x3MR8xd<gcJx?|{FemhQ%~JHGT++_L_P!==BX^jD12Uy(R3 zT<MfPD9``3e5Z<`UVi@{b|9lkdH(;#bVstk6Z^lO+W%eLtzkbzV>X~GiTxi6`@cr* ze;$e&viyGm<OyRR0ED{zpOG&N(m=ZPRO5h0l8DYRqfhMrFBxBC_WKtMV_CA_r@mmA zUwL<Uo;_&agIb?FI0bq39>2OgdmlS+=l?N2Iez<H81gLZQEAARhJ2ZnZ)5s~2<`u> zIFTM2+OI_R^QtCSkxq5MrjsOWX~%DFZcjVIKSq-b<Xs);-z0W?!i<s<p}HHOEJXU5 ziOP&u;@cm^jIz7GbTHhS4u;#e?)pVzs!Ux8F|<=Y3#If~D5W2k87#{TmQqBAnuStN z`lo({qJN2@KC6F;p+2j7V$>{@`j;4LtNwk2+NysYp~k4_A7ZGjdV0h%gXM>n!BYLg zMW3ZkUCvXfx89H$F8d$fZ#@1H&v2=J@FD_T#P!Dg;KlTlA|W?jHIu}#4LL94<i>?s z(+kUo?ITHcxU5urIcalvww&uzPQGAu_cH%qGQ(1Otup_gL<}X}&T4a^F|amB=VEJN zC|8#G|MVnVW&Xc1|6l7c$q}59)$dYR=Kt$g4_Eu~I!S_f<iMUihboWnKQY^C%&ayl z&BeLK`AT*9?D6>~;i80GW&Xc1|KC6o?`<V3H*#v3OHNMsOLwbBMlc*xAdriyWM51f zk^K8syuH1)abXMCm+KjXeIKn<_W!`-{5v}{d#W*4S)DmP-%y_pH`YEMlKPz0!+XhT zYc(hFIEmIslj%90cSPT3!pl$^w6FEa5IIr2)$OlcqGMO2tjERDJQh<Al5DRjIvGjQ z6@}y`$^R#vzbEJap>+P=32Qj$UAy!DjyV4h<@kSo{-2%^boBH8tOS6r7oqh0A0D}u z=l{oy6T6Q8|G^)~@&A9w;s@SW<NtHx2O$67AAkJevBVGjmpgxCJbVq~2SgwNb3T`W z1Z5yW8AwnD67a78%0Pl^pBdmL2_*RUBC2I*Ab}i5z>~P}pq5leDE^J06qiADhJm<( zFjXVuxPl~~hNLx-fCnkDCVa6t5b<yo(Tt-olLH*fh=*G<;=$~H?BABhPY{MR<=lAr z);==FPiYd%EwJ#X%kzJp4I<FvCX`H)fgU%Zw(4;cy!FG%V9E3UN%nVQ|92$&A9Xz6 z?qTB68S9_O|JN1ve`loq-_`8@9&G#Yr+)wM)ge7c@)q#OwYC3ec5VOvzrT^~|Nlnq z|L5Ra0{Q#@Jo_K|oB!N;WE}SY-tB!&<B<=;{uhpbPFXCVEEZ4}3%HSr1tdY-<rf8U zM04-aIx+)>my{nzt`(42*f(~Hzy!@3J2OD(2%u^Wq+d%NrR=lD0e+NR6tW{Ap`fJL zso!MC4hrr{xr*Z!h8JBoRQ(#jvy*CM@`+68u()L%7N0iCc-hin;Y38#At&zINs#Wi zvRHEKP_DXB#{X*>EV=zJ+24}ooYep823_Q%o;Oz8p8yl~e<bYx?nwJT((V7O{C|FA zyXkHNk6c^(|JbhW|DSyO9V!3ce`WUnv0d8#$Bf&Kyz}Td?EigF?S062^h34(g(IL_ zIs!^ZK<Nl59RbnI_PMx>2-tO<TgmSFD5e%j%-Av_AjzTn(R2hPGc9SNyLVU=KOd47 z4%HV292QayDftMgbXeS~4vV|jN{2-mVR6?rby%by_<qRe|C0Tk*#D7q{vUNC-{}S8 HxBve?VHgp- diff --git a/data-providers/src/main/java/datart/data/provider/calcite/SqlFunctionRegisterVisitor.java b/data-providers/src/main/java/datart/data/provider/calcite/SqlFunctionRegisterVisitor.java index e37c0d231..aae4682e0 100644 --- a/data-providers/src/main/java/datart/data/provider/calcite/SqlFunctionRegisterVisitor.java +++ b/data-providers/src/main/java/datart/data/provider/calcite/SqlFunctionRegisterVisitor.java @@ -18,11 +18,12 @@ package datart.data.provider.calcite; -import org.apache.calcite.sql.SqlCall; -import org.apache.calcite.sql.SqlFunction; -import org.apache.calcite.sql.SqlOperator; +import org.apache.calcite.sql.*; import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.util.SqlBasicVisitor; +import org.apache.calcite.sql.validate.SqlNameMatchers; + +import java.util.LinkedList; public class SqlFunctionRegisterVisitor extends SqlBasicVisitor<Object> { @@ -30,13 +31,20 @@ public class SqlFunctionRegisterVisitor extends SqlBasicVisitor<Object> { public Object visit(SqlCall call) { SqlOperator operator = call.getOperator(); if (operator instanceof SqlFunction) { - registerIfNotExists(operator); + registerIfNotExists((SqlFunction) operator); } return operator.acceptCall(this, call); } - private void registerIfNotExists(SqlOperator sqlFunction) { - SqlStdOperatorTable.instance().register(sqlFunction); + private void registerIfNotExists(SqlFunction sqlFunction) { + SqlStdOperatorTable opTab = SqlStdOperatorTable.instance(); + LinkedList<SqlOperator> list = new LinkedList<>(); + opTab.lookupOperatorOverloads(sqlFunction.getSqlIdentifier(), null, SqlSyntax.FUNCTION, list, + SqlNameMatchers.withCaseSensitive(sqlFunction.getSqlIdentifier().isComponentQuoted(0))); + if (list.size() > 0) { + return; + } + opTab.register(sqlFunction); } } diff --git a/pom.xml b/pom.xml index 0288f8071..1e53fb234 100644 --- a/pom.xml +++ b/pom.xml @@ -74,6 +74,13 @@ <build> <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <parameters>true</parameters> + </configuration> + </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>versions-maven-plugin</artifactId> diff --git a/server/pom.xml b/server/pom.xml index f48f43471..85f1bf95d 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -300,6 +300,26 @@ </execution> </executions> </plugin> + + <plugin> + <groupId>com.coderplus.maven.plugins</groupId> + <artifactId>copy-rename-maven-plugin</artifactId> + <version>1.0.1</version> + <executions> + <execution> + <id>rename-file</id> + <phase>compile</phase> + <goals> + <goal>rename</goal> + </goals> + <configuration> + <sourceFile>${project.parent.basedir}/frontend/build/task/index.js</sourceFile> + <destinationFile>${project.basedir}/src/main/resources/javascript/parser.js</destinationFile> + </configuration> + </execution> + </executions> + </plugin> + </plugins> </build> From 369e76256a9878b73d21360ed79f4678182ffb25 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Thu, 30 Dec 2021 14:17:58 +0800 Subject: [PATCH 286/348] chore: view page i18n support --- .../FormGenerator/Basic/BasicFont.tsx | 8 +- .../Basic/BasicFontFamilySelector.tsx | 2 +- .../Basic/BasicFontSizeSelector.tsx | 2 +- .../FormGenerator/Basic/BasicLine.tsx | 4 +- .../FormGenerator/Basic/BasicSelector.tsx | 2 +- .../Customize/ListTemplatePanel.tsx | 2 +- .../ChartTimeSelector/ExactTimeSelector.tsx | 2 +- .../MainPage/pages/ViewPage/Container.tsx | 11 +- .../pages/ViewPage/Main/Editor/SQLEditor.tsx | 10 +- .../pages/ViewPage/Main/Editor/Toolbar.tsx | 23 ++-- .../pages/ViewPage/Main/Outputs/Error.tsx | 4 +- .../pages/ViewPage/Main/Outputs/Results.tsx | 10 +- .../Main/Properties/ColumnPermissions.tsx | 14 ++- .../ViewPage/Main/Properties/Resource.tsx | 6 +- .../ViewPage/Main/Properties/Variables.tsx | 19 +-- .../ViewPage/Main/Properties/VerticalTabs.tsx | 54 ++++++--- .../pages/ViewPage/Main/Properties/index.tsx | 12 +- .../MainPage/pages/ViewPage/Main/Tabs.tsx | 10 +- .../MainPage/pages/ViewPage/Main/index.tsx | 4 +- .../MainPage/pages/ViewPage/SaveForm.tsx | 30 ++--- .../pages/ViewPage/SaveFormContext.ts | 4 +- .../pages/ViewPage/Sidebar/FolderTree.tsx | 39 ++++--- .../pages/ViewPage/Sidebar/Recycle.tsx | 24 ++-- .../MainPage/pages/ViewPage/Sidebar/index.tsx | 18 +-- .../pages/ViewPage/components/SchemaTable.tsx | 22 ++-- .../MainPage/pages/ViewPage/constants.ts | 19 --- .../MainPage/pages/ViewPage/slice/thunks.ts | 5 +- .../src/app/pages/SharePage/PasswordModal.tsx | 2 +- frontend/src/locales/en/translation.json | 110 ++++++++++++++++-- frontend/src/locales/zh/translation.json | 98 +++++++++++++++- 30 files changed, 400 insertions(+), 170 deletions(-) diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicFont.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicFont.tsx index c69f59536..8de5a8055 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicFont.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicFont.tsx @@ -50,7 +50,7 @@ const BasicFont: FC<ItemLayoutProps<ChartStyleSectionConfig>> = memo( <BW label={!options?.hideLabel ? t(data.label) : ''}> <Group> <Select - placeholder={t('pleaseSelect')} + placeholder={t('select')} value={data.value?.fontFamily} dropdownMatchSelectWidth={false} onChange={handleSettingChange('fontFamily')} @@ -65,7 +65,7 @@ const BasicFont: FC<ItemLayoutProps<ChartStyleSectionConfig>> = memo( ))} </Select> <Select - placeholder={t('pleaseSelect')} + placeholder={t('select')} value={data.value?.fontWeight} onChange={handleSettingChange('fontWeight')} > @@ -79,7 +79,7 @@ const BasicFont: FC<ItemLayoutProps<ChartStyleSectionConfig>> = memo( <WithColorPicker> <Group> <Select - placeholder={t('pleaseSelect')} + placeholder={t('select')} value={data.value?.fontSize} onChange={handleSettingChange('fontSize')} > @@ -90,7 +90,7 @@ const BasicFont: FC<ItemLayoutProps<ChartStyleSectionConfig>> = memo( ))} </Select> <Select - placeholder={t('pleaseSelect')} + placeholder={t('select')} value={data.value?.fontStyle} onChange={handleSettingChange('fontStyle')} > diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicFontFamilySelector.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicFontFamilySelector.tsx index 93f8aa196..68ffccaf0 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicFontFamilySelector.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicFontFamilySelector.tsx @@ -36,7 +36,7 @@ const BasicFontFamilySelector: FC<ItemLayoutProps<ChartStyleSectionConfig>> = dropdownMatchSelectWidth {...rest} {...options} - placeholder={t('pleaseSelect')} + placeholder={t('select')} onChange={value => onChange?.(ancestors, value)} > {FONT_FAMILIES.map(o => ( diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicFontSizeSelector.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicFontSizeSelector.tsx index af2f01278..36994b514 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicFontSizeSelector.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicFontSizeSelector.tsx @@ -36,7 +36,7 @@ const BasicFontSizeSelector: FC<ItemLayoutProps<ChartStyleSectionConfig>> = dropdownMatchSelectWidth {...rest} {...options} - placeholder={t('pleaseSelect')} + placeholder={t('select')} onChange={value => onChange?.(ancestors, value)} > {FONT_SIZES.map(o => ( diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicLine.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicLine.tsx index 63544b932..8540bf3f4 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicLine.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicLine.tsx @@ -47,7 +47,7 @@ const BasicLine: FC<ItemLayoutProps<ChartStyleSectionConfig>> = memo( <Group> <Select dropdownMatchSelectWidth - placeholder={t('pleaseSelect')} + placeholder={t('select')} value={data.value?.type} onChange={handleSettingChange('type')} bordered={false} @@ -59,7 +59,7 @@ const BasicLine: FC<ItemLayoutProps<ChartStyleSectionConfig>> = memo( ))} </Select> <Select - placeholder={t('pleaseSelect')} + placeholder={t('select')} value={data.value?.width} onChange={handleSettingChange('width')} bordered={false} diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx index d45ce9da7..f4582d9c7 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx @@ -73,7 +73,7 @@ const BasicSelector: FC<ItemLayoutProps<ChartStyleSectionConfig>> = memo( {...rest} {...options} defaultValue={rest.default} - placeholder={t('pleaseSelect')} + placeholder={t('select')} onChange={handleSelectorValueChange} > {safeInvokeAction()?.map((o, index) => { diff --git a/frontend/src/app/components/FormGenerator/Customize/ListTemplatePanel.tsx b/frontend/src/app/components/FormGenerator/Customize/ListTemplatePanel.tsx index 86f3f9fb0..451b90fb4 100644 --- a/frontend/src/app/components/FormGenerator/Customize/ListTemplatePanel.tsx +++ b/frontend/src/app/components/FormGenerator/Customize/ListTemplatePanel.tsx @@ -147,7 +147,7 @@ const ListTemplatePanel: FC<ItemLayoutProps<ChartStyleSectionConfig>> = memo( <Col span={8}> <Select dropdownMatchSelectWidth - placeholder={t('pleaseSelect')} + placeholder={t('select')} value={currentSelectedItem?.label} onChange={handleColumnChange} > diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ExactTimeSelector.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ExactTimeSelector.tsx index 7d04187c4..49a649d8f 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ExactTimeSelector.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTimeSelector/ExactTimeSelector.tsx @@ -42,7 +42,7 @@ const ExactTimeSelector: FC< showTime value={moment(time as string)} onChange={handleMomentTimeChange} - placeholder={t('pleaseSelect')} + placeholder={t('select')} /> ); }); diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Container.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Container.tsx index 4cca642df..96584eb77 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Container.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Container.tsx @@ -17,6 +17,7 @@ */ import { Split } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { useSplitSizes } from 'app/hooks/useSplitSizes'; import React, { useCallback, useContext } from 'react'; import styled from 'styled-components/macro'; @@ -27,6 +28,8 @@ import { Sidebar } from './Sidebar'; export function Container() { const { editorInstance } = useContext(EditorContext); + const t = useI18NPrefix('view.saveForm'); + const tg = useI18NPrefix('global'); const editorResize = useCallback(() => { editorInstance?.layout(); @@ -57,13 +60,13 @@ export function Container() { <Sidebar /> <Main /> <SaveForm - title="数据视图" + title={t('title')} formProps={{ labelAlign: 'left', - labelCol: { offset: 1, span: 6 }, - wrapperCol: { span: 15 }, + labelCol: { offset: 1, span: 8 }, + wrapperCol: { span: 13 }, }} - okText="保存" + okText={tg('button.save')} /> </StyledContainer> ); diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/SQLEditor.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/SQLEditor.tsx index fba374530..2089dca5c 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/SQLEditor.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/SQLEditor.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import classnames from 'classnames'; import { CommonFormTypes } from 'globalConstants'; import debounce from 'lodash/debounce'; @@ -77,6 +78,7 @@ export const SQLEditor = memo(() => { ) as ViewStatus; const theme = useSelector(selectThemeKey); const viewsData = useSelector(selectViews); + const t = useI18NPrefix('view.editor'); const run = useCallback(() => { const fragment = editorInstance @@ -101,7 +103,7 @@ export const SQLEditor = memo(() => { showSaveForm({ type: CommonFormTypes.Edit, visible: true, - parentIdLabel: '目录', + parentIdLabel: t('folder'), onSave: (values, onClose) => { let index = getInsertedNodeIndex(values, viewsData); @@ -119,7 +121,7 @@ export const SQLEditor = memo(() => { save(); } } - }, [dispatch, actions, stage, status, id, save, showSaveForm, viewsData]); + }, [dispatch, actions, stage, status, id, save, showSaveForm, viewsData, t]); const editorWillMount = useCallback( editor => { @@ -162,12 +164,12 @@ export const SQLEditor = memo(() => { }); editor.onDidAttemptReadOnlyEdit(() => { (messageContribution as any).showMessage( - '回收站中不可编辑', + t('readonlyTip'), editor.getPosition(), ); }); }, - [setEditor, dispatch, actions], + [setEditor, dispatch, actions, t], ); useEffect(() => { diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/Toolbar.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/Toolbar.tsx index f5d230d13..98f2bc8dd 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/Toolbar.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Editor/Toolbar.tsx @@ -27,6 +27,7 @@ import { import { Divider, Dropdown, Menu, Select, Space, Tooltip } from 'antd'; import { ToolbarButton } from 'app/components'; import { Chronograph } from 'app/components/Chronograph'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { CommonFormTypes } from 'globalConstants'; import React, { memo, useCallback, useContext } from 'react'; import { useDispatch, useSelector } from 'react-redux'; @@ -104,6 +105,7 @@ export const Toolbar = memo(({ allowManage }: ToolbarProps) => { selectCurrentEditingViewAttr(state, { name: 'index' }), ) as number; const viewsData = useSelector(selectViews); + const t = useI18NPrefix('view.editor'); const isArchived = status === ViewStatus.Archived; @@ -124,7 +126,7 @@ export const Toolbar = memo(({ allowManage }: ToolbarProps) => { parentId, config, }, - parentIdLabel: '目录', + parentIdLabel: t('folder'), onSave: (values, onClose) => { let index = ViewIndex; @@ -151,6 +153,7 @@ export const Toolbar = memo(({ allowManage }: ToolbarProps) => { config, viewsData, ViewIndex, + t, ]); const sourceChange = useCallback( @@ -173,7 +176,7 @@ export const Toolbar = memo(({ allowManage }: ToolbarProps) => { <Space split={<Divider type="vertical" className="divider" />}> {allowManage && ( <Select - placeholder="请选择数据源" + placeholder={t('source')} value={sourceId} bordered={false} disabled={isArchived} @@ -192,9 +195,9 @@ export const Toolbar = memo(({ allowManage }: ToolbarProps) => { title={ <TipTitle title={[ - `${fragment ? '执行片段' : '执行'}`, - 'Win: [Ctrl + Enter]', - 'Mac: [Command + Enter]', + `${fragment ? t('runSelection') : t('run')}`, + t('runWinTip'), + t('runMacTip'), ]} /> } @@ -212,7 +215,7 @@ export const Toolbar = memo(({ allowManage }: ToolbarProps) => { onClick={onRun} /> </Tooltip> - <Tooltip title="美化" placement="bottom"> + <Tooltip title={t('beautify')} placement="bottom"> <ToolbarButton icon={<AlignCenterOutlined />} disabled={isArchived} @@ -252,7 +255,7 @@ export const Toolbar = memo(({ allowManage }: ToolbarProps) => { <Tooltip title={ <TipTitle - title={['保存', 'Win: [Ctrl + S]', 'Mac: [Command + S]']} + title={[t('save'), t('saveWinTip'), t('saveMacTip')]} /> } placement="bottom" @@ -265,7 +268,7 @@ export const Toolbar = memo(({ allowManage }: ToolbarProps) => { /> </Tooltip> {!isNewView(id) && ( - <Tooltip title="详情设置" placement="bottom"> + <Tooltip title={t('info')} placement="bottom"> <ToolbarButton icon={<SettingFilled />} disabled={isArchived} @@ -274,13 +277,13 @@ export const Toolbar = memo(({ allowManage }: ToolbarProps) => { /> </Tooltip> )} - <Tooltip title="另存为" placement="bottom"> + <Tooltip title={t('saveAs')} placement="bottom"> <ToolbarButton icon={<CopyFilled />} disabled={stage !== ViewViewModelStages.Saveable} /> </Tooltip> - {/* <Tooltip title="保存片段" placement="bottom"> + {/* <Tooltip title={t('saveFragment')} placement="bottom"> <ToolbarButton icon={<SnippetsFilled />} /> </Tooltip> */} </Space> diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Error.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Error.tsx index 8120deb6d..1d303814a 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Error.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Error.tsx @@ -17,6 +17,7 @@ */ import { InfoCircleOutlined } from '@ant-design/icons'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { memo } from 'react'; import { useSelector } from 'react-redux'; import styled from 'styled-components/macro'; @@ -33,12 +34,13 @@ export const Error = memo(() => { const error = useSelector(state => selectCurrentEditingViewAttr(state, { name: 'error' }), ) as string; + const t = useI18NPrefix('view'); return ( <Wrapper> <h3> <InfoCircleOutlined className="icon" /> - 执行错误 + {t('errorTitle')} </h3> <p>{error}</p> </Wrapper> diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx index 3da0fe1f6..855cbb2f9 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Outputs/Results.tsx @@ -23,6 +23,7 @@ import { } from '@ant-design/icons'; import { Tooltip } from 'antd'; import { Popup, ToolbarButton, Tree } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import classnames from 'classnames'; import { memo, useCallback, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; @@ -68,6 +69,7 @@ export const Results = memo(({ height = 0, width = 0 }: ResultsProps) => { selectCurrentEditingViewAttr(state, { name: 'previewResults' }), ) as ViewViewModel['previewResults']; const roles = useSelector(selectRoles); + const t = useI18NPrefix('view'); const dataSource = useMemo( () => previewResults.map(o => ({ ...o, [ROW_KEY]: uuidv4() })), @@ -193,7 +195,7 @@ export const Results = memo(({ height = 0, width = 0 }: ResultsProps) => { /> } > - <Tooltip title="列权限"> + <Tooltip title={t('columnPermission.title')}> <ToolbarButton size="small" iconSize={FONT_SIZE_BASE} @@ -213,7 +215,7 @@ export const Results = memo(({ height = 0, width = 0 }: ResultsProps) => { </Popup>, ]; }, - [columnPermissions, roleDropdownData, checkRoleColumnPermission], + [columnPermissions, roleDropdownData, checkRoleColumnPermission, t], ); const pagination = useMemo( @@ -240,7 +242,9 @@ export const Results = memo(({ height = 0, width = 0 }: ResultsProps) => { ) : ( <InitialDesc> <p> - 请点击 <CaretRightOutlined /> 按钮执行,运行结果将在此处展示 + {t('resultEmpty1')} + <CaretRightOutlined /> + {t('resultEmpty2')} </p> </InitialDesc> ); diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx index 97ccbe8d4..fba3584cb 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/ColumnPermissions.tsx @@ -20,6 +20,7 @@ import { LoadingOutlined, SearchOutlined } from '@ant-design/icons'; import { Button, Col, Input, List, Row } from 'antd'; import { ListItem, ListTitle, Popup, Tree } from 'app/components'; import { useDebouncedSearch } from 'app/hooks/useDebouncedSearch'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import classnames from 'classnames'; import { memo, useCallback, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; @@ -57,6 +58,7 @@ export const ColumnPermissions = memo(() => { selectCurrentEditingViewAttr(state, { name: 'columnPermissions' }), ) as ColumnPermission[]; const roles = useSelector(selectRoles); + const t = useI18NPrefix('view.columnPermission'); const { filteredData, debouncedSearch } = useDebouncedSearch( roles, @@ -153,9 +155,9 @@ export const ColumnPermissions = memo(() => { > {permission ? checkedKeys.length > 0 - ? '部分字段' - : '不可见' - : '全部字段'} + ? t('partial') + : t('none') + : t('all')} </Button> </Popup>, ]} @@ -164,17 +166,17 @@ export const ColumnPermissions = memo(() => { </ListItem> ); }, - [columnDropdownData, columnPermissions, checkColumnPermission, status], + [columnDropdownData, columnPermissions, checkColumnPermission, status, t], ); return ( <Container> - <ListTitle title="列权限" /> + <ListTitle title={t('title')} /> <Searchbar> <Col span={24}> <Input prefix={<SearchOutlined className="icon" />} - placeholder="搜索角色关键字" + placeholder={t('search')} className="input" bordered={false} onChange={debouncedSearch} diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx index 79cc2d0e9..9e0adc902 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Resource.tsx @@ -26,6 +26,7 @@ import { } from '@ant-design/icons'; import { Col, Input, Row } from 'antd'; import { ListTitle, Tree } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { useSearchAndExpand } from 'app/hooks/useSearchAndExpand'; import { selectDataProviderDatabaseListLoading } from 'app/pages/MainPage/slice/selectors'; import { getDataProviderDatabases } from 'app/pages/MainPage/slice/thunks'; @@ -61,6 +62,7 @@ export const Resource = memo(() => { const databaseListLoading = useSelector( selectDataProviderDatabaseListLoading, ); + const t = useI18NPrefix('view.resource'); const { filteredData, onExpand, debouncedSearch, expandedRowKeys } = useSearchAndExpand( @@ -161,12 +163,12 @@ export const Resource = memo(() => { return ( <Container> - <ListTitle title="数据源信息" /> + <ListTitle title={t('title')} /> <Searchbar> <Col span={24}> <Input prefix={<SearchOutlined className="icon" />} - placeholder="搜索数据库 / 表 / 字段关键字" + placeholder={t('search')} className="input" bordered={false} onChange={debouncedSearch} diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx index 3f1bfc9db..a160ceeb0 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx @@ -26,6 +26,7 @@ import { } from '@ant-design/icons'; import { Button, List, Popconfirm } from 'antd'; import { ListItem, ListTitle } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { getRoles } from 'app/pages/MainPage/pages/MemberPage/slice/thunks'; import { DEFAULT_VALUE_DATE_FORMAT, @@ -89,6 +90,8 @@ export const Variables = memo(() => { ) as string; const orgId = useSelector(selectOrgId); const publicVariables = useSelector(selectVariables); + const t = useI18NPrefix('view.variable'); + const tg = useI18NPrefix('global'); useEffect(() => { if (editorCompletionItemProviderRef) { @@ -282,25 +285,25 @@ export const Variables = memo(() => { : variables.some(v => v.name === item.name); return ( <ListItemTitle className={classnames({ duplicate: isDuplicate })}> - {!isPrivate && <span className="prefix">[公共]</span>} + {!isPrivate && <span className="prefix">{t('prefix')}</span>} {item.name} - {isDuplicate && <span className="suffix">重复</span>} + {isDuplicate && <span className="suffix">{t('suffix')}</span>} </ListItemTitle> ); }, - [variables, publicVariables], + [variables, publicVariables, t], ); const titleProps = useMemo( () => ({ - title: '变量配置', + title: t('title'), search: true, add: { - items: [{ key: 'variable', text: '新建变量' }], + items: [{ key: 'variable', text: t('add') }], callback: showAddForm, }, }), - [showAddForm], + [showAddForm, t], ); return ( @@ -327,7 +330,7 @@ export const Variables = memo(() => { />, <Popconfirm key="del" - title="确认删除?" + title={tg('operation.deleteConfirm')} placement="bottom" onConfirm={del(item.id)} > @@ -373,7 +376,7 @@ export const Variables = memo(() => { editingVariable={editingVariable} variables={variables} visible={formVisible} - title="变量" + title={t('formTitle')} type={formType} onSave={save} onCancel={hideForm} diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/VerticalTabs.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/VerticalTabs.tsx index 5c1963696..4cebd1c2b 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/VerticalTabs.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/VerticalTabs.tsx @@ -18,13 +18,16 @@ import classnames from 'classnames'; import { cloneElement, memo, ReactElement, useCallback, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import styled from 'styled-components/macro'; import { FONT_SIZE_TITLE, FONT_WEIGHT_MEDIUM, + FONT_WEIGHT_REGULAR, SPACE, SPACE_XS, } from 'styles/StyleConstants'; +import { getTextWidth } from 'utils/utils'; interface TabProps { name: string; @@ -39,6 +42,7 @@ interface VerticalTabsProps { export const VerticalTabs = memo(({ tabs, onSelect }: VerticalTabsProps) => { const [selectedTab, setSelectedTab] = useState(''); + const { i18n } = useTranslation(); const selectTab = useCallback( name => () => { @@ -51,18 +55,34 @@ export const VerticalTabs = memo(({ tabs, onSelect }: VerticalTabsProps) => { return ( <Wrapper> - {tabs.map(({ name, title, icon }) => ( - <Tab - key={name} - className={classnames({ selected: selectedTab === name })} - onClick={selectTab(name)} - > - {icon && <Word className="icon">{cloneElement(icon)}</Word>} - {title.split('').map((s, index) => ( - <Word key={index}>{s}</Word> - ))} - </Tab> - ))} + {tabs.map(({ name, title, icon }) => { + const rotate = ['en'].includes(i18n.language) ? '90deg' : '0'; + return ( + <Tab + key={name} + className={classnames({ selected: selectedTab === name })} + onClick={selectTab(name)} + > + {icon && ( + <Word rotate={rotate} className="icon"> + {cloneElement(icon)} + </Word> + )} + {title.split('').map((s, index) => { + const wordHeight = getTextWidth( + s, + String(FONT_WEIGHT_REGULAR), + FONT_SIZE_TITLE, + ); + return ( + <Word key={index} rotate={rotate} height={wordHeight}> + {s} + </Word> + ); + })} + </Tab> + ); + })} </Wrapper> ); }); @@ -97,12 +117,14 @@ const Tab = styled.li` } `; -const Word = styled.span` +const Word = styled.span<{ rotate: string; height?: number }>` display: block; width: ${FONT_SIZE_TITLE}; - height: ${FONT_SIZE_TITLE}; - line-height: ${FONT_SIZE_TITLE}; - /* transform: rotate(90deg); */ + height: ${p => (p.height ? `${p.height}px` : FONT_SIZE_TITLE)}; + line-height: ${p => (p.height ? `${p.height}px` : FONT_SIZE_TITLE)}; + font-size: ${FONT_SIZE_TITLE}; + text-align: center; + transform: ${p => `rotate(${p.rotate})`}; &.icon { margin-bottom: ${SPACE}; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/index.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/index.tsx index ca9d447c7..3a84c12a7 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/index.tsx @@ -22,6 +22,7 @@ import { SafetyCertificateOutlined, } from '@ant-design/icons'; import { PaneWrapper } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { memo, useCallback, @@ -44,6 +45,7 @@ interface PropertiesProps { export const Properties = memo(({ allowManage }: PropertiesProps) => { const [selectedTab, setSelectedTab] = useState(''); const { editorInstance } = useContext(EditorContext); + const t = useI18NPrefix('view.properties'); useEffect(() => { editorInstance?.layout(); @@ -51,15 +53,15 @@ export const Properties = memo(({ allowManage }: PropertiesProps) => { const tabTitle = useMemo( () => [ - { name: 'resource', title: '数据源信息', icon: <DatabaseOutlined /> }, - { name: 'variable', title: '变量配置', icon: <FunctionOutlined /> }, + { name: 'reference', title: t('reference'), icon: <DatabaseOutlined /> }, + { name: 'variable', title: t('variable'), icon: <FunctionOutlined /> }, { name: 'columnPermissions', - title: '列权限', + title: t('columnPermissions'), icon: <SafetyCertificateOutlined />, }, ], - [], + [t], ); const tabSelect = useCallback(tab => { @@ -71,7 +73,7 @@ export const Properties = memo(({ allowManage }: PropertiesProps) => { <PaneWrapper selected={selectedTab === 'variable'}> <Variables /> </PaneWrapper> - <PaneWrapper selected={selectedTab === 'resource'}> + <PaneWrapper selected={selectedTab === 'reference'}> <Resource /> </PaneWrapper> <PaneWrapper selected={selectedTab === 'columnPermissions'}> diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Tabs.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Tabs.tsx index fa24ae0ed..097a0dcd5 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Tabs.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Tabs.tsx @@ -23,6 +23,7 @@ import { } from '@ant-design/icons'; import { Button, Space } from 'antd'; import { Confirm, TabPane, Tabs as TabsComponent } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import React, { memo, useCallback, useContext, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; @@ -55,6 +56,7 @@ export const Tabs = memo(() => { const id = useSelector(state => selectCurrentEditingViewAttr(state, { name: 'id' }), ) as string; + const t = useI18NPrefix('view.tabs'); const redirect = useCallback( currentEditingViewKey => { @@ -134,7 +136,7 @@ export const Tabs = memo(() => { </TabsComponent> <Confirm visible={confirmVisible} - title={`${operatingView?.name} 中有未执行的修改,是否执行?`} + title={t('warning')} icon={ <InfoCircleOutlined css={` @@ -144,10 +146,10 @@ export const Tabs = memo(() => { } footer={ <Space> - <Button onClick={removeTab}>放弃</Button> - <Button onClick={hideConfirm}>取消</Button> + <Button onClick={removeTab}>{t('discard')}</Button> + <Button onClick={hideConfirm}>{t('cancel')}</Button> <Button onClick={runTab} type="primary"> - 执行 + {t('execute')} </Button> </Space> } diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/index.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/index.tsx index 80a345aa6..2b9de72d6 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/index.tsx @@ -17,6 +17,7 @@ */ import { EmptyFiller } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { memo, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useRouteMatch } from 'react-router-dom'; @@ -41,6 +42,7 @@ export const Main = memo(() => { } = useRouteMatch<{ viewId: string }>(); const orgId = useSelector(selectOrgId); const editingViews = useSelector(selectEditingViews); + const t = useI18NPrefix('view'); useEffect(() => { dispatch(getSources(orgId)); @@ -60,7 +62,7 @@ export const Main = memo(() => { <Workbench /> </> ) : ( - <EmptyFiller title="请在左侧列表选择数据视图" /> + <EmptyFiller title={t('empty')} /> )} </Container> ); diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx index 15942c280..497432e73 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/SaveForm.tsx @@ -28,6 +28,7 @@ import { TreeSelect, } from 'antd'; import { ModalForm, ModalFormProps } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import debounce from 'debounce-promise'; import { DEFAULT_DEBOUNCE_WAIT } from 'globalConstants'; import { @@ -49,11 +50,7 @@ import { selectPermissionMap, } from '../../slice/selectors'; import { PermissionLevels, ResourceTypes } from '../PermissionPage/constants'; -import { - ConcurrencyControlModes, - CONCURRENCY_CONTROL_MODE_LABEL, - ViewViewModelStages, -} from './constants'; +import { ConcurrencyControlModes, ViewViewModelStages } from './constants'; import { SaveFormContext } from './SaveFormContext'; import { makeSelectViewFolderTree, @@ -99,6 +96,8 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { const currentEditingView = useSelector(selectCurrentEditingView); const orgId = useSelector(selectOrgId); const formRef = useRef<FormInstance>(); + const t = useI18NPrefix('view.saveForm'); + const tg = useI18NPrefix('global'); useEffect(() => { if (initialValues) { @@ -142,9 +141,12 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { > <Form.Item name="name" - label="名称" + label={t('name')} rules={[ - { required: true, message: '名称不能为空' }, + { + required: true, + message: `${t('name')}${tg('validation.required')}`, + }, { validator: debounce((_, value) => { if (!value || initialValues?.name === value) { @@ -167,7 +169,7 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { </Form.Item> <Form.Item name="parentId" label={parentIdLabel}> <TreeSelect - placeholder="根目录" + placeholder={t('root')} treeData={folderTree || []} allowClear onChange={() => { @@ -182,12 +184,12 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { icon={<DoubleRightOutlined rotate={advancedVisible ? -90 : 90} />} onClick={toggleAdvanced} > - 高级配置 + {t('advanced')} </AdvancedToggle> <AdvancedWrapper show={advancedVisible}> <Form.Item name={['config', 'concurrencyControl']} - label="并发控制" + label={t('concurrencyControl')} valuePropName="checked" initialValue={concurrencyControl} > @@ -195,20 +197,20 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { </Form.Item> <Form.Item name={['config', 'concurrencyControlMode']} - label="模式" + label={t('concurrencyControlMode')} initialValue={ConcurrencyControlModes.DirtyRead} > <Radio.Group disabled={!concurrencyControl}> {Object.values(ConcurrencyControlModes).map(value => ( <Radio key={value} value={value}> - {CONCURRENCY_CONTROL_MODE_LABEL[value]} + {t(value.toLowerCase())} </Radio> ))} </Radio.Group> </Form.Item> <Form.Item name={['config', 'cache']} - label="缓存" + label={t('cache')} valuePropName="checked" initialValue={cache} > @@ -216,7 +218,7 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { </Form.Item> <Form.Item name={['config', 'cacheExpires']} - label="失效时间" + label={t('cacheExpires')} initialValue={0} > <InputNumber disabled={!cache} /> diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/SaveFormContext.ts b/frontend/src/app/pages/MainPage/pages/ViewPage/SaveFormContext.ts index 03e073635..fd4de0dff 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/SaveFormContext.ts +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/SaveFormContext.ts @@ -16,6 +16,7 @@ * limitations under the License. */ +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { CommonFormTypes } from 'globalConstants'; import { createContext, useCallback, useMemo, useState } from 'react'; @@ -54,13 +55,14 @@ const saveFormContextValue: SaveFormContextValue = { export const SaveFormContext = createContext(saveFormContextValue); export const useSaveFormContext = (): SaveFormContextValue => { + const t = useI18NPrefix('view.saveForm'); const [type, setType] = useState(CommonFormTypes.Add); const [visible, setVisible] = useState(false); const [simple, setSimple] = useState<boolean | undefined>(false); const [initialValues, setInitialValues] = useState< undefined | SaveFormModel >(); - const [parentIdLabel, setParentIdLabel] = useState('目录'); + const [parentIdLabel, setParentIdLabel] = useState(t('folder')); const [onSave, setOnSave] = useState(() => () => {}); const [onAfterClose, setOnAfterClose] = useState(() => () => {}); diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/FolderTree.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/FolderTree.tsx index 77ffb4548..2a7b75acd 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/FolderTree.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/FolderTree.tsx @@ -19,12 +19,9 @@ import { DeleteOutlined, EditOutlined, MoreOutlined } from '@ant-design/icons'; import { Menu, message, Popconfirm, TreeDataNode } from 'antd'; import { MenuListItem, Popup, Tree, TreeTitle } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { CascadeAccess } from 'app/pages/MainPage/Access'; -import { - selectIsOrgOwner, - selectOrgId, - selectPermissionMap, -} from 'app/pages/MainPage/slice/selectors'; +import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import { CommonFormTypes } from 'globalConstants'; import React, { memo, useCallback, useContext, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; @@ -36,7 +33,6 @@ import { ResourceTypes, } from '../../PermissionPage/constants'; import { SaveFormContext } from '../SaveFormContext'; -import { useViewSlice } from '../slice'; import { selectCurrentEditingViewKey, selectViewListLoading, @@ -60,10 +56,9 @@ export const FolderTree = memo(({ treeData }: FolderTreeProps) => { const loading = useSelector(selectViewListLoading); const currentEditingViewKey = useSelector(selectCurrentEditingViewKey); const orgId = useSelector(selectOrgId); - const isOwner = useSelector(selectIsOrgOwner); - const permissionMap = useSelector(selectPermissionMap); - const { actions } = useViewSlice(); const viewsData = useSelector(selectViews); + const t = useI18NPrefix('view.form'); + const tg = useI18NPrefix('global'); useEffect(() => { dispatch(getViews(orgId)); @@ -89,12 +84,16 @@ export const FolderTree = memo(({ treeData }: FolderTreeProps) => { archive: !isFolder, resolve: () => { dispatch(removeEditingView({ id, resolve: redirect })); - message.success(`成功${isFolder ? '删除' : '移至回收站'}`); + message.success( + isFolder + ? tg('operation.deleteSuccess') + : tg('operation.archiveSuccess'), + ); }, }), ); }, - [dispatch, redirect], + [dispatch, redirect, tg], ); const moreMenuClick = useCallback( @@ -112,7 +111,7 @@ export const FolderTree = memo(({ treeData }: FolderTreeProps) => { name, parentId, }, - parentIdLabel: '目录', + parentIdLabel: t('folder'), onSave: (values, onClose) => { if (isParentIdEqual(parentId, values.parentId)) { index = getInsertedNodeIndex(values, viewsData); @@ -138,7 +137,7 @@ export const FolderTree = memo(({ treeData }: FolderTreeProps) => { break; } }, - [dispatch, showSaveForm, viewsData], + [dispatch, showSaveForm, viewsData, t], ); const renderTreeTitle = useCallback( @@ -164,17 +163,23 @@ export const FolderTree = memo(({ treeData }: FolderTreeProps) => { key="info" prefix={<EditOutlined className="icon" />} > - 基本信息 + {tg('button.info')} </MenuListItem> <MenuListItem key="delete" prefix={<DeleteOutlined className="icon" />} > <Popconfirm - title={`确定${node.isFolder ? '删除' : '移至回收站'}?`} + title={ + node.isFolder + ? tg('operation.deleteConfirm') + : tg('operation.archiveConfirm') + } onConfirm={archive(node.id, node.isFolder)} > - {node.isFolder ? '删除' : '移至回收站'} + {node.isFolder + ? tg('button.delete') + : tg('button.archive')} </Popconfirm> </MenuListItem> </Menu> @@ -188,7 +193,7 @@ export const FolderTree = memo(({ treeData }: FolderTreeProps) => { </TreeTitle> ); }, - [archive, moreMenuClick], + [archive, moreMenuClick, tg], ); const treeSelect = useCallback( 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 217e1931f..0c0ab9a3a 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/Recycle.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/Recycle.tsx @@ -23,6 +23,7 @@ import { } from '@ant-design/icons'; 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, @@ -65,6 +66,8 @@ export const Recycle = memo(({ list }: RecycleProps) => { const views = useSelector(selectViews); const isOwner = useSelector(selectIsOrgOwner); const permissionMap = useSelector(selectPermissionMap); + const t = useI18NPrefix('view.form'); + const tg = useI18NPrefix('global'); useEffect(() => { dispatch(getArchivedViews(orgId)); @@ -90,12 +93,12 @@ export const Recycle = memo(({ list }: RecycleProps) => { archive: false, resolve: () => { dispatch(removeEditingView({ id, resolve: redirect })); - message.success('删除成功'); + message.success(tg('operation.deleteSuccess')); }, }), ); }, - [dispatch, redirect], + [dispatch, redirect, tg], ); const moreMenuClick = useCallback( @@ -109,7 +112,7 @@ export const Recycle = memo(({ list }: RecycleProps) => { visible: true, simple: true, initialValues: { name, parentId: null }, - parentIdLabel: '目录', + parentIdLabel: t('folder'), onSave: (values, onClose) => { let index = getInsertedNodeIndex(values, views); @@ -118,7 +121,7 @@ export const Recycle = memo(({ list }: RecycleProps) => { view: { ...values, id, index }, resolve: () => { dispatch(removeEditingView({ id, resolve: redirect })); - message.success('还原成功'); + message.success(tg('operation.restoreSuccess')); onClose(); }, }), @@ -130,7 +133,7 @@ export const Recycle = memo(({ list }: RecycleProps) => { break; } }, - [dispatch, showSaveForm, redirect, views], + [dispatch, showSaveForm, redirect, views, t, tg], ); const renderTreeTitle = useCallback( @@ -166,14 +169,17 @@ export const Recycle = memo(({ list }: RecycleProps) => { key="reset" prefix={<ReloadOutlined className="icon" />} > - 还原 + {tg('button.restore')} </MenuListItem> <MenuListItem key="delelte" prefix={<DeleteOutlined className="icon" />} > - <Popconfirm title="确认删除?" onConfirm={del(key)}> - 删除 + <Popconfirm + title={tg('operation.deleteConfirm')} + onConfirm={del(key)} + > + {tg('button.delete')} </Popconfirm> </MenuListItem> </Menu> @@ -187,7 +193,7 @@ export const Recycle = memo(({ list }: RecycleProps) => { </TreeTitle> ); }, - [moreMenuClick, del, views, isOwner, permissionMap], + [moreMenuClick, del, views, isOwner, permissionMap, 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 d8735b394..e5d6afa90 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Sidebar/index.tsx @@ -26,6 +26,7 @@ import { } from '@ant-design/icons'; import { ListNav, ListPane, ListTitle } from 'app/components'; import { useDebouncedSearch } from 'app/hooks/useDebouncedSearch'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import { CommonFormTypes } from 'globalConstants'; import React, { memo, useCallback, useContext, useMemo } from 'react'; @@ -53,6 +54,7 @@ export const Sidebar = memo(() => { const orgId = useSelector(selectOrgId); const selectViewTree = useMemo(makeSelectViewTree, []); const viewsData = useSelector(selectViews); + const t = useI18NPrefix('view.sidebar'); const getIcon = useCallback( ({ isFolder }: ViewSimpleViewModel) => @@ -107,7 +109,7 @@ export const Sidebar = memo(() => { type: CommonFormTypes.Add, visible: true, simple: true, - parentIdLabel: '所属目录', + parentIdLabel: t('parent'), onSave: (values, onClose) => { let index = getInsertedNodeIndex(values, viewsData); @@ -128,19 +130,19 @@ export const Sidebar = memo(() => { break; } }, - [dispatch, history, orgId, showSaveForm, viewsData], + [dispatch, history, orgId, showSaveForm, viewsData, t], ); const titles = useMemo( () => [ { key: 'list', - title: '数据视图列表', + title: t('title'), search: true, add: { items: [ - { key: 'view', text: '新建数据视图' }, - { key: 'folder', text: '新建目录' }, + { key: 'view', text: t('addView') }, + { key: 'folder', text: t('addFolder') }, ], callback: add, }, @@ -148,7 +150,7 @@ export const Sidebar = memo(() => { items: [ { key: 'recycle', - text: '回收站', + text: t('recycle'), prefix: <DeleteOutlined className="icon" />, }, ], @@ -164,13 +166,13 @@ export const Sidebar = memo(() => { }, { key: 'recycle', - title: '回收站', + title: t('recycle'), back: true, search: true, onSearch: listSearch, }, ], - [add, treeSearch, listSearch], + [add, treeSearch, listSearch, t], ); return ( diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx index 5c8980262..ddea2ecef 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/components/SchemaTable.tsx @@ -24,6 +24,7 @@ import { import { Dropdown, Menu, TableColumnType, TableProps, Tooltip } from 'antd'; import { ToolbarButton } from 'app/components'; import { VirtualTable } from 'app/components/VirtualTable'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { memo, ReactElement, useMemo } from 'react'; import styled from 'styled-components/macro'; import { @@ -33,12 +34,7 @@ import { WARNING, } from 'styles/StyleConstants'; import { uuidv4 } from 'utils/utils'; -import { - ColumnCategories, - ColumnTypes, - COLUMN_CATEGORY_LABEL, - COLUMN_TYPE_LABEL, -} from '../constants'; +import { ColumnCategories, ColumnTypes } from '../constants'; import { Column, Model } from '../slice/types'; import { getColumnWidthMap } from '../utils'; const ROW_KEY = 'DATART_ROW_KEY'; @@ -78,6 +74,8 @@ export const SchemaTable = memo( () => getColumnWidthMap(model, dataSource || []), [model, dataSource], ); + const t = useI18NPrefix('view.schemaTable'); + const tg = useI18NPrefix('global'); const { columns, @@ -119,19 +117,21 @@ export const SchemaTable = memo( onClick={onSchemaTypeChange(name, column)} > {Object.values(ColumnTypes).map(t => ( - <Menu.Item key={t}>{COLUMN_TYPE_LABEL[t]}</Menu.Item> + <Menu.Item key={t}> + {tg(`columnType.${t.toLowerCase()}`)} + </Menu.Item> ))} {hasCategory && ( <> <Menu.Divider /> <Menu.SubMenu key="categories" - title="分类" + title={t('category')} popupClassName="datart-schema-table-header-menu" > {Object.values(ColumnCategories).map(t => ( <Menu.Item key={`category-${t}`}> - {COLUMN_CATEGORY_LABEL[t]} + {tg(`columnCategory.${t.toLowerCase()}`)} </Menu.Item> ))} </Menu.SubMenu> @@ -140,7 +140,7 @@ export const SchemaTable = memo( </Menu> } > - <Tooltip title={`类型${hasCategory ? '与分类' : ''}`}> + <Tooltip title={hasCategory ? t('typeAndCategory') : t('type')}> <ToolbarButton size="small" iconSize={FONT_SIZE_BASE} @@ -170,6 +170,8 @@ export const SchemaTable = memo( hasCategory, getExtraHeaderActions, onSchemaTypeChange, + t, + tg, ]); return ( <VirtualTable diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/constants.ts b/frontend/src/app/pages/MainPage/pages/ViewPage/constants.ts index ae1e827dc..42a5df94b 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/constants.ts +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/constants.ts @@ -56,22 +56,3 @@ export const UNPERSISTED_ID_PREFIX = 'GENERATED-'; export const DEFAULT_PREVIEW_SIZE = 1000; export const PREVIEW_SIZE_LIST = [100, 1000, 10000, 100000]; export const MAX_RESULT_TABLE_COLUMN_WIDTH = 480; - -export const COLUMN_TYPE_LABEL = { - [ColumnTypes.String]: '字符', - [ColumnTypes.Number]: '数值', - [ColumnTypes.Date]: '日期', -}; - -export const COLUMN_CATEGORY_LABEL = { - [ColumnCategories.Uncategorized]: '未分类', - [ColumnCategories.Country]: '国家', - [ColumnCategories.ProvinceOrState]: '省份', - [ColumnCategories.City]: '城市', - [ColumnCategories.County]: '区县', -}; - -export const CONCURRENCY_CONTROL_MODE_LABEL = { - [ConcurrencyControlModes.DirtyRead]: '延迟更新', - [ConcurrencyControlModes.FastFailOver]: '快速失败', -}; diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/slice/thunks.ts b/frontend/src/app/pages/MainPage/pages/ViewPage/slice/thunks.ts index 2565b6166..72fed6624 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/slice/thunks.ts +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/slice/thunks.ts @@ -19,6 +19,7 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; import sqlReservedWords from 'app/assets/javascripts/sqlReservedWords'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; +import i18n from 'i18next'; import { monaco } from 'react-monaco-editor'; import { RootState } from 'types'; import { request } from 'utils/request'; @@ -111,7 +112,7 @@ export const getViewDetail = createAsyncThunk< const viewSimple = views?.find(v => v.id === viewId); const tempViewModel = generateEditingView({ id: viewId, - name: viewSimple?.name || '加载中...', + name: viewSimple?.name || i18n.t('view.loading'), stage: ViewViewModelStages.Loading, }); dispatch(viewActions.addEditingView(tempViewModel)); @@ -159,7 +160,7 @@ export const runSql = createAsyncThunk< const { script, sourceId, size, fragment, variables } = currentEditingView; if (!sourceId) { - return rejectWithValue('请选择数据源'); + return rejectWithValue(i18n.t('view.selectSource')); } if (!script.trim()) { diff --git a/frontend/src/app/pages/SharePage/PasswordModal.tsx b/frontend/src/app/pages/SharePage/PasswordModal.tsx index 197d86d29..ef6df8ed4 100644 --- a/frontend/src/app/pages/SharePage/PasswordModal.tsx +++ b/frontend/src/app/pages/SharePage/PasswordModal.tsx @@ -53,7 +53,7 @@ const PasswordModal: FC<{ name={INPUT_PASSWORD_KEY} rules={[{ required: true }]} > - <Input.Password placeholder={t('pleaseInputPassword')} /> + <Input.Password placeholder={t('enterPassword')} /> </Form.Item> </Form> </Modal> diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 99de6bfbd..06ca4dd3f 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -32,6 +32,18 @@ "add": "Create ", "edit": "Edit " } + }, + "columnType": { + "string": "String", + "numeric": "Number", + "date": "Date" + }, + "columnCategory": { + "uncategorized": "Uncategorized", + "country": "Country", + "provinceorstate": "ProvinceOrState", + "city": "City", + "county": "County" } }, "login": { @@ -238,7 +250,7 @@ "ago": "Ago", "current": "Current", "fromNow": "From Now", - "pleaseSelect": "Please Select", + "select": "Select", "currentTime": "Current Time", "startTime": "Start Time", "endTime": "end Time", @@ -323,10 +335,10 @@ }, "style": { "font": "Font", - "pleaseSelect": "Please select ...", + "select": "Select ...", "table": { "header": { - "newName": "Please input a new header name", + "newName": "Enter a new header name", "merge": "Merge", "reset": "Reset", "moveUp": "moveUp", @@ -347,7 +359,7 @@ "add": "Add", "edit": "Edit", "remove": "Remove", - "confirm": "Please Confirm" + "confirm": "Confirm" }, "modal": { "title": "Condition Style", @@ -398,8 +410,8 @@ "info": "Info", "sort": "Sort", "size": "Size", - "drop": "Please drag some data fields here", - "dropCount": "Please drag {{count}} fields here at least", + "drop": "Drag some data fields here", + "dropCount": "Drag {{count}} fields here at least", "actions": { "sort": { "title": "Sort", @@ -462,7 +474,7 @@ } }, "setting": { - "pleaseSelect": "Please select ...", + "select": "Select ...", "displayCount": "Display Count", "enableCache": "Enable Cache", "cacheExpire": "Cache Expire Time(sec)", @@ -667,6 +679,84 @@ "noScale": "noScale" } }, + "view": { + "loading": "Loading...", + "selectSource": "You must select a source", + "empty": "Select view in the sidebar", + "resultEmpty1": "Click ", + "resultEmpty2": " button to execute, the results will be displayed here", + "errorTitle": "Error occurred", + "tabs": { + "discard": "Discard", + "cancel": "Cancel", + "execute": "Execute", + "warning": "There are unexecuted changes, still execute?" + }, + "editor": { + "folder": "Folder", + "source": "Select source", + "run": "Run", + "runSelection": "Run selection", + "runWinTip": "Win: [Ctrl + Enter]", + "runMacTip": "Mac: [Command + Enter]", + "beautify": "Beautify", + "save": "保存", + "saveWinTip": "Win: [Ctrl + S]", + "saveMacTip": "Mac: [Command + S]", + "info": "Info", + "saveAs": "Save as", + "saveFragment": "Save Fragment", + "readonlyTip": "Not editable in recycle" + }, + "properties": { + "reference": "Source reference", + "variable": "Variables", + "columnPermissions": "Column Permissions" + }, + "resource": { + "title": "Source info", + "search": "Search database / table / column" + }, + "variable": { + "title": "Variables", + "formTitle": "variable", + "add": "Create variable", + "prefix": "[Public]", + "suffix": "duplicate" + }, + "columnPermission": { + "title": "Column permissions", + "search": "Search role name", + "partial": "Partial", + "none": "None", + "all": "All" + }, + "sidebar": { + "title": "Views", + "addView": "Create view", + "addFolder": "Create folder", + "parent": "Parent", + "recycle": "Recycle" + }, + "saveForm": { + "title": "View", + "name": "Name", + "folder": "Directory", + "root": "Root", + "advanced": "Advanced", + "concurrencyControl": "Concurrency control", + "concurrencyControlMode": "Mode", + "dirtyread": "Dirty read", + "fastfailover": "Fast failover", + "cache": "Cache", + "cacheExpires": "Expires" + }, + "schemaTable": { + "category": "Category", + "type": "Type", + "typeAndCategory": "Type & Category" + } + }, "source": { "source": "Source", "testSuccess": "Test connection succeeded", @@ -674,7 +764,7 @@ "archived": "Archived ", "noPermission": "You do not have permission to access this page", "sidebar": { - "title": "Source List", + "title": "Sources", "add": "Create source", "recycle": "Recycle" }, @@ -694,13 +784,13 @@ }, "share": { "common": { - "confirm": "Please Confirm", + "confirm": "Confirm", "ok": "OK", "cancel": "Cancel" }, "modal": { "password": "Password", - "pleaseInputPassword": "please input password" + "enterPassword": "Enter password" } }, "components": { diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index b9ada9207..66ffd4ce2 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -32,6 +32,18 @@ "add": "新建", "edit": "编辑" } + }, + "columnType": { + "string": "字符", + "numeric": "数值", + "date": "日期" + }, + "columnCategory": { + "uncategorized": "未分类", + "country": "国家", + "provinceorstate": "省份", + "city": "城市", + "county": "区县" } }, "login": { @@ -238,7 +250,7 @@ "ago": "前", "current": "当前", "fromNow": "后", - "pleaseSelect": "请选择", + "select": "请选择", "currentTime": "当前时间", "startTime": "开始时间", "endTime": "结束时间", @@ -323,7 +335,7 @@ }, "style": { "font": "字体", - "pleaseSelect": "请选择 ...", + "select": "请选择 ...", "table": { "header": { "newName": "请输入新名称", @@ -462,7 +474,7 @@ } }, "setting": { - "pleaseSelect": "请选择 ...", + "select": "请选择 ...", "displayCount": "显示数量", "enableCache": "启用缓存", "cacheExpire": "缓存时长(秒)", @@ -666,6 +678,84 @@ "noScale": "实际尺寸" } }, + "view": { + "loading": "加载中...", + "selectSource": "请选择数据源", + "empty": "请在左侧列表选择数据视图", + "resultEmpty1": "请点击 ", + "resultEmpty2": " 按钮执行,运行结果将在此处展示", + "errorTitle": "执行错误", + "tabs": { + "discard": "放弃", + "cancel": "取消", + "execute": "执行", + "warning": "有未执行的修改,是否执行?" + }, + "editor": { + "folder": "目录", + "source": "请选择数据源", + "run": "执行", + "runSelection": "执行片段", + "runWinTip": "Win: [Ctrl + Enter]", + "runMacTip": "Mac: [Command + Enter]", + "beautify": "美化", + "save": "保存", + "saveWinTip": "Win: [Ctrl + S]", + "saveMacTip": "Mac: [Command + S]", + "info": "详情设置", + "saveAs": "另存为", + "saveFragment": "保存片段", + "readonlyTip": "回收站中不可编辑" + }, + "properties": { + "reference": "数据源信息", + "variable": "变量配置", + "columnPermissions": "列权限" + }, + "resource": { + "title": "数据源信息", + "search": "搜索数据库 / 表 / 字段关键字" + }, + "variable": { + "title": "变量配置", + "formTitle": "变量", + "add": "新建变量", + "prefix": "[公共]", + "suffix": "重复" + }, + "columnPermission": { + "title": "列权限", + "search": "搜索角色关键字", + "partial": "部分字段", + "none": "不可见", + "all": "全部字段" + }, + "sidebar": { + "title": "数据视图列表", + "addView": "新建数据视图", + "addFolder": "新建目录", + "parent": "所属目录", + "recycle": "回收站" + }, + "saveForm": { + "title": "数据视图", + "name": "名称", + "folder": "目录", + "root": "根目录", + "advanced": "高级配置", + "concurrencyControl": "并发控制", + "concurrencyControlMode": "模式", + "dirtyread": "延迟更新", + "fastfailover": "快速失败", + "cache": "缓存", + "cacheExpires": "失效时间" + }, + "schemaTable": { + "category": "分类", + "type": "类型", + "typeAndCategory": "类型与分类" + } + }, "source": { "source": "数据源", "testSuccess": "测试连接成功", @@ -699,7 +789,7 @@ }, "modal": { "password": "密码", - "pleaseInputPassword": "请输入密码" + "enterPassword": "请输入密码" } }, "components": { From ff49dbc8f4cd8d4bb38387465c5bbaa56ba5d11a Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Thu, 30 Dec 2021 14:29:18 +0800 Subject: [PATCH 287/348] chore: add copyright to member pages --- .../MainPage/pages/MemberPage/InviteForm.tsx | 18 ++++++++++++++++++ .../pages/MemberPage/Sidebar/MemberList.tsx | 18 ++++++++++++++++++ .../pages/MemberPage/Sidebar/RoleList.tsx | 18 ++++++++++++++++++ .../pages/MemberPage/Sidebar/index.tsx | 18 ++++++++++++++++++ .../pages/MainPage/pages/MemberPage/index.tsx | 18 ++++++++++++++++++ .../MemberPage/pages/MemberDetailPage.tsx | 18 ++++++++++++++++++ .../pages/RoleDetailPage/MemberForm.tsx | 18 ++++++++++++++++++ .../pages/RoleDetailPage/MemberTable.tsx | 18 ++++++++++++++++++ .../MemberPage/pages/RoleDetailPage/index.tsx | 18 ++++++++++++++++++ .../MainPage/pages/MemberPage/slice/index.ts | 18 ++++++++++++++++++ .../pages/MemberPage/slice/selectors.ts | 18 ++++++++++++++++++ .../MainPage/pages/MemberPage/slice/thunks.ts | 18 ++++++++++++++++++ .../MainPage/pages/MemberPage/slice/types.ts | 18 ++++++++++++++++++ .../pages/MainPage/pages/MemberPage/types.ts | 18 ++++++++++++++++++ 14 files changed, 252 insertions(+) diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/InviteForm.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/InviteForm.tsx index 91255b5d7..0cfa14449 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/InviteForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/InviteForm.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Checkbox, Form, FormInstance, Select } from 'antd'; import { ModalForm, ModalFormProps } from 'app/components'; import { User } from 'app/slice/types'; diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/MemberList.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/MemberList.tsx index 9eef5a16a..e30e32e83 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/MemberList.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/MemberList.tsx @@ -1,3 +1,21 @@ +/** + * 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 { LoadingOutlined, UserAddOutlined } from '@ant-design/icons'; import { List, Modal } from 'antd'; import { Avatar, ListItem, ListTitle } from 'app/components'; diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/RoleList.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/RoleList.tsx index f55f95b0b..8ddc5e8a4 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/RoleList.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/RoleList.tsx @@ -1,3 +1,21 @@ +/** + * 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 { LoadingOutlined, PlusOutlined } from '@ant-design/icons'; import { List } from 'antd'; import { ListItem, ListTitle } from 'app/components'; diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/index.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/index.tsx index 8d97507ca..fceff1f23 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { TeamOutlined, UserOutlined } from '@ant-design/icons'; import { ListSwitch } from 'app/components'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/index.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/index.tsx index 558e753b7..b08f9427d 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 React from 'react'; import { Route, Switch, useRouteMatch } from 'react-router-dom'; import styled from 'styled-components/macro'; diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/MemberDetailPage.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/MemberDetailPage.tsx index fc2047c96..ccc494f7c 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/MemberDetailPage.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/MemberDetailPage.tsx @@ -1,3 +1,21 @@ +/** + * 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 { LoadingOutlined } from '@ant-design/icons'; import { Button, Card, Form, message, Popconfirm, Select } from 'antd'; import { DetailPageHeader } from 'app/components/DetailPageHeader'; diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/MemberForm.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/MemberForm.tsx index 70022c945..0763e67b2 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/MemberForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/MemberForm.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Form, FormInstance, ModalProps, Transfer } from 'antd'; import { LoadingMask, ModalForm } from 'app/components'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/MemberTable.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/MemberTable.tsx index 89131e8d3..ddedfb1de 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/MemberTable.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/MemberTable.tsx @@ -1,3 +1,21 @@ +/** + * 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 { DeleteOutlined, PlusOutlined, diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx index ece607c4c..f55631586 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Button, Card, Form, Input, message, Popconfirm } from 'antd'; import { DetailPageHeader } from 'app/components/DetailPageHeader'; import { User } from 'app/slice/types'; diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/slice/index.ts b/frontend/src/app/pages/MainPage/pages/MemberPage/slice/index.ts index 4757dbfeb..b6f55eb45 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/slice/index.ts +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/slice/index.ts @@ -1,3 +1,21 @@ +/** + * 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 { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { useInjectReducer } from 'utils/@reduxjs/injectReducer'; import { diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/slice/selectors.ts b/frontend/src/app/pages/MainPage/pages/MemberPage/slice/selectors.ts index 2dbc8e23f..9abe4d2d3 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/slice/selectors.ts +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/slice/selectors.ts @@ -1,3 +1,21 @@ +/** + * 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 { createSelector } from '@reduxjs/toolkit'; import { RootState } from 'types'; import { initialState } from '.'; diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/slice/thunks.ts b/frontend/src/app/pages/MainPage/pages/MemberPage/slice/thunks.ts index 578315c79..ce684775f 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/slice/thunks.ts +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/slice/thunks.ts @@ -1,3 +1,21 @@ +/** + * 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 { createAsyncThunk } from '@reduxjs/toolkit'; import { User } from 'app/slice/types'; import omit from 'lodash/omit'; diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/slice/types.ts b/frontend/src/app/pages/MainPage/pages/MemberPage/slice/types.ts index 663bebf5a..3087f6f40 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/slice/types.ts +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/slice/types.ts @@ -1,3 +1,21 @@ +/** + * 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 { User } from 'app/slice/types'; export interface MemberState { diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/types.ts b/frontend/src/app/pages/MainPage/pages/MemberPage/types.ts index 7c7f6cb47..24fb71a99 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/types.ts +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/types.ts @@ -1,3 +1,21 @@ +/** + * 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 { MainPageRouteParams } from '../../types'; export interface MemberPageRouteParams extends MainPageRouteParams { From 758bf5ddc61cd9051d91976cab4138de9b29f78a Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Wed, 29 Dec 2021 20:56:30 +0800 Subject: [PATCH 288/348] chore: add i18n edit control --- .../src/app/pages/DashBoardPage/constants.ts | 58 +++++++++++++------ .../BoardToolBar/AddControl/AddControlBtn.tsx | 6 +- .../ControllerConfig/ControllerVisibility.tsx | 38 ++++++++---- .../RadioStyle/RadioStyleForm.tsx | 11 +++- .../OtherSet.tsx/RadioStyle/RadioStyleSet.tsx | 12 +++- .../OtherSet.tsx/SliderStyle/SliderMarks.tsx | 12 +++- .../OtherSet.tsx/SliderStyle/SliderStep.tsx | 4 +- .../OtherSet.tsx/SqlOperator/index.tsx | 4 +- .../ValuesSetter/MaxAndMinSetter/index.tsx | 20 ++++--- .../ValuesSetter/NumberSetter/index.tsx | 8 ++- .../RangeNumberSetter/RangeNumberSet.tsx | 4 +- .../ValuesSetter/SliderSetter/SliderSet.tsx | 9 +-- .../ValuesSetter/TextSetter/index.tsx | 4 +- .../ValuesSetter/TimeSetter/TimeSetter.tsx | 24 +++++--- .../ValuesOptionsSetter/AssistViewFields.tsx | 4 +- .../ValuesOptionsSetter.tsx | 12 +++- .../ValuesSetter/ValuesSetter.tsx | 5 +- .../ControllerConfig/index.tsx | 17 +++--- .../ControllerWidgetPanel/index.tsx | 3 +- .../components/ControllerWidgetPanel/types.ts | 23 ++++++-- frontend/src/locales/en/translation.json | 27 ++++++++- frontend/src/locales/zh/translation.json | 29 +++++++++- 22 files changed, 240 insertions(+), 94 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/constants.ts b/frontend/src/app/pages/DashBoardPage/constants.ts index c47670c9c..96aad995c 100644 --- a/frontend/src/app/pages/DashBoardPage/constants.ts +++ b/frontend/src/app/pages/DashBoardPage/constants.ts @@ -22,9 +22,9 @@ import { } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import { ControllerFacadeTypes } from 'app/types/FilterControlPanel'; import { FilterSqlOperator } from 'globalConstants'; +import i18next from 'i18next'; import { PRIMARY, WHITE } from 'styles/StyleConstants'; import { WidgetType } from './pages/Board/slice/types'; - export const RGL_DRAG_HANDLE = 'dashboard-draggableHandle'; export const STORAGE_BOARD_KEY_PREFIX = 'DATART_BOARD_DATA_'; export const STORAGE_IMAGE_KEY_PREFIX = 'DATART_IMAGE_'; @@ -156,33 +156,53 @@ export const enum ControllerVisibleTypes { export type ControllerVisibleType = Uncapitalize< keyof typeof ControllerVisibleTypes >; +const tfo = (operator: FilterSqlOperator) => { + const preStr = 'viz.common.enum.filterOperator.'; + return i18next.t(preStr + operator); +}; +const tft = (type: ControllerVisibleTypes) => { + const preStr = 'viz.common.enum.controllerVisibilityTypes.'; + return i18next.t(preStr + type); +}; +const getVisibleOptionItem = (type: ControllerVisibleTypes) => { + return { + name: tft(type), + value: type, + }; +}; +const getOperatorItem = (value: FilterSqlOperator) => { + return { + name: tfo(value), + value: value, + }; +}; export const VISIBILITY_TYPE_OPTION = [ - { name: '显示', value: ControllerVisibleTypes.Show }, - { name: '隐藏', value: ControllerVisibleTypes.Hide }, - { name: '条件', value: ControllerVisibleTypes.Condition }, + getVisibleOptionItem(ControllerVisibleTypes.Show), + getVisibleOptionItem(ControllerVisibleTypes.Hide), + getVisibleOptionItem(ControllerVisibleTypes.Condition), ]; export const ALL_SQL_OPERATOR_OPTIONS = [ - { name: '等于', value: FilterSqlOperator.Equal }, - { name: '不相等', value: FilterSqlOperator.NotEqual }, + getOperatorItem(FilterSqlOperator.Equal), + getOperatorItem(FilterSqlOperator.NotEqual), - { name: '包含', value: FilterSqlOperator.In }, - { name: '不包含', value: FilterSqlOperator.NotIn }, + getOperatorItem(FilterSqlOperator.In), + getOperatorItem(FilterSqlOperator.NotIn), - { name: '为空', value: FilterSqlOperator.Null }, - { name: '不为空', value: FilterSqlOperator.NotNull }, + getOperatorItem(FilterSqlOperator.Null), + getOperatorItem(FilterSqlOperator.NotNull), - { name: '前缀包含', value: FilterSqlOperator.PrefixContain }, - { name: '前缀不包含', value: FilterSqlOperator.NotPrefixContain }, + getOperatorItem(FilterSqlOperator.PrefixContain), + getOperatorItem(FilterSqlOperator.NotPrefixContain), - { name: '后缀包含', value: FilterSqlOperator.SuffixContain }, - { name: '后缀不包含', value: FilterSqlOperator.NotSuffixContain }, + getOperatorItem(FilterSqlOperator.SuffixContain), + getOperatorItem(FilterSqlOperator.NotSuffixContain), - { name: '区间', value: FilterSqlOperator.Between }, + getOperatorItem(FilterSqlOperator.Between), - { name: '大于或等于', value: FilterSqlOperator.GreaterThanOrEqual }, - { name: '小于或等于', value: FilterSqlOperator.LessThanOrEqual }, - { name: '大于', value: FilterSqlOperator.GreaterThan }, - { name: '小于', value: FilterSqlOperator.LessThan }, + getOperatorItem(FilterSqlOperator.GreaterThanOrEqual), + getOperatorItem(FilterSqlOperator.LessThanOrEqual), + getOperatorItem(FilterSqlOperator.GreaterThan), + getOperatorItem(FilterSqlOperator.LessThan), ]; export const SQL_OPERATOR_OPTIONS_TYPES = { diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControl/AddControlBtn.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControl/AddControlBtn.tsx index 389f1b535..4a32f3387 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControl/AddControlBtn.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/AddControl/AddControlBtn.tsx @@ -38,7 +38,7 @@ export const AddControlBtn: React.FC<AddControlBtnProps> = () => { const t = useI18NPrefix(`viz.board.action`); const tFilterName = useI18NPrefix(`viz.common.enum.controllerFacadeTypes`); const tType = useI18NPrefix(`viz.board.controlTypes`); - + const tWt = useI18NPrefix(`viz.widget.type`); const { boardId, boardType, showLabel } = useContext(BoardToolBarContext); const dispatch = useDispatch(); const { config: boardConfig } = useContext(BoardConfigContext); @@ -118,13 +118,11 @@ export const AddControlBtn: React.FC<AddControlBtnProps> = () => { ]; const buttonControllers: ButtonItemType<WidgetType>[] = [ { - name: '查询按钮', icon: '', type: 'query', disabled: !!hasQueryControl, }, { - name: '重置按钮', icon: '', type: 'reset', disabled: !!hasResetControl, @@ -168,7 +166,7 @@ export const AddControlBtn: React.FC<AddControlBtnProps> = () => { > {buttonControllers.map(({ name, icon, type, disabled }) => ( <Menu.Item key={type} icon={icon} disabled={disabled}> - {name} + {tWt(type)} </Menu.Item> ))} </Menu.ItemGroup> diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ControllerVisibility.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ControllerVisibility.tsx index 3f1d471b4..ace590329 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ControllerVisibility.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ControllerVisibility.tsx @@ -17,7 +17,11 @@ */ import { Form, FormInstance, Input, Radio, Select } from 'antd'; -import { VISIBILITY_TYPE_OPTION } from 'app/pages/DashBoardPage/constants'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; +import { + ALL_SQL_OPERATOR_OPTIONS, + VISIBILITY_TYPE_OPTION, +} from 'app/pages/DashBoardPage/constants'; import { Widget } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import { FilterSqlOperator } from 'globalConstants'; import { FC, memo, useCallback } from 'react'; @@ -28,6 +32,7 @@ const ControllerVisibility: FC<{ form: FormInstance<{ config: ControllerConfig }> | undefined; otherStrFilterWidgets: Widget[]; }> = memo(({ form, otherStrFilterWidgets }) => { + const tc = useI18NPrefix('viz.control'); const showVisibilityCondition = useCallback(() => { const visibilityType = form?.getFieldValue([ 'config', @@ -41,7 +46,11 @@ const ControllerVisibility: FC<{ }, [form]); return ( - <Form.Item label="是否显示" shouldUpdate rules={[{ required: true }]}> + <Form.Item + label={tc('visibility')} + shouldUpdate + rules={[{ required: true }]} + > {() => { return ( <> @@ -73,7 +82,10 @@ const ControllerVisibility: FC<{ noStyle rules={[{ required: true, message: '' }]} > - <Select placeholder="过滤器名称" style={{ width: '160px' }}> + <Select + placeholder={tc('title')} + style={{ width: '160px' }} + > {otherStrFilterWidgets.map(ele => { return ( <Select.Option key={ele.id} value={ele.id}> @@ -89,13 +101,19 @@ const ControllerVisibility: FC<{ noStyle rules={[{ required: true, message: '' }]} > - <Select placeholder="viewField" style={{ width: '100px' }}> - <Select.Option key={1} value={FilterSqlOperator.Equal}> - {'等于'} - </Select.Option> - <Select.Option key={2} value={FilterSqlOperator.NotEqual}> - {'不等于'} - </Select.Option> + <Select placeholder="" style={{ width: '100px' }}> + {ALL_SQL_OPERATOR_OPTIONS.filter(it => + [ + FilterSqlOperator.Equal, + FilterSqlOperator.NotEqual, + ].includes(it.value), + ).map(it => { + return ( + <Select.Option key={it.value} value={it.value}> + {it.name} + </Select.Option> + ); + })} </Select> </Form.Item> {' - '} 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/OtherSet.tsx/RadioStyle/RadioStyleForm.tsx index 6702f05a6..344032f54 100644 --- 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/OtherSet.tsx/RadioStyle/RadioStyleForm.tsx @@ -16,19 +16,26 @@ * limitations under the License. */ import { Form } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { memo } from 'react'; import { RadioButtonTypeName } from '../..'; import { RadioStyleSet } from './RadioStyleSet'; export interface RadioStyleFormProps {} export const RadioStyleForm: React.FC<RadioStyleFormProps> = memo(() => { + const filterT = useI18NPrefix('viz.common.filter'); + const items = ['default', 'button']; + const options = items.map(it => ({ + label: filterT(it), + value: it, + })); return ( <Form.Item name={RadioButtonTypeName} - label="按钮样式" + label={filterT('radioType')} validateTrigger={['onChange', 'onBlur']} rules={[{ required: true }]} > - <RadioStyleSet /> + <RadioStyleSet options={options} /> </Form.Item> ); }); 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/OtherSet.tsx/RadioStyle/RadioStyleSet.tsx index 8f33a4e83..eab34e4c6 100644 --- 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/OtherSet.tsx/RadioStyle/RadioStyleSet.tsx @@ -20,16 +20,22 @@ import React, { memo } from 'react'; export interface RadioStyleSetProps extends FormItemProps<any> { value?: any; onChange?: any; + options: { label: string; value: string }[]; } export const RadioStyleSet: React.FC<RadioStyleSetProps> = memo( - ({ value, onChange }) => { + ({ value, onChange, options }) => { function _onChange(val) { onChange?.(val); } return ( <Radio.Group onChange={_onChange} defaultValue={value}> - <Radio.Button value="default">常规</Radio.Button> - <Radio.Button value="button">按钮</Radio.Button> + {options.map(it => { + return ( + <Radio.Button key={it.value} value={it.value}> + {it.label} + </Radio.Button> + ); + })} </Radio.Group> ); }, 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/OtherSet.tsx/SliderStyle/SliderMarks.tsx index 864a54037..4d3c14e94 100644 --- 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/OtherSet.tsx/SliderStyle/SliderMarks.tsx @@ -19,16 +19,22 @@ import { Form, Switch } from 'antd'; import React, { memo } from 'react'; import { SliderShowMarksName } from '../..'; -export const SliderMarks: React.FC<{}> = memo(() => { +export const SliderMarks: React.FC<{ + label: string; + switchTexts: [string, string]; +}> = memo(({ label, switchTexts }) => { return ( <Form.Item name={SliderShowMarksName} - label="显示标签" + label={label} valuePropName="checked" validateTrigger={['onChange', 'onBlur']} rules={[{ required: true }]} > - <Switch checkedChildren="开启" unCheckedChildren="关闭" /> + <Switch + checkedChildren={switchTexts[0]} + unCheckedChildren={switchTexts[1]} + /> </Form.Item> ); }); 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/OtherSet.tsx/SliderStyle/SliderStep.tsx index 462b2cafa..74a7f1680 100644 --- 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/OtherSet.tsx/SliderStyle/SliderStep.tsx @@ -19,11 +19,11 @@ import { Form, InputNumber } from 'antd'; import React, { memo } from 'react'; import { SliderStepName } from '../..'; -export const SliderStep: React.FC<{}> = memo(() => { +export const SliderStep: React.FC<{ label: string }> = memo(({ label }) => { return ( <Form.Item name={SliderStepName} - label="步长" + label={label} validateTrigger={['onChange', 'onBlur']} rules={[{ required: true }]} > 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/OtherSet.tsx/SqlOperator/index.tsx index 09c1a3a80..f9175548c 100644 --- 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/OtherSet.tsx/SqlOperator/index.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ import { FormItemProps } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { ALL_SQL_OPERATOR_OPTIONS, SQL_OPERATOR_OPTIONS_TYPES, @@ -33,11 +34,12 @@ export interface SqlOperatorProps { } export const SqlOperator: React.FC<SqlOperatorProps> = memo( ({ controllerType }) => { + const tc = useI18NPrefix(`viz.control`); const hideForm = FixedSqlOperatorTypes.includes(controllerType); const itemProps: FormItemProps<any> = { preserve: true, name: SqlOperatorName, - label: '对应关系', + label: tc('sqlOperator'), hidden: hideForm, }; const optionKeys: FilterSqlOperator[] = diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/MaxAndMinSetter/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/MaxAndMinSetter/index.tsx index ccae5eae4..db59c5843 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/MaxAndMinSetter/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/MaxAndMinSetter/index.tsx @@ -16,35 +16,39 @@ * limitations under the License. */ import { FormItemProps } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { memo } from 'react'; import { MaxValueName, MinValueName } from '../..'; import { NumberSetForm } from '../NumberSetter/NumberSetFrom'; -export interface NumberSetterProps {} -export const MaxValueSetter: React.FC<NumberSetterProps> = memo(() => { +export interface NumberSetterProps { + label: string; +} +export const MaxValueSetter: React.FC<NumberSetterProps> = memo(({ label }) => { const itemProps: FormItemProps<any> = { preserve: true, name: MaxValueName, - label: '最大值', + label: label, required: true, }; return <NumberSetForm {...itemProps} />; }); -export const MinValueSetter: React.FC<NumberSetterProps> = memo(() => { +export const MinValueSetter: React.FC<NumberSetterProps> = memo(({ label }) => { const itemProps: FormItemProps<any> = { preserve: true, name: MinValueName, - label: '最小值', + label: label, required: true, }; return <NumberSetForm {...itemProps} />; }); -export const MaxAndMinSetter: React.FC<NumberSetterProps> = memo(() => { +export const MaxAndMinSetter: React.FC<{}> = memo(() => { + const filterT = useI18NPrefix('viz.common.filter'); return ( <> - <MaxValueSetter /> - <MinValueSetter /> + <MaxValueSetter label={filterT('max')} /> + <MinValueSetter label={filterT('min')} /> </> ); }); diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/NumberSetter/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/NumberSetter/index.tsx index 505da08ec..ab57866e2 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/NumberSetter/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/NumberSetter/index.tsx @@ -20,12 +20,14 @@ import React from 'react'; import { ControllerValuesName } from '../..'; import { NumberSetForm } from './NumberSetFrom'; -export interface NumberSetterProps {} -export const NumberSetter: React.FC<NumberSetterProps> = () => { +export interface NumberSetterProps { + label: string; +} +export const NumberSetter: React.FC<NumberSetterProps> = ({ label }) => { const itemProps: FormItemProps<any> = { preserve: true, name: ControllerValuesName, - label: '默认值', + label: label, required: false, }; return <NumberSetForm {...itemProps} />; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/RangeNumberSetter/RangeNumberSet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/RangeNumberSetter/RangeNumberSet.tsx index b15ccedfb..2776d1167 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/RangeNumberSetter/RangeNumberSet.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/RangeNumberSetter/RangeNumberSet.tsx @@ -17,15 +17,17 @@ */ import { Form, FormItemProps, InputNumber } from 'antd'; import { valueType } from 'antd/lib/statistic/utils'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { memo, useEffect, useState } from 'react'; import { ControllerValuesName } from '../..'; import { rangeNumberValidator } from '../../../utils'; export const RangeNumberSetter: React.FC<{}> = memo(() => { + const tc = useI18NPrefix(`viz.control`); const itemProps: FormItemProps<any> = { preserve: true, name: ControllerValuesName, - label: '默认值', + label: tc('defaultValue'), required: false, }; return <RangeNumberSetForm {...itemProps} />; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/SliderSetter/SliderSet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/SliderSetter/SliderSet.tsx index e2e57cd58..92e4e6486 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/SliderSetter/SliderSet.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/SliderSetter/SliderSet.tsx @@ -23,23 +23,24 @@ export const SliderSetter: React.FC<SliderSetFormProps> = memo(props => { const itemProps: FormItemProps<any> = { preserve: true, name: ControllerValuesName, - label: '默认值', + label: props.label, required: true, }; - return <SliderSetForm {...props} {...itemProps} />; + return <SliderSetForm {...itemProps} {...props} />; }); export const RangeSliderSetter: React.FC<SliderSetFormProps> = memo(props => { const itemProps: FormItemProps<any> = { preserve: true, name: ControllerValuesName, - label: '默认值', + label: props.label, required: false, }; return <RangeSliderSetForm {...itemProps} {...props} />; }); -export type SliderSetFormProps = {} & FormItemProps<any> & SliderSetProps; +export type SliderSetFormProps = { label: string } & FormItemProps<any> & + SliderSetProps; export const RangeSliderSetForm: React.FC<SliderSetFormProps> = memo( ({ ...rest }) => { diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TextSetter/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TextSetter/index.tsx index a991a69a2..381fe8a41 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TextSetter/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TextSetter/index.tsx @@ -16,16 +16,18 @@ * limitations under the License. */ import { FormItemProps } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { memo } from 'react'; import { ControllerValuesName } from '../..'; import { TextSetForm } from './TextSetForm'; export interface TextSetterProps {} export const TextSetter: React.FC<TextSetterProps> = memo(() => { + const tc = useI18NPrefix(`viz.control`); const itemProps: FormItemProps<any> = { preserve: true, name: ControllerValuesName, - label: '默认值', + label: tc('defaultValue'), required: false, }; return <TextSetForm {...itemProps} />; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TimeSetter/TimeSetter.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TimeSetter/TimeSetter.tsx index 2e296c331..f9d8763d9 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TimeSetter/TimeSetter.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/TimeSetter/TimeSetter.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ import { Form, FormInstance, Select } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { ControllerWidgetContent } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import { ControllerFacadeTypes, @@ -47,6 +48,8 @@ export const TimeSetter: React.FC<{ form: FormInstance<ControllerWidgetContent> | undefined; controllerType: ControllerFacadeTypes; }> = ({ controllerType, form }) => { + const tc = useI18NPrefix(`viz.control`); + const filterDataT = useI18NPrefix('viz.common.filter.date'); const getControllerConfig = useCallback(() => { return form?.getFieldValue('config') as ControllerConfig; }, [form]); @@ -170,13 +173,13 @@ export const TimeSetter: React.FC<{ key={TimeFilterValueCategory.Exact} value={TimeFilterValueCategory.Exact} > - {'固定值'} + {filterDataT('exact')} </Select.Option> <Select.Option key={TimeFilterValueCategory.Relative} value={TimeFilterValueCategory.Relative} > - {'相对值'} + {filterDataT('relative')} </Select.Option> </Select> </Form.Item> @@ -202,7 +205,7 @@ export const TimeSetter: React.FC<{ <> <Form.Item name={PickerTypeName} - label={'日期类型'} + label={tc('dateType')} shouldUpdate validateTrigger={['onChange', 'onBlur']} rules={[{ required: true }]} @@ -220,13 +223,14 @@ export const TimeSetter: React.FC<{ {controllerType === ControllerFacadeTypes.Time && ( <> <Form.Item - label={'默认值'} + label={tc('defaultValue')} shouldUpdate rules={[{ required: false }]} > {renderROE(StartTimeROEName, onStartRelativeChange)} - {getStartRelativeOrExact() === TimeFilterValueCategory.Exact && + {getStartRelativeOrExact() === + TimeFilterValueCategory.Exact && renderExact(StartTimeExactName, getPickerType)} {getStartRelativeOrExact() === @@ -243,9 +247,10 @@ export const TimeSetter: React.FC<{ shouldUpdate rules={[{ required: true, validator: RangeTimeValidator }]} > - <Form.Item label={'默认值-起始'} shouldUpdate> + <Form.Item label={filterDataT('startTime')} shouldUpdate> {renderROE(StartTimeROEName, onStartRelativeChange)} - {getStartRelativeOrExact() === TimeFilterValueCategory.Exact && + {getStartRelativeOrExact() === + TimeFilterValueCategory.Exact && renderExact(StartTimeExactName, getPickerType)} {getStartRelativeOrExact() === TimeFilterValueCategory.Relative && ( @@ -253,7 +258,7 @@ export const TimeSetter: React.FC<{ )} </Form.Item> <Form.Item - label={'默认值-结束'} + label={filterDataT('endTime')} name={EndTimeName} shouldUpdate > @@ -262,7 +267,8 @@ export const TimeSetter: React.FC<{ {getEndRelativeOrExact() === TimeFilterValueCategory.Exact && renderExact(EndTimeExactName, getPickerType)} - {getEndRelativeOrExact() === TimeFilterValueCategory.Relative && ( + {getEndRelativeOrExact() === + TimeFilterValueCategory.Relative && ( <RelativeTimeSetter relativeName={EndTimeRelativeName} /> )} </Form.Item> diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/AssistViewFields.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/AssistViewFields.tsx index e8d1d9748..00e54ba5a 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/AssistViewFields.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesOptionsSetter/AssistViewFields.tsx @@ -17,6 +17,7 @@ */ import { Cascader, CascaderProps } from 'antd'; import { CascaderOptionType } from 'antd/lib/cascader'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { BoardContext } from 'app/pages/DashBoardPage/contexts/BoardContext'; import { saveToViewMapAction } from 'app/pages/DashBoardPage/pages/Board/slice/asyncActions'; import { @@ -40,6 +41,7 @@ export interface AssistViewFieldsProps } export const AssistViewFields: React.FC<AssistViewFieldsProps> = memo( ({ onChange, value }) => { + const tc = useI18NPrefix(`viz.control`); const dispatch = useDispatch(); const { orgId } = useContext(BoardContext); const [options, setOptions] = useState<CascaderOptionType[]>([]); @@ -130,7 +132,7 @@ export const AssistViewFields: React.FC<AssistViewFieldsProps> = memo( return ( <Cascader allowClear - placeholder="select viewField" + placeholder={tc('selectViewField')} options={options} onChange={onChange as any} value={value} 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 40ff32f1a..90a843551 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 @@ -17,6 +17,7 @@ */ import { Form, FormInstance, Radio, Select } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { OPERATOR_TYPE_OPTION, ValueOptionType, @@ -36,6 +37,7 @@ const ValuesOptionsSetter: FC<{ form: FormInstance<{ config: ControllerConfig }> | undefined; viewMap: Record<string, ChartDataView>; }> = memo(({ form, viewMap, controllerType }) => { + const tc = useI18NPrefix(`viz.control`); const [optionValues, setOptionValues] = useState<RelationFilterValue[]>([]); const [targetKeys, setTargetKeys] = useState<string[]>([]); @@ -146,7 +148,11 @@ const ValuesOptionsSetter: FC<{ return ( <Wrap> - <Form.Item label="取值配置" shouldUpdate style={{ marginBottom: '0' }}> + <Form.Item + label={tc('valueConfig')} + shouldUpdate + style={{ marginBottom: '0' }} + > <Form.Item name={['config', 'valueOptionType']} validateTrigger={['onChange', 'onBlur']} @@ -157,7 +163,7 @@ const ValuesOptionsSetter: FC<{ {OPERATOR_TYPE_OPTION.map(ele => { return ( <Radio.Button key={ele.value} value={ele.value}> - {ele.name} + {tc(ele.value)} </Radio.Button> ); })} @@ -179,7 +185,7 @@ const ValuesOptionsSetter: FC<{ <div className="transfer"> <Select showSearch - placeholder="请选择默认值" + placeholder={tc('selectDefaultValue')} value={targetKeys} allowClear {...(isMultiple && { mode: 'multiple' })} diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesSetter.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesSetter.tsx index 78e91e0b9..3375bf479 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesSetter.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/ControllerConfig/ValuesSetter/ValuesSetter.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ import { Form, FormInstance, Select } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { ControllerWidgetContent } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import ChartDataView from 'app/types/ChartDataView'; import { ControllerFacadeTypes } from 'app/types/FilterControlPanel'; @@ -36,6 +37,7 @@ export const ValuesSetter: React.FC<{ form: FormInstance<ControllerWidgetContent> | undefined; viewMap: Record<string, ChartDataView>; }> = ({ controllerType, form, viewMap }) => { + const tc = useI18NPrefix('viz.control'); const getControllerConfig = useCallback(() => { return form?.getFieldValue('config') as ControllerConfig; }, [form]); @@ -100,7 +102,7 @@ export const ValuesSetter: React.FC<{ {isText && <TextSetter />} - {isNumberValue && <NumberSetter />} + {isNumberValue && <NumberSetter label={tc('defaultValue')} />} {isRangeNumberValue && <RangeNumberSetter />} @@ -112,6 +114,7 @@ export const ValuesSetter: React.FC<{ <> <MaxAndMinSetter /> <SliderSetter + label={tc('defaultValue')} style={{ paddingRight: '10px' }} maxValue={getMaxAndMin().max} minValue={getMaxAndMin().min} 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 fbc40420f..7d84da556 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 @@ -72,8 +72,8 @@ export interface RelatedViewFormProps { export const WidgetControlForm: React.FC<RelatedViewFormProps> = memo( ({ controllerType, form, viewMap, otherStrFilterWidgets }) => { - const filterT = useI18NPrefix('viz.common.filter'); - + const tc = useI18NPrefix('viz.control'); + const tgb = useI18NPrefix('global.button'); const hasRadio = useMemo(() => { return controllerType === ControllerFacadeTypes.RadioGroup; }, [controllerType]); @@ -87,11 +87,7 @@ export const WidgetControlForm: React.FC<RelatedViewFormProps> = memo( }, [controllerType]); return ( <Wrap> - <Form.Item - name="name" - label={filterT('filterName')} - rules={[{ required: true }]} - > + <Form.Item name="name" label={tc('title')} rules={[{ required: true }]}> <Input /> </Form.Item> <ValuesSetter @@ -102,8 +98,11 @@ export const WidgetControlForm: React.FC<RelatedViewFormProps> = memo( {/* slider */} {sliderTypes && ( <> - <SliderStep /> - <SliderMarks /> + <SliderStep label={tc('step')} /> + <SliderMarks + label={tc('showMark')} + switchTexts={[tgb('open'), tgb('close')]} + /> </> )} {/* sql 对应关系 */} 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 113670018..951e8c3cb 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 @@ -68,6 +68,7 @@ import { const ControllerWidgetPanel: React.FC = memo(props => { const dispatch = useDispatch(); const t = useI18NPrefix('viz.common.enum.controllerFacadeTypes'); + const tGMT = useI18NPrefix(`global.modal.title`); const { type, widgetId, controllerType } = useSelector(selectControllerPanel); const { boardId, boardType, queryVariables } = useContext(BoardContext); @@ -286,7 +287,7 @@ const ControllerWidgetPanel: React.FC = memo(props => { }; return ( <Modal - title={`${type === 'add' ? '添加' : '编辑'}${t(controllerType || '')}`} + title={`${tGMT(type)}${t(controllerType || '')}`} visible={visible} onOk={onSubmit} centered 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 aa46ad0bd..c5d19a306 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 @@ -7,6 +7,7 @@ import { RelationFilterValue } from 'app/types/ChartConfig'; import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { TimeFilterValueCategory } from 'app/types/FilterControlPanel'; import { FilterSqlOperator } from 'globalConstants'; +import i18next from 'i18next'; import { Moment, unitOfTime } from 'moment'; import { VariableValueTypes } from '../../../../../MainPage/pages/VariablePage/constants'; @@ -70,13 +71,23 @@ export const enum PickerTypes { } export type PickerType = Uncapitalize<keyof typeof PickerTypes>; +const td = (value: PickerTypes) => { + const preStr = 'viz.date.'; + return i18next.t(preStr + value); +}; +const getPickerTypeItem = (value: PickerTypes) => { + return { + name: td(value), + value: value, + }; +}; export const PickerTypeOptions = [ - { name: '日期', value: PickerTypes.Date }, - { name: '日期时间', value: PickerTypes.DateTime }, - { name: '年', value: PickerTypes.Year }, - { name: '月', value: PickerTypes.Month }, - { name: '季度', value: PickerTypes.Quarter }, - { name: '周', value: PickerTypes.Week }, + getPickerTypeItem(PickerTypes.Date), + getPickerTypeItem(PickerTypes.DateTime), + getPickerTypeItem(PickerTypes.Year), + getPickerTypeItem(PickerTypes.Quarter), + getPickerTypeItem(PickerTypes.Month), + getPickerTypeItem(PickerTypes.Week), ]; export interface ControllerDateType { diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 06ca4dd3f..4e39e63e3 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -10,7 +10,9 @@ "archive": "Archive", "restore": "Restore", "delete": "Delete", - "info": "Info" + "info": "Info", + "open":"Open", + "close":"Close" }, "operation": { "archiveConfirm": "Archive confirm", @@ -214,6 +216,7 @@ "filterVisibility": "Filter Visibility", "aggregates": "Aggregates", "filterOption": "Filter Option", + "visibility": "Visibility", "facade": "Facade", "widthOption": "Width Option", @@ -677,6 +680,28 @@ "scaleHeight": "scaleHeight", "scaleFull": "scaleFull", "noScale": "noScale" + }, + "control": { + "title":"Control Title", + "valueConfig": "Value Config", + "selectViewField":"Select ViewField", + "selectDefaultValue":"Select DefaultValue", + "defaultValue":"Default Value", + "visibility":"Visibility", + "sqlOperator":"Sql Operator", + "dateType":"Date Type", + "step":"Step", + "showMark":"Show Mark", + "common": "General", + "custom": "Customize" + }, + "date":{ + "year":"Year", + "quarter":"Quarter", + "month":"Month", + "week":"Week", + "date":"Date", + "dateTime":"Date Time" } }, "view": { diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 66ffd4ce2..d60cb045f 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -10,7 +10,9 @@ "archive": "移至回收站", "restore": "还原", "delete": "删除", - "info": "基本信息" + "info": "基本信息", + "open":"开启", + "close":"关闭" }, "operation": { "archiveConfirm": "确定移至回收站?", @@ -214,6 +216,7 @@ "filterVisibility": "是否可见", "aggregates": "聚合方式", "filterOption": "筛选方式", + "visibility": "是否显示", "facade": "控制器", "widthOption": "宽度", @@ -258,7 +261,6 @@ "relative": "相对" }, "category": { - "general": "常规", "customize": "自定义", "condition": "条件", "sourceList": "源列表", @@ -676,6 +678,29 @@ "scaleHeight": "等比高度缩放", "scaleFull": "全屏铺满", "noScale": "实际尺寸" + }, + "control": { + "title":"控制器标题", + "valueConfig": "取值配置", + "selectViewField":"选择数据源字段", + "selectDefaultValue":"选择默认值", + "defaultValue":"默认值", + "visibility":"是否显示", + "sqlOperator":"对应关系", + "dateType":"日期类型", + "step":"步长", + "showMark":"显示标签", + "common": "常规", + "custom": "自定义" + + }, + "date":{ + "year":"年", + "quarter":"季度", + "month":"月", + "week":"周", + "date":"日期", + "dateTime":"日期时间" } }, "view": { From 7d1716f89e16089eaf73f6a642321400258ae668 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Thu, 30 Dec 2021 14:45:57 +0800 Subject: [PATCH 289/348] fix: Solve the problem of "mixed" parameter passing when aggregation is turned on --- frontend/src/app/components/ChartEditor.tsx | 11 ++++--- .../AggregateTypeSection.tsx | 1 - .../ChartDraggableTargetContainer.tsx | 30 +++++++++--------- .../FilterControlPanel/FilterControlPanel.tsx | 4 +-- .../models/ChartEventBroker.ts | 1 - .../models/ChartHttpRequest.ts | 31 ++++++++++++++++--- 6 files changed, 49 insertions(+), 29 deletions(-) diff --git a/frontend/src/app/components/ChartEditor.tsx b/frontend/src/app/components/ChartEditor.tsx index f436ac454..abd1847ee 100644 --- a/frontend/src/app/components/ChartEditor.tsx +++ b/frontend/src/app/components/ChartEditor.tsx @@ -305,20 +305,21 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ const handleAggregationState = state => { const currentChart = ChartManager.instance().getById(chart?.meta?.id); + let targetChartConfig = CloneValueDeep(currentChart?.config); registerChartEvents(currentChart); setChart(currentChart); - let clonedState = CloneValueDeep(currentChart?.config); - + const finalChartConfig = transferChartConfigs( + targetChartConfig, + targetChartConfig, + ); dispatch(actions.updateChartAggregation(state)); dispatch(workbenchSlice.actions.updateShadowChartConfig({})); dispatch( workbenchSlice.actions.updateChartConfig({ type: ChartConfigReducerActionType.INIT, payload: { - init: { - ...clonedState, - }, + init: finalChartConfig, }, }), ); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/AggregateTypeSection.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/AggregateTypeSection.tsx index ba187adc2..63c31782e 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/AggregateTypeSection.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDataConfigSection/AggregateTypeSection.tsx @@ -53,7 +53,6 @@ const AggregateTypeSection: FC<ChartDataConfigSectionProps> = memo( if (aggregation === false) { defaultConfig = handleDefaultConfig(defaultConfig, config.type); } - return <BaseDataConfigSection {...rest} config={defaultConfig} />; }, dataConfigSectionComparer, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx index 362855eab..c3762f498 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableTargetContainer.tsx @@ -88,19 +88,18 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = drop(item: ChartDataSectionField & DragItem, monitor) { let items = Array.isArray(item) ? item : [item]; let needDelete = true; - if ( monitor.getItemType() === CHART_DRAG_ELEMENT_TYPE.DATASET_COLUMN ) { const currentColumns: ChartDataSectionField[] = ( currentConfig.rows || [] ).concat( - items.map(i => ({ + items.map(val => ({ uid: uuidv4(), - colName: i.colName, - category: i.category, - type: i.type, - aggregate: getDefaultAggregate(item), + colName: val.colName, + category: val.category, + type: val.type, + aggregate: getDefaultAggregate(val), })), ); updateCurrentConfigColumns(currentConfig, currentColumns, true); @@ -136,22 +135,21 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = canDrop: (item: ChartDataSectionField, monitor) => { let items = Array.isArray(item) ? item : [item]; - if ( - Array.isArray(item) && - typeof currentConfig.actions === 'object' && - item.every(val => val.type in (currentConfig.actions || {})) - ) { - //zh: 判断是否拖拽多个数据项 en: Determine whether to drag multiple data items - return true; - } - if ( typeof currentConfig.actions === 'object' && - !(item.type in currentConfig.actions) + !items.every(val => val.type in (currentConfig.actions || {})) ) { + //zh: 判断现在拖动的数据项是否可以拖动到当前容器中 en: Determine whether the currently dragged data item can be dragged into the current container return false; } + // if ( + // typeof currentConfig.actions === 'object' && + // !(item.type in currentConfig.actions) + // ) { + // return false; + // } + if (currentConfig.allowSameField) { return true; } diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterControlPanel.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterControlPanel.tsx index 38954f059..75644c518 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterControlPanel.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartFieldAction/FilterControlPanel/FilterControlPanel.tsx @@ -64,7 +64,7 @@ const FilterControllPanel: FC< dataView, i18nPrefix, dataConfig, - aggregation = true, + aggregation, onConfigChange, fetchDataByField, }) => { @@ -77,7 +77,7 @@ const FilterControllPanel: FC< const t = useI18NPrefix(customizeI18NPrefix); const [alias, setAlias] = useState(config.alias); const [aggregate, setAggregate] = useState(() => { - if (Boolean(dataConfig?.disableAggregate)) { + if (Boolean(dataConfig?.disableAggregate) || aggregation === false) { return AggregateFieldActionType.NONE; } if (config.aggregate) { diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts index 0b6e8c1bc..134288078 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts @@ -17,7 +17,6 @@ */ import { ChartLifecycle } from 'app/types/ChartLifecycle'; -import { Debugger } from 'utils/debugger'; import Chart from './Chart'; type BrokerContext = { diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts index 74a8b0219..50878382f 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts @@ -17,6 +17,7 @@ */ import { ChartDatasetPageInfo } from 'app/types/ChartDataset'; +import { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { getStyleValue } from 'app/utils/chartHelper'; import { formatTime, @@ -114,13 +115,13 @@ export class ChartDataRequestBuilder { this.script = script || false; this.aggregation = aggregation; } - private buildAggregators() { const aggColumns = this.chartDataConfigs.reduce<ChartDataSectionField[]>( (acc, cur) => { if (!cur.rows) { return acc; } + if (this.aggregation === false) { return acc; } @@ -131,6 +132,15 @@ export class ChartDataRequestBuilder { ) { return acc.concat(cur.rows); } + + if ( + cur.type === ChartDataSectionType.MIXED && + !cur.rows?.every(v => v.type === ChartDataViewFieldType.NUMERIC) + ) { + return acc.concat( + cur.rows.filter(v => v.type === ChartDataViewFieldType.NUMERIC), + ); + } return acc; }, [], @@ -331,9 +341,6 @@ export class ChartDataRequestBuilder { } } - if (cur.type === ChartDataSectionType.MIXED) { - return acc.concat(cur.rows); - } return acc; }, [], @@ -382,6 +389,22 @@ export class ChartDataRequestBuilder { ) { return acc.concat(cur.rows); } + if ( + cur.type === ChartDataSectionType.MIXED && + !cur.rows?.every( + v => + v.type !== ChartDataViewFieldType.DATE && + v.type !== ChartDataViewFieldType.STRING, + ) + ) { + return acc.concat( + cur.rows.filter( + v => + v.type === ChartDataViewFieldType.DATE || + v.type === ChartDataViewFieldType.STRING, + ), + ); + } return acc; }, [], From 12fc1fdd137def6921f9c4b99a30ac35e3ec0ea1 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Thu, 30 Dec 2021 15:16:27 +0800 Subject: [PATCH 290/348] fix: Modify the problem of judging whether it contains NUMERIC type --- .../app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts index 50878382f..08829f946 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartHttpRequest.ts @@ -135,7 +135,9 @@ export class ChartDataRequestBuilder { if ( cur.type === ChartDataSectionType.MIXED && - !cur.rows?.every(v => v.type === ChartDataViewFieldType.NUMERIC) + cur.rows?.findIndex( + v => v.type === ChartDataViewFieldType.NUMERIC, + ) !== -1 ) { return acc.concat( cur.rows.filter(v => v.type === ChartDataViewFieldType.NUMERIC), @@ -397,6 +399,7 @@ export class ChartDataRequestBuilder { v.type !== ChartDataViewFieldType.STRING, ) ) { + //zh: 判断数据中是否含有 DATE 和 STRING 类型 en: Determine whether the data contains DATE and STRING types return acc.concat( cur.rows.filter( v => From bb54fb5e75e3e804bb35b33842d8a24109818a85 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Thu, 30 Dec 2021 15:21:58 +0800 Subject: [PATCH 291/348] chore: member page i18n support --- .../MainPage/pages/MemberPage/InviteForm.tsx | 6 ++- .../pages/MemberPage/Sidebar/MemberList.tsx | 17 ++++--- .../pages/MemberPage/Sidebar/RoleList.tsx | 9 ++-- .../pages/MemberPage/Sidebar/index.tsx | 8 ++-- .../MemberPage/pages/MemberDetailPage.tsx | 41 ++++++++++------- .../pages/RoleDetailPage/MemberTable.tsx | 22 +++++---- .../MemberPage/pages/RoleDetailPage/index.tsx | 34 +++++++------- frontend/src/locales/en/translation.json | 45 +++++++++++++++++++ frontend/src/locales/zh/translation.json | 45 +++++++++++++++++++ 9 files changed, 171 insertions(+), 56 deletions(-) diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/InviteForm.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/InviteForm.tsx index 0cfa14449..c76fc6140 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/InviteForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/InviteForm.tsx @@ -18,6 +18,7 @@ import { Checkbox, Form, FormInstance, Select } from 'antd'; import { ModalForm, ModalFormProps } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { User } from 'app/slice/types'; import { DEFAULT_DEBOUNCE_WAIT } from 'globalConstants'; import debounce from 'lodash/debounce'; @@ -34,6 +35,7 @@ export const InviteForm = memo( ({ formProps, afterClose, ...modalProps }: ModalFormProps) => { const [options, setOptions] = useState<ValueType[]>([]); const formRef = useRef<FormInstance>(); + const t = useI18NPrefix('member.form'); const debouncedSearchUser = useMemo(() => { const searchUser = async (val: string) => { @@ -71,13 +73,13 @@ export const InviteForm = memo( <Form.Item name="emails"> <Select<ValueType> mode="tags" - placeholder="请搜索或粘贴被邀请成员邮箱" + placeholder={t('search')} options={options} onSearch={debouncedSearchUser} /> </Form.Item> <Form.Item name="sendMail" valuePropName="checked" initialValue={true}> - <Checkbox>需要被邀请成员邮件确认</Checkbox> + <Checkbox>{t('needConfirm')}</Checkbox> </Form.Item> </ModalForm> ); diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/MemberList.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/MemberList.tsx index e30e32e83..b22269718 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/MemberList.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/MemberList.tsx @@ -20,6 +20,7 @@ import { LoadingOutlined, UserAddOutlined } from '@ant-design/icons'; import { List, Modal } from 'antd'; import { Avatar, ListItem, ListTitle } from 'app/components'; import { useDebouncedSearch } from 'app/hooks/useDebouncedSearch'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { memo, ReactElement, @@ -53,6 +54,8 @@ export const MemberList = memo(() => { '/organizations/:orgId/members/:memberId', ); const memberId = matchRoleDetail?.params.memberId; + const t = useI18NPrefix('member.sidebar'); + const { filteredData, debouncedSearch } = useDebouncedSearch( list, (keywords, d) => { @@ -88,7 +91,7 @@ export const MemberList = memo(() => { if (values.sendMail) { if (success.length > 0) { - title.push('邀请邮件已成功发送'); + title.push(t('inviteSuccess')); } } else { if (success.length > 0) { @@ -97,7 +100,7 @@ export const MemberList = memo(() => { } if (fail.length > 0) { - title.push('请检查以下无效邮件地址'); + title.push(t('invalidEmail')); fail.forEach(e => { content.push(<p>{e}</p>); }); @@ -115,7 +118,7 @@ export const MemberList = memo(() => { }), ); }, - [dispatch, orgId], + [dispatch, orgId, t], ); const toDetail = useCallback( @@ -128,16 +131,16 @@ export const MemberList = memo(() => { const titleProps = useMemo( () => ({ key: 'list', - subTitle: '成员列表', + subTitle: t('memberTitle'), search: true, add: { - items: [{ key: 'invite', text: '邀请成员' }], + items: [{ key: 'invite', text: t('inviteMember') }], icon: <UserAddOutlined />, callback: showInviteForm, }, onSearch: debouncedSearch, }), - [showInviteForm, debouncedSearch], + [showInviteForm, debouncedSearch, t], ); return ( <Wrapper> @@ -166,7 +169,7 @@ export const MemberList = memo(() => { /> </ListWrapper> <InviteForm - title="邀请成员" + title={t('inviteMember')} visible={inviteFormVisible} confirmLoading={inviteLoading} onSave={invite} diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/RoleList.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/RoleList.tsx index 8ddc5e8a4..5d7ae277a 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/RoleList.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/RoleList.tsx @@ -20,6 +20,7 @@ import { LoadingOutlined, PlusOutlined } from '@ant-design/icons'; import { List } from 'antd'; import { ListItem, ListTitle } from 'app/components'; import { useDebouncedSearch } from 'app/hooks/useDebouncedSearch'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { memo, useCallback, useEffect, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory, useRouteMatch } from 'react-router-dom'; @@ -38,6 +39,8 @@ export const RoleList = memo(() => { '/organizations/:orgId/roles/:roleId', ); const roleId = matchRoleDetail?.params.roleId; + const t = useI18NPrefix('member.sidebar'); + const { filteredData, debouncedSearch } = useDebouncedSearch( list, (keywords, d) => d.name.toLowerCase().includes(keywords.toLowerCase()), @@ -61,16 +64,16 @@ export const RoleList = memo(() => { const titleProps = useMemo( () => ({ key: 'list', - subTitle: '角色列表', + subTitle: t('roleTitle'), search: true, add: { - items: [{ key: 'add', text: '新建角色' }], + items: [{ key: 'add', text: t('addRole') }], icon: <PlusOutlined />, callback: toAdd, }, onSearch: debouncedSearch, }), - [toAdd, debouncedSearch], + [toAdd, debouncedSearch, t], ); return ( diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/index.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/index.tsx index fceff1f23..9d78b3483 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/Sidebar/index.tsx @@ -18,6 +18,7 @@ import { TeamOutlined, UserOutlined } from '@ant-design/icons'; import { ListSwitch } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; @@ -32,6 +33,7 @@ export const Sidebar = memo(() => { const history = useHistory(); const orgId = useSelector(selectOrgId); const { url } = useRouteMatch(); + const t = useI18NPrefix('member.sidebar'); useEffect(() => { const urlArr = url.split('/'); @@ -40,14 +42,14 @@ export const Sidebar = memo(() => { const titles = useMemo( () => [ - { key: 'members', icon: <UserOutlined />, text: '成员' }, + { key: 'members', icon: <UserOutlined />, text: t('member') }, { key: 'roles', icon: <TeamOutlined />, - text: '角色', + text: t('role'), }, ], - [], + [t], ); const switchSelect = useCallback( diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/MemberDetailPage.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/MemberDetailPage.tsx index ccc494f7c..46a70612b 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/MemberDetailPage.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/MemberDetailPage.tsx @@ -19,6 +19,7 @@ import { LoadingOutlined } from '@ant-design/icons'; import { Button, Card, Form, message, Popconfirm, Select } from 'antd'; import { DetailPageHeader } from 'app/components/DetailPageHeader'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { useCallback, useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory, useRouteMatch } from 'react-router-dom'; @@ -61,6 +62,8 @@ export function MemberDetailPage() { params: { memberId }, } = useRouteMatch<{ memberId: string }>(); const [form] = Form.useForm(); + const t = useI18NPrefix('member.memberDetail'); + const tg = useI18NPrefix('global'); const resetForm = useCallback(() => { form.resetFields(); @@ -107,11 +110,11 @@ export function MemberDetailPage() { orgId: orgId, roles: roleSelectValues.map(id => roles.find(r => r.id === id)!), resolve: () => { - message.success('修改成功'); + message.success(tg('operation.updateSuccess')); }, }), ); - }, [dispatch, orgId, roleSelectValues, roles]); + }, [dispatch, orgId, roleSelectValues, roles, tg]); const remove = useCallback(() => { dispatch( @@ -119,12 +122,12 @@ export function MemberDetailPage() { id: editingMember!.info.id, orgId: orgId, resolve: () => { - message.success('移除成功'); + message.success(t('removeSuccess')); history.replace(`/organizations/${orgId}/members`); }, }), ); - }, [dispatch, history, orgId, editingMember]); + }, [dispatch, history, orgId, editingMember, t]); const grantOrgOwner = useCallback( (grant: boolean) => () => { @@ -133,23 +136,23 @@ export function MemberDetailPage() { userId: editingMember.info.id, orgId, resolve: () => { - message.success(`${grant ? '设置' : '撤销'}成功`); + message.success(grant ? t('grantSuccess') : t('revokeSuccess')); }, }; dispatch(grant ? grantOwner(params) : revokeOwner(params)); } }, - [dispatch, orgId, editingMember], + [dispatch, orgId, editingMember, t], ); return ( <Wrapper> <DetailPageHeader - title="成员详情" + title={t('title')} actions={ <> <Button type="primary" loading={saveMemberLoading} onClick={save}> - 保存 + {tg('button.save')} </Button> {editingMember?.info.orgOwner ? ( <Button @@ -157,16 +160,16 @@ export function MemberDetailPage() { onClick={grantOrgOwner(false)} danger > - 撤销拥有者 + {t('revokeOwner')} </Button> ) : ( <Button loading={grantLoading} onClick={grantOrgOwner(true)}> - 设为组织拥有者 + {t('grantOwner')} </Button> )} - <Popconfirm title="确定移除该成员?" onConfirm={remove}> - <Button danger>移除成员</Button> + <Popconfirm title={t('removeConfirm')} onConfirm={remove}> + <Button danger>{t('remove')}</Button> </Popconfirm> </> } @@ -180,17 +183,21 @@ export function MemberDetailPage() { labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} > - <Form.Item label="用户名">{editingMember?.info.username}</Form.Item> - <Form.Item label="邮箱">{editingMember?.info.email}</Form.Item> - <Form.Item label="用户姓名"> + <Form.Item label={t('username')}> + {editingMember?.info.username} + </Form.Item> + <Form.Item label={t('email')}> + {editingMember?.info.email} + </Form.Item> + <Form.Item label={t('name')}> {editingMember?.info.name || '-'} </Form.Item> - <Form.Item label="角色列表"> + <Form.Item label={t('roles')}> {getMemberRolesLoading ? ( <LoadingOutlined /> ) : ( <Select - placeholder="为用户指定角色" + placeholder={t('assignRole')} mode="multiple" loading={roleListLoading} onDropdownVisibleChange={roleListVisibleChange} diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/MemberTable.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/MemberTable.tsx index ddedfb1de..6c213bdf8 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/MemberTable.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/MemberTable.tsx @@ -22,6 +22,7 @@ import { SearchOutlined, } from '@ant-design/icons'; import { Button, Col, Input, Row, Table } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { User } from 'app/slice/types'; import { DEFAULT_DEBOUNCE_WAIT } from 'globalConstants'; import debounce from 'lodash/debounce'; @@ -40,6 +41,9 @@ export const MemberTable = memo( ({ loading, dataSource, onAdd, onChange }: MemberTableProps) => { const [keywords, setKeywords] = useState(''); const [selectedRowKeys, setSelectedRowKeys] = useState<Key[]>([]); + const t = useI18NPrefix('member.roleDetail'); + const tg = useI18NPrefix('global'); + const filteredSource = useMemo( () => dataSource.filter( @@ -73,19 +77,19 @@ export const MemberTable = memo( const columns = useMemo( () => [ - { dataIndex: 'username', title: '用户名' }, - { dataIndex: 'email', title: '邮箱' }, - { dataIndex: 'name', title: '姓名' }, + { dataIndex: 'username', title: t('username') }, + { dataIndex: 'email', title: t('email') }, + { dataIndex: 'name', title: t('name') }, { - title: '操作', + title: tg('title.action'), width: 80, align: 'center' as const, render: (_, record) => ( - <Action onClick={removeMember(record.id)}>移除</Action> + <Action onClick={removeMember(record.id)}>{t('remove')}</Action> ), }, ], - [removeMember], + [removeMember, t, tg], ); return ( @@ -98,7 +102,7 @@ export const MemberTable = memo( className="btn" onClick={onAdd} > - 添加成员 + {t('addMember')} </Button> </Col> <Col span={14}> @@ -109,13 +113,13 @@ export const MemberTable = memo( className="btn" onClick={removeSelectedMember} > - 批量删除 + {t('deleteAll')} </Button> )} </Col> <Col span={6}> <Input - placeholder="搜索成员关键字" + placeholder={t('searchMember')} prefix={<SearchOutlined className="icon" />} bordered={false} onChange={debouncedSearch} diff --git a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx index f55631586..15f20f9d6 100644 --- a/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/MemberPage/pages/RoleDetailPage/index.tsx @@ -18,6 +18,7 @@ import { Button, Card, Form, Input, message, Popconfirm } from 'antd'; import { DetailPageHeader } from 'app/components/DetailPageHeader'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { User } from 'app/slice/types'; import debounce from 'debounce-promise'; import { CommonFormTypes, DEFAULT_DEBOUNCE_WAIT } from 'globalConstants'; @@ -41,7 +42,6 @@ import { editRole, getRoleMembers, } from '../../slice/thunks'; -import useI18NPrefix from 'app/hooks/useI18NPrefix' import { Role } from '../../slice/types'; import { MemberForm } from './MemberForm'; import { MemberTable } from './MemberTable'; @@ -60,6 +60,7 @@ export function RoleDetailPage() { const editingRole = useSelector(selectEditingRole); const getRoleMembersLoading = useSelector(selectGetRoleMembersLoading); const saveRoleLoading = useSelector(selectSaveRoleLoading); + const t = useI18NPrefix('member.roleDetail'); const tg = useI18NPrefix('global'); const { params } = useRouteMatch<{ roleId: string }>(); const { roleId } = params; @@ -112,7 +113,7 @@ export function RoleDetailPage() { addRole({ role: { ...values, avatar: '', orgId }, resolve: () => { - message.success('新建成功'); + message.success(t('createSuccess')); resetForm(); }, }), @@ -124,7 +125,7 @@ export function RoleDetailPage() { role: { ...values, orgId }, members: memberTableDataSource, resolve: () => { - message.success('修改成功'); + message.success(tg('operation.updateSuccess')); }, }), ); @@ -133,7 +134,7 @@ export function RoleDetailPage() { break; } }, - [dispatch, orgId, formType, memberTableDataSource, resetForm], + [dispatch, orgId, formType, memberTableDataSource, resetForm, t, tg], ); const del = useCallback(() => { @@ -141,17 +142,17 @@ export function RoleDetailPage() { deleteRole({ id: editingRole!.info.id, resolve: () => { - message.success('删除成功'); + message.success(tg('operation.deleteSuccess')); history.replace(`/organizations/${orgId}/roles`); }, }), ); - }, [dispatch, history, orgId, editingRole]); + }, [dispatch, history, orgId, editingRole, tg]); return ( <Wrapper> <DetailPageHeader - title={`${tg(`modal.title.${formType}`)}角色`} + title={`${tg(`modal.title.${formType}`)}${t('role')}`} actions={ <> <Button @@ -159,11 +160,11 @@ export function RoleDetailPage() { loading={saveRoleLoading} onClick={form.submit} > - 保存 + {tg('button.save')} </Button> {formType === CommonFormTypes.Edit && ( - <Popconfirm title="确认删除?" onConfirm={del}> - <Button danger>删除角色</Button> + <Popconfirm title={tg('operation.deleteConfirm')} onConfirm={del}> + <Button danger>{`${tg('button.delete')}${t('role')}`}</Button> </Popconfirm> )} </> @@ -181,10 +182,13 @@ export function RoleDetailPage() { > <Form.Item name="name" - label="名称" + label={t('roleName')} validateFirst rules={[ - { required: true, message: '名称不能为空' }, + { + required: true, + message: `${t('roleName')}${tg('validation.required')}`, + }, { validator: debounce((_, value) => { if (value === editingRole?.info.name) { @@ -205,11 +209,11 @@ export function RoleDetailPage() { > <Input /> </Form.Item> - <Form.Item name="description" label="描述"> + <Form.Item name="description" label={t('description')}> <Input.TextArea /> </Form.Item> {formType === CommonFormTypes.Edit && ( - <Form.Item label="关联成员" wrapperCol={{ span: 17 }}> + <Form.Item label={t('relatedMember')} wrapperCol={{ span: 17 }}> <MemberTable loading={getRoleMembersLoading} dataSource={memberTableDataSource} @@ -221,7 +225,7 @@ export function RoleDetailPage() { </Form> </Card> <MemberForm - title="添加成员" + title={t('addMember')} visible={memberFormVisible} width={992} onCancel={hideMemberForm} diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 06ca4dd3f..93b9e2fc1 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -782,6 +782,51 @@ "duplicateName": "Duplicate Name" } }, + "member": { + "memberDetail": { + "title": "Member detail", + "grantOwner": "Granted to organization owner", + "revokeOwner": "Revoke owner", + "remove": "Remove", + "removeConfirm": "Remove confirm", + "removeSuccess": "Remove successful", + "grantSuccess": "Grant successful", + "revokeSuccess": "Revoke successful", + "username": "Username", + "email": "Email", + "name": "Name", + "roles": "Roles", + "assignRole": "Assign roles" + }, + "roleDetail": { + "role": "Role", + "createSuccess": "Role created successfully", + "roleName": "Name", + "description": "Description", + "relatedMember": "Related member", + "addMember": "Add member", + "deleteAll": "Delete all", + "searchMember": "Search member", + "username": "Username", + "email": "Email", + "name": "Name", + "remove": "Remove" + }, + "form": { + "search": "Search or paste the emails of invited members", + "needConfirm": "Need email confirmation" + }, + "sidebar": { + "member": "Members", + "role": "Roles", + "memberTitle": "Members", + "inviteMember": "Invite member", + "inviteSuccess": "The invitation email has been sent successfully", + "invalidEmail": "Invalid email addresses", + "roleTitle": "Roles", + "addRole": "Create role" + } + }, "share": { "common": { "confirm": "Confirm", diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 66ffd4ce2..0713f71b7 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -781,6 +781,51 @@ "duplicateName": "名称重复" } }, + "member": { + "memberDetail": { + "title": "成员详情", + "grantOwner": "设为组织拥有者", + "revokeOwner": "撤销拥有者", + "remove": "移除成员", + "removeConfirm": "确定移除该成员?", + "removeSuccess": "移除成功", + "grantSuccess": "设置成功", + "revokeSuccess": "撤销成功", + "username": "用户名", + "email": "邮箱", + "name": "用户姓名", + "roles": "角色列表", + "assignRole": "为用户指定角色" + }, + "roleDetail": { + "role": "角色", + "createSuccess": "新建角色成功", + "roleName": "名称", + "description": "描述", + "relatedMember": "关联成员", + "addMember": "添加成员", + "deleteAll": "批量删除", + "searchMember": "搜索成员关键字", + "username": "用户名", + "email": "邮箱", + "name": "用户姓名", + "remove": "移除" + }, + "form": { + "search": "请搜索或粘贴被邀请成员邮箱", + "needConfirm": "需要被邀请成员邮件确认" + }, + "sidebar": { + "member": "成员", + "role": "角色", + "memberTitle": "成员列表", + "inviteMember": "邀请成员", + "inviteSuccess": "邀请邮件已成功发送", + "invalidEmail": "请检查以下无效邮件地址", + "roleTitle": "角色列表", + "addRole": "新建角色" + } + }, "share": { "common": { "confirm": "请确认", From e860237cfce407d8173a2c193a7a28853beb6b41 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 30 Dec 2021 14:56:32 +0800 Subject: [PATCH 292/348] chore: add Associated Widgets i18n --- .../components/ControllerWidgetPanel/RelatedWidgets.tsx | 8 +++++--- frontend/src/locales/en/translation.json | 3 +++ frontend/src/locales/zh/translation.json | 3 +++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/RelatedWidgets.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/RelatedWidgets.tsx index ae4392895..3dbcf42b2 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/RelatedWidgets.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/RelatedWidgets.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ import { Table } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { Widget } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import React, { memo, useEffect, useMemo, useState } from 'react'; @@ -31,6 +32,7 @@ export interface RelatedWidgetsProps { export const RelatedWidgets: React.FC<RelatedWidgetsProps> = memo( ({ widgets, relatedWidgets, onChange }) => { + const tw = useI18NPrefix(`viz.widget`); const [selectedWidgetIds, setSelectedWidgetIds] = useState<string[]>([]); const rowSelection = keys => { @@ -49,11 +51,11 @@ export const RelatedWidgets: React.FC<RelatedWidgetsProps> = memo( const columns = useMemo( () => [ { - title: '组件名称', + title: tw('widgetName'), render: (w: Widget) => <span>{w.config.name}</span>, }, { - title: '组件类型', + title: tw('widgetType'), render: (w: Widget) => <span>{w.config.type}</span>, }, ], @@ -61,7 +63,7 @@ export const RelatedWidgets: React.FC<RelatedWidgetsProps> = memo( ); return ( <> - <h3>关联组件</h3> + <h3>{tw('associatedWidget')}</h3> <Table rowKey={record => record.id} rowSelection={{ diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 1d0f4ee68..6f9a91e00 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -619,6 +619,9 @@ }, "widget": { "widget": "Widget", + "associatedWidget":"Associated Widgets", + "widgetName":"Widget Name", + "widgetType":"Widget Type", "type": { "chart": "Chart", "widgetChart": "privateChart", diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index a0fcce1fa..ef0b6cc21 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -617,6 +617,9 @@ }, "widget": { "widget": "组件", + "associatedWidget":"关联组件", + "widgetName":"组件名称", + "widgetType":"组件类型", "type": { "chart": "数据图表", "widgetChart": "私有图表", From aa8705ffe058eed07a91dcabefe8f8fd4a1aefd5 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 30 Dec 2021 15:36:47 +0800 Subject: [PATCH 293/348] chore: add widget linkage i18n --- .../ControllerWidgetPanel/RelatedViewForm.tsx | 18 +++--- .../ControllerWidgetPanel/RelatedWidgets.tsx | 2 +- .../components/LinkagePanel/LinkageFields.tsx | 27 ++++---- .../components/LinkagePanel/index.tsx | 4 +- .../LinkagePanel/linkageWidgets.tsx | 5 +- frontend/src/locales/en/translation.json | 60 +++++++++++------- frontend/src/locales/zh/translation.json | 63 +++++++++++-------- 7 files changed, 105 insertions(+), 74 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/RelatedViewForm.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/RelatedViewForm.tsx index 20bb34f4a..54f262a79 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/RelatedViewForm.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/RelatedViewForm.tsx @@ -23,6 +23,7 @@ import { RadioChangeEvent, Select, } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { ControllerWidgetContent, RelatedView, @@ -50,6 +51,7 @@ const RadioButton = Radio.Button; const RadioGroup = Radio.Group; export const RelatedViewForm: React.FC<RelatedViewFormProps> = memo( ({ viewMap, form, queryVariables, controllerType, getFormRelatedViews }) => { + const t = useI18NPrefix(`viz.associate`); const isMultiple = useCallback( index => { const relatedViews = getFormRelatedViews(); @@ -64,11 +66,11 @@ export const RelatedViewForm: React.FC<RelatedViewFormProps> = memo( ); const fieldValueValidator = async (opt, fieldValue: string[]) => { if (!fieldValue) { - return Promise.reject(new Error('请关联字段 或 变量')); + return Promise.reject(new Error(t('noValueErr'))); } if (Array.isArray(fieldValue)) { if (fieldValue.length !== 2) { - return Promise.reject(new Error('请选择字段 或 两个变量')); + return Promise.reject(new Error(t('valueErr'))); } } @@ -163,7 +165,7 @@ export const RelatedViewForm: React.FC<RelatedViewFormProps> = memo( return ( <Wrap> - <h3>关联字段/变量</h3> + <h3>{t('title')}</h3> <Form.List name="relatedViews" rules={[ @@ -181,7 +183,7 @@ export const RelatedViewForm: React.FC<RelatedViewFormProps> = memo( <Form.Item noStyle key={index} shouldUpdate> <div className="relatedView"> <h4>{getViewName(index)}</h4> - <div style={{ width: '106px' }}> + <div style={{ width: '140px', textAlign: 'right' }}> <Form.Item {...field} validateTrigger={['onChange', 'onClick', 'onBlur']} @@ -196,12 +198,12 @@ export const RelatedViewForm: React.FC<RelatedViewFormProps> = memo( <RadioButton value={ChartDataViewFieldCategory.Field} > - 字段 + {t('field')} </RadioButton> <RadioButton value={ChartDataViewFieldCategory.Variable} > - 变量 + {t('variable')} </RadioButton> </RadioGroup> </Form.Item> @@ -232,9 +234,7 @@ export const RelatedViewForm: React.FC<RelatedViewFormProps> = memo( <Form.Item> <Form.ErrorList errors={errors} /> </Form.Item> - {!fields.length && ( - <Empty key="empty" description="请选择组件" /> - )} + {!fields.length && <Empty key="empty" />} </> ); }} diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/RelatedWidgets.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/RelatedWidgets.tsx index 3dbcf42b2..b30d7344a 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/RelatedWidgets.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/ControllerWidgetPanel/RelatedWidgets.tsx @@ -59,7 +59,7 @@ export const RelatedWidgets: React.FC<RelatedWidgetsProps> = memo( render: (w: Widget) => <span>{w.config.type}</span>, }, ], - [], + [tw], ); return ( <> diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/LinkageFields.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/LinkageFields.tsx index fee856c22..4d7824455 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/LinkageFields.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/LinkageFields.tsx @@ -17,12 +17,13 @@ */ import { LinkOutlined } from '@ant-design/icons'; import { Divider, Empty, Form, FormInstance, Select } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { Widget } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import { ChartDataSectionField } from 'app/types/ChartConfig'; import ChartDataView, { ChartDataViewFieldType } from 'app/types/ChartDataView'; import React, { memo, useCallback } from 'react'; import styled from 'styled-components/macro'; -import { PRIMARY } from 'styles/StyleConstants'; +import { G20, PRIMARY } from 'styles/StyleConstants'; const { Option } = Select; export interface ViewLinkageItem { sameView?: boolean; @@ -41,7 +42,7 @@ export interface LinkageFieldsProps { } export const LinkageFields: React.FC<LinkageFieldsProps> = memo( ({ form, viewMap, curWidget, chartGroupColumns }) => { - // const dataChart + const t = useI18NPrefix(`viz.linkage`); const renderOptions = useCallback( (index: number, key: 'triggerViewId' | 'linkerViewId') => { const viewLinkages: ViewLinkageItem[] = @@ -58,7 +59,7 @@ export const LinkageFields: React.FC<LinkageFieldsProps> = memo( > <div style={{ display: 'flex', justifyContent: 'space-between' }}> <span>{item.colName}</span> - <span style={{ color: '#ccc' }}>{item.type}</span> + <span style={{ color: G20 }}>{item.type}</span> </div> </Option> )); @@ -73,7 +74,7 @@ export const LinkageFields: React.FC<LinkageFieldsProps> = memo( style={{ display: 'flex', justifyContent: 'space-between' }} > <span>{item.id}</span> - <span style={{ color: '#ccc' }}>{item.type}</span> + <span style={{ color: G20 }}>{item.type}</span> </div> </Option> )); @@ -102,9 +103,11 @@ export const LinkageFields: React.FC<LinkageFieldsProps> = memo( ); return ( <Wrap> - <Divider orientation="left">关联字段</Divider> + <Divider orientation="left">{t('associatedFields')}</Divider> - <div> 数据源 : {viewMap[curWidget?.viewIds?.[0]]?.name}</div> + <div> + {t('dataSource')} : {viewMap[curWidget?.viewIds?.[0]]?.name} + </div> <Form.List name="viewLinkages"> {(fields, _, { errors }) => { return ( @@ -121,13 +124,13 @@ export const LinkageFields: React.FC<LinkageFieldsProps> = memo( name={[field.name, 'triggerColumn']} fieldKey={[field.fieldKey, 'id']} rules={[ - { required: true, message: '请选择 触发字段' }, + { required: true, message: t('selectTriggers') }, ]} > <Select style={{ width: 200 }} showSearch - placeholder="请选择 触发字段" + placeholder={t('selectTriggers')} allowClear > {renderOptions(index, 'triggerViewId')} @@ -146,14 +149,14 @@ export const LinkageFields: React.FC<LinkageFieldsProps> = memo( validateTrigger={['onChange', 'onClick', 'onBlur']} name={[field.name, 'linkerColumn']} rules={[ - { required: true, message: '请选择 联动字段' }, + { required: true, message: t('selectLinker') }, ]} fieldKey={[field.fieldKey, 'id']} > <Select style={{ width: 200 }} showSearch - placeholder="请选择 联动字段" + placeholder={t('selectLinker')} allowClear > {renderOptions(index, 'linkerViewId')} @@ -171,9 +174,7 @@ export const LinkageFields: React.FC<LinkageFieldsProps> = memo( <Form.Item> <Form.ErrorList errors={errors} /> </Form.Item> - {!fields.length && ( - <Empty key="empty" description="请选择组件" /> - )} + {!fields.length && <Empty key="empty" />} </FormWrap> ); }} diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/index.tsx index 078928b27..8f4cbae48 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/index.tsx @@ -17,6 +17,7 @@ */ import { Form, Modal } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { selectDataChartById, selectViewMap, @@ -48,6 +49,7 @@ import { LinkageWidgets } from './linkageWidgets'; export interface LinkagePanelProps {} export const LinkagePanel: React.FC<LinkagePanelProps> = memo(() => { + const t = useI18NPrefix(`viz.linkage`); const [form] = Form.useForm(); const dispatch = useDispatch(); const { type, widgetId } = useSelector(selectLinkagePanel); @@ -224,7 +226,7 @@ export const LinkagePanel: React.FC<LinkagePanelProps> = memo(() => { return ( <Modal // title={`${type} 联动`} - title={'联动设置'} + title={t('title')} visible={visible} onOk={onSubmit} centered diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/linkageWidgets.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/linkageWidgets.tsx index 72d6aa81b..9670b0a0c 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/linkageWidgets.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/linkageWidgets.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ import { Checkbox, Col, Divider, Row } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { Widget } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import React, { memo, useCallback, useEffect, useState } from 'react'; @@ -28,7 +29,7 @@ export interface RelatedWidgetsProps { export const LinkageWidgets: React.FC<RelatedWidgetsProps> = memo( ({ widgets, onChange, curWidget }) => { const [selectedWidgetIds, setSelectedWidgetIds] = useState<string[]>([]); - + const t = useI18NPrefix(`viz.linkage`); useEffect(() => { if (!curWidget) { return; @@ -55,7 +56,7 @@ export const LinkageWidgets: React.FC<RelatedWidgetsProps> = memo( ); return ( <> - <Divider orientation="left">关联组件</Divider> + <Divider orientation="left">{t('associatedWidgets')}</Divider> <Checkbox.Group value={selectedWidgetIds} style={{ width: '100%' }} diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 6f9a91e00..df0ea7248 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -11,8 +11,8 @@ "restore": "Restore", "delete": "Delete", "info": "Info", - "open":"Open", - "close":"Close" + "open": "Open", + "close": "Close" }, "operation": { "archiveConfirm": "Archive confirm", @@ -216,7 +216,6 @@ "filterVisibility": "Filter Visibility", "aggregates": "Aggregates", "filterOption": "Filter Option", - "visibility": "Visibility", "facade": "Facade", "widthOption": "Width Option", @@ -619,9 +618,9 @@ }, "widget": { "widget": "Widget", - "associatedWidget":"Associated Widgets", - "widgetName":"Widget Name", - "widgetType":"Widget Type", + "associatedWidget": "Associated Widgets", + "widgetName": "Widget Name", + "widgetType": "Widget Type", "type": { "chart": "Chart", "widgetChart": "privateChart", @@ -650,6 +649,21 @@ "closeJump": "Close Jump" } }, + "linkage": { + "title": "Linkage settings", + "dataSource": "Data source", + "associatedWidgets": "Associated Widgets", + "associatedFields": "Associated Fields", + "selectTriggers": "Select the trigger field", + "selectLinker": "Select linkage field" + }, + "associate": { + "title": "Please associate fields/variables", + "field": "Field", + "variable": "Variable", + "noValueErr": "Please associate fields or variables", + "valueErr": "Please select a field or two variables" + }, "sidebar": { "folder": "Folder", "presentation": "Presentation", @@ -685,26 +699,26 @@ "noScale": "noScale" }, "control": { - "title":"Control Title", + "title": "Control Title", "valueConfig": "Value Config", - "selectViewField":"Select ViewField", - "selectDefaultValue":"Select DefaultValue", - "defaultValue":"Default Value", - "visibility":"Visibility", - "sqlOperator":"Sql Operator", - "dateType":"Date Type", - "step":"Step", - "showMark":"Show Mark", + "selectViewField": "Select ViewField", + "selectDefaultValue": "Select DefaultValue", + "defaultValue": "Default Value", + "visibility": "Visibility", + "sqlOperator": "Sql Operator", + "dateType": "Date Type", + "step": "Step", + "showMark": "Show Mark", "common": "General", "custom": "Customize" }, - "date":{ - "year":"Year", - "quarter":"Quarter", - "month":"Month", - "week":"Week", - "date":"Date", - "dateTime":"Date Time" + "date": { + "year": "Year", + "quarter": "Quarter", + "month": "Month", + "week": "Week", + "date": "Date", + "dateTime": "Date Time" } }, "view": { @@ -877,4 +891,4 @@ "searchValue": "Search name keywords" } } -} +} \ No newline at end of file diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index ef0b6cc21..df05217c4 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -11,8 +11,8 @@ "restore": "还原", "delete": "删除", "info": "基本信息", - "open":"开启", - "close":"关闭" + "open": "开启", + "close": "关闭" }, "operation": { "archiveConfirm": "确定移至回收站?", @@ -216,7 +216,6 @@ "filterVisibility": "是否可见", "aggregates": "聚合方式", "filterOption": "筛选方式", - "visibility": "是否显示", "facade": "控制器", "widthOption": "宽度", @@ -617,9 +616,9 @@ }, "widget": { "widget": "组件", - "associatedWidget":"关联组件", - "widgetName":"组件名称", - "widgetType":"组件类型", + "associatedWidget": "关联组件", + "widgetName": "组件名称", + "widgetType": "组件类型", "type": { "chart": "数据图表", "widgetChart": "私有图表", @@ -648,6 +647,21 @@ "closeJump": "关闭跳转" } }, + "linkage": { + "title": "联动设置", + "dataSource": "Data source", + "associatedWidgets": "关联组件", + "associatedFields": "关联字段", + "selectTriggers": "选择触发字段", + "selectLinker": "选择联动字段" + }, + "associate": { + "title": "关联字段/变量", + "field": "字段", + "variable": "变量", + "noValueErr": "请关联字段 或 变量", + "valueErr": "请选择字段 或 两个变量" + }, "sidebar": { "folder": "目录", "presentation": "演示", @@ -683,27 +697,26 @@ "noScale": "实际尺寸" }, "control": { - "title":"控制器标题", + "title": "控制器标题", "valueConfig": "取值配置", - "selectViewField":"选择数据源字段", - "selectDefaultValue":"选择默认值", - "defaultValue":"默认值", - "visibility":"是否显示", - "sqlOperator":"对应关系", - "dateType":"日期类型", - "step":"步长", - "showMark":"显示标签", + "selectViewField": "选择数据源字段", + "selectDefaultValue": "选择默认值", + "defaultValue": "默认值", + "visibility": "是否显示", + "sqlOperator": "对应关系", + "dateType": "日期类型", + "step": "步长", + "showMark": "显示标签", "common": "常规", "custom": "自定义" - - }, - "date":{ - "year":"年", - "quarter":"季度", - "month":"月", - "week":"周", - "date":"日期", - "dateTime":"日期时间" + }, + "date": { + "year": "年", + "quarter": "季度", + "month": "月", + "week": "周", + "date": "日期", + "dateTime": "日期时间" } }, "view": { @@ -876,4 +889,4 @@ "searchValue": "搜索名称关键字" } } -} +} \ No newline at end of file From fa2e5c87590a436f44d7a206fff24470c5311714 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Thu, 30 Dec 2021 15:40:07 +0800 Subject: [PATCH 294/348] translate: pages/mainpage/pages/schedulePage --- frontend/src/app/hooks/useI18NPrefix.ts | 5 + .../slice/workbenchSlice.ts | 5 +- .../BasicBaseForm/ExecuteFormItem.tsx | 65 +++++---- .../EditorPage/BasicBaseForm/index.tsx | 17 ++- .../EmailSettingForm/CommonRichText.tsx | 6 +- .../EmailSettingForm/MailTagFormItem.tsx | 9 +- .../EditorPage/EmailSettingForm/index.tsx | 27 ++-- .../EditorPage/ScheduleErrorLog/index.tsx | 16 ++- .../EditorPage/WeChartSetttingForm.tsx | 18 ++- .../pages/SchedulePage/EditorPage/index.tsx | 50 ++++--- .../SchedulePage/Sidebar/ScheduleList.tsx | 23 ++-- .../pages/SchedulePage/Sidebar/index.tsx | 13 +- .../MainPage/pages/SchedulePage/constants.ts | 22 ++-- frontend/src/locales/en/translation.json | 123 ++++++++++++++++++ frontend/src/locales/zh/translation.json | 123 ++++++++++++++++++ 15 files changed, 411 insertions(+), 111 deletions(-) diff --git a/frontend/src/app/hooks/useI18NPrefix.ts b/frontend/src/app/hooks/useI18NPrefix.ts index 5289e1683..1b4facf3b 100644 --- a/frontend/src/app/hooks/useI18NPrefix.ts +++ b/frontend/src/app/hooks/useI18NPrefix.ts @@ -17,6 +17,7 @@ */ import ChartI18NContext from 'app/pages/ChartWorkbenchPage/contexts/Chart18NContext'; +import i18n from 'i18next'; import get from 'lodash/get'; import { useCallback, useContext } from 'react'; import { useTranslation } from 'react-i18next'; @@ -25,6 +26,10 @@ export interface I18NComponentProps { i18nPrefix?: string; } +export function prefixI18N(key) { + return i18n.t(key); +} + function usePrefixI18N(prefix?: string) { const { t, i18n } = useTranslation(); const { i18NConfigs: vizI18NConfigs } = useContext(ChartI18NContext); diff --git a/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts b/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts index e9da680fb..8677ebb7e 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts @@ -501,8 +501,9 @@ const workbenchSlice = createSlice({ ? JSON.parse(payload.config) : CloneValueDeep(payload.config); backendChartConfig = backendChartConfig || {}; - backendChartConfig.aggregation = - backendChartConfig?.aggregation === undefined ? true : false; + if (backendChartConfig?.aggregation === undefined) { + backendChartConfig.aggregation = true; + } state.backendChart = { ...payload, config: backendChartConfig, diff --git a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/BasicBaseForm/ExecuteFormItem.tsx b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/BasicBaseForm/ExecuteFormItem.tsx index f690cfc00..fbc53db6d 100644 --- a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/BasicBaseForm/ExecuteFormItem.tsx +++ b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/BasicBaseForm/ExecuteFormItem.tsx @@ -1,13 +1,14 @@ import { Checkbox, Form, Input, Select, Space } from 'antd'; +import useI18NPrefix, { prefixI18N } from 'app/hooks/useI18NPrefix'; import { FC, useMemo } from 'react'; import { TimeModes } from '../../constants'; const timeModeOptions = [ - { label: '分钟', value: TimeModes.Minute }, - { label: '小时', value: TimeModes.Hour }, - { label: '天', value: TimeModes.Day }, - { label: '月', value: TimeModes.Month }, - { label: '年', value: TimeModes.Year }, + { label: prefixI18N('global.time.minute'), value: TimeModes.Minute }, + { label: prefixI18N('global.time.hour'), value: TimeModes.Hour }, + { label: prefixI18N('global.time.day'), value: TimeModes.Day }, + { label: prefixI18N('global.time.month'), value: TimeModes.Month }, + { label: prefixI18N('global.time.year'), value: TimeModes.Year }, ]; const minutePeriodOptions = Array.from({ length: 50 }, (_, i) => { const n = i + 10; @@ -15,32 +16,32 @@ const minutePeriodOptions = Array.from({ length: 50 }, (_, i) => { }); const minuteOptions = Array.from({ length: 60 }, (_, i) => { - const n = `${`0${i}`.slice(-2)} 分`; + const n = `${`0${i}`.slice(-2)} ${prefixI18N('global.time.m')}`; return { label: n, value: i }; }); const hourOptions = Array.from({ length: 24 }, (_, i) => { - const n = `${`0${i}`.slice(-2)} 时`; + const n = `${`0${i}`.slice(-2)} ${prefixI18N('global.time.h')}`; return { label: n, value: i }; }); const dayOptions = Array.from({ length: 31 }, (_, i) => { - const n = `${`0${i + 1}`.slice(-2)} 日`; + const n = `${`0${i + 1}`.slice(-2)} ${prefixI18N('global.time.d')}`; return { label: n, value: i + 1 }; }); const monthOptions = Array.from({ length: 12 }, (_, i) => { - const n = `${`0${i + 1}`.slice(-2)} 月`; + const n = `${`0${i + 1}`.slice(-2)} ${prefixI18N('global.time.month')}`; return { label: n, value: i + 1 }; }); const weekOptions = [ - { label: '星期天', value: 1 }, - { label: '星期一', value: 2 }, - { label: '星期二', value: 3 }, - { label: '星期三', value: 4 }, - { label: '星期四', value: 5 }, - { label: '星期五', value: 6 }, - { label: '星期六', value: 7 }, + { label: prefixI18N('global.time.sun'), value: 1 }, + { label: prefixI18N('global.time.mon'), value: 2 }, + { label: prefixI18N('global.time.tues'), value: 3 }, + { label: prefixI18N('global.time.wednes'), value: 4 }, + { label: prefixI18N('global.time.thurs'), value: 5 }, + { label: prefixI18N('global.time.fri'), value: 6 }, + { label: prefixI18N('global.time.satur'), value: 7 }, ]; export interface ExecuteFormItemProps { @@ -55,6 +56,10 @@ export const ExecuteFormItem: FC<ExecuteFormItemProps> = ({ periodInput: isInput, onPeriodInputChange, }) => { + const t = useI18NPrefix( + 'main.pages.schedulePage.sidebar.editorPage.basicBaseForm.executeFormItem', + ); + const modeSelect = useMemo(() => { return ( <Form.Item name="periodUnit"> @@ -92,7 +97,7 @@ export const ExecuteFormItem: FC<ExecuteFormItemProps> = ({ case TimeModes.Minute: return ( <> - 每 + {t('per')} <Form.Item name="minute"> <Select options={minutePeriodOptions} style={{ width: 80 }} /> </Form.Item> @@ -102,20 +107,22 @@ export const ExecuteFormItem: FC<ExecuteFormItemProps> = ({ case TimeModes.Hour: return ( <> - 每 {modeSelect} 的{minuteSelect} + {t('per')} {modeSelect} {t('of')} + {minuteSelect} </> ); case TimeModes.Day: return ( <> - 每 {modeSelect} 的{hourSelect} + {t('per')} {modeSelect} {t('of')} + {hourSelect} {minuteSelect} </> ); case TimeModes.Week: return ( <> - 每 {modeSelect} 的{' '} + {t('per')} {modeSelect} {t('of')}{' '} <Form.Item name="weekDay"> <Select options={weekOptions} style={{ width: 80 }} /> </Form.Item> @@ -124,7 +131,7 @@ export const ExecuteFormItem: FC<ExecuteFormItemProps> = ({ case TimeModes.Month: return ( <> - 每 {modeSelect} 的 {daySelect} + {t('per')} {modeSelect} {t('of')} {daySelect} {hourSelect} {minuteSelect} </> @@ -132,7 +139,8 @@ export const ExecuteFormItem: FC<ExecuteFormItemProps> = ({ case TimeModes.Year: return ( <> - 每 {modeSelect}的 + {t('per')} {modeSelect} + {t('of')} <Form.Item name="month"> <Select options={monthOptions} style={{ width: 80 }} /> </Form.Item> @@ -144,23 +152,26 @@ export const ExecuteFormItem: FC<ExecuteFormItemProps> = ({ default: return; } - }, [timeMode, modeSelect, daySelect, minuteSelect, hourSelect]); + }, [timeMode, modeSelect, daySelect, minuteSelect, hourSelect, t]); return ( - <Form.Item label="执行时间设置" required> + <Form.Item label={t('executionTimeSetting')} required> <Space align="baseline"> {isInput ? ( <Form.Item name="cronExpression" - rules={[{ required: true, message: '表达式为必填项' }]} + rules={[{ required: true, message: t('expressionIsRequired') }]} > - <Input placeholder="请输入cron表达式" style={{ width: 300 }} /> + <Input + placeholder={t('pleaseEnterCronExpression')} + style={{ width: 300 }} + /> </Form.Item> ) : ( timeContent )} <Form.Item name="setCronExpressionManually" valuePropName="checked"> <Checkbox onChange={e => onPeriodInputChange(e.target.checked)}> - 手动输入 + {t('manualInput')} </Checkbox> </Form.Item> </Space> diff --git a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/BasicBaseForm/index.tsx b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/BasicBaseForm/index.tsx index b18078301..b915b67af 100644 --- a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/BasicBaseForm/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/BasicBaseForm/index.tsx @@ -1,8 +1,10 @@ import { DatePicker, Form, Input, Radio } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { FC, useCallback } from 'react'; import { JobTypes, JOB_TYPES_OPTIONS } from '../../constants'; import { checkScheduleName } from '../../services'; import { ExecuteFormItem, ExecuteFormItemProps } from './ExecuteFormItem'; + const { RangePicker } = DatePicker; interface BasicBaseFormProps extends ExecuteFormItemProps { @@ -19,6 +21,9 @@ export const BasicBaseForm: FC<BasicBaseFormProps> = ({ children, ...restProps }) => { + const t = useI18NPrefix( + 'main.pages.schedulePage.sidebar.editorPage.basicBaseForm.index', + ); const checkNameUnique = useCallback( async (_, name) => { if (!isAdd && initialName === name) { @@ -28,32 +33,32 @@ export const BasicBaseForm: FC<BasicBaseFormProps> = ({ return Promise.resolve(); } else { const res = await checkScheduleName(orgId, name); - return res ? Promise.resolve() : Promise.reject('名称已存在'); + return res ? Promise.resolve() : Promise.reject(t('nameAlreadyExists')); } }, - [orgId, isAdd, initialName], + [orgId, isAdd, initialName, t], ); return ( <> <Form.Item - label="名称" + label={t('name')} hasFeedback name="name" validateTrigger={'onBlur'} rules={[ - { required: true, message: '名称为必填项' }, + { required: true, message: t('nameRequired') }, { validator: checkNameUnique }, ]} > <Input autoComplete="new-name" /> </Form.Item> - <Form.Item label="类型" name="jobType"> + <Form.Item label={t('type')} name="jobType"> <Radio.Group options={JOB_TYPES_OPTIONS} onChange={e => onJobTypeChange(e.target.value)} /> </Form.Item> - <Form.Item label="有效时间范围" name={'dateRange'}> + <Form.Item label={t('effectiveTimeRange')} name={'dateRange'}> <RangePicker allowClear showTime format="YYYY-MM-DD HH:mm:ss" /> </Form.Item> <ExecuteFormItem {...restProps} /> diff --git a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/EmailSettingForm/CommonRichText.tsx b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/EmailSettingForm/CommonRichText.tsx index 8235350bd..a534f891b 100644 --- a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/EmailSettingForm/CommonRichText.tsx +++ b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/EmailSettingForm/CommonRichText.tsx @@ -1,10 +1,10 @@ +import { prefixI18N } from 'app/hooks/useI18NPrefix'; import Quill from 'quill'; import { ImageDrop } from 'quill-image-drop-module'; import { FC } from 'react'; import ReactQuill from 'react-quill'; import 'react-quill/dist/quill.snow.css'; import styled from 'styled-components/macro'; - Quill.register('modules/imageDrop', ImageDrop); export const Formats = [ @@ -31,7 +31,9 @@ interface CommonRichTextProps { } export const CommonRichText: FC<CommonRichTextProps> = ({ children, - placeholder = '请输入', + placeholder = prefixI18N( + 'main.pages.schedulePage.sidebar.editorPage.emailSettingForm.commonRichText.pleaseEnter', + ), ...restProps }) => { return ( diff --git a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/EmailSettingForm/MailTagFormItem.tsx b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/EmailSettingForm/MailTagFormItem.tsx index 12b9d1e56..f0cca98b2 100644 --- a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/EmailSettingForm/MailTagFormItem.tsx +++ b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/EmailSettingForm/MailTagFormItem.tsx @@ -1,5 +1,6 @@ import { SearchOutlined, UserOutlined } from '@ant-design/icons'; import { AutoComplete, Avatar, Input, Space, Tag } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { DEFAULT_DEBOUNCE_WAIT } from 'globalConstants'; import debounce from 'lodash/debounce'; import { FC, useCallback, useEffect, useMemo, useState } from 'react'; @@ -25,6 +26,9 @@ export const MailTagFormItem: FC<MailTagFormItemProps> = ({ }) => { const [dataSource, setDataSource] = useState<IUserInfo[]>([]); const [keyword, setKeyword] = useState(''); + const t = useI18NPrefix( + 'main.pages.schedulePage.sidebar.editorPage.emailSettingForm.mailTagFormItem', + ); const emails = useMemo(() => { return value ? value.split(';').filter(v => !!v) : []; @@ -117,10 +121,7 @@ export const MailTagFormItem: FC<MailTagFormItemProps> = ({ onSelect={onSelectOrRemoveEmail} onBlur={() => onSearch('')} > - <Input - suffix={<SearchOutlined />} - placeholder="输入邮箱或姓名关键字查找..." - /> + <Input suffix={<SearchOutlined />} placeholder={t('placeholder')} /> </AutoComplete> </> ); diff --git a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/EmailSettingForm/index.tsx b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/EmailSettingForm/index.tsx index 06a29c222..d8c208fa4 100644 --- a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/EmailSettingForm/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/EmailSettingForm/index.tsx @@ -1,5 +1,6 @@ import { DownCircleOutlined, UpCircleOutlined } from '@ant-design/icons'; import { Checkbox, Col, Form, Input, InputNumber, Row } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { FC, useMemo, useState } from 'react'; import { FileTypes, FILE_TYPE_OPTIONS } from '../../constants'; import { CommonRichText } from './CommonRichText'; @@ -14,7 +15,9 @@ export const EmailSettingForm: FC<EmailSettingFormProps> = ({ onFileTypeChange, }) => { const [showBcc, setShowBcc] = useState(false); - + const t = useI18NPrefix( + 'main.pages.schedulePage.sidebar.editorPage.emailSettingForm.index', + ); const hasImgeWidth = useMemo(() => { return fileType && fileType?.length > 0 ? fileType?.includes(FileTypes.Image) @@ -23,21 +26,21 @@ export const EmailSettingForm: FC<EmailSettingFormProps> = ({ const ccLabel = useMemo(() => { return ( <> - 抄送{' '} + {t('CC') + ' '} <span onClick={() => setShowBcc(!showBcc)}> {' '} {showBcc ? <UpCircleOutlined /> : <DownCircleOutlined />} </span> </> ); - }, [showBcc]); + }, [showBcc,t]); return ( <> <Form.Item - label="主题" + label={t('theme')} name="subject" - rules={[{ required: true, message: '主题为必填项' }]} + rules={[{ required: true, message: t('subjectIsRequired') }]} > <Input /> </Form.Item> @@ -45,7 +48,7 @@ export const EmailSettingForm: FC<EmailSettingFormProps> = ({ <Col span={15}> <Form.Item labelCol={{ span: 8 }} - label="文件类型" + label={t('fileType')} name="type" rules={[{ required: true }]} > @@ -59,22 +62,22 @@ export const EmailSettingForm: FC<EmailSettingFormProps> = ({ {hasImgeWidth ? ( <div className="image_width_form_item_wrapper"> <Form.Item - label="图片宽度" + label={t('picWidth')} labelCol={{ span: 10 }} name="imageWidth" rules={[{ required: true }]} > <InputNumber min={100} /> </Form.Item> - <span className="image_width_unit">像素</span> + <span className="image_width_unit">{t('px')}</span> </div> ) : null} </Col> </Row> <Form.Item - label="收件人" + label={t('recipient')} name="to" - rules={[{ required: true, message: '收件人为必填项' }]} + rules={[{ required: true, message: t('recipientIsRequired') }]} > <MailTagFormItem /> </Form.Item> @@ -82,11 +85,11 @@ export const EmailSettingForm: FC<EmailSettingFormProps> = ({ <MailTagFormItem /> </Form.Item> {showBcc ? ( - <Form.Item label="密送" name="bcc"> + <Form.Item label={t('bcc')} name="bcc"> <MailTagFormItem /> </Form.Item> ) : null} - <Form.Item label="邮件内容" validateFirst name="textContent"> + <Form.Item label={t('contentOfEmail')} validateFirst name="textContent"> <CommonRichText placeholder="This email comes from cron job on the datart." /> </Form.Item> </> diff --git a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/ScheduleErrorLog/index.tsx b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/ScheduleErrorLog/index.tsx index 19799f9ac..8aef600de 100644 --- a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/ScheduleErrorLog/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/ScheduleErrorLog/index.tsx @@ -1,4 +1,5 @@ import { Card, Table, TableColumnsType } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { FC, useEffect, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components'; @@ -20,6 +21,9 @@ export const ScheduleErrorLog: FC<ScheduleErrorLogProps> = ({ scheduleId }) => { const logs = useSelector(selectScheduleLogs), loading = useSelector(selectScheduleLogsLoading); const { actions } = useScheduleSlice(); + const t = useI18NPrefix( + 'main.pages.schedulePage.sidebar.editorPage.scheduleErrorLog.index', + ); useEffect(() => { if (scheduleId) { dispatch(getScheduleErrorLogs({ scheduleId, count: 100 })); @@ -31,10 +35,10 @@ export const ScheduleErrorLog: FC<ScheduleErrorLogProps> = ({ scheduleId }) => { }, [scheduleId, dispatch]); const columns: TableColumnsType<ErrorLog> = useMemo(() => { return [ - { title: '开始时间', dataIndex: 'start', key: 'start' }, - { title: '结束时间', dataIndex: 'end', key: 'end' }, + { title: t('startTime'), dataIndex: 'start', key: 'start' }, + { title: t('endTime'), dataIndex: 'end', key: 'end' }, { - title: '日志阶段', + title: t('logPhase'), dataIndex: 'status', key: 'status', render(status: LogStatus) { @@ -42,19 +46,19 @@ export const ScheduleErrorLog: FC<ScheduleErrorLogProps> = ({ scheduleId }) => { }, }, { - title: '执行信息', + title: t('executionInformation'), dataIndex: 'message', key: 'message', render(text, record) { const isSuccess = record?.status === LogStatus.S15; - return isSuccess ? '成功' : text; + return isSuccess ? t('success') : text; }, }, ]; }, []); if (logs?.length > 0) { return ( - <FormCard title="日志"> + <FormCard title={t('log')}> <FormWrapper> <Table rowKey="id" diff --git a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/WeChartSetttingForm.tsx b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/WeChartSetttingForm.tsx index f5590d739..933d960f2 100644 --- a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/WeChartSetttingForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/WeChartSetttingForm.tsx @@ -1,14 +1,22 @@ import { Checkbox, Col, Form, Input, InputNumber, Row } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { FC } from 'react'; import { WECHART_FILE_TYPE_OPTIONS } from '../constants'; + interface WeChartSetttingFormProps {} export const WeChartSetttingForm: FC<WeChartSetttingFormProps> = ({}) => { + const t = useI18NPrefix( + 'main.pages.schedulePage.sidebar.editorPage.weChartSetttingForm', + ); + return ( <> <Form.Item - label="机器人webhook地址" + label={t('RobotWebhookAddress')} name="webHookUrl" - rules={[{ required: true, message: '机器人webhook地址为必填项' }]} + rules={[ + { required: true, message: t('RobotWebhookAddressIsRequired') }, + ]} > <Input /> </Form.Item> @@ -16,7 +24,7 @@ export const WeChartSetttingForm: FC<WeChartSetttingFormProps> = ({}) => { <Col span={12}> <Form.Item labelCol={{ span: 10 }} - label="文件类型" + label={t('fileType')} name="type" rules={[{ required: true }]} > @@ -26,14 +34,14 @@ export const WeChartSetttingForm: FC<WeChartSetttingFormProps> = ({}) => { <Col span={12}> <div className="image_width_form_item_wrapper"> <Form.Item - label="图片宽度" + label={t('picWidth')} labelCol={{ span: 10 }} name="imageWidth" rules={[{ required: true }]} > <InputNumber min={100} /> </Form.Item> - <span className="image_width_unit">像素</span> + <span className="image_width_unit">{t('px')}</span> </div> </Col> </Row> 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 ee1d00618..ffb453d52 100644 --- a/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SchedulePage/EditorPage/index.tsx @@ -9,6 +9,7 @@ import { Tooltip, } from 'antd'; 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 { useDispatch, useSelector } from 'react-redux'; @@ -64,6 +65,7 @@ export const EditorPage: FC = () => { const deleteLoding = useSelector(selectDeleteLoading); const { toDetails } = useToScheduleDetails(); const isArchived = editingSchedule?.status === 0; + const t = useI18NPrefix('main.pages.schedulePage.sidebar.editorPage.index'); const { actions } = useScheduleSlice(); const { scheduleId, orgId } = params; @@ -79,7 +81,7 @@ export const EditorPage: FC = () => { const onFinish = useCallback(() => { form.validateFields().then((values: FormValues) => { if (!(values?.folderContent && values?.folderContent?.length > 0)) { - message.error('请勾选发送内容'); + message.error(t('tickToSendContent')); return; } const params = toScheduleSubmitParams(values, orgId); @@ -88,7 +90,7 @@ export const EditorPage: FC = () => { addSchedule({ params, resolve: (id: string) => { - message.success('新增成功'); + message.success(t('addSuccess')); toDetails(orgId, id); refreshScheduleList(); }, @@ -100,7 +102,7 @@ export const EditorPage: FC = () => { scheduleId: editingSchedule?.id as string, params: { ...params, id: editingSchedule?.id as string }, resolve: () => { - message.success('保存成功'); + message.success(t('saveSuccess')); refreshScheduleList(); }, }), @@ -115,6 +117,7 @@ export const EditorPage: FC = () => { editingSchedule, refreshScheduleList, toDetails, + t, ]); const onResetForm = useCallback(() => { @@ -190,12 +193,12 @@ export const EditorPage: FC = () => { unarchiveSchedule({ id: editingSchedule!.id, resolve: () => { - message.success('还原成功'); + message.success(t('restoredSuccess')); toDetails(orgId); }, }), ); - }, [dispatch, toDetails, orgId, editingSchedule]); + }, [dispatch, toDetails, orgId, editingSchedule, t]); const del = useCallback( archive => () => { @@ -204,13 +207,15 @@ export const EditorPage: FC = () => { id: editingSchedule!.id, archive, resolve: () => { - message.success(`成功${archive ? '移至回收站' : '删除'}`); + message.success( + `${t('success')}${archive ? t('moveToTrash') : t('delete')}`, + ); toDetails(orgId); }, }), ); }, - [dispatch, toDetails, orgId, editingSchedule], + [dispatch, toDetails, orgId, editingSchedule, t], ); useEffect(() => { @@ -234,16 +239,16 @@ export const EditorPage: FC = () => { <Container ref={setContainer}> <Affix offsetTop={0} target={() => container}> <DetailPageHeader - title={isAdd ? '新建定时任务' : editingSchedule?.name} + title={isAdd ? t('newTimedTask') : editingSchedule?.name} actions={ isArchived ? ( <> - <Popconfirm title="确定还原?" onConfirm={unarchive}> - <Button loading={unarchiveLoading}>还原</Button> + <Popconfirm title={t('sureToRestore')} onConfirm={unarchive}> + <Button loading={unarchiveLoading}>{t('restore')}</Button> </Popconfirm> - <Popconfirm title="确定删除?" onConfirm={del(false)}> + <Popconfirm title={t('sureToDelete')} onConfirm={del(false)}> <Button loading={deleteLoding} danger> - 删除 + {t('delete')} </Button> </Popconfirm> </> @@ -251,7 +256,7 @@ export const EditorPage: FC = () => { <> <Tooltip placement="bottom" - title={active ? '停止后允许修改' : ''} + title={active ? t('allowModificationAfterStopping') : ''} > <Button loading={saveLoding} @@ -259,17 +264,20 @@ export const EditorPage: FC = () => { onClick={form.submit} disabled={active} > - 保存 + {t('save')} </Button> </Tooltip> {!isAdd && ( <Tooltip placement="bottom" - title={active ? '停止后允许移至回收站' : ''} + title={active ? t('allowMoveAfterStopping') : ''} > - <Popconfirm title="确定移至回收站?" onConfirm={del(true)}> + <Popconfirm + title={t('sureMoveRecycleBin')} + onConfirm={del(true)} + > <Button loading={deleteLoding} disabled={active} danger> - 移至回收站 + {t('basicSettings')} </Button> </Popconfirm> </Tooltip> @@ -293,7 +301,7 @@ export const EditorPage: FC = () => { {!isAdd && editingSchedule?.id ? ( <ScheduleErrorLog scheduleId={editingSchedule?.id} /> ) : null} - <FormCard title="基本设置"> + <FormCard title={t('basicSettings')}> <FormWrapper> <BasicBaseForm isAdd={isAdd} @@ -309,7 +317,7 @@ export const EditorPage: FC = () => { </FormCard> {jobType === JobTypes.Email ? ( - <FormCard title="邮件设置"> + <FormCard title={t('emailSetting')}> <FormWrapper> <EmailSettingForm fileType={fileType} @@ -318,13 +326,13 @@ export const EditorPage: FC = () => { </FormWrapper> </FormCard> ) : ( - <FormCard title="企业微信设置"> + <FormCard title={t('enterpriseWeChatSettings')}> <FormWrapper> <WeChartSetttingForm /> </FormWrapper> </FormCard> )} - <FormCard title="发送内容设置"> + <FormCard title={t('sendContentSettings')}> <FormWrapper> <SendContentForm /> </FormWrapper> diff --git a/frontend/src/app/pages/MainPage/pages/SchedulePage/Sidebar/ScheduleList.tsx b/frontend/src/app/pages/MainPage/pages/SchedulePage/Sidebar/ScheduleList.tsx index d8eb241f6..45981a991 100644 --- a/frontend/src/app/pages/MainPage/pages/SchedulePage/Sidebar/ScheduleList.tsx +++ b/frontend/src/app/pages/MainPage/pages/SchedulePage/Sidebar/ScheduleList.tsx @@ -6,6 +6,7 @@ import { } from '@ant-design/icons'; import { ButtonProps, List, message, Popconfirm, Space, Tooltip } from 'antd'; import { IW, ListItem, ToolbarButton } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import classnames from 'classnames'; import { FC, memo, ReactNode, useCallback, useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; @@ -55,6 +56,8 @@ const Operations: FC<OperationsProps> = ({ const [executeLoading, setExecuteLoading] = useState(false); const { actions } = useScheduleSlice(); const dispatch = useDispatch(); + const t = useI18NPrefix('main.pages.schedulePage.sidebar.scheduleList'); + const updateScheduleActive = useCallback( (active: boolean) => { dispatch(actions.setEditingScheduleActive(active)); @@ -66,7 +69,7 @@ const Operations: FC<OperationsProps> = ({ startSchedule(scheduleId) .then(res => { if (!!res) { - message.success('启动成功'); + message.success(t('successStarted')); onUpdateScheduleList(); if (editingId === scheduleId) { updateScheduleActive(true); @@ -76,13 +79,13 @@ const Operations: FC<OperationsProps> = ({ .finally(() => { setStartLoading(false); }); - }, [scheduleId, editingId, onUpdateScheduleList, updateScheduleActive]); + }, [scheduleId, editingId, onUpdateScheduleList, updateScheduleActive, t]); const handleStopSchedule = useCallback(() => { setStopLoading(true); stopSchedule(scheduleId) .then(res => { if (!!res) { - message.success('停止成功'); + message.success(t('successStop')); onUpdateScheduleList(); if (editingId === scheduleId) { updateScheduleActive(false); @@ -92,26 +95,26 @@ const Operations: FC<OperationsProps> = ({ .finally(() => { setStopLoading(false); }); - }, [scheduleId, onUpdateScheduleList, editingId, updateScheduleActive]); + }, [scheduleId, onUpdateScheduleList, editingId, updateScheduleActive, t]); const handleExecuteSchedule = useCallback(() => { setExecuteLoading(true); executeSchedule(scheduleId) .then(res => { if (!!res) { - message.success('立即执行成功'); + message.success(t('successImmediately')); onUpdateScheduleList(); } }) .finally(() => { setExecuteLoading(false); }); - }, [scheduleId, onUpdateScheduleList]); + }, [scheduleId, onUpdateScheduleList, t]); return ( <Space onClick={stopPPG}> {!active ? ( <OperationButton - tooltipTitle="启动" + tooltipTitle={t('start')} loading={startLoading} icon={<CaretRightOutlined />} onClick={handleStartSchedule} @@ -119,7 +122,7 @@ const Operations: FC<OperationsProps> = ({ ) : null} {active ? ( <OperationButton - tooltipTitle="停止" + tooltipTitle={t('stop')} loading={stopLoading} icon={<PauseOutlined />} onClick={handleStopSchedule} @@ -127,13 +130,13 @@ const Operations: FC<OperationsProps> = ({ ) : null} <Popconfirm - title="确定立即执行?" + title={t('executeItNow')} okButtonProps={{ loading: executeLoading }} onConfirm={handleExecuteSchedule} > <OperationButton loading={executeLoading} - tooltipTitle="立即执行" + tooltipTitle={t('executeImmediately')} icon={ <SendOutlined rotate={-45} diff --git a/frontend/src/app/pages/MainPage/pages/SchedulePage/Sidebar/index.tsx b/frontend/src/app/pages/MainPage/pages/SchedulePage/Sidebar/index.tsx index c69185165..227e244e9 100644 --- a/frontend/src/app/pages/MainPage/pages/SchedulePage/Sidebar/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/SchedulePage/Sidebar/index.tsx @@ -1,6 +1,7 @@ import { DeleteOutlined } from '@ant-design/icons'; import { ListNav, ListPane, ListTitle } from 'app/components'; import { useDebouncedSearch } from 'app/hooks/useDebouncedSearch'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { useAccess } from 'app/pages/MainPage/Access'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import { memo, useCallback, useMemo } from 'react'; @@ -23,7 +24,7 @@ export const Sidebar = memo(() => { const list = useSelector(selectSchedules); const archived = useSelector(selectArchived); const allowCreate = useAccess(allowCreateSchedule()); - + const t = useI18NPrefix('main.pages.schedulePage.sidebar.index'); const { filteredData: scheduleList, debouncedSearch: listSearch } = useDebouncedSearch(list, (keywords, d) => d.name.toLowerCase().includes(keywords.toLowerCase()), @@ -50,12 +51,12 @@ export const Sidebar = memo(() => { () => [ { key: 'list', - title: '定时任务列表', + title: t('scheduledTaskList'), search: true, onSearch: listSearch, ...allowCreate({ add: { - items: [{ key: 'add', text: '新建定时任务' }], + items: [{ key: 'add', text: t('newTimedTask') }], callback: toAdd, }, }), @@ -63,7 +64,7 @@ export const Sidebar = memo(() => { items: [ { key: 'recycle', - text: '回收站', + text: t('recycle'), prefix: <DeleteOutlined className="icon" />, }, ], @@ -72,13 +73,13 @@ export const Sidebar = memo(() => { }, { key: 'recycle', - title: '回收站', + title: t('recycle'), back: true, search: true, onSearch: archivedSearch, }, ], - [toAdd, moreMenuClick, listSearch, archivedSearch, allowCreate], + [toAdd, moreMenuClick, listSearch, archivedSearch, allowCreate, t], ); return ( diff --git a/frontend/src/app/pages/MainPage/pages/SchedulePage/constants.ts b/frontend/src/app/pages/MainPage/pages/SchedulePage/constants.ts index a62e2cddb..c07f5740f 100644 --- a/frontend/src/app/pages/MainPage/pages/SchedulePage/constants.ts +++ b/frontend/src/app/pages/MainPage/pages/SchedulePage/constants.ts @@ -1,4 +1,6 @@ +import { prefixI18N } from 'app/hooks/useI18NPrefix'; import { FormValues } from './types'; +const Prefix = 'main.pages.schedulePage.constants.'; export enum JobTypes { Email = 'EMAIL', WeChart = 'WECHART', @@ -9,15 +11,15 @@ export enum FileTypes { Image = 'IMAGE', } export const JOB_TYPES_OPTIONS = [ - { label: '邮箱', value: JobTypes.Email }, - { label: '微信', value: JobTypes.WeChart }, + { label: prefixI18N(Prefix + 'email'), value: JobTypes.Email }, + { label: prefixI18N(Prefix + 'weChat'), value: JobTypes.WeChart }, ]; export const FILE_TYPE_OPTIONS = [ // { label: 'Excel', value: FileTypes.Excel }, - { label: '图片', value: FileTypes.Image }, + { label: prefixI18N(Prefix + 'picture'), value: FileTypes.Image }, ]; export const WECHART_FILE_TYPE_OPTIONS = [ - { label: '图片', value: FileTypes.Image }, + { label: prefixI18N(Prefix + 'picture'), value: FileTypes.Image }, ]; export enum TimeModes { @@ -79,12 +81,12 @@ export enum LogStatus { } export const LOG_STATUS_TEXT = { - [LogStatus.S1]: '任务执行', - [LogStatus.S3]: '配置解析', - [LogStatus.S7]: '数据获取', - [LogStatus.S15]: '发送', + [LogStatus.S1]: prefixI18N(Prefix + 'taskExecution'), + [LogStatus.S3]: prefixI18N(Prefix + 'configurationAnalysis'), + [LogStatus.S7]: prefixI18N(Prefix + 'getData'), + [LogStatus.S15]: prefixI18N(Prefix + 'send'), }; export const JOB_TYPE_TEXT = { - [JobTypes.Email]: '邮箱', - [JobTypes.WeChart]: '微信', + [JobTypes.Email]: prefixI18N(Prefix + 'email'), + [JobTypes.WeChart]: prefixI18N(Prefix + 'weChat'), }; diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 2f682fd94..879c6c8ce 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -9,6 +9,23 @@ "required": " is required", "invalidPassword": "Password must be 6-20 characters", "passwordNotMatch": "Password and confirm password does not match" + }, + "time": { + "minute": "分钟", + "hour": "小时", + "day": "天", + "month": "月", + "year": "年", + "m": "分", + "h": "时", + "d": "日", + "sun": "星期天", + "mon": "星期一", + "tues": "星期二", + "wednes": "星期三", + "thurs": "星期四", + "fri": "星期五", + "satur": "星期六" } }, "login": { @@ -120,6 +137,112 @@ "loading": "Loading...", "initError": "Initialization error, please refresh the page and try again", "createOrg": "You have not joined any organization, click to create" + }, + "pages": { + "schedulePage": { + "constants": { + "email": "邮箱", + "weChat": "微信", + "picture": "图片", + "taskExecution": "任务执行", + "configurationAnalysis": "配置解析", + "getData": "数据获取", + "send": "发送" + }, + "sidebar": { + "index": { + "scheduledTaskList": "定时任务列表", + "newTimedTask": "新建定时任务", + "recycle": "回收站" + }, + "scheduleList": { + "successStarted": "启动成功", + "successStop": "停止成功", + "successImmediately": "立即执行成功", + "start": "启动", + "stop": "停止", + "executeItNow": "确定立即执行?", + "executeImmediately": "立即执行" + }, + "editorPage": { + "index": { + "tickToSendContent": "请勾选发送内容", + "addSuccess": "新增成功", + "saveSuccess": "保存成功", + "restoredSuccess": "还原成功", + "success": "成功", + "moveToTrash": "移至回收站", + "delete": "删除", + "newTimedTask": "新建定时任务", + "sureToRestore?": "确定还原?", + "restore": "还原", + "sureToDelete": "确定删除?", + "allowModificationAfterStopping": "停止后允许修改", + "save": "保存", + "allowMoveAfterStopping": "停止后允许移至回收站", + "sureMoveRecycleBin": "确定移至回收站?", + "basicSettings": "基本设置", + "emailSetting": "邮件设置", + "enterpriseWeChatSettings": "企业微信设置", + "sendContentSettings": "发送内容设置" + }, + "weChartSetttingForm": { + "RobotWebhookAddress": "机器人webhook地址", + "RobotWebhookAddressIsRequired": "机器人webhook地址为必填项", + "fileType": "文件类型", + "picWidth": "图片宽度", + "px": "像素" + }, + "scheduleErrorLog": { + "index": { + "startTime": "开始时间", + "endTime": "结束时间", + "logPhase": "日志阶段", + "executionInformation": "执行信息", + "success": "成功", + "log": "日志" + } + }, + "emailSettingForm": { + "commonRichText": { + "pleaseEnter": "请输入" + }, + "index": { + "CC": "抄送", + "theme": "主题", + "subjectIsRequired": "主题为必填项", + "fileType": "文件类型", + "picWidth": "图片宽度", + "px": "像素", + "recipient": "收件人", + "recipientIsRequired": "收件人为必填项", + "bcc": "密送", + "contentOfEmail": "邮件内容" + }, + "mailTagFormItem": { + "placeholder": "输入邮箱或姓名关键字查找..." + } + }, + "basicBaseForm": { + "index": { + "nameAlreadyExists": "名称已存在", + "name": "名称", + "nameRequired": "名称为必填项", + "type": "类型", + "effectiveTimeRange": "有效时间范围" + }, + "executeFormItem": { + "per": "每", + "of": "", + "executionTimeSetting": "执行时间设置", + "expressionIsRequired": "表达式为必填项", + "pleaseEnterCronExpression": "请输入cron表达式", + "manualInput": "手动输入" + } + } + } + } + } } }, "viz": { diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 03107ed20..e72e822df 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -9,6 +9,23 @@ "required": "不能为空", "invalidPassword": "密码长度为6-20位", "passwordNotMatch": "两次输入的密码不一致" + }, + "time": { + "minute": "分钟", + "hour": "小时", + "day": "天", + "month": "月", + "year": "年", + "m": "分", + "h": "时", + "d": "日", + "sun": "星期天", + "mon": "星期一", + "tues": "星期二", + "wednes": "星期三", + "thurs": "星期四", + "fri": "星期五", + "satur": "星期六" } }, "login": { @@ -120,6 +137,112 @@ "loading": "应用配置加载中…", "initError": "初始化错误,请刷新页面重试", "createOrg": "未加入任何组织,点击创建" + }, + "pages": { + "schedulePage": { + "constants": { + "email": "邮箱", + "weChat": "微信", + "picture": "图片", + "taskExecution": "任务执行", + "configurationAnalysis": "配置解析", + "getData": "数据获取", + "send": "发送" + }, + "sidebar": { + "index": { + "scheduledTaskList": "定时任务列表", + "newTimedTask": "新建定时任务", + "recycle": "回收站" + }, + "scheduleList": { + "successStarted": "启动成功", + "successStop": "停止成功", + "successImmediately": "立即执行成功", + "start": "启动", + "stop": "停止", + "executeItNow": "确定立即执行?", + "executeImmediately": "立即执行" + }, + "editorPage": { + "index": { + "tickToSendContent": "请勾选发送内容", + "addSuccess": "新增成功", + "saveSuccess": "保存成功", + "restoredSuccess": "还原成功", + "success": "成功", + "moveToTrash": "移至回收站", + "delete": "删除", + "newTimedTask": "新建定时任务", + "sureToRestore?": "确定还原?", + "restore": "还原", + "sureToDelete": "确定删除?", + "allowModificationAfterStopping": "停止后允许修改", + "save": "保存", + "allowMoveAfterStopping": "停止后允许移至回收站", + "sureMoveRecycleBin": "确定移至回收站?", + "basicSettings": "基本设置", + "emailSetting": "邮件设置", + "enterpriseWeChatSettings": "企业微信设置", + "sendContentSettings": "发送内容设置" + }, + "weChartSetttingForm": { + "RobotWebhookAddress": "机器人webhook地址", + "RobotWebhookAddressIsRequired": "机器人webhook地址为必填项", + "fileType": "文件类型", + "picWidth": "图片宽度", + "px": "像素" + }, + "scheduleErrorLog": { + "index": { + "startTime": "开始时间", + "endTime": "结束时间", + "logPhase": "日志阶段", + "executionInformation": "执行信息", + "success": "成功", + "log": "日志" + } + }, + "emailSettingForm": { + "commonRichText": { + "pleaseEnter": "请输入" + }, + "index": { + "CC": "抄送", + "theme": "主题", + "subjectIsRequired": "主题为必填项", + "fileType": "文件类型", + "picWidth": "图片宽度", + "px": "像素", + "recipient": "收件人", + "recipientIsRequired": "收件人为必填项", + "bcc": "密送", + "contentOfEmail": "邮件内容" + }, + "mailTagFormItem": { + "placeholder": "输入邮箱或姓名关键字查找..." + } + }, + "basicBaseForm": { + "index": { + "nameAlreadyExists": "名称已存在", + "name": "名称", + "nameRequired": "名称为必填项", + "type": "类型", + "effectiveTimeRange": "有效时间范围" + }, + "executeFormItem": { + "per": "每", + "of": "的", + "executionTimeSetting": "执行时间设置", + "expressionIsRequired": "表达式为必填项", + "pleaseEnterCronExpression": "请输入cron表达式", + "manualInput": "手动输入" + } + } + } + } + } } }, "viz": { From a62a566661e1398c90391fee6d469f6295800647 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Thu, 30 Dec 2021 16:13:56 +0800 Subject: [PATCH 295/348] refactor(chart): optimize s2 chart resize --- .../PivotSheetChart/PivotSheetChart.tsx | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/PivotSheetChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/PivotSheetChart.tsx index 636c57e50..b1bd2122f 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/PivotSheetChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/PivotSheetChart.tsx @@ -40,10 +40,7 @@ class PivotSheetChart extends ReactChart { isISOContainer = 'piovt-sheet'; config = Config; chart: any = null; - tableOptions: { - dataset?; - config?; - } = {}; + updateOptions: any = {}; constructor() { super(AntVS2Wrapper, { @@ -55,21 +52,29 @@ class PivotSheetChart extends ReactChart { } onUpdated(options, context): void { - this.tableOptions = options; - if (!this.isMatchRequirement(options.config)) { this.adapter?.unmount(); return; } - this.adapter?.updated( - this.getOptions(context, options.dataset, options.config), + this.updateOptions = this.getOptions( context, + options.dataset, + options.config, ); + this.adapter?.updated(this.updateOptions); } onResize(_, context) { - this.onUpdated(this.tableOptions, context); + if (this.updateOptions?.options) { + this.updateOptions.options = Object.assign( + { + ...this.updateOptions.options, + }, + { width: context.width, height: context.height }, + ); + this.adapter?.updated(this.updateOptions); + } } getOptions(context, dataset?: ChartDataset, config?: ChartConfig) { From 350ee8c35f648cac336db9eec67ac0296c79c44d Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 30 Dec 2021 16:23:31 +0800 Subject: [PATCH 296/348] chore: add i18n widget jump --- .../components/LinkagePanel/index.tsx | 6 +- .../SettingJumpModal/TargetTreeSelect.tsx | 4 +- .../components/SettingJumpModal/config.ts | 4 +- .../components/SettingJumpModal/index.tsx | 56 +++++++++++++------ frontend/src/locales/en/translation.json | 12 +++- frontend/src/locales/zh/translation.json | 10 ++++ 6 files changed, 65 insertions(+), 27 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/index.tsx index 8f4cbae48..047dd7621 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/LinkagePanel/index.tsx @@ -59,12 +59,10 @@ export const LinkagePanel: React.FC<LinkagePanelProps> = memo(() => { () => getCanLinkageWidgets(allWidgets).filter(w => w.id !== widgetId), [allWidgets, widgetId], ); - - // selectDataChartById const widgetMap = useMemo(() => convertToWidgetMap(allWidgets), [allWidgets]); const [visible, setVisible] = useState(false); - // const [sameViewWidgetIds, setSameViewWidgetIds] = useState<string[]>([]); + const sameViewWidgetIds = useRef<string[]>([]); const linkagesRef = useRef<ViewLinkageItem[]>([]); useEffect(() => { @@ -83,7 +81,6 @@ export const LinkagePanel: React.FC<LinkagePanelProps> = memo(() => { }; const onSubmit = useCallback(() => { - // handle onFinish form.submit(); }, [form]); const afterClose = useCallback(() => { @@ -225,7 +222,6 @@ export const LinkagePanel: React.FC<LinkagePanelProps> = memo(() => { }, [curWidget, form, setColNames, widgetMap]); return ( <Modal - // title={`${type} 联动`} title={t('title')} visible={visible} onOk={onSubmit} diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/TargetTreeSelect.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/TargetTreeSelect.tsx index 26559508d..a2bcac469 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/TargetTreeSelect.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/TargetTreeSelect.tsx @@ -1,4 +1,5 @@ import { TreeSelect, TreeSelectProps } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { FC, useCallback, useMemo } from 'react'; import { TargetValueType } from './types'; @@ -27,6 +28,7 @@ export const TargetTreeSelect: FC<TargetTreeSelectProps> = ({ onChange, ...restProps }) => { + const t = useI18NPrefix(`viz.jump`); const _treeData = useMemo(() => { return disabledTreeData(treeData || [], filterBoardId); }, [treeData, filterBoardId]); @@ -52,7 +54,7 @@ export const TargetTreeSelect: FC<TargetTreeSelectProps> = ({ }, [value]); return ( <TreeSelect - placeholder="请选择跳转目标" + placeholder={t('target')} treeData={_treeData} treeDefaultExpandAll treeIcon diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts index 4c1cf89f4..20293771d 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/config.ts @@ -17,6 +17,6 @@ */ export const jumpTypes: { name: string; value: string }[] = [ - { value: 'INTERNAL', name: '仪表盘 / 数据图表' }, - { value: 'URL', name: 'URL' }, + { value: 'INTERNAL', name: '' }, + { value: 'URL', name: '' }, ]; diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx index b50dbe6e0..311a085c1 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SettingJumpModal/index.tsx @@ -5,6 +5,7 @@ import { FundFilled, } from '@ant-design/icons'; import { Form, Input, Modal, ModalProps, Select } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { BoardContext } from 'app/pages/DashBoardPage/contexts/BoardContext'; import { selectDataChartById } from 'app/pages/DashBoardPage/pages/Board/slice/selector'; import { BoardState } from 'app/pages/DashBoardPage/pages/Board/slice/types'; @@ -40,6 +41,8 @@ export const SettingJumpModal: FC<SettingJumpModalProps> = ({ children, ...restProps }) => { + const t = useI18NPrefix(`viz.jump`); + const tv = useI18NPrefix(`global.validation`); const [form] = Form.useForm(); const dispatch = useDispatch(); const selectVizTree = useMemo(makeSelectVizTree, []); @@ -118,8 +121,6 @@ export const SettingJumpModal: FC<SettingJumpModalProps> = ({ ); const onTargetTypeChange = useCallback(value => { setTargetType(value); - // form.setFieldsValue({ filter: undefined }); - // onGetController(value); }, []); const handleClose = useCallback(() => { dispatch( @@ -148,7 +149,7 @@ export const SettingJumpModal: FC<SettingJumpModalProps> = ({ ); return ( <Modal - title="跳转设置" + title={t('title')} visible={visible} width={520} {...restProps} @@ -157,24 +158,26 @@ export const SettingJumpModal: FC<SettingJumpModalProps> = ({ > <Form {...formItemLayout} form={form} onFinish={onFinish}> <Form.Item - label="跳转类型" + label={t('mode')} name="targetType" initialValue={'INTERNAL'} - rules={[{ required: true, message: '跳转类型不能为空' }]} + rules={[{ required: true, message: `${t('mode')}${tv('required')}` }]} > <Select onChange={onTargetTypeChange}> {jumpTypes.map(({ name, value }) => ( <Option key={value} value={value}> - {name} + {t(value)} </Option> ))} </Select> </Form.Item> {targetType === 'INTERNAL' && ( <Form.Item - label="跳转目标" + label={t('target')} name="target" - rules={[{ required: true, message: '跳转目标不能为空' }]} + rules={[ + { required: true, message: `${t('target')}${tv('required')}` }, + ]} > <TargetTreeSelect filterBoardId={boardId} @@ -188,25 +191,37 @@ export const SettingJumpModal: FC<SettingJumpModalProps> = ({ <Form.Item label="URL" name="URL" - rules={[{ required: true, message: '跳转URL不能为空' }]} + rules={[ + { required: true, message: `${t('target')}${tv('required')}` }, + ]} > - <Input placeholder="请输入跳转地址" /> + <Input placeholder="URL" /> </Form.Item> )} {targetType === 'URL' && ( <Form.Item - label="URL参数" + label={`URL ${t('parameters')}`} name="queryName" - rules={[{ required: true, message: 'URL参数名称不能为空' }]} + rules={[ + { + required: true, + message: `URL ${t('parameters')}${tv('required')}`, + }, + ]} > - <Input placeholder="请输入URL中携带的参数名称" /> + <Input placeholder={`URL${t('parameters')}`} /> </Form.Item> )} {chartGroupColumns?.length > 1 && ( <Form.Item - label="关联字段" + label={t('associatedFields')} name="field" - rules={[{ required: true, message: '请选择关联字段' }]} + rules={[ + { + required: true, + message: `${t('associatedFields')}${tv('required')}`, + }, + ]} > <SelectJumpFields form={form} @@ -216,14 +231,19 @@ export const SettingJumpModal: FC<SettingJumpModalProps> = ({ )} {targetType === 'INTERNAL' && ( <Form.Item - label="关联筛选" + label={t('controller')} name="filter" - rules={[{ required: true, message: '关联筛选不能为空' }]} + rules={[ + { + required: true, + message: `${t('controller')}${tv('required')}`, + }, + ]} > <FilterSelect loading={controllerLoading} options={controllers} - placeholder="请选择关联筛选" + placeholder={t('controller')} /> </Form.Item> )} diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index df0ea7248..495c8f41d 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -657,6 +657,16 @@ "selectTriggers": "Select the trigger field", "selectLinker": "Select linkage field" }, + "jump": { + "title": "Jump Settings", + "mode": "Jumping mode", + "target": "Target", + "INTERNAL": "Dashboard/DataChart", + "URL": "URL", + "parameters": "Parameters", + "controller": "Associated Controllers", + "associatedFields": "Associated Fields" + }, "associate": { "title": "Please associate fields/variables", "field": "Field", @@ -742,7 +752,7 @@ "runWinTip": "Win: [Ctrl + Enter]", "runMacTip": "Mac: [Command + Enter]", "beautify": "Beautify", - "save": "保存", + "save": "Save", "saveWinTip": "Win: [Ctrl + S]", "saveMacTip": "Mac: [Command + S]", "info": "Info", diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index df05217c4..df9b2dfbd 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -655,6 +655,16 @@ "selectTriggers": "选择触发字段", "selectLinker": "选择联动字段" }, + "jump": { + "title": "跳转设置", + "mode": "跳转方式", + "target": "跳转目标", + "INTERNAL": "仪表盘 / 数据图表", + "URL": "URL", + "parameters": "Parameters", + "controller": "关联控制器", + "associatedFields": "关联字段" + }, "associate": { "title": "关联字段/变量", "field": "字段", From 3fd7456585dcd635761fea9621235e60d345d41a Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Thu, 30 Dec 2021 16:23:20 +0800 Subject: [PATCH 297/348] refactor(chart): make debugger to sync --- .../models/ChartEventBroker.ts | 21 +++++++------------ .../ChartWorkbenchPage/models/ChartManager.ts | 2 +- frontend/src/utils/debugger.ts | 10 +++------ 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts index 0b6e8c1bc..88f272918 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts @@ -84,20 +84,15 @@ class ChartEventBroker { } } - private async safeInvoke( - event: HooksEvent, - options: any, - context?: BrokerContext, - ) { + private safeInvoke(event: HooksEvent, options: any, context?: BrokerContext) { try { - // await Debugger.instance.measure( - // `ChartEventBroker | ${event} `, - // () => { - // this._listeners.get(event)?.call?.(this._chart, options, context); - // }, - // false, - // ); - this._listeners.get(event)?.call?.(this._chart, options, context); + Debugger.instance.measure( + `ChartEventBroker | ${event} `, + () => { + this._listeners.get(event)?.call?.(this._chart, options, context); + }, + false, + ); } catch (e) { console.error(`ChartEventBroker | ${event} exception ----> `, e); } finally { diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartManager.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartManager.ts index 861a13bbc..492d518de 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartManager.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartManager.ts @@ -69,7 +69,7 @@ class ChartManager { return; } const pluginsPaths = await getChartPluginPaths(); - await Debugger.instance.measure('Plugin Charts | ', async () => { + Debugger.instance.measure('Plugin Charts | ', async () => { await this._loadCustomizeCharts(pluginsPaths); }); } diff --git a/frontend/src/utils/debugger.ts b/frontend/src/utils/debugger.ts index e65abc14f..08f29421b 100644 --- a/frontend/src/utils/debugger.ts +++ b/frontend/src/utils/debugger.ts @@ -31,17 +31,13 @@ export class Debugger { this._enableDebug = !!enable; } - public async measure( - info: string, - fn: VoidFunction, - forceEnable: boolean = true, - ) { + public measure(info: string, fn: VoidFunction, forceEnable: boolean = true) { if (!this._enableDebug || !forceEnable) { - return await fn(); + return fn(); } const start = performance.now(); - await fn(); + fn(); const end = performance.now(); console.info(`Performance - ${info} - `, `${end - start} ms`); } From de10b8131ce7ac9458392c560ee5f0969591f1c3 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 30 Dec 2021 16:52:04 +0800 Subject: [PATCH 298/348] chore: add i18n in widget action --- .../components/WidgetProvider/WidgetMethodProvider.tsx | 9 +++++---- .../pages/BoardEditor/slice/actions/actions.ts | 9 ++++----- frontend/src/locales/en/translation.json | 3 +++ frontend/src/locales/zh/translation.json | 2 ++ 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx index d1632d0cc..19d52c387 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetProvider/WidgetMethodProvider.tsx @@ -18,6 +18,7 @@ import { ExclamationCircleOutlined } from '@ant-design/icons'; import { Modal } from 'antd'; +import usePrefixI18N from 'app/hooks/useI18NPrefix'; import { urlSearchTransfer } from 'app/pages/MainPage/pages/VizPage/utils'; import { ChartMouseEventParams } from 'app/types/DatartChartBase'; import { ControllerFacadeTypes } from 'app/types/FilterControlPanel'; @@ -63,6 +64,7 @@ export const WidgetMethodProvider: FC<{ widgetId: string }> = ({ widgetId, children, }) => { + const t = usePrefixI18N('viz.widget.action'); const { boardId, editing, renderMode, orgId } = useContext(BoardContext); const dispatch = useDispatch(); @@ -73,10 +75,9 @@ export const WidgetMethodProvider: FC<{ widgetId: string }> = ({ (type: WidgetType, wid: string) => { if (type === 'container') { confirm({ - // TODO i18n - title: '确认删除', + title: t('confirmDel'), icon: <ExclamationCircleOutlined />, - content: '该组件内的组件也会被删除,确认是否删除?', + content: t('ContainerConfirmDel'), onOk() { dispatch(editBoardStackActions.deleteWidgets([wid])); }, @@ -95,7 +96,7 @@ export const WidgetMethodProvider: FC<{ widgetId: string }> = ({ } dispatch(editBoardStackActions.deleteWidgets([wid])); }, - [dispatch, boardId], + [dispatch, t, boardId], ); const onWidgetEdit = useCallback( (widget: Widget, wid: string) => { 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 0dd18f839..2d5911a80 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 @@ -35,6 +35,7 @@ import { import { Variable } from 'app/pages/MainPage/pages/VariablePage/slice/types'; import ChartDataView, { ChartDataViewFieldType } from 'app/types/ChartDataView'; import { ControllerFacadeTypes } from 'app/types/FilterControlPanel'; +import i18next from 'i18next'; import produce from 'immer'; import { RootState } from 'types'; import { uuidv4 } from 'utils/utils'; @@ -44,7 +45,6 @@ import { ControllerConfig } from '../../components/ControllerWidgetPanel/types'; import { addWidgetsToEditBoard, getEditChartWidgetDataAsync } from '../thunk'; import { HistoryEditBoard } from '../types'; import { editWidgetsQueryAction } from './controlActions'; - const { confirm } = Modal; export const clearEditBoardState = (boardId: string) => async (dispatch, getState) => { @@ -91,11 +91,10 @@ export const deleteWidgetsAction = () => (dispatch, getState) => { }); if (childWidgetIds.length > 0) { + const perStr = 'viz.widget.action.'; confirm({ - // TODO i18n - title: '注意', - content: - '您要删除的组件中 有Container 组件,删除会将容器内的组件一起删除', + title: i18next.t(perStr + 'confirmDel'), + content: i18next.t(perStr + 'confirmDel1'), onOk() { dispatch(editBoardStackActions.deleteWidgets(selectedIds)); }, diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 495c8f41d..ca2d597d1 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -642,6 +642,9 @@ "fullScreen": "FullScreen", "edit": "Edit", "delete": "Delete", + "confirmDel": "Confirm Delete", + "ContainerConfirmDel": "The components within this component will also be deleted, confirm whether to delete them or not?", + "ContainerConfirmDel1": "The components you want to delete has a Container component, the deletion will remove the components inside the container together", "info": "Info", "makeLinkage": "Set Linkage", "closeLinkage": "Close Linkage", diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index df9b2dfbd..ecceda142 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -640,6 +640,8 @@ "fullScreen": "全屏", "edit": "编辑", "delete": "删除", + "confirmDel": "确认删除", + "ContainerConfirmDel": "该组件内的组件也会被删除,确认是否删除?", "info": "基本信息", "makeLinkage": "联动设置", "closeLinkage": "关闭联动", From 7390e5195b071474d88a95efc124c8d9d3aa6a6d Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Thu, 30 Dec 2021 15:35:14 +0800 Subject: [PATCH 299/348] chore: add copyright to permission pages --- .../IndependentPermissionSetting.tsx | 18 ++++++++++++++++++ .../Main/PermissionForm/PermissionTable.tsx | 18 ++++++++++++++++++ .../Main/PermissionForm/PrivilegeSetting.tsx | 18 ++++++++++++++++++ .../Main/PermissionForm/VizPermissionForm.tsx | 18 ++++++++++++++++++ .../Main/PermissionForm/index.tsx | 18 ++++++++++++++++++ .../Main/PermissionForm/utils.ts | 18 ++++++++++++++++++ .../Main/ResourcesPermissionSetting.tsx | 18 ++++++++++++++++++ .../Main/SubjectsPermissionSetting.tsx | 18 ++++++++++++++++++ .../pages/PermissionPage/Main/index.tsx | 18 ++++++++++++++++++ .../PermissionPage/Sidebar/FlexCollapse.tsx | 18 ++++++++++++++++++ .../PermissionPage/Sidebar/ResourcePanels.tsx | 18 ++++++++++++++++++ .../PermissionPage/Sidebar/ResourceTree.tsx | 18 ++++++++++++++++++ .../pages/PermissionPage/Sidebar/Searchbar.tsx | 18 ++++++++++++++++++ .../PermissionPage/Sidebar/SubjectList.tsx | 18 ++++++++++++++++++ .../PermissionPage/Sidebar/SubjectPanels.tsx | 18 ++++++++++++++++++ .../pages/PermissionPage/Sidebar/index.tsx | 18 ++++++++++++++++++ .../pages/PermissionPage/Sidebar/types.ts | 18 ++++++++++++++++++ .../MainPage/pages/PermissionPage/constants.ts | 18 ++++++++++++++++++ .../MainPage/pages/PermissionPage/index.tsx | 17 +++++++++++++++++ .../pages/PermissionPage/slice/index.tsx | 18 ++++++++++++++++++ .../pages/PermissionPage/slice/selectors.ts | 18 ++++++++++++++++++ .../pages/PermissionPage/slice/thunks.ts | 17 +++++++++++++++++ .../pages/PermissionPage/slice/types.ts | 18 ++++++++++++++++++ .../MainPage/pages/PermissionPage/utils.ts | 18 ++++++++++++++++++ 24 files changed, 430 insertions(+) diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/IndependentPermissionSetting.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/IndependentPermissionSetting.tsx index 41e32a0a8..555a80de1 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/IndependentPermissionSetting.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/IndependentPermissionSetting.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Form, Radio, RadioChangeEvent } from 'antd'; import { memo } from 'react'; import { PermissionLevels } from '../../constants'; 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 105a668bf..7fd7fd124 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 @@ -1,3 +1,21 @@ +/** + * 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 { SearchOutlined } from '@ant-design/icons'; import { Col, Input, Row, Table, TableColumnProps } from 'antd'; import useResizeObserver from 'app/hooks/useResizeObserver'; 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 5e4a4def7..1fec5e89e 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 @@ -1,3 +1,21 @@ +/** + * 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 { Checkbox, Space } from 'antd'; import { memo, useCallback, useEffect, useState } from 'react'; import { 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 d1a4e414f..1ae887f10 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 @@ -1,3 +1,21 @@ +/** + * 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 { Form, Radio } from 'antd'; import { LoadingMask } from 'app/components'; import classnames from 'classnames'; 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 94c1555c4..c94af0b0b 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 @@ -1,3 +1,21 @@ +/** + * 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 { Form } from 'antd'; import { LoadingMask } from 'app/components'; import classnames from 'classnames'; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/utils.ts b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/utils.ts index 71bc59f7e..63560a19a 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/utils.ts +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/PermissionForm/utils.ts @@ -1,3 +1,21 @@ +/** + * 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 { fastDeleteArrayElement, getDiffParams } from 'utils/utils'; import { PermissionLevels, diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/ResourcesPermissionSetting.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/ResourcesPermissionSetting.tsx index ba3fe9562..99cf142ce 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/ResourcesPermissionSetting.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/ResourcesPermissionSetting.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Card } from 'antd'; import { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/SubjectsPermissionSetting.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/SubjectsPermissionSetting.tsx index a52b25e30..6fc46cae1 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/SubjectsPermissionSetting.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/SubjectsPermissionSetting.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Card } from 'antd'; import { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/index.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/index.tsx index 399898e1d..0b1fd2a7a 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import { memo } from 'react'; import { useSelector } from 'react-redux'; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/FlexCollapse.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/FlexCollapse.tsx index 17c9f1b4e..6b5f2ab07 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/FlexCollapse.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/FlexCollapse.tsx @@ -1,3 +1,21 @@ +/** + * 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 { CaretRightFilled } from '@ant-design/icons'; import classnames from 'classnames'; import { diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourcePanels.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourcePanels.tsx index 202294f46..3d283fd43 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourcePanels.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourcePanels.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Col, Radio, Row } from 'antd'; import classNames from 'classnames'; import { memo, useCallback, useMemo, useState } from 'react'; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourceTree.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourceTree.tsx index e5bffa2d7..8acecf37a 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourceTree.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourceTree.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Tree, TreeTitle } from 'app/components'; import { useSearchAndExpand } from 'app/hooks/useSearchAndExpand'; import { memo, useCallback, useEffect, useMemo } from 'react'; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/Searchbar.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/Searchbar.tsx index 78a493619..a606e17fd 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/Searchbar.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/Searchbar.tsx @@ -1,3 +1,21 @@ +/** + * 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 { SearchOutlined } from '@ant-design/icons'; import { Col, Input, Row } from 'antd'; import styled from 'styled-components/macro'; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectList.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectList.tsx index 30ceadabf..d8abb0ba0 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectList.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectList.tsx @@ -1,3 +1,21 @@ +/** + * 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 { LoadingOutlined } from '@ant-design/icons'; import { List } from 'antd'; import { ListItem } from 'app/components'; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectPanels.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectPanels.tsx index 4f52657d5..060176c75 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectPanels.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectPanels.tsx @@ -1,3 +1,21 @@ +/** + * 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 { memo, useMemo } from 'react'; import { useSelector } from 'react-redux'; import { SubjectTypes } from '../constants'; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/index.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/index.tsx index 3acb9cfc5..fb91c2b14 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { FileProtectOutlined, TeamOutlined } from '@ant-design/icons'; import { ListSwitch } from 'app/components'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/types.ts b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/types.ts index 8172015b6..d3ea0acc9 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/types.ts +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/types.ts @@ -1,3 +1,21 @@ +/** + * 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 { ResourceTypes, SubjectTypes } from '../constants'; export interface PanelsProps { diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/constants.ts b/frontend/src/app/pages/MainPage/pages/PermissionPage/constants.ts index eded26659..5aef1289c 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/constants.ts +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/constants.ts @@ -1,3 +1,21 @@ +/** + * 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. + */ + export enum Viewpoints { Subject = 'subject', Resource = 'resource', diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/index.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/index.tsx index b45d91965..b0410ba17 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/index.tsx @@ -1,3 +1,20 @@ +/** + * 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 { EmptyFiller, Split } from 'app/components'; import { useSplitSizes } from 'app/hooks/useSplitSizes'; import { useCallback } from 'react'; 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 213c37b01..bd75d5504 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { createSlice } from '@reduxjs/toolkit'; import { useInjectReducer } from 'utils/@reduxjs/injectReducer'; import { getMembers, getRoles } from '../../MemberPage/slice/thunks'; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/selectors.ts b/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/selectors.ts index 890367128..8738a5208 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/selectors.ts +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/selectors.ts @@ -1,3 +1,21 @@ +/** + * 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 { createSelector } from '@reduxjs/toolkit'; import { RootState } from 'types'; import { initialState } from '.'; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/thunks.ts b/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/thunks.ts index e9e1f6b93..0124c3424 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/thunks.ts +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/thunks.ts @@ -1,3 +1,20 @@ +/** + * 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 { createAsyncThunk } from '@reduxjs/toolkit'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import { RootState } from 'types'; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/types.ts b/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/types.ts index 9287dffef..f4cd28fae 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/types.ts +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/slice/types.ts @@ -1,3 +1,21 @@ +/** + * 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 { TreeDataNode } from 'antd'; import { PermissionLevels, diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/utils.ts b/frontend/src/app/pages/MainPage/pages/PermissionPage/utils.ts index e70793e02..caef38426 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/utils.ts +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/utils.ts @@ -1,3 +1,21 @@ +/** + * 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 { PermissionLevels, ResourceTypes, From 5848601b55b58038f34d7ea917faee3341410ad5 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Thu, 30 Dec 2021 17:00:59 +0800 Subject: [PATCH 300/348] chore: permission page i18n support --- .../Main/PermissionForm/PermissionTable.tsx | 10 +-- .../Main/PermissionForm/PrivilegeSetting.tsx | 5 +- .../Main/PermissionForm/VizPermissionForm.tsx | 67 +++++++++++++++---- .../Main/PermissionForm/index.tsx | 66 +++++++++++++++--- .../Main/ResourcesPermissionSetting.tsx | 13 ++-- .../Main/SubjectsPermissionSetting.tsx | 8 ++- .../PermissionPage/Sidebar/ResourcePanels.tsx | 10 +-- .../PermissionPage/Sidebar/ResourceTree.tsx | 5 +- .../PermissionPage/Sidebar/SubjectList.tsx | 5 +- .../PermissionPage/Sidebar/SubjectPanels.tsx | 8 ++- .../pages/PermissionPage/Sidebar/index.tsx | 15 ++--- .../pages/PermissionPage/constants.ts | 28 -------- .../MainPage/pages/PermissionPage/index.tsx | 10 ++- .../MainPage/pages/PermissionPage/utils.ts | 3 +- frontend/src/locales/en/translation.json | 52 ++++++++++++-- frontend/src/locales/zh/translation.json | 46 ++++++++++++- 16 files changed, 256 insertions(+), 95 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 7fd7fd124..8a34de680 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 @@ -18,6 +18,7 @@ import { SearchOutlined } from '@ant-design/icons'; import { Col, Input, Row, Table, TableColumnProps } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import useResizeObserver from 'app/hooks/useResizeObserver'; import { useSearchAndExpand } from 'app/hooks/useSearchAndExpand'; import { memo, useEffect, useMemo } from 'react'; @@ -65,6 +66,7 @@ export const PermissionTable = memo( onPrivilegeChange, }: PermissionTableProps) => { const { height, ref } = useResizeObserver(); + const t = useI18NPrefix('permission'); const treeData = useMemo(() => { if (dataSource && privileges) { @@ -110,10 +112,10 @@ export const PermissionTable = memo( const columns: TableColumnProps<DataSourceTreeNode>[] = [ { dataIndex: 'name', - title: '资源名称', + title: t('resourceName'), }, { - title: '权限详情', + title: t('privileges'), align: 'center' as const, width: getPrivilegeSettingWidth( viewpoint, @@ -132,14 +134,14 @@ export const PermissionTable = memo( }, ]; return columns; - }, [viewpoint, viewpointType, dataSourceType, privilegeChange]); + }, [viewpoint, viewpointType, dataSourceType, privilegeChange, t]); return ( <> <Toolbar> <Col span={12}> <Input - placeholder="搜索资源名称关键字" + placeholder={t('searchResources')} prefix={<SearchOutlined className="icon" />} bordered={false} onChange={debouncedSearch} 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 1fec5e89e..07a8d8421 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 @@ -17,11 +17,11 @@ */ import { Checkbox, Space } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { memo, useCallback, useEffect, useState } from 'react'; import { PermissionLevels, ResourceTypes, - RESOURCE_TYPE_PERMISSION_LABEL, RESOURCE_TYPE_PERMISSION_MAPPING, SubjectTypes, Viewpoints, @@ -54,6 +54,7 @@ export const PrivilegeSetting = memo( const [values, setValues] = useState<PermissionLevels[]>( getDefaultPermissionArray(), ); + const t = useI18NPrefix('permission'); const resourceType = getPrivilegeSettingType( viewpoint, @@ -86,7 +87,7 @@ export const PrivilegeSetting = memo( checked={level === values[index]} onChange={privilegeChange(index, level)} > - {RESOURCE_TYPE_PERMISSION_LABEL[resourceType!][index]} + {t(`privilegeLabel.${resourceType!.toLowerCase()}.${index}`)} </Checkbox> ))} </Space> 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 1ae887f10..a73d9688c 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 @@ -18,14 +18,13 @@ import { Form, Radio } from 'antd'; import { LoadingMask } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import classnames from 'classnames'; import { memo, useCallback, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components/macro'; import { listToTree } from 'utils/utils'; import { - CREATE_PERMISSION_VALUES, - MODULE_PERMISSION_VALUES, PermissionLevels, ResourceTypes, SubjectTypes, @@ -87,6 +86,7 @@ export const VizPermissionForm = memo( const privileges = useSelector(state => selectPrivileges(state, { viewpoint, dataSourceType }), ); + const t = useI18NPrefix('permission'); const vizTreeData = useMemo(() => { if (folders && storyboards && privileges) { @@ -285,25 +285,68 @@ export const VizPermissionForm = memo( ], ); + const modulePermissionValues = useMemo( + () => [ + { + text: t( + `modulePermissionLabel.${ + PermissionLevels[PermissionLevels.Disable] + }`, + ), + value: PermissionLevels.Disable, + }, + { + text: t( + `modulePermissionLabel.${ + PermissionLevels[PermissionLevels.Enable] + }`, + ), + value: PermissionLevels.Enable, + }, + ], + [t], + ); + const createPermissionValues = useMemo( + () => [ + { + text: t( + `createPermissionLabel.${ + PermissionLevels[PermissionLevels.Disable] + }`, + ), + value: PermissionLevels.Disable, + }, + { + text: t( + `createPermissionLabel.${ + PermissionLevels[PermissionLevels.Create] + }`, + ), + value: PermissionLevels.Create, + }, + ], + [t], + ); + return ( <Wrapper className={classnames({ selected })}> <LoadingMask loading={permissionLoading}> <FormContent labelAlign="left" - labelCol={{ span: 3 }} - wrapperCol={{ span: 19 }} + labelCol={{ span: 4 }} + wrapperCol={{ span: 18 }} > <IndependentPermissionSetting enabled={moduleEnabled} - label="功能权限" - extra="开启功能权限之后,用户才能在 Datart 界面上使用该功能" - values={MODULE_PERMISSION_VALUES} + label={t('modulePermission')} + extra={t('modulePermissionDesc')} + values={modulePermissionValues} onChange={independentPermissionChange('*')} /> - <Form.Item label="资源明细"> + <Form.Item label={t('resourceDetail')}> <Radio.Group value={vizType} onChange={vizTypeChange}> - <Radio value="folder">目录</Radio> - <Radio value="persentation">演示</Radio> + <Radio value="folder">{t('folder')}</Radio> + <Radio value="persentation">{t('presentation')}</Radio> </Radio.Group> </Form.Item> <Form.Item @@ -327,8 +370,8 @@ export const VizPermissionForm = memo( {vizType === 'persentation' && ( <IndependentPermissionSetting enabled={storyboardCreateEnabled} - label="新增故事板" - values={CREATE_PERMISSION_VALUES} + label={t('createStoryboard')} + values={createPermissionValues} onChange={independentPermissionChange( VizResourceSubTypes.Storyboard, )} 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 c94af0b0b..9aef40b25 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 @@ -18,16 +18,14 @@ import { Form } from 'antd'; import { LoadingMask } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import classnames from 'classnames'; import { memo, useCallback, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components/macro'; import { - CREATE_PERMISSION_VALUES, - MODULE_PERMISSION_VALUES, PermissionLevels, ResourceTypes, - RESOURCE_TYPE_LABEL, SubjectTypes, Viewpoints, } from '../../constants'; @@ -80,6 +78,7 @@ export const PermissionForm = memo( const privileges = useSelector(state => selectPrivileges(state, { viewpoint, dataSourceType }), ); + const t = useI18NPrefix('permission'); const { moduleEnabled, createEnabled } = useMemo(() => { let moduleEnabled = PermissionLevels.Disable; @@ -247,20 +246,63 @@ export const PermissionForm = memo( ], ); + const modulePermissionValues = useMemo( + () => [ + { + text: t( + `modulePermissionLabel.${ + PermissionLevels[PermissionLevels.Disable] + }`, + ), + value: PermissionLevels.Disable, + }, + { + text: t( + `modulePermissionLabel.${ + PermissionLevels[PermissionLevels.Enable] + }`, + ), + value: PermissionLevels.Enable, + }, + ], + [t], + ); + const createPermissionValues = useMemo( + () => [ + { + text: t( + `createPermissionLabel.${ + PermissionLevels[PermissionLevels.Disable] + }`, + ), + value: PermissionLevels.Disable, + }, + { + text: t( + `createPermissionLabel.${ + PermissionLevels[PermissionLevels.Create] + }`, + ), + value: PermissionLevels.Create, + }, + ], + [t], + ); + return ( <Wrapper className={classnames({ selected })}> <LoadingMask loading={permissionLoading}> <FormContent labelAlign="left" - labelCol={{ span: 3 }} - wrapperCol={{ span: 19 }} + labelCol={{ span: 4 }} + wrapperCol={{ span: 18 }} > {viewpoint === Viewpoints.Subject && ( <IndependentPermissionSetting enabled={moduleEnabled} - label="功能权限" - extra="开启功能权限之后,用户才能在 Datart 界面上使用该功能" - values={MODULE_PERMISSION_VALUES} + label={t('modulePermission')} + extra={t('modulePermissionDesc')} + values={modulePermissionValues} onChange={independentPermissionChange('*')} /> )} @@ -270,12 +312,14 @@ export const PermissionForm = memo( ) && ( <IndependentPermissionSetting enabled={createEnabled} - label={`新增${RESOURCE_TYPE_LABEL[dataSourceType]}`} - values={CREATE_PERMISSION_VALUES} + label={`${t('add')}${t( + `module.${dataSourceType.toLowerCase()}`, + )}`} + values={createPermissionValues} onChange={independentPermissionChange(dataSourceType)} /> )} - <Form.Item label="资源明细"> + <Form.Item label={t('resourceDetail')}> <PermissionTable viewpoint={viewpoint} viewpointType={viewpointType} diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/ResourcesPermissionSetting.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/ResourcesPermissionSetting.tsx index 99cf142ce..d038246a2 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/ResourcesPermissionSetting.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/ResourcesPermissionSetting.tsx @@ -17,14 +17,10 @@ */ import { Card } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { - ResourceTypes, - RESOURCE_TYPE_LABEL, - SubjectTypes, - Viewpoints, -} from '../constants'; +import { ResourceTypes, SubjectTypes, Viewpoints } from '../constants'; import { selectFolderListLoading, selectFolders, @@ -74,6 +70,7 @@ export const ResourcesPermissionSetting = memo( const permissionLoading = useSelector(state => selectPermissionLoading(state, { viewpoint }), ); + const t = useI18NPrefix('permission'); useEffect(() => { if (viewpointType && viewpointId) { @@ -137,9 +134,9 @@ export const ResourcesPermissionSetting = memo( () => tabSource.map(({ type }) => ({ key: type, - tab: RESOURCE_TYPE_LABEL[type], + tab: t(`module.${type.toLowerCase()}`), })), - [tabSource], + [tabSource, t], ); return ( diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/SubjectsPermissionSetting.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/SubjectsPermissionSetting.tsx index 6fc46cae1..0169143af 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/SubjectsPermissionSetting.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Main/SubjectsPermissionSetting.tsx @@ -17,6 +17,7 @@ */ import { Card } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { ResourceTypes, SubjectTypes, Viewpoints } from '../constants'; @@ -56,6 +57,7 @@ export const SubjectPermissionSetting = memo( const permissionLoading = useSelector(state => selectPermissionLoading(state, { viewpoint }), ); + const t = useI18NPrefix('permission'); useEffect(() => { if (viewpointType && viewpointId) { @@ -86,18 +88,18 @@ export const SubjectPermissionSetting = memo( () => [ { type: SubjectTypes.Role, - label: '角色', + label: t('role'), dataSource: roles, loading: roleListLoading, }, { type: SubjectTypes.UserRole, - label: '成员', + label: t('member'), dataSource: members, loading: memberListLoading, }, ], - [roles, members, roleListLoading, memberListLoading], + [roles, members, roleListLoading, memberListLoading, t], ); const tabList = useMemo( diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourcePanels.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourcePanels.tsx index 3d283fd43..aed075134 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourcePanels.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourcePanels.tsx @@ -17,12 +17,13 @@ */ import { Col, Radio, Row } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import classNames from 'classnames'; import { memo, useCallback, useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; import styled from 'styled-components/macro'; import { SPACE_MD, SPACE_XS } from 'styles/StyleConstants'; -import { ResourceTypes, RESOURCE_TYPE_LABEL } from '../constants'; +import { ResourceTypes } from '../constants'; import { selectFolderListLoading, selectFolders, @@ -53,6 +54,7 @@ export const ResourcePanels = memo( const viewListLoading = useSelector(selectViewListLoading); const sourceListLoading = useSelector(selectSourceListLoading); const scheduleListLoading = useSelector(selectScheduleListLoading); + const t = useI18NPrefix('permission'); const resourcePanels = useMemo( () => [ @@ -97,7 +99,7 @@ export const ResourcePanels = memo( <Panel key={resourceType} id={resourceType} - title={RESOURCE_TYPE_LABEL[resourceType]} + title={t(`module.${resourceType.toLowerCase()}`)} onChange={onToggle} > {resourceType === ResourceTypes.Viz ? ( @@ -105,8 +107,8 @@ export const ResourcePanels = memo( <VizTypeSwitch key="switch"> <Col> <Radio.Group value={vizType} onChange={vizTypeChange}> - <Radio value="folder">目录</Radio> - <Radio value="presentation">演示</Radio> + <Radio value="folder">{t('folder')}</Radio> + <Radio value="presentation">{t('presentation')}</Radio> </Radio.Group> </Col> </VizTypeSwitch> diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourceTree.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourceTree.tsx index 8acecf37a..070952b51 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourceTree.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/ResourceTree.tsx @@ -17,6 +17,7 @@ */ import { Tree, TreeTitle } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { useSearchAndExpand } from 'app/hooks/useSearchAndExpand'; import { memo, useCallback, useEffect, useMemo } from 'react'; import { listToTree } from 'utils/utils'; @@ -32,6 +33,8 @@ interface ResourceTreeProps { export const ResourceTree = memo( ({ loading, dataSource, onSelect }: ResourceTreeProps) => { + const t = useI18NPrefix('permission'); + const treeData = useMemo( () => listToTree(dataSource, null, []) as DataSourceTreeNode[], [dataSource], @@ -73,7 +76,7 @@ export const ResourceTree = memo( return ( <> <Searchbar - placeholder="搜索资源名称关键字" + placeholder={t('searchResources')} onSearch={debouncedSearch} /> <Tree diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectList.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectList.tsx index d8abb0ba0..5bf66823f 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectList.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectList.tsx @@ -20,6 +20,7 @@ import { LoadingOutlined } from '@ant-design/icons'; import { List } from 'antd'; import { ListItem } from 'app/components'; import { useDebouncedSearch } from 'app/hooks/useDebouncedSearch'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { memo } from 'react'; import styled from 'styled-components/macro'; import { SubjectTypes } from '../constants'; @@ -43,13 +44,15 @@ export const SubjectList = memo( loading, onToDetail, }: SubjectListProps) => { + const t = useI18NPrefix('permission'); + const { filteredData, debouncedSearch } = useDebouncedSearch( dataSource, (keywords, d) => d.name.includes(keywords), ); return ( <> - <Searchbar placeholder="搜索关键字" onSearch={debouncedSearch} /> + <Searchbar placeholder={t('search')} onSearch={debouncedSearch} /> <List loading={{ spinning: loading, diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectPanels.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectPanels.tsx index 060176c75..df0d55274 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectPanels.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/SubjectPanels.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { memo, useMemo } from 'react'; import { useSelector } from 'react-redux'; import { SubjectTypes } from '../constants'; @@ -36,23 +37,24 @@ export const SubjectPanels = memo( const members = useSelector(selectMembers); const roleListLoading = useSelector(selectRoleListLoading); const memberListLoading = useSelector(selectMemberListLoading); + const t = useI18NPrefix('permission'); const subjectPanels = useMemo( () => [ { type: SubjectTypes.Role, - label: '角色', + label: t('role'), dataSource: roles, loading: roleListLoading, }, { type: SubjectTypes.UserRole, - label: '成员', + label: t('member'), dataSource: members, loading: memberListLoading, }, ], - [roles, members, roleListLoading, memberListLoading], + [roles, members, roleListLoading, memberListLoading, t], ); return ( diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/index.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/index.tsx index fb91c2b14..ed63239ec 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/Sidebar/index.tsx @@ -18,18 +18,14 @@ import { FileProtectOutlined, TeamOutlined } from '@ant-design/icons'; import { ListSwitch } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { selectOrgId } from 'app/pages/MainPage/slice/selectors'; import { memo, useCallback, useEffect, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router'; import styled from 'styled-components/macro'; import { SPACE_XS } from 'styles/StyleConstants'; -import { - ResourceTypes, - SubjectTypes, - Viewpoints, - VIEWPOINT_LABEL, -} from '../constants'; +import { ResourceTypes, SubjectTypes, Viewpoints } from '../constants'; import { getDataSource } from '../slice/thunks'; import { ResourcePanels } from './ResourcePanels'; import { SubjectPanels } from './SubjectPanels'; @@ -45,6 +41,7 @@ export const Sidebar = memo( const dispatch = useDispatch(); const history = useHistory(); const orgId = useSelector(selectOrgId); + const t = useI18NPrefix('permission'); useEffect(() => { if (viewpointType) { @@ -82,15 +79,15 @@ export const Sidebar = memo( { key: Viewpoints.Subject, icon: <TeamOutlined />, - text: VIEWPOINT_LABEL[Viewpoints.Subject], + text: t(`viewpoint.${Viewpoints.Subject}`), }, { key: Viewpoints.Resource, icon: <FileProtectOutlined />, - text: VIEWPOINT_LABEL[Viewpoints.Resource], + text: t(`viewpoint.${Viewpoints.Resource}`), }, ], - [], + [t], ); return ( diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/constants.ts b/frontend/src/app/pages/MainPage/pages/PermissionPage/constants.ts index 5aef1289c..058026a72 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/constants.ts +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/constants.ts @@ -55,18 +55,6 @@ export enum PermissionLevels { Create = (1 << 7) | Manage, } -export const VIEWPOINT_LABEL = { - [Viewpoints.Subject]: '常规视图', - [Viewpoints.Resource]: '资源视图', -}; - -export const RESOURCE_TYPE_LABEL = { - [ResourceTypes.Viz]: '可视化', - [ResourceTypes.View]: '数据视图', - [ResourceTypes.Source]: '数据源', - [ResourceTypes.Schedule]: '定时任务', -}; - export const RESOURCE_TYPE_PERMISSION_MAPPING = { [ResourceTypes.Viz]: [ PermissionLevels.Read, @@ -78,19 +66,3 @@ export const RESOURCE_TYPE_PERMISSION_MAPPING = { [ResourceTypes.Source]: [PermissionLevels.Read, PermissionLevels.Create], [ResourceTypes.Schedule]: [PermissionLevels.Create], }; - -export const RESOURCE_TYPE_PERMISSION_LABEL = { - [ResourceTypes.Viz]: ['查看', '下载', '分享', '管理'], - [ResourceTypes.View]: ['使用', '管理'], - [ResourceTypes.Source]: ['使用', '管理'], - [ResourceTypes.Schedule]: ['管理'], -}; - -export const MODULE_PERMISSION_VALUES = [ - { text: '禁用', value: PermissionLevels.Disable }, - { text: '启用', value: PermissionLevels.Enable }, -]; -export const CREATE_PERMISSION_VALUES = [ - { text: '禁用', value: PermissionLevels.Disable }, - { text: '启用', value: PermissionLevels.Create }, -]; diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/index.tsx b/frontend/src/app/pages/MainPage/pages/PermissionPage/index.tsx index b0410ba17..d49b92881 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/index.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ import { EmptyFiller, Split } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { useSplitSizes } from 'app/hooks/useSplitSizes'; import { useCallback } from 'react'; import { Route, useRouteMatch } from 'react-router-dom'; @@ -44,6 +45,7 @@ export function PermissionPage() { type: ResourceTypes | SubjectTypes; id: string; }>('/organizations/:orgId/permissions/:viewpoint/:type/:id'); + const t = useI18NPrefix('permission'); const { sizes, setSizes } = useSplitSizes({ limitedSide: 0, range: [256, 768], @@ -77,9 +79,11 @@ export function PermissionPage() { /> ) : ( <EmptyFiller - title={`请在左侧列表选择${ - viewpoint === Viewpoints.Resource ? '资源项' : '角色或用户' - }`} + title={`${t('empty1')}${ + viewpoint === Viewpoints.Resource + ? t('emptyResource') + : t('emptySubject') + }${t('empty2')}`} /> )} </Container> diff --git a/frontend/src/app/pages/MainPage/pages/PermissionPage/utils.ts b/frontend/src/app/pages/MainPage/pages/PermissionPage/utils.ts index caef38426..d3ca0331f 100644 --- a/frontend/src/app/pages/MainPage/pages/PermissionPage/utils.ts +++ b/frontend/src/app/pages/MainPage/pages/PermissionPage/utils.ts @@ -16,6 +16,7 @@ * limitations under the License. */ +import i18n from 'i18next'; import { PermissionLevels, ResourceTypes, @@ -39,7 +40,7 @@ export function generateRootNode( ): DataSourceViewModel { return { id: type === ResourceTypes.Viz ? (vizId as string) : (type as string), - name: '所有资源', + name: i18n.t('permission.allResources'), type, parentId: null, index: null, diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index ca2d597d1..f2306eb40 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -737,7 +737,7 @@ "view": { "loading": "Loading...", "selectSource": "You must select a source", - "empty": "Select view in the sidebar", + "empty": "Select views in the sidebar", "resultEmpty1": "Click ", "resultEmpty2": " button to execute, the results will be displayed here", "errorTitle": "Error occurred", @@ -781,7 +781,7 @@ }, "columnPermission": { "title": "Column permissions", - "search": "Search role name", + "search": "Search role keywords", "partial": "Partial", "none": "None", "all": "All" @@ -882,6 +882,50 @@ "addRole": "Create role" } }, + "permission": { + "empty1": "Select ", + "emptyResource": "resources", + "emptySubject": "roles or members", + "empty2": " in the sidebar", + "allResources": "All resources", + "folder": "Folder", + "presentation": "Presentation", + "search": "Search keywords", + "searchResources": "Search resource keywords", + "member": "Member", + "role": "Role", + "modulePermission": "Module Permission", + "modulePermissionDesc": "You can only access the module after enabling the module permission", + "resourceDetail": "Resource detail", + "createStoryboard": "Create storyboard", + "resourceName": "Resource name", + "privileges": "Privileges", + "add": "Create ", + "viewpoint": { + "subject": "Subject view", + "resource": "Resource view" + }, + "module": { + "source": "Source", + "view": "View", + "viz": "Viz", + "schedule": "Schedule" + }, + "modulePermissionLabel": { + "Enable": "Enable", + "Disable": "Disable" + }, + "createPermissionLabel": { + "Create": "Enable", + "Disable": "Disable" + }, + "privilegeLabel": { + "viz": ["View", "Download", "Share", "Manage"], + "view": ["Access", "Manage"], + "source": ["Access", "Manage"], + "schedule": ["Manage"] + } + }, "share": { "common": { "confirm": "Confirm", @@ -901,7 +945,7 @@ }, "listTitle": { "search": "Search", - "searchValue": "Search name keywords" + "searchValue": "Search keywords" } } -} \ No newline at end of file +} diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index ecceda142..cc4ee5f0a 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -879,6 +879,50 @@ "addRole": "新建角色" } }, + "permission": { + "empty1": "请在左侧列表选择", + "emptyResource": "资源项", + "emptySubject": "角色或用户", + "empty2": "", + "allResources": "所有资源", + "folder": "目录", + "presentation": "演示", + "search": "搜索关键字", + "searchResources": "搜索资源名称关键字", + "member": "成员", + "role": "角色", + "modulePermission": "功能权限", + "modulePermissionDesc": "开启功能权限之后,用户才能在 Datart 界面上使用该功能", + "resourceDetail": "资源明细", + "createStoryboard": "新增故事板", + "resourceName": "资源名称", + "privileges": "权限详情", + "add": "新建", + "viewpoint": { + "subject": "常规视图", + "resource": "资源视图" + }, + "module": { + "source": "数据源", + "view": "数据视图", + "viz": "可视化", + "schedule": "定时任务" + }, + "modulePermissionLabel": { + "Enable": "启用", + "Disable": "禁用" + }, + "createPermissionLabel": { + "Create": "启用", + "Disable": "禁用" + }, + "privilegeLabel": { + "viz": { "0": "查看", "1": "下载", "2": "分享", "3": "管理" }, + "view": { "0": "使用", "1": "管理" }, + "source": { "0": "使用", "1": "管理" }, + "schedule": { "0": "管理" } + } + }, "share": { "common": { "confirm": "请确认", @@ -901,4 +945,4 @@ "searchValue": "搜索名称关键字" } } -} \ No newline at end of file +} From ec4c56f06cb1b9efd8385d3bd8619c4b9fc4c4c1 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 30 Dec 2021 17:25:30 +0800 Subject: [PATCH 301/348] chore: add i18n in story --- .../Editor/StoryPageSetting.tsx | 55 ++----------------- .../StoryBoardPage/Editor/StorySetting.tsx | 7 ++- .../app/pages/StoryBoardPage/Editor/index.tsx | 10 ++-- .../StoryBoardPage/components/StoryHeader.tsx | 29 +++++++--- .../components/StoryOverLay.tsx | 6 +- frontend/src/locales/en/translation.json | 12 +++- frontend/src/locales/zh/translation.json | 12 +++- 7 files changed, 58 insertions(+), 73 deletions(-) diff --git a/frontend/src/app/pages/StoryBoardPage/Editor/StoryPageSetting.tsx b/frontend/src/app/pages/StoryBoardPage/Editor/StoryPageSetting.tsx index e5be49762..ce2da55cf 100644 --- a/frontend/src/app/pages/StoryBoardPage/Editor/StoryPageSetting.tsx +++ b/frontend/src/app/pages/StoryBoardPage/Editor/StoryPageSetting.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ import { Form, Select } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import produce from 'immer'; import React, { memo, @@ -39,6 +40,7 @@ import { updateStoryPage } from '../slice/thunks'; import { StoryBoardState, TransitionEffect } from '../slice/types'; export interface StoryPageSettingProps {} export const StoryPageSetting: React.FC<StoryPageSettingProps> = memo(() => { + const t = useI18NPrefix(`viz.board.setting`); const { stroyBoardId: storyId } = useContext(StoryContext); const dispatch = useDispatch(); const selectedPageIds = useSelector( @@ -89,7 +91,7 @@ export const StoryPageSetting: React.FC<StoryPageSettingProps> = memo(() => { onValuesChange={onValuesChange} > <> - <Form.Item name="in" label="切入"> + <Form.Item name="in" label={t('cutIn')}> <Select style={{ width: '120px' }} placeholder="Select a option"> {EFFECT_IN_OPTIONS.map(ele => ( <Select.Option key={ele} value={ele}> @@ -98,7 +100,7 @@ export const StoryPageSetting: React.FC<StoryPageSettingProps> = memo(() => { ))} </Select> </Form.Item> - <Form.Item name="out" label="切出"> + <Form.Item name="out" label={t('cutOut')}> <Select style={{ width: '120px' }} placeholder="Select a option "> {EFFECT_OUT_OPTIONS.map(ele => ( <Select.Option key={ele} value={ele}> @@ -107,7 +109,7 @@ export const StoryPageSetting: React.FC<StoryPageSettingProps> = memo(() => { ))} </Select> </Form.Item> - <Form.Item name="speed" label="速度"> + <Form.Item name="speed" label={t('speed')}> <Select style={{ width: '120px' }} placeholder="Select a option "> {EFFECT_SPEED_OPTIONS.map(ele => ( <Select.Option key={ele} value={ele}> @@ -117,53 +119,6 @@ export const StoryPageSetting: React.FC<StoryPageSettingProps> = memo(() => { </Select> </Form.Item> </> - {/* <Popover - content={ - <> - <Form.Item name="in" label="切入"> - <Select - style={{ width: '120px' }} - placeholder="Select a option and change input text above" - > - {EFFECT_IN_OPTIONS.map(ele => ( - <Select.Option key={ele} value={ele}> - {ele} - </Select.Option> - ))} - </Select> - </Form.Item> - <Form.Item name="out" label="切出"> - <Select - style={{ width: '120px' }} - placeholder="Select a option and change input text above" - > - {EFFECT_OUT_OPTIONS.map(ele => ( - <Select.Option key={ele} value={ele}> - {ele} - </Select.Option> - ))} - </Select> - </Form.Item> - <Form.Item name="speed" label="速度"> - <Select - style={{ width: '120px' }} - placeholder="Select a option and change input text above" - > - {EFFECT_SPEED_OPTIONS.map(ele => ( - <Select.Option key={ele} value={ele}> - {ele} - </Select.Option> - ))} - </Select> - </Form.Item> - </> - } - title="切换效果" - > - <Button> - 切换效果: [{effect.in}][{effect.out}][{effect.speed}] - </Button> - </Popover> */} </Form> ); }); diff --git a/frontend/src/app/pages/StoryBoardPage/Editor/StorySetting.tsx b/frontend/src/app/pages/StoryBoardPage/Editor/StorySetting.tsx index 8043af15f..91c87923f 100644 --- a/frontend/src/app/pages/StoryBoardPage/Editor/StorySetting.tsx +++ b/frontend/src/app/pages/StoryBoardPage/Editor/StorySetting.tsx @@ -16,6 +16,7 @@ * limitations under the License. */ import { Checkbox, Form, InputNumber } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import produce from 'immer'; import React, { memo, useCallback, useContext, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; @@ -27,12 +28,12 @@ import { updateStory } from '../slice/thunks'; import { StoryBoardState } from '../slice/types'; export interface StorySettingProps {} export const StorySetting: React.FC<StorySettingProps> = memo(() => { + const t = useI18NPrefix(`viz.board.setting`); const dispatch = useDispatch(); const { stroyBoardId: storyId } = useContext(StoryContext); const storyBoard = useSelector((state: { storyBoard: StoryBoardState }) => makeSelectStoryBoardById(state, storyId), ); - // TODO add isLoop option -xieLiuDuo const autoPlay = storyBoard?.config?.autoPlay; const [form] = Form.useForm(); useEffect(() => { @@ -61,10 +62,10 @@ export const StorySetting: React.FC<StorySettingProps> = memo(() => { form={form} layout="inline" > - <Form.Item name="auto" label="自动播放" valuePropName="checked"> + <Form.Item name="auto" label={t('autoPlay')} valuePropName="checked"> <Checkbox /> </Form.Item> - <Form.Item name="delay" label="每页时间(秒)"> + <Form.Item name="delay" label={t('duration')}> <InputNumber /> </Form.Item> </Form> diff --git a/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx b/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx index 967ac8934..e61651a68 100644 --- a/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx +++ b/frontend/src/app/pages/StoryBoardPage/Editor/index.tsx @@ -17,6 +17,7 @@ */ import { Layout, Modal } from 'antd'; import { Split } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { useSplitSizes } from 'app/hooks/useSplitSizes'; import { StoryContext } from 'app/pages/StoryBoardPage/contexts/StoryContext'; import { dispatchResize } from 'app/utils/dispatchResize'; @@ -53,6 +54,7 @@ export const StoryEditor: React.FC<{ storyId: string; onCloseEditor?: () => void; }> = memo(({ storyId, onCloseEditor }) => { + const t = useI18NPrefix(`viz.board.setting`); const domId = useMemo(() => uuidv4(), []); const revealRef = useRef<any>(); const dispatch = useDispatch(); @@ -181,19 +183,15 @@ export const StoryEditor: React.FC<{ const onDeletePages = useCallback( (pageIds: string[]) => { Modal.confirm({ - title: - pageIds.length > 1 - ? '确认删除所有选中的故事页?' - : '确认删除此故事页?', + title: pageIds.length > 1 ? t('delPagesTip') : t('delPageTip'), onOk: () => { - // onDelete(selectedIds); pageIds.forEach(pageId => { dispatch(deleteStoryPage({ storyId, pageId })); }); }, }); }, - [dispatch, storyId], + [dispatch, storyId, t], ); return ( <DndProvider backend={HTML5Backend}> diff --git a/frontend/src/app/pages/StoryBoardPage/components/StoryHeader.tsx b/frontend/src/app/pages/StoryBoardPage/components/StoryHeader.tsx index cf57eb592..44c55fde8 100644 --- a/frontend/src/app/pages/StoryBoardPage/components/StoryHeader.tsx +++ b/frontend/src/app/pages/StoryBoardPage/components/StoryHeader.tsx @@ -24,13 +24,19 @@ import { import { Button, Dropdown } from 'antd'; import { DetailPageHeader } from 'app/components/DetailPageHeader'; import { ShareLinkModal } from 'app/components/VizOperationMenu'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { generateShareLinkAsync } from 'app/utils/fetch'; -import React, { FC, memo, useCallback, useContext, useState } from 'react'; +import { TITLE_SUFFIX } from 'globalConstants'; +import React, { + FC, + memo, + useCallback, + useContext, + useMemo, + useState, +} from 'react'; import { StoryContext } from '../contexts/StoryContext'; import { StoryOverLay } from './StoryOverLay'; -// import { useSelector } from 'react-redux'; - -const TITLE_SUFFIX = ['[已归档]', '[未发布]']; interface StoryHeaderProps { name?: string; @@ -55,7 +61,14 @@ export const StoryHeader: FC<StoryHeaderProps> = memo( allowShare, allowManage, }) => { - const title = `${name || ''} ${TITLE_SUFFIX[Number(status)] || ''}`; + const t = useI18NPrefix(`viz.action`); + const title = useMemo(() => { + const base = name || ''; + const suffix = TITLE_SUFFIX[Number(status)] + ? `[${t(TITLE_SUFFIX[Number(status)])}]` + : ''; + return base + suffix; + }, [name, status, t]); const isArchived = Number(status) === 0; const [showShareLinkModal, setShowShareLinkModal] = useState(false); const { stroyBoardId } = useContext(StoryContext); @@ -94,16 +107,16 @@ export const StoryHeader: FC<StoryHeaderProps> = memo( loading={publishLoading} onClick={onPublish} > - {status === 1 ? '发布' : '取消发布'} + {status === 1 ? t('publish') : t('cancelPublish')} </Button> )} {allowManage && !isArchived && ( <Button key="edit" onClick={toggleEdit}> - 编辑 + {t('edit')} </Button> )} <Button key="run" onClick={playStory}> - 播放 + {t('play')} </Button> <Dropdown overlay={ diff --git a/frontend/src/app/pages/StoryBoardPage/components/StoryOverLay.tsx b/frontend/src/app/pages/StoryBoardPage/components/StoryOverLay.tsx index d70e83eec..a48dc9dd3 100644 --- a/frontend/src/app/pages/StoryBoardPage/components/StoryOverLay.tsx +++ b/frontend/src/app/pages/StoryBoardPage/components/StoryOverLay.tsx @@ -17,6 +17,7 @@ */ import { ShareAltOutlined } from '@ant-design/icons'; import { Menu } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import React, { memo, useMemo } from 'react'; export interface BoardOverLayProps { onOpenShareLink?: () => void; @@ -26,6 +27,7 @@ export interface BoardOverLayProps { } export const StoryOverLay: React.FC<BoardOverLayProps> = memo( ({ onOpenShareLink, allowShare }) => { + const t = useI18NPrefix(`viz.action.share`); const renderList = useMemo( () => [ { @@ -34,10 +36,10 @@ export const StoryOverLay: React.FC<BoardOverLayProps> = memo( onClick: onOpenShareLink, disabled: false, render: allowShare, - content: '分享链接', + content: t('shareLink'), }, ], - [onOpenShareLink, allowShare], + [onOpenShareLink, allowShare, t], ); const actionItems = useMemo( () => diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index f2306eb40..3a69309b6 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -539,6 +539,7 @@ "published": "Published", "unpublished": "Unpublished", "archived": "Archived", + "play": "Play", "share": { "link": "Link", "password": "Password", @@ -613,7 +614,14 @@ "rowHeight": "rowHeight", "scaleMode": "scale Mode", "queryMode": "query Mode", - "openInitQuery": "open Init Query" + "openInitQuery": "open Init Query", + "cutIn": "Cut In", + "cutOut": "Cut Out", + "speed": "Speed", + "autoPlay": "Auto Play", + "duration": "Duration (s) ", + "delPagesTip": "Confirm to delete all selected story pages?", + "delPageTip": "Confirm to delete this story page?" } }, "widget": { @@ -948,4 +956,4 @@ "searchValue": "Search keywords" } } -} +} \ No newline at end of file diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index cc4ee5f0a..ae2d002a6 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -538,6 +538,7 @@ "published": "已发布", "unpublished": "未发布", "archived": "已归档", + "play": "播放", "share": { "link": "链接", "password": "密码", @@ -611,7 +612,14 @@ "rowHeight": "行高", "scaleMode": "缩放模式", "queryMode": "查询模式", - "openInitQuery": "开启初始化查询" + "openInitQuery": "开启初始化查询", + "cutIn": "切入", + "cutOut": "切出", + "speed": "速度", + "autoPlay": "自动播放", + "duration": "停留时间(秒)", + "delPagesTip": "确认删除所有选中的故事页", + "delPageTip": "确认删除此故事页?" } }, "widget": { @@ -945,4 +953,4 @@ "searchValue": "搜索名称关键字" } } -} +} \ No newline at end of file From ffd3be6277d2372d3fb06db77cd6497bb48fc8e7 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Thu, 30 Dec 2021 17:37:37 +0800 Subject: [PATCH 302/348] translate: translate/en --- frontend/src/locales/en/translation.json | 172 +++++++++++------------ frontend/src/locales/zh/translation.json | 4 +- 2 files changed, 88 insertions(+), 88 deletions(-) diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 9addbff2d..3557a7764 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -30,21 +30,21 @@ "passwordNotMatch": "Password and confirm password does not match" }, "time": { - "minute": "分钟", - "hour": "小时", - "day": "天", - "month": "月", - "year": "年", - "m": "分", - "h": "时", - "d": "日", - "sun": "星期天", - "mon": "星期一", - "tues": "星期二", - "wednes": "星期三", - "thurs": "星期四", - "fri": "星期五", - "satur": "星期六" + "minute": "Minute", + "hour": "Hours", + "day": "Day", + "month": "Month", + "year": "Years", + "m": "Minute", + "h": "Hours", + "d": "Day", + "sun": "Sunday", + "mon": "Monday", + "tues": "Tuesday", + "wednes": "Wednesday", + "thurs": "Thursday", + "fri": "Friday", + "satur": "Saturday" }, "modal": { "title": { @@ -162,10 +162,10 @@ }, "subNavs": { "variables": { - "title": "公共变量设置" + "title": "Public variable Settings" }, "orgSettings": { - "title": "组织设置" + "title": "Organization Settings" } }, "background": { @@ -176,103 +176,103 @@ "pages": { "schedulePage": { "constants": { - "email": "邮箱", - "weChat": "微信", - "picture": "图片", - "taskExecution": "任务执行", - "configurationAnalysis": "配置解析", - "getData": "数据获取", - "send": "发送" + "email": "Email", + "weChat": "WeChat", + "picture": "Picture", + "taskExecution": "Task execution", + "configurationAnalysis": "Configure the parsing", + "getData": "Data collection", + "send": "Send" }, "sidebar": { "index": { - "scheduledTaskList": "定时任务列表", - "newTimedTask": "新建定时任务", - "recycle": "回收站" + "scheduledTaskList": "Scheduled task list", + "newTimedTask": "Create scheduled task", + "recycle": "Recycle" }, "scheduleList": { - "successStarted": "启动成功", - "successStop": "停止成功", - "successImmediately": "立即执行成功", - "start": "启动", - "stop": "停止", - "executeItNow": "确定立即执行?", - "executeImmediately": "立即执行" + "successStarted": "Successfully started", + "successStop": "Stopped successfully", + "successImmediately": "Executed successfully immediately", + "start": "Start", + "stop": "Stop", + "executeItNow": "Are you sure to execute it now?", + "executeImmediately": "Execute immediately" }, "editorPage": { "index": { - "tickToSendContent": "请勾选发送内容", - "addSuccess": "新增成功", - "saveSuccess": "保存成功", - "restoredSuccess": "还原成功", - "success": "成功", - "moveToTrash": "移至回收站", - "delete": "删除", - "newTimedTask": "新建定时任务", - "sureToRestore?": "确定还原?", - "restore": "还原", - "sureToDelete": "确定删除?", - "allowModificationAfterStopping": "停止后允许修改", - "save": "保存", - "allowMoveAfterStopping": "停止后允许移至回收站", - "sureMoveRecycleBin": "确定移至回收站?", - "basicSettings": "基本设置", - "emailSetting": "邮件设置", - "enterpriseWeChatSettings": "企业微信设置", - "sendContentSettings": "发送内容设置" + "tickToSendContent": "Please tick to send content", + "addSuccess": "Added successfully", + "saveSuccess": "Saved successfully", + "restoredSuccess": "Restored successfully", + "success": "Success", + "moveToTrash": "Move to recycle bin", + "delete": "Delete", + "newTimedTask": "New timed task", + "sureToRestore?": "Are you sure to restore?", + "restore": "Reduction", + "sureToDelete": "Confirm delete?", + "allowModificationAfterStopping": "Allow modification after stopping", + "save": "Save", + "allowMoveAfterStopping": "Allow moving to the recycle bin after stopping", + "sureMoveRecycleBin": "Are you sure to move to the recycle bin?", + "basicSettings": "Basic settings", + "emailSetting": "Email settings", + "enterpriseWeChatSettings": "Enterprise WeChat Settings", + "sendContentSettings": "Send content settings" }, "weChartSetttingForm": { - "RobotWebhookAddress": "机器人webhook地址", - "RobotWebhookAddressIsRequired": "机器人webhook地址为必填项", - "fileType": "文件类型", - "picWidth": "图片宽度", - "px": "像素" + "RobotWebhookAddress": "Robot webhook address", + "RobotWebhookAddressIsRequired": "Robot webhook address is required", + "fileType": "File type", + "picWidth": "Width", + "px": "px" }, "scheduleErrorLog": { "index": { - "startTime": "开始时间", - "endTime": "结束时间", - "logPhase": "日志阶段", - "executionInformation": "执行信息", - "success": "成功", - "log": "日志" + "startTime": "Start", + "endTime": "End", + "logPhase": "Log phase", + "executionInformation": "Execution information", + "success": "Success", + "log": "Log" } }, "emailSettingForm": { "commonRichText": { - "pleaseEnter": "请输入" + "pleaseEnter": "Please enter" }, "index": { - "CC": "抄送", - "theme": "主题", - "subjectIsRequired": "主题为必填项", - "fileType": "文件类型", - "picWidth": "图片宽度", - "px": "像素", - "recipient": "收件人", - "recipientIsRequired": "收件人为必填项", - "bcc": "密送", - "contentOfEmail": "邮件内容" + "CC": "CC", + "theme": "Theme", + "subjectIsRequired": "Theme is required", + "fileType": "File type", + "picWidth": "Width", + "px": "px", + "recipient": "Recipient", + "recipientIsRequired": "Recipient is required", + "bcc": "BCC", + "contentOfEmail": "Content of email" }, "mailTagFormItem": { - "placeholder": "输入邮箱或姓名关键字查找..." + "placeholder": "Enter email address or name keyword search..." } }, "basicBaseForm": { "index": { - "nameAlreadyExists": "名称已存在", - "name": "名称", - "nameRequired": "名称为必填项", - "type": "类型", - "effectiveTimeRange": "有效时间范围" + "nameAlreadyExists": "Name already exists", + "name": "Name", + "nameRequired": "Name is required", + "type": "Type", + "effectiveTimeRange": "Effective time range" }, "executeFormItem": { - "per": "每", + "per": "Each", "of": "", - "executionTimeSetting": "执行时间设置", - "expressionIsRequired": "表达式为必填项", - "pleaseEnterCronExpression": "请输入cron表达式", - "manualInput": "手动输入" + "executionTimeSetting": "Execution time setting", + "expressionIsRequired": "Expression is required", + "pleaseEnterCronExpression": "Please enter cron expression", + "manualInput": "Manual input" } } } diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 8dfc92fbc..42ac9a3d0 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -384,7 +384,7 @@ "relative": "相对" }, "category": { - "general": "General", + "general": "常规", "customize": "自定义", "condition": "条件", "sourceList": "源列表", @@ -705,7 +705,7 @@ "widget": "组件", "widgetList": "组件列表", "title": "标题", - "align": "Align", + "align": "对齐", "showTitle": "显示标题", "position": "位置", "xAxis": "x轴", From 5cb9196b47288cd9545c6f26c48b239bc4bbf6d1 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 30 Dec 2021 18:08:06 +0800 Subject: [PATCH 303/348] chore: add i18n board action --- .../components/BoardToolBar/ToolBarItem.tsx | 4 +-- frontend/src/locales/en/translation.json | 25 +++++++++++++++---- frontend/src/locales/zh/translation.json | 25 +++++++++++++++---- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/ToolBarItem.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/ToolBarItem.tsx index ad407d846..df058667a 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/ToolBarItem.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/BoardToolBar/ToolBarItem.tsx @@ -175,7 +175,7 @@ export const ToTopBtn: React.FC<ToolBtnProps> = props => { disabled={selectedIds.length !== 1} onClick={toTop} icon={<VerticalAlignTopOutlined />} - tip="置顶" + tip={t('toTop')} {...props} /> ); @@ -192,7 +192,7 @@ export const ToBottomBtn: React.FC<ToolBtnProps> = props => { disabled={selectedIds.length !== 1} onClick={toBottom} icon={<VerticalAlignBottomOutlined />} - tip="置底" + tip={t('toBottom')} {...props} /> ); diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index f2306eb40..d2ca40cb1 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -563,6 +563,8 @@ "container": "Container", "tab": "Tab", "controller": "Controller", + "toTop": "move To Top", + "toBottom": "move To Bottom", "undo": "Undo", "redo": "Redo", "delete": "Delete", @@ -920,10 +922,23 @@ "Disable": "Disable" }, "privilegeLabel": { - "viz": ["View", "Download", "Share", "Manage"], - "view": ["Access", "Manage"], - "source": ["Access", "Manage"], - "schedule": ["Manage"] + "viz": [ + "View", + "Download", + "Share", + "Manage" + ], + "view": [ + "Access", + "Manage" + ], + "source": [ + "Access", + "Manage" + ], + "schedule": [ + "Manage" + ] } }, "share": { @@ -948,4 +963,4 @@ "searchValue": "Search keywords" } } -} +} \ No newline at end of file diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index cc4ee5f0a..e2f390de2 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -562,6 +562,8 @@ "container": "容器", "tab": "标签页", "controller": "控制器", + "toTop": "图层置顶", + "toBottom": "图层置底", "undo": "撤销", "redo": "重做", "delete": "删除", @@ -917,10 +919,23 @@ "Disable": "禁用" }, "privilegeLabel": { - "viz": { "0": "查看", "1": "下载", "2": "分享", "3": "管理" }, - "view": { "0": "使用", "1": "管理" }, - "source": { "0": "使用", "1": "管理" }, - "schedule": { "0": "管理" } + "viz": { + "0": "查看", + "1": "下载", + "2": "分享", + "3": "管理" + }, + "view": { + "0": "使用", + "1": "管理" + }, + "source": { + "0": "使用", + "1": "管理" + }, + "schedule": { + "0": "管理" + } } }, "share": { @@ -945,4 +960,4 @@ "searchValue": "搜索名称关键字" } } -} +} \ No newline at end of file From 99f21bb57f8ffab845f85342d90a49aee32fdd77 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Thu, 30 Dec 2021 18:21:52 +0800 Subject: [PATCH 304/348] fix(chart): add debugger reference --- .../src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts index f4aaad3fe..88f272918 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartEventBroker.ts @@ -17,6 +17,7 @@ */ import { ChartLifecycle } from 'app/types/ChartLifecycle'; +import { Debugger } from 'utils/debugger'; import Chart from './Chart'; type BrokerContext = { From 9800269ae1493c438e4211762957b19e48a19d64 Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Thu, 30 Dec 2021 19:05:32 +0800 Subject: [PATCH 305/348] feat: remove docker-compose.yml.example fix: rename in8n properties --- docker-compose.yml.example | 15 --------------- server/src/main/resources/application.yml | 5 ----- ...en_US.properties => datart_i18n_en.properties} | 0 ...zh_CN.properties => datart_i18n_zh.properties} | 0 4 files changed, 20 deletions(-) delete mode 100644 docker-compose.yml.example rename server/src/main/resources/i18n/{datart_i18n_en_US.properties => datart_i18n_en.properties} (100%) rename server/src/main/resources/i18n/{datart_i18n_zh_CN.properties => datart_i18n_zh.properties} (100%) diff --git a/docker-compose.yml.example b/docker-compose.yml.example deleted file mode 100644 index 52693f538..000000000 --- a/docker-compose.yml.example +++ /dev/null @@ -1,15 +0,0 @@ -version: '3' -services: - datart: - image: java:8 - hostname: datart - container_name: datart - restart: always - volumes: - - "{datart application root path}:/datart" - entrypoint: [ "sh","/datart/bin/datart-server.sh" ] - environment: - - TZ=Asia/Shanghai - logging: - options: - max-size: "1g" \ No newline at end of file diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index a4653ed1e..4ad0f42e2 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -2,11 +2,6 @@ spring: application: name: datart-server - datasource: - druid: - mysql: - usePingMethod: false - main: banner-mode: off diff --git a/server/src/main/resources/i18n/datart_i18n_en_US.properties b/server/src/main/resources/i18n/datart_i18n_en.properties similarity index 100% rename from server/src/main/resources/i18n/datart_i18n_en_US.properties rename to server/src/main/resources/i18n/datart_i18n_en.properties diff --git a/server/src/main/resources/i18n/datart_i18n_zh_CN.properties b/server/src/main/resources/i18n/datart_i18n_zh.properties similarity index 100% rename from server/src/main/resources/i18n/datart_i18n_zh_CN.properties rename to server/src/main/resources/i18n/datart_i18n_zh.properties From d9f86332572d992c6e49b3797aea909dc3b3d7aa Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 30 Dec 2021 19:08:23 +0800 Subject: [PATCH 306/348] feat: add useCacheWidthHeight --- frontend/src/app/hooks/useCacheWidthHeight.ts | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 frontend/src/app/hooks/useCacheWidthHeight.ts diff --git a/frontend/src/app/hooks/useCacheWidthHeight.ts b/frontend/src/app/hooks/useCacheWidthHeight.ts new file mode 100644 index 000000000..f4a55bd93 --- /dev/null +++ b/frontend/src/app/hooks/useCacheWidthHeight.ts @@ -0,0 +1,47 @@ +/** + * 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 { useEffect, useState } from 'react'; +import useResizeObserver from './useResizeObserver'; + +export const useCacheWidthHeight = ( + initWidth: number = 400, + initHeight: number = 300, +) => { + const [cacheW, setCacheW] = useState(initWidth); + const [cacheH, setCacheH] = useState(initHeight); + const { + ref, + width = initWidth, + height = initHeight, + } = useResizeObserver<HTMLDivElement>({ + refreshMode: 'debounce', + refreshRate: 500, + }); + useEffect(() => { + if (width !== 0 && height !== 0) { + setCacheW(width); + setCacheH(height); + } + }, [width, height]); + return { + ref, + cacheW, + cacheH, + }; +}; From 0e2168334b25f31164d7b53053bcaba085065334 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 30 Dec 2021 19:10:57 +0800 Subject: [PATCH 307/348] refactor: ChartPreview --- ...ChartPreviewBoard.tsx => ChartPreview.tsx} | 38 ++++--------------- .../pages/VizPage/ChartPreview/index.ts | 2 +- .../pages/VizPage/Main/VizContainer.tsx | 4 +- 3 files changed, 10 insertions(+), 34 deletions(-) rename frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/{ChartPreviewBoard.tsx => ChartPreview.tsx} (90%) diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreviewBoard.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreview.tsx similarity index 90% rename from frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreviewBoard.tsx rename to frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreview.tsx index f967e5021..73b6f6826 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreviewBoard.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreview.tsx @@ -19,7 +19,7 @@ import { message } from 'antd'; import ChartEditor from 'app/components/ChartEditor'; import { VizHeader } from 'app/components/VizHeader'; -import useResizeObserver from 'app/hooks/useResizeObserver'; +import { useCacheWidthHeight } from 'app/hooks/useCacheWidthHeight'; import Chart from 'app/pages/ChartWorkbenchPage/models/Chart'; import { ChartDataRequestBuilder } from 'app/pages/ChartWorkbenchPage/models/ChartHttpRequest'; import ChartManager from 'app/pages/ChartWorkbenchPage/models/ChartManager'; @@ -59,16 +59,7 @@ const ChartPreviewBoard: FC<{ allowManage, }) => { useVizSlice(); - - const previewBlockObserver = useResizeObserver<HTMLDivElement>({ - refreshMode: 'debounce', - refreshRate: 500, - }); - const controllerObserver = useResizeObserver<HTMLDivElement>({ - refreshMode: 'debounce', - refreshRate: 500, - }); - + const { ref, cacheW, cacheH } = useCacheWidthHeight(); const { actions } = useMainSlice(); const chartManager = ChartManager.instance(); const dispatch = useDispatch(); @@ -233,19 +224,6 @@ const ChartPreviewBoard: FC<{ } }, [dispatch, chartPreview?.backendChart]); - const calcuateChartContainerRegion = () => { - const region = { width: 300, height: 300 }; - if (!controllerObserver?.ref || !previewBlockObserver?.ref) { - return region; - } - return { - width: previewBlockObserver?.width || region.width, - height: - (previewBlockObserver?.height || region.height) - - (controllerObserver?.height || 0), - }; - }; - return ( <StyledChartPreviewBoard> <VizHeader @@ -260,8 +238,8 @@ const ChartPreviewBoard: FC<{ allowShare={allowShare} allowManage={allowManage} /> - <PreviewBlock ref={previewBlockObserver.ref}> - <div ref={controllerObserver.ref}> + <PreviewBlock> + <div> <ControllerPanel viewId={chartPreview?.backendChart?.viewId} view={chartPreview?.backendChart?.view} @@ -269,15 +247,15 @@ const ChartPreviewBoard: FC<{ onChange={handleFilterChange} /> </div> - <ChartWrapper> + <ChartWrapper ref={ref}> <ChartTools.ChartIFrameContainer key={backendChartId} containerId={backendChartId} dataset={chartPreview?.dataset} chart={chart!} config={chartPreview?.chartConfig!} - width={calcuateChartContainerRegion().width} - height={calcuateChartContainerRegion().height} + width={cacheW} + height={cacheH} /> </ChartWrapper> </PreviewBlock> @@ -297,7 +275,6 @@ const ChartPreviewBoard: FC<{ ); export default ChartPreviewBoard; - const StyledChartPreviewBoard = styled.div` display: flex; flex: 1; @@ -308,7 +285,6 @@ const StyledChartPreviewBoard = styled.div` flex-grow: 1000; } `; - const PreviewBlock = styled.div` display: flex; flex: 1; diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/index.ts b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/index.ts index 91ab61921..e4b9db2ac 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/index.ts +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/index.ts @@ -16,4 +16,4 @@ * limitations under the License. */ -export { default as ChartPreviewBoard } from './ChartPreviewBoard'; +export { default as ChartPreview } from './ChartPreview'; diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/Main/VizContainer.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/Main/VizContainer.tsx index 9019d7a1c..e0e9b81cc 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/Main/VizContainer.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/Main/VizContainer.tsx @@ -10,7 +10,7 @@ import { ResourceTypes, VizResourceSubTypes, } from '../../PermissionPage/constants'; -import { ChartPreviewBoard } from '../ChartPreview'; +import { ChartPreview } from '../ChartPreview'; import { FolderViewModel, VizTab } from '../slice/types'; interface VizContainerProps { @@ -70,7 +70,7 @@ export const VizContainer = memo( break; case 'DATACHART': content = ( - <ChartPreviewBoard + <ChartPreview key={id} backendChartId={id} orgId={orgId} From 5cad4e6604fcc48316ed784724edc58cff5aa329 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 30 Dec 2021 19:15:47 +0800 Subject: [PATCH 308/348] refactor: DatachartWidget use hook W and H --- .../WidgetCore/DataChartWidget/index.tsx | 23 ++----------------- .../VizPage/ChartPreview/ChartPreview.tsx | 2 +- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx index d6c2fef94..0e9281ed3 100644 --- a/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/WidgetCore/DataChartWidget/index.tsx @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import useResizeObserver from 'app/hooks/useResizeObserver'; +import { useCacheWidthHeight } from 'app/hooks/useCacheWidthHeight'; import ChartIFrameContainer from 'app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartTools/ChartIFrameContainer'; import Chart from 'app/pages/ChartWorkbenchPage/models/Chart'; import ChartManager from 'app/pages/ChartWorkbenchPage/models/ChartManager'; @@ -33,7 +33,6 @@ import React, { useEffect, useMemo, useRef, - useState, } from 'react'; import styled from 'styled-components/macro'; export interface DataChartWidgetProps {} @@ -43,8 +42,7 @@ export const DataChartWidget: React.FC<DataChartWidgetProps> = memo(() => { const widget = useContext(WidgetContext); const { id: widgetId } = widget; const { widgetChartClick } = useContext(WidgetMethodContext); - const [cacheW, setCacheW] = useState(200); - const [cacheH, setCacheH] = useState(200); + const { ref, cacheW, cacheH } = useCacheWidthHeight(); const widgetRef = useRef<Widget>(widget); useEffect(() => { widgetRef.current = widget; @@ -106,23 +104,6 @@ export const DataChartWidget: React.FC<DataChartWidgetProps> = memo(() => { }; }, [widget]); - const onResize = useCallback(() => {}, []); - - const { - ref, - width = 200, - height = 200, - } = useResizeObserver<HTMLDivElement>({ - refreshMode: 'debounce', - refreshRate: 120, - onResize, - }); - useEffect(() => { - if (width !== 0 && height !== 0) { - setCacheW(width); - setCacheH(height); - } - }, [width, height]); const dataset = useMemo( () => ({ columns: data.columns, diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreview.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreview.tsx index 73b6f6826..e523ec7bf 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreview.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreview.tsx @@ -59,7 +59,7 @@ const ChartPreviewBoard: FC<{ allowManage, }) => { useVizSlice(); - const { ref, cacheW, cacheH } = useCacheWidthHeight(); + const { ref, cacheW, cacheH } = useCacheWidthHeight(800, 600); const { actions } = useMainSlice(); const chartManager = ChartManager.instance(); const dispatch = useDispatch(); From 875804118c77f3566bc63c7a433b04da01e760c5 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Thu, 30 Dec 2021 19:35:47 +0800 Subject: [PATCH 309/348] fix: locale initialization --- .../ColorPicker/ThemeColorSelection.tsx | 3 +- .../src/app/pages/MainPage/Navbar/index.tsx | 7 ++-- frontend/src/app/share.tsx | 26 ++++++++------ frontend/src/globalConstants.ts | 1 + frontend/src/locales/i18n.ts | 34 ++++++++++++++++--- frontend/src/locales/moment.ts | 25 -------------- frontend/src/share.tsx | 14 +++----- frontend/src/utils/request.ts | 2 +- 8 files changed, 55 insertions(+), 57 deletions(-) delete mode 100644 frontend/src/locales/moment.ts diff --git a/frontend/src/app/components/ColorPicker/ThemeColorSelection.tsx b/frontend/src/app/components/ColorPicker/ThemeColorSelection.tsx index ae0e861a7..9885c2266 100644 --- a/frontend/src/app/components/ColorPicker/ThemeColorSelection.tsx +++ b/frontend/src/app/components/ColorPicker/ThemeColorSelection.tsx @@ -32,7 +32,6 @@ function ThemeColorSelection({ children, callbackFn }: themeColorPropTypes) { const [switchStatus, setSwitchStatus] = useState(false); const [colors] = useState(colorThemes); const { i18n } = useTranslation(); - const { language = 'zh' } = i18n; return ( <Popover @@ -53,7 +52,7 @@ function ThemeColorSelection({ children, callbackFn }: themeColorPropTypes) { setSwitchStatus(false); }} > - <ColorTitle>{item[language].title}</ColorTitle> + <ColorTitle>{item[i18n.language].title}</ColorTitle> <ColorBlockWrap> {item.colors.map((v, i) => { return <ColorBlock color={v} key={i}></ColorBlock>; diff --git a/frontend/src/app/pages/MainPage/Navbar/index.tsx b/frontend/src/app/pages/MainPage/Navbar/index.tsx index c70b7b496..0cb392db4 100644 --- a/frontend/src/app/pages/MainPage/Navbar/index.tsx +++ b/frontend/src/app/pages/MainPage/Navbar/index.tsx @@ -43,6 +43,7 @@ import { selectLoggedInUser } from 'app/slice/selectors'; import { logout } from 'app/slice/thunks'; import { downloadFile } from 'app/utils/fetch'; import { BASE_RESOURCE_URL } from 'globalConstants'; +import { changeLang } from 'locales/i18n'; import React, { cloneElement, useCallback, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; @@ -206,16 +207,14 @@ export function Navbar() { setModifyPasswordVisible(true); break; case 'zh': - i18n.changeLanguage('zh'); - break; case 'en': - i18n.changeLanguage('en'); + changeLang(key); break; default: break; } }, - [dispatch, history, i18n], + [dispatch, history], ); const onSetPolling = useCallback( diff --git a/frontend/src/app/share.tsx b/frontend/src/app/share.tsx index 97d4a826c..3994aa508 100644 --- a/frontend/src/app/share.tsx +++ b/frontend/src/app/share.tsx @@ -16,8 +16,10 @@ * limitations under the License. */ +import { ConfigProvider } from 'antd'; import echartsDefaultTheme from 'app/assets/theme/echarts_default_theme.json'; import { registerTheme } from 'echarts'; +import { antdLocales } from 'locales/i18n'; import { Helmet } from 'react-helmet-async'; import { useTranslation } from 'react-i18next'; import { BrowserRouter } from 'react-router-dom'; @@ -30,16 +32,18 @@ export function Share() { const { i18n } = useTranslation(); return ( - <BrowserRouter> - <Helmet - title="Datart Share Link" - htmlAttributes={{ lang: i18n.language }} - > - <meta name="description" content="Data Art" /> - </Helmet> - <LazySharePage /> - <GlobalStyle /> - <OverriddenStyle /> - </BrowserRouter> + <ConfigProvider locale={antdLocales[i18n.language]}> + <BrowserRouter> + <Helmet + title="Datart Share Link" + htmlAttributes={{ lang: i18n.language }} + > + <meta name="description" content="Data Art" /> + </Helmet> + <LazySharePage /> + <GlobalStyle /> + <OverriddenStyle /> + </BrowserRouter> + </ConfigProvider> ); } diff --git a/frontend/src/globalConstants.ts b/frontend/src/globalConstants.ts index 0679cf935..7f103669f 100644 --- a/frontend/src/globalConstants.ts +++ b/frontend/src/globalConstants.ts @@ -25,6 +25,7 @@ export enum StorageKeys { AuthorizationToken = 'AUTHORIZATION_TOKEN', LoggedInUser = 'LOGGED_IN_USER', ShareClientId = 'SHARE_CLIENT_ID', + Locale = 'LOCALE', } export const BASE_API_URL = '/api/v1'; export const BASE_RESOURCE_URL = '/'; diff --git a/frontend/src/locales/i18n.ts b/frontend/src/locales/i18n.ts index 4c1120612..b0fc6c0ef 100644 --- a/frontend/src/locales/i18n.ts +++ b/frontend/src/locales/i18n.ts @@ -1,8 +1,12 @@ -import en_US from 'antd/lib/locale/en_US'; -import zh_CN from 'antd/lib/locale/zh_CN'; +import antd_en_US from 'antd/lib/locale/en_US'; +import antd_zh_CN from 'antd/lib/locale/zh_CN'; +import { StorageKeys } from 'globalConstants'; import i18next from 'i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; +import moment from 'moment'; +import 'moment/locale/zh-cn'; import { initReactI18next } from 'react-i18next'; +import { instance as requestInstance } from 'utils/request'; import en from './en/translation.json'; import { convertLanguageJsonToObject } from './translations'; import zh from './zh/translation.json'; @@ -21,8 +25,15 @@ convertLanguageJsonToObject(en); export const changeLang = lang => { i18next.changeLanguage(lang); + requestInstance.defaults.headers['Accept-Language'] = + lang === 'zh' ? 'zh-CN' : 'en-US'; // FIXME locale + localStorage.setItem(StorageKeys.Locale, lang); + moment.locale(lang === 'zh' ? 'zh-cn' : 'en-us'); // FIXME locale }; +const initialLocale = getInitialLocale(); +moment.locale(initialLocale); + export const i18n = i18next // pass the i18n instance to react-i18next. .use(initReactI18next) @@ -32,7 +43,7 @@ export const i18n = i18next // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ - lng: 'zh', + lng: initialLocale, resources: translationsJson, fallbackLng: 'en', debug: @@ -44,6 +55,19 @@ export const i18n = i18next }); export const antdLocales = { - en: en_US, - zh: zh_CN, + en: antd_en_US, + zh: antd_zh_CN, }; + +function getInitialLocale() { + const storedLocale = localStorage.getItem(StorageKeys.Locale); + if (!storedLocale) { + const browserLocale = ['zh', 'zh-CN'].includes(navigator.language) // FIXME locale + ? 'zh' + : 'en'; + localStorage.setItem(StorageKeys.Locale, browserLocale); + return browserLocale; + } else { + return storedLocale; + } +} diff --git a/frontend/src/locales/moment.ts b/frontend/src/locales/moment.ts deleted file mode 100644 index bbd0a4353..000000000 --- a/frontend/src/locales/moment.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * 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. - */ - -// TODO: add more language here -import moment from 'moment'; -import 'moment/locale/zh-cn'; - -export function setLocale(locale) { - moment.locale(locale); -} diff --git a/frontend/src/share.tsx b/frontend/src/share.tsx index 6561ebda6..507048cca 100644 --- a/frontend/src/share.tsx +++ b/frontend/src/share.tsx @@ -1,6 +1,4 @@ -import { ConfigProvider } from 'antd'; import 'antd/dist/antd.less'; -import zh_CN from 'antd/lib/locale/zh_CN'; import 'app/assets/fonts/iconfont.css'; import { Share } from 'app/share'; import React from 'react'; @@ -20,8 +18,6 @@ const MOUNT_NODE = document.getElementById('root') as HTMLElement; * hot-key [control,shift,command,c] */ -const MainApp = <Share />; - const InspectorWrapper = process.env.NODE_ENV === 'development' ? Inspector : React.Fragment; @@ -29,11 +25,11 @@ ReactDOM.render( <InspectorWrapper> <Provider store={store}> <ThemeProvider> - <ConfigProvider locale={zh_CN}> - <HelmetProvider> - <React.StrictMode>{MainApp}</React.StrictMode> - </HelmetProvider> - </ConfigProvider> + <HelmetProvider> + <React.StrictMode> + <Share /> + </React.StrictMode> + </HelmetProvider> </ThemeProvider> </Provider> </InspectorWrapper>, diff --git a/frontend/src/utils/request.ts b/frontend/src/utils/request.ts index 99810fda5..c4fb24749 100644 --- a/frontend/src/utils/request.ts +++ b/frontend/src/utils/request.ts @@ -21,7 +21,7 @@ import { BASE_API_URL } from 'globalConstants'; import { APIResponse } from 'types'; import { getToken, setToken } from './auth'; -const instance = axios.create({ +export const instance = axios.create({ baseURL: BASE_API_URL, validateStatus(status) { return status < 400; From 8fa6e183e0cfacbe1132748b3f2bd7434da453e9 Mon Sep 17 00:00:00 2001 From: xieliuduo <xliuduo@163.com> Date: Thu, 30 Dec 2021 20:09:12 +0800 Subject: [PATCH 310/348] chore: add playTip on play StoryBoard --- frontend/src/app/pages/StoryBoardPage/Preview/Preview.tsx | 7 ++++--- frontend/src/locales/en/translation.json | 1 + frontend/src/locales/zh/translation.json | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/pages/StoryBoardPage/Preview/Preview.tsx b/frontend/src/app/pages/StoryBoardPage/Preview/Preview.tsx index b680a744e..ca8f5c493 100644 --- a/frontend/src/app/pages/StoryBoardPage/Preview/Preview.tsx +++ b/frontend/src/app/pages/StoryBoardPage/Preview/Preview.tsx @@ -17,6 +17,7 @@ */ import { Layout, message } from 'antd'; import { Split } from 'app/components'; +import usePrefixI18N from 'app/hooks/useI18NPrefix'; import { useSplitSizes } from 'app/hooks/useSplitSizes'; import { vizActions } from 'app/pages/MainPage/pages/VizPage/slice'; import { selectPublishLoading } from 'app/pages/MainPage/pages/VizPage/slice/selectors'; @@ -50,9 +51,8 @@ export const StoryPagePreview: React.FC<{ allowManage?: boolean; }> = memo(({ storyId, allowShare, allowManage }) => { const dispatch = useDispatch(); - + const t = usePrefixI18N('viz.action'); const [currentPageIndex, setCurrentPageIndex] = useState(0); - // const [storyEditing, setStoryEditing] = useState(false); const [editorVisible, setEditorVisible] = useState(false); const storyBoard = useSelector((state: { storyBoard: StoryBoardState }) => @@ -82,8 +82,9 @@ export const StoryPagePreview: React.FC<{ setEditorVisible(c => !c); }, []); const playStory = useCallback(() => { + message.info(t('playTip')); dispatch(vizActions.changePlayingStoryId(storyId || '')); - }, [dispatch, storyId]); + }, [dispatch, storyId, t]); useEffect(() => { if (sortedPages.length === 0) { diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 585f83dd5..299d3d2c4 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -663,6 +663,7 @@ "unpublished": "Unpublished", "archived": "Archived", "play": "Play", + "playTip":"Press Esc to quit playing", "share": { "link": "Link", "password": "Password", diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 48fe0936b..36951c44f 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -663,6 +663,7 @@ "unpublished": "未发布", "archived": "已归档", "play": "播放", + "playTip":"按 Esc 退出播放", "share": { "link": "链接", "password": "密码", From 767942071c82dc40b1324fa4c14dc41d5c8ef7d4 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Thu, 30 Dec 2021 20:11:03 +0800 Subject: [PATCH 311/348] fix: Change the storage location of the aggregation state --- frontend/src/app/components/ChartEditor.tsx | 19 +++++++++++++------ .../slice/workbenchSlice.ts | 13 +++++++++---- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/frontend/src/app/components/ChartEditor.tsx b/frontend/src/app/components/ChartEditor.tsx index e43b1aa28..c836f26ec 100644 --- a/frontend/src/app/components/ChartEditor.tsx +++ b/frontend/src/app/components/ChartEditor.tsx @@ -20,6 +20,7 @@ import { ExclamationCircleOutlined } from '@ant-design/icons'; import { Modal } from 'antd'; import useMount from 'app/hooks/useMount'; import workbenchSlice, { + aggregationSelector, BackendChart, backendChartSelector, ChartConfigReducerActionType, @@ -83,6 +84,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ const chartConfig = useSelector(chartConfigSelector); const shadowChartConfig = useSelector(shadowChartConfigSelector); const backendChart = useSelector(backendChartSelector); + const aggregation = useSelector(aggregationSelector); const [chart, setChart] = useState<Chart>(); useMount( @@ -109,6 +111,9 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ backendChart: originChart as BackendChart, }), ); + if (!originChart) { + dispatch(actions.updateChartAggregation(true)); + } } else { // chartType === 'dataChart' dispatch( @@ -194,7 +199,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ chartConfig: chartConfig!, chartGraphId: chart?.meta.id!, computedFields: dataview?.computedFields || [], - aggregation: backendChart?.config?.aggregation, + aggregation, }; const dataChart: DataChart = { @@ -216,7 +221,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ dataview, onSaveInWidget, orgId, - backendChart?.config?.aggregation, + aggregation, ]); const saveChart = useCallback(async () => { @@ -229,7 +234,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ chartId: dataChartId, index: 0, parentId: 0, - aggregation: backendChart?.config?.aggregation, + aggregation: aggregation, }), ); onSaveInDataChart?.(orgId, dataChartId); @@ -250,7 +255,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ chartId: dataChartId, index: 0, parentId: 0, - aggregation: backendChart?.config?.aggregation, + aggregation, }), ); saveToWidget(); @@ -272,7 +277,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ orgId, chartType, saveToWidget, - backendChart?.config?.aggregation, + aggregation, ]); const registerChartEvents = chart => { @@ -316,6 +321,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ targetChartConfig, targetChartConfig, ); + dispatch(actions.updateChartAggregation(state)); dispatch(workbenchSlice.actions.updateShadowChartConfig({})); dispatch( @@ -327,6 +333,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ }), ); }; + return ( <StyledChartWorkbenchPage> <ChartWorkbench @@ -338,7 +345,7 @@ export const ChartEditor: React.FC<ChartEditorProps> = ({ }, onChangeAggregation: handleAggregationState, }} - aggregation={backendChart?.config?.aggregation} + aggregation={aggregation} chart={chart} dataset={dataset} dataview={dataview} diff --git a/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts b/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts index 8677ebb7e..838600ad5 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts @@ -85,6 +85,7 @@ export type WorkbenchState = { shadowChartConfig?: ChartConfig; backendChart?: BackendChart; backendChartId?: string; + aggregation?: boolean; }; const initState: WorkbenchState = { @@ -138,6 +139,11 @@ export const shadowChartConfigSelector = createSelector( wb => wb.shadowChartConfig, ); +export const aggregationSelector = createSelector( + workbenchSelector, + wb => wb.aggregation, +); + // Effects export const initWorkbenchAction = createAsyncThunk( 'workbench/initWorkbenchAction', @@ -269,7 +275,7 @@ export const refreshDatasetAction = createAsyncThunk( workbenchState.chartConfig?.settings, arg?.pageInfo, true, - workbenchState.backendChart?.config?.aggregation, + workbenchState.aggregation, ); const requestParams = builder .addExtraSorters(arg?.sorter ? [arg?.sorter as any] : []) @@ -457,9 +463,7 @@ const workbenchSlice = createSlice({ } as ChartDataView; }, updateChartAggregation: (state, action: PayloadAction<boolean>) => { - if (state.backendChart) { - state.backendChart.config.aggregation = action.payload; - } + state.aggregation = action.payload; }, resetWorkbenchState: (state, action) => { return initState; @@ -508,6 +512,7 @@ const workbenchSlice = createSlice({ ...payload, config: backendChartConfig, }; + state.aggregation = backendChartConfig.aggregation; const currentChart = ChartManager.instance().getById( backendChartConfig?.chartGraphId, ); From 79cfca1598993f634b17c223e317a810eb7f4a69 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Thu, 30 Dec 2021 20:11:28 +0800 Subject: [PATCH 312/348] chore: add copyright to variable pages --- .../pages/VariablePage/DefaultValue.tsx | 18 ++++++++++++++++++ .../SubjectForm/RowPermissionTable.tsx | 18 ++++++++++++++++++ .../pages/VariablePage/SubjectForm/index.tsx | 18 ++++++++++++++++++ .../pages/VariablePage/VariableForm.tsx | 18 ++++++++++++++++++ .../MainPage/pages/VariablePage/constants.ts | 18 ++++++++++++++++++ .../MainPage/pages/VariablePage/index.tsx | 18 ++++++++++++++++++ .../pages/VariablePage/slice/index.tsx | 18 ++++++++++++++++++ .../pages/VariablePage/slice/selectors.ts | 18 ++++++++++++++++++ .../pages/VariablePage/slice/thunks.ts | 18 ++++++++++++++++++ .../MainPage/pages/VariablePage/slice/types.ts | 18 ++++++++++++++++++ .../pages/MainPage/pages/VariablePage/types.ts | 18 ++++++++++++++++++ frontend/src/locales/en/translation.json | 2 +- 12 files changed, 199 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/DefaultValue.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/DefaultValue.tsx index 53e286430..2f30e54a0 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/DefaultValue.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/DefaultValue.tsx @@ -1,3 +1,21 @@ +/** + * 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 { CheckOutlined } from '@ant-design/icons'; import { Button, DatePicker, Input, InputNumber, Space, Tag } from 'antd'; import moment from 'moment'; diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/RowPermissionTable.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/RowPermissionTable.tsx index b08b9260e..d123c8e9c 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/RowPermissionTable.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/RowPermissionTable.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Checkbox, Table, TableColumnProps } from 'antd'; import { LoadingMask } from 'app/components'; import produce from 'immer'; diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx index cc09e9cc8..40071b776 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Modal, ModalProps, Tabs } from 'antd'; import moment from 'moment'; import { Key, memo, useCallback, useEffect, useState } from 'react'; diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx index f865ae193..0c4e7e830 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx @@ -1,3 +1,21 @@ +/** + * 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 { Checkbox, Form, FormInstance, Input, Radio } from 'antd'; import { ModalForm, ModalFormProps } from 'app/components'; import debounce from 'debounce-promise'; diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/constants.ts b/frontend/src/app/pages/MainPage/pages/VariablePage/constants.ts index c7b308fd8..f1ef1071d 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/constants.ts +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/constants.ts @@ -1,3 +1,21 @@ +/** + * 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. + */ + export enum VariableTypes { Query = 'QUERY', Permission = 'PERMISSION', diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/index.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/index.tsx index b1249a475..17ba0f806 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { DeleteOutlined, EditOutlined, diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/slice/index.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/slice/index.tsx index 45f3662a2..26ece2fde 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/slice/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/slice/index.tsx @@ -1,3 +1,21 @@ +/** + * 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 { createSlice } from '@reduxjs/toolkit'; import { useInjectReducer } from 'utils/@reduxjs/injectReducer'; import { diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/slice/selectors.ts b/frontend/src/app/pages/MainPage/pages/VariablePage/slice/selectors.ts index d9295fd79..ad87d3a2a 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/slice/selectors.ts +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/slice/selectors.ts @@ -1,3 +1,21 @@ +/** + * 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 { createSelector } from '@reduxjs/toolkit'; import { RootState } from 'types'; import { initialState } from '.'; diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/slice/thunks.ts b/frontend/src/app/pages/MainPage/pages/VariablePage/slice/thunks.ts index b9ea2f7fd..aa5c2567a 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/slice/thunks.ts +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/slice/thunks.ts @@ -1,3 +1,21 @@ +/** + * 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 { createAsyncThunk } from '@reduxjs/toolkit'; import { request } from 'utils/request'; import { errorHandle } from 'utils/utils'; diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/slice/types.ts b/frontend/src/app/pages/MainPage/pages/VariablePage/slice/types.ts index d73ba0410..fdd76cb91 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/slice/types.ts +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/slice/types.ts @@ -1,3 +1,21 @@ +/** + * 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 { SubjectTypes } from '../../PermissionPage/constants'; import { VariableTypes, VariableValueTypes } from '../constants'; diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/types.ts b/frontend/src/app/pages/MainPage/pages/VariablePage/types.ts index bac759928..5ba6cca65 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/types.ts +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/types.ts @@ -1,3 +1,21 @@ +/** + * 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 { Variable } from './slice/types'; export interface VariableFormModel diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 585f83dd5..d945a74be 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -162,7 +162,7 @@ }, "subNavs": { "variables": { - "title": "Public variable Settings" + "title": "Public variables" }, "orgSettings": { "title": "Organization Settings" From f29a675b2dda4522378f036bc46f8eccb2249a30 Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Fri, 31 Dec 2021 00:29:18 +0800 Subject: [PATCH 313/348] chore: variable page i18n support --- .../pages/VariablePage/DefaultValue.tsx | 8 ++- .../SubjectForm/RowPermissionTable.tsx | 11 ++-- .../pages/VariablePage/SubjectForm/index.tsx | 8 ++- .../pages/VariablePage/VariableForm.tsx | 56 +++++++++-------- .../MainPage/pages/VariablePage/constants.ts | 12 ---- .../MainPage/pages/VariablePage/index.tsx | 59 +++++++++--------- frontend/src/locales/en/translation.json | 60 +++++++++++++------ frontend/src/locales/zh/translation.json | 39 +++++++++++- 8 files changed, 160 insertions(+), 93 deletions(-) diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/DefaultValue.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/DefaultValue.tsx index 2f30e54a0..58ed14c29 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/DefaultValue.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/DefaultValue.tsx @@ -18,6 +18,7 @@ import { CheckOutlined } from '@ant-design/icons'; import { Button, DatePicker, Input, InputNumber, Space, Tag } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import moment from 'moment'; import { memo, useCallback, useEffect, useState } from 'react'; import styled from 'styled-components/macro'; @@ -35,6 +36,7 @@ interface DefaultValueProps { export const DefaultValue = memo( ({ type, expression, disabled, value = [], onChange }: DefaultValueProps) => { const [inputValue, setInputValue] = useState<any>(void 0); + const t = useI18NPrefix('variable'); useEffect(() => { setInputValue(void 0); @@ -103,7 +105,7 @@ export const DefaultValue = memo( case VariableValueTypes.Number: conditionalInputComponent = ( <InputNumber - placeholder="输入默认值后回车添加" + placeholder={t('enterToAdd')} value={inputValue} className="input" disabled={!!disabled} @@ -127,7 +129,7 @@ export const DefaultValue = memo( default: conditionalInputComponent = ( <Input - placeholder="输入默认值后回车添加" + placeholder={t('enterToAdd')} value={inputValue} className="input" disabled={!!disabled} @@ -142,7 +144,7 @@ export const DefaultValue = memo( <Wrapper direction="vertical" size={0}> {expression || type === VariableValueTypes.Expression ? ( <Input.TextArea - placeholder="请输入表达式" + placeholder={t('enterExpression')} autoSize={{ minRows: 4, maxRows: 8 }} value={value ? value[0] : void 0} disabled={!!disabled} diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/RowPermissionTable.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/RowPermissionTable.tsx index d123c8e9c..db24667eb 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/RowPermissionTable.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/RowPermissionTable.tsx @@ -18,6 +18,7 @@ import { Checkbox, Table, TableColumnProps } from 'antd'; import { LoadingMask } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import produce from 'immer'; import { Key, memo, useCallback, useMemo } from 'react'; import styled from 'styled-components/macro'; @@ -51,6 +52,8 @@ export const RowPermissionTable = memo( onSelectedRowKeyChange, onRowPermissionSubjectChange, }: SubjectFormProps) => { + const t = useI18NPrefix('variable'); + const checkUseDefaultValue = useCallback( id => e => { onRowPermissionSubjectChange( @@ -77,9 +80,9 @@ export const RowPermissionTable = memo( const columns: TableColumnProps<RowPermissionSubject>[] = useMemo( () => [ - { dataIndex: 'name', title: '名称' }, + { dataIndex: 'name', title: t('name') }, { - title: '使用变量默认值', + title: t('useDefaultValue'), width: SPACE_TIMES(32), render: (_, record) => { return ( @@ -92,7 +95,7 @@ export const RowPermissionTable = memo( }, }, { - title: '值', + title: t('value'), width: SPACE_TIMES(72), render: (_, record) => editingVariable && ( @@ -108,7 +111,7 @@ export const RowPermissionTable = memo( ), }, ], - [selectedRowKeys, editingVariable, checkUseDefaultValue, valueChange], + [selectedRowKeys, editingVariable, checkUseDefaultValue, valueChange, t], ); const rowClassName = useCallback( diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx index 40071b776..d79a8f07d 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/SubjectForm/index.tsx @@ -17,6 +17,7 @@ */ import { Modal, ModalProps, Tabs } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import moment from 'moment'; import { Key, memo, useCallback, useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; @@ -66,6 +67,7 @@ export const SubjectForm = memo( const members = useSelector(selectMembers); const roleListLoading = useSelector(selectRoleListLoading); const memberListLoading = useSelector(selectMemberListLoading); + const t = useI18NPrefix('variable'); useEffect(() => { if (editingVariable && rowPermissions && roles) { @@ -185,12 +187,12 @@ export const SubjectForm = memo( scope === VariableScopes.Public ? ( <> <StyledTabs defaultActiveKey={tab} onChange={setTab}> - <Tabs.TabPane key="role" tab="关联角色" /> - <Tabs.TabPane key="member" tab="关联成员" /> + <Tabs.TabPane key="role" tab={t('relatedRole')} /> + <Tabs.TabPane key="member" tab={t('relatedMember')} /> </StyledTabs> </> ) : ( - '关联角色' + t('relatedRole') ) } onOk={save} diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx index 0c4e7e830..d98bfe15b 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx @@ -18,6 +18,7 @@ import { Checkbox, Form, FormInstance, Input, Radio } from 'antd'; import { ModalForm, ModalFormProps } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import debounce from 'debounce-promise'; import { DEFAULT_DEBOUNCE_WAIT } from 'globalConstants'; import moment from 'moment'; @@ -26,13 +27,7 @@ import { SPACE_XS } from 'styles/StyleConstants'; import { request } from 'utils/request'; import { errorHandle } from 'utils/utils'; import { VariableHierarchy } from '../ViewPage/slice/types'; -import { - VariableScopes, - VariableTypes, - VariableValueTypes, - VARIABLE_TYPE_LABEL, - VARIABLE_VALUE_TYPE_LABEL, -} from './constants'; +import { VariableScopes, VariableTypes, VariableValueTypes } from './constants'; import { DefaultValue } from './DefaultValue'; import { Variable } from './slice/types'; import { VariableFormModel } from './types'; @@ -65,6 +60,8 @@ export const VariableForm = memo( ); const [expression, setExpression] = useState(false); const formRef = useRef<FormInstance<VariableFormModel>>(); + const t = useI18NPrefix('variable'); + const tg = useI18NPrefix('global'); useEffect(() => { if (visible && editingVariable) { @@ -123,7 +120,7 @@ export const VariableForm = memo( return Promise.resolve(); } if (variables?.find(({ name }) => name === value)) { - return Promise.reject(new Error('名称重复')); + return Promise.reject(new Error(t('duplicateName'))); } else { return Promise.resolve(); } @@ -141,7 +138,7 @@ export const VariableForm = memo( err => Promise.reject(new Error(err.response.data.message)), ); }, DEFAULT_DEBOUNCE_WAIT), - [scope, editingVariable?.name, variables, orgId], + [scope, editingVariable?.name, variables, orgId, t], ); return ( @@ -150,7 +147,7 @@ export const VariableForm = memo( visible={visible} formProps={{ labelAlign: 'left', - labelCol: { offset: 1, span: 5 }, + labelCol: { offset: 1, span: 6 }, wrapperCol: { span: 16 }, className: '', }} @@ -160,10 +157,13 @@ export const VariableForm = memo( > <Form.Item name="name" - label="名称" + label={t('name')} validateFirst rules={[ - { required: true, message: '名称不能为空' }, + { + required: true, + message: `${t('name')}${tg('validation.required')}`, + }, { validator: nameValidator, }, @@ -171,39 +171,47 @@ export const VariableForm = memo( > <Input /> </Form.Item> - <Form.Item name="label" label="标题"> + <Form.Item name="label" label={t('label')}> <Input /> </Form.Item> - <Form.Item name="type" label="类型" initialValue={type}> + <Form.Item name="type" label={t('type')} initialValue={type}> <Radio.Group onChange={typeChange}> {Object.values(VariableTypes).map(value => ( <Radio.Button key={value} value={value}> - {VARIABLE_TYPE_LABEL[value]} + {t(`variableType.${value.toLowerCase()}`)} </Radio.Button> ))} </Radio.Group> </Form.Item> - <Form.Item name="valueType" label="值类型" initialValue={valueType}> + <Form.Item + name="valueType" + label={t('valueType')} + initialValue={valueType} + > <Radio.Group onChange={valueTypeChange}> {Object.values(VariableValueTypes).map(value => ( <Radio.Button key={value} value={value}> - {VARIABLE_VALUE_TYPE_LABEL[value]} + {t(`variableValueType.${value.toLowerCase()}`)} </Radio.Button> ))} </Radio.Group> </Form.Item> {scope === VariableScopes.Public && type === VariableTypes.Permission && ( - <Form.Item name="permission" label="编辑权限" initialValue={0}> + <Form.Item + name="permission" + label={t('permission.label')} + initialValue={0} + > <Radio.Group> - <Radio.Button value={0}>不可见</Radio.Button> - <Radio.Button value={1}>只读</Radio.Button> - <Radio.Button value={2}>可编辑</Radio.Button> + <Radio.Button value={0}>{t('permission.hidden')}</Radio.Button> + <Radio.Button value={1}>{t('permission.readonly')}</Radio.Button> + <Radio.Button value={2}>{t('permission.editable')}</Radio.Button> </Radio.Group> </Form.Item> )} <Form.Item name="defaultValue" - label="默认值" + label={t('defaultValue')} css={` margin-bottom: ${SPACE_XS}; `} @@ -218,9 +226,7 @@ export const VariableForm = memo( valuePropName="checked" initialValue={expression} > - <Checkbox onChange={expressionChange}> - 使用表达式作为默认值 - </Checkbox> + <Checkbox onChange={expressionChange}>{t('expression')}</Checkbox> </Form.Item> )} </ModalForm> diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/constants.ts b/frontend/src/app/pages/MainPage/pages/VariablePage/constants.ts index f1ef1071d..6c6e1540e 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/constants.ts +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/constants.ts @@ -32,16 +32,4 @@ export enum VariableValueTypes { Expression = 'FRAGMENT', } -export const VARIABLE_TYPE_LABEL = { - [VariableTypes.Query]: '查询变量', - [VariableTypes.Permission]: '权限变量', -}; - -export const VARIABLE_VALUE_TYPE_LABEL = { - [VariableValueTypes.String]: '字符', - [VariableValueTypes.Number]: '数值', - [VariableValueTypes.Date]: '日期', - [VariableValueTypes.Expression]: '表达式', -}; - export const DEFAULT_VALUE_DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss'; diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/index.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/index.tsx index 17ba0f806..2563a378c 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/index.tsx @@ -33,6 +33,7 @@ import { Tag, Tooltip, } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { CommonFormTypes } from 'globalConstants'; import { Moment } from 'moment'; import { Key, useCallback, useEffect, useMemo, useState } from 'react'; @@ -58,8 +59,6 @@ import { VariableScopes, VariableTypes, VariableValueTypes, - VARIABLE_TYPE_LABEL, - VARIABLE_VALUE_TYPE_LABEL, } from './constants'; import { useVariableSlice } from './slice'; import { @@ -106,6 +105,8 @@ export function VariablePage() { const saveLoading = useSelector(selectSaveVariableLoading); const deleteVariablesLoading = useSelector(selectDeleteVariablesLoading); const orgId = useSelector(selectOrgId); + const t = useI18NPrefix('variable'); + const tg = useI18NPrefix('global'); useEffect(() => { dispatch(getVariables(orgId)); @@ -172,12 +173,12 @@ export function VariablePage() { deleteVariable({ ids: [id], resolve: () => { - message.success('删除成功'); + message.success(tg('operation.deleteSuccess')); }, }), ); }, - [dispatch], + [dispatch, tg], ); const delSelectedVariables = useCallback(() => { @@ -185,12 +186,12 @@ export function VariablePage() { deleteVariable({ ids: selectedRowKeys as string[], resolve: () => { - message.success('删除成功'); + message.success(tg('operation.deleteSuccess')); setSelectedRowKeys([]); }, }), ); - }, [dispatch, selectedRowKeys]); + }, [dispatch, selectedRowKeys, tg]); const save = useCallback( (values: VariableFormModel) => { @@ -225,13 +226,13 @@ export function VariablePage() { variable: { ...editingVariable!, ...values, defaultValue }, resolve: () => { hideForm(); - message.success('修改成功'); + message.success(tg('operation.updateSuccess')); }, }), ); } }, - [dispatch, formType, orgId, editingVariable, hideForm], + [dispatch, formType, orgId, editingVariable, hideForm, tg], ); const saveRelations = useCallback( @@ -273,7 +274,7 @@ export function VariablePage() { relToDelete: deleted.map(({ id }) => id), }, }); - message.success('修改成功'); + message.success(tg('operation.updateSuccess')); setSubjectFormVisible(false); } catch (error) { errorHandle(error); @@ -286,37 +287,38 @@ export function VariablePage() { } } }, - [rowPermissions, editingVariable], + [rowPermissions, editingVariable, tg], ); const columns: TableColumnProps<VariableViewModel>[] = useMemo( () => [ - { dataIndex: 'name', title: '名称' }, - { dataIndex: 'label', title: '标签' }, + { dataIndex: 'name', title: t('name') }, + { dataIndex: 'label', title: t('label') }, { dataIndex: 'type', - title: '类型', + title: t('type'), render: (_, record) => ( <Tag color={record.type === VariableTypes.Permission ? WARNING : INFO} > - {VARIABLE_TYPE_LABEL[record.type]} + {t(`variableType.${record.type.toLowerCase()}`)} </Tag> ), }, { dataIndex: 'valueType', - title: '值类型', - render: (_, record) => VARIABLE_VALUE_TYPE_LABEL[record.valueType], + title: t('valueType'), + render: (_, record) => + t(`variableValueType.${record.valueType.toLowerCase()}`), }, { - title: '操作', + title: tg('title.action'), align: 'center', width: 140, render: (_, record) => ( <Actions> {record.type === VariableTypes.Permission && ( - <Tooltip title="关联角色或用户"> + <Tooltip title={t('related')}> <Button type="link" icon={<TeamOutlined />} @@ -324,15 +326,18 @@ export function VariablePage() { /> </Tooltip> )} - <Tooltip title="编辑"> + <Tooltip title={tg('button.edit')}> <Button type="link" icon={<EditOutlined />} onClick={showEditForm(record.id)} /> </Tooltip> - <Tooltip title="删除"> - <Popconfirm title="确认删除?" onConfirm={del(record.id)}> + <Tooltip title={tg('button.delete')}> + <Popconfirm + title={tg('operation.deleteConfirm')} + onConfirm={del(record.id)} + > <Button type="link" icon={<DeleteOutlined />} /> </Popconfirm> </Tooltip> @@ -340,7 +345,7 @@ export function VariablePage() { ), }, ], - [del, showEditForm, showSubjectForm], + [del, showEditForm, showSubjectForm, t, tg], ); const pagination = useMemo( @@ -352,18 +357,18 @@ export function VariablePage() { <Wrapper> <Card> <TableHeader> - <h3>公共变量列表</h3> + <h3>{t('title')}</h3> <Toolbar> {selectedRowKeys.length > 0 && ( <Popconfirm - title="确认删除全部?" + title={t('deleteAllConfirm')} onConfirm={delSelectedVariables} > <Button icon={<DeleteOutlined />} loading={deleteVariablesLoading} > - 批量删除 + {t('deleteAll')} </Button> </Popconfirm> )} @@ -372,7 +377,7 @@ export function VariablePage() { type="primary" onClick={showAddForm} > - 新建 + {tg('button.create')} </Button> </Toolbar> </TableHeader> @@ -390,7 +395,7 @@ export function VariablePage() { orgId={orgId} editingVariable={editingVariable} visible={formVisible} - title="公共变量" + title={t('public')} type={formType} confirmLoading={saveLoading} onSave={save} diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index d945a74be..59bf16f6b 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -5,6 +5,7 @@ "action": "Action" }, "button": { + "create": "Create", "save": "Save", "edit": "Edit", "archive": "Archive", @@ -1052,23 +1053,46 @@ "Disable": "Disable" }, "privilegeLabel": { - "viz": [ - "View", - "Download", - "Share", - "Manage" - ], - "view": [ - "Access", - "Manage" - ], - "source": [ - "Access", - "Manage" - ], - "schedule": [ - "Manage" - ] + "viz": ["View", "Download", "Share", "Manage"], + "view": ["Access", "Manage"], + "source": ["Access", "Manage"], + "schedule": ["Manage"] + } + }, + "variable": { + "title": "Public variables", + "public": "Public variables", + "name": "Name", + "label": "Label", + "type": "Type", + "valueType": "Value type", + "permission": { + "label": "Permission", + "hidden": "Hidden", + "readonly": "Readonly", + "editable": "Editable" + }, + "defaultValue": "Default value", + "expression": "Use expression default value", + "duplicateName": "Duplicate Name", + "related": "Related roles & members", + "deleteAllConfirm": "Delete confirm", + "deleteAll": "Delete all", + "enterToAdd": "Enter to add", + "enterExpression": "Enter expression", + "relatedRole": "Related roles", + "relatedMember": "Related members", + "useDefaultValue": "Use variable default value", + "value": "Value", + "variableType": { + "query": "Query", + "permission": "Permission" + }, + "variableValueType": { + "string": "String", + "numeric": "Number", + "date": "Date", + "fragment": "Expression" } }, "share": { @@ -1093,4 +1117,4 @@ "searchValue": "Search keywords" } } -} \ No newline at end of file +} diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 48fe0936b..0e78316e5 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -5,6 +5,7 @@ "action": "操作" }, "button": { + "create": "新建", "save": "保存", "edit": "编辑", "archive": "移至回收站", @@ -1071,6 +1072,42 @@ } } }, + "variable": { + "title": "公共变量列表", + "public": "公共变量", + "name": "名称", + "label": "标签", + "type": "类型", + "valueType": "值类型", + "permission": { + "label": "编辑权限", + "hidden": "不可见", + "readonly": "只读", + "editable": "可编辑" + }, + "defaultValue": "默认值", + "expression": "使用表达式作为默认值", + "duplicateName": "名称重复", + "related": "关联角色或成员", + "deleteAllConfirm": "确认删除全部?", + "deleteAll": "批量删除", + "enterToAdd": "输入默认值后回车添加", + "enterExpression": "请输入表达式", + "relatedRole": "关联角色", + "relatedMember": "关联成员", + "useDefaultValue": "使用变量默认值", + "value": "值", + "variableType": { + "query": "查询变量", + "permission": "权限变量" + }, + "variableValueType": { + "string": "字符", + "numeric": "数值", + "date": "日期", + "fragment": "表达式" + } + }, "share": { "common": { "confirm": "请确认", @@ -1093,4 +1130,4 @@ "searchValue": "搜索名称关键字" } } -} \ No newline at end of file +} From 9755c206d1ec60224cbf0f482c9009766e26be7e Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Fri, 31 Dec 2021 09:05:00 +0800 Subject: [PATCH 314/348] chore: viz pages i18n support --- .../app/components/VizHeader/VizHeader.tsx | 2 +- .../DashBoardPage/components/TitleHeader.tsx | 2 +- .../VizPage/ChartPreview/ChartPreview.tsx | 10 ++-- .../MainPage/pages/VizPage/Main/index.tsx | 4 +- .../pages/MainPage/pages/VizPage/SaveForm.tsx | 35 +++++++------- .../VizPage/Sidebar/Folders/FolderTree.tsx | 3 +- .../pages/MainPage/pages/VizPage/index.tsx | 4 +- .../StoryBoardPage/components/StoryHeader.tsx | 2 +- frontend/src/locales/en/translation.json | 48 ++++++++++++++----- frontend/src/locales/zh/translation.json | 28 +++++++++-- 10 files changed, 95 insertions(+), 43 deletions(-) diff --git a/frontend/src/app/components/VizHeader/VizHeader.tsx b/frontend/src/app/components/VizHeader/VizHeader.tsx index 01342eb4a..aa84fcfcd 100644 --- a/frontend/src/app/components/VizHeader/VizHeader.tsx +++ b/frontend/src/app/components/VizHeader/VizHeader.tsx @@ -119,7 +119,7 @@ const VizHeader: FC<{ loading={publishLoading} onClick={onPublish} > - {status === 1 ? t('publish') : t('cancelPublish')} + {status === 1 ? t('publish') : t('unpublish')} </Button> )} {allowManage && !isArchived && onGotoEdit && ( diff --git a/frontend/src/app/pages/DashBoardPage/components/TitleHeader.tsx b/frontend/src/app/pages/DashBoardPage/components/TitleHeader.tsx index 1e1e6a326..3f9e73972 100644 --- a/frontend/src/app/pages/DashBoardPage/components/TitleHeader.tsx +++ b/frontend/src/app/pages/DashBoardPage/components/TitleHeader.tsx @@ -142,7 +142,7 @@ const TitleHeader: FC<TitleHeaderProps> = memo( loading={publishLoading} onClick={onPublish} > - {status === 1 ? t('publish') : t('cancelPublish')} + {status === 1 ? t('publish') : t('unpublish')} </Button> )} {allowManage && !isArchived && renderMode === 'read' && ( diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreview.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreview.tsx index e523ec7bf..c3bc22451 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreview.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/ChartPreview/ChartPreview.tsx @@ -20,6 +20,7 @@ import { message } from 'antd'; import ChartEditor from 'app/components/ChartEditor'; import { VizHeader } from 'app/components/VizHeader'; import { useCacheWidthHeight } from 'app/hooks/useCacheWidthHeight'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import Chart from 'app/pages/ChartWorkbenchPage/models/Chart'; import { ChartDataRequestBuilder } from 'app/pages/ChartWorkbenchPage/models/ChartHttpRequest'; import ChartManager from 'app/pages/ChartWorkbenchPage/models/ChartManager'; @@ -69,6 +70,7 @@ const ChartPreviewBoard: FC<{ const [chartPreview, setChartPreview] = useState<ChartPreview>(); const [chart, setChart] = useState<Chart>(); const [editChartVisible, setEditChartVisible] = useState<boolean>(false); + const t = useI18NPrefix('viz.main'); useEffect(() => { const filterSearchParams = filterSearchUrl @@ -214,15 +216,15 @@ const ChartPreviewBoard: FC<{ publish: chartPreview.backendChart.status === 1 ? true : false, resolve: () => { message.success( - `${ - chartPreview.backendChart?.status === 2 ? '取消' : '' - }发布成功`, + chartPreview.backendChart?.status === 2 + ? t('unpublishSuccess') + : t('publishSuccess'), ); }, }), ); } - }, [dispatch, chartPreview?.backendChart]); + }, [dispatch, chartPreview?.backendChart, t]); return ( <StyledChartPreviewBoard> diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/Main/index.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/Main/index.tsx index 4d599bddb..feab2ad31 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/Main/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/Main/index.tsx @@ -6,6 +6,7 @@ import { useCallback, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory, useLocation, useRouteMatch } from 'react-router-dom'; import styled from 'styled-components/macro'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { STICKY_LEVEL } from 'styles/StyleConstants'; import { useVizSlice } from '../slice'; import { @@ -39,6 +40,7 @@ export function Main() { const selectedTab = useSelector(selectSelectedTab); const orgId = useSelector(selectOrgId); const playingStoryId = useSelector(selectPlayingStoryId); + const t = useI18NPrefix('viz.main'); useEffect(() => { if (vizId) { @@ -173,7 +175,7 @@ export function Main() { selectedId={selectedTab?.id} /> ))} - {!tabs.length && <EmptyFiller title="请在左侧列表选择可视化" />} + {!tabs.length && <EmptyFiller title={t('empty')} />} {playingStoryId && <StoryPlayer storyId={playingStoryId} />} </Wrapper> diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx index 4263e92a0..872d47324 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/SaveForm.tsx @@ -1,5 +1,6 @@ import { Form, FormInstance, Input, Radio, TreeSelect } from 'antd'; import { ModalForm, ModalFormProps } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { BoardTypeMap } from 'app/pages/DashBoardPage/pages/Board/slice/types'; import debounce from 'debounce-promise'; import { CommonFormTypes, DEFAULT_DEBOUNCE_WAIT } from 'globalConstants'; @@ -21,13 +22,6 @@ import { selectSaveStoryboardLoading, } from './slice/selectors'; -const VIZ_TYPE_TITLES = { - DATACHART: '数据图表', - DASHBOARD: '仪表板', - FOLDER: '目录', - STORYBOARD: '故事板', -}; - type SaveFormProps = Omit<ModalFormProps, 'type' | 'visible' | 'onSave'>; export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { @@ -47,6 +41,8 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { const isOwner = useSelector(selectIsOrgOwner); const permissionMap = useSelector(selectPermissionMap); const formRef = useRef<FormInstance>(); + const t = useI18NPrefix('viz.saveForm'); + const tg = useI18NPrefix('global'); const getDisabled = useCallback( (_, path: string[]) => @@ -85,7 +81,7 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { <ModalForm formProps={formProps} {...modalProps} - title={VIZ_TYPE_TITLES[vizType]} + title={t(`vizType.${vizType.toLowerCase()}`)} type={type} visible={visible} confirmLoading={saveFolderLoading || saveStoryboardLoading} @@ -99,9 +95,12 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { </IdField> <Form.Item name="name" - label="名称" + label={t('name')} rules={[ - { required: true, message: '名称不能为空' }, + { + required: true, + message: `${t('name')}${tg('validation.required')}`, + }, { validator: debounce((_, value) => { if (!value || initialValues?.name === value) { @@ -128,22 +127,26 @@ export function SaveForm({ formProps, ...modalProps }: SaveFormProps) { <Input /> </Form.Item> {vizType === 'DATACHART' && ( - <Form.Item name="description" label="描述"> + <Form.Item name="description" label={t('description')}> <Input.TextArea /> </Form.Item> )} {vizType === 'DASHBOARD' && type === CommonFormTypes.Add && ( - <Form.Item name="boardType" label="布局类型"> + <Form.Item name="boardType" label={t('boardType.label')}> <Radio.Group> - <Radio.Button value={BoardTypeMap.auto}>自动</Radio.Button> - <Radio.Button value={BoardTypeMap.free}>自由</Radio.Button> + <Radio.Button value={BoardTypeMap.auto}> + {t('boardType.auto')} + </Radio.Button> + <Radio.Button value={BoardTypeMap.free}> + {t('boardType.free')} + </Radio.Button> </Radio.Group> </Form.Item> )} {vizType !== 'STORYBOARD' && ( - <Form.Item name="parentId" label="所属目录"> + <Form.Item name="parentId" label={t('parent')}> <TreeSelect - placeholder="根目录" + placeholder={t('root')} treeData={treeData} allowClear onChange={() => { diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/FolderTree.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/FolderTree.tsx index c1d905808..b92112812 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/FolderTree.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/Sidebar/Folders/FolderTree.tsx @@ -40,7 +40,6 @@ export function FolderTree({ const loading = useSelector(selectVizListLoading); const vizsData = useSelector(selectVizs); const { showSaveForm } = useContext(SaveFormContext); - const t = useI18NPrefix(i18nPrefix); const tg = useI18NPrefix('global'); useEffect(() => { @@ -185,7 +184,7 @@ export function FolderTree({ </TreeTitle> ); }, - [moreMenuClick, archiveViz, t, tg], + [moreMenuClick, archiveViz, tg], ); const onDrop = info => { diff --git a/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx b/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx index 423e1ca32..79c4f798d 100644 --- a/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VizPage/index.tsx @@ -1,4 +1,5 @@ import { Split } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { useSplitSizes } from 'app/hooks/useSplitSizes'; import { useBoardSlice } from 'app/pages/DashBoardPage/pages/Board/slice'; import { useEditBoardSlice } from 'app/pages/DashBoardPage/pages/BoardEditor/slice'; @@ -24,6 +25,7 @@ export function VizPage() { limitedSide: 0, range: [256, 768], }); + const tg = useI18NPrefix('global'); const siderDragEnd = useCallback( sizes => { @@ -52,7 +54,7 @@ export function VizPage() { labelCol: { offset: 1, span: 6 }, wrapperCol: { span: 15 }, }} - okText="保存" + okText={tg('button.save')} /> </Container> </SaveFormContext.Provider> diff --git a/frontend/src/app/pages/StoryBoardPage/components/StoryHeader.tsx b/frontend/src/app/pages/StoryBoardPage/components/StoryHeader.tsx index 44c55fde8..1f0791356 100644 --- a/frontend/src/app/pages/StoryBoardPage/components/StoryHeader.tsx +++ b/frontend/src/app/pages/StoryBoardPage/components/StoryHeader.tsx @@ -107,7 +107,7 @@ export const StoryHeader: FC<StoryHeaderProps> = memo( loading={publishLoading} onClick={onPublish} > - {status === 1 ? t('publish') : t('cancelPublish')} + {status === 1 ? t('publish') : t('unpublish')} </Button> )} {allowManage && !isArchived && ( diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 59bf16f6b..b5c9f1b35 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -421,20 +421,20 @@ } }, "workbench": { - "goBack": "返回管理页面", + "goBack": "Go back", "header": { "goBack": "Back", "run": "Run", "save": "Save", - "saveToDashboard": "保存到仪表盘", - "login": "登陆", - "aggregationSwitch": "聚合开关", - "aggregationSwitchTip": "开启/关闭聚合会清空全部图表配置,确认开启/关闭?", - "open": "开启", - "close": "关闭", + "saveToDashboard": "Save to dashboard", + "login": "Login", + "aggregationSwitch": "Aggregation", + "aggregationSwitchTip": "Switching aggregation will clear all configurations. Are you sure to turn it on / off?", + "open": "Open", + "close": "Close", "lang": { - "zh": "中文", - "en": "英文" + "zh": "zh", + "en": "en" }, "format": { "local": "local", @@ -629,8 +629,8 @@ "borderStyle": "Border Style" }, "paging": { - "title": "常规", - "pageSize": "总行数" + "title": "Common", + "pageSize": "Limit" } }, "present": { @@ -659,7 +659,7 @@ "edit": "Edit", "run": "Run", "publish": "Publish", - "cancelPublish": "Cancel Publish", + "unpublish": "Unpublish", "published": "Published", "unpublished": "Unpublished", "archived": "Archived", @@ -668,7 +668,7 @@ "link": "Link", "password": "Password", "expireDate": "Expire Date", - "enablePassword": "Enable Password", + "enablePassword": "Password", "generateLink": "Generate Link", "shareLink": "Share Link", "downloadData": "Download Data" @@ -865,6 +865,28 @@ "week": "Week", "date": "Date", "dateTime": "Date Time" + }, + "saveForm": { + "name": "Name", + "description": "Description", + "boardType": { + "label": "Board type", + "auto": "Auto", + "free": "Free" + }, + "parent": "Parent", + "root": "Root", + "vizType": { + "datachart": "Datachart", + "dashboard": "Dashboard", + "folder": "Folder", + "storyboard": "Storyboard" + } + }, + "main": { + "publishSuccess": "Publish success", + "unpublishSuccess": "Unpublish success", + "empty": "Select vizs in the sidebar" } }, "view": { diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 0e78316e5..41f72d273 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -428,8 +428,8 @@ "save": "保存", "saveToDashboard": "保存到仪表盘", "login": "登陆", - "aggregationSwitch": "聚合开关", - "aggregationSwitchTip": "开启/关闭聚合会清空全部图表配置,确认开启/关闭?", + "aggregationSwitch": "数据聚合", + "aggregationSwitchTip": "切换数据聚合会清空所有配置,确认开启/关闭?", "open": "开启", "close": "关闭", "lang": { @@ -659,7 +659,7 @@ "edit": "编辑", "run": "运行", "publish": "发布", - "cancelPublish": "取消发布", + "unpublish": "取消发布", "published": "已发布", "unpublished": "未发布", "archived": "已归档", @@ -865,6 +865,28 @@ "week": "周", "date": "日期", "dateTime": "日期时间" + }, + "saveForm": { + "name": "名称", + "description": "描述", + "boardType": { + "label": "布局类型", + "auto": "自动", + "free": "自由" + }, + "parent": "所属目录", + "root": "根目录", + "vizType": { + "datachart": "数据图表", + "dashboard": "仪表板", + "folder": "目录", + "storyboard": "故事板" + } + }, + "main": { + "publishSuccess": "发布成功", + "unpublishSuccess": "取消发布成功", + "empty": "请在左侧列表选择可视化" } }, "view": { From fc55586ff61bee66653a4ad281558a1abd9b363d Mon Sep 17 00:00:00 2001 From: scottsut <scottsut@163.com> Date: Fri, 31 Dec 2021 23:51:32 +0800 Subject: [PATCH 315/348] chore: other pages i18n support --- frontend/src/app/pages/ActivePage/index.tsx | 5 ++- .../src/app/pages/AuthorizationPage/index.tsx | 6 +++- .../pages/ConfirmInvitePage/index.tsx | 9 +++-- .../pages/OrgSettingPage/DeleteConfirm.tsx | 13 ++++--- .../MainPage/pages/OrgSettingPage/index.tsx | 34 +++++++++++-------- frontend/src/app/pages/NotFoundPage/index.tsx | 8 +++-- frontend/src/locales/en/translation.json | 25 ++++++++++++++ frontend/src/locales/zh/translation.json | 25 ++++++++++++++ 8 files changed, 97 insertions(+), 28 deletions(-) diff --git a/frontend/src/app/pages/ActivePage/index.tsx b/frontend/src/app/pages/ActivePage/index.tsx index 951d204ab..4e38411cc 100644 --- a/frontend/src/app/pages/ActivePage/index.tsx +++ b/frontend/src/app/pages/ActivePage/index.tsx @@ -1,4 +1,5 @@ import { EmptyFiller } from 'app/components/EmptyFiller'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { getUserInfoByToken } from 'app/slice/thunks'; import { useCallback, useEffect } from 'react'; import { useDispatch } from 'react-redux'; @@ -9,6 +10,8 @@ import { activeAccount } from './service'; export const ActivePage = () => { const history = useHistory(); const dispatch = useDispatch(); + const t = useI18NPrefix('active'); + const onActiveUser = useCallback( token => { activeAccount(token).then(loginToken => { @@ -37,7 +40,7 @@ export const ActivePage = () => { }, []); return ( <Wrapper> - <EmptyFiller loading title="激活中" /> + <EmptyFiller loading title={t('activating')} /> </Wrapper> ); }; diff --git a/frontend/src/app/pages/AuthorizationPage/index.tsx b/frontend/src/app/pages/AuthorizationPage/index.tsx index 47f3632fd..e0a6ee723 100644 --- a/frontend/src/app/pages/AuthorizationPage/index.tsx +++ b/frontend/src/app/pages/AuthorizationPage/index.tsx @@ -1,4 +1,5 @@ import { EmptyFiller } from 'app/components/EmptyFiller'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { getUserInfoByToken } from 'app/slice/thunks'; import { useCallback, useEffect } from 'react'; import { useDispatch } from 'react-redux'; @@ -10,9 +11,12 @@ export const AuthorizationPage = () => { const history = useHistory(); const paramsMatch = useRouteMatch<{ token: string }>(); const token = paramsMatch.params.token; + const t = useI18NPrefix('authorization'); + const toApp = useCallback(() => { history.replace('/'); }, [history]); + useEffect(() => { if (token) { dispatch(getUserInfoByToken({ token, resolve: toApp })); @@ -20,7 +24,7 @@ export const AuthorizationPage = () => { }, [token, dispatch, toApp]); return ( <Wrapper> - <EmptyFiller loading title="处理中" /> + <EmptyFiller loading title={t('processing')} /> </Wrapper> ); }; diff --git a/frontend/src/app/pages/MainPage/pages/ConfirmInvitePage/index.tsx b/frontend/src/app/pages/MainPage/pages/ConfirmInvitePage/index.tsx index fc62e472d..6f771c929 100644 --- a/frontend/src/app/pages/MainPage/pages/ConfirmInvitePage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/ConfirmInvitePage/index.tsx @@ -1,5 +1,6 @@ import { message } from 'antd'; import { EmptyFiller } from 'app/components/EmptyFiller'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { useCallback, useEffect } from 'react'; import { useHistory } from 'react-router'; import styled from 'styled-components'; @@ -7,14 +8,16 @@ import { confirmInvite } from './service'; export const ConfirmInvitePage = () => { const history = useHistory(); + const t = useI18NPrefix('confirmInvite'); + const onConfirm = useCallback( token => { confirmInvite(token).then(() => { - message.success('成功加入组织'); + message.success(t('join')); history.replace('/'); }); }, - [history], + [history, t], ); useEffect(() => { const search = window.location.search, @@ -27,7 +30,7 @@ export const ConfirmInvitePage = () => { }, []); return ( <Wrapper> - <EmptyFiller loading title="确认邀请中" /> + <EmptyFiller loading title={t('confirming')} /> </Wrapper> ); }; diff --git a/frontend/src/app/pages/MainPage/pages/OrgSettingPage/DeleteConfirm.tsx b/frontend/src/app/pages/MainPage/pages/OrgSettingPage/DeleteConfirm.tsx index 23b4defe7..9283eb66c 100644 --- a/frontend/src/app/pages/MainPage/pages/OrgSettingPage/DeleteConfirm.tsx +++ b/frontend/src/app/pages/MainPage/pages/OrgSettingPage/DeleteConfirm.tsx @@ -1,4 +1,5 @@ import { Button, Form, Input, message, Modal, ModalProps } from 'antd'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { selectCurrentOrganization, selectDeleteOrganizationLoading, @@ -15,6 +16,8 @@ export const DeleteConfirm = (props: ModalProps) => { const currentOrganization = useSelector(selectCurrentOrganization); const loading = useSelector(selectDeleteOrganizationLoading); const confirmDisabled = inputValue !== currentOrganization?.name; + const t = useI18NPrefix('orgSetting'); + const tg = useI18NPrefix('global'); const inputChange = useCallback(e => { setInputValue(e.target.value); @@ -24,17 +27,17 @@ export const DeleteConfirm = (props: ModalProps) => { dispatch( deleteOrganization(() => { history.replace('/'); - message.success('删除成功'); + message.success(tg('operation.deleteSuccess')); }), ); - }, [dispatch, history]); + }, [dispatch, history, tg]); return ( <Modal {...props} footer={[ <Button key="cancel" onClick={props.onCancel}> - 取消 + {t('cancel')} </Button>, <Button key="confirm" @@ -43,13 +46,13 @@ export const DeleteConfirm = (props: ModalProps) => { onClick={deleteOrg} danger > - 确认删除 + {t('delete')} </Button>, ]} > <Form.Item> <Input - placeholder="输入组织名称确认删除" + placeholder={t('enterOrgName')} value={inputValue} onChange={inputChange} /> diff --git a/frontend/src/app/pages/MainPage/pages/OrgSettingPage/index.tsx b/frontend/src/app/pages/MainPage/pages/OrgSettingPage/index.tsx index f97c6a1ff..ebc9ec798 100644 --- a/frontend/src/app/pages/MainPage/pages/OrgSettingPage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/OrgSettingPage/index.tsx @@ -1,5 +1,6 @@ import { Button, Card, Form, Input, message, Upload } from 'antd'; import { Avatar } from 'app/components'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import debounce from 'debounce-promise'; import { BASE_API_URL, @@ -34,6 +35,8 @@ export function OrgSettingPage() { const currentOrganization = useSelector(selectCurrentOrganization); const saveOrganizationLoading = useSelector(selectSaveOrganizationLoading); const [form] = Form.useForm(); + const t = useI18NPrefix('orgSetting'); + const tg = useI18NPrefix('global'); useEffect(() => { if (currentOrganization) { @@ -62,12 +65,12 @@ export function OrgSettingPage() { editOrganization({ organization: { id: currentOrganization?.id, ...values }, resolve: () => { - message.success('修改成功'); + message.success(tg('operation.updateSuccess')); }, }), ); }, - [dispatch, currentOrganization], + [dispatch, currentOrganization, tg], ); const showDeleteConfirm = useCallback(() => { @@ -80,7 +83,7 @@ export function OrgSettingPage() { return ( <Wrapper> - <Card title="基本信息"> + <Card title={t('info')}> <Form name="source_form_" form={form} @@ -89,7 +92,7 @@ export function OrgSettingPage() { wrapperCol={{ span: 16 }} onFinish={save} > - <Form.Item label="头像" className="avatar"> + <Form.Item label={t('avatar')} className="avatar"> <Avatar size={SPACE_UNIT * 20} src={`${BASE_RESOURCE_URL}${currentOrganization?.avatar}`} @@ -108,15 +111,18 @@ export function OrgSettingPage() { onChange={avatarChange} > <Button type="link" loading={avatarLoading}> - 点击上传 + {t('clickToUpload')} </Button> </Upload> </Form.Item> <Form.Item name="name" - label="名称" + label={t('name')} rules={[ - { required: true, message: '名称不能为空' }, + { + required: true, + message: `${t('name')}${tg('validation.required')}`, + }, { validator: debounce((_, value) => { if (value === currentOrganization?.name) { @@ -136,7 +142,7 @@ export function OrgSettingPage() { > <Input /> </Form.Item> - <Form.Item name="description" label="描述"> + <Form.Item name="description" label={t('description')}> <Input.TextArea autoSize={{ minRows: 4, maxRows: 8 }} /> </Form.Item> <Form.Item label=" " colon={false}> @@ -145,21 +151,19 @@ export function OrgSettingPage() { htmlType="submit" loading={saveOrganizationLoading} > - 保存 + {tg('button.save')} </Button> </Form.Item> </Form> </Card> - <Card title="删除组织"> - <h4 className="notice"> - 删除组织时,会将组织内所有资源、成员、角色和其他配置信息一并永久删除,请谨慎操作。 - </h4> + <Card title={t('deleteOrg')}> + <h4 className="notice">{t('deleteOrgDesc')}</h4> <Button danger onClick={showDeleteConfirm}> - 删除组织 + {t('deleteOrg')} </Button> <DeleteConfirm width={480} - title="删除组织" + title={t('deleteOrg')} visible={deleteConfirmVisible} onCancel={hideDeleteConfirm} /> diff --git a/frontend/src/app/pages/NotFoundPage/index.tsx b/frontend/src/app/pages/NotFoundPage/index.tsx index f6c87bfb6..0b0dcaa18 100644 --- a/frontend/src/app/pages/NotFoundPage/index.tsx +++ b/frontend/src/app/pages/NotFoundPage/index.tsx @@ -1,20 +1,22 @@ import { SearchOutlined } from '@ant-design/icons'; +import useI18NPrefix from 'app/hooks/useI18NPrefix'; import { Helmet } from 'react-helmet-async'; import styled from 'styled-components/macro'; import { SPACE_TIMES } from 'styles/StyleConstants'; export function NotFoundPage() { + const t = useI18NPrefix('notfound'); return ( <Wrapper> <Helmet> - <title>404 Page Not Found - + {`404 ${t('title')}`} +

404

-

没有这个页面

+

{t('title')}

); } diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index b5c9f1b35..324ff5a3a 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -1117,6 +1117,31 @@ "fragment": "Expression" } }, + "orgSetting": { + "info": "Info", + "avatar": "Avatar", + "clickToUpload": "Click to upload", + "name": "Name", + "description": "Description", + "deleteOrg": "Delete Organization", + "deleteOrgDesc": "When deleting an organization, all resources, members, roles, and other configurations belonging to the organization will be permanently deleted. Please operate with caution.", + "cancel": "Cancel", + "delete": "Delete", + "enterOrgName": "Enter organization name to delete" + }, + "confirmInvite": { + "join": "Join successful", + "confirming": "Confirming" + }, + "active": { + "activating": "Activating" + }, + "authorization": { + "processing": "Processing" + }, + "notfound": { + "title": "Page not found" + }, "share": { "common": { "confirm": "Confirm", diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 41f72d273..fc806f859 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -1130,6 +1130,31 @@ "fragment": "表达式" } }, + "orgSetting": { + "info": "基本信息", + "avatar": "头像", + "clickToUpload": "点击上传", + "name": "名称", + "description": "描述", + "deleteOrg": "删除组织", + "deleteOrgDesc": "删除组织时,会将组织内所有资源、成员、角色和其他配置信息一并永久删除,请谨慎操作。", + "cancel": "取消", + "delete": "确定删除", + "enterOrgName": "输入组织名称确认删除" + }, + "confirmInvite": { + "join": "成功加入组织", + "confirming": "确认邀请中" + }, + "active": { + "activating": "激活中" + }, + "authorization": { + "processing": "处理中" + }, + "notfound": { + "title": "没有这个页面" + }, "share": { "common": { "confirm": "请确认", From b6cef8f62b5571ae8f2f261cb7f93e2fd36abfb6 Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Mon, 3 Jan 2022 13:25:25 +0800 Subject: [PATCH 316/348] fix:storyboard unarchive bug fix --- .../main/java/datart/server/service/impl/VizServiceImpl.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/datart/server/service/impl/VizServiceImpl.java b/server/src/main/java/datart/server/service/impl/VizServiceImpl.java index 556ee2297..a80c49b47 100644 --- a/server/src/main/java/datart/server/service/impl/VizServiceImpl.java +++ b/server/src/main/java/datart/server/service/impl/VizServiceImpl.java @@ -329,7 +329,10 @@ public boolean unarchiveViz(String vizId, ResourceType vizType, String newName, Storyboard storyboard = storyboardService.retrieve(vizId); storyboardService.requirePermission(storyboard, Const.MANAGE); // check name - folderService.checkUnique(vizType, storyboard.getOrgId(), parentId, newName); + Storyboard check = new Storyboard(); + check.setOrgId(storyboard.getOrgId()); + check.setName(newName); + storyboardService.checkUnique(check); storyboard.setName(newName); storyboard.setStatus(Const.DATA_STATUS_ACTIVE); return 1 == storyboardService.getDefaultMapper().updateByPrimaryKey(storyboard); From fa4085bb50e83ea4eb78a6a8939852d6bb46be23 Mon Sep 17 00:00:00 2001 From: scottsut Date: Mon, 3 Jan 2022 17:28:41 +0800 Subject: [PATCH 317/348] fix: sourcemap work incorrect when building --- frontend/package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index ae074e5eb..4933a0e3b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,7 +16,9 @@ "scripts": { "analyze": "craco build && source-map-explorer 'build/static/js/*.js'", "start": "craco start", - "build": "cross-env GENERATE_SOURCEMAP=false && npm run rollup && craco build", + "build": "cross-env GENERATE_SOURCEMAP=false craco build", + "build:task": "rollup -c", + "build:all": "npm run build && npm run build:task", "test": "craco test", "test:coverage": "npm run test -- --watchAll=false --coverage", "checkTs": "tsc --noEmit", @@ -26,8 +28,7 @@ "lint:css": "stylelint src/**/*.{less,css}", "prettify": "prettier --write src", "prepare": "cd .. && husky install frontend/.husky", - "eject": "react-scripts eject", - "rollup": "rollup -c" + "eject": "react-scripts eject" }, "eslintConfig": { "extends": [ From a76836cae17320de2f143c463c5e879719bce879 Mon Sep 17 00:00:00 2001 From: scottsut Date: Mon, 3 Jan 2022 23:04:17 +0800 Subject: [PATCH 318/348] fix: build task first --- frontend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/package.json b/frontend/package.json index 4933a0e3b..326706a26 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,7 +18,7 @@ "start": "craco start", "build": "cross-env GENERATE_SOURCEMAP=false craco build", "build:task": "rollup -c", - "build:all": "npm run build && npm run build:task", + "build:all": "npm run build:task && npm run build", "test": "craco test", "test:coverage": "npm run test -- --watchAll=false --coverage", "checkTs": "tsc --noEmit", From ccfed12c88bc599f26a4bbf98037136ef2136689 Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Tue, 4 Jan 2022 11:51:57 +0800 Subject: [PATCH 319/348] fix: execute param parse bug fix --- .../main/java/datart/core/data/provider/SingleTypedValue.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/datart/core/data/provider/SingleTypedValue.java b/core/src/main/java/datart/core/data/provider/SingleTypedValue.java index 8659e5ac0..9a7f49d21 100644 --- a/core/src/main/java/datart/core/data/provider/SingleTypedValue.java +++ b/core/src/main/java/datart/core/data/provider/SingleTypedValue.java @@ -20,8 +20,10 @@ import datart.core.base.consts.ValueType; import lombok.Data; +import lombok.NoArgsConstructor; @Data +@NoArgsConstructor public class SingleTypedValue extends TypedValue { private Object value; @@ -31,6 +33,8 @@ public SingleTypedValue(Object value, ValueType valueType) { this.valueType = valueType; } + + @Override public String toString() { return "TypedValue{" + From 8a092489c628748e3ce53c2f7667f02eb11decc5 Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Tue, 4 Jan 2022 12:22:51 +0800 Subject: [PATCH 320/348] fix: modify frontend build command --- server/pom.xml | 2 +- server/src/main/resources/assembly/assembly.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/pom.xml b/server/pom.xml index 85f1bf95d..4e8779f4e 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -271,7 +271,7 @@ npm run - build + build:all ${project.parent.basedir}/frontend diff --git a/server/src/main/resources/assembly/assembly.xml b/server/src/main/resources/assembly/assembly.xml index 02b88c751..39b8648b9 100644 --- a/server/src/main/resources/assembly/assembly.xml +++ b/server/src/main/resources/assembly/assembly.xml @@ -23,7 +23,7 @@ ./ Dockerfile - docker-compose.yml.example + From 087f84922314953c79b0127b76c1719a6658c3df Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 4 Jan 2022 12:34:14 +0800 Subject: [PATCH 321/348] chore(project): fix antv@s2-react peer dependency issue with npm v7+ --- frontend/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/package.json b/frontend/package.json index 326706a26..79cc5e941 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,6 +14,7 @@ "author": "", "license": "Apache-2.0", "scripts": { + "bootstrap": "npm install --legacy-peer-deps", "analyze": "craco build && source-map-explorer 'build/static/js/*.js'", "start": "craco start", "build": "cross-env GENERATE_SOURCEMAP=false craco build", From f64b7bd301e67be70bf43dfaf588fcdc8addeab9 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 4 Jan 2022 12:37:26 +0800 Subject: [PATCH 322/348] chore(project): use build:analyze command --- frontend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/package.json b/frontend/package.json index 79cc5e941..cd134a53c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,11 +15,11 @@ "license": "Apache-2.0", "scripts": { "bootstrap": "npm install --legacy-peer-deps", - "analyze": "craco build && source-map-explorer 'build/static/js/*.js'", "start": "craco start", "build": "cross-env GENERATE_SOURCEMAP=false craco build", "build:task": "rollup -c", "build:all": "npm run build:task && npm run build", + "build:analyze": "craco build && source-map-explorer 'build/static/js/*.js'", "test": "craco test", "test:coverage": "npm run test -- --watchAll=false --coverage", "checkTs": "tsc --noEmit", From bcefafaadfe53c9942d426d968b7baa433c93fe1 Mon Sep 17 00:00:00 2001 From: scottsut Date: Tue, 4 Jan 2022 14:49:00 +0800 Subject: [PATCH 323/348] fix: make row number start at 1 --- frontend/src/app/utils/chartHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/utils/chartHelper.ts b/frontend/src/app/utils/chartHelper.ts index 01aca6c7a..015880f74 100644 --- a/frontend/src/app/utils/chartHelper.ts +++ b/frontend/src/app/utils/chartHelper.ts @@ -412,7 +412,7 @@ export function transformToObjectArray( const result: any[] = Array.apply(null, Array(columns.length)); for (let j = 0, outterLength = result.length; j < outterLength; j++) { let objCol = { - id: j, + id: j + 1, }; for (let i = 0, innerLength = metas.length; i < innerLength; i++) { const key = metas?.[i]?.name; From 941311630c140266d50311ec17d2663e35ab0df7 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 4 Jan 2022 14:47:12 +0800 Subject: [PATCH 324/348] feat(chart): pivot table add data header position options and add basic radio component --- .../FormGenerator/Basic/BasicRadio.tsx | 62 +++++++++++++++++++ .../components/FormGenerator/Basic/index.ts | 1 + .../FormGenerator/Layout/ItemLayout.tsx | 3 + .../PivotSheetChart/PivotSheetChart.tsx | 6 +- .../ChartGraph/PivotSheetChart/config.ts | 26 ++++++++ frontend/src/app/types/ChartConfig.ts | 1 + 6 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 frontend/src/app/components/FormGenerator/Basic/BasicRadio.tsx diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicRadio.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicRadio.tsx new file mode 100644 index 000000000..f08f2a1d2 --- /dev/null +++ b/frontend/src/app/components/FormGenerator/Basic/BasicRadio.tsx @@ -0,0 +1,62 @@ +/** + * 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 { Radio } from 'antd'; +import { ChartStyleSectionConfig } from 'app/types/ChartConfig'; +import { FC, memo } from 'react'; +import styled from 'styled-components/macro'; +import { ItemLayoutProps } from '../types'; +import { itemLayoutComparer } from '../utils'; +import { BW } from './components/BasicWrapper'; + +const BasicRadio: FC> = memo( + ({ ancestors, translate: t = title => title, data: row, onChange }) => { + const { value, comType, options, ...rest } = row; + const items = options?.items || []; + + const handleValueChange = e => { + const newValue = e.target.value; + onChange?.(ancestors, newValue, options?.needRefresh); + }; + + return ( + + + {items?.map(o => { + return ( + + {o.label} + + ); + })} + + + ); + }, + itemLayoutComparer, +); + +export default BasicRadio; + +const StyledBasicRadio = styled(BW)``; diff --git a/frontend/src/app/components/FormGenerator/Basic/index.ts b/frontend/src/app/components/FormGenerator/Basic/index.ts index b99a8fe4b..9e11f3ee8 100644 --- a/frontend/src/app/components/FormGenerator/Basic/index.ts +++ b/frontend/src/app/components/FormGenerator/Basic/index.ts @@ -25,6 +25,7 @@ export { default as BasicInputNumber } from './BasicInputNumber'; export { default as BasicInputPercentage } from './BasicInputPercentage'; export { default as BasicLine } from './BasicLine'; export { default as BasicMarginWidth } from './BasicMarginWidth'; +export { default as BasicRadio } from './BasicRadio'; export { default as BasicSelector } from './BasicSelector'; export { default as BasicSlider } from './BasicSlider'; export { default as BasicSwitch } from './BasicSwitch'; diff --git a/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx b/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx index 8dc9b5a5b..8a0e1e6ca 100644 --- a/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx +++ b/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx @@ -42,6 +42,7 @@ import { BasicInputPercentage, BasicLine, BasicMarginWidth, + BasicRadio, BasicSelector, BasicSlider, BasicSwitch, @@ -162,6 +163,8 @@ const ItemLayout: FC> = memo( return ; case ChartStyleSectionComponentType.TEXT: return ; + case ChartStyleSectionComponentType.RADIO: + return ; default: return
{`no matched component comType of ${data.comType}`}
; } diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/PivotSheetChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/PivotSheetChart.tsx index b1bd2122f..6963d36b6 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/PivotSheetChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/PivotSheetChart.tsx @@ -121,6 +121,10 @@ class PivotSheetChart extends ReactChart { 'style', 'enableSelectedHighlight', ]); + const metricNameShowIn = this.getStyleValue(styleConfigs, [ + 'style', + 'metricNameShowIn', + ]); const enableTotal = this.getStyleValue(settingConfigs, [ 'rowSummary', 'enableTotal', @@ -166,7 +170,7 @@ class PivotSheetChart extends ReactChart { rows: rowSectionConfigRows.map(getValueByColumnKey), columns: columnSectionConfigRows.map(getValueByColumnKey), values: metricsSectionConfigRows.map(getValueByColumnKey), - valueInCols: true, + valueInCols: !!metricNameShowIn, }, meta: rowSectionConfigRows .concat(columnSectionConfigRows) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts index f9e965342..2b4c2c41a 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts @@ -136,6 +136,26 @@ const config: ChartConfig = { default: false, comType: 'checkbox', }, + { + label: 'style.metricNameShowIn.label', + key: 'metricNameShowIn', + default: true, + comType: 'radio', + options: { + items: [ + { + key: 'inCol', + label: '列表头', + value: true, + }, + { + key: 'inRow', + label: '行表头', + value: false, + }, + ], + }, + }, ], }, { @@ -314,6 +334,9 @@ const config: ChartConfig = { enableSelectedHighlight: '启用选中高亮', enableAdjustRowHeight: '启用调整行高', enableAdjustColumnWidth: '启用调整列宽', + metricNameShowIn: { + label: '指标名称位置', + }, tableSize: '表格大小', tableHeaderStyle: '表头样式', tableBodyStyle: '表体样式', @@ -349,6 +372,9 @@ const config: ChartConfig = { enableSelectedHighlight: 'Enable Selected Highlight', enableAdjustRowHeight: 'Enable Adjust Row Height', enableAdjustColumnWidth: 'Enable Adjust Column Width', + metricNameShowIn: { + label: 'Metric Name Position', + }, tableSize: 'Table Size', tableHeaderStyle: 'Table Header Style', tableBodyStyle: 'Table Body Style', diff --git a/frontend/src/app/types/ChartConfig.ts b/frontend/src/app/types/ChartConfig.ts index 7bb8eb0ac..d06fa6872 100644 --- a/frontend/src/app/types/ChartConfig.ts +++ b/frontend/src/app/types/ChartConfig.ts @@ -202,6 +202,7 @@ export const ChartStyleSectionComponentType = { MARGIN_WIDTH: 'marginWidth', TEXT: 'text', CONDITIONSTYLE: 'conditionStylePanel', + RADIO: 'radio', }; type ChartConfigBase = { From 4debb3ef792e94b13779025808cabcbfab45da6b Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 4 Jan 2022 14:56:00 +0800 Subject: [PATCH 325/348] refactor(chart): basic radio component support i18n style --- .../src/app/components/FormGenerator/Basic/BasicRadio.tsx | 2 +- .../components/ChartGraph/PivotSheetChart/config.ts | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicRadio.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicRadio.tsx index f08f2a1d2..114fe9fd8 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicRadio.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicRadio.tsx @@ -46,7 +46,7 @@ const BasicRadio: FC> = memo( {items?.map(o => { return ( - {o.label} + {t(o.label)} ); })} diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts index 2b4c2c41a..c807d3b2e 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts @@ -145,12 +145,12 @@ const config: ChartConfig = { items: [ { key: 'inCol', - label: '列表头', + label: 'style.metricNameShowIn.inCol', value: true, }, { key: 'inRow', - label: '行表头', + label: 'style.metricNameShowIn.inRow', value: false, }, ], @@ -336,6 +336,8 @@ const config: ChartConfig = { enableAdjustColumnWidth: '启用调整列宽', metricNameShowIn: { label: '指标名称位置', + inCol: '列表头', + inRow: '行表头', }, tableSize: '表格大小', tableHeaderStyle: '表头样式', @@ -374,6 +376,8 @@ const config: ChartConfig = { enableAdjustColumnWidth: 'Enable Adjust Column Width', metricNameShowIn: { label: 'Metric Name Position', + inCol: 'Col Header', + inRow: 'Row Header', }, tableSize: 'Table Size', tableHeaderStyle: 'Table Header Style', From 31dc4154f37b5ae280faf095f9147a465ce8b8dc Mon Sep 17 00:00:00 2001 From: tianlei Date: Tue, 4 Jan 2022 14:59:56 +0800 Subject: [PATCH 326/348] fix:(Chart) fix table summarys function --- .../components/ChartGraph/BasicTableChart/BasicTableChart.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx index 88ec32748..86c1029eb 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicTableChart/BasicTableChart.tsx @@ -212,7 +212,7 @@ class BasicTableChart extends ReactChart { .map(c => c.key) .map(k => { const currentSummaryField = aggregateFieldConfigs.find( - c => c.colName === k, + c => getValueByColumnKey(c) === k, ); if (currentSummaryField) { const total = dataColumns.map( From d7668a2edac3186c6f95af8ec2c6284cdeb18c52 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 4 Jan 2022 15:16:37 +0800 Subject: [PATCH 327/348] refactor(chart): add global tranlate --- .../FormGenerator/Basic/BasicSelector.tsx | 2 +- frontend/src/app/hooks/useI18NPrefix.ts | 5 +++++ .../ChartGraph/PivotSheetChart/config.ts | 15 ++++++++++++--- frontend/src/globalConstants.ts | 1 + frontend/src/locales/en/translation.json | 7 ++++++- frontend/src/locales/zh/translation.json | 7 ++++++- 6 files changed, 31 insertions(+), 6 deletions(-) diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx index f4582d9c7..9c678dac4 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx @@ -78,7 +78,7 @@ const BasicSelector: FC> = memo( > {safeInvokeAction()?.map((o, index) => { const key = isEmpty(o['key']) ? index : o.key; - const label = isEmpty(o['label']) ? o : o.label; + const label = isEmpty(o['label']) ? o : t(o.label); const value = isEmpty(o['value']) ? o : o.value; return ( diff --git a/frontend/src/app/hooks/useI18NPrefix.ts b/frontend/src/app/hooks/useI18NPrefix.ts index 1b4facf3b..7dfc73dbd 100644 --- a/frontend/src/app/hooks/useI18NPrefix.ts +++ b/frontend/src/app/hooks/useI18NPrefix.ts @@ -17,6 +17,7 @@ */ import ChartI18NContext from 'app/pages/ChartWorkbenchPage/contexts/Chart18NContext'; +import { DATART_TRANSLATE_HOLDER } from 'globalConstants'; import i18n from 'i18next'; import get from 'lodash/get'; import { useCallback, useContext } from 'react'; @@ -46,6 +47,10 @@ function usePrefixI18N(prefix?: string) { if (contextTranslation) { return contextTranslation; } + if (key.includes(DATART_TRANSLATE_HOLDER)) { + const newKey = key.replace(`${DATART_TRANSLATE_HOLDER}.`, ''); + return t.call(Object.create(null), `${newKey}`, options) as string; + } if (disablePrefix) { return t.call(Object.create(null), `${key}`, options) as string; } diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts index c807d3b2e..0ad2dc14d 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts @@ -196,9 +196,18 @@ const config: ChartConfig = { comType: 'select', options: { items: [ - { label: '左对齐', value: 'left' }, - { label: '居中对齐', value: 'center' }, - { label: '右对齐', value: 'right' }, + { + label: '@global@.viz.common.enum.fontAlignment.left', + value: 'left', + }, + { + label: '@global@.viz.common.enum.fontAlignment.center', + value: 'center', + }, + { + label: '@global@.viz.common.enum.fontAlignment.right', + value: 'right', + }, ], }, }, diff --git a/frontend/src/globalConstants.ts b/frontend/src/globalConstants.ts index 7f103669f..8a64509d3 100644 --- a/frontend/src/globalConstants.ts +++ b/frontend/src/globalConstants.ts @@ -20,6 +20,7 @@ import { FONT_FAMILY } from 'styles/StyleConstants'; export const DATARTSEPERATOR = '@datart@'; export const CHARTCONFIG_FIELD_PLACEHOLDER_UID = '@placeholder@'; +export const DATART_TRANSLATE_HOLDER = '@global@'; export enum StorageKeys { AuthorizationToken = 'AUTHORIZATION_TOKEN', diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 305d6a3fb..13bc41511 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -331,6 +331,11 @@ "hide": "Hide", "show": "Show", "condition": "Condition" + }, + "fontAlignment": { + "left": "Left", + "center": "Center", + "right": "right" } }, "filter": { @@ -664,7 +669,7 @@ "unpublished": "Unpublished", "archived": "Archived", "play": "Play", - "playTip":"Press Esc to quit playing", + "playTip": "Press Esc to quit playing", "share": { "link": "Link", "password": "Password", diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 120309fba..fbaa3f11d 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -331,6 +331,11 @@ "hide": "隐藏", "show": "显示", "condition": "条件" + }, + "fontAlignment": { + "left": "左对齐", + "center": "居中", + "right": "右对齐" } }, "filter": { @@ -664,7 +669,7 @@ "unpublished": "未发布", "archived": "已归档", "play": "播放", - "playTip":"按 Esc 退出播放", + "playTip": "按 Esc 退出播放", "share": { "link": "链接", "password": "密码", From 8bd7d405cabad56371e8357b1ea5c89262c14c18 Mon Sep 17 00:00:00 2001 From: tianlei Date: Tue, 4 Jan 2022 15:41:38 +0800 Subject: [PATCH 328/348] fix:(Chart) fix gauge data --- .../BasicGaugeChart/BasicGaugeChart.tsx | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/BasicGaugeChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/BasicGaugeChart.tsx index ee5d3a879..53b6312f2 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/BasicGaugeChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/BasicGaugeChart.tsx @@ -128,21 +128,22 @@ class BasicGaugeChart extends Chart { 'pointerColor', ); + const dataConfig: { name: string; value: string; itemStyle: any } = { + name: getColumnRenderName(aggConfig), + value: dataColumns?.[0]?.[getValueByColumnKey(aggConfig)] || 0, + itemStyle: { + color: pointerColor, + }, + }; + if (aggConfig?.color?.start) { + dataConfig.itemStyle.color = aggConfig.color.start; + } + return { ...this.getGauge(styleConfigs), - data: dataColumns.map(dc => { - const dataConfig: { name: string; value: string; itemStyle: any } = { - name: getColumnRenderName(aggConfig), - value: dc[getValueByColumnKey(aggConfig)] || 0, - itemStyle: { - color: pointerColor, - }, - }; - if (aggConfig?.color?.start) { - dataConfig.itemStyle.color = aggConfig.color.start; - } - return dataConfig; - }), + data: [ + dataConfig, + ], pointer, ...axis, title, From 6b61284836ba870802a8716485c95dc4df0b660a Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 4 Jan 2022 15:48:14 +0800 Subject: [PATCH 329/348] feat(chart): extract font alignment component --- .../FormGenerator/Customize/FontAlignment.tsx | 75 +++++++++++++++++++ .../FormGenerator/Customize/index.ts | 1 + .../FormGenerator/Layout/ItemLayout.tsx | 3 + .../ChartGraph/PivotSheetChart/config.ts | 27 +------ frontend/src/app/types/ChartConfig.ts | 3 + 5 files changed, 84 insertions(+), 25 deletions(-) create mode 100644 frontend/src/app/components/FormGenerator/Customize/FontAlignment.tsx diff --git a/frontend/src/app/components/FormGenerator/Customize/FontAlignment.tsx b/frontend/src/app/components/FormGenerator/Customize/FontAlignment.tsx new file mode 100644 index 000000000..06131b16f --- /dev/null +++ b/frontend/src/app/components/FormGenerator/Customize/FontAlignment.tsx @@ -0,0 +1,75 @@ +/** + * 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 { ChartStyleSectionConfig } from 'app/types/ChartConfig'; +import { FC, memo } from 'react'; +import { ItemLayout } from '../Layout'; +import { ItemLayoutProps } from '../types'; +import { itemLayoutComparer } from '../utils'; + +const template = { + label: 'style.align', + key: 'align', + default: 'left', + comType: 'select', + options: { + items: [ + { + label: '@global@.viz.common.enum.fontAlignment.left', + value: 'left', + }, + { + label: '@global@.viz.common.enum.fontAlignment.center', + value: 'center', + }, + { + label: '@global@.viz.common.enum.fontAlignment.right', + value: 'right', + }, + ], + }, +}; + +const FontAlignment: FC> = memo( + ({ + ancestors, + translate: t = title => title, + data, + dataConfigs, + onChange, + }) => { + const props = { + ancestors, + data: Object.assign({}, data, { + label: data?.label || template.label, + key: data?.key || template.key, + default: data?.default || template.default, + options: data?.options || template.options, + comType: 'select', + }), + translate: t, + onChange, + dataConfigs, + }; + + return ; + }, + itemLayoutComparer, +); + +export default FontAlignment; diff --git a/frontend/src/app/components/FormGenerator/Customize/index.ts b/frontend/src/app/components/FormGenerator/Customize/index.ts index b27e87a06..bcdb6f591 100644 --- a/frontend/src/app/components/FormGenerator/Customize/index.ts +++ b/frontend/src/app/components/FormGenerator/Customize/index.ts @@ -18,5 +18,6 @@ export { default as ConditionStylePanel } from './ConditionStylePanel'; export { default as DataReferencePanel } from './DataReferencePanel'; +export { default as FontAlignment } from './FontAlignment'; export { default as ListTemplatePanel } from './ListTemplatePanel'; export { default as UnControlledTableHeaderPanel } from './UnControlledTableHeaderPanel'; diff --git a/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx b/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx index 8a0e1e6ca..1d980fb29 100644 --- a/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx +++ b/frontend/src/app/components/FormGenerator/Layout/ItemLayout.tsx @@ -52,6 +52,7 @@ import { import { ConditionStylePanel, DataReferencePanel, + FontAlignment, ListTemplatePanel, UnControlledTableHeaderPanel, } from '../Customize'; @@ -165,6 +166,8 @@ const ItemLayout: FC> = memo( return ; case ChartStyleSectionComponentType.RADIO: return ; + case ChartStyleSectionComponentType.FontAlignment: + return ; default: return
{`no matched component comType of ${data.comType}`}
; } diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts index 0ad2dc14d..a4a539f73 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts @@ -193,23 +193,7 @@ const config: ChartConfig = { label: 'style.align', key: 'align', default: 'right', - comType: 'select', - options: { - items: [ - { - label: '@global@.viz.common.enum.fontAlignment.left', - value: 'left', - }, - { - label: '@global@.viz.common.enum.fontAlignment.center', - value: 'center', - }, - { - label: '@global@.viz.common.enum.fontAlignment.right', - value: 'right', - }, - ], - }, + comType: 'fontAlignment', }, ], }, @@ -253,14 +237,7 @@ const config: ChartConfig = { label: 'style.align', key: 'align', default: 'left', - comType: 'select', - options: { - items: [ - { label: '左对齐', value: 'left' }, - { label: '居中对齐', value: 'center' }, - { label: '右对齐', value: 'right' }, - ], - }, + comType: 'fontAlignment', }, ], }, diff --git a/frontend/src/app/types/ChartConfig.ts b/frontend/src/app/types/ChartConfig.ts index d06fa6872..3ae618e26 100644 --- a/frontend/src/app/types/ChartConfig.ts +++ b/frontend/src/app/types/ChartConfig.ts @@ -203,6 +203,9 @@ export const ChartStyleSectionComponentType = { TEXT: 'text', CONDITIONSTYLE: 'conditionStylePanel', RADIO: 'radio', + + // Customize Component + FontAlignment: 'fontAlignment', }; type ChartConfigBase = { From 9e29158766e07b7f6e9d0d4525adedfc1b053a5b Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Tue, 4 Jan 2022 15:58:21 +0800 Subject: [PATCH 330/348] fix: modify frontend build command --- .../main/java/datart/core/data/provider/SingleTypedValue.java | 2 -- server/pom.xml | 3 ++- server/src/main/resources/migrations/source.1.0.0-alpha.2.sql | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) delete mode 100644 server/src/main/resources/migrations/source.1.0.0-alpha.2.sql diff --git a/core/src/main/java/datart/core/data/provider/SingleTypedValue.java b/core/src/main/java/datart/core/data/provider/SingleTypedValue.java index 9a7f49d21..5cb9dcfe0 100644 --- a/core/src/main/java/datart/core/data/provider/SingleTypedValue.java +++ b/core/src/main/java/datart/core/data/provider/SingleTypedValue.java @@ -33,8 +33,6 @@ public SingleTypedValue(Object value, ValueType valueType) { this.valueType = valueType; } - - @Override public String toString() { return "TypedValue{" + diff --git a/server/pom.xml b/server/pom.xml index 4e8779f4e..9f95f4f01 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -254,7 +254,8 @@ npm - install + run + bootstrap --registry=https://registry.npm.taobao.org ${project.parent.basedir}/frontend diff --git a/server/src/main/resources/migrations/source.1.0.0-alpha.2.sql b/server/src/main/resources/migrations/source.1.0.0-alpha.2.sql deleted file mode 100644 index 5a20f4f43..000000000 --- a/server/src/main/resources/migrations/source.1.0.0-alpha.2.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE `source` -DROP INDEX `prj_name`; \ No newline at end of file From eabe0b6c0ed6f4a14929acbb3e5575b0ed7226b2 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 4 Jan 2022 16:03:59 +0800 Subject: [PATCH 331/348] refactor(chart): support default item translate options --- .../src/app/components/FormGenerator/Basic/BasicRadio.tsx | 3 ++- .../app/components/FormGenerator/Basic/BasicSelector.tsx | 5 +++-- .../components/FormGenerator/Customize/FontAlignment.tsx | 1 + .../components/ChartGraph/PivotSheetChart/config.ts | 1 + frontend/src/app/types/ChartConfig.ts | 6 ++++++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicRadio.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicRadio.tsx index 114fe9fd8..45f4f1711 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicRadio.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicRadio.tsx @@ -28,6 +28,7 @@ const BasicRadio: FC> = memo( ({ ancestors, translate: t = title => title, data: row, onChange }) => { const { value, comType, options, ...rest } = row; const items = options?.items || []; + const needTranslate = !!options?.translateItemLabel; const handleValueChange = e => { const newValue = e.target.value; @@ -46,7 +47,7 @@ const BasicRadio: FC> = memo( {items?.map(o => { return ( - {t(o.label)} + {needTranslate ? t(o.label) : o?.label} ); })} diff --git a/frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx b/frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx index 9c678dac4..5c510a352 100644 --- a/frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx +++ b/frontend/src/app/components/FormGenerator/Basic/BasicSelector.tsx @@ -36,6 +36,7 @@ const BasicSelector: FC> = memo( }) => { const { comType, options, ...rest } = row; const hideLabel = !!options?.hideLabel; + const needTranslate = !!options?.translateItemLabel; const handleSelectorValueChange = value => { onChange?.(ancestors, value, options?.needRefresh); @@ -78,11 +79,11 @@ const BasicSelector: FC> = memo( > {safeInvokeAction()?.map((o, index) => { const key = isEmpty(o['key']) ? index : o.key; - const label = isEmpty(o['label']) ? o : t(o.label); + const label = isEmpty(o['label']) ? o : o.label; const value = isEmpty(o['value']) ? o : o.value; return ( - {label} + {needTranslate ? t(label) : label} ); })} diff --git a/frontend/src/app/components/FormGenerator/Customize/FontAlignment.tsx b/frontend/src/app/components/FormGenerator/Customize/FontAlignment.tsx index 06131b16f..6e6dea52c 100644 --- a/frontend/src/app/components/FormGenerator/Customize/FontAlignment.tsx +++ b/frontend/src/app/components/FormGenerator/Customize/FontAlignment.tsx @@ -28,6 +28,7 @@ const template = { default: 'left', comType: 'select', options: { + translateItemLabel: true, items: [ { label: '@global@.viz.common.enum.fontAlignment.left', diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts index a4a539f73..ee43c15a0 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts @@ -142,6 +142,7 @@ const config: ChartConfig = { default: true, comType: 'radio', options: { + translateItemLabel: true, items: [ { key: 'inCol', diff --git a/frontend/src/app/types/ChartConfig.ts b/frontend/src/app/types/ChartConfig.ts index 3ae618e26..5691454fc 100644 --- a/frontend/src/app/types/ChartConfig.ts +++ b/frontend/src/app/types/ChartConfig.ts @@ -337,6 +337,12 @@ export type ChartStyleSectionRowOption = { getItems?: (cols) => Array; needRefresh?: boolean; fontFamilies?: string[]; + + /** + * Suppport Components: @see BasicRadio, @see BasicSelector and etc + * Default is false for now, will be change in futrue version + */ + translateItemLabel?: boolean; }; export type ChartStyleSelectorItem = { From 7092bcdc8bc663f2c485afbd0e88bc3c091d27be Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 4 Jan 2022 16:09:41 +0800 Subject: [PATCH 332/348] refactor(chart): change font alignment label to global translation --- .../app/components/FormGenerator/Customize/FontAlignment.tsx | 2 +- frontend/src/locales/en/translation.json | 1 + frontend/src/locales/zh/translation.json | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/components/FormGenerator/Customize/FontAlignment.tsx b/frontend/src/app/components/FormGenerator/Customize/FontAlignment.tsx index 6e6dea52c..ec503e9f7 100644 --- a/frontend/src/app/components/FormGenerator/Customize/FontAlignment.tsx +++ b/frontend/src/app/components/FormGenerator/Customize/FontAlignment.tsx @@ -23,7 +23,7 @@ import { ItemLayoutProps } from '../types'; import { itemLayoutComparer } from '../utils'; const template = { - label: 'style.align', + label: '@global@.viz.common.enum.fontAlignment.alignment', key: 'align', default: 'left', comType: 'select', diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 13bc41511..3669f19b5 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -333,6 +333,7 @@ "condition": "Condition" }, "fontAlignment": { + "alignment": "Alignment", "left": "Left", "center": "Center", "right": "right" diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index fbaa3f11d..9e83e410c 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -333,6 +333,7 @@ "condition": "条件" }, "fontAlignment": { + "alignment": "对齐方式", "left": "左对齐", "center": "居中", "right": "右对齐" From fc8969e47f2973704a24cd44d19ce61bda6fd488 Mon Sep 17 00:00:00 2001 From: scottsut Date: Tue, 4 Jan 2022 16:19:03 +0800 Subject: [PATCH 333/348] chore: adjust table & pivotsheet style --- .../components/ChartGraph/MingXiTableChart/config.ts | 12 ++++++------ .../components/ChartGraph/PivotSheetChart/config.ts | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts index cb8b99660..714d9cacf 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts @@ -211,7 +211,7 @@ const config: ChartConfig = { { label: 'style.tableSize', key: 'tableSize', - default: 'default', + default: 'small', comType: 'select', options: { items: [ @@ -231,7 +231,7 @@ const config: ChartConfig = { { label: 'style.bgColor', key: 'bgColor', - default: '#f0f0f0', + default: '#f8f9fa', comType: 'fontColor', }, { @@ -241,9 +241,9 @@ const config: ChartConfig = { default: { fontFamily: 'PingFang SC', fontSize: 12, - fontWeight: 'normal', + fontWeight: 'bold', fontStyle: 'normal', - color: '#6c757d', + color: '#495057', }, }, { @@ -269,7 +269,7 @@ const config: ChartConfig = { { label: 'style.bgColor', key: 'bgColor', - default: '#fafafa', + default: 'rgba(0,0,0,0)', comType: 'fontColor', }, { @@ -281,7 +281,7 @@ const config: ChartConfig = { fontSize: 12, fontWeight: 'normal', fontStyle: 'normal', - color: '#6c757d', + color: '#495057', }, }, { diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts index f9e965342..9d461a7f2 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts @@ -156,7 +156,7 @@ const config: ChartConfig = { fontFamily: 'PingFang SC', fontSize: 12, fontWeight: 'normal', - color: '#6c757d', + color: '#495057', }, options: { fontFamilies: [ @@ -207,7 +207,7 @@ const config: ChartConfig = { fontFamily: 'PingFang SC', fontSize: 12, fontWeight: 'normal', - color: '#6c757d', + color: '#495057', }, options: { fontFamilies: [ From 58175e4007b3b9b36005517a73f774b07b9ccb3e Mon Sep 17 00:00:00 2001 From: scottsut Date: Tue, 4 Jan 2022 16:19:45 +0800 Subject: [PATCH 334/348] chore: change mixed section label --- frontend/src/locales/en/translation.json | 2 +- frontend/src/locales/zh/translation.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/locales/en/translation.json b/frontend/src/locales/en/translation.json index 305d6a3fb..fa775078f 100644 --- a/frontend/src/locales/en/translation.json +++ b/frontend/src/locales/en/translation.json @@ -529,7 +529,7 @@ "data": { "dimension": "Dimension", "metrics": "Metric", - "mixed": "Mixed", + "mixed": "Columns", "filter": "Filter", "colorize": "Color", "colorRange": "Range Color", diff --git a/frontend/src/locales/zh/translation.json b/frontend/src/locales/zh/translation.json index 120309fba..a0e19365a 100644 --- a/frontend/src/locales/zh/translation.json +++ b/frontend/src/locales/zh/translation.json @@ -529,7 +529,7 @@ "data": { "dimension": "维度", "metrics": "指标", - "mixed": "混合", + "mixed": "字段", "filter": "筛选", "colorize": "颜色", "colorRange": "Range Color", From 0501ff77a483c2dbce0a21cf3c9742347fb1b91b Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 4 Jan 2022 16:24:24 +0800 Subject: [PATCH 335/348] refactor(chart): replace font alignment in chart config --- .../components/ChartGraph/BasicBarChart/config.ts | 1 + .../components/ChartGraph/BasicFunnelChart/config.ts | 2 +- .../components/ChartGraph/BasicScatterChart/config.ts | 1 + .../components/ChartGraph/MingXiTableChart/config.ts | 9 +-------- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/config.ts index 90bc04aa4..6c1d4ece6 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/config.ts @@ -171,6 +171,7 @@ const config: ChartConfig = { comType: 'select', default: 'top', options: { + // TODO(Stephen): to be extract customize LabelPosition Component items: [ { label: '上', value: 'top' }, { label: '左', value: 'left' }, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/config.ts index 6cf514c02..7fdb133e4 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/config.ts @@ -71,8 +71,8 @@ const config: ChartConfig = { { label: 'funnel.align', key: 'align', - comType: 'select', default: 'center', + comType: 'select', options: { items: [ { label: '居中', value: 'center' }, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/config.ts index c6d098c1f..9923700f2 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/config.ts @@ -350,6 +350,7 @@ const config: ChartConfig = { default: 'center', comType: 'select', options: { + // TODO(Stephen): to be extract to axis name location component items: [ { label: '开始', value: 'start' }, { label: '结束', value: 'end' }, diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts index cb8b99660..f722f5561 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts @@ -288,14 +288,7 @@ const config: ChartConfig = { label: 'style.align', key: 'align', default: 'left', - comType: 'select', - options: { - items: [ - { label: '左对齐', value: 'left' }, - { label: '居中对齐', value: 'center' }, - { label: '右对齐', value: 'right' }, - ], - }, + comType: 'fontAlignment', }, ], }, From 75ca8e6567e7a3fac410d2a99e3b2c86b6da0286 Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 4 Jan 2022 16:45:07 +0800 Subject: [PATCH 336/348] refactor(chart): delete fenzu table --- .../ChartGraph/FenZuTableChart/FenZuTableChart.tsx | 5 +++++ .../src/app/pages/ChartWorkbenchPage/models/ChartManager.ts | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx index 90a648beb..0c7fdc7da 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/FenZuTableChart/FenZuTableChart.tsx @@ -25,6 +25,11 @@ import { import BasicTableChart from '../BasicTableChart'; import Config from './config'; +/** + * @deprecated Please use @see PivotSheetChart instead + * @class FenZuTableChart + * @extends {BasicTableChart} + */ class FenZuTableChart extends BasicTableChart { config = Config; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartManager.ts b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartManager.ts index 492d518de..a56ccf451 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/models/ChartManager.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/models/ChartManager.ts @@ -41,7 +41,6 @@ const { RoseChart, ScoreChart, MingXiTableChart, - FenZuTableChart, NormalOutlineMapChart, WordCloudChart, ScatterOutlineMapChart, @@ -104,7 +103,6 @@ class ChartManager { private _basicCharts(): Chart[] { return [ - new FenZuTableChart(), new MingXiTableChart(), new PivotSheetChart(), new ScoreChart(), From e35a1b3c71aa299ae3208ae8edf457f82f8d40a1 Mon Sep 17 00:00:00 2001 From: scottsut Date: Tue, 4 Jan 2022 16:44:46 +0800 Subject: [PATCH 337/348] fix(Variable): date value type parse error --- .../src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx | 2 +- frontend/src/app/pages/MainPage/pages/VariablePage/index.tsx | 2 +- .../pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx index d98bfe15b..c92f82e14 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/VariableForm.tsx @@ -70,7 +70,7 @@ export const VariableForm = memo( let defaultValue = editingVariable.defaultValue ? JSON.parse(editingVariable.defaultValue) : []; - if (valueType === VariableValueTypes.Date) { + if (valueType === VariableValueTypes.Date && !expression) { defaultValue = defaultValue.map(str => moment(str)); } setType(type); diff --git a/frontend/src/app/pages/MainPage/pages/VariablePage/index.tsx b/frontend/src/app/pages/MainPage/pages/VariablePage/index.tsx index 2563a378c..a3938b5fd 100644 --- a/frontend/src/app/pages/MainPage/pages/VariablePage/index.tsx +++ b/frontend/src/app/pages/MainPage/pages/VariablePage/index.tsx @@ -196,7 +196,7 @@ export function VariablePage() { const save = useCallback( (values: VariableFormModel) => { let defaultValue: any = values.defaultValue; - if (values.valueType === VariableValueTypes.Date) { + if (values.valueType === VariableValueTypes.Date && !values.expression) { defaultValue = values.defaultValue.map(d => (d as Moment).format(DEFAULT_VALUE_DATE_FORMAT), ); diff --git a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx index a160ceeb0..98ec187de 100644 --- a/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx +++ b/frontend/src/app/pages/MainPage/pages/ViewPage/Main/Properties/Variables.tsx @@ -179,7 +179,7 @@ export const Variables = memo(() => { const save = useCallback( (values: VariableFormModel) => { let defaultValue: any = values.defaultValue; - if (values.valueType === VariableValueTypes.Date) { + if (values.valueType === VariableValueTypes.Date && !values.expression) { defaultValue = values.defaultValue.map(d => (d as Moment).format(DEFAULT_VALUE_DATE_FORMAT), ); From 9bf6e750361a302a68ae2c97005fb17222f152db Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Tue, 4 Jan 2022 16:56:23 +0800 Subject: [PATCH 338/348] feat:update version to 1.0.0-beta.0 --- bin/migrations/migration.1.0.0-beta.0.sql | 2 ++ core/pom.xml | 2 +- data-providers/file-data-provider/pom.xml | 2 +- data-providers/http-data-provider/pom.xml | 2 +- data-providers/jdbc-data-provider/pom.xml | 2 +- data-providers/pom.xml | 2 +- pom.xml | 2 +- security/pom.xml | 2 +- server/pom.xml | 2 +- 9 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 bin/migrations/migration.1.0.0-beta.0.sql diff --git a/bin/migrations/migration.1.0.0-beta.0.sql b/bin/migrations/migration.1.0.0-beta.0.sql new file mode 100644 index 000000000..b6b0b9374 --- /dev/null +++ b/bin/migrations/migration.1.0.0-beta.0.sql @@ -0,0 +1,2 @@ +ALTER TABLE `datachart` + MODIFY COLUMN `config` mediumtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL AFTER `org_id`; \ No newline at end of file diff --git a/core/pom.xml b/core/pom.xml index 35a87ce37..11f2acdeb 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -5,7 +5,7 @@ datart-parent datart - 1.0.0-alpha.3 + 1.0.0-beta.0 4.0.0 diff --git a/data-providers/file-data-provider/pom.xml b/data-providers/file-data-provider/pom.xml index e3e1d310e..18ee29208 100644 --- a/data-providers/file-data-provider/pom.xml +++ b/data-providers/file-data-provider/pom.xml @@ -5,7 +5,7 @@ datart-parent datart - 1.0.0-alpha.3 + 1.0.0-beta.0 ../../pom.xml 4.0.0 diff --git a/data-providers/http-data-provider/pom.xml b/data-providers/http-data-provider/pom.xml index ccbd396f7..5a564262b 100644 --- a/data-providers/http-data-provider/pom.xml +++ b/data-providers/http-data-provider/pom.xml @@ -5,7 +5,7 @@ datart-parent datart - 1.0.0-alpha.3 + 1.0.0-beta.0 ../../pom.xml diff --git a/data-providers/jdbc-data-provider/pom.xml b/data-providers/jdbc-data-provider/pom.xml index 79328b2b5..8e5bdd357 100644 --- a/data-providers/jdbc-data-provider/pom.xml +++ b/data-providers/jdbc-data-provider/pom.xml @@ -5,7 +5,7 @@ datart-parent datart - 1.0.0-alpha.3 + 1.0.0-beta.0 ../../pom.xml 4.0.0 diff --git a/data-providers/pom.xml b/data-providers/pom.xml index 70030b755..950981ee4 100644 --- a/data-providers/pom.xml +++ b/data-providers/pom.xml @@ -5,7 +5,7 @@ datart-parent datart - 1.0.0-alpha.3 + 1.0.0-beta.0 4.0.0 diff --git a/pom.xml b/pom.xml index 1e53fb234..80540bca5 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ datart datart-parent pom - 1.0.0-alpha.3 + 1.0.0-beta.0 diff --git a/security/pom.xml b/security/pom.xml index b25195f13..d2acd004c 100644 --- a/security/pom.xml +++ b/security/pom.xml @@ -5,7 +5,7 @@ datart-parent datart - 1.0.0-alpha.3 + 1.0.0-beta.0 4.0.0 diff --git a/server/pom.xml b/server/pom.xml index 9f95f4f01..45ade66cd 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -5,7 +5,7 @@ datart-parent datart - 1.0.0-alpha.3 + 1.0.0-beta.0 4.0.0 From 1097cca603c3e5b7fe839ff15783e0da3d26c39c Mon Sep 17 00:00:00 2001 From: xieliuduo Date: Tue, 4 Jan 2022 15:57:51 +0800 Subject: [PATCH 339/348] fix: chartPreview task image --- .../SharePage/ChartPreviewBoardForShare.tsx | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/pages/SharePage/ChartPreviewBoardForShare.tsx b/frontend/src/app/pages/SharePage/ChartPreviewBoardForShare.tsx index 65bffa946..170bb6acb 100644 --- a/frontend/src/app/pages/SharePage/ChartPreviewBoardForShare.tsx +++ b/frontend/src/app/pages/SharePage/ChartPreviewBoardForShare.tsx @@ -41,6 +41,7 @@ import { updateFilterAndFetchDatasetForShare, } from './slice/thunks'; +const TitleHeight = 100; const ChartPreviewBoardForShare: FC<{ style?: CSSProperties; chartPreview?: ChartPreview; @@ -70,10 +71,15 @@ const ChartPreviewBoardForShare: FC<{ refreshMode: 'debounce', refreshRate: 500, }); + const { ref: controlRef, height: controlH = 0 } = + useResizeObserver({ + refreshMode: 'debounce', + refreshRate: 500, + }); const headlessBrowserRenderSign = useSelector( selectHeadlessBrowserRenderSign, ); - + console.log('+controlH', controlH); useMount(() => { if (!chartPreview) { return; @@ -148,11 +154,14 @@ const ChartPreviewBoardForShare: FC<{ allowShare allowDownload /> - +
+ +
+
); From 118d35035045901723ff732c5969a4c33b938217 Mon Sep 17 00:00:00 2001 From: xieliuduo Date: Tue, 4 Jan 2022 17:14:02 +0800 Subject: [PATCH 340/348] fix: board in task to image --- .../src/app/pages/SharePage/BoardForShare.tsx | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/pages/SharePage/BoardForShare.tsx b/frontend/src/app/pages/SharePage/BoardForShare.tsx index 1cbbeb85d..4a94fc328 100644 --- a/frontend/src/app/pages/SharePage/BoardForShare.tsx +++ b/frontend/src/app/pages/SharePage/BoardForShare.tsx @@ -38,7 +38,7 @@ import { OnLoadTasksType } from '../MainPage/Navbar/DownloadListPopup'; import { DownloadTask } from '../MainPage/slice/types'; import { DownloadTaskContainer } from './DownloadTaskContainer'; import { HeadlessBrowserIdentifier } from './HeadlessBrowserIdentifier'; - +const TitleHeight = 60; export interface ShareBoardProps { dashboard: Dashboard; renderMode: VizRenderMode; @@ -75,7 +75,24 @@ export const BoardForShare: React.FC = memo( }, [hasFetchItems, needFetchItems]); // for sever Browser - + const { taskW, taskH } = useMemo(() => { + const taskWH = { + taskW: 0, + taskH: 0, + }; + if (boardWidthHeight) { + taskWH.taskW = boardWidthHeight[0] || 0; + } + if (dashboard) { + if (dashboard?.config?.type === 'free') { + const { width, height } = dashboard.config; + const ratio = width / (height || 1) || 1; + const targetHeight = taskWH.taskW / ratio; + taskWH.taskH = targetHeight; + } + } + return taskWH; + }, [boardWidthHeight, dashboard]); const boardDownLoadAction = useCallback( (params: { boardId: string }) => async dispatch => { const { boardId } = params; @@ -135,8 +152,8 @@ export const BoardForShare: React.FC = memo( {viewBoard} ); From 60d10946abb6415888a719c7d7779b1ffc2b8f78 Mon Sep 17 00:00:00 2001 From: xieliuduo Date: Tue, 4 Jan 2022 17:15:00 +0800 Subject: [PATCH 341/348] chore: file rename ChartForShre --- .../{ChartPreviewBoardForShare.tsx => ChartForShare.tsx} | 5 ++--- frontend/src/app/pages/SharePage/SharePage.tsx | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) rename frontend/src/app/pages/SharePage/{ChartPreviewBoardForShare.tsx => ChartForShare.tsx} (98%) diff --git a/frontend/src/app/pages/SharePage/ChartPreviewBoardForShare.tsx b/frontend/src/app/pages/SharePage/ChartForShare.tsx similarity index 98% rename from frontend/src/app/pages/SharePage/ChartPreviewBoardForShare.tsx rename to frontend/src/app/pages/SharePage/ChartForShare.tsx index 170bb6acb..404d54ff0 100644 --- a/frontend/src/app/pages/SharePage/ChartPreviewBoardForShare.tsx +++ b/frontend/src/app/pages/SharePage/ChartForShare.tsx @@ -42,7 +42,7 @@ import { } from './slice/thunks'; const TitleHeight = 100; -const ChartPreviewBoardForShare: FC<{ +const ChartForShare: FC<{ style?: CSSProperties; chartPreview?: ChartPreview; filterSearchParams?: FilterSearchParams; @@ -79,7 +79,6 @@ const ChartPreviewBoardForShare: FC<{ const headlessBrowserRenderSign = useSelector( selectHeadlessBrowserRenderSign, ); - console.log('+controlH', controlH); useMount(() => { if (!chartPreview) { return; @@ -183,7 +182,7 @@ const ChartPreviewBoardForShare: FC<{ }, ); -export default ChartPreviewBoardForShare; +export default ChartForShare; const StyledChartPreviewBoard = styled.div` display: flex; diff --git a/frontend/src/app/pages/SharePage/SharePage.tsx b/frontend/src/app/pages/SharePage/SharePage.tsx index ed082254b..efa57e5fc 100644 --- a/frontend/src/app/pages/SharePage/SharePage.tsx +++ b/frontend/src/app/pages/SharePage/SharePage.tsx @@ -36,7 +36,7 @@ import { urlSearchTransfer } from '../MainPage/pages/VizPage/utils'; import { useStoryBoardSlice } from '../StoryBoardPage/slice'; import { selectShareStoryBoard } from '../StoryBoardPage/slice/selectors'; import BoardForShare from './BoardForShare'; -import ChartPreviewBoardForShare from './ChartPreviewBoardForShare'; +import ChartForShare from './ChartForShare'; import { DownloadTaskContainer } from './DownloadTaskContainer'; import PasswordModal from './PasswordModal'; import { downloadShareDataChartFile } from './sercive'; @@ -191,7 +191,7 @@ export function SharePage() { onLoadTasks={onLoadShareTask} onDownloadFile={onDownloadFile} > - From ee81e56ad29945b61d539ae895b9bea80b24a00f Mon Sep 17 00:00:00 2001 From: Stephen Cui <229063661@qq.com> Date: Tue, 4 Jan 2022 17:37:01 +0800 Subject: [PATCH 342/348] refactor(chart): add chart config i18n --- .../ChartGraph/BasicAreaChart/config.ts | 10 +-- .../ChartGraph/BasicBarChart/config.ts | 71 ++++++++++++++++++ .../ChartGraph/BasicFunnelChart/config.ts | 37 +++++++++ .../ChartGraph/BasicGaugeChart/config.ts | 61 +++++++++++++++ .../ChartGraph/BasicLineChart/config.ts | 62 +++++++++++++++ .../ChartGraph/BasicOutlineMapChart/config.ts | 43 +++++++++++ .../ChartGraph/BasicPieChart/config.ts | 42 +++++++++++ .../ChartGraph/BasicScatterChart/config.ts | 66 ++++++++++++++-- .../ChartGraph/ChartJSChart/config.ts | 10 ++- .../ChartGraph/ClusterBarChart/config.ts | 75 +++++++++++++++++++ .../ChartGraph/ClusterColumnChart/config.ts | 75 +++++++++++++++++++ .../ChartGraph/D3USMapChart/config.ts | 10 ++- .../NormalOutlineMapChart/config.ts | 43 +++++++++++ .../PercentageStackBarChart/config.ts | 71 ++++++++++++++++++ .../PercentageStackColumnChart/config.ts | 71 ++++++++++++++++++ .../ChartGraph/ReChartsChart/config.ts | 9 +++ .../ChartGraph/ReactVizXYPlotChart/config.ts | 10 ++- .../ChartGraph/RephaelPaperChart/config.ts | 9 +++ .../ScatterOutlineMapChart/config.ts | 43 +++++++++++ .../ChartGraph/ScoreChart/config.ts | 20 +++++ .../ChartGraph/StackBarChart/config.ts | 71 ++++++++++++++++++ .../ChartGraph/StackColumnChart/config.ts | 71 ++++++++++++++++++ .../ChartGraph/WaterfallChart/config.ts | 71 ++++++++++++++++++ .../ChartGraph/WordCloudChart/config.ts | 28 ++++++- 24 files changed, 1059 insertions(+), 20 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicAreaChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicAreaChart/config.ts index d9fac9092..7d737abec 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicAreaChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicAreaChart/config.ts @@ -123,16 +123,7 @@ const config: ChartConfig = { showLabelBySwitch: '显示标签2', showLabelByInput: '显示标签3', showLabelWithSelect: '显示标签4', - fontFamily: '字体', - fontSize: '字体大小', - fontColor: '字体颜色', - rotateLabel: '旋转标签', showDataColumns: '选择数据列', - legend: { - label: '图例', - showLabel: '图例-显示标签', - showLabel2: '图例-显示标签2', - }, }, }, { @@ -143,6 +134,7 @@ const config: ChartConfig = { showLabelBySwitch: 'Show Lable Switch', showLabelWithInput: 'Show Label Input', showLabelWithSelect: 'Show Label Select', + showDataColumns: 'Show Data Columns', }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/config.ts index 6c1d4ece6..ab639b619 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicBarChart/config.ts @@ -606,6 +606,77 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + common: { + showAxis: 'Show Axis', + inverseAxis: 'Inverse Axis', + lineStyle: 'Line Style', + borderStyle: 'Border Style', + borderType: 'Border Type', + borderWidth: 'Border Width', + borderColor: 'Border Color', + backgroundColor: 'Background Color', + showLabel: 'Show Label', + unitFont: 'Unit Font', + rotate: 'Rotate', + position: 'Position', + showInterval: 'Show Interval', + interval: 'Interval', + showTitleAndUnit: 'Show Title and Unit', + nameLocation: 'Name Location', + nameRotate: 'Name Rotate', + nameGap: 'Name Gap', + min: 'Min', + max: 'Max', + }, + label: { + title: 'Label', + showLabel: 'Show Label', + position: 'Position', + }, + legend: { + title: 'Legend', + showLegend: 'Show Legend', + type: 'Type', + selectAll: 'Select All', + position: 'Position', + }, + data: { + color: 'Color', + colorize: 'Colorize', + }, + stack: { + title: 'Stack', + enable: 'Enable', + percentage: 'Percentage', + enableTotal: 'Enable Total', + }, + bar: { + title: 'Bar Chart', + enable: 'Enable Horizon', + radius: 'Bar Radius', + width: 'Bar Width', + gap: 'Bar Gap', + }, + xAxis: { + title: 'X Axis', + }, + yAxis: { + title: 'Y Axis', + }, + splitLine: { + title: 'Splite Line', + showHorizonLine: 'Show Horizontal Line', + showVerticalLine: 'Show Vertical Line', + }, + reference: { + title: 'Reference Line', + open: 'Open', + }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/config.ts index 7fdb133e4..97a989b16 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicFunnelChart/config.ts @@ -295,6 +295,43 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + section: { + legend: 'Legend', + detail: 'Detail', + info: 'Info', + }, + label: { + title: 'Title', + showLabel: 'Show Label', + position: 'Position', + metric: 'Metric', + dimension: 'Dimension', + conversion: 'Conversion', + arrival: 'Arrival', + percentage: 'Percentage', + }, + legend: { + title: 'Legend', + showLegend: 'Show Legend', + type: 'Type', + selectAll: 'Select All', + position: 'Position', + }, + funnel: { + title: 'Funnel', + sort: 'Sort', + align: 'Alignment', + gap: 'Gap', + }, + data: { + color: 'Color', + colorize: 'Colorize', + }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/config.ts index 574706ee5..c97244579 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicGaugeChart/config.ts @@ -426,6 +426,67 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + common: { + detailOffsetLeft: 'Offset Left', + detailOffsetTop: 'Offset Top', + distance: 'Distance', + lineStyle: 'Line Style', + splitNumber: 'Split Number', + }, + gauge: { + title: 'Gauge', + max: 'Max', + prefix: 'Prefix', + suffix: 'Suffix', + radius: 'Radius', + startAngle: 'Start Angle', + endAngle: 'End Angle', + }, + label: { + title: 'Label', + showLabel: 'Show Label', + }, + data: { + title: 'Data', + showData: 'Show Data', + }, + pointer: { + title: 'Pointer', + showPointer: 'Show Pointer', + customPointerColor: 'Show Customize Pointer Color', + pointerColor: 'Pointer Color', + pointerLength: 'Pointer Length', + pointerWidth: 'Pointer Width', + lineStyle: 'Line Style', + }, + axis: { + title: 'Axis', + axisLineSize: 'Axis Line Size', + axisLineColor: 'Axis Line Color', + }, + axisTick: { + title: 'Axis Tick', + showAxisTick: 'Show Axis Tick', + }, + axisLabel: { + title: 'Axis Label', + showAxisLabel: 'Show Axis Label', + }, + progress: { + title: 'Progress', + showProgress: 'Show Progress', + roundCap: 'Round Cap', + }, + splitLine: { + title: 'Split Line', + showSplitLine: 'Show Split Line', + splitLineLength: 'Split Line Length', + }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicLineChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicLineChart/config.ts index 709e613e9..91ee0e8e6 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicLineChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicLineChart/config.ts @@ -518,6 +518,68 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + common: { + showAxis: 'Show Axis', + inverseAxis: 'Inverse Axis', + lineStyle: 'Line Style', + borderType: 'Border Type', + borderWidth: 'Border Width', + borderColor: 'Border Color', + backgroundColor: 'Background Color', + showLabel: 'Show Label', + unitFont: 'Unit Font', + rotate: 'Rotate', + position: 'Position', + showInterval: 'Show Interval', + interval: 'Interval', + showTitleAndUnit: 'Show Title and Unit', + nameLocation: 'Name Location', + nameRotate: 'Name Rotate', + nameGap: 'Name Gap', + min: 'Min', + max: 'Max', + }, + label: { + title: 'Label', + showLabel: 'Show Label', + position: 'Position', + }, + legend: { + title: 'Legend', + showLegend: 'Show Legend', + type: 'Type', + selectAll: 'Select All', + position: 'Position', + }, + data: { + color: 'Color', + colorize: 'Colorize', + }, + graph: { + title: 'Graph', + smooth: 'Smooth', + step: 'Step', + }, + xAxis: { + title: 'X Axis', + }, + yAxis: { + title: 'Y Axis', + }, + splitLine: { + title: 'Split Line', + showHorizonLine: 'Show Horizontal Line', + showVerticalLine: 'Show Vertical Line', + }, + reference: { + title: 'Reference', + open: 'Open', + }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicOutlineMapChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicOutlineMapChart/config.ts index 65aa8fbce..d96c31d8d 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicOutlineMapChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicOutlineMapChart/config.ts @@ -281,6 +281,49 @@ const config: ChartConfig = { background: { title: '背景设置' }, }, }, + { + lang: 'en-US', + translation: { + common: { + showAxis: 'Show Axis', + inverseAxis: 'Inverse Axis', + lineStyle: 'Line Style', + borderType: 'Border Type', + borderWidth: 'Border Width', + borderColor: 'Border Color', + backgroundColor: 'Background Color', + showLabel: 'Show Label', + unitFont: 'Unit Font', + rotate: 'Rotate', + position: 'Position', + showInterval: 'Show Interval', + interval: 'Interval', + showTitleAndUnit: 'Show Title and Unit', + nameLocation: 'Name Location', + nameRotate: 'Name Rotate', + nameGap: 'Name Gap', + min: 'Min', + max: 'Max', + }, + metricsAndColor: 'Metrics and Color', + label: { + title: 'Label', + showLabel: 'Show Label', + position: 'Position', + }, + map: { + title: 'Map', + level: 'Level', + enableZoom: 'Enabel Zoom', + backgroundColor: 'Background Color', + borderStyle: 'Border Style', + focusArea: 'Focus Area', + areaColor: 'Area Color', + areaEmphasisColor: 'Area Emphasis Color', + }, + background: { title: 'Background' }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts index df9ae1f2f..d30f16138 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicPieChart/config.ts @@ -265,6 +265,48 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + section: { + legend: 'Legend', + detail: 'Detail', + }, + common: { + showLabel: 'Show Label', + rotate: 'Rotate', + position: 'Position', + }, + pie: { + title: 'Pie', + circle: 'Circle', + roseType: 'Rose', + }, + label: { + title: 'Label', + showLabel: 'Show Label', + position: 'Position', + showName: 'Show Name', + showPercent: 'Show Percentage', + showValue: 'Show Value', + }, + legend: { + title: 'Legend', + showLegend: 'Show Legend', + type: 'Type', + selectAll: 'Select All', + position: 'Position', + }, + reference: { + title: 'Reference', + open: 'Open', + }, + tooltip: { + title: 'Tooltip', + showPercentage: 'Show Percentage', + }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/config.ts index 9923700f2..001c4987e 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/BasicScatterChart/config.ts @@ -533,11 +533,6 @@ const config: ChartConfig = { color: '颜色', colorize: '配色', }, - graph: { - title: '折线图', - smooth: '平滑', - step: '阶梯', - }, xAxis: { title: 'X轴', }, @@ -559,6 +554,67 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + common: { + showAxis: 'Show Axis', + inverseAxis: 'Inverse Axis', + lineStyle: 'Line Style', + borderType: 'Border Type', + borderWidth: 'Border Width', + borderColor: 'Border Color', + backgroundColor: 'Background Color', + showLabel: 'Show Label', + unitFont: 'Unit Font', + rotate: 'Rotate', + position: 'Position', + showInterval: 'Show Interval', + interval: 'Interval', + showTitleAndUnit: 'Show Title and Unit', + nameLocation: 'Name Location', + nameRotate: 'Name Rotate', + nameGap: 'Name Gap', + min: 'Min', + max: 'Max', + }, + label: { + title: 'Label', + showLabel: 'Show Label', + position: 'Position', + }, + legend: { + title: 'Legend', + showLegend: 'Show Legend', + type: 'Type', + selectAll: 'Select All', + position: 'Position', + }, + data: { + color: 'Color', + colorize: 'Colorize', + }, + xAxis: { + title: 'X Axis', + }, + yAxis: { + title: 'Y Axis', + }, + splitLine: { + title: 'Split Line', + showHorizonLine: 'Show Horizontal Line', + showVerticalLine: 'Show Vertical Line', + }, + reference: { + title: 'Reference', + open: 'Open', + }, + scatter: { + title: 'Scatter', + cycleRatio: 'Cycle Ratio', + }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ChartJSChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ChartJSChart/config.ts index f6864d5c0..50bdcfea2 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ChartJSChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ChartJSChart/config.ts @@ -135,7 +135,6 @@ const config: ChartConfig = { legend: { label: '图例', showLabel: '图例-显示标签', - showLabel2: '图例-显示标签2', }, }, }, @@ -147,6 +146,15 @@ const config: ChartConfig = { showLabelBySwitch: 'Show Lable Switch', showLabelWithInput: 'Show Label Input', showLabelWithSelect: 'Show Label Select', + fontFamily: 'Font Family', + fontSize: 'Font Size', + fontColor: 'Font Color', + rotateLabel: 'Rotate Label', + showDataColumns: 'Show Data Column', + legend: { + label: 'Legend', + showLabel: 'Show Legend', + }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterBarChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterBarChart/config.ts index a02b4471a..6a7e8e2f3 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterBarChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterBarChart/config.ts @@ -543,6 +543,81 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + common: { + showAxis: 'Show Axis', + inverseAxis: 'Inverse Axis', + lineStyle: 'Line Style', + borderStyle: 'Border Style', + borderType: 'Border Type', + borderWidth: 'Border Width', + borderColor: 'Border Color', + backgroundColor: 'Background Color', + showLabel: 'Show Label', + unitFont: 'Unit Font', + rotate: 'Rotate', + position: 'Position', + showInterval: 'Show Interval', + interval: 'Interval', + showTitleAndUnit: 'Show Title and Unit', + nameLocation: 'Name Location', + nameRotate: 'Name Rotate', + nameGap: 'Name Gap', + min: 'Min', + max: 'Max', + }, + label: { + title: 'Label', + showLabel: 'Show Label', + position: 'Position', + }, + legend: { + title: 'Legend', + showLegend: 'Show Legend', + type: 'Type', + selectAll: 'Select All', + position: 'Position', + }, + data: { + color: 'Color', + colorize: 'Colorize', + }, + stack: { + title: 'Stack', + enable: 'Enable', + percentage: 'Percentage', + enableTotal: 'Enable Total', + }, + bar: { + title: 'Bar Chart', + enable: 'Enable Horizon', + radius: 'Bar Radius', + width: 'Bar Width', + gap: 'Bar Gap', + }, + xAxis: { + title: 'X Axis', + }, + yAxis: { + title: 'Y Axis', + }, + splitLine: { + title: 'Splite Line', + showHorizonLine: 'Show Horizontal Line', + showVerticalLine: 'Show Vertical Line', + }, + reference: { + title: 'Reference Line', + open: 'Open', + }, + paging: { + title: 'Paging', + pageSize: 'Page Size', + }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterColumnChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterColumnChart/config.ts index a02b4471a..6a7e8e2f3 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterColumnChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ClusterColumnChart/config.ts @@ -543,6 +543,81 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + common: { + showAxis: 'Show Axis', + inverseAxis: 'Inverse Axis', + lineStyle: 'Line Style', + borderStyle: 'Border Style', + borderType: 'Border Type', + borderWidth: 'Border Width', + borderColor: 'Border Color', + backgroundColor: 'Background Color', + showLabel: 'Show Label', + unitFont: 'Unit Font', + rotate: 'Rotate', + position: 'Position', + showInterval: 'Show Interval', + interval: 'Interval', + showTitleAndUnit: 'Show Title and Unit', + nameLocation: 'Name Location', + nameRotate: 'Name Rotate', + nameGap: 'Name Gap', + min: 'Min', + max: 'Max', + }, + label: { + title: 'Label', + showLabel: 'Show Label', + position: 'Position', + }, + legend: { + title: 'Legend', + showLegend: 'Show Legend', + type: 'Type', + selectAll: 'Select All', + position: 'Position', + }, + data: { + color: 'Color', + colorize: 'Colorize', + }, + stack: { + title: 'Stack', + enable: 'Enable', + percentage: 'Percentage', + enableTotal: 'Enable Total', + }, + bar: { + title: 'Bar Chart', + enable: 'Enable Horizon', + radius: 'Bar Radius', + width: 'Bar Width', + gap: 'Bar Gap', + }, + xAxis: { + title: 'X Axis', + }, + yAxis: { + title: 'Y Axis', + }, + splitLine: { + title: 'Splite Line', + showHorizonLine: 'Show Horizontal Line', + showVerticalLine: 'Show Vertical Line', + }, + reference: { + title: 'Reference Line', + open: 'Open', + }, + paging: { + title: 'Paging', + pageSize: 'Page Size', + }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/D3USMapChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/D3USMapChart/config.ts index 3c4230fd6..3e0e53509 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/D3USMapChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/D3USMapChart/config.ts @@ -117,13 +117,10 @@ const config: ChartConfig = { showLabelWithSelect: '显示标签4', fontFamily: '字体', fontSize: '字体大小', - fontColor: '字体颜色', - rotateLabel: '旋转标签', showDataColumns: '选择数据列', legend: { label: '图例', showLabel: '图例-显示标签', - showLabel2: '图例-显示标签2', }, }, }, @@ -135,6 +132,13 @@ const config: ChartConfig = { showLabelBySwitch: 'Show Lable Switch', showLabelWithInput: 'Show Label Input', showLabelWithSelect: 'Show Label Select', + fontFamily: 'Font Family', + fontSize: 'Font Size', + showDataColumns: 'Show Data Columns', + legend: { + label: 'Legend', + showLabel: 'Show label', + }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/NormalOutlineMapChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/NormalOutlineMapChart/config.ts index 44db0abd6..31171589f 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/NormalOutlineMapChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/NormalOutlineMapChart/config.ts @@ -281,6 +281,49 @@ const config: ChartConfig = { background: { title: '背景设置' }, }, }, + { + lang: 'en-US', + translation: { + common: { + showAxis: 'Show Axis', + inverseAxis: 'Inverse Axis', + lineStyle: 'Line Style', + borderType: 'Border Type', + borderWidth: 'Border Width', + borderColor: 'Border Color', + backgroundColor: 'Background Color', + showLabel: 'Show Label', + unitFont: 'Unit Font', + rotate: 'Rotate', + position: 'Position', + showInterval: 'Show Interval', + interval: 'Interval', + showTitleAndUnit: 'Show Title and Unit', + nameLocation: 'Name Location', + nameRotate: 'Name Rotate', + nameGap: 'Name Gap', + min: 'Min', + max: 'Max', + }, + metricsAndColor: 'Metrics and Color', + label: { + title: 'Label', + showLabel: 'Show Label', + position: 'Position', + }, + map: { + title: 'Map', + level: 'Level', + enableZoom: 'Enabel Zoom', + backgroundColor: 'Background Color', + borderStyle: 'Border Style', + focusArea: 'Focus Area', + areaColor: 'Area Color', + areaEmphasisColor: 'Area Emphasis Color', + }, + background: { title: 'Background' }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackBarChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackBarChart/config.ts index 43baa55dc..92aeadfd9 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackBarChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackBarChart/config.ts @@ -533,6 +533,77 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + common: { + showAxis: 'Show Axis', + inverseAxis: 'Inverse Axis', + lineStyle: 'Line Style', + borderStyle: 'Border Style', + borderType: 'Border Type', + borderWidth: 'Border Width', + borderColor: 'Border Color', + backgroundColor: 'Background Color', + showLabel: 'Show Label', + unitFont: 'Unit Font', + rotate: 'Rotate', + position: 'Position', + showInterval: 'Show Interval', + interval: 'Interval', + showTitleAndUnit: 'Show Title and Unit', + nameLocation: 'Name Location', + nameRotate: 'Name Rotate', + nameGap: 'Name Gap', + min: 'Min', + max: 'Max', + }, + label: { + title: 'Label', + showLabel: 'Show Label', + position: 'Position', + }, + legend: { + title: 'Legend', + showLegend: 'Show Legend', + type: 'Type', + selectAll: 'Select All', + position: 'Position', + }, + data: { + color: 'Color', + colorize: 'Colorize', + }, + stack: { + title: 'Stack', + enable: 'Enable', + percentage: 'Percentage', + enableTotal: 'Enable Total', + }, + bar: { + title: 'Bar Chart', + enable: 'Enable Horizon', + radius: 'Bar Radius', + width: 'Bar Width', + gap: 'Bar Gap', + }, + xAxis: { + title: 'X Axis', + }, + yAxis: { + title: 'Y Axis', + }, + splitLine: { + title: 'Splite Line', + showHorizonLine: 'Show Horizontal Line', + showVerticalLine: 'Show Vertical Line', + }, + reference: { + title: 'Reference Line', + open: 'Open', + }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackColumnChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackColumnChart/config.ts index 43baa55dc..92aeadfd9 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackColumnChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PercentageStackColumnChart/config.ts @@ -533,6 +533,77 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + common: { + showAxis: 'Show Axis', + inverseAxis: 'Inverse Axis', + lineStyle: 'Line Style', + borderStyle: 'Border Style', + borderType: 'Border Type', + borderWidth: 'Border Width', + borderColor: 'Border Color', + backgroundColor: 'Background Color', + showLabel: 'Show Label', + unitFont: 'Unit Font', + rotate: 'Rotate', + position: 'Position', + showInterval: 'Show Interval', + interval: 'Interval', + showTitleAndUnit: 'Show Title and Unit', + nameLocation: 'Name Location', + nameRotate: 'Name Rotate', + nameGap: 'Name Gap', + min: 'Min', + max: 'Max', + }, + label: { + title: 'Label', + showLabel: 'Show Label', + position: 'Position', + }, + legend: { + title: 'Legend', + showLegend: 'Show Legend', + type: 'Type', + selectAll: 'Select All', + position: 'Position', + }, + data: { + color: 'Color', + colorize: 'Colorize', + }, + stack: { + title: 'Stack', + enable: 'Enable', + percentage: 'Percentage', + enableTotal: 'Enable Total', + }, + bar: { + title: 'Bar Chart', + enable: 'Enable Horizon', + radius: 'Bar Radius', + width: 'Bar Width', + gap: 'Bar Gap', + }, + xAxis: { + title: 'X Axis', + }, + yAxis: { + title: 'Y Axis', + }, + splitLine: { + title: 'Splite Line', + showHorizonLine: 'Show Horizontal Line', + showVerticalLine: 'Show Vertical Line', + }, + reference: { + title: 'Reference Line', + open: 'Open', + }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReChartsChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReChartsChart/config.ts index f6864d5c0..1257e9135 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReChartsChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReChartsChart/config.ts @@ -147,6 +147,15 @@ const config: ChartConfig = { showLabelBySwitch: 'Show Lable Switch', showLabelWithInput: 'Show Label Input', showLabelWithSelect: 'Show Label Select', + fontFamily: 'Font Family', + fontSize: 'Font Size', + fontColor: 'Font Color', + rotateLabel: 'Rotate Label', + showDataColumns: 'Show Data Columns', + legend: { + label: 'Legend', + showLabel: 'Show Label', + }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactVizXYPlotChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactVizXYPlotChart/config.ts index 702af2fad..0087e925f 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactVizXYPlotChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ReactVizXYPlotChart/config.ts @@ -136,7 +136,6 @@ const config: ChartConfig = { legend: { label: '图例', showLabel: '图例-显示标签', - showLabel2: '图例-显示标签2', }, }, }, @@ -148,6 +147,15 @@ const config: ChartConfig = { showLabelBySwitch: 'Show Lable Switch', showLabelWithInput: 'Show Label Input', showLabelWithSelect: 'Show Label Select', + fontFamily: 'Font Family', + fontSize: 'Font Size', + fontColor: 'Font Color', + rotateLabel: 'Rotate Label', + showDataColumns: 'Show Data Columns', + legend: { + label: 'Legend', + showLabel: 'Show Label', + }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/RephaelPaperChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/RephaelPaperChart/config.ts index f6864d5c0..1257e9135 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/RephaelPaperChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/RephaelPaperChart/config.ts @@ -147,6 +147,15 @@ const config: ChartConfig = { showLabelBySwitch: 'Show Lable Switch', showLabelWithInput: 'Show Label Input', showLabelWithSelect: 'Show Label Select', + fontFamily: 'Font Family', + fontSize: 'Font Size', + fontColor: 'Font Color', + rotateLabel: 'Rotate Label', + showDataColumns: 'Show Data Columns', + legend: { + label: 'Legend', + showLabel: 'Show Label', + }, }, }, ], diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScatterOutlineMapChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScatterOutlineMapChart/config.ts index 1b63bacb3..ae8c592b1 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScatterOutlineMapChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScatterOutlineMapChart/config.ts @@ -293,6 +293,49 @@ const config: ChartConfig = { background: { title: '背景设置' }, }, }, + { + lang: 'en-US', + translation: { + common: { + showAxis: 'Show Axis', + inverseAxis: 'Inverse Axis', + lineStyle: 'Line Style', + borderType: 'Border Type', + borderWidth: 'Border Width', + borderColor: 'Border Color', + backgroundColor: 'Background Color', + showLabel: 'Show Label', + unitFont: 'Unit Font', + rotate: 'Rotate', + position: 'Position', + showInterval: 'Show Interval', + interval: 'Interval', + showTitleAndUnit: 'Show Title and Unit', + nameLocation: 'Name Location', + nameRotate: 'Name Rotate', + nameGap: 'Name Gap', + min: 'Min', + max: 'Max', + }, + metricsAndColor: 'Metrics and Color', + label: { + title: 'Label', + showLabel: 'Show Label', + position: 'Position', + }, + map: { + title: 'Map', + level: 'Level', + enableZoom: 'Enabel Zoom', + backgroundColor: 'Background Color', + borderStyle: 'Border Style', + focusArea: 'Focus Area', + areaColor: 'Area Color', + areaEmphasisColor: 'Area Emphasis Color', + }, + background: { title: 'Background' }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScoreChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScoreChart/config.ts index 891aa79a7..10dabc4e6 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScoreChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/ScoreChart/config.ts @@ -289,6 +289,26 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + score: { + headerTitle: 'Header', + bodyTitle: 'Body', + footerTitle: 'Footer Title', + show: 'Show', + prefixText: 'Prefix Text', + suffixText: 'Suffix Text', + prefxFont: 'Prefix Font', + suffixFont: 'Suffix Font', + common: 'Common', + isFixedFontSize: 'Enable Fixed Font Size', + headerFontSize: 'Header Font Size', + bodyFontSize: 'Body Font Size', + footerFontSize: 'Footer Font Size', + }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackBarChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackBarChart/config.ts index 43baa55dc..187922acf 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackBarChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackBarChart/config.ts @@ -533,6 +533,77 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + common: { + showAxis: 'Show Axis', + inverseAxis: 'Inverse Axis', + lineStyle: 'Line Style', + borderStyle: 'Border Style', + borderType: 'Border Type', + borderWidth: 'Border Width', + borderColor: 'Border Color', + backgroundColor: 'Background Color', + showLabel: 'Show Label', + unitFont: 'Unit Font', + rotate: 'Rotate', + position: 'Position', + showInterval: 'Show Interval', + interval: 'Interval', + showTitleAndUnit: 'Show Title and Unit', + nameLocation: 'Name Location', + nameRotate: 'Name Rotate', + nameGap: 'Name Gap', + min: 'Min', + max: 'Max', + }, + label: { + title: 'Label', + showLabel: 'Show Label', + position: 'Position', + }, + legend: { + title: 'Legend', + showLegend: 'Show Legend', + type: 'Type', + selectAll: 'Select All', + position: 'Position', + }, + data: { + color: 'Color', + colorize: 'Colorize', + }, + stack: { + title: 'Stack', + enable: 'Enable', + percentage: 'Percentage', + enableTotal: 'Enable Total', + }, + bar: { + title: 'Bar Chart', + enable: 'Enable Horizon', + radius: 'Bar Radius', + width: 'Bar Width', + gap: 'Bar Gap', + }, + xAxis: { + title: 'X Axis', + }, + yAxis: { + title: 'Y Axis', + }, + splitLine: { + title: 'Splite Line', + showHorizonLine: 'Show Horizontal Line', + showVerticalLine: 'Show Vertical Line', + }, + reference: { + title: 'Reference Line', + open: 'Open', + }, + }, + } ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackColumnChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackColumnChart/config.ts index 43baa55dc..92aeadfd9 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackColumnChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/StackColumnChart/config.ts @@ -533,6 +533,77 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + common: { + showAxis: 'Show Axis', + inverseAxis: 'Inverse Axis', + lineStyle: 'Line Style', + borderStyle: 'Border Style', + borderType: 'Border Type', + borderWidth: 'Border Width', + borderColor: 'Border Color', + backgroundColor: 'Background Color', + showLabel: 'Show Label', + unitFont: 'Unit Font', + rotate: 'Rotate', + position: 'Position', + showInterval: 'Show Interval', + interval: 'Interval', + showTitleAndUnit: 'Show Title and Unit', + nameLocation: 'Name Location', + nameRotate: 'Name Rotate', + nameGap: 'Name Gap', + min: 'Min', + max: 'Max', + }, + label: { + title: 'Label', + showLabel: 'Show Label', + position: 'Position', + }, + legend: { + title: 'Legend', + showLegend: 'Show Legend', + type: 'Type', + selectAll: 'Select All', + position: 'Position', + }, + data: { + color: 'Color', + colorize: 'Colorize', + }, + stack: { + title: 'Stack', + enable: 'Enable', + percentage: 'Percentage', + enableTotal: 'Enable Total', + }, + bar: { + title: 'Bar Chart', + enable: 'Enable Horizon', + radius: 'Bar Radius', + width: 'Bar Width', + gap: 'Bar Gap', + }, + xAxis: { + title: 'X Axis', + }, + yAxis: { + title: 'Y Axis', + }, + splitLine: { + title: 'Splite Line', + showHorizonLine: 'Show Horizontal Line', + showVerticalLine: 'Show Vertical Line', + }, + reference: { + title: 'Reference Line', + open: 'Open', + }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WaterfallChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WaterfallChart/config.ts index 80838285a..d817e28bc 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WaterfallChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WaterfallChart/config.ts @@ -479,6 +479,77 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + common: { + showAxis: 'Show Axis', + inverseAxis: 'Inverse Axis', + lineStyle: 'Line Style', + borderStyle: 'Border Style', + borderType: 'Border Type', + borderWidth: 'Border Width', + borderColor: 'Border Color', + backgroundColor: 'Background Color', + showLabel: 'Show Label', + unitFont: 'Unit Font', + rotate: 'Rotate', + position: 'Position', + showInterval: 'Show Interval', + interval: 'Interval', + showTitleAndUnit: 'Show Title and Unit', + nameLocation: 'Name Location', + nameRotate: 'Name Rotate', + nameGap: 'Name Gap', + min: 'Min', + max: 'Max', + }, + label: { + title: 'Label', + showLabel: 'Show Label', + position: 'Position', + }, + legend: { + title: 'Legend', + showLegend: 'Show Legend', + type: 'Type', + selectAll: 'Select All', + position: 'Position', + }, + data: { + color: 'Color', + colorize: 'Colorize', + }, + stack: { + title: 'Stack', + enable: 'Enable', + percentage: 'Percentage', + enableTotal: 'Enable Total', + }, + bar: { + title: 'Bar Chart', + enable: 'Enable Horizon', + radius: 'Bar Radius', + width: 'Bar Width', + gap: 'Bar Gap', + }, + xAxis: { + title: 'X Axis', + }, + yAxis: { + title: 'Y Axis', + }, + splitLine: { + title: 'Splite Line', + showHorizonLine: 'Show Horizontal Line', + showVerticalLine: 'Show Vertical Line', + }, + reference: { + title: 'Reference Line', + open: 'Open', + }, + }, + }, ], }; diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WordCloudChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WordCloudChart/config.ts index 47b5b632c..0fcb4e280 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WordCloudChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/WordCloudChart/config.ts @@ -251,7 +251,7 @@ const config: ChartConfig = { label: { title: '标签', fontFamily: '字体', - fontWeight: '字号', + fontWeight: '字体粗细', maxFontSize: '字体最大值', minFontSize: '字体最小值', rotationRangeStart: '起始旋转角度', @@ -264,6 +264,32 @@ const config: ChartConfig = { }, }, }, + { + lang: 'en-US', + translation: { + wordCloud: { + title: 'Word Cloud', + shape: 'Shape', + drawOutOfBound: 'Boundary', + width: 'Width', + height: 'Height', + }, + label: { + title: 'Label', + fontFamily: 'Font Family', + fontWeight: 'Font Weight', + maxFontSize: 'Max Font Size', + minFontSize: 'Min Font Size', + rotationRangeStart: 'Start Rotation Range', + rotationRangeEnd: 'End Rotation Range', + rotationStep: 'Rotation Step', + gridSize: 'Grid Size', + focus: 'Focus', + textShadowBlur: 'Text Shadow Blur', + textShadowColor: 'Text Shadow Color', + }, + }, + }, ], }; From 4611f8c08e527d412ba34af2cbf90c39ec4f108e Mon Sep 17 00:00:00 2001 From: tianlei Date: Tue, 4 Jan 2022 17:52:21 +0800 Subject: [PATCH 343/348] fix:(Chart) fix table default pageSize --- .../components/ChartGraph/MingXiTableChart/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts index 82481fdcf..9a74a849c 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/MingXiTableChart/config.ts @@ -312,7 +312,7 @@ const config: ChartConfig = { { label: 'paging.pageSize', key: 'pageSize', - default: 20, + default: 100, comType: 'inputNumber', options: { needRefresh: true, From e53f89973810d3a0a1caa8767a35a99813d60a20 Mon Sep 17 00:00:00 2001 From: xieliuduo Date: Tue, 4 Jan 2022 17:55:57 +0800 Subject: [PATCH 344/348] fix: auto board task to send image --- frontend/src/app/pages/SharePage/BoardForShare.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/pages/SharePage/BoardForShare.tsx b/frontend/src/app/pages/SharePage/BoardForShare.tsx index 4a94fc328..dbfb04e14 100644 --- a/frontend/src/app/pages/SharePage/BoardForShare.tsx +++ b/frontend/src/app/pages/SharePage/BoardForShare.tsx @@ -77,12 +77,9 @@ export const BoardForShare: React.FC = memo( // for sever Browser const { taskW, taskH } = useMemo(() => { const taskWH = { - taskW: 0, - taskH: 0, + taskW: boardWidthHeight[0] || 0, + taskH: boardWidthHeight[1] || 0, }; - if (boardWidthHeight) { - taskWH.taskW = boardWidthHeight[0] || 0; - } if (dashboard) { if (dashboard?.config?.type === 'free') { const { width, height } = dashboard.config; From 8a322ec1f7898359163e752ebc1fe6b5bb387105 Mon Sep 17 00:00:00 2001 From: "761302945@qq.com" <761302945@qq.com> Date: Tue, 4 Jan 2022 18:01:58 +0800 Subject: [PATCH 345/348] fix: schedule job bug fix --- core/src/main/java/datart/core/common/WebUtils.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/datart/core/common/WebUtils.java b/core/src/main/java/datart/core/common/WebUtils.java index 35a9355d1..3ec3bafde 100644 --- a/core/src/main/java/datart/core/common/WebUtils.java +++ b/core/src/main/java/datart/core/common/WebUtils.java @@ -70,19 +70,19 @@ public static T screenShot(String url, OutputType outputType, int imageWi ExpectedCondition ConditionOfHeight = ExpectedConditions.presenceOfElementLocated(By.id("height")); wait.until(ExpectedConditions.and(ConditionOfSign, ConditionOfWidth, ConditionOfHeight)); - int contentWidth = Integer.parseInt(webDriver.findElement(By.id("width")).getAttribute("value")); + Double contentWidth = Double.parseDouble(webDriver.findElement(By.id("width")).getAttribute("value")); - int contentHeight = Integer.parseInt(webDriver.findElement(By.id("height")).getAttribute("value")); + Double contentHeight = Double.parseDouble(webDriver.findElement(By.id("height")).getAttribute("value")); if (imageWidth != contentWidth) { // scale the window - webDriver.manage().window().setSize(new Dimension(imageWidth, contentHeight)); + webDriver.manage().window().setSize(new Dimension(imageWidth, contentHeight.intValue())); Thread.sleep(1000); } // scale the window again - contentWidth = Integer.parseInt(webDriver.findElement(By.id("width")).getAttribute("value")); - contentHeight = Integer.parseInt(webDriver.findElement(By.id("height")).getAttribute("value")); - webDriver.manage().window().setSize(new Dimension(contentWidth, contentHeight)); + contentWidth = Double.parseDouble(webDriver.findElement(By.id("width")).getAttribute("value")); + contentHeight = Double.parseDouble(webDriver.findElement(By.id("height")).getAttribute("value")); + webDriver.manage().window().setSize(new Dimension(contentWidth.intValue(), contentHeight.intValue())); Thread.sleep(1000); TakesScreenshot screenshot = (TakesScreenshot) webDriver; From d60a5e4bab3f6f2d9608a06e5fc02d397a6c3f00 Mon Sep 17 00:00:00 2001 From: lyp000119 <2319460338@qq.com> Date: Tue, 4 Jan 2022 19:05:12 +0800 Subject: [PATCH 346/348] feat: You can press the control key to select multiple data views --- .../ChartDraggable/ChartDraggableSourceContainer.tsx | 2 +- .../src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts | 3 +++ .../components/SlideSetting/SettingItem/BasicSet/ColorSet.tsx | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableSourceContainer.tsx b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableSourceContainer.tsx index eb4f019b9..b4cb0176c 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableSourceContainer.tsx +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartDraggable/ChartDraggableSourceContainer.tsx @@ -178,7 +178,7 @@ export const ChartDraggableSourceContainer: FC< return ( { - onSelectionChange?.(colName, e.metaKey, e.shiftKey); + onSelectionChange?.(colName, e.metaKey || e.ctrlKey, e.shiftKey); }} ref={drag} className={styleClasses.join(' ')} diff --git a/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts b/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts index 838600ad5..71907a5b3 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/slice/workbenchSlice.ts @@ -505,14 +505,17 @@ const workbenchSlice = createSlice({ ? JSON.parse(payload.config) : CloneValueDeep(payload.config); backendChartConfig = backendChartConfig || {}; + if (backendChartConfig?.aggregation === undefined) { backendChartConfig.aggregation = true; } + state.backendChart = { ...payload, config: backendChartConfig, }; state.aggregation = backendChartConfig.aggregation; + const currentChart = ChartManager.instance().getById( backendChartConfig?.chartGraphId, ); diff --git a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ColorSet.tsx b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ColorSet.tsx index 35323fa13..91e434c88 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ColorSet.tsx +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/components/SlideSetting/SettingItem/BasicSet/ColorSet.tsx @@ -44,6 +44,7 @@ export const ColorSet: FC<{ export default ColorSet; const StyledWrap = styled.div` display: inline-block; + cursor: pointer; `; const StyledColorIcon = styled.span<{ color: string }>` font-size: 1.4em; From 13657246c29001914aa6811d58b5968fe5703aee Mon Sep 17 00:00:00 2001 From: scottsut Date: Tue, 4 Jan 2022 19:34:01 +0800 Subject: [PATCH 347/348] chore: change pivotsheet column & row config position --- .../components/ChartGraph/PivotSheetChart/config.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts index 3853ae05b..b28338fec 100644 --- a/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts +++ b/frontend/src/app/pages/ChartWorkbenchPage/components/ChartOperationPanel/components/ChartGraph/PivotSheetChart/config.ts @@ -21,16 +21,16 @@ import { ChartConfig } from 'app/types/ChartConfig'; const config: ChartConfig = { datas: [ { - label: 'datas.row', - key: 'row', + label: 'datas.column', + key: 'column', type: 'group', options: { sortable: { backendSort: false }, }, }, { - label: 'datas.column', - key: 'column', + label: 'datas.row', + key: 'row', type: 'group', options: { sortable: { backendSort: false }, From 6f9821aa7b3abde723df5589a03013089c7740cc Mon Sep 17 00:00:00 2001 From: scottsut Date: Tue, 4 Jan 2022 19:46:40 +0800 Subject: [PATCH 348/348] chore: update documents --- Deployment.md | 8 ++++---- README_zh.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Deployment.md b/Deployment.md index 41438a85d..527fe2704 100644 --- a/Deployment.md +++ b/Deployment.md @@ -12,7 +12,7 @@ title: 部署 - JDK 1.8+ - MySql5.7+ -- datart安装包(datart-server-1.0.0-alpha.3-install.zip) +- datart安装包(datart-server-1.0.0-beta.x-install.zip) - Mail Server (可选) - [ChromeWebDriver](https://chromedriver.chromium.org/) (可选) - Redis (可选) @@ -20,7 +20,7 @@ title: 部署 方式1 :解压安装包 (官方提供的包) ```bash -unzip datart-server-1.0.0-alpha.3-install.zip +unzip datart-server-1.0.0-beta.x-install.zip ``` 方式2 :自行编译 @@ -32,11 +32,11 @@ cd datart mvn clean package -Dmaven.test.skip=true -cp ./datart-server-1.0.0-alpha.3-install.zip ${deployment_basedir} +cp ./datart-server-1.0.0-beta.x-install.zip ${deployment_basedir} cd ${deployment_basedir} -unzip datart-server-1.0.0-alpha.3-install.zip +unzip datart-server-1.0.0-beta.x-install.zip ``` diff --git a/README_zh.md b/README_zh.md index 021653427..477ca58a8 100644 --- a/README_zh.md +++ b/README_zh.md @@ -42,7 +42,7 @@ datart 是新一代数据可视化开放平台,支持各类企业数据可视 参见 [User Guide](http://running-elephant.gitee.io/datart-docs/docs/source.html) ### 最新版本 Latest Release -参见 [Latest Release](https://gitee.com/running-elephant/datart/releases/1.0.0-alpha.3) +参见 [Latest Release](https://gitee.com/running-elephant/datart/releases) ## Community ### 社区支持 Support