Skip to content

Commit d11706a

Browse files
committed
Address PR comments
1 parent c9071ee commit d11706a

3 files changed

Lines changed: 63 additions & 21 deletions

File tree

.changeset/lovely-poems-do.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
2-
"@wso2is/admin.connections.v1": patch
3-
"@wso2is/forms": patch
2+
"@wso2is/admin.connections.v1": minor
3+
"@wso2is/forms": minor
44
"@wso2is/i18n": patch
55
---
66

7-
Add support for `select`/`dropdown` fields in connection create and edittemplates, including a `useDynamicFieldOptions` hook that resolves fieldoptions from existing connections declared via `optionsSource` metadata.
7+
Add support for `select`/`dropdown` fields in connection create and edit templates, including a `useDynamicFieldOptions` hook that resolves field options from existing connections declared via `optionsSource` metadata.

features/admin.connections.v1/hooks/use-dynamic-field-options.ts

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,32 @@ interface DynamicFieldOptionsSourceInterface {
6868
labelField?: string;
6969
}
7070

71+
/**
72+
* Attributes of a dynamic form field this hook reads or rewrites.
73+
*/
74+
interface DynamicFieldInterface {
75+
/**
76+
* Name of the field, also the key its value is persisted under.
77+
*/
78+
name?: string;
79+
/**
80+
* Placeholder of the field, replaced while the options are being resolved.
81+
*/
82+
placeholder?: string;
83+
/**
84+
* Whether the field is read only.
85+
*/
86+
readOnly?: boolean;
87+
/**
88+
* Declaration of where the options of the field come from, if any.
89+
*/
90+
optionsSource?: DynamicFieldOptionsSourceInterface;
91+
/**
92+
* Renderer specific attributes declared by the connector metadata.
93+
*/
94+
[ key: string ]: unknown;
95+
}
96+
7197
/**
7298
* Context of the form the fields are rendered in.
7399
*/
@@ -79,7 +105,7 @@ interface DynamicFieldOptionsContextInterface {
79105
/**
80106
* Values the form was initialized with, keyed by field name.
81107
*/
82-
currentValues?: Record<string, any>;
108+
currentValues?: Record<string, unknown>;
83109
}
84110

85111
/**
@@ -89,7 +115,7 @@ interface DynamicFieldOptionsResultInterface {
89115
/**
90116
* The given fields, with the options of every `optionsSource` backed field resolved.
91117
*/
92-
fields: Record<string, any>[];
118+
fields: DynamicFieldInterface[];
93119
/**
94120
* Whether the options are still being resolved.
95121
*/
@@ -113,7 +139,7 @@ interface DynamicFieldOptionsResultInterface {
113139
* @returns The fields with resolved options and the resolution status.
114140
*/
115141
const useDynamicFieldOptions = (
116-
fields: Record<string, any>[],
142+
fields: DynamicFieldInterface[],
117143
context?: DynamicFieldOptionsContextInterface
118144
): DynamicFieldOptionsResultInterface => {
119145

@@ -131,7 +157,7 @@ const useDynamicFieldOptions = (
131157
}
132158

133159
return fields
134-
.map((field: Record<string, any>) => field?.optionsSource)
160+
.map((field: DynamicFieldInterface) => field?.optionsSource)
135161
.filter((source: DynamicFieldOptionsSourceInterface) =>
136162
source?.type === DynamicFieldOptionsSourceTypes.CONNECTIONS);
137163
}, [ fields ]);
@@ -242,12 +268,12 @@ const useDynamicFieldOptions = (
242268

243269
const isLoading: boolean = isConnectionListLoading || isResolvingTemplateIds;
244270

245-
const resolvedFields: Record<string, any>[] = useMemo(() => {
271+
const resolvedFields: DynamicFieldInterface[] = useMemo(() => {
246272
if (!Array.isArray(fields)) {
247273
return fields;
248274
}
249275

250-
return fields.map((field: Record<string, any>) => {
276+
return fields.map((field: DynamicFieldInterface) => {
251277
const source: DynamicFieldOptionsSourceInterface = field?.optionsSource;
252278

253279
if (source?.type !== DynamicFieldOptionsSourceTypes.CONNECTIONS) {
@@ -277,7 +303,10 @@ const useDynamicFieldOptions = (
277303
/*
278304
* Keep an already persisted value selectable even when it is not part of the resolved options.
279305
*/
280-
const persistedValue: string = context?.currentValues?.[ field?.name ];
306+
const currentValue: unknown = field?.name
307+
? context?.currentValues?.[ field.name ]
308+
: undefined;
309+
const persistedValue: string = typeof currentValue === "string" ? currentValue : "";
281310

282311
if (!isEmpty(persistedValue)
283312
&& !options.some((option: { value: string }) => option.value === persistedValue)) {

modules/forms/src/legacy/dynamic-forms/components/field-select.tsx

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ import FormGroup from "@oxygen-ui/react/FormGroup";
2020
import { IdentifiableComponentInterface, TestableComponentInterface } from "@wso2is/core/models";
2121
import { Hint } from "@wso2is/react-components";
2222
import { FieldState } from "final-form";
23-
import React, { ReactElement, ReactNode } from "react";
23+
import React, { FunctionComponent, ReactElement, ReactNode } from "react";
2424
import { FieldProps, FieldRenderProps, Field as FinalFormField } from "react-final-form";
2525
import SelectFieldAdapter from "../../../components/adapters/select-field-adapter";
2626
import { getValidation } from "../utils/validate";
2727

2828
/**
2929
* Option of a dynamic select field.
3030
*/
31-
export interface DynamicFieldOptionInterface {
31+
interface DynamicFieldOptionInterface {
3232
/**
3333
* Text displayed for the option.
3434
*/
@@ -39,7 +39,13 @@ export interface DynamicFieldOptionInterface {
3939
value: string;
4040
}
4141

42-
export interface FieldSelectPropsInterface extends Omit<FieldProps<any, any, any>, "component">,
42+
/**
43+
* Value a dynamic select field holds. Multiple selection is not supported.
44+
*/
45+
type DynamicSelectFieldValueType = string;
46+
47+
interface FieldSelectPropsInterface
48+
extends Omit<FieldProps<DynamicSelectFieldValueType, FieldRenderProps<DynamicSelectFieldValueType>>, "component">,
4349
IdentifiableComponentInterface, TestableComponentInterface {
4450

4551
/**
@@ -63,17 +69,22 @@ export interface FieldSelectPropsInterface extends Omit<FieldProps<any, any, any
6369
*/
6470
readOnly?: boolean;
6571
/**
66-
* Validation of the field.
72+
* Validation of the field. Resolves to the error message, or to `undefined` when the value is valid.
6773
*/
68-
validation?: (value: string | number | any, allValues: Record<string, unknown>) => any;
74+
validation?: (
75+
value: DynamicSelectFieldValueType,
76+
allValues: Record<string, unknown>
77+
) => string | undefined | Promise<string | undefined>;
6978
}
7079

7180
/**
7281
* Implementation of the Select Field component of the dynamic form.
7382
*
7483
* @param props - Props injected to the component.
7584
*/
76-
export const FieldSelect = (props: FieldSelectPropsInterface): ReactElement => {
85+
export const FieldSelect: FunctionComponent<FieldSelectPropsInterface> = (
86+
props: FieldSelectPropsInterface
87+
): ReactElement => {
7788

7889
const {
7990
hint,
@@ -93,12 +104,14 @@ export const FieldSelect = (props: FieldSelectPropsInterface): ReactElement => {
93104
<FormGroup>
94105
<FinalFormField
95106
name={ name }
96-
parse={ (value: any) => value }
107+
parse={ (value: DynamicSelectFieldValueType) => value }
97108
initialValue={ initialValue }
98-
validate={ (value: any, allValues: Record<string, unknown>, meta: FieldState<any>) =>
99-
getValidation(value, allValues, meta, required, validation)
100-
}
101-
render={ ({ input, meta }: FieldRenderProps<any>) => (
109+
validate={ (
110+
value: DynamicSelectFieldValueType,
111+
allValues: Record<string, unknown>,
112+
meta: FieldState<DynamicSelectFieldValueType>
113+
) => getValidation(value, allValues, meta, required, validation) }
114+
render={ ({ input, meta }: FieldRenderProps<DynamicSelectFieldValueType>) => (
102115
<SelectFieldAdapter
103116
input={ input }
104117
meta={ meta }

0 commit comments

Comments
 (0)