diff --git a/apps/yadoms-cs/src/app/app-shell/main-app-shell.tsx b/apps/yadoms-cs/src/app/app-shell/main-app-shell.tsx index 97f7d396..c2f3557a 100644 --- a/apps/yadoms-cs/src/app/app-shell/main-app-shell.tsx +++ b/apps/yadoms-cs/src/app/app-shell/main-app-shell.tsx @@ -92,6 +92,9 @@ const useStyles = createStyles((theme) => ({ display: 'none', }, }, + logoBorder: { + borderBottom: '0.0625rem solid #2C2E33', + }, })); interface NavbarLinkProps { @@ -170,10 +173,12 @@ function MainAppShell() { -
+
diff --git a/libs/domain/plugins/src/lib/service/plugin-form.service.spec.ts b/libs/domain/plugins/src/lib/service/plugin-form.service.spec.ts index 04449b63..9d36831e 100644 --- a/libs/domain/plugins/src/lib/service/plugin-form.service.spec.ts +++ b/libs/domain/plugins/src/lib/service/plugin-form.service.spec.ts @@ -1,5 +1,9 @@ import { PluginConfigurationSchemaType } from '../model/plugin-configuration-schema.model'; -import { getInitialValues, InitialValues } from './plugin-form.service'; +import { + getInitialValues, + getInitialValuesFromSectionFields, + InitialValues, +} from './plugin-form.service'; describe('Plugin form store', () => { describe(`setup the correct form`, () => { @@ -274,3 +278,82 @@ describe('Plugin form store', () => { }); }); }); +describe(`getInitialValuesFromSectionFields`, () => { + // TODO: combo section with one content + test(`for comboSection`, () => { + getInitialValuesFromSectionFields( + [ + { + key: 'APIKey', + path: 'configuration.APIKey', + field: { + type: 'string', + required: true, + regex: '[a-zA-Z0-9]{64}', + name: "Clé d'API", + description: + 'Cette clé est nécessaire pour le fonctionnement de votre plugin. Elle peut être obtenue sur simple inscription (gratuite) au [Lametric](https://developer.lametric.com/user/devices).', + regexErrorMessage: "Ce n'est pas une API KEY valide", + }, + }, + { + key: 'PairingMode', + path: 'configuration.PairingMode', + field: { + type: 'comboSection', + content: { + Automatic: { + name: 'Appairage automatique', + type: 'section', + content: { + Port: { + type: 'enum', + values: { + Http: 8080, + Https: 4343, + }, + defaultValue: 'Https', + name: 'Port', + description: + 'Le port de communication de Lametric (exemple Http: 8080, Https: 4343)', + }, + }, + description: + 'Appairage automatique en utilisant le protocole UPNP', + }, + Manual: { + name: 'Appairage manuel', + type: 'section', + content: { + IPAddress: { + type: 'string', + regex: '^(?:[0-9]{1,3}\\.){3}[0-9]{1,3}$', + required: true, + name: 'Adresse IP', + description: "L'adresse IP du module", + regexErrorMessage: "Ce n'est pas une adresse IP valide", + }, + Port: { + type: 'enum', + values: { + Http: 8080, + Https: 4343, + }, + defaultValue: 'Https', + name: 'Port', + description: + 'Le port de communication de Lametric (exemple Http: 8080, Https: 4343)', + }, + }, + description: 'Appairage manuel', + }, + }, + name: "Mode d'appairage", + }, + }, + ], + '', + '' + ); + }); +}); diff --git a/libs/domain/plugins/src/lib/service/plugin-form.service.ts b/libs/domain/plugins/src/lib/service/plugin-form.service.ts index 575be832..63dff310 100644 --- a/libs/domain/plugins/src/lib/service/plugin-form.service.ts +++ b/libs/domain/plugins/src/lib/service/plugin-form.service.ts @@ -1,6 +1,10 @@ import { + EnumField, PluginConfigurationSchema, + PluginConfigurationSchemaField, PluginConfigurationSchemaType, + PluginMultiSelectSectionConfigurationSchema, + PluginSectionConfigurationSchema, } from '../model/plugin-configuration-schema.model'; export interface InitialValues { @@ -8,6 +12,7 @@ export interface InitialValues { displayName: string; configurationSchema: PluginConfigurationSchema; } + export const getInitialValues = (initialValues: InitialValues) => { return { type: initialValues.type, @@ -15,8 +20,10 @@ export const getInitialValues = (initialValues: InitialValues) => { configuration: getFromInitialValues(initialValues.configurationSchema), }; }; -const getFromInitialValues = ( - configurationSchema: PluginConfigurationSchema +export const getFromInitialValues = ( + configurationSchema: + | PluginConfigurationSchema + | PluginMultiSelectSectionConfigurationSchema ): Record => { const newInitialValues: Record = {}; @@ -38,7 +45,7 @@ const getFromInitialValues = ( newInitialValues[key] = field.defaultValue ?? 0.0; break; case PluginConfigurationSchemaType.Enum: - newInitialValues[key] = field.defaultValue; + newInitialValues[key] = getEnumDefaultValue(field); break; case PluginConfigurationSchemaType.Section: newInitialValues[key] = { @@ -59,10 +66,118 @@ const getFromInitialValues = ( }; } break; + case PluginConfigurationSchemaType.CheckboxSection: + sectionKeys = Object.keys(field.content || {}); + if (sectionKeys.length > 0) { + newInitialValues[key] = { + content: getFromInitialValues(field.content || {}), + checkbox: field.defaultValue, + }; + } else { + newInitialValues[key] = { + content: getFromInitialValues(field.content || {}), + }; + } + break; + case PluginConfigurationSchemaType.MultiSelectSection: + newInitialValues[key] = { + content: getFromInitialValues(field.content || {}), + }; + break; default: break; } } + return newInitialValues; +}; +export const getFromInitialValuesTest = ( + configurationSchema: + | PluginConfigurationSchema + | PluginSectionConfigurationSchema + | PluginMultiSelectSectionConfigurationSchema, + parentKey = 'configuration' +): Array<{ + key: string; + path: string; + field: PluginConfigurationSchemaField; +}> => { + const newInitialValues: Array<{ + key: string; + path: string; + field: PluginConfigurationSchemaField; + }> = []; + for (const [key, field] of Object.entries(configurationSchema)) { + const path = parentKey ? `${parentKey}.${key}` : key; + + switch (field?.type) { + case PluginConfigurationSchemaType.Enum: + case PluginConfigurationSchemaType.String: + case PluginConfigurationSchemaType.CustomTime: + case PluginConfigurationSchemaType.Boolean: + case PluginConfigurationSchemaType.Decimal: + case PluginConfigurationSchemaType.Integer: + newInitialValues.push({ key: key, path: path, field: field }); + break; + case PluginConfigurationSchemaType.Section: + case PluginConfigurationSchemaType.ComboSection: + case PluginConfigurationSchemaType.RadioSection: + case PluginConfigurationSchemaType.CheckboxSection: + case PluginConfigurationSchemaType.MultiSelectSection: + newInitialValues.push({ key: key, path: path, field: field }); + break; + default: + } + } + return newInitialValues; +}; + +export const getInitialValuesFromSectionFields = ( + configurationSchema: + | PluginSectionConfigurationSchema + | PluginMultiSelectSectionConfigurationSchema, + parentKey = '', + selectedKey: string +): Array<{ + key: string; + path: string; + field: PluginConfigurationSchemaField; +}> => { + const newInitialValues: Array<{ + key: string; + path: string; + field: PluginConfigurationSchemaField; + }> = []; + for (const [key, field] of Object.entries(configurationSchema)) { + switch (field?.type) { + case PluginConfigurationSchemaType.CheckboxSection: + newInitialValues.push({ + key: key, + path: `${parentKey}.content.${key}`, + field: field, + }); + break; + case PluginConfigurationSchemaType.ComboSection: + newInitialValues.push({ + key: key, + path: `${parentKey}.${selectedKey}.content.${key}`, + field: field, + }); + break; + default: + newInitialValues.push({ + key: key, + path: `${parentKey}.${selectedKey}.content.${key}`, + field: field, + }); + } + } return newInitialValues; }; + +function getEnumDefaultValue(field: EnumField): string { + if (!field.defaultValue) { + return Object.keys(field.values)[0]; + } + return field.defaultValue.toString(); +} diff --git a/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-bool-checkbox/CustomBoolCheckbox.tsx b/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-bool-checkbox/CustomBoolCheckbox.tsx index 87001a9c..a71c83ca 100644 --- a/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-bool-checkbox/CustomBoolCheckbox.tsx +++ b/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-bool-checkbox/CustomBoolCheckbox.tsx @@ -8,6 +8,7 @@ export interface CustomBoolCheckboxProps { pluginKey: string; field: BooleanField; form: FormReturnType; + path: string; } export function CustomBoolCheckbox(props: CustomBoolCheckboxProps) { diff --git a/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-checkbox-section/custom-checkbox.section.tsx b/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-checkbox-section/custom-checkbox.section.tsx index 37fb75a6..6ba5b6dd 100644 --- a/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-checkbox-section/custom-checkbox.section.tsx +++ b/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-checkbox-section/custom-checkbox.section.tsx @@ -1,6 +1,9 @@ -import { CheckboxSectionField } from '@yadoms/domain/plugins'; +import { + CheckboxSectionField, + getInitialValuesFromSectionFields, +} from '@yadoms/domain/plugins'; import { Box, Checkbox } from '@mantine/core'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import renderPluginField from '../../render-plugin-field/render-plugin-field'; import LinkifyText from '../../linkify-text/linkify-text'; import { FormReturnType } from '../../FormReturnType'; @@ -9,12 +12,19 @@ export interface CustomCheckboxSectionProps { pluginKey: string; field: CheckboxSectionField; form: FormReturnType; + path: string; } export function CustomCheckboxSection(props: CustomCheckboxSectionProps) { - const [checked, setChecked] = useState( - !!props.field.defaultValue - ); + const CHECKBOX_PATH = `${props.path}.checkbox`; + const CHECKBOX_VALUE = props.form.getInputProps(CHECKBOX_PATH).value; + + const [checked, setChecked] = useState(!!props.field.defaultValue); + + useEffect(() => { + setChecked(CHECKBOX_VALUE); + }, [CHECKBOX_VALUE]); + return ( ({ @@ -34,15 +44,20 @@ export function CustomCheckboxSection(props: CustomCheckboxSectionProps) { label={props.field.name} description={} checked={checked} - onChange={(event) => setChecked(event.currentTarget.checked)} + {...props.form.getInputProps(CHECKBOX_PATH, { type: 'checkbox' })} /> {checked && (
- {Object.entries(props.field.content).map(([key, value]) => + {getInitialValuesFromSectionFields( + props.field.content, + props.path, + '' + ).map(({ key, path, field }) => renderPluginField({ - field: value, + field: field, form: props.form, + path: path, pluginKey: key, }) )} diff --git a/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-combo-section/custom-combo-section.tsx b/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-combo-section/custom-combo-section.tsx index 5916e0ee..a9fd7535 100644 --- a/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-combo-section/custom-combo-section.tsx +++ b/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-combo-section/custom-combo-section.tsx @@ -2,7 +2,10 @@ import { Box, Group, Select, Text } from '@mantine/core'; import React, { forwardRef, useState } from 'react'; import { ItemProps } from '../../plugin-configuration-modal/plugin-configuration-modal'; import renderPluginField from '../../render-plugin-field/render-plugin-field'; -import { ComboSectionField } from '@yadoms/domain/plugins'; +import { + ComboSectionField, + getInitialValuesFromSectionFields, +} from '@yadoms/domain/plugins'; import LinkifyText from '../../linkify-text/linkify-text'; import { FormReturnType } from '../../FormReturnType'; @@ -10,6 +13,7 @@ export interface CustomComboSectionProps { pluginKey: string; field: ComboSectionField; form: FormReturnType; + path: string; } const SelectItem = forwardRef( @@ -34,7 +38,8 @@ export function CustomComboSection(props: CustomComboSectionProps) { }); // TODO : to be removed when seb added empty content to Linky plugin const selectedComboSectionContent = - props.field.content[selectedComboSection]?.content; + props.field.content[selectedComboSection].content; + return ( ({ @@ -68,10 +73,15 @@ export function CustomComboSection(props: CustomComboSectionProps) { /> {selectedComboSectionContent && (
- {Object.entries(selectedComboSectionContent).map(([key, value]) => + {getInitialValuesFromSectionFields( + selectedComboSectionContent, + props.path, + selectedComboSection + ).map(({ key, path, field }) => renderPluginField({ - field: value, + field: field, form: props.form, + path: path, pluginKey: key, }) )} diff --git a/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-decimal-number/custom-decimal-number.tsx b/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-decimal-number/custom-decimal-number.tsx index 473bf62f..dc6285b2 100644 --- a/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-decimal-number/custom-decimal-number.tsx +++ b/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-decimal-number/custom-decimal-number.tsx @@ -8,6 +8,7 @@ export interface CustomDecimalNumberProps { pluginKey: string; field: DecimalField; form: FormReturnType; + path: string; } export function CustomDecimalNumber(props: CustomDecimalNumberProps) { diff --git a/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-enum-select/custom-enum-select.tsx b/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-enum-select/custom-enum-select.tsx index c197b033..6f9b4f01 100644 --- a/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-enum-select/custom-enum-select.tsx +++ b/libs/pages/plugins/src/lib/ui/custom-plugin-components/custom-enum-select/custom-enum-select.tsx @@ -1,5 +1,5 @@ import { Select } from '@mantine/core'; -import React, { useState } from 'react'; +import React from 'react'; import { ItemProps } from '../../plugin-configuration-modal/plugin-configuration-modal'; import { EnumField } from '@yadoms/domain/plugins'; import LinkifyText from '../../linkify-text/linkify-text'; @@ -9,21 +9,18 @@ export interface CustomEnumSelectProps { pluginKey: string; field: EnumField; form: FormReturnType; + path: string; } export function CustomEnumSelect(props: CustomEnumSelectProps) { - const [value, setValue] = useState( - getEnumValuesData(props.field)[0].value - ); return (