Merge branch 'manuel-rw-gridstack' into gridstack-wip-meierschlumpf
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user