Merge branch 'main' into temp
# Conflicts: # samples/react-json-form/README.md # samples/react-json-form/src/Models/Form.ts # samples/react-json-form/src/Models/FormField.ts # samples/react-json-form/src/Models/SaveObject.ts # samples/react-json-form/src/Providers/SharePointProvider.ts # samples/react-json-form/src/webparts/jsonForm/model/FormField.ts # samples/react-jsonForm/src/Models/FormField.ts
This commit is contained in:
commit
5a67f695b2
Binary file not shown.
After Width: | Height: | Size: 10 MiB |
Binary file not shown.
After Width: | Height: | Size: 122 KiB |
|
@ -0,0 +1,50 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "pnp-sp-dev-spfx-web-parts-react-json-form",
|
||||||
|
"source": "pnp",
|
||||||
|
"title": "Json form builder",
|
||||||
|
"shortDescription": "Build a custom form with ease",
|
||||||
|
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-json-form",
|
||||||
|
"downloadUrl": "https://pnp.github.io/download-partial/?url=https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-json-form",
|
||||||
|
"longDescription": [
|
||||||
|
"Really easy way for the users to build and use a custom form without having to worry about having to setup a SharePoint list, instead stores the data directly in a document library"
|
||||||
|
],
|
||||||
|
"creationDateTime": "2023-05-16",
|
||||||
|
"updateDateTime": "2023-05-16",
|
||||||
|
"products": [
|
||||||
|
"SharePoint"
|
||||||
|
],
|
||||||
|
"metadata": [
|
||||||
|
{
|
||||||
|
"key": "CLIENT-SIDE-DEV",
|
||||||
|
"value": "React"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "SPFX-VERSION",
|
||||||
|
"value": "1.17.1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thumbnails": [
|
||||||
|
{
|
||||||
|
"type": "image",
|
||||||
|
"order": 100,
|
||||||
|
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/react-caml2table/assets/Demo.gif",
|
||||||
|
"alt": "Web Part Preview"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"gitHubAccount": "Tanddant",
|
||||||
|
"pictureUrl": "https://github.com/Tanddant.png",
|
||||||
|
"name": "Dan Toft"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"name": "Build your first SharePoint client-side web part",
|
||||||
|
"description": "Client-side web parts are client-side components that run in the context of a SharePoint page. Client-side web parts can be deployed to SharePoint environments that support the SharePoint Framework. You can also use modern JavaScript web frameworks, tools, and libraries to build them.",
|
||||||
|
"url": "https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
|
@ -4,6 +4,6 @@ export default function useObject<T>(InitialValue?: T) {
|
||||||
const [value, setValue] = useState<T>(InitialValue ?? {} as T);
|
const [value, setValue] = useState<T>(InitialValue ?? {} as T);
|
||||||
const updateValue: (Updates: Partial<T>) => void = (Updates: Partial<T>) => setValue((prev) => ({ ...prev, ...Updates }))
|
const updateValue: (Updates: Partial<T>) => void = (Updates: Partial<T>) => setValue((prev) => ({ ...prev, ...Updates }))
|
||||||
return {
|
return {
|
||||||
value, updateValue, overwriteData: setValue
|
value, updateValue
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -36,4 +36,9 @@ export enum GroupDirection {
|
||||||
export interface IGroupField extends IField {
|
export interface IGroupField extends IField {
|
||||||
Fields: (IField | IChoiceField | IGroupField | IConditionalField)[]
|
Fields: (IField | IChoiceField | IGroupField | IConditionalField)[]
|
||||||
Direction: GroupDirection;
|
Direction: GroupDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IForm {
|
||||||
|
Title: string;
|
||||||
|
Fields: (IField | IChoiceField | IGroupField | IConditionalField)[];
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { FieldType, IConditionalField, IField, IGroupField } from "../Models/FormField";
|
import { FieldType, IConditionalField, IField, IGroupField } from "../webparts/jsonForm/model/FormField";
|
||||||
|
|
||||||
export const generateGuid: () => string = () => {
|
export const generateGuid: () => string = () => {
|
||||||
return Math.random().toString(36).substring(2, 15) +
|
return Math.random().toString(36).substring(2, 15) +
|
||||||
|
@ -8,7 +8,7 @@ export const generateGuid: () => string = () => {
|
||||||
export const NewField: () => IField = () => ({ Id: generateGuid(), Type: FieldType.PlaceHolder } as IField)
|
export const NewField: () => IField = () => ({ Id: generateGuid(), Type: FieldType.PlaceHolder } as IField)
|
||||||
|
|
||||||
|
|
||||||
const UNSUPPORTED_LOOKUP_FIELDTYPES: FieldType[] = [FieldType.PlaceHolder, FieldType.MultiChoice, FieldType.PlaceHolder, FieldType.Label];
|
const UNSUPPORTED_FIELDTYPES: FieldType[] = [FieldType.PlaceHolder, FieldType.MultiChoice, FieldType.PlaceHolder, FieldType.Label];
|
||||||
|
|
||||||
export const GetLookupFields: (Fields: IField[]) => IField[] = (Fields: IField[]) => {
|
export const GetLookupFields: (Fields: IField[]) => IField[] = (Fields: IField[]) => {
|
||||||
const arr: IField[] = [];
|
const arr: IField[] = [];
|
||||||
|
@ -27,5 +27,5 @@ export const GetLookupFields: (Fields: IField[]) => IField[] = (Fields: IField[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return arr.filter(x => x.DisplayName != null && !UNSUPPORTED_LOOKUP_FIELDTYPES.some(bannedType => bannedType == x.Type));;
|
return arr.filter(x => x.DisplayName != null && !UNSUPPORTED_FIELDTYPES.some(bannedType => bannedType == x.Type));;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
|
||||||
import { PropertyFieldCodeEditor, PropertyFieldCodeEditorLanguages } from '@pnp/spfx-property-controls/lib/PropertyFieldCodeEditor';
|
import { PropertyFieldCodeEditor, PropertyFieldCodeEditorLanguages } from '@pnp/spfx-property-controls/lib/PropertyFieldCodeEditor';
|
||||||
import { PropertyFieldListPicker, PropertyFieldListPickerOrderBy } from '@pnp/spfx-property-controls/lib/PropertyFieldListPicker';
|
import { PropertyFieldListPicker, PropertyFieldListPickerOrderBy } from '@pnp/spfx-property-controls/lib/PropertyFieldListPicker';
|
||||||
import { IJsonFormProps, JsonForm } from './components/JsonForm';
|
import { IJsonFormProps, JsonForm } from './components/JsonForm';
|
||||||
import { IForm } from '../../Models/Form';
|
import { IForm } from './model/FormField';
|
||||||
import { IDataProvider, SharePointProvider } from '../../Providers/SharePointProvider';
|
import { SPFI, SPFx, spfi } from '@pnp/sp/presets/all'
|
||||||
|
|
||||||
export interface IJsonFormWebPartProps {
|
export interface IJsonFormWebPartProps {
|
||||||
formJson: string;
|
formJson: string;
|
||||||
|
@ -19,12 +19,12 @@ export interface IJsonFormWebPartProps {
|
||||||
|
|
||||||
export interface AppContext {
|
export interface AppContext {
|
||||||
context: BaseComponentContext;
|
context: BaseComponentContext;
|
||||||
provider: IDataProvider;
|
SP: SPFI;
|
||||||
|
ListId: string;
|
||||||
|
ItemId?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SPFxContext = React.createContext<AppContext>(null);
|
export const SPFxContext = React.createContext<AppContext>(null);
|
||||||
const urlSearchParams = new URLSearchParams(window.location.search);
|
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||||
export const FILLED_FORM_QUERY_KEY = "FormServerRelativeUrl";
|
|
||||||
|
|
||||||
export default class JsonFormWebPart extends BaseClientSideWebPart<IJsonFormWebPartProps> {
|
export default class JsonFormWebPart extends BaseClientSideWebPart<IJsonFormWebPartProps> {
|
||||||
|
|
||||||
|
@ -34,7 +34,9 @@ export default class JsonFormWebPart extends BaseClientSideWebPart<IJsonFormWebP
|
||||||
{
|
{
|
||||||
value: {
|
value: {
|
||||||
context: this.context,
|
context: this.context,
|
||||||
provider: new SharePointProvider(this.context, this.properties.listId)
|
SP: spfi().using(SPFx(this.context)),
|
||||||
|
ListId: urlSearchParams.get("ListId") ?? this.properties.listId,
|
||||||
|
ItemId: urlSearchParams.has("ItemId") ? parseInt(urlSearchParams.get("ItemId")) : null
|
||||||
} as AppContext
|
} as AppContext
|
||||||
},
|
},
|
||||||
React.createElement<IJsonFormProps>(
|
React.createElement<IJsonFormProps>(
|
||||||
|
@ -42,9 +44,7 @@ export default class JsonFormWebPart extends BaseClientSideWebPart<IJsonFormWebP
|
||||||
{
|
{
|
||||||
Form: JSON.parse(this.properties.formJson),
|
Form: JSON.parse(this.properties.formJson),
|
||||||
SaveForm: (updated: IForm) => this.properties.formJson = JSON.stringify({ ...JSON.parse(this.properties.formJson), ...updated }, null, 2),
|
SaveForm: (updated: IForm) => this.properties.formJson = JSON.stringify({ ...JSON.parse(this.properties.formJson), ...updated }, null, 2),
|
||||||
Mode: this.displayMode,
|
Mode: this.displayMode
|
||||||
ListId: this.properties.listId,
|
|
||||||
ServerRelativeUrl: urlSearchParams.has(FILLED_FORM_QUERY_KEY) ? urlSearchParams.get(FILLED_FORM_QUERY_KEY) : null,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { FieldType, GroupDirection, IChoiceField, IConditionalField, IField, IGroupField } from '../../../../Models/FormField';
|
import { FieldType, GroupDirection, IChoiceField, IConditionalField, IField, IGroupField } from '../../model/FormField';
|
||||||
import { Position, SpinButton, TextField, Checkbox, Dropdown, MessageBar, MessageBarType, Text } from '@fluentui/react';
|
import { Position, SpinButton, TextField, Checkbox, Dropdown, MessageBar, MessageBarType, Text } from '@fluentui/react';
|
||||||
import { Label } from 'office-ui-fabric-react';
|
import { Label } from 'office-ui-fabric-react';
|
||||||
|
|
||||||
|
@ -8,52 +8,49 @@ export interface IFieldProps {
|
||||||
onChange: (updates: object) => void;
|
onChange: (updates: object) => void;
|
||||||
form: any;
|
form: any;
|
||||||
field: IField;
|
field: IField;
|
||||||
readonly: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Field: React.FunctionComponent<IFieldProps> = (props: React.PropsWithChildren<IFieldProps>) => {
|
export const Field: React.FunctionComponent<IFieldProps> = (props: React.PropsWithChildren<IFieldProps>) => {
|
||||||
const { field, onChange, form, readonly } = props;
|
const { field, onChange, form } = props;
|
||||||
switch (field.Type) {
|
switch (field.Type) {
|
||||||
case FieldType.Label: return <Label>{field.DisplayName}</Label>;
|
case FieldType.Label: return <Label>{field.DisplayName}</Label>;
|
||||||
|
|
||||||
case FieldType.Header: return <Text variant='xLarge'>{field.DisplayName}</Text>;
|
case FieldType.Header: return <Text variant='xLarge'>{field.DisplayName}</Text>;
|
||||||
|
|
||||||
case FieldType.Text: return <TextField
|
case FieldType.Text: return <TextField
|
||||||
value={form[field.Id] ?? ""}
|
value={form[field.Id]}
|
||||||
label={field.DisplayName}
|
label={field.DisplayName}
|
||||||
readOnly={readonly}
|
|
||||||
onChange={(_, val) => onChange({ [field.Id]: val })}
|
onChange={(_, val) => onChange({ [field.Id]: val })}
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
case FieldType.MultilineText: return <TextField
|
case FieldType.MultilineText: return <TextField
|
||||||
value={form[field.Id] ?? ""}
|
value={form[field.Id]}
|
||||||
label={field.DisplayName}
|
label={field.DisplayName}
|
||||||
rows={5}
|
rows={5}
|
||||||
multiline
|
multiline
|
||||||
readOnly={readonly}
|
|
||||||
onChange={(_, val) => onChange({ [field.Id]: val })}
|
onChange={(_, val) => onChange({ [field.Id]: val })}
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
case FieldType.Number: return <SpinButton
|
case FieldType.Number: return <SpinButton
|
||||||
inputMode='numeric'
|
inputMode='numeric'
|
||||||
labelPosition={Position.top}
|
labelPosition={Position.top}
|
||||||
value={form[field.Id] ?? ""}
|
value={form[field.Id]}
|
||||||
label={field.DisplayName}
|
label={field.DisplayName}
|
||||||
onChange={readonly ? null : (_, val) => onChange({ [field.Id]: Number(val) })}
|
onChange={(_, val) => onChange({ [field.Id]: Number(val) })}
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
case FieldType.Boolean: return <Checkbox
|
case FieldType.Boolean: return <Checkbox
|
||||||
label={field.DisplayName}
|
label={field.DisplayName}
|
||||||
checked={form[field.Id] ?? false}
|
checked={form[field.Id]}
|
||||||
onChange={readonly ? () => null : (_, val) => onChange({ [field.Id]: val })}
|
onChange={(_, val) => onChange({ [field.Id]: val })}
|
||||||
styles={{ root: { alignItems: 'center', marginTop: "1.75em" } }}
|
styles={{ root: { alignItems: 'center', marginTop: "1.75em" } }}
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
case FieldType.Choice: return <Dropdown
|
case FieldType.Choice: return <Dropdown
|
||||||
options={(field as any as IChoiceField).Options.map(x => ({ key: x, text: x }))}
|
options={(field as any as IChoiceField).Options.map(x => ({ key: x, text: x }))}
|
||||||
selectedKey={form[field.Id] ?? ""}
|
selectedKey={form[field.Id]}
|
||||||
label={field.DisplayName}
|
label={field.DisplayName}
|
||||||
onChange={readonly ? null : (_, option) => onChange({ [field.Id]: option.key })}
|
onChange={(_, option) => onChange({ [field.Id]: option.key })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
case FieldType.MultiChoice: return <Dropdown
|
case FieldType.MultiChoice: return <Dropdown
|
||||||
|
@ -61,7 +58,7 @@ export const Field: React.FunctionComponent<IFieldProps> = (props: React.PropsWi
|
||||||
selectedKeys={form[field.Id] ?? []}
|
selectedKeys={form[field.Id] ?? []}
|
||||||
label={field.DisplayName}
|
label={field.DisplayName}
|
||||||
multiSelect
|
multiSelect
|
||||||
onChange={readonly ? null : (_, val) => {
|
onChange={(_, val) => {
|
||||||
let selected: string[] = form[field.Id] ?? [];
|
let selected: string[] = form[field.Id] ?? [];
|
||||||
selected = val.selected ? [...selected, val.key as string] : selected.filter(x => x != val.key);
|
selected = val.selected ? [...selected, val.key as string] : selected.filter(x => x != val.key);
|
||||||
onChange({ [field.Id]: selected })
|
onChange({ [field.Id]: selected })
|
||||||
|
@ -84,7 +81,7 @@ export const Field: React.FunctionComponent<IFieldProps> = (props: React.PropsWi
|
||||||
const f = (field as IConditionalField);
|
const f = (field as IConditionalField);
|
||||||
const visible = form[f.LookupFieldId] == f.MatchValue
|
const visible = form[f.LookupFieldId] == f.MatchValue
|
||||||
if (!visible) return <></>
|
if (!visible) return <></>
|
||||||
return <Field readonly={readonly} field={f.Field} form={form} onChange={onChange} />
|
return <Field field={f.Field} form={form} onChange={onChange} />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { FieldType, GroupDirection, IChoiceField, IConditionalField, IField, IGroupField } from '../../../../Models/FormField';
|
import { FieldType, GroupDirection, IChoiceField, IConditionalField, IField, IGroupField } from '../../model/FormField';
|
||||||
import { ActionButton, ChoiceGroup, DefaultButton, Dialog, DialogFooter, Dropdown, Label, Position, PrimaryButton, SpinButton, Stack, TextField } from '@fluentui/react';
|
import { ActionButton, ChoiceGroup, DefaultButton, Dialog, DialogFooter, Dropdown, Label, Position, PrimaryButton, SpinButton, Stack, TextField } from '@fluentui/react';
|
||||||
import useObject from '../../../../Hooks/UseObject';
|
import useObject from '../../../../Hooks/UseObject';
|
||||||
import { NewField } from '../../../../Util/Util';
|
import { NewField } from '../../../../Util/Util';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { FieldType, GroupDirection, IChoiceField, IConditionalField, IField, IGroupField } from '../../../../Models/FormField';
|
import { FieldType, GroupDirection, IChoiceField, IConditionalField, IField, IGroupField } from '../../model/FormField';
|
||||||
import { ActionButton, Checkbox, Dropdown, Label, MessageBar, MessageBarType, Position, PrimaryButton, SpinButton, Text, TextField, getTheme } from '@fluentui/react';
|
import { ActionButton, Checkbox, Dropdown, Label, MessageBar, MessageBarType, Position, PrimaryButton, SpinButton, Text, TextField, getTheme } from '@fluentui/react';
|
||||||
import { cloneDeep } from '@microsoft/sp-lodash-subset';
|
import { cloneDeep } from '@microsoft/sp-lodash-subset';
|
||||||
import { FieldEditorDialog } from './FieldEditorDialog';
|
import { FieldEditorDialog } from './FieldEditorDialog';
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { IForm } from '../model/FormField';
|
||||||
import useObject from '../../../Hooks/UseObject';
|
import useObject from '../../../Hooks/UseObject';
|
||||||
import { PrimaryButton, Stack, DialogFooter } from '@fluentui/react'
|
import { PrimaryButton, Stack, DialogFooter } from '@fluentui/react'
|
||||||
import { Field } from './Fields/Field';
|
import { Field } from './Fields/Field';
|
||||||
|
@ -7,42 +8,22 @@ import { Placeholder, WebPartTitle } from '@pnp/spfx-controls-react';
|
||||||
import { FormFieldCustomizer } from './Fields/FormFieldCustomizer';
|
import { FormFieldCustomizer } from './Fields/FormFieldCustomizer';
|
||||||
import { GetLookupFields, NewField } from '../../../Util/Util';
|
import { GetLookupFields, NewField } from '../../../Util/Util';
|
||||||
import { cloneDeep } from '@microsoft/sp-lodash-subset';
|
import { cloneDeep } from '@microsoft/sp-lodash-subset';
|
||||||
import { FILLED_FORM_QUERY_KEY, SPFxContext } from '../JsonFormWebPart';
|
import { SPFxContext } from '../JsonFormWebPart';
|
||||||
import { IForm } from '../../../Models/Form';
|
|
||||||
|
|
||||||
export interface IJsonFormProps {
|
export interface IJsonFormProps {
|
||||||
Form: IForm;
|
Form: IForm;
|
||||||
SaveForm: (updated: IForm) => void;
|
SaveForm: (updated: IForm) => void;
|
||||||
Mode: DisplayMode;
|
Mode: DisplayMode;
|
||||||
ServerRelativeUrl?: string;
|
|
||||||
ListId: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const JsonForm: React.FunctionComponent<IJsonFormProps> = (props: React.PropsWithChildren<IJsonFormProps>) => {
|
export const JsonForm: React.FunctionComponent<IJsonFormProps> = (props: React.PropsWithChildren<IJsonFormProps>) => {
|
||||||
const { Mode, ServerRelativeUrl } = props;
|
const { Mode } = props;
|
||||||
const { value: Form, updateValue: UpdateForm, overwriteData: __SETFORM } = useObject<IForm>(props.ServerRelativeUrl ? { Fields: [], Title: "" } : props.Form);
|
const { value: Form, updateValue: UpdateForm } = useObject<IForm>(props.Form);
|
||||||
const { value: filledForm, updateValue, overwriteData: __SETFILLEDFORM } = useObject<any>();
|
const { value: filledForm, updateValue } = useObject<any>();
|
||||||
const { provider } = React.useContext(SPFxContext);
|
const { ListId } = React.useContext(SPFxContext);
|
||||||
|
|
||||||
React.useEffect(() => {
|
console.log(ListId);
|
||||||
if (ServerRelativeUrl != null) {
|
if (ListId == null || ListId == "")
|
||||||
const fetch = async () => {
|
|
||||||
const result = await provider.GetSubmission(ServerRelativeUrl);
|
|
||||||
__SETFILLEDFORM(result.response);
|
|
||||||
__SETFORM(result.form);
|
|
||||||
}
|
|
||||||
fetch();
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const saveForm = async () => {
|
|
||||||
const serverRelativeUrl = await provider.SaveSubmission({ form: Form, response: filledForm });
|
|
||||||
var searchParams = new URLSearchParams(window.location.search);
|
|
||||||
searchParams.set(FILLED_FORM_QUERY_KEY, serverRelativeUrl);
|
|
||||||
window.location.search = searchParams.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.ListId == null || props.ListId == "")
|
|
||||||
return <Placeholder description={'Open the property pane and select a list to store responses'} iconName={'Edit'} iconText={'Please configure web part'} />
|
return <Placeholder description={'Open the property pane and select a list to store responses'} iconName={'Edit'} iconText={'Please configure web part'} />
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -53,14 +34,12 @@ export const JsonForm: React.FunctionComponent<IJsonFormProps> = (props: React.P
|
||||||
<>
|
<>
|
||||||
<Stack tokens={{ childrenGap: 5 }}>
|
<Stack tokens={{ childrenGap: 5 }}>
|
||||||
{Form.Fields.map(field => {
|
{Form.Fields.map(field => {
|
||||||
return <Field readonly={props.ServerRelativeUrl != null} field={field} onChange={updateValue} form={filledForm} />
|
return <Field field={field} onChange={updateValue} form={filledForm} />
|
||||||
})}
|
})}
|
||||||
</Stack>
|
</Stack>
|
||||||
{props.ServerRelativeUrl == null &&
|
<DialogFooter>
|
||||||
<DialogFooter>
|
<PrimaryButton text='Submit' iconProps={{ iconName: "Accept" }} onClick={() => alert(JSON.stringify(filledForm, null, 2))} />
|
||||||
<PrimaryButton text='Submit' iconProps={{ iconName: "Accept" }} onClick={() => saveForm()} />
|
</DialogFooter>
|
||||||
</DialogFooter>
|
|
||||||
}
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
export enum FieldType {
|
||||||
|
Text = "Text",
|
||||||
|
MultilineText = "MultilineText",
|
||||||
|
Number = "Number",
|
||||||
|
Boolean = "Boolean",
|
||||||
|
Choice = "Choice",
|
||||||
|
MultiChoice = "MultiChoice",
|
||||||
|
FieldGroup = "FieldGroup",
|
||||||
|
PlaceHolder = "PlaceHolder",
|
||||||
|
Label = "Label",
|
||||||
|
Conditional = "Conditional",
|
||||||
|
Header = "Header"
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IField {
|
||||||
|
Id: string;
|
||||||
|
DisplayName?: string;
|
||||||
|
Type: FieldType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IChoiceField extends IField {
|
||||||
|
Options: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IConditionalField extends IField {
|
||||||
|
LookupFieldId: string;
|
||||||
|
MatchValue: string | number | boolean;
|
||||||
|
Field: IField;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum GroupDirection {
|
||||||
|
Vertical,
|
||||||
|
Horizontal
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IGroupField extends IField {
|
||||||
|
Fields: (IField | IChoiceField | IGroupField | IConditionalField)[]
|
||||||
|
Direction: GroupDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IForm {
|
||||||
|
Title: string;
|
||||||
|
Fields: (IField | IChoiceField | IGroupField | IConditionalField)[];
|
||||||
|
}
|
Loading…
Reference in New Issue