diff --git a/frontend/src/app/migration/BoardConfig/migrateWidgetConfig.ts b/frontend/src/app/migration/BoardConfig/migrateWidgetConfig.ts new file mode 100644 index 000000000..69f8cee53 --- /dev/null +++ b/frontend/src/app/migration/BoardConfig/migrateWidgetConfig.ts @@ -0,0 +1,64 @@ +/** + * 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 { initTabsTpl } from 'app/pages/DashBoardPage/components/Widgets/TabWidget/tabConfig'; +import { ORIGINAL_TYPE_MAP } from 'app/pages/DashBoardPage/constants'; +import { Widget } from 'app/pages/DashBoardPage/types/widgetTypes'; +import { isEmptyArray } from 'utils/object'; +import { APP_VERSION_RC_1 } from '../constants'; +import MigrationEvent from '../MigrationEvent'; +import MigrationEventDispatcher from '../MigrationEventDispatcher'; + +export const RC1 = (widget?: Widget | any) => { + if (!widget) { + return widget; + } + if (widget?.config?.originalType !== ORIGINAL_TYPE_MAP.tab) { + return widget; + } + + try { + if ( + !isEmptyArray(widget?.config?.customConfig?.props) && + !widget?.config?.customConfig?.props?.find(p => p.key === 'tabGroup') + ) { + widget.config.customConfig.props = [initTabsTpl()].concat( + widget.config.customConfig.props, + ); + return widget; + } + } catch (error) { + console.error('Migration Widget Config Errors | RC.1 | ', error); + return widget; + } +}; + +const migrateWidgetConfig = (widgets: Widget[]): Widget[] => { + if (!Array.isArray(widgets)) { + return []; + } + return widgets + .map(widget => { + const event_rc_1 = new MigrationEvent(APP_VERSION_RC_1, RC1); + const dispatcher = new MigrationEventDispatcher(event_rc_1); + return dispatcher.process(widget as any); + }) + .filter(Boolean) as Widget[]; +}; + +export default migrateWidgetConfig; diff --git a/frontend/src/app/migration/__tests__/migrateWidgetConfig.test.ts b/frontend/src/app/migration/__tests__/migrateWidgetConfig.test.ts new file mode 100644 index 000000000..6b1db65ff --- /dev/null +++ b/frontend/src/app/migration/__tests__/migrateWidgetConfig.test.ts @@ -0,0 +1,245 @@ +/** + * 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 migrateWidgetConfig from '../BoardConfig/migrateWidgetConfig'; +import { APP_VERSION_RC_1 } from '../constants'; + +describe('Widget Config Migration Tests', () => { + describe('RC.1 Custom Tab Config', () => { + test('should return empty array if input is not an array', () => { + const inputWidget = '' as any; + const result = migrateWidgetConfig(inputWidget); + expect(result).toEqual([]); + }); + + test('should not migrate widget when name is not tab', () => { + const inputWidget = [ + { + config: { + name: 'w1', + originalType: 'linkedChart', + }, + }, + { + config: { + name: 'w2', + originalType: 'group', + }, + }, + ]; + const result = migrateWidgetConfig(inputWidget as any[]); + expect(result).toEqual(inputWidget); + }); + + test('should not migrate widget when custom props is empty', () => { + const inputWidget = [ + { + config: { + name: 'w1', + originalType: 'tab', + }, + }, + { + config: { + name: 'w2', + originalType: 'tab', + }, + }, + ]; + const result = migrateWidgetConfig(inputWidget as any[]); + expect(result).toEqual(inputWidget); + }); + + test('should not migrate widget when custom props is empty', () => { + const inputWidget = [ + { + config: { + name: 'w1', + originalType: 'tab', + customConfig: {}, + }, + }, + ]; + const result = migrateWidgetConfig(inputWidget as any[]); + expect(result?.[0]?.config?.customConfig).toEqual({}); + }); + + test('should not migrate widget when custom props has tab group', () => { + const inputWidget = [ + { + config: { + name: 'w1', + originalType: 'tab', + customConfig: { + props: [ + { + label: 'tab.tabGroup', + key: 'tabGroup', + comType: 'group', + rows: [], + }, + ], + }, + }, + }, + ]; + const result = migrateWidgetConfig(inputWidget as any[]); + expect(result?.[0]?.config?.customConfig?.props?.length).toBe(1); + expect(result?.[0]?.config?.customConfig?.props?.[0]).toEqual({ + label: 'tab.tabGroup', + key: 'tabGroup', + comType: 'group', + rows: [], + }); + }); + + test('should not migrate widget when custom props has tab group', () => { + const inputWidget = [ + { + config: { + name: 'w1', + originalType: 'tab', + customConfig: { + props: [ + { + label: 'tab.tabGroup', + key: 'tabGroup', + comType: 'group', + rows: [], + }, + ], + }, + }, + }, + ]; + const result = migrateWidgetConfig(inputWidget as any[]); + expect(result).toEqual(inputWidget); + }); + + test('should migrate widget when custom props has no tab group', () => { + const oldTabConfig = { + label: 'tab.alignTitle', + key: 'align', + default: 'start', + value: 'end', + comType: 'select', + options: { + translateItemLabel: true, + items: [ + { + label: 'viz.common.enum.alignment.start', + value: 'start', + }, + { + label: 'viz.common.enum.alignment.center', + value: 'center', + }, + { + label: 'viz.common.enum.alignment.end', + value: 'end', + }, + ], + }, + }; + const inputWidget = [ + { + config: { + name: 'w1', + originalType: 'tab', + customConfig: { + props: [ + { + label: 'tab.tabTitle', + key: 'tabTitle', + comType: 'group', + rows: [], + }, + ], + }, + }, + }, + { + config: { + name: 'w2', + originalType: 'tab', + customConfig: { + props: [ + { + label: 'tab.tabGroup', + key: 'tabGroup', + comType: 'group', + rows: [oldTabConfig], + }, + ], + }, + }, + }, + ]; + const result = migrateWidgetConfig(inputWidget as any[]); + expect((result?.[0] as any)?.version).toEqual(APP_VERSION_RC_1); + expect(result?.[0]?.config?.customConfig?.props?.length).toBe(2); + expect(result?.[0]?.config?.customConfig?.props?.[0]).toEqual({ + label: 'tab.tabGroup', + key: 'tabGroup', + comType: 'group', + rows: [ + { + label: 'tab.alignTitle', + key: 'align', + default: 'start', + value: 'start', + comType: 'select', + options: { + translateItemLabel: true, + items: [ + { label: 'viz.common.enum.alignment.start', value: 'start' }, + { label: 'viz.common.enum.alignment.center', value: 'center' }, + { label: 'viz.common.enum.alignment.end', value: 'end' }, + ], + }, + }, + { + label: 'tab.position', + key: 'position', + default: 'top', + value: 'top', + comType: 'select', + options: { + translateItemLabel: true, + items: [ + { label: 'viz.common.enum.position.top', value: 'top' }, + { label: 'viz.common.enum.position.bottom', value: 'bottom' }, + { label: 'viz.common.enum.position.left', value: 'left' }, + { label: 'viz.common.enum.position.right', value: 'right' }, + ], + }, + }, + ], + }); + expect(result?.[0]?.config?.customConfig?.props?.[1]).toEqual({ + label: 'tab.tabTitle', + key: 'tabTitle', + comType: 'group', + rows: [], + }); + expect(result?.[1]?.config?.customConfig?.props?.[0]?.rows).toEqual([ + oldTabConfig, + ]); + }); + }); +}); diff --git a/frontend/src/app/migration/constants.ts b/frontend/src/app/migration/constants.ts index 0b8092634..d7ddd869b 100644 --- a/frontend/src/app/migration/constants.ts +++ b/frontend/src/app/migration/constants.ts @@ -21,10 +21,11 @@ export const APP_VERSION_BETA_0 = '1.0.0-beta.0'; export const APP_VERSION_BETA_1 = '1.0.0-beta.1'; export const APP_VERSION_BETA_2 = '1.0.0-beta.2'; export const APP_VERSION_BETA_3 = '1.0.0-beta.3'; -export const APP_VERSION_BETA_4 = '1.0.0-beta.4'; // NEXT: 1.0.0-beta4+100 or 1.0.0-beta5 +export const APP_VERSION_BETA_4 = '1.0.0-beta.4'; export const APP_VERSION_BETA_4_1 = '1.0.0-beta.4+1'; export const APP_VERSION_BETA_4_2 = '1.0.0-beta.4+2'; export const APP_VERSION_RC_0 = '1.0.0-RC.0'; +export const APP_VERSION_RC_1 = '1.0.0-RC.1'; export const APP_SEMANTIC_VERSIONS = [ APP_VERSION_INIT, @@ -36,6 +37,7 @@ export const APP_SEMANTIC_VERSIONS = [ APP_VERSION_BETA_4_1, APP_VERSION_BETA_4_2, APP_VERSION_RC_0, + APP_VERSION_RC_1, ]; export const APP_CURRENT_VERSION = diff --git a/frontend/src/app/pages/DashBoardPage/components/Widgets/TabWidget/tabConfig.ts b/frontend/src/app/pages/DashBoardPage/components/Widgets/TabWidget/tabConfig.ts index 941154c53..27dc24108 100644 --- a/frontend/src/app/pages/DashBoardPage/components/Widgets/TabWidget/tabConfig.ts +++ b/frontend/src/app/pages/DashBoardPage/components/Widgets/TabWidget/tabConfig.ts @@ -98,7 +98,7 @@ export const widgetMeta: WidgetMeta = { ], }; -const initTabsTpl = () => { +export const initTabsTpl = () => { return { label: 'tab.tabGroup', key: 'tabGroup', @@ -108,6 +108,7 @@ const initTabsTpl = () => { label: 'tab.alignTitle', key: 'align', default: 'start', + value: 'start', comType: 'select', options: { translateItemLabel: true, @@ -122,6 +123,7 @@ const initTabsTpl = () => { label: 'tab.position', key: 'position', default: 'top', + value: 'top', comType: 'select', options: { translateItemLabel: true, 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 959179cd7..ca9a0fe38 100644 --- a/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts +++ b/frontend/src/app/pages/DashBoardPage/pages/BoardEditor/slice/thunk.ts @@ -1,4 +1,5 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; +import migrateWidgetConfig from 'app/migration/BoardConfig/migrateWidgetConfig'; import { migrateWidgets } from 'app/migration/BoardConfig/migrateWidgets'; import { ChartDataRequestBuilder } from 'app/models/ChartDataRequestBuilder'; import { @@ -113,7 +114,8 @@ export const fetchEditBoardDetail = createAsyncThunk< serverDataCharts, serverViews, ); - const migratedWidgets = migrateWidgets(serverWidgets, boardType); + let migratedWidgets = migrateWidgets(serverWidgets, boardType); + migratedWidgets = migrateWidgetConfig(migratedWidgets); const { widgetMap, wrappedDataCharts } = getWidgetMap( migratedWidgets, //todo dataCharts,