diff --git a/common/changes/@gooddata/sdk-ui-all/JSVA-GDAI-1081-accessibility-3_2026-01-12-10-58.json b/common/changes/@gooddata/sdk-ui-all/JSVA-GDAI-1081-accessibility-3_2026-01-12-10-58.json new file mode 100644 index 00000000000..1209a00058b --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/JSVA-GDAI-1081-accessibility-3_2026-01-12-10-58.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-kit: Make `EditableLabel` accessible by keyboard.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/JSVA-GDAI-1081-accessibility-3_2026-01-12-14-32.json b/common/changes/@gooddata/sdk-ui-all/JSVA-GDAI-1081-accessibility-3_2026-01-12-14-32.json new file mode 100644 index 00000000000..e9c4727c9dc --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/JSVA-GDAI-1081-accessibility-3_2026-01-12-14-32.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-kit: Restore focus on `UiDrawer` close and add `returnFocusTo` option.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/SHA_master_GDAI-1094_2026-01-13-10-05.json b/common/changes/@gooddata/sdk-ui-all/SHA_master_GDAI-1094_2026-01-13-10-05.json new file mode 100644 index 00000000000..3913eb6f578 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/SHA_master_GDAI-1094_2026-01-13-10-05.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-dashboard: Remove the “Select all” checkbox from the attribute picker", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/jsc-f_1_2026-01-13-11-44.json b/common/changes/@gooddata/sdk-ui-all/jsc-f_1_2026-01-13-11-44.json new file mode 100644 index 00000000000..4809cc85b3c --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/jsc-f_1_2026-01-13-11-44.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-kit: Enhance Input component accessibility by providing proper prefix and suffix aria labels.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/pdo-lx-1997-drill-down-menu-position_2026-01-12-20-24.json b/common/changes/@gooddata/sdk-ui-all/pdo-lx-1997-drill-down-menu-position_2026-01-12-20-24.json new file mode 100644 index 00000000000..3cb2c759fcb --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pdo-lx-1997-drill-down-menu-position_2026-01-12-20-24.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-charts, sdk-ui-dashboards: Open dashboard drilldown menu at the position of the click, not in the center of the insight", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/pko-f1-2107_2026-01-13-14-37.json b/common/changes/@gooddata/sdk-ui-all/pko-f1-2107_2026-01-13-14-37.json new file mode 100644 index 00000000000..958e2e11a63 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pko-f1-2107_2026-01-13-14-37.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-dashboard: Fix insight elements DOM order according to a11y findings. Visually unchanged.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/config/rush/version-policies.json b/common/config/rush/version-policies.json index 3b122e5c11c..8cbbdee67d8 100644 --- a/common/config/rush/version-policies.json +++ b/common/config/rush/version-policies.json @@ -12,14 +12,14 @@ { "definitionName": "lockStepVersion", "policyName": "sdk", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "nextBump": "prerelease", "mainProject": "@gooddata/sdk-ui-all" }, { "definitionName": "lockStepVersion", "policyName": "sdk-examples", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "nextBump": "prerelease", "mainProject": "@gooddata/sdk-ui-all" } diff --git a/examples/playground/.eslintrc.cjs b/examples/playground/.eslintrc.cjs index cce70c63ef9..332b348f204 100644 --- a/examples/playground/.eslintrc.cjs +++ b/examples/playground/.eslintrc.cjs @@ -1,16 +1,15 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [ tsOverride(__dirname, { - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-argument": "off", + "@typescript-eslint/no-unsafe-assignment": "warn", }), ], }; diff --git a/examples/playground/src/createBackend.ts b/examples/playground/src/createBackend.ts index b7e49ff2f4e..3a2602e99b7 100644 --- a/examples/playground/src/createBackend.ts +++ b/examples/playground/src/createBackend.ts @@ -1,11 +1,14 @@ -// (C) 2022-2025 GoodData Corporation +// (C) 2022-2026 GoodData Corporation + import { RecommendedCachingConfiguration, withCaching } from "@gooddata/sdk-backend-base"; import { type IAnalyticalBackend } from "@gooddata/sdk-backend-spi"; import { TigerTokenAuthProvider, tigerFactory } from "@gooddata/sdk-backend-tiger"; export function createBackend(): IAnalyticalBackend { return withCaching( - tigerFactory().withAuthentication(new TigerTokenAuthProvider(import.meta.env.VITE_TIGER_API_TOKEN)), + tigerFactory().withAuthentication( + new TigerTokenAuthProvider(import.meta.env["VITE_TIGER_API_TOKEN"] as string), + ), RecommendedCachingConfiguration, ); } diff --git a/examples/sdk-interactive-examples/examples-template/.eslintrc.cjs b/examples/sdk-interactive-examples/examples-template/.eslintrc.cjs index 6f763a177ec..8902a8111c0 100644 --- a/examples/sdk-interactive-examples/examples-template/.eslintrc.cjs +++ b/examples/sdk-interactive-examples/examples-template/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/examples/sdk-interactive-examples/examples-template/package.json b/examples/sdk-interactive-examples/examples-template/package.json index 12b557f6693..5e3262c1943 100644 --- a/examples/sdk-interactive-examples/examples-template/package.json +++ b/examples/sdk-interactive-examples/examples-template/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-examples-template", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "GoodData interactive example template", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-attributefilter/.eslintrc.cjs b/examples/sdk-interactive-examples/examples/example-attributefilter/.eslintrc.cjs index 6f763a177ec..8902a8111c0 100644 --- a/examples/sdk-interactive-examples/examples/example-attributefilter/.eslintrc.cjs +++ b/examples/sdk-interactive-examples/examples/example-attributefilter/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/examples/sdk-interactive-examples/examples/example-attributefilter/package.json b/examples/sdk-interactive-examples/examples/example-attributefilter/package.json index 8865fa98c5c..2051076ecb9 100644 --- a/examples/sdk-interactive-examples/examples/example-attributefilter/package.json +++ b/examples/sdk-interactive-examples/examples/example-attributefilter/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-attributefilter", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "This example demonstrates how to use the AttributeFilter component to filter data in a visualization.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-chartconfig/.eslintrc.cjs b/examples/sdk-interactive-examples/examples/example-chartconfig/.eslintrc.cjs index 6f763a177ec..8902a8111c0 100644 --- a/examples/sdk-interactive-examples/examples/example-chartconfig/.eslintrc.cjs +++ b/examples/sdk-interactive-examples/examples/example-chartconfig/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/examples/sdk-interactive-examples/examples/example-chartconfig/package.json b/examples/sdk-interactive-examples/examples/example-chartconfig/package.json index 95aa5d245d0..01da0a73be0 100644 --- a/examples/sdk-interactive-examples/examples/example-chartconfig/package.json +++ b/examples/sdk-interactive-examples/examples/example-chartconfig/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-chartconfig", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "This interactive example demonstrates how to manipulate the chart config.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-columnchart/.eslintrc.cjs b/examples/sdk-interactive-examples/examples/example-columnchart/.eslintrc.cjs index 6f763a177ec..8902a8111c0 100644 --- a/examples/sdk-interactive-examples/examples/example-columnchart/.eslintrc.cjs +++ b/examples/sdk-interactive-examples/examples/example-columnchart/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/examples/sdk-interactive-examples/examples/example-columnchart/package.json b/examples/sdk-interactive-examples/examples/example-columnchart/package.json index 49b826806b6..ce1fd37718e 100644 --- a/examples/sdk-interactive-examples/examples/example-columnchart/package.json +++ b/examples/sdk-interactive-examples/examples/example-columnchart/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-columnchart", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "This example demonstrates the usage of the ColumnChart component with the viewBy and stackBy properties.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-combochart/.eslintrc.cjs b/examples/sdk-interactive-examples/examples/example-combochart/.eslintrc.cjs index 6f763a177ec..8902a8111c0 100644 --- a/examples/sdk-interactive-examples/examples/example-combochart/.eslintrc.cjs +++ b/examples/sdk-interactive-examples/examples/example-combochart/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/examples/sdk-interactive-examples/examples/example-combochart/package.json b/examples/sdk-interactive-examples/examples/example-combochart/package.json index 48e4b0163bb..c09b3bd33c2 100644 --- a/examples/sdk-interactive-examples/examples/example-combochart/package.json +++ b/examples/sdk-interactive-examples/examples/example-combochart/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-combochart", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "Example demonstrates ComboChart secondaryMeasures definition. ", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-dashboard/.eslintrc.cjs b/examples/sdk-interactive-examples/examples/example-dashboard/.eslintrc.cjs index 6f763a177ec..8902a8111c0 100644 --- a/examples/sdk-interactive-examples/examples/example-dashboard/.eslintrc.cjs +++ b/examples/sdk-interactive-examples/examples/example-dashboard/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/examples/sdk-interactive-examples/examples/example-dashboard/package.json b/examples/sdk-interactive-examples/examples/example-dashboard/package.json index 5d267cbbbc0..137746260f3 100644 --- a/examples/sdk-interactive-examples/examples/example-dashboard/package.json +++ b/examples/sdk-interactive-examples/examples/example-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-dashboard", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "This example shows how to use the Dashboard component.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-datefilter/.eslintrc.cjs b/examples/sdk-interactive-examples/examples/example-datefilter/.eslintrc.cjs index 6f763a177ec..8902a8111c0 100644 --- a/examples/sdk-interactive-examples/examples/example-datefilter/.eslintrc.cjs +++ b/examples/sdk-interactive-examples/examples/example-datefilter/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/examples/sdk-interactive-examples/examples/example-datefilter/package.json b/examples/sdk-interactive-examples/examples/example-datefilter/package.json index fb10525f89d..4196733f212 100644 --- a/examples/sdk-interactive-examples/examples/example-datefilter/package.json +++ b/examples/sdk-interactive-examples/examples/example-datefilter/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-datefilter", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "Example demonstrates usage of Date Filter component.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-dependentfilters/.eslintrc.cjs b/examples/sdk-interactive-examples/examples/example-dependentfilters/.eslintrc.cjs index 6f763a177ec..8902a8111c0 100644 --- a/examples/sdk-interactive-examples/examples/example-dependentfilters/.eslintrc.cjs +++ b/examples/sdk-interactive-examples/examples/example-dependentfilters/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/examples/sdk-interactive-examples/examples/example-dependentfilters/package.json b/examples/sdk-interactive-examples/examples/example-dependentfilters/package.json index cea4780d716..302f4d8dffb 100644 --- a/examples/sdk-interactive-examples/examples/example-dependentfilters/package.json +++ b/examples/sdk-interactive-examples/examples/example-dependentfilters/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-dependentfilters", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "This example demonstrates how to use multiple attribute filters linked together to filter data in a visualization.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-execute/.eslintrc.cjs b/examples/sdk-interactive-examples/examples/example-execute/.eslintrc.cjs index 6f763a177ec..8902a8111c0 100644 --- a/examples/sdk-interactive-examples/examples/example-execute/.eslintrc.cjs +++ b/examples/sdk-interactive-examples/examples/example-execute/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/examples/sdk-interactive-examples/examples/example-execute/package.json b/examples/sdk-interactive-examples/examples/example-execute/package.json index 684dfdf85de..397e34e302f 100644 --- a/examples/sdk-interactive-examples/examples/example-execute/package.json +++ b/examples/sdk-interactive-examples/examples/example-execute/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-execute", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "This example demonstrates using Execute component and build custom visualization.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-granularity/.eslintrc.cjs b/examples/sdk-interactive-examples/examples/example-granularity/.eslintrc.cjs index 6f763a177ec..8902a8111c0 100644 --- a/examples/sdk-interactive-examples/examples/example-granularity/.eslintrc.cjs +++ b/examples/sdk-interactive-examples/examples/example-granularity/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/examples/sdk-interactive-examples/examples/example-granularity/package.json b/examples/sdk-interactive-examples/examples/example-granularity/package.json index cecac65eb39..6e76d4c61b8 100644 --- a/examples/sdk-interactive-examples/examples/example-granularity/package.json +++ b/examples/sdk-interactive-examples/examples/example-granularity/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-granularity", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "This example exmplains DateFilter granularity ", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-headline/.eslintrc.cjs b/examples/sdk-interactive-examples/examples/example-headline/.eslintrc.cjs index 6f763a177ec..8902a8111c0 100644 --- a/examples/sdk-interactive-examples/examples/example-headline/.eslintrc.cjs +++ b/examples/sdk-interactive-examples/examples/example-headline/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/examples/sdk-interactive-examples/examples/example-headline/package.json b/examples/sdk-interactive-examples/examples/example-headline/package.json index 98359d52a43..3196d809880 100644 --- a/examples/sdk-interactive-examples/examples/example-headline/package.json +++ b/examples/sdk-interactive-examples/examples/example-headline/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-headline", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "This example shows how to use the Headline component.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-pivottable/.eslintrc.cjs b/examples/sdk-interactive-examples/examples/example-pivottable/.eslintrc.cjs index 6f763a177ec..8902a8111c0 100644 --- a/examples/sdk-interactive-examples/examples/example-pivottable/.eslintrc.cjs +++ b/examples/sdk-interactive-examples/examples/example-pivottable/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/examples/sdk-interactive-examples/examples/example-pivottable/package.json b/examples/sdk-interactive-examples/examples/example-pivottable/package.json index 94984b3a281..9df7c891fed 100644 --- a/examples/sdk-interactive-examples/examples/example-pivottable/package.json +++ b/examples/sdk-interactive-examples/examples/example-pivottable/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-pivottable", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "Basic PivotTable manipulation.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-relativedatefilter/.eslintrc.cjs b/examples/sdk-interactive-examples/examples/example-relativedatefilter/.eslintrc.cjs index 6f763a177ec..8902a8111c0 100644 --- a/examples/sdk-interactive-examples/examples/example-relativedatefilter/.eslintrc.cjs +++ b/examples/sdk-interactive-examples/examples/example-relativedatefilter/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/examples/sdk-interactive-examples/examples/example-relativedatefilter/package.json b/examples/sdk-interactive-examples/examples/example-relativedatefilter/package.json index c915a44dafb..fe532571232 100644 --- a/examples/sdk-interactive-examples/examples/example-relativedatefilter/package.json +++ b/examples/sdk-interactive-examples/examples/example-relativedatefilter/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-relativedatefilter", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "Example demonstrates how to set relative DateFilter for visualization.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-repeater/.eslintrc.cjs b/examples/sdk-interactive-examples/examples/example-repeater/.eslintrc.cjs index 6f763a177ec..8902a8111c0 100644 --- a/examples/sdk-interactive-examples/examples/example-repeater/.eslintrc.cjs +++ b/examples/sdk-interactive-examples/examples/example-repeater/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm-react"], rules: { - "import/no-unassigned-import": "off", + "import/no-unassigned-import": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/examples/sdk-interactive-examples/examples/example-repeater/package.json b/examples/sdk-interactive-examples/examples/example-repeater/package.json index b2784eec597..23f68323104 100644 --- a/examples/sdk-interactive-examples/examples/example-repeater/package.json +++ b/examples/sdk-interactive-examples/examples/example-repeater/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-repeater", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "This example demonstrates how to use Repeater component.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/package.json b/examples/sdk-interactive-examples/package.json index 3556b4fc43c..cfa80f7001d 100644 --- a/examples/sdk-interactive-examples/package.json +++ b/examples/sdk-interactive-examples/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-examples", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "private": false, "description": "GoodData React interactive examples", "license": "LicenseRef-LICENSE", diff --git a/libs/api-client-tiger/package.json b/libs/api-client-tiger/package.json index ed7707da1c8..07421757b4e 100644 --- a/libs/api-client-tiger/package.json +++ b/libs/api-client-tiger/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/api-client-tiger", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "description": "API Client for GoodData Cloud and GoodData.CN", "repository": { "type": "git", diff --git a/libs/sdk-backend-base/package.json b/libs/sdk-backend-base/package.json index 2931e45f640..7f5d9340e3a 100644 --- a/libs/sdk-backend-base/package.json +++ b/libs/sdk-backend-base/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-backend-base", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "description": "GoodData.UI SDK - Base for backend implementations", "repository": { "type": "git", diff --git a/libs/sdk-backend-mockingbird/.eslintrc.cjs b/libs/sdk-backend-mockingbird/.eslintrc.cjs index 373f29dc928..fcac9012d77 100644 --- a/libs/sdk-backend-mockingbird/.eslintrc.cjs +++ b/libs/sdk-backend-mockingbird/.eslintrc.cjs @@ -1,4 +1,4 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); @@ -6,13 +6,10 @@ module.exports = { extends: ["@gooddata/eslint-config/esm"], overrides: [ tsOverride(__dirname, { - "@typescript-eslint/require-await": "off", - "@typescript-eslint/no-unnecessary-type-assertion": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-unsafe-argument": "off", - "@typescript-eslint/naming-convention": "off", + "@typescript-eslint/no-unsafe-member-access": "warn", + "@typescript-eslint/no-unsafe-assignment": "warn", + "@typescript-eslint/no-unsafe-return": "warn", + "@typescript-eslint/no-unsafe-argument": "warn", }), ], }; diff --git a/libs/sdk-backend-mockingbird/package.json b/libs/sdk-backend-mockingbird/package.json index 633fa3a3925..aa59a46102c 100644 --- a/libs/sdk-backend-mockingbird/package.json +++ b/libs/sdk-backend-mockingbird/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-backend-mockingbird", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "description": "Mock GoodData Backend SPI implementation", "repository": { "type": "git", diff --git a/libs/sdk-backend-mockingbird/src/geoService.ts b/libs/sdk-backend-mockingbird/src/geoService.ts index 546fce0d75c..344d28149de 100644 --- a/libs/sdk-backend-mockingbird/src/geoService.ts +++ b/libs/sdk-backend-mockingbird/src/geoService.ts @@ -1,4 +1,4 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation import { type IGeoService, type IGeoStyleSpecification } from "@gooddata/sdk-backend-spi"; @@ -13,6 +13,6 @@ export function createMockGeoService(style?: IGeoStyleSpecification): IGeoServic const resolvedStyle = style ?? DEFAULT_GEO_STYLE; return { - getDefaultStyle: async () => resolvedStyle, + getDefaultStyle: async () => Promise.resolve(resolvedStyle), }; } diff --git a/libs/sdk-backend-mockingbird/src/legacyRecordedBackend/legacyBackendTypes.ts b/libs/sdk-backend-mockingbird/src/legacyRecordedBackend/legacyBackendTypes.ts index a3444dce50f..0ff18b1fd4c 100644 --- a/libs/sdk-backend-mockingbird/src/legacyRecordedBackend/legacyBackendTypes.ts +++ b/libs/sdk-backend-mockingbird/src/legacyRecordedBackend/legacyBackendTypes.ts @@ -1,4 +1,5 @@ -// (C) 2019-2024 GoodData Corporation +// (C) 2019-2026 GoodData Corporation + import { isEmpty } from "lodash-es"; export interface IMeasureHeaderItem { @@ -76,7 +77,7 @@ export type IResultHeaderItem = | IResultMeasureHeaderItem | IResultTotalHeaderItem; -export interface Warning { +export interface IWarning { warningCode: string; message: string; parameters?: any[]; @@ -92,7 +93,7 @@ export interface IExecutionResult { offset: number[]; total: number[]; }; - warnings?: Warning[]; + warnings?: IWarning[]; } export interface IExecutionResponse { diff --git a/libs/sdk-backend-mockingbird/src/recordedBackend/attributes.ts b/libs/sdk-backend-mockingbird/src/recordedBackend/attributes.ts index 2e52f45feba..b783826fdec 100644 --- a/libs/sdk-backend-mockingbird/src/recordedBackend/attributes.ts +++ b/libs/sdk-backend-mockingbird/src/recordedBackend/attributes.ts @@ -1,4 +1,5 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation + import { compact } from "lodash-es"; import { newAttributeMetadataObject } from "@gooddata/sdk-backend-base"; @@ -52,7 +53,7 @@ export class RecordedAttributes implements IWorkspaceAttributesService { throw new UnexpectedResponseError(`No element recordings for df ${objRefToString(ref)}`, 404, {}); } - return recording.obj; + return Promise.resolve(recording.obj); }; public getAttribute = async (ref: ObjRef): Promise => { @@ -70,7 +71,7 @@ export class RecordedAttributes implements IWorkspaceAttributesService { throw new UnexpectedResponseError(`No attribute recording ${objRefToString(ref)}`, 404, {}); } - return this.sanitizeAttribute(recording.attribute); + return Promise.resolve(this.sanitizeAttribute(recording.attribute)); }; public getAttributeByDisplayForm = async (ref: ObjRef): Promise => { @@ -88,7 +89,7 @@ export class RecordedAttributes implements IWorkspaceAttributesService { throw new UnexpectedResponseError(`No attribute recording ${objRefToString(ref)}`, 404, {}); } - return this.sanitizeAttribute(recording.attribute); + return Promise.resolve(this.sanitizeAttribute(recording.attribute)); }; public async getCommonAttributes(attributeRefs: ObjRef[]): Promise { @@ -99,7 +100,7 @@ export class RecordedAttributes implements IWorkspaceAttributesService { throw new UnexpectedResponseError(`No common attributes response set for key ${key}`, 404, {}); } - return response; + return Promise.resolve(response); } public getCommonAttributesBatch(attributesRefsBatch: ObjRef[][]): Promise { diff --git a/libs/sdk-backend-mockingbird/src/recordedBackend/catalog.ts b/libs/sdk-backend-mockingbird/src/recordedBackend/catalog.ts index 2b387e5699f..553f1da9099 100644 --- a/libs/sdk-backend-mockingbird/src/recordedBackend/catalog.ts +++ b/libs/sdk-backend-mockingbird/src/recordedBackend/catalog.ts @@ -1,4 +1,4 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation import { type IWorkspaceCatalog, @@ -105,7 +105,9 @@ export class RecordedCatalogFactory implements IWorkspaceCatalogFactory { const typeFilteredItems = catalog.items.filter((item) => this.options.types.includes(item.type)); const catalogItems = typeFilteredItems.map(this.convertToCatalogItem.bind(this)); - return new RecordedCatalog(this.workspace, this.config, catalog.groups, catalogItems); + return Promise.resolve( + new RecordedCatalog(this.workspace, this.config, catalog.groups, catalogItems), + ); }; private convertToCatalogItem(catalogItem: CatalogItem) { @@ -264,7 +266,9 @@ class RecordedAvailableCatalogFactory implements IWorkspaceCatalogAvailableItems } public load = async (): Promise => { - return new RecordedAvailableCatalog(this.workspace, this.config, this.groups, this.items); + return Promise.resolve( + new RecordedAvailableCatalog(this.workspace, this.config, this.groups, this.items), + ); }; } diff --git a/libs/sdk-backend-mockingbird/src/recordedBackend/dashboards.ts b/libs/sdk-backend-mockingbird/src/recordedBackend/dashboards.ts index d776b4d2cb7..458734a4e99 100644 --- a/libs/sdk-backend-mockingbird/src/recordedBackend/dashboards.ts +++ b/libs/sdk-backend-mockingbird/src/recordedBackend/dashboards.ts @@ -1,4 +1,4 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation import { cloneDeep, isEmpty, isEqual } from "lodash-es"; import { v4 as uuidv4 } from "uuid"; @@ -208,7 +208,7 @@ export class RecordedDashboards implements IWorkspaceDashboardsService { _type: "visual" | "slides" | undefined, _tabId?: string, ): Promise => { - return null; + return Promise.resolve(null); }; public getDashboardReferencedObjects = ( @@ -240,7 +240,7 @@ export class RecordedDashboards implements IWorkspaceDashboardsService { if (!areObjRefsEqual(dashboard.ref, updatedDashboard.ref)) { throw new Error("Cannot update dashboard with different refs!"); } else if (isEqual(dashboard, updatedDashboard)) { - return dashboard; + return Promise.resolve(dashboard); } let savedDashboard: Partial = cloneDeep(updatedDashboard) as Partial; @@ -323,7 +323,7 @@ export class RecordedDashboards implements IWorkspaceDashboardsService { this.addOrUpdateLocalDashboard(savedDashboard as IDashboard); - return savedDashboard as IDashboard; + return Promise.resolve(savedDashboard as IDashboard); }; updateDashboardMeta(_: IDashboardObjectIdentity & Partial): Promise { diff --git a/libs/sdk-backend-mockingbird/src/recordedBackend/index.ts b/libs/sdk-backend-mockingbird/src/recordedBackend/index.ts index 5ab6113a5b8..fa72face13b 100644 --- a/libs/sdk-backend-mockingbird/src/recordedBackend/index.ts +++ b/libs/sdk-backend-mockingbird/src/recordedBackend/index.ts @@ -1,4 +1,4 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation import { DummyGenAIChatThread, @@ -208,9 +208,9 @@ function recordedWorkspace( return { workspace, async getDescriptor(): Promise { - return recordedDescriptor(this.workspace, implConfig); + return Promise.resolve(recordedDescriptor(this.workspace, implConfig)); }, - async updateDescriptor(): Promise { + updateDescriptor(): Promise { throw new NotSupported("not supported"); }, getParentWorkspace(): Promise { @@ -240,19 +240,19 @@ function recordedWorkspace( settings(): IWorkspaceSettingsService { return { async getSettings(): Promise { - return { + return Promise.resolve({ workspace, ...(implConfig.globalSettings ?? {}), - }; + }); }, async getSettingsForCurrentUser(): Promise { - return { + return Promise.resolve({ userId: USER_ID, workspace, locale, separators, ...(implConfig.globalSettings ?? {}), - }; + }); }, async setAlertDefault(): Promise { return Promise.resolve(); @@ -319,10 +319,10 @@ function recordedWorkspace( styling(): IWorkspaceStylingService { return { async getColorPalette(): Promise { - return implConfig.globalPalette ?? []; + return Promise.resolve(implConfig.globalPalette ?? []); }, async getTheme(): Promise { - return implConfig.theme ?? {}; + return Promise.resolve(implConfig.theme ?? {}); }, async getActiveTheme(): Promise { return Promise.resolve(undefined); @@ -657,7 +657,7 @@ function recordedOrganizations(implConfig: RecordedBackendConfig): IOrganization function recordedUserService(implConfig: RecordedBackendConfig): IUserService { return { async getUser(): Promise { - return ( + return Promise.resolve( implConfig.userManagement?.user ?? { login: USER_ID, ref: idRef(USER_ID), @@ -665,11 +665,11 @@ function recordedUserService(implConfig: RecordedBackendConfig): IUserService { fullName: "", firstName: "", lastName: "", - } + }, ); }, async getUserWithDetails(): Promise { - return ( + return Promise.resolve( implConfig.userManagement?.user ?? { login: USER_ID, ref: idRef(USER_ID), @@ -677,17 +677,18 @@ function recordedUserService(implConfig: RecordedBackendConfig): IUserService { fullName: "", firstName: "", lastName: "", - } + }, ); }, settings(): IUserSettingsService { return { - getSettings: async () => ({ - userId: USER_ID, - locale, - separators, - ...(implConfig.globalSettings ?? {}), - }), + getSettings: async () => + Promise.resolve({ + userId: USER_ID, + locale, + separators, + ...(implConfig.globalSettings ?? {}), + }), setLocale: () => Promise.resolve(), setMetadataLocale: () => Promise.resolve(), setFormatLocale: () => Promise.resolve(), @@ -700,32 +701,33 @@ function recordedUserService(implConfig: RecordedBackendConfig): IUserService { // return true for all function recordedPermissionsFactory(): IWorkspacePermissionsService { return { - getPermissionsForCurrentUser: async (): Promise => ({ - canAccessWorkbench: true, - canCreateAnalyticalDashboard: true, - canCreateReport: true, - canCreateVisualization: true, - canExecuteRaw: true, - canExportReport: true, - canExportTabular: true, - canExportPdf: true, - canInitData: true, - canManageAnalyticalDashboard: true, - canManageMetric: true, - canManageProject: true, - canManageReport: true, - canUploadNonProductionCSV: true, - canCreateScheduledMail: true, - canListUsersInProject: true, - canManageDomain: true, - canInviteUserToProject: true, - canRefreshData: true, - canManageACL: true, - canManageScheduledMail: true, - canCreateFilterView: true, - canCreateAutomation: true, - canUseAiAssistant: true, - }), + getPermissionsForCurrentUser: async (): Promise => + Promise.resolve({ + canAccessWorkbench: true, + canCreateAnalyticalDashboard: true, + canCreateReport: true, + canCreateVisualization: true, + canExecuteRaw: true, + canExportReport: true, + canExportTabular: true, + canExportPdf: true, + canInitData: true, + canManageAnalyticalDashboard: true, + canManageMetric: true, + canManageProject: true, + canManageReport: true, + canUploadNonProductionCSV: true, + canCreateScheduledMail: true, + canListUsersInProject: true, + canManageDomain: true, + canInviteUserToProject: true, + canRefreshData: true, + canManageACL: true, + canManageScheduledMail: true, + canCreateFilterView: true, + canCreateAutomation: true, + canUseAiAssistant: true, + }), }; } diff --git a/libs/sdk-backend-mockingbird/src/recordedBackend/insights.ts b/libs/sdk-backend-mockingbird/src/recordedBackend/insights.ts index 3c4141282ec..76ca7f17153 100644 --- a/libs/sdk-backend-mockingbird/src/recordedBackend/insights.ts +++ b/libs/sdk-backend-mockingbird/src/recordedBackend/insights.ts @@ -1,4 +1,4 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation import { cloneDeep, isEmpty } from "lodash-es"; @@ -72,7 +72,7 @@ export class RecordedInsights implements IWorkspaceInsightsService { this.insights[recordingId] = { obj: newInsight }; - return newInsight; + return Promise.resolve(newInsight); } public async getInsight(ref: ObjRef): Promise { @@ -92,7 +92,7 @@ export class RecordedInsights implements IWorkspaceInsightsService { throw new UnexpectedResponseError(`No insight with ID: ${id}`, 404, {}); } - return this.createInsightWithRef(recording.obj); + return Promise.resolve(this.createInsightWithRef(recording.obj)); } public async getInsights(query?: IInsightsQueryOptions): Promise { @@ -108,7 +108,7 @@ export class RecordedInsights implements IWorkspaceInsightsService { insights.sort(comparator(orderBy)); } - return new InMemoryPaging(insights, limit, offset); + return Promise.resolve(new InMemoryPaging(insights, limit, offset)); } public getInsightsQuery(): IInsightsQuery { @@ -126,7 +126,7 @@ export class RecordedInsights implements IWorkspaceInsightsService { existingRecording.obj = cloneDeep(insight); - return existingRecording.obj; + return Promise.resolve(existingRecording.obj); } public updateInsightMeta(_: Partial & IMetadataObjectIdentity): Promise { @@ -142,27 +142,29 @@ export class RecordedInsights implements IWorkspaceInsightsService { } delete this.insights[recordingId]; + + return Promise.resolve(); } public async getVisualizationClass(ref: ObjRef): Promise { return isUriRef(ref) - ? this.getVisualizationClassByUri(ref.uri) - : this.getVisualizationClassById(ref.identifier); + ? Promise.resolve(this.getVisualizationClassByUri(ref.uri)) + : Promise.resolve(this.getVisualizationClassById(ref.identifier)); } public async getVisualizationClasses(): Promise { - return this.visClasses; + return Promise.resolve(this.visClasses); } public getInsightReferencedObjects = async ( _insight: IInsight, _types?: SupportedInsightReferenceTypes[], ): Promise => { - return {}; + return Promise.resolve({}); }; public getInsightReferencingObjects = async (_ref: ObjRef): Promise => { - return {}; + return Promise.resolve({}); }; public getInsightWithAddedFilters = async ( @@ -176,7 +178,7 @@ export class RecordedInsights implements IWorkspaceInsightsService { // we assume that all the filters already use idRefs exclusively const mergedFilters = mergeFilters(insightFilters(insight), filters); - return insightSetFilters(insight, mergedFilters); + return Promise.resolve(insightSetFilters(insight, mergedFilters)); }; async getInsightWithCatalogItems(ref: ObjRef): Promise<{ @@ -205,7 +207,7 @@ export class RecordedInsights implements IWorkspaceInsightsService { return this.insightRefType === "uri" ? uriRef(uri) : idRef(id, "insight"); } - private async getVisualizationClassByUri(uri: string): Promise { + private getVisualizationClassByUri(uri: string): IVisualizationClass { const result = this.visClasses.find((visClass) => visClassUri(visClass) === uri); if (!result) { @@ -215,7 +217,7 @@ export class RecordedInsights implements IWorkspaceInsightsService { return result; } - private async getVisualizationClassById(id: string): Promise { + private getVisualizationClassById(id: string): IVisualizationClass { const result = this.visClasses.find((visClass) => visClassId(visClass) === id); if (!result) { diff --git a/libs/sdk-backend-mockingbird/src/recordedBackend/tests/elementsUtils.test.ts b/libs/sdk-backend-mockingbird/src/recordedBackend/tests/elementsUtils.test.ts index db51073379c..7104534a5e3 100644 --- a/libs/sdk-backend-mockingbird/src/recordedBackend/tests/elementsUtils.test.ts +++ b/libs/sdk-backend-mockingbird/src/recordedBackend/tests/elementsUtils.test.ts @@ -1,4 +1,5 @@ -// (C) 2022-2025 GoodData Corporation +// (C) 2022-2026 GoodData Corporation + import { describe, expect, it } from "vitest"; import { ReferenceMd, ReferenceRecordings } from "@gooddata/reference-workspace"; @@ -163,7 +164,7 @@ describe("elementsUtils", () => { }); it("should limit the elements if a string filter is provided", () => { - const actual = resolveStringFilter(elements[0].title!)(elements); + const actual = resolveStringFilter(elements[0].title)(elements); expect(actual).toEqual([elements[0]]); }); }); diff --git a/libs/sdk-backend-spi/package.json b/libs/sdk-backend-spi/package.json index 24cdcc74759..7a1ede849d0 100644 --- a/libs/sdk-backend-spi/package.json +++ b/libs/sdk-backend-spi/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-backend-spi", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "description": "GoodData Backend SPI abstraction interfaces", "repository": { "type": "git", diff --git a/libs/sdk-backend-tiger/.eslintrc.cjs b/libs/sdk-backend-tiger/.eslintrc.cjs index 767f2ecb22a..2ceaa0c9130 100644 --- a/libs/sdk-backend-tiger/.eslintrc.cjs +++ b/libs/sdk-backend-tiger/.eslintrc.cjs @@ -1,4 +1,4 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); @@ -6,22 +6,15 @@ module.exports = { extends: ["@gooddata/eslint-config/esm"], overrides: [ tsOverride(__dirname, { - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-unsafe-argument": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/require-await": "off", - "@typescript-eslint/prefer-promise-reject-errors": "off", - "@typescript-eslint/restrict-template-expressions": "off", - "@typescript-eslint/no-unnecessary-type-assertion": "off", - "@typescript-eslint/naming-convention": "off", - "@typescript-eslint/no-duplicate-type-constituents": "off", - "@typescript-eslint/no-base-to-string": "off", - "@typescript-eslint/unbound-method": "off", - "@typescript-eslint/no-unsafe-enum-comparison": "off", - "@typescript-eslint/no-floating-promises": "off", - "@typescript-eslint/restrict-plus-operands": "off", + "@typescript-eslint/no-unsafe-member-access": "warn", + "@typescript-eslint/no-unsafe-return": "warn", + "@typescript-eslint/no-unsafe-argument": "warn", + "@typescript-eslint/no-unsafe-call": "warn", + "@typescript-eslint/no-unsafe-assignment": "warn", + "@typescript-eslint/prefer-promise-reject-errors": "warn", + "@typescript-eslint/restrict-template-expressions": "warn", + "@typescript-eslint/no-base-to-string": "warn", + "@typescript-eslint/unbound-method": "warn", }), ], }; diff --git a/libs/sdk-backend-tiger/api/sdk-backend-tiger.api.md b/libs/sdk-backend-tiger/api/sdk-backend-tiger.api.md index 5a0ae28ea29..c0277865e04 100644 --- a/libs/sdk-backend-tiger/api/sdk-backend-tiger.api.md +++ b/libs/sdk-backend-tiger/api/sdk-backend-tiger.api.md @@ -106,16 +106,6 @@ export type DependentEntitiesGraphRequest = DependentEntitiesRequest; // @internal (undocumented) export type DependentEntitiesGraphResponse = DependentEntitiesResponse; -// @internal (undocumented) -export interface Entitlement { - // (undocumented) - expiry?: string; - // (undocumented) - id: string; - // (undocumented) - value?: string; -} - export { GdStorageFile } export { GenerateLdmRequest } @@ -124,7 +114,7 @@ export { GenerateLdmRequest } export type GenerateLogicalModelRequest = GenerateLdmRequest; // @internal -export function getIdOrigin(id: string): OriginInfoWithId; +export function getIdOrigin(id: string): IOriginInfoWithId; // @internal (undocumented) export interface IApiToken { @@ -309,6 +299,16 @@ export interface IDataSourceUpsertRequest { username?: string; } +// @internal (undocumented) +export interface IEntitlement { + // (undocumented) + expiry?: string; + // (undocumented) + id: string; + // (undocumented) + value?: string; +} + // @internal (undocumented) export interface IInvitationUserResponse { // (undocumented) @@ -326,12 +326,38 @@ export type INotificationChannel = Omit; export { Invitation } +// @internal (undocumented) +export interface IOriginInfoWithId { + // (undocumented) + id: string; + // (undocumented) + originId: string; + // (undocumented) + originType: JsonApiDatasetOutMetaOriginOriginTypeEnum; +} + // @public export interface IRedirectToTigerAuthenticationParams { // (undocumented) externalProviderId: string; } +// @internal (undocumented) +export interface IScanRequest { + // (undocumented) + scanTables: boolean; + // (undocumented) + scanViews: boolean; + // (undocumented) + schemata: string[]; + // (undocumented) + separator: string; + // (undocumented) + tablePrefix: string; + // (undocumented) + viewPrefix: string; +} + // @alpha (undocumented) export const isTigerCompatibleType: (obj: unknown) => obj is TigerObjectType; @@ -347,16 +373,6 @@ export const objectTypeToTigerIdType: { [objectType in TigerCompatibleObjectType // @internal (undocumented) export type OrganizationPermission = JsonApiOrganizationOutMetaPermissionsEnum; -// @internal (undocumented) -export interface OriginInfoWithId { - // (undocumented) - id: string; - // (undocumented) - originId: string; - // (undocumented) - originType: JsonApiDatasetOutMetaOriginOriginTypeEnum; -} - // @internal (undocumented) export type PutWorkspaceLayoutRequest = LayoutApiPutWorkspaceLayoutRequest; @@ -368,22 +384,6 @@ export function redirectToTigerAuthentication(context: IAuthenticationContext, e // @public export type RedirectToTigerAuthenticationHandler = (context: IAuthenticationContext, error: NotAuthenticated) => void; -// @internal (undocumented) -export interface ScanRequest { - // (undocumented) - scanTables: boolean; - // (undocumented) - scanViews: boolean; - // (undocumented) - schemata: string[]; - // (undocumented) - separator: string; - // (undocumented) - tablePrefix: string; - // (undocumented) - viewPrefix: string; -} - // @internal (undocumented) export type ScanResult = ScanResultPdm; @@ -453,7 +453,7 @@ export type TigerSpecificFunctions = { deleteApiToken?: (userId: string, tokenId: string) => Promise; someDataSourcesExists?: (filter?: string) => Promise; generateLogicalModel?: (dataSourceId: string, generateLogicalModelRequest: GenerateLogicalModelRequest) => Promise; - scanDataSource?: (dataSourceId: string, scanRequest: ScanRequest) => Promise; + scanDataSource?: (dataSourceId: string, scanRequest: IScanRequest) => Promise; createDemoWorkspace?: (sampleWorkspace: WorkspaceDefinition) => Promise; createDemoDataSource?: (sampleDataSource: DataSourceDefinition) => Promise; createWorkspace?: (id: string, name: string, parentId?: string) => Promise; @@ -462,7 +462,7 @@ export type TigerSpecificFunctions = { canDeleteWorkspace?: (id: string) => Promise; getWorkspaceLogicalModel?: (id: string, includeParents?: boolean) => Promise; getWorkspaceEntitiesDatasets?: (id: string) => Promise; - getEntitlements?: () => Promise>; + getEntitlements?: () => Promise>; putWorkspaceLayout?: (requestParameters: PutWorkspaceLayoutRequest) => Promise; getWorkspaceAnalyticsModelAac?: (workspaceId: string, exclude?: Array<"ACTIVITY_INFO">) => Promise; setWorkspaceAnalyticsModelAac?: (workspaceId: string, analyticsModel: AacAnalyticsModel) => Promise; diff --git a/libs/sdk-backend-tiger/package.json b/libs/sdk-backend-tiger/package.json index cb9ecdc2fa1..8d1f0672f17 100644 --- a/libs/sdk-backend-tiger/package.json +++ b/libs/sdk-backend-tiger/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-backend-tiger", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "description": "GoodData Backend SPI implementation for GoodData Cloud and GoodData.CN", "repository": { "type": "git", diff --git a/libs/sdk-backend-tiger/src/backend/features/feature.ts b/libs/sdk-backend-tiger/src/backend/features/feature.ts index bc54dbd86ed..7a243fab5cb 100644 --- a/libs/sdk-backend-tiger/src/backend/features/feature.ts +++ b/libs/sdk-backend-tiger/src/backend/features/feature.ts @@ -877,6 +877,13 @@ export function mapFeatures(features: FeaturesMap): Partial "BOOLEAN", FeatureFlagsValues.enableImplicitDrillToUrl, ), + ...loadFeature( + features, + TigerFeaturesNames.EnableDrillMenuPositioningAtCursor, + "enableDrillMenuPositioningAtCursor", + "BOOLEAN", + FeatureFlagsValues.enableDrillMenuPositioningAtCursor, + ), }; } diff --git a/libs/sdk-backend-tiger/src/backend/features/hub.ts b/libs/sdk-backend-tiger/src/backend/features/hub.ts index ce44b60023b..7e9890d1424 100644 --- a/libs/sdk-backend-tiger/src/backend/features/hub.ts +++ b/libs/sdk-backend-tiger/src/backend/features/hub.ts @@ -1,4 +1,4 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import axios, { type AxiosResponse } from "axios"; @@ -28,7 +28,7 @@ export async function getFeatureHubFeatures( const featuresMap = data.reduce((prev, item) => ({ ...prev, [item.key]: item }), {} as FeaturesMap); return mapFeatures(featuresMap); } catch (err) { - console.error("Loading features from FeatureHub was not successful. Err: " + err); + console.error("Loading features from FeatureHub was not successful. Err:", err); } return DefaultFeatureFlags; @@ -50,7 +50,7 @@ async function loadHubFeatures( } const promise = getFeatureHubData(host, key, context, state[key]); - promise.then(({ data, headers, status }) => { + void promise.then(({ data, headers, status }) => { if (status === 304) { loadFeatures(state[key].data, resolve, callFailed); return; diff --git a/libs/sdk-backend-tiger/src/backend/features/index.ts b/libs/sdk-backend-tiger/src/backend/features/index.ts index 03ec68da0f0..0a6ffbbd053 100644 --- a/libs/sdk-backend-tiger/src/backend/features/index.ts +++ b/libs/sdk-backend-tiger/src/backend/features/index.ts @@ -70,7 +70,7 @@ async function loadFeatures( } if (featuresAreStatic(features)) { - return await getStaticFeatures(features.static); + return getStaticFeatures(features.static); } return Promise.resolve({}); } diff --git a/libs/sdk-backend-tiger/src/backend/features/static.ts b/libs/sdk-backend-tiger/src/backend/features/static.ts index 255acfb03e2..a8643804555 100644 --- a/libs/sdk-backend-tiger/src/backend/features/static.ts +++ b/libs/sdk-backend-tiger/src/backend/features/static.ts @@ -1,13 +1,11 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import { type IStaticFeatures } from "@gooddata/api-client-tiger"; import { type FeatureDef, type FeaturesMap, mapFeatures } from "./feature.js"; import { type ITigerFeatureFlags } from "../uiFeatures.js"; -export async function getStaticFeatures({ - items, -}: IStaticFeatures["static"]): Promise> { +export function getStaticFeatures({ items }: IStaticFeatures["static"]): Partial { return mapFeatures(remapStaticFeatures(items)); } diff --git a/libs/sdk-backend-tiger/src/backend/features/test/static.test.ts b/libs/sdk-backend-tiger/src/backend/features/test/static.test.ts index 205cde9b65b..dbb619807f4 100644 --- a/libs/sdk-backend-tiger/src/backend/features/test/static.test.ts +++ b/libs/sdk-backend-tiger/src/backend/features/test/static.test.ts @@ -1,4 +1,4 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import { describe, expect, it } from "vitest"; @@ -21,13 +21,13 @@ describe("static features", () => { }; } - it("empty definition", async () => { - const results = await getStaticFeatures(createFeatures()); + it("empty definition", () => { + const results = getStaticFeatures(createFeatures()); expect(results).toEqual({}); }); - it("full definition", async () => { - const results = await getStaticFeatures( + it("full definition", () => { + const results = getStaticFeatures( createFeatures({ [TigerFeaturesNames.DashboardEditModeDevRollout]: "ENABLED", [TigerFeaturesNames.EnableMetricSqlAndDataExplain]: "ENABLED", @@ -43,8 +43,8 @@ describe("static features", () => { }); }); - it("full definition with earlyAccess set - in static features has no sense", async () => { - const results = await getStaticFeatures( + it("full definition with earlyAccess set - in static features has no sense", () => { + const results = getStaticFeatures( createFeatures( { [TigerFeaturesNames.DashboardEditModeDevRollout]: "ENABLED", diff --git a/libs/sdk-backend-tiger/src/backend/index.ts b/libs/sdk-backend-tiger/src/backend/index.ts index 2a8a7da0f7e..53784a26f56 100644 --- a/libs/sdk-backend-tiger/src/backend/index.ts +++ b/libs/sdk-backend-tiger/src/backend/index.ts @@ -1,4 +1,4 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation import { type AxiosInstance, type AxiosResponse } from "axios"; import { inRange, isEmpty, isError, omit } from "lodash-es"; @@ -319,7 +319,7 @@ export class TigerBackend implements IAnalyticalBackend { ): Promise => { try { // the return await is crucial here so that we also catch the async errors - return await call(this.client, await this.getAsyncCallContext()); + return await call(this.client, this.getAsyncCallContext()); } catch (err) { invariant(isError(err)); // if this bombs, the code in the try block threw something strange @@ -334,7 +334,7 @@ export class TigerBackend implements IAnalyticalBackend { try { await this.triggerAuthentication(); // the return await is crucial here so that we also catch the async errors - return await call(this.client, await this.getAsyncCallContext()); + return await call(this.client, this.getAsyncCallContext()); } catch (err2) { invariant(isError(err2)); // if this bombs, the code in the try block threw something strange throw this.handleAnalyticalBackendError(errorConverter(err2)); @@ -363,7 +363,7 @@ export class TigerBackend implements IAnalyticalBackend { return { client: this.client, backend: this }; }; - private getAsyncCallContext = async (): Promise => { + private getAsyncCallContext = (): IAuthenticatedAsyncCallContext => { const getPrincipal = async (): Promise => { if (!this.authProvider) { throw new NotAuthenticated("Cannot obtain principal without an authProvider."); diff --git a/libs/sdk-backend-tiger/src/backend/organization/styling.ts b/libs/sdk-backend-tiger/src/backend/organization/styling.ts index 55fd1bba391..a000df1183c 100644 --- a/libs/sdk-backend-tiger/src/backend/organization/styling.ts +++ b/libs/sdk-backend-tiger/src/backend/organization/styling.ts @@ -72,7 +72,7 @@ export class OrganizationStylingService implements IOrganizationStylingService { public getActiveTheme = () => this.getActiveSetting("activeTheme"); public async setActiveTheme(themeRef: ObjRef): Promise { - const themeId = await objRefToIdentifier(themeRef, this.authCall); + const themeId = objRefToIdentifier(themeRef, this.authCall); await this.settingsService.setTheme(themeId); } @@ -101,7 +101,7 @@ export class OrganizationStylingService implements IOrganizationStylingService { if (!theme.ref) { return this.createTheme(theme); } - const id = await objRefToIdentifier(theme.ref, this.authCall); + const id = objRefToIdentifier(theme.ref, this.authCall); return await this.authCall((client) => EntitiesApi_UpdateEntityThemes( client.axios, @@ -124,7 +124,7 @@ export class OrganizationStylingService implements IOrganizationStylingService { } public async deleteTheme(themeRef: ObjRef): Promise { - const id = await objRefToIdentifier(themeRef, this.authCall); + const id = objRefToIdentifier(themeRef, this.authCall); await this.authCall((client) => EntitiesApi_DeleteEntityThemes(client.axios, client.basePath, { id, @@ -151,7 +151,7 @@ export class OrganizationStylingService implements IOrganizationStylingService { public getActiveColorPalette = () => this.getActiveSetting("activeColorPalette"); public async setActiveColorPalette(colorPaletteRef: ObjRef): Promise { - const colorPaletteId = await objRefToIdentifier(colorPaletteRef, this.authCall); + const colorPaletteId = objRefToIdentifier(colorPaletteRef, this.authCall); await this.settingsService.setColorPalette(colorPaletteId); } @@ -188,7 +188,7 @@ export class OrganizationStylingService implements IOrganizationStylingService { return this.createColorPalette(colorPalette); } if (isValidColorPalette(colorPalette.colorPalette)) { - const id = await objRefToIdentifier(colorPalette.ref, this.authCall); + const id = objRefToIdentifier(colorPalette.ref, this.authCall); return await this.authCall((client) => EntitiesApi_UpdateEntityColorPalettes( client.axios, @@ -209,7 +209,7 @@ export class OrganizationStylingService implements IOrganizationStylingService { } public async deleteColorPalette(colorPaletteRef: ObjRef): Promise { - const id = await objRefToIdentifier(colorPaletteRef, this.authCall); + const id = objRefToIdentifier(colorPaletteRef, this.authCall); await this.authCall((client) => EntitiesApi_DeleteEntityColorPalettes(client.axios, client.basePath, { id }), ); diff --git a/libs/sdk-backend-tiger/src/backend/organization/users.ts b/libs/sdk-backend-tiger/src/backend/organization/users.ts index 45f35ba6abf..0f7096e7643 100644 --- a/libs/sdk-backend-tiger/src/backend/organization/users.ts +++ b/libs/sdk-backend-tiger/src/backend/organization/users.ts @@ -119,7 +119,7 @@ export class OrganizationUsersService implements IOrganizationUserService { jsonApiUserGroupInDocument: { data: { type: "userGroup", - id: id!, + id: id, attributes: { name, }, @@ -133,11 +133,11 @@ export class OrganizationUsersService implements IOrganizationUserService { return this.authCall(async (client) => { const { id, name } = group; await EntitiesApi_PatchEntityUserGroups(client.axios, client.basePath, { - id: id!, + id: id, jsonApiUserGroupPatchDocument: { data: { type: "userGroup", - id: id!, + id: id, attributes: { name, }, diff --git a/libs/sdk-backend-tiger/src/backend/settings/settings.ts b/libs/sdk-backend-tiger/src/backend/settings/settings.ts index 210b29a6273..0e222dba8f6 100644 --- a/libs/sdk-backend-tiger/src/backend/settings/settings.ts +++ b/libs/sdk-backend-tiger/src/backend/settings/settings.ts @@ -1,4 +1,4 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import { v4 as uuidv4 } from "uuid"; @@ -11,7 +11,7 @@ import { convertApiError } from "../../utils/errorHandling.js"; export class TigerSettingsService { constructor() {} - public async getSettings(): Promise { + public getSettings(): Promise { throw new UnexpectedError("This method needs to be implemented."); } @@ -64,19 +64,19 @@ export class TigerSettingsService { } } - protected async getSettingByType(_type: TigerSettingsType): Promise { + protected getSettingByType(_type: TigerSettingsType): any { throw new UnexpectedError("This method needs to be implemented."); } - protected async deleteSettingByType(_type: TigerSettingsType): Promise { + protected deleteSettingByType(_type: TigerSettingsType): any { throw new UnexpectedError("This method needs to be implemented."); } - protected async updateSetting(_type: TigerSettingsType, _id: string, _content: any): Promise { + protected updateSetting(_type: TigerSettingsType, _id: string, _content: any): any { throw new UnexpectedError("This method needs to be implemented."); } - protected async createSetting(_type: TigerSettingsType, _id: string, _content: any): Promise { + protected createSetting(_type: TigerSettingsType, _id: string, _content: any): any { throw new UnexpectedError("This method needs to be implemented."); } } diff --git a/libs/sdk-backend-tiger/src/backend/tigerSpecificFunctions.ts b/libs/sdk-backend-tiger/src/backend/tigerSpecificFunctions.ts index 04054cfc0e2..7feccdfb459 100644 --- a/libs/sdk-backend-tiger/src/backend/tigerSpecificFunctions.ts +++ b/libs/sdk-backend-tiger/src/backend/tigerSpecificFunctions.ts @@ -156,7 +156,7 @@ export interface IApiTokenExtended extends IApiToken { /** * @internal */ -export interface ScanRequest { +export interface IScanRequest { scanTables: boolean; scanViews: boolean; separator: string; @@ -173,7 +173,7 @@ export type ScanResult = ScanResultPdm; /** * @internal */ -export interface Entitlement { +export interface IEntitlement { id: string; value?: string; expiry?: string; @@ -444,7 +444,7 @@ export type TigerSpecificFunctions = { dataSourceId: string, generateLogicalModelRequest: GenerateLogicalModelRequest, ) => Promise; - scanDataSource?: (dataSourceId: string, scanRequest: ScanRequest) => Promise; + scanDataSource?: (dataSourceId: string, scanRequest: IScanRequest) => Promise; createDemoWorkspace?: (sampleWorkspace: WorkspaceDefinition) => Promise; createDemoDataSource?: (sampleDataSource: DataSourceDefinition) => Promise; createWorkspace?: (id: string, name: string, parentId?: string) => Promise; @@ -456,7 +456,7 @@ export type TigerSpecificFunctions = { canDeleteWorkspace?: (id: string) => Promise; getWorkspaceLogicalModel?: (id: string, includeParents?: boolean) => Promise; getWorkspaceEntitiesDatasets?: (id: string) => Promise; - getEntitlements?: () => Promise>; + getEntitlements?: () => Promise>; putWorkspaceLayout?: (requestParameters: PutWorkspaceLayoutRequest) => Promise; getWorkspaceAnalyticsModelAac?: ( workspaceId: string, @@ -924,7 +924,7 @@ export const buildTigerSpecificFunctions = ( throw convertApiError(error); } }, - scanDataSource: async (dataSourceId: string, scanRequest: ScanRequest) => { + scanDataSource: async (dataSourceId: string, scanRequest: IScanRequest) => { try { return await authApiCall(async (sdk) => { return await ScanModelApi_ScanDataSource(sdk.axios, sdk.basePath, { @@ -1703,7 +1703,7 @@ export const buildTigerSpecificFunctions = ( dataSourceId, scanSqlRequest: { sql }, }).then((response) => { - return response.data as ScanSqlResult; + return response.data; }); }); } catch (error: any) { @@ -1721,7 +1721,7 @@ export const buildTigerSpecificFunctions = ( workspaceId, hierarchyObjectIdentification, }).then((response) => { - return response.data as Array; + return response.data; }); }); } catch (error: any) { diff --git a/libs/sdk-backend-tiger/src/backend/uiFeatures.ts b/libs/sdk-backend-tiger/src/backend/uiFeatures.ts index cef45f30082..23f23430ea9 100644 --- a/libs/sdk-backend-tiger/src/backend/uiFeatures.ts +++ b/libs/sdk-backend-tiger/src/backend/uiFeatures.ts @@ -133,6 +133,7 @@ export enum TigerFeaturesNames { EnableFiscalCalendars = "enableFiscalCalendars", EnablePivotTablePagination = "enablePivotTablePagination", EnableImplicitDrillToUrl = "enableImplicitDrillToUrl", + EnableDrillMenuPositioningAtCursor = "enableDrillMenuPositioningAtCursor", } export type ITigerFeatureFlags = { @@ -259,6 +260,7 @@ export type ITigerFeatureFlags = { enableFiscalCalendars: (typeof FeatureFlagsValues)["enableFiscalCalendars"][number]; enablePivotTablePagination: (typeof FeatureFlagsValues)["enablePivotTablePagination"][number]; enableImplicitDrillToUrl: (typeof FeatureFlagsValues)["enableImplicitDrillToUrl"][number]; + enableDrillMenuPositioningAtCursor: (typeof FeatureFlagsValues)["enableDrillMenuPositioningAtCursor"][number]; }; export const DefaultFeatureFlags: ITigerFeatureFlags = { @@ -383,8 +385,9 @@ export const DefaultFeatureFlags: ITigerFeatureFlags = { enableDashboardSectionHeadersDateDataSet: false, enableAnomalyDetectionAlert: false, enableFiscalCalendars: false, - enablePivotTablePagination: false, + enablePivotTablePagination: true, enableImplicitDrillToUrl: false, + enableDrillMenuPositioningAtCursor: false, }; export const FeatureFlagsValues = { @@ -512,4 +515,5 @@ export const FeatureFlagsValues = { enableFiscalCalendars: [true, false] as const, enablePivotTablePagination: [true, false] as const, enableImplicitDrillToUrl: [true, false] as const, + enableDrillMenuPositioningAtCursor: [true, false] as const, }; diff --git a/libs/sdk-backend-tiger/src/backend/workspace/accessControl/index.ts b/libs/sdk-backend-tiger/src/backend/workspace/accessControl/index.ts index c9cf6d892cf..b81dac77534 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/accessControl/index.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/accessControl/index.ts @@ -35,7 +35,7 @@ export class TigerWorkspaceAccessControlService implements IWorkspaceAccessContr ) {} public async getAccessList(sharedObject: ObjRef): Promise { - const objectId = await objRefToIdentifier(sharedObject, this.authCall); + const objectId = objRefToIdentifier(sharedObject, this.authCall); const permissions = await this.authCall((client) => { return ActionsApi_DashboardPermissions(client.axios, client.basePath, { workspaceId: this.workspace, @@ -64,28 +64,27 @@ export class TigerWorkspaceAccessControlService implements IWorkspaceAccessContr } public async changeAccess(sharedObject: ObjRef, grantees: IGranularAccessGrantee[]): Promise { - const objectId = await objRefToIdentifier(sharedObject, this.authCall); + const objectId = objRefToIdentifier(sharedObject, this.authCall); //ivec investigate - const manageDashboardPermissionsRequestInner: ManageDashboardPermissionsRequestInner[] = - await Promise.all( - grantees.map(async (grantee) => { - if (grantee.type === "allWorkspaceUsers") { - return { - assigneeRule: { - type: grantee.type, - }, - permissions: grantee.permissions, - }; - } + const manageDashboardPermissionsRequestInner: ManageDashboardPermissionsRequestInner[] = grantees.map( + (grantee) => { + if (grantee.type === "allWorkspaceUsers") { return { - assigneeIdentifier: { - id: await objRefToIdentifier(grantee.granteeRef, this.authCall), - type: isGranularUserAccessGrantee(grantee) ? "user" : "userGroup", + assigneeRule: { + type: grantee.type, }, permissions: grantee.permissions, }; - }), - ); + } + return { + assigneeIdentifier: { + id: objRefToIdentifier(grantee.granteeRef, this.authCall), + type: isGranularUserAccessGrantee(grantee) ? "user" : "userGroup", + }, + permissions: grantee.permissions, + }; + }, + ); await this.authCall((client) => { return ActionsApi_ManageDashboardPermissions(client.axios, client.basePath, { @@ -100,7 +99,7 @@ export class TigerWorkspaceAccessControlService implements IWorkspaceAccessContr sharedObject: ObjRef, search?: string, ): Promise { - const objectId = await objRefToIdentifier(sharedObject, this.authCall); + const objectId = objRefToIdentifier(sharedObject, this.authCall); const availableGrantees = await this.authCall((client) => { return ActionsApi_AvailableAssignees(client.axios, client.basePath, { workspaceId: this.workspace, diff --git a/libs/sdk-backend-tiger/src/backend/workspace/attributes/elements/date.ts b/libs/sdk-backend-tiger/src/backend/workspace/attributes/elements/date.ts index 559bdc9a116..877f38d4338 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/attributes/elements/date.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/attributes/elements/date.ts @@ -1,4 +1,4 @@ -// (C) 2021-2025 GoodData Corporation +// (C) 2021-2026 GoodData Corporation import { addDays, addMonths, addYears, format, getMonth, setDate, setMonth } from "date-fns"; @@ -31,7 +31,7 @@ export const getRelativeDateFilterShiftedValues = ( let startDate = currentDate; switch (granularity) { - case DATE_GRANULARITY.YEAR: { + case DATE_GRANULARITY.YEAR as string: { startDate = addYears(startDate, from); startDate = setMonth(startDate, 0); startDate = setDate(startDate, 1); @@ -44,7 +44,7 @@ export const getRelativeDateFilterShiftedValues = ( return iterateDates(startDate, endDate); } - case DATE_GRANULARITY.MONTH: { + case DATE_GRANULARITY.MONTH as string: { startDate = currentDate; startDate = addMonths(startDate, from); startDate = setDate(startDate, 1); @@ -56,7 +56,7 @@ export const getRelativeDateFilterShiftedValues = ( return iterateDates(startDate, endDate); } - case DATE_GRANULARITY.DATE: { + case DATE_GRANULARITY.DATE as string: { startDate = addDays(startDate, from); let endDate = currentDate; @@ -65,7 +65,7 @@ export const getRelativeDateFilterShiftedValues = ( return iterateDates(startDate, endDate); } - case DATE_GRANULARITY.QUARTER: { + case DATE_GRANULARITY.QUARTER as string: { startDate = getFirstDayQuarter(currentDate, from); const endDate = getLastDayQuarter(currentDate, to); diff --git a/libs/sdk-backend-tiger/src/backend/workspace/catalog/datasetLoader.ts b/libs/sdk-backend-tiger/src/backend/workspace/catalog/datasetLoader.ts index d5c8e984dc4..d9e301464fe 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/catalog/datasetLoader.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/catalog/datasetLoader.ts @@ -3,13 +3,11 @@ import { type EntitiesApiGetAllEntitiesAttributesRequest, type ITigerClientBase, - type JsonApiAttributeHierarchyOutWithLinks, type JsonApiAttributeOutIncludes, type JsonApiAttributeOutList, type JsonApiAttributeOutWithLinks, type JsonApiDatasetLinkage, type JsonApiDatasetOutWithLinks, - type JsonApiLabelLinkage, type JsonApiLabelOutWithLinks, MetadataUtilities, } from "@gooddata/api-client-tiger"; @@ -44,7 +42,7 @@ function getAttributeLabels( if (!included) { return []; } - const labelsRefs = (attribute.relationships?.labels?.data ?? []) as JsonApiLabelLinkage[]; + const labelsRefs = attribute.relationships?.labels?.data ?? []; return labelsRefs .map((ref) => { const obj = lookupRelatedObject(included, ref.id, ref.type); @@ -144,9 +142,7 @@ function createDateDatasets(attributes: JsonApiAttributeOutList): ICatalogDateDa function createAttributeHierarchies(attributes: JsonApiAttributeOutList): ICatalogAttributeHierarchy[] { const included = attributes.included ?? []; - const outAttributeHierarchies = included.filter( - (item) => item.type === "attributeHierarchy", - ) as JsonApiAttributeHierarchyOutWithLinks[]; + const outAttributeHierarchies = included.filter((item) => item.type === "attributeHierarchy"); return outAttributeHierarchies.map(convertAttributeHierarchy); } diff --git a/libs/sdk-backend-tiger/src/backend/workspace/dashboards/index.ts b/libs/sdk-backend-tiger/src/backend/workspace/dashboards/index.ts index 224cc7bd681..d8b057aa795 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/dashboards/index.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/dashboards/index.ts @@ -172,7 +172,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { options?: IGetDashboardOptions, ): Promise => { const includeUser = options?.loadUserData ? ["createdBy" as const, "modifiedBy" as const] : []; - const id = await objRefToIdentifier(ref, this.authCall); + const id = objRefToIdentifier(ref, this.authCall); const result = await this.authCall((client) => { return DashboardsApi_GetEntityAnalyticalDashboards( client.axios, @@ -353,7 +353,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { include.push("dashboardPlugins"); } - const id = await objRefToIdentifier(ref, this.authCall); + const id = objRefToIdentifier(ref, this.authCall); return this.authCall((client) => DashboardsApi_GetEntityAnalyticalDashboards( @@ -468,7 +468,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { }; } - const objectId = await objRefToIdentifier(originalDashboard.ref, this.authCall); + const objectId = objRefToIdentifier(originalDashboard.ref, this.authCall); const userSettings = await getSettingsForCurrentUser(this.authCall, this.workspace); const isWidgetIdentifiersEnabled = userSettings.enableWidgetIdentifiersRollout ?? true; const enableDashboardSectionHeadersDateDataSet = @@ -518,7 +518,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { public updateDashboardMeta = async ( updatedDashboard: IDashboardObjectIdentity & Partial, ): Promise => { - const objectId = await objRefToIdentifier(updatedDashboard.ref, this.authCall); + const objectId = objRefToIdentifier(updatedDashboard.ref, this.authCall); const result = await this.authCall((client) => { return DashboardsApi_PatchEntityAnalyticalDashboards( @@ -561,7 +561,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { }; public deleteDashboard = async (ref: ObjRef): Promise => { - const id = await objRefToIdentifier(ref, this.authCall); + const id = objRefToIdentifier(ref, this.authCall); await this.authCall((client) => DashboardsApi_DeleteEntityAnalyticalDashboards( @@ -584,7 +584,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { filtersByTab?: FiltersByTab, options?: IDashboardExportPdfOptions, ): Promise => { - const dashboardId = await objRefToIdentifier(dashboardRef, this.authCall); + const dashboardId = objRefToIdentifier(dashboardRef, this.authCall); // skip all time date filter from stored filters, when missing, it's correctly // restored to All time during the load later @@ -643,7 +643,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { filtersByTab?: FiltersByTab, options?: IDashboardExportPresentationOptions, ): Promise => { - const dashboardId = await objRefToIdentifier(dashboardRef, this.authCall); + const dashboardId = objRefToIdentifier(dashboardRef, this.authCall); // skip all time date filter from stored filters, when missing, it's correctly // restored to All time during the load later @@ -707,7 +707,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { dashboardRef: ObjRef, options?: IDashboardExportTabularOptions, ): Promise => { - const dashboardId = await objRefToIdentifier(dashboardRef, this.authCall); + const dashboardId = objRefToIdentifier(dashboardRef, this.authCall); return this.authCall(async (client) => { let title: string; @@ -834,7 +834,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { options?: IDashboardExportImageOptions, ): Promise => { return this.authCall(async (client) => { - const dashboardId = await objRefToIdentifier(dashboardRef, this.authCall); + const dashboardId = objRefToIdentifier(dashboardRef, this.authCall); // skip all time date filter from stored filters, when missing, it's correctly // restored to All time during the load later @@ -885,58 +885,58 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { }); }; - public createScheduledMail = async () => { + public createScheduledMail = () => { throw new NotSupported("Tiger backend does not support scheduled emails."); }; - public updateScheduledMail = async () => { + public updateScheduledMail = () => { throw new NotSupported("Tiger backend does not support scheduled emails."); }; - public deleteScheduledMail = async () => { + public deleteScheduledMail = () => { throw new NotSupported("Tiger backend does not support scheduled emails."); }; - public getScheduledMailsForDashboard = async () => { + public getScheduledMailsForDashboard = () => { throw new NotSupported("Tiger backend does not support scheduled emails."); }; - public getScheduledMailsCountForDashboard = async () => { + public getScheduledMailsCountForDashboard = () => { // FIXME Not supported - return 0; + return Promise.resolve(0); }; - public getAllWidgetAlertsForCurrentUser = async () => { + public getAllWidgetAlertsForCurrentUser = () => { // FIXME Not supported - return []; + return Promise.resolve([]); }; - public getDashboardWidgetAlertsForCurrentUser = async () => { + public getDashboardWidgetAlertsForCurrentUser = () => { throw new NotSupported("Tiger backend does not support alerting."); }; - public getWidgetAlertsCountForWidgets = async () => { + public getWidgetAlertsCountForWidgets = () => { // FIXME Not supported - return []; + return Promise.resolve([]); }; - public createWidgetAlert = async () => { + public createWidgetAlert = () => { throw new NotSupported("Tiger backend does not support alerting."); }; - public updateWidgetAlert = async () => { + public updateWidgetAlert = () => { throw new NotSupported("Tiger backend does not support alerting."); }; - public deleteWidgetAlert = async () => { + public deleteWidgetAlert = () => { throw new NotSupported("Tiger backend does not support alerting."); }; - public deleteWidgetAlerts = async () => { + public deleteWidgetAlerts = () => { throw new NotSupported("Tiger backend does not support alerting."); }; - public getWidgetReferencedObjects = async () => { + public getWidgetReferencedObjects = () => { throw new NotSupported("Tiger backend does not support alerting."); }; @@ -945,12 +945,14 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { filters: IFilter[], attributeFilterConfigs: IDashboardAttributeFilterConfig[], ): Promise => { - return resolveWidgetFilters( - filters, - widget.ignoreDashboardFilters, - widget.dateDataSet, - (refs) => objRefsToIdentifiers(refs, this.authCall), - attributeFilterConfigs, + return Promise.resolve( + resolveWidgetFilters( + filters, + widget.ignoreDashboardFilters, + widget.dateDataSet, + (refs) => objRefsToIdentifiers(refs, this.authCall), + attributeFilterConfigs, + ), ); }; @@ -960,13 +962,15 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { otherFilters: IFilter[], attributeFilterConfigs: IDashboardAttributeFilterConfig[], ): Promise => { - return resolveWidgetFiltersWithMultipleDateFilters( - commonDateFilters, - otherFilters, - widget.ignoreDashboardFilters, - widget.dateDataSet, - (refs) => objRefsToIdentifiers(refs, this.authCall), - attributeFilterConfigs, + return Promise.resolve( + resolveWidgetFiltersWithMultipleDateFilters( + commonDateFilters, + otherFilters, + widget.ignoreDashboardFilters, + widget.dateDataSet, + (refs) => objRefsToIdentifiers(refs, this.authCall), + attributeFilterConfigs, + ), ); }; @@ -1000,7 +1004,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { }; public deleteDashboardPlugin = async (ref: ObjRef): Promise => { - const id = await objRefToIdentifier(ref, this.authCall); + const id = objRefToIdentifier(ref, this.authCall); await this.authCall((client) => EntitiesApi_DeleteEntityDashboardPlugins( @@ -1024,7 +1028,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { const includeUser = options?.loadUserData ? { include: ["createdBy" as const, "modifiedBy" as const] } : {}; - const objectId = await objRefToIdentifier(ref, this.authCall); + const objectId = objRefToIdentifier(ref, this.authCall); const result = await this.authCall((client) => { return EntitiesApi_GetEntityDashboardPlugins( client.axios, @@ -1090,7 +1094,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { public getFilterViewsForCurrentUser = async (dashboard: ObjRef): Promise => { try { - const dashboardId = await objRefToIdentifier(dashboard, this.authCall); + const dashboardId = objRefToIdentifier(dashboard, this.authCall); const result = await this.authCall(async (client) => { const profile = await ProfileApi_GetCurrent(client.axios); return FilterViewsApi_GetAllEntitiesFilterViews(client.axios, client.basePath, { @@ -1117,7 +1121,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { try { const { name, dashboard, isDefault, filterContext, tabLocalIdentifier } = filterView; - const dashboardId = await objRefToIdentifier(dashboard, this.authCall); + const dashboardId = objRefToIdentifier(dashboard, this.authCall); const userSettings = await getSettingsForCurrentUser(this.authCall, this.workspace); const useDateFilterLocalIdentifiers = userSettings.enableDateFilterIdentifiersRollout ?? true; const enableDashboardTabs = userSettings.enableDashboardTabs ?? false; @@ -1193,7 +1197,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { public deleteFilterView = async (ref: ObjRef): Promise => { try { - const id = await objRefToIdentifier(ref, this.authCall); + const id = objRefToIdentifier(ref, this.authCall); await this.authCall((client) => FilterViewsApi_DeleteEntityFilterViews(client.axios, client.basePath, { workspaceId: this.workspace, @@ -1206,7 +1210,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { }; public setFilterViewAsDefault = async (ref: ObjRef, isDefault: boolean): Promise => { - const id = await objRefToIdentifier(ref, this.authCall); + const id = objRefToIdentifier(ref, this.authCall); const userSettings = await getSettingsForCurrentUser(this.authCall, this.workspace); const enableDashboardTabs = userSettings.enableDashboardTabs ?? false; @@ -1353,7 +1357,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { return buildDashboardPermissions(["EDIT"]); } - const dashboardObjectId = await objRefToIdentifier(ref, this.authCall); + const dashboardObjectId = objRefToIdentifier(ref, this.authCall); const dashboardWithPermissionsResponse = await this.authCall((client) => { return DashboardsApi_GetEntityAnalyticalDashboards(client.axios, client.basePath, { workspaceId: this.workspace, @@ -1444,7 +1448,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { filterContext, useDateFilterLocalIdentifiers, ); - const objectId = await objRefToIdentifier(filterContext.ref, this.authCall); + const objectId = objRefToIdentifier(filterContext.ref, this.authCall); const result = await this.authCall((client) => { return FilterContextApi_UpdateEntityFilterContexts( @@ -1475,7 +1479,7 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { }; private getFilterContext = async (filterContextRef: ObjRef) => { - const filterContextId = await objRefToIdentifier(filterContextRef, this.authCall); + const filterContextId = objRefToIdentifier(filterContextRef, this.authCall); const result = await this.authCall((client) => { return FilterContextApi_GetEntityFilterContexts( client.axios, diff --git a/libs/sdk-backend-tiger/src/backend/workspace/dashboards/tests/widgetFilters.test.ts b/libs/sdk-backend-tiger/src/backend/workspace/dashboards/tests/widgetFilters.test.ts index 59562bd71bf..225d6f05396 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/dashboards/tests/widgetFilters.test.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/dashboards/tests/widgetFilters.test.ts @@ -1,4 +1,5 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation + import { describe, expect, it } from "vitest"; import { @@ -15,31 +16,29 @@ import { resolveWidgetFilters } from "../widgetFilters.js"; describe("resolveWidgetFilters", () => { const objRefsToIdentifiersMock: Parameters[3] = (refs) => - Promise.resolve( - refs.map((ref) => { - if (isUriRef(ref)) { - const regex = /\/([^/]+)\/?$/; - const matches = regex.exec(ref.uri); - if (!matches) { - throw new Error(`Unexpected URI: "${ref.uri}"`); - } - return matches[1]; + refs.map((ref) => { + if (isUriRef(ref)) { + const regex = /\/([^/]+)\/?$/; + const matches = regex.exec(ref.uri); + if (!matches) { + throw new Error(`Unexpected URI: "${ref.uri}"`); } - return ref.identifier; - }), - ); + return matches[1]; + } + return ref.identifier; + }); - it("should return all attribute filters if ignoredFilters are empty", async () => { + it("should return all attribute filters if ignoredFilters are empty", () => { const filterToKeep = newPositiveAttributeFilter(idRef("to-keep"), ["foo"]); const filters = [filterToKeep]; - const actual = await resolveWidgetFilters(filters, [], undefined, objRefsToIdentifiersMock); + const actual = resolveWidgetFilters(filters, [], undefined, objRefsToIdentifiersMock); expect(actual).toEqual([filterToKeep]); }); - it("should remove ignored attribute filters", async () => { + it("should remove ignored attribute filters", () => { const filterToKeep = newPositiveAttributeFilter(idRef("to-keep"), ["foo"]); const filters = [ @@ -48,7 +47,7 @@ describe("resolveWidgetFilters", () => { newNegativeAttributeFilter(idRef("to-ignore"), ["bar"]), ]; - const actual = await resolveWidgetFilters( + const actual = resolveWidgetFilters( filters, [{ type: "attributeFilterReference", displayForm: uriRef("/gdc/md/to-ignore") }], undefined, @@ -58,7 +57,7 @@ describe("resolveWidgetFilters", () => { expect(actual).toEqual([filterToKeep]); }); - it("should remove date filters with different dimension", async () => { + it("should remove date filters with different dimension", () => { const filterToKeep = newRelativeDateFilter(idRef("dimension"), "GDC.time.date", 1, 1); const filters = [ @@ -67,7 +66,7 @@ describe("resolveWidgetFilters", () => { newRelativeDateFilter(idRef("other2"), "GDC.time.date", 3, 3), ]; - const actual = await resolveWidgetFilters( + const actual = resolveWidgetFilters( filters, [], uriRef("/gdc/md/dimension"), @@ -77,13 +76,13 @@ describe("resolveWidgetFilters", () => { expect(actual).toEqual([filterToKeep]); }); - it("should remove all date filters if the last one with the correct dimension is all time", async () => { + it("should remove all date filters if the last one with the correct dimension is all time", () => { const filters = [ newRelativeDateFilter(idRef("dimension"), "GDC.time.date", 1, 1), newAllTimeFilter(idRef("dimension")), ]; - const actual = await resolveWidgetFilters( + const actual = resolveWidgetFilters( filters, [], uriRef("/gdc/md/dimension"), @@ -93,11 +92,11 @@ describe("resolveWidgetFilters", () => { expect(actual).toEqual([]); }); - it("should keep the last date filter if the last one with the correct dimension is NOT all time", async () => { + it("should keep the last date filter if the last one with the correct dimension is NOT all time", () => { const filterToKeep = newRelativeDateFilter(idRef("dimension"), "GDC.time.date", 1, 1); const filters = [newAllTimeFilter(idRef("dimension")), filterToKeep]; - const actual = await resolveWidgetFilters( + const actual = resolveWidgetFilters( filters, [], uriRef("/gdc/md/dimension"), diff --git a/libs/sdk-backend-tiger/src/backend/workspace/dashboards/widgetFilters.ts b/libs/sdk-backend-tiger/src/backend/workspace/dashboards/widgetFilters.ts index 21d6c6e3660..64f7f7fbf6a 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/dashboards/widgetFilters.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/dashboards/widgetFilters.ts @@ -1,4 +1,4 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import { zip } from "lodash-es"; @@ -17,7 +17,7 @@ import { isDateFilter, } from "@gooddata/sdk-model"; -type NormalizeIds = (refs: ObjRef[]) => Promise; +type NormalizeIds = (refs: ObjRef[]) => string[]; /** * Performs widget filter resolution: @@ -32,13 +32,13 @@ type NormalizeIds = (refs: ObjRef[]) => Promise; * @param normalizeIds - function providing normalization of any ObjRef to identifier * @internal */ -export async function resolveWidgetFilters( +export function resolveWidgetFilters( filters: IFilter[], ignoreDashboardFilters: IWidget["ignoreDashboardFilters"], dateDataSet: IWidget["dateDataSet"], normalizeIds: NormalizeIds, attributeFilterConfigs: IDashboardAttributeFilterConfig[] = [], -): Promise { +): IFilter[] { const dateFilters = filters.filter(isDateFilter); const attributeFilters = filters.filter(isAttributeFilter); @@ -49,15 +49,13 @@ export async function resolveWidgetFilters( return filters; } - const [dateFiltersToKeep, attributeFiltersToKeep] = await Promise.all([ - getRelevantDateFiltersForWidget(dateFilters, dateDataSet, normalizeIds), - getRelevantAttributeFiltersForWidget( - attributeFilters, - ignoreDashboardFilters, - normalizeIds, - attributeFilterConfigs, - ), - ]); + const dateFiltersToKeep = getRelevantDateFiltersForWidget(dateFilters, dateDataSet, normalizeIds); + const attributeFiltersToKeep = getRelevantAttributeFiltersForWidget( + attributeFilters, + ignoreDashboardFilters, + normalizeIds, + attributeFilterConfigs, + ); const filtersToKeep = [...dateFiltersToKeep, ...attributeFiltersToKeep]; @@ -78,14 +76,14 @@ export async function resolveWidgetFilters( * @param normalizeIds - function providing normalization of any ObjRef to identifier * @internal */ -export async function resolveWidgetFiltersWithMultipleDateFilters( +export function resolveWidgetFiltersWithMultipleDateFilters( commonDateFilters: IDateFilter[], otherFilters: IFilter[], ignoreDashboardFilters: IWidget["ignoreDashboardFilters"], dateDataSet: IWidget["dateDataSet"], normalizeIds: NormalizeIds, attributeFilterConfigs: IDashboardAttributeFilterConfig[], -): Promise { +): IFilter[] { const dateFilters = otherFilters.filter(isDateFilter); const attributeFilters = otherFilters.filter(isAttributeFilter); @@ -96,16 +94,22 @@ export async function resolveWidgetFiltersWithMultipleDateFilters( return otherFilters; } - const [commonDateFiltersToKeep, dateFiltersToKeep, attributeFiltersToKeep] = await Promise.all([ - getRelevantDateFiltersForWidget(commonDateFilters, dateDataSet, normalizeIds), - getRelevantDateFiltersWithDimensionForWidget(dateFilters, ignoreDashboardFilters, normalizeIds), - getRelevantAttributeFiltersForWidget( - attributeFilters, - ignoreDashboardFilters, - normalizeIds, - attributeFilterConfigs, - ), - ]); + const commonDateFiltersToKeep = getRelevantDateFiltersForWidget( + commonDateFilters, + dateDataSet, + normalizeIds, + ); + const dateFiltersToKeep = getRelevantDateFiltersWithDimensionForWidget( + dateFilters, + ignoreDashboardFilters, + normalizeIds, + ); + const attributeFiltersToKeep = getRelevantAttributeFiltersForWidget( + attributeFilters, + ignoreDashboardFilters, + normalizeIds, + attributeFilterConfigs, + ); const filtersToKeep = [...dateFiltersToKeep, ...attributeFiltersToKeep]; // filter the original filter arrays to maintain order of the items @@ -120,18 +124,18 @@ export async function resolveWidgetFiltersWithMultipleDateFilters( return [...keptCommonDateFilters, ...keptOtherFilters]; } -async function getRelevantDateFiltersForWidget( +function getRelevantDateFiltersForWidget( filters: IDateFilter[], dateDataSet: IWidget["dateDataSet"], normalizeIds: NormalizeIds, -): Promise { +): IDateFilter[] { if (!dateDataSet || !filters.length || filters.every(isAllTimeDateFilter)) { return []; } - const [dateDatasetId, ...filterIds] = await normalizeIds([ + const [dateDatasetId, ...filterIds] = normalizeIds([ dateDataSet, - ...filters.map((filter) => filterObjRef(filter)!), + ...filters.map((filter) => filterObjRef(filter)), ]); const withRelevantDimension = zip(filters, filterIds) @@ -142,11 +146,11 @@ async function getRelevantDateFiltersForWidget( return !candidate || isAllTimeDateFilter(candidate) ? [] : [candidate]; } -async function getRelevantDateFiltersWithDimensionForWidget( +function getRelevantDateFiltersWithDimensionForWidget( filters: IDateFilter[], ignoreDashboardFilters: IWidget["ignoreDashboardFilters"], normalizeIds: NormalizeIds, -): Promise { +): IDateFilter[] { if (!ignoreDashboardFilters.length) { return filters; } @@ -156,9 +160,9 @@ async function getRelevantDateFiltersWithDimensionForWidget( } // get all the necessary uris in one call by concatenating both arrays - const ids = await normalizeIds([ + const ids = normalizeIds([ ...ignoreDashboardFilters.map(dashboardFilterReferenceObjRef), - ...filters.map((filter) => filterObjRef(filter)!), + ...filters.map((filter) => filterObjRef(filter)), ]); // re-split the uris array to the two parts corresponding to the original arrays @@ -172,12 +176,12 @@ async function getRelevantDateFiltersWithDimensionForWidget( .filter((f) => !isAllTimeDateFilter(f)); } -async function getRelevantAttributeFiltersForWidget( +function getRelevantAttributeFiltersForWidget( filters: IAttributeFilter[], ignoreDashboardFilters: IWidget["ignoreDashboardFilters"], normalizeIds: NormalizeIds, attributeFilterConfigs: IDashboardAttributeFilterConfig[], -): Promise { +): IAttributeFilter[] { if (!ignoreDashboardFilters.length) { return filters; } @@ -187,9 +191,9 @@ async function getRelevantAttributeFiltersForWidget( } // get all the necessary uris in one call by concatenating both arrays - const ids = await normalizeIds([ + const ids = normalizeIds([ ...ignoreDashboardFilters.map(dashboardFilterReferenceObjRef), - ...filters.map((filter) => filterObjRef(filter)!), + ...filters.map((filter) => filterObjRef(filter)), ...attributeFilterConfigs .filter((config) => !!config.displayAsLabel) .map((config) => config.displayAsLabel!), @@ -215,7 +219,7 @@ async function getRelevantAttributeFiltersForWidget( ); return ( !ignoredIds.includes(id!) && - (!config || !ignoredIds.includes(config.normalizedDisplayAsLabel!)) + (!config || !ignoredIds.includes(config.normalizedDisplayAsLabel)) ); }) .map(([filter]) => filter!); diff --git a/libs/sdk-backend-tiger/src/backend/workspace/dataFilters/index.ts b/libs/sdk-backend-tiger/src/backend/workspace/dataFilters/index.ts index 88ed0b71bbe..7831fb59f27 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/dataFilters/index.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/dataFilters/index.ts @@ -123,7 +123,7 @@ export class TigerDataFiltersService implements IDataFiltersService { updatedDataFilter: IWorkspaceDataFilter, ): Promise => { return this.authCall(async (client) => { - const objectId = await objRefToIdentifier(updatedDataFilter.ref, this.authCall); + const objectId = objRefToIdentifier(updatedDataFilter.ref, this.authCall); await EntitiesApi_PatchEntityWorkspaceDataFilters(client.axios, client.basePath, { workspaceId: this.workspace, objectId, @@ -144,7 +144,7 @@ export class TigerDataFiltersService implements IDataFiltersService { public updateDataFilterValue = async (dataFilter: ObjRef, values: string[]): Promise => { return this.authCall(async (client) => { - const dataFilterId = await objRefToIdentifier(dataFilter, this.authCall); + const dataFilterId = objRefToIdentifier(dataFilter, this.authCall); await this.deleteExistingSettings(client, dataFilterId); await EntitiesApi_CreateEntityWorkspaceDataFilterSettings(client.axios, client.basePath, { @@ -194,7 +194,7 @@ export class TigerDataFiltersService implements IDataFiltersService { public deleteDataFilter = async (ref: ObjRef): Promise => { return this.authCall(async (client) => { - const objectId = await objRefToIdentifier(ref, this.authCall); + const objectId = objRefToIdentifier(ref, this.authCall); await EntitiesApi_DeleteEntityWorkspaceDataFilters(client.axios, client.basePath, { workspaceId: this.workspace, objectId, diff --git a/libs/sdk-backend-tiger/src/backend/workspace/datasets/index.ts b/libs/sdk-backend-tiger/src/backend/workspace/datasets/index.ts index 8d4be3e8457..28e7438201d 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/datasets/index.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/datasets/index.ts @@ -1,4 +1,4 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation import { EntitiesApi_GetAllEntitiesDatasets, @@ -28,12 +28,12 @@ export class TigerWorkspaceDataSets implements IWorkspaceDatasetsService { public readonly workspace: string, ) {} - public async getDatasets(): Promise { - return this.authCall(async () => []); + public getDatasets(): Promise { + return this.authCall(async () => Promise.resolve([])); } public async getAllDatasetsMeta(): Promise { - return this.authCall(async () => []); + return this.authCall(async () => Promise.resolve([])); } public getDataSets(refs: ObjRef[]): Promise { @@ -56,7 +56,7 @@ export class TigerWorkspaceDataSets implements IWorkspaceDatasetsService { } public async getDataset(ref: ObjRef): Promise { - const objectId = await objRefToIdentifier(ref, this.authCall); + const objectId = objRefToIdentifier(ref, this.authCall); return this.authCall(async (client) => { const result = await EntitiesApi_GetEntityDatasets( @@ -79,7 +79,7 @@ export class TigerWorkspaceDataSets implements IWorkspaceDatasetsService { public async updateDatasetMeta( dataSet: Partial & IMetadataObjectIdentity, ): Promise { - const objectId = await objRefToIdentifier(dataSet.ref, this.authCall); + const objectId = objRefToIdentifier(dataSet.ref, this.authCall); return this.authCall(async (client) => { const result = await EntitiesApi_PatchEntityDatasets( diff --git a/libs/sdk-backend-tiger/src/backend/workspace/dateFilterConfigs/index.ts b/libs/sdk-backend-tiger/src/backend/workspace/dateFilterConfigs/index.ts index e87251f79ae..a3518ba32a6 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/dateFilterConfigs/index.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/dateFilterConfigs/index.ts @@ -36,7 +36,7 @@ export class TigerWorkspaceDateFilterConfigsQuery implements IDateFilterConfigsQ } public async query(): Promise { - return new InMemoryPaging([DefaultDateFilterConfig], this.limit, this.offset); + return Promise.resolve(new InMemoryPaging([DefaultDateFilterConfig], this.limit, this.offset)); } public async queryCustomDateFilterConfig(): Promise { diff --git a/libs/sdk-backend-tiger/src/backend/workspace/exportDefinitions/index.ts b/libs/sdk-backend-tiger/src/backend/workspace/exportDefinitions/index.ts index 67e1d199806..960d1c9d971 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/exportDefinitions/index.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/exportDefinitions/index.ts @@ -115,7 +115,7 @@ export class TigerWorkspaceExportDefinitions implements IWorkspaceExportDefiniti ): EntitiesApiGetAllEntitiesExportDefinitionsRequest => { const orderBy = options?.orderBy; const usesOrderingByUpdated = !orderBy || orderBy === "updated"; - const sortConfiguration = usesOrderingByUpdated ? {} : { sort: [orderBy!] }; // sort: ["modifiedAt", "createdAt"] + const sortConfiguration = usesOrderingByUpdated ? {} : { sort: [orderBy] }; // sort: ["modifiedAt", "createdAt"] const includeUser = options?.loadUserData || options?.author ? { include: ["createdBy" as const, "modifiedBy" as const] } @@ -129,7 +129,7 @@ export class TigerWorkspaceExportDefinitions implements IWorkspaceExportDefiniti ref: ObjRef, options: IGetExportDefinitionOptions = {}, ): Promise => { - const id = await objRefToIdentifier(ref, this.authCall); + const id = objRefToIdentifier(ref, this.authCall); const enableAutomationFilterContext = await this.getEnableAutomationFilterContext(); const includeUser = options?.loadUserData @@ -195,7 +195,7 @@ export class TigerWorkspaceExportDefinitions implements IWorkspaceExportDefiniti ref: ObjRef, exportDefinition: IExportDefinitionMetadataObjectDefinition, ): Promise => { - const id = await objRefToIdentifier(ref, this.authCall); + const id = objRefToIdentifier(ref, this.authCall); const enableAutomationFilterContext = await this.getEnableAutomationFilterContext(); const updateResponse = await this.authCall((client) => { @@ -225,7 +225,7 @@ export class TigerWorkspaceExportDefinitions implements IWorkspaceExportDefiniti }; public deleteExportDefinition = async (ref: ObjRef): Promise => { - const id = await objRefToIdentifier(ref, this.authCall); + const id = objRefToIdentifier(ref, this.authCall); await this.authCall((client) => EntitiesApi_DeleteEntityExportDefinitions(client.axios, client.basePath, { diff --git a/libs/sdk-backend-tiger/src/backend/workspace/facts/index.ts b/libs/sdk-backend-tiger/src/backend/workspace/facts/index.ts index c1d41098403..e2bb1cade42 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/facts/index.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/facts/index.ts @@ -44,7 +44,7 @@ export class TigerWorkspaceFacts implements IWorkspaceFactsService { } public async getFact(ref: ObjRef, opts: { include?: ["dataset"] } = {}): Promise { - const id = await objRefToIdentifier(ref, this.authCall); + const id = objRefToIdentifier(ref, this.authCall); const result = await this.authCall((client) => EntitiesApi_GetEntityFacts( client.axios, diff --git a/libs/sdk-backend-tiger/src/backend/workspace/genAI/ChatThread.ts b/libs/sdk-backend-tiger/src/backend/workspace/genAI/ChatThread.ts index ac4d4dafe9d..545b1a1dc4d 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/genAI/ChatThread.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/genAI/ChatThread.ts @@ -355,7 +355,7 @@ function convertChatHistoryInteraction( : {}), ...(data.semanticSearch ? { - semanticSearch: convertSemanticSearch(data.semanticSearch as SearchResult), + semanticSearch: convertSemanticSearch(data.semanticSearch), } : {}), ...(data.createdVisualizations @@ -410,7 +410,7 @@ function convertChatEvaluation( : {}), ...(data.semanticSearch ? { - semanticSearch: convertSemanticSearch(data.semanticSearch as SearchResult), + semanticSearch: convertSemanticSearch(data.semanticSearch), } : {}), ...(data.createdVisualizations diff --git a/libs/sdk-backend-tiger/src/backend/workspace/insights/index.ts b/libs/sdk-backend-tiger/src/backend/workspace/insights/index.ts index 69e94715397..6a018bf538a 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/insights/index.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/insights/index.ts @@ -96,7 +96,7 @@ export class TigerWorkspaceInsights implements IWorkspaceInsightsService { }; public getVisualizationClasses = async (): Promise => { - return this.authCall(async () => visualizationClassesMocks); + return this.authCall(() => Promise.resolve(visualizationClassesMocks)); }; public getInsights = async (options?: IInsightsQueryOptions): Promise => { @@ -141,7 +141,7 @@ export class TigerWorkspaceInsights implements IWorkspaceInsightsService { const usesOrderingByUpdated = !orderBy || orderBy === "updated"; const sortConfiguration = usesOrderingByUpdated ? { sort: ["modifiedAt,createdAt,title,desc"] } - : { sort: [orderBy!] }; + : { sort: [orderBy] }; const includeUser = options?.loadUserData || options?.author ? { include: ["createdBy" as const, "modifiedBy" as const] } @@ -181,26 +181,22 @@ export class TigerWorkspaceInsights implements IWorkspaceInsightsService { ).then((res: any) => res.data); }); - const attributes: ICatalogAttribute[] = (response as any).data.map( - (item: JsonApiAttributeOutWithLinks) => { - const includedItems = (response as any).included || []; - const labels = (item.relationships?.labels?.data ?? []).map((label) => label.id); - const dataset = item.relationships?.dataset?.data?.id; - - const relatedLabels = includedItems - .filter((item: any) => labels.includes(item.id)) - .filter(isLabelItem); - const relatedDataset = includedItems - .filter((item: any) => item.id === dataset) - .filter(isDataSetItem); - const primaryRelatedLabel = relatedLabels.find((label: any) => label.attributes?.primary); - const geoLabels = relatedLabels.filter((label: any) => - label.attributes?.valueType?.match(/GEO/), - ); - const defaultLabel = primaryRelatedLabel ?? relatedLabels[0]; - return convertAttribute(item, defaultLabel, geoLabels, relatedLabels, relatedDataset[0]); - }, - ); + const attributes: ICatalogAttribute[] = response.data.map((item: JsonApiAttributeOutWithLinks) => { + const includedItems = response.included || []; + const labels = (item.relationships?.labels?.data ?? []).map((label) => label.id); + const dataset = item.relationships?.dataset?.data?.id; + + const relatedLabels = includedItems + .filter((item: any) => labels.includes(item.id)) + .filter(isLabelItem); + const relatedDataset = includedItems + .filter((item: any) => item.id === dataset) + .filter(isDataSetItem); + const primaryRelatedLabel = relatedLabels.find((label: any) => label.attributes?.primary); + const geoLabels = relatedLabels.filter((label: any) => label.attributes?.valueType?.match(/GEO/)); + const defaultLabel = primaryRelatedLabel ?? relatedLabels[0]; + return convertAttribute(item, defaultLabel, geoLabels, relatedLabels, relatedDataset[0]); + }); return attributes; }; @@ -243,7 +239,7 @@ export class TigerWorkspaceInsights implements IWorkspaceInsightsService { insight: IInsight; included: JsonApiMetricOutIncludes[] | undefined; }> => { - const id = await objRefToIdentifier(ref, this.authCall); + const id = objRefToIdentifier(ref, this.authCall); const includeObj = references.length ? { include: references } : {}; const response = await this.authCall((client) => EntitiesApi_GetEntityVisualizationObjects( @@ -340,7 +336,7 @@ export class TigerWorkspaceInsights implements IWorkspaceInsightsService { public updateInsightMeta = async ( insightMeta: Partial & IMetadataObjectIdentity, ): Promise => { - const objectId = await objRefToIdentifier(insightMeta.ref, this.authCall); + const objectId = objRefToIdentifier(insightMeta.ref, this.authCall); const response = await this.authCall((client) => { return EntitiesApi_PatchEntityVisualizationObjects( client.axios, @@ -376,7 +372,7 @@ export class TigerWorkspaceInsights implements IWorkspaceInsightsService { }; public deleteInsight = async (ref: ObjRef): Promise => { - const id = await objRefToIdentifier(ref, this.authCall); + const id = objRefToIdentifier(ref, this.authCall); await this.authCall((client) => EntitiesApi_DeleteEntityVisualizationObjects(client.axios, client.basePath, { @@ -394,8 +390,8 @@ export class TigerWorkspaceInsights implements IWorkspaceInsightsService { }; public getInsightReferencingObjects = async (ref: ObjRef): Promise => { - const id = await objRefToIdentifier(ref, this.authCall); - const entitiesGraph = (await this.authCall((client) => + const id = objRefToIdentifier(ref, this.authCall); + const entitiesGraph = await this.authCall((client) => ActionsApi_GetDependentEntitiesGraphFromEntryPoints(client.axios, client.basePath, { workspaceId: this.workspace, dependentEntitiesRequest: { @@ -407,7 +403,7 @@ export class TigerWorkspaceInsights implements IWorkspaceInsightsService { ], }, }).then((res: any) => res.data.graph), - )) as any; + ); const analyticalDashboards = entitiesGraph.nodes .filter(({ type }: { type: string }) => type === "analyticalDashboard") .map(convertGraphEntityNodeToAnalyticalDashboard); @@ -426,7 +422,7 @@ export class TigerWorkspaceInsights implements IWorkspaceInsightsService { // we assume that all the filters in tiger already use idRefs exclusively const mergedFilters = mergeFilters(insightFilters(insight), filters); - return insightSetFilters(insight, mergedFilters); + return Promise.resolve(insightSetFilters(insight, mergedFilters)); }; } @@ -437,16 +433,16 @@ function createInsightFromBackend(data: JsonApiVisualizationObjectOutDocument, r const insight = insightFromInsightDefinition( convertVisualizationObject( - visualizationObject.attributes!.content! as + visualizationObject.attributes.content as | VisualizationObjectModelV1.IVisualizationObject | VisualizationObjectModelV2.IVisualizationObject, - visualizationObject.attributes!.title!, - visualizationObject.attributes!.description!, - visualizationObject.attributes!.tags, + visualizationObject.attributes.title!, + visualizationObject.attributes.description!, + visualizationObject.attributes.tags, ), visualizationObject.id, links!.self, - visualizationObject.attributes!.tags, + visualizationObject.attributes.tags, isInheritedObject(visualizationObject), visualizationObject.attributes?.isHidden, visualizationObject.attributes?.createdAt, diff --git a/libs/sdk-backend-tiger/src/backend/workspace/measures/index.ts b/libs/sdk-backend-tiger/src/backend/workspace/measures/index.ts index 0d49871e861..984c162c03b 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/measures/index.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/measures/index.ts @@ -131,7 +131,7 @@ export class TigerWorkspaceMeasures implements IWorkspaceMeasuresService { ), ); const metric = metricMetadata.data; - const maql = metric.data.attributes!.content!.maql || ""; + const maql = metric.data.attributes.content.maql || ""; const regexTokens = tokenizeExpression(maql); return regexTokens.map((regexToken) => this.resolveToken(regexToken, metric)); @@ -221,7 +221,7 @@ export class TigerWorkspaceMeasures implements IWorkspaceMeasuresService { } async updateMeasure(measure: IMeasureMetadataObject): Promise { - const objectId = await objRefToIdentifier(measure.ref, this.authCall); + const objectId = objRefToIdentifier(measure.ref, this.authCall); const metricAttributes = convertMetricToBackend(measure); const result = await this.authCall((client) => { return EntitiesApi_UpdateEntityMetrics( @@ -250,7 +250,7 @@ export class TigerWorkspaceMeasures implements IWorkspaceMeasuresService { async updateMeasureMeta( measure: Partial & IMetadataObjectIdentity, ): Promise { - const objectId = await objRefToIdentifier(measure.ref, this.authCall); + const objectId = objRefToIdentifier(measure.ref, this.authCall); const result = await this.authCall((client) => { return EntitiesApi_PatchEntityMetrics( client.axios, @@ -283,7 +283,7 @@ export class TigerWorkspaceMeasures implements IWorkspaceMeasuresService { } async deleteMeasure(measureRef: ObjRef): Promise { - const objectId = await objRefToIdentifier(measureRef, this.authCall); + const objectId = objRefToIdentifier(measureRef, this.authCall); await this.authCall((client) => { return EntitiesApi_DeleteEntityMetrics(client.axios, client.basePath, { @@ -294,7 +294,7 @@ export class TigerWorkspaceMeasures implements IWorkspaceMeasuresService { } public getMeasureReferencingObjects = async (ref: ObjRef): Promise => { - const id = await objRefToIdentifier(ref, this.authCall); + const id = objRefToIdentifier(ref, this.authCall); const insights = this.authCall((client) => MetadataUtilities.getAllPagesOf(client, EntitiesApi_GetAllEntitiesVisualizationObjects, { @@ -337,7 +337,7 @@ export class TigerWorkspaceMeasures implements IWorkspaceMeasuresService { } public async getMeasure(ref: ObjRef, options: IGetMeasureOptions = {}): Promise { - const id = await objRefToIdentifier(ref, this.authCall); + const id = objRefToIdentifier(ref, this.authCall); const result = await this.authCall((client) => EntitiesApi_GetEntityMetrics( client.axios, diff --git a/libs/sdk-backend-tiger/src/backend/workspace/styling/index.ts b/libs/sdk-backend-tiger/src/backend/workspace/styling/index.ts index d47cd348af9..4688aba576a 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/styling/index.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/styling/index.ts @@ -38,7 +38,7 @@ export class TigerWorkspaceStyling implements IWorkspaceStylingService { * * @returns boolean */ - private async isStylizable(activeStyleId: string): Promise { + private isStylizable(activeStyleId: string): boolean { return activeStyleId !== ""; } @@ -47,7 +47,7 @@ export class TigerWorkspaceStyling implements IWorkspaceStylingService { const activeColorPaletteId = (userSettings["activeColorPalette"] as IColorPaletteMetadataObject)?.id ?? ""; - return (await this.isStylizable(activeColorPaletteId)) + return this.isStylizable(activeColorPaletteId) ? this.authCall(async (client) => EntitiesApi_GetAllEntitiesColorPalettes(client.axios, client.basePath, { filter: `id=="${activeColorPaletteId}"`, @@ -70,7 +70,7 @@ export class TigerWorkspaceStyling implements IWorkspaceStylingService { const userSettings = await getSettingsForCurrentUser(this.authCall, this.workspace); const activeThemeId = (userSettings["activeTheme"] as IThemeMetadataObject)?.id ?? ""; - return (await this.isStylizable(activeThemeId)) + return this.isStylizable(activeThemeId) ? this.authCall(async (client) => EntitiesApi_GetAllEntitiesThemes(client.axios, client.basePath, { filter: `id=="${activeThemeId}"`, @@ -98,14 +98,14 @@ export class TigerWorkspaceStyling implements IWorkspaceStylingService { public getActiveTheme = () => this.getActiveSetting("activeTheme"); public async setActiveTheme(themeRef: ObjRef): Promise { - const themeId = await objRefToIdentifier(themeRef, this.authCall); + const themeId = objRefToIdentifier(themeRef, this.authCall); await this.settingsService.setTheme(themeId); } public getActiveColorPalette = () => this.getActiveSetting("activeColorPalette"); public async setActiveColorPalette(colorPaletteRef: ObjRef): Promise { - const colorPaletteId = await objRefToIdentifier(colorPaletteRef, this.authCall); + const colorPaletteId = objRefToIdentifier(colorPaletteRef, this.authCall); await this.settingsService.setColorPalette(colorPaletteId); } diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/ExportDefinitionsConverter.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/ExportDefinitionsConverter.ts index 1b2fb072f6f..61527357078 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/ExportDefinitionsConverter.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/ExportDefinitionsConverter.ts @@ -1,4 +1,4 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import { isEmpty } from "lodash-es"; import { v4 as uuid } from "uuid"; @@ -134,7 +134,7 @@ export const convertVisualExportRequest = ( enableAutomationFilterContext && metadata?.filtersByTab ? Object.entries(metadata.filtersByTab).reduce>( (acc, [tabId, tabFilters]) => { - acc[tabId] = (tabFilters as FilterContextItem[]).map(cloneWithSanitizedIds); + acc[tabId] = tabFilters.map(cloneWithSanitizedIds); return acc; }, {}, @@ -229,7 +229,7 @@ export const convertSlidesExportRequest = ( const filtersByTab = metadataObj?.filtersByTab ? Object.entries(metadataObj.filtersByTab).reduce>( (acc, [tabId, tabFilters]) => { - acc[tabId] = (tabFilters as FilterContextItem[]).map(cloneWithSanitizedIds); + acc[tabId] = tabFilters.map(cloneWithSanitizedIds); return acc; }, {}, @@ -385,7 +385,7 @@ const convertExportDefinitionRequestPayload = ( enableAutomationFilterContext && metadata?.filtersByTab ? Object.entries(metadata.filtersByTab).reduce>( (acc, [tabId, tabFilters]) => { - acc[tabId] = (tabFilters as FilterContextItem[]).map(cloneWithSanitizedIds); + acc[tabId] = tabFilters.map(cloneWithSanitizedIds); return acc; }, {}, diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/InsightConverter.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/InsightConverter.ts index 53c3dc08497..64c4c6c4fb2 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/InsightConverter.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/InsightConverter.ts @@ -1,4 +1,4 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import { type JsonApiAnalyticalDashboardOutIncludes, @@ -50,12 +50,12 @@ export const visualizationObjectsItemToInsight = ( ): IInsight => { const { id, attributes, relationships = {} } = visualizationObject; const { createdBy, modifiedBy } = relationships; - const { content, title, description, tags, isHidden, createdAt, modifiedAt } = attributes!; + const { content, title, description, tags, isHidden, createdAt, modifiedAt } = attributes; const links = "links" in visualizationObject ? visualizationObject.links : undefined; return insightFromInsightDefinition( convertVisualizationObject( - content! as + content as | VisualizationObjectModelV1.IVisualizationObject | VisualizationObjectModelV2.IVisualizationObject, title!, diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/MetadataConverter.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/MetadataConverter.ts index ba476b69f79..a431a871e41 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/MetadataConverter.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/MetadataConverter.ts @@ -1,4 +1,4 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation import { keyBy } from "lodash-es"; @@ -13,7 +13,6 @@ import { type JsonApiFactOutDocument, type JsonApiFactOutList, type JsonApiFactOutWithLinks, - type JsonApiLabelLinkage, type JsonApiLabelOutWithLinks, type JsonApiMetricOutList, type JsonApiMetricOutWithLinks, @@ -94,7 +93,7 @@ export function convertAttributeLabels( attribute: JsonApiAttributeOut | JsonApiAttributeOutWithLinks, labelsMap: Record, ): IAttributeDisplayFormMetadataObject[] { - const labelsRefs = (attribute.relationships?.labels?.data ?? []) as JsonApiLabelLinkage[]; + const labelsRefs = attribute.relationships?.labels?.data ?? []; const defaultView = attribute.relationships?.defaultView?.data; return labelsRefs @@ -285,9 +284,7 @@ export function convertDatasetWithLinks(dataset: JsonApiDatasetOutWithLinks): ID type DatasetRelationships = | JsonApiAttributeOut["relationships"] - | JsonApiAttributeOutWithLinks["relationships"] | JsonApiFactOut["relationships"] - | JsonApiFactOutWithLinks["relationships"] | undefined; /** diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/ObjectInheritance.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/ObjectInheritance.ts index 769c3e0650d..8a955962502 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/ObjectInheritance.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/ObjectInheritance.ts @@ -1,4 +1,4 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import { type JsonApiDatasetOutMeta, @@ -26,7 +26,7 @@ export function getObjectOrigin(obj: JsonApiMetadataLikeObject): /** * @internal */ -export interface OriginInfoWithId { +export interface IOriginInfoWithId { originType: JsonApiDatasetOutMetaOriginOriginTypeEnum; originId: string; id: string; @@ -43,7 +43,7 @@ export interface OriginInfoWithId { * @param id - string that represent id with or without prefix * @internal */ -export function getIdOrigin(id: string): OriginInfoWithId { +export function getIdOrigin(id: string): IOriginInfoWithId { const data = id.split(PrefixSeparator); //prefix + id diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/SemanticQualityConverter.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/SemanticQualityConverter.ts index 7cdcfca8fcd..2042ee3cb04 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/SemanticQualityConverter.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/SemanticQualityConverter.ts @@ -1,4 +1,4 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation import type { AfmGetQualityIssuesResponse, @@ -11,7 +11,6 @@ import { type ISemanticQualityIssue, type ISemanticQualityIssuesCalculation, type ISemanticQualityReport, - type Identifier, type SemanticQualityIssueAttributeName, type SemanticQualityIssueCode, type SemanticQualityIssueSeverity, @@ -48,7 +47,7 @@ export function convertQualityIssue(issue: AfmQualityIssue): ISemanticQualityIss severity: convertQualityIssueSeverity(issue.severity), objects: issue.objects.map((obj) => ({ type: obj.type as GenAIObjectType, - identifier: obj.id as Identifier, + identifier: obj.id, title: obj.title, })), detail: { diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/UsersConverter.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/UsersConverter.ts index 5860f4964b1..4d83c1ae333 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/UsersConverter.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/UsersConverter.ts @@ -1,4 +1,5 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation + import { isEmpty } from "lodash-es"; import { @@ -32,8 +33,8 @@ export const convertUser = (user: IUserProfile): IUser => { } = user; return { - ref: uriRef(links!.user!), - login: userId!, + ref: uriRef(links.user), + login: userId, fullName: name, email: email, firstName: firstName, diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/afm/GrandTotalsConverter.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/afm/GrandTotalsConverter.ts index 5dc96ab9550..1b89a4a25e2 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/afm/GrandTotalsConverter.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/afm/GrandTotalsConverter.ts @@ -1,4 +1,4 @@ -// (C) 2022-2025 GoodData Corporation +// (C) 2022-2026 GoodData Corporation import { isEmpty } from "lodash-es"; @@ -88,7 +88,7 @@ function combineHeaders( return combinedHeaderItems; } -interface GrandTotal { +interface IGrandTotal { dimensionIdx: number; data: DataValue[]; } @@ -108,7 +108,7 @@ function transformGrandTotal( headerItems: Readonly, totalDimensions: number[], definition: IExecutionDefinition, -): GrandTotal[] { +): IGrandTotal[] { if (totalDimensions.length !== 1) { // If the grand total belongs to multiple or zero dimensions it is either // a grand total from a >2D result or it is a total of totals, diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/AnalyticalDashboardConverter.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/AnalyticalDashboardConverter.ts index 6ed83deb721..d73ee7f2002 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/AnalyticalDashboardConverter.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/AnalyticalDashboardConverter.ts @@ -1,4 +1,4 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import { invariant } from "ts-invariant"; @@ -82,7 +82,7 @@ export function convertDashboard( analyticalDashboard: JsonApiAnalyticalDashboardOutDocument, filterContext?: IFilterContext, ): IDashboard { - const content = analyticalDashboard.data.attributes!.content; + const content = analyticalDashboard.data.attributes.content; if (AnalyticalDashboardModelV1.isAnalyticalDashboard(content)) { return convertDashboardV1(analyticalDashboard, filterContext); @@ -98,7 +98,7 @@ export function convertDashboard( export function convertFilterContextFromBackend( filterContext: JsonApiFilterContextOutDocument, ): IFilterContext { - const content = filterContext.data.attributes!.content; + const content = filterContext.data.attributes.content; if (AnalyticalDashboardModelV1.isFilterContext(content)) { return convertFilterContextFromBackendV1(filterContext); diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/common/filterContextUtils.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/common/filterContextUtils.ts index c1187984358..46825c5e159 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/common/filterContextUtils.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/common/filterContextUtils.ts @@ -1,4 +1,4 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import { invariant } from "ts-invariant"; @@ -45,7 +45,7 @@ export function getFilterContextFromIncluded( function convertFilterContextFromIncluded(filterContext: JsonApiFilterContextOutWithLinks): IFilterContext { const { id, type, attributes } = filterContext; - const { title = "", description = "", content } = attributes!; + const { title = "", description = "", content } = attributes; return { ref: idRef(id, type as ObjectType), diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/v1/AnalyticalDashboardConverter.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/v1/AnalyticalDashboardConverter.ts index 710e457c896..6cc2be2997c 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/v1/AnalyticalDashboardConverter.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/v1/AnalyticalDashboardConverter.ts @@ -1,4 +1,4 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import { updateWith } from "lodash-es"; import { v4 as uuidv4 } from "uuid"; @@ -115,7 +115,7 @@ export function convertFilterContextFromBackend( filterContext: JsonApiFilterContextOutDocument, ): IFilterContext { const { id, type, attributes } = filterContext.data; - const { title = "", description = "", content } = attributes!; + const { title = "", description = "", content } = attributes; return { ref: idRef(id, type as ObjectType), diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/v2/AnalyticalDashboardConverter.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/v2/AnalyticalDashboardConverter.ts index 5e52717de70..ca4599b0863 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/v2/AnalyticalDashboardConverter.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/analyticalDashboards/v2/AnalyticalDashboardConverter.ts @@ -1,4 +1,4 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import { updateWith } from "lodash-es"; import { v4 as uuidv4 } from "uuid"; @@ -309,7 +309,7 @@ export function convertFilterContextFromBackend( filterContext: JsonApiFilterContextOutDocument, ): IFilterContext { const { id, type, attributes } = filterContext.data; - const { title = "", description = "", content } = attributes!; + const { title = "", description = "", content } = attributes; return { ref: idRef(id, type as ObjectType), diff --git a/libs/sdk-backend-tiger/src/index.ts b/libs/sdk-backend-tiger/src/index.ts index 7e5333d6436..27ca85aa560 100644 --- a/libs/sdk-backend-tiger/src/index.ts +++ b/libs/sdk-backend-tiger/src/index.ts @@ -1,4 +1,4 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation /** * This package provides the Analytical Backend implementation for GoodData Cloud and GoodData.CN. @@ -84,7 +84,7 @@ export type { TigerSpecificFunctions, IApiToken, IApiTokenExtended, - Entitlement, + IEntitlement, IDataSourceApiResult, IDataSourceUpsertRequest, IDataSourceTestConnectionRequest, @@ -113,7 +113,7 @@ export type { ICustomApplicationSetting, ScanSqlResult, WorkspaceEntitiesDatasets, - ScanRequest, + IScanRequest, ScanResult, IDataSourceCacheStrategy, INotificationChannel, @@ -127,7 +127,7 @@ export { tigerIdTypeToObjectType, objectTypeToTigerIdType, } from "./types/refTypeMapping.js"; -export type { OriginInfoWithId } from "./convertors/fromBackend/ObjectInheritance.js"; +export type { IOriginInfoWithId } from "./convertors/fromBackend/ObjectInheritance.js"; export { getIdOrigin } from "./convertors/fromBackend/ObjectInheritance.js"; export { toAfmExecution } from "./convertors/toBackend/afm/toAfmResultSpec.js"; diff --git a/libs/sdk-backend-tiger/src/typings.d.ts b/libs/sdk-backend-tiger/src/typings.d.ts index 132a367566f..ea8ea61a742 100644 --- a/libs/sdk-backend-tiger/src/typings.d.ts +++ b/libs/sdk-backend-tiger/src/typings.d.ts @@ -1,10 +1,12 @@ -// (C) 2022-2024 GoodData Corporation +// (C) 2022-2026 GoodData Corporation + // declare package json so that we can import it even without resolveJsonModule which breaks outputs declare module "*/package.json" { export const name: string; export const version: string; } +// eslint-disable-next-line @typescript-eslint/naming-convention interface Window { // this variable is set before e2e and causes widget identifiers to be deterministic for recording snapshots useSafeWidgetLocalIdentifiersForE2e: boolean; diff --git a/libs/sdk-backend-tiger/src/utils/api.ts b/libs/sdk-backend-tiger/src/utils/api.ts index 418e96586a9..9750320eace 100644 --- a/libs/sdk-backend-tiger/src/utils/api.ts +++ b/libs/sdk-backend-tiger/src/utils/api.ts @@ -1,4 +1,5 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation + import { UnexpectedError } from "@gooddata/sdk-backend-spi"; import { type Identifier, type ObjRef, type Uri, isIdentifierRef, isUriRef } from "@gooddata/sdk-model"; @@ -17,7 +18,9 @@ export const objRefToUri = async ( workspace: string, authCall: TigerAuthenticatedCallGuard, ): Promise => { - return isUriRef(ref) ? ref.uri : authCall(async () => `/${workspace}/${ref.type}/${ref.identifier}`); + return isUriRef(ref) + ? ref.uri + : authCall(() => Promise.resolve(`/${workspace}/${ref.type}/${ref.identifier}`)); }; /** @@ -28,10 +31,7 @@ export const objRefToUri = async ( * * @internal */ -export const objRefToIdentifier = async ( - ref: ObjRef, - _authCall: TigerAuthenticatedCallGuard, -): Promise => { +export const objRefToIdentifier = (ref: ObjRef, _authCall: TigerAuthenticatedCallGuard): Identifier => { if (isIdentifierRef(ref)) { return ref.identifier; } @@ -55,10 +55,7 @@ export const objRefToIdentifier = async ( * * @internal */ -export const objRefsToIdentifiers = ( - refs: ObjRef[], - authCall: TigerAuthenticatedCallGuard, -): Promise => { +export const objRefsToIdentifiers = (refs: ObjRef[], authCall: TigerAuthenticatedCallGuard): Identifier[] => { // there is no bulk api yet, so do it one by one - return Promise.all(refs.map((ref) => objRefToIdentifier(ref, authCall))); + return refs.map((ref) => objRefToIdentifier(ref, authCall)); }; diff --git a/libs/sdk-embedding/.eslintrc.cjs b/libs/sdk-embedding/.eslintrc.cjs index 517b7eeb340..395c3d780ba 100644 --- a/libs/sdk-embedding/.eslintrc.cjs +++ b/libs/sdk-embedding/.eslintrc.cjs @@ -1,21 +1,19 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm"], rules: { - "import/export": "off", + "import/export": "warn", }, overrides: [ tsOverride(__dirname, { - "@typescript-eslint/no-namespace": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/no-unsafe-argument": "off", - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-unsafe-enum-comparison": "off", + "@typescript-eslint/no-unsafe-assignment": "warn", + "@typescript-eslint/no-unsafe-call": "warn", + "@typescript-eslint/no-unsafe-member-access": "warn", + "@typescript-eslint/no-unsafe-argument": "warn", + "@typescript-eslint/no-unsafe-return": "warn", }), ], }; diff --git a/libs/sdk-embedding/package.json b/libs/sdk-embedding/package.json index a0226f0158c..44083c9f02c 100644 --- a/libs/sdk-embedding/package.json +++ b/libs/sdk-embedding/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-embedding", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "description": "GoodData Embedding APIs", "repository": { "type": "git", diff --git a/libs/sdk-embedding/src/iframe/EmbeddedAnalyticalDesigner.ts b/libs/sdk-embedding/src/iframe/EmbeddedAnalyticalDesigner.ts index 4ef8332150e..89dea048bf0 100644 --- a/libs/sdk-embedding/src/iframe/EmbeddedAnalyticalDesigner.ts +++ b/libs/sdk-embedding/src/iframe/EmbeddedAnalyticalDesigner.ts @@ -1,4 +1,4 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import { type IInsightDefinition } from "@gooddata/sdk-model"; @@ -299,7 +299,11 @@ export type AdDrillableItemsCommandData = IGdcAdMessageEnvelope< * @public */ export function isAdDrillableItemsCommandData(obj: unknown): obj is AdDrillableItemsCommandData { - return obj !== null && typeof obj === "object" && getEventType(obj) === GdcAdCommandType.DrillableItems; + return ( + obj !== null && + typeof obj === "object" && + getEventType(obj) === (GdcAdCommandType.DrillableItems as string) + ); } // @@ -401,7 +405,11 @@ export type AdOpenInsightCommandData = IGdcAdMessageEnvelope< * @public */ export function isAdOpenInsightCommandData(obj: unknown): obj is AdOpenInsightCommandData { - return obj !== null && typeof obj === "object" && getEventType(obj) === GdcAdCommandType.OpenInsight; + return ( + obj !== null && + typeof obj === "object" && + getEventType(obj) === (GdcAdCommandType.OpenInsight as string) + ); } // @@ -432,7 +440,9 @@ export type AdClearCommandData = IGdcAdMessageEnvelope = IGdcMessageEnvelope< * @public */ export function isCommandFailedData(obj: unknown): obj is CommandFailedData { - return obj !== null && typeof obj === "object" && getEventType(obj) === GdcEventType.AppCommandFailed; + return ( + obj !== null && + typeof obj === "object" && + getEventType(obj) === (GdcEventType.AppCommandFailed as string) + ); } /** diff --git a/libs/sdk-model/.eslintrc.cjs b/libs/sdk-model/.eslintrc.cjs index d73e665474b..1615f837868 100644 --- a/libs/sdk-model/.eslintrc.cjs +++ b/libs/sdk-model/.eslintrc.cjs @@ -1,4 +1,4 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); @@ -6,16 +6,13 @@ module.exports = { extends: ["@gooddata/eslint-config/esm"], overrides: [ tsOverride(__dirname, { - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-redundant-type-constituents": "off", - "@typescript-eslint/no-unnecessary-type-assertion": "off", - "@typescript-eslint/no-unsafe-argument": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/no-implied-eval": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-duplicate-type-constituents": "off", - "@typescript-eslint/restrict-template-expressions": "off", + "@typescript-eslint/no-unsafe-return": "warn", + "@typescript-eslint/no-unsafe-call": "warn", + "@typescript-eslint/no-unsafe-argument": "warn", + "@typescript-eslint/no-unsafe-member-access": "warn", + "@typescript-eslint/no-unsafe-assignment": "warn", + "@typescript-eslint/no-implied-eval": "warn", + "@typescript-eslint/restrict-template-expressions": "warn", }), ], }; diff --git a/libs/sdk-model/api/sdk-model.api.md b/libs/sdk-model/api/sdk-model.api.md index 404e0752214..b3824811baa 100644 --- a/libs/sdk-model/api/sdk-model.api.md +++ b/libs/sdk-model/api/sdk-model.api.md @@ -105,13 +105,13 @@ export function attributeAlias(attribute: IAttribute): string | undefined; export class AttributeBuilder { // @internal constructor(input: AttributeBuilderInput); - alias: (alias?: string | undefined) => this; + alias: (alias?: string) => this; build: () => IAttribute; defaultLocalId: () => this; displayForm: (ref: ObjRef) => this; - localId: (localId?: Identifier | undefined) => this; + localId: (localId?: Identifier) => this; noAlias: () => this; - showAllValues: (showAllValues?: boolean | undefined) => this; + showAllValues: (showAllValues?: boolean) => this; } // @public @@ -3799,6 +3799,7 @@ export interface ISettings { enableDescriptions?: boolean; enableDestinationTesting?: boolean; enableDrilledTooltip?: boolean; + enableDrillMenuPositioningAtCursor?: boolean; enableDrillToUrlByDefault?: boolean; enableEmbedButtonInAD?: boolean; enableEmbedButtonInKD?: boolean; @@ -5017,7 +5018,7 @@ export function measureArithmeticOperator(measure: IMeasure): ArithmeticMeasureO export class MeasureBuilder extends MeasureBuilderBase { // @internal constructor(measureOrRef: IMeasure | ObjRef); - aggregation: (aggregation?: MeasureAggregation | undefined) => this; + aggregation: (aggregation?: MeasureAggregation) => this; // (undocumented) protected buildDefinition(): IMeasureDefinition; defaultAggregation: () => this; @@ -5034,7 +5035,7 @@ export class MeasureBuilder extends MeasureBuilderBase { export abstract class MeasureBuilderBase { // @internal protected constructor(); - alias: (alias?: string | undefined) => this; + alias: (alias?: string) => this; // (undocumented) build: () => IMeasure; protected abstract buildDefinition(): T; @@ -5042,13 +5043,13 @@ export abstract class MeasureBuilderBase { protected customLocalId: boolean; defaultFormat: () => this; defaultLocalId: () => this; - format: (format?: string | undefined) => this; + format: (format?: string) => this; protected abstract generateLocalId(): string; protected initializeFromExisting(measure: MeasureEnvelope): void; - localId: (localId?: Identifier | undefined) => this; + localId: (localId?: Identifier) => this; noAlias: () => this; noTitle: () => this; - title: (title?: string | undefined) => this; + title: (title?: string) => this; } // @public diff --git a/libs/sdk-model/package.json b/libs/sdk-model/package.json index 9a7d59a315d..75c2d395ff6 100644 --- a/libs/sdk-model/package.json +++ b/libs/sdk-model/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-model", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "description": "GoodData Model definitions used by UI components and Backend SPI", "repository": { "type": "git", diff --git a/libs/sdk-model/src/execution/attribute/factory.ts b/libs/sdk-model/src/execution/attribute/factory.ts index b299a114919..f227b27ead6 100644 --- a/libs/sdk-model/src/execution/attribute/factory.ts +++ b/libs/sdk-model/src/execution/attribute/factory.ts @@ -1,4 +1,4 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation import { cloneDeep, isEmpty } from "lodash-es"; import SparkMD5 from "spark-md5"; @@ -51,7 +51,7 @@ export class AttributeBuilder { * * @param alias - alias to use instead of attribute title; undefined to use server-defined value */ - public alias = (alias?: string | undefined): this => { + public alias = (alias?: string): this => { if (!alias) { return this.noAlias(); } @@ -83,7 +83,7 @@ export class AttributeBuilder { * * @param showAllValues - flag defining whether to return all attribute values for given attribute; undefined to use backend default behavior(false) */ - public showAllValues = (showAllValues?: boolean | undefined): this => { + public showAllValues = (showAllValues?: boolean): this => { if (showAllValues === undefined) { delete this.attribute.showAllValues; } else { @@ -118,7 +118,7 @@ export class AttributeBuilder { * @param localId - local identifier to set; if not specified, the builder will ensure local id will * be generated */ - public localId = (localId?: Identifier | undefined): this => { + public localId = (localId?: Identifier): this => { if (!localId || localId.trim().length === 0) { return this.defaultLocalId(); } diff --git a/libs/sdk-model/src/execution/buckets/tests/bucket.test.ts b/libs/sdk-model/src/execution/buckets/tests/bucket.test.ts index 0b571879edb..9dde0a4a5cb 100644 --- a/libs/sdk-model/src/execution/buckets/tests/bucket.test.ts +++ b/libs/sdk-model/src/execution/buckets/tests/bucket.test.ts @@ -1,4 +1,5 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation + import { InvariantError } from "ts-invariant"; import { describe, expect, it } from "vitest"; @@ -372,7 +373,7 @@ describe("bucketModifyItems", () => { if (isMeasure(bucketItem)) { (bucketItem as IMeasure).measure.title = "Modified measure title"; } else { - (bucketItem as IAttribute).attribute.alias = "Modified attribute alias"; + bucketItem.attribute.alias = "Modified attribute alias"; } return bucketItem; }; diff --git a/libs/sdk-model/src/execution/buckets/tests/bucketArray.test.ts b/libs/sdk-model/src/execution/buckets/tests/bucketArray.test.ts index e471e06eb1f..bd767428dd0 100644 --- a/libs/sdk-model/src/execution/buckets/tests/bucketArray.test.ts +++ b/libs/sdk-model/src/execution/buckets/tests/bucketArray.test.ts @@ -1,4 +1,5 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation + import { describe, expect, it } from "vitest"; import { Account, Activity, Velocity, Won } from "../../../../__mocks__/model.js"; @@ -316,7 +317,7 @@ describe("bucketsModifyItem", () => { if (isMeasure(bucketItem)) { (bucketItem as IMeasure).measure.title = "Modified measure title"; } else { - (bucketItem as IAttribute).attribute.alias = "Modified attribute alias"; + bucketItem.attribute.alias = "Modified attribute alias"; } return bucketItem; }; diff --git a/libs/sdk-model/src/execution/filter/factory.ts b/libs/sdk-model/src/execution/filter/factory.ts index b1ba9851f1d..77b05bc7736 100644 --- a/libs/sdk-model/src/execution/filter/factory.ts +++ b/libs/sdk-model/src/execution/filter/factory.ts @@ -298,7 +298,7 @@ export function newMeasureValueFilter( range: { operator, from: val1, - to: val2OrTreatNullValuesAsInComparison!, + to: val2OrTreatNullValuesAsInComparison, ...nullValuesProp, }, }, diff --git a/libs/sdk-model/src/execution/measure/factory.ts b/libs/sdk-model/src/execution/measure/factory.ts index aacbdf19fa8..b150d886481 100644 --- a/libs/sdk-model/src/execution/measure/factory.ts +++ b/libs/sdk-model/src/execution/measure/factory.ts @@ -1,4 +1,4 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation import { cloneDeep, isEmpty } from "lodash-es"; import SparkMD5 from "spark-md5"; @@ -84,7 +84,7 @@ export abstract class MeasureBuilderBase { * @param localId - local identifier to set; if not specified, the builder will ensure local id will * be generated */ - public localId = (localId?: Identifier | undefined): this => { + public localId = (localId?: Identifier): this => { if (!localId || localId.trim().length === 0) { return this.defaultLocalId(); } @@ -115,7 +115,7 @@ export abstract class MeasureBuilderBase { * * @param alias - alias to use instead of measure title; undefined to use the title instead */ - public alias = (alias?: string | undefined): this => { + public alias = (alias?: string): this => { if (!alias) { return this.noAlias(); } @@ -143,7 +143,7 @@ export abstract class MeasureBuilderBase { * * @param title - alternative title to use instead of server-defined value; undefined to use server-defined value */ - public title = (title?: string | undefined): this => { + public title = (title?: string): this => { if (!title) { return this.noTitle(); } @@ -173,7 +173,7 @@ export abstract class MeasureBuilderBase { * * @param format - measure format string; or undefined if you want to fall back to server-defined value */ - public format = (format?: string | undefined): this => { + public format = (format?: string): this => { if (!format) { return this.defaultFormat(); } @@ -244,7 +244,7 @@ export abstract class MeasureBuilderBase { */ private getOrGenerateLocalId(): string { if (this.customLocalId && !isEmpty(this.measure.localIdentifier)) { - return this.measure.localIdentifier!; + return this.measure.localIdentifier; } return sanitizeLocalId( @@ -314,7 +314,7 @@ export class MeasureBuilder extends MeasureBuilderBase { * * @param aggregation - aggregation to use; if undefined will reset to default */ - public aggregation = (aggregation?: MeasureAggregation | undefined): this => { + public aggregation = (aggregation?: MeasureAggregation): this => { if (!aggregation) { return this.defaultAggregation(); } diff --git a/libs/sdk-model/src/execution/results/tests/typeGuards.test.ts b/libs/sdk-model/src/execution/results/tests/typeGuards.test.ts index 3f7456260ac..2f86bf21103 100644 --- a/libs/sdk-model/src/execution/results/tests/typeGuards.test.ts +++ b/libs/sdk-model/src/execution/results/tests/typeGuards.test.ts @@ -1,10 +1,9 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation + import { describe, expect, it } from "vitest"; import { InvalidInputTestCases } from "../../../../__mocks__/typeGuards.js"; import { - type IDimensionItemDescriptor, - type IResultHeader, isAttributeDescriptor, isMeasureDescriptor, isMeasureGroupDescriptor, @@ -16,7 +15,7 @@ import { describe("result type guards", () => { describe("isAttributeDescriptor", () => { - const Scenarios: Array<[boolean, string, IDimensionItemDescriptor | any]> = [ + const Scenarios: Array<[boolean, string, any]> = [ ...InvalidInputTestCases, [true, "attribute descriptor", { attributeHeader: { name: "my attribute" } }], [false, "measure group descriptor", { measureGroupHeader: { items: [] } }], @@ -68,7 +67,7 @@ describe("result type guards", () => { }); }); describe("isResultAttributeHeader", () => { - const Scenarios: Array<[boolean, string, IResultHeader | any]> = [ + const Scenarios: Array<[boolean, string, any]> = [ ...InvalidInputTestCases, [ true, diff --git a/libs/sdk-model/src/insight/tests/insight.test.ts b/libs/sdk-model/src/insight/tests/insight.test.ts index 15903e4e6c0..0f67fb5cdab 100644 --- a/libs/sdk-model/src/insight/tests/insight.test.ts +++ b/libs/sdk-model/src/insight/tests/insight.test.ts @@ -1,4 +1,5 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation + import { describe, expect, it } from "vitest"; import { newInsight } from "../../../__mocks__/insights.js"; @@ -520,7 +521,7 @@ describe("insightModifyItems", () => { if (isMeasure(bucketItem)) { (bucketItem as IMeasure).measure.title = "Modified measure title"; } else { - (bucketItem as IAttribute).attribute.alias = "Modified attribute alias"; + bucketItem.attribute.alias = "Modified attribute alias"; } return bucketItem; }; diff --git a/libs/sdk-model/src/ldm/metadata/attributeDisplayForm/index.ts b/libs/sdk-model/src/ldm/metadata/attributeDisplayForm/index.ts index 030c56da4b4..98dc2828e7f 100644 --- a/libs/sdk-model/src/ldm/metadata/attributeDisplayForm/index.ts +++ b/libs/sdk-model/src/ldm/metadata/attributeDisplayForm/index.ts @@ -1,4 +1,4 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation import { invariant } from "ts-invariant"; @@ -66,6 +66,7 @@ export interface IAttributeDisplayFormMetadataObject extends IMetadataObject { * Subtype of the display form * (e.g. GDC.geo.pin, or GDC.link, see constants above). */ + // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents displayFormType?: AttributeDisplayFormType | string; /** diff --git a/libs/sdk-model/src/settings/index.ts b/libs/sdk-model/src/settings/index.ts index 7926959f040..47b7ce586fe 100644 --- a/libs/sdk-model/src/settings/index.ts +++ b/libs/sdk-model/src/settings/index.ts @@ -1,4 +1,4 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import { isEmpty } from "lodash-es"; @@ -670,6 +670,11 @@ export interface ISettings { */ enableImplicitDrillToUrl?: boolean; + /** + * Enables positioning of drill menu at the cursor click point (instead of default positioning). + */ + enableDrillMenuPositioningAtCursor?: boolean; + /** * Enable anomaly detection alert */ diff --git a/libs/sdk-ui-all/.eslintrc.cjs b/libs/sdk-ui-all/.eslintrc.cjs index 5f03f0b51e7..c02bdb8efc8 100644 --- a/libs/sdk-ui-all/.eslintrc.cjs +++ b/libs/sdk-ui-all/.eslintrc.cjs @@ -1,11 +1,11 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); module.exports = { extends: ["@gooddata/eslint-config/esm"], rules: { - "import/export": "off", + "import/export": "warn", }, overrides: [tsOverride(__dirname)], }; diff --git a/libs/sdk-ui-all/package.json b/libs/sdk-ui-all/package.json index e6632919abc..4e4b2169b91 100644 --- a/libs/sdk-ui-all/package.json +++ b/libs/sdk-ui-all/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-ui-all", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "description": "GoodData SDK - All-In-One", "repository": { "type": "git", diff --git a/libs/sdk-ui-catalog/.eslintrc.cjs b/libs/sdk-ui-catalog/.eslintrc.cjs index 2f953e51fca..93b19bed569 100644 --- a/libs/sdk-ui-catalog/.eslintrc.cjs +++ b/libs/sdk-ui-catalog/.eslintrc.cjs @@ -1,4 +1,4 @@ -// (C) 2020-2025 GoodData Corporation +// (C) 2020-2026 GoodData Corporation const { tsOverride } = require("@gooddata/eslint-config/tsOverride"); @@ -6,15 +6,9 @@ module.exports = { extends: ["@gooddata/eslint-config/esm-react-vitest"], overrides: [ tsOverride(__dirname, { - "@typescript-eslint/no-explicit-any": ["error", { fixToUnknown: true }], - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/no-misused-promises": "off", - "@typescript-eslint/naming-convention": "off", - "@typescript-eslint/no-duplicate-type-constituents": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/restrict-template-expressions": "off", - "@typescript-eslint/require-await": "off", - "@typescript-eslint/no-floating-promises": "off", + "@typescript-eslint/no-unsafe-member-access": "warn", + "@typescript-eslint/no-unsafe-assignment": "warn", + "@typescript-eslint/restrict-template-expressions": "warn", }), ], }; diff --git a/libs/sdk-ui-catalog/api/sdk-ui-catalog.api.md b/libs/sdk-ui-catalog/api/sdk-ui-catalog.api.md index dde8fd45dae..46a09fc560d 100644 --- a/libs/sdk-ui-catalog/api/sdk-ui-catalog.api.md +++ b/libs/sdk-ui-catalog/api/sdk-ui-catalog.api.md @@ -17,13 +17,16 @@ import { ReactNode } from 'react'; export function AnalyticsCatalog(props: IAnalyticsCatalogProps): JSX.Element; // @internal (undocumented) -export function AnalyticsCatalogDetail({ backend, workspace, locale, ...restProps }: AnalyticsCatalogDetailProps): JSX.Element; +export function AnalyticsCatalogDetail({ backend, workspace, locale, ...restProps }: IAnalyticsCatalogDetailProps): JSX.Element; // @internal (undocumented) -export function AnalyticsCatalogDetailContent({ backend, workspace, locale, ...restProps }: AnalyticsCatalogDetailContentProps): JSX.Element; +export function AnalyticsCatalogDetailContent({ backend, workspace, locale, ...restProps }: IAnalyticsCatalogDetailContentProps): JSX.Element; + +// @internal +export function AnalyticsCatalogFilter(props: IAnalyticsCatalogFilterProps): JSX.Element; // @internal (undocumented) -export interface AnalyticsCatalogDetailContentProps extends Omit { +export interface IAnalyticsCatalogDetailContentProps extends Omit { backend?: IAnalyticalBackend; locale?: string; objectId: string; @@ -33,7 +36,7 @@ export interface AnalyticsCatalogDetailContentProps extends Omit { +export interface IAnalyticsCatalogDetailProps extends Omit { backend?: IAnalyticalBackend; locale?: string; objectId: string; @@ -41,30 +44,6 @@ export interface AnalyticsCatalogDetailProps extends Omit(props: IAnalyticsCatalogFilterProps): JSX.Element; - -// @internal (undocumented) -export interface CatalogDetailContentProps { - objectDefinition?: Partial | null; - objectId?: string | null; - objectType?: ObjectType | null; - onCatalogItemNavigation?: (event: MouseEvent_2, ref: ICatalogItemRef) => void; - onCatalogItemUpdate?: (item: ICatalogItem, changes: Partial & ICatalogItemRef) => void; - onCatalogItemUpdateError?: (error: Error) => void; - onOpenClick?: (event: MouseEvent_2, linkClickEvent: OpenHandlerEvent) => void; - onTagClick?: (tag: string) => void; -} - -// @internal (undocumented) -export interface CatalogDetailProps extends CatalogDetailContentProps { - dataTestId?: string; - node?: HTMLElement; - onClose: () => void; - open: boolean; - zIndex?: number; -} - // @internal export interface IAnalyticsCatalogFilterProps { actions?: ReactNode; @@ -92,6 +71,27 @@ export interface IAnalyticsCatalogProps { workspace?: string; } +// @internal (undocumented) +export interface ICatalogDetailContentProps { + objectDefinition?: Partial | null; + objectId?: string | null; + objectType?: ObjectType | null; + onCatalogItemNavigation?: (event: MouseEvent_2, ref: ICatalogItemRef) => void; + onCatalogItemUpdate?: (item: ICatalogItem, changes: Partial & ICatalogItemRef) => void; + onCatalogItemUpdateError?: (error: Error) => void; + onOpenClick?: (event: MouseEvent_2, linkClickEvent: OpenHandlerEvent) => void; + onTagClick?: (tag: string) => void; +} + +// @internal (undocumented) +export interface ICatalogDetailProps extends ICatalogDetailContentProps { + dataTestId?: string; + node?: HTMLElement; + onClose: () => void; + open: boolean; + zIndex?: number; +} + // @internal export interface ICatalogItem extends ICatalogItemRef { // (undocumented) diff --git a/libs/sdk-ui-catalog/package.json b/libs/sdk-ui-catalog/package.json index 81df61a2d94..a90cd012671 100644 --- a/libs/sdk-ui-catalog/package.json +++ b/libs/sdk-ui-catalog/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-ui-catalog", - "version": "11.16.0-alpha.4", + "version": "11.16.0-alpha.5", "description": "GoodData SDK - Analytics Catalog", "repository": { "type": "git", diff --git a/libs/sdk-ui-catalog/src/AnalyticsCatalogDetail.tsx b/libs/sdk-ui-catalog/src/AnalyticsCatalogDetail.tsx index edd39ed22aa..ed47f60555a 100644 --- a/libs/sdk-ui-catalog/src/AnalyticsCatalogDetail.tsx +++ b/libs/sdk-ui-catalog/src/AnalyticsCatalogDetail.tsx @@ -1,14 +1,14 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation import type { MouseEvent, PropsWithChildren } from "react"; import type { IAnalyticalBackend } from "@gooddata/sdk-backend-spi"; import { BackendProvider, WorkspaceProvider, useBackendStrict, useWorkspaceStrict } from "@gooddata/sdk-ui"; -import { CatalogDetail, type CatalogDetailProps } from "./catalogDetail/CatalogDetail.js"; +import { CatalogDetail, type ICatalogDetailProps } from "./catalogDetail/CatalogDetail.js"; import { CatalogDetailContent, - type CatalogDetailContentProps, + type ICatalogDetailContentProps, type OpenHandlerEvent, } from "./catalogDetail/CatalogDetailContent.js"; import { CatalogResourceProvider } from "./catalogResource/index.js"; @@ -22,7 +22,7 @@ import { QualityProvider } from "./quality/QualityContext.js"; /** * @internal */ -export interface AnalyticsCatalogDetailProps extends Omit { +export interface IAnalyticsCatalogDetailProps extends Omit { /** * An object id of the catalog item. */ @@ -53,7 +53,7 @@ export function AnalyticsCatalogDetail({ workspace, locale, ...restProps -}: AnalyticsCatalogDetailProps) { +}: IAnalyticsCatalogDetailProps) { return ( @@ -64,8 +64,8 @@ export function AnalyticsCatalogDetail({ /** * @internal */ -export interface AnalyticsCatalogDetailContentProps - extends Omit { +export interface IAnalyticsCatalogDetailContentProps + extends Omit { /** * An object id of the catalog item. */ @@ -100,7 +100,7 @@ export function AnalyticsCatalogDetailContent({ workspace, locale, ...restProps -}: AnalyticsCatalogDetailContentProps) { +}: IAnalyticsCatalogDetailContentProps) { return ( diff --git a/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetail.tsx b/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetail.tsx index 04749c57082..8efb9886f45 100644 --- a/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetail.tsx +++ b/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetail.tsx @@ -1,17 +1,15 @@ -// (C) 2025 GoodData Corporation - -import { useRef } from "react"; +// (C) 2025-2026 GoodData Corporation import { useIntl } from "react-intl"; import { UiDrawer } from "@gooddata/sdk-ui-kit"; -import { CatalogDetailContent, type CatalogDetailContentProps } from "./CatalogDetailContent.js"; +import { CatalogDetailContent, type ICatalogDetailContentProps } from "./CatalogDetailContent.js"; /** * @internal */ -export interface CatalogDetailProps extends CatalogDetailContentProps { +export interface ICatalogDetailProps extends ICatalogDetailContentProps { /** * Whether the overlay is open or not. */ @@ -38,15 +36,19 @@ export interface CatalogDetailProps extends CatalogDetailContentProps { /** * @internal */ -export function CatalogDetail({ open, onClose, dataTestId, zIndex, node, ...restProps }: CatalogDetailProps) { +export function CatalogDetail({ + open, + onClose, + dataTestId, + zIndex, + node, + ...restProps +}: ICatalogDetailProps) { const intl = useIntl(); - const focusRef = useRef(null); - return ( - + ); } diff --git a/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailContent.tsx b/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailContent.tsx index 1717881bcd4..77fa72c52d1 100644 --- a/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailContent.tsx +++ b/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailContent.tsx @@ -1,6 +1,6 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation -import { type MouseEvent, type RefObject, useCallback, useMemo, useRef } from "react"; +import { type MouseEvent, useCallback, useMemo, useRef } from "react"; import { useIntl } from "react-intl"; @@ -8,7 +8,7 @@ import { type SemanticQualityIssueAttributeName } from "@gooddata/sdk-model"; import { useLocalStorage, useWorkspaceStrict } from "@gooddata/sdk-ui"; import { type IUiTab, UiButton, UiSkeleton, UiTabs } from "@gooddata/sdk-ui-kit"; -import { CatalogDetailHeader, type CatalogDetailHeaderRef } from "./CatalogDetailHeader.js"; +import { CatalogDetailHeader, type ICatalogDetailHeaderRef } from "./CatalogDetailHeader.js"; import { CatalogDetailStatus } from "./CatalogDetailStatus.js"; import { CatalogDetailTabMetadata } from "./CatalogDetailTabMetadata.js"; import { CatalogDetailTabQuality } from "./CatalogDetailTabQuality.js"; @@ -48,7 +48,7 @@ export type OpenHandlerEvent = { /** * @internal */ -export interface CatalogDetailContentProps { +export interface ICatalogDetailContentProps { /** * An object id of the catalog item. */ @@ -83,10 +83,6 @@ export interface CatalogDetailContentProps { onCatalogItemUpdateError?: (error: Error) => void; } -type Props = CatalogDetailContentProps & { - focusRef?: RefObject; -}; - /** * @internal */ @@ -94,13 +90,12 @@ export function CatalogDetailContent({ objectId, objectType, objectDefinition, - focusRef, onOpenClick, onTagClick, onCatalogItemUpdate, onCatalogItemUpdateError, onCatalogItemNavigation, -}: Props) { +}: ICatalogDetailContentProps) { const intl = useIntl(); const workspaceId = useWorkspaceStrict(); @@ -140,7 +135,7 @@ export function CatalogDetailContent({ const issues = useQualityIssuesById(item?.identifier ?? "") ?? []; const issueCount = issues.length > 0 ? `(${issues.length})` : ""; - const headerRef = useRef(null); + const headerRef = useRef(null); const handleEditClick = useCallback((attributeName: SemanticQualityIssueAttributeName) => { if (attributeName === "TITLE") { @@ -188,7 +183,6 @@ export function CatalogDetailContent({ { onOpenClick?.(event, { item, diff --git a/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailContentRow.tsx b/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailContentRow.tsx index bb9f2f0f13c..7a1d48bd5dc 100644 --- a/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailContentRow.tsx +++ b/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailContentRow.tsx @@ -1,24 +1,24 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation import type { ReactNode } from "react"; -export interface CatalogDetailContentRowProps { +export interface ICatalogDetailContentRowProps { title: ReactNode; content?: ReactNode; } -export function CatalogDetailContentRow({ title, content }: CatalogDetailContentRowProps) { +export function CatalogDetailContentRow({ title, content }: ICatalogDetailContentRowProps) { if (!content) { return null; } return ( <> -
+
{title} -
-
+ +
{content} -
+ ); } diff --git a/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailHeader.tsx b/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailHeader.tsx index 3bce296380e..4c818246307 100644 --- a/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailHeader.tsx +++ b/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailHeader.tsx @@ -1,4 +1,4 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation import { type ReactNode, type RefObject, useImperativeHandle, useRef } from "react"; @@ -9,18 +9,18 @@ import { EditableLabel, UiCard } from "@gooddata/sdk-ui-kit"; import { CatalogItemLockMemo, type ICatalogItem } from "../catalogItem/index.js"; import { ObjectTypeIconMemo, ObjectTypeTooltip } from "../objectType/index.js"; -export interface CatalogDetailHeaderRef { +export interface ICatalogDetailHeaderRef { focusTitle: () => void; focusDescription: () => void; } -interface Props { +interface IProps { item: ICatalogItem; canEdit: boolean; actions: ReactNode; updateItemTitle: (title: string) => void; updateItemDescription: (description: string) => void; - headerRef: RefObject; + headerRef: RefObject; } export function CatalogDetailHeader({ @@ -30,7 +30,7 @@ export function CatalogDetailHeader({ updateItemTitle, updateItemDescription, headerRef, -}: Props) { +}: IProps) { const intl = useIntl(); const type = item.type ?? "analyticalDashboard"; @@ -63,6 +63,7 @@ export function CatalogDetailHeader({ visualizationType={visualizationType} anchor={ intl.formatMessage(descriptor), [intl]); const normalizedFormat = normalizeFormatValue(format); @@ -126,7 +126,7 @@ export const CatalogDetailMetricSettings = memo(function CatalogDetailMetricSett ); }); -interface MetricTypeDropdownProps { +interface IMetricTypeDropdownProps { canEdit: boolean; metricType?: MetricType; onMetricTypeChange?: (metricType: MetricType | undefined) => void; @@ -136,7 +136,7 @@ const MetricTypeDropdown = memo(function MetricTypeDropdown({ canEdit, metricType, onMetricTypeChange, -}: MetricTypeDropdownProps) { +}: IMetricTypeDropdownProps) { const intl = useIntl(); const selectedOption = METRIC_TYPE_OPTIONS.find((option) => option.value === metricType) ?? DEFAULT_METRIC_TYPE_OPTION; diff --git a/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailTabMetadata.tsx b/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailTabMetadata.tsx index a4b330123fa..3cb01dd7df5 100644 --- a/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailTabMetadata.tsx +++ b/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailTabMetadata.tsx @@ -1,4 +1,4 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation import cx from "classnames"; import { FormattedMessage, useIntl } from "react-intl"; @@ -48,7 +48,7 @@ export function CatalogDetailTabMetadata({ const granularities = item.dataSet?.attributes ?? []; return ( -
+
{item.dataSet && !isDataSet ? ( } @@ -89,7 +89,9 @@ export function CatalogDetailTabMetadata({ <> } + anchor={ + + } content={ } @@ -107,6 +109,9 @@ export function CatalogDetailTabMetadata({ type="checkbox" checked={item.isHidden !== true} disabled={!canEdit} + aria-label={intl.formatMessage({ + id: "analyticsCatalog.column.title.isHidden", + })} onChange={(event) => { onIsHiddenChange(!event.target.checked); }} @@ -141,6 +146,6 @@ export function CatalogDetailTabMetadata({ /> } /> -
+ ); } diff --git a/libs/sdk-ui-catalog/src/catalogDetail/hooks/useCatalogItemLoad.ts b/libs/sdk-ui-catalog/src/catalogDetail/hooks/useCatalogItemLoad.ts index 6726e72d26f..036798bdb84 100644 --- a/libs/sdk-ui-catalog/src/catalogDetail/hooks/useCatalogItemLoad.ts +++ b/libs/sdk-ui-catalog/src/catalogDetail/hooks/useCatalogItemLoad.ts @@ -1,4 +1,4 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation import type { IAnalyticalWorkspace } from "@gooddata/sdk-backend-spi"; import { useBackendStrict, useCancelablePromise, useWorkspaceStrict } from "@gooddata/sdk-ui"; @@ -14,13 +14,13 @@ import { import type { ICatalogItem } from "../../catalogItem/index.js"; import type { ObjectType } from "../../objectType/index.js"; -export interface UseCatalogItemLoad { +export interface IUseCatalogItemLoad { objectId?: string | null; objectType?: ObjectType | null; objectDefinition?: Partial | null; } -export function useCatalogItemLoad({ objectDefinition, objectId, objectType }: UseCatalogItemLoad): { +export function useCatalogItemLoad({ objectDefinition, objectId, objectType }: IUseCatalogItemLoad): { status: "loading" | "success" | "error" | "pending"; item?: ICatalogItem | null; error?: Error; diff --git a/libs/sdk-ui-catalog/src/catalogDetail/hooks/useCatalogItemUpdate.ts b/libs/sdk-ui-catalog/src/catalogDetail/hooks/useCatalogItemUpdate.ts index dbf12787a7b..36c99c6ea00 100644 --- a/libs/sdk-ui-catalog/src/catalogDetail/hooks/useCatalogItemUpdate.ts +++ b/libs/sdk-ui-catalog/src/catalogDetail/hooks/useCatalogItemUpdate.ts @@ -1,4 +1,4 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation import { useCallback, useEffect, useState } from "react"; @@ -15,7 +15,7 @@ import type { ICatalogItem, ICatalogItemRef } from "../../catalogItem/types.js"; import { useMounted } from "../../hooks/useMounted.js"; import type { ObjectType } from "../../objectType/index.js"; -export interface UseCatalogItemUpdate { +export interface IUseCatalogItemUpdate { currentUser: IUser | null | undefined; objectId?: string | null; objectType?: ObjectType | null; @@ -36,7 +36,7 @@ export function useCatalogItemUpdate({ objectDefinition, onUpdate, onError, -}: UseCatalogItemUpdate) { +}: IUseCatalogItemUpdate) { const backend = useBackendStrict(); const workspace = useWorkspaceStrict(); diff --git a/libs/sdk-ui-catalog/src/catalogItem/useCatalogItemFeed.ts b/libs/sdk-ui-catalog/src/catalogItem/useCatalogItemFeed.ts index 6ac3274266c..864a9664888 100644 --- a/libs/sdk-ui-catalog/src/catalogItem/useCatalogItemFeed.ts +++ b/libs/sdk-ui-catalog/src/catalogItem/useCatalogItemFeed.ts @@ -1,4 +1,4 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; @@ -238,7 +238,7 @@ function useFirstLoad( setError(null); let mounted = true; - (async () => { + void (async () => { try { const firstPages = await Promise.all(endpoints.map((ep) => ep.query())); diff --git a/libs/sdk-ui-catalog/src/filter/FilterContext.tsx b/libs/sdk-ui-catalog/src/filter/FilterContext.tsx index ee287f6b913..ff6c5a62090 100644 --- a/libs/sdk-ui-catalog/src/filter/FilterContext.tsx +++ b/libs/sdk-ui-catalog/src/filter/FilterContext.tsx @@ -1,4 +1,4 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation import { type PropsWithChildren, createContext, useContext, useMemo, useReducer } from "react"; @@ -20,7 +20,7 @@ interface IFilterParams { isInverted: boolean; } -interface IFilterState { +interface IFilterStateBase { types: ObjectType[]; origin: ObjectOrigin; createdBy: IFilterParams; @@ -29,7 +29,7 @@ interface IFilterState { isHidden: boolean | undefined; } -interface FilterState extends IFilterState { +interface IFilterState extends IFilterStateBase { // Derived state isModified: boolean; } @@ -57,7 +57,7 @@ type FilterReducerAction = | { type: "reset" } | { type: "toggleTag"; payload: string }; -const initialState: IFilterState = { +const initialState: IFilterStateBase = { types: [], origin: "ALL", createdBy: { values: [], isInverted: true }, @@ -66,7 +66,7 @@ const initialState: IFilterState = { isHidden: undefined, }; -const initialFullState: FilterState = { +const initialFullState: IFilterState = { ...initialState, // Derived state isModified: false, @@ -85,13 +85,13 @@ const initialActions: IFilterActions = { toggleTag: () => {}, }; -const FilterStateContext = createContext(initialFullState); +const FilterStateContext = createContext(initialFullState); const FilterActionsContext = createContext(initialActions); export function FilterProvider({ children }: PropsWithChildren) { const [filters, dispatch] = useReducer(filterReducer, initialState); - const state: FilterState = useMemo( + const state: IFilterState = useMemo( () => ({ ...filters, // Derived state @@ -121,7 +121,7 @@ export function FilterProvider({ children }: PropsWithChildren) { ); } -function filterReducer(state: IFilterState, action: FilterReducerAction): IFilterState { +function filterReducer(state: IFilterStateBase, action: FilterReducerAction): IFilterStateBase { switch (action.type) { // Setters case "setTypes": { diff --git a/libs/sdk-ui-catalog/src/header/Header.tsx b/libs/sdk-ui-catalog/src/header/Header.tsx index cde4000458e..685fcb3af6a 100644 --- a/libs/sdk-ui-catalog/src/header/Header.tsx +++ b/libs/sdk-ui-catalog/src/header/Header.tsx @@ -14,7 +14,7 @@ export function Header({ searchNode }: Props) { const intl = useIntl(); return ( -
+

@@ -37,6 +37,6 @@ export function Header({ searchNode }: Props) { />
{searchNode} -
+ ); } diff --git a/libs/sdk-ui-catalog/src/index.ts b/libs/sdk-ui-catalog/src/index.ts index f4299ed5b5b..669ab59e15b 100644 --- a/libs/sdk-ui-catalog/src/index.ts +++ b/libs/sdk-ui-catalog/src/index.ts @@ -1,4 +1,4 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation /* * Analytics Catalog public API. @@ -7,9 +7,9 @@ export { AnalyticsCatalog, type IAnalyticsCatalogProps } from "./AnalyticsCatalog.js"; export { AnalyticsCatalogDetail, - type AnalyticsCatalogDetailProps, + type IAnalyticsCatalogDetailProps, AnalyticsCatalogDetailContent, - type AnalyticsCatalogDetailContentProps, + type IAnalyticsCatalogDetailContentProps, } from "./AnalyticsCatalogDetail.js"; export { AnalyticsCatalogFilter, type IAnalyticsCatalogFilterProps } from "./AnalyticsCatalogFilter.js"; @@ -17,9 +17,9 @@ export { AnalyticsCatalogFilter, type IAnalyticsCatalogFilterProps } from "./Ana * Supplementary API. */ -export { type CatalogDetailProps } from "./catalogDetail/CatalogDetail.js"; +export { type ICatalogDetailProps } from "./catalogDetail/CatalogDetail.js"; export { - type CatalogDetailContentProps, + type ICatalogDetailContentProps, type OpenHandlerEvent, } from "./catalogDetail/CatalogDetailContent.js"; diff --git a/libs/sdk-ui-catalog/src/main/Main.tsx b/libs/sdk-ui-catalog/src/main/Main.tsx index 7aed76bcdff..7eafa024948 100644 --- a/libs/sdk-ui-catalog/src/main/Main.tsx +++ b/libs/sdk-ui-catalog/src/main/Main.tsx @@ -1,4 +1,4 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation import { type MouseEvent } from "react"; @@ -65,7 +65,7 @@ export function Main({ return (
-
+
}> @@ -77,7 +77,7 @@ export function Main({ -
+ {({ items, next, hasNext, totalCount, status, updateItem }) => ( <> diff --git a/libs/sdk-ui-catalog/src/main/hooks/useCatalogItemOpen.ts b/libs/sdk-ui-catalog/src/main/hooks/useCatalogItemOpen.ts index 8f59c88cf10..5c8526934df 100644 --- a/libs/sdk-ui-catalog/src/main/hooks/useCatalogItemOpen.ts +++ b/libs/sdk-ui-catalog/src/main/hooks/useCatalogItemOpen.ts @@ -1,4 +1,5 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation + import { type MouseEvent, useCallback, useEffect, useState } from "react"; import { areObjRefsEqual } from "@gooddata/sdk-model"; @@ -7,7 +8,7 @@ import type { OpenHandlerEvent } from "../../catalogDetail/CatalogDetailContent. import type { ICatalogItem, ICatalogItemRef } from "../../catalogItem/index.js"; export function useCatalogItemOpen( - onCatalogItemOpenClick?: ((e: MouseEvent, item: OpenHandlerEvent) => void) | undefined, + onCatalogItemOpenClick?: (e: MouseEvent, item: OpenHandlerEvent) => void, onCatalogDetailOpened?: (ref: ICatalogItemRef) => void, onCatalogDetailClosed?: () => void, openCatalogItemRef?: ICatalogItemRef, diff --git a/libs/sdk-ui-catalog/src/objectType/ObjectTypeIcon.tsx b/libs/sdk-ui-catalog/src/objectType/ObjectTypeIcon.tsx index ed0f829c0cb..96853a87b9c 100644 --- a/libs/sdk-ui-catalog/src/objectType/ObjectTypeIcon.tsx +++ b/libs/sdk-ui-catalog/src/objectType/ObjectTypeIcon.tsx @@ -1,15 +1,18 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation import { type ComponentProps, memo } from "react"; import cx from "classnames"; +import type { IntlShape } from "react-intl"; import { type IconType, UiIcon } from "@gooddata/sdk-ui-kit"; +import { getObjectTypeLabel } from "./labels.js"; import type { ObjectType } from "./types.js"; import type { VisualizationType } from "../catalogItem/types.js"; -type Props = ComponentProps<"div"> & { +export type ObjectTypeIconProps = ComponentProps<"div"> & { + intl: IntlShape; type: ObjectType; visualizationType?: VisualizationType; size?: 14 | 18; @@ -17,28 +20,31 @@ type Props = ComponentProps<"div"> & { }; export function ObjectTypeIcon({ + intl, type, size = 14, backgroundSize, visualizationType, className, ...htmlProps -}: Props) { +}: ObjectTypeIconProps) { const sizes = { size, backgroundSize }; + const label = getObjectTypeLabel(intl, type, visualizationType); return ( - {type === "attribute" ? : null} - {type === "fact" ? : null} - {type === "measure" ? : null} - {type === "analyticalDashboard" ? : null} - {type === "dataSet" ? : null} + {type === "attribute" ? : null} + {type === "fact" ? : null} + {type === "measure" ? : null} + {type === "analyticalDashboard" ? : null} + {type === "dataSet" ? : null} {type === "insight" ? ( ) : null} diff --git a/libs/sdk-ui-catalog/src/objectType/ObjectTypeTooltip.tsx b/libs/sdk-ui-catalog/src/objectType/ObjectTypeTooltip.tsx index db6e91abe2a..ffe75a7aeae 100644 --- a/libs/sdk-ui-catalog/src/objectType/ObjectTypeTooltip.tsx +++ b/libs/sdk-ui-catalog/src/objectType/ObjectTypeTooltip.tsx @@ -1,11 +1,12 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation import type { ReactNode } from "react"; -import { type IntlShape, type MessageDescriptor, defineMessages } from "react-intl"; +import { type IntlShape } from "react-intl"; import { UiTooltip } from "@gooddata/sdk-ui-kit"; +import { getObjectTypeLabel } from "./labels.js"; import type { ObjectType } from "./types.js"; import type { VisualizationType } from "../catalogItem/types.js"; @@ -17,7 +18,7 @@ type Props = { }; export function ObjectTypeTooltip({ intl, type, visualizationType, anchor }: Props) { - const tooltipContent = getTooltipContent(intl, type, visualizationType); + const tooltipContent = getObjectTypeLabel(intl, type, visualizationType); return ( ); } - -const objectTypeMessages: Record = defineMessages({ - analyticalDashboard: { id: "analyticsCatalog.objectType.dashboard.tooltip" }, - insight: { id: "analyticsCatalog.objectType.visualization.tooltip" }, - measure: { id: "analyticsCatalog.objectType.metric.tooltip" }, - attribute: { id: "analyticsCatalog.objectType.attribute.tooltip" }, - fact: { id: "analyticsCatalog.objectType.fact.tooltip" }, - dataSet: { id: "analyticsCatalog.objectType.dateDataset.tooltip" }, -}); - -const visualizationTypeMessages: Record = defineMessages({ - table: { id: "analyticsCatalog.visualizationType.table.tooltip" }, - area: { id: "analyticsCatalog.visualizationType.area.tooltip" }, - treemap: { id: "analyticsCatalog.visualizationType.treemap.tooltip" }, - scatter: { id: "analyticsCatalog.visualizationType.scatter.tooltip" }, - donut: { id: "analyticsCatalog.visualizationType.donut.tooltip" }, - headline: { id: "analyticsCatalog.visualizationType.headline.tooltip" }, - column: { id: "analyticsCatalog.visualizationType.column.tooltip" }, - line: { id: "analyticsCatalog.visualizationType.line.tooltip" }, - pyramid: { id: "analyticsCatalog.visualizationType.pyramid.tooltip" }, - funnel: { id: "analyticsCatalog.visualizationType.funnel.tooltip" }, - heatmap: { id: "analyticsCatalog.visualizationType.heatmap.tooltip" }, - bubble: { id: "analyticsCatalog.visualizationType.bubble.tooltip" }, - pie: { id: "analyticsCatalog.visualizationType.pie.tooltip" }, - bar: { id: "analyticsCatalog.visualizationType.bar.tooltip" }, - combo: { id: "analyticsCatalog.visualizationType.combo.tooltip" }, - bullet: { id: "analyticsCatalog.visualizationType.bullet.tooltip" }, - waterfall: { id: "analyticsCatalog.visualizationType.waterfall.tooltip" }, - dependencywheel: { id: "analyticsCatalog.visualizationType.dependencywheel.tooltip" }, - sankey: { id: "analyticsCatalog.visualizationType.sankey.tooltip" }, - pushpin: { id: "analyticsCatalog.visualizationType.pushpin.tooltip" }, - repeater: { id: "analyticsCatalog.visualizationType.repeater.tooltip" }, -}); - -function getTooltipContent( - intl: IntlShape, - type: ObjectType, - visualizationType: VisualizationType | undefined, -): string { - if (type === "insight" && visualizationType && visualizationType in visualizationTypeMessages) { - return intl.formatMessage(visualizationTypeMessages[visualizationType]); - } - return intl.formatMessage(objectTypeMessages[type]); -} diff --git a/libs/sdk-ui-catalog/src/objectType/labels.ts b/libs/sdk-ui-catalog/src/objectType/labels.ts new file mode 100644 index 00000000000..bfbd3a27b0e --- /dev/null +++ b/libs/sdk-ui-catalog/src/objectType/labels.ts @@ -0,0 +1,50 @@ +// (C) 2025-2026 GoodData Corporation + +import { type IntlShape, type MessageDescriptor, defineMessages } from "react-intl"; + +import type { ObjectType } from "./types.js"; +import type { VisualizationType } from "../catalogItem/types.js"; + +const objectTypeMessages: Record = defineMessages({ + analyticalDashboard: { id: "analyticsCatalog.objectType.dashboard.tooltip" }, + insight: { id: "analyticsCatalog.objectType.visualization.tooltip" }, + measure: { id: "analyticsCatalog.objectType.metric.tooltip" }, + attribute: { id: "analyticsCatalog.objectType.attribute.tooltip" }, + fact: { id: "analyticsCatalog.objectType.fact.tooltip" }, + dataSet: { id: "analyticsCatalog.objectType.dateDataset.tooltip" }, +}); + +const visualizationTypeMessages: Record = defineMessages({ + table: { id: "analyticsCatalog.visualizationType.table.tooltip" }, + area: { id: "analyticsCatalog.visualizationType.area.tooltip" }, + treemap: { id: "analyticsCatalog.visualizationType.treemap.tooltip" }, + scatter: { id: "analyticsCatalog.visualizationType.scatter.tooltip" }, + donut: { id: "analyticsCatalog.visualizationType.donut.tooltip" }, + headline: { id: "analyticsCatalog.visualizationType.headline.tooltip" }, + column: { id: "analyticsCatalog.visualizationType.column.tooltip" }, + line: { id: "analyticsCatalog.visualizationType.line.tooltip" }, + pyramid: { id: "analyticsCatalog.visualizationType.pyramid.tooltip" }, + funnel: { id: "analyticsCatalog.visualizationType.funnel.tooltip" }, + heatmap: { id: "analyticsCatalog.visualizationType.heatmap.tooltip" }, + bubble: { id: "analyticsCatalog.visualizationType.bubble.tooltip" }, + pie: { id: "analyticsCatalog.visualizationType.pie.tooltip" }, + bar: { id: "analyticsCatalog.visualizationType.bar.tooltip" }, + combo: { id: "analyticsCatalog.visualizationType.combo.tooltip" }, + bullet: { id: "analyticsCatalog.visualizationType.bullet.tooltip" }, + waterfall: { id: "analyticsCatalog.visualizationType.waterfall.tooltip" }, + dependencywheel: { id: "analyticsCatalog.visualizationType.dependencywheel.tooltip" }, + sankey: { id: "analyticsCatalog.visualizationType.sankey.tooltip" }, + pushpin: { id: "analyticsCatalog.visualizationType.pushpin.tooltip" }, + repeater: { id: "analyticsCatalog.visualizationType.repeater.tooltip" }, +}); + +export function getObjectTypeLabel( + intl: IntlShape, + type: ObjectType, + visualizationType: VisualizationType | undefined, +): string { + if (type === "insight" && visualizationType && visualizationType in visualizationTypeMessages) { + return intl.formatMessage(visualizationTypeMessages[visualizationType]); + } + return intl.formatMessage(objectTypeMessages[type]); +} diff --git a/libs/sdk-ui-catalog/src/objectType/tests/ObjectTypeIcon.test.tsx b/libs/sdk-ui-catalog/src/objectType/tests/ObjectTypeIcon.test.tsx new file mode 100644 index 00000000000..bbcd789a0cf --- /dev/null +++ b/libs/sdk-ui-catalog/src/objectType/tests/ObjectTypeIcon.test.tsx @@ -0,0 +1,32 @@ +// (C) 2025-2026 GoodData Corporation + +import { render, screen } from "@testing-library/react"; +import { useIntl } from "react-intl"; +import { describe, expect, it } from "vitest"; + +import { TestIntlProvider } from "../../localization/TestIntlProvider.js"; +import { ObjectTypeIcon, type ObjectTypeIconProps } from "../ObjectTypeIcon.js"; + +const wrapper = TestIntlProvider; + +function TestObjectTypeIcon(props: Omit) { + const intl = useIntl(); + return ; +} + +describe("ObjectTypeIcon", () => { + it("renders object type icon with accessible label", () => { + render(, { wrapper }); + expect(screen.getByRole("img", { name: "Dashboard" })).toBeInTheDocument(); + }); + + it("renders insight icon label based on visualization type when available", () => { + render(, { wrapper }); + expect(screen.getByRole("img", { name: "Table" })).toBeInTheDocument(); + }); + + it("falls back to visualization label when visualization type is not provided", () => { + render(, { wrapper }); + expect(screen.getByRole("img", { name: "Visualization" })).toBeInTheDocument(); + }); +}); diff --git a/libs/sdk-ui-catalog/src/quality/QualityIssueObjects.tsx b/libs/sdk-ui-catalog/src/quality/QualityIssueObjects.tsx index 38ba2559a0c..08b2e16b555 100644 --- a/libs/sdk-ui-catalog/src/quality/QualityIssueObjects.tsx +++ b/libs/sdk-ui-catalog/src/quality/QualityIssueObjects.tsx @@ -1,8 +1,9 @@ -// (C) 2025 GoodData Corporation +// (C) 2025-2026 GoodData Corporation import { type MouseEvent } from "react"; import cx from "classnames"; +import { useIntl } from "react-intl"; import { type ISemanticQualityIssueObject } from "@gooddata/sdk-model"; import { UiIcon, UiTooltip } from "@gooddata/sdk-ui-kit"; @@ -17,13 +18,14 @@ type Props = { }; export function QualityIssueObjects({ objects, onObjectClick }: Props) { + const intl = useIntl(); return (