@gooddata/sdk-ui-dashboard 11.36.0-alpha.3 → 11.36.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +63 -115
- package/esm/__version.d.ts +1 -1
- package/esm/__version.js +1 -1
- package/esm/index.d.ts +5 -13
- package/esm/index.js +2 -10
- package/esm/internal.d.ts +1 -1
- package/esm/model/commandHandlers/dashboard/common/filterViews.js +24 -1
- package/esm/model/commandHandlers/dashboard/common/parameterHydration.d.ts +7 -1
- package/esm/model/commandHandlers/dashboard/common/parameterHydration.js +16 -2
- package/esm/model/commandHandlers/dashboard/common/stateInitializers.js +4 -2
- package/esm/model/commandHandlers/drill/resolveDrillToCustomUrl.d.ts +7 -1
- package/esm/model/commandHandlers/drill/resolveDrillToCustomUrl.js +80 -4
- package/esm/model/commandHandlers/filterContext/filterViewHandler.js +10 -0
- package/esm/model/commandHandlers/filterContext/filterViewParameters.d.ts +7 -0
- package/esm/model/commandHandlers/filterContext/filterViewParameters.js +11 -0
- package/esm/model/store/config/configSelectors.d.ts +0 -6
- package/esm/model/store/config/configSelectors.js +0 -8
- package/esm/model/store/tabs/index.d.ts +4 -0
- package/esm/model/store/tabs/parameters/parametersReducers.d.ts +11 -1
- package/esm/model/store/tabs/parameters/parametersReducers.js +16 -8
- package/esm/model/store/tabs/parameters/parametersSelectors.d.ts +7 -0
- package/esm/model/store/tabs/parameters/parametersSelectors.js +17 -0
- package/esm/model/types/commonTypes.d.ts +11 -2
- package/esm/model/utils/measureValueFilterUtils.d.ts +14 -0
- package/esm/model/utils/measureValueFilterUtils.js +21 -0
- package/esm/presentation/alerting/DefaultAlertingDialog/{DefaultAlertingDialogNew.d.ts → DefaultAlertingDialog.d.ts} +1 -1
- package/esm/presentation/alerting/DefaultAlertingDialog/{DefaultAlertingDialogNew.js → DefaultAlertingDialog.js} +6 -12
- package/esm/presentation/alerting/DefaultAlertingDialog/components/AlertAttributeSelect.js +43 -9
- package/esm/presentation/alerting/DefaultAlertingDialog/hooks/useSaveAlertToBackend.js +13 -25
- package/esm/presentation/alerting/types.d.ts +1 -72
- package/esm/presentation/automationFilters/hooks/useValidateExistingAutomationFilters.d.ts +1 -2
- package/esm/presentation/automationFilters/hooks/useValidateExistingAutomationFilters.js +5 -5
- package/esm/presentation/dashboard/DashboardHeader/AlertingDialogProvider.js +1 -8
- package/esm/presentation/dashboard/DashboardHeader/ScheduledEmailDialogProvider.js +17 -8
- package/esm/presentation/dashboard/DashboardHeader/ShareDialogDashboardHeader.js +5 -2
- package/esm/presentation/dashboard/components/DashboardRenderer.js +2 -2
- package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditor.js +97 -13
- package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParameters.d.ts +1 -1
- package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParameters.js +3 -3
- package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/DashboardParametersSection.d.ts +3 -2
- package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/DashboardParametersSection.js +17 -4
- package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/InsightParametersSection.d.ts +4 -2
- package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/InsightParametersSection.js +37 -4
- package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/Parameter.d.ts +4 -3
- package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/Parameter.js +3 -4
- package/esm/presentation/filterBar/attributeFilter/DefaultDashboardAttributeFilter.js +4 -1
- package/esm/presentation/filterBar/filterBar/DefaultDashboardFilterGroup.js +4 -1
- package/esm/presentation/localization/bundles/de-DE.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/de-DE.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/en-AU.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/en-AU.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/en-GB.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/en-GB.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/en-US.localization-bundle.d.ts +4 -36
- package/esm/presentation/localization/bundles/en-US.localization-bundle.js +4 -36
- package/esm/presentation/localization/bundles/es-419.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/es-419.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/es-ES.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/es-ES.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/fi-FI.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/fi-FI.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/fr-CA.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/fr-CA.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/fr-FR.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/fr-FR.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/id-ID.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/id-ID.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/it-IT.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/it-IT.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/ja-JP.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/ja-JP.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/ko-KR.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/ko-KR.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/nl-NL.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/nl-NL.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/pl-PL.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/pl-PL.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/pt-BR.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/pt-BR.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/pt-PT.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/pt-PT.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/ru-RU.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/ru-RU.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/sl-SI.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/sl-SI.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/th-TH.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/th-TH.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/tr-TR.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/tr-TR.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/uk-UA.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/uk-UA.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/vi-VN.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/vi-VN.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/zh-HK.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/zh-HK.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.js +2 -9
- package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.d.ts +2 -9
- package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.js +2 -9
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/DefaultScheduledEmailDialog.js +26 -59
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/hooks/useEditScheduledEmail.d.ts +2 -6
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/hooks/useEditScheduledEmail.js +22 -104
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/hooks/useSaveScheduledEmailToBackend.js +12 -33
- package/esm/presentation/scheduledEmail/hooks/useWidgetAutomationFilters.d.ts +3 -0
- package/esm/presentation/scheduledEmail/hooks/useWidgetAutomationFilters.js +46 -0
- package/esm/presentation/scheduledEmail/types.d.ts +1 -7
- package/esm/presentation/scheduledEmail/utils/filters.d.ts +2 -0
- package/esm/presentation/scheduledEmail/utils/filters.js +5 -0
- package/esm/presentation/shareDialog/DefaultShareDialog.d.ts +1 -1
- package/esm/presentation/shareDialog/DefaultShareDialog.js +2 -2
- package/esm/presentation/shareDialog/types.d.ts +5 -1
- package/esm/presentation/widget/insight/configuration/DrillTargets/useInvalidFilteringParametersIdentifiers.d.ts +2 -2
- package/esm/presentation/widget/insight/configuration/DrillTargets/useInvalidFilteringParametersIdentifiers.js +36 -5
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/EditAlert.js +2 -2
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useInsightWidgetAlerting.js +3 -6
- package/esm/presentation/widget/insight/configuration/InsightAlerts.js +1 -9
- package/esm/sdk-ui-dashboard.d.ts +28 -240
- package/package.json +20 -20
- package/esm/model/react/filtering/shared.d.ts +0 -6
- package/esm/model/react/filtering/shared.js +0 -38
- package/esm/model/react/filtering/useAutomationAvailableDashboardFilters.d.ts +0 -13
- package/esm/model/react/filtering/useAutomationAvailableDashboardFilters.js +0 -54
- package/esm/model/react/filtering/useDashboardScheduledExportFilters.d.ts +0 -19
- package/esm/model/react/filtering/useDashboardScheduledExportFilters.js +0 -18
- package/esm/model/react/filtering/useScheduledExportFilters.d.ts +0 -26
- package/esm/model/react/filtering/useScheduledExportFilters.js +0 -23
- package/esm/model/react/filtering/useWidgetAlertFilters.d.ts +0 -33
- package/esm/model/react/filtering/useWidgetAlertFilters.js +0 -48
- package/esm/model/react/filtering/useWidgetScheduledExportFilters.d.ts +0 -33
- package/esm/model/react/filtering/useWidgetScheduledExportFilters.js +0 -48
- package/esm/model/react/useDashboardAlerting/useEnableAutomationFilterContext.d.ts +0 -4
- package/esm/model/react/useDashboardAlerting/useEnableAutomationFilterContext.js +0 -20
- package/esm/model/react/useDashboardAlertsOld.d.ts +0 -32
- package/esm/model/react/useDashboardAlertsOld.js +0 -141
- package/esm/presentation/alerting/DefaultAlertingDialog/DefaultAlertingDialogOld.d.ts +0 -5
- package/esm/presentation/alerting/DefaultAlertingDialog/DefaultAlertingDialogOld.js +0 -36
- package/esm/presentation/alerting/DefaultAlertingDialog/components/AlertAttributeSelectOld.d.ts +0 -17
- package/esm/presentation/alerting/DefaultAlertingDialog/components/AlertAttributeSelectOld.js +0 -103
- package/esm/presentation/alerting/DefaultAlertingManagementDialog/DefaultAlertingManagementDialogOld.d.ts +0 -5
- package/esm/presentation/alerting/DefaultAlertingManagementDialog/DefaultAlertingManagementDialogOld.js +0 -53
- package/esm/presentation/alerting/DefaultAlertingManagementDialog/components/AlertOld.d.ts +0 -9
- package/esm/presentation/alerting/DefaultAlertingManagementDialog/components/AlertOld.js +0 -84
- package/esm/presentation/alerting/DefaultAlertingManagementDialog/components/AlertsListOld.d.ts +0 -11
- package/esm/presentation/alerting/DefaultAlertingManagementDialog/components/AlertsListOld.js +0 -16
- package/esm/presentation/dashboard/DashboardHeader/AlertingDialogProviderOld.d.ts +0 -1
- package/esm/presentation/dashboard/DashboardHeader/AlertingDialogProviderOld.js +0 -12
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentFilters.d.ts +0 -29
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentFilters.js +0 -61
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentFiltersList.d.ts +0 -6
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentFiltersList.js +0 -12
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentItems.d.ts +0 -17
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentItems.js +0 -68
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentsWrapper.d.ts +0 -4
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentsWrapper.js +0 -6
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/DashboardAttachments.d.ts +0 -15
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/DashboardAttachments.js +0 -42
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/WidgetAttachments.d.ts +0 -18
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/WidgetAttachments.js +0 -25
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/types.d.ts +0 -2
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/types.js +0 -2
- package/esm/presentation/widget/insight/configuration/InsightAlertsOld.d.ts +0 -2
- package/esm/presentation/widget/insight/configuration/InsightAlertsOld.js +0 -43
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type SagaIterator } from "redux-saga";
|
|
2
|
-
import { type DashboardTextAttributeFilter, type IAttributeDisplayFormMetadataObject, type IDrillToCustomUrl as IDrillToCustomUrlModel, type ObjRef, type TextAttributeFilter } from "@gooddata/sdk-model";
|
|
2
|
+
import { type DashboardTextAttributeFilter, type IAttributeDisplayFormMetadataObject, type IDrillToCustomUrl as IDrillToCustomUrlModel, type MeasureValueFilterCondition, type ObjRef, type TextAttributeFilter } from "@gooddata/sdk-model";
|
|
3
3
|
import { type IDrillEvent, type IDrillEventIntersectionElement } from "@gooddata/sdk-ui";
|
|
4
4
|
import { type IDrillToCustomUrl } from "../../commands/drill.js";
|
|
5
5
|
import { type DashboardContext } from "../../types/commonTypes.js";
|
|
@@ -22,6 +22,8 @@ export declare function loadAttributeElementsForDrillIntersection(drillIntersect
|
|
|
22
22
|
export declare function getAttributeDisplayForms(projectId: string, objRefs: ObjRef[], ctx: DashboardContext): Promise<IAttributeDisplayFormMetadataObject[]>;
|
|
23
23
|
export declare function getAttributeIdentifiersReplacements(url: string, drillIntersectionElements: IDrillEventIntersectionElement[], ctx: DashboardContext): SagaIterator<IDrillToUrlPlaceholderReplacement[]>;
|
|
24
24
|
export declare function getDashboardAttributeFilterReplacements(url: string, ctx: DashboardContext): SagaIterator<IDrillToUrlPlaceholderReplacement[]>;
|
|
25
|
+
export declare function getDashboardMeasureValueFilterReplacements(url: string): SagaIterator<IDrillToUrlPlaceholderReplacement[]>;
|
|
26
|
+
export declare function getInsightMeasureValueFilterReplacements(url: string, widgetRef: ObjRef): SagaIterator<IDrillToUrlPlaceholderReplacement[]>;
|
|
25
27
|
export declare function getInsightAttributeFilterReplacements(url: string, widgetRef: ObjRef): SagaIterator<IDrillToUrlPlaceholderReplacement[]>;
|
|
26
28
|
export declare function getInsightIdentifiersReplacements(customUrl: string, widgetRef: ObjRef, ctx: DashboardContext): SagaIterator<IDrillToUrlPlaceholderReplacement[]>;
|
|
27
29
|
export declare function resolveDrillToCustomUrl(drillConfig: IDrillToCustomUrlModel, widgetRef: ObjRef, event: IDrillEvent, ctx: DashboardContext, cmd: IDrillToCustomUrl): SagaIterator<string>;
|
|
@@ -29,4 +31,8 @@ export declare function resolveDrillToCustomUrl(drillConfig: IDrillToCustomUrlMo
|
|
|
29
31
|
* @internal
|
|
30
32
|
*/
|
|
31
33
|
export declare function stringifyTextFilterSelection(filter: DashboardTextAttributeFilter | TextAttributeFilter): string;
|
|
34
|
+
/**
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
export declare function stringifyMeasureValueFilterCondition(conditions: MeasureValueFilterCondition[] | undefined): string;
|
|
32
38
|
export {};
|
|
@@ -2,19 +2,21 @@
|
|
|
2
2
|
import stringify from "json-stable-stringify";
|
|
3
3
|
import { groupBy } from "lodash-es";
|
|
4
4
|
import { all, call, select } from "redux-saga/effects";
|
|
5
|
-
import { areObjRefsEqual, dashboardAttributeFilterItemDisplayForm, filterAttributeElements, filterObjRef, idRef, insightId, isArbitraryAttributeFilter, isAttributeDescriptor, isAttributeElementsByValue, isDashboardArbitraryAttributeFilter, isDashboardAttributeFilter, isDashboardTextAttributeFilter, isNegativeAttributeFilter, isTextAttributeFilter, } from "@gooddata/sdk-model";
|
|
6
|
-
import { getAttributeIdentifiersPlaceholdersFromUrl, getDashboardAttributeFilterPlaceholdersFromUrl, getInsightAttributeFilterPlaceholdersFromUrl, } from "@gooddata/sdk-model/internal";
|
|
5
|
+
import { areObjRefsEqual, dashboardAttributeFilterItemDisplayForm, dashboardFilterObjRef, filterAttributeElements, filterObjRef, idRef, insightFilters as insightDefinitionFilters, insightId, isArbitraryAttributeFilter, isAttributeDescriptor, isAttributeElementsByValue, isComparisonCondition, isDashboardArbitraryAttributeFilter, isDashboardAttributeFilter, isDashboardTextAttributeFilter, isMeasureValueFilter, isNegativeAttributeFilter, isRangeCondition, isTextAttributeFilter, measureValueFilterConditions, measureValueFilterMeasure, } from "@gooddata/sdk-model";
|
|
6
|
+
import { getAttributeIdentifiersPlaceholdersFromUrl, getDashboardAttributeFilterPlaceholdersFromUrl, getDashboardMeasureValueFilterPlaceholdersFromUrl, getInsightAttributeFilterPlaceholdersFromUrl, getInsightMeasureValueFilterPlaceholdersFromUrl, } from "@gooddata/sdk-model/internal";
|
|
7
7
|
import { isDrillIntersectionAttributeItem, } from "@gooddata/sdk-ui";
|
|
8
8
|
import { invalidArgumentsProvided } from "../../events/general.js";
|
|
9
9
|
import { queryWidgetFilters } from "../../queries/widgets.js";
|
|
10
10
|
import { query } from "../../store/_infra/queryCall.js";
|
|
11
|
-
import { selectAllCatalogDisplayFormsMap, selectCatalogDateAttributes, } from "../../store/catalog/catalogSelectors.js";
|
|
11
|
+
import { selectAllCatalogDisplayFormsMap, selectAllCatalogMeasuresMap, selectCatalogDateAttributes, } from "../../store/catalog/catalogSelectors.js";
|
|
12
|
+
import { selectEnableMeasureValueFilterKD } from "../../store/config/configSelectors.js";
|
|
12
13
|
import { selectInsightByRef } from "../../store/insights/insightsSelectors.js";
|
|
13
14
|
import { selectDashboardId } from "../../store/meta/metaSelectors.js";
|
|
14
15
|
import { selectAttributeFilterConfigsOverrides } from "../../store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
|
|
15
|
-
import { selectFilterContextAttributeFilterItems } from "../../store/tabs/filterContext/filterContextSelectors.js";
|
|
16
|
+
import { selectFilterContextAttributeFilterItems, selectFilterContextMeasureValueFilters, } from "../../store/tabs/filterContext/filterContextSelectors.js";
|
|
16
17
|
import { selectAnalyticalWidgetByRef } from "../../store/tabs/layout/layoutSelectors.js";
|
|
17
18
|
import { DRILL_TO_URL_PLACEHOLDER } from "../../types/drillTypes.js";
|
|
19
|
+
import { dashboardMeasureValueFilterMatchesIdentifier, insightMeasureValueFilterMatchesIdentifier, } from "../../utils/measureValueFilterUtils.js";
|
|
18
20
|
import { getElementTitle, getElementsSecondaryTitles } from "./getElementTitle.js";
|
|
19
21
|
export function* loadElementTitle(dfRef, dfIdentifier, attrElementUri, ctx) {
|
|
20
22
|
const elementTitle = yield call(getElementTitle, ctx.workspace, dfRef, attrElementUri, ctx);
|
|
@@ -164,6 +166,49 @@ export function* getDashboardAttributeFilterReplacements(url, ctx) {
|
|
|
164
166
|
const attributeFilterConfigs = yield select(selectAttributeFilterConfigsOverrides);
|
|
165
167
|
return yield all(attributeFilterPlaceholders.map((placeholder) => call(resolveDashboardAttributeFilterReplacement, placeholder, attributeFilters, catalogDisplayForms, attributeFilterConfigs, ctx)));
|
|
166
168
|
}
|
|
169
|
+
function resolveDashboardMeasureValueFilterReplacement({ placeholder: toBeReplaced, identifier }, measureValueFilters, catalogMeasures) {
|
|
170
|
+
const usedFilter = measureValueFilters.find((filter) => {
|
|
171
|
+
const measureRef = dashboardFilterObjRef(filter);
|
|
172
|
+
return dashboardMeasureValueFilterMatchesIdentifier(measureRef, identifier, catalogMeasures);
|
|
173
|
+
});
|
|
174
|
+
const parsedFilter = stringifyMeasureValueFilterCondition(usedFilter?.dashboardMeasureValueFilter.conditions);
|
|
175
|
+
const replacement = usedFilter ? encodeParameterIfSet(parsedFilter) : undefined;
|
|
176
|
+
return {
|
|
177
|
+
toBeReplaced,
|
|
178
|
+
replacement: replacement,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
export function* getDashboardMeasureValueFilterReplacements(url) {
|
|
182
|
+
const measureValueFilterPlaceholders = getDashboardMeasureValueFilterPlaceholdersFromUrl(url);
|
|
183
|
+
if (measureValueFilterPlaceholders.length === 0) {
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
const measureValueFilters = yield select(selectFilterContextMeasureValueFilters);
|
|
187
|
+
const catalogMeasures = yield select(selectAllCatalogMeasuresMap);
|
|
188
|
+
return measureValueFilterPlaceholders.map((placeholder) => resolveDashboardMeasureValueFilterReplacement(placeholder, measureValueFilters, catalogMeasures));
|
|
189
|
+
}
|
|
190
|
+
function resolveInsightMeasureValueFilterReplacement({ placeholder: toBeReplaced, identifier }, measureValueFilters) {
|
|
191
|
+
const usedFilter = measureValueFilters.find((filter) => {
|
|
192
|
+
const measureRef = measureValueFilterMeasure(filter);
|
|
193
|
+
return insightMeasureValueFilterMatchesIdentifier(measureRef, identifier);
|
|
194
|
+
});
|
|
195
|
+
const parsedFilter = stringifyMeasureValueFilterCondition(usedFilter ? measureValueFilterConditions(usedFilter) : undefined);
|
|
196
|
+
const replacement = usedFilter ? encodeParameterIfSet(parsedFilter) : undefined;
|
|
197
|
+
return {
|
|
198
|
+
toBeReplaced,
|
|
199
|
+
replacement: replacement,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
export function* getInsightMeasureValueFilterReplacements(url, widgetRef) {
|
|
203
|
+
const measureValueFilterPlaceholders = getInsightMeasureValueFilterPlaceholdersFromUrl(url);
|
|
204
|
+
if (measureValueFilterPlaceholders.length === 0) {
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
const widget = yield select(selectAnalyticalWidgetByRef(widgetRef));
|
|
208
|
+
const insight = yield select(selectInsightByRef(widget.insight));
|
|
209
|
+
const measureValueFilters = insight ? insightDefinitionFilters(insight).filter(isMeasureValueFilter) : [];
|
|
210
|
+
return measureValueFilterPlaceholders.map((placeholder) => resolveInsightMeasureValueFilterReplacement(placeholder, measureValueFilters));
|
|
211
|
+
}
|
|
167
212
|
export function* getInsightAttributeFilterReplacements(url, widgetRef) {
|
|
168
213
|
const attributeFilterPlaceholders = getInsightAttributeFilterPlaceholdersFromUrl(url);
|
|
169
214
|
if (attributeFilterPlaceholders.length === 0) {
|
|
@@ -224,10 +269,20 @@ export function* resolveDrillToCustomUrl(drillConfig, widgetRef, event, ctx, cmd
|
|
|
224
269
|
const attributeIdentifiersReplacements = yield call(getAttributeIdentifiersReplacements, customUrl, event.drillContext.intersection, ctx);
|
|
225
270
|
const dashboardAttributeFilterReplacements = yield call(getDashboardAttributeFilterReplacements, customUrl, ctx);
|
|
226
271
|
const insightAttributeFilterReplacements = yield call(getInsightAttributeFilterReplacements, customUrl, widgetRef);
|
|
272
|
+
const dashboardMeasureValueFilterReplacements = yield call(getDashboardMeasureValueFilterReplacements, customUrl);
|
|
273
|
+
const enableMeasureValueFilterKD = yield select(selectEnableMeasureValueFilterKD);
|
|
274
|
+
const insightMeasureValueFilterReplacements = enableMeasureValueFilterKD
|
|
275
|
+
? yield call(getInsightMeasureValueFilterReplacements, customUrl, widgetRef)
|
|
276
|
+
: getInsightMeasureValueFilterPlaceholdersFromUrl(customUrl).map(({ placeholder }) => ({
|
|
277
|
+
toBeReplaced: placeholder,
|
|
278
|
+
replacement: undefined,
|
|
279
|
+
}));
|
|
227
280
|
const missingReplacement = [
|
|
228
281
|
...attributeIdentifiersReplacements,
|
|
229
282
|
...dashboardAttributeFilterReplacements,
|
|
230
283
|
...insightAttributeFilterReplacements,
|
|
284
|
+
...dashboardMeasureValueFilterReplacements,
|
|
285
|
+
...insightMeasureValueFilterReplacements,
|
|
231
286
|
].find(({ replacement }) => replacement === undefined);
|
|
232
287
|
if (missingReplacement) {
|
|
233
288
|
throw invalidArgumentsProvided(ctx, cmd, `Drill to custom URL unable to resolve missing parameter ${missingReplacement.toBeReplaced}`);
|
|
@@ -237,6 +292,8 @@ export function* resolveDrillToCustomUrl(drillConfig, widgetRef, event, ctx, cmd
|
|
|
237
292
|
...attributeIdentifiersReplacements,
|
|
238
293
|
...dashboardAttributeFilterReplacements,
|
|
239
294
|
...insightAttributeFilterReplacements,
|
|
295
|
+
...dashboardMeasureValueFilterReplacements,
|
|
296
|
+
...insightMeasureValueFilterReplacements,
|
|
240
297
|
...insightIdentifiersReplacements,
|
|
241
298
|
];
|
|
242
299
|
return applyReplacements(customUrl, replacements);
|
|
@@ -265,3 +322,22 @@ function stringifyMatchFilterSelection(literal, operator, isNegative) {
|
|
|
265
322
|
const prefix = isNegative ? `NOT_${operatorStr}` : operatorStr;
|
|
266
323
|
return `${prefix}${stringify([literal])}`;
|
|
267
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* @internal
|
|
327
|
+
*/
|
|
328
|
+
export function stringifyMeasureValueFilterCondition(conditions) {
|
|
329
|
+
if (!conditions || conditions.length === 0) {
|
|
330
|
+
return "ALL";
|
|
331
|
+
}
|
|
332
|
+
return conditions
|
|
333
|
+
.map((condition) => {
|
|
334
|
+
if (isComparisonCondition(condition)) {
|
|
335
|
+
return `${condition.comparison.operator}(${condition.comparison.value})`;
|
|
336
|
+
}
|
|
337
|
+
if (isRangeCondition(condition)) {
|
|
338
|
+
return `${condition.range.operator}(${condition.range.from},${condition.range.to})`;
|
|
339
|
+
}
|
|
340
|
+
return "ALL";
|
|
341
|
+
})
|
|
342
|
+
.join("|");
|
|
343
|
+
}
|
|
@@ -4,6 +4,7 @@ import { areObjRefsEqual, isDashboardAttributeFilter, } from "@gooddata/sdk-mode
|
|
|
4
4
|
import { defaultErrorHandler } from "@gooddata/sdk-ui";
|
|
5
5
|
import { changeFilterContextSelectionByParams, reloadFilterViews, } from "../../commands/filters.js";
|
|
6
6
|
import { filterViewApplicationFailed, filterViewApplicationSucceeded, filterViewCreationFailed, filterViewCreationSucceeded, filterViewDefaultStatusChangeFailed, filterViewDefaultStatusChangeSucceeded, filterViewDeletionFailed, filterViewDeletionSucceeded, } from "../../events/filters.js";
|
|
7
|
+
import { selectCatalogParameters } from "../../store/catalog/catalogSelectors.js";
|
|
7
8
|
import { selectIsApplyFiltersAllAtOnceEnabledAndSet } from "../../store/config/configSelectors.js";
|
|
8
9
|
import { selectCrossFilteringFiltersLocalIdentifiers } from "../../store/drill/drillSelectors.js";
|
|
9
10
|
import { selectFilterViews } from "../../store/filterViews/filterViewsReducersSelectors.js";
|
|
@@ -11,9 +12,11 @@ import { filterViewsActions } from "../../store/filterViews/index.js";
|
|
|
11
12
|
import { selectAttributeFilterConfigsOverrides } from "../../store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
|
|
12
13
|
import { selectFilterContextDefinition, selectWorkingFilterContextDefinition, } from "../../store/tabs/filterContext/filterContextSelectors.js";
|
|
13
14
|
import { tabsActions } from "../../store/tabs/index.js";
|
|
15
|
+
import { selectFilterViewParameters } from "../../store/tabs/parameters/parametersSelectors.js";
|
|
14
16
|
import { selectActiveTabLocalIdentifier } from "../../store/tabs/tabsSelectors.js";
|
|
15
17
|
import { loadFilterViews } from "../dashboard/initializeDashboardHandler/loadFilterViews.js";
|
|
16
18
|
import { resetCrossFiltering } from "./common.js";
|
|
19
|
+
import { resolveFilterViewParameterValues } from "./filterViewParameters.js";
|
|
17
20
|
function createFilterView(ctx, filterView) {
|
|
18
21
|
return ctx.backend.workspace(ctx.workspace).dashboards().createFilterView(filterView);
|
|
19
22
|
}
|
|
@@ -36,6 +39,7 @@ export function* saveFilterViewHandler(ctx, cmd) {
|
|
|
36
39
|
!filter.attributeFilter.localIdentifier ||
|
|
37
40
|
!virtualFilters.includes(filter.attributeFilter.localIdentifier)),
|
|
38
41
|
};
|
|
42
|
+
const parameters = yield select(selectFilterViewParameters);
|
|
39
43
|
const filterView = {
|
|
40
44
|
name: cmd.payload.name,
|
|
41
45
|
dashboard: ctx.dashboardRef,
|
|
@@ -43,6 +47,7 @@ export function* saveFilterViewHandler(ctx, cmd) {
|
|
|
43
47
|
isDefault: cmd.payload.isDefault,
|
|
44
48
|
// Include tabId if there's an active tab
|
|
45
49
|
...(activeTabLocalIdentifier ? { tabLocalIdentifier: activeTabLocalIdentifier } : {}),
|
|
50
|
+
...(parameters ? { parameters } : {}),
|
|
46
51
|
};
|
|
47
52
|
try {
|
|
48
53
|
const newFilterView = yield call(createFilterView, ctx, filterView);
|
|
@@ -91,6 +96,11 @@ export function* applyFilterViewHandler(ctx, cmd) {
|
|
|
91
96
|
resetOthers: true,
|
|
92
97
|
correlationId: cmd.correlationId,
|
|
93
98
|
}));
|
|
99
|
+
if (filterView.parameters && filterView.parameters.length > 0) {
|
|
100
|
+
const workspaceParameters = yield select(selectCatalogParameters);
|
|
101
|
+
const values = resolveFilterViewParameterValues(filterView.parameters, workspaceParameters);
|
|
102
|
+
yield put(tabsActions.setParameterRuntimeValues({ values }));
|
|
103
|
+
}
|
|
94
104
|
yield put(filterViewApplicationSucceeded(ctx, filterView, cmd.correlationId));
|
|
95
105
|
}
|
|
96
106
|
else {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type IDashboardParameter, type IParameterMetadataObject, type ObjRef } from "@gooddata/sdk-model";
|
|
2
|
+
interface IResolvedFilterViewParameter {
|
|
3
|
+
ref: ObjRef;
|
|
4
|
+
value: number | undefined;
|
|
5
|
+
}
|
|
6
|
+
export declare function resolveFilterViewParameterValues(parameters: ReadonlyArray<IDashboardParameter>, workspaceParameters: ReadonlyArray<IParameterMetadataObject>): IResolvedFilterViewParameter[];
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { areObjRefsEqual, } from "@gooddata/sdk-model";
|
|
3
|
+
export function resolveFilterViewParameterValues(parameters, workspaceParameters) {
|
|
4
|
+
return parameters.map((parameter) => {
|
|
5
|
+
if (parameter.value !== undefined) {
|
|
6
|
+
return { ref: parameter.ref, value: parameter.value };
|
|
7
|
+
}
|
|
8
|
+
const workspaceParameter = workspaceParameters.find((item) => areObjRefsEqual(item.ref, parameter.ref));
|
|
9
|
+
return { ref: parameter.ref, value: workspaceParameter?.definition.defaultValue };
|
|
10
|
+
});
|
|
11
|
+
}
|
|
@@ -467,12 +467,6 @@ export declare const selectEnableExecutionCancelling: DashboardSelector<boolean>
|
|
|
467
467
|
* @internal
|
|
468
468
|
*/
|
|
469
469
|
export declare const selectEnableDashboardShareLink: DashboardSelector<boolean>;
|
|
470
|
-
/**
|
|
471
|
-
* Selector for the automation filter context feature flag
|
|
472
|
-
*
|
|
473
|
-
* @internal
|
|
474
|
-
*/
|
|
475
|
-
export declare const selectEnableAutomationFilterContext: DashboardSelector<boolean>;
|
|
476
470
|
/**
|
|
477
471
|
* Selector for the date filter local identifiers feature flag
|
|
478
472
|
*
|
|
@@ -630,14 +630,6 @@ export const selectEnableExecutionCancelling = createSelector(selectConfig, (sta
|
|
|
630
630
|
export const selectEnableDashboardShareLink = createSelector(selectConfig, (state) => {
|
|
631
631
|
return Boolean(state.settings?.enableDashboardShareLink);
|
|
632
632
|
});
|
|
633
|
-
/**
|
|
634
|
-
* Selector for the automation filter context feature flag
|
|
635
|
-
*
|
|
636
|
-
* @internal
|
|
637
|
-
*/
|
|
638
|
-
export const selectEnableAutomationFilterContext = createSelector(selectConfig, (state) => {
|
|
639
|
-
return Boolean(state.settings?.enableAutomationFilterContext);
|
|
640
|
-
});
|
|
641
633
|
/**
|
|
642
634
|
* Selector for the date filter local identifiers feature flag
|
|
643
635
|
*
|
|
@@ -575,6 +575,10 @@ export declare const tabsActions: import("@reduxjs/toolkit").CaseReducerActions<
|
|
|
575
575
|
payload: import("./parameters/parametersReducers.js").ISetParameterRuntimeValuePayload;
|
|
576
576
|
type: string;
|
|
577
577
|
}) => void | import("./tabsState.js").ITabsState | import("immer").WritableDraft<import("./tabsState.js").ITabsState>;
|
|
578
|
+
readonly setParameterRuntimeValues: (state: import("immer").WritableDraft<import("./tabsState.js").ITabsState>, action: {
|
|
579
|
+
payload: import("./parameters/parametersReducers.js").ISetParameterRuntimeValuesPayload;
|
|
580
|
+
type: string;
|
|
581
|
+
}) => void | import("./tabsState.js").ITabsState | import("immer").WritableDraft<import("./tabsState.js").ITabsState>;
|
|
578
582
|
readonly removeParameter: (state: import("immer").WritableDraft<import("./tabsState.js").ITabsState>, action: {
|
|
579
583
|
payload: import("./parameters/parametersReducers.js").IRemoveParameterPayload;
|
|
580
584
|
type: string;
|
|
@@ -17,7 +17,13 @@ export interface IAddParameterPayload {
|
|
|
17
17
|
*/
|
|
18
18
|
export interface ISetParameterRuntimeValuePayload {
|
|
19
19
|
ref: ObjRef;
|
|
20
|
-
value: number;
|
|
20
|
+
value: number | undefined;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* @alpha
|
|
24
|
+
*/
|
|
25
|
+
export interface ISetParameterRuntimeValuesPayload {
|
|
26
|
+
values: ISetParameterRuntimeValuePayload[];
|
|
21
27
|
}
|
|
22
28
|
/**
|
|
23
29
|
* @alpha
|
|
@@ -34,6 +40,10 @@ export declare const parametersReducers: {
|
|
|
34
40
|
payload: ISetParameterRuntimeValuePayload;
|
|
35
41
|
type: string;
|
|
36
42
|
}>;
|
|
43
|
+
setParameterRuntimeValues: ParametersReducer<{
|
|
44
|
+
payload: ISetParameterRuntimeValuesPayload;
|
|
45
|
+
type: string;
|
|
46
|
+
}>;
|
|
37
47
|
removeParameter: ParametersReducer<{
|
|
38
48
|
payload: IRemoveParameterPayload;
|
|
39
49
|
type: string;
|
|
@@ -20,14 +20,11 @@ const addParameter = (state, action) => {
|
|
|
20
20
|
};
|
|
21
21
|
};
|
|
22
22
|
const setParameterRuntimeValue = (state, action) => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const entry = activeTab.parameters.parameters.find((item) => areObjRefsEqual(item.parameter.ref, ref));
|
|
29
|
-
if (entry) {
|
|
30
|
-
entry.runtimeOverride = value;
|
|
23
|
+
setRuntimeOverride(state, action.payload);
|
|
24
|
+
};
|
|
25
|
+
const setParameterRuntimeValues = (state, action) => {
|
|
26
|
+
for (const entry of action.payload.values) {
|
|
27
|
+
setRuntimeOverride(state, entry);
|
|
31
28
|
}
|
|
32
29
|
};
|
|
33
30
|
const removeParameter = (state, action) => {
|
|
@@ -39,8 +36,19 @@ const removeParameter = (state, action) => {
|
|
|
39
36
|
parameters: activeTab.parameters.parameters.filter((entry) => !areObjRefsEqual(entry.parameter.ref, action.payload.ref)),
|
|
40
37
|
};
|
|
41
38
|
};
|
|
39
|
+
function setRuntimeOverride(state, { ref, value }) {
|
|
40
|
+
const activeTab = getActiveTab(state);
|
|
41
|
+
if (!activeTab?.parameters) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const entry = activeTab.parameters.parameters.find((item) => areObjRefsEqual(item.parameter.ref, ref));
|
|
45
|
+
if (entry && entry.runtimeOverride !== value) {
|
|
46
|
+
entry.runtimeOverride = value;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
42
49
|
export const parametersReducers = {
|
|
43
50
|
addParameter,
|
|
44
51
|
setParameterRuntimeValue,
|
|
52
|
+
setParameterRuntimeValues,
|
|
45
53
|
removeParameter,
|
|
46
54
|
};
|
|
@@ -20,6 +20,13 @@ export declare const selectActiveParameterRefKeys: DashboardSelector<ReadonlySet
|
|
|
20
20
|
* @internal
|
|
21
21
|
*/
|
|
22
22
|
export declare const selectDashboardParameterEntries: DashboardSelector<IDashboardParameterEntry[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Returns the active tab's parameters in the shape persisted by a filter view.
|
|
25
|
+
* Runtime overrides become persisted `value`; existing parameter values are kept when no runtime value exists.
|
|
26
|
+
*
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
export declare const selectFilterViewParameters: DashboardSelector<IDashboardParameter[] | undefined>;
|
|
23
30
|
/**
|
|
24
31
|
* Returns a selector that yields the entry held by the active tab for a given parameter ref,
|
|
25
32
|
* or `undefined` if no such entry exists.
|
|
@@ -35,6 +35,23 @@ export const selectActiveParameterRefKeys = createSelector(selectDashboardParame
|
|
|
35
35
|
* @internal
|
|
36
36
|
*/
|
|
37
37
|
export const selectDashboardParameterEntries = createSelector(selectParametersState, (state) => state.parameters);
|
|
38
|
+
/**
|
|
39
|
+
* Returns the active tab's parameters in the shape persisted by a filter view.
|
|
40
|
+
* Runtime overrides become persisted `value`; existing parameter values are kept when no runtime value exists.
|
|
41
|
+
*
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
export const selectFilterViewParameters = createSelector(selectDashboardParameterEntries, (entries) => {
|
|
45
|
+
if (entries.length === 0) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
return entries.map((entry) => {
|
|
49
|
+
if (entry.runtimeOverride === undefined) {
|
|
50
|
+
return entry.parameter;
|
|
51
|
+
}
|
|
52
|
+
return { ...entry.parameter, value: entry.runtimeOverride };
|
|
53
|
+
});
|
|
54
|
+
});
|
|
38
55
|
/**
|
|
39
56
|
* Returns a selector that yields the entry held by the active tab for a given parameter ref,
|
|
40
57
|
* or `undefined` if no such entry exists.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type IAnalyticalBackend, type IDashboardReferences } from "@gooddata/sdk-backend-spi";
|
|
2
|
-
import { type FilterContextItem, type IColorPalette, type IDashboard, type IDashboardLayout, type IDateFilterConfig, type IEntitlementDescriptor, type IInsight, type IMeasureValueFilter, type ISeparators, type ISettings, type Identifier, type ObjRef } from "@gooddata/sdk-model";
|
|
2
|
+
import { type FilterContextItem, type IColorPalette, type IDashboard, type IDashboardLayout, type IDashboardParameter, type IDateFilterConfig, type IEntitlementDescriptor, type IInsight, type IMeasureValueFilter, type ISeparators, type ISettings, type Identifier, type ObjRef } from "@gooddata/sdk-model";
|
|
3
3
|
import { type ILocale } from "@gooddata/sdk-ui";
|
|
4
4
|
import { type IDashboardFilter, type IMenuButtonItemsVisibility, type RenderMode } from "../../types.js";
|
|
5
5
|
import { type ExtendedDashboardWidget } from "./layoutTypes.js";
|
|
@@ -112,6 +112,15 @@ export type DashboardConfig = {
|
|
|
112
112
|
* Incompatible overrides/conversions will lead to a toast message with warning.
|
|
113
113
|
*/
|
|
114
114
|
overrideDefaultFilters?: FilterContextItem[];
|
|
115
|
+
/**
|
|
116
|
+
* Override runtime values of dashboard parameters on the active tab.
|
|
117
|
+
*
|
|
118
|
+
* @remarks
|
|
119
|
+
* Each entry's `value` is applied as the parameter's `runtimeOverride` when its `ref` matches
|
|
120
|
+
* a parameter on the loaded dashboard. Refs that don't match are silently ignored.
|
|
121
|
+
* The override applies only to the active tab — other tabs keep their hydrated defaults.
|
|
122
|
+
*/
|
|
123
|
+
overrideDefaultParameters?: IDashboardParameter[];
|
|
115
124
|
/**
|
|
116
125
|
* Override dashboard title.
|
|
117
126
|
*/
|
|
@@ -415,7 +424,7 @@ export interface IDashboardFocusObject {
|
|
|
415
424
|
*
|
|
416
425
|
* @public
|
|
417
426
|
*/
|
|
418
|
-
export type ResolvedDashboardConfig = Omit<Required<DashboardConfig>, "mapboxToken" | "agGridToken" | "maxZoomLevel" | "exportId" | "exportType" | "exportMetadata" | "focusObject" | "slideConfig" | "references" | "entitlements" | "initialContent" | "executionTimestamp" | "overrideDefaultFilters" | "overrideTitle" | "hideWidgetTitles" | "workspaceDescriptor" | "evaluationFrequency" | "externalRecipient" | "openAutomationOnLoad" | "hideAddTabButton"> & DashboardConfig;
|
|
427
|
+
export type ResolvedDashboardConfig = Omit<Required<DashboardConfig>, "mapboxToken" | "agGridToken" | "maxZoomLevel" | "exportId" | "exportType" | "exportMetadata" | "focusObject" | "slideConfig" | "references" | "entitlements" | "initialContent" | "executionTimestamp" | "overrideDefaultFilters" | "overrideDefaultParameters" | "overrideTitle" | "hideWidgetTitles" | "workspaceDescriptor" | "evaluationFrequency" | "externalRecipient" | "openAutomationOnLoad" | "hideAddTabButton"> & DashboardConfig;
|
|
419
428
|
/**
|
|
420
429
|
*
|
|
421
430
|
* @beta
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ICatalogMeasure, type ObjRef, type ObjRefInScope } from "@gooddata/sdk-model";
|
|
2
|
+
import { type ObjRefMap } from "../../_staging/metadata/objRefMap.js";
|
|
3
|
+
/**
|
|
4
|
+
* Matches a dashboard MVF measure reference against the identifier used in drill URL placeholders.
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export declare function dashboardMeasureValueFilterMatchesIdentifier(measureRef: ObjRef, identifier: string, catalogMeasures: ObjRefMap<ICatalogMeasure>): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Matches an insight MVF measure reference against the identifier used in drill URL placeholders.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export declare function insightMeasureValueFilterMatchesIdentifier(measureRef: ObjRefInScope, identifier: string): boolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { areObjRefsEqual, idRef, objRefToString, } from "@gooddata/sdk-model";
|
|
3
|
+
/**
|
|
4
|
+
* Matches a dashboard MVF measure reference against the identifier used in drill URL placeholders.
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export function dashboardMeasureValueFilterMatchesIdentifier(measureRef, identifier, catalogMeasures) {
|
|
9
|
+
const catalogMeasure = catalogMeasures.get(measureRef);
|
|
10
|
+
return (catalogMeasure?.measure.id === identifier ||
|
|
11
|
+
objRefToString(measureRef) === identifier ||
|
|
12
|
+
areObjRefsEqual(measureRef, idRef(identifier, "measure")));
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Matches an insight MVF measure reference against the identifier used in drill URL placeholders.
|
|
16
|
+
*
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export function insightMeasureValueFilterMatchesIdentifier(measureRef, identifier) {
|
|
20
|
+
return (objRefToString(measureRef) === identifier || areObjRefsEqual(measureRef, idRef(identifier, "measure")));
|
|
21
|
+
}
|
|
@@ -3,4 +3,4 @@ export declare function AlertingDialogRenderer({ alertToEdit, users, usersError,
|
|
|
3
3
|
/**
|
|
4
4
|
* @alpha
|
|
5
5
|
*/
|
|
6
|
-
export declare function
|
|
6
|
+
export declare function DefaultAlertingDialog(props: IAlertingDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -6,7 +6,6 @@ import { FormattedMessage, defineMessage, useIntl } from "react-intl";
|
|
|
6
6
|
import { ValidationContextStore, convertError, createInvalidDatapoint, createInvalidNode, useValidationContextValue, } from "@gooddata/sdk-ui";
|
|
7
7
|
import { Button, ConfirmDialogBase, ContentDivider, Hyperlink, Message, Overlay, OverlayController, OverlayControllerProvider, ScrollablePanel, UiIcon, UiIconButton, UiTooltip, useId, } from "@gooddata/sdk-ui-kit";
|
|
8
8
|
import { useDashboardSelector } from "../../../model/react/DashboardStoreProvider.js";
|
|
9
|
-
import { useEnableAlertingAutomationFilterContext } from "../../../model/react/useDashboardAlerting/useEnableAutomationFilterContext.js";
|
|
10
9
|
import { selectEnableAlertOncePerInterval, selectEnableAnomalyDetectionAlert, selectEnableAutomationManagement, selectExternalRecipient, selectIsWhiteLabeled, selectLocale, } from "../../../model/store/config/configSelectors.js";
|
|
11
10
|
import { selectMaxAutomationRecipients } from "../../../model/store/entitlements/entitlementsSelectors.js";
|
|
12
11
|
import { selectCanUseAiAssistant } from "../../../model/store/permissions/permissionsSelectors.js";
|
|
@@ -59,7 +58,7 @@ export function AlertingDialogRenderer({ alertToEdit, users, usersError, notific
|
|
|
59
58
|
onDeleteSuccess?.(alert);
|
|
60
59
|
setAlertToDelete(null);
|
|
61
60
|
};
|
|
62
|
-
const { maxAutomationsRecipients, isExecutionTimestampMode
|
|
61
|
+
const { maxAutomationsRecipients, isExecutionTimestampMode } = useDefaultAlertingDialogData();
|
|
63
62
|
const { editedAutomationFilters, setEditedAutomationFilters, availableFilters, availableFiltersAsVisibleFilters, filtersForNewAutomation, } = useAutomationFiltersSelect({
|
|
64
63
|
automationToEdit: alertToEdit,
|
|
65
64
|
widget,
|
|
@@ -80,7 +79,6 @@ export function AlertingDialogRenderer({ alertToEdit, users, usersError, notific
|
|
|
80
79
|
automationToEdit: alertToEdit,
|
|
81
80
|
widget,
|
|
82
81
|
insight,
|
|
83
|
-
enableAutomationFilterContext,
|
|
84
82
|
});
|
|
85
83
|
const [isApplyCurrentFiltersDialogOpen, setIsApplyCurrentFiltersDialogOpen] = useState(!isValid);
|
|
86
84
|
const { isSavingAlert, handleCreateAlert, handleUpdateAlert } = useSaveAlertToBackend({
|
|
@@ -138,7 +136,7 @@ export function AlertingDialogRenderer({ alertToEdit, users, usersError, notific
|
|
|
138
136
|
} })),
|
|
139
137
|
};
|
|
140
138
|
}, [widget, intl]);
|
|
141
|
-
if (isApplyCurrentFiltersDialogOpen
|
|
139
|
+
if (isApplyCurrentFiltersDialogOpen) {
|
|
142
140
|
return (_jsx(ApplyCurrentFiltersConfirmDialog, { automationType: "alert", onCancel: () => onCancel?.(), onEdit: () => {
|
|
143
141
|
onApplyCurrentFilters();
|
|
144
142
|
setIsApplyCurrentFiltersDialogOpen(false);
|
|
@@ -162,12 +160,10 @@ export function AlertingDialogRenderer({ alertToEdit, users, usersError, notific
|
|
|
162
160
|
: undefined, initialFocus: dialogTitleRef, submitOnEnterKey: false, onCancel: onCancel, onSubmit: handleSaveAlert, headline: undefined, headerLeftButtonRenderer: () => (_jsx(AlertingDialogHeader, { title: editedAutomation?.title ?? "", onChange: onTitleChange, onCancel: onCancel, placeholder: intl.formatMessage({
|
|
163
161
|
id: "dialogs.alert.title.placeholder",
|
|
164
162
|
}), ref: dialogTitleRef, secondaryTitle: secondaryTitle, secondaryTitleIcon: secondaryTitleIcon, isSecondaryTitleVisible: isSecondaryTitleVisible ? isParentValid : undefined })), children: [
|
|
165
|
-
_jsx("h2", { className: "sr-only", id: titleElementId, children: intl.formatMessage({ id: "dialogs.alert.accessibility.label.title" }) }), _jsxs(ScrollablePanel, { className:
|
|
166
|
-
"gd-
|
|
167
|
-
}), children: [
|
|
168
|
-
_jsx("div", { className: "gd-divider-with-margin" }), enableAutomationFilterContext ? (_jsxs(_Fragment, { children: [
|
|
163
|
+
_jsx("h2", { className: "sr-only", id: titleElementId, children: intl.formatMessage({ id: "dialogs.alert.accessibility.label.title" }) }), _jsxs(ScrollablePanel, { className: "gd-notifications-channel-dialog-content-wrapper gd-notification-channel-dialog-with-automation-filters", children: [
|
|
164
|
+
_jsx("div", { className: "gd-divider-with-margin" }), _jsxs(_Fragment, { children: [
|
|
169
165
|
_jsx(AutomationFiltersSelect, { availableFilters: availableFilters, selectedFilters: editedAutomationFilters, onFiltersChange: onFiltersChange, storeFilters: true, onStoreFiltersChange: () => { }, isDashboardAutomation: false, overlayPositionType: OVERLAY_POSITION_TYPE, disableDateFilters: isAnomalyDetection(editedAutomation?.alert) }), _jsx(ContentDivider, { className: "gd-divider-with-margin" })
|
|
170
|
-
] })
|
|
166
|
+
] }), _jsxs(FormFieldGroup, { label: _jsx(FormattedMessage, { id: "insightAlert.config.when" }), children: [
|
|
171
167
|
_jsx(FormField, { label: intl.formatMessage({ id: "insightAlert.config.metric" }), htmlFor: "alert.measure", children: _jsx(AlertMeasureSelect, { selectedMeasure: selectedMeasure, onMeasureChange: onMeasureChange, measures: supportedMeasures, overlayPositionType: OVERLAY_POSITION_TYPE, id: "alert.measure", closeOnParentScroll: CLOSE_ON_PARENT_SCROLL }) }), Boolean(canManageAttributes) &&
|
|
172
168
|
supportedAttributes.filter((a) => a.type === "attribute").length >
|
|
173
169
|
0 && (_jsx(FormField, { label: _jsx(FormattedMessage, { id: "insightAlert.config.for" }), htmlFor: "alert.attribute", children: _jsx(AlertAttributeSelect, { id: "alert.attribute", selectedAttribute: selectedAttribute, selectedValue: selectedValue, onAttributeChange: onAttributeChange, attributes: supportedAttributes, catalogAttributes: catalogAttributes, catalogDateDatasets: catalogDateDatasets, getAttributeValues: getAttributeValues, isResultLoading: isResultLoading, showLabel: false, closeOnParentScroll: CLOSE_ON_PARENT_SCROLL }) })), _jsx(FormField, { label: _jsx(FormattedMessage, { id: "insightAlert.config.condition" }), htmlFor: "alert.condition", children: _jsx(AlertComparisonOperatorSelect, { id: "alert.condition", measure: selectedMeasure, enableAnomalyDetectionAlert: enableAnomalyDetectionAlert ? enableAiAssistant : false, selectedComparisonOperator: selectedComparisonOperator, selectedRelativeOperator: selectedRelativeOperator, selectedAiOperator: selectedAiOperator, onAnomalyDetectionChange: onAnomalyDetectionChange, onComparisonOperatorChange: onComparisonOperatorChange, onRelativeOperatorChange: onRelativeOperatorChange, overlayPositionType: OVERLAY_POSITION_TYPE, closeOnParentScroll: CLOSE_ON_PARENT_SCROLL }) }), !isAnomalyDetection(editedAutomation?.alert) && (_jsx(FormField, { label: _jsx(FormattedMessage, { id: "insightAlert.config.threshold" }), htmlFor: "alert.value", children: _jsx(AlertThresholdInput, { id: "alert.value", value: value, onChange: onChange, onBlur: onBlur, suffix: getValueSuffix(editedAutomation?.alert), errorMessage: thresholdErrorMessage }) })), isChangeOrDifferenceOperator(editedAutomation?.alert) && (_jsx(FormField, { label: _jsx(FormattedMessage, { id: "insightAlert.config.comparison" }), htmlFor: "alert.comparison", children: _jsx(AlertComparisonPeriodSelect, { id: "alert.comparison", measure: selectedMeasure, alert: editedAutomation, selectedComparison: selectedComparator?.comparator, onComparisonChange: (comparisonType) => {
|
|
@@ -195,7 +191,7 @@ export function AlertingDialogRenderer({ alertToEdit, users, usersError, notific
|
|
|
195
191
|
/**
|
|
196
192
|
* @alpha
|
|
197
193
|
*/
|
|
198
|
-
export function
|
|
194
|
+
export function DefaultAlertingDialog(props) {
|
|
199
195
|
const { isLoading, onCancel, alertToEdit } = props;
|
|
200
196
|
const locale = useDashboardSelector(selectLocale);
|
|
201
197
|
if (isLoading) {
|
|
@@ -206,11 +202,9 @@ export function DefaultAlertingDialogNew(props) {
|
|
|
206
202
|
function useDefaultAlertingDialogData() {
|
|
207
203
|
const maxAutomationsRecipients = useDashboardSelector(selectMaxAutomationRecipients);
|
|
208
204
|
const isExecutionTimestampMode = !!useDashboardSelector(selectExecutionTimestamp);
|
|
209
|
-
const enableAutomationFilterContext = useEnableAlertingAutomationFilterContext();
|
|
210
205
|
return {
|
|
211
206
|
maxAutomationsRecipients,
|
|
212
207
|
isExecutionTimestampMode,
|
|
213
|
-
enableAutomationFilterContext,
|
|
214
208
|
};
|
|
215
209
|
}
|
|
216
210
|
function AlertingDialogFooter({ isWhiteLabeled, helpTextId, alertToEdit, isSavingAlert, onDeleteClick, }) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// (C) 2019-2026 GoodData Corporation
|
|
3
|
-
import { useCallback, useMemo } from "react";
|
|
3
|
+
import { useCallback, useMemo, useState } from "react";
|
|
4
4
|
import cx from "classnames";
|
|
5
5
|
import { FormattedMessage, useIntl } from "react-intl";
|
|
6
6
|
import { areObjRefsEqual, } from "@gooddata/sdk-model";
|
|
7
|
-
import { Dropdown, DropdownButton, UiMenu, } from "@gooddata/sdk-ui-kit";
|
|
7
|
+
import { Dropdown, DropdownButton, InvertableSelectSearchBar, Item, Separator, UiMenu, } from "@gooddata/sdk-ui-kit";
|
|
8
8
|
import { getSelectedCatalogAttribute, getSelectedCatalogAttributeValue } from "../utils/getters.js";
|
|
9
9
|
const createInteractiveItem = (id, title, attribute, value, isSelected, subItems) => ({
|
|
10
10
|
type: "interactive",
|
|
@@ -26,6 +26,34 @@ const createSeparator = (id) => ({
|
|
|
26
26
|
function CustomStaticItem({ item: _item }) {
|
|
27
27
|
return _jsx("div", { className: "gd-alert-attribute-select__dropdown-separator" });
|
|
28
28
|
}
|
|
29
|
+
function AttributeValuesSearchContent({ attribute, values, isSelected, selectedAttributeValue, onAttributeChange, onClose, }) {
|
|
30
|
+
const intl = useIntl();
|
|
31
|
+
const [searchString, setSearchString] = useState("");
|
|
32
|
+
const filteredValues = useMemo(() => {
|
|
33
|
+
if (!searchString) {
|
|
34
|
+
return values;
|
|
35
|
+
}
|
|
36
|
+
const loweredSearch = searchString.toLowerCase();
|
|
37
|
+
return values.filter((item) => (item.title ?? item.name ?? "").toLowerCase().includes(loweredSearch));
|
|
38
|
+
}, [searchString, values]);
|
|
39
|
+
return (_jsxs("div", { className: cx("gd-alert-attribute-select__submenu-content", "s-alert-attribute-submenu-content"), children: [
|
|
40
|
+
_jsx("div", { children: _jsx(InvertableSelectSearchBar, { onSearch: setSearchString, searchString: searchString, searchPlaceholder: intl.formatMessage({
|
|
41
|
+
id: "attributesDropdown.placeholder",
|
|
42
|
+
}), className: "gd-alert-attribute-select__menu-item_search" }) }), _jsx(Item, { className: "gd-alert-attribute-select__menu-item_wrapper", checked: Boolean(isSelected && !selectedAttributeValue), onClick: (e) => {
|
|
43
|
+
onAttributeChange(attribute, undefined);
|
|
44
|
+
onClose();
|
|
45
|
+
e.preventDefault();
|
|
46
|
+
e.stopPropagation();
|
|
47
|
+
}, children: _jsxs("div", { className: "gd-alert-attribute-select__menu-item s-menu-alert-attribute-item-value", children: [intl.formatMessage({
|
|
48
|
+
id: "insightAlert.config.selectAttribute",
|
|
49
|
+
}), " ", "(", values.length, ")"] }) }), _jsx(Separator, {}), _jsx("div", { className: "gd-alert-attribute-select__menu-item__values", children: filteredValues.map((value, index) => (_jsx(Item, { checked: Boolean(isSelected && value.value === selectedAttributeValue?.value), className: "gd-alert-attribute-select__menu-item_wrapper", onClick: (e) => {
|
|
50
|
+
onAttributeChange(attribute, value);
|
|
51
|
+
onClose();
|
|
52
|
+
e.preventDefault();
|
|
53
|
+
e.stopPropagation();
|
|
54
|
+
}, children: _jsx("div", { className: "gd-alert-attribute-select__menu-item s-menu-alert-attribute-item-value", children: (value.title ?? value.name) || `(${intl.formatMessage({ id: "empty_value" })})` }) }, index))) })
|
|
55
|
+
] }));
|
|
56
|
+
}
|
|
29
57
|
export function AlertAttributeSelect({ id, selectedAttribute: selectedAttributeProp, getAttributeValues, isResultLoading, selectedValue, onAttributeChange, attributes, catalogAttributes, catalogDateDatasets, showLabel = true, closeOnParentScroll, }) {
|
|
30
58
|
const intl = useIntl();
|
|
31
59
|
const availableAttributes = useMemo(() => {
|
|
@@ -47,17 +75,22 @@ export function AlertAttributeSelect({ id, selectedAttribute: selectedAttributeP
|
|
|
47
75
|
}
|
|
48
76
|
const values = getAttributeValues(item);
|
|
49
77
|
const hasDisplayForm = selectedAttribute?.displayForms.some((df) => areObjRefsEqual(df.ref, attribute.attribute.attribute.displayForm));
|
|
50
|
-
|
|
78
|
+
const isSelected = Boolean(hasDisplayForm);
|
|
79
|
+
if (values.length > 5) {
|
|
80
|
+
attributeItems.push({
|
|
81
|
+
type: "content",
|
|
82
|
+
id: `attribute-${item.id}`,
|
|
83
|
+
stringTitle: item.title || intl.formatMessage({ id: "empty_value" }),
|
|
84
|
+
data: undefined,
|
|
85
|
+
Component: ({ onClose }) => (_jsx(AttributeValuesSearchContent, { attribute: attribute, values: values, isSelected: isSelected, selectedAttributeValue: selectedAttributeValue, onAttributeChange: onAttributeChange, onClose: onClose })),
|
|
86
|
+
});
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
51
89
|
const subItems = [
|
|
52
|
-
// "All" option
|
|
53
90
|
createInteractiveItem(`all-${item.id}`, `${accessibilityAriaLabel} (${values.length})`, attribute, undefined, Boolean(hasDisplayForm && !selectedAttributeValue)),
|
|
54
|
-
// Separator after All option
|
|
55
91
|
createSeparator(`separator-${item.id}`),
|
|
92
|
+
...values.map((value) => createInteractiveItem(`value-${value.value}`, (value.title ?? value.name) || intl.formatMessage({ id: "empty_value" }), attribute, value, Boolean(hasDisplayForm && selectedAttributeValue?.value === value.value))),
|
|
56
93
|
];
|
|
57
|
-
// Add individual value items
|
|
58
|
-
for (const value of values) {
|
|
59
|
-
subItems.push(createInteractiveItem(`value-${value.value}`, (value.title ?? value.name) || intl.formatMessage({ id: "empty_value" }), attribute, value, Boolean(hasDisplayForm && selectedAttributeValue?.value === value.value)));
|
|
60
|
-
}
|
|
61
94
|
// Check if any child is selected to determine parent selection state
|
|
62
95
|
const hasSelectedChild = subItems.some((item) => item.type === "interactive" && "isSelected" in item && item.isSelected);
|
|
63
96
|
// Create attribute item with submenu
|
|
@@ -81,6 +114,7 @@ export function AlertAttributeSelect({ id, selectedAttribute: selectedAttributeP
|
|
|
81
114
|
catalogDateDatasets,
|
|
82
115
|
getAttributeValues,
|
|
83
116
|
intl,
|
|
117
|
+
onAttributeChange,
|
|
84
118
|
selectedAttribute,
|
|
85
119
|
selectedAttributeValue,
|
|
86
120
|
]);
|