Merge branch 'manuel-rw-gridstack' into gridstack-wip-meierschlumpf

This commit is contained in:
Meierschlumpf
2023-01-07 17:59:43 +01:00
56 changed files with 962 additions and 785 deletions

View File

@@ -1,4 +1,15 @@
import { Alert, Button, Group, MultiSelect, Stack, Switch, TextInput, Text } from '@mantine/core';
import {
Alert,
Button,
Group,
MultiSelect,
Stack,
Switch,
TextInput,
Text,
NumberInput,
Slider,
} from '@mantine/core';
import { ContextModalProps } from '@mantine/modals';
import { IconAlertTriangle } from '@tabler/icons';
import { Trans, useTranslation } from 'next-i18next';
@@ -8,10 +19,12 @@ import type { IWidgetOptionValue } from '../../../../widgets/widgets';
import { useConfigContext } from '../../../../config/provider';
import { useConfigStore } from '../../../../config/store';
import { IWidget } from '../../../../widgets/widgets';
import { useColorTheme } from '../../../../tools/color';
export type WidgetEditModalInnerProps = {
widgetId: string;
options: IWidget<string, any>['properties'];
widgetOptions: IWidget<string, any>['properties'];
};
type IntegrationOptionsValueType = IWidget<string, any>['properties'][string];
@@ -23,7 +36,11 @@ export const WidgetsEditModal = ({
}: ContextModalProps<WidgetEditModalInnerProps>) => {
const { t } = useTranslation([`modules/${innerProps.widgetId}`, 'common']);
const [moduleProperties, setModuleProperties] = useState(innerProps.options);
const items = Object.entries(moduleProperties ?? {}) as [string, IntegrationOptionsValueType][];
// const items = Object.entries(moduleProperties ?? {}) as [string, IntegrationOptionsValueType][];
const items = Object.entries(innerProps.widgetOptions ?? {}) as [
string,
IntegrationOptionsValueType
][];
// Find the Key in the "Widgets" Object that matches the widgetId
const currentWidgetDefinition = Widgets[innerProps.widgetId as keyof typeof Widgets];
@@ -67,8 +84,9 @@ export const WidgetsEditModal = ({
return (
<Stack>
{items.map(([key, value], index) => {
{items.map(([key, defaultValue], index) => {
const option = (currentWidgetDefinition as any).options[key] as IWidgetOptionValue;
const value = moduleProperties[key] ?? defaultValue;
if (!option) {
return (
@@ -83,39 +101,15 @@ export const WidgetsEditModal = ({
</Alert>
);
}
switch (option.type) {
case 'switch':
return (
<Switch
key={`${option.type}-${index}`}
label={t(`descriptor.settings.${key}.label`)}
checked={value as boolean}
onChange={(ev) => handleChange(key, ev.currentTarget.checked)}
/>
);
case 'text':
return (
<TextInput
key={`${option.type}-${index}`}
label={t(`descriptor.settings.${key}.label`)}
value={value as string}
onChange={(ev) => handleChange(key, ev.currentTarget.value)}
/>
);
case 'multi-select':
return (
<MultiSelect
key={`${option.type}-${index}`}
data={getMutliselectData(key)}
label={t(`descriptor.settings.${key}.label`)}
value={value as string[]}
onChange={(v) => handleChange(key, v)}
/>
);
default:
return null;
}
return WidgetOptionTypeSwitch(
option,
index,
t,
key,
value,
handleChange,
getMutliselectData
);
})}
<Group position="right">
<Button onClick={() => context.closeModal(id)} variant="light">
@@ -126,3 +120,77 @@ export const WidgetsEditModal = ({
</Stack>
);
};
// Widget switch
// Widget options are computed based on their type.
// here you can define new types for options (along with editing the widgets.d.ts file)
function WidgetOptionTypeSwitch(
option: IWidgetOptionValue,
index: number,
t: any,
key: string,
value: string | number | boolean | string[],
handleChange: (key: string, value: IntegrationOptionsValueType) => void,
getMutliselectData: (option: string) => any
) {
const { primaryColor, secondaryColor } = useColorTheme();
switch (option.type) {
case 'switch':
return (
<Switch
key={`${option.type}-${index}`}
label={t(`descriptor.settings.${key}.label`)}
checked={value as boolean}
onChange={(ev) => handleChange(key, ev.currentTarget.checked)}
/>
);
case 'text':
return (
<TextInput
color={primaryColor}
key={`${option.type}-${index}`}
label={t(`descriptor.settings.${key}.label`)}
value={value as string}
onChange={(ev) => handleChange(key, ev.currentTarget.value)}
/>
);
case 'multi-select':
return (
<MultiSelect
color={primaryColor}
key={`${option.type}-${index}`}
data={getMutliselectData(key)}
label={t(`descriptor.settings.${key}.label`)}
value={value as string[]}
onChange={(v) => handleChange(key, v)}
/>
);
case 'number':
return (
<NumberInput
color={primaryColor}
key={`${option.type}-${index}`}
label={t(`descriptor.settings.${key}.label`)}
value={value as number}
onChange={(v) => handleChange(key, v!)}
/>
);
case 'slider':
return (
<Stack spacing="xs">
<Text>{t(`descriptor.settings.${key}.label`)}</Text>
<Slider
color={primaryColor}
key={`${option.type}-${index}`}
value={value as number}
min={option.min}
max={option.max}
step={option.step}
onChange={(v) => handleChange(key, v)}
/>
</Stack>
);
default:
return null;
}
}

View File

@@ -6,6 +6,7 @@ import { useWrapperColumnCount } from '../../Wrappers/gridstack/store';
import { GenericTileMenu } from '../GenericTileMenu';
import { WidgetEditModalInnerProps } from './WidgetsEditModal';
import { WidgetsRemoveModalInnerProps } from './WidgetsRemoveModal';
import WidgetsDefinitions from '../../../../widgets';
export type WidgetChangePositionModalInnerProps = {
widgetId: string;
@@ -23,6 +24,14 @@ export const WidgetsMenu = ({ integration, widget }: WidgetsMenuProps) => {
const wrapperColumnCount = useWrapperColumnCount();
if (!widget || !wrapperColumnCount) return null;
// 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 get the widget definition
const widgetDefinitionObject =
WidgetsDefinitions[widgetDefinition as keyof typeof WidgetsDefinitions];
const handleDeleteClick = () => {
openContextModalGeneric<WidgetsRemoveModalInnerProps>({
@@ -54,7 +63,10 @@ export const WidgetsMenu = ({ integration, widget }: WidgetsMenuProps) => {
innerProps: {
widgetId: integration,
options: widget.properties,
// Cast as the right type for the correct widget
widgetOptions: widgetDefinitionObject.options as any,
},
zIndex: 5,
});
};