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 diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 250fc3cf89..ce82fff2e7 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -81,6 +81,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 a617eebe1e..1765e8cb94 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx @@ -40,7 +40,7 @@ interface DryRunOptions { files: Array<{ path: string; content: string }>; } -interface DryRunResult extends ScaffolderDryRunResponse { +export interface DryRunResult extends ScaffolderDryRunResponse { id: number; } diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx index 462c3b58fd..df6e8ef5f2 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx @@ -25,8 +25,10 @@ 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'; +import { downloadBlob } from '../../../lib/download'; const useStyles = makeStyles((theme: BackstageTheme) => ({ root: { @@ -53,6 +55,17 @@ 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()} + > + + dryRun.deleteResult(result.id)} > @@ -81,3 +104,26 @@ export function DryRunResultsList() { ); } + +async function downloadDirectoryContents( + 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); + } + + const blob = await zip.generateAsync({ type: 'blob' }); + downloadBlob(blob, name); +} diff --git a/plugins/scaffolder/src/lib/download/helpers.ts b/plugins/scaffolder/src/lib/download/helpers.ts new file mode 100644 index 0000000000..2cc5d86973 --- /dev/null +++ b/plugins/scaffolder/src/lib/download/helpers.ts @@ -0,0 +1,24 @@ +/* + * 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'; diff --git a/yarn.lock b/yarn.lock index 3fe496d73c..c8e21815dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8837,6 +8837,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 @@ -28551,6 +28552,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" @@ -31205,6 +31213,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" @@ -31541,6 +31561,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" @@ -34937,7 +34966,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 @@ -37795,7 +37824,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: