diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Checkbox.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Checkbox.tsx index 239d12db35..8034019049 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Checkbox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Checkbox.tsx @@ -21,9 +21,11 @@ export interface CheckboxBaseProps { ripple?: boolean; indeterminate?: boolean; style?: ComponentStyle; + defaultChecked?: boolean; + defaultValue?: string; } -export type CheckboxInputProps = Omit, 'onChange' | 'type' | 'value' | 'checked' | 'id' | 'style'> & ILayoutSizeProps; +export type CheckboxInputProps = Omit, 'onChange' | 'type' | 'value' | 'defaultValue' | 'checked' | 'defaultChecked' | 'id' | 'style'> & ILayoutSizeProps; export interface ICheckboxControlledProps extends CheckboxInputProps { value?: string; @@ -35,7 +37,7 @@ export interface ICheckboxControlledProps extends CheckboxInputProps { export interface ICheckboxObjectProps extends CheckboxInputProps { value?: string; - state: Partial>; + state?: Partial>; checked?: never; onChange?: CheckboxOnChangeEvent; autoHide?: boolean; @@ -50,9 +52,11 @@ export interface CheckboxType { export const Checkbox: CheckboxType = observer(function Checkbox({ name, value, + defaultValue, state, label, checked, + defaultChecked, children, mod, ripple, @@ -63,14 +67,15 @@ export const Checkbox: CheckboxType = observer(function Checkbox({ }: CheckboxBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps)) { const checkboxState = useCheckboxState({ value, + defaultValue, checked, - defaultChecked: rest.defaultChecked, + defaultChecked, state, name, onChange, }); - if (autoHide && !isControlPresented(name, state)) { + if (autoHide && !isControlPresented(name, state, defaultChecked)) { return null; } diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx index 9e2cf2b8bf..902b38179d 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx @@ -27,7 +27,7 @@ export const FieldCheckbox: CheckboxType = function FieldCheckbox({ }: CheckboxBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps)) { const styles = useStyles(baseFormControlStyles, fieldCheckboxStyles); - if (rest.autoHide && !isControlPresented(rest.name, rest.state)) { + if (rest.autoHide && !isControlPresented(rest.name, rest.state, rest.defaultChecked)) { return null; } diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckboxNew.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckboxNew.tsx index 82c135094e..7b1b32be62 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckboxNew.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckboxNew.tsx @@ -39,7 +39,7 @@ export const FieldCheckboxNew: CheckboxType = function FieldCheckboxNew({ }: CheckboxBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps)) { const styles = useStyles(baseFormControlStylesNew, fieldCheckboxStyles); - if (rest.autoHide && !isControlPresented(rest.name, rest.state)) { + if (rest.autoHide && !isControlPresented(rest.name, rest.state, rest.defaultChecked)) { return null; } diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx index 3ab94b7e6d..e7331067d9 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx @@ -81,6 +81,8 @@ interface IBaseProps { mod?: Array; label?: string; description?: string; + defaultValue?: string; + defaultChecked?: boolean; } interface SwitchType { @@ -91,10 +93,12 @@ interface SwitchType { export const Switch: SwitchType = observer(function Switch({ name, value, + defaultValue, label, description, state, checked, + defaultChecked, className, children, onChange, @@ -105,8 +109,9 @@ export const Switch: SwitchType = observer(function Switch({ }: IBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps)) { const checkboxState = useCheckboxState({ value, + defaultValue, checked, - defaultChecked: rest.defaultChecked, + defaultChecked, state, name, onChange, @@ -119,7 +124,7 @@ export const Switch: SwitchType = observer(function Switch({ checkboxState.checked && switchState.checked ); - if (autoHide && !isControlPresented(name, state)) { + if (autoHide && !isControlPresented(name, state, defaultChecked)) { return null; } diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/SwitchNew.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/SwitchNew.tsx index 07b7e68946..c0ff751944 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/SwitchNew.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/SwitchNew.tsx @@ -85,6 +85,8 @@ const switchState = { interface IBaseProps { mod?: Array; description?: string; + defaultValue?: string; + defaultChecked?: boolean; } interface SwitchType { @@ -95,9 +97,11 @@ interface SwitchType { export const SwitchNew: SwitchType = observer(function SwitchNew({ name, value, + defaultValue, description, state, checked, + defaultChecked, className, children, onChange, @@ -108,8 +112,9 @@ export const SwitchNew: SwitchType = observer(function SwitchNew({ }: IBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps)) { const checkboxState = useCheckboxState({ value, + defaultValue, checked, - defaultChecked: rest.defaultChecked, + defaultChecked, state, name, onChange, @@ -122,7 +127,7 @@ export const SwitchNew: SwitchType = observer(function SwitchNew({ checkboxState.checked && switchState.checked ); - if (autoHide && !isControlPresented(name, state)) { + if (autoHide && !isControlPresented(name, state, defaultChecked)) { return null; } diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/useCheckboxState.ts b/webapp/packages/core-blocks/src/FormControls/Checkboxes/useCheckboxState.ts index 9ecf383417..ef616454f0 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/useCheckboxState.ts +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/useCheckboxState.ts @@ -15,6 +15,7 @@ export type CheckboxOnChangeEvent = (value: boolean, name: T) => void; export type CheckboxStateOptions = { value: string | undefined; + defaultValue: string | undefined; checked: boolean | undefined; defaultChecked: boolean | undefined; } & ( @@ -39,22 +40,21 @@ export function useCheckboxState(options: CheckboxStateOpti const [count, refresh] = useState(0); const context = useContext(FormContext); const optionsRef = useObjectRef({ ...options, context, count }); - const { state, name, value } = optionsRef; + const { state, name } = optionsRef; - let checked = optionsRef.checked ?? false; + let checked = optionsRef.checked ?? optionsRef.defaultChecked ?? false; + const value = optionsRef.value ?? optionsRef.defaultValue ?? undefined; if (state !== undefined && name !== undefined && name in state) { const currentState = state[name as TKey]; - if (typeof value === 'string' && Array.isArray(currentState)) { - checked = currentState.includes(value); + if (typeof value === 'string') { + checked = Array.isArray(currentState) ? currentState.includes(value) : currentState === value; } else if (typeof currentState === 'string') { checked = currentState.toLowerCase() === 'true'; } else { checked = !!currentState; } - } else if (optionsRef.defaultChecked !== undefined) { - checked = optionsRef.defaultChecked; } return useObjectRef({ diff --git a/webapp/packages/core-blocks/src/FormControls/ComboboxNew.tsx b/webapp/packages/core-blocks/src/FormControls/ComboboxNew.tsx index a76d3da5cd..aa884b8b52 100644 --- a/webapp/packages/core-blocks/src/FormControls/ComboboxNew.tsx +++ b/webapp/packages/core-blocks/src/FormControls/ComboboxNew.tsx @@ -97,10 +97,11 @@ const styles = composes( ` ); -type BaseProps = Omit, 'onChange' | 'onSelect' | 'name' | 'value'> & ILayoutSizeProps & { +type BaseProps = Omit, 'onChange' | 'onSelect' | 'name' | 'value' | 'defaultValue'> & ILayoutSizeProps & { propertyName?: string; items: TValue[]; searchable?: boolean; + defaultValue?: string; keySelector: (item: TValue) => TKey; valueSelector: (item: TValue) => string; onSwitch?: (state: boolean) => void; @@ -116,7 +117,7 @@ type ControlledProps = BaseProps & { type ObjectProps = BaseProps & { name: TKey; - state: TState; + state?: TState; onSelect?: (value: TState[TKey], name: TKey | undefined, prev: TState[TKey]) => void; onChange?: (value: string, name: TKey | undefined) => any; value?: never; @@ -129,6 +130,7 @@ interface ComboboxType { export const ComboboxNew: ComboboxType = observer(function ComboboxNew({ value: controlledValue, + defaultValue, name, state, propertyName, @@ -154,14 +156,10 @@ export const ComboboxNew: ComboboxType = observer(function ComboboxNew({ gutter: 4, }); const [searchValue, setSearchValue] = useState(''); - let value: string | number | readonly string[] | undefined = controlledValue; + let value: string | number | readonly string[] | undefined = controlledValue ?? defaultValue ?? undefined; - if (state) { - if (name in state) { - value = state[name]; - } else if (rest.defaultValue !== undefined) { - value = rest.defaultValue; - } + if (state && name !== undefined && name in state) { + value = state[name]; } const selectedItem = items.find(item => keySelector(item) === value); diff --git a/webapp/packages/core-blocks/src/FormControls/InputField.tsx b/webapp/packages/core-blocks/src/FormControls/InputField.tsx index 5b63ae2c49..1fad732ce0 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputField.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputField.tsx @@ -16,18 +16,18 @@ import { baseFormControlStyles } from './baseFormControlStyles'; import { FormContext } from './FormContext'; import { isControlPresented } from './isControlPresented'; -type BaseProps = Omit, 'onChange' | 'name' | 'value'> & { +type BaseProps = Omit, 'onChange' | 'name' | 'value' | 'defaultValue'> & { description?: string; mod?: 'surface'; long?: boolean; short?: boolean; + defaultValue?: string; }; type ControlledProps = BaseProps & { name?: string; value?: string; onChange?: (value: string, name?: string) => any; - state?: never; autoHide?: never; }; @@ -37,7 +37,6 @@ type ObjectProps = BaseProps & { state: TState; onChange?: (value: string, name: TKey) => any; autoHide?: boolean; - value?: never; }; @@ -49,6 +48,7 @@ interface InputFieldType { export const InputField: InputFieldType = observer(function InputField({ name, value: valueControlled, + defaultValue, required, state, children, @@ -76,17 +76,13 @@ export const InputField: InputFieldType = observer(function InputField({ } }, [state, name, context, onChange]); - let value: any = valueControlled; + let value: any = valueControlled ?? defaultValue ?? undefined; - if (state) { - if (name in state) { - value = state[name]; - } else if (rest.defaultValue !== undefined) { - value = rest.defaultValue; - } + if (state && name !== undefined && name in state) { + value = state[name]; } - if (autoHide && !isControlPresented(name, state)) { + if (autoHide && !isControlPresented(name, state, defaultValue)) { return null; } diff --git a/webapp/packages/core-blocks/src/FormControls/InputFieldNew.tsx b/webapp/packages/core-blocks/src/FormControls/InputFieldNew.tsx index 8a587ef907..ddc48a5dad 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputFieldNew.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputFieldNew.tsx @@ -28,11 +28,12 @@ const INPUT_FIELD_STYLES = css` } `; -type BaseProps = Omit, 'onChange' | 'name' | 'value'> & ILayoutSizeProps & { +type BaseProps = Omit, 'onChange' | 'name' | 'value' | 'defaultValue'> & ILayoutSizeProps & { description?: string; mod?: 'surface'; ref?: React.Ref; style?: ComponentStyle; + defaultValue?: string | number; }; type ControlledProps = BaseProps & { @@ -47,7 +48,7 @@ type ControlledProps = BaseProps & { type ObjectProps = BaseProps & { name: TKey; - state: TState; + state?: TState; mapState?: (value: TState[TKey]) => TState[TKey]; mapValue?: (value: TState[TKey]) => TState[TKey]; onChange?: (value: TState[TKey], name: TKey) => any; @@ -64,6 +65,7 @@ export const InputFieldNew: InputFieldType = observer(function InputFieldNew({ name, style, value: valueControlled, + defaultValue, required, state, mapState, @@ -96,18 +98,14 @@ export const InputFieldNew: InputFieldType = observer(function InputFieldNew({ } }, [state, name, context, onChange]); - if (autoHide && !isControlPresented(name, state)) { + if (autoHide && !isControlPresented(name, state, defaultValue)) { return null; } - let value: any = valueControlled; + let value: any = valueControlled ?? defaultValue ?? undefined; - if (state) { - if (name in state) { - value = state[name]; - } else if (rest.defaultValue !== undefined) { - value = rest.defaultValue; - } + if (state && name !== undefined && name in state) { + value = state[name]; } if (mapState) { diff --git a/webapp/packages/core-blocks/src/FormControls/isControlPresented.ts b/webapp/packages/core-blocks/src/FormControls/isControlPresented.ts index 63a89795c1..d8fcb8ca8a 100644 --- a/webapp/packages/core-blocks/src/FormControls/isControlPresented.ts +++ b/webapp/packages/core-blocks/src/FormControls/isControlPresented.ts @@ -6,9 +6,14 @@ * you may not use this file except in compliance with the License. */ -export function isControlPresented(name: string | undefined, state: any): boolean { +export function isControlPresented( + name: string | undefined, state: any, defaultValue?: string | number | boolean +): boolean { if (state !== undefined && name !== undefined) { - return name in state && state[name] !== null; + if (name in state) { + return state[name] !== null; + } + return defaultValue !== undefined; } return true; } diff --git a/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/ObjectPropertyInfoFormNew.tsx b/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/ObjectPropertyInfoFormNew.tsx index f92a2fd2a5..197d31a5a1 100644 --- a/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/ObjectPropertyInfoFormNew.tsx +++ b/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/ObjectPropertyInfoFormNew.tsx @@ -16,8 +16,8 @@ import { TextPlaceholder } from '../../TextPlaceholder'; import { RenderField } from './RenderField'; interface ObjectPropertyFormProps extends ILayoutSizeProps { - properties: ObjectPropertyInfo[] | undefined; - state: Record; + properties: ObjectPropertyInfo[]; + state?: Record; category?: string | null; editable?: boolean; autofillToken?: string; @@ -48,7 +48,7 @@ export const ObjectPropertyInfoFormNew: React.FC = obse } }, [onFocus]); - if (!properties || properties.length === 0) { + if (properties.length === 0) { return Properties empty; } diff --git a/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx b/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx index d74fa06303..459df06ba8 100644 --- a/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx +++ b/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx @@ -21,7 +21,7 @@ const RESERVED_KEYWORDS = ['no', 'off', 'new-password']; interface RenderFieldProps { property: ObjectPropertyInfo; - state: Record; + state?: Record; editable?: boolean; autofillToken?: string; disabled?: boolean; @@ -32,20 +32,31 @@ interface RenderFieldProps { className?: string; } -function isCheckbox(property: ObjectPropertyInfo) { - return property.dataType?.toLowerCase() === 'boolean'; +type ControlType = 'checkbox' | 'combobox' | 'link' | 'input'; + +function getControlTypeFor(property: ObjectPropertyInfo): ControlType { + const dataType = property.dataType?.toLowerCase(); + + if (dataType === 'boolean') { + return 'checkbox'; + } else if (property.validValues && property.validValues.length > 0) { + return 'combobox'; + } else if (property.features.includes('href')) { + return 'link'; + } + + return 'input'; } -function getDefaultValueFor(property: ObjectPropertyInfo) { - const checkbox = isCheckbox(property); - const value = property.value; +function getValue(value: any, controlType: ControlType) { + const checkbox = controlType === 'checkbox'; if (value === null || value === undefined) { return checkbox ? false : ''; } if (typeof value === 'string') { - return checkbox ? value === 'true' : value; + return checkbox ? value.toLowerCase() === 'true' : value; } return value.displayName || value.value || JSON.stringify(value); @@ -63,17 +74,17 @@ export const RenderField: React.FC = observer(function RenderF onFocus, className, }) { - const href = property.features.includes('href'); + const controltype = getControlTypeFor(property); const password = property.features.includes('password'); - const checkbox = isCheckbox(property); - const combobox = property.validValues && property.validValues.length > 0; - const defaultValue = getDefaultValueFor(property); + + const value = getValue(property.value, controltype); + const defaultValue = getValue(property.defaultValue, controltype); let description: string | undefined; - if (href) { + if (controltype === 'link') { return ( - {property.description} + {property.description} ); } @@ -84,7 +95,7 @@ export const RenderField: React.FC = observer(function RenderF } return ( - {state[property.id!]} + {state?.[property.id!]} ); } @@ -93,12 +104,12 @@ export const RenderField: React.FC = observer(function RenderF description = 'Password saved'; } - if (checkbox) { + if (controltype === 'checkbox') { return ( = observer(function RenderF ); } - if (combobox) { + if (controltype === 'combobox') { return ( = observer(function RenderF items={property.validValues!} keySelector={value => value} valueSelector={value => value} - defaultValue={property.defaultValue} + defaultValue={defaultValue} title={property.description} disabled={disabled} className={className} @@ -132,7 +143,7 @@ export const RenderField: React.FC = observer(function RenderF title={property.description} name={property.id!} state={state} - defaultValue={defaultValue} + value={state === undefined ? value : undefined} description={description} disabled={disabled} readOnly={readOnly} diff --git a/webapp/packages/core-connections/src/ConnectionForm/Options/Options.tsx b/webapp/packages/core-connections/src/ConnectionForm/Options/Options.tsx index 6cd6f0f1e8..bb0a3470a2 100644 --- a/webapp/packages/core-connections/src/ConnectionForm/Options/Options.tsx +++ b/webapp/packages/core-connections/src/ConnectionForm/Options/Options.tsx @@ -227,7 +227,7 @@ export const Options: TabContainerPanelComponent = observe - {(authModel && !driver.data?.anonymousAccess) && ( + {(authModel && !driver.data?.anonymousAccess && properties) && ( {translate('connections_connection_edit_authentication')} diff --git a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectInfoTab/ObjectProperties.tsx b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectInfoTab/ObjectProperties.tsx index b7f4462d5d..70246acd4e 100644 --- a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectInfoTab/ObjectProperties.tsx +++ b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectInfoTab/ObjectProperties.tsx @@ -30,12 +30,13 @@ export const ObjectProperties = observer(function ObjectProperties({ const { dbObject, isLoading } = useDatabaseObjectInfo(objectId); const styles = useStyles(BASE_CONTAINERS_STYLES); const { categories, isUncategorizedExists } = useObjectPropertyCategories(dbObject?.properties ?? emptyArray); + const properties = dbObject?.properties; - if (!dbObject?.properties && isLoading) { + if (!properties && isLoading) { return ; } - if (!dbObject?.properties || dbObject.properties.length === 0) { + if (!properties || properties.length === 0) { return {translate('plugin_object_viewer_table_no_items')}; } @@ -44,9 +45,8 @@ export const ObjectProperties = observer(function ObjectProperties({ {isUncategorizedExists && ( @@ -56,9 +56,8 @@ export const ObjectProperties = observer(function ObjectProperties({ {category}