From 66f9dd51dd9637e55ee9589e3112799e92f5e308 Mon Sep 17 00:00:00 2001 From: Meier Lukas Date: Thu, 30 Mar 2023 21:46:59 +0200 Subject: [PATCH 1/9] =?UTF-8?q?=E2=9C=A8=20Add=20migration=20for=20multipl?= =?UTF-8?q?e=20widgets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tools/config/getConfig.ts | 28 ++++++++++++++++++++++++++-- src/tools/config/writeConfig.ts | 10 ++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 src/tools/config/writeConfig.ts diff --git a/src/tools/config/getConfig.ts b/src/tools/config/getConfig.ts index c17ee3881..3d6139a9f 100644 --- a/src/tools/config/getConfig.ts +++ b/src/tools/config/getConfig.ts @@ -1,9 +1,13 @@ import Consola from 'consola'; +import { v4 as uuidv4 } from 'uuid'; import { BackendConfigType, ConfigType } from '../../types/config'; import { backendMigrateConfig } from './backendMigrateConfig'; import { configExists } from './configExists'; import { getFallbackConfig } from './getFallbackConfig'; import { readConfig } from './readConfig'; +import { writeConfig } from './writeConfig'; + +const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/; export const getConfig = (name: string): BackendConfigType => { if (!configExists(name)) return getFallbackConfig() as unknown as ConfigType; @@ -12,9 +16,29 @@ export const getConfig = (name: string): BackendConfigType => { // to the new format. const config = readConfig(name); if (config.schemaVersion === undefined) { - Consola.log('Migrating config file...', config); + Consola.log('Migrating config file...', config.name); return backendMigrateConfig(config, name); } - return config; + let backendConfig = config as BackendConfigType; + + if (backendConfig.widgets.some((widget) => !uuidRegex.test(widget.id))) { + backendConfig = { + ...backendConfig, + widgets: backendConfig.widgets.map((widget) => ({ + ...widget, + id: uuidv4(), + type: widget.id, + })), + }; + + Consola.log( + 'Migrating config file to multiple widgets...', + backendConfig.configProperties.name + ); + + writeConfig(backendConfig); + } + + return backendConfig; }; diff --git a/src/tools/config/writeConfig.ts b/src/tools/config/writeConfig.ts new file mode 100644 index 000000000..5d57d9d03 --- /dev/null +++ b/src/tools/config/writeConfig.ts @@ -0,0 +1,10 @@ +import fs from 'fs'; +import { BackendConfigType } from '../../types/config'; +import { generateConfigPath } from './generateConfigPath'; + +export function writeConfig(config: BackendConfigType) { + const path = generateConfigPath(config.configProperties.name); + return fs.writeFileSync(path, JSON.stringify(config, null, 4), { + encoding: 'utf8', + }); +} From 43dc1cd70c2fcf3d47539f7315290f3e49acb78d Mon Sep 17 00:00:00 2001 From: Meier Lukas Date: Thu, 30 Mar 2023 21:54:44 +0200 Subject: [PATCH 2/9] =?UTF-8?q?=E2=9C=A8=20Change=20rendering=20from=20id?= =?UTF-8?q?=20to=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Dashboard/Wrappers/WrapperContent.tsx | 7 ++++--- src/widgets/WidgetWrapper.tsx | 6 +++--- src/widgets/widgets.ts | 3 ++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/components/Dashboard/Wrappers/WrapperContent.tsx b/src/components/Dashboard/Wrappers/WrapperContent.tsx index 1d1d3ad87..6eff1f62c 100644 --- a/src/components/Dashboard/Wrappers/WrapperContent.tsx +++ b/src/components/Dashboard/Wrappers/WrapperContent.tsx @@ -42,17 +42,18 @@ export function WrapperContent({ apps, refs, widgets }: WrapperContentProps) { ); })} {widgets.map((widget) => { - const definition = Widgets[widget.id as keyof typeof Widgets] as + const definition = Widgets[widget.type as keyof typeof Widgets] as | IWidgetDefinition | undefined; if (!definition) return null; + console.log(definition); return ( diff --git a/src/widgets/WidgetWrapper.tsx b/src/widgets/WidgetWrapper.tsx index 457890537..b8fa03ced 100644 --- a/src/widgets/WidgetWrapper.tsx +++ b/src/widgets/WidgetWrapper.tsx @@ -6,7 +6,7 @@ import ErrorBoundary from './boundary'; import { IWidget } from './widgets'; interface WidgetWrapperProps { - widgetId: string; + widgetType: string; widget: IWidget; className: string; WidgetComponent: ComponentType<{ widget: IWidget }>; @@ -14,7 +14,7 @@ interface WidgetWrapperProps { // If a property has no value, set it to the default value const useWidget = >(widget: T): T => { - const definition = Widgets[widget.id as keyof typeof Widgets]; + const definition = Widgets[widget.type as keyof typeof Widgets]; return useMemo(() => { const newProps = { ...widget.properties }; @@ -33,7 +33,7 @@ const useWidget = >(widget: T): T => { }; export const WidgetWrapper = ({ - widgetId, + widgetType: widgetId, widget, className, WidgetComponent, diff --git a/src/widgets/widgets.ts b/src/widgets/widgets.ts index d6559ed25..998413fea 100644 --- a/src/widgets/widgets.ts +++ b/src/widgets/widgets.ts @@ -13,7 +13,8 @@ import { ShapeType } from '../types/shape'; // Type of widgets which are saved to config export type IWidget = { - id: TKey; + id: string; + type: TKey; properties: { [key in keyof TDefinition['options']]: MakeLessSpecific< TDefinition['options'][key]['defaultValue'] From 525985b1dcbdc94f162b8447e9f4985700b10c1b Mon Sep 17 00:00:00 2001 From: Meier Lukas Date: Thu, 30 Mar 2023 22:20:56 +0200 Subject: [PATCH 3/9] =?UTF-8?q?=E2=9C=A8=20Migrate=20tiles=20from=20id=20t?= =?UTF-8?q?o=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChangeWidgetPositionModal.tsx | 11 +++++--- .../WidgetsTab/AvailableWidgetsTab.tsx | 10 +++---- .../WidgetsTab/WidgetElementType.tsx | 6 +++-- .../Tiles/Widgets/WidgetsEditModal.tsx | 18 ++++++++----- .../Dashboard/Tiles/Widgets/WidgetsMenu.tsx | 27 +++++-------------- .../Tiles/Widgets/WidgetsRemoveModal.tsx | 8 +++--- src/modules/common/MediaDisplay.tsx | 2 +- src/pages/api/modules/calendar.ts | 2 +- src/pages/api/modules/dashdot/info.ts | 2 +- src/pages/api/modules/dashdot/storage.ts | 2 +- src/pages/api/modules/rss/index.ts | 2 +- src/tools/config/migrateConfig.ts | 21 ++++++++++----- src/widgets/WidgetWrapper.tsx | 4 +-- src/widgets/dashDot/DashDotCompactStorage.tsx | 2 +- 14 files changed, 59 insertions(+), 58 deletions(-) diff --git a/src/components/Dashboard/Modals/ChangePosition/ChangeWidgetPositionModal.tsx b/src/components/Dashboard/Modals/ChangePosition/ChangeWidgetPositionModal.tsx index 241503adb..439460cfa 100644 --- a/src/components/Dashboard/Modals/ChangePosition/ChangeWidgetPositionModal.tsx +++ b/src/components/Dashboard/Modals/ChangePosition/ChangeWidgetPositionModal.tsx @@ -28,7 +28,7 @@ export const ChangeWidgetPositionModal = ({ updateConfig( configName, (prev) => { - const currentWidget = prev.widgets.find((x) => x.id === innerProps.widgetId); + const currentWidget = prev.widgets.find((x) => x.type === innerProps.widgetType); currentWidget!.shape[shapeSize] = { location: { x, @@ -42,7 +42,10 @@ export const ChangeWidgetPositionModal = ({ return { ...prev, - widgets: [...prev.widgets.filter((x) => x.id !== innerProps.widgetId), currentWidget!], + widgets: [ + ...prev.widgets.filter((x) => x.type !== innerProps.widgetType), + currentWidget!, + ], }; }, true @@ -54,8 +57,8 @@ export const ChangeWidgetPositionModal = ({ closeModal(id); }; - const widthData = useWidthData(innerProps.widgetId); - const heightData = useHeightData(innerProps.widgetId); + const widthData = useWidthData(innerProps.widgetType); + const heightData = useHeightData(innerProps.widgetType); return ( { const { t } = useTranslation('layout/element-selector/selector'); - const activeWidgets = useConfigContext().config?.widgets ?? []; return ( <> @@ -23,11 +21,9 @@ export const AvailableIntegrationElements = ({ - {Object.entries(widgets) - .filter(([widgetId]) => !activeWidgets.some((aw) => aw.id === widgetId)) - .map(([k, v]) => ( - - ))} + {Object.entries(widgets).map(([k, v]) => ( + + ))} ); diff --git a/src/components/Dashboard/Modals/SelectElement/Components/WidgetsTab/WidgetElementType.tsx b/src/components/Dashboard/Modals/SelectElement/Components/WidgetsTab/WidgetElementType.tsx index ce3a2b708..8ff521b09 100644 --- a/src/components/Dashboard/Modals/SelectElement/Components/WidgetsTab/WidgetElementType.tsx +++ b/src/components/Dashboard/Modals/SelectElement/Components/WidgetsTab/WidgetElementType.tsx @@ -2,6 +2,7 @@ import { useModals } from '@mantine/modals'; import { showNotification } from '@mantine/notifications'; import { IconChecks, TablerIcon } from '@tabler/icons'; import { useTranslation } from 'next-i18next'; +import { v4 as uuidv4 } from 'uuid'; import { useConfigContext } from '../../../../../../config/provider'; import { useConfigStore } from '../../../../../../config/store'; import { IWidget, IWidgetDefinition } from '../../../../../../widgets/widgets'; @@ -32,9 +33,10 @@ export const WidgetElementType = ({ id, image, disabled, widget }: WidgetElement (prev) => ({ ...prev, widgets: [ - ...prev.widgets.filter((w) => w.id !== widget.id), + ...prev.widgets, { - id: widget.id, + id: uuidv4(), + type: widget.id, properties: Object.entries(widget.options).reduce((prev, [k, v]) => { const newPrev = prev; newPrev[k] = v.defaultValue; diff --git a/src/components/Dashboard/Tiles/Widgets/WidgetsEditModal.tsx b/src/components/Dashboard/Tiles/Widgets/WidgetsEditModal.tsx index f58f30750..f92409919 100644 --- a/src/components/Dashboard/Tiles/Widgets/WidgetsEditModal.tsx +++ b/src/components/Dashboard/Tiles/Widgets/WidgetsEditModal.tsx @@ -25,7 +25,7 @@ import { IWidget } from '../../../../widgets/widgets'; import { DraggableList } from './DraggableList'; export type WidgetEditModalInnerProps = { - widgetId: string; + widgetType: string; options: IWidget['properties']; widgetOptions: IWidget['properties']; }; @@ -37,7 +37,8 @@ export const WidgetsEditModal = ({ id, innerProps, }: ContextModalProps) => { - const { t } = useTranslation([`modules/${innerProps.widgetId}`, 'common']); + console.log('?'); + const { t } = useTranslation([`modules/${innerProps.widgetType}`, 'common']); const [moduleProperties, setModuleProperties] = useState(innerProps.options); const items = Object.entries(innerProps.widgetOptions ?? {}) as [ string, @@ -45,7 +46,7 @@ export const WidgetsEditModal = ({ ][]; // Find the Key in the "Widgets" Object that matches the widgetId - const currentWidgetDefinition = Widgets[innerProps.widgetId as keyof typeof Widgets]; + const currentWidgetDefinition = Widgets[innerProps.widgetType as keyof typeof Widgets]; const { name: configName } = useConfigContext(); const updateConfig = useConfigStore((x) => x.updateConfig); @@ -63,12 +64,15 @@ export const WidgetsEditModal = ({ updateConfig( configName, (prev) => { - const currentWidget = prev.widgets.find((x) => x.id === innerProps.widgetId); + const currentWidget = prev.widgets.find((x) => x.type === innerProps.widgetType); currentWidget!.properties = moduleProperties; return { ...prev, - widgets: [...prev.widgets.filter((x) => x.id !== innerProps.widgetId), currentWidget!], + widgets: [ + ...prev.widgets.filter((x) => x.type !== innerProps.widgetType), + currentWidget!, + ], }; }, true @@ -76,6 +80,8 @@ export const WidgetsEditModal = ({ context.closeModal(id); }; + console.log('??'); + return ( {items.map(([key, _], index) => { @@ -100,7 +106,7 @@ export const WidgetsEditModal = ({ ; wrapperColumnCount: number; }; @@ -27,8 +27,8 @@ export const WidgetsMenu = ({ integration, widget }: WidgetsMenuProps) => { // Match widget.id with WidgetsDefinitions // First get the keys const keys = Object.keys(WidgetsDefinitions); - // Then find the key that matches the widget.id - const widgetDefinition = keys.find((key) => key === widget.id); + // Then find the key that matches the widget.type + const widgetDefinition = keys.find((key) => key === widget.type); // Then get the widget definition const widgetDefinitionObject = WidgetsDefinitions[widgetDefinition as keyof typeof WidgetsDefinitions]; @@ -38,7 +38,7 @@ export const WidgetsMenu = ({ integration, widget }: WidgetsMenuProps) => { modal: 'integrationRemove', title: {t('common:remove')}, innerProps: { - widgetId: integration, + widgetType: integration, }, styles: { inner: { @@ -55,37 +55,24 @@ export const WidgetsMenu = ({ integration, widget }: WidgetsMenuProps) => { size: 'xl', title: null, innerProps: { - widgetId: integration, + widgetType: integration, widget, wrapperColumnCount, }, - styles: { - inner: { - position: 'sticky', - top: 30, - }, - }, }); }; const handleEditClick = () => { openContextModalGeneric({ modal: 'integrationOptions', - title: {t('descriptor.settings.title')}, + title: t('descriptor.settings.title'), innerProps: { - widgetId: integration, + widgetType: integration, options: widget.properties, // Cast as the right type for the correct widget widgetOptions: widgetDefinitionObject.options as any, }, zIndex: 5, - styles: { - inner: { - position: 'sticky', - top: 30, - maxHeight: '100%', - }, - }, }); }; diff --git a/src/components/Dashboard/Tiles/Widgets/WidgetsRemoveModal.tsx b/src/components/Dashboard/Tiles/Widgets/WidgetsRemoveModal.tsx index f92e34380..336bb1034 100644 --- a/src/components/Dashboard/Tiles/Widgets/WidgetsRemoveModal.tsx +++ b/src/components/Dashboard/Tiles/Widgets/WidgetsRemoveModal.tsx @@ -6,7 +6,7 @@ import { useConfigContext } from '../../../../config/provider'; import { useConfigStore } from '../../../../config/store'; export type WidgetsRemoveModalInnerProps = { - widgetId: string; + widgetType: string; }; export const WidgetsRemoveModal = ({ @@ -14,7 +14,7 @@ export const WidgetsRemoveModal = ({ id, innerProps, }: ContextModalProps) => { - const { t } = useTranslation([`modules/${innerProps.widgetId}`, 'common']); + const { t } = useTranslation([`modules/${innerProps.widgetType}`, 'common']); const { name: configName } = useConfigContext(); if (!configName) return null; const updateConfig = useConfigStore((x) => x.updateConfig); @@ -23,7 +23,7 @@ export const WidgetsRemoveModal = ({ configName, (prev) => ({ ...prev, - widgets: prev.widgets.filter((w) => w.id !== innerProps.widgetId), + widgets: prev.widgets.filter((w) => w.type !== innerProps.widgetType), }), true ); @@ -35,7 +35,7 @@ export const WidgetsRemoveModal = ({ ]} - values={{ item: innerProps.widgetId }} + values={{ item: innerProps.widgetType }} /> ), diff --git a/src/widgets/rss/RssWidgetTile.tsx b/src/widgets/rss/RssWidgetTile.tsx index fb25026d0..b1eab57cd 100644 --- a/src/widgets/rss/RssWidgetTile.tsx +++ b/src/widgets/rss/RssWidgetTile.tsx @@ -1,5 +1,3 @@ -import { defineWidget } from '../helper'; -import { IWidget } from '../widgets'; import { ActionIcon, Badge, @@ -31,6 +29,8 @@ import dayjs from 'dayjs'; import { useTranslation } from 'next-i18next'; import Link from 'next/link'; import { useState } from 'react'; +import { IWidget } from '../widgets'; +import { defineWidget } from '../helper'; const definition = defineWidget({ id: 'rss',