Skip to content

Commit

Permalink
Tweaks to code and test web part to accomodate changes made in pnp#1625
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom German committed Dec 1, 2023
1 parent 8d665e8 commit e027b1a
Show file tree
Hide file tree
Showing 11 changed files with 91 additions and 80 deletions.
2 changes: 1 addition & 1 deletion src/common/utilities/CustomFormatting.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { Icon } from "office-ui-fabric-react";
import { Icon } from "@fluentui/react/lib/Icon";
import { FormulaEvaluation } from "./FormulaEvaluation";
import { ASTNode, Context } from "./FormulaEvaluation.types";
import { ICustomFormattingExpressionNode, ICustomFormattingNode } from "./ICustomFormatting";
Expand Down
138 changes: 68 additions & 70 deletions src/controls/dynamicForm/DynamicForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,13 @@ import { MessageBar, MessageBarType } from "@fluentui/react/lib/MessageBar";
import { ProgressIndicator } from "@fluentui/react/lib/ProgressIndicator";
import { IStackTokens, Stack } from "@fluentui/react/lib/Stack";
import { Icon } from "@fluentui/react/lib/components/Icon/Icon";
import * as React from "react";
import { IUploadImageResult } from "../../common/SPEntities";
import SPservice from "../../services/SPService";
import { IFilePickerResult } from "../filePicker";
import { DynamicField } from "./dynamicField";
import {
DateFormat,
FieldChangeAdditionalData,
IDynamicFieldProps,
} from "./dynamicField/IDynamicFieldProps";
import { IFilePickerResult } from "../filePicker";
import { IDynamicFormProps } from "./IDynamicFormProps";
import { IDynamicFormState } from "./IDynamicFormState";
import { FilePicker, IFilePickerResult } from "../filePicker";

// pnp/sp, helpers / utils
import { sp } from "@pnp/sp";
Expand All @@ -48,6 +42,10 @@ import { FormulaEvaluation } from "../../common/utilities/FormulaEvaluation";
import { Context } from "../../common/utilities/FormulaEvaluation.types";
import CustomFormattingHelper from "../../common/utilities/CustomFormatting";

// Dynamic Form Props / State
import { IDynamicFormProps } from "./IDynamicFormProps";
import { IDynamicFormState } from "./IDynamicFormState";

const stackTokens: IStackTokens = { childrenGap: 20 };

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

// Content Type
let contentTypeId = this.props.contentTypeId;
if (this.state.contentTypeId !== undefined) contentTypeId = this.state.contentTypeId;

return (
<div>
{infoErrorMessages.map((ie, i) => (
Expand All @@ -196,8 +198,8 @@ export class DynamicForm extends React.Component<
{headerContent}
{this.props.enableFileSelection === true &&
this.props.listItemId === undefined &&
this.props.contentTypeId !== undefined &&
this.props.contentTypeId.startsWith("0x0101") &&
contentTypeId !== undefined &&
contentTypeId.startsWith("0x0101") &&
this.renderFileSelectionControl()}
{(bodySections.length > 0 && !customFormattingDisabled) && bodySections
.filter(bs => bs.fields.filter(bsf => hiddenByFormula.indexOf(bsf) < 0).length > 0)
Expand Down Expand Up @@ -311,14 +313,18 @@ export class DynamicForm extends React.Component<
const {
listId,
listItemId,
contentTypeId,
onSubmitted,
onBeforeSubmit,
onSubmitError,
enableFileSelection,
validationErrorDialogProps,
returnListItemInstanceOnSubmit
} = this.props;

let contentTypeId = this.props.contentTypeId;
if (this.state.contentTypeId !== undefined) contentTypeId = this.state.contentTypeId;

const fileSelectRendered = !listItemId && contentTypeId.startsWith("0x0101") && enableFileSelection === true;

try {

Expand Down Expand Up @@ -351,7 +357,7 @@ export class DynamicForm extends React.Component<
}

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

if (enableFileSelection === true && this.state.selectedFile === undefined && this.props.listItemId === undefined) {
this.setState({
missingSelectedFile: true,
isValidationErrorDialogOpen:
validationErrorDialogProps
?.showDialogOnValidationError === true,
validationErrors
});
return;
}

if (enableFileSelection === true && this.state.selectedFile === undefined && this.props.listItemId === undefined) {
if (fileSelectRendered === true && this.state.selectedFile === undefined && this.props.listItemId === undefined) {
this.setState({
missingSelectedFile: true,
isValidationErrorDialogOpen:
Expand Down Expand Up @@ -546,7 +541,7 @@ export class DynamicForm extends React.Component<
(!contentTypeId.startsWith("0x0120") &&
contentTypeId.startsWith("0x01"))
) {
if (contentTypeId === undefined || enableFileSelection === true) {
if (fileSelectRendered === true) {
await this.addFileToLibrary(objects);
}
else {
Expand Down Expand Up @@ -620,10 +615,7 @@ export class DynamicForm extends React.Component<
}
console.log("Error", error);
}
} else if (contentTypeId.startsWith("0x01") && enableFileSelection === true) {
// We are adding a folder or a Document Set
await this.addFileToLibrary(objects);
}
}

this.setState({
isSaving: false,
Expand All @@ -638,6 +630,9 @@ export class DynamicForm extends React.Component<
}
};

/**
* Adds selected file to the library
*/
private addFileToLibrary = async (objects: {}): Promise<void> => {
const {
selectedFile
Expand All @@ -651,49 +646,52 @@ export class DynamicForm extends React.Component<
returnListItemInstanceOnSubmit
} = this.props;

try {
const idField = "ID";
const contentTypeIdField = "ContentTypeId";

const library = await sp.web.lists.getById(listId);
const itemTitle =
selectedFile !== undefined && selectedFile.fileName !== undefined && selectedFile.fileName !== ""
? (selectedFile.fileName as string).replace(
/["|*|:|<|>|?|/|\\||]/g,
"_"
) // Replace not allowed chars in folder name
: ""; // Empty string will be replaced by SPO with Folder Item ID

const fileCreatedResult = await library.rootFolder.files.addChunked(encodeURI(itemTitle), await selectedFile.downloadFileContent());
const fields = await fileCreatedResult.file.listItemAllFields();

if (fields[idField]) {
// Read the ID of the just created folder or Document Set
const folderId = fields[idField];

// Set the content type ID for the target item
objects[contentTypeIdField] = contentTypeId;
// Update the just created folder or Document Set
const iur = await library.items.getById(folderId).update(objects);
if (onSubmitted) {
onSubmitted(
iur.data,
returnListItemInstanceOnSubmit !== false
? iur.item
: undefined
);

if (selectedFile !== undefined) {
try {
const idField = "ID";
const contentTypeIdField = "ContentTypeId";

const library = await sp.web.lists.getById(listId);
const itemTitle =
selectedFile !== undefined && selectedFile.fileName !== undefined && selectedFile.fileName !== ""
? (selectedFile.fileName as string).replace(
/["|*|:|<|>|?|/|\\||]/g,
"_"
) // Replace not allowed chars in folder name
: ""; // Empty string will be replaced by SPO with Folder Item ID

const fileCreatedResult = await library.rootFolder.files.addChunked(encodeURI(itemTitle), await selectedFile.downloadFileContent());
const fields = await fileCreatedResult.file.listItemAllFields();

if (fields[idField]) {
// Read the ID of the just created folder or Document Set
const folderId = fields[idField];

// Set the content type ID for the target item
objects[contentTypeIdField] = contentTypeId;
// Update the just created folder or Document Set
const iur = await library.items.getById(folderId).update(objects);
if (onSubmitted) {
onSubmitted(
iur.data,
returnListItemInstanceOnSubmit !== false
? iur.item
: undefined
);
}
} else {
throw new Error(
"Unable to read the ID of the just created folder or Document Set"
);
}
} catch (error) {
if (onSubmitError) {
onSubmitError(objects, error);
}
console.log("Error", error);
}
} else {
throw new Error(
"Unable to read the ID of the just created folder or Document Set"
);
}
} catch (error) {
if (onSubmitError) {
onSubmitError(objects, error);
}
console.log("Error", error);
}
}

/**
Expand Down Expand Up @@ -999,6 +997,7 @@ export class DynamicForm extends React.Component<
}

this.setState({
contentTypeId,
clientValidationFormulas,
customFormatting: {
header: headerJSON,
Expand Down Expand Up @@ -1435,5 +1434,4 @@ export class DynamicForm extends React.Component<
}
}


}
3 changes: 2 additions & 1 deletion src/controls/dynamicForm/IDynamicFormState.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IInstalledLanguageInfo } from '@pnp/sp/regional-settings';
import { ISPField } from '../../common/SPEntities';
import { MessageBarType } from 'office-ui-fabric-react/lib/MessageBar';
import { MessageBarType } from '@fluentui/react/lib/MessageBar';
import { ICustomFormattingBodySection, ICustomFormattingNode } from '../../common/utilities/ICustomFormatting';
import { IDynamicFieldProps } from './dynamicField/IDynamicFieldProps';
import { IFilePickerResult } from "../filePicker";
Expand Down Expand Up @@ -33,4 +33,5 @@ export interface IDynamicFormState {
isValidationErrorDialogOpen: boolean;
selectedFile?: IFilePickerResult;
missingSelectedFile?: boolean;
contentTypeId?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"dynamicFormCustomFormattingEnabled": true,
"dynamicFormClientSideValidationEnabled": true,
"dynamicFormFieldValidationEnabled" : true,
"dynamicFormFileSelectionEnabled": false,
"controlVisibility": {
"all": false,
"accessibleAccordion": false,
Expand Down
15 changes: 12 additions & 3 deletions src/webparts/controlsTest/ControlsTestWebPart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,13 @@ export default class ControlsTestWebPart extends BaseClientSideWebPart<IControls
}
); */

const element: React.ReactElement<IControlsTestProps> = React.createElement(
let listItemId: number = Number(this.properties.dynamicFormListItemId);
if (listItemId < 1 || isNaN(listItemId)) {
listItemId = undefined;
}
console.log(listItemId);

const element: React.ReactElement<IControlsTestProps> = React.createElement(
ControlsTest,
{

Expand All @@ -94,11 +99,12 @@ export default class ControlsTestWebPart extends BaseClientSideWebPart<IControls
title: this.properties.title ?? "Sample title",
displayMode: this.displayMode,
dynamicFormListId: this.properties.dynamicFormListId,
dynamicFormListItemId: this.properties.dynamicFormListItemId,
dynamicFormListItemId: listItemId?.toString() ?? undefined,
dynamicFormErrorDialogEnabled: this.properties.dynamicFormErrorDialogEnabled,
dynamicFormCustomFormattingEnabled: this.properties.dynamicFormCustomFormattingEnabled,
dynamicFormClientSideValidationEnabled: this.properties.dynamicFormClientSideValidationEnabled,
dynamicFormFieldValidationEnabled: this.properties.dynamicFormFieldValidationEnabled,
dynamicFormFileSelectionEnabled: this.properties.dynamicFormFileSelectionEnabled,
onOpenPropertyPane: () => {
this.context.propertyPane.open();
},
Expand Down Expand Up @@ -153,7 +159,7 @@ export default class ControlsTestWebPart extends BaseClientSideWebPart<IControls
}
}),
PropertyPaneTextField('dynamicFormListItemId', {
label: 'List Item ID for Dynamic Form'
label: 'List Item ID for Dynamic Form',
}),
PropertyPaneToggle('dynamicFormErrorDialogEnabled', {
label: 'Dynamic Form Error Dialog'
Expand All @@ -167,6 +173,9 @@ export default class ControlsTestWebPart extends BaseClientSideWebPart<IControls
PropertyPaneToggle('dynamicFormFieldValidationEnabled', {
label: 'Dynamic Form Field Validation'
}),
PropertyPaneToggle('dynamicFormFileSelectionEnabled', {
label: 'Dynamic Form File Selection'
}),
]
},
{
Expand Down
1 change: 1 addition & 0 deletions src/webparts/controlsTest/IControlsTestWebPartProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ export interface IControlsTestWebPartProps {
dynamicFormCustomFormattingEnabled: boolean;
dynamicFormClientSideValidationEnabled: boolean;
dynamicFormFieldValidationEnabled: boolean;
dynamicFormFileSelectionEnabled: boolean;
controlVisibility: ControlVisibility
}
1 change: 1 addition & 0 deletions src/webparts/controlsTest/components/ControlsTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,7 @@ export default class ControlsTest extends React.Component<IControlsTestProps, IC
useClientSideValidation={this.props.dynamicFormClientSideValidationEnabled}
useFieldValidation={this.props.dynamicFormFieldValidationEnabled}
useCustomFormatting={this.props.dynamicFormCustomFormattingEnabled}
enableFileSelection={this.props.dynamicFormFileSelectionEnabled}
/>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/webparts/controlsTest/propertyPane/IListPickerState.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
import { IDropdownOption } from '@fluentui/react/lib/Dropdown';

export interface IListPickerState {
loading: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
IPropertyPaneField,
PropertyPaneFieldType
} from '@microsoft/sp-property-pane';
import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
import { IDropdownOption } from '@fluentui/react/lib/Dropdown';
import { IPropertyPaneCustomFieldProps } from '@microsoft/sp-property-pane';
import { WebPartContext } from '@microsoft/sp-webpart-base';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { ValidControls } from '../../IControlsTestWebPartProps';
import { TextField, Toggle } from 'office-ui-fabric-react';
import { TextField, Toggle } from '@fluentui/react';

export interface IControlTogglesProps {
label: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
import { Spinner } from 'office-ui-fabric-react/lib/components/Spinner';
import { Dropdown, IDropdownOption } from '@fluentui/react/lib/components/Dropdown';
import { Spinner } from '@fluentui/react/lib/components/Spinner';
import { SPHttpClient } from "@microsoft/sp-http";
import { WebPartContext } from '@microsoft/sp-webpart-base';
import { ISPList } from '../../../../common/SPEntities';
Expand Down

0 comments on commit e027b1a

Please sign in to comment.