0.12.0-1 Plugins und diverses
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { TabView, TabPanel } from 'primereact/tabview';
|
||||
import { Accordion, AccordionTab } from 'primereact/accordion';
|
||||
import { InputText } from 'primereact/inputtext';
|
||||
@@ -357,6 +357,17 @@ function isNotificationEventToggleSetting(setting) {
|
||||
return setting?.type === 'boolean' && NOTIFICATION_EVENT_TOGGLE_KEYS.has(normalizeSettingKey(setting?.key));
|
||||
}
|
||||
|
||||
function isReadonlySetting(setting) {
|
||||
try {
|
||||
// API gibt validation als parsed object zurück, nicht validation_json als String
|
||||
const v = setting?.validation;
|
||||
if (v && typeof v === 'object') return v.readonly === true;
|
||||
return JSON.parse(setting?.validation_json || '{}')?.readonly === true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function SettingField({
|
||||
setting,
|
||||
value,
|
||||
@@ -367,7 +378,8 @@ function SettingField({
|
||||
ownerError,
|
||||
ownerDirty,
|
||||
onChange,
|
||||
variant = 'default'
|
||||
variant = 'default',
|
||||
disabled = false
|
||||
}) {
|
||||
const ownerKey = ownerSetting?.key;
|
||||
const pathHasValue = Boolean(String(value ?? '').trim());
|
||||
@@ -384,13 +396,15 @@ function SettingField({
|
||||
<InputSwitch
|
||||
id={setting.key}
|
||||
checked={Boolean(value)}
|
||||
onChange={(event) => onChange?.(setting.key, event.value)}
|
||||
disabled={disabled}
|
||||
onChange={disabled ? undefined : (event) => onChange?.(setting.key, event.value)}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<label htmlFor={setting.key}>
|
||||
<label htmlFor={setting.key} className={disabled ? 'setting-label--readonly' : undefined}>
|
||||
{setting.label}
|
||||
{setting.required && <span className="required">*</span>}
|
||||
{disabled ? <span className="setting-badge--coming-soon"> (bald)</span> : null}
|
||||
</label>
|
||||
)}
|
||||
|
||||
@@ -424,7 +438,8 @@ function SettingField({
|
||||
<InputSwitch
|
||||
id={setting.key}
|
||||
checked={Boolean(value)}
|
||||
onChange={(event) => onChange?.(setting.key, event.value)}
|
||||
disabled={disabled}
|
||||
onChange={disabled ? undefined : (event) => onChange?.(setting.key, event.value)}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@@ -780,10 +795,22 @@ export default function DynamicSettingsForm({
|
||||
const notificationToggleKeys = new Set(
|
||||
notificationToggleSettings.map((setting) => normalizeSettingKey(setting?.key))
|
||||
);
|
||||
const regularSettings = baseSettings.filter(
|
||||
(setting) => !notificationToggleKeys.has(normalizeSettingKey(setting?.key))
|
||||
);
|
||||
const renderSetting = (setting, variant = 'default') => {
|
||||
|
||||
// Abhängigkeitsbaum aufbauen: depends_on → Kinder
|
||||
const dependentsByParent = new Map();
|
||||
const rootSettings = [];
|
||||
for (const setting of baseSettings) {
|
||||
if (notificationToggleKeys.has(normalizeSettingKey(setting?.key))) continue;
|
||||
const dep = setting?.depends_on;
|
||||
if (dep) {
|
||||
if (!dependentsByParent.has(dep)) dependentsByParent.set(dep, []);
|
||||
dependentsByParent.get(dep).push(setting);
|
||||
} else {
|
||||
rootSettings.push(setting);
|
||||
}
|
||||
}
|
||||
|
||||
const renderSetting = (setting, variant = 'default', disabled = false, onChangeFn = onChange) => {
|
||||
const value = values?.[setting.key];
|
||||
const error = errors?.[setting.key] || null;
|
||||
const dirty = Boolean(dirtyKeys?.has?.(setting.key));
|
||||
@@ -805,17 +832,53 @@ export default function DynamicSettingsForm({
|
||||
ownerValue={ownerValue}
|
||||
ownerError={ownerError}
|
||||
ownerDirty={ownerDirty}
|
||||
onChange={onChange}
|
||||
onChange={onChangeFn}
|
||||
variant={variant}
|
||||
disabled={disabled}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
// Alle Nachkommen eines Keys rekursiv auf false setzen
|
||||
const cascadeOff = (key) => {
|
||||
const children = dependentsByParent.get(key) || [];
|
||||
for (const child of children) {
|
||||
onChange?.(child.key, false);
|
||||
cascadeOff(child.key);
|
||||
}
|
||||
};
|
||||
|
||||
// Rekursiv: Setting + seine Kinder rendern
|
||||
// Wenn ein Parent auf false geht → alle Kinder werden auf false gesetzt
|
||||
const renderWithChildren = (setting, depth = 0) => {
|
||||
const children = dependentsByParent.get(setting.key) || [];
|
||||
const readonly = depth > 0 && isReadonlySetting(setting);
|
||||
const active = toBoolean(values?.[setting.key]);
|
||||
|
||||
const effectiveOnChange = children.length > 0
|
||||
? (key, value) => {
|
||||
onChange?.(key, value);
|
||||
if (!value) cascadeOff(key);
|
||||
}
|
||||
: onChange;
|
||||
|
||||
return (
|
||||
<React.Fragment key={setting.key}>
|
||||
{renderSetting(setting, 'default', readonly, effectiveOnChange)}
|
||||
{children.length > 0 && active && !readonly ? (
|
||||
<div className={`settings-grid settings-grid--depth-${depth + 1}`}>
|
||||
{children.map((child) => renderWithChildren(child, depth + 1))}
|
||||
</div>
|
||||
) : null}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{regularSettings.length > 0 ? (
|
||||
{rootSettings.length > 0 ? (
|
||||
<div className="settings-grid">
|
||||
{regularSettings.map((setting) => renderSetting(setting))}
|
||||
{rootSettings.map((setting) => renderWithChildren(setting, 0))}
|
||||
</div>
|
||||
) : null}
|
||||
{pushoverEnabled && notificationToggleSettings.length > 0 ? (
|
||||
|
||||
Reference in New Issue
Block a user