@gooddata/sdk-backend-tiger 11.55.0-alpha.2 → 11.55.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/__version.d.ts +1 -1
- package/esm/__version.js +1 -1
- package/esm/backend/workspace/catalog/availableItemsFactory.d.ts +0 -7
- package/esm/backend/workspace/catalog/availableItemsFactory.d.ts.map +1 -1
- package/esm/backend/workspace/catalog/availableItemsFactory.js +3 -29
- package/esm/backend/workspace/computedAttributes/index.d.ts.map +1 -1
- package/esm/backend/workspace/computedAttributes/index.js +19 -7
- package/esm/backend/workspace/genAI/SemanticSearchQuery.js +1 -1
- package/esm/backend/workspace/insights/index.d.ts.map +1 -1
- package/esm/backend/workspace/insights/index.js +5 -0
- package/esm/convertors/toBackend/ConditionalFormattingConverter.d.ts +27 -0
- package/esm/convertors/toBackend/ConditionalFormattingConverter.d.ts.map +1 -0
- package/esm/convertors/toBackend/ConditionalFormattingConverter.js +72 -0
- package/package.json +12 -12
package/esm/__version.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "11.55.0-alpha.
|
|
1
|
+
export declare const LIB_VERSION = "11.55.0-alpha.3";
|
|
2
2
|
export declare const LIB_DESCRIPTION = "GoodData Backend SPI implementation for GoodData Cloud and GoodData.CN";
|
|
3
3
|
export declare const LIB_NAME = "@gooddata/sdk-backend-tiger";
|
|
4
4
|
//# sourceMappingURL=__version.d.ts.map
|
package/esm/__version.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// (C) 2021 GoodData Corporation
|
|
2
2
|
// DO NOT CHANGE THIS FILE, IT IS RE-GENERATED ON EVERY BUILD
|
|
3
|
-
export const LIB_VERSION = "11.55.0-alpha.
|
|
3
|
+
export const LIB_VERSION = "11.55.0-alpha.3";
|
|
4
4
|
export const LIB_DESCRIPTION = "GoodData Backend SPI implementation for GoodData Cloud and GoodData.CN";
|
|
5
5
|
export const LIB_NAME = "@gooddata/sdk-backend-tiger";
|
|
@@ -21,13 +21,6 @@ export declare class TigerWorkspaceCatalogAvailableItemsFactory implements IWork
|
|
|
21
21
|
withSignal(signal: AbortSignal): IWorkspaceCatalogAvailableItemsFactory;
|
|
22
22
|
load(): Promise<TigerWorkspaceCatalogWithAvailableItems>;
|
|
23
23
|
}
|
|
24
|
-
/**
|
|
25
|
-
* Whether a reference points at a computed attribute - either because it says so, or because its
|
|
26
|
-
* identifier is one of the workspace's computed attributes. The fabricated display form of a
|
|
27
|
-
* computed attribute shares the computed attribute's id, so the identifier match holds for both the
|
|
28
|
-
* attribute reference and its display form reference.
|
|
29
|
-
*/
|
|
30
|
-
export declare const isComputedAttributeRef: (ref: ObjRef, computedAttributeIds: Set<string>) => boolean;
|
|
31
24
|
/**
|
|
32
25
|
* @internal
|
|
33
26
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"availableItemsFactory.d.ts","sourceRoot":"","sources":["../../../../src/backend/workspace/catalog/availableItemsFactory.ts"],"names":[],"mappings":"AAOA,OAAO,EACH,KAAK,sCAAsC,EAC3C,KAAK,iDAAiD,EACzD,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,WAAW,EAChB,KAAK,eAAe,EAEpB,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,OAAO,EACZ,KAAK,kBAAkB,EACvB,KAAK,MAAM,
|
|
1
|
+
{"version":3,"file":"availableItemsFactory.d.ts","sourceRoot":"","sources":["../../../../src/backend/workspace/catalog/availableItemsFactory.ts"],"names":[],"mappings":"AAOA,OAAO,EACH,KAAK,sCAAsC,EAC3C,KAAK,iDAAiD,EACzD,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,WAAW,EAChB,KAAK,eAAe,EAEpB,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,OAAO,EACZ,KAAK,kBAAkB,EACvB,KAAK,MAAM,EAmBd,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAE3E,OAAO,EAAE,uCAAuC,EAAE,MAAM,gCAAgC,CAAC;AAiDzF,qBAAa,0CAA2C,YAAW,sCAAsC;IAEjG,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAMxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAX5B,YACqB,QAAQ,EAAE,2BAA2B,EACrC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,aAAa,EAAE,EACvB,KAAK,EAAE,WAAW,EAAE,EACpB,OAAO,GAAE,iDAKzB,EACgB,MAAM,CAAC,yBAAa,EACrC;IAEG,WAAW,CACd,OAAO,EAAE,OAAO,CAAC,iDAAiD,CAAC,GACpE,sCAAsC,CAaxC;IAEM,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,sCAAsC,CAEzE;IAEM,QAAQ,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,sCAAsC,CAEhF;IAEM,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,sCAAsC,CAEzE;IAEM,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,sCAAsC,CAEzE;IAEM,QAAQ,CAAC,KAAK,EAAE,mBAAmB,EAAE,GAAG,sCAAsC,CAEpF;IAEM,UAAU,CAAC,OAAO,EAAE,kBAAkB,GAAG,sCAAsC,CAErF;IAEM,UAAU,CAAC,UAAU,EAAE,OAAO,GAAG,sCAAsC,CAI7E;IAEM,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,sCAAsC,CAS7E;IAEY,IAAI,IAAI,OAAO,CAAC,uCAAuC,CAAC,CAwDpE;CACJ;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAMxF;AAED,gBAAgB;AAChB,eAAO,MAAM,8BAA8B,iGA8B1C,CAAC"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { compact, intersectionWith, uniq } from "lodash-es";
|
|
3
3
|
import { InvariantError } from "ts-invariant";
|
|
4
4
|
import { ActionsApi_ComputeValidObjects } from "@gooddata/api-client-tiger/endpoints/validObjects";
|
|
5
|
-
import { areObjRefsEqual, attributeLocalId, insightAttributes, insightFilters, insightMeasures, isAttribute, isCatalogAttribute, isCatalogAttributeHierarchy, isCatalogComputedAttribute, isCatalogFact, isCatalogMeasure, isFilter,
|
|
5
|
+
import { areObjRefsEqual, attributeLocalId, insightAttributes, insightFilters, insightMeasures, isAttribute, isCatalogAttribute, isCatalogAttributeHierarchy, isCatalogComputedAttribute, isCatalogFact, isCatalogMeasure, isFilter, isLocalIdRef, isMeasure, isMeasureValueFilter, isRankingFilter, measureLocalId, } from "@gooddata/sdk-model";
|
|
6
6
|
import { jsonApiIdToObjRef } from "../../../convertors/fromBackend/ObjRefConverter.js";
|
|
7
7
|
import { convertAfmFilters } from "../../../convertors/toBackend/afm/AfmFiltersConverter.js";
|
|
8
8
|
import { convertAttribute } from "../../../convertors/toBackend/afm/AttributeConverter.js";
|
|
@@ -11,6 +11,7 @@ import { TigerWorkspaceCatalogWithAvailableItems } from "./catalogWithAvailableI
|
|
|
11
11
|
//ivec investigate
|
|
12
12
|
const typesMatching = {
|
|
13
13
|
attribute: "attributes",
|
|
14
|
+
computedAttribute: "computedAttributes",
|
|
14
15
|
fact: "facts",
|
|
15
16
|
measure: "measures",
|
|
16
17
|
// dateDatasets are not supported by tiger in this context
|
|
@@ -111,19 +112,7 @@ export class TigerWorkspaceCatalogAvailableItemsFactory {
|
|
|
111
112
|
const relevantItems = insight
|
|
112
113
|
? [...insightMeasures(insight), ...insightAttributes(insight), ...insightFilters(insight)]
|
|
113
114
|
: items;
|
|
114
|
-
|
|
115
|
-
// makes it fail for the WHOLE insight - which takes the catalog availability and the date
|
|
116
|
-
// datasets down with it. Leaving computed attributes out narrows the answer (their own
|
|
117
|
-
// restrictions are not applied) instead of losing it.
|
|
118
|
-
//
|
|
119
|
-
// Identified against the CATALOG rather than against the reference's own type: an insight
|
|
120
|
-
// built before the reference carried the computed attribute type still points at one with a
|
|
121
|
-
// plain displayForm type, and such a reference must be dropped too or the request 400s.
|
|
122
|
-
// TODO INE (CQ-2796): include them once the action accepts them
|
|
123
|
-
const computedAttributeIds = new Set(this.items.filter(isCatalogComputedAttribute).map((item) => item.computedAttribute.id));
|
|
124
|
-
const attributes = relevantItems
|
|
125
|
-
.filter(isAttribute)
|
|
126
|
-
.filter((attribute) => !isComputedAttributeRef(attribute.attribute.displayForm, computedAttributeIds));
|
|
115
|
+
const attributes = relevantItems.filter(isAttribute);
|
|
127
116
|
const measures = relevantItems.filter(isMeasure);
|
|
128
117
|
const filters = relevantItems.filter(isFilter);
|
|
129
118
|
const attributeLocalIds = new Set(attributes.map((attribute) => attributeLocalId(attribute)));
|
|
@@ -153,25 +142,10 @@ export class TigerWorkspaceCatalogAvailableItemsFactory {
|
|
|
153
142
|
const allAvailableItems = [
|
|
154
143
|
...availableItems,
|
|
155
144
|
...(types.includes("attributeHierarchy") ? this.items.filter(isCatalogAttributeHierarchy) : []),
|
|
156
|
-
// The action cannot evaluate a computed attribute yet, so one would never come back in
|
|
157
|
-
// the response and filterAvailableItems would drop it - hence the pass-through. Only
|
|
158
|
-
// when the query was actually sent: an empty query already answers with every item, and
|
|
159
|
-
// appending would list the computed attributes twice.
|
|
160
|
-
// TODO INE (CQ-2796): drop this once the action evaluates them
|
|
161
|
-
...(types.includes("computedAttribute") && !afmValidObjectsQueryEmpty
|
|
162
|
-
? this.items.filter(isCatalogComputedAttribute)
|
|
163
|
-
: []),
|
|
164
145
|
];
|
|
165
146
|
return new TigerWorkspaceCatalogWithAvailableItems(this.groups, this.items, allAvailableItems, this.options);
|
|
166
147
|
}
|
|
167
148
|
}
|
|
168
|
-
/**
|
|
169
|
-
* Whether a reference points at a computed attribute - either because it says so, or because its
|
|
170
|
-
* identifier is one of the workspace's computed attributes. The fabricated display form of a
|
|
171
|
-
* computed attribute shares the computed attribute's id, so the identifier match holds for both the
|
|
172
|
-
* attribute reference and its display form reference.
|
|
173
|
-
*/
|
|
174
|
-
export const isComputedAttributeRef = (ref, computedAttributeIds) => isIdentifierRef(ref) && (ref.type === "computedAttribute" || computedAttributeIds.has(ref.identifier));
|
|
175
149
|
/**
|
|
176
150
|
* @internal
|
|
177
151
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/backend/workspace/computedAttributes/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/backend/workspace/computedAttributes/index.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACR,6BAA6B,EAC7B,4BAA4B,EAC5B,uBAAuB,EACvB,mCAAmC,EACtC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,gCAAgC,EACrC,KAAK,0CAA0C,EAC/C,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,MAAM,EAGd,MAAM,qBAAqB,CAAC;AAO7B,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAI3E,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,qBAAa,gCAAiC,YAAW,mCAAmC;IAEpF,OAAO,CAAC,QAAQ,CAAC,QAAQ;aACT,SAAS,EAAE,MAAM;IAFrC,YACqB,QAAQ,EAAE,2BAA2B,EACtC,SAAS,EAAE,MAAM,EACjC;IAEE,uBAAuB,CACzB,iBAAiB,EAAE,0CAA0C,GAC9D,OAAO,CAAC,gCAAgC,CAAC,CAgB3C;IAEK,uBAAuB,CACzB,iBAAiB,EAAE,gCAAgC,GACpD,OAAO,CAAC,gCAAgC,CAAC,CAkB3C;IAEK,2BAA2B,CAC7B,iBAAiB,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,uBAAuB,GAC1E,OAAO,CAAC,gCAAgC,CAAC,CA4B3C;IAEK,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CASxD;IAEY,oBAAoB,CAC7B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,4BAAiC,GAC3C,OAAO,CAAC,gCAAgC,CAAC,CAW3C;IAEY,oCAAoC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CA2BjG;IAEY,sCAAsC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAsDvG;IAEM,0BAA0B,IAAI,uBAAuB,CAE3D;CACJ"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { uniqBy } from "lodash-es";
|
|
2
3
|
import { MetadataUtilities } from "@gooddata/api-client-tiger";
|
|
3
|
-
import { EntitiesApi_CreateEntityComputedAttributes, EntitiesApi_DeleteEntityComputedAttributes, EntitiesApi_GetAllEntitiesMetrics, EntitiesApi_GetAllEntitiesVisualizationObjects, EntitiesApi_GetEntityComputedAttributes, EntitiesApi_PatchEntityComputedAttributes, EntitiesApi_UpdateEntityComputedAttributes, } from "@gooddata/api-client-tiger/endpoints/entitiesObjects";
|
|
4
|
-
import { isIdentifierRef, } from "@gooddata/sdk-model";
|
|
4
|
+
import { DashboardsApi_GetAllEntitiesAnalyticalDashboards, EntitiesApi_CreateEntityComputedAttributes, EntitiesApi_DeleteEntityComputedAttributes, EntitiesApi_GetAllEntitiesMetrics, EntitiesApi_GetAllEntitiesVisualizationObjects, EntitiesApi_GetEntityComputedAttributes, EntitiesApi_PatchEntityComputedAttributes, EntitiesApi_UpdateEntityComputedAttributes, } from "@gooddata/api-client-tiger/endpoints/entitiesObjects";
|
|
5
|
+
import { insightId, isIdentifierRef, } from "@gooddata/sdk-model";
|
|
5
6
|
import { convertComputedAttributeFromBackend } from "../../../convertors/fromBackend/ComputedAttributeConverter.js";
|
|
6
7
|
import { visualizationObjectsItemToInsight } from "../../../convertors/fromBackend/InsightConverter.js";
|
|
8
|
+
import { convertAnalyticalDashboardWithLinks } from "../../../convertors/fromBackend/MetadataConverter.js";
|
|
7
9
|
import { convertMetricFromBackend } from "../../../convertors/fromBackend/MetricConverter.js";
|
|
8
10
|
import { convertComputedAttributeToBackend } from "../../../convertors/toBackend/ComputedAttributeConverter.js";
|
|
9
11
|
import { objRefToIdentifier } from "../../../utils/api.js";
|
|
@@ -119,16 +121,15 @@ export class TigerWorkspaceComputedAttributes {
|
|
|
119
121
|
}
|
|
120
122
|
async getComputedAttributeReferencingObjects(ref) {
|
|
121
123
|
const id = objRefToIdentifier(ref, this.authCall);
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
+
// Visualizations grouping by the computed attribute, metrics that reference it, and
|
|
125
|
+
// dashboards that filter by it or embed those visualizations. The backend allows the
|
|
126
|
+
// delete; the catalog refuses it and lists these titles instead.
|
|
124
127
|
const insights = this.authCall((client) => MetadataUtilities.getAllPagesOf(client, EntitiesApi_GetAllEntitiesVisualizationObjects, {
|
|
125
128
|
workspaceId: this.workspace,
|
|
126
|
-
// return only visualizationObjects that have a link to the given computed attribute
|
|
127
129
|
filter: `computedAttributes.id==${id}`,
|
|
128
130
|
})
|
|
129
131
|
.then(MetadataUtilities.mergeEntitiesResults)
|
|
130
132
|
.then((visualizationObjects) => visualizationObjects.data.map((visualizationObject) => visualizationObjectsItemToInsight(visualizationObject, visualizationObjects.included))));
|
|
131
|
-
// Reports nothing until a metric can reference a computed attribute (pending backend support).
|
|
132
133
|
const measures = this.authCall((client) => MetadataUtilities.getAllPagesOf(client, EntitiesApi_GetAllEntitiesMetrics, {
|
|
133
134
|
workspaceId: this.workspace,
|
|
134
135
|
include: ["computedAttributes"],
|
|
@@ -137,7 +138,18 @@ export class TigerWorkspaceComputedAttributes {
|
|
|
137
138
|
.then(MetadataUtilities.mergeEntitiesResults)
|
|
138
139
|
.then((metrics) => metrics.data.map((metric) => convertMetricFromBackend(metric, metrics.included))));
|
|
139
140
|
const [insightList, measureList] = await Promise.all([insights, measures]);
|
|
140
|
-
|
|
141
|
+
const dashboardFilterParts = [`labels.id==${id}`];
|
|
142
|
+
if (insightList.length > 0) {
|
|
143
|
+
const insightIds = insightList.map((insight) => `"${insightId(insight)}"`).join(",");
|
|
144
|
+
dashboardFilterParts.push(`visualizationObjects.id=in=(${insightIds})`);
|
|
145
|
+
}
|
|
146
|
+
const analyticalDashboards = await this.authCall((client) => MetadataUtilities.getAllPagesOf(client, DashboardsApi_GetAllEntitiesAnalyticalDashboards, {
|
|
147
|
+
workspaceId: this.workspace,
|
|
148
|
+
filter: dashboardFilterParts.join(","),
|
|
149
|
+
})
|
|
150
|
+
.then(MetadataUtilities.mergeEntitiesResults)
|
|
151
|
+
.then((dashboards) => uniqBy(dashboards.data.map((dashboard) => convertAnalyticalDashboardWithLinks(dashboard)), (dashboard) => dashboard.id)));
|
|
152
|
+
return { insights: insightList, measures: measureList, analyticalDashboards };
|
|
141
153
|
}
|
|
142
154
|
getComputedAttributesQuery() {
|
|
143
155
|
return new ComputedAttributesQuery(this.authCall, { workspaceId: this.workspace });
|
|
@@ -60,7 +60,7 @@ export class SemanticSearchQuery {
|
|
|
60
60
|
async query(options) {
|
|
61
61
|
const response = await this.authCall((client) => GenAiApi_AiSearch(client.axios, client.basePath, {
|
|
62
62
|
workspaceId: this.workspaceId,
|
|
63
|
-
|
|
63
|
+
aiSearchRequest: this.config,
|
|
64
64
|
}, options));
|
|
65
65
|
// Casting because api-client has loose typing for object type
|
|
66
66
|
return response.data;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/backend/workspace/insights/index.ts"],"names":[],"mappings":"AA+BA,OAAO,EACH,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,8BAA8B,EAEtC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,mBAAmB,EACxB,KAAK,MAAM,EASd,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/backend/workspace/insights/index.ts"],"names":[],"mappings":"AA+BA,OAAO,EACH,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,8BAA8B,EAEtC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,mBAAmB,EACxB,KAAK,MAAM,EASd,MAAM,qBAAqB,CAAC;AAkB7B,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAM3E,qBAAa,sBAAuB,YAAW,yBAAyB;IAEhE,OAAO,CAAC,QAAQ,CAAC,QAAQ;aACT,SAAS,EAAE,MAAM;IAFrC,YACqB,QAAQ,EAAE,2BAA2B,EACtC,SAAS,EAAE,MAAM,EACjC;IAEG,qBAAqB,gDAS1B;IAEK,uBAAuB,uCAE5B;IAEK,WAAW,iFA6BhB;IAEK,gBAAgB,uBAErB;IAEF,OAAO,CAAC,4BAA4B,CAqBlC;IAEF,OAAO,CAAC,eAAe,CAmCrB;IAEF;;;OAGG;IACI,0BAA0B;;;OAyB/B;IAEF,OAAO,CAAC,wBAAwB,CAiB9B;IAEK,UAAU,mEAKf;IAEK,aAAa,qDAoClB;IAEK,aAAa,2CAuBlB;IAEK,iBAAiB,6FA2BtB;IAEK,gBAAgB,wFAerB;IAEK,aAAa,iCASlB;IAEK,2BAA2B,6GAKhC;IAEK,4BAA4B,gDAoBjC;IAEK,0BAA0B,GAAU,CAAC,2EAY1C;CACL"}
|
|
@@ -12,6 +12,7 @@ import { convertVisualizationObjectsToInsights, insightFromInsightDefinition, }
|
|
|
12
12
|
import { isInheritedObject } from "../../../convertors/fromBackend/ObjectInheritance.js";
|
|
13
13
|
import { convertUserIdentifier } from "../../../convertors/fromBackend/UsersConverter.js";
|
|
14
14
|
import { convertVisualizationObject } from "../../../convertors/fromBackend/visualizationObjects/VisualizationObjectConverter.js";
|
|
15
|
+
import { convertConditionalFormatting } from "../../../convertors/toBackend/ConditionalFormattingConverter.js";
|
|
15
16
|
import { convertInsight } from "../../../convertors/toBackend/InsightConverter.js";
|
|
16
17
|
import { objRefToIdentifier, objRefToUri } from "../../../utils/api.js";
|
|
17
18
|
import { InsightsQuery } from "./insightsQuery.js";
|
|
@@ -160,6 +161,8 @@ export class TigerWorkspaceInsights {
|
|
|
160
161
|
attributes: {
|
|
161
162
|
description: insightSummary(insight),
|
|
162
163
|
content: convertInsight(insight),
|
|
164
|
+
// dual-write: content (authoritative) + the typed projection
|
|
165
|
+
conditionalFormatting: convertConditionalFormatting(insight),
|
|
163
166
|
title: insightTitle(insight),
|
|
164
167
|
tags: insightTags(insight),
|
|
165
168
|
...(insight.insight.isHidden === undefined
|
|
@@ -185,6 +188,8 @@ export class TigerWorkspaceInsights {
|
|
|
185
188
|
attributes: {
|
|
186
189
|
description: insightSummary(insight),
|
|
187
190
|
content: convertInsight(insight),
|
|
191
|
+
// dual-write: content (authoritative) + the typed projection
|
|
192
|
+
conditionalFormatting: convertConditionalFormatting(insight),
|
|
188
193
|
title: insightTitle(insight),
|
|
189
194
|
tags: insightTags(insight),
|
|
190
195
|
isHidden: insight.insight.isHidden,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type JsonApiVisualizationObjectInAttributesConditionalFormatting } from "@gooddata/api-client-tiger";
|
|
2
|
+
import { type IInsightDefinition } from "@gooddata/sdk-model";
|
|
3
|
+
/**
|
|
4
|
+
* Projects the insight's conditional formatting (persisted free-form under
|
|
5
|
+
* `properties.controls.conditionalFormatting`) into the typed visualizationObject entity attribute.
|
|
6
|
+
*
|
|
7
|
+
* Dual-write: `content` — which still carries the same rules inside `properties` — stays
|
|
8
|
+
* authoritative; this typed attribute is a parallel, server-validated projection that readers switch
|
|
9
|
+
* to later. Two boundary guarantees:
|
|
10
|
+
* - Returns `null` (never `undefined`) when there is no formatting, so the PUT body explicitly clears
|
|
11
|
+
* the projection rather than relying on the server's omitted-attribute semantics — otherwise a
|
|
12
|
+
* cleared CF could leave a stale typed projection diverging from the authoritative `content`.
|
|
13
|
+
* - A malformed blob (`content` is free-form and unvalidated) also degrades to `null`: the projection
|
|
14
|
+
* must never break a save, since `content` remains the source of truth.
|
|
15
|
+
*
|
|
16
|
+
* `version` and `customTargets` are intentionally NOT carried — the typed schema does not model them
|
|
17
|
+
* yet, and `content` stays authoritative until the switch, so nothing is lost. This is an allow-list:
|
|
18
|
+
* a field added to {@link IConditionalFormatting} will not auto-propagate; extend this projection (and
|
|
19
|
+
* its test) when the typed schema grows.
|
|
20
|
+
*
|
|
21
|
+
* The projection is a structural copy except for relative-date granularities, which the SDK stores in
|
|
22
|
+
* its own vocabulary (`GDC.time.*`) while the typed schema uses tiger's (`YEAR`, `MONTH_OF_YEAR`, ...);
|
|
23
|
+
* those are translated via the canonical granularity mapping, and a granularity tiger does not model
|
|
24
|
+
* degrades the projection to `null` like any other malformed-blob case.
|
|
25
|
+
*/
|
|
26
|
+
export declare function convertConditionalFormatting(insight: IInsightDefinition): JsonApiVisualizationObjectInAttributesConditionalFormatting | null;
|
|
27
|
+
//# sourceMappingURL=ConditionalFormattingConverter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConditionalFormattingConverter.d.ts","sourceRoot":"","sources":["../../../src/convertors/toBackend/ConditionalFormattingConverter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,2DAA2D,EAAE,MAAM,4BAA4B,CAAC;AAE9G,OAAO,EAIH,KAAK,kBAAkB,EAE1B,MAAM,qBAAqB,CAAC;AAI7B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,4BAA4B,CACxC,OAAO,EAAE,kBAAkB,GAC5B,2DAA2D,GAAG,IAAI,CAsCpE"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { NotSupported } from "@gooddata/sdk-backend-spi";
|
|
3
|
+
import { insightProperties, } from "@gooddata/sdk-model";
|
|
4
|
+
import { toTigerGranularity } from "../fromBackend/dateGranularityConversions.js";
|
|
5
|
+
/**
|
|
6
|
+
* Projects the insight's conditional formatting (persisted free-form under
|
|
7
|
+
* `properties.controls.conditionalFormatting`) into the typed visualizationObject entity attribute.
|
|
8
|
+
*
|
|
9
|
+
* Dual-write: `content` — which still carries the same rules inside `properties` — stays
|
|
10
|
+
* authoritative; this typed attribute is a parallel, server-validated projection that readers switch
|
|
11
|
+
* to later. Two boundary guarantees:
|
|
12
|
+
* - Returns `null` (never `undefined`) when there is no formatting, so the PUT body explicitly clears
|
|
13
|
+
* the projection rather than relying on the server's omitted-attribute semantics — otherwise a
|
|
14
|
+
* cleared CF could leave a stale typed projection diverging from the authoritative `content`.
|
|
15
|
+
* - A malformed blob (`content` is free-form and unvalidated) also degrades to `null`: the projection
|
|
16
|
+
* must never break a save, since `content` remains the source of truth.
|
|
17
|
+
*
|
|
18
|
+
* `version` and `customTargets` are intentionally NOT carried — the typed schema does not model them
|
|
19
|
+
* yet, and `content` stays authoritative until the switch, so nothing is lost. This is an allow-list:
|
|
20
|
+
* a field added to {@link IConditionalFormatting} will not auto-propagate; extend this projection (and
|
|
21
|
+
* its test) when the typed schema grows.
|
|
22
|
+
*
|
|
23
|
+
* The projection is a structural copy except for relative-date granularities, which the SDK stores in
|
|
24
|
+
* its own vocabulary (`GDC.time.*`) while the typed schema uses tiger's (`YEAR`, `MONTH_OF_YEAR`, ...);
|
|
25
|
+
* those are translated via the canonical granularity mapping, and a granularity tiger does not model
|
|
26
|
+
* degrades the projection to `null` like any other malformed-blob case.
|
|
27
|
+
*/
|
|
28
|
+
export function convertConditionalFormatting(insight) {
|
|
29
|
+
const conditionalFormatting = insightProperties(insight)["controls"]?.["conditionalFormatting"];
|
|
30
|
+
if (!conditionalFormatting ||
|
|
31
|
+
!Array.isArray(conditionalFormatting.rules) ||
|
|
32
|
+
conditionalFormatting.rules.some((rule) => !Array.isArray(rule?.conditions) ||
|
|
33
|
+
rule.conditions.some((condition) => !condition || typeof condition !== "object"))) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
// Array.isArray() narrows the readonly rules array to any[]; re-annotate to keep element types.
|
|
37
|
+
const rules = conditionalFormatting.rules;
|
|
38
|
+
try {
|
|
39
|
+
return {
|
|
40
|
+
enabled: conditionalFormatting.enabled,
|
|
41
|
+
rules: rules.map((rule) => ({
|
|
42
|
+
id: rule.id,
|
|
43
|
+
target: rule.target,
|
|
44
|
+
conditions: rule.conditions.map((condition) => ({
|
|
45
|
+
id: condition.id,
|
|
46
|
+
operator: condition.operator,
|
|
47
|
+
value: convertValue(condition.value),
|
|
48
|
+
format: condition.format,
|
|
49
|
+
})),
|
|
50
|
+
})),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
// toTigerGranularity throws NotSupported for a granularity the free-form blob may carry but
|
|
55
|
+
// tiger does not model; the projection degrades like any other malformed-blob case.
|
|
56
|
+
if (error instanceof NotSupported) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function convertValue(value) {
|
|
63
|
+
if (value.kind === "relativeDate") {
|
|
64
|
+
return {
|
|
65
|
+
kind: value.kind,
|
|
66
|
+
granularity: toTigerGranularity(value.granularity),
|
|
67
|
+
from: value.from,
|
|
68
|
+
to: value.to,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-backend-tiger",
|
|
3
|
-
"version": "11.55.0-alpha.
|
|
3
|
+
"version": "11.55.0-alpha.3",
|
|
4
4
|
"description": "GoodData Backend SPI implementation for GoodData Cloud and GoodData.CN",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "GoodData",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"ts-invariant": "0.10.3",
|
|
35
35
|
"tslib": "2.8.1",
|
|
36
36
|
"uuid": "11.1.1",
|
|
37
|
-
"@gooddata/api-client-tiger": "11.55.0-alpha.
|
|
38
|
-
"@gooddata/sdk-backend-base": "11.55.0-alpha.
|
|
39
|
-
"@gooddata/sdk-
|
|
40
|
-
"@gooddata/sdk-
|
|
41
|
-
"@gooddata/
|
|
42
|
-
"@gooddata/
|
|
37
|
+
"@gooddata/api-client-tiger": "11.55.0-alpha.3",
|
|
38
|
+
"@gooddata/sdk-backend-base": "11.55.0-alpha.3",
|
|
39
|
+
"@gooddata/sdk-backend-spi": "11.55.0-alpha.3",
|
|
40
|
+
"@gooddata/sdk-code-convertors": "11.55.0-alpha.3",
|
|
41
|
+
"@gooddata/util": "11.55.0-alpha.3",
|
|
42
|
+
"@gooddata/sdk-model": "11.55.0-alpha.3"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@gooddata/fixtures": "3.7.0",
|
|
@@ -60,14 +60,14 @@
|
|
|
60
60
|
"eslint-plugin-sonarjs": "3.0.6",
|
|
61
61
|
"npm-run-all": "4.1.5",
|
|
62
62
|
"oxfmt": "0.52.0",
|
|
63
|
-
"oxlint": "1.
|
|
63
|
+
"oxlint": "1.57.0",
|
|
64
64
|
"oxlint-tsgolint": "0.15.0",
|
|
65
65
|
"typescript": "5.9.3",
|
|
66
66
|
"vitest": "4.1.8",
|
|
67
|
-
"@gooddata/catalog-export": "11.55.0-alpha.
|
|
68
|
-
"@gooddata/eslint-config": "11.55.0-alpha.
|
|
69
|
-
"@gooddata/
|
|
70
|
-
"@gooddata/
|
|
67
|
+
"@gooddata/catalog-export": "11.55.0-alpha.3",
|
|
68
|
+
"@gooddata/eslint-config": "11.55.0-alpha.3",
|
|
69
|
+
"@gooddata/oxlint-config": "11.55.0-alpha.3",
|
|
70
|
+
"@gooddata/reference-workspace": "11.55.0-alpha.3"
|
|
71
71
|
},
|
|
72
72
|
"scripts": {
|
|
73
73
|
"_phase:build": "npm run build",
|