diff --git a/packages/scripts/src/commands/app-data/report/reporters/asset-summary.spec.ts b/packages/scripts/src/commands/app-data/report/reporters/asset-summary.spec.ts index f4eccecbe..a9e267791 100644 --- a/packages/scripts/src/commands/app-data/report/reporters/asset-summary.spec.ts +++ b/packages/scripts/src/commands/app-data/report/reporters/asset-summary.spec.ts @@ -71,6 +71,19 @@ describe("Asset Summary Report", () => { ]); }); + it("Allows authors to specify assets with preceding forward slash", async () => { + const { asset_summary } = await reporter.process({ + template: [ + { + flow_type: "template", + flow_name: "test_forward_slash", + rows: [{ type: "audio", value: "/mock_audio.mp3" }], + }, + ], + }); + expect(asset_summary.data).toEqual([{ path: "mock_audio.mp3", size_kb: 2048, count: 1 }]); + }); + it("Reports missing assets", async () => { const { assets_missing } = await reporter.process(MOCK_WORKBOOK_DATA); expect(assets_missing.data).toEqual([{ path: "missing_audio.mp3", count: 1, missing: true }]); diff --git a/packages/scripts/src/commands/app-data/report/reporters/asset-summary.ts b/packages/scripts/src/commands/app-data/report/reporters/asset-summary.ts index f628bdd19..978e58c91 100644 --- a/packages/scripts/src/commands/app-data/report/reporters/asset-summary.ts +++ b/packages/scripts/src/commands/app-data/report/reporters/asset-summary.ts @@ -1,6 +1,6 @@ -import { FlowTypes, IAssetEntryHashmap, IDeploymentConfigJson } from "data-models"; +import { FlowTypes, IAssetEntryHashmap } from "data-models"; import { IReportTable } from "../report.types"; -import { isObjectLiteral, kbToMB, sortJsonKeys } from "shared"; +import { cleanAssetName, isObjectLiteral, kbToMB, sortJsonKeys } from "shared"; import { IParsedWorkbookData } from "../../convert/types"; interface IReportData { @@ -147,6 +147,8 @@ export class AssetsSummaryReport { } private markAsset(name: string) { + // NOTE - use same method as frontend asset service to allow assets with preceding `/` + name = cleanAssetName(name); this.reportSummary[name] ??= 0; this.reportSummary[name]++; } diff --git a/packages/shared/src/utils/string-utils.ts b/packages/shared/src/utils/string-utils.ts index aaf8ab5ea..63a1ae2d3 100644 --- a/packages/shared/src/utils/string-utils.ts +++ b/packages/shared/src/utils/string-utils.ts @@ -43,3 +43,9 @@ export function parseStringValue(v: string): any { if (v.match(/^"[a-z0-9.]*"$/gi)) return v.replace(/"/g, ""); return v; } + +/** Remove preceding `/` from any named asset paths */ +export function cleanAssetName(value: string) { + if (value.startsWith("/")) value = value.substring(1); + return value; +} diff --git a/src/app/shared/components/template/services/template-asset.service.ts b/src/app/shared/components/template/services/template-asset.service.ts index 9603436a3..c1d6a1857 100644 --- a/src/app/shared/components/template/services/template-asset.service.ts +++ b/src/app/shared/components/template/services/template-asset.service.ts @@ -6,6 +6,7 @@ import { TemplateTranslateService } from "./template-translate.service"; import { IAssetEntry, IAssetContentsEntryMinimal } from "data-models"; import { HttpClient } from "@angular/common/http"; import { BehaviorSubject, lastValueFrom } from "rxjs"; +import { cleanAssetName } from "packages/shared/src/utils/string-utils"; /** Synced assets are automatically copied during build to asset subfolder */ const ASSETS_BASE = `assets/app_data/assets`; @@ -55,7 +56,7 @@ export class TemplateAssetService extends AsyncServiceBase { * 4. default theme, default language */ getTranslatedAssetPath(value: string) { - let assetName = this.cleanAssetName(value); + let assetName = cleanAssetName(value); const assetEntry = this.assetsContentsList$.value[assetName]; if (!assetEntry) { console.error("Asset missing", value, assetName); @@ -86,12 +87,6 @@ export class TemplateAssetService extends AsyncServiceBase { return this.getAssetPath(assetName, assetEntry); } - private cleanAssetName(value: string) { - // remove prefix slash - if (value.startsWith("/")) value = value.substring(1); - return value; - } - private getAssetPath( assetName: string, contentsEntry: IAssetContentsEntryMinimal | Partial