diff --git a/src/4.3_to_5.0/__snapshots__/migrate_43_to_50.test.ts.snap b/src/4.3_to_5.0/__snapshots__/migrate_43_to_50.test.ts.snap index bd938192..8d0554a7 100644 --- a/src/4.3_to_5.0/__snapshots__/migrate_43_to_50.test.ts.snap +++ b/src/4.3_to_5.0/__snapshots__/migrate_43_to_50.test.ts.snap @@ -2497,24 +2497,7 @@ exports[`migrate_43_to_50 returns a valid ActiveUI5 /ui folder on a small input "widgets": { "children": { "content": { - "children": { - "kpi": { - "entry": { - "canRead": true, - "canWrite": true, - "content": "{"query":{"mdx":"SELECT NON EMPTY Hierarchize(AddCalculatedMembers(Descendants({[Geography].[City].[ALL].[AllMember]}, 1, SELF_AND_BEFORE))) ON ROWS, NON EMPTY {[Measures].[contributors.COUNT]} ON COLUMNS FROM [EquityDerivativesCube]","updateMode":"once"},"filters":["[Geography].[City].[ALL].[AllMember].[New York]"],"queryContext":[],"mapping":{"rows":["[Geography].[City].[City]"],"columns":[],"measures":["[Measures].[contributors.COUNT]"]},"serverKey":"my-server","titles":{"[Measures].[contributors.COUNT]":"Custom title for contributors.COUNT"}}", - "isDirectory": false, - "lastEditor": "admin", - "owners": [ - "admin", - ], - "readers": [ - "admin", - ], - "timestamp": 1607879735685, - }, - }, - }, + "children": {}, "entry": { "isDirectory": true, "owners": [ @@ -2526,41 +2509,7 @@ exports[`migrate_43_to_50 returns a valid ActiveUI5 /ui folder on a small input }, }, "structure": { - "children": { - "kpi": { - "children": { - "kpi_metadata": { - "entry": { - "canRead": true, - "canWrite": true, - "content": "{"name":"KPI","widgetKey":"kpi"}", - "isDirectory": true, - "lastEditor": "admin", - "owners": [ - "admin", - ], - "readers": [ - "admin", - ], - "timestamp": 1607879735685, - }, - }, - }, - "entry": { - "canRead": true, - "canWrite": true, - "isDirectory": true, - "lastEditor": "admin", - "owners": [ - "admin", - ], - "readers": [ - "admin", - ], - "timestamp": 1607879735685, - }, - }, - }, + "children": {}, "entry": { "isDirectory": true, "owners": [ @@ -2619,7 +2568,7 @@ exports[`migrate_43_to_50 returns a valid ActiveUI5 /ui folder on a small input "failed": 0, "partial": 0, "removed": 0, - "success": 1, + "success": 0, }, } `; diff --git a/src/4.3_to_5.0/__test_resources__/legacyKpi.ts b/src/4.3_to_5.0/__test_resources__/legacyKpi.ts index 01f27b3c..e32e9a9b 100644 --- a/src/4.3_to_5.0/__test_resources__/legacyKpi.ts +++ b/src/4.3_to_5.0/__test_resources__/legacyKpi.ts @@ -31,9 +31,6 @@ export const legacyKpi: LegacyWidgetState = { configuration: { featuredValues: { locations: { - "": { - title: "Empty measure title", - }, // "EUR, USD" is not a member of the sandbox, but it is used here to check that the script supports member names including ",". "[Currency].[Currency].[AllMember].[EUR, USD],[Measures].[contributors.COUNT]": { diff --git a/src/4.3_to_5.0/__test_resources__/smallLegacyUIFolder.ts b/src/4.3_to_5.0/__test_resources__/smallLegacyUIFolder.ts index 070eb16c..aeb3ad70 100644 --- a/src/4.3_to_5.0/__test_resources__/smallLegacyUIFolder.ts +++ b/src/4.3_to_5.0/__test_resources__/smallLegacyUIFolder.ts @@ -47,19 +47,6 @@ export const smallLegacyUIFolder = { canWrite: true, }, }, - kpi: { - entry: { - content: - '{"description": "A KPI containing a custom title with an empty tupleKey","name":"KPI","type":"container","value": {"style": {},"showTitleBar": true,"body": {"serverUrl": "","mdx": "SELECT NON EMPTY Hierarchize(AddCalculatedMembers(Descendants({[Geography].[City].[ALL].[AllMember]},1,SELF_AND_BEFORE))) ON ROWS,NON EMPTY {[Measures].[contributors.COUNT]} ON COLUMNS FROM (SELECT[Geography].[City].[ALL].[AllMember].[New York] ON COLUMNS FROM [EquityDerivativesCube])","contextValues": {},"updateMode": "once","ranges": {"row": {},"column": {}},"configuration": {"featuredValues": {"locations":{"":{"title": "Title with empty location"},"[Measures].[contributors.COUNT]": {"title": "Custom title for contributors.COUNT"}}}}},"containerKey":"featured-values"},"writable": true}', - isDirectory: false, - owners: ["admin"], - readers: ["admin"], - timestamp: 1607879735685, - lastEditor: "admin", - canRead: true, - canWrite: true, - }, - }, }, }, i18n: { @@ -119,17 +106,6 @@ export const smallLegacyUIFolder = { canWrite: true, }, }, - kpi: { - entry: { - isDirectory: true, - owners: ["admin"], - readers: ["admin"], - timestamp: 1607879735685, - lastEditor: "admin", - canRead: true, - canWrite: true, - }, - }, }, }, }, diff --git a/src/4.3_to_5.0/__test_resources__/smallLegacyUIFolderWithInvalidKpiTitle.ts b/src/4.3_to_5.0/__test_resources__/smallLegacyUIFolderWithInvalidKpiTitle.ts new file mode 100644 index 00000000..5e322132 --- /dev/null +++ b/src/4.3_to_5.0/__test_resources__/smallLegacyUIFolderWithInvalidKpiTitle.ts @@ -0,0 +1,241 @@ +/** + * The shortened version of the content of the /ui folder on a Content Server, useful for unit tests. + * Contains a KPI widget containing a custom title with an empty `tupleKey` for its location. + */ +export const smallLegacyUIFolderWithInvalidKpiTitle = { + entry: { + isDirectory: true, + owners: ["admin"], + readers: ["admin"], + timestamp: 1607879725132, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + children: { + bookmarks: { + entry: { + isDirectory: true, + owners: ["ROLE_CS_ROOT"], + readers: ["ROLE_USER"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + children: { + content: { + entry: { + isDirectory: true, + owners: ["ROLE_USER"], + readers: ["ROLE_USER"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + children: { + kpi: { + entry: { + content: + '{"description": "A KPI containing a custom title with an empty tupleKey","name":"KPI","type":"container","value": {"style": {},"showTitleBar": true,"body": {"serverUrl": "","mdx": "SELECT NON EMPTY Hierarchize(AddCalculatedMembers(Descendants({[Geography].[City].[ALL].[AllMember]},1,SELF_AND_BEFORE))) ON ROWS,NON EMPTY {[Measures].[contributors.COUNT]} ON COLUMNS FROM (SELECT[Geography].[City].[ALL].[AllMember].[New York] ON COLUMNS FROM [EquityDerivativesCube])","contextValues": {},"updateMode": "once","ranges": {"row": {},"column": {}},"configuration": {"featuredValues": {"locations":{"":{"title": "Title with empty location"},"[Measures].[contributors.COUNT]": {"title": "Custom title for contributors.COUNT"}}}}},"containerKey":"featured-values"},"writable": true}', + isDirectory: false, + owners: ["admin"], + readers: ["admin"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + }, + }, + }, + i18n: { + entry: { + isDirectory: true, + owners: ["ROLE_CS_ROOT"], + readers: ["ROLE_USER"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + children: { + "en-US": { + entry: { + isDirectory: true, + owners: ["ROLE_CS_ROOT"], + readers: ["ROLE_USER"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + }, + "fr-FR": { + entry: { + isDirectory: true, + owners: ["ROLE_CS_ROOT"], + readers: ["ROLE_USER"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + }, + }, + }, + structure: { + entry: { + isDirectory: true, + owners: ["ROLE_USER"], + readers: ["ROLE_USER"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + children: { + kpi: { + entry: { + isDirectory: true, + owners: ["admin"], + readers: ["admin"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + }, + }, + }, + }, + }, + settings: { + entry: { + isDirectory: true, + owners: ["ROLE_CS_ROOT"], + readers: ["ROLE_USER"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + children: { + default: { + entry: { + isDirectory: true, + owners: ["ROLE_CS_ROOT"], + readers: ["ROLE_USER"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + children: { + preferences: { + entry: { + content: '{\n "allow": [],\n "deny": [],\n "map": {}\n}', + isDirectory: false, + owners: ["ROLE_CS_ROOT"], + readers: ["ROLE_USER"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + }, + }, + }, + roles: { + entry: { + isDirectory: true, + owners: ["ROLE_CS_ROOT"], + readers: ["ROLE_USER"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + }, + users: { + entry: { + isDirectory: true, + owners: ["ROLE_USER"], + readers: ["ROLE_USER"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + children: { + user1: { + entry: { + isDirectory: true, + owners: ["user1"], + readers: ["user1"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + children: { + preferences: { + entry: { + content: + '{\n "map": {\n "defaultPermissions": {\n "owners": [\n "user2"\n ],\n "readers": [\n "user2"\n ]\n }\n }\n}', + isDirectory: false, + owners: ["user1"], + readers: ["user1"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + }, + }, + }, + admin: { + entry: { + isDirectory: true, + owners: ["admin"], + readers: ["admin"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + children: { + preferences: { + entry: { + content: + '{\n "map": {\n "tree.search.maxResults": 10,\n "global.theme": "dark-activeviam",\n "userFilters.enabled": true,\n "showLegacyCharts": true,\n "showLegacyMaps": true,\n "widgets.Tabular.drillthrough.selectedColumns": {\n "https://activepivot-ranch.activeviam.com:5900": {\n "EquityDerivativesCube": [\n {\n "functionName": "MemberValue",\n "columnName": "delta"\n },\n {\n "functionName": "Caption",\n "columnName": "delta"\n },\n {\n "functionName": "MemberValue",\n "columnName": "gamma"\n },\n {\n "functionName": "Caption",\n "columnName": "gamma"\n },\n {\n "functionName": "MemberValue",\n "columnName": "pnlVega"\n },\n {\n "functionName": "Caption",\n "columnName": "pnlVega"\n },\n {\n "functionName": "MemberValue",\n "columnName": "Desk"\n },\n {\n "functionName": "Caption",\n "columnName": "Desk"\n },\n {\n "functionName": "MemberValue",\n "columnName": "Currency"\n },\n {\n "functionName": "Caption",\n "columnName": "Currency"\n },\n {\n "functionName": "MemberValue",\n "columnName": "Date"\n },\n {\n "functionName": "Caption",\n "columnName": "Date"\n },\n {\n "columnName": "HostName",\n "functionName": "MemberValue"\n },\n {\n "columnName": "HostName",\n "functionName": "Caption"\n }\n ],\n "EquityDerivativesCubeDist": [\n {\n "functionName": "MemberValue",\n "columnName": "BumpedMtmDown"\n },\n {\n "functionName": "Caption",\n "columnName": "BumpedMtmDown"\n },\n {\n "functionName": "MemberValue",\n "columnName": "ProductQtyMultiplier"\n },\n {\n "functionName": "Caption",\n "columnName": "ProductQtyMultiplier"\n },\n {\n "functionName": "MemberValue",\n "columnName": "ProductQtyMultiplier"\n },\n {\n "functionName": "Caption",\n "columnName": "ProductQtyMultiplier"\n },\n {\n "functionName": "MemberValue",\n "columnName": "vega"\n },\n {\n "functionName": "Caption",\n "columnName": "vega"\n },\n {\n "functionName": "MemberValue",\n "columnName": "rho"\n },\n {\n "functionName": "Caption",\n "columnName": "rho"\n },\n {\n "functionName": "MemberValue",\n "columnName": "productId"\n },\n {\n "functionName": "Caption",\n "columnName": "productId"\n },\n {\n "functionName": "MemberValue",\n "columnName": "pnlVega"\n },\n {\n "functionName": "Caption",\n "columnName": "pnlVega"\n },\n {\n "functionName": "MemberValue",\n "columnName": "pnlDelta"\n },\n {\n "functionName": "Caption",\n "columnName": "pnlDelta"\n },\n {\n "functionName": "MemberValue",\n "columnName": "pnl"\n },\n {\n "functionName": "Caption",\n "columnName": "pnl"\n },\n {\n "functionName": "MemberValue",\n "columnName": "gamma"\n },\n {\n "functionName": "Caption",\n "columnName": "gamma"\n },\n {\n "functionName": "MemberValue",\n "columnName": "delta"\n },\n {\n "functionName": "Caption",\n "columnName": "delta"\n },\n {\n "functionName": "MemberValue",\n "columnName": "TradeId"\n },\n {\n "functionName": "Caption",\n "columnName": "TradeId"\n },\n {\n "functionName": "MemberValue",\n "columnName": "ProductQtyMultiplier"\n },\n {\n "functionName": "Caption",\n "columnName": "ProductQtyMultiplier"\n },\n {\n "functionName": "MemberValue",\n "columnName": "ProductQtyMultiplier"\n },\n {\n "functionName": "Caption",\n "columnName": "ProductQtyMultiplier"\n },\n {\n "functionName": "MemberValue",\n "columnName": "ProductBaseMtm"\n },\n {\n "functionName": "Caption",\n "columnName": "ProductBaseMtm"\n },\n {\n "columnName": "ProductQtyMultiplier",\n "functionName": "MemberValue"\n },\n {\n "columnName": "ProductQtyMultiplier",\n "functionName": "Caption"\n }\n ]\n }\n },\n "defaultPermissions": {\n "owners": [\n "admin"\n ],\n "readers": [\n "admin"\n ]\n },\n "project.content-editor.configuration": {\n "autoSwitchToFieldsOnEmptyWidget": true,\n "advancedModeDropdownHidden": false,\n "hideFieldsControls": false,\n "mdx-common": {\n "regularModeTab": "filters",\n "advancedModeEnabled": false,\n "advancedModeTab": "mdx"\n }\n },\n "user.contextValues": {\n "EquityDerivativesCube": {},\n "EquityDerivativesCubeDist": {}\n },\n "user.filters": {\n "EquityDerivativesCube": ["[Geography].[City].[ALL].[AllMember].[Berlin]"],\n "EquityDerivativesCubeDist": []\n },\n "filtering.hierarchyToFilterType.[Geography].[City]": "explicit",\n "filtering.hierarchyToFilterType.[Currency].[Currency]": "explicit",\n "filtering.hierarchyToFilterType.[Trades].[Trades]": "topcount",\n "servers.alias": {\n "https://activepivot-ranch.activeviam.com:5900": "http://localhost:8080"\n }\n }\n}', + isDirectory: false, + owners: ["admin"], + readers: ["admin"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + }, + }, + }, + }, + }, + }, + }, + version: { + entry: { + content: '{"package":"4.3.8","contentServerApi":"0.1.0"}', + isDirectory: false, + owners: ["ROLE_CS_ROOT"], + readers: ["ROLE_USER"], + timestamp: 1607879735685, + lastEditor: "admin", + canRead: true, + canWrite: true, + }, + }, + }, +}; diff --git a/src/4.3_to_5.0/getMigratedKpiTitles.test.ts b/src/4.3_to_5.0/accumulateMigratedKpiTitles.test.ts similarity index 76% rename from src/4.3_to_5.0/getMigratedKpiTitles.test.ts rename to src/4.3_to_5.0/accumulateMigratedKpiTitles.test.ts index f720a443..ed2c87fc 100644 --- a/src/4.3_to_5.0/getMigratedKpiTitles.test.ts +++ b/src/4.3_to_5.0/accumulateMigratedKpiTitles.test.ts @@ -1,12 +1,13 @@ import { dataModelsForTests } from "@activeviam/data-model-5.0"; -import { getMigratedKpiTitles } from "./getMigratedKpiTitles"; +import { accumulateMigratedKpiTitles } from "./accumulateMigratedKpiTitles"; import { legacyKpi } from "./__test_resources__/legacyKpi"; import { _getQueryInLegacyWidgetState } from "./_getQueryInLegacyWidgetState"; import { MdxSelect, parse } from "@activeviam/mdx-5.0"; +import { KpiWidgetState } from "@activeviam/activeui-sdk-5.0"; const cube = dataModelsForTests.sandbox.catalogs[0].cubes[0]; -describe("getMigratedKpiTitles", () => { +describe("accumulateMigratedKpiTitles", () => { it("returns the migrated KPI titles corresponding to the legacy KPI state, ready to be used in Atoti UI 5.0", () => { const legacyQuery = _getQueryInLegacyWidgetState(legacyKpi); @@ -15,7 +16,9 @@ describe("getMigratedKpiTitles", () => { } const legacyMdx = parse(legacyQuery.mdx); - const migratedKpiTitles = getMigratedKpiTitles(legacyKpi, { + const migratedTitles: KpiWidgetState["titles"] = {}; + accumulateMigratedKpiTitles(legacyKpi, { + migratedTitles, cube, legacyMdx, mapping: { @@ -31,7 +34,7 @@ describe("getMigratedKpiTitles", () => { ], }, }); - expect(migratedKpiTitles).toMatchInlineSnapshot(` + expect(migratedTitles).toMatchInlineSnapshot(` { "[Measures].[contributors.COUNT],[Currency].[Currency].[AllMember].[EUR, USD]": "Hello World", } diff --git a/src/4.3_to_5.0/getMigratedKpiTitles.ts b/src/4.3_to_5.0/accumulateMigratedKpiTitles.ts similarity index 53% rename from src/4.3_to_5.0/getMigratedKpiTitles.ts rename to src/4.3_to_5.0/accumulateMigratedKpiTitles.ts index 51defb1c..2abb7abf 100644 --- a/src/4.3_to_5.0/getMigratedKpiTitles.ts +++ b/src/4.3_to_5.0/accumulateMigratedKpiTitles.ts @@ -12,7 +12,6 @@ import { getMeasuresPositionOnAxis, MdxSelect, } from "@activeviam/mdx-5.0"; -import _isEmpty from "lodash/isEmpty"; interface LegacyKpiTitle { title: string; @@ -44,55 +43,55 @@ function _getLegacyKpiTitles( } = {}; const memberUniqueNames = tupleKey.split(/,(?![^\[]*\])/); for (const memberUniqueName of memberUniqueNames) { - if (!memberUniqueName) { - continue; - } - const compoundIdentifier = - parse(memberUniqueName); - const specificCompoundIdentifier = getSpecificCompoundIdentifier( - compoundIdentifier, - { cube }, - ); - if (specificCompoundIdentifier.type === "measure") { - tuple[`[Measures].[Measures]`] = [ - specificCompoundIdentifier.measureName, - ]; - } else if (specificCompoundIdentifier.type === "member") { - const hierarchyUniqueName = quote( - specificCompoundIdentifier.dimensionName, - specificCompoundIdentifier.hierarchyName, + if (memberUniqueName) { + const compoundIdentifier = + parse(memberUniqueName); + const specificCompoundIdentifier = getSpecificCompoundIdentifier( + compoundIdentifier, + { cube }, ); - tuple[hierarchyUniqueName] = specificCompoundIdentifier.path; + if (specificCompoundIdentifier.type === "measure") { + tuple[`[Measures].[Measures]`] = [ + specificCompoundIdentifier.measureName, + ]; + } else if (specificCompoundIdentifier.type === "member") { + const hierarchyUniqueName = quote( + specificCompoundIdentifier.dimensionName, + specificCompoundIdentifier.hierarchyName, + ); + tuple[hierarchyUniqueName] = specificCompoundIdentifier.path; + } } } - if (!_isEmpty(tuple)) { - legacyTitles.push({ title, tuple }); - } + legacyTitles.push({ title, tuple }); } return legacyTitles; } /** - * Returns the migrated KPI widget titles corresponding to legacyKpiState. + * Accumulates the migrated KPI widget titles corresponding to legacyKpiState. + * Mutates `migratedTitles`. */ -export function getMigratedKpiTitles( +export function accumulateMigratedKpiTitles( // Legacy widget states are not typed. // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types legacyKpiState: any, { + migratedTitles = {}, legacyMdx, mapping, cube, }: { + migratedTitles: KpiWidgetState["titles"]; legacyMdx: MdxSelect; mapping: DataVisualizationWidgetMapping; cube: Cube; }, -): KpiWidgetState["titles"] { +): void { const legacyTitles = _getLegacyKpiTitles(legacyKpiState, { cube }); - const migratedTitles: KpiWidgetState["titles"] = {}; + const errors: Error[] = []; const numberOfColumnFields = mapping.columns?.length ?? 0; @@ -114,35 +113,44 @@ export function getMigratedKpiTitles( const ordinalFields = [...(mapping.columns ?? []), ...(mapping.rows ?? [])]; legacyTitles.forEach(({ title, tuple }) => { - const memberUniqueNames: string[] = []; - - ordinalFields.forEach((field) => { - if (field.type === "hierarchy") { - const hierarchyUniqueName = quote( - field.dimensionName, - field.hierarchyName, - ); - const namePath = tuple[hierarchyUniqueName]; - if (namePath) { - memberUniqueNames.push( - `${hierarchyUniqueName}.${quote(...namePath)}`, + try { + const memberUniqueNames: string[] = []; + + ordinalFields.forEach((field) => { + if (field.type === "hierarchy") { + const hierarchyUniqueName = quote( + field.dimensionName, + field.hierarchyName, ); + const namePath = tuple[hierarchyUniqueName]; + if (namePath) { + memberUniqueNames.push( + `${hierarchyUniqueName}.${quote(...namePath)}`, + ); + } } + }); + + if (measuresPositionInTuple > -1) { + const measureName = tuple[quote("Measures", "Measures")][0]; + memberUniqueNames.splice( + measuresPositionInTuple, + 0, + quote("Measures", measureName), + ); } - }); - - if (measuresPositionInTuple > -1) { - const measureName = tuple[quote("Measures", "Measures")][0]; - memberUniqueNames.splice( - measuresPositionInTuple, - 0, - quote("Measures", measureName), - ); - } - const tupleKey = memberUniqueNames.join(","); - migratedTitles[tupleKey] = title; + const tupleKey = memberUniqueNames.join(","); + migratedTitles[tupleKey] = title; + } catch (error) { + errors.push(error as Error); + } }); - return migratedTitles; + if (errors.length > 0) { + throw new Error( + `One or more errors occurred while migrating the titles for the kpi named ${legacyKpiState.name}: ` + + errors.map((e) => e.message).join(", "), + ); + } } diff --git a/src/4.3_to_5.0/migrateKpi.ts b/src/4.3_to_5.0/migrateKpi.ts index 96c799a9..592389de 100644 --- a/src/4.3_to_5.0/migrateKpi.ts +++ b/src/4.3_to_5.0/migrateKpi.ts @@ -29,7 +29,7 @@ import { _getQueryInLegacyWidgetState } from "./_getQueryInLegacyWidgetState"; import { _getTargetCubeFromServerUrl } from "./_getTargetCubeFromServerUrl"; import { _migrateQuery } from "./_migrateQuery"; import { produce } from "immer"; -import { getMigratedKpiTitles } from "./getMigratedKpiTitles"; +import { accumulateMigratedKpiTitles } from "./accumulateMigratedKpiTitles"; import { PartialMigrationError } from "../PartialMigrationError"; const moveExpressionToWithClause = ( @@ -210,13 +210,15 @@ export function migrateKpi( }), }; + const migratedTitles: KpiWidgetState["titles"] = {}; try { if (legacyMdx) { // Migrate manually entered KPI titles. - const migratedTitles = getMigratedKpiTitles(legacyKpiState, { + accumulateMigratedKpiTitles(legacyKpiState, { cube, mapping, legacyMdx, + migratedTitles, }); if (migratedTitles && Object.keys(migratedTitles).length > 0) { migratedWidgetState.titles = migratedTitles; @@ -224,6 +226,11 @@ export function migrateKpi( } } catch (error) { // Migrating the KPI titles is a best effort. + // If there is an error while migrating one of the titles, the successfully migrated titles are still persisted. + if (migratedTitles && Object.keys(migratedTitles).length > 0) { + migratedWidgetState.titles = migratedTitles; + } + // The migration script should not fail if this part errors. throw new PartialMigrationError( `Could not migrate the titles of the featured values widget named "${legacyKpiState.name}"`, diff --git a/src/migrateContentServer.test.ts b/src/migrateContentServer.test.ts index 49066c6b..702b2638 100644 --- a/src/migrateContentServer.test.ts +++ b/src/migrateContentServer.test.ts @@ -4,6 +4,7 @@ import { smallLegacyPivotFolder } from "./4.3_to_5.0/__test_resources__/smallLeg import { smallLegacyUIFolder } from "./4.3_to_5.0/__test_resources__/smallLegacyUIFolder"; import { migrateContentServer } from "./migrateContentServer"; import _cloneDeep from "lodash/cloneDeep"; +import { smallLegacyUIFolderWithInvalidKpiTitle } from "./4.3_to_5.0/__test_resources__/smallLegacyUIFolderWithInvalidKpiTitle"; jest.mock(`./4.3_to_5.0/generateId`, () => { let counter = 0; @@ -235,7 +236,10 @@ describe("migrateContentServer", () => { it("migrates the KPI custom titles while dropping custom titles with an empty `tupleKey` for their location", async () => { const contentServer: ContentRecord = { - children: { ui: smallLegacyUIFolder, pivot: smallLegacyPivotFolder }, + children: { + ui: smallLegacyUIFolderWithInvalidKpiTitle, + pivot: smallLegacyPivotFolder, + }, entry: { owners: [], readers: [],