From fe25880fbc176cbd5fec6942dd3c2336a658eb96 Mon Sep 17 00:00:00 2001 From: fyyyyy Date: Tue, 15 Aug 2023 19:08:35 +0200 Subject: [PATCH 01/13] Feature: add zip download to dry run results page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See issue #19318 Signed-off-by: fyyyyy Signed-off-by: Fredrik Adelöw --- .../DryRunResults/DryRunResultsList.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx index 462c3b58fd..9163261985 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx @@ -25,6 +25,7 @@ import { makeStyles } from '@material-ui/core/styles'; import CancelIcon from '@material-ui/icons/Cancel'; import CheckIcon from '@material-ui/icons/Check'; import DeleteIcon from '@material-ui/icons/Delete'; +import DownloadIcon from '@material-ui/icons/GetApp'; import React from 'react'; import { useDryRun } from '../DryRunContext'; @@ -67,9 +68,18 @@ export function DryRunResultsList() { + dryRun.downloadResult(result.id)} + > + + dryRun.deleteResult(result.id)} > From d59fd8cf06c78c77c491acc72892b91358f96ba1 Mon Sep 17 00:00:00 2001 From: fyyyyy Date: Tue, 15 Aug 2023 19:10:14 +0200 Subject: [PATCH 02/13] Update DryRunContext.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add zip download fn Signed-off-by: fyyyyy Signed-off-by: Fredrik Adelöw --- .../TemplateEditorPage/DryRunContext.tsx | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx index a617eebe1e..47d121b616 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx @@ -26,6 +26,7 @@ import React, { useRef, useState, } from 'react'; +import * as zip from "@zip.js/zip.js"; import { scaffolderApiRef, ScaffolderDryRunResponse, @@ -50,6 +51,7 @@ interface DryRun { selectResult(id: number): void; deleteResult(id: number): void; + downloadResult(id: number): void; execute(options: DryRunOptions): Promise; } @@ -122,6 +124,22 @@ export function DryRunProvider(props: DryRunProviderProps) { }); }, []); + const downloadResult = useCallback((id: number) => { + setState(prevState => { + const index = prevState.results.findIndex(r => r.id === id); + if (index === -1) { + return prevState; + } + const result = prevState.results[index]; + console.log('Result', result.id); + createZipDownload(result.directoryContents, 'result_' + result.id) + return { + results: prevState.results, + selectedResult: prevState.selectedResult, + }; + }); + }, []); + const execute = useCallback( async (options: DryRunOptions) => { if (!scaffolderApi.dryRun) { @@ -158,6 +176,7 @@ export function DryRunProvider(props: DryRunProviderProps) { ...state, selectResult, deleteResult, + downloadResult, execute, }), [state, selectResult, deleteResult, execute], @@ -177,3 +196,36 @@ export function useDryRun(): DryRun { } return value; } + +async function createZipDownload(directoryContents: { path: string; base64Content: string; executable: boolean; }[], name: string) { + // needs zip.js + + // Creates a BlobWriter object where the zip content will be written. + const zipFileWriter = new zip.BlobWriter(); + + // Creates a ZipWriter object writing data via `zipFileWriter`, adds the entry + const zipWriter = new zip.ZipWriter(zipFileWriter); + + for (const d of directoryContents) { + // Decode text content from base64 to ascii + const converted = atob(d.base64Content); + + // Creates a TextReader object storing the text of the entry to add in the zip (i.e. "Hello world!"). + const fileReader = new zip.TextReader(converted); + + await zipWriter.add(d.path, fileReader); + } + + // Closes the writer. + await zipWriter.close(); + + // Retrieves the Blob object containing the zip content into `zipFileBlob` + const zipFileBlob = await zipFileWriter.getData(); + + // Download zip + const a = document.createElement('a'); + a.href = URL.createObjectURL(zipFileBlob); + a.download = `dry-run-${name}.zip`; + a.click(); +} + From 740b5bb8d4aa6ece15573b5859cac6a757807831 Mon Sep 17 00:00:00 2001 From: fyyyyy Date: Tue, 15 Aug 2023 19:11:00 +0200 Subject: [PATCH 03/13] add zip.js to package.json for scaffolder plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: fyyyyy Signed-off-by: Fredrik Adelöw --- plugins/scaffolder/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 47e628bfcb..f5cf5eb6bc 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -73,6 +73,7 @@ "@rjsf/validator-ajv8": "5.7.3", "@types/react": "^16.13.1 || ^17.0.0", "@uiw/react-codemirror": "^4.9.3", + "@zip.js/zip.js": "^2.7.24", "classnames": "^2.2.6", "event-source-polyfill": "^1.0.31", "git-url-parse": "^13.0.0", From 0119c326394a0db03a1b09dc9f4d055071bebc96 Mon Sep 17 00:00:00 2001 From: fyyyyy Date: Tue, 15 Aug 2023 19:19:56 +0200 Subject: [PATCH 04/13] Add changeset three-hounds-wonder.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add changeset Signed-off-by: fyyyyy Signed-off-by: Fredrik Adelöw --- .changeset/three-hounds-wonder.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/three-hounds-wonder.md diff --git a/.changeset/three-hounds-wonder.md b/.changeset/three-hounds-wonder.md new file mode 100644 index 0000000000..fd4cb486bc --- /dev/null +++ b/.changeset/three-hounds-wonder.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +adding a .zip download to dry run results page, including zip.js as dependency From 525d3c8b67e856408cb8949ed0a091fe5c19d75d Mon Sep 17 00:00:00 2001 From: fyyyyy Date: Tue, 15 Aug 2023 19:24:06 +0200 Subject: [PATCH 05/13] Update yarn.lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: fyyyyy Signed-off-by: Fredrik Adelöw --- yarn.lock | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/yarn.lock b/yarn.lock index 29953fc257..00e3730ac1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8796,6 +8796,7 @@ __metadata: "@types/json-schema": ^7.0.9 "@types/react": ^16.13.1 || ^17.0.0 "@uiw/react-codemirror": ^4.9.3 + "@zip.js/zip.js": ^2.7.24 classnames: ^2.2.6 event-source-polyfill: ^1.0.31 git-url-parse: ^13.0.0 @@ -19346,6 +19347,13 @@ __metadata: languageName: node linkType: hard +"@zip.js/zip.js@npm:^2.7.24": + version: 2.7.28 + resolution: "@zip.js/zip.js@npm:2.7.28" + checksum: 2447e7250daeb0a518c68347034075ad244e8e53e3ee83a2e3e078f919328edcc24a6c68f1814d42e231526230360164cce79d70f14cb9a16a07e91ae1e25257 + languageName: node + linkType: hard + "@zxing/text-encoding@npm:0.9.0": version: 0.9.0 resolution: "@zxing/text-encoding@npm:0.9.0" From 400beacb7072fdc529b4405235d877bfcca8283d Mon Sep 17 00:00:00 2001 From: TRIGUBF Date: Wed, 23 Aug 2023 16:50:35 +0200 Subject: [PATCH 06/13] revoke url, remove anchor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../src/components/TemplateEditorPage/DryRunContext.tsx | 2 ++ yarn.lock | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx index 47d121b616..530b9f5be1 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx @@ -227,5 +227,7 @@ async function createZipDownload(directoryContents: { path: string; base64Conten a.href = URL.createObjectURL(zipFileBlob); a.download = `dry-run-${name}.zip`; a.click(); + URL.revokeObjectURL(a.href); + a.remove(); } diff --git a/yarn.lock b/yarn.lock index 00e3730ac1..f7e0fb0f75 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19348,9 +19348,9 @@ __metadata: linkType: hard "@zip.js/zip.js@npm:^2.7.24": - version: 2.7.28 - resolution: "@zip.js/zip.js@npm:2.7.28" - checksum: 2447e7250daeb0a518c68347034075ad244e8e53e3ee83a2e3e078f919328edcc24a6c68f1814d42e231526230360164cce79d70f14cb9a16a07e91ae1e25257 + version: 2.7.24 + resolution: "@zip.js/zip.js@npm:2.7.24" + checksum: f56f973748d063158cbb6f07ccf4d4c64d35952bb2ecf3d9922db935b17f4e689b6d8568041083195ff4679a0d1a9378fa78adca7428819239d4a3fb4a1dd2d2 languageName: node linkType: hard From 149c6f03ca3707a49ffc74b06602b983ccb6600d Mon Sep 17 00:00:00 2001 From: TRIGUBF Date: Wed, 23 Aug 2023 17:06:22 +0200 Subject: [PATCH 07/13] replace zip.js with JSzip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- plugins/scaffolder/package.json | 2 +- .../TemplateEditorPage/DryRunContext.tsx | 31 ++++++-------- yarn.lock | 41 ++++++++++++++----- 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index f5cf5eb6bc..cb73dcbe85 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -73,7 +73,6 @@ "@rjsf/validator-ajv8": "5.7.3", "@types/react": "^16.13.1 || ^17.0.0", "@uiw/react-codemirror": "^4.9.3", - "@zip.js/zip.js": "^2.7.24", "classnames": "^2.2.6", "event-source-polyfill": "^1.0.31", "git-url-parse": "^13.0.0", @@ -81,6 +80,7 @@ "immer": "^9.0.1", "json-schema": "^0.4.0", "json-schema-library": "^7.3.9", + "jszip": "^3.10.1", "lodash": "^4.17.21", "luxon": "^3.0.0", "qs": "^6.9.4", diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx index 530b9f5be1..d73b6ebc3f 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx @@ -26,7 +26,7 @@ import React, { useRef, useState, } from 'react'; -import * as zip from "@zip.js/zip.js"; +import JSZip from 'jszip'; import { scaffolderApiRef, ScaffolderDryRunResponse, @@ -198,33 +198,28 @@ export function useDryRun(): DryRun { } async function createZipDownload(directoryContents: { path: string; base64Content: string; executable: boolean; }[], name: string) { - // needs zip.js - - // Creates a BlobWriter object where the zip content will be written. - const zipFileWriter = new zip.BlobWriter(); - - // Creates a ZipWriter object writing data via `zipFileWriter`, adds the entry - const zipWriter = new zip.ZipWriter(zipFileWriter); + const zip = new JSZip(); for (const d of directoryContents) { // Decode text content from base64 to ascii const converted = atob(d.base64Content); - // Creates a TextReader object storing the text of the entry to add in the zip (i.e. "Hello world!"). - const fileReader = new zip.TextReader(converted); - - await zipWriter.add(d.path, fileReader); + // add folder/file to zip + await zip.file(d.path, converted); } - // Closes the writer. - await zipWriter.close(); + zip.generateAsync({type:"blob"}).then((blob) => { + saveAs(blob, name); + }, (err) => { + throw new Error(err); + }); +} - // Retrieves the Blob object containing the zip content into `zipFileBlob` - const zipFileBlob = await zipFileWriter.getData(); - // Download zip +// Download zip +function saveAs(blob: Blob, name: string) { const a = document.createElement('a'); - a.href = URL.createObjectURL(zipFileBlob); + a.href = URL.createObjectURL(blob); a.download = `dry-run-${name}.zip`; a.click(); URL.revokeObjectURL(a.href); diff --git a/yarn.lock b/yarn.lock index f7e0fb0f75..05f71c20df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8796,7 +8796,6 @@ __metadata: "@types/json-schema": ^7.0.9 "@types/react": ^16.13.1 || ^17.0.0 "@uiw/react-codemirror": ^4.9.3 - "@zip.js/zip.js": ^2.7.24 classnames: ^2.2.6 event-source-polyfill: ^1.0.31 git-url-parse: ^13.0.0 @@ -8804,6 +8803,7 @@ __metadata: immer: ^9.0.1 json-schema: ^0.4.0 json-schema-library: ^7.3.9 + jszip: ^3.10.1 lodash: ^4.17.21 luxon: ^3.0.0 msw: ^1.0.0 @@ -19347,13 +19347,6 @@ __metadata: languageName: node linkType: hard -"@zip.js/zip.js@npm:^2.7.24": - version: 2.7.24 - resolution: "@zip.js/zip.js@npm:2.7.24" - checksum: f56f973748d063158cbb6f07ccf4d4c64d35952bb2ecf3d9922db935b17f4e689b6d8568041083195ff4679a0d1a9378fa78adca7428819239d4a3fb4a1dd2d2 - languageName: node - linkType: hard - "@zxing/text-encoding@npm:0.9.0": version: 0.9.0 resolution: "@zxing/text-encoding@npm:0.9.0" @@ -28415,6 +28408,13 @@ __metadata: languageName: node linkType: hard +"immediate@npm:~3.0.5": + version: 3.0.6 + resolution: "immediate@npm:3.0.6" + checksum: f9b3486477555997657f70318cc8d3416159f208bec4cca3ff3442fd266bc23f50f0c9bd8547e1371a6b5e82b821ec9a7044a4f7b944798b25aa3cc6d5e63e62 + languageName: node + linkType: hard + "immer@npm:9.0.7": version: 9.0.7 resolution: "immer@npm:9.0.7" @@ -31066,6 +31066,18 @@ __metadata: languageName: node linkType: hard +"jszip@npm:^3.10.1": + version: 3.10.1 + resolution: "jszip@npm:3.10.1" + dependencies: + lie: ~3.3.0 + pako: ~1.0.2 + readable-stream: ~2.3.6 + setimmediate: ^1.0.5 + checksum: abc77bfbe33e691d4d1ac9c74c8851b5761fba6a6986630864f98d876f3fcc2d36817dfc183779f32c00157b5d53a016796677298272a714ae096dfe6b1c8b60 + languageName: node + linkType: hard + "just-diff-apply@npm:^4.0.1": version: 4.0.1 resolution: "just-diff-apply@npm:4.0.1" @@ -31402,6 +31414,15 @@ __metadata: languageName: node linkType: hard +"lie@npm:~3.3.0": + version: 3.3.0 + resolution: "lie@npm:3.3.0" + dependencies: + immediate: ~3.0.5 + checksum: 33102302cf19766f97919a6a98d481e01393288b17a6aa1f030a3542031df42736edde8dab29ffdbf90bebeffc48c761eb1d064dc77592ca3ba3556f9fe6d2a8 + languageName: node + linkType: hard + "lilconfig@npm:2.1.0, lilconfig@npm:^2.0.3": version: 2.1.0 resolution: "lilconfig@npm:2.1.0" @@ -34784,7 +34805,7 @@ __metadata: languageName: node linkType: hard -"pako@npm:^1.0.10, pako@npm:~1.0.5": +"pako@npm:^1.0.10, pako@npm:~1.0.2, pako@npm:~1.0.5": version: 1.0.11 resolution: "pako@npm:1.0.11" checksum: 1be2bfa1f807608c7538afa15d6f25baa523c30ec870a3228a89579e474a4d992f4293859524e46d5d87fd30fa17c5edf34dbef0671251d9749820b488660b16 @@ -37609,7 +37630,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^2.0.0, readable-stream@npm:^2.0.1, readable-stream@npm:^2.0.2, readable-stream@npm:^2.0.5, readable-stream@npm:^2.2.2, readable-stream@npm:^2.3.3, readable-stream@npm:^2.3.5, readable-stream@npm:^2.3.6": +"readable-stream@npm:^2.0.0, readable-stream@npm:^2.0.1, readable-stream@npm:^2.0.2, readable-stream@npm:^2.0.5, readable-stream@npm:^2.2.2, readable-stream@npm:^2.3.3, readable-stream@npm:^2.3.5, readable-stream@npm:^2.3.6, readable-stream@npm:~2.3.6": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" dependencies: From a40410b42c23cbaa1a877573958d06ac5e003944 Mon Sep 17 00:00:00 2001 From: TRIGUBF Date: Wed, 23 Aug 2023 17:13:54 +0200 Subject: [PATCH 08/13] move jszip to async import MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../src/components/TemplateEditorPage/DryRunContext.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx index d73b6ebc3f..d9f853275f 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx @@ -26,7 +26,7 @@ import React, { useRef, useState, } from 'react'; -import JSZip from 'jszip'; +const {default: JSZip} = await import('jszip'); import { scaffolderApiRef, ScaffolderDryRunResponse, From 4d8aeacfa5fc7de643a4d1b094ce09f7c83955c8 Mon Sep 17 00:00:00 2001 From: TRIGUBF Date: Fri, 25 Aug 2023 11:33:54 +0200 Subject: [PATCH 09/13] move download logic to DryRunResultsList and helper, move jszip zo async import, add ownload helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../TemplateEditorPage/DryRunContext.tsx | 51 +------------------ .../DryRunResults/DryRunResultsList.tsx | 41 ++++++++++++++- .../scaffolder/src/lib/download/helpers.ts | 25 +++++++++ plugins/scaffolder/src/lib/download/index.ts | 17 +++++++ 4 files changed, 82 insertions(+), 52 deletions(-) create mode 100644 plugins/scaffolder/src/lib/download/helpers.ts create mode 100644 plugins/scaffolder/src/lib/download/index.ts diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx index d9f853275f..1765e8cb94 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx @@ -26,7 +26,6 @@ import React, { useRef, useState, } from 'react'; -const {default: JSZip} = await import('jszip'); import { scaffolderApiRef, ScaffolderDryRunResponse, @@ -41,7 +40,7 @@ interface DryRunOptions { files: Array<{ path: string; content: string }>; } -interface DryRunResult extends ScaffolderDryRunResponse { +export interface DryRunResult extends ScaffolderDryRunResponse { id: number; } @@ -51,7 +50,6 @@ interface DryRun { selectResult(id: number): void; deleteResult(id: number): void; - downloadResult(id: number): void; execute(options: DryRunOptions): Promise; } @@ -124,22 +122,6 @@ export function DryRunProvider(props: DryRunProviderProps) { }); }, []); - const downloadResult = useCallback((id: number) => { - setState(prevState => { - const index = prevState.results.findIndex(r => r.id === id); - if (index === -1) { - return prevState; - } - const result = prevState.results[index]; - console.log('Result', result.id); - createZipDownload(result.directoryContents, 'result_' + result.id) - return { - results: prevState.results, - selectedResult: prevState.selectedResult, - }; - }); - }, []); - const execute = useCallback( async (options: DryRunOptions) => { if (!scaffolderApi.dryRun) { @@ -176,7 +158,6 @@ export function DryRunProvider(props: DryRunProviderProps) { ...state, selectResult, deleteResult, - downloadResult, execute, }), [state, selectResult, deleteResult, execute], @@ -196,33 +177,3 @@ export function useDryRun(): DryRun { } return value; } - -async function createZipDownload(directoryContents: { path: string; base64Content: string; executable: boolean; }[], name: string) { - const zip = new JSZip(); - - for (const d of directoryContents) { - // Decode text content from base64 to ascii - const converted = atob(d.base64Content); - - // add folder/file to zip - await zip.file(d.path, converted); - } - - zip.generateAsync({type:"blob"}).then((blob) => { - saveAs(blob, name); - }, (err) => { - throw new Error(err); - }); -} - - -// Download zip -function saveAs(blob: Blob, name: string) { - const a = document.createElement('a'); - a.href = URL.createObjectURL(blob); - a.download = `dry-run-${name}.zip`; - a.click(); - URL.revokeObjectURL(a.href); - a.remove(); -} - diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx index 9163261985..384d48e871 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx @@ -27,7 +27,7 @@ import CheckIcon from '@material-ui/icons/Check'; import DeleteIcon from '@material-ui/icons/Delete'; import DownloadIcon from '@material-ui/icons/GetApp'; import React from 'react'; -import { useDryRun } from '../DryRunContext'; +import { DryRunResult, useDryRun } from '../DryRunContext'; const useStyles = makeStyles((theme: BackstageTheme) => ({ root: { @@ -72,7 +72,7 @@ export function DryRunResultsList() { edge="end" aria-label="download" title="Download as .zip" - onClick={() => dryRun.downloadResult(result.id)} + onClick={() => downloadResult(result)} > @@ -91,3 +91,40 @@ export function DryRunResultsList() { ); } + + +async function downloadResult(result: DryRunResult) { + await createZipDownload(result.directoryContents, `dry-run-result-${result.id}.zip`) +} + + +async function createZipDownload(directoryContents: { path: string; base64Content: string; executable: boolean; }[], name: string) { + const {default: JSZip} = await import('jszip'); + const zip = new JSZip(); + + for (const d of directoryContents) { + // Decode text content from base64 to ascii + const converted = atob(d.base64Content); + + // add folder/file to zip + await zip.file(d.path, converted); + } + + zip.generateAsync({type:"blob"}).then((blob) => { + // Download zip + downloadBlob(blob, name); + }, (err) => { + throw new Error(err); + }); +} + + + +function downloadBlob(blob: Blob, name: string) { + const a = document.createElement('a'); + a.href = URL.createObjectURL(blob); + a.download = name; + a.click(); + URL.revokeObjectURL(a.href); + a.remove(); +} diff --git a/plugins/scaffolder/src/lib/download/helpers.ts b/plugins/scaffolder/src/lib/download/helpers.ts new file mode 100644 index 0000000000..2b596480d4 --- /dev/null +++ b/plugins/scaffolder/src/lib/download/helpers.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function downloadBlob(blob: Blob, name: string) { + const a = document.createElement('a'); + a.href = URL.createObjectURL(blob); + a.download = name; + a.click(); + URL.revokeObjectURL(a.href); + a.remove(); +} + diff --git a/plugins/scaffolder/src/lib/download/index.ts b/plugins/scaffolder/src/lib/download/index.ts new file mode 100644 index 0000000000..0b51b8e61d --- /dev/null +++ b/plugins/scaffolder/src/lib/download/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { downloadBlob } from './helpers'; From eb8a79542ea68777b50b160c0bbf770573b8304a Mon Sep 17 00:00:00 2001 From: TRIGUBF Date: Fri, 25 Aug 2023 11:35:23 +0200 Subject: [PATCH 10/13] use download helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../DryRunResults/DryRunResultsList.tsx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx index 384d48e871..0d9fcbc350 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx @@ -28,6 +28,7 @@ import DeleteIcon from '@material-ui/icons/Delete'; import DownloadIcon from '@material-ui/icons/GetApp'; import React from 'react'; import { DryRunResult, useDryRun } from '../DryRunContext'; +import { downloadBlob } from '../../../lib/download'; const useStyles = makeStyles((theme: BackstageTheme) => ({ root: { @@ -117,14 +118,3 @@ async function createZipDownload(directoryContents: { path: string; base64Conten throw new Error(err); }); } - - - -function downloadBlob(blob: Blob, name: string) { - const a = document.createElement('a'); - a.href = URL.createObjectURL(blob); - a.download = name; - a.click(); - URL.revokeObjectURL(a.href); - a.remove(); -} From e7f7ba34252098788e2ff60e7d97068620876b35 Mon Sep 17 00:00:00 2001 From: TRIGUBF Date: Fri, 25 Aug 2023 12:05:02 +0200 Subject: [PATCH 11/13] track async download state, disable button while downloading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../DryRunResults/DryRunResultsList.tsx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx index 0d9fcbc350..2d7f78ac54 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx @@ -55,6 +55,14 @@ export function DryRunResultsList() { {dryRun.results.map(result => { const failed = result.log.some(l => l.body.status === 'failed'); + let isLoading = false; + + async function downloadResult() { + isLoading = true; + await downloadDirectoryContents(result.directoryContents, `dry-run-result-${result.id}.zip`) + isLoading = false; + } + return ( downloadResult(result)} + disabled={isLoading} + onClick={() => downloadResult()} > @@ -94,12 +103,8 @@ export function DryRunResultsList() { } -async function downloadResult(result: DryRunResult) { - await createZipDownload(result.directoryContents, `dry-run-result-${result.id}.zip`) -} - -async function createZipDownload(directoryContents: { path: string; base64Content: string; executable: boolean; }[], name: string) { +async function downloadDirectoryContents(directoryContents: { path: string; base64Content: string; executable: boolean; }[], name: string) { const {default: JSZip} = await import('jszip'); const zip = new JSZip(); From f3ba736e7e47087ab9b28072c8b40f5c60dd999e Mon Sep 17 00:00:00 2001 From: TRIGUBF Date: Fri, 25 Aug 2023 12:25:05 +0200 Subject: [PATCH 12/13] replace .then with async MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../DryRunResults/DryRunResultsList.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx index 2d7f78ac54..11031fc50c 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx @@ -116,10 +116,6 @@ async function downloadDirectoryContents(directoryContents: { path: string; base await zip.file(d.path, converted); } - zip.generateAsync({type:"blob"}).then((blob) => { - // Download zip - downloadBlob(blob, name); - }, (err) => { - throw new Error(err); - }); + const blob = await zip.generateAsync({type:"blob"}); + downloadBlob(blob, name); } From d031da5f0ef28f741a2adae05e0bd79ec81eabe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 4 Sep 2023 09:55:34 +0200 Subject: [PATCH 13/13] pretty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../DryRunResults/DryRunResultsList.tsx | 26 ++++++++++++------- .../scaffolder/src/lib/download/helpers.ts | 1 - 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx index 11031fc50c..df6e8ef5f2 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx @@ -27,7 +27,7 @@ import CheckIcon from '@material-ui/icons/Check'; import DeleteIcon from '@material-ui/icons/Delete'; import DownloadIcon from '@material-ui/icons/GetApp'; import React from 'react'; -import { DryRunResult, useDryRun } from '../DryRunContext'; +import { useDryRun } from '../DryRunContext'; import { downloadBlob } from '../../../lib/download'; const useStyles = makeStyles((theme: BackstageTheme) => ({ @@ -59,10 +59,13 @@ export function DryRunResultsList() { async function downloadResult() { isLoading = true; - await downloadDirectoryContents(result.directoryContents, `dry-run-result-${result.id}.zip`) + await downloadDirectoryContents( + result.directoryContents, + `dry-run-result-${result.id}.zip`, + ); isLoading = false; } - + return (