Skip to content

Commit

Permalink
Merge branch 'develop' into webtool-id-check
Browse files Browse the repository at this point in the history
  • Loading branch information
jmhauck authored Sep 6, 2024
2 parents 325bd53 + 38a5614 commit 696e578
Show file tree
Hide file tree
Showing 6 changed files with 386 additions and 47 deletions.
5 changes: 5 additions & 0 deletions guides/Adding a Demo.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,8 @@ To incorporate the demo with the other demos in the repository,
* [ ] Edit the command files `build.bat` and `build.sh` in the main repository folder and add your demo so that it is built along with the repository.
* [ ] Edit `demos\index.html` and add your demo.

For debugging, add `--devtool=source-map` to the `build` script in package.json and change the "mode" to "development", e.g.,
```
"build": "webpack --mode=development --node-env=production --devtool=source-map",
```
This makes the source in the debugger readable.
2 changes: 2 additions & 0 deletions packages/common/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,8 @@ export interface ISourceFile {
filename: string;
}

export type TPossibleSourceFile = ISourceFile | undefined;

/**
* Information for storing a resource in a storage item.
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/resources/copyAssociatedFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ export function _detemplatizeResources(
* @param destinationAuthentication Credentials for the request to the storage
* @returns A promise which resolves to a list of the result of the copies
*/
function _sendZipsSeriallyToItem(
export function _sendZipsSeriallyToItem(
zipInfos: IZipInfo[],
destinationItemId: string,
destinationAuthentication: UserSession,
Expand Down
204 changes: 204 additions & 0 deletions packages/common/test/resources/copyAssociatedFiles.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
copyFilesAsResources,
copyAssociatedFilesByType,
_detemplatizeResources,
_sendZipsSeriallyToItem,
} from "../../src/resources/copyAssociatedFiles";
import { createCopyResults } from "../../src/resources/createCopyResults";
import JSZip from "jszip";
Expand Down Expand Up @@ -548,6 +549,209 @@ describe("Module `copyAssociatedFiles`: functions for sending resources to AGO",
} as interfaces.IAssociatedFileCopyResults);
});
});

describe("_sendZipsSeriallyToItem", () => {
it("handles single zip", async () => {
const zipInfos: interfaces.IZipInfo[] = [
{
filename: "zip1",
zip: new JSZip(),
filelist: [
{
folder: "fld",
filename: "file1",
type: interfaces.EFileType.Data,
mimeType: "text",
url: "http://esri.com",
},
],
},
];

const copyZipIntoItemSpy = spyOn(copyZipIntoItem, "copyZipIntoItem").and.callFake(
(zipInfo: interfaces.IZipInfo) => {
return new Promise<interfaces.IZipCopyResults>((resolve) => {
resolve(_createIZipCopyResults(true, true, zipInfo.filelist));
});
},
);

const results: interfaces.IAssociatedFileCopyResults[] = await _sendZipsSeriallyToItem(
zipInfos,
"itm1234567890",
MOCK_USER_SESSION,
);

expect(copyZipIntoItemSpy).toHaveBeenCalledTimes(1);
expect(results).toEqual([
{
folder: "fld",
filename: "file1",
type: interfaces.EFileType.Data,
mimeType: "text",
url: "http://esri.com",
fetchedFromSource: true,
copiedToDestination: true,
},
]);
});

it("handles two zips", async () => {
const zipInfos: interfaces.IZipInfo[] = [
{
filename: "zip1",
zip: new JSZip(),
filelist: [
{
folder: "fld",
filename: "file1",
type: interfaces.EFileType.Data,
mimeType: "text",
url: "http://esri.com",
},
],
},
{
filename: "zip2",
zip: new JSZip(),
filelist: [
{
folder: "fld",
filename: "file2",
type: interfaces.EFileType.Data,
mimeType: "text",
url: "http://esri.com",
},
],
},
];

const copyZipIntoItemSpy = spyOn(copyZipIntoItem, "copyZipIntoItem").and.callFake(
(zipInfo: interfaces.IZipInfo) => {
return new Promise<interfaces.IZipCopyResults>((resolve) => {
resolve(_createIZipCopyResults(true, true, zipInfo.filelist));
});
},
);

const results: interfaces.IAssociatedFileCopyResults[] = await _sendZipsSeriallyToItem(
zipInfos,
"itm1234567890",
MOCK_USER_SESSION,
);

expect(copyZipIntoItemSpy).toHaveBeenCalledTimes(2);
expect(results).toEqual([
{
folder: "fld",
filename: "file1",
type: interfaces.EFileType.Data,
mimeType: "text",
url: "http://esri.com",
fetchedFromSource: true,
copiedToDestination: true,
},
{
folder: "fld",
filename: "file2",
type: interfaces.EFileType.Data,
mimeType: "text",
url: "http://esri.com",
fetchedFromSource: true,
copiedToDestination: true,
},
]);
});

it("handles three zips", async () => {
const zipInfos: interfaces.IZipInfo[] = [
{
filename: "zip1",
zip: new JSZip(),
filelist: [
{
folder: "fld",
filename: "file1",
type: interfaces.EFileType.Data,
mimeType: "text",
url: "http://esri.com",
},
],
},
{
filename: "zip2",
zip: new JSZip(),
filelist: [
{
folder: "fld",
filename: "file2",
type: interfaces.EFileType.Data,
mimeType: "text",
url: "http://esri.com",
},
],
},
{
filename: "zip3",
zip: new JSZip(),
filelist: [
{
folder: "fld",
filename: "file3",
type: interfaces.EFileType.Data,
mimeType: "text",
url: "http://esri.com",
},
],
},
];

const copyZipIntoItemSpy = spyOn(copyZipIntoItem, "copyZipIntoItem").and.callFake(
(zipInfo: interfaces.IZipInfo) => {
return new Promise<interfaces.IZipCopyResults>((resolve) => {
resolve(_createIZipCopyResults(true, true, zipInfo.filelist));
});
},
);

const results: interfaces.IAssociatedFileCopyResults[] = await _sendZipsSeriallyToItem(
zipInfos,
"itm1234567890",
MOCK_USER_SESSION,
);

expect(copyZipIntoItemSpy).toHaveBeenCalledTimes(3);
expect(results).toEqual([
{
folder: "fld",
filename: "file1",
type: interfaces.EFileType.Data,
mimeType: "text",
url: "http://esri.com",
fetchedFromSource: true,
copiedToDestination: true,
},
{
folder: "fld",
filename: "file2",
type: interfaces.EFileType.Data,
mimeType: "text",
url: "http://esri.com",
fetchedFromSource: true,
copiedToDestination: true,
},
{
folder: "fld",
filename: "file3",
type: interfaces.EFileType.Data,
mimeType: "text",
url: "http://esri.com",
fetchedFromSource: true,
copiedToDestination: true,
},
]);
});
});
});

describe("_detemplatizeResources", () => {
Expand Down
39 changes: 39 additions & 0 deletions packages/creator/src/helpers/add-content-to-solution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
IItemProgressCallback,
IItemTemplate,
IItemUpdate,
TPossibleSourceFile,
ISolutionItemData,
ISourceFile,
isWorkforceProject,
Expand Down Expand Up @@ -394,6 +395,10 @@ export function _postProcessIgnoredItems(templates: IItemTemplate[], templateDic
}
return invalidDes ? Object.assign(result, template.data) : result;
}, {});

// adlib breaks Form data files, so we'll save any in the templates list so that we can restore them
const dataFiles = _getDataFilesFromTemplates(templates);

Object.keys(updateDictionary).forEach((k) => {
removeTemplate(templates, k);
templates = templates.map((t) => {
Expand All @@ -402,9 +407,27 @@ export function _postProcessIgnoredItems(templates: IItemTemplate[], templateDic
});
});

// Restore the data files to the templates
_restoreDataFilesToTemplates(templates, dataFiles);

return templates;
}

/**
* Retrieves the Form dataFiles from a list of templates and removes them from the templates.
*
* @param templates Templates to be scanned and have their `dataFile` property deleted
* @returns List of Form dataFiles from the templates, which have their `dataFile` property removed;
* the list is in the same order as the templates and has `undefined` for templates that don't have a dataFile
*/
export function _getDataFilesFromTemplates(templates: IItemTemplate[]): TPossibleSourceFile[] {
return templates.reduce((acc: ISourceFile[], template: IItemTemplate) => {
const dataFile = template.dataFile;
delete template.dataFile;
return acc.concat(dataFile);
}, []);
}

/**
* Recursively runs through an object to find and replace any strings found in a dictionary.
*
Expand Down Expand Up @@ -477,6 +500,22 @@ export function _replaceRemainingIdsInString(ids: string[], str: string): string
return updatedStr;
}

/**
* Restores the Form dataFiles to the templates.
*
* @param templates Templates to be updated with the dataFiles; the `dataFile` property is added back to the templates
* that originally had it
* @param dataFiles List of Form dataFiles to be restored to the templates; the list is in the same order
* as the templates and has `undefined` for templates that don't have a dataFile
*/
export function _restoreDataFilesToTemplates(templates: IItemTemplate[], dataFiles: TPossibleSourceFile[]): void {
templates.forEach((template: IItemTemplate, i: number) => {
if (dataFiles[i]) {
template.dataFile = dataFiles[i];
}
});
}

/**
* Finds and templatizes any URLs in solution items' descriptions.
*
Expand Down
Loading

0 comments on commit 696e578

Please sign in to comment.