From 30e5787e08f29785a463450df70d2d573bd4c917 Mon Sep 17 00:00:00 2001 From: git-action Date: Mon, 14 Sep 2026 15:21:30 +0000 Subject: [PATCH 1/2] =?UTF-8?q?chore:=20sync=20sdk/=20from=20gdc-ui=20?= =?UTF-8?q?=E2=86=92=20gooddata-ui-sdk/=20(5f11bab)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit risk: low --- NOTICE | 10 +- .../autoinstallers/lint-staged/package.json | 2 +- .../autoinstallers/lint-staged/pnpm-lock.yaml | 164 +- .../SHA_master_1_2026-11-09-11-45.json | 10 + .../SHA_master_1_2026-14-09-12-45.json | 10 + ...tooltip-docs-link_2026-09-14-09-44-59.json | 11 + .../ine-cq-2958_2026-09-11-14-53-39.json | 11 + .../ine-cq-2968_2026-09-11-14-47-14.json | 11 + .../jkd-gdai-2315-fe_2026-09-10-16-30-00.json | 10 + ...bject-permissions_2026-09-11-12-00-00.json | 10 + ...ed-widget-removal_2026-09-10-13-30-00.json | 10 + ...b-menu-zindex-fix_2026-09-11-12-55-50.json | 10 + ...-2812-cancel-error-hygiene_2026-08-13.json | 10 + ...o-lx-2812-error-boundaries_2026-08-13.json | 10 + ...tform-context-keep-mounted_2026-08-13.json | 10 + ...ate-default-theme_2026-09-10-14-00-00.json | 10 + ...opdown-popup-role_2026-09-11-08-00-00.json | 11 + ...ip-width-defaults_2026-09-09-10-00-00.json | 10 + ...xport-mode-in-search_2026-09-11-00-00.json | 10 + .../pvep-master-1_2026-09-11-11-52-06.json | 10 + .../pvep-master-1_2026-09-14-09-25-47.json | 10 + .../pvep-master-2_2026-09-14-11-07-06.json | 10 + .../pvep-master_2026-09-10-08-25-41.json | 10 + .../pvep-master_2026-09-14-07-47-37.json | 10 + .../pvep-master_2026-09-14-10-25-34.json | 10 + ...filters-edit-mode_2026-09-10-14-00-00.json | 10 + common/config/rush/.pnpmfile.cjs | 2 +- common/config/rush/pnpm-lock.yaml | 1506 ++++++++++------- common/config/rush/version-policies.json | 4 +- common/scripts/install-run-rush.js | 2 + common/scripts/install-run.js | 2 + examples/playground/package.json | 9 +- examples/playground/vite.config.ts | 1 - .../examples-template/package.json | 7 +- .../scripts/updateWorkspaceVersion.mjs | 3 +- .../examples-template/vite.config.ts | 1 + .../example-attributefilter/package.json | 7 +- .../scripts/updateWorkspaceVersion.mjs | 4 +- .../example-attributefilter/vite.config.ts | 1 + .../examples/example-chartconfig/package.json | 7 +- .../scripts/updateWorkspaceVersion.mjs | 4 +- .../example-chartconfig/vite.config.ts | 1 + .../examples/example-columnchart/package.json | 7 +- .../scripts/updateWorkspaceVersion.mjs | 4 +- .../example-columnchart/vite.config.ts | 1 + .../examples/example-combochart/package.json | 7 +- .../scripts/updateWorkspaceVersion.mjs | 4 +- .../example-combochart/vite.config.ts | 1 + .../examples/example-dashboard/package.json | 7 +- .../scripts/updateWorkspaceVersion.mjs | 2 + .../examples/example-dashboard/vite.config.ts | 1 + .../examples/example-datefilter/package.json | 7 +- .../scripts/updateWorkspaceVersion.mjs | 4 +- .../example-datefilter/vite.config.ts | 1 + .../example-dependentfilters/package.json | 7 +- .../scripts/updateWorkspaceVersion.mjs | 2 + .../example-dependentfilters/vite.config.ts | 1 + .../examples/example-execute/package.json | 7 +- .../scripts/updateWorkspaceVersion.mjs | 3 +- .../examples/example-execute/vite.config.ts | 1 + .../examples/example-granularity/package.json | 7 +- .../scripts/updateWorkspaceVersion.mjs | 3 +- .../example-granularity/vite.config.ts | 1 + .../examples/example-headline/package.json | 7 +- .../scripts/updateWorkspaceVersion.mjs | 3 +- .../examples/example-headline/vite.config.ts | 1 + .../examples/example-pivottable/package.json | 7 +- .../scripts/updateWorkspaceVersion.mjs | 3 +- .../example-pivottable/vite.config.ts | 1 + .../example-relativedatefilter/package.json | 7 +- .../scripts/updateWorkspaceVersion.mjs | 3 +- .../example-relativedatefilter/vite.config.ts | 1 + .../examples/example-repeater/package.json | 7 +- .../scripts/updateWorkspaceVersion.mjs | 3 +- .../examples/example-repeater/vite.config.ts | 1 + .../sdk-interactive-examples/package.json | 2 +- .../openapi-generator/index.mustache | 2 + libs/api-client-tiger/package.json | 7 +- .../src/endpoints/actions/index.ts | 2 +- .../src/endpoints/authActions/index.ts | 2 +- .../src/endpoints/automation/index.ts | 2 +- .../src/endpoints/entitiesObjects/index.ts | 2 +- .../src/endpoints/execution/index.ts | 2 +- .../src/endpoints/explain/index.ts | 2 +- .../src/endpoints/export/index.ts | 2 +- .../src/endpoints/genAI/index.ts | 2 +- .../src/endpoints/labelElements/index.ts | 2 +- .../src/endpoints/layout/index.ts | 2 +- .../src/endpoints/locationStyle/index.ts | 2 +- .../src/endpoints/profile/index.ts | 2 +- .../src/endpoints/result/index.ts | 4 +- .../src/endpoints/scanModel/index.ts | 2 +- .../src/endpoints/smartFunctions/index.ts | 2 +- .../src/endpoints/userManagement/index.ts | 2 +- .../src/endpoints/validDescendants/index.ts | 2 +- .../src/endpoints/validObjects/index.ts | 2 +- .../src/gd-tiger-model/index.ts | 8 +- .../src/generated/afm-rest-api/index.ts | 3 +- .../src/generated/ai-json-api/index.ts | 3 +- .../src/generated/auth-json-api/index.ts | 3 +- .../generated/automation-json-api/index.ts | 3 +- .../src/generated/export-json-api/index.ts | 3 +- .../src/generated/metadata-json-api/index.ts | 3 +- .../src/generated/result-json-api/index.ts | 3 +- .../src/generated/scan-json-api/index.ts | 3 +- libs/api-client-tiger/src/index.ts | 4 +- libs/sdk-backend-base/.dependency-cruiser.js | 1 - .../api/sdk-backend-base.api.md | 5 +- libs/sdk-backend-base/package.json | 7 +- .../src/cachingBackend/index.ts | 9 +- .../src/decoratedBackend/dashboards.ts | 4 +- .../src/decoratedBackend/insights.ts | 8 +- libs/sdk-backend-base/src/index.ts | 2 +- libs/sdk-backend-base/vitest.config.ts | 1 - .../.dependency-cruiser.js | 1 - libs/sdk-backend-mockingbird/package.json | 7 +- libs/sdk-backend-mockingbird/src/index.ts | 2 +- libs/sdk-backend-mockingbird/vitest.config.ts | 1 - libs/sdk-backend-spi/.dependency-cruiser.js | 1 - .../api/sdk-backend-spi.api.md | 5 +- libs/sdk-backend-spi/package.json | 7 +- libs/sdk-backend-spi/src/common/settings.ts | 2 +- libs/sdk-backend-spi/src/index.ts | 2 +- .../src/workspace/dashboards/index.ts | 3 +- .../src/workspace/insights/index.ts | 4 +- libs/sdk-backend-spi/vitest.config.ts | 1 - libs/sdk-backend-tiger/.dependency-cruiser.js | 1 - libs/sdk-backend-tiger/package.json | 7 +- libs/sdk-backend-tiger/src/backend/index.ts | 8 +- .../src/backend/workspace/dashboards/index.ts | 10 +- .../src/backend/workspace/insights/index.ts | 9 +- .../fromBackend/genAIConvertor.test.ts | 171 ++ .../convertors/fromBackend/genAIConvertor.ts | 268 ++- .../convertors/shared/layoutConverter.test.ts | 88 + .../toBackend/afm/DimensionsConverter.ts | 2 +- libs/sdk-backend-tiger/src/index.ts | 4 +- .../tests/goodmock/snapshot-and-sanitize.mjs | 2 +- libs/sdk-backend-tiger/vitest.config.ts | 1 - .../vitest.integrated.config.ts | 2 +- .../.dependency-cruiser.js | 1 - libs/sdk-code-convertors/.oxlintrc.json | 6 + libs/sdk-code-convertors/package.json | 7 +- .../sdk-code-convertors/python/pyproject.toml | 2 +- .../scripts/check-python-types.mjs | 2 +- .../src/errorContext.test.ts | 39 +- libs/sdk-code-convertors/src/index.ts | 2 +- .../src/utils/configUtils.test.ts | 8 +- .../src/utils/yamlUtils.test.ts | 47 +- .../src/visualisationConversion.test.ts | 20 +- .../src/visualisationErrorContext.test.ts | 124 +- libs/sdk-code-convertors/vitest.config.ts | 1 - libs/sdk-code-schemas/.dependency-cruiser.js | 1 - libs/sdk-code-schemas/eslint.config.ts | 4 +- libs/sdk-code-schemas/package.json | 7 +- .../scripts/refresh-schema.mjs | 2 +- libs/sdk-code-schemas/src/index.ts | 3 +- libs/sdk-code-schemas/vitest.config.ts | 1 - libs/sdk-e2e-utils/package.json | 7 +- libs/sdk-e2e-utils/src/goodmock.ts | 14 +- libs/sdk-e2e-utils/src/index.ts | 2 +- libs/sdk-embedding/.dependency-cruiser.js | 1 - libs/sdk-embedding/package.json | 7 +- libs/sdk-embedding/src/index.ts | 2 +- libs/sdk-embedding/src/internal/index.ts | 2 +- libs/sdk-embedding/vitest.config.ts | 1 - libs/sdk-model/.dependency-cruiser.js | 1 - libs/sdk-model/api/sdk-model.api.md | 25 +- libs/sdk-model/package.json | 7 +- libs/sdk-model/src/dashboard/drillUrl.ts | 84 +- .../sdk-model/src/dashboard/drillUrls.test.ts | 107 ++ libs/sdk-model/src/index.ts | 5 +- libs/sdk-model/src/insight/index.ts | 55 +- libs/sdk-model/src/internal.ts | 7 +- .../attributeDisplayForm/index.test.ts | 2 +- libs/sdk-model/src/reports/brandKit.ts | 8 +- .../src/reports/builtinPageLayouts.ts | 12 +- libs/sdk-model/src/reports/pageLayout.ts | 4 +- libs/sdk-model/src/reports/report.ts | 2 +- libs/sdk-model/src/reports/reports.test.ts | 28 +- libs/sdk-model/src/reports/slot.ts | 8 +- libs/sdk-model/src/reports/variables.ts | 51 +- libs/sdk-model/vitest.config.ts | 1 - .../.dependency-cruiser.js | 1 - .../sdk-pluggable-application-model.api.md | 1 + .../package.json | 7 +- .../src/hostUi.ts | 10 + .../src/index.ts | 2 +- libs/sdk-ui-all/.dependency-cruiser.js | 1 - libs/sdk-ui-all/package.json | 7 +- libs/sdk-ui-all/src/index.ts | 4 +- libs/sdk-ui-application-header/package.json | 7 +- libs/sdk-ui-application-header/src/index.ts | 2 +- libs/sdk-ui-application-header/typings.d.ts | 2 +- .../vitest.config.ts | 1 - libs/sdk-ui-catalog/.dependency-cruiser.js | 1 - libs/sdk-ui-catalog/.oxlintrc.json | 12 +- libs/sdk-ui-catalog/eslint.config.ts | 14 +- libs/sdk-ui-catalog/package.json | 9 +- .../CatalogDetailTabMetadata.tsx | 2 - .../src/catalogItem/CatalogItemLock.tsx | 1 - .../catalogItem/CatalogItemVisibilityIcon.tsx | 1 - libs/sdk-ui-catalog/src/header/Header.tsx | 1 - libs/sdk-ui-catalog/src/index.ts | 2 +- .../src/localization/bundles/ru-RU.json | 4 +- .../src/localization/bundles/zh-HK.json | 16 +- libs/sdk-ui-catalog/vitest.config.ts | 1 - libs/sdk-ui-charts/.dependency-cruiser.js | 1 - libs/sdk-ui-charts/package.json | 9 +- .../src/highcharts/adapter/highcharts.d.ts | 2 +- libs/sdk-ui-charts/src/index.ts | 2 +- libs/sdk-ui-charts/src/internal.ts | 2 +- libs/sdk-ui-charts/src/typings.d.ts | 4 +- libs/sdk-ui-charts/vitest.config.ts | 1 - libs/sdk-ui-dashboard/.dependency-cruiser.js | 1 - .../api/sdk-ui-dashboard.api.md | 130 +- libs/sdk-ui-dashboard/package.json | 9 +- .../dateFilterConfigConverters.ts | 2 +- .../dateFilterOptionMapping.ts | 2 +- .../dateFilterConfig/defaultConfig.ts | 2 +- .../src/_staging/metadata/objRefMap.ts | 2 +- libs/sdk-ui-dashboard/src/index.ts | 4 +- libs/sdk-ui-dashboard/src/internal.ts | 2 +- .../common/validateDrillToCustomUrlParams.ts | 10 +- .../dashboard/saveDashboardHandler.test.ts | 264 ++- .../dashboard/saveDashboardHandler.ts | 113 +- .../drill/displayFormPlaceholderRef.test.ts | 47 + ...etAttributeIdentifiersReplacements.test.ts | 160 ++ .../drill/resolveDrillToCustomUrl.ts | 65 +- .../removeAttributeFiltersHandler.test.ts | 59 + .../removeAttributeFiltersHandler.ts | 3 +- .../removeRestrictedFiltersHandler.test.ts | 71 + .../removeRestrictedFiltersHandler.ts | 75 + .../src/model/commandHandlers/index.ts | 2 + .../drillDisplayFormIdentifiers.test.ts | 50 + .../validation/insightDrillDefinitionUtils.ts | 16 +- .../src/model/commands/base.ts | 1 + .../src/model/commands/filters.ts | 27 + .../src/model/commands/index.ts | 2 + .../dashboardFilterSelectors.test.ts | 28 +- .../filtering/dashboardFilterSelectors.ts | 60 +- .../model/store/insights/insightsSelectors.ts | 71 +- .../model/store/tabs/layout/layoutReducers.ts | 32 +- .../store/tabs/layout/layoutSelectors.test.ts | 101 ++ .../store/tabs/layout/layoutSelectors.ts | 50 + .../src/model/store/ui/uiReducers.ts | 16 + .../src/model/store/ui/uiSelectors.ts | 16 + .../src/model/store/ui/uiState.ts | 8 + .../customizationApis/customizationLogging.ts | 4 +- libs/sdk-ui-dashboard/src/plugins/engine.ts | 2 +- .../AlertingDialogFieldLabelWithTooltip.tsx | 1 - .../automations/alerting/types.ts | 23 + .../contexts/AlertingDialogContext.ts | 13 + .../AlertingManagementDialogContext.ts | 25 + .../contexts/AutomationsContext.ts | 71 + .../contexts/ScheduledEmailDialogContext.ts | 9 + .../ScheduledEmailManagementDialogContext.ts | 5 +- .../DefaultScheduledEmailManagementDialog.tsx | 3 + .../scheduledExportDialogState.shape.test.tsx | 5 +- .../automations/scheduledEmail/types.ts | 15 + .../components/AutomationFiltersSelect.tsx | 1 - .../dateFilterConfigConverters.ts | 2 +- .../dateFilterOptionMapping.ts | 2 +- .../shared/dateFilterConfig/defaultConfig.ts | 2 +- .../automations/shared/filters/index.ts | 2 +- .../DashboardHeader/DashboardHeader.tsx | 6 + .../DefaultDashboardSettingsDialog.tsx | 24 +- .../DrillToUrl/CustomUrlEditor.tsx | 49 +- .../DashboardParametersSection.tsx | 5 +- .../DisplayFormParam.tsx | 3 +- .../InsightParametersSection.tsx | 3 +- .../drill/utils/drillToCustomUrlUtils.ts | 11 +- .../filterBar/filterBar/DefaultFilterBar.tsx | 12 +- .../RestrictedFiltersPlaceholder.test.tsx | 54 +- .../RestrictedFiltersPlaceholder.tsx | 119 +- .../InsightNotSavedDialog.tsx | 72 + .../localization/bundles/de-DE.json | 15 + .../localization/bundles/en-AU.json | 15 + .../localization/bundles/en-GB.json | 15 + .../localization/bundles/en-US.json | 36 +- .../localization/bundles/es-419.json | 15 + .../localization/bundles/es-ES.json | 15 + .../localization/bundles/fi-FI.json | 15 + .../localization/bundles/fr-CA.json | 15 + .../localization/bundles/fr-FR.json | 15 + .../localization/bundles/id-ID.json | 15 + .../localization/bundles/it-IT.json | 15 + .../localization/bundles/ja-JP.json | 15 + .../localization/bundles/ko-KR.json | 15 + .../localization/bundles/nl-NL.json | 15 + .../localization/bundles/pl-PL.json | 15 + .../localization/bundles/pt-BR.json | 15 + .../localization/bundles/pt-PT.json | 15 + .../localization/bundles/ru-RU.json | 21 +- .../localization/bundles/sl-SI.json | 15 + .../localization/bundles/th-TH.json | 15 + .../localization/bundles/tr-TR.json | 15 + .../localization/bundles/uk-UA.json | 15 + .../localization/bundles/vi-VN.json | 15 + .../localization/bundles/zh-HK.json | 201 ++- .../localization/bundles/zh-Hans.json | 15 + .../localization/bundles/zh-Hant.json | 15 + .../settingButton/DefaultSettingButton.tsx | 1 - .../invalidFilteringParameters.test.ts | 84 + ...seInvalidAttributeDisplayFormIdentifier.ts | 36 +- ...seInvalidFilteringParametersIdentifiers.ts | 28 +- .../CustomUiMenuComponents.tsx | 14 + .../DashboardInsightMenuContainer.tsx | 10 +- .../DashboardInsightMenu/index.tsx | 32 +- .../getDefaultInsightEditMenuItems.test.tsx | 49 + .../DashboardWidgetInsightGuard.test.tsx | 24 + .../DashboardWidgetInsightGuard.tsx | 17 +- .../EditableDashboardInsightWidget.tsx | 9 +- .../EditableRestrictedInsightWidget.test.tsx | 154 ++ .../EditableRestrictedInsightWidget.tsx | 81 + .../DefaultWidgetDeleteDialog.test.tsx | 64 + .../DefaultWidgetDeleteDialog.tsx | 13 +- .../presentation/widgetDeleteDialog/types.ts | 6 + .../styles/scss/filterBar.scss | 19 +- .../styles/scss/insightsNotSavedDialog.scss | 26 + libs/sdk-ui-dashboard/styles/scss/main.scss | 1 + libs/sdk-ui-dashboard/vitest.config.ts | 1 - libs/sdk-ui-ext/.dependency-cruiser.js | 1 - libs/sdk-ui-ext/api/sdk-ui-ext.api.md | 3 + libs/sdk-ui-ext/package.json | 9 +- libs/sdk-ui-ext/src/index.ts | 3 +- .../conditionalFormatting/CfSelect.tsx | 4 +- .../conditionalFormattingColors.test.ts | 4 +- libs/sdk-ui-ext/src/internal/index.ts | 2 +- .../src/internal/translations/zh-HK.json | 162 +- .../internal/utils/comparisonHelper.test.ts | 25 +- .../share/objectShareController.helpers.ts | 37 + .../src/share/useCopyObjectPermissions.ts | 41 + libs/sdk-ui-ext/src/typings.d.ts | 4 +- libs/sdk-ui-ext/vitest.config.ts | 1 - libs/sdk-ui-filters/.dependency-cruiser.js | 1 - libs/sdk-ui-filters/package.json | 9 +- .../utils/DateFilterOptionMapping.test.ts | 5 +- libs/sdk-ui-filters/src/index.ts | 2 +- libs/sdk-ui-filters/src/internal.ts | 2 +- libs/sdk-ui-filters/vitest.config.ts | 1 - libs/sdk-ui-gen-ai/package.json | 9 +- libs/sdk-ui-gen-ai/src/components/Input.tsx | 14 +- .../intelligence/panel/IntelligenceFooter.tsx | 1 - .../contents/CustomHyperlink.test.tsx | 194 +++ .../messages/contents/CustomHyperlink.tsx | 20 +- .../ConversationVisualisation.test.tsx | 180 +- .../ConversationVisualisation.tsx | 284 +++- .../components/utils/markdownUtils.test.ts | 7 + .../src/components/utils/markdownUtils.ts | 6 +- libs/sdk-ui-gen-ai/src/context.ts | 2 +- libs/sdk-ui-gen-ai/src/index.ts | 2 +- libs/sdk-ui-gen-ai/src/internal.ts | 2 +- .../src/localization/bundles/zh-HK.json | 36 +- .../store/chatWindow/chatWindowSelectors.ts | 5 + .../store/chatWindow/chatWindowSlice.test.ts | 34 + .../src/store/chatWindow/chatWindowSlice.ts | 19 +- libs/sdk-ui-gen-ai/src/store/localStorage.ts | 26 + .../sideEffects/conversationSession.test.ts | 88 + .../store/sideEffects/conversationSession.ts | 53 + .../src/store/sideEffects/index.ts | 7 + .../store/sideEffects/onChatOpenSync.test.ts | 65 +- .../src/store/sideEffects/onChatOpenSync.ts | 19 +- .../src/store/sideEffects/onThreadLoad.ts | 14 + libs/sdk-ui-geo/.dependency-cruiser.js | 1 - libs/sdk-ui-geo/package.json | 9 +- libs/sdk-ui-geo/src/index.ts | 2 +- libs/sdk-ui-geo/src/internal/index.ts | 2 +- libs/sdk-ui-geo/src/typings.d.ts | 4 +- libs/sdk-ui-geo/vitest.config.ts | 1 - libs/sdk-ui-kit/.dependency-cruiser.js | 1 - libs/sdk-ui-kit/api/sdk-ui-kit.api.md | 3 +- libs/sdk-ui-kit/package.json | 9 +- .../scripts/validateUiComponents.js | 5 +- libs/sdk-ui-kit/src/@ui/@types/icon.ts | 1 + .../src/@ui/UiDropdown/UiDropdown.test.tsx | 71 + .../src/@ui/UiDropdown/UiDropdown.tsx | 17 +- libs/sdk-ui-kit/src/@ui/UiDropdown/types.ts | 6 + libs/sdk-ui-kit/src/@ui/UiIcon/icons.tsx | 7 + .../UiMenuCustomContentKeyboard.test.tsx | 79 + .../sdk-ui-kit/src/@ui/UiTabs/UiTabs.test.tsx | 13 + .../DefaultUiTabsAllTabs.tsx | 5 +- .../DefaultUiTabsAllTabsButton.tsx | 5 +- .../DefaultUiTabsTabActions.tsx | 6 +- .../sdk-ui-kit/src/@ui/UiTags/UiTags.test.tsx | 22 +- .../src/@ui/UiTooltip/UiTooltip.scss | 5 + .../src/@ui/UiTooltip/UiTooltip.test.tsx | 33 + .../src/@ui/UiTooltip/UiTooltip.tsx | 4 + libs/sdk-ui-kit/src/@ui/UiTooltip/types.ts | 6 +- libs/sdk-ui-kit/src/@ui/defaultTheme.scss | 10 +- .../src/Dialog/CsvDelimiterPicker.tsx | 4 +- .../src/List/DateDatasetsListItem.test.tsx | 5 +- .../src/Menu/__snapshots__/Menu.test.tsx.snap | 6 +- .../positioning/PositionedMenuContent.tsx | 4 + .../src/RecurrenceForm/utils/utils.test.ts | 76 +- libs/sdk-ui-kit/src/index.ts | 2 +- libs/sdk-ui-kit/src/typings.d.ts | 2 +- .../sdk-ui-kit/src/utils/domUtilities.test.ts | 67 +- libs/sdk-ui-kit/src/utils/domUtilities.ts | 9 +- libs/sdk-ui-kit/vitest.config.ts | 1 - libs/sdk-ui-loaders/.dependency-cruiser.js | 1 - libs/sdk-ui-loaders/package.json | 7 +- .../src/dashboard/dashboardLoader.tsx | 10 +- .../dynamicComponentLoaders.ts | 2 +- .../src/dashboard/useDashboardLoader.ts | 6 +- libs/sdk-ui-loaders/src/index.ts | 2 +- libs/sdk-ui-pivot/.dependency-cruiser.js | 1 - libs/sdk-ui-pivot/package.json | 9 +- .../eventHandlers/sortingEventHandlers.ts | 2 +- .../src/impl/stickyRowHandler.test.ts | 20 +- libs/sdk-ui-pivot/src/impl/tableFacade.ts | 10 +- .../impl/updates/componentUpdateAnalyzer.ts | 11 +- libs/sdk-ui-pivot/src/index.ts | 2 +- libs/sdk-ui-pivot/src/next/index.ts | 2 +- .../src/next/types/conditionalFormatting.ts | 2 +- libs/sdk-ui-pivot/src/typings.d.ts | 4 +- libs/sdk-ui-pivot/vitest.config.ts | 1 - .../.dependency-cruiser.js | 1 - .../sdk-ui-pluggable-application/package.json | 7 +- .../sdk-ui-pluggable-application/src/index.ts | 2 +- .../api/sdk-ui-pluggable-host.api.md | 35 + libs/sdk-ui-pluggable-host/package.json | 9 +- .../src/components/HostErrorBoundary.test.tsx | 69 + .../src/components/HostErrorBoundary.tsx | 93 + .../src/components/HostUiContainer.tsx | 78 +- .../src/components/Root.tsx | 10 +- libs/sdk-ui-pluggable-host/src/debug.ts | 2 +- libs/sdk-ui-pluggable-host/src/index.ts | 5 + .../loadPlatformContext.test.ts | 35 + .../platformContext/loadPlatformContext.ts | 24 +- .../useLoadPlatformContext.test.tsx | 132 ++ .../platformContext/useLoadPlatformContext.ts | 73 +- .../src/translations/zh-HK.json | 4 +- libs/sdk-ui-pluggable-host/src/typings.d.ts | 2 +- .../src/ui/DefaultHostUi.tsx | 106 +- libs/sdk-ui-pluggable-host/vitest.config.ts | 1 - .../.dependency-cruiser.js | 1 - libs/sdk-ui-semantic-search/package.json | 9 +- libs/sdk-ui-semantic-search/src/index.ts | 2 +- libs/sdk-ui-semantic-search/src/internal.ts | 2 +- .../src/localization/bundles/zh-HK.json | 6 +- libs/sdk-ui-semantic-search/vitest.config.ts | 1 - libs/sdk-ui-tests-app/.dependency-cruiser.js | 1 - libs/sdk-ui-tests-app/package.json | 9 +- libs/sdk-ui-tests-app/src/backend.ts | 2 +- libs/sdk-ui-tests-app/vite.config.ts | 3 +- libs/sdk-ui-tests-e2e/package.json | 7 +- .../playwright/playwright.config.ts | 1 - libs/sdk-ui-tests-e2e/rolldown.config.ts | 1 - .../package.json | 7 +- .../.dependency-cruiser.js | 1 - libs/sdk-ui-tests-scenarios/package.json | 7 +- libs/sdk-ui-tests-scenarios/src/index.ts | 2 +- libs/sdk-ui-tests-scenarios/vitest.config.ts | 1 - libs/sdk-ui-tests-storybook/.oxlintrc.json | 6 + .../sdk-ui-tests-storybook/.storybook/main.js | 2 +- .../.storybook/preview.js | 2 +- libs/sdk-ui-tests-storybook/eslint.config.ts | 6 - ...ull-featured_icon_0_document_0_desktop.png | Bin 133220 -> 133567 bytes ...i_UiIcon_-_themed_0_document_0_desktop.png | Bin 133029 -> 133132 bytes libs/sdk-ui-tests-storybook/package.json | 7 +- .../scripts/neobackstop-cleanup-artifacts.cjs | 23 +- .../stories/_infra/toBackstop.ts | 8 +- .../axis/LabelSubsection.stories.tsx | 2 +- .../legend/LegendSection.stories.tsx | 2 +- .../TextFilter.stories.tsx | 2 +- .../kit/Dialog/Dialog.stories.tsx | 2 +- .../EditableLabelExamples.stories.tsx | 2 +- .../NumericInput.stories.tsx | 2 +- .../kit/Form/Form.stories.tsx | 2 +- .../kit/Header/Header.stories.tsx | 4 +- .../kit/Input/Input.stories.tsx | 6 +- .../stories/visual-regression/ui/assets.d.ts | 2 +- .../pivotTable/index.stories.tsx | 2 +- libs/sdk-ui-tests-storybook/vite.config.ts | 1 - .../.dependency-cruiser.js | 1 - libs/sdk-ui-theme-provider/package.json | 7 +- libs/sdk-ui-theme-provider/src/index.ts | 2 +- libs/sdk-ui-theme-provider/src/internal.ts | 2 +- .../src/variablesSpec/allThemeCssVariables.ts | 2 + .../src/variablesSpec/internal/tooltip.ts | 10 + .../src/variablesSpec/validate/log.ts | 4 +- .../variablesSpec/validate/validate.test.ts | 21 + .../src/variablesSpec/validate/validate.ts | 28 +- libs/sdk-ui-theme-provider/vitest.config.ts | 1 - .../sdk-ui-vis-commons/.dependency-cruiser.js | 1 - libs/sdk-ui-vis-commons/package.json | 9 +- libs/sdk-ui-vis-commons/src/index.ts | 2 +- libs/sdk-ui-vis-commons/vitest.config.ts | 1 - .../.dependency-cruiser.js | 1 - libs/sdk-ui-web-components/package.json | 7 +- .../sdk-ui-web-components/scripts/copy-dts.js | 5 +- libs/sdk-ui-web-components/src/index.ts | 2 +- .../sdk-ui-web-components/src/tigerBackend.ts | 5 +- libs/sdk-ui-web-components/vite.config.ts | 1 - libs/sdk-ui-web-components/vitest.config.ts | 1 - libs/sdk-ui/package.json | 7 +- .../src/base/errors/errorHandling.test.ts | 7 + libs/sdk-ui/src/base/errors/errorHandling.ts | 2 + .../src/base/localization/bundles/de-DE.json | 3 + .../src/base/localization/bundles/en-AU.json | 3 + .../src/base/localization/bundles/en-GB.json | 3 + .../src/base/localization/bundles/es-419.json | 3 + .../src/base/localization/bundles/es-ES.json | 3 + .../src/base/localization/bundles/fi-FI.json | 3 + .../src/base/localization/bundles/fr-CA.json | 3 + .../src/base/localization/bundles/fr-FR.json | 3 + .../src/base/localization/bundles/id-ID.json | 3 + .../src/base/localization/bundles/it-IT.json | 3 + .../src/base/localization/bundles/ja-JP.json | 3 + .../src/base/localization/bundles/ko-KR.json | 3 + .../src/base/localization/bundles/nl-NL.json | 3 + .../src/base/localization/bundles/pl-PL.json | 3 + .../src/base/localization/bundles/pt-BR.json | 3 + .../src/base/localization/bundles/pt-PT.json | 3 + .../src/base/localization/bundles/ru-RU.json | 3 + .../src/base/localization/bundles/sl-SI.json | 3 + .../src/base/localization/bundles/th-TH.json | 3 + .../src/base/localization/bundles/tr-TR.json | 3 + .../src/base/localization/bundles/uk-UA.json | 3 + .../src/base/localization/bundles/vi-VN.json | 3 + .../src/base/localization/bundles/zh-HK.json | 253 +-- .../base/localization/bundles/zh-Hans.json | 3 + .../base/localization/bundles/zh-Hant.json | 5 +- .../sdk-ui/src/base/react/useDebugEquality.ts | 6 +- .../src/base/react/validation/types.test.ts | 2 +- libs/sdk-ui/src/index.ts | 2 +- libs/sdk-ui/src/internal.ts | 2 +- libs/sdk-ui/src/typings.d.ts | 2 +- libs/util/.dependency-cruiser.js | 1 - libs/util/package.json | 7 +- libs/util/src/index.ts | 2 +- libs/util/src/testUtils.ts | 2 +- libs/util/vitest.config.ts | 1 - .../pluggable-module/harness/package.json | 9 +- .../pluggable-module/harness/vite.config.ts | 3 +- .../pluggable-module/module/package.json | 9 +- .../pluggable-module/module/src/index.ts | 2 +- .../pluggable-module/module/vite.config.ts | 3 +- .../pluggable-module/module/vitest.config.ts | 1 - tools/app-toolkit/.dependency-cruiser.js | 1 - tools/app-toolkit/.oxlintrc.json | 3 + tools/app-toolkit/package.json | 7 +- .../scripts/preparePackageJson.mjs | 8 +- .../app-toolkit/src/_base/terminal/loggers.ts | 6 +- tools/app-toolkit/src/typings.d.ts | 4 +- tools/catalog-export/.dependency-cruiser.js | 1 - tools/catalog-export/package.json | 7 +- tools/catalog-export/src/cli/loggers.ts | 2 +- tools/catalog-export/src/typings.d.ts | 4 +- tools/catalog-export/vitest.config.ts | 1 - tools/create-pluggable-module/.oxlintrc.json | 3 + .../create-pluggable-module/eslint.config.ts | 6 - tools/create-pluggable-module/package.json | 7 +- .../__snapshots__/snapshot.test.ts.snap | 11 +- tools/create-pluggable-module/src/index.ts | 2 +- .../create-pluggable-module/vitest.config.ts | 1 - .../.dependency-cruiser.js | 1 - .../dashboard-plugin-template/.oxlintrc.json | 11 +- .../eslint.config.ts | 7 - tools/dashboard-plugin-template/package.json | 7 +- .../src/plugin/Plugin.tsx | 2 +- .../src/plugin_engine/index.ts | 2 +- .../webpack.config.cjs | 2 +- tools/eslint-config/PACKAGES_V9.md | 3 +- tools/eslint-config/PACKAGES_V9_OXLINT.md | 2 +- tools/eslint-config/package.json | 4 +- tools/eslint-config/scripts/updatePackage.ts | 1 - .../src/configurations/eslint.ts | 36 +- .../src/configurations/playwright.ts | 12 +- .../src/configurations/vitest.ts | 7 +- tools/i18n-toolkit/.dependency-cruiser.js | 1 - tools/i18n-toolkit/package.json | 7 +- tools/i18n-toolkit/src/utils/console.ts | 2 +- tools/i18n-toolkit/validate-esm.cjs | 2 +- tools/lint-config/package.json | 2 +- .../src/configurations/chai-friendly.ts | 3 +- .../lint-config/src/configurations/eslint.ts | 57 +- .../src/configurations/no-barrel-files.ts | 6 +- .../src/configurations/playwright.ts | 7 +- .../lint-config/src/configurations/sonarjs.ts | 6 +- .../src/configurations/storybook.ts | 49 +- .../src/configurations/typescript.ts | 64 +- .../lint-config/src/configurations/vitest.ts | 7 +- tools/lint-config/src/index.ts | 6 +- tools/lint-config/src/types.ts | 7 + tools/lint-config/src/utils/scopeRules.ts | 2 +- tools/mock-handling/.dependency-cruiser.js | 1 - tools/mock-handling/.oxlintrc.json | 3 + tools/mock-handling/eslint.config.ts | 11 +- tools/mock-handling/package.json | 7 +- tools/mock-handling/src/index.ts | 2 +- tools/mock-handling/src/typings.d.ts | 4 +- tools/oxlint-config/PACKAGES.md | 4 +- tools/oxlint-config/package.json | 12 +- tools/oxlint-config/scripts/updatePackage.ts | 2 - .../src/configurations/eslint.ts | 33 +- .../src/configurations/playwright.ts | 7 +- .../src/configurations/typescript.ts | 6 +- .../src/configurations/vitest.ts | 3 +- tools/plugin-toolkit/.dependency-cruiser.js | 1 - tools/plugin-toolkit/package.json | 7 +- .../scripts/preparePackageJson.mjs | 9 +- .../src/_base/terminal/loggers.ts | 6 +- .../src/inspectCmds/inspectDashboard.ts | 3 +- .../plugin-toolkit/src/inspectCmds/output.ts | 5 +- .../src/listCmds/listCmdAction.ts | 2 +- tools/plugin-toolkit/src/typings.d.ts | 4 +- .../react-app-template/.dependency-cruiser.js | 1 - tools/react-app-template/package.json | 7 +- .../src/harness/PluginLoader.tsx | 27 +- .../.dependency-cruiser.js | 1 - tools/reference-workspace-mgmt/package.json | 7 +- .../.dependency-cruiser.js | 1 - tools/reference-workspace/package.json | 7 +- tools/reference-workspace/src/index.ts | 2 +- tools/reference-workspace/src/typings.d.ts | 6 +- tools/stylelint-config/package.json | 2 +- 617 files changed, 8313 insertions(+), 2611 deletions(-) create mode 100644 common/changes/@gooddata/sdk-ui-all/SHA_master_1_2026-11-09-11-45.json create mode 100644 common/changes/@gooddata/sdk-ui-all/SHA_master_1_2026-14-09-12-45.json create mode 100644 common/changes/@gooddata/sdk-ui-all/ine-cq-2825-timezone-tooltip-docs-link_2026-09-14-09-44-59.json create mode 100644 common/changes/@gooddata/sdk-ui-all/ine-cq-2958_2026-09-11-14-53-39.json create mode 100644 common/changes/@gooddata/sdk-ui-all/ine-cq-2968_2026-09-11-14-47-14.json create mode 100644 common/changes/@gooddata/sdk-ui-all/jkd-gdai-2315-fe_2026-09-10-16-30-00.json create mode 100644 common/changes/@gooddata/sdk-ui-all/jsc-f1-2861-copy-object-permissions_2026-09-11-12-00-00.json create mode 100644 common/changes/@gooddata/sdk-ui-all/mkn-olp-restricted-widget-removal_2026-09-10-13-30-00.json create mode 100644 common/changes/@gooddata/sdk-ui-all/pb-menu-zindex-fix_2026-09-11-12-55-50.json create mode 100644 common/changes/@gooddata/sdk-ui-all/pdo-lx-2812-cancel-error-hygiene_2026-08-13.json create mode 100644 common/changes/@gooddata/sdk-ui-all/pdo-lx-2812-error-boundaries_2026-08-13.json create mode 100644 common/changes/@gooddata/sdk-ui-all/pdo-lx-2812-platform-context-keep-mounted_2026-08-13.json create mode 100644 common/changes/@gooddata/sdk-ui-all/pdo-regenerate-default-theme_2026-09-10-14-00-00.json create mode 100644 common/changes/@gooddata/sdk-ui-all/pdo-uidropdown-popup-role_2026-09-11-08-00-00.json create mode 100644 common/changes/@gooddata/sdk-ui-all/pdo-uitooltip-width-defaults_2026-09-09-10-00-00.json create mode 100644 common/changes/@gooddata/sdk-ui-all/pkoz-lx-2965-host-export-mode-in-search_2026-09-11-00-00.json create mode 100644 common/changes/@gooddata/sdk-ui-all/pvep-master-1_2026-09-11-11-52-06.json create mode 100644 common/changes/@gooddata/sdk-ui-all/pvep-master-1_2026-09-14-09-25-47.json create mode 100644 common/changes/@gooddata/sdk-ui-all/pvep-master-2_2026-09-14-11-07-06.json create mode 100644 common/changes/@gooddata/sdk-ui-all/pvep-master_2026-09-10-08-25-41.json create mode 100644 common/changes/@gooddata/sdk-ui-all/pvep-master_2026-09-14-07-47-37.json create mode 100644 common/changes/@gooddata/sdk-ui-all/pvep-master_2026-09-14-10-25-34.json create mode 100644 common/changes/@gooddata/sdk-ui-all/scv-restricted-filters-edit-mode_2026-09-10-14-00-00.json create mode 100644 libs/sdk-backend-tiger/src/convertors/shared/layoutConverter.test.ts create mode 100644 libs/sdk-ui-dashboard/src/model/commandHandlers/drill/displayFormPlaceholderRef.test.ts create mode 100644 libs/sdk-ui-dashboard/src/model/commandHandlers/drill/getAttributeIdentifiersReplacements.test.ts create mode 100644 libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/removeAttributeFiltersHandler.test.ts create mode 100644 libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/removeRestrictedFiltersHandler.test.ts create mode 100644 libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/removeRestrictedFiltersHandler.ts create mode 100644 libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/validation/drillDisplayFormIdentifiers.test.ts create mode 100644 libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutSelectors.test.ts create mode 100644 libs/sdk-ui-dashboard/src/presentation/insightNotSavedDialog/InsightNotSavedDialog.tsx create mode 100644 libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillTargets/invalidFilteringParameters.test.ts create mode 100644 libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/getDefaultInsightEditMenuItems.test.tsx create mode 100644 libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/EditableRestrictedInsightWidget.test.tsx create mode 100644 libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/EditableRestrictedInsightWidget.tsx create mode 100644 libs/sdk-ui-dashboard/src/presentation/widgetDeleteDialog/DefaultWidgetDeleteDialog.test.tsx create mode 100644 libs/sdk-ui-dashboard/styles/scss/insightsNotSavedDialog.scss create mode 100644 libs/sdk-ui-ext/src/share/useCopyObjectPermissions.ts create mode 100644 libs/sdk-ui-gen-ai/src/components/messages/contents/CustomHyperlink.test.tsx create mode 100644 libs/sdk-ui-gen-ai/src/store/sideEffects/conversationSession.test.ts create mode 100644 libs/sdk-ui-gen-ai/src/store/sideEffects/conversationSession.ts create mode 100644 libs/sdk-ui-kit/src/@ui/UiDropdown/UiDropdown.test.tsx create mode 100644 libs/sdk-ui-kit/src/@ui/UiMenu/UiMenuCustomContentKeyboard.test.tsx create mode 100644 libs/sdk-ui-kit/src/@ui/UiTooltip/UiTooltip.test.tsx create mode 100644 libs/sdk-ui-pluggable-host/src/components/HostErrorBoundary.test.tsx create mode 100644 libs/sdk-ui-pluggable-host/src/components/HostErrorBoundary.tsx create mode 100644 libs/sdk-ui-pluggable-host/src/platformContext/useLoadPlatformContext.test.tsx create mode 100644 libs/sdk-ui-theme-provider/src/variablesSpec/internal/tooltip.ts diff --git a/NOTICE b/NOTICE index ae98f185ea7..c32e59c63c7 100644 --- a/NOTICE +++ b/NOTICE @@ -7,9 +7,9 @@ The following 3rd-party software packages may be used by or distributed with gooddata-ui-sdk. Any information relevant to third-party vendors listed below are collected using common, reasonable means. -Date generated: 2026-9-10 +Date generated: 2026-9-14 -Revision ID: 134c47a0c4df31513dbb70f1253bfcf3a9a37ca9 +Revision ID: 2ddc75aa28e022016649b61c0188b349322c1327 ================================================================================ ================================================================================ @@ -43212,7 +43212,7 @@ MIT Authors: richiebendall@gmail.com Package Manager: NPM -Project URL: https://www.npmjs.com/package/char-regex +Project URL: https://github.com/Richienb/char-regex#readme Package Download URL: https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz Dependency Path: remark-emoji > node-emoji > char-regex File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml @@ -48198,7 +48198,7 @@ MIT Authors: tituswormer@gmail.com Package Manager: NPM -Project URL: https://www.npmjs.com/package/micromark-extension-gfm-table +Project URL: https://github.com/micromark/micromark-extension-gfm-table#readme Package Download URL: https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz Dependency Path: remark-gfm > micromark-extension-gfm > micromark-extension-gfm-table File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml @@ -64353,4 +64353,4 @@ File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -Report Generated by FOSSA on 2026-9-10 \ No newline at end of file +Report Generated by FOSSA on 2026-9-14 \ No newline at end of file diff --git a/common/autoinstallers/lint-staged/package.json b/common/autoinstallers/lint-staged/package.json index 0832c2fcbbd..8aa4971c39e 100644 --- a/common/autoinstallers/lint-staged/package.json +++ b/common/autoinstallers/lint-staged/package.json @@ -6,6 +6,6 @@ "@gooddata/frontend-npm-scripts": "^1.4.0", "lint-staged": "^10.5.4", "oxfmt": "0.66.0", - "oxlint": "1.57.0" + "oxlint": "1.58.0" } } diff --git a/common/autoinstallers/lint-staged/pnpm-lock.yaml b/common/autoinstallers/lint-staged/pnpm-lock.yaml index f447bb3ef93..ae9587c874b 100644 --- a/common/autoinstallers/lint-staged/pnpm-lock.yaml +++ b/common/autoinstallers/lint-staged/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0 + specifier: 1.58.0 + version: 1.58.0 packages: @@ -149,116 +149,116 @@ packages: cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.57.0': - resolution: {integrity: sha512-C7EiyfAJG4B70496eV543nKiq5cH0o/xIh/ufbjQz3SIvHhlDDsyn+mRFh+aW8KskTyUpyH2LGWL8p2oN6bl1A==} + '@oxlint/binding-android-arm-eabi@1.58.0': + resolution: {integrity: sha512-1T7UN3SsWWxpWyWGn1cT3ASNJOo+pI3eUkmEl7HgtowapcV8kslYpFQcYn431VuxghXakPNlbjRwhqmR37PFOg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.57.0': - resolution: {integrity: sha512-9i80AresjZ/FZf5xK8tKFbhQnijD4s1eOZw6/FHUwD59HEZbVLRc2C88ADYJfLZrF5XofWDiRX/Ja9KefCLy7w==} + '@oxlint/binding-android-arm64@1.58.0': + resolution: {integrity: sha512-GryzujxuiRv2YFF7bRy8mKcxlbuAN+euVUtGJt9KKbLT8JBUIosamVhcthLh+VEr6KE6cjeVMAQxKAzJcoN7dg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.57.0': - resolution: {integrity: sha512-0eUfhRz5L2yKa9I8k3qpyl37XK3oBS5BvrgdVIx599WZK63P8sMbg+0s4IuxmIiZuBK68Ek+Z+gcKgeYf0otsg==} + '@oxlint/binding-darwin-arm64@1.58.0': + resolution: {integrity: sha512-7/bRSJIwl4GxeZL9rPZ11anNTyUO9epZrfEJH/ZMla3+/gbQ6xZixh9nOhsZ0QwsTW7/5J2A/fHbD1udC5DQQA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.57.0': - resolution: {integrity: sha512-UvrSuzBaYOue+QMAcuDITe0k/Vhj6KZGjfnI6x+NkxBTke/VoM7ZisaxgNY0LWuBkTnd1OmeQfEQdQ48fRjkQg==} + '@oxlint/binding-darwin-x64@1.58.0': + resolution: {integrity: sha512-EqdtJSiHweS2vfILNrpyJ6HUwpEq2g7+4Zx1FPi4hu3Hu7tC3znF6ufbXO8Ub2LD4mGgznjI7kSdku9NDD1Mkg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.57.0': - resolution: {integrity: sha512-wtQq0dCoiw4bUwlsNVDJJ3pxJA218fOezpgtLKrbQqUtQJcM9yP8z+I9fu14aHg0uyAxIY+99toL6uBa2r7nxA==} + '@oxlint/binding-freebsd-x64@1.58.0': + resolution: {integrity: sha512-VQt5TH4M42mY20F545G637RKxV/yjwVtKk2vfXuazfReSIiuvWBnv+FVSvIV5fKVTJNjt3GSJibh6JecbhGdBw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.57.0': - resolution: {integrity: sha512-qxFWl2BBBFcT4djKa+OtMdnLgoHEJXpqjyGwz8OhW35ImoCwR5qtAGqApNYce5260FQqoAHW8S8eZTjiX67Tsg==} + '@oxlint/binding-linux-arm-gnueabihf@1.58.0': + resolution: {integrity: sha512-fBYcj4ucwpAtjJT3oeBdFBYKvNyjRSK+cyuvBOTQjh0jvKp4yeA4S/D0IsCHus/VPaNG5L48qQkh+Vjy3HL2/Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.57.0': - resolution: {integrity: sha512-SQoIsBU7J0bDW15/f0/RvxHfY3Y0+eB/caKBQtNFbuerTiA6JCYx9P1MrrFTwY2dTm/lMgTSgskvCEYk2AtG/Q==} + '@oxlint/binding-linux-arm-musleabihf@1.58.0': + resolution: {integrity: sha512-0BeuFfwlUHlJ1xpEdSD1YO3vByEFGPg36uLjK1JgFaxFb4W6w17F8ET8sz5cheZ4+x5f2xzdnRrrWv83E3Yd8g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.57.0': - resolution: {integrity: sha512-jqxYd1W6WMeozsCmqe9Rzbu3SRrGTyGDAipRlRggetyYbUksJqJKvUNTQtZR/KFoJPb+grnSm5SHhdWrywv3RQ==} + '@oxlint/binding-linux-arm64-gnu@1.58.0': + resolution: {integrity: sha512-TXlZgnPTlxrQzxG9ZXU7BNwx1Ilrr17P3GwZY0If2EzrinqRH3zXPc3HrRcBJgcsoZNMuNL5YivtkJYgp467UQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@oxlint/binding-linux-arm64-musl@1.57.0': - resolution: {integrity: sha512-i66WyEPVEvq9bxRUCJ/MP5EBfnTDN3nhwEdFZFTO5MmLLvzngfWEG3NSdXQzTT3vk5B9i6C2XSIYBh+aG6uqyg==} + '@oxlint/binding-linux-arm64-musl@1.58.0': + resolution: {integrity: sha512-zSoYRo5dxHLcUx93Stl2hW3hSNjPt99O70eRVWt5A1zwJ+FPjeCCANCD2a9R4JbHsdcl11TIQOjyigcRVOH2mw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@oxlint/binding-linux-ppc64-gnu@1.57.0': - resolution: {integrity: sha512-oMZDCwz4NobclZU3pH+V1/upVlJZiZvne4jQP+zhJwt+lmio4XXr4qG47CehvrW1Lx2YZiIHuxM2D4YpkG3KVA==} + '@oxlint/binding-linux-ppc64-gnu@1.58.0': + resolution: {integrity: sha512-NQ0U/lqxH2/VxBYeAIvMNUK1y0a1bJ3ZicqkF2c6wfakbEciP9jvIE4yNzCFpZaqeIeRYaV7AVGqEO1yrfVPjA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] - '@oxlint/binding-linux-riscv64-gnu@1.57.0': - resolution: {integrity: sha512-uoBnjJ3MMEBbfnWC1jSFr7/nSCkcQYa72NYoNtLl1imshDnWSolYCjzb8LVCwYCCfLJXD+0gBLD7fyC14c0+0g==} + '@oxlint/binding-linux-riscv64-gnu@1.58.0': + resolution: {integrity: sha512-X9J+kr3gIC9FT8GuZt0ekzpNUtkBVzMVU4KiKDSlocyQuEgi3gBbXYN8UkQiV77FTusLDPsovjo95YedHr+3yg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] - '@oxlint/binding-linux-riscv64-musl@1.57.0': - resolution: {integrity: sha512-BdrwD7haPZ8a9KrZhKJRSj6jwCor+Z8tHFZ3PT89Y3Jq5v3LfMfEePeAmD0LOTWpiTmzSzdmyw9ijneapiVHKQ==} + '@oxlint/binding-linux-riscv64-musl@1.58.0': + resolution: {integrity: sha512-CDze3pi1OO3Wvb/QsXjmLEY4XPKGM6kIo82ssNOgmcl1IdndF9VSGAE38YLhADWmOac7fjqhBw82LozuUVxD0Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] - '@oxlint/binding-linux-s390x-gnu@1.57.0': - resolution: {integrity: sha512-BNs+7ZNsRstVg2tpNxAXfMX/Iv5oZh204dVyb8Z37+/gCh+yZqNTlg6YwCLIMPSk5wLWIGOaQjT0GUOahKYImw==} + '@oxlint/binding-linux-s390x-gnu@1.58.0': + resolution: {integrity: sha512-b/89glbxFaEAcA6Uf1FvCNecBJEgcUTsV1quzrqXM/o4R1M4u+2KCVuyGCayN2UpsRWtGGLb+Ver0tBBpxaPog==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] - '@oxlint/binding-linux-x64-gnu@1.57.0': - resolution: {integrity: sha512-AghS18w+XcENcAX0+BQGLiqjpqpaxKJa4cWWP0OWNLacs27vHBxu7TYkv9LUSGe5w8lOJHeMxcYfZNOAPqw2bg==} + '@oxlint/binding-linux-x64-gnu@1.58.0': + resolution: {integrity: sha512-0/yYpkq9VJFCEcuRlrViGj8pJUFFvNS4EkEREaN7CB1EcLXJIaVSSa5eCihwBGXtOZxhnblWgxks9juRdNQI7w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@oxlint/binding-linux-x64-musl@1.57.0': - resolution: {integrity: sha512-E/FV3GB8phu/Rpkhz5T96hAiJlGzn91qX5yj5gU754P5cmVGXY1Jw/VSjDSlZBCY3VHjsVLdzgdkJaomEmcNOg==} + '@oxlint/binding-linux-x64-musl@1.58.0': + resolution: {integrity: sha512-hr6FNvmcAXiH+JxSvaJ4SJ1HofkdqEElXICW9sm3/Rd5eC3t7kzvmLyRAB3NngKO2wzXRCAm4Z/mGWfrsS4X8w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@oxlint/binding-openharmony-arm64@1.57.0': - resolution: {integrity: sha512-xvZ2yZt0nUVfU14iuGv3V25jpr9pov5N0Wr28RXnHFxHCRxNDMtYPHV61gGLhN9IlXM96gI4pyYpLSJC5ClLCQ==} + '@oxlint/binding-openharmony-arm64@1.58.0': + resolution: {integrity: sha512-R+O368VXgRql1K6Xar+FEo7NEwfo13EibPMoTv3sesYQedRXd6m30Dh/7lZMxnrQVFfeo4EOfYIP4FpcgWQNHg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.57.0': - resolution: {integrity: sha512-Z4D8Pd0AyHBKeazhdIXeUUy5sIS3Mo0veOlzlDECg6PhRRKgEsBJCCV1n+keUZtQ04OP+i7+itS3kOykUyNhDg==} + '@oxlint/binding-win32-arm64-msvc@1.58.0': + resolution: {integrity: sha512-Q0FZiAY/3c4YRj4z3h9K1PgaByrifrfbBoODSeX7gy97UtB7pySPUQfC2B/GbxWU6k7CzQrRy5gME10PltLAFQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.57.0': - resolution: {integrity: sha512-StOZ9nFMVKvevicbQfql6Pouu9pgbeQnu60Fvhz2S6yfMaii+wnueLnqQ5I1JPgNF0Syew4voBlAaHD13wH6tw==} + '@oxlint/binding-win32-ia32-msvc@1.58.0': + resolution: {integrity: sha512-Y8FKBABrSPp9H0QkRLHDHOSUgM/309a3IvOVgPcVxYcX70wxJrk608CuTg7w+C6vEd724X5wJoNkBcGYfH7nNQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.57.0': - resolution: {integrity: sha512-6PuxhYgth8TuW0+ABPOIkGdBYw+qYGxgIdXPHSVpiCDm+hqTTWCmC739St1Xni0DJBt8HnSHTG67i1y6gr8qrA==} + '@oxlint/binding-win32-x64-msvc@1.58.0': + resolution: {integrity: sha512-bCn5rbiz5My+Bj7M09sDcnqW0QJyINRVxdZ65x1/Y2tGrMwherwK/lpk+HRQCKvXa8pcaQdF5KY5j54VGZLwNg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -497,12 +497,12 @@ packages: vite-plus: optional: true - oxlint@1.57.0: - resolution: {integrity: sha512-DGFsuBX5MFZX9yiDdtKjTrYPq45CZ8Fft6qCltJITYZxfwYjVdGf/6wycGYTACloauwIPxUnYhBVeZbHvleGhw==} + oxlint@1.58.0: + resolution: {integrity: sha512-t4s9leczDMqlvOSjnbCQe7gtoLkWgBGZ7sBdCJ9EOj5IXFSG/X7OAzK4yuH4iW+4cAYe8kLFbC8tuYMwWZm+Cg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - oxlint-tsgolint: '>=0.15.0' + oxlint-tsgolint: '>=0.18.0' peerDependenciesMeta: oxlint-tsgolint: optional: true @@ -709,61 +709,61 @@ snapshots: '@oxfmt/binding-win32-x64-msvc@0.66.0': optional: true - '@oxlint/binding-android-arm-eabi@1.57.0': + '@oxlint/binding-android-arm-eabi@1.58.0': optional: true - '@oxlint/binding-android-arm64@1.57.0': + '@oxlint/binding-android-arm64@1.58.0': optional: true - '@oxlint/binding-darwin-arm64@1.57.0': + '@oxlint/binding-darwin-arm64@1.58.0': optional: true - '@oxlint/binding-darwin-x64@1.57.0': + '@oxlint/binding-darwin-x64@1.58.0': optional: true - '@oxlint/binding-freebsd-x64@1.57.0': + '@oxlint/binding-freebsd-x64@1.58.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.57.0': + '@oxlint/binding-linux-arm-gnueabihf@1.58.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.57.0': + '@oxlint/binding-linux-arm-musleabihf@1.58.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.57.0': + '@oxlint/binding-linux-arm64-gnu@1.58.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.57.0': + '@oxlint/binding-linux-arm64-musl@1.58.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.57.0': + '@oxlint/binding-linux-ppc64-gnu@1.58.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.57.0': + '@oxlint/binding-linux-riscv64-gnu@1.58.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.57.0': + '@oxlint/binding-linux-riscv64-musl@1.58.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.57.0': + '@oxlint/binding-linux-s390x-gnu@1.58.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.57.0': + '@oxlint/binding-linux-x64-gnu@1.58.0': optional: true - '@oxlint/binding-linux-x64-musl@1.57.0': + '@oxlint/binding-linux-x64-musl@1.58.0': optional: true - '@oxlint/binding-openharmony-arm64@1.57.0': + '@oxlint/binding-openharmony-arm64@1.58.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.57.0': + '@oxlint/binding-win32-arm64-msvc@1.58.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.57.0': + '@oxlint/binding-win32-ia32-msvc@1.58.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.57.0': + '@oxlint/binding-win32-x64-msvc@1.58.0': optional: true '@types/parse-json@4.0.2': {} @@ -1005,27 +1005,27 @@ snapshots: '@oxfmt/binding-win32-ia32-msvc': 0.66.0 '@oxfmt/binding-win32-x64-msvc': 0.66.0 - oxlint@1.57.0: + oxlint@1.58.0: optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.57.0 - '@oxlint/binding-android-arm64': 1.57.0 - '@oxlint/binding-darwin-arm64': 1.57.0 - '@oxlint/binding-darwin-x64': 1.57.0 - '@oxlint/binding-freebsd-x64': 1.57.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.57.0 - '@oxlint/binding-linux-arm-musleabihf': 1.57.0 - '@oxlint/binding-linux-arm64-gnu': 1.57.0 - '@oxlint/binding-linux-arm64-musl': 1.57.0 - '@oxlint/binding-linux-ppc64-gnu': 1.57.0 - '@oxlint/binding-linux-riscv64-gnu': 1.57.0 - '@oxlint/binding-linux-riscv64-musl': 1.57.0 - '@oxlint/binding-linux-s390x-gnu': 1.57.0 - '@oxlint/binding-linux-x64-gnu': 1.57.0 - '@oxlint/binding-linux-x64-musl': 1.57.0 - '@oxlint/binding-openharmony-arm64': 1.57.0 - '@oxlint/binding-win32-arm64-msvc': 1.57.0 - '@oxlint/binding-win32-ia32-msvc': 1.57.0 - '@oxlint/binding-win32-x64-msvc': 1.57.0 + '@oxlint/binding-android-arm-eabi': 1.58.0 + '@oxlint/binding-android-arm64': 1.58.0 + '@oxlint/binding-darwin-arm64': 1.58.0 + '@oxlint/binding-darwin-x64': 1.58.0 + '@oxlint/binding-freebsd-x64': 1.58.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.58.0 + '@oxlint/binding-linux-arm-musleabihf': 1.58.0 + '@oxlint/binding-linux-arm64-gnu': 1.58.0 + '@oxlint/binding-linux-arm64-musl': 1.58.0 + '@oxlint/binding-linux-ppc64-gnu': 1.58.0 + '@oxlint/binding-linux-riscv64-gnu': 1.58.0 + '@oxlint/binding-linux-riscv64-musl': 1.58.0 + '@oxlint/binding-linux-s390x-gnu': 1.58.0 + '@oxlint/binding-linux-x64-gnu': 1.58.0 + '@oxlint/binding-linux-x64-musl': 1.58.0 + '@oxlint/binding-openharmony-arm64': 1.58.0 + '@oxlint/binding-win32-arm64-msvc': 1.58.0 + '@oxlint/binding-win32-ia32-msvc': 1.58.0 + '@oxlint/binding-win32-x64-msvc': 1.58.0 p-map@4.0.0: dependencies: diff --git a/common/changes/@gooddata/sdk-ui-all/SHA_master_1_2026-11-09-11-45.json b/common/changes/@gooddata/sdk-ui-all/SHA_master_1_2026-11-09-11-45.json new file mode 100644 index 00000000000..2b016713a32 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/SHA_master_1_2026-11-09-11-45.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "comment": "sdk-ui-gen-ai: Enhance Markdown handling and improve CustomHyperlink processing.", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/SHA_master_1_2026-14-09-12-45.json b/common/changes/@gooddata/sdk-ui-all/SHA_master_1_2026-14-09-12-45.json new file mode 100644 index 00000000000..ac04f126eac --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/SHA_master_1_2026-14-09-12-45.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "comment": "sdk-ui-dashboard: Support saving draft insights during dashboard save flow.", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/ine-cq-2825-timezone-tooltip-docs-link_2026-09-14-09-44-59.json b/common/changes/@gooddata/sdk-ui-all/ine-cq-2825-timezone-tooltip-docs-link_2026-09-14-09-44-59.json new file mode 100644 index 00000000000..072f95fdd44 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/ine-cq-2825-timezone-tooltip-docs-link_2026-09-14-09-44-59.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "sdk-ui-dashboard: Add help link.", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all", + "email": "ivan.nejezchleb@gooddata.com" +} diff --git a/common/changes/@gooddata/sdk-ui-all/ine-cq-2958_2026-09-11-14-53-39.json b/common/changes/@gooddata/sdk-ui-all/ine-cq-2958_2026-09-11-14-53-39.json new file mode 100644 index 00000000000..cc065ce42a2 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/ine-cq-2958_2026-09-11-14-53-39.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Reference computed attributes in drill to URL placeholders", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all", + "email": "ivan.nejezchleb@gooddata.com" +} diff --git a/common/changes/@gooddata/sdk-ui-all/ine-cq-2968_2026-09-11-14-47-14.json b/common/changes/@gooddata/sdk-ui-all/ine-cq-2968_2026-09-11-14-47-14.json new file mode 100644 index 00000000000..d34b8c78040 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/ine-cq-2968_2026-09-11-14-47-14.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Keep arrow keys inside a rich text editor instead of navigating the surrounding menu", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all", + "email": "ivan.nejezchleb@gooddata.com" +} diff --git a/common/changes/@gooddata/sdk-ui-all/jkd-gdai-2315-fe_2026-09-10-16-30-00.json b/common/changes/@gooddata/sdk-ui-all/jkd-gdai-2315-fe_2026-09-10-16-30-00.json new file mode 100644 index 00000000000..30ef8db23a4 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/jkd-gdai-2315-fe_2026-09-10-16-30-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "comment": "sdk-backend-tiger: Copilot adding a chart to an open dashboard now renders the patched draft as a single card, and follow-up proposals in the same conversation keep working after a reload.", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/jsc-f1-2861-copy-object-permissions_2026-09-11-12-00-00.json b/common/changes/@gooddata/sdk-ui-all/jsc-f1-2861-copy-object-permissions_2026-09-11-12-00-00.json new file mode 100644 index 00000000000..7fbe9635483 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/jsc-f1-2861-copy-object-permissions_2026-09-11-12-00-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-ext: Add the useCopyObjectPermissions hook, which reproduces one object's own access on another.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/mkn-olp-restricted-widget-removal_2026-09-10-13-30-00.json b/common/changes/@gooddata/sdk-ui-all/mkn-olp-restricted-widget-removal_2026-09-10-13-30-00.json new file mode 100644 index 00000000000..4007807c080 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/mkn-olp-restricted-widget-removal_2026-09-10-13-30-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "comment": "sdk-ui-all: Anyone who can edit a dashboard can now remove a restricted visualization widget from it, which until now had no menu at all; neither the menu nor the delete confirmation names such a widget.", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/pb-menu-zindex-fix_2026-09-11-12-55-50.json b/common/changes/@gooddata/sdk-ui-all/pb-menu-zindex-fix_2026-09-11-12-55-50.json new file mode 100644 index 00000000000..13abf3e6481 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pb-menu-zindex-fix_2026-09-11-12-55-50.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-kit: Menu z-index is supplied by the active OverlayController", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/pdo-lx-2812-cancel-error-hygiene_2026-08-13.json b/common/changes/@gooddata/sdk-ui-all/pdo-lx-2812-cancel-error-hygiene_2026-08-13.json new file mode 100644 index 00000000000..68dd615bdca --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pdo-lx-2812-cancel-error-hygiene_2026-08-13.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui:Convert aborted executions to CANCELLED instead of UNKNOWN_ERROR; sdk-backend-tiger no longer logs request cancellations as backend errors.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/pdo-lx-2812-error-boundaries_2026-08-13.json b/common/changes/@gooddata/sdk-ui-all/pdo-lx-2812-error-boundaries_2026-08-13.json new file mode 100644 index 00000000000..d0c26e61d9a --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pdo-lx-2812-error-boundaries_2026-08-13.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-pluggable-host:Add HostErrorBoundary so an uncaught error renders an error screen instead of unmounting the whole host page.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/pdo-lx-2812-platform-context-keep-mounted_2026-08-13.json b/common/changes/@gooddata/sdk-ui-all/pdo-lx-2812-platform-context-keep-mounted_2026-08-13.json new file mode 100644 index 00000000000..de13534e14c --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pdo-lx-2812-platform-context-keep-mounted_2026-08-13.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-pluggable-host:Keep the mounted app rendered while the same workspace's platform context refreshes instead of swapping it for a loader.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/pdo-regenerate-default-theme_2026-09-10-14-00-00.json b/common/changes/@gooddata/sdk-ui-all/pdo-regenerate-default-theme_2026-09-10-14-00-00.json new file mode 100644 index 00000000000..f17a350ed16 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pdo-regenerate-default-theme_2026-09-10-14-00-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "comment": "sdk-ui-kit: Regenerate defaultTheme.scss from its spec, restoring the :root defaults for --gd-avatar-background-color, --gd-viz-tooltip-max-height and the geo multi-layer legend variables, which were referenced without a fallback", + "type": "patch", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/pdo-uidropdown-popup-role_2026-09-11-08-00-00.json b/common/changes/@gooddata/sdk-ui-all/pdo-uidropdown-popup-role_2026-09-11-08-00-00.json new file mode 100644 index 00000000000..1ddce075d26 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pdo-uidropdown-popup-role_2026-09-11-08-00-00.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "sdk-ui-kit: UiDropdown no longer repeats a listbox, menu, tree or grid popupRole on the floating panel around the body that already carries it", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all", + "email": "petr.dolejsi@gooddata.com" +} diff --git a/common/changes/@gooddata/sdk-ui-all/pdo-uitooltip-width-defaults_2026-09-09-10-00-00.json b/common/changes/@gooddata/sdk-ui-all/pdo-uitooltip-width-defaults_2026-09-09-10-00-00.json new file mode 100644 index 00000000000..56b1782f5c5 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pdo-uitooltip-width-defaults_2026-09-09-10-00-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "comment": "sdk-ui-kit: UiTooltip caps its width at 300px by default (override via the --gd-tooltip-maxWidth CSS variable, or by setting an explicit width)", + "type": "patch", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/pkoz-lx-2965-host-export-mode-in-search_2026-09-11-00-00.json b/common/changes/@gooddata/sdk-ui-all/pkoz-lx-2965-host-export-mode-in-search_2026-09-11-00-00.json new file mode 100644 index 00000000000..ac495101aa3 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pkoz-lx-2965-host-export-mode-in-search_2026-09-11-00-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "comment": "sdk-ui-pluggable-host: The host hides its navigation, chat and brand title for an export mode named in the search string as well as in the fragment, and recognises the reports module's export_slideshow mode next to the dashboards' export.", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/pvep-master-1_2026-09-11-11-52-06.json b/common/changes/@gooddata/sdk-ui-all/pvep-master-1_2026-09-11-11-52-06.json new file mode 100644 index 00000000000..5e0d7a2c4b1 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pvep-master-1_2026-09-11-11-52-06.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-gen-ai: Render waterfall charts in the AI assistant chat.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} \ No newline at end of file diff --git a/common/changes/@gooddata/sdk-ui-all/pvep-master-1_2026-09-14-09-25-47.json b/common/changes/@gooddata/sdk-ui-all/pvep-master-1_2026-09-14-09-25-47.json new file mode 100644 index 00000000000..125fa79da47 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pvep-master-1_2026-09-14-09-25-47.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-gen-ai: Render donut, pyramid and funnel charts in the AI assistant chat.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} \ No newline at end of file diff --git a/common/changes/@gooddata/sdk-ui-all/pvep-master-2_2026-09-14-11-07-06.json b/common/changes/@gooddata/sdk-ui-all/pvep-master-2_2026-09-14-11-07-06.json new file mode 100644 index 00000000000..8c0d688e360 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pvep-master-2_2026-09-14-11-07-06.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-gen-ai: Render radar charts in the AI assistant chat.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} \ No newline at end of file diff --git a/common/changes/@gooddata/sdk-ui-all/pvep-master_2026-09-10-08-25-41.json b/common/changes/@gooddata/sdk-ui-all/pvep-master_2026-09-10-08-25-41.json new file mode 100644 index 00000000000..a80c06c274b --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pvep-master_2026-09-10-08-25-41.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-gen-ai: Start a new conversation instead of resuming the last one when the AI Assistant is opened after 8 hours of inactivity.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} \ No newline at end of file diff --git a/common/changes/@gooddata/sdk-ui-all/pvep-master_2026-09-14-07-47-37.json b/common/changes/@gooddata/sdk-ui-all/pvep-master_2026-09-14-07-47-37.json new file mode 100644 index 00000000000..9038cf18865 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pvep-master_2026-09-14-07-47-37.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-gen-ai: Render heatmap charts in the AI assistant chat.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} \ No newline at end of file diff --git a/common/changes/@gooddata/sdk-ui-all/pvep-master_2026-09-14-10-25-34.json b/common/changes/@gooddata/sdk-ui-all/pvep-master_2026-09-14-10-25-34.json new file mode 100644 index 00000000000..7891dfafda7 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pvep-master_2026-09-14-10-25-34.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-gen-ai: Render stacked area charts in the AI assistant chat.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} \ No newline at end of file diff --git a/common/changes/@gooddata/sdk-ui-all/scv-restricted-filters-edit-mode_2026-09-10-14-00-00.json b/common/changes/@gooddata/sdk-ui-all/scv-restricted-filters-edit-mode_2026-09-10-14-00-00.json new file mode 100644 index 00000000000..bac5b4f7395 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/scv-restricted-filters-edit-mode_2026-09-10-14-00-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "comment": "sdk-ui-dashboard: Let an editor remove the dashboard filters they are not allowed to read, through the removeRestrictedFilters command and the action the filter bar notice offers in edit mode.", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/config/rush/.pnpmfile.cjs b/common/config/rush/.pnpmfile.cjs index 1e8ca5d7fd9..b35f30848ee 100644 --- a/common/config/rush/.pnpmfile.cjs +++ b/common/config/rush/.pnpmfile.cjs @@ -3,7 +3,7 @@ "use strict"; // baseline-browser-mapping needs to be updated to the latest version every 14 days -const baselineBrowserMappingVersion = "2.11.21"; +const baselineBrowserMappingVersion = "2.11.23"; // browserslist needs to be updated every 6 months const browserslistVersion = "4.28.9"; diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index ae05853be03..39fa89edb4f 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -4,13 +4,16 @@ settings: autoInstallPeers: false excludeLinksFromLockfile: false +overrides: + minimatch@>=10.0.0 <10.2.3: 10.2.5 + pnpmfileChecksum: sha256-E1T7OJ3DLTjpDqf4RdJzK9VDtAxgm4gDEQCLYdHD8nI= importers: .: {} - ../../examples/playground: + ../../../sdk/examples/playground: devDependencies: '@codemirror/state': specifier: 6.5.3 @@ -95,7 +98,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -133,11 +136,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 react: specifier: 19.1.1 version: 19.1.1 @@ -148,8 +154,8 @@ importers: specifier: 1.0.3 version: 1.0.3 sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 ts-invariant: specifier: 0.10.3 version: 0.10.3 @@ -161,15 +167,15 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../examples/sdk-interactive-examples: + ../../../sdk/examples/sdk-interactive-examples: devDependencies: validate-npm-package-name: specifier: 5.0.1 version: 5.0.1 - ../../examples/sdk-interactive-examples/examples-template: + ../../../sdk/examples/sdk-interactive-examples/examples-template: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -243,7 +249,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -275,11 +281,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 process: specifier: 0.11.10 version: 0.11.10 @@ -291,12 +300,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-html: specifier: ~3.2.0 - version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../examples/sdk-interactive-examples/examples/example-attributefilter: + ../../../sdk/examples/sdk-interactive-examples/examples/example-attributefilter: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -370,7 +379,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -402,11 +411,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 process: specifier: 0.11.10 version: 0.11.10 @@ -418,12 +430,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-html: specifier: ~3.2.0 - version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../examples/sdk-interactive-examples/examples/example-chartconfig: + ../../../sdk/examples/sdk-interactive-examples/examples/example-chartconfig: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -497,7 +509,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -529,11 +541,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 process: specifier: 0.11.10 version: 0.11.10 @@ -545,12 +560,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-html: specifier: ~3.2.0 - version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../examples/sdk-interactive-examples/examples/example-columnchart: + ../../../sdk/examples/sdk-interactive-examples/examples/example-columnchart: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -624,7 +639,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -656,11 +671,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 process: specifier: 0.11.10 version: 0.11.10 @@ -672,12 +690,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-html: specifier: ~3.2.0 - version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../examples/sdk-interactive-examples/examples/example-combochart: + ../../../sdk/examples/sdk-interactive-examples/examples/example-combochart: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -751,7 +769,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -783,11 +801,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 process: specifier: 0.11.10 version: 0.11.10 @@ -799,12 +820,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-html: specifier: ~3.2.0 - version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../examples/sdk-interactive-examples/examples/example-dashboard: + ../../../sdk/examples/sdk-interactive-examples/examples/example-dashboard: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -878,7 +899,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -910,11 +931,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 process: specifier: 0.11.10 version: 0.11.10 @@ -926,12 +950,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-html: specifier: ~3.2.0 - version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../examples/sdk-interactive-examples/examples/example-datefilter: + ../../../sdk/examples/sdk-interactive-examples/examples/example-datefilter: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -1005,7 +1029,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -1037,11 +1061,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 process: specifier: 0.11.10 version: 0.11.10 @@ -1053,12 +1080,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-html: specifier: ~3.2.0 - version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../examples/sdk-interactive-examples/examples/example-dependentfilters: + ../../../sdk/examples/sdk-interactive-examples/examples/example-dependentfilters: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -1132,7 +1159,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -1164,11 +1191,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 process: specifier: 0.11.10 version: 0.11.10 @@ -1180,12 +1210,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-html: specifier: ~3.2.0 - version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../examples/sdk-interactive-examples/examples/example-execute: + ../../../sdk/examples/sdk-interactive-examples/examples/example-execute: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -1268,7 +1298,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -1300,11 +1330,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 process: specifier: 0.11.10 version: 0.11.10 @@ -1316,12 +1349,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-html: specifier: ~3.2.0 - version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../examples/sdk-interactive-examples/examples/example-granularity: + ../../../sdk/examples/sdk-interactive-examples/examples/example-granularity: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -1395,7 +1428,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -1427,11 +1460,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 process: specifier: 0.11.10 version: 0.11.10 @@ -1443,12 +1479,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-html: specifier: ~3.2.0 - version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../examples/sdk-interactive-examples/examples/example-headline: + ../../../sdk/examples/sdk-interactive-examples/examples/example-headline: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -1522,7 +1558,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -1554,11 +1590,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 process: specifier: 0.11.10 version: 0.11.10 @@ -1570,12 +1609,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-html: specifier: ~3.2.0 - version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../examples/sdk-interactive-examples/examples/example-pivottable: + ../../../sdk/examples/sdk-interactive-examples/examples/example-pivottable: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -1649,7 +1688,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -1681,11 +1720,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 process: specifier: 0.11.10 version: 0.11.10 @@ -1697,12 +1739,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-html: specifier: ~3.2.0 - version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../examples/sdk-interactive-examples/examples/example-relativedatefilter: + ../../../sdk/examples/sdk-interactive-examples/examples/example-relativedatefilter: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -1776,7 +1818,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -1808,11 +1850,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 process: specifier: 0.11.10 version: 0.11.10 @@ -1824,12 +1869,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-html: specifier: ~3.2.0 - version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../examples/sdk-interactive-examples/examples/example-repeater: + ../../../sdk/examples/sdk-interactive-examples/examples/example-repeater: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -1903,7 +1948,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -1935,11 +1980,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 process: specifier: 0.11.10 version: 0.11.10 @@ -1951,12 +1999,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-html: specifier: ~3.2.0 - version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../libs/api-client-tiger: + ../../../sdk/libs/api-client-tiger: dependencies: '@gooddata/sdk-model': specifier: workspace:* @@ -2038,19 +2086,22 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../libs/sdk-backend-base: + ../../../sdk/libs/sdk-backend-base: dependencies: '@braintree/sanitize-url': specifier: ^6.0.0 @@ -2141,19 +2192,22 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../libs/sdk-backend-mockingbird: + ../../../sdk/libs/sdk-backend-mockingbird: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -2232,19 +2286,22 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../libs/sdk-backend-spi: + ../../../sdk/libs/sdk-backend-spi: dependencies: '@gooddata/sdk-model': specifier: workspace:* @@ -2308,19 +2365,22 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../libs/sdk-backend-tiger: + ../../../sdk/libs/sdk-backend-tiger: dependencies: '@gooddata/api-client-tiger': specifier: workspace:* @@ -2444,19 +2504,22 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../libs/sdk-code-convertors: + ../../../sdk/libs/sdk-code-convertors: dependencies: '@gooddata/api-client-tiger': specifier: workspace:* @@ -2517,19 +2580,22 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../libs/sdk-code-schemas: + ../../../sdk/libs/sdk-code-schemas: devDependencies: '@gooddata/eslint-config': specifier: workspace:* @@ -2580,11 +2646,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 readdirp: specifier: 4.1.2 version: 4.1.2 @@ -2593,9 +2662,9 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../libs/sdk-e2e-utils: + ../../../sdk/libs/sdk-e2e-utils: dependencies: '@playwright/test': specifier: 1.62.1 @@ -2665,16 +2734,19 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 - ../../libs/sdk-embedding: + ../../../sdk/libs/sdk-embedding: dependencies: '@gooddata/sdk-model': specifier: workspace:* @@ -2738,19 +2810,22 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../libs/sdk-model: + ../../../sdk/libs/sdk-model: dependencies: '@types/geojson': specifier: ^7946.0.16 @@ -2829,19 +2904,22 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../libs/sdk-pluggable-application-model: + ../../../sdk/libs/sdk-pluggable-application-model: dependencies: '@gooddata/sdk-model': specifier: workspace:* @@ -2902,16 +2980,19 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 - ../../libs/sdk-ui: + ../../../sdk/libs/sdk-ui: dependencies: '@gooddata/number-formatter': specifier: ^1.0.6 @@ -3056,11 +3137,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -3081,12 +3165,12 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest-dom: specifier: 0.1.1 version: 0.1.1(vitest@4.1.8) - ../../libs/sdk-ui-all: + ../../../sdk/libs/sdk-ui-all: dependencies: '@gooddata/sdk-backend-spi': specifier: workspace:* @@ -3165,16 +3249,19 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 - ../../libs/sdk-ui-application-header: + ../../../sdk/libs/sdk-ui-application-header: dependencies: '@gooddata/sdk-backend-spi': specifier: workspace:* @@ -3286,11 +3373,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 react: specifier: 19.1.1 version: 19.1.1 @@ -3311,15 +3401,15 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest-dom: specifier: 0.1.1 version: 0.1.1(vitest@4.1.8) - ../../libs/sdk-ui-catalog: + ../../../sdk/libs/sdk-ui-catalog: dependencies: '@codemirror/autocomplete': specifier: 6.20.0 @@ -3464,11 +3554,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -3479,8 +3572,8 @@ importers: specifier: 19.1.1 version: 19.1.1(react@19.1.1) sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 stylelint: specifier: 16.26.1 version: 16.26.1(typescript@7.0.2) @@ -3489,12 +3582,12 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest-dom: specifier: 0.1.1 version: 0.1.1(vitest@4.1.8) - ../../libs/sdk-ui-charts: + ../../../sdk/libs/sdk-ui-charts: dependencies: '@gooddata/number-formatter': specifier: ^1.0.6 @@ -3675,11 +3768,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -3690,8 +3786,8 @@ importers: specifier: 19.1.1 version: 19.1.1(react@19.1.1) sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 stylelint: specifier: 16.26.1 version: 16.26.1(typescript@7.0.2) @@ -3700,12 +3796,12 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest-dom: specifier: 0.1.1 version: 0.1.1(vitest@4.1.8) - ../../libs/sdk-ui-dashboard: + ../../../sdk/libs/sdk-ui-dashboard: dependencies: '@codemirror/language': specifier: 6.12.1 @@ -3931,11 +4027,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -3946,8 +4045,8 @@ importers: specifier: 19.1.1 version: 19.1.1(react@19.1.1) sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 stylelint: specifier: 16.26.1 version: 16.26.1(typescript@7.0.2) @@ -3959,12 +4058,12 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest-dom: specifier: 0.1.1 version: 0.1.1(vitest@4.1.8) - ../../libs/sdk-ui-ext: + ../../../sdk/libs/sdk-ui-ext: dependencies: '@codemirror/commands': specifier: 6.10.1 @@ -4199,11 +4298,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -4214,8 +4316,8 @@ importers: specifier: 19.1.1 version: 19.1.1(react@19.1.1) sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 stylelint: specifier: 16.26.1 version: 16.26.1(typescript@7.0.2) @@ -4227,12 +4329,12 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest-dom: specifier: 0.1.1 version: 0.1.1(vitest@4.1.8) - ../../libs/sdk-ui-filters: + ../../../sdk/libs/sdk-ui-filters: dependencies: '@gooddata/sdk-backend-spi': specifier: workspace:* @@ -4392,11 +4494,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -4407,8 +4512,8 @@ importers: specifier: 19.1.1 version: 19.1.1(react@19.1.1) sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 stylelint: specifier: 16.26.1 version: 16.26.1(typescript@7.0.2) @@ -4417,12 +4522,12 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest-dom: specifier: 0.1.1 version: 0.1.1(vitest@4.1.8) - ../../libs/sdk-ui-gen-ai: + ../../../sdk/libs/sdk-ui-gen-ai: dependencies: '@codemirror/autocomplete': specifier: 6.20.0 @@ -4624,11 +4729,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -4639,8 +4747,8 @@ importers: specifier: 19.1.1 version: 19.1.1(react@19.1.1) sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 stylelint: specifier: 16.26.1 version: 16.26.1(typescript@7.0.2) @@ -4652,12 +4760,12 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest-dom: specifier: 0.1.1 version: 0.1.1(vitest@4.1.8) - ../../libs/sdk-ui-geo: + ../../../sdk/libs/sdk-ui-geo: dependencies: '@gooddata/number-formatter': specifier: ^1.0.6 @@ -4802,11 +4910,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -4817,8 +4928,8 @@ importers: specifier: 19.1.1 version: 19.1.1(react@19.1.1) sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 stylelint: specifier: 16.26.1 version: 16.26.1(typescript@7.0.2) @@ -4827,12 +4938,12 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest-dom: specifier: 0.1.1 version: 0.1.1(vitest@4.1.8) - ../../libs/sdk-ui-kit: + ../../../sdk/libs/sdk-ui-kit: dependencies: '@aaronhayes/react-use-hubspot-form': specifier: 2.1.2 @@ -5091,11 +5202,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -5106,8 +5220,8 @@ importers: specifier: 19.1.1 version: 19.1.1(react@19.1.1) sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 stylelint: specifier: 16.26.1 version: 16.26.1(typescript@7.0.2) @@ -5119,12 +5233,12 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest-dom: specifier: 0.1.1 version: 0.1.1(vitest@4.1.8) - ../../libs/sdk-ui-loaders: + ../../../sdk/libs/sdk-ui-loaders: dependencies: '@gooddata/sdk-backend-spi': specifier: workspace:* @@ -5230,11 +5344,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -5248,7 +5365,7 @@ importers: specifier: 7.0.2 version: 7.0.2 - ../../libs/sdk-ui-pivot: + ../../../sdk/libs/sdk-ui-pivot: dependencies: '@gooddata/number-formatter': specifier: ^1.0.6 @@ -5393,11 +5510,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -5408,8 +5528,8 @@ importers: specifier: 19.1.1 version: 19.1.1(react@19.1.1) sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 stylelint: specifier: 16.26.1 version: 16.26.1(typescript@7.0.2) @@ -5418,12 +5538,12 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest-dom: specifier: 0.1.1 version: 0.1.1(vitest@4.1.8) - ../../libs/sdk-ui-pluggable-application: + ../../../sdk/libs/sdk-ui-pluggable-application: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -5520,11 +5640,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 react: specifier: 19.1.1 version: 19.1.1 @@ -5536,9 +5659,9 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../libs/sdk-ui-pluggable-host: + ../../../sdk/libs/sdk-ui-pluggable-host: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -5665,11 +5788,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 react: specifier: 19.1.1 version: 19.1.1 @@ -5686,8 +5812,8 @@ importers: specifier: 1.0.3 version: 1.0.3 sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 tslib: specifier: 2.8.1 version: 2.8.1 @@ -5696,15 +5822,15 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest-dom: specifier: 0.1.1 version: 0.1.1(vitest@4.1.8) - ../../libs/sdk-ui-semantic-search: + ../../../sdk/libs/sdk-ui-semantic-search: dependencies: '@gooddata/sdk-backend-spi': specifier: workspace:* @@ -5822,11 +5948,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -5837,8 +5966,8 @@ importers: specifier: 19.1.1 version: 19.1.1(react@19.1.1) sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 stylelint: specifier: 16.26.1 version: 16.26.1(typescript@7.0.2) @@ -5847,12 +5976,12 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest-dom: specifier: 0.1.1 version: 0.1.1(vitest@4.1.8) - ../../libs/sdk-ui-tests-app: + ../../../sdk/libs/sdk-ui-tests-app: devDependencies: '@gooddata/eslint-config': specifier: workspace:* @@ -5916,7 +6045,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) core-js: specifier: 3.45.1 version: 3.45.1 @@ -5957,11 +6086,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 react: specifier: 19.1.1 version: 19.1.1 @@ -5972,16 +6104,16 @@ importers: specifier: 1.0.3 version: 1.0.3 sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 typescript: specifier: 7.0.2 version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../libs/sdk-ui-tests-e2e: + ../../../sdk/libs/sdk-ui-tests-e2e: devDependencies: '@gooddata/eslint-config': specifier: workspace:* @@ -6059,11 +6191,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 rolldown: specifier: 1.0.3 version: 1.0.3 @@ -6071,7 +6206,7 @@ importers: specifier: 7.0.2 version: 7.0.2 - ../../libs/sdk-ui-tests-reference-workspace: + ../../../sdk/libs/sdk-ui-tests-reference-workspace: devDependencies: '@gooddata/catalog-export': specifier: workspace:* @@ -6119,16 +6254,19 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 - ../../libs/sdk-ui-tests-scenarios: + ../../../sdk/libs/sdk-ui-tests-scenarios: devDependencies: '@gooddata/eslint-config': specifier: workspace:* @@ -6251,11 +6389,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 react: specifier: 19.1.1 version: 19.1.1 @@ -6273,9 +6414,9 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../libs/sdk-ui-tests-storybook: + ../../../sdk/libs/sdk-ui-tests-storybook: devDependencies: '@gooddata/eslint-config': specifier: workspace:* @@ -6351,13 +6492,13 @@ importers: version: 10.5.6(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1)) '@storybook/builder-vite': specifier: 10.5.6 - version: 10.5.6(esbuild@0.28.1)(rollup@4.62.3)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3))(webpack@5.107.2(esbuild@0.28.1)) + version: 10.5.6(esbuild@0.28.1)(rollup@4.62.3)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3))(webpack@5.107.2(esbuild@0.28.1)) '@storybook/cli': specifier: 10.5.6 version: 10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1) '@storybook/react-vite': specifier: 10.5.6 - version: 10.5.6(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(esbuild@0.28.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.62.3)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(typescript@7.0.2)(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3))(webpack@5.107.2(esbuild@0.28.1)) + version: 10.5.6(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(esbuild@0.28.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.62.3)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(typescript@7.0.2)(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3))(webpack@5.107.2(esbuild@0.28.1)) '@types/lodash-es': specifier: 4.17.12 version: 4.17.12 @@ -6434,11 +6575,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 react: specifier: 19.1.1 version: 19.1.1 @@ -6474,12 +6618,12 @@ importers: version: 11.1.1 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-static-copy: specifier: 4.1.0 - version: 4.1.0(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 4.1.0(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) - ../../libs/sdk-ui-theme-provider: + ../../../sdk/libs/sdk-ui-theme-provider: dependencies: '@gooddata/sdk-backend-spi': specifier: workspace:* @@ -6603,11 +6747,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -6622,9 +6769,9 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../libs/sdk-ui-vis-commons: + ../../../sdk/libs/sdk-ui-vis-commons: dependencies: '@gooddata/number-formatter': specifier: ^1.0.6 @@ -6751,11 +6898,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -6766,8 +6916,8 @@ importers: specifier: 19.1.1 version: 19.1.1(react@19.1.1) sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 stylelint: specifier: 16.26.1 version: 16.26.1(typescript@7.0.2) @@ -6776,12 +6926,12 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest-dom: specifier: 0.1.1 version: 0.1.1(vitest@4.1.8) - ../../libs/sdk-ui-web-components: + ../../../sdk/libs/sdk-ui-web-components: dependencies: '@gooddata/sdk-backend-spi': specifier: workspace:* @@ -6911,11 +7061,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 raf: specifier: 3.4.1 version: 3.4.1 @@ -6936,15 +7089,15 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vite-plugin-css-injected-by-js: specifier: 3.1.1 - version: 3.1.1(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 3.1.1(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../libs/util: + ../../../sdk/libs/util: dependencies: lodash-es: specifier: ^4.17.23 @@ -7005,19 +7158,22 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../templates/pluggable-module/harness: + ../../../sdk/templates/pluggable-module/harness: dependencies: '@gooddata/sdk-model': specifier: workspace:* @@ -7067,7 +7223,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -7099,25 +7255,28 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 rolldown: specifier: 1.0.3 version: 1.0.3 sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 typescript: specifier: 7.0.2 version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../templates/pluggable-module/module: + ../../../sdk/templates/pluggable-module/module: dependencies: '@gooddata/sdk-model': specifier: workspace:* @@ -7149,7 +7308,7 @@ importers: version: link:../../../tools/oxlint-config '@module-federation/vite': specifier: 1.16.11 - version: 1.16.11(node-fetch@2.7.0)(typescript@7.0.2)(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 1.16.11(node-fetch@2.7.0)(typescript@7.0.2)(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) '@testing-library/dom': specifier: 10.4.1 version: 10.4.1 @@ -7176,7 +7335,7 @@ importers: version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) '@vitejs/plugin-react': specifier: 6.0.2 - version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + version: 6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -7214,11 +7373,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 react: specifier: 19.1.1 version: 19.1.1 @@ -7229,19 +7391,19 @@ importers: specifier: 1.0.3 version: 1.0.3 sass: - specifier: 1.100.0 - version: 1.100.0 + specifier: 1.104.0 + version: 1.104.0 typescript: specifier: 7.0.2 version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../tools/app-toolkit: + ../../../sdk/tools/app-toolkit: dependencies: chalk: specifier: 5.3.0 @@ -7323,19 +7485,22 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../tools/catalog-export: + ../../../sdk/tools/catalog-export: dependencies: '@gooddata/api-client-tiger': specifier: workspace:* @@ -7429,19 +7594,22 @@ importers: specifier: 4.1.5 version: 4.1.5 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../tools/create-pluggable-module: + ../../../sdk/tools/create-pluggable-module: devDependencies: '@gooddata/eslint-config': specifier: workspace:* @@ -7489,11 +7657,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 tslib: specifier: 2.8.1 version: 2.8.1 @@ -7502,12 +7673,12 @@ importers: version: 7.0.2 vite: specifier: 8.0.16 - version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../tools/dashboard-plugin-template: + ../../../sdk/tools/dashboard-plugin-template: dependencies: tslib: specifier: 2.8.1 @@ -7625,11 +7796,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 react: specifier: 19.1.1 version: 19.1.1 @@ -7653,7 +7827,7 @@ importers: version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) webpack: specifier: 5.107.2 version: 5.107.2(esbuild@0.28.1)(webpack-cli@7.0.3) @@ -7667,11 +7841,11 @@ importers: specifier: 5.2.4 version: 5.2.4(tslib@2.8.1)(webpack-cli@7.0.3)(webpack@5.107.2) - ../../tools/eslint-config: + ../../../sdk/tools/eslint-config: devDependencies: '@eslint/js': - specifier: 9.28.0 - version: 9.28.0 + specifier: 9.39.5 + version: 9.39.5 '@gooddata/lint-config': specifier: workspace:* version: link:../lint-config @@ -7758,9 +7932,9 @@ importers: version: 7.0.2 vite-node: specifier: 5.3.0 - version: 5.3.0(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.33.0)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 5.3.0(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.33.0)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../tools/i18n-toolkit: + ../../../sdk/tools/i18n-toolkit: dependencies: '@formatjs/cli-lib': specifier: ^6.1.1 @@ -7845,19 +8019,22 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../tools/lint-config: + ../../../sdk/tools/lint-config: devDependencies: npm-run-all: specifier: 4.1.5 @@ -7869,7 +8046,7 @@ importers: specifier: 7.0.2 version: 7.0.2 - ../../tools/mock-handling: + ../../../sdk/tools/mock-handling: dependencies: '@gooddata/sdk-backend-base': specifier: workspace:* @@ -7957,23 +8134,23 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../tools/oxlint-config: + ../../../sdk/tools/oxlint-config: devDependencies: - '@eslint/js': - specifier: 9.28.0 - version: 9.28.0 '@gooddata/eslint-config': specifier: workspace:* version: link:../eslint-config @@ -7992,9 +8169,6 @@ importers: '@typescript-eslint/parser': specifier: 8.58.0 version: 8.58.0(eslint@9.39.5(jiti@2.6.1)) - '@vitest/eslint-plugin': - specifier: 1.6.19 - version: 1.6.19(@typescript-eslint/eslint-plugin@8.58.0(@typescript-eslint/parser@8.58.0(eslint@9.39.5(jiti@2.6.1)))(eslint@9.39.5(jiti@2.6.1)))(eslint@9.39.5(jiti@2.6.1))(typescript@7.0.2)(vitest@4.1.8) eslint: specifier: ^9.39.2 version: 9.39.5(jiti@2.6.1) @@ -8035,11 +8209,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 react: specifier: 19.1.1 version: 19.1.1 @@ -8054,9 +8231,9 @@ importers: version: 7.0.2 vite-node: specifier: 5.3.0 - version: 5.3.0(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.33.0)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 5.3.0(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.33.0)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../tools/plugin-toolkit: + ../../../sdk/tools/plugin-toolkit: dependencies: '@gooddata/sdk-backend-spi': specifier: workspace:* @@ -8162,19 +8339,22 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../tools/react-app-template: + ../../../sdk/tools/react-app-template: dependencies: '@codemirror/state': specifier: 6.5.3 @@ -8298,11 +8478,14 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 source-map-loader: specifier: 4.0.2 version: 4.0.2(webpack@5.107.2) @@ -8322,7 +8505,7 @@ importers: specifier: 5.2.4 version: 5.2.4(tslib@2.8.1)(webpack-cli@7.0.3)(webpack@5.107.2) - ../../tools/reference-workspace: + ../../../sdk/tools/reference-workspace: dependencies: '@gooddata/sdk-backend-spi': specifier: workspace:* @@ -8380,16 +8563,19 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 - ../../tools/reference-workspace-mgmt: + ../../../sdk/tools/reference-workspace-mgmt: dependencies: '@gooddata/catalog-export': specifier: workspace:* @@ -8450,19 +8636,22 @@ importers: specifier: 0.66.0 version: 0.66.0 oxlint: - specifier: 1.57.0 - version: 1.57.0(oxlint-tsgolint@0.18.1) + specifier: 1.67.0 + version: 1.67.0(oxlint-tsgolint@0.22.1) + oxlint-plugin-eslint: + specifier: 1.82.0 + version: 1.82.0 oxlint-tsgolint: - specifier: 0.18.1 - version: 0.18.1 + specifier: 0.22.1 + version: 0.22.1 typescript: specifier: 7.0.2 version: 7.0.2 vitest: specifier: 4.1.8 - version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + version: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - ../../tools/stylelint-config: + ../../../sdk/tools/stylelint-config: dependencies: postcss: specifier: 8.5.26 @@ -9039,10 +9228,6 @@ packages: resolution: {integrity: sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.28.0': - resolution: {integrity: sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.39.5': resolution: {integrity: sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -9253,14 +9438,6 @@ packages: '@internationalized/string@3.2.9': resolution: {integrity: sha512-kzP/M/mbQxODlmOt4bIQZ2SBVUWUSqMLXooXixnX7noche8WHaQcA+nwFN1K2KCF/cp+LDUhcJsCicwkvhD1pg==} - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.1': - resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==} - engines: {node: 20 || >=22} - '@isaacs/cliui@9.0.0': resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} engines: {node: '>=18'} @@ -10200,154 +10377,154 @@ packages: cpu: [x64] os: [win32] - '@oxlint-tsgolint/darwin-arm64@0.18.1': - resolution: {integrity: sha512-CxSd15ZwHn70UJFTXVvy76bZ9zwI097cVyjvUFmYRJwvkQF3VnrTf2oe1gomUacErksvtqLgn9OKvZhLMYwvog==} + '@oxlint-tsgolint/darwin-arm64@0.22.1': + resolution: {integrity: sha512-4150Lpgc1YM09GcjA6GSrra1JoPjC7aOpfywLjWEY4vW0Sd1qKzqHF1WRaiw0/qUZ40OATYdv3aRd7ipPkWQbw==} cpu: [arm64] os: [darwin] - '@oxlint-tsgolint/darwin-x64@0.18.1': - resolution: {integrity: sha512-LE7VW/T/VcKhl3Z1ev5BusrxdlQ3DWweSeOB+qpBeur2h8+vCWq+M7tCO29C7lveBDfx1+rNwj4aiUVlA+Qs+g==} + '@oxlint-tsgolint/darwin-x64@0.22.1': + resolution: {integrity: sha512-vFWcPWYOgZs4HWcgS1EjUZg33NLcNfEYU49KGImmCfZWkflENrmBYV4HN/C0YeAPum6ZZ/goPSvQrB/cOD+NfA==} cpu: [x64] os: [darwin] - '@oxlint-tsgolint/linux-arm64@0.18.1': - resolution: {integrity: sha512-2AG8YIXVJJbnM0rcsJmzzWOjZXBu5REwowgUpbHZueF7OYM3wR7Xu8pXEpAojEHAtYYZ3X4rpPoetomkJx7kCw==} + '@oxlint-tsgolint/linux-arm64@0.22.1': + resolution: {integrity: sha512-6LiUpP0Zir3+29FvBm7Y28q/dBjSHqTZ5MhG1Ckw4fGhI4cAvbcwXaKvbjx1TP7rRmBNOoq/M5xdpHjTb+GAew==} cpu: [arm64] os: [linux] - '@oxlint-tsgolint/linux-x64@0.18.1': - resolution: {integrity: sha512-f8vDYPEdiwpA2JaDEkadTXfuqIgweQ8zcL4SX75EN2kkW2oAynjN7cd8m86uXDgB0JrcyOywbRtwnXdiIzXn2A==} + '@oxlint-tsgolint/linux-x64@0.22.1': + resolution: {integrity: sha512-fuX1hEQfpHauUbXADsfqVhRzrUrGabzGXbj5wsp2vKhV5uk/Rze8Mba9GdjFGECzvXudMGqHqxB4r6jGRdhxVA==} cpu: [x64] os: [linux] - '@oxlint-tsgolint/win32-arm64@0.18.1': - resolution: {integrity: sha512-fBdML05KMDAL9ebWeoHIzkyI86Eq6r9YH5UDRuXJ9vAIo1EnKo0ti7hLUxNdc2dy2FF/T4k98p5wkkXvLyXqfA==} + '@oxlint-tsgolint/win32-arm64@0.22.1': + resolution: {integrity: sha512-8SZidAj+jrbZf9ZjBEYW0tiNZ+KasqB2zgW26qdiPpQSF/DzURnPmXz651IeA9YsmbVdHGIooEHUmev6QJdquA==} cpu: [arm64] os: [win32] - '@oxlint-tsgolint/win32-x64@0.18.1': - resolution: {integrity: sha512-cYZMhNrsq9ZZ3OUWHyawqiS+c8HfieYG0zuZP2LbEuWWPfdZM/22iAlo608J+27G1s9RXQhvgX6VekwWbXbD7A==} + '@oxlint-tsgolint/win32-x64@0.22.1': + resolution: {integrity: sha512-QweSk9H5lFh5Y+WUf2Kq/OAN88V6+62ZwGhP38gqdRotI90luXSMkruFTj7Q2rYrzH4ZVNaSqx7NY8JpSfIzqg==} cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.57.0': - resolution: {integrity: sha512-C7EiyfAJG4B70496eV543nKiq5cH0o/xIh/ufbjQz3SIvHhlDDsyn+mRFh+aW8KskTyUpyH2LGWL8p2oN6bl1A==} + '@oxlint/binding-android-arm-eabi@1.67.0': + resolution: {integrity: sha512-VrSi571rDv1N8HaEDM+DEX8nmT0y9jJo8tzzW13vsOWTx59xQczCIJx68n2zWOXRT5YKZsOZXp4qkHN/10x4mw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.57.0': - resolution: {integrity: sha512-9i80AresjZ/FZf5xK8tKFbhQnijD4s1eOZw6/FHUwD59HEZbVLRc2C88ADYJfLZrF5XofWDiRX/Ja9KefCLy7w==} + '@oxlint/binding-android-arm64@1.67.0': + resolution: {integrity: sha512-l6+NdYxMoRohix5r5bbigW16LPicceCwGcQ6LKKuE1kUdjgFfQolJjrJsQYPFetIs78Gxj/G/f5TEGoTCwj9nQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.57.0': - resolution: {integrity: sha512-0eUfhRz5L2yKa9I8k3qpyl37XK3oBS5BvrgdVIx599WZK63P8sMbg+0s4IuxmIiZuBK68Ek+Z+gcKgeYf0otsg==} + '@oxlint/binding-darwin-arm64@1.67.0': + resolution: {integrity: sha512-jOzXxS1AxFxhImLIRbtGIMrEwaXcgMw3gR57WB1cRk8ai+vpr6726kxXqVvlNsrXtJ/FrmOm8RxlC0m8SW24Qg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.57.0': - resolution: {integrity: sha512-UvrSuzBaYOue+QMAcuDITe0k/Vhj6KZGjfnI6x+NkxBTke/VoM7ZisaxgNY0LWuBkTnd1OmeQfEQdQ48fRjkQg==} + '@oxlint/binding-darwin-x64@1.67.0': + resolution: {integrity: sha512-3DFAVY94OqjIZHXIPz37yGRSWwOFTAqChQ64/M69GYLawzP0KiwdhDNfqdKKYT0bTR/DNxmMnQsj3ns+8+X/Lg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.57.0': - resolution: {integrity: sha512-wtQq0dCoiw4bUwlsNVDJJ3pxJA218fOezpgtLKrbQqUtQJcM9yP8z+I9fu14aHg0uyAxIY+99toL6uBa2r7nxA==} + '@oxlint/binding-freebsd-x64@1.67.0': + resolution: {integrity: sha512-e4dDKZuLu8TR9DEBssWSDahlPgZBwojTTHZUvnjBRJfJJbpxYCjfjKfi0Z1+CSLMiJBwI2yCDtRM1XJQaARjmg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.57.0': - resolution: {integrity: sha512-qxFWl2BBBFcT4djKa+OtMdnLgoHEJXpqjyGwz8OhW35ImoCwR5qtAGqApNYce5260FQqoAHW8S8eZTjiX67Tsg==} + '@oxlint/binding-linux-arm-gnueabihf@1.67.0': + resolution: {integrity: sha512-BKytFdcQzbITV3xlnzDUDTEDtbUMCCiC4EaNTDZ4FyT8gdNvBC4gfiLucXp/sQl0XU3p7syTlorUWVVVBZab2g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.57.0': - resolution: {integrity: sha512-SQoIsBU7J0bDW15/f0/RvxHfY3Y0+eB/caKBQtNFbuerTiA6JCYx9P1MrrFTwY2dTm/lMgTSgskvCEYk2AtG/Q==} + '@oxlint/binding-linux-arm-musleabihf@1.67.0': + resolution: {integrity: sha512-XYAv0esBDX7BpTzRDjVX2Vdj+zndd8ll2dFQiaeQ6zTZr7A8GRDTN7fH3FP3jU+O0vCDx85oH/EtG7BzPgAXuw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.57.0': - resolution: {integrity: sha512-jqxYd1W6WMeozsCmqe9Rzbu3SRrGTyGDAipRlRggetyYbUksJqJKvUNTQtZR/KFoJPb+grnSm5SHhdWrywv3RQ==} + '@oxlint/binding-linux-arm64-gnu@1.67.0': + resolution: {integrity: sha512-zizRMjA0i6u/2B0evgda04iycu+MoNuf1pBy6Eh+1CjC5wMEG7qN5zdDKTCvFc0KSYSDM9QTG3gjZHirgtQuKg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-arm64-musl@1.57.0': - resolution: {integrity: sha512-i66WyEPVEvq9bxRUCJ/MP5EBfnTDN3nhwEdFZFTO5MmLLvzngfWEG3NSdXQzTT3vk5B9i6C2XSIYBh+aG6uqyg==} + '@oxlint/binding-linux-arm64-musl@1.67.0': + resolution: {integrity: sha512-zB/Tf6sUjmmvvbva9Gj3JTJ8rJ9t4I8/U0o6vSRtd0DRIsIuyegBwJAzhSUFQHdMijIRJkW0exs/yBhpw2S20w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxlint/binding-linux-ppc64-gnu@1.57.0': - resolution: {integrity: sha512-oMZDCwz4NobclZU3pH+V1/upVlJZiZvne4jQP+zhJwt+lmio4XXr4qG47CehvrW1Lx2YZiIHuxM2D4YpkG3KVA==} + '@oxlint/binding-linux-ppc64-gnu@1.67.0': + resolution: {integrity: sha512-kgU40Gt74CK0TCsF51KZymkIwN9U0BajKsMijB52zPqOeZU9NAHkA/NSQkZDHEaCakx42DxhXkODiAqf2b4Gug==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.57.0': - resolution: {integrity: sha512-uoBnjJ3MMEBbfnWC1jSFr7/nSCkcQYa72NYoNtLl1imshDnWSolYCjzb8LVCwYCCfLJXD+0gBLD7fyC14c0+0g==} + '@oxlint/binding-linux-riscv64-gnu@1.67.0': + resolution: {integrity: sha512-tOYhkk/iaG9aD3FvGpBFd1Lrw0x0RaVoJBxjUkfNzS50rC5NS5BteNCwgr8A2zCdADrIIoze6D7u6U5Ic++/iQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-musl@1.57.0': - resolution: {integrity: sha512-BdrwD7haPZ8a9KrZhKJRSj6jwCor+Z8tHFZ3PT89Y3Jq5v3LfMfEePeAmD0LOTWpiTmzSzdmyw9ijneapiVHKQ==} + '@oxlint/binding-linux-riscv64-musl@1.67.0': + resolution: {integrity: sha512-sEtywrPb+0b+tHYl1SDCrw903fiC4eyKoNqzP3v+f2JT3Xcv4NEYG+P8rj+eEnX7IWhqV/xj8/JmcmVj21CXaA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxlint/binding-linux-s390x-gnu@1.57.0': - resolution: {integrity: sha512-BNs+7ZNsRstVg2tpNxAXfMX/Iv5oZh204dVyb8Z37+/gCh+yZqNTlg6YwCLIMPSk5wLWIGOaQjT0GUOahKYImw==} + '@oxlint/binding-linux-s390x-gnu@1.67.0': + resolution: {integrity: sha512-BvR8Moa0zCLxroOx4vZaZN9nUfwAUpSTwjZdxZyKy4bv3PrzrXrxKR/ZQ0L9wNSvlPhnMJeZfa3q5w6ZCTuN6Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.57.0': - resolution: {integrity: sha512-AghS18w+XcENcAX0+BQGLiqjpqpaxKJa4cWWP0OWNLacs27vHBxu7TYkv9LUSGe5w8lOJHeMxcYfZNOAPqw2bg==} + '@oxlint/binding-linux-x64-gnu@1.67.0': + resolution: {integrity: sha512-mm2cxM6fksOpq6l0uFws8BUGKAR4dNa/cZCn37Npq7PFbhD5HDJqWfnoIvTaeRKMy5XdS2tO0MA0qbHDrnXAAA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-musl@1.57.0': - resolution: {integrity: sha512-E/FV3GB8phu/Rpkhz5T96hAiJlGzn91qX5yj5gU754P5cmVGXY1Jw/VSjDSlZBCY3VHjsVLdzgdkJaomEmcNOg==} + '@oxlint/binding-linux-x64-musl@1.67.0': + resolution: {integrity: sha512-WmbMuLapKyDlobMkXAaAL0Y+Uczh4LETfIfQsUpbId4Ip8Ai82/jqeYTOoUCkuuhBFapgqP253+d83tLKOksJg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxlint/binding-openharmony-arm64@1.57.0': - resolution: {integrity: sha512-xvZ2yZt0nUVfU14iuGv3V25jpr9pov5N0Wr28RXnHFxHCRxNDMtYPHV61gGLhN9IlXM96gI4pyYpLSJC5ClLCQ==} + '@oxlint/binding-openharmony-arm64@1.67.0': + resolution: {integrity: sha512-9g/PqxYJelzzTAOR5Y+RiRqdeydhEuXv2KxNeFcAKQ7UsvnWSY1OP4MsuPMbTO2Pf70tz7mFhl1j13H3fyh+8g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.57.0': - resolution: {integrity: sha512-Z4D8Pd0AyHBKeazhdIXeUUy5sIS3Mo0veOlzlDECg6PhRRKgEsBJCCV1n+keUZtQ04OP+i7+itS3kOykUyNhDg==} + '@oxlint/binding-win32-arm64-msvc@1.67.0': + resolution: {integrity: sha512-2VhwE6Gatb0vJGnN0TBuQMbKCOiZlSQ/zJvVWYLK4a9d4iDiJOen/yVQkGpmsJ90MuH66fzi0kEKI0jRQMDxGA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.57.0': - resolution: {integrity: sha512-StOZ9nFMVKvevicbQfql6Pouu9pgbeQnu60Fvhz2S6yfMaii+wnueLnqQ5I1JPgNF0Syew4voBlAaHD13wH6tw==} + '@oxlint/binding-win32-ia32-msvc@1.67.0': + resolution: {integrity: sha512-EQ3VExXfeM1InbE5+JjufhZZTWy+kHUwgt3yZR7gQ47Je/mE0WspQPan0OJznh493L5anM210YNJtH1PXjTSFg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.57.0': - resolution: {integrity: sha512-6PuxhYgth8TuW0+ABPOIkGdBYw+qYGxgIdXPHSVpiCDm+hqTTWCmC739St1Xni0DJBt8HnSHTG67i1y6gr8qrA==} + '@oxlint/binding-win32-x64-msvc@1.67.0': + resolution: {integrity: sha512-bw24y+/1MHS4QDkons3YyHkPT9uCMoLHHgQhb+mb8NOjTYwub1CZ+K9Ngr8aO5DMrDrkqHwTzlTwFP2vS8Y/ZQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -12075,8 +12252,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.11.21: - resolution: {integrity: sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==} + baseline-browser-mapping@2.11.23: + resolution: {integrity: sha512-le521dGVfxM7yRX0EikCoSz+rOK+hHzdDt/E7mG1jOJB/6WAAUuwVroLwaB7ApaUsz5Q0kFlDXLSA9MheUIfRQ==} engines: {node: '>=6.0.0'} hasBin: true @@ -13108,7 +13285,6 @@ packages: eslint@9.39.5: resolution: {integrity: sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true peerDependencies: jiti: '*' @@ -14731,10 +14907,6 @@ packages: minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - minimatch@10.1.1: - resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} - engines: {node: 20 || >=22} - minimatch@10.2.3: resolution: {integrity: sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==} engines: {node: 18 || 20 || >=22} @@ -14805,6 +14977,11 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + nanoid@3.3.18: resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -15004,19 +15181,26 @@ packages: vite-plus: optional: true - oxlint-tsgolint@0.18.1: - resolution: {integrity: sha512-Hgb0wMfuXBYL0ddY+1hAG8IIfC40ADwPnBuUaC6ENAuCtTF4dHwsy7mCYtQ2e7LoGvfoSJRY0+kqQRiembJ/jQ==} + oxlint-plugin-eslint@1.82.0: + resolution: {integrity: sha512-u86jGed4TZWbar5rXdxROcU+zaRXhKuzdvNwmmFPuhlhxv8LH5ioyjeuE/QgSUjzjFVPU0q5UokWHnkknvnw3w==} + engines: {node: ^20.19.0 || >=22.12.0} + + oxlint-tsgolint@0.22.1: + resolution: {integrity: sha512-YUSGSLUnoolsu8gxISEDio3q1rtsCozwfOzASUn3DT2mR2EeQ93uEEnen7s+6LpF+lyTQFln1pQfqwBh/fsVEg==} hasBin: true - oxlint@1.57.0: - resolution: {integrity: sha512-DGFsuBX5MFZX9yiDdtKjTrYPq45CZ8Fft6qCltJITYZxfwYjVdGf/6wycGYTACloauwIPxUnYhBVeZbHvleGhw==} + oxlint@1.67.0: + resolution: {integrity: sha512-blwwaHPdoH8piQ5/z0KHeoHFR7FZgl12WluKJfu4qFLPkZl6mK04PkLE45Fw1NxfBRSlh40Gu7MkxHUw++ociQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - oxlint-tsgolint: '>=0.15.0' + oxlint-tsgolint: '>=0.22.1' + vite-plus: '*' peerDependenciesMeta: oxlint-tsgolint: optional: true + vite-plus: + optional: true p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} @@ -15286,6 +15470,14 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + postcss@8.5.10: + resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.23: + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} + engines: {node: ^10 || ^12 || >=14} + postcss@8.5.26: resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} engines: {node: ^10 || ^12 || >=14} @@ -15808,8 +16000,8 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sass@1.100.0: - resolution: {integrity: sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==} + sass@1.104.0: + resolution: {integrity: sha512-btHMApW2bgolvClhRW8AlQJzgI9lUB3pPSofBQQT+E46GWvf9o0TVQ13SYv5riWZVFyPN+JNz3TKW9XhBlc10w==} engines: {node: '>=20.19.0'} hasBin: true @@ -17709,8 +17901,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.28.0': {} - '@eslint/js@9.39.5': {} '@eslint/object-schema@2.1.7': {} @@ -17982,12 +18172,6 @@ snapshots: dependencies: '@swc/helpers': 0.5.23 - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.1': - dependencies: - '@isaacs/balanced-match': 4.0.1 - '@isaacs/cliui@9.0.0': {} '@isaacs/fs-minipass@4.0.1': @@ -18006,11 +18190,11 @@ snapshots: '@dagrejs/graphlib': 2.2.4 '@joint/core': 4.3.0 - '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@7.0.2)(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@7.0.2)(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3))': dependencies: glob: 13.0.2 react-docgen-typescript: 2.4.0(typescript@7.0.2) - vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) optionalDependencies: typescript: 7.0.2 @@ -18342,12 +18526,12 @@ snapshots: find-pkg: 2.0.0 resolve: 1.22.8 - '@module-federation/vite@1.16.11(node-fetch@2.7.0)(typescript@7.0.2)(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3))': + '@module-federation/vite@1.16.11(node-fetch@2.7.0)(typescript@7.0.2)(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3))': dependencies: '@module-federation/dts-plugin': 2.6.0(node-fetch@2.7.0)(typescript@7.0.2) '@module-federation/runtime': 2.6.0(node-fetch@2.7.0) '@module-federation/sdk': 2.6.0(node-fetch@2.7.0) - vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) transitivePeerDependencies: - bufferutil - node-fetch @@ -18784,79 +18968,79 @@ snapshots: '@oxfmt/binding-win32-x64-msvc@0.66.0': optional: true - '@oxlint-tsgolint/darwin-arm64@0.18.1': + '@oxlint-tsgolint/darwin-arm64@0.22.1': optional: true - '@oxlint-tsgolint/darwin-x64@0.18.1': + '@oxlint-tsgolint/darwin-x64@0.22.1': optional: true - '@oxlint-tsgolint/linux-arm64@0.18.1': + '@oxlint-tsgolint/linux-arm64@0.22.1': optional: true - '@oxlint-tsgolint/linux-x64@0.18.1': + '@oxlint-tsgolint/linux-x64@0.22.1': optional: true - '@oxlint-tsgolint/win32-arm64@0.18.1': + '@oxlint-tsgolint/win32-arm64@0.22.1': optional: true - '@oxlint-tsgolint/win32-x64@0.18.1': + '@oxlint-tsgolint/win32-x64@0.22.1': optional: true - '@oxlint/binding-android-arm-eabi@1.57.0': + '@oxlint/binding-android-arm-eabi@1.67.0': optional: true - '@oxlint/binding-android-arm64@1.57.0': + '@oxlint/binding-android-arm64@1.67.0': optional: true - '@oxlint/binding-darwin-arm64@1.57.0': + '@oxlint/binding-darwin-arm64@1.67.0': optional: true - '@oxlint/binding-darwin-x64@1.57.0': + '@oxlint/binding-darwin-x64@1.67.0': optional: true - '@oxlint/binding-freebsd-x64@1.57.0': + '@oxlint/binding-freebsd-x64@1.67.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.57.0': + '@oxlint/binding-linux-arm-gnueabihf@1.67.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.57.0': + '@oxlint/binding-linux-arm-musleabihf@1.67.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.57.0': + '@oxlint/binding-linux-arm64-gnu@1.67.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.57.0': + '@oxlint/binding-linux-arm64-musl@1.67.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.57.0': + '@oxlint/binding-linux-ppc64-gnu@1.67.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.57.0': + '@oxlint/binding-linux-riscv64-gnu@1.67.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.57.0': + '@oxlint/binding-linux-riscv64-musl@1.67.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.57.0': + '@oxlint/binding-linux-s390x-gnu@1.67.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.57.0': + '@oxlint/binding-linux-x64-gnu@1.67.0': optional: true - '@oxlint/binding-linux-x64-musl@1.57.0': + '@oxlint/binding-linux-x64-musl@1.67.0': optional: true - '@oxlint/binding-openharmony-arm64@1.57.0': + '@oxlint/binding-openharmony-arm64@1.67.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.57.0': + '@oxlint/binding-win32-arm64-msvc@1.67.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.57.0': + '@oxlint/binding-win32-ia32-msvc@1.67.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.57.0': + '@oxlint/binding-win32-x64-msvc@1.67.0': optional: true '@parcel/watcher-android-arm64@2.6.0': @@ -19335,12 +19519,12 @@ snapshots: axe-core: 4.12.1 storybook: 10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1) - '@storybook/builder-vite@10.5.6(esbuild@0.28.1)(rollup@4.62.3)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3))(webpack@5.107.2(esbuild@0.28.1))': + '@storybook/builder-vite@10.5.6(esbuild@0.28.1)(rollup@4.62.3)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3))(webpack@5.107.2(esbuild@0.28.1))': dependencies: - '@storybook/csf-plugin': 10.5.6(esbuild@0.28.1)(rollup@4.62.3)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3))(webpack@5.107.2(esbuild@0.28.1)) + '@storybook/csf-plugin': 10.5.6(esbuild@0.28.1)(rollup@4.62.3)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3))(webpack@5.107.2(esbuild@0.28.1)) storybook: 10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1) ts-dedent: 2.3.0 - vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) transitivePeerDependencies: - esbuild - rollup @@ -19384,14 +19568,14 @@ snapshots: - utf-8-validate - vite-plus - '@storybook/csf-plugin@10.5.6(esbuild@0.28.1)(rollup@4.62.3)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3))(webpack@5.107.2(esbuild@0.28.1))': + '@storybook/csf-plugin@10.5.6(esbuild@0.28.1)(rollup@4.62.3)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3))(webpack@5.107.2(esbuild@0.28.1))': dependencies: storybook: 10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1) unplugin: 2.3.11 optionalDependencies: esbuild: 0.28.1 rollup: 4.62.3 - vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) webpack: 5.107.2(esbuild@0.28.1) '@storybook/global@5.0.0': {} @@ -19409,11 +19593,11 @@ snapshots: '@types/react': 19.1.11 '@types/react-dom': 19.1.7(@types/react@19.1.11) - '@storybook/react-vite@10.5.6(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(esbuild@0.28.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.62.3)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(typescript@7.0.2)(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3))(webpack@5.107.2(esbuild@0.28.1))': + '@storybook/react-vite@10.5.6(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(esbuild@0.28.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.62.3)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(typescript@7.0.2)(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3))(webpack@5.107.2(esbuild@0.28.1))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@7.0.2)(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@7.0.2)(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) '@rollup/pluginutils': 5.4.0(rollup@4.62.3) - '@storybook/builder-vite': 10.5.6(esbuild@0.28.1)(rollup@4.62.3)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3))(webpack@5.107.2(esbuild@0.28.1)) + '@storybook/builder-vite': 10.5.6(esbuild@0.28.1)(rollup@4.62.3)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3))(webpack@5.107.2(esbuild@0.28.1)) '@storybook/react': 10.5.6(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1))(typescript@7.0.2) empathic: 2.0.1 magic-string: 0.30.21 @@ -19423,7 +19607,7 @@ snapshots: resolve: 1.22.12 storybook: 10.5.6(@types/react@19.1.11)(prettier@3.9.6)(react@19.1.1) tsconfig-paths: 4.2.0 - vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) optionalDependencies: typescript: 7.0.2 transitivePeerDependencies: @@ -19843,8 +20027,8 @@ snapshots: '@typescript-eslint/project-service@8.58.0': dependencies: - '@typescript-eslint/tsconfig-utils': 8.65.0 - '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/tsconfig-utils': 8.58.0 + '@typescript-eslint/types': 8.58.0 debug: 4.4.3 typescript: 6.0.3 transitivePeerDependencies: @@ -20087,10 +20271,10 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.12.2': optional: true - '@vitejs/plugin-react@6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3))': + '@vitejs/plugin-react@6.0.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) '@vitest/coverage-v8@4.1.8(vitest@4.1.8)': dependencies: @@ -20104,7 +20288,7 @@ snapshots: obug: 2.1.4 std-env: 4.2.0 tinyrainbow: 3.1.0 - vitest: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vitest: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) '@vitest/eslint-plugin@1.6.19(@typescript-eslint/eslint-plugin@8.58.0(@typescript-eslint/parser@8.58.0(eslint@9.39.5(jiti@2.6.1)))(eslint@9.39.5(jiti@2.6.1)))(eslint@9.39.5(jiti@2.6.1))(typescript@7.0.2)(vitest@4.1.8)': dependencies: @@ -20114,7 +20298,7 @@ snapshots: optionalDependencies: '@typescript-eslint/eslint-plugin': 8.58.0(@typescript-eslint/parser@8.58.0(eslint@9.39.5(jiti@2.6.1)))(eslint@9.39.5(jiti@2.6.1)) typescript: 7.0.2 - vitest: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vitest: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color @@ -20135,13 +20319,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.8(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3))': + '@vitest/mocker@4.1.8(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3))': dependencies: '@vitest/spy': 4.1.8 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) '@vitest/pretty-format@3.2.4': dependencies: @@ -20288,11 +20472,11 @@ snapshots: acorn-loose@8.5.2: dependencies: - acorn: 8.17.0 + acorn: 8.16.0 acorn-walk@8.3.5: dependencies: - acorn: 8.17.0 + acorn: 8.16.0 acorn@8.16.0: {} @@ -20618,7 +20802,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.11.21: {} + baseline-browser-mapping@2.11.23: {} basic-ftp@5.3.1: {} @@ -20680,7 +20864,7 @@ snapshots: browserslist@4.28.9: dependencies: - baseline-browser-mapping: 2.11.21 + baseline-browser-mapping: 2.11.23 caniuse-lite: 1.0.30001810 electron-to-chromium: 1.5.422 node-releases: 2.0.54 @@ -21741,7 +21925,7 @@ snapshots: functional-red-black-tree: 1.0.1 jsx-ast-utils-x: 0.1.0 lodash.merge: 4.6.2 - minimatch: 10.1.1 + minimatch: 10.2.5 scslre: 0.3.0 semver: 7.7.3 typescript: 6.0.3 @@ -22452,7 +22636,7 @@ snapshots: semver: 7.7.4 optionalDependencies: jest-diff: 29.7.0 - vitest: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vitest: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) html-webpack-plugin@5.6.4(webpack@5.107.2): dependencies: @@ -23700,10 +23884,6 @@ snapshots: minimalistic-assert@1.0.1: {} - minimatch@10.1.1: - dependencies: - '@isaacs/brace-expansion': 5.0.1 - minimatch@10.2.3: dependencies: brace-expansion: 5.0.8 @@ -23765,6 +23945,8 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 + nanoid@3.3.16: {} + nanoid@3.3.18: {} napi-postinstall@0.3.4: {} @@ -24055,37 +24237,39 @@ snapshots: '@oxfmt/binding-win32-ia32-msvc': 0.66.0 '@oxfmt/binding-win32-x64-msvc': 0.66.0 - oxlint-tsgolint@0.18.1: + oxlint-plugin-eslint@1.82.0: {} + + oxlint-tsgolint@0.22.1: optionalDependencies: - '@oxlint-tsgolint/darwin-arm64': 0.18.1 - '@oxlint-tsgolint/darwin-x64': 0.18.1 - '@oxlint-tsgolint/linux-arm64': 0.18.1 - '@oxlint-tsgolint/linux-x64': 0.18.1 - '@oxlint-tsgolint/win32-arm64': 0.18.1 - '@oxlint-tsgolint/win32-x64': 0.18.1 - - oxlint@1.57.0(oxlint-tsgolint@0.18.1): + '@oxlint-tsgolint/darwin-arm64': 0.22.1 + '@oxlint-tsgolint/darwin-x64': 0.22.1 + '@oxlint-tsgolint/linux-arm64': 0.22.1 + '@oxlint-tsgolint/linux-x64': 0.22.1 + '@oxlint-tsgolint/win32-arm64': 0.22.1 + '@oxlint-tsgolint/win32-x64': 0.22.1 + + oxlint@1.67.0(oxlint-tsgolint@0.22.1): optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.57.0 - '@oxlint/binding-android-arm64': 1.57.0 - '@oxlint/binding-darwin-arm64': 1.57.0 - '@oxlint/binding-darwin-x64': 1.57.0 - '@oxlint/binding-freebsd-x64': 1.57.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.57.0 - '@oxlint/binding-linux-arm-musleabihf': 1.57.0 - '@oxlint/binding-linux-arm64-gnu': 1.57.0 - '@oxlint/binding-linux-arm64-musl': 1.57.0 - '@oxlint/binding-linux-ppc64-gnu': 1.57.0 - '@oxlint/binding-linux-riscv64-gnu': 1.57.0 - '@oxlint/binding-linux-riscv64-musl': 1.57.0 - '@oxlint/binding-linux-s390x-gnu': 1.57.0 - '@oxlint/binding-linux-x64-gnu': 1.57.0 - '@oxlint/binding-linux-x64-musl': 1.57.0 - '@oxlint/binding-openharmony-arm64': 1.57.0 - '@oxlint/binding-win32-arm64-msvc': 1.57.0 - '@oxlint/binding-win32-ia32-msvc': 1.57.0 - '@oxlint/binding-win32-x64-msvc': 1.57.0 - oxlint-tsgolint: 0.18.1 + '@oxlint/binding-android-arm-eabi': 1.67.0 + '@oxlint/binding-android-arm64': 1.67.0 + '@oxlint/binding-darwin-arm64': 1.67.0 + '@oxlint/binding-darwin-x64': 1.67.0 + '@oxlint/binding-freebsd-x64': 1.67.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.67.0 + '@oxlint/binding-linux-arm-musleabihf': 1.67.0 + '@oxlint/binding-linux-arm64-gnu': 1.67.0 + '@oxlint/binding-linux-arm64-musl': 1.67.0 + '@oxlint/binding-linux-ppc64-gnu': 1.67.0 + '@oxlint/binding-linux-riscv64-gnu': 1.67.0 + '@oxlint/binding-linux-riscv64-musl': 1.67.0 + '@oxlint/binding-linux-s390x-gnu': 1.67.0 + '@oxlint/binding-linux-x64-gnu': 1.67.0 + '@oxlint/binding-linux-x64-musl': 1.67.0 + '@oxlint/binding-openharmony-arm64': 1.67.0 + '@oxlint/binding-win32-arm64-msvc': 1.67.0 + '@oxlint/binding-win32-ia32-msvc': 1.67.0 + '@oxlint/binding-win32-x64-msvc': 1.67.0 + oxlint-tsgolint: 0.22.1 p-limit@2.3.0: dependencies: @@ -24309,9 +24493,9 @@ snapshots: postcss-resolve-nested-selector@0.1.6: {} - postcss-safe-parser@7.0.1(postcss@8.5.26): + postcss-safe-parser@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.26 + postcss: 8.5.10 postcss-scss@4.0.9(postcss@8.5.26): dependencies: @@ -24328,6 +24512,18 @@ snapshots: postcss-value-parser@4.2.0: {} + postcss@8.5.10: + dependencies: + nanoid: 3.3.16 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.23: + dependencies: + nanoid: 3.3.16 + picocolors: 1.1.1 + source-map-js: 1.2.1 + postcss@8.5.26: dependencies: nanoid: 3.3.18 @@ -24988,7 +25184,7 @@ snapshots: safer-buffer@2.1.2: {} - sass@1.100.0: + sass@1.104.0: dependencies: chokidar: 5.0.0 immutable: 5.1.9 @@ -25481,9 +25677,9 @@ snapshots: micromatch: 4.0.8 normalize-path: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.26 + postcss: 8.5.10 postcss-resolve-nested-selector: 0.1.6 - postcss-safe-parser: 7.0.1(postcss@8.5.26) + postcss-safe-parser: 7.0.1(postcss@8.5.10) postcss-selector-parser: 7.1.4 postcss-value-parser: 4.2.0 resolve-from: 5.0.0 @@ -25735,7 +25931,7 @@ snapshots: tsconfig-paths-webpack-plugin@4.2.0: dependencies: chalk: 4.1.2 - enhanced-resolve: 5.24.3 + enhanced-resolve: 5.20.1 tapable: 2.3.3 tsconfig-paths: 4.2.0 @@ -26000,13 +26196,13 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite-node@5.3.0(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.33.0)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3): + vite-node@5.3.0(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.33.0)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3): dependencies: cac: 6.7.14 es-module-lexer: 2.3.1 obug: 2.1.4 pathe: 2.0.3 - vite: 7.3.6(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.33.0)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vite: 7.3.6(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.33.0)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) transitivePeerDependencies: - '@types/node' - jiti @@ -26020,11 +26216,11 @@ snapshots: - tsx - yaml - vite-plugin-css-injected-by-js@3.1.1(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)): + vite-plugin-css-injected-by-js@3.1.1(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)): dependencies: - vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - vite-plugin-html@3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)): + vite-plugin-html@3.2.2(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)): dependencies: '@rollup/pluginutils': 4.2.1 colorette: 2.0.20 @@ -26038,17 +26234,17 @@ snapshots: html-minifier-terser: 6.1.0 node-html-parser: 5.4.2 pathe: 0.2.0 - vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - vite-plugin-static-copy@4.1.0(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)): + vite-plugin-static-copy@4.1.0(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)): dependencies: chokidar: 3.6.0 p-map: 7.0.6 picocolors: 1.1.1 tinyglobby: 0.2.17 - vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - vite@7.3.6(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.33.0)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3): + vite@7.3.6(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.33.0)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3): dependencies: esbuild: 0.28.1 fdir: 6.5.0(picomatch@4.0.5) @@ -26061,15 +26257,15 @@ snapshots: fsevents: 2.3.3 jiti: 2.6.1 lightningcss: 1.33.0 - sass: 1.100.0 + sass: 1.104.0 terser: 5.49.0 yaml: 2.8.3 - vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3): + vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3): dependencies: lightningcss: 1.33.0 picomatch: 4.0.5 - postcss: 8.5.26 + postcss: 8.5.23 rolldown: 1.0.3 tinyglobby: 0.2.17 optionalDependencies: @@ -26077,7 +26273,7 @@ snapshots: esbuild: 0.28.1 fsevents: 2.3.3 jiti: 2.6.1 - sass: 1.100.0 + sass: 1.104.0 terser: 5.49.0 yaml: 2.8.3 @@ -26089,12 +26285,12 @@ snapshots: dom-accessibility-api: 0.6.3 lodash-es: 4.18.1 redent: 4.0.0 - vitest: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vitest: 4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) - vitest@4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3): + vitest@4.1.8(@types/node@24.12.0)(@vitest/coverage-v8@4.1.8)(esbuild@0.28.1)(happy-dom@20.12.0)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3): dependencies: '@vitest/expect': 4.1.8 - '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3)) + '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3)) '@vitest/pretty-format': 4.1.8 '@vitest/runner': 4.1.8 '@vitest/snapshot': 4.1.8 @@ -26111,7 +26307,7 @@ snapshots: tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.100.0)(terser@5.49.0)(yaml@2.8.3) + vite: 8.0.16(@types/node@24.12.0)(esbuild@0.28.1)(jiti@2.6.1)(sass@1.104.0)(terser@5.49.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.12.0 diff --git a/common/config/rush/version-policies.json b/common/config/rush/version-policies.json index 3cb269ec38e..632b011f7e2 100644 --- a/common/config/rush/version-policies.json +++ b/common/config/rush/version-policies.json @@ -2,14 +2,14 @@ { "definitionName": "lockStepVersion", "policyName": "sdk", - "version": "11.57.0-alpha.1", + "version": "11.57.0-alpha.3", "nextBump": "prerelease", "mainProject": "@gooddata/sdk-ui-all" }, { "definitionName": "lockStepVersion", "policyName": "sdk-not-npm-publish", - "version": "11.57.0-alpha.1", + "version": "11.57.0-alpha.3", "nextBump": "prerelease", "mainProject": "@gooddata/sdk-ui-all" } diff --git a/common/scripts/install-run-rush.js b/common/scripts/install-run-rush.js index 5b1da11a79b..4daf9508912 100644 --- a/common/scripts/install-run-rush.js +++ b/common/scripts/install-run-rush.js @@ -1,3 +1,5 @@ +// (C) 2026 GoodData Corporation + // THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. // // This script is intended for usage in an automated build environment where the Rush command may not have diff --git a/common/scripts/install-run.js b/common/scripts/install-run.js index 75d6014e61c..875968d0f25 100644 --- a/common/scripts/install-run.js +++ b/common/scripts/install-run.js @@ -1,3 +1,5 @@ +// (C) 2026 GoodData Corporation + // THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. // // This script is intended for usage in an automated build environment where a Node tool may not have diff --git a/examples/playground/package.json b/examples/playground/package.json index 080c7d16fab..ea762e474ac 100644 --- a/examples/playground/package.json +++ b/examples/playground/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/playground", - "version": "11.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": true, "description": "GoodData.UI SDK - Developer Playground", "license": "LicenseRef-LICENSE", @@ -67,12 +67,13 @@ "maplibre-gl": "^4.7.1", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "react": "19.1.1", "react-dom": "19.1.1", "rolldown": "1.0.3", - "sass": "1.100.0", + "sass": "1.104.0", "ts-invariant": "0.10.3", "tslib": "2.8.1", "typescript": "7.0.2", diff --git a/examples/playground/vite.config.ts b/examples/playground/vite.config.ts index c72d2ccb932..c960b7939dd 100644 --- a/examples/playground/vite.config.ts +++ b/examples/playground/vite.config.ts @@ -221,7 +221,6 @@ try { const serverOptions = httpsOptions ? { https: httpsOptions } : {}; // https://vitejs.dev/config/ -// eslint-disable-next-line no-restricted-exports export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), ""); const backendUrl = env["VITE_BACKEND_URL"] ?? "https://staging.dev-latest.stg11.panther.intgdc.com"; diff --git a/examples/sdk-interactive-examples/examples-template/package.json b/examples/sdk-interactive-examples/examples-template/package.json index 17f08ef7c9d..22789a72e79 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "GoodData interactive example template", "license": "LicenseRef-LICENSE", @@ -61,8 +61,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "process": "0.11.10", "rolldown": "1.0.3", "typescript": "7.0.2", diff --git a/examples/sdk-interactive-examples/examples-template/scripts/updateWorkspaceVersion.mjs b/examples/sdk-interactive-examples/examples-template/scripts/updateWorkspaceVersion.mjs index a815e858593..3f45c9395d9 100644 --- a/examples/sdk-interactive-examples/examples-template/scripts/updateWorkspaceVersion.mjs +++ b/examples/sdk-interactive-examples/examples-template/scripts/updateWorkspaceVersion.mjs @@ -2,7 +2,7 @@ import fs from "fs"; -import packageData from "../package.json" assert { type: "json" }; +import packageData from "../package.json" with { type: "json" }; const packageJsonPath = "./package.json"; @@ -25,4 +25,5 @@ packageData.devDependencies = updatedDevDependencies; await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageData, null, 2)); +// oxlint-disable-next-line eslint-js/no-console console.log("Updated package.json with version:", packageData.version); diff --git a/examples/sdk-interactive-examples/examples-template/vite.config.ts b/examples/sdk-interactive-examples/examples-template/vite.config.ts index 3a04ff46b81..da3b113b984 100644 --- a/examples/sdk-interactive-examples/examples-template/vite.config.ts +++ b/examples/sdk-interactive-examples/examples-template/vite.config.ts @@ -9,6 +9,7 @@ import packageJson from "./package.json" with { type: "json" }; const backendUrl = packageJson.gooddata.hostname; const workspaceId = packageJson.gooddata.workspaceId; +// oxlint-disable-next-line eslint-js/no-console console.log("backendUrl: ", backendUrl); export default defineConfig({ diff --git a/examples/sdk-interactive-examples/examples/example-attributefilter/package.json b/examples/sdk-interactive-examples/examples/example-attributefilter/package.json index b67dba9cf46..fc65a1aed4b 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "This example demonstrates how to use the AttributeFilter component to filter data in a visualization.", "license": "LicenseRef-LICENSE", @@ -61,8 +61,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "process": "0.11.10", "rolldown": "1.0.3", "typescript": "7.0.2", diff --git a/examples/sdk-interactive-examples/examples/example-attributefilter/scripts/updateWorkspaceVersion.mjs b/examples/sdk-interactive-examples/examples/example-attributefilter/scripts/updateWorkspaceVersion.mjs index a409578244e..3f45c9395d9 100644 --- a/examples/sdk-interactive-examples/examples/example-attributefilter/scripts/updateWorkspaceVersion.mjs +++ b/examples/sdk-interactive-examples/examples/example-attributefilter/scripts/updateWorkspaceVersion.mjs @@ -1,7 +1,8 @@ // (C) 2026 GoodData Corporation + import fs from "fs"; -import packageData from "../package.json" assert { type: "json" }; +import packageData from "../package.json" with { type: "json" }; const packageJsonPath = "./package.json"; @@ -24,4 +25,5 @@ packageData.devDependencies = updatedDevDependencies; await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageData, null, 2)); +// oxlint-disable-next-line eslint-js/no-console console.log("Updated package.json with version:", packageData.version); diff --git a/examples/sdk-interactive-examples/examples/example-attributefilter/vite.config.ts b/examples/sdk-interactive-examples/examples/example-attributefilter/vite.config.ts index 3a04ff46b81..da3b113b984 100644 --- a/examples/sdk-interactive-examples/examples/example-attributefilter/vite.config.ts +++ b/examples/sdk-interactive-examples/examples/example-attributefilter/vite.config.ts @@ -9,6 +9,7 @@ import packageJson from "./package.json" with { type: "json" }; const backendUrl = packageJson.gooddata.hostname; const workspaceId = packageJson.gooddata.workspaceId; +// oxlint-disable-next-line eslint-js/no-console console.log("backendUrl: ", backendUrl); export default defineConfig({ diff --git a/examples/sdk-interactive-examples/examples/example-chartconfig/package.json b/examples/sdk-interactive-examples/examples/example-chartconfig/package.json index e5312c573dc..2f98d6b4f87 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "This interactive example demonstrates how to manipulate the chart config.", "license": "LicenseRef-LICENSE", @@ -61,8 +61,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "process": "0.11.10", "rolldown": "1.0.3", "typescript": "7.0.2", diff --git a/examples/sdk-interactive-examples/examples/example-chartconfig/scripts/updateWorkspaceVersion.mjs b/examples/sdk-interactive-examples/examples/example-chartconfig/scripts/updateWorkspaceVersion.mjs index a409578244e..3f45c9395d9 100644 --- a/examples/sdk-interactive-examples/examples/example-chartconfig/scripts/updateWorkspaceVersion.mjs +++ b/examples/sdk-interactive-examples/examples/example-chartconfig/scripts/updateWorkspaceVersion.mjs @@ -1,7 +1,8 @@ // (C) 2026 GoodData Corporation + import fs from "fs"; -import packageData from "../package.json" assert { type: "json" }; +import packageData from "../package.json" with { type: "json" }; const packageJsonPath = "./package.json"; @@ -24,4 +25,5 @@ packageData.devDependencies = updatedDevDependencies; await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageData, null, 2)); +// oxlint-disable-next-line eslint-js/no-console console.log("Updated package.json with version:", packageData.version); diff --git a/examples/sdk-interactive-examples/examples/example-chartconfig/vite.config.ts b/examples/sdk-interactive-examples/examples/example-chartconfig/vite.config.ts index 3a04ff46b81..da3b113b984 100644 --- a/examples/sdk-interactive-examples/examples/example-chartconfig/vite.config.ts +++ b/examples/sdk-interactive-examples/examples/example-chartconfig/vite.config.ts @@ -9,6 +9,7 @@ import packageJson from "./package.json" with { type: "json" }; const backendUrl = packageJson.gooddata.hostname; const workspaceId = packageJson.gooddata.workspaceId; +// oxlint-disable-next-line eslint-js/no-console console.log("backendUrl: ", backendUrl); export default defineConfig({ diff --git a/examples/sdk-interactive-examples/examples/example-columnchart/package.json b/examples/sdk-interactive-examples/examples/example-columnchart/package.json index bb93cf2ae7a..ddd80f30114 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "This example demonstrates the usage of the ColumnChart component with the viewBy and stackBy properties.", "license": "LicenseRef-LICENSE", @@ -61,8 +61,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "process": "0.11.10", "rolldown": "1.0.3", "typescript": "7.0.2", diff --git a/examples/sdk-interactive-examples/examples/example-columnchart/scripts/updateWorkspaceVersion.mjs b/examples/sdk-interactive-examples/examples/example-columnchart/scripts/updateWorkspaceVersion.mjs index a409578244e..3f45c9395d9 100644 --- a/examples/sdk-interactive-examples/examples/example-columnchart/scripts/updateWorkspaceVersion.mjs +++ b/examples/sdk-interactive-examples/examples/example-columnchart/scripts/updateWorkspaceVersion.mjs @@ -1,7 +1,8 @@ // (C) 2026 GoodData Corporation + import fs from "fs"; -import packageData from "../package.json" assert { type: "json" }; +import packageData from "../package.json" with { type: "json" }; const packageJsonPath = "./package.json"; @@ -24,4 +25,5 @@ packageData.devDependencies = updatedDevDependencies; await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageData, null, 2)); +// oxlint-disable-next-line eslint-js/no-console console.log("Updated package.json with version:", packageData.version); diff --git a/examples/sdk-interactive-examples/examples/example-columnchart/vite.config.ts b/examples/sdk-interactive-examples/examples/example-columnchart/vite.config.ts index 3a04ff46b81..da3b113b984 100644 --- a/examples/sdk-interactive-examples/examples/example-columnchart/vite.config.ts +++ b/examples/sdk-interactive-examples/examples/example-columnchart/vite.config.ts @@ -9,6 +9,7 @@ import packageJson from "./package.json" with { type: "json" }; const backendUrl = packageJson.gooddata.hostname; const workspaceId = packageJson.gooddata.workspaceId; +// oxlint-disable-next-line eslint-js/no-console console.log("backendUrl: ", backendUrl); export default defineConfig({ diff --git a/examples/sdk-interactive-examples/examples/example-combochart/package.json b/examples/sdk-interactive-examples/examples/example-combochart/package.json index 20e6a550901..a558e74c104 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "Example demonstrates ComboChart secondaryMeasures definition. ", "license": "LicenseRef-LICENSE", @@ -61,8 +61,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "process": "0.11.10", "rolldown": "1.0.3", "typescript": "7.0.2", diff --git a/examples/sdk-interactive-examples/examples/example-combochart/scripts/updateWorkspaceVersion.mjs b/examples/sdk-interactive-examples/examples/example-combochart/scripts/updateWorkspaceVersion.mjs index a409578244e..3f45c9395d9 100644 --- a/examples/sdk-interactive-examples/examples/example-combochart/scripts/updateWorkspaceVersion.mjs +++ b/examples/sdk-interactive-examples/examples/example-combochart/scripts/updateWorkspaceVersion.mjs @@ -1,7 +1,8 @@ // (C) 2026 GoodData Corporation + import fs from "fs"; -import packageData from "../package.json" assert { type: "json" }; +import packageData from "../package.json" with { type: "json" }; const packageJsonPath = "./package.json"; @@ -24,4 +25,5 @@ packageData.devDependencies = updatedDevDependencies; await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageData, null, 2)); +// oxlint-disable-next-line eslint-js/no-console console.log("Updated package.json with version:", packageData.version); diff --git a/examples/sdk-interactive-examples/examples/example-combochart/vite.config.ts b/examples/sdk-interactive-examples/examples/example-combochart/vite.config.ts index 3a04ff46b81..da3b113b984 100644 --- a/examples/sdk-interactive-examples/examples/example-combochart/vite.config.ts +++ b/examples/sdk-interactive-examples/examples/example-combochart/vite.config.ts @@ -9,6 +9,7 @@ import packageJson from "./package.json" with { type: "json" }; const backendUrl = packageJson.gooddata.hostname; const workspaceId = packageJson.gooddata.workspaceId; +// oxlint-disable-next-line eslint-js/no-console console.log("backendUrl: ", backendUrl); export default defineConfig({ diff --git a/examples/sdk-interactive-examples/examples/example-dashboard/package.json b/examples/sdk-interactive-examples/examples/example-dashboard/package.json index 74256133401..1a7e1926cb4 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "This example shows how to use the Dashboard component.", "license": "LicenseRef-LICENSE", @@ -61,8 +61,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "process": "0.11.10", "rolldown": "1.0.3", "typescript": "7.0.2", diff --git a/examples/sdk-interactive-examples/examples/example-dashboard/scripts/updateWorkspaceVersion.mjs b/examples/sdk-interactive-examples/examples/example-dashboard/scripts/updateWorkspaceVersion.mjs index 2fe8462f644..3f45c9395d9 100644 --- a/examples/sdk-interactive-examples/examples/example-dashboard/scripts/updateWorkspaceVersion.mjs +++ b/examples/sdk-interactive-examples/examples/example-dashboard/scripts/updateWorkspaceVersion.mjs @@ -1,4 +1,5 @@ // (C) 2026 GoodData Corporation + import fs from "fs"; import packageData from "../package.json" with { type: "json" }; @@ -24,4 +25,5 @@ packageData.devDependencies = updatedDevDependencies; await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageData, null, 2)); +// oxlint-disable-next-line eslint-js/no-console console.log("Updated package.json with version:", packageData.version); diff --git a/examples/sdk-interactive-examples/examples/example-dashboard/vite.config.ts b/examples/sdk-interactive-examples/examples/example-dashboard/vite.config.ts index 3a04ff46b81..da3b113b984 100644 --- a/examples/sdk-interactive-examples/examples/example-dashboard/vite.config.ts +++ b/examples/sdk-interactive-examples/examples/example-dashboard/vite.config.ts @@ -9,6 +9,7 @@ import packageJson from "./package.json" with { type: "json" }; const backendUrl = packageJson.gooddata.hostname; const workspaceId = packageJson.gooddata.workspaceId; +// oxlint-disable-next-line eslint-js/no-console console.log("backendUrl: ", backendUrl); export default defineConfig({ diff --git a/examples/sdk-interactive-examples/examples/example-datefilter/package.json b/examples/sdk-interactive-examples/examples/example-datefilter/package.json index caa4a8cfff8..79465f4af92 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "Example demonstrates usage of Date Filter component.", "license": "LicenseRef-LICENSE", @@ -61,8 +61,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "process": "0.11.10", "rolldown": "1.0.3", "typescript": "7.0.2", diff --git a/examples/sdk-interactive-examples/examples/example-datefilter/scripts/updateWorkspaceVersion.mjs b/examples/sdk-interactive-examples/examples/example-datefilter/scripts/updateWorkspaceVersion.mjs index a409578244e..3f45c9395d9 100644 --- a/examples/sdk-interactive-examples/examples/example-datefilter/scripts/updateWorkspaceVersion.mjs +++ b/examples/sdk-interactive-examples/examples/example-datefilter/scripts/updateWorkspaceVersion.mjs @@ -1,7 +1,8 @@ // (C) 2026 GoodData Corporation + import fs from "fs"; -import packageData from "../package.json" assert { type: "json" }; +import packageData from "../package.json" with { type: "json" }; const packageJsonPath = "./package.json"; @@ -24,4 +25,5 @@ packageData.devDependencies = updatedDevDependencies; await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageData, null, 2)); +// oxlint-disable-next-line eslint-js/no-console console.log("Updated package.json with version:", packageData.version); diff --git a/examples/sdk-interactive-examples/examples/example-datefilter/vite.config.ts b/examples/sdk-interactive-examples/examples/example-datefilter/vite.config.ts index 3a04ff46b81..da3b113b984 100644 --- a/examples/sdk-interactive-examples/examples/example-datefilter/vite.config.ts +++ b/examples/sdk-interactive-examples/examples/example-datefilter/vite.config.ts @@ -9,6 +9,7 @@ import packageJson from "./package.json" with { type: "json" }; const backendUrl = packageJson.gooddata.hostname; const workspaceId = packageJson.gooddata.workspaceId; +// oxlint-disable-next-line eslint-js/no-console console.log("backendUrl: ", backendUrl); export default defineConfig({ diff --git a/examples/sdk-interactive-examples/examples/example-dependentfilters/package.json b/examples/sdk-interactive-examples/examples/example-dependentfilters/package.json index ce4f2e3b366..d672d4f5eab 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "This example demonstrates how to use multiple attribute filters linked together to filter data in a visualization.", "license": "LicenseRef-LICENSE", @@ -61,8 +61,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "process": "0.11.10", "rolldown": "1.0.3", "typescript": "7.0.2", diff --git a/examples/sdk-interactive-examples/examples/example-dependentfilters/scripts/updateWorkspaceVersion.mjs b/examples/sdk-interactive-examples/examples/example-dependentfilters/scripts/updateWorkspaceVersion.mjs index 2fe8462f644..3f45c9395d9 100644 --- a/examples/sdk-interactive-examples/examples/example-dependentfilters/scripts/updateWorkspaceVersion.mjs +++ b/examples/sdk-interactive-examples/examples/example-dependentfilters/scripts/updateWorkspaceVersion.mjs @@ -1,4 +1,5 @@ // (C) 2026 GoodData Corporation + import fs from "fs"; import packageData from "../package.json" with { type: "json" }; @@ -24,4 +25,5 @@ packageData.devDependencies = updatedDevDependencies; await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageData, null, 2)); +// oxlint-disable-next-line eslint-js/no-console console.log("Updated package.json with version:", packageData.version); diff --git a/examples/sdk-interactive-examples/examples/example-dependentfilters/vite.config.ts b/examples/sdk-interactive-examples/examples/example-dependentfilters/vite.config.ts index 3a04ff46b81..da3b113b984 100644 --- a/examples/sdk-interactive-examples/examples/example-dependentfilters/vite.config.ts +++ b/examples/sdk-interactive-examples/examples/example-dependentfilters/vite.config.ts @@ -9,6 +9,7 @@ import packageJson from "./package.json" with { type: "json" }; const backendUrl = packageJson.gooddata.hostname; const workspaceId = packageJson.gooddata.workspaceId; +// oxlint-disable-next-line eslint-js/no-console console.log("backendUrl: ", backendUrl); export default defineConfig({ diff --git a/examples/sdk-interactive-examples/examples/example-execute/package.json b/examples/sdk-interactive-examples/examples/example-execute/package.json index 46571274b17..f3196f5c534 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "This example demonstrates using Execute component and build custom visualization.", "license": "LicenseRef-LICENSE", @@ -64,8 +64,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "process": "0.11.10", "rolldown": "1.0.3", "typescript": "7.0.2", diff --git a/examples/sdk-interactive-examples/examples/example-execute/scripts/updateWorkspaceVersion.mjs b/examples/sdk-interactive-examples/examples/example-execute/scripts/updateWorkspaceVersion.mjs index a815e858593..3f45c9395d9 100644 --- a/examples/sdk-interactive-examples/examples/example-execute/scripts/updateWorkspaceVersion.mjs +++ b/examples/sdk-interactive-examples/examples/example-execute/scripts/updateWorkspaceVersion.mjs @@ -2,7 +2,7 @@ import fs from "fs"; -import packageData from "../package.json" assert { type: "json" }; +import packageData from "../package.json" with { type: "json" }; const packageJsonPath = "./package.json"; @@ -25,4 +25,5 @@ packageData.devDependencies = updatedDevDependencies; await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageData, null, 2)); +// oxlint-disable-next-line eslint-js/no-console console.log("Updated package.json with version:", packageData.version); diff --git a/examples/sdk-interactive-examples/examples/example-execute/vite.config.ts b/examples/sdk-interactive-examples/examples/example-execute/vite.config.ts index 3a04ff46b81..da3b113b984 100644 --- a/examples/sdk-interactive-examples/examples/example-execute/vite.config.ts +++ b/examples/sdk-interactive-examples/examples/example-execute/vite.config.ts @@ -9,6 +9,7 @@ import packageJson from "./package.json" with { type: "json" }; const backendUrl = packageJson.gooddata.hostname; const workspaceId = packageJson.gooddata.workspaceId; +// oxlint-disable-next-line eslint-js/no-console console.log("backendUrl: ", backendUrl); export default defineConfig({ diff --git a/examples/sdk-interactive-examples/examples/example-granularity/package.json b/examples/sdk-interactive-examples/examples/example-granularity/package.json index 57d4c3938fb..d607eb72eb9 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "This example exmplains DateFilter granularity ", "license": "LicenseRef-LICENSE", @@ -61,8 +61,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "process": "0.11.10", "rolldown": "1.0.3", "typescript": "7.0.2", diff --git a/examples/sdk-interactive-examples/examples/example-granularity/scripts/updateWorkspaceVersion.mjs b/examples/sdk-interactive-examples/examples/example-granularity/scripts/updateWorkspaceVersion.mjs index a815e858593..3f45c9395d9 100644 --- a/examples/sdk-interactive-examples/examples/example-granularity/scripts/updateWorkspaceVersion.mjs +++ b/examples/sdk-interactive-examples/examples/example-granularity/scripts/updateWorkspaceVersion.mjs @@ -2,7 +2,7 @@ import fs from "fs"; -import packageData from "../package.json" assert { type: "json" }; +import packageData from "../package.json" with { type: "json" }; const packageJsonPath = "./package.json"; @@ -25,4 +25,5 @@ packageData.devDependencies = updatedDevDependencies; await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageData, null, 2)); +// oxlint-disable-next-line eslint-js/no-console console.log("Updated package.json with version:", packageData.version); diff --git a/examples/sdk-interactive-examples/examples/example-granularity/vite.config.ts b/examples/sdk-interactive-examples/examples/example-granularity/vite.config.ts index 3a04ff46b81..da3b113b984 100644 --- a/examples/sdk-interactive-examples/examples/example-granularity/vite.config.ts +++ b/examples/sdk-interactive-examples/examples/example-granularity/vite.config.ts @@ -9,6 +9,7 @@ import packageJson from "./package.json" with { type: "json" }; const backendUrl = packageJson.gooddata.hostname; const workspaceId = packageJson.gooddata.workspaceId; +// oxlint-disable-next-line eslint-js/no-console console.log("backendUrl: ", backendUrl); export default defineConfig({ diff --git a/examples/sdk-interactive-examples/examples/example-headline/package.json b/examples/sdk-interactive-examples/examples/example-headline/package.json index 1db631402f7..72d8dbe55e0 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "This example shows how to use the Headline component.", "license": "LicenseRef-LICENSE", @@ -61,8 +61,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "process": "0.11.10", "rolldown": "1.0.3", "typescript": "7.0.2", diff --git a/examples/sdk-interactive-examples/examples/example-headline/scripts/updateWorkspaceVersion.mjs b/examples/sdk-interactive-examples/examples/example-headline/scripts/updateWorkspaceVersion.mjs index a815e858593..3f45c9395d9 100644 --- a/examples/sdk-interactive-examples/examples/example-headline/scripts/updateWorkspaceVersion.mjs +++ b/examples/sdk-interactive-examples/examples/example-headline/scripts/updateWorkspaceVersion.mjs @@ -2,7 +2,7 @@ import fs from "fs"; -import packageData from "../package.json" assert { type: "json" }; +import packageData from "../package.json" with { type: "json" }; const packageJsonPath = "./package.json"; @@ -25,4 +25,5 @@ packageData.devDependencies = updatedDevDependencies; await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageData, null, 2)); +// oxlint-disable-next-line eslint-js/no-console console.log("Updated package.json with version:", packageData.version); diff --git a/examples/sdk-interactive-examples/examples/example-headline/vite.config.ts b/examples/sdk-interactive-examples/examples/example-headline/vite.config.ts index 3a04ff46b81..da3b113b984 100644 --- a/examples/sdk-interactive-examples/examples/example-headline/vite.config.ts +++ b/examples/sdk-interactive-examples/examples/example-headline/vite.config.ts @@ -9,6 +9,7 @@ import packageJson from "./package.json" with { type: "json" }; const backendUrl = packageJson.gooddata.hostname; const workspaceId = packageJson.gooddata.workspaceId; +// oxlint-disable-next-line eslint-js/no-console console.log("backendUrl: ", backendUrl); export default defineConfig({ diff --git a/examples/sdk-interactive-examples/examples/example-pivottable/package.json b/examples/sdk-interactive-examples/examples/example-pivottable/package.json index fb88090731c..baac7d97226 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "Basic PivotTable manipulation.", "license": "LicenseRef-LICENSE", @@ -61,8 +61,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "process": "0.11.10", "rolldown": "1.0.3", "typescript": "7.0.2", diff --git a/examples/sdk-interactive-examples/examples/example-pivottable/scripts/updateWorkspaceVersion.mjs b/examples/sdk-interactive-examples/examples/example-pivottable/scripts/updateWorkspaceVersion.mjs index a815e858593..3f45c9395d9 100644 --- a/examples/sdk-interactive-examples/examples/example-pivottable/scripts/updateWorkspaceVersion.mjs +++ b/examples/sdk-interactive-examples/examples/example-pivottable/scripts/updateWorkspaceVersion.mjs @@ -2,7 +2,7 @@ import fs from "fs"; -import packageData from "../package.json" assert { type: "json" }; +import packageData from "../package.json" with { type: "json" }; const packageJsonPath = "./package.json"; @@ -25,4 +25,5 @@ packageData.devDependencies = updatedDevDependencies; await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageData, null, 2)); +// oxlint-disable-next-line eslint-js/no-console console.log("Updated package.json with version:", packageData.version); diff --git a/examples/sdk-interactive-examples/examples/example-pivottable/vite.config.ts b/examples/sdk-interactive-examples/examples/example-pivottable/vite.config.ts index 3a04ff46b81..da3b113b984 100644 --- a/examples/sdk-interactive-examples/examples/example-pivottable/vite.config.ts +++ b/examples/sdk-interactive-examples/examples/example-pivottable/vite.config.ts @@ -9,6 +9,7 @@ import packageJson from "./package.json" with { type: "json" }; const backendUrl = packageJson.gooddata.hostname; const workspaceId = packageJson.gooddata.workspaceId; +// oxlint-disable-next-line eslint-js/no-console console.log("backendUrl: ", backendUrl); export default defineConfig({ diff --git a/examples/sdk-interactive-examples/examples/example-relativedatefilter/package.json b/examples/sdk-interactive-examples/examples/example-relativedatefilter/package.json index 8718e83138a..4f22ef3e6f3 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "Example demonstrates how to set relative DateFilter for visualization.", "license": "LicenseRef-LICENSE", @@ -61,8 +61,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "process": "0.11.10", "rolldown": "1.0.3", "typescript": "7.0.2", diff --git a/examples/sdk-interactive-examples/examples/example-relativedatefilter/scripts/updateWorkspaceVersion.mjs b/examples/sdk-interactive-examples/examples/example-relativedatefilter/scripts/updateWorkspaceVersion.mjs index a815e858593..3f45c9395d9 100644 --- a/examples/sdk-interactive-examples/examples/example-relativedatefilter/scripts/updateWorkspaceVersion.mjs +++ b/examples/sdk-interactive-examples/examples/example-relativedatefilter/scripts/updateWorkspaceVersion.mjs @@ -2,7 +2,7 @@ import fs from "fs"; -import packageData from "../package.json" assert { type: "json" }; +import packageData from "../package.json" with { type: "json" }; const packageJsonPath = "./package.json"; @@ -25,4 +25,5 @@ packageData.devDependencies = updatedDevDependencies; await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageData, null, 2)); +// oxlint-disable-next-line eslint-js/no-console console.log("Updated package.json with version:", packageData.version); diff --git a/examples/sdk-interactive-examples/examples/example-relativedatefilter/vite.config.ts b/examples/sdk-interactive-examples/examples/example-relativedatefilter/vite.config.ts index 3a04ff46b81..da3b113b984 100644 --- a/examples/sdk-interactive-examples/examples/example-relativedatefilter/vite.config.ts +++ b/examples/sdk-interactive-examples/examples/example-relativedatefilter/vite.config.ts @@ -9,6 +9,7 @@ import packageJson from "./package.json" with { type: "json" }; const backendUrl = packageJson.gooddata.hostname; const workspaceId = packageJson.gooddata.workspaceId; +// oxlint-disable-next-line eslint-js/no-console console.log("backendUrl: ", backendUrl); export default defineConfig({ diff --git a/examples/sdk-interactive-examples/examples/example-repeater/package.json b/examples/sdk-interactive-examples/examples/example-repeater/package.json index 8d4278d096f..7dfb768bb72 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "This example demonstrates how to use Repeater component.", "license": "LicenseRef-LICENSE", @@ -61,8 +61,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "process": "0.11.10", "rolldown": "1.0.3", "typescript": "7.0.2", diff --git a/examples/sdk-interactive-examples/examples/example-repeater/scripts/updateWorkspaceVersion.mjs b/examples/sdk-interactive-examples/examples/example-repeater/scripts/updateWorkspaceVersion.mjs index a815e858593..3f45c9395d9 100644 --- a/examples/sdk-interactive-examples/examples/example-repeater/scripts/updateWorkspaceVersion.mjs +++ b/examples/sdk-interactive-examples/examples/example-repeater/scripts/updateWorkspaceVersion.mjs @@ -2,7 +2,7 @@ import fs from "fs"; -import packageData from "../package.json" assert { type: "json" }; +import packageData from "../package.json" with { type: "json" }; const packageJsonPath = "./package.json"; @@ -25,4 +25,5 @@ packageData.devDependencies = updatedDevDependencies; await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageData, null, 2)); +// oxlint-disable-next-line eslint-js/no-console console.log("Updated package.json with version:", packageData.version); diff --git a/examples/sdk-interactive-examples/examples/example-repeater/vite.config.ts b/examples/sdk-interactive-examples/examples/example-repeater/vite.config.ts index 3a04ff46b81..da3b113b984 100644 --- a/examples/sdk-interactive-examples/examples/example-repeater/vite.config.ts +++ b/examples/sdk-interactive-examples/examples/example-repeater/vite.config.ts @@ -9,6 +9,7 @@ import packageJson from "./package.json" with { type: "json" }; const backendUrl = packageJson.gooddata.hostname; const workspaceId = packageJson.gooddata.workspaceId; +// oxlint-disable-next-line eslint-js/no-console console.log("backendUrl: ", backendUrl); export default defineConfig({ diff --git a/examples/sdk-interactive-examples/package.json b/examples/sdk-interactive-examples/package.json index 5cc7d3e123e..ea7ab0fb86d 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "private": false, "description": "GoodData React interactive examples", "license": "LicenseRef-LICENSE", diff --git a/libs/api-client-tiger/openapi-generator/index.mustache b/libs/api-client-tiger/openapi-generator/index.mustache index d9939b2b520..f5c045c6f6c 100644 --- a/libs/api-client-tiger/openapi-generator/index.mustache +++ b/libs/api-client-tiger/openapi-generator/index.mustache @@ -1,6 +1,8 @@ // (C) 2024-2026 GoodData Corporation /* oxlint-disable no-barrel-files/no-barrel-files */ +/* eslint-disable no-restricted-syntax */ + {{>licenseInfo}} diff --git a/libs/api-client-tiger/package.json b/libs/api-client-tiger/package.json index 0504417828c..c303c88ca32 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "API Client for GoodData Cloud and GoodData.CN", "license": "MIT", "author": "GoodData", @@ -92,8 +92,9 @@ "mkdirp": "1.0.4", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "typescript": "7.0.2", "vitest": "4.1.8" } diff --git a/libs/api-client-tiger/src/endpoints/actions/index.ts b/libs/api-client-tiger/src/endpoints/actions/index.ts index ca6c7dd7566..168b05d2cd8 100644 --- a/libs/api-client-tiger/src/endpoints/actions/index.ts +++ b/libs/api-client-tiger/src/endpoints/actions/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax // Actions API - Export commonly used ActionsApi functions export { diff --git a/libs/api-client-tiger/src/endpoints/authActions/index.ts b/libs/api-client-tiger/src/endpoints/authActions/index.ts index 8fc5d00bd88..b5a7f4c96dd 100644 --- a/libs/api-client-tiger/src/endpoints/authActions/index.ts +++ b/libs/api-client-tiger/src/endpoints/authActions/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax // Auth Actions API - Export auth-related ActionsApi functions with AuthApi_ prefix export { diff --git a/libs/api-client-tiger/src/endpoints/automation/index.ts b/libs/api-client-tiger/src/endpoints/automation/index.ts index fd1586d6bc8..b88cec37845 100644 --- a/libs/api-client-tiger/src/endpoints/automation/index.ts +++ b/libs/api-client-tiger/src/endpoints/automation/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax // Automation API - Export ActionsAutomation functions with AutomationApi_ prefix export { diff --git a/libs/api-client-tiger/src/endpoints/entitiesObjects/index.ts b/libs/api-client-tiger/src/endpoints/entitiesObjects/index.ts index 94e1a867b07..7143cea0772 100644 --- a/libs/api-client-tiger/src/endpoints/entitiesObjects/index.ts +++ b/libs/api-client-tiger/src/endpoints/entitiesObjects/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax export { // DashboardsApi diff --git a/libs/api-client-tiger/src/endpoints/execution/index.ts b/libs/api-client-tiger/src/endpoints/execution/index.ts index 3c2409efaf3..06dafbf9880 100644 --- a/libs/api-client-tiger/src/endpoints/execution/index.ts +++ b/libs/api-client-tiger/src/endpoints/execution/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax export { // Execution API diff --git a/libs/api-client-tiger/src/endpoints/explain/index.ts b/libs/api-client-tiger/src/endpoints/explain/index.ts index 18fbec51c5a..5999c19f0ed 100644 --- a/libs/api-client-tiger/src/endpoints/explain/index.ts +++ b/libs/api-client-tiger/src/endpoints/explain/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax // Explain API export { diff --git a/libs/api-client-tiger/src/endpoints/export/index.ts b/libs/api-client-tiger/src/endpoints/export/index.ts index faaab620336..174cc5cde24 100644 --- a/libs/api-client-tiger/src/endpoints/export/index.ts +++ b/libs/api-client-tiger/src/endpoints/export/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax // Export API - Export ActionsExport functions with ExportApi_ prefix export { diff --git a/libs/api-client-tiger/src/endpoints/genAI/index.ts b/libs/api-client-tiger/src/endpoints/genAI/index.ts index 37c0634ec49..95c502b5750 100644 --- a/libs/api-client-tiger/src/endpoints/genAI/index.ts +++ b/libs/api-client-tiger/src/endpoints/genAI/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax import type { AxiosInstance, AxiosPromise, AxiosRequestConfig } from "axios"; diff --git a/libs/api-client-tiger/src/endpoints/labelElements/index.ts b/libs/api-client-tiger/src/endpoints/labelElements/index.ts index 1cdf8ceb68b..bd92dee9d6b 100644 --- a/libs/api-client-tiger/src/endpoints/labelElements/index.ts +++ b/libs/api-client-tiger/src/endpoints/labelElements/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax // Label Elements API export { diff --git a/libs/api-client-tiger/src/endpoints/layout/index.ts b/libs/api-client-tiger/src/endpoints/layout/index.ts index 8279b6460db..6ecc9126afc 100644 --- a/libs/api-client-tiger/src/endpoints/layout/index.ts +++ b/libs/api-client-tiger/src/endpoints/layout/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax // Layout API - Export all LayoutApi functions export { diff --git a/libs/api-client-tiger/src/endpoints/locationStyle/index.ts b/libs/api-client-tiger/src/endpoints/locationStyle/index.ts index b63c4aac70d..120ee0671aa 100644 --- a/libs/api-client-tiger/src/endpoints/locationStyle/index.ts +++ b/libs/api-client-tiger/src/endpoints/locationStyle/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax export { LocationStyleApi_GetDefaultStyle, diff --git a/libs/api-client-tiger/src/endpoints/profile/index.ts b/libs/api-client-tiger/src/endpoints/profile/index.ts index 569ed5932ca..24482734e41 100644 --- a/libs/api-client-tiger/src/endpoints/profile/index.ts +++ b/libs/api-client-tiger/src/endpoints/profile/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax export { isLiveFeatures, diff --git a/libs/api-client-tiger/src/endpoints/result/index.ts b/libs/api-client-tiger/src/endpoints/result/index.ts index 3be81890dfc..6851aaa465a 100644 --- a/libs/api-client-tiger/src/endpoints/result/index.ts +++ b/libs/api-client-tiger/src/endpoints/result/index.ts @@ -1,13 +1,13 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax import { type AxiosInstance, type AxiosPromise, type AxiosRequestConfig } from "axios"; import type { GeoJsonFeatureCollection } from "../../generated/result-json-api/api.js"; // Result API - Export ActionsApi functions with ResultApi_ prefix -// eslint-disable-next-line no-duplicate-imports -- Using both import and export from same module for re-exporting with aliases +// oxlint-disable-next-line eslint-js/no-duplicate-imports -- Using both import and export from same module for re-exporting with aliases export { ActionsApi_AnalyzeCsv as ResultApi_AnalyzeCsv, type ActionsApiAnalyzeCsvRequest as ResultApiAnalyzeCsvRequest, diff --git a/libs/api-client-tiger/src/endpoints/scanModel/index.ts b/libs/api-client-tiger/src/endpoints/scanModel/index.ts index c10f84dd1cd..c0f086a2302 100644 --- a/libs/api-client-tiger/src/endpoints/scanModel/index.ts +++ b/libs/api-client-tiger/src/endpoints/scanModel/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax // Scan Model API - Export scan model ActionsApi functions with ScanModelApi_ prefix export { diff --git a/libs/api-client-tiger/src/endpoints/smartFunctions/index.ts b/libs/api-client-tiger/src/endpoints/smartFunctions/index.ts index c399f3696c2..f06af4036be 100644 --- a/libs/api-client-tiger/src/endpoints/smartFunctions/index.ts +++ b/libs/api-client-tiger/src/endpoints/smartFunctions/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax // Smart Functions API - Export ActionsApi functions with SmartFunctionsApi_ prefix export { diff --git a/libs/api-client-tiger/src/endpoints/userManagement/index.ts b/libs/api-client-tiger/src/endpoints/userManagement/index.ts index 84869aa4c2a..0f8881127f2 100644 --- a/libs/api-client-tiger/src/endpoints/userManagement/index.ts +++ b/libs/api-client-tiger/src/endpoints/userManagement/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax // User Management API export { diff --git a/libs/api-client-tiger/src/endpoints/validDescendants/index.ts b/libs/api-client-tiger/src/endpoints/validDescendants/index.ts index dfc2424da27..39a0348a1cb 100644 --- a/libs/api-client-tiger/src/endpoints/validDescendants/index.ts +++ b/libs/api-client-tiger/src/endpoints/validDescendants/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax // Valid Descendants API export { diff --git a/libs/api-client-tiger/src/endpoints/validObjects/index.ts b/libs/api-client-tiger/src/endpoints/validObjects/index.ts index 03d560ecdbf..8800e28a656 100644 --- a/libs/api-client-tiger/src/endpoints/validObjects/index.ts +++ b/libs/api-client-tiger/src/endpoints/validObjects/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax // Valid Objects API export { diff --git a/libs/api-client-tiger/src/gd-tiger-model/index.ts b/libs/api-client-tiger/src/gd-tiger-model/index.ts index b8c6f448758..29d6d416d4e 100644 --- a/libs/api-client-tiger/src/gd-tiger-model/index.ts +++ b/libs/api-client-tiger/src/gd-tiger-model/index.ts @@ -1,5 +1,7 @@ // (C) 2007-2026 GoodData Corporation +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax + import * as AnalyticalDashboardModelV1 from "./AnalyticalDashboardModelV1.js"; import * as AnalyticalDashboardModelV2 from "./AnalyticalDashboardModelV2.js"; import * as AnalyticalDashboardModelV3 from "./AnalyticalDashboardModelV3.js"; @@ -9,36 +11,30 @@ import * as VisualizationObjectModelV2 from "./VisualizationObjectModelV2.js"; /** * @public */ -// oxlint-disable-next-line no-barrel-files/no-barrel-files export { AnalyticalDashboardModelV1 }; /** * @public */ -// oxlint-disable-next-line no-barrel-files/no-barrel-files export { AnalyticalDashboardModelV2 }; /** * @alpha */ -// oxlint-disable-next-line no-barrel-files/no-barrel-files export { AnalyticalDashboardModelV3 }; /** * @public */ -// oxlint-disable-next-line no-barrel-files/no-barrel-files export { VisualizationObjectModelV1 }; /** * @public */ -// oxlint-disable-next-line no-barrel-files/no-barrel-files export { VisualizationObjectModelV2 }; /** * Tiger-specific types for analytical objects * @internal */ -// oxlint-disable-next-line no-barrel-files/no-barrel-files export type * from "./TigerTypes.js"; diff --git a/libs/api-client-tiger/src/generated/afm-rest-api/index.ts b/libs/api-client-tiger/src/generated/afm-rest-api/index.ts index 6f5b9ded866..153ab89f1d5 100644 --- a/libs/api-client-tiger/src/generated/afm-rest-api/index.ts +++ b/libs/api-client-tiger/src/generated/afm-rest-api/index.ts @@ -1,6 +1,7 @@ // (C) 2024-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax + /** * OpenAPI definition * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) diff --git a/libs/api-client-tiger/src/generated/ai-json-api/index.ts b/libs/api-client-tiger/src/generated/ai-json-api/index.ts index e8f7c312b4b..f09a96bf37d 100644 --- a/libs/api-client-tiger/src/generated/ai-json-api/index.ts +++ b/libs/api-client-tiger/src/generated/ai-json-api/index.ts @@ -1,6 +1,7 @@ // (C) 2024-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax + /** * Gen-AI HTTP API * HTTP API for chat sessions, items, and SSE messages. diff --git a/libs/api-client-tiger/src/generated/auth-json-api/index.ts b/libs/api-client-tiger/src/generated/auth-json-api/index.ts index 6f5b9ded866..153ab89f1d5 100644 --- a/libs/api-client-tiger/src/generated/auth-json-api/index.ts +++ b/libs/api-client-tiger/src/generated/auth-json-api/index.ts @@ -1,6 +1,7 @@ // (C) 2024-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax + /** * OpenAPI definition * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) diff --git a/libs/api-client-tiger/src/generated/automation-json-api/index.ts b/libs/api-client-tiger/src/generated/automation-json-api/index.ts index 6f5b9ded866..153ab89f1d5 100644 --- a/libs/api-client-tiger/src/generated/automation-json-api/index.ts +++ b/libs/api-client-tiger/src/generated/automation-json-api/index.ts @@ -1,6 +1,7 @@ // (C) 2024-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax + /** * OpenAPI definition * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) diff --git a/libs/api-client-tiger/src/generated/export-json-api/index.ts b/libs/api-client-tiger/src/generated/export-json-api/index.ts index 6f5b9ded866..153ab89f1d5 100644 --- a/libs/api-client-tiger/src/generated/export-json-api/index.ts +++ b/libs/api-client-tiger/src/generated/export-json-api/index.ts @@ -1,6 +1,7 @@ // (C) 2024-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax + /** * OpenAPI definition * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) diff --git a/libs/api-client-tiger/src/generated/metadata-json-api/index.ts b/libs/api-client-tiger/src/generated/metadata-json-api/index.ts index 6f5b9ded866..153ab89f1d5 100644 --- a/libs/api-client-tiger/src/generated/metadata-json-api/index.ts +++ b/libs/api-client-tiger/src/generated/metadata-json-api/index.ts @@ -1,6 +1,7 @@ // (C) 2024-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax + /** * OpenAPI definition * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) diff --git a/libs/api-client-tiger/src/generated/result-json-api/index.ts b/libs/api-client-tiger/src/generated/result-json-api/index.ts index 6f5b9ded866..153ab89f1d5 100644 --- a/libs/api-client-tiger/src/generated/result-json-api/index.ts +++ b/libs/api-client-tiger/src/generated/result-json-api/index.ts @@ -1,6 +1,7 @@ // (C) 2024-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax + /** * OpenAPI definition * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) diff --git a/libs/api-client-tiger/src/generated/scan-json-api/index.ts b/libs/api-client-tiger/src/generated/scan-json-api/index.ts index 6f5b9ded866..153ab89f1d5 100644 --- a/libs/api-client-tiger/src/generated/scan-json-api/index.ts +++ b/libs/api-client-tiger/src/generated/scan-json-api/index.ts @@ -1,6 +1,7 @@ // (C) 2024-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax + /** * OpenAPI definition * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) diff --git a/libs/api-client-tiger/src/index.ts b/libs/api-client-tiger/src/index.ts index 4d186f8e1d9..4a6735ac654 100644 --- a/libs/api-client-tiger/src/index.ts +++ b/libs/api-client-tiger/src/index.ts @@ -1,6 +1,6 @@ // (C) 2019-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax /** * This package provides low-level functions for communication with GoodData Cloud and GoodData.CN. @@ -6453,5 +6453,5 @@ export const defaultTigerClient: ITigerClient = tigerClientFactory(defaultAxios) /** * @deprecated This will be removed in the next major release, please use the named export "tigerFactory" instead */ -// eslint-disable-next-line no-restricted-exports +// oxlint-disable-next-line eslint-js/no-restricted-exports export default defaultTigerClient; diff --git a/libs/sdk-backend-base/.dependency-cruiser.js b/libs/sdk-backend-base/.dependency-cruiser.js index 7b575751809..593fba33716 100644 --- a/libs/sdk-backend-base/.dependency-cruiser.js +++ b/libs/sdk-backend-base/.dependency-cruiser.js @@ -7,7 +7,6 @@ import { PublicLibraryRules, } from "../../common/config/dep-cruiser/default.config.js"; -// eslint-disable-next-line no-restricted-exports export default { forbidden: [...DefaultRules, ...DefaultSdkRules, ...PublicLibraryRules], options: DefaultOptions, diff --git a/libs/sdk-backend-base/api/sdk-backend-base.api.md b/libs/sdk-backend-base/api/sdk-backend-base.api.md index a45439a9518..16a74ac281b 100644 --- a/libs/sdk-backend-base/api/sdk-backend-base.api.md +++ b/libs/sdk-backend-base/api/sdk-backend-base.api.md @@ -108,6 +108,7 @@ import { IGetVisualizationClassesOptions } from '@gooddata/sdk-backend-spi'; import { IGroupableCatalogItemBase } from '@gooddata/sdk-model'; import { IInsight } from '@gooddata/sdk-model'; import { IInsightDefinition } from '@gooddata/sdk-model'; +import { IInsightDefinitionWithOptionalIdentity } from '@gooddata/sdk-model'; import { IInsightReferences } from '@gooddata/sdk-backend-spi'; import { IInsightReferencing } from '@gooddata/sdk-backend-spi'; import { IInsightsQuery } from '@gooddata/sdk-backend-spi'; @@ -689,7 +690,7 @@ export abstract class DecoratedWorkspaceCatalogFactory implements IWorkspaceCata export abstract class DecoratedWorkspaceDashboardsService implements IWorkspaceDashboardsService { protected constructor(decorated: IWorkspaceDashboardsService, workspace: string); // (undocumented) - createDashboard(dashboard: IDashboardDefinition): Promise; + createDashboard(dashboard: IDashboardDefinition, generateId?: boolean): Promise; // (undocumented) createDashboardPlugin(plugin: IDashboardPluginDefinition): Promise; // (undocumented) @@ -803,7 +804,7 @@ export abstract class DecoratedWorkspaceExportTemplatesService implements IWorks export abstract class DecoratedWorkspaceInsightsService implements IWorkspaceInsightsService { protected constructor(decorated: IWorkspaceInsightsService, workspace: string); // (undocumented) - createInsight(insight: IInsightDefinition): Promise; + createInsight(insight: IInsightDefinitionWithOptionalIdentity, generateId?: boolean): Promise; // (undocumented) protected readonly decorated: IWorkspaceInsightsService; // (undocumented) diff --git a/libs/sdk-backend-base/package.json b/libs/sdk-backend-base/package.json index 95689c0d5c3..856e9a91ec2 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "GoodData.UI SDK - Base for backend implementations", "license": "MIT", "author": "GoodData", @@ -71,8 +71,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "typescript": "7.0.2", "vitest": "4.1.8" } diff --git a/libs/sdk-backend-base/src/cachingBackend/index.ts b/libs/sdk-backend-base/src/cachingBackend/index.ts index 28868a97d3b..3479877cbb9 100644 --- a/libs/sdk-backend-base/src/cachingBackend/index.ts +++ b/libs/sdk-backend-base/src/cachingBackend/index.ts @@ -83,7 +83,7 @@ import { type IFiscalYear, type IGeoJsonFeature, type IInsight, - type IInsightDefinition, + type IInsightDefinitionWithOptionalIdentity, type IMeasure, type IMeasureDefinitionType, type IMetadataObject, @@ -2367,9 +2367,12 @@ class WithInsightsCaching extends DecoratedWorkspaceInsightsService { // Insight mutations are not cached, but they must invalidate the read cache so that edits // made during a session are never served stale (the SDK has no separate invalidation signal). - public override async createInsight(insight: IInsightDefinition): Promise { + public override async createInsight( + insight: IInsightDefinitionWithOptionalIdentity, + generateId?: boolean, + ): Promise { try { - return await super.createInsight(insight); + return await super.createInsight(insight, generateId); } finally { this.invalidateCache(); } diff --git a/libs/sdk-backend-base/src/decoratedBackend/dashboards.ts b/libs/sdk-backend-base/src/decoratedBackend/dashboards.ts index 02ed5420f2f..58091d9ae97 100644 --- a/libs/sdk-backend-base/src/decoratedBackend/dashboards.ts +++ b/libs/sdk-backend-base/src/decoratedBackend/dashboards.ts @@ -103,8 +103,8 @@ export abstract class DecoratedWorkspaceDashboardsService implements IWorkspaceD return this.decorated.getDashboardReferencedObjects(dashboard, types); } - createDashboard(dashboard: IDashboardDefinition): Promise { - return this.decorated.createDashboard(dashboard); + createDashboard(dashboard: IDashboardDefinition, generateId?: boolean): Promise { + return this.decorated.createDashboard(dashboard, generateId); } updateDashboard(dashboard: IDashboard, updatedDashboard: IDashboardDefinition): Promise { diff --git a/libs/sdk-backend-base/src/decoratedBackend/insights.ts b/libs/sdk-backend-base/src/decoratedBackend/insights.ts index 0374150d622..30b2e306b42 100644 --- a/libs/sdk-backend-base/src/decoratedBackend/insights.ts +++ b/libs/sdk-backend-base/src/decoratedBackend/insights.ts @@ -18,6 +18,7 @@ import { type IFilter, type IInsight, type IInsightDefinition, + type IInsightDefinitionWithOptionalIdentity, type IMetadataObjectBase, type IMetadataObjectIdentity, type IObjectCertificationWrite, @@ -68,8 +69,11 @@ export abstract class DecoratedWorkspaceInsightsService implements IWorkspaceIns return this.decorated.getInsightsQuery(); } - public createInsight(insight: IInsightDefinition): Promise { - return this.decorated.createInsight(insight); + public createInsight( + insight: IInsightDefinitionWithOptionalIdentity, + generateId?: boolean, + ): Promise { + return this.decorated.createInsight(insight, generateId); } public updateInsight(insight: IInsight): Promise { diff --git a/libs/sdk-backend-base/src/index.ts b/libs/sdk-backend-base/src/index.ts index 8b868624b7d..a0a438685b0 100644 --- a/libs/sdk-backend-base/src/index.ts +++ b/libs/sdk-backend-base/src/index.ts @@ -1,6 +1,6 @@ // (C) 2019-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files /** * This package provides foundational reusable code useful for building new or decorating existing Analytical Backend implementations. diff --git a/libs/sdk-backend-base/vitest.config.ts b/libs/sdk-backend-base/vitest.config.ts index 04ad74ff664..09371ab4118 100644 --- a/libs/sdk-backend-base/vitest.config.ts +++ b/libs/sdk-backend-base/vitest.config.ts @@ -2,7 +2,6 @@ import { defineConfig } from "vitest/config"; -// eslint-disable-next-line no-restricted-exports export default defineConfig({ resolve: { preserveSymlinks: true, diff --git a/libs/sdk-backend-mockingbird/.dependency-cruiser.js b/libs/sdk-backend-mockingbird/.dependency-cruiser.js index 7b575751809..593fba33716 100644 --- a/libs/sdk-backend-mockingbird/.dependency-cruiser.js +++ b/libs/sdk-backend-mockingbird/.dependency-cruiser.js @@ -7,7 +7,6 @@ import { PublicLibraryRules, } from "../../common/config/dep-cruiser/default.config.js"; -// eslint-disable-next-line no-restricted-exports export default { forbidden: [...DefaultRules, ...DefaultSdkRules, ...PublicLibraryRules], options: DefaultOptions, diff --git a/libs/sdk-backend-mockingbird/package.json b/libs/sdk-backend-mockingbird/package.json index c9018aaf400..168a39b9b5a 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "Mock GoodData Backend SPI implementation", "license": "MIT", "author": "GoodData", @@ -67,8 +67,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "typescript": "7.0.2", "vitest": "4.1.8" } diff --git a/libs/sdk-backend-mockingbird/src/index.ts b/libs/sdk-backend-mockingbird/src/index.ts index 7a05293d103..23959cb6eb9 100644 --- a/libs/sdk-backend-mockingbird/src/index.ts +++ b/libs/sdk-backend-mockingbird/src/index.ts @@ -1,6 +1,6 @@ // (C) 2019-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files /** * This package provides a mock Analytical Backend implementation used mainly for testing. diff --git a/libs/sdk-backend-mockingbird/vitest.config.ts b/libs/sdk-backend-mockingbird/vitest.config.ts index 04ad74ff664..09371ab4118 100644 --- a/libs/sdk-backend-mockingbird/vitest.config.ts +++ b/libs/sdk-backend-mockingbird/vitest.config.ts @@ -2,7 +2,6 @@ import { defineConfig } from "vitest/config"; -// eslint-disable-next-line no-restricted-exports export default defineConfig({ resolve: { preserveSymlinks: true, diff --git a/libs/sdk-backend-spi/.dependency-cruiser.js b/libs/sdk-backend-spi/.dependency-cruiser.js index f25517f11b7..382b0a8c871 100644 --- a/libs/sdk-backend-spi/.dependency-cruiser.js +++ b/libs/sdk-backend-spi/.dependency-cruiser.js @@ -6,7 +6,6 @@ import { DefaultSdkRules, } from "../../common/config/dep-cruiser/default.config.js"; -// eslint-disable-next-line no-restricted-exports export default { forbidden: [...DefaultRules, ...DefaultSdkRules], options: DefaultOptions, diff --git a/libs/sdk-backend-spi/api/sdk-backend-spi.api.md b/libs/sdk-backend-spi/api/sdk-backend-spi.api.md index 65117f52a64..9a3f4c941f2 100644 --- a/libs/sdk-backend-spi/api/sdk-backend-spi.api.md +++ b/libs/sdk-backend-spi/api/sdk-backend-spi.api.md @@ -108,6 +108,7 @@ import { IGeoJsonFeature } from '@gooddata/sdk-model'; import { IGranularAccessGrantee } from '@gooddata/sdk-model'; import { IInsight } from '@gooddata/sdk-model'; import { IInsightDefinition } from '@gooddata/sdk-model'; +import type { IInsightDefinitionWithOptionalIdentity } from '@gooddata/sdk-model'; import { IIpAllowlist } from '@gooddata/sdk-model'; import { IIpAllowlistDefinition } from '@gooddata/sdk-model'; import type { IListedDashboard } from '@gooddata/sdk-model'; @@ -2980,7 +2981,7 @@ export interface IWorkspaceComputedAttributesService { // @alpha export interface IWorkspaceDashboardsService { - createDashboard(dashboard: IDashboardDefinition): Promise; + createDashboard(dashboard: IDashboardDefinition, generateId?: boolean): Promise; createDashboardPlugin(plugin: IDashboardPluginDefinition): Promise; createFilterView(filterView: IDashboardFilterViewSaveRequest): Promise; createScheduledMail(scheduledMail: IScheduledMailDefinition, exportFilterContext?: IFilterContextDefinition): Promise; @@ -3110,7 +3111,7 @@ export interface IWorkspaceFactsService { // @public export interface IWorkspaceInsightsService { - createInsight(insight: IInsightDefinition): Promise; + createInsight(insight: IInsightDefinitionWithOptionalIdentity, generatedId?: boolean): Promise; deleteInsight(ref: ObjRef): Promise; getInsight(ref: ObjRef, options?: IGetInsightOptions): Promise; getInsightReferencedObjects(insight: IInsight, types?: SupportedInsightReferenceTypes[]): Promise; diff --git a/libs/sdk-backend-spi/package.json b/libs/sdk-backend-spi/package.json index cadb57f7abe..d0b0d4f544f 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "GoodData Backend SPI abstraction interfaces", "license": "MIT", "author": "GoodData", @@ -62,8 +62,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "typescript": "7.0.2", "vitest": "4.1.8" } diff --git a/libs/sdk-backend-spi/src/common/settings.ts b/libs/sdk-backend-spi/src/common/settings.ts index 8e1c3df3a44..c29e7a5b07e 100644 --- a/libs/sdk-backend-spi/src/common/settings.ts +++ b/libs/sdk-backend-spi/src/common/settings.ts @@ -1,5 +1,5 @@ // (C) 2020-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files export type { IUserSettings, IWorkspaceSettings, IUserWorkspaceSettings } from "@gooddata/sdk-model"; diff --git a/libs/sdk-backend-spi/src/index.ts b/libs/sdk-backend-spi/src/index.ts index bc758d8c59a..a8367bbba1a 100644 --- a/libs/sdk-backend-spi/src/index.ts +++ b/libs/sdk-backend-spi/src/index.ts @@ -1,6 +1,6 @@ // (C) 2019-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files /** * This package provides definitions of the Service Provider Interface (SPI) for the Analytical Backend. diff --git a/libs/sdk-backend-spi/src/workspace/dashboards/index.ts b/libs/sdk-backend-spi/src/workspace/dashboards/index.ts index 13c88a09e21..a82cbe3159d 100644 --- a/libs/sdk-backend-spi/src/workspace/dashboards/index.ts +++ b/libs/sdk-backend-spi/src/workspace/dashboards/index.ts @@ -635,9 +635,10 @@ export interface IWorkspaceDashboardsService { * Create and save dashboard for the provided dashboard definition * * @param dashboard - dashboard definition + * @param generateId - whether to generate a new identifier for the dashboard, default is true * @returns promise of the created dashboard */ - createDashboard(dashboard: IDashboardDefinition): Promise; + createDashboard(dashboard: IDashboardDefinition, generateId?: boolean): Promise; /** * Update dashboard diff --git a/libs/sdk-backend-spi/src/workspace/insights/index.ts b/libs/sdk-backend-spi/src/workspace/insights/index.ts index 22fea59af67..c7952922c64 100644 --- a/libs/sdk-backend-spi/src/workspace/insights/index.ts +++ b/libs/sdk-backend-spi/src/workspace/insights/index.ts @@ -8,6 +8,7 @@ import type { IFilter, IInsight, IInsightDefinition, + IInsightDefinitionWithOptionalIdentity, IMetadataObject, IMetadataObjectBase, IMetadataObjectIdentity, @@ -96,9 +97,10 @@ export interface IWorkspaceInsightsService { * Create and save insight for the provided insight definition * * @param insight - insight definition + * @param generatedId - if true, backend will generate insight id, otherwise the id must be provided in the insight definition, defaults to true * @returns promise of created insight */ - createInsight(insight: IInsightDefinition): Promise; + createInsight(insight: IInsightDefinitionWithOptionalIdentity, generatedId?: boolean): Promise; /** * Update provided insight diff --git a/libs/sdk-backend-spi/vitest.config.ts b/libs/sdk-backend-spi/vitest.config.ts index e8188177383..f1f67daac91 100644 --- a/libs/sdk-backend-spi/vitest.config.ts +++ b/libs/sdk-backend-spi/vitest.config.ts @@ -2,7 +2,6 @@ import { defineConfig } from "vitest/config"; -// eslint-disable-next-line no-restricted-exports export default defineConfig({ resolve: { preserveSymlinks: true, diff --git a/libs/sdk-backend-tiger/.dependency-cruiser.js b/libs/sdk-backend-tiger/.dependency-cruiser.js index 91b5e93379d..1f55fadc71a 100644 --- a/libs/sdk-backend-tiger/.dependency-cruiser.js +++ b/libs/sdk-backend-tiger/.dependency-cruiser.js @@ -8,7 +8,6 @@ import { moduleWithDependencies, } from "../../common/config/dep-cruiser/default.config.js"; -// eslint-disable-next-line no-restricted-exports export default { forbidden: [ ...DefaultRules, diff --git a/libs/sdk-backend-tiger/package.json b/libs/sdk-backend-tiger/package.json index 022b8ca878a..aa56166b4fc 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "GoodData Backend SPI implementation for GoodData Cloud and GoodData.CN", "license": "MIT", "author": "GoodData", @@ -93,8 +93,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "typescript": "7.0.2", "vitest": "4.1.8" } diff --git a/libs/sdk-backend-tiger/src/backend/index.ts b/libs/sdk-backend-tiger/src/backend/index.ts index b9d7b7f97c0..ff764ecae03 100644 --- a/libs/sdk-backend-tiger/src/backend/index.ts +++ b/libs/sdk-backend-tiger/src/backend/index.ts @@ -1,6 +1,6 @@ // (C) 2019-2026 GoodData Corporation -import { type AxiosInstance, type AxiosResponse } from "axios"; +import axios, { type AxiosInstance, type AxiosResponse } from "axios"; import { inRange, isEmpty, isError, omit } from "lodash-es"; import { invariant } from "ts-invariant"; @@ -449,6 +449,12 @@ function interceptBackendErrorsToConsole(client: AxiosInstance): AxiosInstance { (error) => { const response: AxiosResponse = error.response; + // Cancellations are expected whenever a component aborts its in-flight requests + // on unmount; logging them as backend errors only floods the console. + if (axios.isCancel(error)) { + return Promise.reject(error); + } + // If there is no response object (for example for blocked requests), print the whole error. if (!response) { console.error("Tiger backend threw an error:", error); 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 d63829f8143..3e0a407aa1e 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/dashboards/index.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/dashboards/index.ts @@ -463,7 +463,10 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { ); }; - public createDashboard = async (dashboard: IDashboardDefinition): Promise => { + public createDashboard = async ( + dashboard: IDashboardDefinition, + generateId = true, + ): Promise => { // Process filter contexts for each tab first const dashboardWithTabFilterContexts = await this.processDashboardTabsFilterContexts(dashboard); @@ -495,6 +498,11 @@ export class TigerWorkspaceDashboards implements IWorkspaceDashboardsService { workspaceId: this.workspace, jsonApiAnalyticalDashboardPostOptionalIdDocument: { data: { + ...(generateId + ? {} + : { + id: dashboard.identifier, + }), type: "analyticalDashboard", attributes: { content: dashboardContent, 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 7ffccc2e23a..48823ce36cf 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/insights/index.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/insights/index.ts @@ -47,6 +47,7 @@ import { type IFilter, type IInsight, type IInsightDefinition, + type IInsightDefinitionWithOptionalIdentity, type IMetadataObjectBase, type IMetadataObjectIdentity, type IObjectCertificationWrite, @@ -257,12 +258,18 @@ export class TigerWorkspaceInsights implements IWorkspaceInsightsService { return insight; }; - public createInsight = async (insight: IInsightDefinition): Promise => { + public createInsight = async ( + insight: IInsightDefinitionWithOptionalIdentity, + generateId = true, + ): Promise => { const createResponse = await this.authCall((client) => { return EntitiesApi_CreateEntityVisualizationObjects(client.axios, client.basePath, { workspaceId: this.workspace, jsonApiVisualizationObjectPostOptionalIdDocument: { data: { + ...(generateId || !insight.insight.identifier + ? {} + : { id: insight.insight.identifier }), type: "visualizationObject", attributes: { description: insightSummary(insight), diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.test.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.test.ts index 94a4f460b76..71bf2daf3bb 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.test.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.test.ts @@ -4,11 +4,14 @@ import { describe, expect, it, vi } from "vitest"; import { type AiConversationItemResponse } from "@gooddata/api-client-tiger"; import { + type IChatConversationDashboardContent, + type IChatConversationItem, type IChatConversationMultipartContent, type IChatConversationMultipartPart, type IChatConversationWhatIfContent, isChatConversationSearchContent, } from "@gooddata/sdk-backend-spi"; +import { type IInsightWidget, type IdentifierRef } from "@gooddata/sdk-model"; import { convertChatConversationErrorFromBackend, @@ -356,4 +359,172 @@ describe("genAIConvertor", () => { errorSpy.mockRestore(); }); }); + + describe("dashboard patch", () => { + const DASHBOARD_ID = "existing_dashboard"; + + // Shapes mirror what gen-ai puts on the wire: the base rides ahead of the patch as its + // own `dashboard` part, carrying the real dashboard id and no references of its own. + const section = (vis: string) => ({ + widgets: [{ visualization: vis, title: vis, columns: 6, rows: 22 }], + }); + + const baseDocument = (widgets: string[]) => ({ + type: "dashboard", + id: DASHBOARD_ID, + title: "Existing dashboard", + version: "3", + sections: widgets.map(section), + }); + + const basePart = (widgets: string[] = ["chart1"]) => ({ + type: "dashboard", + dashboard: baseDocument(widgets), + saved_dashboard_id: DASHBOARD_ID, + references: null, + }); + + const patchPart = (vis: string) => ({ + type: "dashboardPatch", + patch: { + dashboard_id: DASHBOARD_ID, + operations: [{ op: "add", path: "/sections/-", value: section(vis) }], + references: null, + }, + }); + + const makeItem = (parts: object[], itemIndex = 0): AiConversationItemResponse => + ({ + conversationId: "conv-1", + itemIndex, + itemId: `item-${itemIndex}`, + role: "assistant", + createdAt: "2024-01-01T00:00:00Z", + content: { type: "multipart", parts }, + }) as unknown as AiConversationItemResponse; + + const dashboardParts = (item: IChatConversationItem) => + (item.content as IChatConversationMultipartContent).parts.filter( + (part): part is IChatConversationDashboardContent => part.type === "dashboard", + ); + + /** Ids of the visualizations the dashboard's widgets point at, in layout order. */ + const widgetVisualizations = (part: IChatConversationDashboardContent) => + (part.dashboard?.layout?.sections ?? []).flatMap((section) => + section.items.map((item) => { + const widget = item.widget as IInsightWidget; + return (widget?.insight as IdentifierRef)?.identifier; + }), + ); + + it("applies a patch against the base sent as a sibling part in the same message", () => { + const converted = convertChatConversationItemFromBackend( + makeItem([{ type: "text", text: "Added it." }, basePart(), patchPart("chart2")]), + [], + [], + dateNormalizer, + )!; + + const parts = dashboardParts(converted); + + // The base part is folded into the patch: a single card, showing the patched draft. + expect(parts).toHaveLength(1); + expect(widgetVisualizations(parts[0]!)).toEqual(["chart1", "chart2"]); + }); + + it("does not offer the unchanged base dashboard as a card of its own", () => { + const converted = convertChatConversationItemFromBackend( + makeItem([basePart(), patchPart("chart2")]), + [], + [], + dateNormalizer, + )!; + + const unchanged = dashboardParts(converted).filter( + (part) => widgetVisualizations(part).length === 1, + ); + + expect(unchanged).toEqual([]); + }); + + it("keeps a standalone dashboard part when no patch accompanies it", () => { + const converted = convertChatConversationItemFromBackend( + makeItem([basePart()]), + [], + [], + dateNormalizer, + )!; + + const parts = dashboardParts(converted); + + expect(parts).toHaveLength(1); + expect(widgetVisualizations(parts[0]!)).toEqual(["chart1"]); + expect(parts[0]!.saved).toBe(DASHBOARD_ID); + }); + + it("resolves the base from history for a follow-up patch that carries none", () => { + const history: IChatConversationItem[] = []; + + const first = convertChatConversationItemFromBackend( + makeItem([basePart(), patchPart("chart2")], 0), + [], + history, + dateNormalizer, + )!; + history.push(first); + + const second = convertChatConversationItemFromBackend( + makeItem([patchPart("chart3")], 1), + [], + history, + dateNormalizer, + )!; + + const parts = dashboardParts(second); + + expect(parts).toHaveLength(1); + // The operations are defined against the relayed document, so the second proposal + // rebases on the same base rather than on the result of the first one. + expect(widgetVisualizations(parts[0]!)).toEqual(["chart1", "chart3"]); + }); + + it("rebases on a base resent in the current message rather than the one in history", () => { + const history: IChatConversationItem[] = []; + + const first = convertChatConversationItemFromBackend( + makeItem([basePart(), patchPart("chart2")], 0), + [], + history, + dateNormalizer, + )!; + history.push(first); + + // The user edited the dashboard in between, so gen-ai relays the changed document. + const second = convertChatConversationItemFromBackend( + makeItem([basePart(["chart1", "edited"]), patchPart("chart3")], 1), + [], + history, + dateNormalizer, + )!; + + const parts = dashboardParts(second); + + expect(parts).toHaveLength(1); + expect(widgetVisualizations(parts[0]!)).toEqual(["chart1", "edited", "chart3"]); + }); + + it("renders no dashboard card when a patch has no base to apply to", () => { + const converted = convertChatConversationItemFromBackend( + makeItem([patchPart("chart2")]), + [], + [], + dateNormalizer, + )!; + + const parts = dashboardParts(converted); + + expect(parts).toHaveLength(1); + expect(parts[0]!.dashboard).toBeNull(); + }); + }); }); diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.ts index 3c077011aa1..be758d710cc 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.ts @@ -15,6 +15,7 @@ import { type AiDashboardPatchPart, type AiInteractionStepResponse, type AiKeyDriverAnalysis, + type AiMultipartContentPartsInner, type AiSearchObject, type AiSearchRelationship, type AiSuggestions, @@ -195,84 +196,7 @@ function convertChatConversationContentFromBackend( case "multipart": return { type: "multipart", - // Unknown parts are dropped rather than failing the whole item, so the rest - // of the message (known parts) keeps rendering normally. - parts: content.parts - .map((part): IChatConversationMultipartPart | undefined => { - switch (part.type) { - case "text": - return { - type: "text", - text: part.text, - }; - case "alertProposal": - return { - type: "alertProposal", - alertProposal: convertAlertProposalFrom(part.alertProposal), - }; - case "visualization": - return { - type: "visualization", - visualization: part.visualization - ? visualizationObjectsItemToInsight( - yamlVisualisationToMetadataObject( - [], - part.visualization as AacVisualisation, - ), - ) - : null, - }; - case "dashboard": { - return { - type: "dashboard", - ...applyDashboardDefinition(part), - }; - } - case "dashboardPatch": { - if (!part.patch) { - return undefined; - } - - return { - type: "dashboard", - ...applyDashboardPatch(history, part.patch), - }; - } - case "kda": - return { - type: "kda", - kda: convertKda( - part.kda as AiKeyDriverAnalysis, - dateNormalizer, - locale, - timezone, - ), - }; - case "whatIf": - return { - type: "whatIf", - whatIf: convertWhatIf(part.whatIf as AiWhatIfScenario), - }; - case "searchResults": - return { - type: "searchResults", - keywords: part.keywords, - searchResults: convertSearchResults(part.objects), - relationships: convertSearchRelationships(part.relationships), - }; - case "clarifyingQuestions": - return { - type: "clarifyingQuestions", - questions: part.questions, - }; - default: - // Unknown part type (e.g. sent by a newer backend): log and drop - // it, do not fail the whole item. - assertNever(part); - return undefined; - } - }) - .filter((part): part is IChatConversationMultipartPart => part !== undefined), + parts: convertMultipartParts(content.parts, history, dateNormalizer, locale, timezone), suggestions: convertChatSuggestionItemFromBackend(content.suggestions), }; case "toolCall": @@ -297,6 +221,133 @@ function convertChatConversationContentFromBackend( } } +/** + * Converts the parts of a single multipart message. + * + * Parts are converted in order, and each one sees the siblings converted before it. That matters + * for `dashboardPatch`: the base document it applies to arrives as a `dashboard` part next to it + * in the same message, and `history` only holds the previous messages - the current item is + * appended to it after it has been converted, in both the replay and the SSE path. + * + * A `dashboard` part that only carries the base for a sibling patch is folded into that patch: it + * is used as the base but not emitted, so the message renders a single card showing the patched + * draft instead of a second card offering the unchanged dashboard. + */ +function convertMultipartParts( + rawParts: AiMultipartContentPartsInner[], + history: IChatConversationItem[], + dateNormalizer: DateNormalizer, + locale?: FormattingLocale, + timezone?: string, +): IChatConversationMultipartPart[] { + const patchedDashboardIds = new Set( + rawParts.flatMap((part) => + part.type === "dashboardPatch" && part.patch?.dashboard_id ? [part.patch.dashboard_id] : [], + ), + ); + + const siblings: IChatConversationMultipartPart[] = []; + const parts: IChatConversationMultipartPart[] = []; + + rawParts.forEach((rawPart) => { + const part = convertMultipartPart(rawPart, history, siblings, dateNormalizer, locale, timezone); + + // Unknown parts are dropped rather than failing the whole item, so the rest + // of the message (known parts) keeps rendering normally. + if (!part) { + return; + } + + siblings.push(part); + + const isPatchBase = + rawPart.type === "dashboard" && + part.type === "dashboard" && + !!part.dashboard && + patchedDashboardIds.has(part.dashboard.identifier); + + if (!isPatchBase) { + parts.push(part); + } + }); + + return parts; +} + +function convertMultipartPart( + part: AiMultipartContentPartsInner, + history: IChatConversationItem[], + siblings: IChatConversationMultipartPart[], + dateNormalizer: DateNormalizer, + locale?: FormattingLocale, + timezone?: string, +): IChatConversationMultipartPart | undefined { + switch (part.type) { + case "text": + return { + type: "text", + text: part.text, + }; + case "alertProposal": + return { + type: "alertProposal", + alertProposal: convertAlertProposalFrom(part.alertProposal), + }; + case "visualization": + return { + type: "visualization", + visualization: part.visualization + ? visualizationObjectsItemToInsight( + yamlVisualisationToMetadataObject([], part.visualization as AacVisualisation), + ) + : null, + }; + case "dashboard": { + return { + type: "dashboard", + ...applyDashboardDefinition(part), + }; + } + case "dashboardPatch": { + if (!part.patch) { + return undefined; + } + + return { + type: "dashboard", + ...applyDashboardPatch(history, siblings, part.patch), + }; + } + case "kda": + return { + type: "kda", + kda: convertKda(part.kda as AiKeyDriverAnalysis, dateNormalizer, locale, timezone), + }; + case "whatIf": + return { + type: "whatIf", + whatIf: convertWhatIf(part.whatIf as AiWhatIfScenario), + }; + case "searchResults": + return { + type: "searchResults", + keywords: part.keywords, + searchResults: convertSearchResults(part.objects), + relationships: convertSearchRelationships(part.relationships), + }; + case "clarifyingQuestions": + return { + type: "clarifyingQuestions", + questions: part.questions, + }; + default: + // Unknown part type (e.g. sent by a newer backend): log and drop + // it, do not fail the whole item. + assertNever(part); + return undefined; + } +} + function tryParseJson(jsonString: string): string | object { try { return JSON.parse(jsonString); @@ -655,7 +706,11 @@ function asNonPersistedFilterContext( // Apply dashboard patch to the items -function applyDashboardPatch(items: IChatConversationItem[], patch: AiDashboardPatchPart["patch"]) { +function applyDashboardPatch( + items: IChatConversationItem[], + siblings: IChatConversationMultipartPart[], + patch: AiDashboardPatchPart["patch"], +) { if (!patch?.dashboard_id) { return { dashboard: null, @@ -663,13 +718,14 @@ function applyDashboardPatch(items: IChatConversationItem[], patch: AiDashboardP }; } - const related = collectRelatedItems(items, { + const related = collectRelatedItems(items, siblings, { identifier: patch.dashboard_id, type: "analyticalDashboard", }); - const last = related[related.length - 1]; + // The most recent card for this dashboard need not carry a base - a patch that failed to + // apply resolves to one without. Rebase on the last card that actually has one. + const last = related.filter((part) => !!part.base).pop(); const base = last?.base; - const saved = last?.saved; const previousInsights = last?.insights ?? []; if (!base) { @@ -697,24 +753,43 @@ function applyDashboardPatch(items: IChatConversationItem[], patch: AiDashboardP }; } - const { dashboard, insights } = buildDashboardReferences(newDocument, patch.references, saved); + const { dashboard, insights } = buildDashboardReferences( + newDocument, + patch.references, + patch.dashboard_id, + ); + // `base` is carried over unchanged: the operations are defined against the relayed document, + // not against the result of a previous proposal, so a follow-up patch - which arrives without + // a base of its own as long as the relayed document has not changed - rebases on the same one. + // + // `saved` deliberately stays unset. The dashboard does exist saved, but this card describes a + // change the user has not accepted yet, so it has to offer the draft and not the saved copy. return { + base, dashboard: convertToTemporaryFilterContexts(dashboard), insights: [...previousInsights, ...insights], }; } -function collectRelatedItems(items: IChatConversationItem[], ref: ObjRef) { +function collectRelatedItems( + items: IChatConversationItem[], + siblings: IChatConversationMultipartPart[], + ref: ObjRef, +) { const related: IChatConversationDashboardContent[] = []; + const collect = (part: IChatConversationMultipartPart) => { + if (part.type === "dashboard" && part.dashboard && areObjRefsEqual(part.dashboard.ref, ref)) { + related.push(part); + } + }; items.forEach((item) => { if (item.content.type === "multipart") { - item.content.parts.forEach((part) => { - if (part.type === "dashboard" && part.dashboard && areObjRefsEqual(part.dashboard.ref, ref)) { - related.push(part); - } - }); + item.content.parts.forEach(collect); } }); + // Siblings come last: a base resent in the current message wins over anything in history, + // which is exactly what happens when the user edited the dashboard since the last proposal. + siblings.forEach(collect); return related; } @@ -770,13 +845,20 @@ function buildDashboardReferences( ? convertFilterContextFromBackend(buildFilterContextWrapper(data.filterContext)) : undefined; - const vis = [...(references?.visualizations ?? []), ...(references?.new_visualizations ?? [])]; - const insights = - vis.map((vis) => { + const existingInsights = + (references?.visualizations ?? []).map((vis) => { return visualizationObjectsItemToInsight( yamlVisualisationToMetadataObject(entities, vis as AacVisualisation), ); }) ?? []; + const newInsights = + (references?.new_visualizations ?? []).map((vis) => { + const insight = visualizationObjectsItemToInsight( + yamlVisualisationToMetadataObject(entities, vis as AacVisualisation), + ); + insight.insight.isDraft = true; + return insight; + }) ?? []; const dashboard = data ? convertDashboard( @@ -787,6 +869,6 @@ function buildDashboardReferences( return { dashboard, - insights, + insights: [...existingInsights, ...newInsights], }; } diff --git a/libs/sdk-backend-tiger/src/convertors/shared/layoutConverter.test.ts b/libs/sdk-backend-tiger/src/convertors/shared/layoutConverter.test.ts new file mode 100644 index 00000000000..04fa3231905 --- /dev/null +++ b/libs/sdk-backend-tiger/src/convertors/shared/layoutConverter.test.ts @@ -0,0 +1,88 @@ +// (C) 2026 GoodData Corporation + +import { describe, expect, it } from "vitest"; + +import { type IDashboardLayout, type IInsightWidget, idRef } from "@gooddata/sdk-model"; + +import { cloneWithSanitizedIds as sanitizeFromBackend } from "../fromBackend/IdSanitization.js"; +import { cloneWithSanitizedIds as sanitizeToBackend } from "../toBackend/IdSanitization.js"; + +import { convertLayout } from "./layoutConverter.js"; + +function layoutWithDrillUrl(url: string): IDashboardLayout { + const widget = { + type: "insight", + insight: idRef("insight1", "insight"), + ignoreDashboardFilters: [], + drills: [ + { + type: "drillToCustomUrl", + transition: "new-window", + origin: { type: "drillFromAttribute", attribute: idRef("label1", "displayForm") }, + target: { url }, + }, + ], + title: "widget", + description: "", + } as unknown as IInsightWidget; + + return { + type: "IDashboardLayout", + sections: [{ type: "IDashboardLayoutSection", items: [{ type: "IDashboardLayoutItem", widget }] }], + } as unknown as IDashboardLayout; +} + +function drillUrlOf(layout: unknown) { + return (layout as any).sections[0].items[0].widget.drills[0].target.url; +} + +/** + * The url stored on the backend is an array of string chunks and object references; the converters + * build it on save and flatten it back on load. These assert the reference each placeholder is + * stored as, and that loading the stored form reproduces the original url verbatim. + */ +describe("drill to custom url layout conversion", () => { + it("stores a display form placeholder as a label reference and loads it back unchanged", () => { + const url = "https://example.com/?q={attribute_title(campaign_channels.category)}&x=1"; + + const stored = sanitizeToBackend(convertLayout(false, layoutWithDrillUrl(url))); + + expect(drillUrlOf(stored)).toEqual([ + "https://example.com/?q=", + { identifier: { id: "campaign_channels.category", type: "label" } }, + "&x=1", + ]); + + const loaded = convertLayout(true, sanitizeFromBackend(stored) as IDashboardLayout); + expect(drillUrlOf(loaded)).toBe(url); + }); + + it("stores a computed attribute placeholder as a computed attribute reference and loads it back unchanged", () => { + const url = "https://example.com/?q={attribute_title(computed_attribute/ca1)}&x=1"; + + const stored = sanitizeToBackend(convertLayout(false, layoutWithDrillUrl(url))); + + expect(drillUrlOf(stored)).toEqual([ + "https://example.com/?q=", + { identifier: { id: "ca1", type: "computedAttribute" } }, + "&x=1", + ]); + + const loaded = convertLayout(true, sanitizeFromBackend(stored) as IDashboardLayout); + expect(drillUrlOf(loaded)).toBe(url); + }); + + it("leaves the filter selection placeholders as plain text on both sides", () => { + const url = + "https://example.com/?a={dash_attribute_filter_selection(label1)}" + + "&b={dash_attribute_filter_selection(computed_attribute/ca1)}" + + "&c={attribute_filter_selection(label1)}"; + + const stored = sanitizeToBackend(convertLayout(false, layoutWithDrillUrl(url))); + + expect(drillUrlOf(stored)).toEqual([url]); + + const loaded = convertLayout(true, sanitizeFromBackend(stored) as IDashboardLayout); + expect(drillUrlOf(loaded)).toBe(url); + }); +}); diff --git a/libs/sdk-backend-tiger/src/convertors/toBackend/afm/DimensionsConverter.ts b/libs/sdk-backend-tiger/src/convertors/toBackend/afm/DimensionsConverter.ts index f8466779278..37be149949d 100644 --- a/libs/sdk-backend-tiger/src/convertors/toBackend/afm/DimensionsConverter.ts +++ b/libs/sdk-backend-tiger/src/convertors/toBackend/afm/DimensionsConverter.ts @@ -117,7 +117,7 @@ function handleAttributeSort(sortItem: IAttributeSortItem, dims: Dimension[], so const dimIdx = dims.findIndex((dim) => dim.itemIdentifiers.includes(attributeIdentifier)); if (dimIdx < 0) { - // eslint-disable-next-line no-console + // oxlint-disable-next-line eslint-js/no-console console.log( `attempting to sort by attribute with localId ${attributeIdentifier} but this attribute is not in any dimension.`, ); diff --git a/libs/sdk-backend-tiger/src/index.ts b/libs/sdk-backend-tiger/src/index.ts index 64a20d7a8f3..70e07e32439 100644 --- a/libs/sdk-backend-tiger/src/index.ts +++ b/libs/sdk-backend-tiger/src/index.ts @@ -1,6 +1,6 @@ // (C) 2019-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files /** * This package provides the Analytical Backend implementation for GoodData Cloud and GoodData.CN. @@ -145,5 +145,5 @@ export { convertInsightToVisualizationContent } from "./convertors/toBackend/Ins /** * @deprecated This will be removed in the next major release, please use the named export "tigerFactory" instead */ -// eslint-disable-next-line no-restricted-exports +// oxlint-disable-next-line eslint-js/no-restricted-exports export default tigerFactory; diff --git a/libs/sdk-backend-tiger/tests/goodmock/snapshot-and-sanitize.mjs b/libs/sdk-backend-tiger/tests/goodmock/snapshot-and-sanitize.mjs index 3ad9f48560b..c6d2375f67f 100755 --- a/libs/sdk-backend-tiger/tests/goodmock/snapshot-and-sanitize.mjs +++ b/libs/sdk-backend-tiger/tests/goodmock/snapshot-and-sanitize.mjs @@ -78,5 +78,5 @@ for (const mapping of sanitized) { } writeFileSync(outputPath, JSON.stringify({ mappings: sanitized }, null, 4) + "\n"); -// eslint-disable-next-line no-console +// oxlint-disable-next-line eslint-js/no-console console.log(`Wrote ${sanitized.length} mappings to ${outputPath}`); diff --git a/libs/sdk-backend-tiger/vitest.config.ts b/libs/sdk-backend-tiger/vitest.config.ts index 41a17e74341..5ef19da7554 100644 --- a/libs/sdk-backend-tiger/vitest.config.ts +++ b/libs/sdk-backend-tiger/vitest.config.ts @@ -2,7 +2,6 @@ import { defineConfig } from "vitest/config"; -// eslint-disable-next-line no-restricted-exports export default defineConfig({ resolve: { preserveSymlinks: true, diff --git a/libs/sdk-backend-tiger/vitest.integrated.config.ts b/libs/sdk-backend-tiger/vitest.integrated.config.ts index a74ab3bdb4d..a583324f83a 100644 --- a/libs/sdk-backend-tiger/vitest.integrated.config.ts +++ b/libs/sdk-backend-tiger/vitest.integrated.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from "vitest/config"; -// eslint-disable-next-line no-restricted-exports +// oxlint-disable-next-line eslint-js/no-restricted-exports export default defineConfig({ test: { include: ["**/tests/integrated/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"], diff --git a/libs/sdk-code-convertors/.dependency-cruiser.js b/libs/sdk-code-convertors/.dependency-cruiser.js index 7b575751809..593fba33716 100644 --- a/libs/sdk-code-convertors/.dependency-cruiser.js +++ b/libs/sdk-code-convertors/.dependency-cruiser.js @@ -7,7 +7,6 @@ import { PublicLibraryRules, } from "../../common/config/dep-cruiser/default.config.js"; -// eslint-disable-next-line no-restricted-exports export default { forbidden: [...DefaultRules, ...DefaultSdkRules, ...PublicLibraryRules], options: DefaultOptions, diff --git a/libs/sdk-code-convertors/.oxlintrc.json b/libs/sdk-code-convertors/.oxlintrc.json index 833c141e390..23a8eca69c1 100644 --- a/libs/sdk-code-convertors/.oxlintrc.json +++ b/libs/sdk-code-convertors/.oxlintrc.json @@ -10,6 +10,12 @@ "rules": { "@typescript-eslint/no-explicit-any": "warn" } + }, + { + "files": ["wasm/**/*"], + "globals": { + "Javy": "readonly" + } } ] } diff --git a/libs/sdk-code-convertors/package.json b/libs/sdk-code-convertors/package.json index a9833ef7728..9a6b7fdf589 100644 --- a/libs/sdk-code-convertors/package.json +++ b/libs/sdk-code-convertors/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-code-convertors", - "version": "11.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "GoodData AAC declarative converters", "license": "MIT", "author": "GoodData", @@ -68,8 +68,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "typescript": "7.0.2", "vitest": "4.1.8" } diff --git a/libs/sdk-code-convertors/python/pyproject.toml b/libs/sdk-code-convertors/python/pyproject.toml index 2d134b2b329..ee0614cea3b 100644 --- a/libs/sdk-code-convertors/python/pyproject.toml +++ b/libs/sdk-code-convertors/python/pyproject.toml @@ -2,7 +2,7 @@ [project] name = "gooddata-code-convertors" -version = "11.57.0a1" +version = "11.57.0a3" description = "GoodData AAC YAML / Declarative API code converters (WASM-powered)" readme = "README.md" license = { file = "LICENSE" } diff --git a/libs/sdk-code-convertors/scripts/check-python-types.mjs b/libs/sdk-code-convertors/scripts/check-python-types.mjs index 02b6c551a94..fdcb7fe091d 100644 --- a/libs/sdk-code-convertors/scripts/check-python-types.mjs +++ b/libs/sdk-code-convertors/scripts/check-python-types.mjs @@ -60,5 +60,5 @@ if (failed) { } const fileNames = GENERATED_FILES.map((path) => path.split("/").pop()).join(" and "); -// eslint-disable-next-line no-console -- CLI script with intentional progress logging +// oxlint-disable-next-line eslint-js/no-console -- CLI script with intentional progress logging console.log(`Python types check passed — ${fileNames} are in sync with metadata.json.`); diff --git a/libs/sdk-code-convertors/src/errorContext.test.ts b/libs/sdk-code-convertors/src/errorContext.test.ts index bc30d8adeaf..9b8c5aad194 100644 --- a/libs/sdk-code-convertors/src/errorContext.test.ts +++ b/libs/sdk-code-convertors/src/errorContext.test.ts @@ -30,23 +30,24 @@ describe("error context propagation", () => { }, }; + let error: ICoreError | undefined; try { declarativeDashboardToYaml([], dashboard); - expect.fail("Should have thrown error"); } catch (err: unknown) { - const error = err as ICoreError; - expect(error.context?.path).toEqual([ - "dashboard", - "my_dash", - "layout", - "sections", - "0", - "items", - "0", - "insight", - "visualisation", - ]); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.context?.path).toEqual([ + "dashboard", + "my_dash", + "layout", + "sections", + "0", + "items", + "0", + "insight", + "visualisation", + ]); }); }); @@ -80,18 +81,14 @@ describe("error context propagation", () => { }, }; + let error: ICoreError | undefined; try { declarativeAttributeHierarchyToYaml(hierarchy); - expect.fail("Should have thrown error"); } catch (err: unknown) { - const error = err as ICoreError; - expect(error.context?.path).toEqual([ - "attribute_hierarchy", - "my_hierarchy", - "attributes", - "0", - ]); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.context?.path).toEqual(["attribute_hierarchy", "my_hierarchy", "attributes", "0"]); }); }); }); diff --git a/libs/sdk-code-convertors/src/index.ts b/libs/sdk-code-convertors/src/index.ts index cc523e6c016..0a10d24c621 100644 --- a/libs/sdk-code-convertors/src/index.ts +++ b/libs/sdk-code-convertors/src/index.ts @@ -1,6 +1,6 @@ // (C) 2024-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files // AAC schema types (curated public surface — isolates api-extractor from generated internals) export type { diff --git a/libs/sdk-code-convertors/src/utils/configUtils.test.ts b/libs/sdk-code-convertors/src/utils/configUtils.test.ts index fd1daef0b19..74f22952a89 100644 --- a/libs/sdk-code-convertors/src/utils/configUtils.test.ts +++ b/libs/sdk-code-convertors/src/utils/configUtils.test.ts @@ -93,12 +93,14 @@ describe("loadColorDefinitions", () => { }); it("refuses a slot it does not name, reporting which", () => { + let error: ICoreError | undefined; try { loadColorDefinitions([{ id: "properties.color.other", color: guid("5") }]); - expect.fail("Should have thrown error"); } catch (err: unknown) { - expect((err as ICoreError).code).toBe(CoreErrorCode.ItemNotSupported); - expect((err as ICoreError).message).toContain("properties.color.other"); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.code).toBe(CoreErrorCode.ItemNotSupported); + expect(error?.message).toContain("properties.color.other"); }); }); diff --git a/libs/sdk-code-convertors/src/utils/yamlUtils.test.ts b/libs/sdk-code-convertors/src/utils/yamlUtils.test.ts index eb58825ea7a..818e11e3997 100644 --- a/libs/sdk-code-convertors/src/utils/yamlUtils.test.ts +++ b/libs/sdk-code-convertors/src/utils/yamlUtils.test.ts @@ -13,31 +13,33 @@ describe("yamlUtils", () => { it("should throw error with context when reference type is not supported", () => { const context = { type: "test", path: ["root"] }; + let error: ICoreError | undefined; try { getIdentifier({ uri: "/foo" }, true, context); - expect.fail("Should have thrown error"); } catch (err: unknown) { - const error = err as ICoreError; - expect(error.code).toBe(CoreErrorCode.ReferenceTypeNotSupported); - expect(error.context).toEqual(context); - expect(error.message).toContain("in: root"); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.code).toBe(CoreErrorCode.ReferenceTypeNotSupported); + expect(error?.context).toEqual(context); + expect(error?.message).toContain("in: root"); }); }); describe("createFilterContextItemKeyName", () => { it("should throw error with context for unsupported item", () => { const context = { type: "test", path: ["dashboard"] }; + let error: ICoreError | undefined; try { // @ts-expect-error - passing invalid item createFilterContextItemKeyName({ unknown: "item" }, "date", context); - expect.fail("Should have thrown error"); } catch (err: unknown) { - const error = err as ICoreError; - expect(error.code).toBe(CoreErrorCode.ItemNotSupported); - expect(error.context).toEqual(context); - expect(error.message).toContain("in: dashboard"); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.code).toBe(CoreErrorCode.ItemNotSupported); + expect(error?.context).toEqual(context); + expect(error?.message).toContain("in: dashboard"); }); it("should propagate context to getIdentifier in date filter", () => { @@ -48,29 +50,31 @@ describe("yamlUtils", () => { granularity: "GDC.time.year", }, }; + let error: ICoreError | undefined; try { createFilterContextItemKeyName(item, "date", context); - expect.fail("Should have thrown error"); } catch (err: unknown) { - const error = err as ICoreError; - expect(error.context?.path).toEqual(["dashboard", "dateFilter", "dataSet"]); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.context?.path).toEqual(["dashboard", "dateFilter", "dataSet"]); }); }); describe("createFilterItemKeyName", () => { it("should throw error with context for unsupported item", () => { const context = { type: "test", path: ["filter"] }; + let error: ICoreError | undefined; try { // @ts-expect-error - passing invalid item createFilterItemKeyName({ unknown: "item" }, "date", context); - expect.fail("Should have thrown error"); } catch (err: unknown) { - const error = err as ICoreError; - expect(error.code).toBe(CoreErrorCode.ItemNotSupported); - expect(error.context).toEqual(context); - expect(error.message).toContain("in: filter"); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.code).toBe(CoreErrorCode.ItemNotSupported); + expect(error?.context).toEqual(context); + expect(error?.message).toContain("in: filter"); }); it("should propagate context to getIdentifier in absolute date filter", () => { @@ -80,13 +84,14 @@ describe("yamlUtils", () => { dataSet: { uri: "/foo" }, // invalid for getIdentifier }, }; + let error: ICoreError | undefined; try { createFilterItemKeyName(item, "date", context); - expect.fail("Should have thrown error"); } catch (err: unknown) { - const error = err as ICoreError; - expect(error.context?.path).toEqual(["filter", "absoluteDateFilter", "dataSet"]); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.context?.path).toEqual(["filter", "absoluteDateFilter", "dataSet"]); }); }); }); diff --git a/libs/sdk-code-convertors/src/visualisationConversion.test.ts b/libs/sdk-code-convertors/src/visualisationConversion.test.ts index 8e8716db0b1..eb2150e2f9e 100644 --- a/libs/sdk-code-convertors/src/visualisationConversion.test.ts +++ b/libs/sdk-code-convertors/src/visualisationConversion.test.ts @@ -569,15 +569,17 @@ describe("visualisation conversion", () => { metrics: [{ field: "m1" }], }); + let error: ICoreError | undefined; try { yamlVisualisationToDeclarative(emptyEntities, clashing); - expect.fail("Should have thrown error"); } catch (err: unknown) { - expect((err as ICoreError).code).toBe(CoreErrorCode.DuplicateFilterName); - expect((err as ICoreError).message).toContain("af"); - // The dashboard wording names a tab and filter groups, neither of which a query has. - expect((err as ICoreError).message).not.toContain("dashboard"); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.code).toBe(CoreErrorCode.DuplicateFilterName); + expect(error?.message).toContain("af"); + // The dashboard wording names a tab and filter groups, neither of which a query has. + expect(error?.message).not.toContain("dashboard"); }); it("leaves a measure's own carried filter unnamed, which must never claim one", () => { @@ -662,13 +664,15 @@ describe("visualisation conversion", () => { }) as Visualisation; it("refuses one id claimed by two layers, which would name neither", () => { + let error: ICoreError | undefined; try { yamlVisualisationToDeclarative(emptyEntities, withLayerIds("dup", "dup")); - expect.fail("Should have thrown error"); } catch (err: unknown) { - expect((err as ICoreError).code).toBe(CoreErrorCode.DuplicateLayerIdentifier); - expect((err as ICoreError).message).toContain('"dup"'); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.code).toBe(CoreErrorCode.DuplicateLayerIdentifier); + expect(error?.message).toContain('"dup"'); }); it("converts layers whose ids differ", () => { diff --git a/libs/sdk-code-convertors/src/visualisationErrorContext.test.ts b/libs/sdk-code-convertors/src/visualisationErrorContext.test.ts index 2730759e637..72211d55807 100644 --- a/libs/sdk-code-convertors/src/visualisationErrorContext.test.ts +++ b/libs/sdk-code-convertors/src/visualisationErrorContext.test.ts @@ -12,14 +12,15 @@ describe("declarativeVisualisationToYaml error context", () => { // content is empty which is invalid for isInsight }; + let error: ICoreError | undefined; try { declarativeVisualisationToYaml([], visualisation); - expect.fail("Should have thrown error"); } catch (err: unknown) { - const error = err as ICoreError; - expect(error.context?.type).toBe("visualisation"); - expect(error.context?.path).toEqual(["visualisation", "my_vis"]); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.context?.type).toBe("visualisation"); + expect(error?.context?.path).toEqual(["visualisation", "my_vis"]); }); it("should include full path for invalid attribute in bucket", () => { @@ -43,23 +44,24 @@ describe("declarativeVisualisationToYaml error context", () => { }, }; + let error: ICoreError | undefined; try { declarativeVisualisationToYaml([], visualisation); - expect.fail("Should have thrown error"); } catch (err: unknown) { - const error = err as ICoreError; - expect(error.context?.path).toEqual([ - "visualisation", - "my_vis", - "insight", - "buckets", - "0", - "items", - "0", - "attribute", - "displayForm", - ]); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.context?.path).toEqual([ + "visualisation", + "my_vis", + "insight", + "buckets", + "0", + "items", + "0", + "attribute", + "displayForm", + ]); }); it("should include full path for invalid measure in bucket", () => { @@ -87,23 +89,24 @@ describe("declarativeVisualisationToYaml error context", () => { }, }; + let error: ICoreError | undefined; try { declarativeVisualisationToYaml([], visualisation); - expect.fail("Should have thrown error"); } catch (err: unknown) { - const error = err as ICoreError; - expect(error.context?.path).toEqual([ - "visualisation", - "my_vis", - "insight", - "buckets", - "0", - "items", - "0", - "measure", - "item", - ]); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.context?.path).toEqual([ + "visualisation", + "my_vis", + "insight", + "buckets", + "0", + "items", + "0", + "measure", + "item", + ]); }); it("should include full path for unsupported bucket item type", () => { @@ -124,22 +127,23 @@ describe("declarativeVisualisationToYaml error context", () => { }, }; + let error: ICoreError | undefined; try { declarativeVisualisationToYaml([], visualisation); - expect.fail("Should have thrown error"); } catch (err: unknown) { - const error = err as ICoreError; - // Based on the code, it uses bucketItemErrorContext which has bi and ii - expect(error.context?.path).toEqual([ - "visualisation", - "my_vis", - "insight", - "buckets", - "0", - "items", - "0", - ]); + error = err as ICoreError; } + expect(error).toBeDefined(); + // Based on the code, it uses bucketItemErrorContext which has bi and ii + expect(error?.context?.path).toEqual([ + "visualisation", + "my_vis", + "insight", + "buckets", + "0", + "items", + "0", + ]); }); it("should include full path for invalid filter", () => { @@ -158,22 +162,23 @@ describe("declarativeVisualisationToYaml error context", () => { }, }; + let error: ICoreError | undefined; try { declarativeVisualisationToYaml([], visualisation); - expect.fail("Should have thrown error"); } catch (err: unknown) { - const error = err as ICoreError; - expect(error.context?.path).toEqual([ - "visualisation", - "my_vis", - "insight", - "filters", - "0", - "date", - "positiveAttributeFilter", - "displayForm", - ]); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.context?.path).toEqual([ + "visualisation", + "my_vis", + "insight", + "filters", + "0", + "date", + "positiveAttributeFilter", + "displayForm", + ]); }); }); @@ -221,15 +226,16 @@ describe("declarativeVisualisationToYaml layer overrides", () => { { attributeFilterConfigs: { f1: { displayAsLabel: { identifier: "x", type: "displayForm" } } } }, ], ])("refuses a layer carrying its own %s, which the grammar cannot express", (field, override) => { + let error: ICoreError | undefined; try { declarativeVisualisationToYaml([], withLayer(override)); - expect.fail("Should have thrown error"); } catch (err: unknown) { - const error = err as ICoreError; - expect(error.code).toBe(CoreErrorCode.ItemNotSupported); - expect(error.message).toContain(`layer "layer1" own ${field}`); - expect(error.context?.path).toEqual(["visualisation", "my_map", "insight", "layers", "0", field]); + error = err as ICoreError; } + expect(error).toBeDefined(); + expect(error?.code).toBe(CoreErrorCode.ItemNotSupported); + expect(error?.message).toContain(`layer "layer1" own ${field}`); + expect(error?.context?.path).toEqual(["visualisation", "my_map", "insight", "layers", "0", field]); }); // Present-but-empty is the shape stored layers carry, and it loses nothing. diff --git a/libs/sdk-code-convertors/vitest.config.ts b/libs/sdk-code-convertors/vitest.config.ts index a4e9c324d3d..e5597c5dfbd 100644 --- a/libs/sdk-code-convertors/vitest.config.ts +++ b/libs/sdk-code-convertors/vitest.config.ts @@ -2,7 +2,6 @@ import { defineConfig } from "vitest/config"; -// eslint-disable-next-line no-restricted-exports export default defineConfig({ resolve: { preserveSymlinks: true, diff --git a/libs/sdk-code-schemas/.dependency-cruiser.js b/libs/sdk-code-schemas/.dependency-cruiser.js index 7b575751809..593fba33716 100644 --- a/libs/sdk-code-schemas/.dependency-cruiser.js +++ b/libs/sdk-code-schemas/.dependency-cruiser.js @@ -7,7 +7,6 @@ import { PublicLibraryRules, } from "../../common/config/dep-cruiser/default.config.js"; -// eslint-disable-next-line no-restricted-exports export default { forbidden: [...DefaultRules, ...DefaultSdkRules, ...PublicLibraryRules], options: DefaultOptions, diff --git a/libs/sdk-code-schemas/eslint.config.ts b/libs/sdk-code-schemas/eslint.config.ts index a8db92cf5b1..c070b053311 100644 --- a/libs/sdk-code-schemas/eslint.config.ts +++ b/libs/sdk-code-schemas/eslint.config.ts @@ -1,5 +1,3 @@ // (C) 2026 GoodData Corporation -import config from "@gooddata/eslint-config/oxlint-esm-vitest"; - -export default [...config]; +export { default } from "@gooddata/eslint-config/oxlint-esm-vitest"; diff --git a/libs/sdk-code-schemas/package.json b/libs/sdk-code-schemas/package.json index 80147a8749d..015b34a8f9a 100644 --- a/libs/sdk-code-schemas/package.json +++ b/libs/sdk-code-schemas/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-code-schemas", - "version": "11.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "GoodData AAC JSON Schema types and compiled schemas", "license": "MIT", "author": "GoodData", @@ -65,8 +65,9 @@ "lodash-es": "^4.17.23", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "readdirp": "4.1.2", "typescript": "7.0.2", "vitest": "4.1.8" diff --git a/libs/sdk-code-schemas/scripts/refresh-schema.mjs b/libs/sdk-code-schemas/scripts/refresh-schema.mjs index 2a64d2fc3a9..d9fd9af4e0f 100644 --- a/libs/sdk-code-schemas/scripts/refresh-schema.mjs +++ b/libs/sdk-code-schemas/scripts/refresh-schema.mjs @@ -1,6 +1,6 @@ // (C) 2026 GoodData Corporation -/* eslint-disable no-console -- CLI script with intentional progress logging */ +// oxlint-disable eslint-js/no-console -- CLI script with intentional progress logging // // Generates TypeScript types and compiled JSON schema from the AAC JSON Schema source files. diff --git a/libs/sdk-code-schemas/src/index.ts b/libs/sdk-code-schemas/src/index.ts index 0891ca5fcf5..3eb7df67e60 100644 --- a/libs/sdk-code-schemas/src/index.ts +++ b/libs/sdk-code-schemas/src/index.ts @@ -10,7 +10,8 @@ * @packageDocumentation */ -// oxlint-disable no-barrel-files/no-barrel-files +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax + export type * as v1 from "./v1/metadata.js"; export { metadata_v1 } from "./v1/schema.js"; diff --git a/libs/sdk-code-schemas/vitest.config.ts b/libs/sdk-code-schemas/vitest.config.ts index 5763e9a98d7..f51ea80caac 100644 --- a/libs/sdk-code-schemas/vitest.config.ts +++ b/libs/sdk-code-schemas/vitest.config.ts @@ -2,7 +2,6 @@ import { defineConfig } from "vitest/config"; -// eslint-disable-next-line no-restricted-exports export default defineConfig({ resolve: { preserveSymlinks: true, diff --git a/libs/sdk-e2e-utils/package.json b/libs/sdk-e2e-utils/package.json index 10fe2afdbb3..120399dde3e 100644 --- a/libs/sdk-e2e-utils/package.json +++ b/libs/sdk-e2e-utils/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-e2e-utils", - "version": "11.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "GoodData utility functions for Playwright E2E tests", "license": "MIT", "author": "GoodData", @@ -61,8 +61,9 @@ "jiti": "2.6.1", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "typescript": "7.0.2" } } diff --git a/libs/sdk-e2e-utils/src/goodmock.ts b/libs/sdk-e2e-utils/src/goodmock.ts index f660017f543..24e5149c0bd 100644 --- a/libs/sdk-e2e-utils/src/goodmock.ts +++ b/libs/sdk-e2e-utils/src/goodmock.ts @@ -33,7 +33,7 @@ export async function loadMappings(host: string, mappingFilePath: string): Promi body: JSON.stringify(json), }); - // eslint-disable-next-line no-console + // oxlint-disable-next-line eslint-js/no-console console.log(`Goodmock mappings loaded from ${mappingFilePath} (status: ${response.status})`); } @@ -47,7 +47,7 @@ export async function resetScenarios(host: string): Promise { const response = await fetch(`http://${host}/__admin/scenarios/reset`, { method: "POST", }); - // eslint-disable-next-line no-console + // oxlint-disable-next-line eslint-js/no-console console.log(`Goodmock scenarios reset (status: ${response.status})`); } @@ -59,7 +59,7 @@ export async function resetMappings(host: string): Promise { const response = await fetch(`http://${host}/__admin/reset`, { method: "POST", }); - // eslint-disable-next-line no-console + // oxlint-disable-next-line eslint-js/no-console console.log(`Goodmock mappings reset (status: ${response.status})`); } @@ -83,7 +83,7 @@ export async function mockLogRequests(host: string): Promise { }, }), }); - // eslint-disable-next-line no-console + // oxlint-disable-next-line eslint-js/no-console console.log(`Goodmock log requests mocked (status: ${response.status})`); } @@ -119,7 +119,7 @@ export async function startRecording(host: string, backendHost: string): Promise response: { proxyBaseUrl: backendHost }, }), }); - // eslint-disable-next-line no-console + // oxlint-disable-next-line eslint-js/no-console console.log(`Goodmock recording started, proxying to ${backendHost} (status: ${response.status})`); } @@ -219,7 +219,7 @@ function sanitizeWorkspaceId( const sanitizedDataString = dataString.split(sourceWorkspaceId).join(targetWorkspaceId); const sanitizedData = JSON.parse(sanitizedDataString) as { mappings: IGoodmockMapping[] }; - // eslint-disable-next-line no-console + // oxlint-disable-next-line eslint-js/no-console console.log(`Sanitized workspaceId in mappings (${sourceWorkspaceId} -> ${targetWorkspaceId})`); return sanitizedData.mappings; @@ -402,6 +402,6 @@ export async function snapshotAndSaveRecording( mkdirSync(dirname(mappingFilePath), { recursive: true }); writeFileSync(mappingFilePath, output); - // eslint-disable-next-line no-console + // oxlint-disable-next-line eslint-js/no-console console.log(`Recording saved to ${mappingFilePath} (${sanitizedMappings.length} mappings)`); } diff --git a/libs/sdk-e2e-utils/src/index.ts b/libs/sdk-e2e-utils/src/index.ts index 171b83b1b10..b49415a1541 100644 --- a/libs/sdk-e2e-utils/src/index.ts +++ b/libs/sdk-e2e-utils/src/index.ts @@ -1,6 +1,6 @@ // (C) 2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files export { authHeader, authedRouteFetch, injectAuthHeader } from "./auth.js"; export { diff --git a/libs/sdk-embedding/.dependency-cruiser.js b/libs/sdk-embedding/.dependency-cruiser.js index 7b575751809..593fba33716 100644 --- a/libs/sdk-embedding/.dependency-cruiser.js +++ b/libs/sdk-embedding/.dependency-cruiser.js @@ -7,7 +7,6 @@ import { PublicLibraryRules, } from "../../common/config/dep-cruiser/default.config.js"; -// eslint-disable-next-line no-restricted-exports export default { forbidden: [...DefaultRules, ...DefaultSdkRules, ...PublicLibraryRules], options: DefaultOptions, diff --git a/libs/sdk-embedding/package.json b/libs/sdk-embedding/package.json index 18f764d087e..11bc76cbbc0 100644 --- a/libs/sdk-embedding/package.json +++ b/libs/sdk-embedding/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-embedding", - "version": "11.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "GoodData Embedding APIs", "license": "MIT", "author": "GoodData", @@ -67,8 +67,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "typescript": "7.0.2", "vitest": "4.1.8" } diff --git a/libs/sdk-embedding/src/index.ts b/libs/sdk-embedding/src/index.ts index e0dc840f5a1..e0d1890d8ad 100644 --- a/libs/sdk-embedding/src/index.ts +++ b/libs/sdk-embedding/src/index.ts @@ -1,6 +1,6 @@ // (C) 2019-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files /** * This package defines APIs for embedding and interfacing with the embedded GoodData applications - Analytical Designer and Dashboards/KPI Dashboards. diff --git a/libs/sdk-embedding/src/internal/index.ts b/libs/sdk-embedding/src/internal/index.ts index a037d34edec..7ff0eaafa9b 100644 --- a/libs/sdk-embedding/src/internal/index.ts +++ b/libs/sdk-embedding/src/internal/index.ts @@ -3,7 +3,7 @@ import { messagingUtils } from "./messagingUtils.js"; import { validators } from "./validators.js"; -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files export { messagingUtils, validators }; export { diff --git a/libs/sdk-embedding/vitest.config.ts b/libs/sdk-embedding/vitest.config.ts index 04ad74ff664..09371ab4118 100644 --- a/libs/sdk-embedding/vitest.config.ts +++ b/libs/sdk-embedding/vitest.config.ts @@ -2,7 +2,6 @@ import { defineConfig } from "vitest/config"; -// eslint-disable-next-line no-restricted-exports export default defineConfig({ resolve: { preserveSymlinks: true, diff --git a/libs/sdk-model/.dependency-cruiser.js b/libs/sdk-model/.dependency-cruiser.js index 7b575751809..593fba33716 100644 --- a/libs/sdk-model/.dependency-cruiser.js +++ b/libs/sdk-model/.dependency-cruiser.js @@ -7,7 +7,6 @@ import { PublicLibraryRules, } from "../../common/config/dep-cruiser/default.config.js"; -// eslint-disable-next-line no-restricted-exports export default { forbidden: [...DefaultRules, ...DefaultSdkRules, ...PublicLibraryRules], options: DefaultOptions, diff --git a/libs/sdk-model/api/sdk-model.api.md b/libs/sdk-model/api/sdk-model.api.md index 5c081c79711..4cf02b7a7b1 100644 --- a/libs/sdk-model/api/sdk-model.api.md +++ b/libs/sdk-model/api/sdk-model.api.md @@ -3554,12 +3554,10 @@ export interface IInPlatformNotificationChannelMetadataObject extends INotificat export type IInPlatformNotificationChannelMetadataObjectDefinition = ToMdObjectDefinition; // @public -export type IInsight = IInsightDefinition & { +export type IInsight = IInsightDefinition & IInsightIdentity & { insight: IAuditable & { - identifier: string; - uri: string; - ref: ObjRef; isLocked?: boolean; + isDraft?: boolean; certification?: IObjectCertification; }; }; @@ -3582,6 +3580,20 @@ export type IInsightDefinition = { }; }; +// @public +export type IInsightDefinitionWithOptionalIdentity = IInsightDefinition & { + insight: Partial; +}; + +// @public +export type IInsightIdentity = { + insight: { + identifier: string; + uri: string; + ref: ObjRef; + }; +}; + // @alpha export interface IInsightLayerDefinition { attributeFilterConfigs?: IAttributeFilterConfigs; @@ -7659,7 +7671,7 @@ export type RemotePluggableApplicationsRegistry = IRemotePluggableApplicationsRe export type ReportBackground = IReportColorBackground | IReportImageBackground; // @alpha -export type ReportBuiltInVariable = "reportTitle" | "periodStart" | "periodEnd" | "workspaceName" | "generatedAt" | "pageNumber" | "totalPages" | "logo" | "logoInverse"; +export type ReportBuiltInVariable = "reportName" | "reportDescription" | "periodStart" | "periodEnd" | "reportDateRange" | "reportAttributeFilters" | "exportedAt" | "exportedBy" | "lastModifiedAt" | "lastModifiedBy" | "workspaceName" | "workspaceId" | "totalPages" | "currentPageNumber" | "logo" | "logoInverse"; // @alpha export const ReportBuiltInVariables: ReportBuiltInVariable[]; @@ -7706,6 +7718,9 @@ export const ReportsBrandKitImageVariablePrefix = "image_"; // @alpha export type ReportSlot = IReportVisualizationSlot | IReportTextSlot | IReportImageSlot; +// @alpha +export function reportTextPlaceholder(name: string): string; + // @alpha export type ReportTextSlotKind = "title" | "subtitle" | "sectionTitle" | "description" | "summary" | "body" | "custom"; diff --git a/libs/sdk-model/package.json b/libs/sdk-model/package.json index 417180b5709..c4a24dd261c 100644 --- a/libs/sdk-model/package.json +++ b/libs/sdk-model/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-model", - "version": "11.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "GoodData Model definitions used by UI components and Backend SPI", "license": "MIT", "author": "GoodData", @@ -71,8 +71,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "typescript": "7.0.2", "vitest": "4.1.8" } diff --git a/libs/sdk-model/src/dashboard/drillUrl.ts b/libs/sdk-model/src/dashboard/drillUrl.ts index abd73b59d15..281ef4082db 100644 --- a/libs/sdk-model/src/dashboard/drillUrl.ts +++ b/libs/sdk-model/src/dashboard/drillUrl.ts @@ -1,7 +1,8 @@ // (C) 2022-2026 GoodData Corporation +import { type IAttributeDisplayFormMetadataObject } from "../ldm/metadata/attributeDisplayForm/index.js"; import { idRef } from "../objRef/factory.js"; -import { type IdentifierRef, isIdentifierRef } from "../objRef/index.js"; +import { type IdentifierRef, type ObjRef, isComputedAttributeRef, isIdentifierRef } from "../objRef/index.js"; /** * @internal @@ -34,12 +35,87 @@ const dashboardMeasureValueFilterMatchRegexp = /\{dash_mvf_condition\((.*?)\)\}/ const insightAttributeFilterMatchRegexp = /\{attribute_filter_selection\((.*?)\)\}/g; const insightMeasureValueFilterMatchRegexp = /\{mvf_condition\((.*?)\)\}/g; -const attributeIdentifierToPlaceholder = (ref: IdentifierRef) => `{attribute_title(${ref.identifier})}`; +/** + * A placeholder names its target by identifier alone, which used to be enough because every target + * was a display form. A computed attribute has no labels on the backend and must be referenced by + * its own object type, so its identifier carries this type prefix to keep the two apart - both when + * a placeholder is turned into a stored reference and when that reference is rendered back into the + * URL. A bare identifier keeps meaning a display form, so URLs stored before this existed parse + * unchanged; the prefix cannot collide with an identifier because "/" is not a legal identifier + * character. + */ +const COMPUTED_ATTRIBUTE_PREFIX = "computed_attribute/"; + +const isComputedAttributePlaceholderIdentifier = (identifier: string): boolean => + identifier.startsWith(COMPUTED_ATTRIBUTE_PREFIX); + +/** + * The identifier of the object a placeholder points at, without the type prefix. + */ +const placeholderIdentifier = (identifier: string): string => + isComputedAttributePlaceholderIdentifier(identifier) + ? identifier.slice(COMPUTED_ATTRIBUTE_PREFIX.length) + : identifier; + +const placeholderToRef = (identifier: string): IdentifierRef => + isComputedAttributePlaceholderIdentifier(identifier) + ? idRef(placeholderIdentifier(identifier), "computedAttribute") + : idRef(identifier, "displayForm"); + +/** + * The identifier text a placeholder uses to name the given object, exactly as it appears inside the + * placeholder in the URL - type-prefixed for a computed attribute, bare for a display form. + * + * @internal + */ +export const placeholderIdentifierText = (ref: ObjRef): string => { + const prefix = isComputedAttributeRef(ref) ? COMPUTED_ATTRIBUTE_PREFIX : ""; + // Tiger references objects by identifier only; the uri branch just keeps the function total. + const identifier = isIdentifierRef(ref) ? ref.identifier : ref.uri; + + return `${prefix}${identifier}`; +}; + +/** + * The reference a placeholder uses to name the given display form. + * + * The identifier always comes from `id` and only the kind of object is taken from the ref, because a + * display form can be described by a uri ref, which a placeholder has no way to express - placeholders + * name their target by identifier alone. + * + * @internal + */ +export const displayFormPlaceholderRef = (df: IAttributeDisplayFormMetadataObject): ObjRef => + isComputedAttributeRef(df.ref) ? idRef(df.id, "computedAttribute") : idRef(df.id, "displayForm"); + +/** + * Builds the `{attribute_title(...)}` placeholder text referencing the given object. + * + * @internal + */ +export const attributeIdentifierToPlaceholder = (ref: ObjRef): string => + `{attribute_title(${placeholderIdentifierText(ref)})}`; + +/** + * Builds the `{dash_attribute_filter_selection(...)}` placeholder text referencing the given object. + * + * @internal + */ +export const dashboardAttributeFilterToPlaceholder = (ref: ObjRef): string => + `{dash_attribute_filter_selection(${placeholderIdentifierText(ref)})}`; + +/** + * Builds the `{attribute_filter_selection(...)}` placeholder text referencing the given object. + * + * @internal + */ +export const insightAttributeFilterToPlaceholder = (ref: ObjRef): string => + `{attribute_filter_selection(${placeholderIdentifierText(ref)})}`; const matchToUrlPlaceholder = (match: any): IDrillToUrlPlaceholder => ({ placeholder: match[0], - identifier: match[1], - ref: idRef(match[1], "displayForm"), + identifier: placeholderIdentifier(match[1]), + ref: placeholderToRef(match[1]), toBeEncoded: match.index !== 0, }); diff --git a/libs/sdk-model/src/dashboard/drillUrls.test.ts b/libs/sdk-model/src/dashboard/drillUrls.test.ts index 67a27911ab7..e274163e0cd 100644 --- a/libs/sdk-model/src/dashboard/drillUrls.test.ts +++ b/libs/sdk-model/src/dashboard/drillUrls.test.ts @@ -2,10 +2,19 @@ import { describe, expect, it } from "vitest"; +import { type IAttributeDisplayFormMetadataObject } from "../ldm/metadata/attributeDisplayForm/index.js"; +import { idRef, uriRef } from "../objRef/factory.js"; + import { + attributeIdentifierToPlaceholder, + dashboardAttributeFilterToPlaceholder, + displayFormPlaceholderRef, getAttributeIdentifiersPlaceholdersFromUrl, + getDashboardAttributeFilterPlaceholdersFromUrl, getDashboardMeasureValueFilterPlaceholdersFromUrl, + getInsightAttributeFilterPlaceholdersFromUrl, getInsightMeasureValueFilterPlaceholdersFromUrl, + insightAttributeFilterToPlaceholder, joinDrillUrlParts, splitDrillUrlParts, } from "./drillUrl.js"; @@ -35,6 +44,104 @@ describe("drill url placeholders", () => { expect(joinDrillUrlParts(url)).toBe(url); }); + it("should reference a computed attribute by its own type, not as a display form", () => { + const url = "https://example.com/?q={attribute_title(computed_attribute/ca1)}"; + + expect(getAttributeIdentifiersPlaceholdersFromUrl(url)).toEqual([ + { + placeholder: "{attribute_title(computed_attribute/ca1)}", + identifier: "ca1", + ref: { + identifier: "ca1", + type: "computedAttribute", + }, + toBeEncoded: true, + }, + ]); + + const urlParts = splitDrillUrlParts(url); + expect(urlParts).toEqual(["https://example.com/?q=", idRef("ca1", "computedAttribute"), ""]); + expect(joinDrillUrlParts(urlParts)).toBe(url); + }); + + it("should build the placeholder text for a display form and for a computed attribute", () => { + expect(attributeIdentifierToPlaceholder(idRef("label1", "displayForm"))).toBe( + "{attribute_title(label1)}", + ); + expect(attributeIdentifierToPlaceholder(idRef("ca1", "computedAttribute"))).toBe( + "{attribute_title(computed_attribute/ca1)}", + ); + }); + + it("should reference a computed attribute from the filter selection placeholders", () => { + expect( + getDashboardAttributeFilterPlaceholdersFromUrl( + "https://example.com/?f={dash_attribute_filter_selection(computed_attribute/ca1)}", + ), + ).toEqual([ + { + placeholder: "{dash_attribute_filter_selection(computed_attribute/ca1)}", + identifier: "ca1", + ref: { identifier: "ca1", type: "computedAttribute" }, + toBeEncoded: true, + }, + ]); + + expect( + getInsightAttributeFilterPlaceholdersFromUrl( + "https://example.com/?f={attribute_filter_selection(computed_attribute/ca1)}", + ), + ).toEqual([ + { + placeholder: "{attribute_filter_selection(computed_attribute/ca1)}", + identifier: "ca1", + ref: { identifier: "ca1", type: "computedAttribute" }, + toBeEncoded: true, + }, + ]); + }); + + it("should keep the filter selection placeholders unprefixed for a display form", () => { + expect(dashboardAttributeFilterToPlaceholder(idRef("label1", "displayForm"))).toBe( + "{dash_attribute_filter_selection(label1)}", + ); + expect(dashboardAttributeFilterToPlaceholder(idRef("ca1", "computedAttribute"))).toBe( + "{dash_attribute_filter_selection(computed_attribute/ca1)}", + ); + expect(insightAttributeFilterToPlaceholder(idRef("label1", "displayForm"))).toBe( + "{attribute_filter_selection(label1)}", + ); + expect(insightAttributeFilterToPlaceholder(idRef("ca1", "computedAttribute"))).toBe( + "{attribute_filter_selection(computed_attribute/ca1)}", + ); + }); + + it("should name a display form by identifier even when its ref is a uri", () => { + // A placeholder can only name its target by identifier, so a uri-backed display form has to + // fall back to its id rather than leaking the uri into the URL. + const uriBackedDisplayForm = { + id: "label1", + ref: uriRef("/gdc/md/project/obj/123"), + } as IAttributeDisplayFormMetadataObject; + + expect(displayFormPlaceholderRef(uriBackedDisplayForm)).toEqual(idRef("label1", "displayForm")); + expect(attributeIdentifierToPlaceholder(displayFormPlaceholderRef(uriBackedDisplayForm))).toBe( + "{attribute_title(label1)}", + ); + }); + + it("should keep the computed attribute type when naming a display form", () => { + const computedAttribute = { + id: "ca1", + ref: idRef("ca1", "computedAttribute"), + } as IAttributeDisplayFormMetadataObject; + + expect(displayFormPlaceholderRef(computedAttribute)).toEqual(idRef("ca1", "computedAttribute")); + expect(attributeIdentifierToPlaceholder(displayFormPlaceholderRef(computedAttribute))).toBe( + "{attribute_title(computed_attribute/ca1)}", + ); + }); + it("should extract dashboard measure value filter placeholders", () => { const placeholders = getDashboardMeasureValueFilterPlaceholdersFromUrl( "https://example.com/?condition={dash_mvf_condition(metric.revenue)}", diff --git a/libs/sdk-model/src/index.ts b/libs/sdk-model/src/index.ts index 3fec43155b8..8406268c2f0 100644 --- a/libs/sdk-model/src/index.ts +++ b/libs/sdk-model/src/index.ts @@ -1,6 +1,6 @@ // (C) 2019-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files /** * This package provides domain models for GoodData.UI. @@ -514,7 +514,9 @@ export { export { type IInsight, + type IInsightIdentity, type IInsightDefinition, + type IInsightDefinitionWithOptionalIdentity, type IVisualizationClass, type IVisualizationClassBody, type VisualizationProperties, @@ -1507,6 +1509,7 @@ export { type IReportVariableDefinition, ReportBuiltInVariables, getReportTextPlaceholders, + reportTextPlaceholder, resolveReportTextPlaceholders, } from "./reports/variables.js"; diff --git a/libs/sdk-model/src/insight/index.ts b/libs/sdk-model/src/insight/index.ts index 61bba91c6ff..4732d497f9f 100644 --- a/libs/sdk-model/src/insight/index.ts +++ b/libs/sdk-model/src/insight/index.ts @@ -54,8 +54,38 @@ import { type IUser } from "../user/index.js"; * * @public */ -export type IInsight = IInsightDefinition & { - insight: IAuditable & { +export type IInsight = IInsightDefinition & + IInsightIdentity & { + insight: IAuditable & { + /** + * Insight is locked for editing & deleting + */ + isLocked?: boolean; + + /** + * Insight is draft only, its not saved yet + */ + isDraft?: boolean; + + /** + * Certification metadata. + * @internal + */ + certification?: IObjectCertification; + }; + }; + +/** + * Identity of an Insight. Insight is typically created using Analytical Designer + * and can be embedded using UI SDK. + * + * @remarks + * Identity of an Insight contains all metadata needed to reference the Insight. + * + * @public + */ +export type IInsightIdentity = { + insight: { /** * Unique identifier of the Insight */ @@ -70,17 +100,6 @@ export type IInsight = IInsightDefinition & { * Object to use when referencing insight. */ ref: ObjRef; - - /** - * Insight is locked for editing & deleting - */ - isLocked?: boolean; - - /** - * Certification metadata. - * @internal - */ - certification?: IObjectCertification; }; }; @@ -204,6 +223,16 @@ export type IInsightDefinition = { }; }; +/** + * Insight definition specifies what and how should be visualized by an insight + * with optional identity. + * + * @public + */ +export type IInsightDefinitionWithOptionalIdentity = IInsightDefinition & { + insight: Partial; +}; + /** * Object defining the {@link IVisualizationClass} object body. * diff --git a/libs/sdk-model/src/internal.ts b/libs/sdk-model/src/internal.ts index 733c0b3f172..b6399fe7ad4 100644 --- a/libs/sdk-model/src/internal.ts +++ b/libs/sdk-model/src/internal.ts @@ -1,10 +1,15 @@ // (C) 2023-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files export { type IDrillToUrlPlaceholder, + attributeIdentifierToPlaceholder, + dashboardAttributeFilterToPlaceholder, + displayFormPlaceholderRef, + insightAttributeFilterToPlaceholder, joinDrillUrlParts, + placeholderIdentifierText, splitDrillUrlParts, getAttributeIdentifiersPlaceholdersFromUrl, getDashboardAttributeFilterPlaceholdersFromUrl, diff --git a/libs/sdk-model/src/ldm/metadata/attributeDisplayForm/index.test.ts b/libs/sdk-model/src/ldm/metadata/attributeDisplayForm/index.test.ts index 6c15b6e625b..0705ea3856b 100644 --- a/libs/sdk-model/src/ldm/metadata/attributeDisplayForm/index.test.ts +++ b/libs/sdk-model/src/ldm/metadata/attributeDisplayForm/index.test.ts @@ -11,7 +11,7 @@ import { attributeDisplayFormMetadataObjectTitle, } from "./index.js"; -/* oxlint-disable no-undef */ +// oxlint-disable no-undef describe("attribute display form", () => { const _attributeDisplayFormTitle = "Account"; diff --git a/libs/sdk-model/src/reports/brandKit.ts b/libs/sdk-model/src/reports/brandKit.ts index e4645b649d0..28fa5b714b7 100644 --- a/libs/sdk-model/src/reports/brandKit.ts +++ b/libs/sdk-model/src/reports/brandKit.ts @@ -10,7 +10,7 @@ import { type IRgbColorValue } from "../colors/index.js"; export interface IReportsBrandKitImage { /** * Identifier the image is referenced by from report content, as the - * `{{image_}}` variable. Must match /^[a-zA-Z0-9_]+$/. + * `{image_}` variable. Must match /^[a-zA-Z0-9_]+$/. */ id: string; @@ -130,18 +130,18 @@ export interface IReportsBrandKitTypography { */ export interface IReportsBrandKitAssets { /** - * Primary logo URL; resolves the `{{logo}}` report variable, taking precedence over + * Primary logo URL; resolves the `{logo}` report variable, taking precedence over * the workspace white-labeling logo. */ logo?: string; /** - * Logo variant for dark backgrounds; resolves the `{{logoInverse}}` report variable. + * Logo variant for dark backgrounds; resolves the `{logoInverse}` report variable. */ logoInverse?: string; /** - * Additional brand images, each resolving its `{{image_}}` report variable. + * Additional brand images, each resolving its `{image_}` report variable. */ images?: IReportsBrandKitImage[]; } diff --git a/libs/sdk-model/src/reports/builtinPageLayouts.ts b/libs/sdk-model/src/reports/builtinPageLayouts.ts index f3519103212..eb07e2763e7 100644 --- a/libs/sdk-model/src/reports/builtinPageLayouts.ts +++ b/libs/sdk-model/src/reports/builtinPageLayouts.ts @@ -32,7 +32,7 @@ const vizSlot = (localIdentifier: string): IReportVisualizationSlot => ({ const logoSlot = (localIdentifier: string): IReportImageSlot => ({ type: "image", localIdentifier, - source: { type: "url", url: "{{logo}}" }, + source: { type: "url", url: "{logo}" }, fit: "contain", altText: "Logo", style: { horizontalAlign: "start", verticalAlign: "end" }, @@ -64,7 +64,7 @@ const footerSlots = () => [ ...textSlot({ localIdentifier: "footerPageNumber", kind: "custom", - content: "{{pageNumber}} / {{totalPages}}", + content: "{currentPageNumber} / {totalPages}", }), style: { horizontalAlign: "end", verticalAlign: "end" }, } satisfies IReportTextSlot, @@ -164,11 +164,11 @@ export const BuiltInReportPageLayoutCover: IReportPageLayout = builtInPage({ format: "widescreen", layout: column([slot("coverTitle", 2), slot("coverSubtitle", 1), footerRow()]), slots: [ - textSlot({ localIdentifier: "coverTitle", kind: "title", content: "{{reportTitle}}" }), + textSlot({ localIdentifier: "coverTitle", kind: "title", content: "{reportName}" }), textSlot({ localIdentifier: "coverSubtitle", kind: "subtitle", - content: "{{periodStart}} – {{periodEnd}}", + content: "{periodStart} – {periodEnd}", }), ...footerSlots(), ], @@ -338,11 +338,11 @@ export const BuiltInReportPageLayoutPortraitCover: IReportPageLayout = builtInPa format: PORTRAIT_FORMAT, layout: column([slot("coverTitle", 2), slot("coverSubtitle", 1), footerRow()]), slots: [ - textSlot({ localIdentifier: "coverTitle", kind: "title", content: "{{reportTitle}}" }), + textSlot({ localIdentifier: "coverTitle", kind: "title", content: "{reportName}" }), textSlot({ localIdentifier: "coverSubtitle", kind: "subtitle", - content: "{{periodStart}} – {{periodEnd}}", + content: "{periodStart} – {periodEnd}", }), ...footerSlots(), ], diff --git a/libs/sdk-model/src/reports/pageLayout.ts b/libs/sdk-model/src/reports/pageLayout.ts index db9e3c6b40c..c2f6ff455e9 100644 --- a/libs/sdk-model/src/reports/pageLayout.ts +++ b/libs/sdk-model/src/reports/pageLayout.ts @@ -19,8 +19,8 @@ import { type IReportBoxStyle, isReportImageBackground } from "./styling.js"; * embedded in template/report content ({@link IReportContentPage}). * * There is no header/footer chrome: page title, description, footer, page numbers and - * logos are ordinary slots in the layout tree (text slots with `{{pageNumber}}`/`{{totalPages}}`, - * an image slot with `{{logo}}`). Every slot fills its layout area completely. + * logos are ordinary slots in the layout tree (text slots with `{currentPageNumber}`/`{totalPages}`, + * an image slot with `{logo}`). Every slot fills its layout area completely. * * @alpha */ diff --git a/libs/sdk-model/src/reports/report.ts b/libs/sdk-model/src/reports/report.ts index a3f40266e8a..02dd535d52e 100644 --- a/libs/sdk-model/src/reports/report.ts +++ b/libs/sdk-model/src/reports/report.ts @@ -63,7 +63,7 @@ export interface IReportBase { * @remarks * At execution time the period materializes as an absolute date filter on each * visualization slot's dateDataSet (lowest precedence, per-slot opt-out via - * ignoreReportPeriod). Also available as `{{periodStart}}` in text. + * ignoreReportPeriod). Also available as `{periodStart}` in text. */ periodStart: ReportDateString; diff --git a/libs/sdk-model/src/reports/reports.test.ts b/libs/sdk-model/src/reports/reports.test.ts index e03cf5795ef..77b1ae7fe58 100644 --- a/libs/sdk-model/src/reports/reports.test.ts +++ b/libs/sdk-model/src/reports/reports.test.ts @@ -33,7 +33,11 @@ import { } from "./pageLayout.js"; import { isReport, isReportDefinition, isReportTemplate, isReportTemplateDefinition } from "./report.js"; import { isReportImageSlot, isReportSlot, isReportTextSlot, isReportVisualizationSlot } from "./slot.js"; -import { getReportTextPlaceholders, resolveReportTextPlaceholders } from "./variables.js"; +import { + getReportTextPlaceholders, + reportTextPlaceholder, + resolveReportTextPlaceholders, +} from "./variables.js"; const body: IReportPageBody = { kind: "content", @@ -53,22 +57,36 @@ const body: IReportPageBody = { describe("placeholder helpers", () => { it("collects distinct placeholders in order of first occurrence", () => { - expect(getReportTextPlaceholders("{{periodStart}} to {{periodEnd}} ({{periodStart}})")).toEqual([ + expect(getReportTextPlaceholders("{periodStart} to {periodEnd} ({periodStart})")).toEqual([ "periodStart", "periodEnd", ]); }); it("ignores malformed markers", () => { - expect(getReportTextPlaceholders("{{1bad}} {{ spaced }} {{}} {{good_1}}")).toEqual(["good_1"]); + expect(getReportTextPlaceholders("{1bad} { spaced } {} {good_1}")).toEqual(["good_1"]); + }); + + it("resolves a marker inside braces, leaving the braces in place", () => { + expect(getReportTextPlaceholders("{{periodStart}}")).toEqual(["periodStart"]); + expect(resolveReportTextPlaceholders("{{a}}", { a: "1" })).toBe("{1}"); + }); + + it("reads markers written back to back", () => { + expect(getReportTextPlaceholders("{a}{b}")).toEqual(["a", "b"]); + expect(resolveReportTextPlaceholders("{a}{b}", { a: "1", b: "2" })).toBe("12"); + }); + + it("builds a marker the collector reads back", () => { + expect(getReportTextPlaceholders(reportTextPlaceholder("periodStart"))).toEqual(["periodStart"]); }); it("resolves known values and keeps unknown markers", () => { - expect(resolveReportTextPlaceholders("{{a}} and {{b}}", { a: "1" })).toBe("1 and {{b}}"); + expect(resolveReportTextPlaceholders("{a} and {b}", { a: "1" })).toBe("1 and {b}"); }); it("does not expand values recursively", () => { - expect(resolveReportTextPlaceholders("{{a}}", { a: "{{b}}", b: "x" })).toBe("{{b}}"); + expect(resolveReportTextPlaceholders("{a}", { a: "{b}", b: "x" })).toBe("{b}"); }); }); diff --git a/libs/sdk-model/src/reports/slot.ts b/libs/sdk-model/src/reports/slot.ts index f7111391e8f..9f3527069c5 100644 --- a/libs/sdk-model/src/reports/slot.ts +++ b/libs/sdk-model/src/reports/slot.ts @@ -64,7 +64,7 @@ export interface IReportVisualizationSlot extends IReportSlotBase { insight?: ObjRef; /** - * Optional title rendered above the visualization. Supports `{{variables}}`. + * Optional title rendered above the visualization. Supports `{variables}`. */ title?: string; @@ -124,7 +124,7 @@ export interface IReportStaticTextSource { type: "static"; /** - * Markdown content with `{{variable}}` placeholders. Stored raw — placeholders are + * Markdown content with `{variable}` placeholders. Stored raw — placeholders are * resolved only at render/export time. */ content: string; @@ -139,7 +139,7 @@ export interface IReportAiTextSource { type: "ai"; /** - * Instruction for the generator. Supports `{{variables}}`. + * Instruction for the generator. Supports `{variables}`. */ prompt: string; @@ -193,7 +193,7 @@ export type ReportImageSource = type: "url"; /** - * Image URL. Supports `{{variables}}` — a logo slot uses `{{logo}}`. + * Image URL. Supports `{variables}` — a logo slot uses `{logo}`. */ url: string; } diff --git a/libs/sdk-model/src/reports/variables.ts b/libs/sdk-model/src/reports/variables.ts index 203c4f98c07..eb9de4922f7 100644 --- a/libs/sdk-model/src/reports/variables.ts +++ b/libs/sdk-model/src/reports/variables.ts @@ -11,19 +11,26 @@ export type ReportDateString = string; * Variables resolved by the rendering runtime; they are never declared or stored. * * @remarks - * Referenced from report text as `{{name}}`. Custom variable names must not collide with these; + * Referenced from report text as `{name}`. Custom variable names must not collide with these; * on collision the built-in wins. * * @alpha */ export type ReportBuiltInVariable = - | "reportTitle" + | "reportName" + | "reportDescription" | "periodStart" | "periodEnd" + | "reportDateRange" + | "reportAttributeFilters" + | "exportedAt" + | "exportedBy" + | "lastModifiedAt" + | "lastModifiedBy" | "workspaceName" - | "generatedAt" - | "pageNumber" + | "workspaceId" | "totalPages" + | "currentPageNumber" | "logo" | "logoInverse"; @@ -33,13 +40,20 @@ export type ReportBuiltInVariable = * @alpha */ export const ReportBuiltInVariables: ReportBuiltInVariable[] = [ - "reportTitle", + "reportName", + "reportDescription", "periodStart", "periodEnd", + "reportDateRange", + "reportAttributeFilters", + "exportedAt", + "exportedBy", + "lastModifiedAt", + "lastModifiedBy", "workspaceName", - "generatedAt", - "pageNumber", + "workspaceId", "totalPages", + "currentPageNumber", "logo", "logoInverse", ]; @@ -48,14 +62,14 @@ export const ReportBuiltInVariables: ReportBuiltInVariable[] = [ * A custom variable declared by report content and given a value by a report. * * @remarks - * Referenced from text as `{{name}}`. Values come from {@link IReportBase.variableValues}, + * Referenced from text as `{name}`. Values come from {@link IReportBase.variableValues}, * falling back to {@link IReportVariableDefinition.defaultValue}. * * @alpha */ export interface IReportVariableDefinition { /** - * Variable name as used inside the `{{...}}` marker. Must match /^[a-zA-Z][a-zA-Z0-9_]*$/. + * Variable name as used inside the `{...}` marker. Must match /^[a-zA-Z][a-zA-Z0-9_]*$/. * Built-in names ({@link ReportBuiltInVariable}) are reserved. */ name: string; @@ -74,10 +88,19 @@ export interface IReportVariableDefinition { defaultValue?: string; } -const placeholderRegex = /\{\{([a-zA-Z][a-zA-Z0-9_]*)\}\}/g; +const placeholderRegex = /\{([a-zA-Z][a-zA-Z0-9_]*)\}/g; /** - * Collects the distinct `{{variable}}` names referenced in the text, in order of first occurrence. + * The marker referencing the named variable from report text. + * + * @alpha + */ +export function reportTextPlaceholder(name: string): string { + return `{${name}}`; +} + +/** + * Collects the distinct `{variable}` names referenced in the text, in order of first occurrence. * * @alpha */ @@ -93,9 +116,13 @@ export function getReportTextPlaceholders(text: string): string[] { } /** - * Replaces `{{variable}}` markers with values. Markers with no value are left as-is. + * Replaces `{variable}` markers with values. Markers with no value are left as-is. * Values are inserted verbatim — there is no recursive expansion. * + * @remarks + * A marker resolves wherever it appears, braces around it included, so there is no escape for a + * literal `{name}` in report text. + * * @alpha */ export function resolveReportTextPlaceholders(text: string, values: Record): string { diff --git a/libs/sdk-model/vitest.config.ts b/libs/sdk-model/vitest.config.ts index 04ad74ff664..09371ab4118 100644 --- a/libs/sdk-model/vitest.config.ts +++ b/libs/sdk-model/vitest.config.ts @@ -2,7 +2,6 @@ import { defineConfig } from "vitest/config"; -// eslint-disable-next-line no-restricted-exports export default defineConfig({ resolve: { preserveSymlinks: true, diff --git a/libs/sdk-pluggable-application-model/.dependency-cruiser.js b/libs/sdk-pluggable-application-model/.dependency-cruiser.js index 7b575751809..593fba33716 100644 --- a/libs/sdk-pluggable-application-model/.dependency-cruiser.js +++ b/libs/sdk-pluggable-application-model/.dependency-cruiser.js @@ -7,7 +7,6 @@ import { PublicLibraryRules, } from "../../common/config/dep-cruiser/default.config.js"; -// eslint-disable-next-line no-restricted-exports export default { forbidden: [...DefaultRules, ...DefaultSdkRules, ...PublicLibraryRules], options: DefaultOptions, diff --git a/libs/sdk-pluggable-application-model/api/sdk-pluggable-application-model.api.md b/libs/sdk-pluggable-application-model/api/sdk-pluggable-application-model.api.md index 3f271de8f8c..17bd8b7eb9e 100644 --- a/libs/sdk-pluggable-application-model/api/sdk-pluggable-application-model.api.md +++ b/libs/sdk-pluggable-application-model/api/sdk-pluggable-application-model.api.md @@ -157,6 +157,7 @@ export interface IHostUiMountOptions { navigate: (url: string) => void; onAskAiAssistant?: (question: string, agentId?: string, userContext?: IGenAIUserContext, appendToChat?: boolean, replaceUserContext?: boolean) => void; onChatToggleRequested?: () => void; + onError?: (error: string, context: string) => void; pathname: string; replace: (url: string) => void; resolvedApplications: PluggableApplicationRegistryItem[]; diff --git a/libs/sdk-pluggable-application-model/package.json b/libs/sdk-pluggable-application-model/package.json index 551eefbe068..e313f82e3b5 100644 --- a/libs/sdk-pluggable-application-model/package.json +++ b/libs/sdk-pluggable-application-model/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-pluggable-application-model", - "version": "11.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "GoodData SDK model contracts for pluggable applications", "license": "MIT", "author": "GoodData Corporation", @@ -59,8 +59,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "typescript": "7.0.2" } } diff --git a/libs/sdk-pluggable-application-model/src/hostUi.ts b/libs/sdk-pluggable-application-model/src/hostUi.ts index f389ccdfe9d..7a88e9e21f8 100644 --- a/libs/sdk-pluggable-application-model/src/hostUi.ts +++ b/libs/sdk-pluggable-application-model/src/hostUi.ts @@ -79,6 +79,16 @@ export interface IHostUiMountOptions { appendToChat?: boolean, replaceUserContext?: boolean, ) => void; + + /** + * Reports an error caught inside the host UI module's own React tree. + * + * @remarks + * The host UI renders in a React root separate from the host application's, so the + * host's own error boundary cannot observe failures here. Implementations should + * route caught errors through this callback to keep them visible in host telemetry. + */ + onError?: (error: string, context: string) => void; } /** diff --git a/libs/sdk-pluggable-application-model/src/index.ts b/libs/sdk-pluggable-application-model/src/index.ts index 9af8087766f..67bc6546f01 100644 --- a/libs/sdk-pluggable-application-model/src/index.ts +++ b/libs/sdk-pluggable-application-model/src/index.ts @@ -1,6 +1,6 @@ // (C) 2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files /** * Model contracts for pluggable application integration. diff --git a/libs/sdk-ui-all/.dependency-cruiser.js b/libs/sdk-ui-all/.dependency-cruiser.js index 7b575751809..593fba33716 100644 --- a/libs/sdk-ui-all/.dependency-cruiser.js +++ b/libs/sdk-ui-all/.dependency-cruiser.js @@ -7,7 +7,6 @@ import { PublicLibraryRules, } from "../../common/config/dep-cruiser/default.config.js"; -// eslint-disable-next-line no-restricted-exports export default { forbidden: [...DefaultRules, ...DefaultSdkRules, ...PublicLibraryRules], options: DefaultOptions, diff --git a/libs/sdk-ui-all/package.json b/libs/sdk-ui-all/package.json index b6bcb95072f..14b7b1c3fe3 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "GoodData SDK - All-In-One", "license": "LicenseRef-LICENSE", "author": "GoodData", @@ -66,8 +66,9 @@ "eslint-plugin-sonarjs": "3.0.6", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "typescript": "7.0.2" } } diff --git a/libs/sdk-ui-all/src/index.ts b/libs/sdk-ui-all/src/index.ts index aab043854cd..a24e6b20f7e 100644 --- a/libs/sdk-ui-all/src/index.ts +++ b/libs/sdk-ui-all/src/index.ts @@ -1,6 +1,6 @@ // (C) 2019-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files /** * This is an all-in-one package that has all GoodData.UI packages as dependencies and re-exports their public API. @@ -12,7 +12,7 @@ * @packageDocumentation */ -/* eslint-disable no-duplicate-imports,no-restricted-syntax */ +// oxlint-disable eslint-js/no-duplicate-imports, eslint-js/no-restricted-syntax export * from "@gooddata/sdk-model"; export type { IExportResult as IExportResultModel } from "@gooddata/sdk-model"; diff --git a/libs/sdk-ui-application-header/package.json b/libs/sdk-ui-application-header/package.json index b7d1066102a..6d7dc3b3d6d 100644 --- a/libs/sdk-ui-application-header/package.json +++ b/libs/sdk-ui-application-header/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-ui-application-header", - "version": "11.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "GoodData SDK application header components — workspace picker, notifications dropdown", "license": "MIT", "author": "GoodData Corporation", @@ -78,8 +78,9 @@ "jiti": "2.6.1", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "react": "19.1.1", "react-dom": "19.1.1", "react-intl": "10.1.25", diff --git a/libs/sdk-ui-application-header/src/index.ts b/libs/sdk-ui-application-header/src/index.ts index f54d3abf733..9ad6e95ef95 100644 --- a/libs/sdk-ui-application-header/src/index.ts +++ b/libs/sdk-ui-application-header/src/index.ts @@ -1,6 +1,6 @@ // (C) 2022-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files export { AppHeaderNotifications } from "./AppHeaderNotifications/AppHeaderNotifications.js"; export { WorkspacePicker, type IWorkspacePickerProps } from "./WorkspacePicker/WorkspacePicker.js"; diff --git a/libs/sdk-ui-application-header/typings.d.ts b/libs/sdk-ui-application-header/typings.d.ts index e91815950af..cc84f2143ae 100644 --- a/libs/sdk-ui-application-header/typings.d.ts +++ b/libs/sdk-ui-application-header/typings.d.ts @@ -1,6 +1,6 @@ // (C) 2022-2026 GoodData Corporation -/* eslint-disable no-restricted-exports */ +// oxlint-disable eslint-js/no-restricted-exports // eslint-disable-next-line @typescript-eslint/naming-convention interface Window { diff --git a/libs/sdk-ui-application-header/vitest.config.ts b/libs/sdk-ui-application-header/vitest.config.ts index d3caf083fd5..38ef4696597 100644 --- a/libs/sdk-ui-application-header/vitest.config.ts +++ b/libs/sdk-ui-application-header/vitest.config.ts @@ -2,7 +2,6 @@ import { defineConfig } from "vitest/config"; -// eslint-disable-next-line no-restricted-exports export default defineConfig({ resolve: { preserveSymlinks: true, diff --git a/libs/sdk-ui-catalog/.dependency-cruiser.js b/libs/sdk-ui-catalog/.dependency-cruiser.js index 2d46387557b..f5bb76853af 100644 --- a/libs/sdk-ui-catalog/.dependency-cruiser.js +++ b/libs/sdk-ui-catalog/.dependency-cruiser.js @@ -7,7 +7,6 @@ import { PublicLibraryRules, } from "../../common/config/dep-cruiser/default.config.js"; -// eslint-disable-next-line no-restricted-exports export default { forbidden: [...DefaultRules, ...DefaultSdkRules, ...PublicLibraryRules], options: DefaultOptions, diff --git a/libs/sdk-ui-catalog/.oxlintrc.json b/libs/sdk-ui-catalog/.oxlintrc.json index e231486cf68..abca5634928 100644 --- a/libs/sdk-ui-catalog/.oxlintrc.json +++ b/libs/sdk-ui-catalog/.oxlintrc.json @@ -3,5 +3,15 @@ "extends": ["node_modules/@gooddata/oxlint-config/dist/esm-react-vitest.json"], "options": { "typeAware": true - } + }, + "overrides": [ + { + "files": ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"], + "rules": { + "@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/eslint.config.ts b/libs/sdk-ui-catalog/eslint.config.ts index c19ceedce04..47cfed3232f 100644 --- a/libs/sdk-ui-catalog/eslint.config.ts +++ b/libs/sdk-ui-catalog/eslint.config.ts @@ -1,15 +1,3 @@ // (C) 2020-2026 GoodData Corporation -import config from "@gooddata/eslint-config/oxlint-esm-react-vitest"; - -export default [ - ...config, - { - files: ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"], - rules: { - "@typescript-eslint/no-unsafe-member-access": "warn", - "@typescript-eslint/no-unsafe-assignment": "warn", - "@typescript-eslint/restrict-template-expressions": "warn", - }, - }, -]; +export { default } from "@gooddata/eslint-config/oxlint-esm-react-vitest"; diff --git a/libs/sdk-ui-catalog/package.json b/libs/sdk-ui-catalog/package.json index 3fcdbf02903..e7bfd589d6b 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.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "GoodData SDK - Analytics Catalog", "license": "MIT", "author": "GoodData Corporation", @@ -105,12 +105,13 @@ "happy-dom": "20.12.0", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "raf": "3.4.1", "react": "19.1.1", "react-dom": "19.1.1", - "sass": "1.100.0", + "sass": "1.104.0", "stylelint": "16.26.1", "typescript": "7.0.2", "vitest": "4.1.8", diff --git a/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailTabMetadata.tsx b/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailTabMetadata.tsx index 42f6540452e..7893826d468 100644 --- a/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailTabMetadata.tsx +++ b/libs/sdk-ui-catalog/src/catalogDetail/CatalogDetailTabMetadata.tsx @@ -125,7 +125,6 @@ export function CatalogDetailTabMetadata({ arrowPlacement="left" optimalPlacement offset={10} - width={280} triggerBy={["hover", "click"]} /> @@ -162,7 +161,6 @@ export function CatalogDetailTabMetadata({ arrowPlacement="left" optimalPlacement offset={10} - width={280} triggerBy={["hover", "click"]} /> diff --git a/libs/sdk-ui-catalog/src/catalogItem/CatalogItemLock.tsx b/libs/sdk-ui-catalog/src/catalogItem/CatalogItemLock.tsx index 725d545af40..c2000f7c3a9 100644 --- a/libs/sdk-ui-catalog/src/catalogItem/CatalogItemLock.tsx +++ b/libs/sdk-ui-catalog/src/catalogItem/CatalogItemLock.tsx @@ -18,7 +18,6 @@ export function CatalogItemLock({ intl }: Props) { triggerBy={["hover"]} anchor={} content={intl.formatMessage({ id: "analyticsCatalog.catalogItem.lock" })} - width={255} /> ); } diff --git a/libs/sdk-ui-catalog/src/catalogItem/CatalogItemVisibilityIcon.tsx b/libs/sdk-ui-catalog/src/catalogItem/CatalogItemVisibilityIcon.tsx index b8dc0f4d98a..4211978b2e4 100644 --- a/libs/sdk-ui-catalog/src/catalogItem/CatalogItemVisibilityIcon.tsx +++ b/libs/sdk-ui-catalog/src/catalogItem/CatalogItemVisibilityIcon.tsx @@ -27,7 +27,6 @@ export function CatalogItemVisibilityIcon({ intl, item, ...htmlProps }: Props) { triggerBy={["hover", "focus"]} anchor={} content={intl.formatMessage({ id: "analyticsCatalog.column.isHidden.icon.tooltip" })} - width={255} /> ); diff --git a/libs/sdk-ui-catalog/src/header/Header.tsx b/libs/sdk-ui-catalog/src/header/Header.tsx index ad3f49c567e..02224baa146 100644 --- a/libs/sdk-ui-catalog/src/header/Header.tsx +++ b/libs/sdk-ui-catalog/src/header/Header.tsx @@ -32,7 +32,6 @@ export function Header({ searchNode, createNode }: Props) { arrowPlacement="left" optimalPlacement offset={10} - width={300} triggerBy={["hover", "click", "focus"]} />
diff --git a/libs/sdk-ui-catalog/src/index.ts b/libs/sdk-ui-catalog/src/index.ts index 0e993476586..a2fccf244bc 100644 --- a/libs/sdk-ui-catalog/src/index.ts +++ b/libs/sdk-ui-catalog/src/index.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files /* * Analytics Catalog public API. diff --git a/libs/sdk-ui-catalog/src/localization/bundles/ru-RU.json b/libs/sdk-ui-catalog/src/localization/bundles/ru-RU.json index bc410011f62..ab5e3a24016 100644 --- a/libs/sdk-ui-catalog/src/localization/bundles/ru-RU.json +++ b/libs/sdk-ui-catalog/src/localization/bundles/ru-RU.json @@ -172,7 +172,7 @@ "analyticsCatalog.parameter.dialog.edit.title": "Изменить параметр", "analyticsCatalog.parameter.dialog.sectionHeader": "Определение параметра", "analyticsCatalog.parameter.dialog.sectionHeader.tooltip": "Создайте инструкцию YAML, которая определяет параметр.", - "analyticsCatalog.parameter.dialog.edit.duplicate": "Сохранить как новую", + "analyticsCatalog.parameter.dialog.edit.duplicate": "Сохранить как новый", "analyticsCatalog.parameter.dialog.edit.idImmutable": "Идентификатор параметра нельзя изменить при сохранении существующего параметра. Вместо этого используйте \"Сохранить как новый\".", "analyticsCatalog.parameter.dialog.help": "Как создать параметр?", "analyticsCatalog.parameter.dialog.submit.error": "Не удалось сохранить параметр.", @@ -201,7 +201,7 @@ "analyticsCatalog.parameter.delete.error": "Не удалось удалить параметр.", "analyticsCatalog.computedAttribute.dialog.create.title": "Создать вычисляемый атрибут", "analyticsCatalog.computedAttribute.dialog.edit.title": "Изменить вычисляемый атрибут", - "analyticsCatalog.computedAttribute.dialog.edit.duplicate": "Сохранить как новую", + "analyticsCatalog.computedAttribute.dialog.edit.duplicate": "Сохранить как новый", "analyticsCatalog.computedAttribute.dialog.edit.idImmutable": "Идентификатор вычисляемого атрибута нельзя изменить при сохранении существующего вычисляемого атрибута. Вместо этого используйте \"Сохранить как новую\".", "analyticsCatalog.computedAttribute.dialog.sectionHeader": "Определение вычисляемого атрибута", "analyticsCatalog.computedAttribute.dialog.sectionHeader.tooltip": "Напишите выражение MAQL, которое присваивает каждой строке значение, используя ветви CASE WHEN для метрики или факта.", diff --git a/libs/sdk-ui-catalog/src/localization/bundles/zh-HK.json b/libs/sdk-ui-catalog/src/localization/bundles/zh-HK.json index d5a837db6c8..c6c488c2320 100644 --- a/libs/sdk-ui-catalog/src/localization/bundles/zh-HK.json +++ b/libs/sdk-ui-catalog/src/localization/bundles/zh-HK.json @@ -12,7 +12,7 @@ "analyticsCatalog.objectType.dateDataset.button.ariaLabel": "日期數據集:{count}", "analyticsCatalog.objectType.dashboard.name": "儀表板", "analyticsCatalog.objectType.visualization.name": "可視化", - "analyticsCatalog.objectType.metric.name": "計量", + "analyticsCatalog.objectType.metric.name": "指標", "analyticsCatalog.objectType.attribute.name": "屬性", "analyticsCatalog.objectType.fact.name": "事實", "analyticsCatalog.objectType.dateDataset.name": "日期數據集", @@ -36,7 +36,7 @@ "analyticsCatalog.visualizationType.bullet.tooltip": "子彈圖", "analyticsCatalog.visualizationType.waterfall.tooltip": "瀑布圖", "analyticsCatalog.visualizationType.dependencywheel.tooltip": "依賴關係輪圖", - "analyticsCatalog.visualizationType.sankey.tooltip": "桑基图", + "analyticsCatalog.visualizationType.sankey.tooltip": "桑基圖", "analyticsCatalog.visualizationType.pushpin.tooltip": "大頭針", "analyticsCatalog.visualizationType.repeater.tooltip": "重複:", "analyticsCatalog.filter.title": "篩選器", @@ -81,7 +81,7 @@ "analyticsCatalog.certification.field.message.placeholder": "新增認證訊息", "analyticsCatalog.column.isHidden.field.tooltip": "在所有使用者的 Smart Search 和 AI Assistant 結果中包含。", "analyticsCatalog.column.title.isHiddenFromKda": "用於主要驅動因素分析", - "analyticsCatalog.column.isHiddenFromKda.field.tooltip": "分析哪些因素推動所選指標的變化。系統會按影響程度識別並排序主要驅動因素,協助你在無需手動操作的情況下理解績效變化。", + "analyticsCatalog.column.isHiddenFromKda.field.tooltip": "分析哪些因素推動所選指標的變化。系統會按影響程度識別並排序主要驅動因素,協助您在無需手動操作的情況下理解績效變化。", "analyticsCatalog.tags.manager.label.more": "更多標籤", "analyticsCatalog.tags.manager.label.noTags": "沒有標籤", "analyticsCatalog.tags.manager.label.close": "關閉", @@ -91,7 +91,7 @@ "analyticsCatalog.tags.manager.label.saveLabel": "儲存", "analyticsCatalog.tags.manager.label.removeLabel": "刪除", "analyticsCatalog.error.unknown.message": "未知錯誤", - "analyticsCatalog.error.unknown.description": "我哋不太肯定出咗乜嘢問題。 請稍後再試。", + "analyticsCatalog.error.unknown.description": "我們不太確定發生了什麼問題。 請稍後再試。", "analyticsCatalog.error.notFound.title": "我們找不到此項目", "analyticsCatalog.error.notFound.description": "它可能已被刪除,或者您沒有存取權限。", "analyticsCatalog.error.unauthorized.message": "未經授權", @@ -121,9 +121,9 @@ "analyticsCatalog.catalogItem.actionsMenu.ariaLabel": "{name} 的操作", "analyticsCatalog.tooltip.content": "集中式目錄涵蓋儀表板、指標、可視化、事實和屬性。在單一位置探索、管理和更新所有對象,以支援一致的管理、更快速的洞察和更佳的協作。", "analyticsCatalog.search.label": "按標題或描述搜尋…", - "analyticsCatalog.empty.search.title": "未搵到匹配項", + "analyticsCatalog.empty.search.title": "找不到相符項目", "analyticsCatalog.empty.search.description": "檢查拼寫或調整過濾器。", - "analyticsCatalog.empty.filters.title": "未搵到匹配項", + "analyticsCatalog.empty.filters.title": "找不到相符項目", "analyticsCatalog.empty.filters.description": "在所選篩選器下未找到相符的項目。", "analyticsCatalog.quality.tooltip.title": "驗證 {count, plural, other {發現}}:", "analyticsCatalog.quality.tooltip.identicalTitle": "有 {count, plural, other {# 個欄位}}使用相同標題", @@ -228,9 +228,9 @@ "analyticsCatalog.computedAttribute.dialog.delete.submit": "刪除", "analyticsCatalog.computedAttribute.delete.success": "已刪除計算屬性。", "analyticsCatalog.computedAttribute.delete.error": "無法刪除計算屬性。", - "analyticsCatalog.metric.dialog.create.title": "創建計量", + "analyticsCatalog.metric.dialog.create.title": "創建指標", "analyticsCatalog.metric.dialog.edit.title": "編輯指標", - "analyticsCatalog.metric.dialog.sectionHeader": "計量定義", + "analyticsCatalog.metric.dialog.sectionHeader": "指標定義", "analyticsCatalog.metric.dialog.sectionHeader.tooltip": "在 YAML 中定義指標,包括其 MAQL 表達式和格式。", "analyticsCatalog.metric.actions.openInEditor": "在指標編輯器中開啟", "analyticsCatalog.metric.dialog.edit.duplicate": "重複", diff --git a/libs/sdk-ui-catalog/vitest.config.ts b/libs/sdk-ui-catalog/vitest.config.ts index 4519132dd76..af977b0c330 100644 --- a/libs/sdk-ui-catalog/vitest.config.ts +++ b/libs/sdk-ui-catalog/vitest.config.ts @@ -2,7 +2,6 @@ import { defineConfig } from "vitest/config"; -// eslint-disable-next-line no-restricted-exports export default defineConfig({ resolve: { preserveSymlinks: true, diff --git a/libs/sdk-ui-charts/.dependency-cruiser.js b/libs/sdk-ui-charts/.dependency-cruiser.js index 2403da0962d..9f70c3bd649 100644 --- a/libs/sdk-ui-charts/.dependency-cruiser.js +++ b/libs/sdk-ui-charts/.dependency-cruiser.js @@ -9,7 +9,6 @@ import { moduleWithDependencies, } from "../../common/config/dep-cruiser/default.config.js"; -// eslint-disable-next-line no-restricted-exports export default { forbidden: [ ...DefaultRules, diff --git a/libs/sdk-ui-charts/package.json b/libs/sdk-ui-charts/package.json index 2d957f989d1..a9079ee2de3 100644 --- a/libs/sdk-ui-charts/package.json +++ b/libs/sdk-ui-charts/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-ui-charts", - "version": "11.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "GoodData.UI SDK - Charts", "license": "LicenseRef-LICENSE", "author": "GoodData Corporation", @@ -136,12 +136,13 @@ "happy-dom": "20.12.0", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "raf": "3.4.1", "react": "19.1.1", "react-dom": "19.1.1", - "sass": "1.100.0", + "sass": "1.104.0", "stylelint": "16.26.1", "typescript": "7.0.2", "vitest": "4.1.8", diff --git a/libs/sdk-ui-charts/src/highcharts/adapter/highcharts.d.ts b/libs/sdk-ui-charts/src/highcharts/adapter/highcharts.d.ts index fefbdbb8529..6d343fb1127 100644 --- a/libs/sdk-ui-charts/src/highcharts/adapter/highcharts.d.ts +++ b/libs/sdk-ui-charts/src/highcharts/adapter/highcharts.d.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files, eslint-js/no-restricted-syntax export * from "highcharts"; diff --git a/libs/sdk-ui-charts/src/index.ts b/libs/sdk-ui-charts/src/index.ts index fecf5ac554f..5b1eef0d3e6 100644 --- a/libs/sdk-ui-charts/src/index.ts +++ b/libs/sdk-ui-charts/src/index.ts @@ -1,6 +1,6 @@ // (C) 2007-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files /** * This package provides a set of React-based chart visualizations that you can use to visualize your data. diff --git a/libs/sdk-ui-charts/src/internal.ts b/libs/sdk-ui-charts/src/internal.ts index 5df5ac48dd5..2032308b91a 100644 --- a/libs/sdk-ui-charts/src/internal.ts +++ b/libs/sdk-ui-charts/src/internal.ts @@ -1,6 +1,6 @@ // (C) 2025-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files export { type IRawChartProps, RawChart } from "./charts/_base/RawChart.js"; export { type IChartTransformationProps } from "./highcharts/ChartTransformation.js"; diff --git a/libs/sdk-ui-charts/src/typings.d.ts b/libs/sdk-ui-charts/src/typings.d.ts index 5caade09651..6f9aef68e99 100644 --- a/libs/sdk-ui-charts/src/typings.d.ts +++ b/libs/sdk-ui-charts/src/typings.d.ts @@ -1,6 +1,6 @@ -// (C) 2007-2025 GoodData Corporation +// (C) 2007-2026 GoodData Corporation -/* eslint-disable no-restricted-exports */ +// oxlint-disable eslint-js/no-restricted-exports declare module "*/package.json" { export const name: string; diff --git a/libs/sdk-ui-charts/vitest.config.ts b/libs/sdk-ui-charts/vitest.config.ts index 42f9309ff3b..2fd0204cf86 100644 --- a/libs/sdk-ui-charts/vitest.config.ts +++ b/libs/sdk-ui-charts/vitest.config.ts @@ -2,7 +2,6 @@ import { defineConfig } from "vitest/config"; -// eslint-disable-next-line no-restricted-exports export default defineConfig({ resolve: { preserveSymlinks: true, diff --git a/libs/sdk-ui-dashboard/.dependency-cruiser.js b/libs/sdk-ui-dashboard/.dependency-cruiser.js index 48b00b00bb5..95e745fa4ac 100644 --- a/libs/sdk-ui-dashboard/.dependency-cruiser.js +++ b/libs/sdk-ui-dashboard/.dependency-cruiser.js @@ -9,7 +9,6 @@ import { moduleWithDependencies, } from "../../common/config/dep-cruiser/default.config.js"; -// eslint-disable-next-line no-restricted-exports export default { forbidden: [ ...DefaultRules, diff --git a/libs/sdk-ui-dashboard/api/sdk-ui-dashboard.api.md b/libs/sdk-ui-dashboard/api/sdk-ui-dashboard.api.md index 931d7989529..feacd50458a 100644 --- a/libs/sdk-ui-dashboard/api/sdk-ui-dashboard.api.md +++ b/libs/sdk-ui-dashboard/api/sdk-ui-dashboard.api.md @@ -410,9 +410,7 @@ export type AlertMetricComparator = { // @beta export enum AlertMetricComparatorType { - // (undocumented) PreviousPeriod = 0, - // (undocumented) SamePeriodPreviousYear = 1 } @@ -839,7 +837,7 @@ export function createScheduledEmail(scheduledEmail: IAutomationMetadataObjectDe // @beta export function crossFiltering(insight: IInsight, drillDefinition: ICrossFiltering_2, drillEvent: IDashboardDrillEvent, correlationId?: string): ICrossFiltering; -// @beta (undocumented) +// @beta export type CustomAlertingDialogComponent = ComponentType; // @beta @@ -847,7 +845,7 @@ export type CustomAlertingDialogContextDecoratorComponent = ComponentType<{ children?: ReactNode; }>; -// @beta (undocumented) +// @beta export type CustomAlertingManagementDialogComponent = ComponentType; // @beta @@ -993,7 +991,7 @@ export type CustomSaveAsNewButtonComponent = ComponentType; -// @beta (undocumented) +// @beta export type CustomScheduledEmailDialogComponent = ComponentType; // @beta @@ -1001,7 +999,7 @@ export type CustomScheduledEmailDialogContextDecoratorComponent = ComponentType< children?: ReactNode; }>; -// @beta (undocumented) +// @beta export type CustomScheduledEmailManagementDialogComponent = ComponentType; // @beta @@ -1105,10 +1103,10 @@ export type DashboardAttributeFilterSelectionChangedPayload = { export { dashboardAttributeFilterToAttributeFilter } // @public -export type DashboardCommands = InitializeDashboard | SaveDashboardAs | RequestAsyncRender | ResolveAsyncRender | ChangeFilterContextSelection | ChangeDateFilterSelection | ChangeAttributeFilterSelection | ReplaceAttributeFilterItemSelection | IChangeRenderMode | IChangeDashboardDensity | IRequestOpenDensityDialog | IChangeDashboardTimezoneOverride | ISaveDashboard | IRenameDashboard | IResetDashboard | IExportDashboardToPdf | IExportDashboardToExcel | IExportDashboardToPdfPresentation | IExportDashboardToPptPresentation | IDeleteDashboard | ITriggerEvent | IUpsertExecutionResult | IAddAttributeFilter | IAddTextAttributeFilter | IRemoveAttributeFilters | IMoveAttributeFilter | ISetAttributeFilterParents | ISetAttributeFilterDependentDateFilters | IAddLayoutSection | IMoveLayoutSection | IRemoveLayoutSection | ChangeLayoutSectionHeader | IResizeHeight | IResizeWidth | IAddSectionItems | IReplaceSectionItem | IMoveSectionItem | IMoveSectionItemToNewSection | IRemoveSectionItem | IRemoveSectionItemByWidgetRef | IUndoLayoutChanges | IChangeKpiWidgetHeader | IChangeKpiWidgetDescription | IChangeKpiWidgetConfiguration | IChangeKpiWidgetMeasure | IChangeKpiWidgetFilterSettings | IChangeKpiWidgetComparison | IRefreshKpiWidget | ISetDrillForKpiWidget | IRemoveDrillForKpiWidget | IChangeInsightWidgetHeader | IChangeInsightWidgetDescription | IChangeInsightWidgetIgnoreCrossFiltering | IChangeInsightWidgetFilterSettings | IChangeInsightWidgetVisProperties | ChangeInsightWidgetVisConfiguration | IChangeInsightWidgetInsight | IModifyDrillsForInsightWidget | IRemoveDrillsForInsightWidget | IRefreshInsightWidget | IExportInsightWidget | ICreateAlert | ISaveAlert | ICreateScheduledEmail | ISaveScheduledEmail | IChangeSharing | ISetAttributeFilterDisplayForm | ISetAttributeFilterTitle | ISetMeasureValueFilterTitle | ISetMeasureValueFilterDimensionality | ISetAttributeFilterSelectionMode | IChangeRichTextWidgetContent | IChangeRichTextWidgetFilterSettings | IAddVisualizationToVisualizationSwitcherWidgetContent | IUpdateVisualizationsFromVisualizationSwitcherWidgetContent | IChangeVisualizationSwitcherActiveVisualization | IDrill | IDrillDown | IDrillToAttributeUrl | IDrillToCustomUrl | IDrillToDashboard | IDrillToInsight | IDrillToLegacyDashboard | IChangeDrillableItems | IAddDrillTargets | ISetDashboardDateFilterConfigMode | ISetDashboardAttributeFilterConfigMode | ISetDashboardMeasureValueFilterConfigMode | ISetDashboardAttributeFilterSelectionType | ISetDashboardAttributeFilterConfigDisplayAsLabel | IRemoveDrillDownForInsightWidget | IRemoveDrillToUrlForInsightWidget | IAddDrillDownForInsightWidget | IModifyDrillDownForInsightWidget | ICrossFiltering | IKeyDriverAnalysis | IAttributeHierarchyModified | IAddDateFilter | IAddMeasureValueFilter | IRemoveMeasureValueFilters | IRemoveDateFilters | IMoveDateFilter | IChangeMeasureValueFilterCondition | IMoveMeasureValueFilter | ISetDashboardDateFilterWithDimensionConfigMode | ISetDateFilterConfigTitle | IInitializeAutomations | IRefreshAutomations | ISetAttributeFilterLimitingItems | ISaveFilterView | IDeleteFilterView | IApplyFilterView | ISetFilterViewAsDefault | IReloadFilterViews | IToggleLayoutSectionHeaders | IToggleLayoutDirection | IApplyFilterContextWorkingSelection | IResetFilterContextWorkingSelection | IChangeIgnoreExecutionTimestamp | ISwitchDashboardTab | ICreateDashboardTab | IRepositionDashboardTab | IDeleteDashboardTab | IStartRenamingDashboardTab | ICancelRenamingDashboardTab | IRenameDashboardTab | ISetScreenSize | IExportRawInsightWidget | IExportSlidesInsightWidget | IExportImageInsightWidget | ISetShowWidgetAsTable | IChangeParameterValues; +export type DashboardCommands = InitializeDashboard | SaveDashboardAs | RequestAsyncRender | ResolveAsyncRender | ChangeFilterContextSelection | ChangeDateFilterSelection | ChangeAttributeFilterSelection | ReplaceAttributeFilterItemSelection | IChangeRenderMode | IChangeDashboardDensity | IRequestOpenDensityDialog | IChangeDashboardTimezoneOverride | ISaveDashboard | IRenameDashboard | IResetDashboard | IExportDashboardToPdf | IExportDashboardToExcel | IExportDashboardToPdfPresentation | IExportDashboardToPptPresentation | IDeleteDashboard | ITriggerEvent | IUpsertExecutionResult | IAddAttributeFilter | IAddTextAttributeFilter | IRemoveAttributeFilters | IMoveAttributeFilter | ISetAttributeFilterParents | ISetAttributeFilterDependentDateFilters | IAddLayoutSection | IMoveLayoutSection | IRemoveLayoutSection | ChangeLayoutSectionHeader | IResizeHeight | IResizeWidth | IAddSectionItems | IReplaceSectionItem | IMoveSectionItem | IMoveSectionItemToNewSection | IRemoveSectionItem | IRemoveSectionItemByWidgetRef | IUndoLayoutChanges | IChangeKpiWidgetHeader | IChangeKpiWidgetDescription | IChangeKpiWidgetConfiguration | IChangeKpiWidgetMeasure | IChangeKpiWidgetFilterSettings | IChangeKpiWidgetComparison | IRefreshKpiWidget | ISetDrillForKpiWidget | IRemoveDrillForKpiWidget | IChangeInsightWidgetHeader | IChangeInsightWidgetDescription | IChangeInsightWidgetIgnoreCrossFiltering | IChangeInsightWidgetFilterSettings | IChangeInsightWidgetVisProperties | ChangeInsightWidgetVisConfiguration | IChangeInsightWidgetInsight | IModifyDrillsForInsightWidget | IRemoveDrillsForInsightWidget | IRefreshInsightWidget | IExportInsightWidget | ICreateAlert | ISaveAlert | ICreateScheduledEmail | ISaveScheduledEmail | IChangeSharing | ISetAttributeFilterDisplayForm | ISetAttributeFilterTitle | ISetMeasureValueFilterTitle | ISetMeasureValueFilterDimensionality | ISetAttributeFilterSelectionMode | IChangeRichTextWidgetContent | IChangeRichTextWidgetFilterSettings | IAddVisualizationToVisualizationSwitcherWidgetContent | IUpdateVisualizationsFromVisualizationSwitcherWidgetContent | IChangeVisualizationSwitcherActiveVisualization | IDrill | IDrillDown | IDrillToAttributeUrl | IDrillToCustomUrl | IDrillToDashboard | IDrillToInsight | IDrillToLegacyDashboard | IChangeDrillableItems | IAddDrillTargets | ISetDashboardDateFilterConfigMode | ISetDashboardAttributeFilterConfigMode | ISetDashboardMeasureValueFilterConfigMode | ISetDashboardAttributeFilterSelectionType | ISetDashboardAttributeFilterConfigDisplayAsLabel | IRemoveDrillDownForInsightWidget | IRemoveDrillToUrlForInsightWidget | IAddDrillDownForInsightWidget | IModifyDrillDownForInsightWidget | ICrossFiltering | IKeyDriverAnalysis | IAttributeHierarchyModified | IAddDateFilter | IAddMeasureValueFilter | IRemoveMeasureValueFilters | IRemoveRestrictedFilters | IRemoveDateFilters | IMoveDateFilter | IChangeMeasureValueFilterCondition | IMoveMeasureValueFilter | ISetDashboardDateFilterWithDimensionConfigMode | ISetDateFilterConfigTitle | IInitializeAutomations | IRefreshAutomations | ISetAttributeFilterLimitingItems | ISaveFilterView | IDeleteFilterView | IApplyFilterView | ISetFilterViewAsDefault | IReloadFilterViews | IToggleLayoutSectionHeaders | IToggleLayoutDirection | IApplyFilterContextWorkingSelection | IResetFilterContextWorkingSelection | IChangeIgnoreExecutionTimestamp | ISwitchDashboardTab | ICreateDashboardTab | IRepositionDashboardTab | IDeleteDashboardTab | IStartRenamingDashboardTab | ICancelRenamingDashboardTab | IRenameDashboardTab | ISetScreenSize | IExportRawInsightWidget | IExportSlidesInsightWidget | IExportImageInsightWidget | ISetShowWidgetAsTable | IChangeParameterValues; // @public -export type DashboardCommandType = "GDC.DASH/CMD.INITIALIZE" | "GDC.DASH/CMD.SAVE" | "GDC.DASH/CMD.SAVEAS" | "GDC.DASH/CMD.RESET" | "GDC.DASH/CMD.RENAME" | "GDC.DASH/CMD.DELETE" | "GDC.DASH/CMD.CHANGE_RENDER_MODE" | "GDC.DASH/CMD.SHARING.CHANGE" | "GDC.DASH/CMD.EXPORT.PDF" | "GDC.DASH/CMD.EXPORT.EXCEL" | "GDC.DASH/CMD.EXPORT.PDF_PRESENTATION" | "GDC.DASH/CMD.EXPORT.PPT_PRESENTATION" | "GDC.DASH/CMD.EVENT.TRIGGER" | "GDC.DASH/CMD.EXECUTION_RESULT.UPSERT" | "GDC.DASH/CMD.FILTER_CONTEXT.CHANGE_SELECTION" | "GDC.DASH/CMD.FILTER_CONTEXT.DATE_FILTER.CHANGE_SELECTION" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.ADD" | "GDC.DASH/CMD.FILTER_CONTEXT.TEXT_ATTRIBUTE_FILTER.ADD" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.REMOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.MOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.CHANGE_SELECTION" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER_ITEM.REPLACE_SELECTION" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.SET_PARENTS" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.SET_DISPLAY_FORM" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.SET_TITLE" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.SET_SELECTION_MODE" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.SET_DEPENDENT_DATE_FILTERS" | "GDC.DASH/CMD.FILTER_CONTEXT.DATE_FILTER.ADD" | "GDC.DASH/CMD.FILTER_CONTEXT.DATE_FILTER.REMOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.DATE_FILTER.MOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.ADD" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.REMOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.MOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.CHANGE_CONDITION" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.SET_DIMENSIONALITY" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.SET_TITLE" | "GDC.DASH/CMD.ATTRIBUTE_FILTER_CONFIG.SET_MODE" | "GDC.DASH/CMD.MEASURE_VALUE_FILTER_CONFIG.SET_MODE" | "GDC.DASH/CMD.ATTRIBUTE_FILTER_CONFIG.SET_AVAILABLE_MODE" | "GDC.DASH/CMD.ATTRIBUTE_FILTER_CONFIG.SET_LIMITING_ITEMS" | "GDC.DASH/CMD.ATTRIBUTE_FILTER_CONFIG.SET_DISPLAY_AS_LABEL" | "GDC.DASH/CMD.DATE_FILTER_CONFIG.SET_MODE" | "GDC.DASH/CMD.DATE_FILTER_WITH_DIMENSION_CONFIG.SET_MODE" | "GDC.DASH/CMD.DATE_FILTER_CONFIG.SET_TITLE" | "GDC.DASH/CMD.FLUID_LAYOUT.ADD_SECTION" | "GDC.DASH/CMD.FLUID_LAYOUT.MOVE_SECTION" | "GDC.DASH/CMD.FLUID_LAYOUT.MOVE_ITEM_TO_NEW_SECTION" | "GDC.DASH/CMD.FLUID_LAYOUT.REMOVE_SECTION" | "GDC.DASH/CMD.FLUID_LAYOUT.CHANGE_SECTION_HEADER" | "GDC.DASH/CMD.FLUID_LAYOUT.ADD_ITEMS" | "GDC.DASH/CMD.FLUID_LAYOUT.REPLACE_ITEM" | "GDC.DASH/CMD.FLUID_LAYOUT.MOVE_ITEM" | "GDC.DASH/CMD.FLUID_LAYOUT.REMOVE_ITEM" | "GDC.DASH/CMD.FLUID_LAYOUT.REMOVE_ITEM_BY_WIDGET_REF" | "GDC.DASH/CMD.FLUID_LAYOUT.UNDO" | "GDC.DASH/CMD.FLUID_LAYOUT.RESIZE_HEIGHT" | "GDC.DASH/CMD.FLUID_LAYOUT.RESIZE_WIDTH" | "GDC.DASH/CMD.FLUID_LAYOUT.SET_SCREEN_SIZE" | "GDC.DASH/CMD.FLEXIBLE_LAYOUT.TOGGLE_LAYOUT_SECTION_HEADERS" | "GDC.DASH/CMD.FLEXIBLE_LAYOUT.TOGGLE_LAYOUT_DIRECTION" | "GDC.DASH/CMD.KPI_WIDGET.CHANGE_HEADER" | "GDC.DASH/CMD.KPI_WIDGET.CHANGE_MEASURE" | "GDC.DASH/CMD.KPI_WIDGET.CHANGE_FILTER_SETTINGS" | "GDC.DASH/CMD.KPI_WIDGET.CHANGE_COMPARISON" | "GDC.DASH/CMD.KPI_WIDGET.REFRESH" | "GDC.DASH/CMD.KPI_WIDGET.SET_DRILL" | "GDC.DASH/CMD.KPI_WIDGET.REMOVE_DRILL" | "GDC.DASH/CMD.KPI_WIDGET.CHANGE_DESCRIPTION" | "GDC.DASH/CMD.KPI_WIDGET.CHANGE_CONFIGURATION" | "GDC.DASH/CMD.INSIGHT_WIDGET.CHANGE_HEADER" | "GDC.DASH/CMD.INSIGHT_WIDGET.CHANGE_DESCRIPTION" | "GDC.DASH/CMD.INSIGHT_WIDGET.CHANGE_FILTER_SETTINGS" | "GDC.DASH/CMD.INSIGHT_WIDGET.CHANGE_PROPERTIES" | "GDC.DASH/CMD.INSIGHT_WIDGET.CHANGE_CONFIGURATION" | "GDC.DASH/CMD.INSIGHT_WIDGET.CHANGE_INSIGHT" | "GDC.DASH/CMD.INSIGHT_WIDGET.CHANGE_IGNORE_CROSS_FILTERING" | "GDC.DASH/CMD.INSIGHT_WIDGET.EXPORT" | "GDC.DASH/CMD.INSIGHT_WIDGET.MODIFY_DRILLS" | "GDC.DASH/CMD.INSIGHT_WIDGET.REMOVE_DRILLS" | "GDC.DASH/CMD.INSIGHT_WIDGET.REMOVE_DRILL_DOWN" | "GDC.DASH/CMD.INSIGHT_WIDGET.REMOVE_DRILL_TO_URL" | "GDC.DASH/CMD.INSIGHT_WIDGET.ADD_DRILL_DOWN" | "GDC.DASH/CMD.INSIGHT_WIDGET.MODIFY_DRILL_DOWN" | "GDC.DASH/CMD.INSIGHT_WIDGET.REFRESH" | "GDC.DASH/CMD.RICH_TEXT_WIDGET.CHANGE_CONTENT" | "GDC.DASH/CMD.RICH_TEXT_WIDGET.CHANGE_FILTER_SETTINGS" | "GDC.DASH/CMD.VISUALIZATION_SWITCHER_WIDGET.ADD_VISUALIZATION" | "GDC.DASH/CMD.VISUALIZATION_SWITCHER_WIDGET.UPDATE_VISUALIZATIONS" | "GDC.DASH/CMD.VISUALIZATION_SWITCHER_WIDGET.CHANGE_ACTIVE_VISUALIZATION" | "GDC.DASH/CMD.ALERT.CREATE" | "GDC.DASH/CMD.ALERT.SAVE" | "GDC.DASH/CMD.SCHEDULED_EMAIL.CREATE" | "GDC.DASH/CMD.SCHEDULED_EMAIL.SAVE" | "GDC.DASH/CMD.DRILL" | "GDC.DASH/CMD.DRILL.DRILL_DOWN" | "GDC.DASH/CMD.DRILL.DRILL_TO_INSIGHT" | "GDC.DASH/CMD.DRILL.DRILL_TO_DASHBOARD" | "GDC.DASH/CMD.DRILL.DRILL_TO_ATTRIBUTE_URL" | "GDC.DASH/CMD.DRILL.DRILL_TO_CUSTOM_URL" | "GDC.DASH/CMD.DRILL.DRILL_TO_LEGACY_DASHBOARD" | "GDC.DASH/CMD.DRILL.DRILLABLE_ITEMS.CHANGE" | "GDC.DASH/CMD.DRILL.CROSS_FILTERING" | "GDC.DASH/CMD.DRILL.KEY_DRIVER_ANALYSIS" | "GDC.DASH/CMD.DRILL_TARGETS.ADD" | "GDC.DASH/CMD.RENDER.ASYNC.REQUEST" | "GDC.DASH/CMD.RENDER.ASYNC.RESOLVE" | "GDC.DASH/CMD.ATTRIBUTE_HIERARCHY_MODIFIED" | "GDC.DASH/CMD.AUTOMATIONS.INITIALIZE" | "GDC.DASH/CMD.AUTOMATIONS.REFRESH" | "GDC.DASH/CMD.FILTER_CONTEXT.FILTER_VIEW.SAVE" | "GDC.DASH/CMD.FILTER_CONTEXT.FILTER_VIEW.DELETE" | "GDC.DASH/CMD.FILTER_CONTEXT.FILTER_VIEW.APPLY" | "GDC.DASH/CMD.FILTER_CONTEXT.FILTER_VIEW.CHANGE_DEFAULT_STATUS" | "GDC.DASH/CMD.FILTER_CONTEXT.FILTER_VIEW.RELOAD" | "GDC.DASH/CMD.FILTER_CONTEXT.APPLY_WORKING_SELECTION" | "GDC.DASH/CMD.FILTER_CONTEXT.RESET_WORKING_SELECTION" | "GDC.DASH/CMD.CHANGE_IGNORE_EXECUTION_TIMESTAMP" | "GDC.DASH/CMD.TAB.SWITCH" | "GDC.DASH/CMD.TAB.REPOSITION" | "GDC.DASH/CMD.TAB.CREATE" | "GDC.DASH/CMD.TAB.DELETE" | "GDC.DASH/CMD.TAB.RENAME_MODE.START" | "GDC.DASH/CMD.TAB.RENAME_MODE.CANCEL" | "GDC.DASH/CMD.TAB.RENAME" | "GDC.DASH/CMD.INSIGHT_WIDGET.EXPORT_RAW" | "GDC.DASH/CMD.INSIGHT_WIDGET.EXPORT_SLIDES" | "GDC.DASH/CMD.INSIGHT_WIDGET.EXPORT_IMAGE" | "GDC.DASH/CMD.SHOW_WIDGET_AS_TABLE.SET" | "GDC.DASH/CMD.CHANGE_DENSITY" | "GDC.DASH/CMD.OPEN_DENSITY_DIALOG" | "GDC.DASH/CMD.CHANGE_TIMEZONE_OVERRIDE" | "GDC.DASH/CMD.PARAMETERS.CHANGE_VALUES"; +export type DashboardCommandType = "GDC.DASH/CMD.INITIALIZE" | "GDC.DASH/CMD.SAVE" | "GDC.DASH/CMD.SAVEAS" | "GDC.DASH/CMD.RESET" | "GDC.DASH/CMD.RENAME" | "GDC.DASH/CMD.DELETE" | "GDC.DASH/CMD.CHANGE_RENDER_MODE" | "GDC.DASH/CMD.SHARING.CHANGE" | "GDC.DASH/CMD.EXPORT.PDF" | "GDC.DASH/CMD.EXPORT.EXCEL" | "GDC.DASH/CMD.EXPORT.PDF_PRESENTATION" | "GDC.DASH/CMD.EXPORT.PPT_PRESENTATION" | "GDC.DASH/CMD.EVENT.TRIGGER" | "GDC.DASH/CMD.EXECUTION_RESULT.UPSERT" | "GDC.DASH/CMD.FILTER_CONTEXT.CHANGE_SELECTION" | "GDC.DASH/CMD.FILTER_CONTEXT.DATE_FILTER.CHANGE_SELECTION" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.ADD" | "GDC.DASH/CMD.FILTER_CONTEXT.TEXT_ATTRIBUTE_FILTER.ADD" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.REMOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.MOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.CHANGE_SELECTION" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER_ITEM.REPLACE_SELECTION" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.SET_PARENTS" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.SET_DISPLAY_FORM" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.SET_TITLE" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.SET_SELECTION_MODE" | "GDC.DASH/CMD.FILTER_CONTEXT.ATTRIBUTE_FILTER.SET_DEPENDENT_DATE_FILTERS" | "GDC.DASH/CMD.FILTER_CONTEXT.DATE_FILTER.ADD" | "GDC.DASH/CMD.FILTER_CONTEXT.DATE_FILTER.REMOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.DATE_FILTER.MOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.ADD" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.REMOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.RESTRICTED_FILTERS.REMOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.MOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.CHANGE_CONDITION" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.SET_DIMENSIONALITY" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.SET_TITLE" | "GDC.DASH/CMD.ATTRIBUTE_FILTER_CONFIG.SET_MODE" | "GDC.DASH/CMD.MEASURE_VALUE_FILTER_CONFIG.SET_MODE" | "GDC.DASH/CMD.ATTRIBUTE_FILTER_CONFIG.SET_AVAILABLE_MODE" | "GDC.DASH/CMD.ATTRIBUTE_FILTER_CONFIG.SET_LIMITING_ITEMS" | "GDC.DASH/CMD.ATTRIBUTE_FILTER_CONFIG.SET_DISPLAY_AS_LABEL" | "GDC.DASH/CMD.DATE_FILTER_CONFIG.SET_MODE" | "GDC.DASH/CMD.DATE_FILTER_WITH_DIMENSION_CONFIG.SET_MODE" | "GDC.DASH/CMD.DATE_FILTER_CONFIG.SET_TITLE" | "GDC.DASH/CMD.FLUID_LAYOUT.ADD_SECTION" | "GDC.DASH/CMD.FLUID_LAYOUT.MOVE_SECTION" | "GDC.DASH/CMD.FLUID_LAYOUT.MOVE_ITEM_TO_NEW_SECTION" | "GDC.DASH/CMD.FLUID_LAYOUT.REMOVE_SECTION" | "GDC.DASH/CMD.FLUID_LAYOUT.CHANGE_SECTION_HEADER" | "GDC.DASH/CMD.FLUID_LAYOUT.ADD_ITEMS" | "GDC.DASH/CMD.FLUID_LAYOUT.REPLACE_ITEM" | "GDC.DASH/CMD.FLUID_LAYOUT.MOVE_ITEM" | "GDC.DASH/CMD.FLUID_LAYOUT.REMOVE_ITEM" | "GDC.DASH/CMD.FLUID_LAYOUT.REMOVE_ITEM_BY_WIDGET_REF" | "GDC.DASH/CMD.FLUID_LAYOUT.UNDO" | "GDC.DASH/CMD.FLUID_LAYOUT.RESIZE_HEIGHT" | "GDC.DASH/CMD.FLUID_LAYOUT.RESIZE_WIDTH" | "GDC.DASH/CMD.FLUID_LAYOUT.SET_SCREEN_SIZE" | "GDC.DASH/CMD.FLEXIBLE_LAYOUT.TOGGLE_LAYOUT_SECTION_HEADERS" | "GDC.DASH/CMD.FLEXIBLE_LAYOUT.TOGGLE_LAYOUT_DIRECTION" | "GDC.DASH/CMD.KPI_WIDGET.CHANGE_HEADER" | "GDC.DASH/CMD.KPI_WIDGET.CHANGE_MEASURE" | "GDC.DASH/CMD.KPI_WIDGET.CHANGE_FILTER_SETTINGS" | "GDC.DASH/CMD.KPI_WIDGET.CHANGE_COMPARISON" | "GDC.DASH/CMD.KPI_WIDGET.REFRESH" | "GDC.DASH/CMD.KPI_WIDGET.SET_DRILL" | "GDC.DASH/CMD.KPI_WIDGET.REMOVE_DRILL" | "GDC.DASH/CMD.KPI_WIDGET.CHANGE_DESCRIPTION" | "GDC.DASH/CMD.KPI_WIDGET.CHANGE_CONFIGURATION" | "GDC.DASH/CMD.INSIGHT_WIDGET.CHANGE_HEADER" | "GDC.DASH/CMD.INSIGHT_WIDGET.CHANGE_DESCRIPTION" | "GDC.DASH/CMD.INSIGHT_WIDGET.CHANGE_FILTER_SETTINGS" | "GDC.DASH/CMD.INSIGHT_WIDGET.CHANGE_PROPERTIES" | "GDC.DASH/CMD.INSIGHT_WIDGET.CHANGE_CONFIGURATION" | "GDC.DASH/CMD.INSIGHT_WIDGET.CHANGE_INSIGHT" | "GDC.DASH/CMD.INSIGHT_WIDGET.CHANGE_IGNORE_CROSS_FILTERING" | "GDC.DASH/CMD.INSIGHT_WIDGET.EXPORT" | "GDC.DASH/CMD.INSIGHT_WIDGET.MODIFY_DRILLS" | "GDC.DASH/CMD.INSIGHT_WIDGET.REMOVE_DRILLS" | "GDC.DASH/CMD.INSIGHT_WIDGET.REMOVE_DRILL_DOWN" | "GDC.DASH/CMD.INSIGHT_WIDGET.REMOVE_DRILL_TO_URL" | "GDC.DASH/CMD.INSIGHT_WIDGET.ADD_DRILL_DOWN" | "GDC.DASH/CMD.INSIGHT_WIDGET.MODIFY_DRILL_DOWN" | "GDC.DASH/CMD.INSIGHT_WIDGET.REFRESH" | "GDC.DASH/CMD.RICH_TEXT_WIDGET.CHANGE_CONTENT" | "GDC.DASH/CMD.RICH_TEXT_WIDGET.CHANGE_FILTER_SETTINGS" | "GDC.DASH/CMD.VISUALIZATION_SWITCHER_WIDGET.ADD_VISUALIZATION" | "GDC.DASH/CMD.VISUALIZATION_SWITCHER_WIDGET.UPDATE_VISUALIZATIONS" | "GDC.DASH/CMD.VISUALIZATION_SWITCHER_WIDGET.CHANGE_ACTIVE_VISUALIZATION" | "GDC.DASH/CMD.ALERT.CREATE" | "GDC.DASH/CMD.ALERT.SAVE" | "GDC.DASH/CMD.SCHEDULED_EMAIL.CREATE" | "GDC.DASH/CMD.SCHEDULED_EMAIL.SAVE" | "GDC.DASH/CMD.DRILL" | "GDC.DASH/CMD.DRILL.DRILL_DOWN" | "GDC.DASH/CMD.DRILL.DRILL_TO_INSIGHT" | "GDC.DASH/CMD.DRILL.DRILL_TO_DASHBOARD" | "GDC.DASH/CMD.DRILL.DRILL_TO_ATTRIBUTE_URL" | "GDC.DASH/CMD.DRILL.DRILL_TO_CUSTOM_URL" | "GDC.DASH/CMD.DRILL.DRILL_TO_LEGACY_DASHBOARD" | "GDC.DASH/CMD.DRILL.DRILLABLE_ITEMS.CHANGE" | "GDC.DASH/CMD.DRILL.CROSS_FILTERING" | "GDC.DASH/CMD.DRILL.KEY_DRIVER_ANALYSIS" | "GDC.DASH/CMD.DRILL_TARGETS.ADD" | "GDC.DASH/CMD.RENDER.ASYNC.REQUEST" | "GDC.DASH/CMD.RENDER.ASYNC.RESOLVE" | "GDC.DASH/CMD.ATTRIBUTE_HIERARCHY_MODIFIED" | "GDC.DASH/CMD.AUTOMATIONS.INITIALIZE" | "GDC.DASH/CMD.AUTOMATIONS.REFRESH" | "GDC.DASH/CMD.FILTER_CONTEXT.FILTER_VIEW.SAVE" | "GDC.DASH/CMD.FILTER_CONTEXT.FILTER_VIEW.DELETE" | "GDC.DASH/CMD.FILTER_CONTEXT.FILTER_VIEW.APPLY" | "GDC.DASH/CMD.FILTER_CONTEXT.FILTER_VIEW.CHANGE_DEFAULT_STATUS" | "GDC.DASH/CMD.FILTER_CONTEXT.FILTER_VIEW.RELOAD" | "GDC.DASH/CMD.FILTER_CONTEXT.APPLY_WORKING_SELECTION" | "GDC.DASH/CMD.FILTER_CONTEXT.RESET_WORKING_SELECTION" | "GDC.DASH/CMD.CHANGE_IGNORE_EXECUTION_TIMESTAMP" | "GDC.DASH/CMD.TAB.SWITCH" | "GDC.DASH/CMD.TAB.REPOSITION" | "GDC.DASH/CMD.TAB.CREATE" | "GDC.DASH/CMD.TAB.DELETE" | "GDC.DASH/CMD.TAB.RENAME_MODE.START" | "GDC.DASH/CMD.TAB.RENAME_MODE.CANCEL" | "GDC.DASH/CMD.TAB.RENAME" | "GDC.DASH/CMD.INSIGHT_WIDGET.EXPORT_RAW" | "GDC.DASH/CMD.INSIGHT_WIDGET.EXPORT_SLIDES" | "GDC.DASH/CMD.INSIGHT_WIDGET.EXPORT_IMAGE" | "GDC.DASH/CMD.SHOW_WIDGET_AS_TABLE.SET" | "GDC.DASH/CMD.CHANGE_DENSITY" | "GDC.DASH/CMD.OPEN_DENSITY_DIALOG" | "GDC.DASH/CMD.CHANGE_TIMEZONE_OVERRIDE" | "GDC.DASH/CMD.PARAMETERS.CHANGE_VALUES"; // @public export type DashboardConfig = { @@ -1849,7 +1847,7 @@ export function DefaultScheduledEmailDialogTimezone(input: IScheduledEmailDialog // @beta export function DefaultScheduledEmailDialogWidgetAttachments(props: IScheduledEmailDialogWidgetAttachmentsProps): ReactElement; -// @beta (undocumented) +// @beta export function DefaultScheduledEmailManagementDialog(input: IScheduledEmailManagementDialogProps): JSX.Element; // @internal (undocumented) @@ -2680,37 +2678,24 @@ export interface IAlertingDialogComparisonPeriodProps { // @beta export interface IAlertingDialogContextValue { alertToEdit?: IAutomationMetadataObject; - // (undocumented) commonDateFilterId?: string; - // (undocumented) createAlert(alert: IAutomationMetadataObjectDefinition): Promise; - // (undocumented) dashboardEvaluationFrequency?: string; - // (undocumented) dashboardFilters: FilterContextItem[]; - // (undocumented) dashboardId?: string; dashboardParameters: IDashboardParameter[]; - // (undocumented) deleteAlert(alert: IAutomationMetadataObject): Promise; - // (undocumented) executionResultByRef: (ref: ObjRef | undefined) => { executionResult?: IExecutionResult; } | undefined; - // (undocumented) hiddenFilters: FilterContextItem[]; - // (undocumented) insight?: IInsight; isLoading: boolean; - // (undocumented) mode: "create" | "edit"; notificationChannels: INotificationChannelIdentifier[] | INotificationChannelMetadataObject[]; parameterValues: IInsightParameterValue[]; - // (undocumented) saveAlert(alert: IAutomationMetadataObject): Promise; - // (undocumented) widget?: IWidget; - // (undocumented) widgetTitle?: string; } @@ -2751,7 +2736,7 @@ export interface IAlertingDialogMeasureProps { selectedMeasure: AlertMetric | undefined; } -// @beta (undocumented) +// @beta export interface IAlertingDialogProps extends IAutomationDialogCallbacks { // @deprecated alertToEdit?: IAutomationMetadataObject; @@ -2824,41 +2809,27 @@ export interface IAlertingDialogTriggerModeProps { // @alpha export interface IAlertingManagementDialogContextValue { - // (undocumented) alertingDialogReturnFocusTo?: string; automations: IAutomationMetadataObject[]; - // (undocumented) automationsInvalidationId?: number; - // (undocumented) canManageWorkspace: boolean; - // (undocumented) currentUser?: IUser; - // (undocumented) dashboardId?: string; - // (undocumented) dashboardTitle?: string; - // (undocumented) enableAccessibilityMode: boolean; - // (undocumented) getInsightByWidgetRef: (ref: ObjRef | undefined) => IInsight | undefined; - // (undocumented) getWidgetByRef: (ref: ObjRef | undefined) => IWidget | undefined; - // (undocumented) isAlertDialogOpen: boolean; - // (undocumented) isEmbedded: boolean; isLoading: boolean; - // (undocumented) managementDialogContext: { widgetRef?: ObjRef; }; - // (undocumented) pauseAlert(alert: IAutomationMetadataObject): Promise; - // (undocumented) resumeAlert(alert: IAutomationMetadataObject): Promise; } -// @beta (undocumented) +// @beta export interface IAlertingManagementDialogProps extends IAutomationManagementDialogCallbacks { // @deprecated alertDataError?: GoodDataSdkError; @@ -3053,43 +3024,24 @@ export interface IAutomationParameter { // @beta export interface IAutomationsContextValue { - // (undocumented) allowHourlyRecurrence: boolean; - // (undocumented) attributeFilterConfigs: IDashboardAttributeFilterConfig[]; - // (undocumented) attributeFilterConfigsByTab: Record; - // (undocumented) attributeFilterSelectionTypeMap: Map; - // (undocumented) attributeFilterSelectionTypeMapByTab: Record>; - // (undocumented) automationAvailableFilters: FilterContextItem[]; - // (undocumented) automationFiltersByTab: IAutomationFiltersTab[]; - // (undocumented) availableFilters: FilterContextItem[]; - // (undocumented) catalogAttributes: ICatalogAttribute[]; - // (undocumented) catalogDateDatasets: ICatalogDateDataset[]; - // (undocumented) catalogMeasures: ICatalogMeasure[]; - // (undocumented) commonDateFilterId: string | undefined; - // (undocumented) currentUser: IUser; - // (undocumented) dateFilterConfig: IAutomationsDateFilterConfig; - // (undocumented) dateFilterConfigOverridesByTab: Record; - // (undocumented) dateFilterConfigs: IDashboardDateFilterConfigItem[]; - // (undocumented) dateFilterConfigsByTab: Record; - // (undocumented) dateFilterContextConfig: IDashboardDateFilterConfig_2 | undefined; - // (undocumented) defaultSelectedFilters: FilterContextItem[]; exportTimezones?: { isTimezoneFeatureEnabled: boolean; @@ -3099,9 +3051,7 @@ export interface IAutomationsContextValue { effectiveTimezone: string | undefined; scheduledExportTimezone: string | undefined; }; - // (undocumented) externalRecipient: string | undefined; - // (undocumented) features: { canCreateAutomation: boolean; enableAlertOncePerInterval: boolean; @@ -3111,38 +3061,23 @@ export interface IAutomationsContextValue { enableSlideshowExports: boolean; enableAutomationEvaluationMode: boolean; }; - // (undocumented) getAttributeFilterDisplayForm: (displayForm: ObjRef) => IAttributeDisplayFormMetadataObject | undefined; - // (undocumented) getCatalogAttributeByRef: (ref: ObjRef) => ICatalogAttribute | ICatalogDateAttribute | undefined; - // (undocumented) hiddenFilters: FilterContextItem[]; - // (undocumented) isExecutionTimestampMode: boolean; - // (undocumented) isSecondaryTitleVisible: boolean; - // (undocumented) isWhiteLabeled: boolean; - // (undocumented) locale: ILocale; - // (undocumented) lockedFilters: FilterContextItem[]; - // (undocumented) maxAutomationsRecipients: number; - // (undocumented) measureValueFilterConfigs: IDashboardMeasureValueFilterConfig[]; - // (undocumented) measureValueFilterConfigsByTab: Record; - // (undocumented) parameters: IAutomationsParameters; scheduleEmailDialogReturnFocusTo?: string; - // (undocumented) separators: ISeparators; - // (undocumented) settings?: ISettings; tabIds: string[]; timezone: string | undefined; - // (undocumented) weekStart: WeekStart; widgetExistsByRef: (ref: ObjRef | undefined) => boolean; widgetLocalIdToTabIdMap: Record; @@ -3150,13 +3085,9 @@ export interface IAutomationsContextValue { // @beta export interface IAutomationsDateFilterConfig { - // (undocumented) availableGranularities: DateFilterGranularity[]; - // (undocumented) dateFilterOptions: IDateFilterOptionsByType; - // (undocumented) getGranularitiesForTab: (tabId: string) => DateFilterGranularity[]; - // (undocumented) getOptionsForTab: (tabId: string) => IDateFilterOptionsByType | undefined; } @@ -8094,6 +8025,12 @@ export interface IRemoveParameterPayload { ref: ObjRef; } +// @beta +export interface IRemoveRestrictedFilters extends IDashboardCommand { + // (undocumented) + readonly type: "GDC.DASH/CMD.FILTER_CONTEXT.RESTRICTED_FILTERS.REMOVE"; +} + // @beta (undocumented) export interface IRemoveSectionItem extends IDashboardCommand { // (undocumented) @@ -8296,6 +8233,7 @@ export interface IResolvedFilterValues { // @alpha export interface IRestrictedFiltersPlaceholderProps { count: number; + onRemove?: () => void; } // @alpha @@ -8498,34 +8436,25 @@ export type IScheduledEmailDialogActionBarBlockProps = IUseScheduledEmailDialogA // @beta export interface IScheduledEmailDialogContextValue { attributeFiltersModeMap: Map; - // (undocumented) commonDateFilterId?: string; commonDateFilterMode: DashboardDateFilterConfigMode; - // (undocumented) createScheduledEmail(se: IAutomationMetadataObjectDefinition): Promise; dashboardFilters?: FilterContextItem[]; - // (undocumented) dashboardId?: string; - // (undocumented) dashboardTitle: string; dateFiltersModeMap: Map; dateFormat: string | undefined; - // (undocumented) deleteScheduledEmail(se: IAutomationMetadataObject): Promise; exportParametersByTab: Record; exportTemplates: IExportTemplate[]; hiddenFilters: FilterContextItem[]; - // (undocumented) insight?: IInsight; isCrossFiltering: boolean; isLoading: boolean; notificationChannels: INotificationChannelIdentifier[] | INotificationChannelMetadataObject[]; - // (undocumented) saveScheduledEmail(se: IAutomationMetadataObject): Promise; scheduledExportToEdit?: IAutomationMetadataObject; - // (undocumented) widget?: IWidget; - // (undocumented) widgetTitle?: string; } @@ -8581,7 +8510,7 @@ export interface IScheduledEmailDialogMessageProps { value: string; } -// @beta (undocumented) +// @beta export interface IScheduledEmailDialogProps extends IAutomationDialogCallbacks { // @deprecated dashboardFilters?: FilterContextItem[]; @@ -8697,7 +8626,7 @@ export interface IScheduledEmailManagementDialogContextValue { unlimitedAutomations: boolean; } -// @beta (undocumented) +// @beta export interface IScheduledEmailManagementDialogProps extends IAutomationManagementDialogCallbacks { // @deprecated automations?: IAutomationMetadataObject[]; @@ -10049,6 +9978,11 @@ export interface IUiState { // (undocumented) insightListLastUpdateRequested: number; // (undocumented) + insightNotSavedDialog: { + open: boolean; + saveConfirmed: boolean; + }; + // (undocumented) kpiAlerts: { openedWidgetRef: ObjRef | undefined; highlightedWidgetRef: ObjRef | undefined; @@ -11250,6 +11184,9 @@ export function removeNestedLayoutSection(index: ILayoutSectionPath, stashIdenti // @alpha export function removeNestedLayoutSectionItem(itemPath: ILayoutItemPath, stashIdentifier?: StashedDashboardItemsId, correlationId?: string): IRemoveSectionItem; +// @beta +export function removeRestrictedFilters(correlationId?: string): IRemoveRestrictedFilters; + // @beta export function removeSectionItem(sectionIndex: number, itemIndex: number, stashIdentifier?: StashedDashboardItemsId, correlationId?: string): IRemoveSectionItem; @@ -13802,6 +13739,18 @@ newSize?: IVisualizationSizeInfo; }; type: string; }) => void | ITabsState | WritableDraft; +readonly replaceInsightWidgetInsightForTab: (state: WritableDraft, action: { +payload: { +ref: ObjRef; +insightRef: ObjRef; +properties: VisualizationProperties | undefined; +header: IWidgetHeader | undefined; +newSize?: IVisualizationSizeInfo; +} & IUndoPayload & { +tabId: string; +}; +type: string; +}) => void | ITabsState | WritableDraft; readonly replaceWidgetFilterSettings: (state: WritableDraft, action: { payload: IUndoPayload & { ref: ObjRef; @@ -14009,6 +13958,9 @@ export const uiActions: { closeAlertingDialog: ActionCreatorWithoutPayload<"uiSlice/closeAlertingDialog">; openSaveAsDialog: ActionCreatorWithoutPayload<"uiSlice/openSaveAsDialog">; closeSaveAsDialog: ActionCreatorWithoutPayload<"uiSlice/closeSaveAsDialog">; + openInsightNotSavedDialog: ActionCreatorWithoutPayload<"uiSlice/openInsightNotSavedDialog">; + closeInsightNotSavedDialog: ActionCreatorWithoutPayload<"uiSlice/closeInsightNotSavedDialog">; + confirmInsightNotSavedDialogSubmit: ActionCreatorWithoutPayload<"uiSlice/confirmInsightNotSavedDialogSubmit">; setFilterBarExpanded: ActionCreatorWithPayload; closeKpiAlertDialog: ActionCreatorWithoutPayload<"uiSlice/closeKpiAlertDialog">; openKpiAlertDialog: ActionCreatorWithPayload; diff --git a/libs/sdk-ui-dashboard/package.json b/libs/sdk-ui-dashboard/package.json index dae7a2212a7..a6b5405c664 100644 --- a/libs/sdk-ui-dashboard/package.json +++ b/libs/sdk-ui-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-ui-dashboard", - "version": "11.57.0-alpha.1", + "version": "11.57.0-alpha.3", "description": "GoodData SDK - Dashboard Component", "license": "LicenseRef-LICENSE", "author": "GoodData Corporation", @@ -138,12 +138,13 @@ "happy-dom": "20.12.0", "npm-run-all": "4.1.5", "oxfmt": "0.66.0", - "oxlint": "1.57.0", - "oxlint-tsgolint": "0.18.1", + "oxlint": "1.67.0", + "oxlint-plugin-eslint": "1.82.0", + "oxlint-tsgolint": "0.22.1", "raf": "3.4.1", "react": "19.1.1", "react-dom": "19.1.1", - "sass": "1.100.0", + "sass": "1.104.0", "stylelint": "16.26.1", "svgo": "2.8.3", "typescript": "7.0.2", diff --git a/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/dateFilterConfigConverters.ts b/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/dateFilterConfigConverters.ts index 0f5318aeb5c..716847cb797 100644 --- a/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/dateFilterConfigConverters.ts +++ b/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/dateFilterConfigConverters.ts @@ -1,6 +1,6 @@ // (C) 2019-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files // Moved to sdk-ui-filters (shared with the CF date picker); re-exported for existing import sites. export { convertDateFilterConfigToDateFilterOptions } from "@gooddata/sdk-ui-filters"; diff --git a/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/dateFilterOptionMapping.ts b/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/dateFilterOptionMapping.ts index eee5dbad9cc..de7121b5e98 100644 --- a/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/dateFilterOptionMapping.ts +++ b/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/dateFilterOptionMapping.ts @@ -1,6 +1,6 @@ // (C) 2021-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files // Moved to sdk-ui-filters (shared with the CF date picker); re-exported for existing import sites. export { diff --git a/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/defaultConfig.ts b/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/defaultConfig.ts index e683cfd89c5..edb0913a73b 100644 --- a/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/defaultConfig.ts +++ b/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/defaultConfig.ts @@ -1,6 +1,6 @@ // (C) 2021-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files // Moved to @gooddata/sdk-ui-filters (shared with the CF date pickers); re-exported for existing import sites. export { diff --git a/libs/sdk-ui-dashboard/src/_staging/metadata/objRefMap.ts b/libs/sdk-ui-dashboard/src/_staging/metadata/objRefMap.ts index e286d0e47d1..674c7a71594 100644 --- a/libs/sdk-ui-dashboard/src/_staging/metadata/objRefMap.ts +++ b/libs/sdk-ui-dashboard/src/_staging/metadata/objRefMap.ts @@ -144,7 +144,7 @@ export class ObjRefMap { const strictMatch = this.itemsByIdentifier[this.idRefToKey(key.identifier, key.type)]; if (!strictMatch && !key.type && this.config.strictTypeCheck) { - // eslint-disable-next-line no-console + // oxlint-disable-next-line eslint-js/no-console console.debug( "You are working with an analytical backend which can only match entities by idRefs that contain both identifier and type. However, while trying to find match an object by ref your code supplied just the identifier without type.", ); diff --git a/libs/sdk-ui-dashboard/src/index.ts b/libs/sdk-ui-dashboard/src/index.ts index a7bac5c5735..be3826b6b35 100644 --- a/libs/sdk-ui-dashboard/src/index.ts +++ b/libs/sdk-ui-dashboard/src/index.ts @@ -1,6 +1,6 @@ // (C) 2019-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files /** * This package provides a Dashboard component that enables you to embed dashboards into your application as React components. @@ -348,6 +348,8 @@ export { removeMeasureValueFilter, removeMeasureValueFilters, removeDateFilter, + removeRestrictedFilters, + type IRemoveRestrictedFilters, moveMeasureValueFilter, moveDateFilter, changeMeasureValueFilterCondition, diff --git a/libs/sdk-ui-dashboard/src/internal.ts b/libs/sdk-ui-dashboard/src/internal.ts index 6b8d30436b3..34a9ee5f374 100644 --- a/libs/sdk-ui-dashboard/src/internal.ts +++ b/libs/sdk-ui-dashboard/src/internal.ts @@ -1,6 +1,6 @@ // (C) 2022-2026 GoodData Corporation -/* oxlint-disable no-barrel-files/no-barrel-files */ +// oxlint-disable no-barrel-files/no-barrel-files /** * This file is used to re-export internal parts of the package that are used in other GoodData applications. diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/common/validateDrillToCustomUrlParams.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/common/validateDrillToCustomUrlParams.ts index a6ce658051a..6041309c606 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/common/validateDrillToCustomUrlParams.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/common/validateDrillToCustomUrlParams.ts @@ -12,7 +12,6 @@ import { areObjRefsEqual, dashboardAttributeFilterItemToAttributeFilter, filterObjRef, - idRef, isArbitraryAttributeFilter, isAttributeFilter, isDrillToCustomUrl, @@ -20,6 +19,7 @@ import { isNegativeAttributeFilter, widgetRef, } from "@gooddata/sdk-model"; +import { displayFormPlaceholderRef } from "@gooddata/sdk-model/internal"; import { type ObjRefMap } from "../../../_staging/metadata/objRefMap.js"; import { queryWidgetFilters } from "../../queries/widgets.js"; @@ -160,7 +160,7 @@ function sanitizeAttributeFilter( ...filter, negativeAttributeFilter: { ...filter.negativeAttributeFilter, - displayForm: idRef(displayForm.id, "displayForm"), + displayForm: displayFormPlaceholderRef(displayForm), }, }; } else if (isArbitraryAttributeFilter(filter)) { @@ -168,7 +168,7 @@ function sanitizeAttributeFilter( ...filter, arbitraryAttributeFilter: { ...filter.arbitraryAttributeFilter, - displayForm: idRef(displayForm.id, "displayForm"), + displayForm: displayFormPlaceholderRef(displayForm), }, }; } else if (isMatchAttributeFilter(filter)) { @@ -176,7 +176,7 @@ function sanitizeAttributeFilter( ...filter, matchAttributeFilter: { ...filter.matchAttributeFilter, - displayForm: idRef(displayForm.id, "displayForm"), + displayForm: displayFormPlaceholderRef(displayForm), }, }; } else { @@ -184,7 +184,7 @@ function sanitizeAttributeFilter( ...filter, positiveAttributeFilter: { ...filter.positiveAttributeFilter, - displayForm: idRef(displayForm.id, "displayForm"), + displayForm: displayFormPlaceholderRef(displayForm), }, }; } diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveDashboardHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveDashboardHandler.test.ts index 195ecb3ff79..a3b03f17922 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveDashboardHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveDashboardHandler.test.ts @@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it } from "vitest"; -import { type IDashboardDefinition } from "@gooddata/sdk-model"; +import { type IDashboardDefinition, areObjRefsEqual, isInsightWidget } from "@gooddata/sdk-model"; import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; import { @@ -11,11 +11,16 @@ import { } from "../../../tests/SimpleDashboard.test.helpers.js"; import { saveDashboard } from "../../commands/dashboard.js"; import { addLayoutSection } from "../../commands/layout.js"; +import { createDashboardTab, switchDashboardTab } from "../../commands/tabs.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type DashboardSaved } from "../../events/dashboard.js"; +import { selectInsights } from "../../store/insights/insightsSelectors.js"; import { selectPersistedDashboard } from "../../store/meta/metaSelectors.js"; import { selectFilterContextIdentity } from "../../store/tabs/filterContext/filterContextSelectors.js"; import { selectBasicLayout } from "../../store/tabs/layout/layoutSelectors.js"; +import { selectActiveTabLocalIdentifier } from "../../store/tabs/tabsSelectors.js"; +import { uiActions } from "../../store/ui/index.js"; +import { selectIsInsightNotSavedDialogOpen } from "../../store/ui/uiSelectors.js"; import { TestInsightItem } from "../../tests/Layout.test.helpers.js"; import { isTemporaryIdentity } from "../../utils/dashboardItemUtils.js"; @@ -109,6 +114,263 @@ describe("save dashboard handler", () => { expect(Tester.emittedEventsDigest()).toMatchSnapshot(); }); + + it("should open warning dialog and block save when dashboard contains draft insight", async () => { + await Tester.dispatchAndWaitFor( + addLayoutSection(0, {}, [TestInsightItem], false, TestCorrelation), + "GDC.DASH/EVT.FLUID_LAYOUT.SECTION_ADDED", + ); + + const stateWithSection = Tester.state(); + const firstWidget = selectBasicLayout(stateWithSection).sections[0].items[0].widget; + expect(firstWidget && isInsightWidget(firstWidget)).toBe(true); + + if (!firstWidget || !isInsightWidget(firstWidget)) { + throw new Error("Expected first dashboard widget to be an insight widget."); + } + + Tester.dispatch({ + type: "insights/setInsights", + payload: [ + { + insight: { + ref: firstWidget.insight, + isDraft: true, + }, + }, + ], + }); + + Tester.dispatch(saveDashboard()); + await Tester.wait(200); + + expect(selectIsInsightNotSavedDialogOpen(Tester.state())).toBe(true); + expect(Tester.emittedEvents().some((event) => event.type === "GDC.DASH/EVT.SAVED")).toBe(false); + }); + + it("should open warning dialog when draft insight exists only on an inactive tab", async () => { + const firstTabId = Tester.select(selectActiveTabLocalIdentifier); + expect(firstTabId).toBeDefined(); + + await Tester.dispatchAndWaitFor(createDashboardTab("Tab 2"), "GDC.DASH/EVT.TAB.SWITCHED"); + await Tester.dispatchAndWaitFor( + addLayoutSection(0, {}, [TestInsightItem], false, TestCorrelation), + "GDC.DASH/EVT.FLUID_LAYOUT.SECTION_ADDED", + ); + + const stateWithSection = Tester.state(); + const firstWidget = selectBasicLayout(stateWithSection).sections[0].items[0].widget; + expect(firstWidget && isInsightWidget(firstWidget)).toBe(true); + + if (!firstWidget || !isInsightWidget(firstWidget) || !firstTabId) { + throw new Error( + "Expected first dashboard widget to be an insight widget and first tab id set.", + ); + } + + Tester.dispatch({ + type: "insights/setInsights", + payload: [ + { + insight: { + ref: firstWidget.insight, + isDraft: true, + }, + }, + ], + }); + + await Tester.dispatchAndWaitFor(switchDashboardTab(firstTabId), "GDC.DASH/EVT.TAB.SWITCHED"); + + Tester.dispatch(saveDashboard()); + await Tester.wait(200); + + expect(selectIsInsightNotSavedDialogOpen(Tester.state())).toBe(true); + expect(Tester.emittedEvents().some((event) => event.type === "GDC.DASH/EVT.SAVED")).toBe(false); + }); + + it("should save draft insight first and then save dashboard after confirmation", async () => { + await Tester.dispatchAndWaitFor( + addLayoutSection(0, {}, [TestInsightItem], false, TestCorrelation), + "GDC.DASH/EVT.FLUID_LAYOUT.SECTION_ADDED", + ); + + const stateWithSection = Tester.state(); + const firstWidget = selectBasicLayout(stateWithSection).sections[0].items[0].widget; + expect(firstWidget && isInsightWidget(firstWidget)).toBe(true); + + if (!firstWidget || !isInsightWidget(firstWidget)) { + throw new Error("Expected first dashboard widget to be an insight widget."); + } + + Tester.dispatch({ + type: "insights/setInsights", + payload: [ + { + insight: { + ref: firstWidget.insight, + title: "Draft insight", + isDraft: true, + }, + }, + ], + }); + + const oldInsightRef = firstWidget.insight; + + Tester.dispatch(saveDashboard(undefined, TestCorrelation)); + await Tester.wait(200); + + expect(selectIsInsightNotSavedDialogOpen(Tester.state())).toBe(true); + expect(Tester.emittedEvents().some((event) => event.type === "GDC.DASH/EVT.SAVED")).toBe(false); + + Tester.dispatch(uiActions.confirmInsightNotSavedDialogSubmit()); + const savedEvent: DashboardSaved = await Tester.waitFor("GDC.DASH/EVT.SAVED", 5000); + + const stateAfterSave = Tester.state(); + const insightWidgetAfterSave = selectBasicLayout(stateAfterSave).sections[0].items[0].widget; + expect(insightWidgetAfterSave && isInsightWidget(insightWidgetAfterSave)).toBe(true); + + if (!insightWidgetAfterSave || !isInsightWidget(insightWidgetAfterSave)) { + throw new Error("Expected first dashboard widget to be an insight widget."); + } + + const insightsAfterSave = selectInsights(stateAfterSave); + + expect(selectIsInsightNotSavedDialogOpen(stateAfterSave)).toBe(false); + expect(savedEvent.correlationId).toBe(TestCorrelation); + expect(areObjRefsEqual(insightWidgetAfterSave.insight, oldInsightRef)).toBe(true); + expect(insightsAfterSave.some((insight) => insight.insight.isDraft)).toBe(false); + }); + + it("should ignore pending save when draft insight save is canceled", async () => { + await Tester.dispatchAndWaitFor( + addLayoutSection(0, {}, [TestInsightItem], false, TestCorrelation), + "GDC.DASH/EVT.FLUID_LAYOUT.SECTION_ADDED", + ); + + const stateWithSection = Tester.state(); + const firstWidget = selectBasicLayout(stateWithSection).sections[0].items[0].widget; + expect(firstWidget && isInsightWidget(firstWidget)).toBe(true); + + if (!firstWidget || !isInsightWidget(firstWidget)) { + throw new Error("Expected first dashboard widget to be an insight widget."); + } + + Tester.dispatch({ + type: "insights/setInsights", + payload: [ + { + insight: { + ref: firstWidget.insight, + title: "Draft insight", + isDraft: true, + }, + }, + ], + }); + + Tester.dispatch(saveDashboard(undefined, TestCorrelation)); + await Tester.wait(200); + + expect(selectIsInsightNotSavedDialogOpen(Tester.state())).toBe(true); + + Tester.dispatch(uiActions.closeInsightNotSavedDialog()); + await Tester.wait(200); + + expect(selectIsInsightNotSavedDialogOpen(Tester.state())).toBe(false); + expect( + Tester.emittedEvents().some( + (event) => + event.type === "GDC.DASH/EVT.COMMAND.FAILED" && + event.correlationId === TestCorrelation, + ), + ).toBe(false); + expect( + Tester.emittedEvents().some( + (event) => event.type === "GDC.DASH/EVT.SAVED" && event.correlationId === TestCorrelation, + ), + ).toBe(false); + }); + + it("should save dashboard after confirmation when draft insight is used on active and inactive tabs", async () => { + const firstTabId = Tester.select(selectActiveTabLocalIdentifier); + expect(firstTabId).toBeDefined(); + + await Tester.dispatchAndWaitFor( + addLayoutSection(0, {}, [TestInsightItem], false, TestCorrelation), + "GDC.DASH/EVT.FLUID_LAYOUT.SECTION_ADDED", + ); + + const stateWithFirstTabSection = Tester.state(); + const firstTabWidget = selectBasicLayout(stateWithFirstTabSection).sections[0].items[0].widget; + + expect(firstTabWidget && isInsightWidget(firstTabWidget)).toBe(true); + + if (!firstTabWidget || !isInsightWidget(firstTabWidget) || !firstTabId) { + throw new Error("Expected first tab widget to be an insight widget and first tab id set."); + } + + const draftInsightRef = firstTabWidget.insight; + + await Tester.dispatchAndWaitFor(createDashboardTab("Tab 2"), "GDC.DASH/EVT.TAB.SWITCHED"); + const secondTabId = Tester.select(selectActiveTabLocalIdentifier); + + await Tester.dispatchAndWaitFor( + addLayoutSection(0, {}, [TestInsightItem], false, TestCorrelation), + "GDC.DASH/EVT.FLUID_LAYOUT.SECTION_ADDED", + ); + + const stateWithSecondTabSection = Tester.state(); + const secondTabWidget = selectBasicLayout(stateWithSecondTabSection).sections[0].items[0].widget; + + expect(secondTabWidget && isInsightWidget(secondTabWidget)).toBe(true); + + if (!secondTabWidget || !isInsightWidget(secondTabWidget) || !secondTabId) { + throw new Error("Expected second tab widget to be an insight widget and second tab id set."); + } + + expect(areObjRefsEqual(secondTabWidget.insight, draftInsightRef)).toBe(true); + + Tester.dispatch({ + type: "insights/setInsights", + payload: [ + { + insight: { + ref: draftInsightRef, + title: "Draft insight", + isDraft: true, + }, + }, + ], + }); + + await Tester.dispatchAndWaitFor(switchDashboardTab(firstTabId), "GDC.DASH/EVT.TAB.SWITCHED"); + + Tester.dispatch(saveDashboard(undefined, TestCorrelation)); + await Tester.wait(200); + + expect(selectIsInsightNotSavedDialogOpen(Tester.state())).toBe(true); + expect(Tester.emittedEvents().some((event) => event.type === "GDC.DASH/EVT.SAVED")).toBe(false); + + Tester.dispatch(uiActions.confirmInsightNotSavedDialogSubmit()); + const savedEvent: DashboardSaved = await Tester.waitFor("GDC.DASH/EVT.SAVED", 5000); + + await Tester.dispatchAndWaitFor(switchDashboardTab(secondTabId), "GDC.DASH/EVT.TAB.SWITCHED"); + + const stateAfterSave = Tester.state(); + const secondTabWidgetAfterSave = selectBasicLayout(stateAfterSave).sections[0].items[0].widget; + + expect(secondTabWidgetAfterSave && isInsightWidget(secondTabWidgetAfterSave)).toBe(true); + + if (!secondTabWidgetAfterSave || !isInsightWidget(secondTabWidgetAfterSave)) { + throw new Error("Expected second tab widget to be an insight widget."); + } + + expect(areObjRefsEqual(secondTabWidgetAfterSave.insight, draftInsightRef)).toBe(true); + expect(selectIsInsightNotSavedDialogOpen(stateAfterSave)).toBe(false); + expect(savedEvent.correlationId).toBe(TestCorrelation); + }); }); }); diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveDashboardHandler.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveDashboardHandler.ts index 6a20f594de0..221735d0585 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveDashboardHandler.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveDashboardHandler.ts @@ -3,7 +3,7 @@ import { type AnyAction } from "@reduxjs/toolkit"; import { type BatchAction, batchActions } from "redux-batched-actions"; import { type SagaIterator } from "redux-saga"; -import { type SagaReturnType, call, put, select } from "redux-saga/effects"; +import { type SagaReturnType, call, put, select, take } from "redux-saga/effects"; import { invariant } from "ts-invariant"; import { isUnexpectedResponseError } from "@gooddata/sdk-backend-spi"; @@ -17,7 +17,10 @@ import { type IDashboardTab, type IFilterContext, type IFilterContextDefinition, + type IInsight, type ITempFilterContext, + areObjRefsEqual, + insightRef, isTempFilterContext, } from "@gooddata/sdk-model"; @@ -36,6 +39,11 @@ import { dispatchDashboardEvent } from "../../store/_infra/eventDispatcher.js"; import { accessibleDashboardsActions } from "../../store/accessibleDashboards/index.js"; import { selectBackendCapabilities } from "../../store/backendCapabilities/backendCapabilitiesSelectors.js"; import { selectLocale } from "../../store/config/configSelectors.js"; +import { insightsActions } from "../../store/insights/index.js"; +import { + selectDraftInsightsUsedOnDashboard, + selectInsights, +} from "../../store/insights/insightsSelectors.js"; import { listedDashboardsActions } from "../../store/listedDashboards/index.js"; import { metaActions } from "../../store/meta/index.js"; import { selectDashboardDescriptor, selectPersistedDashboard } from "../../store/meta/metaSelectors.js"; @@ -46,11 +54,20 @@ import { selectDateFilterConfigOverridesByTab } from "../../store/tabs/dateFilte import { selectDateFilterConfigsOverridesByTab } from "../../store/tabs/dateFilterConfigs/dateFilterConfigsSelectors.js"; import { selectFilterContextStatesByTab } from "../../store/tabs/filterContext/filterContextSelectors.js"; import { tabsActions } from "../../store/tabs/index.js"; -import { filterOutCustomWidgets, selectBasicLayoutByTab } from "../../store/tabs/layout/layoutSelectors.js"; +import { + filterOutCustomWidgets, + selectAllInsightWidgetRefsByTab, + selectBasicLayoutByTab, +} from "../../store/tabs/layout/layoutSelectors.js"; import { selectMeasureValueFilterConfigsOverridesByTab } from "../../store/tabs/measureValueFilterConfigs/measureValueFilterConfigsSelectors.js"; import { selectSmartPersistedTabsParameters } from "../../store/tabs/parameters/parametersSelectors.js"; import { selectTabs } from "../../store/tabs/tabsSelectors.js"; import { DEFAULT_TAB_ID, type ITabState } from "../../store/tabs/tabsState.js"; +import { uiActions } from "../../store/ui/index.js"; +import { + selectIsInsightNotSavedDialogOpen, + selectIsInsightNotSavedDialogSaveConfirmed, +} from "../../store/ui/uiSelectors.js"; import { type DashboardContext } from "../../types/commonTypes.js"; import { type ExtendedDashboardWidget } from "../../types/layoutTypes.js"; import { type PromiseFnReturnType } from "../../types/sagas.js"; @@ -95,6 +112,56 @@ type DashboardSaveResult = { created: boolean; }; +function* persistDraftInsights( + ctx: DashboardContext, + cmd: ISaveDashboard, + insights: IInsight[], +): SagaIterator { + for (const draftInsight of insights) { + const persistedInsight = yield call(async () => { + return ctx.backend.workspace(ctx.workspace).insights().createInsight(draftInsight, false); + }); + + const persistedInsightWithDraftState: IInsight = { + ...persistedInsight, + insight: { + ...persistedInsight.insight, + isDraft: false, + }, + }; + + const currentInsights: ReturnType = yield select(selectInsights); + const updatedInsights = currentInsights.map((insight) => { + if (areObjRefsEqual(insightRef(insight), insightRef(draftInsight))) { + return persistedInsightWithDraftState; + } + + return insight; + }); + + const widgetRefsWithDraftInsightByTab: ReturnType< + ReturnType + > = yield select(selectAllInsightWidgetRefsByTab(insightRef(draftInsight))); + + for (const { tabId, widgetRef } of widgetRefsWithDraftInsightByTab) { + yield put( + tabsActions.replaceInsightWidgetInsightForTab({ + tabId, + ref: widgetRef, + insightRef: insightRef(persistedInsightWithDraftState), + properties: undefined, + header: undefined, + undo: { + cmd, + }, + }), + ); + } + + yield put(insightsActions.setInsights(updatedInsights)); + } +} + type DashboardSaveFn = ( ctx: DashboardContext, saveCtx: DashboardSaveContext, @@ -149,7 +216,7 @@ function saveDashboard( return ctx.backend .workspace(ctx.workspace) .dashboards() - .createDashboard(dashboardToSave) + .createDashboard(dashboardToSave, !ctx.config?.isAiMode) .then((dashboard) => ({ dashboard, created: true })); } throw error; @@ -581,10 +648,48 @@ function* save( export function* saveDashboardHandler( ctx: DashboardContext, cmd: ISaveDashboard, -): SagaIterator { +): SagaIterator { try { + const isInsightNotSavedDialogSaveConfirmed: ReturnType< + typeof selectIsInsightNotSavedDialogSaveConfirmed + > = yield select(selectIsInsightNotSavedDialogSaveConfirmed); + + const draftInsightsOnDashboard: ReturnType = yield select( + selectDraftInsightsUsedOnDashboard, + ); + + let shouldPersistDraftInsights = isInsightNotSavedDialogSaveConfirmed; + + if (draftInsightsOnDashboard.length > 0 && !shouldPersistDraftInsights) { + yield put(uiActions.openInsightNotSavedDialog()); + + const draftInsightDialogAction: + | ReturnType + | ReturnType = yield take([ + uiActions.confirmInsightNotSavedDialogSubmit.type, + uiActions.closeInsightNotSavedDialog.type, + ]); + + if (draftInsightDialogAction.type === uiActions.closeInsightNotSavedDialog.type) { + return undefined; + } + + shouldPersistDraftInsights = true; + } + yield put(savingActions.setSavingStart()); + const isInsightNotSavedDialogOpen: ReturnType = + yield select(selectIsInsightNotSavedDialogOpen); + + if (isInsightNotSavedDialogOpen) { + yield put(uiActions.closeInsightNotSavedDialog()); + } + + if (shouldPersistDraftInsights && draftInsightsOnDashboard.length > 0) { + yield call(persistDraftInsights, ctx, cmd, draftInsightsOnDashboard); + } + const persistedDashboard: ReturnType = yield select(selectPersistedDashboard); diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/drill/displayFormPlaceholderRef.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/drill/displayFormPlaceholderRef.test.ts new file mode 100644 index 00000000000..3ab93488517 --- /dev/null +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/drill/displayFormPlaceholderRef.test.ts @@ -0,0 +1,47 @@ +// (C) 2026 GoodData Corporation + +import { describe, expect, it } from "vitest"; + +import { type IAttributeDisplayFormMetadataObject, areObjRefsEqual, idRef } from "@gooddata/sdk-model"; +import { + displayFormPlaceholderRef, + getDashboardAttributeFilterPlaceholdersFromUrl, +} from "@gooddata/sdk-model/internal"; + +const label = { + type: "displayForm", + id: "shared_id", + ref: idRef("shared_id", "displayForm"), + attribute: idRef("attr1", "attribute"), +} as IAttributeDisplayFormMetadataObject; + +// A computed attribute's display form is fabricated client-side and its ref carries the computed +// attribute type; here it deliberately shares its id with the label above. +const computedAttribute = { + type: "displayForm", + id: "shared_id", + ref: idRef("shared_id", "computedAttribute"), + attribute: idRef("shared_id", "computedAttribute"), +} as IAttributeDisplayFormMetadataObject; + +function placeholderRef(url: string) { + return getDashboardAttributeFilterPlaceholdersFromUrl(url)[0].ref; +} + +describe("displayFormPlaceholderRef", () => { + it("matches a placeholder stored before computed attributes existed to the label", () => { + const ref = placeholderRef("https://example.com/?f={dash_attribute_filter_selection(shared_id)}"); + + expect(areObjRefsEqual(displayFormPlaceholderRef(label), ref)).toBe(true); + expect(areObjRefsEqual(displayFormPlaceholderRef(computedAttribute), ref)).toBe(false); + }); + + it("matches a computed attribute placeholder to the computed attribute", () => { + const ref = placeholderRef( + "https://example.com/?f={dash_attribute_filter_selection(computed_attribute/shared_id)}", + ); + + expect(areObjRefsEqual(displayFormPlaceholderRef(computedAttribute), ref)).toBe(true); + expect(areObjRefsEqual(displayFormPlaceholderRef(label), ref)).toBe(false); + }); +}); diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/drill/getAttributeIdentifiersReplacements.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/drill/getAttributeIdentifiersReplacements.test.ts new file mode 100644 index 00000000000..10b6e40b948 --- /dev/null +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/drill/getAttributeIdentifiersReplacements.test.ts @@ -0,0 +1,160 @@ +// (C) 2026 GoodData Corporation + +// @vitest-environment node + +import { runSaga } from "redux-saga"; +import { describe, expect, it, vi } from "vitest"; + +import { type IAttributeDisplayFormMetadataObject, idRef } from "@gooddata/sdk-model"; +import { type IDrillEventIntersectionElement } from "@gooddata/sdk-ui"; + +import { + selectAllCatalogDisplayFormsMap, + selectCatalogDateAttributes, +} from "../../store/catalog/catalogSelectors.js"; +import { type DashboardContext } from "../../types/commonTypes.js"; + +import { getAttributeIdentifiersReplacements } from "./resolveDrillToCustomUrl.js"; + +// A computed attribute's display form is fabricated client-side; its ref carries the computed +// attribute type rather than "displayForm". +const computedAttributeDisplayForm = { + type: "displayForm", + id: "ca1", + ref: idRef("ca1", "computedAttribute"), + attribute: idRef("ca1", "computedAttribute"), + title: "Performance band", +} as IAttributeDisplayFormMetadataObject; + +function intersection(labelId: string, primaryValue: string): IDrillEventIntersectionElement[] { + return [ + { + header: { + attributeHeader: { + identifier: labelId, + ref: idRef(labelId, "computedAttribute"), + localIdentifier: "a1", + uri: "", + name: "Performance band", + formOf: { + identifier: labelId, + ref: idRef(labelId, "computedAttribute"), + uri: "", + name: "Performance band", + }, + }, + attributeHeaderItem: { uri: primaryValue, name: primaryValue }, + }, + } as unknown as IDrillEventIntersectionElement, + ]; +} + +function createContext(elementTitle: string) { + const queryBuilder = { + withLimit: () => queryBuilder, + withOptions: () => queryBuilder, + query: () => Promise.resolve({ items: [{ title: elementTitle }] }), + }; + + const getAttributeDisplayForms = vi.fn().mockResolvedValue([]); + const getComputedAttribute = vi.fn().mockResolvedValue({ + type: "computedAttribute", + id: "ca1", + ref: idRef("ca1", "computedAttribute"), + displayForms: [computedAttributeDisplayForm], + }); + + const backend = { + capabilities: { supportsElementUris: false }, + workspace: () => ({ + attributes: () => ({ + getAttributeDisplayForms, + elements: () => ({ forDisplayForm: () => queryBuilder }), + }), + computedAttributes: () => ({ getComputedAttribute }), + }), + }; + + return { + ctx: { workspace: "ws", backend } as unknown as DashboardContext, + getAttributeDisplayForms, + getComputedAttribute, + }; +} + +/** + * @param catalogHit - whether the catalog carries the computed attribute's display form + */ +function run(saga: any, catalogHit: boolean, ...args: any[]) { + const displayFormsMap = { + get: (ref: any) => + catalogHit && ref?.identifier === "ca1" ? computedAttributeDisplayForm : undefined, + }; + + return runSaga( + { + dispatch: () => {}, + getState: () => ({}), + channel: undefined as any, + effectMiddlewares: [ + (next: any) => (effect: any) => { + if (effect?.type === "SELECT") { + if (effect.payload.selector === selectAllCatalogDisplayFormsMap) { + return next({ + ...effect, + payload: { ...effect.payload, selector: () => displayFormsMap }, + }); + } + if (effect.payload.selector === selectCatalogDateAttributes) { + return next({ ...effect, payload: { ...effect.payload, selector: () => [] } }); + } + } + return next(effect); + }, + ], + }, + saga, + ...args, + ).toPromise(); +} + +const URL = "https://example.com/?q={attribute_title(computed_attribute/ca1)}"; +const EXPECTED = [{ toBeReplaced: "{attribute_title(computed_attribute/ca1)}", replacement: "High" }]; + +describe("getAttributeIdentifiersReplacements", () => { + it("resolves a computed attribute placeholder from the catalog", async () => { + const { ctx, getAttributeDisplayForms, getComputedAttribute } = createContext("High"); + + const replacements = await run( + getAttributeIdentifiersReplacements, + true, + URL, + intersection("ca1", "high"), + ctx, + ); + + expect(replacements).toEqual(EXPECTED); + // the catalog already had it, so nothing needs loading + expect(getAttributeDisplayForms).not.toHaveBeenCalled(); + expect(getComputedAttribute).not.toHaveBeenCalled(); + }); + + it("resolves a computed attribute the catalog does not carry", async () => { + // A computed attribute excluded from the catalog by tags, or created after the dashboard was + // initialised, still turns up in the drill intersection and has to resolve. + const { ctx, getAttributeDisplayForms, getComputedAttribute } = createContext("High"); + + const replacements = await run( + getAttributeIdentifiersReplacements, + false, + URL, + intersection("ca1", "high"), + ctx, + ); + + expect(replacements).toEqual(EXPECTED); + // it must be loaded through the computedAttributes service, never asked for as a label + expect(getComputedAttribute).toHaveBeenCalledWith(idRef("ca1", "computedAttribute")); + expect(getAttributeDisplayForms).not.toHaveBeenCalled(); + }); +}); diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/drill/resolveDrillToCustomUrl.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/drill/resolveDrillToCustomUrl.ts index 92b1f4f2d7a..1cb36df81f2 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/drill/resolveDrillToCustomUrl.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/drill/resolveDrillToCustomUrl.ts @@ -22,7 +22,6 @@ import { dashboardFilterObjRef, filterAttributeElements, filterObjRef, - idRef, insightFilters as insightDefinitionFilters, insightId, isArbitraryAttributeFilter, @@ -44,6 +43,7 @@ import { } from "@gooddata/sdk-model"; import { type IDrillToUrlPlaceholder, + displayFormPlaceholderRef, getAttributeIdentifiersPlaceholdersFromUrl, getDashboardAttributeFilterPlaceholdersFromUrl, getDashboardMeasureValueFilterPlaceholdersFromUrl, @@ -75,6 +75,7 @@ import { selectAnalyticalWidgetByRef } from "../../store/tabs/layout/layoutSelec import { type DashboardContext } from "../../types/commonTypes.js"; import { DRILL_TO_URL_PLACEHOLDER } from "../../types/drillTypes.js"; import { type PromiseFnReturnType } from "../../types/sagas.js"; +import { resolveDisplayFormMetadata } from "../../utils/displayFormResolver.js"; import { dashboardMeasureValueFilterMatchesIdentifier, insightMeasureValueFilterMatchesIdentifier, @@ -89,13 +90,13 @@ interface IDrillToUrlPlaceholderReplacement { } interface IDrillToUrlElement { - identifier: string; + ref: ObjRef; elementTitle: string | null; } export function* loadElementTitle( dfRef: ObjRef, - dfIdentifier: string, + placeholderRef: ObjRef, attrElementUri: string, ctx: DashboardContext, ): SagaIterator { @@ -107,7 +108,7 @@ export function* loadElementTitle( ctx, ); return { - identifier: dfIdentifier, + ref: placeholderRef, elementTitle, }; } @@ -276,7 +277,7 @@ export function* loadAttributeElementsForDrillIntersection( } acc.push({ - identifier: displayForm.id, + ref: displayFormPlaceholderRef(displayForm), elementTitle: attributeHeaderItem.uri, }); return acc; @@ -284,8 +285,6 @@ export function* loadAttributeElementsForDrillIntersection( const loadedElement: IDrillToUrlElement[] = yield all( displayFormForValueLoad.reduce((acc: CallEffect[], displayForm) => { - const { id: dfIdentifier, ref: dfRef } = displayForm; - const attributeHeaderItem = findDrillIntersectionAttributeHeaderItem( drillIntersectionElements, displayForm, @@ -294,7 +293,15 @@ export function* loadAttributeElementsForDrillIntersection( return acc; } - acc.push(call(loadElementTitle, dfRef, dfIdentifier, attributeHeaderItem.uri, ctx)); + acc.push( + call( + loadElementTitle, + displayForm.ref, + displayFormPlaceholderRef(displayForm), + attributeHeaderItem.uri, + ctx, + ), + ); return acc; }, []), @@ -306,14 +313,6 @@ export function* loadAttributeElementsForDrillIntersection( const encodeParameterIfSet = (parameter: string | undefined | null): string | undefined | null => parameter === null || parameter === undefined ? parameter : encodeURIComponent(parameter); -export function getAttributeDisplayForms( - projectId: string, - objRefs: ObjRef[], - ctx: DashboardContext, -): Promise { - return ctx.backend.workspace(projectId).attributes().getAttributeDisplayForms(objRefs); -} - export function* getAttributeIdentifiersReplacements( url: string, drillIntersectionElements: IDrillEventIntersectionElement[], @@ -325,24 +324,36 @@ export function* getAttributeIdentifiersReplacements( return []; } - const displayForms: PromiseFnReturnType = yield call( - getAttributeDisplayForms, - ctx.workspace, - attributeIdentifiersPlaceholders.map((placeholder) => idRef(placeholder.identifier)), + // The placeholder refs carry their own type, so this resolves a label through the labels API and a + // computed attribute through the computedAttributes service - the labels API cannot describe one. + // It reads the catalog first but falls back to loading, so a computed attribute that the catalog + // does not carry (excluded by tags, or created after the dashboard was initialised) still resolves. + const { resolved, missing }: SagaReturnType = yield call( + resolveDisplayFormMetadata, ctx, + attributeIdentifiersPlaceholders.map(({ ref }) => ref), ); + if (missing.length > 0) { + console.warn( + "Drill to custom URL: no metadata found for attributes referenced by attribute_title placeholders; those placeholders cannot be resolved.", + { missing }, + ); + } + const elements: SagaReturnType = yield call( loadAttributeElementsForDrillIntersection, drillIntersectionElements, - displayForms, + [...resolved.values()], ctx, ); return attributeIdentifiersPlaceholders.map( - ({ placeholder: toBeReplaced, identifier, toBeEncoded }): IDrillToUrlPlaceholderReplacement => { - const elementTitle = elements.find( - (element: IDrillToUrlElement) => element.identifier === identifier, + ({ placeholder: toBeReplaced, ref, toBeEncoded }): IDrillToUrlPlaceholderReplacement => { + // Matched by reference, not by identifier alone: a computed attribute and a label can + // share an identifier, and they must not resolve to each other's element titles. + const elementTitle = elements.find((element: IDrillToUrlElement) => + areObjRefsEqual(element.ref, ref), )?.elementTitle; const replacement = toBeEncoded ? encodeParameterIfSet(elementTitle) : elementTitle; @@ -367,7 +378,7 @@ function* resolveDashboardAttributeFilterReplacement( return false; } const df = catalogDisplayForms.get(dashboardAttributeFilterItemDisplayForm(filter)); - return df && areObjRefsEqual(idRef(df.id), ref); + return df && areObjRefsEqual(displayFormPlaceholderRef(df), ref); }); if (textFilter && isDashboardTextAttributeFilter(textFilter)) { @@ -384,7 +395,7 @@ function* resolveDashboardAttributeFilterReplacement( let usedFilter = standardFilters.find((filter) => { const df = catalogDisplayForms.get(filter.attributeFilter.displayForm); - return df && areObjRefsEqual(idRef(df.id), ref); + return df && areObjRefsEqual(displayFormPlaceholderRef(df), ref); }); let attributeElementsValues = []; @@ -570,7 +581,7 @@ export function* getInsightAttributeFilterReplacements( const usedFilter = insightAttributeFilters.find((filter) => { const filterRef = filterObjRef(filter); const df = filterRef && catalogDisplayForms.get(filterRef); - return df && areObjRefsEqual(idRef(df.id), ref); + return df && areObjRefsEqual(displayFormPlaceholderRef(df), ref); }); let parsedFilter: string | undefined; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/removeAttributeFiltersHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/removeAttributeFiltersHandler.test.ts new file mode 100644 index 00000000000..4f714bd0d29 --- /dev/null +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/removeAttributeFiltersHandler.test.ts @@ -0,0 +1,59 @@ +// (C) 2026 GoodData Corporation + +// @vitest-environment node + +import { describe, expect, it } from "vitest"; + +import { idRef } from "@gooddata/sdk-model"; + +import { removeAttributeFilters } from "../../../commands/filters.js"; +import { tabsActions } from "../../../store/tabs/index.js"; +import { type DashboardContext } from "../../../types/commonTypes.js"; + +import { removeAttributeFiltersHandler } from "./removeAttributeFiltersHandler.js"; + +const ctx = { workspace: "ws" } as DashboardContext; + +const filterItem = (localIdentifier: string, parents: string[] = []) => ({ + attributeFilter: { + displayForm: idRef(localIdentifier), + localIdentifier, + filterElementsBy: parents.map((filterLocalIdentifier) => ({ + filterLocalIdentifier, + over: { attributes: [] }, + })), + }, +}); + +describe("removeAttributeFiltersHandler", () => { + it("leaves a child with no reference to any of the parents removed with it", () => { + const generator = removeAttributeFiltersHandler( + ctx, + removeAttributeFilters(["parent-a", "parent-b"]), + ); + generator.next(); + + const effects = []; + let step = generator.next([ + filterItem("parent-a"), + filterItem("parent-b"), + filterItem("child", ["parent-a", "parent-b"]), + ]); + while (!step.done) { + effects.push(step.value); + step = generator.next([]); + } + + const parentUpdates = effects + .map((effect) => (effect as any)?.payload?.action?.payload) + .filter(Array.isArray) + .flat() + .filter((action) => action.type === tabsActions.setAttributeFilterParents.type) + .map((action) => action.payload); + + expect(parentUpdates).toEqual([ + { filterLocalId: "child", parentFilters: [] }, + { filterLocalId: "child", parentFilters: [] }, + ]); + }); +}); diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/removeAttributeFiltersHandler.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/removeAttributeFiltersHandler.ts index 3e70fe47f75..85fc5806e15 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/removeAttributeFiltersHandler.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/removeAttributeFiltersHandler.ts @@ -82,8 +82,9 @@ export function* removeAttributeFiltersHandler( ...affectedChildren.map((item) => tabsActions.setAttributeFilterParents({ filterLocalId: dashboardAttributeFilterItemLocalIdentifier(item)!, + // affectedChildren is a pre-loop snapshot, so drop every id being removed parentFilters: (dashboardAttributeFilterItemFilterElementsBy(item) ?? []).filter( - (parent) => parent.filterLocalIdentifier !== removedLocalId, + (parent) => !filterLocalIds.includes(parent.filterLocalIdentifier), ), }), ), diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/removeRestrictedFiltersHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/removeRestrictedFiltersHandler.test.ts new file mode 100644 index 00000000000..ff967798b58 --- /dev/null +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/removeRestrictedFiltersHandler.test.ts @@ -0,0 +1,71 @@ +// (C) 2026 GoodData Corporation + +// @vitest-environment node + +import { call, select } from "redux-saga/effects"; +import { describe, expect, it } from "vitest"; + +import { type FilterContextItem, idRef } from "@gooddata/sdk-model"; + +import { + type IRemoveDateFilters, + removeAttributeFilters, + removeMeasureValueFilters, + removeRestrictedFilters, +} from "../../commands/filters.js"; +import { selectReportedRestrictedDashboardFilters } from "../../store/filtering/dashboardFilterSelectors.js"; +import { type DashboardContext } from "../../types/commonTypes.js"; + +import { removeAttributeFiltersHandler } from "./attributeFilter/removeAttributeFiltersHandler.js"; +import { removeDateFiltersHandler } from "./dateFilter/removeDateFiltersHandler.js"; +import { removeMeasureValueFilterHandler } from "./measureValueFilter/removeMeasureValueFilterHandler.js"; +import { removeRestrictedFiltersHandler } from "./removeRestrictedFiltersHandler.js"; + +const ctx = { workspace: "ws" } as DashboardContext; +const dataSet = idRef("dataset", "dataSet"); + +const asFilter = (filter: unknown) => filter as FilterContextItem; +const attributeFilter = asFilter({ + attributeFilter: { displayForm: idRef("label", "displayForm"), localIdentifier: "attribute" }, +}); +const dateFilter = asFilter({ + dateFilter: { type: "relative", dataSet, localIdentifier: "date" }, +}); +const measureValueFilter = asFilter({ + dashboardMeasureValueFilter: { measure: idRef("metric"), localIdentifier: "measure-value" }, +}); + +describe("removeRestrictedFiltersHandler", () => { + it("removes each reported type through its own handler, which cleans up after it", () => { + const generator = removeRestrictedFiltersHandler(ctx, removeRestrictedFilters("corr")); + + expect(generator.next().value).toEqual(select(selectReportedRestrictedDashboardFilters)); + + const restricted = [attributeFilter, dateFilter, measureValueFilter]; + expect(generator.next(restricted).value).toEqual( + call(removeAttributeFiltersHandler, ctx, removeAttributeFilters(["attribute"], "corr")), + ); + + expect(generator.next().value).toEqual( + call(removeDateFiltersHandler, ctx, { + type: "GDC.DASH/CMD.FILTER_CONTEXT.DATE_FILTER.REMOVE", + correlationId: "corr", + payload: { dataSets: [dataSet] }, + } as IRemoveDateFilters), + ); + + expect(generator.next().value).toEqual( + call(removeMeasureValueFilterHandler, ctx, removeMeasureValueFilters(["measure-value"], "corr")), + ); + + expect(generator.next().done).toBe(true); + }); + + it("asks for no removal when nothing is restricted", () => { + const generator = removeRestrictedFiltersHandler(ctx, removeRestrictedFilters()); + + generator.next(); + + expect(generator.next([]).done).toBe(true); + }); +}); diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/removeRestrictedFiltersHandler.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/removeRestrictedFiltersHandler.ts new file mode 100644 index 00000000000..6e99034cd7c --- /dev/null +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/removeRestrictedFiltersHandler.ts @@ -0,0 +1,75 @@ +// (C) 2026 GoodData Corporation + +import { type SagaIterator } from "redux-saga"; +import { call, select } from "redux-saga/effects"; + +import { + isDashboardAttributeFilterItem, + isDashboardDateFilterWithDimension, + isDashboardMeasureValueFilter, +} from "@gooddata/sdk-model"; + +import { + type IRemoveDateFilters, + type IRemoveRestrictedFilters, + removeAttributeFilters, + removeMeasureValueFilters, +} from "../../commands/filters.js"; +import { + filterLocalIdentifiers, + selectReportedRestrictedDashboardFilters, +} from "../../store/filtering/dashboardFilterSelectors.js"; +import { type DashboardContext } from "../../types/commonTypes.js"; + +import { removeAttributeFiltersHandler } from "./attributeFilter/removeAttributeFiltersHandler.js"; +import { removeDateFiltersHandler } from "./dateFilter/removeDateFiltersHandler.js"; +import { removeMeasureValueFilterHandler } from "./measureValueFilter/removeMeasureValueFilterHandler.js"; + +/** + * Removes the filters the active tab's notice reports. Each type goes through its own removal handler, + * which is what cleans up the dependencies, configs and widget ignore lists the filter leaves behind. + */ +export function* removeRestrictedFiltersHandler( + ctx: DashboardContext, + cmd: IRemoveRestrictedFilters, +): SagaIterator { + const restricted: ReturnType = yield select( + selectReportedRestrictedDashboardFilters, + ); + + const attributeFilterLocalIds = [ + ...filterLocalIdentifiers(restricted.filter(isDashboardAttributeFilterItem)), + ]; + const measureValueFilterLocalIds = [ + ...filterLocalIdentifiers(restricted.filter(isDashboardMeasureValueFilter)), + ]; + const dateFilterDataSets = restricted + .filter(isDashboardDateFilterWithDimension) + .map((filter) => filter.dateFilter.dataSet!); + + if (attributeFilterLocalIds.length) { + yield call( + removeAttributeFiltersHandler, + ctx, + removeAttributeFilters(attributeFilterLocalIds, cmd.correlationId), + ); + } + + if (dateFilterDataSets.length) { + // there is no factory taking more than one data set + const command: IRemoveDateFilters = { + type: "GDC.DASH/CMD.FILTER_CONTEXT.DATE_FILTER.REMOVE", + correlationId: cmd.correlationId, + payload: { dataSets: dateFilterDataSets }, + }; + yield call(removeDateFiltersHandler, ctx, command); + } + + if (measureValueFilterLocalIds.length) { + yield call( + removeMeasureValueFilterHandler, + ctx, + removeMeasureValueFilters(measureValueFilterLocalIds, cmd.correlationId), + ); + } +} diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/index.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/index.ts index d083227717d..1ebe2eb1310 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/index.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/index.ts @@ -75,6 +75,7 @@ import { changeMeasureValueFilterDimensionalityHandler } from "./filterContext/m import { changeMeasureValueFilterTitleHandler } from "./filterContext/measureValueFilter/changeMeasureValueFilterTitleHandler.js"; import { moveMeasureValueFilterHandler } from "./filterContext/measureValueFilter/moveMeasureValueFilterHandler.js"; import { removeMeasureValueFilterHandler } from "./filterContext/measureValueFilter/removeMeasureValueFilterHandler.js"; +import { removeRestrictedFiltersHandler } from "./filterContext/removeRestrictedFiltersHandler.js"; import { addLayoutSectionHandler } from "./layout/addLayoutSectionHandler.js"; import { addSectionItemsHandler } from "./layout/addSectionItemsHandler.js"; import { changeLayoutSectionHeaderHandler } from "./layout/changeLayoutSectionHeaderHandler.js"; @@ -186,6 +187,7 @@ export const DefaultCommandHandlers: { "GDC.DASH/CMD.FILTER_CONTEXT.DATE_FILTER.MOVE": moveDateFilterHandler, "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.ADD": addMeasureValueFilterHandler, "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.REMOVE": removeMeasureValueFilterHandler, + "GDC.DASH/CMD.FILTER_CONTEXT.RESTRICTED_FILTERS.REMOVE": removeRestrictedFiltersHandler, "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.MOVE": moveMeasureValueFilterHandler, "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.CHANGE_CONDITION": changeMeasureValueFilterConditionHandler, diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/validation/drillDisplayFormIdentifiers.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/validation/drillDisplayFormIdentifiers.test.ts new file mode 100644 index 00000000000..436bbdd2278 --- /dev/null +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/validation/drillDisplayFormIdentifiers.test.ts @@ -0,0 +1,50 @@ +// (C) 2026 GoodData Corporation + +import { describe, expect, it } from "vitest"; + +import { type IDrillToCustomUrl, idRef } from "@gooddata/sdk-model"; + +import { + extractDashboardFilterDisplayFormIdentifiers, + extractDisplayFormIdentifiers, + extractInsightFilterDisplayFormIdentifiers, +} from "./insightDrillDefinitionUtils.js"; + +/** + * These refs are fed to resolveDisplayFormMetadata when a drill is saved. A computed attribute + * rebuilt as a display form resolves as missing there, and the drill is rejected - so every extractor + * has to keep the type the placeholder carried. + */ +function drillWithUrl(url: string): IDrillToCustomUrl { + return { + type: "drillToCustomUrl", + transition: "new-window", + origin: { type: "drillFromAttribute", attribute: idRef("label1", "displayForm") }, + target: { url }, + } as IDrillToCustomUrl; +} + +describe("drill display form identifier extraction", () => { + it.each([ + [ + "attribute_title", + extractDisplayFormIdentifiers, + "https://e.com/?a={attribute_title(computed_attribute/ca1)}&b={attribute_title(label1)}", + ], + [ + "dash_attribute_filter_selection", + extractDashboardFilterDisplayFormIdentifiers, + "https://e.com/?a={dash_attribute_filter_selection(computed_attribute/ca1)}&b={dash_attribute_filter_selection(label1)}", + ], + [ + "attribute_filter_selection", + extractInsightFilterDisplayFormIdentifiers, + "https://e.com/?a={attribute_filter_selection(computed_attribute/ca1)}&b={attribute_filter_selection(label1)}", + ], + ])("keeps the computed attribute type for %s placeholders", (_name, extract, url) => { + expect(extract([drillWithUrl(url)])).toEqual([ + idRef("ca1", "computedAttribute"), + idRef("label1", "displayForm"), + ]); + }); +}); diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/validation/insightDrillDefinitionUtils.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/validation/insightDrillDefinitionUtils.ts index 64dee061c40..19eaf61a7fa 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/validation/insightDrillDefinitionUtils.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/validation/insightDrillDefinitionUtils.ts @@ -161,9 +161,9 @@ export function extractDisplayFormIdentifiers(drillDefinitions: InsightDrillDefi .flatMap((drillItem) => { if (isDrillToCustomUrl(drillItem)) { const params = getAttributeIdentifiersPlaceholdersFromUrl(drillItem.target.url); - // normalize ref take the value from state ... - // md object has to be identifier - return params.map((param) => idRef(param.identifier, "displayForm")); + // the placeholder's own ref already names the object by identifier and carries its + // type, which a computed attribute needs to resolve as anything other than a label + return params.map((param) => param.ref); } else { return [drillItem.target.displayForm, drillItem.target.hyperlinkDisplayForm]; } @@ -177,11 +177,7 @@ export function extractDashboardFilterDisplayFormIdentifiers( const dashboardAttributeFilterPlaceholdersFromUrl = getDashboardAttributeFilterPlaceholdersFromUrl( drillItem.target.url, ); - // normalize ref take the value from state ... - // md object has to be identifier - return dashboardAttributeFilterPlaceholdersFromUrl.map((param) => - idRef(param.identifier, "displayForm"), - ); + return dashboardAttributeFilterPlaceholdersFromUrl.map((param) => param.ref); }); } @@ -192,9 +188,7 @@ export function extractInsightFilterDisplayFormIdentifiers( const insightAttributeFilterPlaceholders = getInsightAttributeFilterPlaceholdersFromUrl( drillItem.target.url, ); - // normalize ref take the value from state ... - // md object has to be identifier - return insightAttributeFilterPlaceholders.map((param) => idRef(param.identifier, "displayForm")); + return insightAttributeFilterPlaceholders.map((param) => param.ref); }); } diff --git a/libs/sdk-ui-dashboard/src/model/commands/base.ts b/libs/sdk-ui-dashboard/src/model/commands/base.ts index d38d97b83ea..89ff4d886dd 100644 --- a/libs/sdk-ui-dashboard/src/model/commands/base.ts +++ b/libs/sdk-ui-dashboard/src/model/commands/base.ts @@ -44,6 +44,7 @@ export type DashboardCommandType = | "GDC.DASH/CMD.FILTER_CONTEXT.DATE_FILTER.MOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.ADD" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.REMOVE" + | "GDC.DASH/CMD.FILTER_CONTEXT.RESTRICTED_FILTERS.REMOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.MOVE" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.CHANGE_CONDITION" | "GDC.DASH/CMD.FILTER_CONTEXT.MEASURE_VALUE_FILTER.SET_DIMENSIONALITY" diff --git a/libs/sdk-ui-dashboard/src/model/commands/filters.ts b/libs/sdk-ui-dashboard/src/model/commands/filters.ts index 5d73b8fedfd..d25032eb25d 100644 --- a/libs/sdk-ui-dashboard/src/model/commands/filters.ts +++ b/libs/sdk-ui-dashboard/src/model/commands/filters.ts @@ -2218,3 +2218,30 @@ export function setMeasureValueFilterTitle( }, }; } + +/** + * Removes the filters the active tab's filter bar reports as not applied. + * + * @remarks + * Filters the author hid are kept: they are already left out of every execution. Saving the dashboard + * makes the removal permanent, for everyone. + * + * @beta + */ +export interface IRemoveRestrictedFilters extends IDashboardCommand { + readonly type: "GDC.DASH/CMD.FILTER_CONTEXT.RESTRICTED_FILTERS.REMOVE"; +} + +/** + * Creates the {@link IRemoveRestrictedFilters} command. + * + * @param correlationId - specify correlation id to use for this command. this will be included in all + * events that will be emitted during the command processing + * @beta + */ +export function removeRestrictedFilters(correlationId?: string): IRemoveRestrictedFilters { + return { + type: "GDC.DASH/CMD.FILTER_CONTEXT.RESTRICTED_FILTERS.REMOVE", + correlationId, + }; +} diff --git a/libs/sdk-ui-dashboard/src/model/commands/index.ts b/libs/sdk-ui-dashboard/src/model/commands/index.ts index ded4eb30286..28d26199955 100644 --- a/libs/sdk-ui-dashboard/src/model/commands/index.ts +++ b/libs/sdk-ui-dashboard/src/model/commands/index.ts @@ -58,6 +58,7 @@ import { type IRemoveAttributeFilters, type IRemoveDateFilters, type IRemoveMeasureValueFilters, + type IRemoveRestrictedFilters, type IResetFilterContextWorkingSelection, type ISaveFilterView, type ISetAttributeFilterDependentDateFilters, @@ -261,6 +262,7 @@ export type DashboardCommands = | IAddDateFilter | IAddMeasureValueFilter | IRemoveMeasureValueFilters + | IRemoveRestrictedFilters | IRemoveDateFilters | IMoveDateFilter | IChangeMeasureValueFilterCondition diff --git a/libs/sdk-ui-dashboard/src/model/store/filtering/dashboardFilterSelectors.test.ts b/libs/sdk-ui-dashboard/src/model/store/filtering/dashboardFilterSelectors.test.ts index 08e70426dfa..38c7c356b5b 100644 --- a/libs/sdk-ui-dashboard/src/model/store/filtering/dashboardFilterSelectors.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/filtering/dashboardFilterSelectors.test.ts @@ -9,6 +9,7 @@ import { type FilterContextItem, idRef } from "@gooddata/sdk-model"; import { selectExecutableDashboardFilters, + selectReportedRestrictedDashboardFilters, selectRestrictedDashboardFilterCount, selectRestrictedDashboardFilterLocalIdentifiers, selectRestrictedDashboardFilterLocalIdentifiersForTab, @@ -59,9 +60,9 @@ describe("restricted filter selectors", () => { expect([...forTab("unknown-tab")]).toEqual([]); }); - it("counts the restricted filters the viewer would otherwise see, but not the hidden ones", () => { - const count = (attributeFilterConfigs: { localIdentifier: string; mode: string }[]) => - combinerOf(selectRestrictedDashboardFilterCount)( + it("reports the restricted filters the viewer would otherwise see, but not the hidden ones", () => { + const reported = (attributeFilterConfigs: { localIdentifier: string; mode: string }[]) => + combinerOf(selectReportedRestrictedDashboardFilters)( [forbiddenFilter], undefined, [], @@ -69,17 +70,17 @@ describe("restricted filter selectors", () => { [], ); - expect(count([])).toBe(1); - expect(count([{ localIdentifier: "forbidden", mode: "active" }])).toBe(1); - expect(count([{ localIdentifier: "forbidden", mode: "hidden" }])).toBe(0); + expect(reported([])).toEqual([forbiddenFilter]); + expect(reported([{ localIdentifier: "forbidden", mode: "active" }])).toEqual([forbiddenFilter]); + expect(reported([{ localIdentifier: "forbidden", mode: "hidden" }])).toEqual([]); }); - it("counts a restricted measure value filter unless the author hid that one too", () => { + it("reports a restricted measure value filter unless the author hid that one too", () => { const forbiddenMeasureValueFilter = { dashboardMeasureValueFilter: { measure: idRef("metric"), localIdentifier: "forbidden-mvf" }, } as FilterContextItem; - const count = (measureValueFilterConfigs: { localIdentifier: string; mode: string }[]) => - combinerOf(selectRestrictedDashboardFilterCount)( + const reported = (measureValueFilterConfigs: { localIdentifier: string; mode: string }[]) => + combinerOf(selectReportedRestrictedDashboardFilters)( [forbiddenMeasureValueFilter], undefined, [], @@ -87,7 +88,12 @@ describe("restricted filter selectors", () => { measureValueFilterConfigs, ); - expect(count([])).toBe(1); - expect(count([{ localIdentifier: "forbidden-mvf", mode: "hidden" }])).toBe(0); + expect(reported([])).toEqual([forbiddenMeasureValueFilter]); + expect(reported([{ localIdentifier: "forbidden-mvf", mode: "hidden" }])).toEqual([]); + }); + + it("counts what it reports", () => { + expect(combinerOf(selectRestrictedDashboardFilterCount)([forbiddenFilter])).toBe(1); + expect(combinerOf(selectRestrictedDashboardFilterCount)([])).toBe(0); }); }); diff --git a/libs/sdk-ui-dashboard/src/model/store/filtering/dashboardFilterSelectors.ts b/libs/sdk-ui-dashboard/src/model/store/filtering/dashboardFilterSelectors.ts index 15a82ff5a81..b0d0fb060da 100644 --- a/libs/sdk-ui-dashboard/src/model/store/filtering/dashboardFilterSelectors.ts +++ b/libs/sdk-ui-dashboard/src/model/store/filtering/dashboardFilterSelectors.ts @@ -53,7 +53,7 @@ const commonDateFilter: FilterContextItem = newAllTimeDashboardDateFilter( generateDateFilterLocalIdentifier(0), ); -function filterLocalIdentifiers(filters: FilterContextItem[]): ReadonlySet { +export function filterLocalIdentifiers(filters: FilterContextItem[]): ReadonlySet { return new Set( filters .map(dashboardFilterLocalIdentifier) @@ -76,36 +76,46 @@ const selectRestrictedDashboardFilters: DashboardSelector = export const selectRestrictedDashboardFilterLocalIdentifiers: DashboardSelector> = createSelector(selectRestrictedDashboardFilters, filterLocalIdentifiers); +/** + * Selects the filters the current user is forbidden to access that the filter bar reports: the ones + * the author hid are left out, so they stay in the filter context and out of every execution. + */ +export const selectReportedRestrictedDashboardFilters: DashboardSelector = + createSelector( + selectRestrictedDashboardFilters, + selectDateFilterConfigOverrides, + selectDateFilterConfigsOverrides, + selectAttributeFilterConfigsOverrides, + selectMeasureValueFilterConfigsOverrides, + ( + restricted, + commonDateFilterConfig, + dateFilterWithDimensionConfigs, + attributeFilterConfigs, + measureValueFilterConfigs, + ) => + restricted.filter((filter) => + // isFilterContextItemHidden covers attribute and date filters only + isDashboardMeasureValueFilter(filter) + ? measureValueFilterConfigs.find( + (config) => config.localIdentifier === dashboardFilterLocalIdentifier(filter), + )?.mode !== "hidden" + : !isFilterContextItemHidden(filter, { + commonDateFilterConfig, + dateFilterWithDimensionConfigs, + attributeFilterConfigs, + }), + ), + ); + /** * Selects how many filters the current user is forbidden to access, excluding those the author hid. * * @alpha */ export const selectRestrictedDashboardFilterCount: DashboardSelector = createSelector( - selectRestrictedDashboardFilters, - selectDateFilterConfigOverrides, - selectDateFilterConfigsOverrides, - selectAttributeFilterConfigsOverrides, - selectMeasureValueFilterConfigsOverrides, - ( - restricted, - commonDateFilterConfig, - dateFilterWithDimensionConfigs, - attributeFilterConfigs, - measureValueFilterConfigs, - ) => - restricted.filter((filter) => - // isFilterContextItemHidden covers attribute and date filters only - isDashboardMeasureValueFilter(filter) - ? measureValueFilterConfigs.find( - (config) => config.localIdentifier === dashboardFilterLocalIdentifier(filter), - )?.mode !== "hidden" - : !isFilterContextItemHidden(filter, { - commonDateFilterConfig, - dateFilterWithDimensionConfigs, - attributeFilterConfigs, - }), - ).length, + selectReportedRestrictedDashboardFilters, + (reported) => reported.length, ); /** diff --git a/libs/sdk-ui-dashboard/src/model/store/insights/insightsSelectors.ts b/libs/sdk-ui-dashboard/src/model/store/insights/insightsSelectors.ts index d580dd8f621..fb16064d451 100644 --- a/libs/sdk-ui-dashboard/src/model/store/insights/insightsSelectors.ts +++ b/libs/sdk-ui-dashboard/src/model/store/insights/insightsSelectors.ts @@ -16,6 +16,7 @@ import { insightAttributes, insightMeasures, insightRef, + isDrillToInsight, measureAlias, measureItem, measureLocalId, @@ -32,7 +33,7 @@ import { selectCatalogMeasures, } from "../catalog/catalogSelectors.js"; import { selectLocale } from "../config/configSelectors.js"; -import { selectWidgetByRef } from "../tabs/layout/layoutSelectors.js"; +import { selectAllTabsInsightWidgetContexts, selectWidgetByRef } from "../tabs/layout/layoutSelectors.js"; import { type DashboardSelector, type DashboardState } from "../types.js"; import { insightsAdapter } from "./insightsEntityAdapter.js"; @@ -63,6 +64,35 @@ export const selectInsightRefs: DashboardSelector = createSelector(sel return insights.map(insightRef); }); +const addUniqueInsightRef = (insightRefs: ObjRef[], ref: ObjRef) => { + if (!insightRefs.some((existingRef) => areObjRefsEqual(existingRef, ref))) { + insightRefs.push(ref); + } +}; + +/** + * Selects refs of insights referenced by dashboard state (widgets, visualization switcher visualizations, and drills). + * + * @internal + */ +export const selectDashboardInsightRefs: DashboardSelector = createSelector( + selectAllTabsInsightWidgetContexts, + (contexts) => { + const insightRefs: ObjRef[] = []; + + contexts.forEach(({ widget }) => { + addUniqueInsightRef(insightRefs, widget.insight); + widget.drills.forEach((drill) => { + if (isDrillToInsight(drill)) { + addUniqueInsightRef(insightRefs, drill.target); + } + }); + }); + + return insightRefs; + }, +); + /** * Selects all insights and returns them in a mapping of obj ref to the insight object. * @@ -76,6 +106,45 @@ export const selectInsightsMap: DashboardSelector> = createS }, ); +/** + * Selects insights referenced by dashboard state (widgets, visualization switcher visualizations, and drills). + * + * @internal + */ +export const selectInsightsUsedOnDashboard: DashboardSelector = createSelector( + selectDashboardInsightRefs, + selectInsightsMap, + selectInsights, + (insightRefs, insightsMap, insights) => { + return insightRefs + .map((ref) => { + return ( + insightsMap.get(ref) ?? + insights.find((currentInsight) => { + return currentInsight.insight.ref + ? areObjRefsEqual(currentInsight.insight.ref, ref) + : false; + }) + ); + }) + .filter((insight): insight is IInsight => { + return Boolean(insight); + }); + }, +); + +/** + * Selects draft insights referenced by dashboard state (widgets, visualization switcher visualizations, and drills). + * + * @internal + */ +export const selectDraftInsightsUsedOnDashboard: DashboardSelector = createSelector( + selectInsightsUsedOnDashboard, + (insights) => { + return insights.filter((insight) => insight.insight.isDraft); + }, +); + /** * Selects insight used on a dashboard by its ref. * diff --git a/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutReducers.ts b/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutReducers.ts index 322fd1cf8bf..d9e110ebcdb 100644 --- a/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutReducers.ts +++ b/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutReducers.ts @@ -56,7 +56,7 @@ import { } from "../../../types/layoutTypes.js"; import { type IWidgetDescription, type IWidgetHeader } from "../../../types/widgetTypes.js"; import { addArrayElements, removeArrayElement } from "../../../utils/arrayOps.js"; -import { resetUndoReducer, undoReducer, withUndo } from "../../_infra/undoEnhancer.js"; +import { type IUndoPayload, resetUndoReducer, undoReducer, withUndo } from "../../_infra/undoEnhancer.js"; import { type ITabsState } from "../tabsState.js"; import { type ILayoutState, layoutInitialState } from "./layoutState.js"; @@ -868,6 +868,12 @@ type ReplaceWidgetInsight = { newSize?: IVisualizationSizeInfo; }; +type ReplaceWidgetInsightWithUndo = ReplaceWidgetInsight & IUndoPayload; + +type ReplaceWidgetInsightForTab = ReplaceWidgetInsightWithUndo & { + tabId: string; +}; + const replaceInsightWidgetInsightCore: CoreLayoutReducer = (state, action) => { invariant(state.layout); @@ -894,6 +900,29 @@ const replaceInsightWidgetInsightCore: CoreLayoutReducer = // Wrap with undo and adapt to TabsState const replaceInsightWidgetInsight = adaptLayoutReducer(withUndo(replaceInsightWidgetInsightCore)); + +const replaceInsightWidgetInsightForTab: LayoutReducer = (state, action) => { + if (!state.tabs) { + return; + } + + const { tabId, ...replacementPayload } = action.payload; + const tab = state.tabs.find((item) => item.localIdentifier === tabId); + + if (!tab?.layout) { + return; + } + + const reduceForTab = withUndo(replaceInsightWidgetInsightCore); + const result = reduceForTab(tab.layout, { + ...action, + payload: replacementPayload, + }); + + if (result !== undefined) { + tab.layout = result; + } +}; // // @@ -1331,6 +1360,7 @@ export const layoutReducers = { replaceInsightWidgetVisProperties, replaceInsightWidgetVisConfiguration, replaceInsightWidgetInsight, + replaceInsightWidgetInsightForTab, replaceWidgetFilterSettings, replaceWidgetDateDataset, replaceKpiWidgetMeasure, diff --git a/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutSelectors.test.ts b/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutSelectors.test.ts new file mode 100644 index 00000000000..500910575e3 --- /dev/null +++ b/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutSelectors.test.ts @@ -0,0 +1,101 @@ +// (C) 2021-2026 GoodData Corporation + +import { describe, expect, it } from "vitest"; + +import { areObjRefsEqual, idRef } from "@gooddata/sdk-model"; + +import { type DashboardState } from "../../types.js"; + +import { selectAllInsightWidgetRefs } from "./layoutSelectors.js"; + +describe("layoutSelectors", () => { + describe("selectAllInsightWidgetRefs", () => { + it("should match insight widgets in nested layouts and visualization switcher visualizations", () => { + const targetInsightRef = idRef("target-insight", "insight"); + const topLevelWidgetRef = idRef("top-level-widget", "insight"); + const nestedWidgetRef = idRef("nested-widget", "insight"); + const switcherChildWidgetRef = idRef("switcher-child-widget", "insight"); + + const state = { + tabs: { + tabs: [ + { + localIdentifier: "tab-1", + layout: { + layout: { + type: "IDashboardLayout", + sections: [ + { + type: "IDashboardLayoutSection", + items: [ + { + type: "IDashboardLayoutItem", + size: { xl: { gridWidth: 12 } }, + widget: { + type: "insight", + identifier: "top-level-widget", + ref: topLevelWidgetRef, + insight: targetInsightRef, + }, + }, + { + type: "IDashboardLayoutItem", + size: { xl: { gridWidth: 12 } }, + widget: { + type: "IDashboardLayout", + sections: [ + { + type: "IDashboardLayoutSection", + items: [ + { + type: "IDashboardLayoutItem", + size: { xl: { gridWidth: 12 } }, + widget: { + type: "insight", + identifier: "nested-widget", + ref: nestedWidgetRef, + insight: targetInsightRef, + }, + }, + ], + }, + ], + }, + }, + { + type: "IDashboardLayoutItem", + size: { xl: { gridWidth: 12 } }, + widget: { + type: "visualizationSwitcher", + identifier: "switcher-widget", + ref: idRef("switcher-widget", "insight"), + visualizations: [ + { + type: "insight", + identifier: "switcher-child-widget", + ref: switcherChildWidgetRef, + insight: targetInsightRef, + }, + ], + }, + }, + ], + }, + ], + }, + }, + }, + ], + activeTabLocalIdentifier: "tab-1", + }, + } as unknown as DashboardState; + + const refs = selectAllInsightWidgetRefs(targetInsightRef)(state); + + expect(refs).toHaveLength(3); + expect(refs.some((ref) => areObjRefsEqual(ref, topLevelWidgetRef))).toBe(true); + expect(refs.some((ref) => areObjRefsEqual(ref, nestedWidgetRef))).toBe(true); + expect(refs.some((ref) => areObjRefsEqual(ref, switcherChildWidgetRef))).toBe(true); + }); + }); +}); diff --git a/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutSelectors.ts b/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutSelectors.ts index 306eaf59f42..741040a5473 100644 --- a/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutSelectors.ts +++ b/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutSelectors.ts @@ -15,6 +15,7 @@ import { type InsightDrillDefinition, type ObjRef, type ScreenSize, + areObjRefsEqual, dashboardAttributeFilterItemLocalIdentifier, filterContextItemsToDashboardFiltersByWidget, isDashboardAttributeFilterItem, @@ -109,6 +110,55 @@ export const selectBasicLayoutByTab: DashboardSelector< ); }); +export type IInsightWidgetRefWithTab = { + tabId: string; + widgetRef: ObjRef; +}; + +/** + * Selects refs of all insight widgets with matching insight reference across all tabs, + * including owning tab identifiers. + * + * @internal + */ +export const selectAllInsightWidgetRefsByTab: ( + insight: ObjRef | undefined, +) => DashboardSelector = createMemoizedSelector((insight: ObjRef | undefined) => + createSelector(selectAllTabsInsightWidgetContexts, (contexts): IInsightWidgetRefWithTab[] => { + if (!insight) { + return []; + } + + return contexts + .filter((context) => areObjRefsEqual(context.widget.insight, insight)) + .map((context) => ({ + tabId: context.tab.localIdentifier ?? DEFAULT_TAB_ID, + widgetRef: context.widget.ref, + })) + .filter((item, index, allItems) => { + return ( + allItems.findIndex( + (candidate) => + candidate.tabId === item.tabId && + areObjRefsEqual(candidate.widgetRef, item.widgetRef), + ) === index + ); + }); + }), +); + +/** + * Selects refs of all insight widgets with matching insight reference across all tabs. + * + * @internal + */ +export const selectAllInsightWidgetRefs: (insight: ObjRef | undefined) => DashboardSelector = + createMemoizedSelector((insight: ObjRef | undefined) => + createSelector(selectAllInsightWidgetRefsByTab(insight), (widgetRefsByTab): ObjRef[] => { + return widgetRefsByTab.map(({ widgetRef }) => widgetRef); + }), + ); + /** * This selector returns current layout's stash. This stash can contain items that were removed from the layout with the * intent of further using the item elsewhere on the layout. The stash is a mapping of stashIdentifier to an array diff --git a/libs/sdk-ui-dashboard/src/model/store/ui/uiReducers.ts b/libs/sdk-ui-dashboard/src/model/store/ui/uiReducers.ts index 36ec26ab6b6..3efd21726fc 100644 --- a/libs/sdk-ui-dashboard/src/model/store/ui/uiReducers.ts +++ b/libs/sdk-ui-dashboard/src/model/store/ui/uiReducers.ts @@ -154,6 +154,19 @@ const closeSaveAsDialog: UiReducer = (state) => { state.saveAsDialog.open = false; }; +const openInsightNotSavedDialog: UiReducer = (state) => { + state.insightNotSavedDialog.open = true; +}; + +const closeInsightNotSavedDialog: UiReducer = (state) => { + state.insightNotSavedDialog.open = false; + state.insightNotSavedDialog.saveConfirmed = false; +}; + +const confirmInsightNotSavedDialogSubmit: UiReducer = (state) => { + state.insightNotSavedDialog.saveConfirmed = true; +}; + const openSettingsDialog: UiReducer = (state) => { state.settingsDialog.open = true; }; @@ -525,6 +538,9 @@ export const uiReducers = { closeAlertingDialog, openSaveAsDialog, closeSaveAsDialog, + openInsightNotSavedDialog, + closeInsightNotSavedDialog, + confirmInsightNotSavedDialogSubmit, setFilterBarExpanded, closeKpiAlertDialog, openKpiAlertDialog, diff --git a/libs/sdk-ui-dashboard/src/model/store/ui/uiSelectors.ts b/libs/sdk-ui-dashboard/src/model/store/ui/uiSelectors.ts index 2b82da0e3eb..18b7bb5feeb 100644 --- a/libs/sdk-ui-dashboard/src/model/store/ui/uiSelectors.ts +++ b/libs/sdk-ui-dashboard/src/model/store/ui/uiSelectors.ts @@ -122,6 +122,22 @@ export const selectIsSaveAsDialogOpen: DashboardSelector = createSelect (state) => state.saveAsDialog.open, ); +/** + * @internal + */ +export const selectIsInsightNotSavedDialogOpen: DashboardSelector = createSelector( + selectSelf, + (state) => state.insightNotSavedDialog.open, +); + +/** + * @internal + */ +export const selectIsInsightNotSavedDialogSaveConfirmed: DashboardSelector = createSelector( + selectSelf, + (state) => state.insightNotSavedDialog.saveConfirmed, +); + /** * @alpha */ diff --git a/libs/sdk-ui-dashboard/src/model/store/ui/uiState.ts b/libs/sdk-ui-dashboard/src/model/store/ui/uiState.ts index 475d3876bc7..d2e4f9bc5ac 100644 --- a/libs/sdk-ui-dashboard/src/model/store/ui/uiState.ts +++ b/libs/sdk-ui-dashboard/src/model/store/ui/uiState.ts @@ -59,6 +59,10 @@ export interface IUiState { saveAsDialog: { open: boolean; }; + insightNotSavedDialog: { + open: boolean; + saveConfirmed: boolean; + }; settingsDialog: { open: boolean; }; @@ -165,6 +169,10 @@ export const uiInitialState: IUiState = { saveAsDialog: { open: false, }, + insightNotSavedDialog: { + open: false, + saveConfirmed: false, + }, settingsDialog: { open: false, }, diff --git a/libs/sdk-ui-dashboard/src/plugins/customizationApis/customizationLogging.ts b/libs/sdk-ui-dashboard/src/plugins/customizationApis/customizationLogging.ts index f5bda9e02bf..cf68af34317 100644 --- a/libs/sdk-ui-dashboard/src/plugins/customizationApis/customizationLogging.ts +++ b/libs/sdk-ui-dashboard/src/plugins/customizationApis/customizationLogging.ts @@ -28,11 +28,11 @@ export class DashboardCustomizationLogger implements IDashboardCustomizationLogg this.currentPlugin = plugin; }; public debug = (message: string, ...optionalParams: any[]): void => { - // eslint-disable-next-line no-console + // oxlint-disable-next-line eslint-js/no-console console.debug(addPluginInfoToMessage(this.currentPlugin, message), optionalParams); }; public log = (message: string, ...optionalParams: any[]): void => { - // eslint-disable-next-line no-console + // oxlint-disable-next-line eslint-js/no-console console.log(addPluginInfoToMessage(this.currentPlugin, message), optionalParams); }; public warn = (message: string, ...optionalParams: any[]): void => { diff --git a/libs/sdk-ui-dashboard/src/plugins/engine.ts b/libs/sdk-ui-dashboard/src/plugins/engine.ts index ce6cb70e8c7..22303a20fe7 100644 --- a/libs/sdk-ui-dashboard/src/plugins/engine.ts +++ b/libs/sdk-ui-dashboard/src/plugins/engine.ts @@ -68,7 +68,7 @@ export function newDashboardEngine(): IDashboardEngine { const customizationBuilder = new DashboardCustomizationBuilder(); const eventRegistration = new DefaultDashboardEventHandling(); - // eslint-disable-next-line no-console + // oxlint-disable-next-line eslint-js/no-console console.debug( `DashboardEngine ${this.version} initializing with plugins: ${plugins .map(pluginDebugStr) diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/blocks/AlertingDialogFieldLabelWithTooltip.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/blocks/AlertingDialogFieldLabelWithTooltip.tsx index 31604048520..6dc7cec70b3 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/blocks/AlertingDialogFieldLabelWithTooltip.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/blocks/AlertingDialogFieldLabelWithTooltip.tsx @@ -33,7 +33,6 @@ export function AlertingDialogFieldLabelWithTooltip({ arrowPlacement="left" optimalPlacement offset={10} - width={280} triggerBy={["hover", "click"]} />
diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/types.ts b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/types.ts index 34dd94214fd..cdc567a2821 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/types.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/types.ts @@ -47,6 +47,11 @@ import { type AttributeValue } from "./hooks/useAttributeValuesFromExecResults.j /// /** + * Props of the alerting create/edit dialog, accepted by `AlertingDialogComponent`. + * + * Extends {@link IAutomationDialogCallbacks} with data props that are all deprecated — the dialog + * reads its data from `useAlertingDialogContext()` instead. + * * @beta */ export interface IAlertingDialogProps extends IAutomationDialogCallbacks { @@ -625,6 +630,11 @@ export interface IAlertingDialogFormFieldGroupProps { } /** + * Props of the alerting management dialog, accepted by `AlertingManagementDialogComponent`. + * + * Extends {@link IAutomationManagementDialogCallbacks} with data props that are all deprecated — + * the dialog reads its data from `useAlertingManagementDialogContext()` instead. + * * @beta */ export interface IAlertingManagementDialogProps extends IAutomationManagementDialogCallbacks { @@ -664,6 +674,9 @@ export interface IAlertingManagementDialogProps extends IAutomationManagementDia /// /** + * Type of a replacement for the alerting create/edit dialog — the shape expected by the + * `AlertingDialogComponent` dashboard prop. + * * @beta */ export type CustomAlertingDialogComponent = ComponentType; @@ -703,6 +716,9 @@ export type CustomAlertingDialogComponent = ComponentType; export type CustomAlertingDialogContextDecoratorComponent = ComponentType<{ children?: ReactNode }>; /** + * Type of a replacement for the alerting management dialog — the shape expected by the + * `AlertingManagementDialogComponent` dashboard prop. + * * @beta */ export type CustomAlertingManagementDialogComponent = ComponentType; @@ -776,7 +792,14 @@ export interface IAlertDropdownProps { * @beta */ export enum AlertMetricComparatorType { + /** + * Compares against the immediately preceding period at the alert's selected granularity + * (e.g. previous week, previous month). + */ PreviousPeriod, + /** + * Compares against the same period one year earlier. + */ SamePeriodPreviousYear, } diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/contexts/AlertingDialogContext.ts b/libs/sdk-ui-dashboard/src/presentation/automations/contexts/AlertingDialogContext.ts index cd455704c4e..c1da628570b 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/contexts/AlertingDialogContext.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/contexts/AlertingDialogContext.ts @@ -26,13 +26,21 @@ import type { * @beta */ export interface IAlertingDialogContextValue { + /** Whether the dialog creates a new alert or edits an existing one. */ mode: "create" | "edit"; + /** Widget the alert targets; undefined when alerting for a dashboard rather than a widget. */ widget?: IWidget; + /** Insight of {@link IAlertingDialogContextValue.widget}; undefined when alerting for a dashboard. */ insight?: IInsight; + /** Title of {@link IAlertingDialogContextValue.widget}; undefined when alerting for a dashboard. */ widgetTitle?: string; + /** Id of the dashboard the alert belongs to. */ dashboardId?: string; + /** The dashboard's applied filters available to the alert — cross-filtering, hidden, and empty filters excluded. */ dashboardFilters: FilterContextItem[]; + /** Raw dashboard hidden filters (`selectDashboardHiddenFilters`); combined with the edited filters via `getAppliedWidgetFilters` inside the dialog. */ hiddenFilters: FilterContextItem[]; + /** Looks up a widget's execution result by ref; used to resolve attribute values for the condition's "for" field. */ executionResultByRef: (ref: ObjRef | undefined) => { executionResult?: IExecutionResult } | undefined; /** Effective widget parameter values for the dialog's widget (replaces direct selectEffectiveParameterValuesForWidget read) */ parameterValues: IInsightParameterValue[]; @@ -42,10 +50,15 @@ export interface IAlertingDialogContextValue { * read in useAutomationAlertParameters). */ dashboardParameters: IDashboardParameter[]; + /** Local identifier of the dashboard's common (dashboard-level) date filter, when the automation-available filters include one. */ commonDateFilterId?: string; + /** The dashboard's configured evaluation frequency (cron expression); seeds the new alert's trigger interval when set. */ dashboardEvaluationFrequency?: string; + /** Creates a new alert on the backend. */ createAlert(alert: IAutomationMetadataObjectDefinition): Promise; + /** Saves changes to an existing alert on the backend. */ saveAlert(alert: IAutomationMetadataObject): Promise; + /** Deletes the alert from the backend. */ deleteAlert(alert: IAutomationMetadataObject): Promise; /** The alert being edited; undefined when creating a new one. */ alertToEdit?: IAutomationMetadataObject; diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/contexts/AlertingManagementDialogContext.ts b/libs/sdk-ui-dashboard/src/presentation/automations/contexts/AlertingManagementDialogContext.ts index 33350f26582..0d8b742dcef 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/contexts/AlertingManagementDialogContext.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/contexts/AlertingManagementDialogContext.ts @@ -12,15 +12,36 @@ import type { IAutomationMetadataObject, IInsight, IUser, IWidget, ObjRef } from * @alpha */ export interface IAlertingManagementDialogContextValue { + /** The logged-in user; from selectCurrentUser. Used to decide whether the user may edit/delete an alert they didn't create. */ currentUser?: IUser; + /** Id of the dashboard the management dialog is rendered on. Used to preselect the dashboard filter in the enhanced automations list. */ dashboardId?: string; + /** Title of the dashboard the management dialog is rendered on. Used as the label of the preselected dashboard filter in the enhanced automations list. */ dashboardTitle?: string; + /** Whether the current user may manage the workspace; from selectCanManageWorkspace. Combined with alert ownership to gate edit/delete. */ canManageWorkspace: boolean; + /** + * Whether the alert create/edit dialog is currently open (from store UI slice). + * Used by the management dialog's focus-return logic (refocus when the edit dialog closes). + */ isAlertDialogOpen: boolean; + /** Element ID to return focus to when the alerting dialog closes; from selectAlertingDialogReturnFocusTo, read via useAlertingDialogAccessibility. */ alertingDialogReturnFocusTo?: string; + /** Widget the management dialog is scoped to, when opened for a single widget rather than the whole dashboard; from selectIsAlertingManagementDialogContext. */ managementDialogContext: { widgetRef?: ObjRef }; + /** + * Cache-bust counter for the automation list: reset to 0 when a management dialog opens, + * incremented on invalidation. 0 means nothing has been invalidated since the dialog opened; + * consumers reload when the value changes and is not 0. + */ automationsInvalidationId?: number; + /** + * Whether the dashboard is rendered in an embedded context. + */ isEmbedded: boolean; + /** + * Whether accessibility mode is active (for aria/keyboard focus management). + */ enableAccessibilityMode: boolean; /** * Alerts visible in the management dialog, scoped to the current dashboard context. @@ -34,9 +55,13 @@ export interface IAlertingManagementDialogContextValue { * management list. */ isLoading: boolean; + /** Looks up a dashboard widget (KPI, insight, rich text, or visualization-switcher) by ref, filtering out non-widget layout containers; bridges identifier↔URI ref mismatches the same way as selectWidgetByRef. */ getWidgetByRef: (ref: ObjRef | undefined) => IWidget | undefined; + /** Looks up the insight of an insight widget by the widget's ref; undefined for a non-insight widget. */ getInsightByWidgetRef: (ref: ObjRef | undefined) => IInsight | undefined; + /** Persists the given alert via the alerts save command; resolves with the saved alert, rejects with the command's error. */ pauseAlert(alert: IAutomationMetadataObject): Promise; + /** Persists the given alert via the alerts save command; resolves with the saved alert, rejects with the command's error. Functionally identical to {@link IAlertingManagementDialogContextValue.pauseAlert} — distinguished only by name for call-site clarity. */ resumeAlert(alert: IAutomationMetadataObject): Promise; } diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/contexts/AutomationsContext.ts b/libs/sdk-ui-dashboard/src/presentation/automations/contexts/AutomationsContext.ts index b6834a4dcd0..bf68cea3bb0 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/contexts/AutomationsContext.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/contexts/AutomationsContext.ts @@ -35,9 +35,23 @@ import type { IAutomationFiltersTab } from "../../../model/store/filtering/types * @beta */ export interface IAutomationsDateFilterConfig { + /** Granularities from the dashboard's effective (resolved) date-filter configuration; the fallback when no tab-scoped value is available. */ availableGranularities: DateFilterGranularity[]; + /** Date-filter options (presets) from the dashboard's effective (resolved) date-filter configuration; the fallback when no tab-scoped value is available. */ dateFilterOptions: IDateFilterOptionsByType; + /** + * Granularities from the given dashboard tab's effective (resolved) date-filter configuration — + * inherited settings included, not only tab-specific overrides. Empty when the tab has no + * effective configuration, in which case the caller falls back to + * {@link IAutomationsDateFilterConfig.availableGranularities}. + */ getGranularitiesForTab: (tabId: string) => DateFilterGranularity[]; + /** + * Date-filter options from the given dashboard tab's effective (resolved) date-filter + * configuration — inherited settings included, not only tab-specific overrides. Undefined when + * the tab has no effective configuration, in which case the caller falls back to + * {@link IAutomationsDateFilterConfig.dateFilterOptions}. + */ getOptionsForTab: (tabId: string) => IDateFilterOptionsByType | undefined; } @@ -70,37 +84,76 @@ export interface IAutomationsParameters { * @beta */ export interface IAutomationsContextValue { + /** Workspace locale for message formatting and number/date localization; from selectLocale. */ locale: ILocale; + /** Number formatting separators (decimal/thousands); from selectSeparators. */ separators: ISeparators; + /** Workspace/dashboard feature settings object; from selectSettings. */ settings?: ISettings; + /** Workspace attribute catalog, including computed attributes; from selectCatalogAttributesWithComputed. */ catalogAttributes: ICatalogAttribute[]; + /** Workspace date dataset catalog; from selectCatalogDateDatasets. */ catalogDateDatasets: ICatalogDateDataset[]; + /** Workspace measure catalog; from selectCatalogMeasures. */ catalogMeasures: ICatalogMeasure[]; + /** Date filter granularities and presets for automation date filter chips; see {@link IAutomationsDateFilterConfig}. */ dateFilterConfig: IAutomationsDateFilterConfig; + /** + * Persisted common date filter config for the active tab, used for its custom title; + * from selectPersistedDashboardFilterContextDateFilterConfig. + */ dateFilterContextConfig: IDashboardDateFilterConfig | undefined; + /** Dashboard-level attribute filter config overrides for the active tab; from selectAttributeFilterConfigsOverrides. */ attributeFilterConfigs: IDashboardAttributeFilterConfig[]; + /** Same as {@link IAutomationsContextValue.attributeFilterConfigs}, keyed by tab identifier; from selectAttributeFilterConfigsOverridesByTab. */ attributeFilterConfigsByTab: Record; + /** Attribute filter selection type (single/multi) by local identifier for the active tab; from selectAttributeFilterConfigsSelectionTypeMap. */ attributeFilterSelectionTypeMap: Map; + /** Same as {@link IAutomationsContextValue.attributeFilterSelectionTypeMap}, keyed by tab identifier; from selectAttributeFilterConfigsSelectionTypeMapByTab. */ attributeFilterSelectionTypeMapByTab: Record< string, Map >; + /** Per-dataset (dimension) date filter config overrides for the active tab; from selectDateFilterConfigsOverrides. */ dateFilterConfigs: IDashboardDateFilterConfigItem[]; + /** Same as {@link IAutomationsContextValue.dateFilterConfigs}, keyed by tab identifier; from selectDateFilterConfigsOverridesByTab. */ dateFilterConfigsByTab: Record; + /** Dashboard-level common (whole-dashboard) date filter config override, keyed by tab identifier; from selectDateFilterConfigOverridesByTab. */ dateFilterConfigOverridesByTab: Record; + /** Dashboard-level measure value filter config overrides for the active tab; from selectMeasureValueFilterConfigsOverrides. */ measureValueFilterConfigs: IDashboardMeasureValueFilterConfig[]; + /** Same as {@link IAutomationsContextValue.measureValueFilterConfigs}, keyed by tab identifier; from selectMeasureValueFilterConfigsOverridesByTab. */ measureValueFilterConfigsByTab: Record; + /** Local identifier of the dashboard's common date filter, when the automation-available filters include one; from selectAutomationCommonDateFilterId. */ commonDateFilterId: string | undefined; + /** Dashboard filters configured as read-only (locked); from selectDashboardLockedFilters. */ lockedFilters: FilterContextItem[]; + /** Dashboard filters configured as hidden; from selectDashboardHiddenFilters. */ hiddenFilters: FilterContextItem[]; + /** Dashboard's applied filters with cross-filtering filters removed; from selectDashboardFiltersWithoutCrossFiltering. */ availableFilters: FilterContextItem[]; + /** Automation-available filters structured per dashboard tab, for whole-dashboard automations on a tabbed dashboard; from selectAutomationFiltersByTab. */ automationFiltersByTab: IAutomationFiltersTab[]; + /** Automation-available filters with empty (all-values) filters removed; preselects filters for a new automation. From selectAutomationDefaultSelectedFilters. */ defaultSelectedFilters: FilterContextItem[]; + /** Dashboard filters available to an automation — hidden filters removed, common date filter included; from selectAutomationAvailableDashboardFilters. */ automationAvailableFilters: FilterContextItem[]; + /** + * Maximum number of recipients allowed on an automation, derived from the recipient-count + * entitlement (`Infinity` when the unlimited-recipients entitlement is present); from + * selectMaxAutomationRecipients. + */ maxAutomationsRecipients: number; + /** + * Whether the dashboard is opened at a past execution timestamp (a scheduled run's historical + * snapshot); disables create/save actions in the dialogs. Derived from selectExecutionTimestamp. + */ isExecutionTimestampMode: boolean; + /** Whether the workspace's minimum-recurrence entitlement permits hourly schedules; derived from selectEntitlementMinimumRecurrenceMinutes. */ allowHourlyRecurrence: boolean; + /** The logged-in user; from selectCurrentUser. */ currentUser: IUser; + /** The workspace's configured first day of the week; from selectWeekStart. */ weekStart: WeekStart; /** * Automation timezone to display and compute schedule ("Starts on", alert crons, next-run): @@ -142,18 +195,30 @@ export interface IAutomationsContextValue { */ scheduledExportTimezone: string | undefined; }; + /** Whether the dashboard is white-labeled (hides GoodData branding and help links); from selectIsWhiteLabeled. */ isWhiteLabeled: boolean; + /** Whether the dialog header renders a secondary title row below the main title; always true in the current hydration. */ isSecondaryTitleVisible: boolean; + /** External (non-workspace) recipient the dialog is scoped to, when opened via an external share link; from selectExternalRecipient. */ externalRecipient: string | undefined; + /** Feature flags and permissions gating automation dialog behavior. */ features: { + /** Whether the current user may create new automations; gates the management dialogs' create button. From selectCanCreateAutomation. */ canCreateAutomation: boolean; + /** Whether the "once per interval" alert trigger option is offered; from selectEnableAlertOncePerInterval. */ enableAlertOncePerInterval: boolean; + /** Whether anomaly-detection alert conditions are offered; from selectEnableAnomalyDetectionAlert. */ enableAnomalyDetectionAlert: boolean; + /** Whether the current user may use the AI assistant; combined with enableAnomalyDetectionAlert to gate anomaly-detection alert conditions. From selectCanUseAiAssistant. */ canUseAiAssistant: boolean; + /** Whether the current user may manage the workspace; from selectCanManageWorkspace. */ canManageWorkspace: boolean; + /** Whether scheduled slideshow (PDF slides) exports are offered; from selectEnableSlideshowExports. */ enableSlideshowExports: boolean; + /** Whether the automation evaluation-mode setting is enabled; from selectEnableAutomationEvaluationMode. */ enableAutomationEvaluationMode: boolean; }; + /** Workspace parameter catalog and effective dashboard parameter values for automations; see {@link IAutomationsParameters}. */ parameters: IAutomationsParameters; /** * Local identifiers of the dashboard's tabs, in layout order; empty when the dashboard has none. @@ -163,7 +228,13 @@ export interface IAutomationsContextValue { tabIds: string[]; /** Maps a widget's localIdentifier to the localIdentifier of the tab that owns it. */ widgetLocalIdToTabIdMap: Record; + /** Looks up a catalog attribute (or date attribute) by ref; backed by selectAllCatalogAttributesMap. Used to resolve attribute names for filter labels. */ getCatalogAttributeByRef: (ref: ObjRef) => ICatalogAttribute | ICatalogDateAttribute | undefined; + /** + * Looks up an attribute filter's display form by ref, preferring the dashboard's own attribute + * filter display forms before falling back to the workspace catalog; combines + * selectAttributeFilterDisplayFormsMap and selectAllCatalogDisplayFormsMap. + */ getAttributeFilterDisplayForm: (displayForm: ObjRef) => IAttributeDisplayFormMetadataObject | undefined; /** * Element ID to return focus to when the scheduled-email dialog closes. diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/contexts/ScheduledEmailDialogContext.ts b/libs/sdk-ui-dashboard/src/presentation/automations/contexts/ScheduledEmailDialogContext.ts index f16839f123e..15bce45c00c 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/contexts/ScheduledEmailDialogContext.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/contexts/ScheduledEmailDialogContext.ts @@ -26,10 +26,15 @@ import type { * @beta */ export interface IScheduledEmailDialogContextValue { + /** Widget the scheduled export targets; undefined when scheduling an export for a dashboard rather than a widget. */ widget?: IWidget; + /** Insight of {@link IScheduledEmailDialogContextValue.widget}; undefined when scheduling for a dashboard. */ insight?: IInsight; + /** Title of {@link IScheduledEmailDialogContextValue.widget}; undefined when scheduling for a dashboard. */ widgetTitle?: string; + /** Id of the dashboard the scheduled export belongs to. */ dashboardId?: string; + /** Dashboard title; used as the subject placeholder. */ dashboardTitle: string; /** * Dashboard filters the export will use: the saved filters when editing, otherwise the currently @@ -41,6 +46,7 @@ export interface IScheduledEmailDialogContextValue { * getAppliedDashboardFilters/getAppliedWidgetFilters inside the dialog, mirroring the alerting context. */ hiddenFilters: FilterContextItem[]; + /** Local identifier of the dashboard's common (dashboard-level) date filter, when the automation-available filters include one. */ commonDateFilterId?: string; /** * Effective export parameter overrides keyed by tab, scoped to the dialog's widget when present. @@ -63,8 +69,11 @@ export interface IScheduledEmailDialogContextValue { /** Effective mode map for attribute filters (localIdentifier → mode). */ attributeFiltersModeMap: Map; // CRUD — observer-hook semantics preserved by the dialog; these are the backend calls. + /** Creates a new scheduled export on the backend. */ createScheduledEmail(se: IAutomationMetadataObjectDefinition): Promise; + /** Saves changes to an existing scheduled export on the backend. */ saveScheduledEmail(se: IAutomationMetadataObject): Promise; + /** Deletes the scheduled export from the backend. */ deleteScheduledEmail(se: IAutomationMetadataObject): Promise; /** The scheduled export being edited; undefined when creating a new one. */ scheduledExportToEdit?: IAutomationMetadataObject; diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/contexts/ScheduledEmailManagementDialogContext.ts b/libs/sdk-ui-dashboard/src/presentation/automations/contexts/ScheduledEmailManagementDialogContext.ts index a189625ce42..69015df3960 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/contexts/ScheduledEmailManagementDialogContext.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/contexts/ScheduledEmailManagementDialogContext.ts @@ -21,8 +21,9 @@ export interface IScheduledEmailManagementDialogContextValue { */ isScheduleEmailDialogOpen: boolean; /** - * Monotonic counter that increments whenever the automation list is invalidated. - * Consumers can use this as a cache-bust key for re-fetching. + * Cache-bust counter for the automation list: reset to 0 when a management dialog opens, + * incremented on invalidation. 0 means nothing has been invalidated since the dialog opened; + * consumers reload when the value changes and is not 0. */ automationsInvalidationId?: number; /** diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailManagementDialog/DefaultScheduledEmailManagementDialog.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailManagementDialog/DefaultScheduledEmailManagementDialog.tsx index 561d1242189..2bb4991a576 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailManagementDialog/DefaultScheduledEmailManagementDialog.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailManagementDialog/DefaultScheduledEmailManagementDialog.tsx @@ -9,6 +9,9 @@ import { type IScheduledEmailManagementDialogProps } from "../types.js"; import { DefaultScheduledEmailManagementDialogContent } from "./DefaultScheduledEmailManagementDialogContent.js"; /** + * Default implementation of the scheduled-email management dialog: the list of the dashboard's + * scheduled exports, with actions to add, edit, or delete one. + * * @beta */ export function ScheduledEmailManagementDialog({ diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportDialogState.shape.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportDialogState.shape.test.tsx index 3c04019d3eb..ea0ab40278c 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportDialogState.shape.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportDialogState.shape.test.tsx @@ -14,7 +14,6 @@ import { } from "@gooddata/sdk-model"; import type { IAutomationFiltersTab } from "../../../../model/store/filtering/types.js"; -import type * as AutomationFiltersSelectModule from "../../shared/automationFilters/useAutomationFiltersSelect.js"; // --------------------------------------------------------------------------- // Mocks — vi.mock calls are hoisted; factories must not reference top-level @@ -47,8 +46,8 @@ vi.hoisted(() => { vi.resetModules(); }); -vi.mock("../../shared/automationFilters/useAutomationFiltersSelect.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock(import("../../shared/automationFilters/useAutomationFiltersSelect.js"), async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, useAutomationFiltersSelect: mockUseAutomationFiltersSelect }; }); diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/types.ts b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/types.ts index de44f492313..ba7b8770b50 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/types.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/types.ts @@ -41,6 +41,11 @@ import { /// /** + * Props of the scheduled-email create/edit dialog, accepted by `ScheduledEmailDialogComponent`. + * + * Extends {@link IAutomationDialogCallbacks} with data props that are all deprecated — the dialog + * reads its data from `useScheduledEmailDialogContext()` instead. + * * @beta */ export interface IScheduledEmailDialogProps extends IAutomationDialogCallbacks { @@ -769,6 +774,10 @@ export interface IScheduledEmailDialogShellProps extends Pick< } /** + * Props of the scheduled-email management dialog, accepted by `ScheduledEmailManagementDialogComponent`. + * + * Extends {@link IAutomationManagementDialogCallbacks} with data props that are all deprecated — + * the dialog reads its data from `useScheduledEmailManagementDialogContext()` instead. * * @beta */ @@ -809,6 +818,9 @@ export interface IScheduledEmailManagementDialogProps extends IAutomationManagem /// /** + * Type of a replacement for the scheduled-email create/edit dialog — the shape expected by the + * `ScheduledEmailDialogComponent` dashboard prop. + * * @beta */ export type CustomScheduledEmailDialogComponent = ComponentType; @@ -855,6 +867,9 @@ export type CustomScheduledEmailDialogContextDecoratorComponent = ComponentType< }>; /** + * Type of a replacement for the scheduled-email management dialog — the shape expected by the + * `ScheduledEmailManagementDialogComponent` dashboard prop. + * * @beta */ export type CustomScheduledEmailManagementDialogComponent = diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/components/AutomationFiltersSelect.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/components/AutomationFiltersSelect.tsx index 789ef5ba586..0927eb6e7e9 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/components/AutomationFiltersSelect.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/components/AutomationFiltersSelect.tsx @@ -204,7 +204,6 @@ function AutomationCheckboxOrNote({ arrowPlacement="left" triggerBy={["hover", "focus"]} optimalPlacement - width={300} content={useFiltersTooltip} anchor={ ; } +function InsightNotSavedDialogWrapper() { + return ; +} + function TopBarWrapper() { const topBarProps = useTopBarProps(); return ; @@ -107,6 +112,7 @@ export function DashboardHeader(): ReactElement { + diff --git a/libs/sdk-ui-dashboard/src/presentation/dashboardSettingsDialog/DefaultDashboardSettingsDialog.tsx b/libs/sdk-ui-dashboard/src/presentation/dashboardSettingsDialog/DefaultDashboardSettingsDialog.tsx index 5612ca16b18..cc0fc8b628e 100644 --- a/libs/sdk-ui-dashboard/src/presentation/dashboardSettingsDialog/DefaultDashboardSettingsDialog.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/dashboardSettingsDialog/DefaultDashboardSettingsDialog.tsx @@ -46,6 +46,9 @@ import { TimezoneOption } from "./TimezoneOption.js"; import { type IDashboardSettingsDialogProps } from "./types.js"; import { useDialogData } from "./useDialogData.js"; +const DASHBOARD_TIMEZONE_DOC_LINK = + "https://www.gooddata.ai/docs/cloud/customize-appearance/manage-timezones/#change-the-time-zone-on-a-dashboard"; + /** * @alpha */ @@ -269,9 +272,24 @@ export function DefaultDashboardSettingsDialog({ label={intl.formatMessage({ id: "settingsDashboardDialog.section.timezone.defaultTimezone", })} - tooltip={intl.formatMessage({ - id: "settingsDashboardDialog.section.timezone.defaultTimezone.tooltip", - })} + tooltip={ + + isWhiteLabeled ? null : ( + + {chunks} + + ), + }} + /> + } timezoneConfig={currentData.timezoneConfig} onChange={(timezoneId: string | undefined) => { setCurrentData({ diff --git a/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditor.tsx b/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditor.tsx index 8b2ca22df6c..8716f48fb3a 100644 --- a/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditor.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditor.tsx @@ -4,7 +4,7 @@ import { type ReactElement, useCallback, useMemo, useState } from "react"; import { HighlightStyle, StreamLanguage, type StringStream, syntaxHighlighting } from "@codemirror/language"; import { Tag } from "@lezer/highlight"; -import { compact, uniqBy } from "lodash-es"; +import { compact, escapeRegExp, uniqBy } from "lodash-es"; import { FormattedMessage, type IntlShape, useIntl } from "react-intl"; import { @@ -12,11 +12,9 @@ import { type IDashboardAttributeFilterConfig, type IDashboardMeasureValueFilter, type IMeasureValueFilter, - type IdentifierRef, type ObjRef, dashboardAttributeFilterItemToAttributeFilter, filterObjRef, - idRef, insightFilters as insightDefinitionFilters, isArbitraryAttributeFilter, isAttributeFilter, @@ -27,6 +25,12 @@ import { objRefToString, serializeObjRef, } from "@gooddata/sdk-model"; +import { + attributeIdentifierToPlaceholder, + dashboardAttributeFilterToPlaceholder, + displayFormPlaceholderRef, + insightAttributeFilterToPlaceholder, +} from "@gooddata/sdk-model/internal"; import { ConfirmDialogBase, FullScreenOverlay, @@ -167,7 +171,9 @@ const buildValidDisplayFormsFormattingRule = (attributeDisplayForms: IAttributeW return undefined; } const validAttributePlaceholders = attributeDisplayForms - .map(({ displayForm }) => `{attribute_title\\(${displayForm.id}\\)}`) + .map(({ displayForm }) => + escapeRegExp(attributeIdentifierToPlaceholder(displayFormPlaceholderRef(displayForm))), + ) .join("|"); return { regex: new RegExp(`^${validAttributePlaceholders}`), token: customTags.attribute.toString() }; }; @@ -178,12 +184,11 @@ const buildValidInsightFiltersFormattingRule = (attributeFilters: IAttributeFilt } const validInsightAttributeFilterPlaceholders = attributeFilters - .map((filter) => { - // these filters always come from useSanitizedInsightFilters, which rewrites the display form - // ref to idRef(displayForm.id, "displayForm") or drops the filter -> never a uri ref here - const { identifier } = filterObjRef(filter) as IdentifierRef; - return `{attribute_filter_selection\\(${identifier}\\)}`; - }) + .map((filter) => + // these filters always come from useSanitizedInsightFilters, which rewrites the display + // form ref to the canonical placeholder ref or drops the filter -> never a uri ref here + escapeRegExp(insightAttributeFilterToPlaceholder(filterObjRef(filter))), + ) .join("|"); return { regex: new RegExp(`^${validInsightAttributeFilterPlaceholders}`), @@ -199,17 +204,13 @@ const buildValidDashboardFiltersFormattingRule = ( return undefined; } - const filterPlaceholders = attributeFilters.map((filter) => { - const ref = filterObjRef(filter); - const id = objRefToString(ref); - return `{dash_attribute_filter_selection\\(${id}\\)}`; - }); + const filterPlaceholders = attributeFilters.map((filter) => + escapeRegExp(dashboardAttributeFilterToPlaceholder(filterObjRef(filter))), + ); const configPlaceholders = attributeFilterConfigs - .filter((config) => !!config.displayAsLabel) - .map((config) => { - const id = !!config.displayAsLabel && objRefToString(config.displayAsLabel); - return `{dash_attribute_filter_selection\\(${id}\\)}`; - }); + .map((config) => config.displayAsLabel) + .filter((displayAsLabel): displayAsLabel is ObjRef => !!displayAsLabel) + .map((displayAsLabel) => escapeRegExp(dashboardAttributeFilterToPlaceholder(displayAsLabel))); const validDashboardAttributeFilterPlaceholders = [...filterPlaceholders, ...configPlaceholders].join( "|", @@ -635,7 +636,7 @@ function useSanitizeAttributeFilter() { ...filter, negativeAttributeFilter: { ...filter.negativeAttributeFilter, - displayForm: idRef(displayForm.id, "displayForm"), + displayForm: displayFormPlaceholderRef(displayForm), }, }; } else if (isPositiveAttributeFilter(filter)) { @@ -643,7 +644,7 @@ function useSanitizeAttributeFilter() { ...filter, positiveAttributeFilter: { ...filter.positiveAttributeFilter, - displayForm: idRef(displayForm.id, "displayForm"), + displayForm: displayFormPlaceholderRef(displayForm), }, }; } else if (isArbitraryAttributeFilter(filter)) { @@ -651,7 +652,7 @@ function useSanitizeAttributeFilter() { ...filter, arbitraryAttributeFilter: { ...filter.arbitraryAttributeFilter, - label: idRef(displayForm.id, "displayForm"), + label: displayFormPlaceholderRef(displayForm), }, }; } else if (isMatchAttributeFilter(filter)) { @@ -659,7 +660,7 @@ function useSanitizeAttributeFilter() { ...filter, matchAttributeFilter: { ...filter.matchAttributeFilter, - label: idRef(displayForm.id, "displayForm"), + label: displayFormPlaceholderRef(displayForm), }, }; } diff --git a/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/DashboardParametersSection.tsx b/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/DashboardParametersSection.tsx index 0bbef51a7a5..fafa172ab69 100644 --- a/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/DashboardParametersSection.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/DashboardParametersSection.tsx @@ -12,6 +12,7 @@ import { filterObjRef, objRefToString, } from "@gooddata/sdk-model"; +import { dashboardAttributeFilterToPlaceholder } from "@gooddata/sdk-model/internal"; import { MeasureValueFilterDetailsBubble } from "@gooddata/sdk-ui-filters/internal"; import { useDashboardSelector } from "../../../../../model/react/DashboardStoreProvider.js"; @@ -72,7 +73,7 @@ export function DashboardParametersSection({ item={df} iconClassName="gd-icon-filter" onAdd={() => { - onAdd(`{dash_attribute_filter_selection(${filterIdentifier})}`); + onAdd(dashboardAttributeFilterToPlaceholder(df.ref)); }} isFilter /> @@ -82,7 +83,7 @@ export function DashboardParametersSection({ item={secondaryDf} iconClassName="gd-icon-filter" onAdd={() => { - onAdd(`{dash_attribute_filter_selection(${filterSecondaryIdentifier})}`); + onAdd(dashboardAttributeFilterToPlaceholder(secondaryDf.ref)); }} isFilter /> diff --git a/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/DisplayFormParam.tsx b/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/DisplayFormParam.tsx index 64bf54f83d3..0fa982bc122 100644 --- a/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/DisplayFormParam.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/DisplayFormParam.tsx @@ -7,6 +7,7 @@ import { type IAttributeDisplayFormMetadataObject, dashboardAttributeFilterItemTitle, } from "@gooddata/sdk-model"; +import { attributeIdentifierToPlaceholder, displayFormPlaceholderRef } from "@gooddata/sdk-model/internal"; import { useWorkspaceStrict } from "@gooddata/sdk-ui"; import { useDashboardSelector } from "../../../../../model/react/DashboardStoreProvider.js"; @@ -52,7 +53,7 @@ export function DisplayFormParam({ item, onAdd, iconClassName, isFilter }: IXPro iconClassName={ iconClassName ?? getDisplayFormIcon(item.displayFormType as AttributeDisplayFormType) } - onAdd={() => onAdd(`{attribute_title(${item.id})}`)} + onAdd={() => onAdd(attributeIdentifierToPlaceholder(displayFormPlaceholderRef(item)))} intl={intl} /> ); diff --git a/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/InsightParametersSection.tsx b/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/InsightParametersSection.tsx index 0c2438b018c..0e7fe0bebb5 100644 --- a/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/InsightParametersSection.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/InsightParametersSection.tsx @@ -18,6 +18,7 @@ import { measureTitle, objRefToString, } from "@gooddata/sdk-model"; +import { insightAttributeFilterToPlaceholder } from "@gooddata/sdk-model/internal"; import { MeasureValueFilterDetailsBubble } from "@gooddata/sdk-ui-filters/internal"; import { useDashboardSelector } from "../../../../../model/react/DashboardStoreProvider.js"; @@ -85,7 +86,7 @@ export function InsightParametersSection({ df && ( onAdd(`{attribute_filter_selection(${df.id})}`)} + onAdd={() => onAdd(insightAttributeFilterToPlaceholder(df.ref))} iconClassName="gd-icon-filter" key={index} isFilter diff --git a/libs/sdk-ui-dashboard/src/presentation/drill/utils/drillToCustomUrlUtils.ts b/libs/sdk-ui-dashboard/src/presentation/drill/utils/drillToCustomUrlUtils.ts index aacc94b5e56..48b48802710 100644 --- a/libs/sdk-ui-dashboard/src/presentation/drill/utils/drillToCustomUrlUtils.ts +++ b/libs/sdk-ui-dashboard/src/presentation/drill/utils/drillToCustomUrlUtils.ts @@ -5,7 +5,10 @@ import { type IDrillToCustomUrl, areObjRefsEqual, } from "@gooddata/sdk-model"; -import { getAttributeIdentifiersPlaceholdersFromUrl } from "@gooddata/sdk-model/internal"; +import { + displayFormPlaceholderRef, + getAttributeIdentifiersPlaceholdersFromUrl, +} from "@gooddata/sdk-model/internal"; import { type IDrillEvent, isDrillIntersectionAttributeItem } from "@gooddata/sdk-ui"; /** @@ -38,8 +41,10 @@ export function getDrillToCustomUrlMissingAttributes( for (const placeholder of attributePlaceholders) { const displayForm = displayFormsMap[placeholder.identifier]; - // Configuration error handled elsewhere - if (!displayForm) { + // Configuration error handled elsewhere. The map is keyed by bare identifier, which a computed + // attribute can share with a label, so the kind of object is checked too rather than reporting + // whichever of the two happens to be in the map. + if (!displayForm || !areObjRefsEqual(displayFormPlaceholderRef(displayForm), placeholder.ref)) { continue; } diff --git a/libs/sdk-ui-dashboard/src/presentation/filterBar/filterBar/DefaultFilterBar.tsx b/libs/sdk-ui-dashboard/src/presentation/filterBar/filterBar/DefaultFilterBar.tsx index 072c8ae0391..e6ab3bcf87a 100644 --- a/libs/sdk-ui-dashboard/src/presentation/filterBar/filterBar/DefaultFilterBar.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/filterBar/filterBar/DefaultFilterBar.tsx @@ -36,11 +36,13 @@ import { changeWorkingAttributeFilterSelection, changeWorkingMeasureValueFilterCondition, clearDateFilterSelection, + removeRestrictedFilters, replaceAttributeFilterItemSelection, replaceWorkingAttributeFilterItemSelection, setAttributeFilterDisplayForm, } from "../../../model/commands/filters.js"; import { useDashboardDispatch, useDashboardSelector } from "../../../model/react/DashboardStoreProvider.js"; +import { useDispatchDashboardCommand } from "../../../model/react/useDispatchDashboardCommand.js"; import { selectSupportsElementUris } from "../../../model/store/backendCapabilities/backendCapabilitiesSelectors.js"; import { selectEnableDashboardFilterGroups, @@ -360,6 +362,11 @@ export function DefaultFilterBar(props: IFilterBarProps): ReactElement { const { DashboardDateFilterComponentProvider, RestrictedFiltersPlaceholderComponentProvider } = useDashboardComponentsContext(); const restrictedFilterCount = useDashboardSelector(selectRestrictedDashboardFilterCount); + const dispatchRemoveRestrictedFilters = useDispatchDashboardCommand(removeRestrictedFilters); + const removeRestrictedFiltersFromDashboard = useCallback( + () => dispatchRemoveRestrictedFilters(), + [dispatchRemoveRestrictedFilters], + ); const canAddMoreFilters = useDashboardSelector(selectCanAddMoreFilters); const haveAllFiltersHidden = areAllFiltersHidden( draggableFiltersWithPlaceholder, @@ -396,7 +403,10 @@ export function DefaultFilterBar(props: IFilterBarProps): ReactElement { return ( {restrictedFilterCount > 0 ? ( - + ) : null}
void) { return render( - + , ); } @@ -26,6 +26,54 @@ describe("RestrictedFiltersPlaceholder", () => { expect(screen.getByText("3 filters weren't applied")).toBeInTheDocument(); }); + it("reaches the remove action by keyboard alone", async () => { + const onRemove = vi.fn(); + renderPlaceholder(1, onRemove); + const user = userEvent.setup(); + + await user.tab(); + await user.keyboard("{Enter}"); + + expect(screen.getByRole("button", { name: "Remove restricted filters" })).toHaveFocus(); + + await user.keyboard("{Enter}"); + + expect(onRemove).toHaveBeenCalledTimes(1); + }); + + it("hands the focus to the next control before it disappears", async () => { + const onRemove = vi.fn(); + render( + + + + , + ); + const user = userEvent.setup(); + + await user.tab(); + await user.keyboard("{Enter}"); + await user.keyboard("{Enter}"); + + expect(onRemove).toHaveBeenCalledTimes(1); + expect(screen.getByRole("button", { name: "Date filter" })).toHaveFocus(); + }); + + it("becomes a dialog only when the action is asked for, and lets the keyboard leave again", async () => { + renderPlaceholder(1, vi.fn()); + const user = userEvent.setup(); + + await user.tab(); + expect(screen.getByRole("tooltip")).toBeInTheDocument(); + + await user.keyboard("{Enter}"); + expect(screen.getByRole("dialog", { name: "1 filter wasn't applied" })).toBeInTheDocument(); + + await user.tab(); + expect(screen.queryByRole("dialog")).not.toBeInTheDocument(); + expect(screen.getByTestId("restricted-filters")).toHaveFocus(); + }); + it("gives the reason on focus, so it is reachable without a pointer", async () => { renderPlaceholder(2); diff --git a/libs/sdk-ui-dashboard/src/presentation/filterBar/filterBar/RestrictedFiltersPlaceholder.tsx b/libs/sdk-ui-dashboard/src/presentation/filterBar/filterBar/RestrictedFiltersPlaceholder.tsx index d3f7425c1a2..f32e3543d00 100644 --- a/libs/sdk-ui-dashboard/src/presentation/filterBar/filterBar/RestrictedFiltersPlaceholder.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/filterBar/filterBar/RestrictedFiltersPlaceholder.tsx @@ -1,8 +1,10 @@ // (C) 2026 GoodData Corporation +import { type ReactNode, useRef, useState } from "react"; + import { FormattedMessage, useIntl } from "react-intl"; -import { UiTooltip } from "@gooddata/sdk-ui-kit"; +import { UiButton, UiFocusManager, UiTooltip, getFocusableElements } from "@gooddata/sdk-ui-kit"; /** * Props of the component reporting the dashboard filters that could not be applied. @@ -12,31 +14,116 @@ import { UiTooltip } from "@gooddata/sdk-ui-kit"; export interface IRestrictedFiltersPlaceholderProps { /** How many filters were left out of the dashboard. */ count: number; + + /** Removes the filters from the dashboard for good; absent unless the dashboard is being edited. */ + onRemove?: () => void; } /** * Reports filters left out because the current user may not read the objects they filter by. */ -export function RestrictedFiltersPlaceholder({ count }: IRestrictedFiltersPlaceholderProps) { +export function RestrictedFiltersPlaceholder({ count, onRemove }: IRestrictedFiltersPlaceholderProps) { const intl = useIntl(); + const wrapperRef = useRef(null); + // hovering must not steal the focus, so only a deliberate open moves it into the tooltip + const [isOpenedForAction, setIsOpenedForAction] = useState(false); + + const openForAction = () => setIsOpenedForAction(true); + + const withFocusInside = (content: ReactNode, onClose: () => void) => + isOpenedForAction ? ( + { + setIsOpenedForAction(false); + onClose(); + }} + > + {content} + + ) : ( + content + ); + + // the notice goes away with the filters it reports, so the focus has to move out of it first + const focusNextControl = () => { + const wrapper = wrapperRef.current; + const { focusableElements } = getFocusableElements(wrapper?.parentElement); + focusableElements.find((element) => !wrapper?.contains(element))?.focus(); + }; + + const noticeText = intl.formatMessage({ id: "filterBar.restrictedFilters" }, { count }); + + const notice = ( + <> + + {noticeText} + + ); return ( - // the filter bar counts its rows by measuring its direct children, so the tooltip's own - // wrapper and its screen-reader copy have to sit inside a single one of them - + // the bar counts its rows by measuring its direct children, so keep the tooltip's own + // elements inside one of them + { + if (!open) { + setIsOpenedForAction(false); + } + }} + content={({ onClose, type }) => { + const reason = ( + + ); + if (type === "screen-reader") { + return reason; + } + + return withFocusInside( +
+ {reason} + {onRemove ? ( + { + focusNextControl(); + onClose(); + onRemove(); + }} + /> + ) : null} +
, + onClose, + ); + }} anchor={ - // focusable so the reason is reachable without a pointer; it opens nothing - - - - + onRemove ? ( + + ) : ( + + {notice} + + ) } /> diff --git a/libs/sdk-ui-dashboard/src/presentation/insightNotSavedDialog/InsightNotSavedDialog.tsx b/libs/sdk-ui-dashboard/src/presentation/insightNotSavedDialog/InsightNotSavedDialog.tsx new file mode 100644 index 00000000000..65db704f950 --- /dev/null +++ b/libs/sdk-ui-dashboard/src/presentation/insightNotSavedDialog/InsightNotSavedDialog.tsx @@ -0,0 +1,72 @@ +// (C) 2026 GoodData Corporation + +import { useCallback, useState } from "react"; + +import { useIntl } from "react-intl"; + +import { ConfirmDialog, Typography, UiButton, UiIcon } from "@gooddata/sdk-ui-kit"; + +import { useDashboardDispatch, useDashboardSelector } from "../../model/react/DashboardStoreProvider.js"; +import { selectDraftInsightsUsedOnDashboard } from "../../model/store/insights/insightsSelectors.js"; +import { uiActions } from "../../model/store/ui/index.js"; +import { selectIsInsightNotSavedDialogOpen } from "../../model/store/ui/uiSelectors.js"; + +/** + * @internal + */ +export function InsightNotSavedDialog() { + const intl = useIntl(); + const dispatch = useDashboardDispatch(); + const [showVisualisationsList, setShowVisualisationsList] = useState(true); + + const isInsightNotSavedDialogOpen = useDashboardSelector(selectIsInsightNotSavedDialogOpen); + const submitDialog = useCallback(() => { + dispatch(uiActions.confirmInsightNotSavedDialogSubmit()); + }, [dispatch]); + const closeDialog = useCallback(() => dispatch(uiActions.closeInsightNotSavedDialog()), [dispatch]); + + const unsavedInsights = useDashboardSelector(selectDraftInsightsUsedOnDashboard); + + if (!isInsightNotSavedDialogOpen) { + return null; + } + + return ( + +
+ + {intl.formatMessage({ id: "insightNotSavedDialog.message" })} + + setShowVisualisationsList(!showVisualisationsList)} + /> + {showVisualisationsList ? ( +
    + {unsavedInsights.map((insight) => ( +
  • + {insight.insight.title} +
  • + ))} +
+ ) : null} +
+
+ ); +} diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/de-DE.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/de-DE.json index 07f946e637b..a20030cdf1f 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/de-DE.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/de-DE.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Ihre Testversion ist abgelaufen.", + "dashboard.contractExpired.trial.description": "Wenn Sie GoodData Cloud weiterhin nutzen möchten, kontaktieren Sie uns bitte.", + "dashboard.contractExpired.nonTrial.title": "Ihr Zugriff ist gesperrt.", + "dashboard.contractExpired.nonTrial.description": "Wenden Sie sich an den Kontoadministrator, um wieder Zugriff zu erhalten.", + "dashboard.contractExpired.buttonTitle": "Kontakt", "loading": "Lädt…", "untitled": "Unbenannt", "empty_value": "leerer Wert", + "deleted_value": "gelöschter Wert", "gs.list.cancel": "Abbrechen", "gs.list.apply": "Anwenden", "gs.list.only": "Nur", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Interaktion konfiguriert.", "messages.drill.InteractionUpdatedSuccess": "Interaktion aktualisiert.", "filterBar.label": "Filter", + "filterBar.restrictedFilters.remove": "Eingeschränkte Filter entfernen", + "filterBar.restrictedFilters.reason": "{count, plural, one {Sie haben keinen Zugriff auf # Filter.} other {Sie haben keinen Zugriff auf # Filter.}}", + "filterBar.restrictedFilters": "{count, plural, one {# Filter wurde nicht angewendet} other {# Filter wurden nicht angewendet}}", "filterBar.showAll": "Alle anzeigen", "filterBar.showLess": "Weniger anzeigen", "filterBar.filterListAutoExpanded": "Filterliste wurde automatisch eingeblendet", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "Geplante Exporte", "deleteWidgetDialog.headline": "Widget entfernen?", "deleteWidgetDialog.objectsMessage": "Die folgenden Objekttypen, die mit dem Widget {title} verbunden sind, werden nicht mehr funktionieren:", + "deleteWidgetDialog.objectsMessage.restricted": "Die folgenden mit dem Element verknüpften Objekttypen funktionieren nicht mehr:", "deleteWidgetDialog.alerts": "Warnungen", "deleteWidgetDialog.schedules": "Geplante Exporte", "create.dashboard": "Dashboard erstellen", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} kann nicht nach {parentTitle} gefiltert werden. Es besteht keine Verbindung zwischen den Filterattributen und dem Datenmodell.", "attributesDropdown.details.dataset": "Dataset", "attributesDropdown.details.values": "Werte", + "attributesDropdown.details.definedAs": "Definiert als", "attributesDropdown.details.shortening_decoration": "…und {count} weitere", "layout.header.characters.left": "Noch {currentCharactersCount}/{maximumCharactersCount} Zeichen", "layout.header.add.title.placeholder": "Titel hier hinzufügen...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "Die Visualisierung kann nicht nach {attributeName} gefiltert werden. Markierung des Kontrollfelds entfernen.", "configurationPanel.kpiCantBeFilteredByAttribute": " Leistungskennzahl kann nicht nach {attributeName} gefiltert werden. Markierung des Kontrollfelds entfernen.", "configurationPanel.vizCantBeFilteredByDate": "Die Visualisierung kann nicht nach Datum gefiltert werden. Markierung des Kontrollfelds entfernen.", + "configurationPanel.dateDatasetsLoadFailed": "Zugehörige Datumsdaten konnten nicht geladen werden. Schließen Sie den Konfigurationsbereich und versuchen Sie es erneut.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Filtern ist auf diese Visualisierung nicht anwendbar.", "configurationPanel.mvfBlockedByRankingFilter": "Dieser Filter kann nicht angewendet werden, weil die Visualisierung einen Top-/Bottom-Werte-Filter verwendet. Entfernen Sie den Top-/Bottom-Werte-Filter, um diesen Filter anzuwenden.", "configurationPanel.mvfMissingMeasure": "Die in diesem Filter verwendete Metrik existiert im workspace nicht mehr.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "In die Visualisierung bohren", "configurationPanel.drillConfig.drillDown": "Nach unten verfeinern", "configurationPanel.drillConfig.disableDrillDownTooltip": "Drilldown ist in der Konfiguration dieser Visualisierung deaktiviert.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "In Details gehen ist für berechnete Attribute nicht verfügbar.", "configurationPanel.drillConfig.drillIntoUrl": "URL-Ansicht verfeinern", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Ungültige URL-Parameter", "configurationPanel.drillConfig.select": "Befehl auswählen…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Rich Text löschen?", "richText.deleteDialog.message": "Der Rich Text und sein gesamter Inhalt werden unwiderruflich gelöscht.", "richText.emptyContent": "Kein Rich-Text-Inhalt", + "visualizationSwitcher.restrictedEntry": "Eingeschränkt", "visualizationSwitcher.emptyContent": "Keine Visualisierung im Switcher", "visualizationSwitcherToolbar.visualizationsList.header": "Visualisierungen", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Visualisierungen", @@ -809,6 +823,7 @@ "granularity.hour": "Stunde", "granularity.minute": "Minute", "widget.options.menu.export": "Exportieren", + "insightMenu.restrictedWidget.options": "Optionen für Visualisierung mit eingeschränktem Zugriff", "menu.close": "Menü schließen", "controlButtons.asTable": "Als Tabelle anzeigen", "controlButtons.asOriginal": "Originalvisualisierung anzeigen", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/en-AU.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/en-AU.json index b50367c2d08..f6d140403e2 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/en-AU.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/en-AU.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Your trial has ended.", + "dashboard.contractExpired.trial.description": "Contact us if you would like to continue using GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "Your access is locked.", + "dashboard.contractExpired.nonTrial.description": "Contact the account administrator to regain access.", + "dashboard.contractExpired.buttonTitle": "Contact us", "loading": "Loading…", "untitled": "Untitled", "empty_value": "empty value", + "deleted_value": "deleted value", "gs.list.cancel": "Cancel", "gs.list.apply": "Apply", "gs.list.only": "Only", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Setup sorted.", "messages.drill.InteractionUpdatedSuccess": "Interaction updated.", "filterBar.label": "Filters", + "filterBar.restrictedFilters.remove": "Remove access-restricted filters", + "filterBar.restrictedFilters.reason": "{count, plural, one {You do not have access to # filter.} other {You do not have access to # filters.}}", + "filterBar.restrictedFilters": "{count, plural, one {# filter was not applied} other {# filters were not applied}}", "filterBar.showAll": "Display all", "filterBar.showLess": "Show less", "filterBar.filterListAutoExpanded": "Filter list has been automatically expanded", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "scheduled exports", "deleteWidgetDialog.headline": "Remove widget?", "deleteWidgetDialog.objectsMessage": "The following types of objects associated with the widget {title} will no longer function:", + "deleteWidgetDialog.objectsMessage.restricted": "The following types of objects associated with the widget will no longer function:", "deleteWidgetDialog.alerts": "alerts", "deleteWidgetDialog.schedules": "scheduled exports", "create.dashboard": "Create Dashboard", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} can't be filtered by {parentTitle}. There's no connection between the filter attributes in the data model.", "attributesDropdown.details.dataset": "Dataset", "attributesDropdown.details.values": "Values", + "attributesDropdown.details.definedAs": "Defined as", "attributesDropdown.details.shortening_decoration": "...and {count} more", "layout.header.characters.left": "{currentCharactersCount} / {maximumCharactersCount} characters left", "layout.header.add.title.placeholder": "Add Title here...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "The visualisation cannot be filtered by {attributeName}. Unselect the check box.", "configurationPanel.kpiCantBeFilteredByAttribute": "The kpi cannot be filtered by {attributeName}. Unselect the check box.", "configurationPanel.vizCantBeFilteredByDate": "The visualization cannot be filtered by Date. Unselect the check box.", + "configurationPanel.dateDatasetsLoadFailed": "Related date data could not be loaded. Close the configuration panel and try again.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Filter is not applicable to this visualisation.", "configurationPanel.mvfBlockedByRankingFilter": "This filter can't be applied because the visualisation uses a Top/bottom values filter. Remove the Top/bottom values filter to apply this filter.", "configurationPanel.mvfMissingMeasure": "The metric used in this filter no longer exists in the workspace.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Drill into visualisation", "configurationPanel.drillConfig.drillDown": "Drill down", "configurationPanel.drillConfig.disableDrillDownTooltip": "Drill down is turned off in this visualisation's configuration.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Drill down is not available for computed attributes.", "configurationPanel.drillConfig.drillIntoUrl": "Drill into URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Invalid URL parameters", "configurationPanel.drillConfig.select": "Select action…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Delete rich text?", "richText.deleteDialog.message": "The rich text and all of its content will be permanently deleted.", "richText.emptyContent": "No rich text content", + "visualizationSwitcher.restrictedEntry": "Restricted", "visualizationSwitcher.emptyContent": "No visualisation in switcher", "visualizationSwitcherToolbar.visualizationsList.header": "Visualisations", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Visualisations", @@ -809,6 +823,7 @@ "granularity.hour": "hour", "granularity.minute": "minute", "widget.options.menu.export": "Export", + "insightMenu.restrictedWidget.options": "Restricted visualisation options", "menu.close": "Close menu", "controlButtons.asTable": "Display as table", "controlButtons.asOriginal": "Show original visualisation", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/en-GB.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/en-GB.json index 1501654bc25..6c67c58f9d2 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/en-GB.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/en-GB.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Your trial has ended.", + "dashboard.contractExpired.trial.description": "Contact us if you would like to continue using GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "Your access is locked.", + "dashboard.contractExpired.nonTrial.description": "Contact the account administrator to regain access.", + "dashboard.contractExpired.buttonTitle": "Contact us", "loading": "Loading…", "untitled": "Untitled", "empty_value": "empty value", + "deleted_value": "deleted value", "gs.list.cancel": "Cancel", "gs.list.apply": "Apply", "gs.list.only": "Only", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Interaction configured.", "messages.drill.InteractionUpdatedSuccess": "Interaction updated.", "filterBar.label": "Filters", + "filterBar.restrictedFilters.remove": "Remove restricted filters", + "filterBar.restrictedFilters.reason": "{count, plural, one {You do not have access to # filter.} other {You do not have access to # filters.}}", + "filterBar.restrictedFilters": "{count, plural, one {# filter was not applied} other {# filters were not applied}}", "filterBar.showAll": "Show all", "filterBar.showLess": "Show less", "filterBar.filterListAutoExpanded": "Filter list has been automatically expanded", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "scheduled exports", "deleteWidgetDialog.headline": "Remove widget?", "deleteWidgetDialog.objectsMessage": "The following types of objects associated with the widget {title} will no longer function:", + "deleteWidgetDialog.objectsMessage.restricted": "The following types of objects associated with the widget will no longer function:", "deleteWidgetDialog.alerts": "alerts", "deleteWidgetDialog.schedules": "scheduled exports", "create.dashboard": "Create dashboard", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} cannot be filtered by {parentTitle}. There is no connection between the filter attributes in the data model.", "attributesDropdown.details.dataset": "Dataset", "attributesDropdown.details.values": "Values", + "attributesDropdown.details.definedAs": "Defined as", "attributesDropdown.details.shortening_decoration": "...and {count} more", "layout.header.characters.left": "{currentCharactersCount} / {maximumCharactersCount} characters left", "layout.header.add.title.placeholder": "Add Title here...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "The visualisation cannot be filtered by {attributeName}. Unselect the check box.", "configurationPanel.kpiCantBeFilteredByAttribute": "The kpi cannot be filtered by {attributeName}. Unselect the check box.", "configurationPanel.vizCantBeFilteredByDate": "The visualisation cannot be filtered by Date. Unselect the check box.", + "configurationPanel.dateDatasetsLoadFailed": "Unable to load related date data. Close the configuration panel and try again.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Filter is not applicable to this visualisation.", "configurationPanel.mvfBlockedByRankingFilter": "This filter can't be applied because the visualisation uses a Top/bottom values filter. Remove the Top/bottom values filter to apply this filter.", "configurationPanel.mvfMissingMeasure": "The metric used in this filter no longer exists in the workspace.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Drill into visualisation", "configurationPanel.drillConfig.drillDown": "Drill down", "configurationPanel.drillConfig.disableDrillDownTooltip": "Drill down is turned off in this visualisation's configuration.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Drill down is unavailable for computed attributes.", "configurationPanel.drillConfig.drillIntoUrl": "Drill into URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Invalid URL parameters", "configurationPanel.drillConfig.select": "Choose action…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Delete rich text?", "richText.deleteDialog.message": "The rich text and all of its content will be permanently deleted.", "richText.emptyContent": "No rich text content", + "visualizationSwitcher.restrictedEntry": "Restricted", "visualizationSwitcher.emptyContent": "No visualisation in switcher", "visualizationSwitcherToolbar.visualizationsList.header": "Visualisations", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Visualisations", @@ -809,6 +823,7 @@ "granularity.hour": "hour", "granularity.minute": "minute", "widget.options.menu.export": "Export", + "insightMenu.restrictedWidget.options": "Restricted visualisation options", "menu.close": "Close menu", "controlButtons.asTable": "Display as table", "controlButtons.asOriginal": "Show original visualisation", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/en-US.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/en-US.json index ea94db9149d..10705ef20be 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/en-US.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/en-US.json @@ -71,6 +71,26 @@ "text": "Dashboard save failed. Remove any unavailable visualizations, then try again, or contact your administrator.", "crowdinContext": "Error notification shown when saving a dashboard fails" }, + "insightNotSavedDialog.headline": { + "text": "Save dashboard", + "crowdinContext": "Headline shown when dashboard save is blocked because it contains draft visualizations" + }, + "insightNotSavedDialog.message": { + "text": "The following objects will be saved together with the dashboard.", + "crowdinContext": "Message shown when dashboard save is blocked due to draft visualizations" + }, + "insightNotSavedDialog.visualisations": { + "text": "Visualizations ({count})", + "crowdinContext": "Title of the list of draft visualizations. {count} is the number of draft visualizations." + }, + "insightNotSavedDialog.close": { + "text": "Close", + "crowdinContext": "Button label used to close the draft-visualization warning dialog" + }, + "insightNotSavedDialog.saveAll": { + "text": "Save all", + "crowdinContext": "Button label used to save all draft visualizations" + }, "messages.dashboard.incompatibleDefaultFilters.title": { "text": "Warning Some dashboard filters couldn’t be applied. Check the filters to make sure you’re viewing the right data.", "crowdinContext": "Title of the warning message shown if default filter overrides are incompatible with the current dashboard filters." @@ -119,6 +139,10 @@ "text": "Filters", "crowdinContext": "Label for the filter bar section" }, + "filterBar.restrictedFilters.remove": { + "text": "Remove restricted filters", + "crowdinContext": "Action in the filter bar notice tooltip, shown in edit mode. Removes the filters the user is not allowed to access from the dashboard for good." + }, "filterBar.restrictedFilters.reason": { "text": "{count, plural, one {You don't have access to # filter.} other {You don't have access to # filters.}}", "crowdinContext": "Tooltip on the filter bar notice, giving the reason why that many dashboard filters were left out. Uses pluralization based on the number of filters." @@ -472,8 +496,8 @@ "crowdinContext": "Label of the default time zone picker in the dashboard settings dialog" }, "settingsDashboardDialog.section.timezone.defaultTimezone.tooltip": { - "text": "Time zone used for date filters and date values on this dashboard.", - "crowdinContext": "Tooltip of the default time zone picker in the dashboard settings dialog" + "text": "Time zone used for date filters and date values on this dashboard. Learn more", + "crowdinContext": "Tooltip of the default time zone picker in the dashboard settings dialog, with a learn more link to the documentation" }, "settingsDashboardDialog.section.timezone.defaultTimezone.help": { "text": "More information", @@ -583,6 +607,10 @@ "text": "Following types objects associated with the widget {title} will no longer work:", "crowdinContext": "Warning message about objects that will be affected when deleting a widget. The {title} placeholder shows the specific widget name." }, + "deleteWidgetDialog.objectsMessage.restricted": { + "text": "The following types of objects associated with the widget will no longer work:", + "crowdinContext": "The same warning for a widget the user has no access to, which therefore must not be named." + }, "deleteWidgetDialog.alerts": { "text": "alerts", "crowdinContext": "Label for alerts that will be affected by widget removal" @@ -3287,6 +3315,10 @@ "text": "Export", "crowdinContext": "Export to file with XLSX extension." }, + "insightMenu.restrictedWidget.options": { + "text": "Restricted visualization options", + "crowdinContext": "Accessible name of the menu of a visualization the user has no access to; it must not name the visualization." + }, "menu.close": { "text": "Close menu", "crowdinContext": "Button label to close a menu" diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/es-419.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/es-419.json index 654654cd27c..94c532f0473 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/es-419.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/es-419.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Su período de prueba ha finalizado.", + "dashboard.contractExpired.trial.description": "Contacte con nosotros si desea seguir utilizando GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "Su acceso está bloqueado.", + "dashboard.contractExpired.nonTrial.description": "Contacte con el administrador de la cuenta para volver a tener acceso.", + "dashboard.contractExpired.buttonTitle": "Contacto", "loading": "Cargando…", "untitled": "Sin título", "empty_value": "valor vacío", + "deleted_value": "valor eliminado", "gs.list.cancel": "Cancelar", "gs.list.apply": "Aplicar", "gs.list.only": "Solo", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Interacción configurada.", "messages.drill.InteractionUpdatedSuccess": "Interacción actualizada.", "filterBar.label": "Filtros", + "filterBar.restrictedFilters.remove": "Quitar filtros restringidos", + "filterBar.restrictedFilters.reason": "{count, plural, one {No tiene acceso a # filtro.} other {No tiene acceso a # filtros.}}", + "filterBar.restrictedFilters": "{count, plural, one {No se aplicó # filtro} other {No se aplicaron # filtros}}", "filterBar.showAll": "Mostrar todo", "filterBar.showLess": "Mostrar menos", "filterBar.filterListAutoExpanded": "La lista de filtros se expandió automáticamente", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "exportaciones programadas", "deleteWidgetDialog.headline": "¿Quitar el widget?", "deleteWidgetDialog.objectsMessage": "Los siguientes tipos de objetos asociados al widget {title} ya no funcionarán:", + "deleteWidgetDialog.objectsMessage.restricted": "Los siguientes tipos de objetos asociados con el elemento ya no funcionarán:", "deleteWidgetDialog.alerts": "alertas", "deleteWidgetDialog.schedules": "exportaciones programadas", "create.dashboard": "Crear panel", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} no se puede filtrar por {parentTitle}. No hay ninguna conexión entre los atributos de filtro en el modelo de datos.", "attributesDropdown.details.dataset": "Conjunto de datos", "attributesDropdown.details.values": "Valores", + "attributesDropdown.details.definedAs": "Definido como", "attributesDropdown.details.shortening_decoration": "…y {count} más", "layout.header.characters.left": "Quedan {currentCharactersCount} / {maximumCharactersCount} caracteres", "layout.header.add.title.placeholder": "Agregar título aquí...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "La visualización no puede filtrarse por {attributeName}. Desmarque la casilla de verificación.", "configurationPanel.kpiCantBeFilteredByAttribute": "El KPI no se puede filtrar por {attributeName}. Desmarque la casilla de verificación.", "configurationPanel.vizCantBeFilteredByDate": "La visualización no puede filtrarse por Fecha. Desmarque la casilla de verificación.", + "configurationPanel.dateDatasetsLoadFailed": "No se pudieron cargar los datos de fecha relacionados. Cierre el panel de configuración e inténtelo de nuevo.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "El filtro no se puede aplicar a esta visualización.", "configurationPanel.mvfBlockedByRankingFilter": "Este filtro no se puede aplicar porque la visualización usa un filtro de valores superiores/inferiores. Quite el filtro de valores superiores/inferiores para aplicar este filtro.", "configurationPanel.mvfMissingMeasure": "La métrica usada en este filtro ya no existe en el espacio de trabajo.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Profundizar en la visualización", "configurationPanel.drillConfig.drillDown": "Profundización", "configurationPanel.drillConfig.disableDrillDownTooltip": "La opción de profundizar está desactivada en la configuración de esta visualización.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Detallar no está disponible para los atributos calculados.", "configurationPanel.drillConfig.drillIntoUrl": "Explorar hasta la URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Parámetros de URL no válidos", "configurationPanel.drillConfig.select": "Seleccione una acción…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "¿Eliminar texto enriquecido?", "richText.deleteDialog.message": "El texto enriquecido y todo su contenido se eliminará de forma permanente.", "richText.emptyContent": "Sin contenido de texto enriquecido", + "visualizationSwitcher.restrictedEntry": "Restringido", "visualizationSwitcher.emptyContent": "No hay visualización en el conmutador", "visualizationSwitcherToolbar.visualizationsList.header": "Visualizaciones", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Visualizaciones", @@ -809,6 +823,7 @@ "granularity.hour": "hora", "granularity.minute": "minuto", "widget.options.menu.export": "Exportar", + "insightMenu.restrictedWidget.options": "Opciones de la visualización restringida", "menu.close": "Cerrar menú", "controlButtons.asTable": "Mostrar como tabla", "controlButtons.asOriginal": "Mostrar visualización original", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/es-ES.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/es-ES.json index 5710f8fc645..29ee19b47ec 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/es-ES.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/es-ES.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Su prueba ha terminado.", + "dashboard.contractExpired.trial.description": "Contacte con nosotros si desea seguir utilizando GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "Su acceso se ha bloqueado.", + "dashboard.contractExpired.nonTrial.description": "Contacte con el administrador de la cuenta para volver a tener acceso.", + "dashboard.contractExpired.buttonTitle": "Contacte con nosotros", "loading": "Cargando…", "untitled": "Sin título", "empty_value": "valor vacío", + "deleted_value": "valor eliminado", "gs.list.cancel": "Cancelar", "gs.list.apply": "Aplicar", "gs.list.only": "Solo", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Interacción configurada.", "messages.drill.InteractionUpdatedSuccess": "Interacción actualizada.", "filterBar.label": "Filtros", + "filterBar.restrictedFilters.remove": "Quitar filtros restringidos", + "filterBar.restrictedFilters.reason": "{count, plural, one {No tiene acceso a # filtro.} other {No tiene acceso a # filtros.}}", + "filterBar.restrictedFilters": "{count, plural, one {No se aplicó # filtro} other {No se aplicaron # filtros}}", "filterBar.showAll": "Mostrar todo", "filterBar.showLess": "Mostrar menos", "filterBar.filterListAutoExpanded": "La lista de filtros se ha ampliado automáticamente", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "exportaciones programadas", "deleteWidgetDialog.headline": "¿Quitar el widget?", "deleteWidgetDialog.objectsMessage": "Los siguientes tipos de objetos asociados al widget {title} ya no funcionarán:", + "deleteWidgetDialog.objectsMessage.restricted": "Los siguientes tipos de objetos asociados al elemento ya no funcionarán:", "deleteWidgetDialog.alerts": "alertas", "deleteWidgetDialog.schedules": "exportaciones programadas", "create.dashboard": "Crear panel", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} no se puede filtrar por {parentTitle}. No hay ninguna conexión entre los atributos de filtro en el modelo de datos.", "attributesDropdown.details.dataset": "Conjunto de datos", "attributesDropdown.details.values": "Valores", + "attributesDropdown.details.definedAs": "Definido como", "attributesDropdown.details.shortening_decoration": "…y {count} más", "layout.header.characters.left": "Quedan {currentCharactersCount} / {maximumCharactersCount} caracteres", "layout.header.add.title.placeholder": "Añadir título aquí...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "La visualización no puede filtrarse por {attributeName}. Desmarque la casilla de verificación.", "configurationPanel.kpiCantBeFilteredByAttribute": "El KPI no se puede filtrar por {attributeName}. Desmarque la casilla de verificación.", "configurationPanel.vizCantBeFilteredByDate": "La visualización no puede filtrarse por Fecha. Desmarque la casilla de verificación.", + "configurationPanel.dateDatasetsLoadFailed": "No se pudieron cargar los datos de fecha relacionados. Cierre el panel de configuración e inténtelo de nuevo.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "El filtro no se puede aplicar a esta visualización.", "configurationPanel.mvfBlockedByRankingFilter": "Este filtro no se puede aplicar porque la visualización usa un filtro de valores superiores/inferiores. Quite el filtro de valores superiores/inferiores para aplicar este filtro.", "configurationPanel.mvfMissingMeasure": "La métrica usada en este filtro ya no existe en el espacio de trabajo.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Profundice en la visualización", "configurationPanel.drillConfig.drillDown": "Exploración vertical", "configurationPanel.drillConfig.disableDrillDownTooltip": "La exploración está desactivada en la configuración de esta visualización.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "La opción de detallar no está disponible para los atributos calculados.", "configurationPanel.drillConfig.drillIntoUrl": "Explorar hasta la URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Parámetros de URL no válidos", "configurationPanel.drillConfig.select": "Elija una acción…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "¿Eliminar texto enriquecido?", "richText.deleteDialog.message": "El texto enriquecido y todo su contenido se eliminará de forma permanente.", "richText.emptyContent": "Sin contenido de texto enriquecido", + "visualizationSwitcher.restrictedEntry": "Restringido", "visualizationSwitcher.emptyContent": "No hay visualización en el conmutador", "visualizationSwitcherToolbar.visualizationsList.header": "Visualizaciones", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Visualizaciones", @@ -809,6 +823,7 @@ "granularity.hour": "hora", "granularity.minute": "minuto", "widget.options.menu.export": "Exportar", + "insightMenu.restrictedWidget.options": "Opciones de la visualización restringida", "menu.close": "Cerrar menú", "controlButtons.asTable": "Mostrar como tabla", "controlButtons.asOriginal": "Mostrar visualización original", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/fi-FI.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/fi-FI.json index b1fcc8bed8e..db28053a663 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/fi-FI.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/fi-FI.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Kokeilusi on päättynyt.", + "dashboard.contractExpired.trial.description": "Ota yhteyttä, jos haluat jatkaa GoodData Cloudin käyttöä.", + "dashboard.contractExpired.nonTrial.title": "Pääsysi on lukittu.", + "dashboard.contractExpired.nonTrial.description": "Ota yhteyttä tilin ylläpitäjään pääsyn palauttamiseksi.", + "dashboard.contractExpired.buttonTitle": "Ota meihin yhteyttä", "loading": "Ladataan…", "untitled": "Nimeämätön", "empty_value": "tyhjä arvo", + "deleted_value": "poistettu arvo", "gs.list.cancel": "Peruuta", "gs.list.apply": "Sovella", "gs.list.only": "Vain", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Vuorovaikutus määritetty.", "messages.drill.InteractionUpdatedSuccess": "Vuorovaikutus päivitetty.", "filterBar.label": "Suodattimet", + "filterBar.restrictedFilters.remove": "Poista rajoitetut suodattimet", + "filterBar.restrictedFilters.reason": "{count, plural, one {Sinulla ei ole käyttöoikeutta # suodattimeen.} other {Sinulla ei ole käyttöoikeutta # suodattimeen.}}", + "filterBar.restrictedFilters": "{count, plural, one {# suodatin jätettiin käyttämättä} other {# suodatinta jätettiin käyttämättä}}", "filterBar.showAll": "Näytä kaikki", "filterBar.showLess": "Näytä vähemmän", "filterBar.filterListAutoExpanded": "Suodatinluettelo on laajennettu automaattisesti", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "suunnitellut viennit", "deleteWidgetDialog.headline": "Poistetaanko widgetti?", "deleteWidgetDialog.objectsMessage": "Seuraavat tyyppiset pienoissovellukseen liittyvät objektit eivät {title} enää toimi:", + "deleteWidgetDialog.objectsMessage.restricted": "Seuraavat elementtiin liittyvät objektityypit eivät enää toimi:", "deleteWidgetDialog.alerts": "hälytykset", "deleteWidgetDialog.schedules": "suunnitellut viennit", "create.dashboard": "Luo kojelauta", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} ei voida suodattaa {parentTitle} avulla. Tietomallissa ei ole yhteyttä suodatinattribuuttien välillä.", "attributesDropdown.details.dataset": "Tietojoukko", "attributesDropdown.details.values": "Arvot", + "attributesDropdown.details.definedAs": "Määritelty muodossa", "attributesDropdown.details.shortening_decoration": "…ja {count} lisää", "layout.header.characters.left": "{currentCharactersCount} /{maximumCharactersCount} merkkiä jäljellä", "layout.header.add.title.placeholder": "Lisää otsikko tähän...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "Visualisointia ei voida suodattaa {attributeName}. Poista valintaruudun valinta.", "configurationPanel.kpiCantBeFilteredByAttribute": "KPI:ta ei voi suodattaa {attributeName}. Poista valintamerkki.", "configurationPanel.vizCantBeFilteredByDate": "Visualisointia ei voida suodattaa päivämäärän mukaan. Poista valinta valintaruudusta.", + "configurationPanel.dateDatasetsLoadFailed": "Liittyviä päivämäärätietoja ei voitu ladata. Sulje määrityspaneeli ja yritä uudelleen.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Suodatin ei sovellu tähän visualisointiin.", "configurationPanel.mvfBlockedByRankingFilter": "Tätä suodatinta ei voi käyttää, koska visualisointi käyttää Ylä-/ala-arvojen suodatinta. Poista Ylä-/ala-arvojen suodatin, jotta voit käyttää tätä suodatinta.", "configurationPanel.mvfMissingMeasure": "Tässä suodattimessa käytettyä metriikkaa ei enää ole työtilassa.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Poraa visualisointiin", "configurationPanel.drillConfig.drillDown": "Poraa alas", "configurationPanel.drillConfig.disableDrillDownTooltip": "Poraus on pois päältä tämän visualisoinnin kokoonpanossa.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Poraaminen syvemmälle ei ole käytettävissä laskennallisille attribuuteille.", "configurationPanel.drillConfig.drillIntoUrl": "Poraa URL-osoitteeseen", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Virheelliset URL-parametrit", "configurationPanel.drillConfig.select": "Valitse toiminto...", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Poista rich text?", "richText.deleteDialog.message": "Rich text ja sen kaikki sisältö poistetaan peruuttamattomasti.", "richText.emptyContent": "Ei rich text -sisältöä", + "visualizationSwitcher.restrictedEntry": "Rajoitettu", "visualizationSwitcher.emptyContent": "Ei visualisointia vaihtimessa", "visualizationSwitcherToolbar.visualizationsList.header": "Visualisoinnit", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Visualisoinnit", @@ -809,6 +823,7 @@ "granularity.hour": "tunti", "granularity.minute": "minuutti", "widget.options.menu.export": "Vie", + "insightMenu.restrictedWidget.options": "Rajoitetun visualisoinnin asetukset", "menu.close": "Sulje valikko", "controlButtons.asTable": "Näytä taulukkona", "controlButtons.asOriginal": "Näytä alkuperäinen visualisointi", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/fr-CA.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/fr-CA.json index 92bd4754e58..bca0ad091e7 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/fr-CA.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/fr-CA.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Votre essai est terminé.", + "dashboard.contractExpired.trial.description": "Contactez-nous si vous souhaitez continuer à utiliser GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "Votre accès est bloqué.", + "dashboard.contractExpired.nonTrial.description": "Contactez l’administrateur du compte pour récupérer l’accès.", + "dashboard.contractExpired.buttonTitle": "Contactez-nous", "loading": "Chargement en cours…", "untitled": "Sans titre", "empty_value": "valeur vide", + "deleted_value": "valeur supprimée", "gs.list.cancel": "Annuler", "gs.list.apply": "Appliquer", "gs.list.only": "Uniquement", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Interaction configurée", "messages.drill.InteractionUpdatedSuccess": "Interaction modifiée", "filterBar.label": "Filtres", + "filterBar.restrictedFilters.remove": "Supprimer les filtres restreints", + "filterBar.restrictedFilters.reason": "{count, plural, one {Vous n’avez pas accès à # filtre.} other {Vous n’avez pas accès à # filtres.}}", + "filterBar.restrictedFilters": "{count, plural, one {# filtre n’a pas été appliqué} other {# filtres n’ont pas été appliqués}}", "filterBar.showAll": "Afficher tout", "filterBar.showLess": "Montrer moins", "filterBar.filterListAutoExpanded": "La liste de filtres a été automatiquement développée", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "Exportations programmées", "deleteWidgetDialog.headline": "Supprimer le widget?", "deleteWidgetDialog.objectsMessage": "Les types d’objets suivants associés au widget {title} ne fonctionneront plus :", + "deleteWidgetDialog.objectsMessage.restricted": "Les types d’objets suivants associés à l’élément ne fonctionneront plus :", "deleteWidgetDialog.alerts": "Alertes", "deleteWidgetDialog.schedules": "Exportations programmées", "create.dashboard": "Créer un tableau de bord", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} ne peut pas être filtré par {parentTitle}. Il n’existe aucune connexion entre les attributs du filtre dans le modèle de données.", "attributesDropdown.details.dataset": "Ensemble de données", "attributesDropdown.details.values": "Valeurs", + "attributesDropdown.details.definedAs": "Défini comme", "attributesDropdown.details.shortening_decoration": "…et {count} de plus", "layout.header.characters.left": "{currentCharactersCount}/{maximumCharactersCount} caractères restant", "layout.header.add.title.placeholder": "Ajouter un titre ici...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "La visualisation ne peut pas être filtrée par {attributeName}. Désélectionnez la case à cocher.", "configurationPanel.kpiCantBeFilteredByAttribute": "Le KPI ne peut pas être filtré par {attributeName}. Décochez la case.", "configurationPanel.vizCantBeFilteredByDate": "La visualisation ne peut pas être filtrée par la Date. Désélectionnez la case à cocher.", + "configurationPanel.dateDatasetsLoadFailed": "Les données de date associées n’ont pas pu être chargées. Fermez le panneau de configuration et réessayez.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Le filtre ne s’applique pas à cette visualisation.", "configurationPanel.mvfBlockedByRankingFilter": "Ce filtre ne peut pas être appliqué, car la visualisation utilise un filtre des valeurs supérieures/inférieures. Supprimez le filtre des valeurs supérieures/inférieures pour appliquer ce filtre.", "configurationPanel.mvfMissingMeasure": "La métrique utilisée dans ce filtre n’existe plus dans l’espace de travail.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Explorer plus en détail la visualisation", "configurationPanel.drillConfig.drillDown": "Exploration descendante", "configurationPanel.drillConfig.disableDrillDownTooltip": "L’exploration en profondeur est désactivée dans la configuration de cette visualisation.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Explorer en détail n’est pas disponible pour les attributs calculés.", "configurationPanel.drillConfig.drillIntoUrl": "Explorer l’URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Paramètres URL non valides", "configurationPanel.drillConfig.select": "Choisir une action…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Supprimer le texte enrichi ?", "richText.deleteDialog.message": "Le texte enrichi et tout son contenu seront supprimés de manière irréversible.", "richText.emptyContent": "Pas de texte enrichi", + "visualizationSwitcher.restrictedEntry": "Restreint", "visualizationSwitcher.emptyContent": "Pas de visualisation dans le sélecteur", "visualizationSwitcherToolbar.visualizationsList.header": "Visualisations", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Visualisations", @@ -809,6 +823,7 @@ "granularity.hour": "heure", "granularity.minute": "minute", "widget.options.menu.export": "Exporter", + "insightMenu.restrictedWidget.options": "Options de la visualisation restreinte", "menu.close": "Fermer le menu", "controlButtons.asTable": "Afficher sous forme de tableau", "controlButtons.asOriginal": "Afficher la visualisation originale", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/fr-FR.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/fr-FR.json index 675436f844e..91b96ae3eac 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/fr-FR.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/fr-FR.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Votre essai est terminé.", + "dashboard.contractExpired.trial.description": "Contactez-nous si vous souhaitez continuer à utiliser GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "Votre accès est bloqué.", + "dashboard.contractExpired.nonTrial.description": "Contactez l'administrateur du compte pour récupérer l'accès.", + "dashboard.contractExpired.buttonTitle": "Contactez-nous", "loading": "Chargement en cours…", "untitled": "Sans titre", "empty_value": "valeur vide", + "deleted_value": "valeur supprimée", "gs.list.cancel": "Annuler", "gs.list.apply": "Appliquer", "gs.list.only": "Uniquement", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Interaction configurée", "messages.drill.InteractionUpdatedSuccess": "Interaction modifiée", "filterBar.label": "Filtres", + "filterBar.restrictedFilters.remove": "Supprimer les filtres restreints", + "filterBar.restrictedFilters.reason": "{count, plural, one {Vous n’avez pas accès à # filtre.} other {Vous n’avez pas accès à # filtres.}}", + "filterBar.restrictedFilters": "{count, plural, one {# filtre n’a pas été appliqué} other {# filtres n’ont pas été appliqués}}", "filterBar.showAll": "Afficher tout", "filterBar.showLess": "Montrer moins", "filterBar.filterListAutoExpanded": "La liste de filtres a été automatiquement développée", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "exportations programmées", "deleteWidgetDialog.headline": "Supprimer le widget ?", "deleteWidgetDialog.objectsMessage": "Les types d'objets suivants associés au widget {title} ne fonctionneront plus :", + "deleteWidgetDialog.objectsMessage.restricted": "Les types d’objets suivants associés à l’élément ne fonctionneront plus :", "deleteWidgetDialog.alerts": "alertes", "deleteWidgetDialog.schedules": "exportations programmées", "create.dashboard": "Créer un tableau de bord", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} ne peut pas être filtré par {parentTitle}. Il n'existe aucune connexion entre les attributs du filtre dans le modèle de données.", "attributesDropdown.details.dataset": "Ensemble de données", "attributesDropdown.details.values": "Valeurs", + "attributesDropdown.details.definedAs": "Défini comme", "attributesDropdown.details.shortening_decoration": "…et {count} de plus", "layout.header.characters.left": "{currentCharactersCount}/{maximumCharactersCount} caractères restant", "layout.header.add.title.placeholder": "Ajouter un titre ici...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "La visualisation ne peut pas être filtrée par {attributeName}. Désélectionnez la case à cocher.", "configurationPanel.kpiCantBeFilteredByAttribute": "Le KPI ne peut pas être filtré par {attributeName}. Décochez la case.", "configurationPanel.vizCantBeFilteredByDate": "La visualisation ne peut pas être filtrée par date. Désélectionnez la case à cocher.", + "configurationPanel.dateDatasetsLoadFailed": "Les données de date associées n’ont pas pu être chargées. Fermez le panneau de configuration et réessayez.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Le filtre ne peut pas être appliqué à cette visualisation.", "configurationPanel.mvfBlockedByRankingFilter": "Ce filtre ne peut pas être appliqué, car la visualisation utilise un filtre de valeurs Top/Bottom. Supprimez le filtre de valeurs Top/Bottom pour appliquer ce filtre.", "configurationPanel.mvfMissingMeasure": "La métrique utilisée dans ce filtre n’existe plus dans l’espace de travail.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Explorer la visualisation", "configurationPanel.drillConfig.drillDown": "Exploration descendante", "configurationPanel.drillConfig.disableDrillDownTooltip": "L'exploration descendante est désactivée dans la configuration de cette visualisation.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Explorer en détail n’est pas disponible pour les attributs calculés.", "configurationPanel.drillConfig.drillIntoUrl": "Explorer l’URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Paramètres d'URL non valides", "configurationPanel.drillConfig.select": "Choisir une action…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Supprimer le texte enrichi ?", "richText.deleteDialog.message": "Le texte enrichi et tout son contenu seront supprimés de manière irréversible.", "richText.emptyContent": "Pas de texte enrichi", + "visualizationSwitcher.restrictedEntry": "Restreint", "visualizationSwitcher.emptyContent": "Pas de visualisation dans le commutateur", "visualizationSwitcherToolbar.visualizationsList.header": "Visualisations", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Visualisations", @@ -809,6 +823,7 @@ "granularity.hour": "heure", "granularity.minute": "minute", "widget.options.menu.export": "Exporter", + "insightMenu.restrictedWidget.options": "Options de visualisation restreinte", "menu.close": "Fermer le menu", "controlButtons.asTable": "Afficher sous forme de tableau", "controlButtons.asOriginal": "Afficher la visualisation originale", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/id-ID.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/id-ID.json index 3bdd7e3abea..47d65dcb2fd 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/id-ID.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/id-ID.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Uji coba Anda telah berakhir.", + "dashboard.contractExpired.trial.description": "Hubungi kami jika Anda ingin terus menggunakan GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "Akses Anda dikunci.", + "dashboard.contractExpired.nonTrial.description": "Hubungi administrator akun untuk mendapatkan kembali akses.", + "dashboard.contractExpired.buttonTitle": "Hubungi kami", "loading": "Memuat…", "untitled": "Tanpa judul", "empty_value": "nilai kosong", + "deleted_value": "nilai yang dihapus", "gs.list.cancel": "Batal", "gs.list.apply": "Terapkan", "gs.list.only": "Hanya", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Interaksi dikonfigurasi.", "messages.drill.InteractionUpdatedSuccess": "Interaksi diperbarui.", "filterBar.label": "Filter", + "filterBar.restrictedFilters.remove": "Hapus filter terbatas", + "filterBar.restrictedFilters.reason": "{count, plural, other {Anda tidak memiliki akses ke # filter.}}", + "filterBar.restrictedFilters": "{count, plural, other {# filter tidak diterapkan}}", "filterBar.showAll": "Tampilkan semua", "filterBar.showLess": "Tampilkan lebih sedikit", "filterBar.filterListAutoExpanded": "Daftar filter telah diperluas secara otomatis", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "ekspor terjadwal", "deleteWidgetDialog.headline": "Hapus widget?", "deleteWidgetDialog.objectsMessage": "Jenis objek berikut yang terkait dengan widget {title} tidak akan lagi berfungsi:", + "deleteWidgetDialog.objectsMessage.restricted": "Jenis objek berikut yang terkait dengan widget tidak akan lagi berfungsi:", "deleteWidgetDialog.alerts": "peringatan", "deleteWidgetDialog.schedules": "ekspor terjadwal", "create.dashboard": "Buat dasbor", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} tidak dapat difilter oleh {parentTitle}. Tidak ada koneksi antara atribut filter dalam model data.", "attributesDropdown.details.dataset": "Dataset", "attributesDropdown.details.values": "Nilai", + "attributesDropdown.details.definedAs": "Didefinisikan sebagai", "attributesDropdown.details.shortening_decoration": "…dan {count} lainnya", "layout.header.characters.left": "{currentCharactersCount} / {maximumCharactersCount} karakter tersisa", "layout.header.add.title.placeholder": "Tambahkan Judul di sini...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "Visualisasi tidak dapat difilter oleh {attributeName}. Batalkan pilihan kotak centang.", "configurationPanel.kpiCantBeFilteredByAttribute": "kpi tidak dapat difilter oleh {attributeName}. Batalkan pilihan kotak centang.", "configurationPanel.vizCantBeFilteredByDate": "Visualisasi tidak dapat difilter oleh Tanggal. Batalkan pilihan kotak centang.", + "configurationPanel.dateDatasetsLoadFailed": "Data tanggal terkait tidak dapat dimuat. Tutup panel konfigurasi dan coba lagi.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Filter tidak dapat diterapkan pada visualisasi ini.", "configurationPanel.mvfBlockedByRankingFilter": "Filter ini tidak dapat diterapkan karena visualisasi menggunakan filter nilai Teratas/Terbawah. Hapus filter nilai Teratas/Terbawah untuk menerapkan filter ini.", "configurationPanel.mvfMissingMeasure": "Metrik yang digunakan dalam filter ini tidak lagi ada di ruang kerja.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Telusuri ke visualisasi", "configurationPanel.drillConfig.drillDown": "Telusuri ke bawah", "configurationPanel.drillConfig.disableDrillDownTooltip": "Telusuri ke bawah dimatikan dalam konfigurasi visualisasi ini.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Telusuri ke bawah tidak tersedia untuk atribut terkomputasi.", "configurationPanel.drillConfig.drillIntoUrl": "Telusuri ke URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Parameter URL tidak valid", "configurationPanel.drillConfig.select": "Pilih tindakan…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Hapus rich text?", "richText.deleteDialog.message": "Rich text dan semua kontennya akan dihapus secara permanen.", "richText.emptyContent": "Tidak ada konten rich text", + "visualizationSwitcher.restrictedEntry": "Dibatasi", "visualizationSwitcher.emptyContent": "Tidak ada visualisasi dalam pengalih", "visualizationSwitcherToolbar.visualizationsList.header": "Visualisasi", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Visualisasi", @@ -809,6 +823,7 @@ "granularity.hour": "jam", "granularity.minute": "menit", "widget.options.menu.export": "Ekspor", + "insightMenu.restrictedWidget.options": "Opsi visualisasi terbatas", "menu.close": "Tutup menu", "controlButtons.asTable": "Tampilkan sebagai tabel", "controlButtons.asOriginal": "Tampilkan visualisasi asli", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/it-IT.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/it-IT.json index c94c6898979..3159a56fcbf 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/it-IT.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/it-IT.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Il periodo di prova è terminato.", + "dashboard.contractExpired.trial.description": "È possibile contattarci qualora si desiderasse continuare a utilizzare GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "L'accesso è bloccato.", + "dashboard.contractExpired.nonTrial.description": "Contattare l'amministratore dell'account per recuperare l'accesso.", + "dashboard.contractExpired.buttonTitle": "Contattaci", "loading": "Caricamento…", "untitled": "Senza titolo", "empty_value": "Valore vuoto", + "deleted_value": "valore eliminato", "gs.list.cancel": "Annulla", "gs.list.apply": "Applica", "gs.list.only": "Solo", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Interazione configurata.", "messages.drill.InteractionUpdatedSuccess": "Interazione aggiornata.", "filterBar.label": "Filtri", + "filterBar.restrictedFilters.remove": "Rimuovi i filtri con restrizioni", + "filterBar.restrictedFilters.reason": "{count, plural, one {Non disponi dell'accesso a # filtro.} other {Non disponi dell'accesso a # filtri.}}", + "filterBar.restrictedFilters": "{count, plural, one {# filtro non è stato applicato} other {# filtri non sono stati applicati}}", "filterBar.showAll": "Mostra tutto", "filterBar.showLess": "Mostra di meno", "filterBar.filterListAutoExpanded": "L'elenco dei filtri è stato espanso automaticamente", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "esportazioni programmate", "deleteWidgetDialog.headline": "Rimuovere il widget?", "deleteWidgetDialog.objectsMessage": "I seguenti tipi di oggetti associati al widget {title} non funzionano più:", + "deleteWidgetDialog.objectsMessage.restricted": "I seguenti tipi di oggetti associati all'elemento non funzioneranno più:", "deleteWidgetDialog.alerts": "avvisi", "deleteWidgetDialog.schedules": "esportazioni programmate", "create.dashboard": "Creare cruscotto", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} non può essere filtrato per {parentTitle}. Non esiste alcun collegamento tra gli attributi dei filtri nel modello dei dati.", "attributesDropdown.details.dataset": "Set di dati", "attributesDropdown.details.values": "Valori", + "attributesDropdown.details.definedAs": "Definito come", "attributesDropdown.details.shortening_decoration": "…e altri {count}", "layout.header.characters.left": "{currentCharactersCount} / {maximumCharactersCount} caratteri rimasti", "layout.header.add.title.placeholder": "Aggiungi titolo qui...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "La visualizzazione non può essere filtrata da {attributeName}. Deselezionare la casella di controllo.", "configurationPanel.kpiCantBeFilteredByAttribute": "Il KPI non può essere filtrato per {attributeName}. Deselezionare la casella di controllo.", "configurationPanel.vizCantBeFilteredByDate": "La visualizzazione non può essere filtrata per data. Deselezionare la casella di controllo.", + "configurationPanel.dateDatasetsLoadFailed": "Non è stato possibile caricare i dati relativi alle date. Chiudere il pannello di configurazione e riprovare.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Il filtro non può essere applicato a questa visualizzazione.", "configurationPanel.mvfBlockedByRankingFilter": "Questo filtro non può essere applicato perché la visualizzazione usa un filtro Valori superiori/inferiori. Rimuovi il filtro Valori superiori/inferiori per applicare questo filtro.", "configurationPanel.mvfMissingMeasure": "La metrica usata in questo filtro non esiste più nell'area di lavoro.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Approfondimento della visualizzazione", "configurationPanel.drillConfig.drillDown": "Drill-down", "configurationPanel.drillConfig.disableDrillDownTooltip": "Il drill down è disattivato nella configurazione di questa visualizzazione.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Approfondisci non è disponibile per gli attributi calcolati.", "configurationPanel.drillConfig.drillIntoUrl": "Fai il drill dell'URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Parametri dell'URL non validi", "configurationPanel.drillConfig.select": "Scegli azione...", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Eliminare il testo formattato?", "richText.deleteDialog.message": "Il testo formattato e tutti i suoi contenuti verranno eliminati in modo irreversibile.", "richText.emptyContent": "Nessun contenuto in testo formattato", + "visualizationSwitcher.restrictedEntry": "Limitato", "visualizationSwitcher.emptyContent": "Nessuna visualizzazione nel selettore", "visualizationSwitcherToolbar.visualizationsList.header": "Visualizzazioni", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Visualizzazioni", @@ -809,6 +823,7 @@ "granularity.hour": "ora", "granularity.minute": "minuto", "widget.options.menu.export": "Esporta", + "insightMenu.restrictedWidget.options": "Opzioni della visualizzazione con accesso limitato", "menu.close": "Chiudere il menu", "controlButtons.asTable": "Mostra come tabella", "controlButtons.asOriginal": "Mostra la visualizzazione originale", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/ja-JP.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/ja-JP.json index a5f10e69915..68a69b5cc25 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/ja-JP.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/ja-JP.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "トライアルは終了しました。", + "dashboard.contractExpired.trial.description": "引き続き GoodData Cloud をご利用になる場合は、こちらまでお問い合わせください。", + "dashboard.contractExpired.nonTrial.title": "アクセスはロックされています。", + "dashboard.contractExpired.nonTrial.description": "アカウント管理者に連絡して、アクセス権を再取得してください。", + "dashboard.contractExpired.buttonTitle": "お問い合わせ先", "loading": "読み込んでいます…", "untitled": "無題", "empty_value": "空の値", + "deleted_value": "消去された値", "gs.list.cancel": "キャンセル", "gs.list.apply": "適用", "gs.list.only": "のみ選択", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "操作が設定されました。", "messages.drill.InteractionUpdatedSuccess": "操作が更新されました。", "filterBar.label": "フィルター", + "filterBar.restrictedFilters.remove": "制限付きフィルターを削除", + "filterBar.restrictedFilters.reason": "{count, plural, other {# 件のフィルターにアクセスできません。}}", + "filterBar.restrictedFilters": "{count, plural, other {# 件のフィルターが適用されませんでした}}", "filterBar.showAll": "すべて表示", "filterBar.showLess": "表示を減らす", "filterBar.filterListAutoExpanded": "フィルター リストが自動的に展開されました", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "エクスポート予定", "deleteWidgetDialog.headline": "ウィジェットを削除しますか?", "deleteWidgetDialog.objectsMessage": "ウィジェット{title}に関連付けられた、以下のタイプのオブジェクトは、動作しなくなります。", + "deleteWidgetDialog.objectsMessage.restricted": "ウィジェットに関連付けられている次の種類のオブジェクトは機能しなくなります:", "deleteWidgetDialog.alerts": "アラート", "deleteWidgetDialog.schedules": "エクスポート予定", "create.dashboard": "ダッシュボードを作成", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} フィルターが無効 {parentTitle}。フィルターアトリビュートとデータモデルが無関係です。", "attributesDropdown.details.dataset": "データセット", "attributesDropdown.details.values": "値", + "attributesDropdown.details.definedAs": "定義", "attributesDropdown.details.shortening_decoration": "…及び{count}その他", "layout.header.characters.left": "残り {currentCharactersCount} / {maximumCharactersCount} 文字", "layout.header.add.title.placeholder": "こちらにタイトルを追加します…", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "ビジュアライゼーションは{attributeName} でフィルターできません。チェックボックスをオフにします。", "configurationPanel.kpiCantBeFilteredByAttribute": "KPIは{attributeName}でフィルターできません。チェックボックスの選択を解除してください。", "configurationPanel.vizCantBeFilteredByDate": "ビジュアライゼーションを日付でフィルターすることはできません。チェックボックスの選択を解除してください。", + "configurationPanel.dateDatasetsLoadFailed": "関連する日付データを読み込めませんでした。構成パネルを閉じて、もう一度お試しください。", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "このビジュアライゼーションにはフィルターを適用できません。", "configurationPanel.mvfBlockedByRankingFilter": "このフィルターは、ビジュアライゼーションで上位/下位値フィルターが使用されているため適用できません。このフィルターを適用するには、上位/下位値フィルターを削除してください。", "configurationPanel.mvfMissingMeasure": "このフィルターで使用されているメトリックは、ワークスペースに存在しなくなりました。", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "ビジュアライゼーションのドリル", "configurationPanel.drillConfig.drillDown": "ドリルダウン", "configurationPanel.drillConfig.disableDrillDownTooltip": "このビジュアライゼーションの設定では、ドリルダウンはオフになっています。", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "計算アトリビュートではドリルダウンを使用できません。", "configurationPanel.drillConfig.drillIntoUrl": "URL にドリル", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "無効な URL パラメーター", "configurationPanel.drillConfig.select": "アクションを選択...", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "リッチテキストを削除しますか?", "richText.deleteDialog.message": "リッチテキストとそのコンテンツはすべて元に戻せない状態で削除されます。", "richText.emptyContent": "リッチテキストのコンテンツがありません", + "visualizationSwitcher.restrictedEntry": "制限あり", "visualizationSwitcher.emptyContent": "スイッチャーでのビジュアライゼーションなし", "visualizationSwitcherToolbar.visualizationsList.header": "ビジュアライゼーション", "visualizationSwitcherToolbar.visualizationsList.tooltip": "ビジュアライゼーション", @@ -809,6 +823,7 @@ "granularity.hour": "時", "granularity.minute": "分", "widget.options.menu.export": "エクスポート", + "insightMenu.restrictedWidget.options": "制限されたビジュアライゼーションのオプション", "menu.close": "メニューを閉じる", "controlButtons.asTable": "表として表示", "controlButtons.asOriginal": "オリジナルのビジュアライゼーションを表示", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/ko-KR.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/ko-KR.json index 02444115953..83f507b5640 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/ko-KR.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/ko-KR.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "체험 기간이 종료되었습니다.", + "dashboard.contractExpired.trial.description": "GoodData Cloud를 계속 사용하시려는 경우 저희에게 연락주시기 바랍니다.", + "dashboard.contractExpired.nonTrial.title": "접근이 차단되었습니다.", + "dashboard.contractExpired.nonTrial.description": "계정 관리자에게 연락하여 접근 권한을 복구하세요.", + "dashboard.contractExpired.buttonTitle": "문의하기", "loading": "로딩 중…", "untitled": "제목 없음", "empty_value": "빈 값", + "deleted_value": "삭제된 값", "gs.list.cancel": "취소", "gs.list.apply": "적용", "gs.list.only": "만 해당됨", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "인터랙션이 구성되었습니다.", "messages.drill.InteractionUpdatedSuccess": "인터랙션이 업데이트되었습니다.", "filterBar.label": "필터(들)", + "filterBar.restrictedFilters.remove": "제한된 필터 제거", + "filterBar.restrictedFilters.reason": "{count, plural, other {#개의 필터에 액세스할 수 없습니다.}}", + "filterBar.restrictedFilters": "{count, plural, other {#개의 필터가 적용되지 않았습니다}}", "filterBar.showAll": "모두 보기", "filterBar.showLess": "간단히 보기", "filterBar.filterListAutoExpanded": "필터 목록이 자동으로 확장되었습니다", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "예약된 내보내기", "deleteWidgetDialog.headline": "위젯을 제거하시겠습니까?", "deleteWidgetDialog.objectsMessage": "위젯 {title}와 연관된 다음 유형의 객체는 더 이상 작동하지 않습니다:", + "deleteWidgetDialog.objectsMessage.restricted": "위젯과 연결된 다음 유형의 객체는 더 이상 작동하지 않습니다:", "deleteWidgetDialog.alerts": "알림", "deleteWidgetDialog.schedules": "예약된 내보내기", "create.dashboard": "대시보드 생성", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle}은(는) {parentTitle}(으)로 필터링할 수 없습니다. 데이터 모델에서 필터 속성 간의 연결이 없습니다.", "attributesDropdown.details.dataset": "데이터셋", "attributesDropdown.details.values": "값", + "attributesDropdown.details.definedAs": "다음으로 정의됨", "attributesDropdown.details.shortening_decoration": "…및 {count} 더보기", "layout.header.characters.left": "{currentCharactersCount} /{maximumCharactersCount} 남은 문자 수", "layout.header.add.title.placeholder": "여기에 제목 추가...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "시각화는 {attributeName}(으)로 필터링할 수 없습니다. 체크박스를 선택 해제하세요.", "configurationPanel.kpiCantBeFilteredByAttribute": "KPI는 {attributeName}(으)로 필터링할 수 없습니다. 체크박스를 선택 해제하세요.", "configurationPanel.vizCantBeFilteredByDate": "시각화는 날짜로 필터링할 수 없습니다. 체크 박스를 선택 해제하세요.", + "configurationPanel.dateDatasetsLoadFailed": "관련 날짜 데이터를 로드할 수 없습니다. 구성 패널을 닫고 다시 시도하십시오.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "이 시각화에는 필터를 적용할 수 없습니다.", "configurationPanel.mvfBlockedByRankingFilter": "이 필터는 시각화에서 상위/하위 값 필터를 사용하므로 적용할 수 없습니다. 이 필터를 적용하려면 상위/하위 값 필터를 제거하세요.", "configurationPanel.mvfMissingMeasure": "이 필터에 사용된 메트릭이 더 이상 작업 공간에 존재하지 않습니다.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "시각화 드릴 다운", "configurationPanel.drillConfig.drillDown": "드릴 다운", "configurationPanel.drillConfig.disableDrillDownTooltip": "이 시각화의 구성에서 드릴 다운이 꺼져 있습니다.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "계산된 속성에는 드릴 다운을 사용할 수 없습니다.", "configurationPanel.drillConfig.drillIntoUrl": "URL 드릴 다운", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "잘못된 URL 매개변수", "configurationPanel.drillConfig.select": "작업 선택…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "서식 있는 텍스트 삭제하시겠습니까?", "richText.deleteDialog.message": "서식 있는 텍스트 및 모든 내용이 되돌릴 수 없이 삭제됩니다.", "richText.emptyContent": "서식 있는 텍스트 없음", + "visualizationSwitcher.restrictedEntry": "제한됨", "visualizationSwitcher.emptyContent": "전환기에 시각화 없음", "visualizationSwitcherToolbar.visualizationsList.header": "시각화", "visualizationSwitcherToolbar.visualizationsList.tooltip": "시각화", @@ -809,6 +823,7 @@ "granularity.hour": "시간", "granularity.minute": "분", "widget.options.menu.export": "내보내기", + "insightMenu.restrictedWidget.options": "제한된 시각화 옵션", "menu.close": "메뉴 닫기", "controlButtons.asTable": "표로 표시", "controlButtons.asOriginal": "원본 시각화 보기", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/nl-NL.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/nl-NL.json index e7dbb44751a..fcf27e2cb19 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/nl-NL.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/nl-NL.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Uw proefperiode is afgelopen.", + "dashboard.contractExpired.trial.description": "Neem contact met ons op als u GoodData Cloud wilt blijven gebruiken.", + "dashboard.contractExpired.nonTrial.title": "Uw toegang is vergrendeld.", + "dashboard.contractExpired.nonTrial.description": "Neem contact op met de accountbeheerder om weer toegang te krijgen.", + "dashboard.contractExpired.buttonTitle": "Contacteer ons", "loading": "Wordt geladen…", "untitled": "Zonder titel", "empty_value": "lege waarde", + "deleted_value": "verwijderde waarde", "gs.list.cancel": "Annuleren", "gs.list.apply": "Toepassen", "gs.list.only": "Alleen", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Interactie geconfigureerd.", "messages.drill.InteractionUpdatedSuccess": "Interactie bijgewerkt.", "filterBar.label": "Filters", + "filterBar.restrictedFilters.remove": "Verwijder beperkte filters", + "filterBar.restrictedFilters.reason": "{count, plural, one {U hebt geen toegang tot # filter.} other {U hebt geen toegang tot # filters.}}", + "filterBar.restrictedFilters": "{count, plural, one {# filter is niet toegepast} other {# filters zijn niet toegepast}}", "filterBar.showAll": "Alle tonen", "filterBar.showLess": "Minder tonen", "filterBar.filterListAutoExpanded": "Filterlijst is automatisch uitgevouwen", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "geplande export", "deleteWidgetDialog.headline": "Widget verwijderen?", "deleteWidgetDialog.objectsMessage": "De volgende typen objecten die zijn gekoppeld aan de widget {title} werken niet meer:", + "deleteWidgetDialog.objectsMessage.restricted": "De volgende typen objecten die aan het element zijn gekoppeld, werken niet meer:", "deleteWidgetDialog.alerts": "waarschuwingen", "deleteWidgetDialog.schedules": "geplande export", "create.dashboard": "Dashboard maken", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} kan niet worden gefilterd op {parentTitle}. Er is geen verbinding tussen de filterattributen in het gegevensmodel.", "attributesDropdown.details.dataset": "Dataset", "attributesDropdown.details.values": "Waarden", + "attributesDropdown.details.definedAs": "Gedefinieerd als", "attributesDropdown.details.shortening_decoration": "…en {count} meer", "layout.header.characters.left": "Nog {currentCharactersCount} / {maximumCharactersCount} tekens", "layout.header.add.title.placeholder": "Titel hier toevoegen...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "De visualisatie kan niet worden gefilterd op {attributeName}. Schakel het selectievakje uit.", "configurationPanel.kpiCantBeFilteredByAttribute": "De KPI kan niet worden gefilterd op {attributeName}. Vink het selectievakje af.", "configurationPanel.vizCantBeFilteredByDate": "De visualisatie kan niet worden gefilterd op Datum. Schakel het selectievakje uit.", + "configurationPanel.dateDatasetsLoadFailed": "Gerelateerde datumgegevens konden niet worden geladen. Sluit het configuratiepaneel en probeer het opnieuw.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Filter is niet van toepassing op deze visualisatie.", "configurationPanel.mvfBlockedByRankingFilter": "Dit filter kan niet worden toegepast omdat de visualisatie een filter voor Top-/onderste waarden gebruikt. Verwijder het filter voor Top-/onderste waarden om dit filter toe te passen.", "configurationPanel.mvfMissingMeasure": "De metriek die in dit filter wordt gebruikt, bestaat niet meer in de werkruimte.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Boor in visualisatie", "configurationPanel.drillConfig.drillDown": "Inzoomen", "configurationPanel.drillConfig.disableDrillDownTooltip": "Inzoomen is uitgeschakeld in de configuratie van deze visualisatie.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Inzoomen op details is niet beschikbaar voor berekende attributen.", "configurationPanel.drillConfig.drillIntoUrl": "Inzoomen op URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Ongeldige URL-parameters", "configurationPanel.drillConfig.select": "Actie kiezen…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Tekst met opmaak verwijderen?", "richText.deleteDialog.message": "De tekst met opmaak en alle inhoud wordt onomkeerbaar verwijderd.", "richText.emptyContent": "Geen inhoud met tekst met opmaak", + "visualizationSwitcher.restrictedEntry": "Beperkt", "visualizationSwitcher.emptyContent": "Geen visualisatie in schakelaar", "visualizationSwitcherToolbar.visualizationsList.header": "Visualisaties", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Visualisaties", @@ -809,6 +823,7 @@ "granularity.hour": "uur", "granularity.minute": "minuut", "widget.options.menu.export": "Exporteren", + "insightMenu.restrictedWidget.options": "Opties voor beperkte visualisatie", "menu.close": "Menu sluiten", "controlButtons.asTable": "Als tabel weergeven", "controlButtons.asOriginal": "Toon originele visualisatie", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/pl-PL.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/pl-PL.json index d9e81161de2..94ac5e7b6c4 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/pl-PL.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/pl-PL.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Twój okres próbny dobiegł końca.", + "dashboard.contractExpired.trial.description": "Skontaktuj się z nami, jeśli chcesz kontynuować korzystanie z GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "Twój dostęp jest zablokowany.", + "dashboard.contractExpired.nonTrial.description": "Skontaktuj się z administratorem konta, aby odzyskać dostęp.", + "dashboard.contractExpired.buttonTitle": "Skontaktuj się z nami", "loading": "Ładowanie…", "untitled": "Bez tytułu", "empty_value": "pusta wartość", + "deleted_value": "usunięta wartość", "gs.list.cancel": "Anuluj", "gs.list.apply": "Zastosuj", "gs.list.only": "Tylko", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Interakcja skonfigurowana.", "messages.drill.InteractionUpdatedSuccess": "Interakcja zaktualizowana.", "filterBar.label": "Filtry", + "filterBar.restrictedFilters.remove": "Usuń filtry z ograniczonym dostępem", + "filterBar.restrictedFilters.reason": "{count, plural, one {Nie masz dostępu do # filtru.} few {Nie masz dostępu do # filtrów.} many {Nie masz dostępu do # filtrów.} other {Nie masz dostępu do # filtra.}}", + "filterBar.restrictedFilters": "{count, plural, one {# filtr nie został zastosowany} few {# filtry nie zostały zastosowane} many {# filtrów nie zostało zastosowanych} other {# filtra nie zastosowano}}", "filterBar.showAll": "Pokaż wszystko", "filterBar.showLess": "Pokaż mniej", "filterBar.filterListAutoExpanded": "Lista filtrów została automatycznie rozwinięta", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "zaplanowane eksporty", "deleteWidgetDialog.headline": "Usunąć widżet?", "deleteWidgetDialog.objectsMessage": "Następujące typy obiektów powiązanych z widżetem {title} przestaną działać:", + "deleteWidgetDialog.objectsMessage.restricted": "Następujące typy obiektów powiązanych z elementem przestaną działać:", "deleteWidgetDialog.alerts": "alerty", "deleteWidgetDialog.schedules": "zaplanowane eksporty", "create.dashboard": "Utwórz pulpit nawigacyjny", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} nie można filtrować za pomocą {parentTitle}. W modelu danych nie ma połączenia między atrybutami filtra.", "attributesDropdown.details.dataset": "Zestaw danych", "attributesDropdown.details.values": "Wartości", + "attributesDropdown.details.definedAs": "Zdefiniowane jako", "attributesDropdown.details.shortening_decoration": "…i {count} więcej", "layout.header.characters.left": "{currentCharactersCount} /{maximumCharactersCount} pozostało znaków", "layout.header.add.title.placeholder": "Dodaj tytuł tutaj...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "Wizualizacja nie może być filtrowana przez {attributeName}. Odznacz pole wyboru.", "configurationPanel.kpiCantBeFilteredByAttribute": "KPI nie może być filtrowany przez {attributeName}. Odznacz pole wyboru.", "configurationPanel.vizCantBeFilteredByDate": "Wizualizacja nie może być filtrowana wg daty. Odznacz pole wyboru.", + "configurationPanel.dateDatasetsLoadFailed": "Nie udało się załadować powiązanych danych dotyczących dat. Zamknij panel konfiguracji i spróbuj ponownie.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Filtr nie ma zastosowania do tej wizualizacji.", "configurationPanel.mvfBlockedByRankingFilter": "Tego filtra nie można zastosować, ponieważ wizualizacja używa filtra Top/bottom values. Usuń filtr Top/bottom values, aby zastosować ten filtr.", "configurationPanel.mvfMissingMeasure": "Metryka używana w tym filtrze już nie istnieje w przestrzeni roboczej.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Przewijanie do wizualizacji", "configurationPanel.drillConfig.drillDown": "Przewijanie w dół", "configurationPanel.drillConfig.disableDrillDownTooltip": "Przewijanie w dół jest wyłączony w konfiguracji tej wizualizacji.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Opcja „przejdź w dół szczegółów” nie jest dostępna dla atrybutów obliczeniowych.", "configurationPanel.drillConfig.drillIntoUrl": "Przewijanie do URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Nieprawidłowe parametry URL", "configurationPanel.drillConfig.select": "Wybierz działanie…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Usunąć tekst sformatowany?", "richText.deleteDialog.message": "Tekst sformatowany oraz cała jego zawartość zostaną nieodwracalnie usunięte.", "richText.emptyContent": "Brak treści sformatowanej", + "visualizationSwitcher.restrictedEntry": "Ograniczone", "visualizationSwitcher.emptyContent": "Brak wizualizacji w przełączniku", "visualizationSwitcherToolbar.visualizationsList.header": "Wizualizacje", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Wizualizacje", @@ -809,6 +823,7 @@ "granularity.hour": "godzina", "granularity.minute": "minuta", "widget.options.menu.export": "Eksportuj", + "insightMenu.restrictedWidget.options": "Opcje wizualizacji z ograniczonym dostępem", "menu.close": "Zamknij menu", "controlButtons.asTable": "Pokaż jako tabelę", "controlButtons.asOriginal": "Pokaż oryginalną wizualizację", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/pt-BR.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/pt-BR.json index 81837879c04..36332d03896 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/pt-BR.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/pt-BR.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Seu período de teste terminou.", + "dashboard.contractExpired.trial.description": "Entre em contato conosco se deseja continuar usando o GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "Seu acesso está bloqueado.", + "dashboard.contractExpired.nonTrial.description": "Entre em contato com o administrador da conta para recuperar o acesso.", + "dashboard.contractExpired.buttonTitle": "Fale conosco", "loading": "Carregando…", "untitled": "Sem título", "empty_value": "valor vazio", + "deleted_value": "valor excluído", "gs.list.cancel": "Cancelar", "gs.list.apply": "Aplicar", "gs.list.only": "Só", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Interação configurada.", "messages.drill.InteractionUpdatedSuccess": "Interação atualizada.", "filterBar.label": "Filtros", + "filterBar.restrictedFilters.remove": "Remover filtros restritos", + "filterBar.restrictedFilters.reason": "{count, plural, one {Você não tem acesso a # filtro.} other {Você não tem acesso a # filtros.}}", + "filterBar.restrictedFilters": "{count, plural, one {# filtro não foi aplicado} other {# filtros não foram aplicados}}", "filterBar.showAll": "Exibir tudo", "filterBar.showLess": "Exibir menos", "filterBar.filterListAutoExpanded": "A lista de filtros foi expandida automaticamente", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "exportações programadas", "deleteWidgetDialog.headline": "Remover widget?", "deleteWidgetDialog.objectsMessage": "Os seguintes tipos de objetos associados ao widget {title} não funcionarão mais:", + "deleteWidgetDialog.objectsMessage.restricted": "Os seguintes tipos de objetos associados ao elemento não funcionarão mais:", "deleteWidgetDialog.alerts": "alertas", "deleteWidgetDialog.schedules": "exportações programadas", "create.dashboard": "Criar dashboard", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} não pode ser filtrado por {parentTitle}. Não há conexão entre os atributos do filtro e o modelo de dados.", "attributesDropdown.details.dataset": "Conjunto de Dados", "attributesDropdown.details.values": "Valores", + "attributesDropdown.details.definedAs": "Definido como", "attributesDropdown.details.shortening_decoration": "…e mais {count}", "layout.header.characters.left": "{currentCharactersCount}/{maximumCharactersCount} caracteres restantes", "layout.header.add.title.placeholder": "Adicione o título aqui...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "A visualização não pode ser filtrada pelo {attributeName}. Desmarque a caixa de seleção.", "configurationPanel.kpiCantBeFilteredByAttribute": "O KPI não pode ser filtrado por {attributeName}. Desmarque a caixa de seleção.", "configurationPanel.vizCantBeFilteredByDate": "A visualização não pode ser filtrada por Data. Desmarque a caixa de seleção.", + "configurationPanel.dateDatasetsLoadFailed": "Não foi possível carregar os dados de data relacionados. Feche o painel de configuração e tente novamente.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "O filtro não é aplicável a esta visualização.", "configurationPanel.mvfBlockedByRankingFilter": "Este filtro não pode ser aplicado porque a visualização usa um filtro de valores Top/bottom. Remova o filtro de valores Top/bottom para aplicar este filtro.", "configurationPanel.mvfMissingMeasure": "A métrica usada neste filtro não existe mais no espaço de trabalho.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Explorar a visualização", "configurationPanel.drillConfig.drillDown": "Detalhamento aprofundado", "configurationPanel.drillConfig.disableDrillDownTooltip": "A busca detalhada está desativada na configuração desta visualização.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Detalhar não está disponível para atributos calculados.", "configurationPanel.drillConfig.drillIntoUrl": "Detalhar URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Parâmetros inválidos da URL", "configurationPanel.drillConfig.select": "Escolher ação…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Excluir rich text?", "richText.deleteDialog.message": "O rich text e todo o seu conteúdo serão excluídos, isso não pode ser desfeito.", "richText.emptyContent": "Sem conteúdo de rich text", + "visualizationSwitcher.restrictedEntry": "Restrito", "visualizationSwitcher.emptyContent": "Nenhuma visualização no switcher", "visualizationSwitcherToolbar.visualizationsList.header": "Visualizações", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Visualizações", @@ -809,6 +823,7 @@ "granularity.hour": "hora", "granularity.minute": "minuto", "widget.options.menu.export": "Exportar", + "insightMenu.restrictedWidget.options": "Opções da visualização restrita", "menu.close": "Fechar menu", "controlButtons.asTable": "Mostrar como tabela", "controlButtons.asOriginal": "Mostrar visualização original", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/pt-PT.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/pt-PT.json index ac15c77b3b1..38214cf9bab 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/pt-PT.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/pt-PT.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "A sua avaliação terminou.", + "dashboard.contractExpired.trial.description": "Contacte-nos se pretender continuar a usar o GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "O seu acesso encontra-se bloqueado.", + "dashboard.contractExpired.nonTrial.description": "Para recuperar o acesso, contacte o administrador de conta.", + "dashboard.contractExpired.buttonTitle": "Contacte-nos", "loading": "A carregar…", "untitled": "Sem título", "empty_value": "valor vazio", + "deleted_value": "valor eliminado", "gs.list.cancel": "Cancelar", "gs.list.apply": "Aplicar", "gs.list.only": "Só", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Interação configurada.", "messages.drill.InteractionUpdatedSuccess": "Interação atualizada.", "filterBar.label": "Filtros", + "filterBar.restrictedFilters.remove": "Remover filtros restritos", + "filterBar.restrictedFilters.reason": "{count, plural, one {Você não tem acesso a # filtro.} other {Você não tem acesso a # filtros.}}", + "filterBar.restrictedFilters": "{count, plural, one {# filtro não foi aplicado} other {# filtros não foram aplicados}}", "filterBar.showAll": "Mostrar tudo", "filterBar.showLess": "Mostrar menos", "filterBar.filterListAutoExpanded": "A lista de filtros foi expandida automaticamente", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "Exportações programadas", "deleteWidgetDialog.headline": "Remover widget?", "deleteWidgetDialog.objectsMessage": "Os seguintes tipos de objetos associados ao widget {title} deixarão de funcionar:", + "deleteWidgetDialog.objectsMessage.restricted": "Os seguintes tipos de objetos associados ao elemento deixarão de funcionar:", "deleteWidgetDialog.alerts": "Alertas", "deleteWidgetDialog.schedules": "Exportações programadas", "create.dashboard": "Criar dashboard", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} não pode ser filtrado por {parentTitle}. Não há ligação entre os atributos de filtro no modelo de dados.", "attributesDropdown.details.dataset": "Conjunto de dados", "attributesDropdown.details.values": "Valores", + "attributesDropdown.details.definedAs": "Definido como", "attributesDropdown.details.shortening_decoration": "…e {count} mais", "layout.header.characters.left": "{currentCharactersCount} / {maximumCharactersCount} carateres remanescentes", "layout.header.add.title.placeholder": "Adicionar Título aqui...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "A visualização não pode ser filtrada por {attributeName}. Desmarque a caixa de seleção.", "configurationPanel.kpiCantBeFilteredByAttribute": "Não é possível filtrar o kpi por {attributeName}. Desmarque a caixa de verificação.", "configurationPanel.vizCantBeFilteredByDate": "A visualização não pode ser filtrada por Data. Desmarque a caixa de seleção.", + "configurationPanel.dateDatasetsLoadFailed": "Não foi possível carregar os dados de data relacionados. Feche o painel de configuração e tente novamente.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "O filtro não é aplicável a esta visualização.", "configurationPanel.mvfBlockedByRankingFilter": "Este filtro não pode ser aplicado porque a visualização utiliza um filtro de Valores superiores/inferiores. Remova o filtro de Valores superiores/inferiores para aplicar este filtro.", "configurationPanel.mvfMissingMeasure": "A métrica usada neste filtro não existe mais no espaço de trabalho.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Aprofunde-se na visualização", "configurationPanel.drillConfig.drillDown": "Exploração descendente", "configurationPanel.drillConfig.disableDrillDownTooltip": "A pesquisa detalhada está desativada na configuração desta visualização.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Detalhar não está disponível para atributos calculados.", "configurationPanel.drillConfig.drillIntoUrl": "Aprofundar URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Parâmetros de URL inválidos", "configurationPanel.drillConfig.select": "Escolher ação…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Eliminar Rich Text?", "richText.deleteDialog.message": "O Rich Text e todo o seu conteúdo será eliminado de forma irreversível.", "richText.emptyContent": "Nenhum conteúdo Rich Text", + "visualizationSwitcher.restrictedEntry": "Restrito", "visualizationSwitcher.emptyContent": "Nenhuma visualização no alternador", "visualizationSwitcherToolbar.visualizationsList.header": "Visualizações", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Visualizações", @@ -809,6 +823,7 @@ "granularity.hour": "hora", "granularity.minute": "minuto", "widget.options.menu.export": "Exportar", + "insightMenu.restrictedWidget.options": "Opções de visualização restrita", "menu.close": "Fechar menu", "controlButtons.asTable": "Mostrar como tabela", "controlButtons.asOriginal": "Mostrar visualização original", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/ru-RU.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/ru-RU.json index bc3677566d5..bc165ab66aa 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/ru-RU.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/ru-RU.json @@ -1,13 +1,19 @@ { + "dashboard.contractExpired.trial.title": "Срок действия вашей пробной версии истек.", + "dashboard.contractExpired.trial.description": "Свяжитесь с нами, если вы хотите продолжить использование GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "Ваш доступ заблокирован.", + "dashboard.contractExpired.nonTrial.description": "Обратитесь к администратору учетной записи, чтобы восстановить доступ.", + "dashboard.contractExpired.buttonTitle": "Связаться с нами", "loading": "Загрузка…", "untitled": "Без названия", "empty_value": "значение отсутствует", + "deleted_value": "удаленное значение", "gs.list.cancel": "Отмена", "gs.list.apply": "Применить", "gs.list.only": "Только", "attributesDropdown.onlyLabel": "Выбрать только {itemTitle}", "messages.dashboardSaveSuccess": "Отлично. Мы сохранили ваш дашборд.", - "options.menu.save.as": "Сохранить как новую", + "options.menu.save.as": "Сохранить как новый", "options.menu.save.as.tooltip": "Пустой дашборд нельзя сохранить.", "options.menu.settings": "Настройки", "messages.dashboardSaveFailed": "Не удалось сохранить дашборд, повторите попытку.", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Взаимодействие настроено.", "messages.drill.InteractionUpdatedSuccess": "Взаимодействие обновлено.", "filterBar.label": "Фильтры", + "filterBar.restrictedFilters.remove": "Удалить фильтры с ограниченным доступом", + "filterBar.restrictedFilters.reason": "{count, plural, one {У вас нет доступа к # фильтру.} few {У вас нет доступа к # фильтрам.} many {У вас нет доступа к # фильтрам.} other {У вас нет доступа к # фильтрам.}}", + "filterBar.restrictedFilters": "{count, plural, one {# фильтр не применен} few {# фильтра не применены} many {# фильтров не применены} other {# фильтра не применено}}", "filterBar.showAll": "Показать все", "filterBar.showLess": "Скрыть", "filterBar.filterListAutoExpanded": "Список фильтров был автоматически развернут", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "запланированные экспорты", "deleteWidgetDialog.headline": "Удалить виджет?", "deleteWidgetDialog.objectsMessage": "Следующие типы объектов, связанных с виджетом {title}, перестанут работать:", + "deleteWidgetDialog.objectsMessage.restricted": "Следующие типы объектов, связанных с виджетом, перестанут работать:", "deleteWidgetDialog.alerts": "оповещения", "deleteWidgetDialog.schedules": "запланированные экспорты", "create.dashboard": "Создать дашборд", @@ -198,7 +208,7 @@ "dialogs.schedule.email.recipients.note": "Примечание: Все получатели, помеченные как «(гость)», получат тот же вид дашборда, что и вы.", "dialogs.schedule.email.subject.label": "Тема:", "dialogs.schedule.email.recipients.label": "Получателей", - "dialogs.schedule.email.filters": "Дашборд содержит изменения фильтра, которые будут сохранены в расписании.", + "dialogs.schedule.email.filters": "Фильтры ({count})", "dialogs.schedule.email.tabs.general": "Общие", "dialogs.schedule.email.tabs.filters": "Фильтры", "dialogs.schedule.email.destination": "Направление", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} нельзя фильтровать по {parentTitle}. В модели данных нет связи между атрибутами фильтра.", "attributesDropdown.details.dataset": "Датасет", "attributesDropdown.details.values": "Значения", + "attributesDropdown.details.definedAs": "Определяется как", "attributesDropdown.details.shortening_decoration": "…и еще {count}", "layout.header.characters.left": "осталось символов: {currentCharactersCount}/{maximumCharactersCount}", "layout.header.add.title.placeholder": "Добавьте заголовок здесь...", @@ -443,7 +454,7 @@ "visualizationsList.noVisualizationsFound": "Подходящих визуализаций не найдено.", "search_insights": "Найти по всем визуализациям…", "search_insights.similar": "Похожие", - "save.as.new": "Сохранить как новую", + "save.as.new": "Сохранить как новый", "addPanel.deleteItem": "Сбросьте, чтобы удалить", "addPanel.newItem": "Новый элемент", "addPanel.attributeFilter": "Фильтр атрибутов", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "Эту визуализацию нельзя фильтровать по {attributeName}. Снимите флажок.", "configurationPanel.kpiCantBeFilteredByAttribute": "Этот КПЭ нельзя фильтровать по {attributeName}. Снимите флажок.", "configurationPanel.vizCantBeFilteredByDate": "Эту визуализацию нельзя фильтровать по дате. Снимите флажок.", + "configurationPanel.dateDatasetsLoadFailed": "Не удалось загрузить связанные данные о датах. Закройте панель конфигурации и повторите попытку.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Фильтр неприменим к этой визуализации.", "configurationPanel.mvfBlockedByRankingFilter": "Этот фильтр нельзя применить, потому что в визуализации используется фильтр значений Top/bottom. Чтобы применить этот фильтр, удалите фильтр значений Top/bottom.", "configurationPanel.mvfMissingMeasure": "Показатель, используемый в этом фильтре, больше не существует в рабочей области.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Дрил в визуализацию", "configurationPanel.drillConfig.drillDown": "Углубиться", "configurationPanel.drillConfig.disableDrillDownTooltip": "Детализация отключена в конфигурации этого анализа.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Детализация недоступна для вычисляемых атрибутов.", "configurationPanel.drillConfig.drillIntoUrl": "Углубиться в URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Неверные параметры URL", "configurationPanel.drillConfig.select": "Выбрать действие…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Удалить форматированный текст?", "richText.deleteDialog.message": "Форматированный текст и всё его содержимое будут безвозвратно удалены.", "richText.emptyContent": "Нет содержимого форматированного текста", + "visualizationSwitcher.restrictedEntry": "Ограничено", "visualizationSwitcher.emptyContent": "В переключателе нет визуализации", "visualizationSwitcherToolbar.visualizationsList.header": "Анализы", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Анализы", @@ -809,6 +823,7 @@ "granularity.hour": "час", "granularity.minute": "минута", "widget.options.menu.export": "Экспортировать", + "insightMenu.restrictedWidget.options": "Параметры визуализации с ограниченным доступом", "menu.close": "Закрыть меню", "controlButtons.asTable": "Показать в виде таблицы", "controlButtons.asOriginal": "Показать исходную визуализацию", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/sl-SI.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/sl-SI.json index 11371cb6adf..c20402083c2 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/sl-SI.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/sl-SI.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Vaša preizkusna različica se je končala.", + "dashboard.contractExpired.trial.description": "Kontaktirajte nas, če želite še naprej uporabljati GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "Vaš dostop je zaklenjen.", + "dashboard.contractExpired.nonTrial.description": "Za ponovno pridobitev dostopa kontaktirajte skrbnika računa.", + "dashboard.contractExpired.buttonTitle": "Kontaktirajte nas", "loading": "Nalaganje…", "untitled": "Brez naslova", "empty_value": "prazna vrednost", + "deleted_value": "izbrisana vrednost", "gs.list.cancel": "Prekliči", "gs.list.apply": "Uporabi", "gs.list.only": "Samo", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Interakcija nastavljena.", "messages.drill.InteractionUpdatedSuccess": "Interakcija posodobljena.", "filterBar.label": "Filtri", + "filterBar.restrictedFilters.remove": "Odstrani omejene filtre", + "filterBar.restrictedFilters.reason": "{count, plural, one {Nimate dostopa do # filtra.} two {Nimate dostopa do # filtrov.} few {Nimate dostopa do # filtrov.} other {Nimate dostopa do # filtrov.}}", + "filterBar.restrictedFilters": "{count, plural, one {# filter ni bil uporabljen} two {# filtra nista bila uporabljena} few {# filtri niso bili uporabljeni} other {# filtrov ni bilo uporabljenih}}", "filterBar.showAll": "Prikaži vse", "filterBar.showLess": "Prikaži manj", "filterBar.filterListAutoExpanded": "Seznam filtrov je bil samodejno razširjen", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "načrtovani izvozi", "deleteWidgetDialog.headline": "Odstraniti gradnik?", "deleteWidgetDialog.objectsMessage": "Naslednji tipi objektov, povezani z gradnikom {title}, ne bodo več delovali:", + "deleteWidgetDialog.objectsMessage.restricted": "Naslednje vrste objektov, povezane z gradnikom, ne bodo več delovale:", "deleteWidgetDialog.alerts": "opozorila", "deleteWidgetDialog.schedules": "načrtovani izvozi", "create.dashboard": "Ustvari nadzorno ploščo", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} ni mogoče filtrirati po {parentTitle}. V modelu podatkov ni povezave med atributoma filtra.", "attributesDropdown.details.dataset": "Podatkovni sklop", "attributesDropdown.details.values": "Vrednosti", + "attributesDropdown.details.definedAs": "Določeno kot", "attributesDropdown.details.shortening_decoration": "…in še {count} drugih", "layout.header.characters.left": "{currentCharactersCount} / {maximumCharactersCount} znakov preostane", "layout.header.add.title.placeholder": "Dodajte naslov tukaj...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "Vizualizacije ni mogoče filtrirati glede na {attributeName}. Odznačite potrditveno polje.", "configurationPanel.kpiCantBeFilteredByAttribute": "KPI-ja ni mogoče filtrirati glede na {attributeName}. Odznačite potrditveno polje.", "configurationPanel.vizCantBeFilteredByDate": "Vizualizacije ni mogoče filtrirati po datumu. Odznačite potrditveno polje.", + "configurationPanel.dateDatasetsLoadFailed": "Povezanih datumskih podatkov ni bilo mogoče naložiti. Zaprite podokno za konfiguracijo in poskusite znova.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Filter ni uporaben za to vizualizacijo.", "configurationPanel.mvfBlockedByRankingFilter": "Tega filtra ni mogoče uporabiti, ker vizualizacija uporablja filter Najvišje/najnižje vrednosti. Odstranite filter Najvišje/najnižje vrednosti, da uporabite ta filter.", "configurationPanel.mvfMissingMeasure": "Metrika, uporabljena v tem filtru, ne obstaja več v delovnem prostoru.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Poglobitev v vizualizacijo", "configurationPanel.drillConfig.drillDown": "Poglobiti se", "configurationPanel.drillConfig.disableDrillDownTooltip": "Poglobitev je izključena v tej konfiguraciji vizualizacije.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Drilldown ni na voljo za izračunane atribute.", "configurationPanel.drillConfig.drillIntoUrl": "Poglobitev v URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Neveljavni URL parametri", "configurationPanel.drillConfig.select": "Izberi dejanje…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Želite izbrisati obogateno besedilo?", "richText.deleteDialog.message": "Obogateno besedilo in vsa njegova vsebina bosta nepreklicno izbrisana.", "richText.emptyContent": "Ni vsebine obogatenega besedila", + "visualizationSwitcher.restrictedEntry": "Omejeno", "visualizationSwitcher.emptyContent": "Brez vizualizacije v preklopniku", "visualizationSwitcherToolbar.visualizationsList.header": "Vizualizacije", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Vizualizacije", @@ -809,6 +823,7 @@ "granularity.hour": "ura", "granularity.minute": "minuta", "widget.options.menu.export": "Izvozi", + "insightMenu.restrictedWidget.options": "Možnosti omejene vizualizacije", "menu.close": "Zapri meni", "controlButtons.asTable": "Pokaži kot tabela", "controlButtons.asOriginal": "Pokaži kot prvotna vizualizacija", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/th-TH.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/th-TH.json index 64da2a9b067..f714870cb12 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/th-TH.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/th-TH.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "ช่วงทดลองใช้ของคุณสิ้นสุดแล้ว.", + "dashboard.contractExpired.trial.description": "ติดต่อเราหากคุณต้องการใช้งาน GoodData Cloud ต่อไป", + "dashboard.contractExpired.nonTrial.title": "การเข้าถึงของคุณถูกล็อก.", + "dashboard.contractExpired.nonTrial.description": "ติดต่อผู้ดูแลระบบบัญชีเพื่อรับการเข้าถึงอีกครั้ง", + "dashboard.contractExpired.buttonTitle": "ติดต่อเรา", "loading": "กำลังโหลด…", "untitled": "ไม่มีชื่อ", "empty_value": "ค่าว่าง", + "deleted_value": "ค่าที่ถูกลบ", "gs.list.cancel": "ยกเลิก", "gs.list.apply": "นำไปใช้", "gs.list.only": "เท่านั้น", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "กำหนดค่าการโต้ตอบแล้ว", "messages.drill.InteractionUpdatedSuccess": "อัปเดตการโต้ตอบแล้ว", "filterBar.label": "ตัวกรอง", + "filterBar.restrictedFilters.remove": "ลบตัวกรองที่ถูกจำกัด", + "filterBar.restrictedFilters.reason": "{count, plural, other {คุณไม่มีสิทธิ์เข้าถึงตัวกรอง # รายการ}}", + "filterBar.restrictedFilters": "{count, plural, other {ไม่ได้ใช้ตัวกรอง # รายการ}}", "filterBar.showAll": "แสดงทั้งหมด", "filterBar.showLess": "แสดงน้อยลง", "filterBar.filterListAutoExpanded": "รายการตัวกรองถูกขยายโดยอัตโนมัติ", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "การส่งออกตามกำหนดการ", "deleteWidgetDialog.headline": "นำวิดเจ็ตออกหรือไม่?", "deleteWidgetDialog.objectsMessage": "อ็อบเจ็กต์ประเภทต่อไปนี้ที่เชื่อมโยงกับวิดเจ็ต {title} จะไม่ทำงานอีกต่อไป:", + "deleteWidgetDialog.objectsMessage.restricted": "อ็อบเจ็กต์ประเภทต่อไปนี้ที่เชื่อมโยงกับวิดเจ็ตจะไม่ทำงานอีกต่อไป:", "deleteWidgetDialog.alerts": "การแจ้งเตือน", "deleteWidgetDialog.schedules": "การส่งออกตามกำหนดการ", "create.dashboard": "สร้างแดชบอร์ด", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} ไม่สามารถถูกกรองโดย {parentTitle} ไม่มีการเชื่อมต่อระหว่างแอตทริบิวต์ของตัวกรองในแบบจำลองข้อมูล", "attributesDropdown.details.dataset": "ชุดข้อมูล", "attributesDropdown.details.values": "ค่า", + "attributesDropdown.details.definedAs": "กำหนดเป็น", "attributesDropdown.details.shortening_decoration": "…และอีก {count} รายการ", "layout.header.characters.left": "เหลืออีก {currentCharactersCount} / {maximumCharactersCount} อักขระ", "layout.header.add.title.placeholder": "เพิ่มชื่อที่นี่...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "การแสดงภาพข้อมูลไม่สามารถถูกกรองโดย {attributeName} ได้ ยกเลิกการเลือกช่องทำเครื่องหมาย", "configurationPanel.kpiCantBeFilteredByAttribute": "KPI ไม่สามารถถูกกรองโดย {attributeName} ได้ ยกเลิกการเลือกช่องทำเครื่องหมาย", "configurationPanel.vizCantBeFilteredByDate": "การแสดงภาพข้อมูลไม่สามารถถูกกรองตามวันที่ได้ ยกเลิกการเลือกช่องทำเครื่องหมาย", + "configurationPanel.dateDatasetsLoadFailed": "ไม่สามารถโหลดข้อมูลวันที่ที่เกี่ยวข้องได้ ปิดแผงการกำหนดค่าแล้วลองอีกครั้ง", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "ตัวกรองไม่สามารถใช้ได้กับการแสดงภาพข้อมูลนี้", "configurationPanel.mvfBlockedByRankingFilter": "ไม่สามารถใช้ตัวกรองนี้ได้ เนื่องจากการแสดงภาพข้อมูลใช้ตัวกรองค่าบนสุด/ล่างสุด นำตัวกรองค่าบนสุด/ล่างสุดออกเพื่อใช้ตัวกรองนี้", "configurationPanel.mvfMissingMeasure": "เมตริกที่ใช้ในตัวกรองนี้ไม่มีอยู่ในพื้นที่ทำงานอีกต่อไป", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "เจาะลึกไปยังการแสดงภาพข้อมูล", "configurationPanel.drillConfig.drillDown": "เจาะลึกลง", "configurationPanel.drillConfig.disableDrillDownTooltip": "การเจาะลึกลงถูกปิดในกำหนดค่าของการแสดงภาพข้อมูลนี้", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "การเจาะลึกลงไม่พร้อมใช้งานสำหรับแอตทริบิวต์ที่คำนวณ", "configurationPanel.drillConfig.drillIntoUrl": "เจาะลึกไปยัง URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "พารามิเตอร์ URL ไม่ถูกต้อง", "configurationPanel.drillConfig.select": "เลือกการดำเนินการ…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "ลบ Rich Text หรือไม่?", "richText.deleteDialog.message": "Rich Text และเนื้อหาทั้งหมดจะถูกลบอย่างไม่สามารถย้อนกลับได้", "richText.emptyContent": "ไม่มีเนื้อหา Rich Text", + "visualizationSwitcher.restrictedEntry": "ถูกจำกัด", "visualizationSwitcher.emptyContent": "ไม่มีการแสดงภาพข้อมูลในตัวสลับ", "visualizationSwitcherToolbar.visualizationsList.header": "การแสดงภาพข้อมูล", "visualizationSwitcherToolbar.visualizationsList.tooltip": "การแสดงภาพข้อมูล", @@ -809,6 +823,7 @@ "granularity.hour": "ชั่วโมง", "granularity.minute": "นาที", "widget.options.menu.export": "ส่งออก", + "insightMenu.restrictedWidget.options": "ตัวเลือกการแสดงภาพข้อมูลที่ถูกจำกัด", "menu.close": "ปิดเมนู", "controlButtons.asTable": "แสดงเป็นตาราง", "controlButtons.asOriginal": "แสดงการแสดงภาพข้อมูลเดิม", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/tr-TR.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/tr-TR.json index 52c3fab056b..7ee5f6e6b36 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/tr-TR.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/tr-TR.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Deneme süreniz sona erdi.", + "dashboard.contractExpired.trial.description": "GoodData Cloud'u kullanmaya devam etmek istiyorsanız bizimle iletişime geçin.", + "dashboard.contractExpired.nonTrial.title": "Erişiminiz kilitlendi.", + "dashboard.contractExpired.nonTrial.description": "Erişimi yeniden kazanmak için hesap yöneticisiyle iletişime geçin.", + "dashboard.contractExpired.buttonTitle": "Bize Ulaşın", "loading": "Yükleniyor…", "untitled": "Başlıksız", "empty_value": "boş değer", + "deleted_value": "silinmiş değer", "gs.list.cancel": "İptal", "gs.list.apply": "Uygula", "gs.list.only": "Yalnızca", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Etkileşim yapılandırıldı.", "messages.drill.InteractionUpdatedSuccess": "Etkileşim güncellendi.", "filterBar.label": "Filtreler", + "filterBar.restrictedFilters.remove": "Kısıtlı filtreleri kaldır", + "filterBar.restrictedFilters.reason": "{count, plural, one {# filtreye erişiminiz yok.} other {# filtreye erişiminiz yok.}}", + "filterBar.restrictedFilters": "{count, plural, one {# filtre uygulanmadı} other {# filtre uygulanmadı}}", "filterBar.showAll": "Tümünü göster", "filterBar.showLess": "Daha az göster", "filterBar.filterListAutoExpanded": "Filtre listesi otomatik olarak genişletildi", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "zamanlanmış dışa aktarımlar", "deleteWidgetDialog.headline": "Widget kaldırılsın mı?", "deleteWidgetDialog.objectsMessage": "Aşağıdaki türdeki widget {title} ile ilişkili nesneler artık çalışmayacak:", + "deleteWidgetDialog.objectsMessage.restricted": "Öğeyle ilişkili aşağıdaki nesne türleri artık çalışmayacak:", "deleteWidgetDialog.alerts": "uyarılar", "deleteWidgetDialog.schedules": "zamanlanmış dışa aktarımlar", "create.dashboard": "Gösterge tablosu oluştur", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle}, {parentTitle} ile filtrelenemez. Veri modelinde filtre öznitelikleri arasında bağlantı yok.", "attributesDropdown.details.dataset": "Veri kümesi", "attributesDropdown.details.values": "Değerler", + "attributesDropdown.details.definedAs": "Şöyle tanımlanır", "attributesDropdown.details.shortening_decoration": "…ve {count} daha fazla", "layout.header.characters.left": "{currentCharactersCount} / {maximumCharactersCount} karakter kaldı", "layout.header.add.title.placeholder": "Buraya Başlık Ekleyin...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "Görselleştirme {attributeName} ile filtrelenemez. Onay kutusunun işaretini kaldırın.", "configurationPanel.kpiCantBeFilteredByAttribute": "KPI, {attributeName} tarafından filtrelenemez. Onay kutusunun işaretini kaldırın.", "configurationPanel.vizCantBeFilteredByDate": "Görselleştirme Tarihe göre filtrelenemez. Onay kutusunun işaretini kaldırın.", + "configurationPanel.dateDatasetsLoadFailed": "İlgili tarih verileri yüklenemedi. Yapılandırma panelini kapatıp tekrar deneyin.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Filtre bu görselleştirme için uygulanamaz.", "configurationPanel.mvfBlockedByRankingFilter": "Bu filtre, görselleştirme bir En üst/En alt değerler filtresi kullandığı için uygulanamaz. Bu filtreyi uygulamak için En üst/En alt değerler filtresini kaldırın.", "configurationPanel.mvfMissingMeasure": "Bu filtrede kullanılan metrik artık çalışma alanında mevcut değil.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Görselleştirmeye derinlemesine inceleme yap", "configurationPanel.drillConfig.drillDown": "Detayına in", "configurationPanel.drillConfig.disableDrillDownTooltip": "Bu görselleştirmenin yapılandırmasında ayrıntıya inme devre dışı bırakılmış.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Hesaplanan öznitelikler için ayrıntıya inilemez.", "configurationPanel.drillConfig.drillIntoUrl": "URL'yi ayrıntılı incele", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Geçersiz URL parametreleri", "configurationPanel.drillConfig.select": "Eylem seçin…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Zengin metin silinsin mi?", "richText.deleteDialog.message": "Zengin metin ve tüm içeriği geri döndürülemez şekilde silinecektir.", "richText.emptyContent": "Zengin metin içeriği yok", + "visualizationSwitcher.restrictedEntry": "Kısıtlı", "visualizationSwitcher.emptyContent": "Değiştiricide görselleştirme yok", "visualizationSwitcherToolbar.visualizationsList.header": "Görselleştirmeler", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Görselleştirmeler", @@ -809,6 +823,7 @@ "granularity.hour": "saat", "granularity.minute": "dakika", "widget.options.menu.export": "Dışa aktar", + "insightMenu.restrictedWidget.options": "Kısıtlanmış görselleştirme seçenekleri", "menu.close": "Menüyü kapat", "controlButtons.asTable": "Tablo olarak göster", "controlButtons.asOriginal": "Orijinal görselleştirmeyi göster", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/uk-UA.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/uk-UA.json index 0163b8c1205..bfa3135fe49 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/uk-UA.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/uk-UA.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Ваш пробний період завершився.", + "dashboard.contractExpired.trial.description": "Зв’яжіться з нами, якщо хочете й надалі користуватися GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "Ваш доступ заблоковано.", + "dashboard.contractExpired.nonTrial.description": "Зверніться до адміністратора облікового запису, щоб відновити доступ.", + "dashboard.contractExpired.buttonTitle": "Зв’язатися з нами", "loading": "Завантаження…", "untitled": "Без назви", "empty_value": "порожнє значення", + "deleted_value": "видалене значення", "gs.list.cancel": "Скасувати", "gs.list.apply": "Застосувати", "gs.list.only": "Лише", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Взаємодію налаштовано.", "messages.drill.InteractionUpdatedSuccess": "Взаємодію оновлено.", "filterBar.label": "Фільтри", + "filterBar.restrictedFilters.remove": "Видалити обмежені фільтри", + "filterBar.restrictedFilters.reason": "{count, plural, one {У вас немає доступу до # фільтра.} few {У вас немає доступу до # фільтрів.} many {У вас немає доступу до # фільтрів.} other {У вас немає доступу до # фільтра.}}", + "filterBar.restrictedFilters": "{count, plural, one {Не застосовано # фільтр} few {Не застосовано # фільтри} many {Не застосовано # фільтрів} other {Не застосовано # фільтра}}", "filterBar.showAll": "Показати все", "filterBar.showLess": "Показати менше", "filterBar.filterListAutoExpanded": "Список фільтрів було автоматично розгорнуто", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "заплановані експорти", "deleteWidgetDialog.headline": "Видалити віджет?", "deleteWidgetDialog.objectsMessage": "Наведені нижче типи об’єктів, пов’язаних із віджетом {title}, більше не працюватимуть:", + "deleteWidgetDialog.objectsMessage.restricted": "Такі типи об’єктів, пов’язаних з елементом, більше не працюватимуть:", "deleteWidgetDialog.alerts": "сповіщення", "deleteWidgetDialog.schedules": "заплановані експорти", "create.dashboard": "Створити інформаційну панель", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} не можна фільтрувати за {parentTitle}. Між атрибутами фільтра в моделі даних немає зв’язку.", "attributesDropdown.details.dataset": "Набір даних", "attributesDropdown.details.values": "Значення", + "attributesDropdown.details.definedAs": "Визначено як", "attributesDropdown.details.shortening_decoration": "…і ще {count}", "layout.header.characters.left": "Залишилося символів: {currentCharactersCount} / {maximumCharactersCount}", "layout.header.add.title.placeholder": "Додайте заголовок тут...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "Візуалізацію не можна фільтрувати за {attributeName}. Зніміть прапорець.", "configurationPanel.kpiCantBeFilteredByAttribute": "KPI не можна фільтрувати за {attributeName}. Зніміть прапорець.", "configurationPanel.vizCantBeFilteredByDate": "Візуалізацію не можна фільтрувати за датою. Зніміть прапорець.", + "configurationPanel.dateDatasetsLoadFailed": "Не вдалося завантажити пов’язані дані дат. Закрийте панель конфігурації та повторіть спробу.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Фільтр не можна застосувати до цієї візуалізації.", "configurationPanel.mvfBlockedByRankingFilter": "Цей фільтр не можна застосувати, оскільки візуалізація використовує фільтр верхніх/нижніх значень. Видаліть фільтр верхніх/нижніх значень, щоб застосувати цей фільтр.", "configurationPanel.mvfMissingMeasure": "Метрика, яка використовується в цьому фільтрі, більше не існує в робочій області.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Перейти до візуалізації", "configurationPanel.drillConfig.drillDown": "Деталізувати вниз", "configurationPanel.drillConfig.disableDrillDownTooltip": "Деталізацію вимкнено в конфігурації цієї візуалізації.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Обчислювані атрибути неможливо деталізувати.", "configurationPanel.drillConfig.drillIntoUrl": "Перейти за URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Недійсні параметри URL", "configurationPanel.drillConfig.select": "Виберіть дію…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Видалити форматований текст?", "richText.deleteDialog.message": "Форматований текст і весь його вміст буде безповоротно видалено.", "richText.emptyContent": "Немає вмісту форматованого тексту", + "visualizationSwitcher.restrictedEntry": "Обмежено", "visualizationSwitcher.emptyContent": "У перемикачі немає візуалізації", "visualizationSwitcherToolbar.visualizationsList.header": "Візуалізації", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Візуалізації", @@ -809,6 +823,7 @@ "granularity.hour": "година", "granularity.minute": "хвилина", "widget.options.menu.export": "Експортувати", + "insightMenu.restrictedWidget.options": "Параметри візуалізації з обмеженим доступом", "menu.close": "Закрити меню", "controlButtons.asTable": "Показати як таблицю", "controlButtons.asOriginal": "Показати початкову візуалізацію", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/vi-VN.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/vi-VN.json index c9193ed6665..56d3e2da19e 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/vi-VN.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/vi-VN.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "Bản dùng thử của bạn đã kết thúc.", + "dashboard.contractExpired.trial.description": "Liên hệ với chúng tôi nếu bạn muốn tiếp tục dùng GoodData Cloud.", + "dashboard.contractExpired.nonTrial.title": "Quyền truy cập của bạn đã bị khóa.", + "dashboard.contractExpired.nonTrial.description": "Liên hệ với quản trị viên tài khoản để lấy lại quyền truy cập.", + "dashboard.contractExpired.buttonTitle": "Liên hệ với chúng tôi", "loading": "Đang tải…", "untitled": "Không có tiêu đề", "empty_value": "giá trị trống", + "deleted_value": "giá trị đã xóa", "gs.list.cancel": "Hủy", "gs.list.apply": "Áp dụng", "gs.list.only": "Chỉ", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "Đã cấu hình tương tác.", "messages.drill.InteractionUpdatedSuccess": "Đã cập nhật tương tác.", "filterBar.label": "Bộ lọc", + "filterBar.restrictedFilters.remove": "Xóa các bộ lọc bị hạn chế", + "filterBar.restrictedFilters.reason": "{count, plural, other {Bạn không có quyền truy cập vào # bộ lọc.}}", + "filterBar.restrictedFilters": "{count, plural, other {# bộ lọc chưa được áp dụng}}", "filterBar.showAll": "Hiện tất cả", "filterBar.showLess": "Hiện ít", "filterBar.filterListAutoExpanded": "Danh sách bộ lọc đã được tự động mở rộng", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "các mục xuất theo lịch", "deleteWidgetDialog.headline": "Loại bỏ tiện ích?", "deleteWidgetDialog.objectsMessage": "Các loại đối tượng sau liên kết với tiện ích {title} sẽ không còn hoạt động:", + "deleteWidgetDialog.objectsMessage.restricted": "Các loại đối tượng sau đây được liên kết với tiện ích sẽ không còn hoạt động:", "deleteWidgetDialog.alerts": "cảnh báo", "deleteWidgetDialog.schedules": "các mục xuất theo lịch", "create.dashboard": "Tạo bảng điều khiển", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} không thể được lọc theo {parentTitle}. Không có kết nối giữa các thuộc tính bộ lọc trong mô hình dữ liệu.", "attributesDropdown.details.dataset": "Tập dữ liệu", "attributesDropdown.details.values": "Giá trị", + "attributesDropdown.details.definedAs": "Được định nghĩa là", "attributesDropdown.details.shortening_decoration": "…và {count} nữa", "layout.header.characters.left": "{currentCharactersCount} / {maximumCharactersCount} ký tự còn lại", "layout.header.add.title.placeholder": "Thêm Tiêu đề tại đây...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "Trực quan hóa không thể được lọc theo {attributeName}. Bỏ chọn hộp kiểm.", "configurationPanel.kpiCantBeFilteredByAttribute": "KPI không thể được lọc theo {attributeName}. Bỏ chọn hộp kiểm.", "configurationPanel.vizCantBeFilteredByDate": "Trực quan hóa không thể được lọc theo Ngày. Bỏ chọn hộp kiểm.", + "configurationPanel.dateDatasetsLoadFailed": "Không thể tải dữ liệu ngày liên quan. Hãy đóng bảng cấu hình và thử lại.", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "Bộ lọc không áp dụng được cho trực quan hóa này.", "configurationPanel.mvfBlockedByRankingFilter": "Không thể áp dụng bộ lọc này vì trực quan hóa sử dụng bộ lọc giá trị Trên cùng/dưới cùng. Hãy xóa bộ lọc giá trị Trên cùng/dưới cùng để áp dụng bộ lọc này.", "configurationPanel.mvfMissingMeasure": "Thước đo được dùng trong bộ lọc này không còn tồn tại trong không gian làm việc.", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "Đi sâu vào trực quan hóa", "configurationPanel.drillConfig.drillDown": "Đi sâu xuống", "configurationPanel.drillConfig.disableDrillDownTooltip": "Đi sâu xuống đang tắt trong cấu hình của trực quan hóa này.", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "Tính năng đi sâu xuống không khả dụng cho các thuộc tính được tính toán.", "configurationPanel.drillConfig.drillIntoUrl": "Đi sâu vào URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "Tham số URL không hợp lệ", "configurationPanel.drillConfig.select": "Chọn hành động…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "Xóa văn bản có định dạng?", "richText.deleteDialog.message": "Văn bản có định dạng và toàn bộ nội dung của nó sẽ bị xóa vĩnh viễn.", "richText.emptyContent": "Không có nội dung văn bản đa định dạng", + "visualizationSwitcher.restrictedEntry": "Bị hạn chế", "visualizationSwitcher.emptyContent": "Không có trực quan hóa trong trình chuyển đổi", "visualizationSwitcherToolbar.visualizationsList.header": "Trực quan hóa", "visualizationSwitcherToolbar.visualizationsList.tooltip": "Trực quan hóa", @@ -809,6 +823,7 @@ "granularity.hour": "giờ", "granularity.minute": "phút", "widget.options.menu.export": "Xuất", + "insightMenu.restrictedWidget.options": "Tùy chọn trực quan hóa bị hạn chế", "menu.close": "Đóng menu", "controlButtons.asTable": "Hiển thị dưới dạng bảng", "controlButtons.asOriginal": "Hiển thị trực quan hóa ban đầu", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/zh-HK.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/zh-HK.json index bbc8647ed95..90d82917ceb 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/zh-HK.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/zh-HK.json @@ -1,19 +1,25 @@ { + "dashboard.contractExpired.trial.title": "您的試用期已結束。", + "dashboard.contractExpired.trial.description": "如果您想繼續使用GoodData Cloud,請聯繫我們。", + "dashboard.contractExpired.nonTrial.title": "您的存取權限已被鎖定。", + "dashboard.contractExpired.nonTrial.description": "請與帳戶管理員聯繫以重新獲得存取權限。", + "dashboard.contractExpired.buttonTitle": "聯絡我們", "loading": "載入中...", "untitled": "《無題》", "empty_value": "空值", + "deleted_value": "已刪除值", "gs.list.cancel": "取消", "gs.list.apply": "應用", "gs.list.only": "只", "attributesDropdown.onlyLabel": "只揀{itemTitle}", - "messages.dashboardSaveSuccess": "很好. 我哋儲存咗你嘅儀錶板。", + "messages.dashboardSaveSuccess": "很好。我們已儲存您的儀表板。", "options.menu.save.as": "另存新檔", "options.menu.save.as.tooltip": "無法儲存空儀表板。", "options.menu.settings": "設置", "messages.dashboardSaveFailed": "控制面板保存失敗。 刪除任何不可用的可視化效果,然後重試,或聯繫您的管理員。", - "messages.dashboard.incompatibleDefaultFilters.title": "警告無法應用某些儀表板篩選器。 檢查篩選條件以確保你查看的數據正確無誤。", + "messages.dashboard.incompatibleDefaultFilters.title": "警告無法應用某些儀表板篩選器。 檢查篩選條件以確保您查看的數據正確無誤。", "messages.dashboard.invalidDrills.title": "一些交互已被刪除", - "messages.dashboard.invalidDrills.body.modern": "一個或多個儀表板/可視化/計量/屬性已被更改或刪除,導致從以下小組件中刪除了一些交互: {listOfWidgetTitles}", + "messages.dashboard.invalidDrills.body.modern": "一個或多個儀表板/可視化/指標/屬性已被更改或刪除,導致從以下小組件中刪除了一些交互: {listOfWidgetTitles}", "messages.dashboard.sanitizedDrills.title": "部分互動設定已更新", "messages.dashboard.sanitizedDrills.body.modern": "部分已儲存的下鑽篩選器設定不再符合目前的儀表板或可視化,並已從以下元件中移除:{listOfWidgetTitles}", "messages.dashboard.invalidCustomUrlDrills.title": "某些切入到URL交互不起作用", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "已配置交互。", "messages.drill.InteractionUpdatedSuccess": "交互已更新。", "filterBar.label": "篩選器", + "filterBar.restrictedFilters.remove": "移除受限制的篩選器", + "filterBar.restrictedFilters.reason": "{count, plural, other {您無權存取 # 個篩選器。}}", + "filterBar.restrictedFilters": "{count, plural, other {未套用 # 個篩選器}}", "filterBar.showAll": "顯示全部", "filterBar.showLess": "顯示簡要信息", "filterBar.filterListAutoExpanded": "篩選器清單已自動展開", @@ -31,7 +40,7 @@ "filterBar.invalidFilterSelection": "要應用更改,請為以下過濾器選擇有效值: {names}", "filterBar.applyFilters": "套用所有篩選器", "geochart.alternateView.tablist.label": "圖層表格", - "filterBar.executionTimestampNotificationMessage": "注意。 你正在查看最新數據,但對於任何相對日期篩選器,儀表板都將其視為{date}“今天”。", + "filterBar.executionTimestampNotificationMessage": "注意。 您正在查看最新數據,但對於任何相對日期篩選器,儀表板都將其視為{date}“今天”。", "filterBar.executionTimestampNotificationAction": "重置至今日", "options.menu.export": "匯出", "options.menu.export.header.data": "數據", @@ -86,7 +95,7 @@ "dialogs.export.pdf.pageOrientation.option.landscape": "橫向", "dialogs.export.pdf.includePageExportInfo": "包括頁面導出信息", "dialogs.schedule.email.accessibilityTitle": "定時電子郵件", - "dialogs.schedule.email.delete.success": "成功! 你排程的電子郵件已刪除。", + "dialogs.schedule.email.delete.success": "成功! 您排程的電子郵件已刪除。", "dialogs.schedule.email.submit.success": "成功! 您的儀表板已排程透過電子郵件發送。", "dialogs.schedule.email.submit.error": "無法排程儀表板。 請稍後再試。", "dialogs.schedule.email.save.success": "成功! 您的排程已儲存。", @@ -96,8 +105,8 @@ "dialogs.save.as.new.title": "將儀表板另存為新儀表板", "dialogs.save.as.new.desc": "為新儀表板指定一個新的描述性名稱,以便以後更容易找到它。", "dialogs.save.as.new.default.title": "副本 {title}", - "dialogs.save.as.new.alertsAndEmailsMessage": "警示和電子郵件計劃唔會重複", - "dialogs.save.as.new.alertsMessage": "警示唔會重複", + "dialogs.save.as.new.alertsAndEmailsMessage": "警示和電子郵件排程不會被複製", + "dialogs.save.as.new.alertsMessage": "警示不會被複製", "dialogs.save.as.new.emailsMessage": "電子郵件排程不會重複", "cancelConfirmationDialog.headline": "放棄更改?", "cancelConfirmationDialog.message": "所有更改都將丟失", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "計劃導出", "deleteWidgetDialog.headline": "刪除小部件?", "deleteWidgetDialog.objectsMessage": "與小組件{title}關聯的以下類型對象將不再有效:", + "deleteWidgetDialog.objectsMessage.restricted": "與元件關聯的以下物件類型將不再運作:", "deleteWidgetDialog.alerts": "警報", "deleteWidgetDialog.schedules": "計劃導出", "create.dashboard": "創建儀表板", @@ -149,20 +159,20 @@ "drill_modal_picker.drill_to_url.disabled.missing_attributes": "錯誤:無法鑽研。請選取包含以下內容的項目:{attributes}。", "drill_modal_picker.label": "選擇drill action", "drillModal.backToTop": "返回頁首", - "filters.alertMessage.relativePreset": "係 {calendarIcon} {range}", + "filters.alertMessage.relativePreset": "在 {calendarIcon} {range}", "filters.alertMessage.relativePreset.inPeriod": "在時期 {calendarIcon} {range}", "filters.config.warning.multipleWorkspacesConfigs": "有多個工作區日期篩選器配置與此工作區關聯。 使用了第一個。", "filters.config.warning.selectedFilterNotValid": "默認篩選器選項無效,而是使用第一個可用選項。", "filters.config.warning.allOptionsHidden": "儀表板日期篩選器配置被忽略,因為它會隱藏所有篩選器選項。", "filters.config.warning.conflictingIdentifiers": "儀表板日期篩選器配置被忽略,因為它包含具有相同標識符的日期篩選器選項。", - "filters.config.warning.workspace.notAvailable": "工作區日期篩選器配置未定義,抑或你冇存取權限。", + "filters.config.warning.workspace.notAvailable": "工作區日期篩選器配置尚未定義,或您沒有存取權限。", "filters.configurationPanel.header": "篩選器", "filters.configurationPanel.crossFiltering.toggle": "交叉篩選", - "filters.configurationPanel.crossFiltering.toggle.tooltip": "允許用戶透過單擊可視化中嘅數據啲嚟篩選儀表板。", + "filters.configurationPanel.crossFiltering.toggle.tooltip": "允許使用者透過點擊可視化中的數據點來篩選儀表板。", "filters.configurationPanel.userFilterReset.toggle": "重置", "filters.configurationPanel.userFilterReset.toggle.tooltip": "允許用戶將所有過濾器重置為默認值。", "filters.configurationPanel.userFilterSave.toggle": "自動保存上一個狀態", - "filters.configurationPanel.userFilterSave.toggle.tooltip": "允許自動保存過濾器嘅最後狀態。 当用戶返回時,佢哋嘅過濾器將保持原樣。", + "filters.configurationPanel.userFilterSave.toggle.tooltip": "允許自動儲存篩選器的最後狀態。 當使用者返回時,其篩選器將保持原樣。", "filters.configurationPanel.filterViews.toggle": "儲存視圖", "filters.configurationPanel.filterViews.toggle.tooltip": "

允許使用者將篩選器狀態儲存為個人視圖,以便以後返回。

只有儲存視圖的使用者才能訪問該視圖並將其設置為默認視圖。

", "filters.configurationPanel.persistentFiltersAcrossTabs.toggle": "跨分頁保留篩選器", @@ -170,7 +180,7 @@ "settingsDashboardDialog.sectionHeaders.dateDataset": "描述中的日期範圍", "settingsDashboardDialog.sectionHeaders.dateDataset.tooltip": "日期範圍過濾器用於章節描述中指標參考的日期數據集。", "dateDataset.autoSelect": "自動選擇", - "dateDataset.notFound": "搵唔到", + "dateDataset.notFound": "找不到", "dialogs.schedule.email.attachments.label": "附件", "dialogs.schedule.email.title.placeholder": "《無標題》時間表", "dialogs.alert.title.placeholder": "警報名稱", @@ -179,23 +189,23 @@ "dialogs.alert.accessibility.label.title": "警報名稱", "dialogs.schedule.accessibility.label.email.title": "排程名稱", "dialogs.schedule.email.message.label": "消息", - "dialogs.schedule.email.max.recipients": "錯誤:收件人過多-你最多可以加起來。{maxRecipients}", + "dialogs.schedule.email.max.recipients": "錯誤:收件人過多-您最多可以加起來。{maxRecipients}", "dialogs.schedule.email.min.recipients": "錯誤:必填字段-選擇收件人以繼續。", "dialogs.schedule.email.usersLoad.error": "錯誤:無法加載用戶-請稍後重試。", "dialogs.schedule.email.user.missing.email": "錯誤:以下收件人的電子郵件地址無效-請修復它們以繼續: {recipients}。", "dialogs.schedule.email.user.missing.email.tooltip": "錯誤:此收件人的電子郵件地址無效。", - "dialogs.schedule.email.user.invalid.external": "錯誤:以下收件人冇所需嘅訪問權限-請刪除佢哋以繼續: {recipients}。", + "dialogs.schedule.email.user.invalid.external": "錯誤:以下收件人沒有所需的存取權限 — 請移除他們以繼續:{recipients}。", "dialogs.schedule.email.user.invalid.external.tooltip": "錯誤:此收件人沒有所需的訪問權限。", "dialogs.schedule.email.user.invalid.onlyYou": "錯誤:只有您可以成為收件人-刪除其他人以繼續。", "dialogs.schedule.email.user.used.external": "電子郵件“{email}”不屬於此工作區。 接收者可能會收到敏感數據。", "dialogs.schedule.email.user.remove": "刪除 {name}", "dialogs.schedule.email.userAndEmail.remove": "刪去 {name} ({email})", - "dialogs.schedule.email.user.warning.external": "警告:外部收件人-“{email}”將收到與你相同的儀表板视圖。", + "dialogs.schedule.email.user.warning.external": "警告:外部收件人-“{email}”將收到與您相同的儀表板視圖。", "dialogs.schedule.email.user.unknown": "這是一名未知使用者,無法添加為收件人。", - "dialogs.schedule.email.user.noMatch": "冇匹配嘅使用者或組。", + "dialogs.schedule.email.user.noMatch": "沒有相符的使用者或群組。", "dialogs.schedule.email.user.notMe": "此使用者不被允許。 收件人僅能只有您。", "dialogs.schedule.email.user.guest": "(遊客)", - "dialogs.schedule.email.recipients.note": "注意:所有標記為“( guest )”的收件人都將收到與您相同的控制面板视圖。", + "dialogs.schedule.email.recipients.note": "注意:所有標記為“( guest )”的收件人都將收到與您相同的控制面板視圖。", "dialogs.schedule.email.subject.label": "主題", "dialogs.schedule.email.recipients.label": "收件人", "dialogs.schedule.email.filters": "過濾器({count})", @@ -204,7 +214,7 @@ "dialogs.schedule.email.destination": "目的地", "dialogs.schedule.email.destination.missing": "沒有可用的目的地。", "dialogs.schedule.email.destination.help": "創建目標", - "dialogs.schedule.email.message.placeholder": "你好,你預定嘅電郵已經準備就緒。 你可以喺附件中下載儀表板。", + "dialogs.schedule.email.message.placeholder": "您好,您排程的電郵已準備就緒。 您可以在附件中下載儀表板。", "dialogs.schedule.email.create": "創建", "dialogs.schedule.email.closeLabel": "關閉對話框", "dialogs.schedule.email.backLabel": "返回上一步", @@ -215,28 +225,28 @@ "dialogs.schedule.email.save": "儲存", "dialogs.schedule.email.save.executionTimestampMode": "要創建或編輯預定的匯出,請將儀表板日期重置為今日。", "dialogs.alert.save.executionTimestampMode": "要創建或編輯警報,請將儀表板日期重置為今日。", - "dialogs.schedule.email.widgetError": "錯誤:無法發送時間表 — 源小部件已被刪除。 刪除時間表或聯絡你的管理員。", - "dialogs.schedule.email.destinationWarning": "所選目標僅支持將匯出發送畀自己。", + "dialogs.schedule.email.widgetError": "錯誤:無法發送時間表 — 源小部件已被刪除。 刪除時間表或聯絡您的管理員。", + "dialogs.schedule.email.destinationWarning": "所選目標僅支援將匯出傳送給自己。", "dialogs.automation.filters.showAll": "顯示全部", - "dialogs.automation.filters.showAll.ariaDescription": "用嚟顯示所有濾鏡。", + "dialogs.automation.filters.showAll.ariaDescription": "用於顯示所有篩選器。", "dialogs.automation.filters.showLess": "顯示簡要信息", - "dialogs.automation.filters.showLess.ariaDescription": "用嚟顯示少啲濾鏡。", + "dialogs.automation.filters.showLess.ariaDescription": "用於顯示較少篩選器。", "dialogs.automation.filters.add": "添加篩選器", "dialogs.automation.filters.addDisabled": "添加過濾器已禁用 — 所有過濾器都已添加。", "dialogs.automation.filters.title": "添加篩選器", - "dialogs.automation.filters.noFilters": "冇更多可用嘅過濾器", - "dialogs.automation.filters.useFiltersMessage": "始終將呢啲篩選器用于將來嘅導出", + "dialogs.automation.filters.noFilters": "沒有更多可用的篩選器", + "dialogs.automation.filters.useFiltersMessage": "日後的匯出一律使用這些篩選器", "dialogs.automation.filters.searchAriaLabel": "搜尋過濾器", "dialogs.automation.filters.deleteAriaLabel": "除濾網", "dialogs.automation.filters.deleteTooltip": "除濾網", - "dialogs.automation.filters.lockedTooltip": "呢個過濾器係上鎖嘅,唔可以拆。", + "dialogs.automation.filters.lockedTooltip": "此篩選器已鎖定,無法移除。", "dialogs.automation.parameters.chip": "{title} 為 {value}", "automationParameters.announcement.added": "參數 {title} 已新增。", "automationParameters.announcement.removed": "參數 {title} 已移除。", "automationParameters.announcement.changed": "參數 {title} 已變更為 {value}。", - "dialogs.automation.filters.useFiltersMessage.tooltip": "選中以保留呢啲過濾器以進行每次導出。 如果未選中,導出將使用儀錶板中最新嘅默認過濾器。", + "dialogs.automation.filters.useFiltersMessage.tooltip": "勾選以在每次匯出時保留這些篩選器。 如果未勾選,匯出將使用儀表板中最新的預設篩選器。", "dialogs.automation.filters.useFiltersMessage.parameters.tooltip": "勾選以保留這些篩選器及參數值供每次匯出使用。若未勾選,匯出會使用儀表板的最新預設值。", - "dialogs.automation.filters.activeFilters": "注意:呢啲過濾器將始終用于將來嘅導出。", + "dialogs.automation.filters.activeFilters": "注意:這些篩選器將一律用於日後的匯出。", "dialogs.schedule.email.timezone": "時區", "dialogs.automation.timezone.default": "預設", "dialogs.automation.timezone.default.tooltip": "遵循為儀表板設定的時區;如儀表板未設定時區,則遵循為您的組織、工作區或使用者帳戶設定的時區。如該設定變更,時區會自動更新。", @@ -256,7 +266,7 @@ "dialogs.automation.applyCurrentFilters.schedule.confirm": "警告:創建此計劃時使用的某些篩選器不再可用或無效。 編輯將應用當前的控制面板過濾器。", "dialogs.automation.applyCurrentFilters.schedule.timezone.confirm": "警告:建立此計劃時所用的時區不再與儀表板相符。編輯將套用儀表板目前的時區。", "dialogs.automation.applyCurrentFilters.schedule.filtersAndTimezone.confirm": "警告:建立此計劃時所用的部分篩選器和時區不再可用或有效。編輯將套用目前的儀表板篩選器和時區。", - "dialogs.automation.filters.schedule.ariaLabel": "有關選項嘅信息:將來導出時,請始終使用呢啲過濾器。", + "dialogs.automation.filters.schedule.ariaLabel": "有關此選項的資訊:日後匯出時一律使用這些篩選器。", "dialogs.schedule.management.title": "排程匯出", "dialogs.schedule.management.delete.dialog": "刪除排程?", "dialogs.schedule.management.delete.dialog.confirm": "該排程 將被永久刪除。", @@ -264,7 +274,7 @@ "dialogs.schedule.management.create": "創建", "dialogs.schedule.management.create.new": "創新", "dialogs.schedule.management.create.tooManyMessage": "您的組織已達到計劃導出的限制。 請與您的管理員聯繫以創建更多。", - "dialogs.schedule.management.noSchedules": "冇計劃嘅導出。{br}新建。", + "dialogs.schedule.management.noSchedules": "沒有已排程的匯出。{br}新建。", "dialogs.schedule.management.attachments.xlsx.settings": "XLSX選項", "dialogs.schedule.management.attachments.csv.settings": "CSV 選項", "dialogs.schedule.management.attachments.cells.merged": "保持屬性儲存格合併", @@ -274,7 +284,7 @@ "dialogs.export.pdf.headline": "匯出設定 (.pdf)", "dialogs.schedule.management.attachments.delete": "刪除 {format} 附件", "dialogs.schedule.management.attachments.removed": "已移除 {format} 附件。", - "dialogs.schedule.management.attachments.message": "注意。 交叉篩選將唔會喺排程嘅匯出中應用。", + "dialogs.schedule.management.attachments.message": "注意。 交叉篩選將不會套用於排程的匯出中。", "scheduledEmail.attachmentFormat.widget.png": "快照(.png)", "scheduledEmail.attachmentFormat.widget.pptx": "單滑軌(.pptx)", "scheduledEmail.attachmentFormat.widget.pdf": "單滑軌(.pdf)", @@ -302,7 +312,7 @@ "dialogs.alerting.footer.title": "如何創建警示?", "dialogs.alerting.footer.title.short": "幫助", "dialogs.alerting.management.list.title": "您的警示", - "dialogs.alerting.management.noAlerts": "冇警示。", + "dialogs.alerting.management.noAlerts": "沒有警示。", "dialogs.alerting.title.placeholder": "無標題警示", "dialogs.alerting.management.delete.dialog": "刪除警示?", "dialogs.alerting.management.delete.dialog.confirm": "警報及其所有通知將被永久刪除。", @@ -322,9 +332,9 @@ "gs.date.tomorrow": "聽日", "gs.date.yesterday": "昨日", "messages.exportResultError": "無法匯出數據。 請稍後再試。", - "messages.exportResultError.tooManyRows": "出口失敗。 行太多 ({actual})。 限制係 {limit}。", + "messages.exportResultError.tooManyRows": "匯出失敗。 行數過多({actual})。 上限為 {limit}。", "messages.exportResultError.timeout": "匯出逾時。請縮小匯出範圍(較少列或欄),然後再試一次。", - "messages.exportResultRestrictedError": "你無法導出此可視化效果,因為它包含受限數據。", + "messages.exportResultRestrictedError": "您無法導出此可視化效果,因為它包含受限數據。", "messages.exportResultStart": "匯出中", "messages.exportResultSuccess": "匯出成功。", "messages.sharingChangedSuccess": "共享已更新。", @@ -332,17 +342,17 @@ "messages.shareLinkCopied": "連結已複製。", "messages.sharingDialogError.general": "無法載入共享設置。 請稍後再試。", "messages.settingsDialogError.general": "無法加載儀表板設置。 請稍後重試。", - "visualization.dataTooLarge.headline": "顯示嘅數據啲過多", + "visualization.dataTooLarge.headline": "要顯示的數據點過多", "visualization.dataTooLarge.text": "嘗試將一個或多個過濾器應用於儀表板。", - "visualization.execute_protected_report.headline": "你無權查看此報告", + "visualization.execute_protected_report.headline": "您無權查看此報告", "visualization.execute_protected_report.text": "請與管理員聯繫。", - "visualization.empty.headline": "冇啱您的篩選器選擇嘅數據", - "visualization.error.headline": "抱歉,我哋無法顯示此可視化效果", + "visualization.empty.headline": "沒有符合您篩選器選擇的數據", + "visualization.error.headline": "抱歉,我們無法顯示此可視化", "visualization.error.text": "請與管理員聯繫。", "visualization.ErrorMessageResultCacheMissing": "可視化需要更新", "visualization.ErrorDescriptionResultCacheMissing": "基礎數據已更改或過期。 重新整理頁面。", - "visualization.warning.export.too_small": "冇足夠嘅可視化空間", - "options.menu.unsupported.error": "目前無法匯出可視化效果。 嘗試應用不同的篩選器,或使用不同的計量或屬性。", + "visualization.warning.export.too_small": "可視化空間不足", + "options.menu.unsupported.error": "目前無法匯出可視化效果。 嘗試應用不同的篩選器,或使用不同的指標或屬性。", "options.menu.unsupported.loading": "目前無法匯出可視化效果。", "options.menu.unsupported.incompatibleWidget": "無法排程自定義小組件的匯出。", "options.menu.unsupported.schedulingForInsightNotEnabled": "您無法排程匯出該小組件。", @@ -378,14 +388,14 @@ "widget.drill.dialog.exportToCSV.raw": "原始(.csv)", "share.button.text": "共享", "share.button.tooltip": "共享儀表板", - "dashboard.error.empty.heading": "此儀表板係空的", + "dashboard.error.empty.heading": "此儀表板是空的", "dashboard.error.empty.text": "已刪除所有可視化效果。", "dashboard.shareDialog.underLenientControl.label": "如果其他使用者切入到此儀表板,則可以訪問此儀表板", "dashboard.shareDialog.lock.label": "只有管理員才能編輯此儀表板", "header.lockStatus.tooltip": "此儀表板已鎖定。 只有管理員才能編輯此儀表板。", "header.shareStatus.private.text": "私人", "header.shareStatus.private.strict.tooltip": "只有您可以查看和編輯此儀表板。", - "header.shareStatus.private.not.strict.tooltip": "創建者可以編輯此儀錶板。 具有適當用戶角色嘅其他使用者可以喺切入到此儀錶板時編輯此儀錶板。", + "header.shareStatus.private.not.strict.tooltip": "建立者可以編輯此儀表板。 具有適當使用者角色的其他使用者可以在向下切入到此儀表板時進行編輯。", "topBar.timezoneIndicator.label": "時區: ", "topBar.timezoneIndicator.tooltip": "時區", "dashboard.shareDialog.removeAccessGranteeTooltip": "刪除對此儀表板的存取權限。", @@ -403,7 +413,7 @@ "attributesDropdown.selectionMode.multi": "多個值", "attributesDropdown.selectionMode.multi.tooltip": "選取多於一個值。某些條件(包含、開始於、結束於)只支援單一值。", "attributesDropdown.selectionMode.single": "單值", - "attributesDropdown.selectionMode.disabled.tooltip": "如果在“篩選依據”中選擇了任何篩選器,則唔允許選擇單值。 要使用“單值”選擇,請禁用“篩選依據”中嘅所有篩選器。", + "attributesDropdown.selectionMode.disabled.tooltip": "如果在“篩選依據”中選擇了任何篩選器,則不允許使用單值選擇。 若要使用單值選擇,請停用“篩選依據”中的所有篩選器。", "attributesDropdown.selectionType.as": "如", "attributesDropdown.selectionType.listOrText": "列表或文字", "attributesDropdown.selectionType.list": "清單", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} 無法被 {parentTitle} 篩選。資料模型中的篩選器屬性之間沒有連線。", "attributesDropdown.details.dataset": "數據", "attributesDropdown.details.values": "值", + "attributesDropdown.details.definedAs": "定義為", "attributesDropdown.details.shortening_decoration": "… 同{count}更多", "layout.header.characters.left": "{currentCharactersCount} / {maximumCharactersCount} 剩餘字符數", "layout.header.add.title.placeholder": "在此處添加標題...", @@ -427,7 +438,7 @@ "controlButtons.edit.tooltip": "編輯儀表板", "controlButtons.edit.executionTimestampMode.tooltip": "要編輯儀表板,請把日期重置為今日。", "controlButtons.setting.value": "設置", - "controlButtons.setting.title": "與此儀表板相關的所有設置。 你可以更改儀表板描述交叉篩選、允許保存的篩選條件同警報評估頻率。", + "controlButtons.setting.title": "與此儀表板相關的所有設置。 您可以更改儀表板描述交叉篩選、允許保存的篩選條件同警報評估頻率。", "controlButtons.saveAndPublish.value": "儲存並發佈", "controlButtons.save.value": "儲存", "controlButtons.saveAndPublish.title": "所有更改將立即對可以存取此儀表板的每個人可見。", @@ -437,10 +448,10 @@ "controlButtons.saving.value": "儲存...", "gs.visualizationsList.tabs.all": "都", "gs.visualizationsList.tabs.my": "由我創建", - "visualizationsList.noInsights": "此工作區唔包含任何可視化效果。", + "visualizationsList.noInsights": "此工作區不包含任何可視化。", "visualizationsList.create": "創建可視化效果", "visualizationsList.noUserInsights": "未創建任何可視化效果。", - "visualizationsList.noVisualizationsFound": "冇匹配嘅可視化效果。", + "visualizationsList.noVisualizationsFound": "沒有相符的可視化。", "search_insights": "搜尋所有可視化效果…", "search_insights.similar": "相似", "save.as.new": "另存新檔", @@ -457,9 +468,9 @@ "addPanel.richTextWidget": "富文字元件", "addPanel.dashboardFilter": "儀表板篩選器", "addPanel.visualizationSwitcher": "可視化切換器", - "addPanel.visualizationSwitcher.tooltip": "把多個可視化合併到一個元素中,並使用導航下拉列表喺它們之間切換。", + "addPanel.visualizationSwitcher.tooltip": "將多個可視化合併到單一元素中,並使用導航下拉選單在它們之間切換。", "addPanel.dashboardLayout": "列容器", - "addPanel.dashboardLayout.tooltip": "創建垂直嘅Widget組,並將其放置喺分區內嘅單個列中。 非常適合堆疊多件物品。", + "addPanel.dashboardLayout.tooltip": "建立垂直的小工具群組,放置在區段內的單一欄中。 非常適合堆疊多個項目。", "addPanel.dashboardLayout.tooltip.learnMore": "瞭解更多信息", "sidebar.collapse": "收合面板", "sidebar.search": "搜尋可視化", @@ -470,8 +481,8 @@ "configurationPanel.drillConfig.targetTab": "去標籤", "configurationPanel.drillConfig.drillIntoDashboard.searchPlaceholder": "搜索所有儀表板...", "configurationPanel.drillConfig.forbiddenDashboard": "(未與您分享)", - "configurationPanel.drillConfig.forbiddenDashboard.tooltip": "儀錶板唔會與你共享,但其他用戶可以訪問此儀錶板。", - "configurationPanel.drillConfig.notSharedDashboard.tooltip": "儀錶板唔會與你共享,但所有用戶都可以訪問它,如果佢哋切入到它。", + "configurationPanel.drillConfig.forbiddenDashboard.tooltip": "儀表板未與您共享,但其他使用者可以存取此儀表板。", + "configurationPanel.drillConfig.notSharedDashboard.tooltip": "儀表板未與您共享,但所有使用者只要向下切入即可存取。", "configurationPanel.remove.form.dashboard": "從儀表板中刪除", "filterBar.filter.drop": "拖放以添加", "filterBar.filter.addFilterPlaceholder": "拖{icon}到呢度", @@ -481,38 +492,40 @@ "configurationPanel.filterBy": "篩選依據", "configurationPanel.dateAs": "如", "configurationPanel.vizCantBeFilteredByAttribute": "無法通過 {attributeName}篩選可視化效果。 取消選中該複選框。", - "configurationPanel.kpiCantBeFilteredByAttribute": "KPI唔可以透過 {attributeName}進行篩選。 取消選中該複選框。", + "configurationPanel.kpiCantBeFilteredByAttribute": "KPI 無法透過 {attributeName} 進行篩選。 請取消勾選該核取方塊。", "configurationPanel.vizCantBeFilteredByDate": "無法按日期篩選可視化效果。 取消選中該複選框。", + "configurationPanel.dateDatasetsLoadFailed": "無法載入相關日期資料。請關閉設定面板,然後再試一次。", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "篩選器不適用於此可視化。", "configurationPanel.mvfBlockedByRankingFilter": "無法套用此篩選器,因為此可視化使用了熱門/冷門值篩選器。請移除熱門/冷門值篩選器以套用此篩選器。", "configurationPanel.mvfMissingMeasure": "此篩選器中使用的指標已不再存在於工作區中。", "filters.mvf.missingMetric.tooltip": "錯誤:此篩選器中使用的指標已不再存在於工作區中。", - "configurationPanel.kpiCantBeFilteredByDate": "KPI唔可以按日期篩選。 取消選中該複選框。", + "configurationPanel.kpiCantBeFilteredByDate": "KPI 無法按日期篩選。 請取消勾選該核取方塊。", "configurationPanel.unrelatedVizDateInfo": "“{dateDataSet}”無法再應用於可視化效果。 選擇其他維度或編輯可視化效果。", - "configurationPanel.unrelatedKpiDateInfo": "“{dateDataSet}”唔可以再應用於KPI。 選擇其他維度或編輯KPI。", + "configurationPanel.unrelatedKpiDateInfo": "“{dateDataSet}”無法再套用於KPI。 請選擇其他維度或編輯KPI。", "configurationPanel.interactions": "相互作用", "configurationPanel.drillConfig.interactions": "切入交互", "configurationPanel.drillConfig.addInteraction": "添加交互", "configurationPanel.drillConfig.clickHint": "当我點擊時", - "configurationPanel.drillConfig.measureValue": "計量值", + "configurationPanel.drillConfig.measureValue": "指標值", "configurationPanel.drillConfig.attributeValue": "屬性值", - "configurationPanel.drillConfig.selectTarget": "我諗", + "configurationPanel.drillConfig.selectTarget": "我想要", "configurationPanel.drillConfig.clickHintItem": "當我點擊(值)時", "configurationPanel.drillConfig.drillIntoDashboard": "切入到儀表板", "configurationPanel.drillConfig.drillIntoInsight": "深入了解可視化效果", "configurationPanel.drillConfig.drillDown": "向下切入", "configurationPanel.drillConfig.disableDrillDownTooltip": "在此可視化的配置中,“向下切入”處於關閉狀態。", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "向下鑽取不適用於計算屬性。", "configurationPanel.drillConfig.drillIntoUrl": "切入到URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "無效的URL參數", "configurationPanel.drillConfig.select": "選擇操作...", - "configurationPanel.drillConfig.drillIntoDashboard.dateFilterWarning": "可視化效果中嘅日期屬性值唔會被傳輸以篩選目標儀錶板。", + "configurationPanel.drillConfig.drillIntoDashboard.dateFilterWarning": "可視化中的日期屬性值不會被傳輸以篩選目標儀表板。", "configurationPanel.drillConfig.filterSelection.button.withCount": "使用 {count, plural, other {# 個篩選器}}", "configurationPanel.drillConfig.filterSelection.subview.title": "篩選器", "configurationPanel.drillConfig.filterSelection.subview.tooltip": "所選篩選器會傳遞至鑽取目的地。", "configurationPanel.drillConfig.filterSelection.section.drilledDataPoint": "已鑽取的資料點", "configurationPanel.drillConfig.filterSelection.section.visualization": "可視化", "configurationPanel.drillConfig.filterSelection.section.dashboard": "儀表板", - "configurationPanel.drillConfig.filterSelection.section.metric": "計量", + "configurationPanel.drillConfig.filterSelection.section.metric": "指標", "configurationPanel.drillConfig.filterSelection.drillDownInsightFilter.tooltip": "可視化篩選器一律套用至向下鑽取。", "configurationPanel.drillConfig.filterSelection.drillDownDashboardFilter.tooltip": "儀表板篩選器一律套用至向下鑽取。", "configurationPanel.drillConfig.filterSelection.rankingFilter.tooltip": "頂部/底部篩選器無法傳遞至鑽取目的地。", @@ -533,8 +546,8 @@ "configurationPanel.visualprops.customDescription": "自定義", "configurationPanel.visualprops.customDescriptionHelp": "為此可視化效果實例添加自定義說明。", "configurationPanel.visualprops.noneDescription": "沒有", - "configurationPanel.visualprops.includeMetrics": "包括計量說明", - "configurationPanel.visualprops.includeMetricsHelp": "顯示部分,其中包含可視化計量列表及其描述。", + "configurationPanel.visualprops.includeMetrics": "包括指標說明", + "configurationPanel.visualprops.includeMetricsHelp": "顯示部分,其中包含可視化指標列表及其描述。", "configurationPanel.visualprops.descriptionPlaceholder": "添加描述...", "configurationPanel.drillIntoUrl.defaultButtonValue": "選擇網址", "configurationPanel.drillIntoUrl.attributeUrlSectionTitle": "屬性標籤中的超連結", @@ -589,7 +602,7 @@ "layout.widget.height.min": "Widget位於最小高度", "layout.widget.height.max": "細部件處於最大高度", "dropzone.new.row.desc": "拖放以建立{nbsp}新區段", - "dropzone.widget.desc": "放喺度", + "dropzone.widget.desc": "拖放至此", "dropzone.widget.last.in.row.desc": "拖放到 現有部分", "dropzone.widget.last.in.container.row.desc": "拖放到 現有容器", "deleteKpiConfirmationDialog.headline": "刪除KPI", @@ -599,7 +612,7 @@ "newDashboard.dropInsight": "液滴可視化", "attributesDropdown.filterConfiguredMessage": "{parentTitle} 已經被 {childTitle} 篩選器直接過濾或透過其他篩選器過濾。", "attributesDropdown.attributeNameWithData": "數據為", - "filter.visibilityMode.tooltip.hidden": "此篩選器係隱藏的。 它只能透過編輯模式存取。", + "filter.visibilityMode.tooltip.hidden": "此篩選器已隱藏。 只能透過編輯模式存取。", "filter.visibilityMode.tooltip.readonly.editMode": "此篩選器已鎖定。 它只能透過編輯模式進行更改。", "filter.visibilityMode.tooltip.readonly.viewMode": "此篩選器已鎖定。", "filter.resetButton.tooltip": "全部重設為預設值", @@ -622,19 +635,20 @@ "configurationPanel.respectCrossFiltering": "遵循交叉篩選", "configurationPanel.respectCrossFiltering.tooltip": "禁用此選項可忽略來自其他可視化的交叉篩選。", "richText.formattingOptions": "格式設置選項", - "richText.summaryDashboard.generating.reload": "我哋目前正喺產生儀表板摘要。請重新載入頁面,以查看產生程序是否已完成。", - "richText.summaryDashboard.generating.shortly": "我哋目前正喺產生儀表板摘要。將會喺短時間內提供。", + "richText.summaryDashboard.generating.reload": "我們目前正在產生儀表板摘要。請重新載入頁面,以查看產生程序是否已完成。", + "richText.summaryDashboard.generating.shortly": "我們目前正在產生儀表板摘要。將於短時間內提供。", "richText.summaryDashboard.failed": "儀表板摘要產生失敗。請稍後再試。", "richText.summaryDashboard.empty": "(未有可用的儀表板摘要)", "richText.deleteDialog.header": "刪除富文字?", "richText.deleteDialog.message": "富文字及其所有內容將被不可逆地刪除。", "richText.emptyContent": "無富文字內容", - "visualizationSwitcher.emptyContent": "切換器中冇可視化效果", + "visualizationSwitcher.restrictedEntry": "受限制", + "visualizationSwitcher.emptyContent": "切換器中沒有可視化", "visualizationSwitcherToolbar.visualizationsList.header": "可視化", "visualizationSwitcherToolbar.visualizationsList.tooltip": "可視化", "visualizationSwitcherToolbar.visualizationsList.prev": "以前", "visualizationSwitcherToolbar.visualizationsList.next": "下一個", - "visualizationSwitcherToolbar.visualizationsList.empty": "切換器中冇可視化效果,請添加一個以繼續。", + "visualizationSwitcherToolbar.visualizationsList.empty": "切換器中沒有可視化,請新增一個以繼續。", "visualizationSwitcherToolbar.visualizationsList.add": "添加可視化", "visualizationSwitcherToolbar.remove": "移除切換器", "visualizationSwitcher.configurationPanel.remove.from.switcher": "從切換器中刪除", @@ -654,9 +668,9 @@ "nestedLayout.emptyDropZone.message": "拖動到此處{br}添加到容器", "nestedLayout.emptyDropZone.active.message": "拖放到此處{br}添加到容器", "attributesDropdown.valuesLimiting.title": "按以下條件篩選值", - "attributesDropdown.valuesLimiting.empty": "透過應用儀錶板過濾器或添加計量嚟限制篩選器選項。", + "attributesDropdown.valuesLimiting.empty": "透過套用儀表板篩選器或新增指標來限制篩選器選項。", "attributesDropdown.valuesLimiting.addLink": "增加", - "attributesDropdown.valuesLimiting.addMetricTitle": "選擇計量", + "attributesDropdown.valuesLimiting.addMetricTitle": "選擇指標", "attributesDropdown.valuesLimiting.addFilterTitle": "選擇儀表板篩選器", "attributesDropdown.valuesLimiting.addItemTitle": "增加", "attributesDropdown.valuesLimiting.searchPlaceholder": "搜尋...", @@ -664,12 +678,12 @@ "attributesDropdown.valuesLimiting.countAttribute": "計數 {attribute}", "attributesDropdown.valuesLimiting.metricsEmpty": "無需添加更多項目。", "attributesDropdown.valuesLimiting.unknownItem": "未知項目", - "attributesDropdown.valuesLimiting.searchNoMatch": "未搵到匹配項。", + "attributesDropdown.valuesLimiting.searchNoMatch": "找不到相符的項目。", "attributesDropdown.valuesLimiting.filtersEmpty": "無需添加更多儀表板篩選器。", "attributesDropdown.valuesLimiting.addFilters.title": "儀表板篩選器", - "attributesDropdown.valuesLimiting.addFilters.description": "使用現有嘅儀錶板篩選器嚟隱藏唔相關嘅值。 ", - "attributesDropdown.valuesLimiting.addLimitingItem.title": "計量", - "attributesDropdown.valuesLimiting.addLimitingItem.description": "使用指標隱藏唔相關嘅值。 僅顯示指標結果為非null嘅值。 瞭解更多信息", + "attributesDropdown.valuesLimiting.addFilters.description": "使用現有的儀表板篩選器來隱藏不相關的值。 ", + "attributesDropdown.valuesLimiting.addLimitingItem.title": "指標", + "attributesDropdown.valuesLimiting.addLimitingItem.description": "使用指標隱藏不相關的值。 僅顯示該指標結果為非null的值。 了解更多", "attributesDropdown.valuesLimiting.commonDateFilterTitle": "{dateFilterTitle} 如 {dataSetTitle}", "attributesDropdown.valuesLimiting.addDateTitle": "選擇入住日期", "attributesDropdown.valuesLimiting.disableDateFilter": "篩選器不可用:篩選器 {dateFilterTitle} 已在使用此日期數據集。", @@ -682,11 +696,11 @@ "filters.filterViews.dropdown.unsetAsDefault": "取消設為預設值", "filters.filterViews.dropdown.unsetAsDefault.ariaLabel": "未設定 {name} 為預設", "filters.filterViews.dropdown.isDefault": "(默認)", - "filters.filterViews.dropdown.tooltip": "

視圖是儲存的篩選器集,可讓您快速返抵特定的過濾器狀態。

如果把视圖設置為默認視圖,則每次打開儀表板時,該視圖都將自動應用。

", + "filters.filterViews.dropdown.tooltip": "

視圖是儲存的篩選器集,可讓您快速返抵特定的過濾器狀態。

如果把視圖設置為默認視圖,則每次打開儀表板時,該視圖都將自動應用。

", "filters.filterViews.dropdown.newButton": "創建視圖", - "filters.filterViews.dropdown.emptyList": "你尚未儲存此儀表板的任何視圖。", + "filters.filterViews.dropdown.emptyList": "您尚未儲存此儀表板的任何視圖。", "filters.filterViews.toast.viewSaved": "很好!您的視圖已儲存。", - "filters.filterViews.toast.viewDeleted": "很好!我哋已刪除了您的視圖。", + "filters.filterViews.toast.viewDeleted": "很好!我們已刪除您的視圖。", "filters.filterViews.toast.viewApplied": "很好!您的視圖已被應用。", "filters.filterViews.toast.viewSetAsDefault": "很好!您的視圖設置為默認視圖。", "filters.filterViews.toast.viewUnsetAsDefault": "很好!您的視圖不再設置為默認視圖。", @@ -694,7 +708,7 @@ "filters.filterViews.toast.viewNotDeleted": "失敗! 您的視圖未被刪除。 請再試一次。", "filters.filterViews.toast.viewNotSetAsDefault": "失敗! 您的視圖未設置為默認視圖。 請再試一次。", "filters.filterViews.toast.viewNotUnsetAsDefault": "失敗! 您的視圖仍設置為默認視圖。 請再試一次。", - "filters.filterViews.toast.viewNotApplied": "失敗! 您的视圖未被應用。 請再試一次。", + "filters.filterViews.toast.viewNotApplied": "失敗! 您的視圖未被應用。 請再試一次。", "parameter.toast.reset": "警告: 參數「{name}」超出範圍,因此在您設定有效值之前,會套用預設值。", "parameter.toast.removed": "警告: 參數「{name}」已被移除,因為該參數已不存在。", "parameter.toast.incompatible": "警告: 參數「{name}」不再相容,已被忽略。", @@ -703,7 +717,7 @@ "filters.filterViews.list.ariaLabel.noActions": "已保存的視圖列表", "filters.filterViews.add.title": "創建視圖", "filters.filterViews.add.nameLabel": "名字", - "filters.filterViews.add.namePlaceholder": "無標題视圖", + "filters.filterViews.add.namePlaceholder": "無標題視圖", "filters.filterViews.add.setAsDefaultLabel": "設為預設值", "filters.filterViews.add.deleteTooltip": "刪除", "filters.filterViews.add.deleteTooltip.ariaLabel": "刪去 {name}", @@ -716,7 +730,7 @@ "filters.filterViews.delete.deleteButton": "刪除", "filters.filterViews.delete.cancelButton": "取消", "filters.filterViews.tooltip.ariaLabel": "有關已保存視圖的信息", - "filters.locked.filter.tooltip": "呢個過濾器上鎖咗", + "filters.locked.filter.tooltip": "此篩選器已鎖定", "insightAlert.config.action.edit": "編輯", "insightAlert.config.action.pause": "暫停", "insightAlert.config.action.resume": "取消暫停", @@ -726,12 +740,12 @@ "insightAlert.config.comparisonOperator.greaterThan": "大於", "insightAlert.config.comparisonOperator.greaterThanOrEquals": "大於或等於", "insightAlert.config.changeOperator.header": "漲跌幅%", - "insightAlert.config.changeOperator.header.info": "改變{spacer}計算主要(當前時間段)和次要(上一個時間段)計量值之間的相對變化。{spacer}公式{spacer}(小學 - 中學) / 中學", + "insightAlert.config.changeOperator.header.info": "改變{spacer}計算主要(當前時間段)和次要(上一個時間段)指標值之間的相對變化。{spacer}公式{spacer}(小學 - 中學) / 中學", "input.unit.percent": "百分比值", "insightAlert.config.differenceOperator.header": "差異 #", - "insightAlert.config.differenceOperator.header.info": "不同之處{spacer}計算主要(當前時間段)和次要(上一個時間段)計量值之間的淨差。{spacer}公式{spacer}小學 - 中學", + "insightAlert.config.differenceOperator.header.info": "不同之處{spacer}計算主要(當前時間段)和次要(上一個時間段)指標值之間的淨差。{spacer}公式{spacer}小學 - 中學", "insightAlert.config.aiOperator.header": "人工智能", - "insightAlert.config.aiOperator.header.info": "所有人工智能運算子都係基於人工智能函數。", + "insightAlert.config.aiOperator.header.info": "所有人工智能運算子都是基於人工智能函數。", "insightAlert.config.anomalyDetection": "有異常", "insightAlert.config.sensitivity": "靈敏度", "insightAlert.config.sensitivity.low": "低", @@ -757,16 +771,16 @@ "insightAlert.config.differenceOperator.decreasesBy": "減少", "insightAlert.config.differenceOperator.changesBy": "更改", "insightAlert.config.alerts": "通知", - "insightAlert.config.alerts.empty": "此可視化冇警示。", + "insightAlert.config.alerts.empty": "此可視化沒有警示。", "insightAlert.config.noAlertMeasures": "通知", - "insightAlert.config.noAlertMeasures.title": "冇可用於警示嘅計量。", - "insightAlert.config.noAlertMeasures.description": "請添加計量以啟用警示。", + "insightAlert.config.noAlertMeasures.title": "沒有可用於警示的指標。", + "insightAlert.config.noAlertMeasures.description": "請添加指標以啟用警示。", "insightAlert.config.trigger": "觸發", "insightAlert.config.interval": "觸發間隔", "insightAlert.config.interval.tooltip": "每個所選間隔最多只觸發一次(例如每天或每週一次)", - "insightAlert.config.metric": "計量", + "insightAlert.config.metric": "指標", "insightAlert.config.action": "行動", - "insightAlert.config.when": "幾時", + "insightAlert.config.when": "當", "insightAlert.config.for": "為", "insightAlert.config.condition": "條件", "insightAlert.config.threshold": "門檻", @@ -798,7 +812,7 @@ "insightAlert.config.invalidWidget": "錯誤:無法完全編輯警報 — 來源元件已被刪除。刪除警報或聯絡您的管理員。", "insightAlert.config.unusedWidget": "無法完全編輯警報 — 來源元件無法使用。", "insightAlert.config.missingThreshold": "錯誤:必填欄位 — 輸入臨界值以繼續。", - "insightAlert.config.selectMetric": "選擇計量", + "insightAlert.config.selectMetric": "選擇指標", "insightAlert.config.selectAttribute": "所有", "alert.accessibility.destination.label": "選擇發送警示的方式", "granularity.year": "年", @@ -809,17 +823,18 @@ "granularity.hour": "小時", "granularity.minute": "分鐘", "widget.options.menu.export": "匯出", + "insightMenu.restrictedWidget.options": "受限制的可視化選項", "menu.close": "關閉餐牌", "controlButtons.asTable": "顯示為表", "controlButtons.asOriginal": "顯示原始可視化", "controlButtons.announcement.switchedToTable": "可視化切換到表格視圖", "controlButtons.announcement.switchedToOriginal": "可視化畫面切換回原來的畫面", - "automationFilters.announcement.filterAdded": " {title}過濾器加咗。", - "automationFilters.announcement.filterRemoved": "去咗過濾器 {title} 。", - "automationFilters.announcement.filterChanged": "過濾器 {title} 換咗。", + "automationFilters.announcement.filterAdded": "已新增篩選器 {title}。", + "automationFilters.announcement.filterRemoved": "已移除篩選器 {title}。", + "automationFilters.announcement.filterChanged": "已變更篩選器 {title}。", "dashboard.crossFilter.success": "成功:{count, plural, one {# 過濾器} other {# 從圖表中應用的}}過濾器。", "kdaDialog.dialog.filters.title": "篩選器", - "kdaDialog.dialog.filters.noFilters": "冇濾網", + "kdaDialog.dialog.filters.noFilters": "沒有篩選器", "kdaDialog.dialog.filters.add.tooltip": "添加篩選器", "kdaDialog.dialog.filters.search": "搜尋", "kdaDialog.dialog.title": "主要驅動因素分析{metric}", @@ -837,7 +852,7 @@ "kdaDialog.replaceConfirmation.message": "已有關鍵驅動分析在進行或顯示。開始新分析會捨棄目前結果。", "kdaDialog.replaceConfirmation.stay": "留", "kdaDialog.replaceConfirmation.runAnyway": "仍然執行", - "kdaDialog.dialog.bars.metric.title": "計量", + "kdaDialog.dialog.bars.metric.title": "指標", "kdaDialog.dialog.bars.filters.title": "篩選器", "kdaDialog.dialog.bars.date.title": "日期範圍: {title}", "kdaDialog.dialog.bars.date.splitter": "對", @@ -865,7 +880,7 @@ "kdaDialog.dialog.bars.date.period.title": "期比", "kdaDialog.dialog.bars.date.period.samePeriodPreviousYear": "上年同期", "kdaDialog.dialog.bars.date.period.previousPeriod": "上一期", - "kdaDialog.dialog.keyDrives.empty": "冇關鍵驅動力", + "kdaDialog.dialog.keyDrives.empty": "沒有關鍵驅動因素", "kdaDialog.dialog.keyDriver.chart.std": "改變顯著性閾值", "kdaDialog.dialog.keyDrives.error.general.title": "抱歉,我們無法顯示關鍵驅動因素", "kdaDialog.dialog.keyDrives.error.general.description": "我們無法為此指標計算關鍵驅動因素。若問題持續,請聯絡系統管理員。", @@ -874,7 +889,7 @@ "kdaDialog.dialog.keyDrives.error.details.title": "原始錯誤響應", "kdaDialog.dialog.keyDrives.error.details.title.tooltip": "原始錯誤響應顯示有關已發生錯誤的後端信息。 它僅對管理員可見。", "drill.kda.from": "從", - "drill.kda.in": "係", + "drill.kda.in": "在", "drill.kda.drop": "下降 {where} {title}", "drill.kda.increase": "增加 {where} {title}", "drill.kda.no_change": "無變化 {where} {title}", @@ -882,7 +897,7 @@ "dashboard.tabs.default.label": "無題標籤", "dashboard.tabs.move.left": "左移", "dashboard.tabs.move.right": "移右", - "dashboard.tabs.delete.disabled-tooltip": "你唔可以刪除最後一個標籤。 當只剩下一個標籤頁時,標籤頁導航喺檢視模式下就唔會睇到。", + "dashboard.tabs.delete.disabled-tooltip": "您無法刪除最後一個分頁。 當只剩下一個分頁時,分頁導航在檢視模式下將不會顯示。", "dashboard.tabs.add-button-tooltip": "加入新標籤", "dashboard.tabs.rename": "改名", "dashboard.tabs.accessibility.label": "儀表板標籤", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/zh-Hans.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/zh-Hans.json index a96e78e2273..9772ed55cbe 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/zh-Hans.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/zh-Hans.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "您的试用已结束。", + "dashboard.contractExpired.trial.description": "如果想继续使用 GoodData Cloud,请联系我们。", + "dashboard.contractExpired.nonTrial.title": "您的访问权限已被锁定。", + "dashboard.contractExpired.nonTrial.description": "请联系账户管理员以重新获得访问权限。", + "dashboard.contractExpired.buttonTitle": "联系我们", "loading": "正在加载…", "untitled": "无标题", "empty_value": "空值", + "deleted_value": "已删除的值", "gs.list.cancel": "取消", "gs.list.apply": "应用", "gs.list.only": "仅", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "交互已配置。", "messages.drill.InteractionUpdatedSuccess": "交互已更新。", "filterBar.label": "筛选器", + "filterBar.restrictedFilters.remove": "移除受限筛选器", + "filterBar.restrictedFilters.reason": "{count, plural, other {您无权访问 # 个筛选器。}}", + "filterBar.restrictedFilters": "{count, plural, other {# 个筛选器未应用}}", "filterBar.showAll": "显示全部", "filterBar.showLess": "显示更少", "filterBar.filterListAutoExpanded": "筛选器列表已自动展开", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "计划的导出", "deleteWidgetDialog.headline": "移除小部件?", "deleteWidgetDialog.objectsMessage": "以下与小部件 {title} 关联的类型对象将无法使用:", + "deleteWidgetDialog.objectsMessage.restricted": "以下与该组件关联的对象类型将无法正常工作:", "deleteWidgetDialog.alerts": "警报", "deleteWidgetDialog.schedules": "计划的导出", "create.dashboard": "创建控制面板", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} 无法被 {parentTitle} 筛选。数据模型中的筛选器属性之间没有关联。", "attributesDropdown.details.dataset": "数据集", "attributesDropdown.details.values": "数值", + "attributesDropdown.details.definedAs": "定义为", "attributesDropdown.details.shortening_decoration": "…和另外 {count} 个", "layout.header.characters.left": "还剩 {currentCharactersCount} / {maximumCharactersCount} 个字符", "layout.header.add.title.placeholder": "在此处添加标题...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "可视化无法按 {attributeName} 筛选。请取消选中该复选框。", "configurationPanel.kpiCantBeFilteredByAttribute": "KPI 无法按 {attributeName} 筛选。请取消选中该复选框。", "configurationPanel.vizCantBeFilteredByDate": "可视化无法按日期筛选。请取消选中该复选框。", + "configurationPanel.dateDatasetsLoadFailed": "无法加载相关日期数据。请关闭配置面板,然后重试。", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "筛选器不适用于此可视化。", "configurationPanel.mvfBlockedByRankingFilter": "无法应用此筛选器,因为该可视化使用了 Top/bottom values 筛选器。请移除 Top/bottom values 筛选器以应用此筛选器。", "configurationPanel.mvfMissingMeasure": "此筛选器中使用的指标在工作区中已不存在。", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "深入可视化", "configurationPanel.drillConfig.drillDown": "深入查看", "configurationPanel.drillConfig.disableDrillDownTooltip": "在此可视化的配置中,向下钻取处于关闭状态。", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "计算属性不支持向下钻取。", "configurationPanel.drillConfig.drillIntoUrl": "深入查看 URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "URL 参数无效", "configurationPanel.drillConfig.select": "选择操作…", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "删除富文本?", "richText.deleteDialog.message": "富文本及其所有内容将被不可逆地删除。", "richText.emptyContent": "无富文本内容", + "visualizationSwitcher.restrictedEntry": "受限", "visualizationSwitcher.emptyContent": "切换器中无可视化", "visualizationSwitcherToolbar.visualizationsList.header": "可视化", "visualizationSwitcherToolbar.visualizationsList.tooltip": "可视化", @@ -809,6 +823,7 @@ "granularity.hour": "hour(小时)", "granularity.minute": "minute(分钟)", "widget.options.menu.export": "导出", + "insightMenu.restrictedWidget.options": "受限的可视化选项", "menu.close": "关闭菜单", "controlButtons.asTable": "以表格形式显示", "controlButtons.asOriginal": "显示原始可视化", diff --git a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/zh-Hant.json b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/zh-Hant.json index 44b46bbb00b..ffddb38db5b 100644 --- a/libs/sdk-ui-dashboard/src/presentation/localization/bundles/zh-Hant.json +++ b/libs/sdk-ui-dashboard/src/presentation/localization/bundles/zh-Hant.json @@ -1,7 +1,13 @@ { + "dashboard.contractExpired.trial.title": "您的試用期已結束。", + "dashboard.contractExpired.trial.description": "如果您想繼續使用 GoodData Cloud,請聯絡我們。", + "dashboard.contractExpired.nonTrial.title": "您的存取權限已被鎖定。", + "dashboard.contractExpired.nonTrial.description": "請聯絡帳戶管理員以重新獲得存取權限。", + "dashboard.contractExpired.buttonTitle": "聯絡我們", "loading": "載入中…", "untitled": "無標題", "empty_value": "空值", + "deleted_value": "刪除的值", "gs.list.cancel": "取消", "gs.list.apply": "申請", "gs.list.only": "僅有的", @@ -23,6 +29,9 @@ "messages.drill.InteractionConfiguredSuccess": "交互已配置。", "messages.drill.InteractionUpdatedSuccess": "互動已更新。", "filterBar.label": "過濾器", + "filterBar.restrictedFilters.remove": "移除受限制的篩選器", + "filterBar.restrictedFilters.reason": "{count, plural, other {您無權存取 # 個篩選器。}}", + "filterBar.restrictedFilters": "{count, plural, other {未套用 # 個篩選器}}", "filterBar.showAll": "顯示所有", "filterBar.showLess": "顯示較少", "filterBar.filterListAutoExpanded": "篩選器清單已自動展開", @@ -137,6 +146,7 @@ "deleteDashboardDialog.schedules": "預定匯出", "deleteWidgetDialog.headline": "刪除小部件?", "deleteWidgetDialog.objectsMessage": "與小部件關聯的以下類型物件{title} 將不再起作用:", + "deleteWidgetDialog.objectsMessage.restricted": "與小工具相關聯的下列物件類型將不再運作:", "deleteWidgetDialog.alerts": "警報", "deleteWidgetDialog.schedules": "預定匯出", "create.dashboard": "建立儀表板", @@ -416,6 +426,7 @@ "attributesDropdown.noConnectionMessage": "{childTitle} 無法過濾 {parentTitle}。資料模型中的過濾器屬性之間沒有任何關聯。", "attributesDropdown.details.dataset": "數據集", "attributesDropdown.details.values": "價值觀", + "attributesDropdown.details.definedAs": "定義為", "attributesDropdown.details.shortening_decoration": "…和{count} 更多的", "layout.header.characters.left": "{currentCharactersCount} /{maximumCharactersCount} 剩餘字符", "layout.header.add.title.placeholder": "在此新增標題...", @@ -483,6 +494,7 @@ "configurationPanel.vizCantBeFilteredByAttribute": "可視化不能依以下條件過濾{attributeName}。取消選取該複選框。", "configurationPanel.kpiCantBeFilteredByAttribute": "kpi 無法過濾 {attributeName}。取消選取該複選框。", "configurationPanel.vizCantBeFilteredByDate": "可視化無法按日期過濾。取消選取該複選框。", + "configurationPanel.dateDatasetsLoadFailed": "無法載入相關日期資料。請關閉設定面板,然後再試一次。", "configurationPanel.vizCantBeFilteredByMeasureValueFilter": "篩選不適用於此視覺化。", "configurationPanel.mvfBlockedByRankingFilter": "無法套用此篩選,因為該視覺化使用了前/後值篩選。請移除前/後值篩選以套用此篩選。", "configurationPanel.mvfMissingMeasure": "此篩選器中使用的指標已不存在於工作區中。", @@ -502,6 +514,7 @@ "configurationPanel.drillConfig.drillIntoInsight": "鑽入", "configurationPanel.drillConfig.drillDown": "向下鑽取", "configurationPanel.drillConfig.disableDrillDownTooltip": "在此視覺化配置中,向下鑽取已關閉。", + "configurationPanel.drillConfig.computedAttributeDrillDownTooltip": "計算屬性無法使用向下鑽取。", "configurationPanel.drillConfig.drillIntoUrl": "鑽取 URL", "configurationPanel.drillConfig.drillIntoUrl.invalidCustomUrl": "無效的 URL 參數", "configurationPanel.drillConfig.select": "選擇行動...", @@ -629,6 +642,7 @@ "richText.deleteDialog.header": "刪除富文本?", "richText.deleteDialog.message": "富文本及其所有內容將不可逆轉地刪除。", "richText.emptyContent": "沒有富文本內容", + "visualizationSwitcher.restrictedEntry": "受限制", "visualizationSwitcher.emptyContent": "切換器中沒有可視化", "visualizationSwitcherToolbar.visualizationsList.header": "視覺化", "visualizationSwitcherToolbar.visualizationsList.tooltip": "視覺化", @@ -809,6 +823,7 @@ "granularity.hour": "小時", "granularity.minute": "分分鐘", "widget.options.menu.export": "匯出", + "insightMenu.restrictedWidget.options": "受限制的視覺化選項", "menu.close": "關閉選單", "controlButtons.asTable": "以表格形式顯示", "controlButtons.asOriginal": "顯示原始可視化", diff --git a/libs/sdk-ui-dashboard/src/presentation/topBar/buttonBar/button/settingButton/DefaultSettingButton.tsx b/libs/sdk-ui-dashboard/src/presentation/topBar/buttonBar/button/settingButton/DefaultSettingButton.tsx index 8b3450c9044..ea53e7e42fd 100644 --- a/libs/sdk-ui-dashboard/src/presentation/topBar/buttonBar/button/settingButton/DefaultSettingButton.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/topBar/buttonBar/button/settingButton/DefaultSettingButton.tsx @@ -67,7 +67,6 @@ export function DefaultSettingButton({ } - width={300} anchor={ { + // a computed attribute's display form and a label that happen to share an identifier + const computedAttributeDf = { id: "shared_id", ref: idRef("shared_id", "computedAttribute") } as never; + const labelDf = { id: "shared_id", ref: idRef("shared_id", "displayForm") } as never; + + function sanitize(df: never): IAttributeFilter { + // mirrors useSanitizeAttributeFilter: the ref is rewritten to the canonical placeholder ref + return newPositiveAttributeFilter(displayFormPlaceholderRef(df), ["a"]); + } + + function placeholderRefIn(url: string) { + return getDashboardAttributeFilterPlaceholdersFromUrl(url)[0].ref; + } + + it("inserts a placeholder that matches the sanitized filter", () => { + const inserted = dashboardAttributeFilterToPlaceholder( + displayFormPlaceholderRef(computedAttributeDf), + ); + + expect(inserted).toBe("{dash_attribute_filter_selection(computed_attribute/shared_id)}"); + + const filter = sanitize(computedAttributeDf); + // this is the comparison useInvalidFilteringParametersIdentifiers makes; a mismatch here would + // report a perfectly good placeholder as an invalid parameter + expect( + areObjRefsEqual(displayFormPlaceholderRef(computedAttributeDf), placeholderRefIn(inserted)), + ).toBe(true); + expect(areObjRefsEqual(filterObjRef(filter), placeholderRefIn(inserted))).toBe(true); + }); + + it("does not match a label sharing the identifier", () => { + const inserted = dashboardAttributeFilterToPlaceholder( + displayFormPlaceholderRef(computedAttributeDf), + ); + const labelFilter = sanitize(labelDf); + + expect(areObjRefsEqual(filterObjRef(labelFilter), placeholderRefIn(inserted))).toBe(false); + }); + + it("keeps a display form placeholder unprefixed and matching its own filter", () => { + const inserted = dashboardAttributeFilterToPlaceholder(displayFormPlaceholderRef(labelDf)); + + expect(inserted).toBe("{dash_attribute_filter_selection(shared_id)}"); + + const filter = sanitize(labelDf); + expect(areObjRefsEqual(filterObjRef(filter), placeholderRefIn(inserted))).toBe(true); + }); + + it("names an invalid parameter with the text that is actually in the URL", () => { + // the warning quotes these back to the user, so a stripped identifier would name text the + // user cannot find anywhere in the URL they wrote + const url = dashboardAttributeFilterToPlaceholder(displayFormPlaceholderRef(computedAttributeDf)); + const { ref } = getDashboardAttributeFilterPlaceholdersFromUrl(url)[0]; + + expect(placeholderIdentifierText(ref)).toBe("computed_attribute/shared_id"); + expect(url).toContain(placeholderIdentifierText(ref)); + + expect(placeholderIdentifierText(displayFormPlaceholderRef(labelDf))).toBe("shared_id"); + }); +}); diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillTargets/useInvalidAttributeDisplayFormIdentifier.ts b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillTargets/useInvalidAttributeDisplayFormIdentifier.ts index 6b023ff2715..6aa1c675418 100644 --- a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillTargets/useInvalidAttributeDisplayFormIdentifier.ts +++ b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillTargets/useInvalidAttributeDisplayFormIdentifier.ts @@ -2,8 +2,11 @@ import { useMemo } from "react"; -import { type IAttributeDescriptor, areObjRefsEqual, idRef } from "@gooddata/sdk-model"; -import { getAttributeIdentifiersPlaceholdersFromUrl } from "@gooddata/sdk-model/internal"; +import { type IAttributeDescriptor, areObjRefsEqual } from "@gooddata/sdk-model"; +import { + getAttributeIdentifiersPlaceholdersFromUrl, + placeholderIdentifierText, +} from "@gooddata/sdk-model/internal"; import { useDashboardSelector } from "../../../../../model/react/DashboardStoreProvider.js"; import { selectAllCatalogDisplayFormsMap } from "../../../../../model/store/catalog/catalogSelectors.js"; @@ -18,19 +21,22 @@ export function useInvalidAttributeDisplayFormIdentifiers( return useMemo(() => { if (isDrillToCustomUrlConfig(urlDrillTarget)) { const parameters = getAttributeIdentifiersPlaceholdersFromUrl(urlDrillTarget.customUrl); - return parameters - .filter(({ identifier }) => { - // parameter is invalid if either it points to display form that no longer exists - const relevantDf = displayForms.get(idRef(identifier, "displayForm")); - if (!relevantDf) { - return false; - } - // or if it points to an attribute that is no longer a valid drill target - return !attributes.some((attribute) => - areObjRefsEqual(relevantDf.attribute, attribute.attributeHeader.formOf), - ); - }) - .map(({ identifier }) => identifier); + return ( + parameters + .filter(({ ref }) => { + // parameter is invalid if either it points to display form that no longer exists + const relevantDf = displayForms.get(ref); + if (!relevantDf) { + return false; + } + // or if it points to an attribute that is no longer a valid drill target + return !attributes.some((attribute) => + areObjRefsEqual(relevantDf.attribute, attribute.attributeHeader.formOf), + ); + }) + // named as it is written in the URL, so the warning quotes text the user can find there + .map(({ ref }) => placeholderIdentifierText(ref)) + ); } return []; }, [displayForms, urlDrillTarget, attributes]); diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillTargets/useInvalidFilteringParametersIdentifiers.ts b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillTargets/useInvalidFilteringParametersIdentifiers.ts index 52cf3bda300..99cf7d72877 100644 --- a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillTargets/useInvalidFilteringParametersIdentifiers.ts +++ b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillTargets/useInvalidFilteringParametersIdentifiers.ts @@ -11,13 +11,13 @@ import { type IMeasureValueFilter, areObjRefsEqual, filterObjRef, - idRef, } from "@gooddata/sdk-model"; import { getDashboardAttributeFilterPlaceholdersFromUrl, getDashboardMeasureValueFilterPlaceholdersFromUrl, getInsightAttributeFilterPlaceholdersFromUrl, getInsightMeasureValueFilterPlaceholdersFromUrl, + placeholderIdentifierText, } from "@gooddata/sdk-model/internal"; import { useDashboardSelector } from "../../../../../model/react/DashboardStoreProvider.js"; @@ -59,40 +59,42 @@ export function useInvalidFilteringParametersIdentifiers( ); const invalidDashboardParameters = dashboardAttributeFilterParameters - .filter(({ identifier }) => { + // The placeholder's own ref is used rather than a display-form one rebuilt from the + // identifier: a computed attribute shares the shape of a display form but not its type, + // and the filters are sanitized to that same typed ref. + .filter(({ ref }) => { // parameter is invalid if either it points to display form that no longer exists - const relevantDf = displayForms.get(idRef(identifier, "displayForm")); + const relevantDf = displayForms.get(ref); if (!relevantDf) { return true; } return ( !dashboardFilters?.some((filter) => { - return areObjRefsEqual(filterObjRef(filter), idRef(identifier, "displayForm")); + return areObjRefsEqual(filterObjRef(filter), ref); }) && !attributeFilterConfigs?.some((config) => { - return ( - config.displayAsLabel && - areObjRefsEqual(config.displayAsLabel, idRef(identifier, "displayForm")) - ); + return config.displayAsLabel && areObjRefsEqual(config.displayAsLabel, ref); }) ); }) - .map(({ identifier }) => identifier); + // named as it is written in the URL, so the warning quotes text the user can find there + .map(({ ref }) => placeholderIdentifierText(ref)); const invalidInsightParameters = insightAttributeFilterParameters - .filter(({ identifier }) => { + .filter(({ ref }) => { // parameter is invalid if either it points to display form that no longer exists - const relevantDf = displayForms.get(idRef(identifier, "displayForm")); + const relevantDf = displayForms.get(ref); if (!relevantDf) { return true; } return !insightFilters?.some((filter) => { - return areObjRefsEqual(filterObjRef(filter), idRef(identifier, "displayForm")); + return areObjRefsEqual(filterObjRef(filter), ref); }); }) - .map(({ identifier }) => identifier); + // named as it is written in the URL, so the warning quotes text the user can find there + .map(({ ref }) => placeholderIdentifierText(ref)); const invalidDashboardMvfParameters = dashboardMeasureValueFilterParameters .filter(({ identifier }) => { diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/CustomUiMenuComponents.tsx b/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/CustomUiMenuComponents.tsx index ed503d225f7..f0e93d80eba 100644 --- a/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/CustomUiMenuComponents.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/CustomUiMenuComponents.tsx @@ -125,6 +125,20 @@ export function CustomUiMenuContentComponent({ item }: IUiMenuContentProps(); + const selector = createSelector((ctx) => ({ + parentItem: ctx.focusedItem ? getItemInteractiveParent(ctx.items, ctx.focusedItem.id) : undefined, + })); + const { parentItem } = useContextStore(selector); + + return parentItem ? : null; +} + export function CustomUiMenuHeaderComponent() { const { formatMessage } = useIntl(); const { useContextStore, createSelector } = typedUiMenuContextStore(); diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/DashboardInsightMenuContainer.tsx b/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/DashboardInsightMenuContainer.tsx index 89daa56a6bf..20ad7f33d16 100644 --- a/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/DashboardInsightMenuContainer.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/DashboardInsightMenuContainer.tsx @@ -7,13 +7,21 @@ import { ItemsWrapper } from "@gooddata/sdk-ui-kit"; interface IDashboardInsightMenuContainerProps { children: ReactNode; ariaLabelledBy?: string; + + /** Name for a menu that has no title to point at, which is how a restricted widget's menu is named. */ + ariaLabel?: string; } const itemsWrapperStyle: CSSProperties = { width: "100%" }; export function DashboardInsightMenuContainer(props: IDashboardInsightMenuContainerProps) { return ( -
+
{props.children} diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/index.tsx b/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/index.tsx index 970e55ef22a..34ee7e5e34a 100644 --- a/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/index.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/index.tsx @@ -10,6 +10,8 @@ import { useState, } from "react"; +import { useIntl } from "react-intl"; + import { type IInsightWidget, objRefToString, widgetRef } from "@gooddata/sdk-model"; import { type IUiMenuContext, @@ -33,6 +35,7 @@ import { CustomUiMenuContentComponent, CustomUiMenuContentItemComponent, CustomUiMenuHeaderComponent, + CustomUiMenuHeaderComponentWithoutTitle, CustomUiMenuInteractiveItemComponent, type IMenuData, type IMenuItemData, @@ -159,10 +162,17 @@ export function DashboardInsightMenuBody({ onClose, renderMode, setSubmenu, + showTitle = true, }: IDashboardInsightMenuProps & { setSubmenu?: Dispatch>; renderMode: RenderMode; + /** + * Whether the menu names the widget it belongs to. Off for a widget the user is not allowed to + * see, whose stored title can name the object they have no access to. + */ + showTitle?: boolean; }) { + const intl = useIntl(); const widgetRefAsString = objRefToString(widgetRef(widget)); const latestWidgetRef = useRef(widget); latestWidgetRef.current = widget; @@ -202,6 +212,10 @@ export function DashboardInsightMenuBody({ const menuId = `insight-menu-${widgetRefAsString}`; const menuLabelId = `${menuId}-label`; + // without the title there is no element carrying menuLabelId, so the name goes on the menu itself + const menuLabel = showTitle + ? undefined + : intl.formatMessage({ id: "insightMenu.restrictedWidget.options" }); const getMaxHeight = (context: IUiMenuContext) => { if (getSelectedMenuId(context) === "Alerts") { @@ -212,7 +226,10 @@ export function DashboardInsightMenuBody({ return ( - + maxHeight={getMaxHeight} containerBottomPadding="small" @@ -221,12 +238,15 @@ export function DashboardInsightMenuBody({ InteractiveItem={CustomUiMenuInteractiveItemComponent} ContentItem={CustomUiMenuContentItemComponent} Content={CustomUiMenuContentComponent} - MenuHeader={CustomUiMenuHeaderComponent} + MenuHeader={ + showTitle ? CustomUiMenuHeaderComponent : CustomUiMenuHeaderComponentWithoutTitle + } shouldCloseOnSelect - ariaAttributes={{ - id: menuId, - "aria-labelledby": menuLabelId, - }} + ariaAttributes={ + menuLabel + ? { id: menuId, "aria-label": menuLabel } + : { id: menuId, "aria-labelledby": menuLabelId } + } onSelect={handleSelect} onLevelChange={handleSubmenuOpen} menuCtxData={{ diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/getDefaultInsightEditMenuItems.test.tsx b/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/getDefaultInsightEditMenuItems.test.tsx new file mode 100644 index 00000000000..d785b058164 --- /dev/null +++ b/libs/sdk-ui-dashboard/src/presentation/widget/insightMenu/DefaultDashboardInsightMenu/getDefaultInsightEditMenuItems.test.tsx @@ -0,0 +1,49 @@ +// (C) 2026 GoodData Corporation + +import { describe, expect, it, vi } from "vitest"; + +import { type IInsightWidget, idRef } from "@gooddata/sdk-model"; + +import { getDefaultInsightEditMenuItems } from "./getDefaultInsightEditMenuItems.js"; + +const widget: IInsightWidget = { + type: "insight", + insight: idRef("insight-1", "insight"), + ref: idRef("widget-1"), + uri: "/widget-1", + identifier: "widget-1", + title: "Confidential revenue", + description: "", + drills: [], + ignoreDashboardFilters: [], +}; + +const dependencies = { + intl: { formatMessage: ({ id }: { id: string }) => id } as never, + dispatch: vi.fn(), + eventDispatch: vi.fn(), +}; + +describe("getDefaultInsightEditMenuItems", () => { + it("offers removal alone for a widget whose insight the editor cannot read", () => { + const items = getDefaultInsightEditMenuItems(widget, { + ...dependencies, + includeConfigurations: false, + includeInteractions: false, + }); + + // a restricted widget gets one entry, and no separator that would imply a missing one + expect(items.map((item) => item.itemId)).toEqual(["InteractionPanelRemove"]); + }); + + it("keeps configuration and interactions for a readable one", () => { + const items = getDefaultInsightEditMenuItems(widget, dependencies); + + expect(items.map((item) => item.itemId)).toEqual([ + "ConfigurationPanelSubmenu", + "InteractionPanelSubmenu", + "InteractionPanelRemoveSeparator", + "InteractionPanelRemove", + ]); + }); +}); diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/DashboardWidgetInsightGuard.test.tsx b/libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/DashboardWidgetInsightGuard.test.tsx index b12503689af..e8fac595e94 100644 --- a/libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/DashboardWidgetInsightGuard.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/DashboardWidgetInsightGuard.test.tsx @@ -125,6 +125,30 @@ describe("DashboardWidgetInsightGuard", () => { vi.clearAllMocks(); }); + it("hands a restricted widget to the rendering the mode asks for, if any", () => { + function RestrictedStandIn() { + return
the edit mode stand-in
; + } + mockUseDashboardSelector.mockImplementation((selector: (state: DashboardState) => unknown) => + selector(stateWith({ ref: insightRef, type: "insight", reason: "forbidden" })), + ); + + render( + + + , + ); + + expect(screen.getByText("the edit mode stand-in")).toBeInTheDocument(); + expect(screen.queryByText("the default placeholder")).not.toBeInTheDocument(); + }); + it("renders the widget when its insight is available", () => { renderGuard(stateWith()); diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/DashboardWidgetInsightGuard.tsx b/libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/DashboardWidgetInsightGuard.tsx index f29060935c6..fcd739972a1 100644 --- a/libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/DashboardWidgetInsightGuard.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/DashboardWidgetInsightGuard.tsx @@ -12,21 +12,30 @@ import { type IDefaultDashboardInsightWidgetProps } from "./types.js"; interface IDashboardWidgetInsightGuardProps extends Omit { Component: ComponentType; + + /** + * What stands in for a widget the user is not allowed to see. Defaults to the placeholder tile, + * which is all a viewer can be offered; edit mode passes a rendering that keeps the selection and + * the remove entry. + */ + RestrictedComponent?: ComponentType>; } // Sometimes this component is rendered even before insights are ready, which blows up. // Since the behavior is nearly impossible to replicate reliably, let's be defensive here and not render // anything until the insights "catch up". export function DashboardWidgetInsightGuard(props: IDashboardWidgetInsightGuardProps) { - const { widget, screen, dashboardItemClasses, exportData, Component } = props; + const { widget, screen, dashboardItemClasses, exportData, Component, RestrictedComponent } = props; const insights = useDashboardSelector(selectInsightsMap); const isRestricted = useIsWidgetRestricted(widget); const { RestrictedPlaceholderComponentProvider } = useDashboardComponentsContext(); - // view, edit and export modes all reach the widget through this guard, so short-circuiting here is - // what strips the config panel, menu and selection from a restricted widget in edit mode + // view, edit and export modes all reach the widget through this guard, so this is the single + // short-circuit that keeps a restricted insight from reaching the widget in any of them if (isRestricted) { - return ( + return RestrictedComponent ? ( + + ) : ( ) { - return ; + return ( + + ); } /** diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/EditableRestrictedInsightWidget.test.tsx b/libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/EditableRestrictedInsightWidget.test.tsx new file mode 100644 index 00000000000..c64fc32d87a --- /dev/null +++ b/libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/EditableRestrictedInsightWidget.test.tsx @@ -0,0 +1,154 @@ +// (C) 2026 GoodData Corporation + +import { fireEvent, render, screen } from "@testing-library/react"; +import { IntlProvider } from "react-intl"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import { type IInsightWidget, idRef } from "@gooddata/sdk-model"; + +import { type IInsightMenuItem } from "../../insightMenu/types.js"; + +const mockSelection = vi.fn(); +const mockMenuItems = vi.fn(); +const mockPlaceholderProvider = vi.fn(); + +// `isolate: false` shares one module graph per worker, so the modules mocked below may already have +// been evaluated against their real dependencies by a test file that ran earlier in the same worker. +vi.hoisted(() => { + vi.resetModules(); +}); + +vi.mock("../../../../model/react/useWidgetSelection.js", () => ({ + useWidgetSelection: () => mockSelection(), +})); + +vi.mock("./useEditableInsightMenu.js", () => ({ + useEditableInsightMenu: (config: unknown) => mockMenuItems(config), +})); + +vi.mock("../../../dashboardContexts/DashboardComponentsContext.js", () => ({ + useDashboardComponentsContext: () => ({ + RestrictedPlaceholderComponentProvider: mockPlaceholderProvider, + }), +})); + +const { EditableRestrictedInsightWidget } = await import("./EditableRestrictedInsightWidget.js"); + +const widget: IInsightWidget = { + type: "insight", + insight: idRef("insight-1", "insight"), + ref: idRef("widget-1"), + uri: "/widget-1", + identifier: "widget-1", + title: "Confidential revenue", + description: "", + drills: [], + ignoreDashboardFilters: [], +}; + +const onRemove = vi.fn(); +const removeItem: IInsightMenuItem = { + type: "button", + itemId: "InteractionPanelRemove", + itemName: "Remove from dashboard", + tooltip: "", + icon: "gd-icon-trash", + disabled: false, + onClick: onRemove, +}; + +function PlaceholderStandIn() { + return
no access to this visualization
; +} + +const closeConfigPanel = vi.fn(); +const onSelected = vi.fn(); + +function renderWidget({ hasConfigPanelOpen = false }: { hasConfigPanelOpen?: boolean } = {}) { + mockSelection.mockReturnValue({ + isSelectable: true, + isSelected: hasConfigPanelOpen, + onSelected, + closeConfigPanel, + hasConfigPanelOpen, + }); + + return render( + + + , + ); +} + +describe("EditableRestrictedInsightWidget", () => { + beforeEach(() => { + vi.clearAllMocks(); + mockPlaceholderProvider.mockImplementation(() => PlaceholderStandIn); + mockMenuItems.mockReturnValue({ menuItems: [removeItem] }); + }); + + it("shows the placeholder and never the stored title", () => { + renderWidget(); + + expect(screen.getByText("no access to this visualization")).toBeInTheDocument(); + expect(screen.queryByText("Confidential revenue")).not.toBeInTheDocument(); + }); + + it("asks for the menu of a widget with no readable insight, which is removal alone", () => { + renderWidget(); + + expect(mockMenuItems).toHaveBeenCalledWith(expect.objectContaining({ widget, insight: undefined })); + }); + + it("removes the widget when the entry is chosen", () => { + renderWidget({ hasConfigPanelOpen: true }); + + fireEvent.click(screen.getByText("Remove from dashboard")); + + expect(onRemove).toHaveBeenCalledTimes(1); + }); + + it("puts the entry in a menu that can be operated with the keyboard", () => { + renderWidget({ hasConfigPanelOpen: true }); + + // `hidden: true` because the overlay parks itself off-screen with visibility:hidden until it + // has measured its anchor, which never happens without layout + const menu = screen.getByRole("menu", { hidden: true }); + expect(screen.getByRole("menuitem", { hidden: true })).toHaveTextContent("Remove from dashboard"); + + // the menu holds the focus and points at the item through aria-activedescendant, so the key + // goes to the menu itself + fireEvent.keyDown(menu, { code: "Enter" }); + + expect(onRemove).toHaveBeenCalledTimes(1); + }); + + it("names the menu without naming the widget", () => { + renderWidget({ hasConfigPanelOpen: true }); + + // the titleless header renders no element to point at, so the name has to be on the menu + const menu = screen.getByRole("menu", { hidden: true }); + expect(menu).toHaveAttribute("aria-label", "Restricted visualization options"); + expect(menu).not.toHaveAttribute("aria-labelledby"); + expect(screen.getByRole("dialog", { hidden: true })).toHaveAttribute( + "aria-label", + "Restricted visualization options", + ); + }); + + it("offers no menu until the widget is selected", () => { + renderWidget(); + + expect(screen.queryByText("Remove from dashboard")).not.toBeInTheDocument(); + }); +}); diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/EditableRestrictedInsightWidget.tsx b/libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/EditableRestrictedInsightWidget.tsx new file mode 100644 index 00000000000..85c1ea8ced2 --- /dev/null +++ b/libs/sdk-ui-dashboard/src/presentation/widget/widget/InsightWidget/EditableRestrictedInsightWidget.tsx @@ -0,0 +1,81 @@ +// (C) 2026 GoodData Corporation + +import cx from "classnames"; + +import { widgetRef } from "@gooddata/sdk-model"; + +import { useWidgetSelection } from "../../../../model/react/useWidgetSelection.js"; +import { useDashboardComponentsContext } from "../../../dashboardContexts/DashboardComponentsContext.js"; +import { DashboardItem } from "../../../presentationComponents/DashboardItems/DashboardItem.js"; +import { DashboardItemVisualization } from "../../../presentationComponents/DashboardItems/DashboardItemVisualization.js"; +import { DashboardInsightEditMenuBubble } from "../../insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/DashboardInsightEditMenuBubble.js"; +import { DashboardInsightMenuBody } from "../../insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/index.js"; + +import { type IDefaultDashboardInsightWidgetProps } from "./types.js"; +import { useEditableInsightMenu } from "./useEditableInsightMenu.js"; + +/** + * Stands in for an insight widget the editor is not allowed to see. It keeps the selection and the + * context menu of an ordinary widget, because the editor may still want the widget gone; the menu is + * built by the standard builder for a widget with no readable insight, which leaves removal alone. + * + * It renders the standard menu body — keyboard handling, focus management and item rendering come + * with it — with its title suppressed, because the widget title can name the object the editor may + * not see. It does not go through `InsightMenuComponentProvider`: a replacement menu would have no + * reason to honour that. + */ +export function EditableRestrictedInsightWidget({ + widget, + screen, + dashboardItemClasses, +}: Omit) { + const { isSelectable, isSelected, onSelected, closeConfigPanel, hasConfigPanelOpen } = useWidgetSelection( + widgetRef(widget), + ); + const { RestrictedPlaceholderComponentProvider } = useDashboardComponentsContext(); + const Content = RestrictedPlaceholderComponentProvider(widget); + const { menuItems } = useEditableInsightMenu({ + closeMenu: closeConfigPanel, + insight: undefined, + widget, + }); + + return ( + + + hasConfigPanelOpen ? ( + + + + ) : null + } + > + {({ clientHeight, clientWidth }) => ( +
+ +
+ )} +
+
+ ); +} diff --git a/libs/sdk-ui-dashboard/src/presentation/widgetDeleteDialog/DefaultWidgetDeleteDialog.test.tsx b/libs/sdk-ui-dashboard/src/presentation/widgetDeleteDialog/DefaultWidgetDeleteDialog.test.tsx new file mode 100644 index 00000000000..2592fa7b826 --- /dev/null +++ b/libs/sdk-ui-dashboard/src/presentation/widgetDeleteDialog/DefaultWidgetDeleteDialog.test.tsx @@ -0,0 +1,64 @@ +// (C) 2026 GoodData Corporation + +import { render, screen } from "@testing-library/react"; +import { IntlProvider } from "react-intl"; +import { describe, expect, it, vi } from "vitest"; + +import { type IInsightWidget, idRef } from "@gooddata/sdk-model"; + +import { DefaultWidgetDeleteDialog } from "./DefaultWidgetDeleteDialog.js"; + +const widget: IInsightWidget = { + type: "insight", + insight: idRef("insight-1", "insight"), + ref: idRef("widget-1"), + uri: "/widget-1", + identifier: "widget-1", + title: "Confidential revenue", + description: "", + drills: [], + ignoreDashboardFilters: [], +}; + +const messages = { + "deleteWidgetDialog.headline": "Delete widget?", + "deleteWidgetDialog.objectsMessage": "Objects associated with the widget {title} will stop working:", + "deleteWidgetDialog.objectsMessage.restricted": "Objects associated with this widget will stop working:", + "deleteWidgetDialog.alerts": "Alerts", + "deleteWidgetDialog.schedules": "Schedules", + cancel: "Cancel", + delete: "Delete", +}; + +function renderDialog({ isRestricted = false }: { isRestricted?: boolean } = {}) { + return render( + + + , + ); +} + +describe("DefaultWidgetDeleteDialog", () => { + it("never names a widget the user is not allowed to see", () => { + renderDialog({ isRestricted: true }); + + expect(screen.queryByText(/Confidential revenue/)).not.toBeInTheDocument(); + expect( + screen.getByText("Objects associated with this widget will stop working:"), + ).toBeInTheDocument(); + }); + + it("names an ordinary widget, which is what makes the warning useful", () => { + renderDialog(); + + expect(screen.getByText(/Confidential revenue/)).toBeInTheDocument(); + }); +}); diff --git a/libs/sdk-ui-dashboard/src/presentation/widgetDeleteDialog/DefaultWidgetDeleteDialog.tsx b/libs/sdk-ui-dashboard/src/presentation/widgetDeleteDialog/DefaultWidgetDeleteDialog.tsx index 92ee1dda3c3..36b991595cc 100644 --- a/libs/sdk-ui-dashboard/src/presentation/widgetDeleteDialog/DefaultWidgetDeleteDialog.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/widgetDeleteDialog/DefaultWidgetDeleteDialog.tsx @@ -9,6 +9,7 @@ import { ConfirmDialog } from "@gooddata/sdk-ui-kit"; import { eagerRemoveSectionItemByWidgetRef } from "../../model/commands/layout.js"; import { useDashboardDispatch, useDashboardSelector } from "../../model/react/DashboardStoreProvider.js"; +import { useIsWidgetRestricted } from "../../model/react/useIsWidgetRestricted.js"; import { dispatchAndWaitFor } from "../../model/store/_infra/dispatchAndWaitFor.js"; import { selectDashboardUserAutomationAlertsInContext, @@ -30,6 +31,9 @@ const deleteMessages = defineMessages({ objects: { id: "deleteWidgetDialog.objectsMessage", }, + objectsRestricted: { + id: "deleteWidgetDialog.objectsMessage.restricted", + }, alerts: { id: "deleteWidgetDialog.alerts", }, @@ -62,6 +66,7 @@ export function useWidgetDeleteDialogProps(): IWidgetDeleteDialogProps { }, [dispatch, widget]); const isVisible = useDashboardSelector(selectIsWidgetDeleteDialogOpen); + const isRestricted = useIsWidgetRestricted(widget!); const alerts = useDashboardSelector( selectDashboardUserAutomationAlertsInContext(widget?.localIdentifier), ); @@ -76,6 +81,7 @@ export function useWidgetDeleteDialogProps(): IWidgetDeleteDialogProps { onCancel, onDelete, widget, + isRestricted, }; } @@ -89,6 +95,7 @@ export function DefaultWidgetDeleteDialog({ onDelete, onCancel, widget, + isRestricted = false, }: IWidgetDeleteDialogProps): ReactElement | null { const intl = useIntl(); @@ -113,7 +120,11 @@ export function DefaultWidgetDeleteDialog({ submitButtonText={intl.formatMessage(deleteMessages.delete)} >
- + {isRestricted ? ( + + ) : ( + + )}