Skip to content

Commit e027b1a

Browse files
author
Tom German
committed
Tweaks to code and test web part to accomodate changes made in #1625
1 parent 8d665e8 commit e027b1a

File tree

11 files changed

+91
-80
lines changed

11 files changed

+91
-80
lines changed

src/common/utilities/CustomFormatting.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from "react";
2-
import { Icon } from "office-ui-fabric-react";
2+
import { Icon } from "@fluentui/react/lib/Icon";
33
import { FormulaEvaluation } from "./FormulaEvaluation";
44
import { ASTNode, Context } from "./FormulaEvaluation.types";
55
import { ICustomFormattingExpressionNode, ICustomFormattingNode } from "./ICustomFormatting";

src/controls/dynamicForm/DynamicForm.tsx

Lines changed: 68 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,13 @@ import { MessageBar, MessageBarType } from "@fluentui/react/lib/MessageBar";
1818
import { ProgressIndicator } from "@fluentui/react/lib/ProgressIndicator";
1919
import { IStackTokens, Stack } from "@fluentui/react/lib/Stack";
2020
import { Icon } from "@fluentui/react/lib/components/Icon/Icon";
21-
import * as React from "react";
22-
import { IUploadImageResult } from "../../common/SPEntities";
23-
import SPservice from "../../services/SPService";
24-
import { IFilePickerResult } from "../filePicker";
2521
import { DynamicField } from "./dynamicField";
2622
import {
2723
DateFormat,
2824
FieldChangeAdditionalData,
2925
IDynamicFieldProps,
3026
} from "./dynamicField/IDynamicFieldProps";
31-
import { IFilePickerResult } from "../filePicker";
32-
import { IDynamicFormProps } from "./IDynamicFormProps";
33-
import { IDynamicFormState } from "./IDynamicFormState";
27+
import { FilePicker, IFilePickerResult } from "../filePicker";
3428

3529
// pnp/sp, helpers / utils
3630
import { sp } from "@pnp/sp";
@@ -48,6 +42,10 @@ import { FormulaEvaluation } from "../../common/utilities/FormulaEvaluation";
4842
import { Context } from "../../common/utilities/FormulaEvaluation.types";
4943
import CustomFormattingHelper from "../../common/utilities/CustomFormatting";
5044

45+
// Dynamic Form Props / State
46+
import { IDynamicFormProps } from "./IDynamicFormProps";
47+
import { IDynamicFormState } from "./IDynamicFormState";
48+
5149
const stackTokens: IStackTokens = { childrenGap: 20 };
5250

5351
/**
@@ -179,6 +177,10 @@ export class DynamicForm extends React.Component<
179177
footerContent = this._customFormatter.renderCustomFormatContent(customFormatting.footer, this.getFormValuesForValidation(), true) as JSX.Element;
180178
}
181179

180+
// Content Type
181+
let contentTypeId = this.props.contentTypeId;
182+
if (this.state.contentTypeId !== undefined) contentTypeId = this.state.contentTypeId;
183+
182184
return (
183185
<div>
184186
{infoErrorMessages.map((ie, i) => (
@@ -196,8 +198,8 @@ export class DynamicForm extends React.Component<
196198
{headerContent}
197199
{this.props.enableFileSelection === true &&
198200
this.props.listItemId === undefined &&
199-
this.props.contentTypeId !== undefined &&
200-
this.props.contentTypeId.startsWith("0x0101") &&
201+
contentTypeId !== undefined &&
202+
contentTypeId.startsWith("0x0101") &&
201203
this.renderFileSelectionControl()}
202204
{(bodySections.length > 0 && !customFormattingDisabled) && bodySections
203205
.filter(bs => bs.fields.filter(bsf => hiddenByFormula.indexOf(bsf) < 0).length > 0)
@@ -311,14 +313,18 @@ export class DynamicForm extends React.Component<
311313
const {
312314
listId,
313315
listItemId,
314-
contentTypeId,
315316
onSubmitted,
316317
onBeforeSubmit,
317318
onSubmitError,
318319
enableFileSelection,
319320
validationErrorDialogProps,
320321
returnListItemInstanceOnSubmit
321322
} = this.props;
323+
324+
let contentTypeId = this.props.contentTypeId;
325+
if (this.state.contentTypeId !== undefined) contentTypeId = this.state.contentTypeId;
326+
327+
const fileSelectRendered = !listItemId && contentTypeId.startsWith("0x0101") && enableFileSelection === true;
322328

323329
try {
324330

@@ -351,7 +357,7 @@ export class DynamicForm extends React.Component<
351357
}
352358

353359
// Check min and max values for number fields
354-
if (field.fieldType === "Number" && field.newValue !== undefined) {
360+
if (field.fieldType === "Number" && field.newValue !== undefined && field.newValue.trim() !== "") {
355361
if ((field.newValue < field.minimumValue) || (field.newValue > field.maximumValue)) {
356362
shouldBeReturnBack = true;
357363
}
@@ -380,18 +386,7 @@ export class DynamicForm extends React.Component<
380386
return;
381387
}
382388

383-
if (enableFileSelection === true && this.state.selectedFile === undefined && this.props.listItemId === undefined) {
384-
this.setState({
385-
missingSelectedFile: true,
386-
isValidationErrorDialogOpen:
387-
validationErrorDialogProps
388-
?.showDialogOnValidationError === true,
389-
validationErrors
390-
});
391-
return;
392-
}
393-
394-
if (enableFileSelection === true && this.state.selectedFile === undefined && this.props.listItemId === undefined) {
389+
if (fileSelectRendered === true && this.state.selectedFile === undefined && this.props.listItemId === undefined) {
395390
this.setState({
396391
missingSelectedFile: true,
397392
isValidationErrorDialogOpen:
@@ -546,7 +541,7 @@ export class DynamicForm extends React.Component<
546541
(!contentTypeId.startsWith("0x0120") &&
547542
contentTypeId.startsWith("0x01"))
548543
) {
549-
if (contentTypeId === undefined || enableFileSelection === true) {
544+
if (fileSelectRendered === true) {
550545
await this.addFileToLibrary(objects);
551546
}
552547
else {
@@ -620,10 +615,7 @@ export class DynamicForm extends React.Component<
620615
}
621616
console.log("Error", error);
622617
}
623-
} else if (contentTypeId.startsWith("0x01") && enableFileSelection === true) {
624-
// We are adding a folder or a Document Set
625-
await this.addFileToLibrary(objects);
626-
}
618+
}
627619

628620
this.setState({
629621
isSaving: false,
@@ -638,6 +630,9 @@ export class DynamicForm extends React.Component<
638630
}
639631
};
640632

633+
/**
634+
* Adds selected file to the library
635+
*/
641636
private addFileToLibrary = async (objects: {}): Promise<void> => {
642637
const {
643638
selectedFile
@@ -651,49 +646,52 @@ export class DynamicForm extends React.Component<
651646
returnListItemInstanceOnSubmit
652647
} = this.props;
653648

654-
try {
655-
const idField = "ID";
656-
const contentTypeIdField = "ContentTypeId";
657-
658-
const library = await sp.web.lists.getById(listId);
659-
const itemTitle =
660-
selectedFile !== undefined && selectedFile.fileName !== undefined && selectedFile.fileName !== ""
661-
? (selectedFile.fileName as string).replace(
662-
/["|*|:|<|>|?|/|\\||]/g,
663-
"_"
664-
) // Replace not allowed chars in folder name
665-
: ""; // Empty string will be replaced by SPO with Folder Item ID
666-
667-
const fileCreatedResult = await library.rootFolder.files.addChunked(encodeURI(itemTitle), await selectedFile.downloadFileContent());
668-
const fields = await fileCreatedResult.file.listItemAllFields();
669-
670-
if (fields[idField]) {
671-
// Read the ID of the just created folder or Document Set
672-
const folderId = fields[idField];
673-
674-
// Set the content type ID for the target item
675-
objects[contentTypeIdField] = contentTypeId;
676-
// Update the just created folder or Document Set
677-
const iur = await library.items.getById(folderId).update(objects);
678-
if (onSubmitted) {
679-
onSubmitted(
680-
iur.data,
681-
returnListItemInstanceOnSubmit !== false
682-
? iur.item
683-
: undefined
684-
);
649+
650+
if (selectedFile !== undefined) {
651+
try {
652+
const idField = "ID";
653+
const contentTypeIdField = "ContentTypeId";
654+
655+
const library = await sp.web.lists.getById(listId);
656+
const itemTitle =
657+
selectedFile !== undefined && selectedFile.fileName !== undefined && selectedFile.fileName !== ""
658+
? (selectedFile.fileName as string).replace(
659+
/["|*|:|<|>|?|/|\\||]/g,
660+
"_"
661+
) // Replace not allowed chars in folder name
662+
: ""; // Empty string will be replaced by SPO with Folder Item ID
663+
664+
const fileCreatedResult = await library.rootFolder.files.addChunked(encodeURI(itemTitle), await selectedFile.downloadFileContent());
665+
const fields = await fileCreatedResult.file.listItemAllFields();
666+
667+
if (fields[idField]) {
668+
// Read the ID of the just created folder or Document Set
669+
const folderId = fields[idField];
670+
671+
// Set the content type ID for the target item
672+
objects[contentTypeIdField] = contentTypeId;
673+
// Update the just created folder or Document Set
674+
const iur = await library.items.getById(folderId).update(objects);
675+
if (onSubmitted) {
676+
onSubmitted(
677+
iur.data,
678+
returnListItemInstanceOnSubmit !== false
679+
? iur.item
680+
: undefined
681+
);
682+
}
683+
} else {
684+
throw new Error(
685+
"Unable to read the ID of the just created folder or Document Set"
686+
);
687+
}
688+
} catch (error) {
689+
if (onSubmitError) {
690+
onSubmitError(objects, error);
691+
}
692+
console.log("Error", error);
685693
}
686-
} else {
687-
throw new Error(
688-
"Unable to read the ID of the just created folder or Document Set"
689-
);
690694
}
691-
} catch (error) {
692-
if (onSubmitError) {
693-
onSubmitError(objects, error);
694-
}
695-
console.log("Error", error);
696-
}
697695
}
698696

699697
/**
@@ -999,6 +997,7 @@ export class DynamicForm extends React.Component<
999997
}
1000998

1001999
this.setState({
1000+
contentTypeId,
10021001
clientValidationFormulas,
10031002
customFormatting: {
10041003
header: headerJSON,
@@ -1435,5 +1434,4 @@ export class DynamicForm extends React.Component<
14351434
}
14361435
}
14371436

1438-
14391437
}

src/controls/dynamicForm/IDynamicFormState.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { IInstalledLanguageInfo } from '@pnp/sp/regional-settings';
22
import { ISPField } from '../../common/SPEntities';
3-
import { MessageBarType } from 'office-ui-fabric-react/lib/MessageBar';
3+
import { MessageBarType } from '@fluentui/react/lib/MessageBar';
44
import { ICustomFormattingBodySection, ICustomFormattingNode } from '../../common/utilities/ICustomFormatting';
55
import { IDynamicFieldProps } from './dynamicField/IDynamicFieldProps';
66
import { IFilePickerResult } from "../filePicker";
@@ -33,4 +33,5 @@ export interface IDynamicFormState {
3333
isValidationErrorDialogOpen: boolean;
3434
selectedFile?: IFilePickerResult;
3535
missingSelectedFile?: boolean;
36+
contentTypeId?: string;
3637
}

src/webparts/controlsTest/ControlsTestWebPart.manifest.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"dynamicFormCustomFormattingEnabled": true,
3030
"dynamicFormClientSideValidationEnabled": true,
3131
"dynamicFormFieldValidationEnabled" : true,
32+
"dynamicFormFileSelectionEnabled": false,
3233
"controlVisibility": {
3334
"all": false,
3435
"accessibleAccordion": false,

src/webparts/controlsTest/ControlsTestWebPart.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,13 @@ export default class ControlsTestWebPart extends BaseClientSideWebPart<IControls
8282
}
8383
); */
8484

85-
const element: React.ReactElement<IControlsTestProps> = React.createElement(
85+
let listItemId: number = Number(this.properties.dynamicFormListItemId);
86+
if (listItemId < 1 || isNaN(listItemId)) {
87+
listItemId = undefined;
88+
}
89+
console.log(listItemId);
8690

91+
const element: React.ReactElement<IControlsTestProps> = React.createElement(
8792
ControlsTest,
8893
{
8994

@@ -94,11 +99,12 @@ export default class ControlsTestWebPart extends BaseClientSideWebPart<IControls
9499
title: this.properties.title ?? "Sample title",
95100
displayMode: this.displayMode,
96101
dynamicFormListId: this.properties.dynamicFormListId,
97-
dynamicFormListItemId: this.properties.dynamicFormListItemId,
102+
dynamicFormListItemId: listItemId?.toString() ?? undefined,
98103
dynamicFormErrorDialogEnabled: this.properties.dynamicFormErrorDialogEnabled,
99104
dynamicFormCustomFormattingEnabled: this.properties.dynamicFormCustomFormattingEnabled,
100105
dynamicFormClientSideValidationEnabled: this.properties.dynamicFormClientSideValidationEnabled,
101106
dynamicFormFieldValidationEnabled: this.properties.dynamicFormFieldValidationEnabled,
107+
dynamicFormFileSelectionEnabled: this.properties.dynamicFormFileSelectionEnabled,
102108
onOpenPropertyPane: () => {
103109
this.context.propertyPane.open();
104110
},
@@ -153,7 +159,7 @@ export default class ControlsTestWebPart extends BaseClientSideWebPart<IControls
153159
}
154160
}),
155161
PropertyPaneTextField('dynamicFormListItemId', {
156-
label: 'List Item ID for Dynamic Form'
162+
label: 'List Item ID for Dynamic Form',
157163
}),
158164
PropertyPaneToggle('dynamicFormErrorDialogEnabled', {
159165
label: 'Dynamic Form Error Dialog'
@@ -167,6 +173,9 @@ export default class ControlsTestWebPart extends BaseClientSideWebPart<IControls
167173
PropertyPaneToggle('dynamicFormFieldValidationEnabled', {
168174
label: 'Dynamic Form Field Validation'
169175
}),
176+
PropertyPaneToggle('dynamicFormFileSelectionEnabled', {
177+
label: 'Dynamic Form File Selection'
178+
}),
170179
]
171180
},
172181
{

src/webparts/controlsTest/IControlsTestWebPartProps.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@ export interface IControlsTestWebPartProps {
3030
dynamicFormCustomFormattingEnabled: boolean;
3131
dynamicFormClientSideValidationEnabled: boolean;
3232
dynamicFormFieldValidationEnabled: boolean;
33+
dynamicFormFileSelectionEnabled: boolean;
3334
controlVisibility: ControlVisibility
3435
}

src/webparts/controlsTest/components/ControlsTest.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,7 @@ export default class ControlsTest extends React.Component<IControlsTestProps, IC
974974
useClientSideValidation={this.props.dynamicFormClientSideValidationEnabled}
975975
useFieldValidation={this.props.dynamicFormFieldValidationEnabled}
976976
useCustomFormatting={this.props.dynamicFormCustomFormattingEnabled}
977+
enableFileSelection={this.props.dynamicFormFileSelectionEnabled}
977978
/>
978979
</div>
979980
</div>

src/webparts/controlsTest/propertyPane/IListPickerState.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
1+
import { IDropdownOption } from '@fluentui/react/lib/Dropdown';
22

33
export interface IListPickerState {
44
loading: boolean;

src/webparts/controlsTest/propertyPane/PropertyPaneListPicker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
IPropertyPaneField,
66
PropertyPaneFieldType
77
} from '@microsoft/sp-property-pane';
8-
import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
8+
import { IDropdownOption } from '@fluentui/react/lib/Dropdown';
99
import { IPropertyPaneCustomFieldProps } from '@microsoft/sp-property-pane';
1010
import { WebPartContext } from '@microsoft/sp-webpart-base';
1111

src/webparts/controlsTest/propertyPane/controls/ControlToggles.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { ValidControls } from '../../IControlsTestWebPartProps';
3-
import { TextField, Toggle } from 'office-ui-fabric-react';
3+
import { TextField, Toggle } from '@fluentui/react';
44

55
export interface IControlTogglesProps {
66
label: string;

0 commit comments

Comments
 (0)