Skip to content

Commit

Permalink
Adds ability to create files/folders in subfolder using DynamicForm. C…
Browse files Browse the repository at this point in the history
…loses #1901
  • Loading branch information
martinlingstuyl committed Nov 27, 2024
1 parent 79c38b1 commit d16f4bb
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 3 deletions.
1 change: 1 addition & 0 deletions docs/documentation/docs/controls/DynamicForm.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ The `DynamicForm` can be configured with the following properties:
| validationErrorDialogProps | IValidationErrorDialogProps | no | Specifies validation error dialog properties |
| customIcons | { [ columnInternalName: string ]: string } | no | Specifies custom icons for the form. The key of this dictionary is the column internal name, the value is the Fluent UI icon name. |
| storeLastActiveTab | boolean | no | When uploading files: Specifies if last active tab will be stored after the Upload panel has been closed. Note: the value of selected tab is stored in the queryString hash. Default - `true` |
| folderPath | string | no | Server relative or library relative folder to create the item in. This option is only available for document libraries and works only when the contentTypeId is specified and has a base type of type Document or Folder. Defaults to the root folder of the library. |

## Validation Error Dialog Properties `IValidationErrorDialogProps`
| Property | Type | Required | Description |
Expand Down
31 changes: 28 additions & 3 deletions src/controls/dynamicForm/DynamicForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import "@pnp/sp/lists";
import "@pnp/sp/content-types";
import "@pnp/sp/folders";
import "@pnp/sp/items";
import { IFolder } from "@pnp/sp/folders";
import { IInstalledLanguageInfo } from "@pnp/sp/presets/all";
import { cloneDeep, isEqual } from "lodash";
import { ICustomFormatting, ICustomFormattingBodySection, ICustomFormattingNode } from "../../common/utilities/ICustomFormatting";
Expand Down Expand Up @@ -599,7 +600,8 @@ export class DynamicForm extends React.Component<

const library = await sp.web.lists.getById(listId);
const folderFileName = this.getFolderName(objects);
const newFolder = await library.rootFolder.addSubFolderUsingPath(folderFileName);
const folder = !this.props.folderPath ? library.rootFolder : await this.getFolderByPath(this.props.folderPath, library.rootFolder);
const newFolder = await folder.addSubFolderUsingPath(folderFileName);
const fields = await newFolder.listItemAllFields();

if (fields[idField]) {
Expand Down Expand Up @@ -675,8 +677,9 @@ export class DynamicForm extends React.Component<
"_"
).trim() // Replace not allowed chars in folder name and trim empty spaces at the start or end.
: ""; // Empty string will be replaced by SPO with Folder Item ID

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

const folder = !this.props.folderPath ? library.rootFolder : await this.getFolderByPath(this.props.folderPath, library.rootFolder);
const fileCreatedResult = await folder.files.addChunked(encodeURI(itemTitle), await selectedFile.downloadFileContent());
const fields = await fileCreatedResult.file.listItemAllFields();

if (fields[idField]) {
Expand Down Expand Up @@ -1496,4 +1499,26 @@ export class DynamicForm extends React.Component<

return folderNameValue.replace(/["|*|:|<|>|?|/|\\||]/g, "_").trim();
}

/**
* Returns a pnp/sp folder object based on the folderPath and the library the folder is in.
* The folderPath can be a server relative path, but should be in the same library.
* @param folderPath The path to the folder coming from the component properties
* @param rootFolder The rootFolder object of the library
* @returns
*/
private getFolderByPath = async (folderPath: string, rootFolder: IFolder): Promise<IFolder> => {
const libraryFolder = await rootFolder();
const normalizedFolderPath = decodeURIComponent(folderPath).toLowerCase().replace(/\/$/, "");
const serverRelativeLibraryPath = libraryFolder.ServerRelativeUrl.toLowerCase().replace(/\/$/, "");

// In case of a server relative path in the same library, return the folder
if (`${normalizedFolderPath}/`.startsWith(`${serverRelativeLibraryPath}/`)) {
return sp.web.getFolderByServerRelativePath(normalizedFolderPath);
}

// In other cases, expect a list-relative path and return the folder
const folder = sp.web.getFolderByServerRelativePath(`${serverRelativeLibraryPath}/${normalizedFolderPath}`);
return folder;
};
}
7 changes: 7 additions & 0 deletions src/controls/dynamicForm/IDynamicFormProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,11 @@ export interface IDynamicFormProps {
* @default true
*/
storeLastActiveTab?: boolean;

/**
* Library relative folder to create the item in.
* This option is only available for document libraries and works only when the contentTypeId is specified and has a base type of type Document or Folder.
* Defaults to the root folder.
*/
folderPath?: string;
}

0 comments on commit d16f4bb

Please sign in to comment.