@gooddata/sdk-ui-dashboard 11.43.0-alpha.0 → 11.43.0-alpha.1
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 +128 -128
- package/esm/__version.d.ts +1 -1
- package/esm/__version.js +1 -1
- package/esm/index.d.ts +3 -2
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -1
- package/esm/model/commandHandlers/filterContext/dateFilter/removeDateFiltersHandler.d.ts.map +1 -1
- package/esm/model/commandHandlers/filterContext/dateFilter/removeDateFiltersHandler.js +22 -4
- package/esm/model/commandHandlers/scheduledEmail/createScheduledEmailHandler.d.ts.map +1 -1
- package/esm/model/commandHandlers/scheduledEmail/createScheduledEmailHandler.js +3 -1
- package/esm/model/commandHandlers/scheduledEmail/csvRawExecutionDefinition.d.ts +2 -2
- package/esm/model/commandHandlers/scheduledEmail/csvRawExecutionDefinition.d.ts.map +1 -1
- package/esm/model/commandHandlers/scheduledEmail/csvRawExecutionDefinition.js +36 -3
- package/esm/model/commandHandlers/scheduledEmail/saveScheduledEmailHandler.d.ts.map +1 -1
- package/esm/model/commandHandlers/scheduledEmail/saveScheduledEmailHandler.js +3 -1
- package/esm/model/store/executionResults/executionResultsSelectors.d.ts +4 -0
- package/esm/model/store/executionResults/executionResultsSelectors.d.ts.map +1 -1
- package/esm/model/store/executionResults/executionResultsSelectors.js +4 -1
- package/esm/model/store/filtering/dashboardFilterSelectors.d.ts +1 -30
- package/esm/model/store/filtering/dashboardFilterSelectors.d.ts.map +1 -1
- package/esm/model/store/filtering/dashboardFilterSelectors.js +3 -0
- package/esm/model/store/filtering/types.d.ts +33 -0
- package/esm/model/store/filtering/types.d.ts.map +1 -0
- package/esm/model/store/filtering/types.js +2 -0
- package/esm/model/store/tabs/dateFilterConfig/dateFilterConfigSelectors.d.ts +14 -0
- package/esm/model/store/tabs/dateFilterConfig/dateFilterConfigSelectors.d.ts.map +1 -1
- package/esm/model/store/tabs/dateFilterConfig/dateFilterConfigSelectors.js +35 -0
- package/esm/model/store/tabs/parameters/parametersSelectors.d.ts +12 -0
- package/esm/model/store/tabs/parameters/parametersSelectors.d.ts.map +1 -1
- package/esm/model/store/tabs/parameters/parametersSelectors.js +37 -12
- package/esm/presentation/automations/_staging/alerting/DefaultAlertingDialog/DefaultAlertingDialog.d.ts.map +1 -1
- package/esm/presentation/automations/_staging/alerting/DefaultAlertingDialog/DefaultAlertingDialog.js +9 -3
- package/esm/presentation/automations/_staging/alerting/DefaultAlertingManagementDialog/components/PauseAlertRunner.js +1 -1
- package/esm/presentation/automations/connectors/hooks/useBuildAutomationsContext.d.ts +3 -0
- package/esm/presentation/automations/connectors/hooks/useBuildAutomationsContext.d.ts.map +1 -0
- package/esm/presentation/automations/connectors/hooks/useBuildAutomationsContext.js +110 -0
- package/esm/presentation/automations/connectors/hooks/useBuildAutomationsContext.test.d.ts +2 -0
- package/esm/presentation/automations/connectors/hooks/useBuildAutomationsContext.test.d.ts.map +1 -0
- package/esm/presentation/automations/connectors/hooks/useBuildAutomationsContext.test.js +99 -0
- package/esm/presentation/automations/connectors/hooks/useWidgetAutomationFilters.d.ts +4 -0
- package/esm/presentation/automations/connectors/hooks/useWidgetAutomationFilters.d.ts.map +1 -0
- package/esm/presentation/automations/connectors/hooks/useWidgetAutomationFilters.js +46 -0
- package/esm/presentation/automations/contexts/AutomationsContext.d.ts +42 -2
- package/esm/presentation/automations/contexts/AutomationsContext.d.ts.map +1 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/DefaultScheduledEmailDialog.d.ts.map +1 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/DefaultScheduledEmailDialog.js +8 -2
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useEditScheduledEmail.d.ts +1 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useEditScheduledEmail.d.ts.map +1 -1
- package/esm/presentation/automations/scheduledEmail/hooks/useWidgetAutomationFilters.d.ts +2 -3
- package/esm/presentation/automations/scheduledEmail/hooks/useWidgetAutomationFilters.d.ts.map +1 -1
- package/esm/presentation/automations/scheduledEmail/hooks/useWidgetAutomationFilters.js +4 -45
- package/esm/presentation/automations/shared/automationFilters/components/AutomationDateFilter.d.ts.map +1 -1
- package/esm/presentation/automations/shared/automationFilters/components/AutomationDateFilter.js +9 -16
- package/esm/presentation/automations/shared/automationFilters/components/AutomationDateFilter.test.d.ts +2 -0
- package/esm/presentation/automations/shared/automationFilters/components/AutomationDateFilter.test.d.ts.map +1 -0
- package/esm/presentation/automations/shared/automationFilters/components/AutomationDateFilter.test.js +131 -0
- package/esm/presentation/automations/shared/automationFilters/components/AutomationFiltersSelect.d.ts +1 -1
- package/esm/presentation/automations/shared/automationFilters/components/AutomationFiltersSelect.d.ts.map +1 -1
- package/esm/presentation/automations/shared/automationFilters/hooks/useAutomationVisibleFilters.d.ts.map +1 -1
- package/esm/presentation/automations/shared/automationFilters/hooks/useAutomationVisibleFilters.js +1 -1
- package/esm/presentation/automations/shared/automationFilters/hooks/useDefaultSelectedFiltersForExistingAutomation.d.ts +1 -1
- package/esm/presentation/automations/shared/automationFilters/hooks/useDefaultSelectedFiltersForExistingAutomation.d.ts.map +1 -1
- package/esm/presentation/automations/shared/automationFilters/hooks/useDefaultSelectedFiltersForExistingAutomation.js +4 -6
- package/esm/presentation/automations/shared/automationFilters/hooks/useDefaultSelectedFiltersForNewAutomation.d.ts +1 -1
- package/esm/presentation/automations/shared/automationFilters/hooks/useDefaultSelectedFiltersForNewAutomation.d.ts.map +1 -1
- package/esm/presentation/automations/shared/automationFilters/hooks/useDefaultSelectedFiltersForNewAutomation.js +3 -4
- package/esm/presentation/automations/shared/automationFilters/hooks/useValidateExistingAutomationFilters.d.ts +1 -1
- package/esm/presentation/automations/shared/automationFilters/hooks/useValidateExistingAutomationFilters.d.ts.map +1 -1
- package/esm/presentation/automations/shared/automationFilters/hooks/useValidateExistingAutomationFilters.js +4 -10
- package/esm/presentation/automations/shared/automationFilters/useAutomationFilters.d.ts +1 -1
- package/esm/presentation/automations/shared/automationFilters/useAutomationFilters.d.ts.map +1 -1
- package/esm/presentation/automations/shared/automationFilters/useAutomationFilters.js +3 -28
- package/esm/presentation/automations/shared/automationFilters/useAutomationFiltersSelect.d.ts +2 -2
- package/esm/presentation/automations/shared/automationFilters/useAutomationFiltersSelect.d.ts.map +1 -1
- package/esm/presentation/automations/shared/automationFilters/useAutomationFiltersSelect.js +2 -5
- package/esm/presentation/automations/shared/automationFilters/utils.d.ts +1 -1
- package/esm/presentation/automations/shared/automationFilters/utils.d.ts.map +1 -1
- package/esm/presentation/automations/shared/dateFilterConfig/dateFilterConfigConverters.d.ts +10 -0
- package/esm/presentation/automations/shared/dateFilterConfig/dateFilterConfigConverters.d.ts.map +1 -0
- package/esm/presentation/automations/shared/dateFilterConfig/dateFilterConfigConverters.js +89 -0
- package/esm/presentation/automations/shared/dateFilterConfig/dateFilterOptionMapping.d.ts +34 -0
- package/esm/presentation/automations/shared/dateFilterConfig/dateFilterOptionMapping.d.ts.map +1 -0
- package/esm/presentation/automations/shared/dateFilterConfig/dateFilterOptionMapping.js +261 -0
- package/esm/presentation/automations/shared/dateFilterConfig/defaultConfig.d.ts +12 -0
- package/esm/presentation/automations/shared/dateFilterConfig/defaultConfig.d.ts.map +1 -0
- package/esm/presentation/automations/shared/dateFilterConfig/defaultConfig.js +437 -0
- package/esm/presentation/automations/shared/exportUtils/filterUtils.d.ts +3 -0
- package/esm/presentation/automations/shared/exportUtils/filterUtils.d.ts.map +1 -0
- package/esm/presentation/automations/shared/exportUtils/filterUtils.js +14 -0
- package/esm/presentation/automations/shared/hooks/useAttributeFilterDisplayFormFromMap.d.ts +3 -0
- package/esm/presentation/automations/shared/hooks/useAttributeFilterDisplayFormFromMap.d.ts.map +1 -0
- package/esm/presentation/automations/shared/hooks/useAttributeFilterDisplayFormFromMap.js +7 -0
- package/esm/presentation/automations/shared/hooks/useCommonDateFilterTitle.d.ts +3 -0
- package/esm/presentation/automations/shared/hooks/useCommonDateFilterTitle.d.ts.map +1 -0
- package/esm/presentation/automations/shared/hooks/useCommonDateFilterTitle.js +6 -0
- package/esm/presentation/automations/shared/hooks/useDateFiltersTitles.d.ts +4 -0
- package/esm/presentation/automations/shared/hooks/useDateFiltersTitles.d.ts.map +1 -0
- package/esm/presentation/automations/shared/hooks/useDateFiltersTitles.js +19 -0
- package/esm/presentation/automations/shared/hooks/useFiltersNamings.d.ts +13 -0
- package/esm/presentation/automations/shared/hooks/useFiltersNamings.d.ts.map +1 -0
- package/esm/presentation/automations/shared/hooks/useFiltersNamings.js +196 -0
- package/esm/presentation/automations/shared/utils/automationUtils.d.ts +24 -0
- package/esm/presentation/automations/shared/utils/automationUtils.d.ts.map +1 -0
- package/esm/presentation/automations/shared/utils/automationUtils.js +135 -0
- package/esm/presentation/automations/shared/utils/filterContextUtils.d.ts +4 -0
- package/esm/presentation/automations/shared/utils/filterContextUtils.d.ts.map +1 -0
- package/esm/presentation/automations/shared/utils/filterContextUtils.js +67 -0
- package/esm/presentation/filterBar/attributeFilter/dashboardDropdownBody/configuration/hooks/useDependentDateFilterConfigurationState.d.ts.map +1 -1
- package/esm/presentation/filterBar/attributeFilter/dashboardDropdownBody/configuration/hooks/useDependentDateFilterConfigurationState.js +34 -16
- package/esm/presentation/filterBar/attributeFilter/dashboardDropdownBody/configuration/hooks/useDependentDateFiltersConfiguration.d.ts.map +1 -1
- package/esm/presentation/filterBar/attributeFilter/dashboardDropdownBody/configuration/hooks/useDependentDateFiltersConfiguration.js +23 -8
- package/esm/presentation/filterBar/attributeFilter/useDependentDateFilters.d.ts.map +1 -1
- package/esm/presentation/filterBar/attributeFilter/useDependentDateFilters.js +17 -6
- package/esm/presentation/topBar/menuButton/DefaultMenuButton.js +1 -1
- package/esm/presentation/widget/insight/ViewModeDashboardInsight/InsightDrillDialog/DrillDialogInsight.d.ts.map +1 -1
- package/esm/presentation/widget/insight/ViewModeDashboardInsight/InsightDrillDialog/DrillDialogInsight.js +11 -2
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useCreateAlert.d.ts.map +1 -0
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useInsightWidgetAlerting.d.ts.map +1 -1
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useInsightWidgetAlerting.js +2 -2
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useSaveAlertToBackend.d.ts.map +1 -0
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useUpdateAlert.d.ts.map +1 -0
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useWidgetAutomationFilters.d.ts +4 -0
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useWidgetAutomationFilters.d.ts.map +1 -0
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useWidgetAutomationFilters.js +46 -0
- package/esm/presentation/widget/insight/configuration/InsightAlertsNew.d.ts.map +1 -1
- package/esm/presentation/widget/insight/configuration/InsightAlertsNew.js +1 -1
- package/esm/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/DashboardInsightMenuItemButton.d.ts.map +1 -1
- package/esm/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/DashboardInsightMenuItemButton.js +2 -2
- package/esm/presentation/widget/insightMenu/types.js +1 -1
- package/esm/presentation/widget/widget/warningPartialResult/InsightWidgetWarningPartialResult.d.ts.map +1 -1
- package/esm/presentation/widget/widget/warningPartialResult/InsightWidgetWarningPartialResult.js +1 -1
- package/esm/sdk-ui-dashboard.d.ts +11 -2
- package/esm/tsdoc-metadata.json +1 -1
- package/package.json +20 -20
- package/esm/presentation/automations/_staging/alerting/DefaultAlertingDialog/hooks/useCreateAlert.d.ts.map +0 -1
- package/esm/presentation/automations/_staging/alerting/DefaultAlertingDialog/hooks/useSaveAlertToBackend.d.ts.map +0 -1
- package/esm/presentation/automations/_staging/alerting/DefaultAlertingDialog/hooks/useUpdateAlert.d.ts.map +0 -1
- /package/esm/presentation/{automations/_staging/alerting/DefaultAlertingDialog → widget/insight/configuration/InsightAlertConfig}/hooks/useCreateAlert.d.ts +0 -0
- /package/esm/presentation/{automations/_staging/alerting/DefaultAlertingDialog → widget/insight/configuration/InsightAlertConfig}/hooks/useCreateAlert.js +0 -0
- /package/esm/presentation/{automations/_staging/alerting/DefaultAlertingDialog → widget/insight/configuration/InsightAlertConfig}/hooks/useSaveAlertToBackend.d.ts +0 -0
- /package/esm/presentation/{automations/_staging/alerting/DefaultAlertingDialog → widget/insight/configuration/InsightAlertConfig}/hooks/useSaveAlertToBackend.js +0 -0
- /package/esm/presentation/{automations/_staging/alerting/DefaultAlertingDialog → widget/insight/configuration/InsightAlertConfig}/hooks/useUpdateAlert.d.ts +0 -0
- /package/esm/presentation/{automations/_staging/alerting/DefaultAlertingDialog → widget/insight/configuration/InsightAlertConfig}/hooks/useUpdateAlert.js +0 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// (C) 2024-2026 GoodData Corporation
|
|
2
|
+
import { useIntl } from "react-intl";
|
|
3
|
+
import { areObjRefsEqual, dashboardAttributeFilterItemLocalIdentifier, dashboardAttributeFilterItemTitle, getAttributeElementsItems, isAllTimeDashboardDateFilter, isAllValuesDashboardAttributeFilter, isDashboardArbitraryAttributeFilter, isDashboardAttributeFilter, isDashboardCommonDateFilter, isDashboardDateFilter, isDashboardDateFilterWithDimension, isDashboardMatchAttributeFilter, isDashboardMeasureValueFilter, objRefToString, serializeObjRef, } from "@gooddata/sdk-model";
|
|
4
|
+
import { DateFilterHelpers, getAttributeFilterSubtitle, getLocalizedIcuDateFormatPattern, getMeasureValueFilterConditionLabel, getTextFilterStateText, } from "@gooddata/sdk-ui-filters";
|
|
5
|
+
import { useAutomationsContext } from "../../contexts/AutomationsContext.js";
|
|
6
|
+
import { convertDateFilterConfigToDateFilterOptions } from "../dateFilterConfig/dateFilterConfigConverters.js";
|
|
7
|
+
import { matchDateFilterToDateFilterOptionWithPreference } from "../dateFilterConfig/dateFilterOptionMapping.js";
|
|
8
|
+
import { defaultDateFilterConfig } from "../dateFilterConfig/defaultConfig.js";
|
|
9
|
+
import { ensureAllTimeFilterForExport } from "../exportUtils/filterUtils.js";
|
|
10
|
+
import { useAttributeFilterDisplayFormFromMap } from "./useAttributeFilterDisplayFormFromMap.js";
|
|
11
|
+
import { useCommonDateFilterTitle } from "./useCommonDateFilterTitle.js";
|
|
12
|
+
import { useDateFiltersTitles } from "./useDateFiltersTitles.js";
|
|
13
|
+
const PERCENT_FORMAT_REGEX = /%/;
|
|
14
|
+
function isPercentageFormat(format) {
|
|
15
|
+
return !!format && PERCENT_FORMAT_REGEX.test(format);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Hook that gathers all dependencies needed for filter naming transformations.
|
|
19
|
+
* Reusable across different hooks that need to transform filters to namings.
|
|
20
|
+
*
|
|
21
|
+
* @param filtersForTitles - Array of filters (date filters will be extracted for titles)
|
|
22
|
+
* @returns Object containing all dependencies needed for filter naming transformations
|
|
23
|
+
*/
|
|
24
|
+
function useFilterNamingDependencies(filtersForTitles) {
|
|
25
|
+
const intl = useIntl();
|
|
26
|
+
const { locale, settings, catalogMeasures: measures, separators, getCatalogAttributeByRef, } = useAutomationsContext();
|
|
27
|
+
const dateFormat = settings?.formatLocale
|
|
28
|
+
? getLocalizedIcuDateFormatPattern(settings.formatLocale)
|
|
29
|
+
: settings?.responsiveUiDateFormat;
|
|
30
|
+
const getAttributeFilterDisplayFormFromMap = useAttributeFilterDisplayFormFromMap();
|
|
31
|
+
const dateFiltersForTitles = filtersForTitles.filter(isDashboardDateFilterWithDimension);
|
|
32
|
+
const commonDateFilterTitle = useCommonDateFilterTitle(intl);
|
|
33
|
+
const allDateFiltersTitlesObj = useDateFiltersTitles(dateFiltersForTitles, intl);
|
|
34
|
+
return {
|
|
35
|
+
intl,
|
|
36
|
+
locale,
|
|
37
|
+
dateFormat,
|
|
38
|
+
getAttributeFilterDisplayFormFromMap,
|
|
39
|
+
getCatalogAttributeByRef,
|
|
40
|
+
measures,
|
|
41
|
+
separators,
|
|
42
|
+
commonDateFilterTitle,
|
|
43
|
+
allDateFiltersTitlesObj,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Pure function that transforms filters into filter namings.
|
|
48
|
+
* Extracted to avoid code duplication between useFiltersNamings and useFiltersByTabNamings.
|
|
49
|
+
*/
|
|
50
|
+
function transformFiltersToNamings(filtersToDisplay, deps) {
|
|
51
|
+
const { intl, dateFormat, getAttributeFilterDisplayFormFromMap, getCatalogAttributeByRef, measures, separators, commonDateFilterTitle, allDateFiltersTitlesObj, } = deps;
|
|
52
|
+
// we want to show all time filter in the list of filters even if it is not stored
|
|
53
|
+
const extendedFiltersToDisplay = ensureAllTimeFilterForExport(filtersToDisplay);
|
|
54
|
+
return extendedFiltersToDisplay.map((filter) => {
|
|
55
|
+
if (isDashboardAttributeFilter(filter)) {
|
|
56
|
+
const displayForm = getAttributeFilterDisplayFormFromMap(filter.attributeFilter.displayForm);
|
|
57
|
+
if (!displayForm) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
const attribute = getCatalogAttributeByRef(displayForm.attribute);
|
|
61
|
+
if (!attribute) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
const valuesAsAttributeElements = getAttributeElementsItems(filter.attributeFilter.attributeElements)?.map((element) => ({
|
|
65
|
+
title: element,
|
|
66
|
+
uri: element,
|
|
67
|
+
}));
|
|
68
|
+
const subtitle = getAttributeFilterSubtitle(filter.attributeFilter.negativeSelection, valuesAsAttributeElements, intl);
|
|
69
|
+
return {
|
|
70
|
+
type: "attributeFilter",
|
|
71
|
+
all: isAllValuesDashboardAttributeFilter(filter),
|
|
72
|
+
id: filter.attributeFilter.localIdentifier,
|
|
73
|
+
title: filter.attributeFilter.title ?? attribute.attribute.title,
|
|
74
|
+
subtitle,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
else if (isDashboardDateFilter(filter)) {
|
|
78
|
+
/**
|
|
79
|
+
* Shenanigans inspired by core date filter and dashboard date filter implementation
|
|
80
|
+
* to get the date filter option for its subtitle.
|
|
81
|
+
*/
|
|
82
|
+
const dateFilterOptionInfo = matchDateFilterToDateFilterOptionWithPreference(filter, convertDateFilterConfigToDateFilterOptions(defaultDateFilterConfig), undefined);
|
|
83
|
+
const dateFilterOption = DateFilterHelpers.applyExcludeCurrentPeriod(dateFilterOptionInfo.dateFilterOption, dateFilterOptionInfo.excludeCurrentPeriod);
|
|
84
|
+
const subtitle = DateFilterHelpers.getDateFilterTitleUsingTranslator(dateFilterOption, intl, "full", dateFormat);
|
|
85
|
+
const a = filter;
|
|
86
|
+
if (isDashboardDateFilterWithDimension(a)) {
|
|
87
|
+
const key = serializeObjRef(a.dateFilter.dataSet);
|
|
88
|
+
return {
|
|
89
|
+
type: "dateFilter",
|
|
90
|
+
all: isAllTimeDashboardDateFilter(a),
|
|
91
|
+
id: a.dateFilter.localIdentifier ?? `dateFilter:${key}`,
|
|
92
|
+
title: allDateFiltersTitlesObj[key],
|
|
93
|
+
subtitle,
|
|
94
|
+
dataSet: a.dateFilter.dataSet,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const b = filter;
|
|
98
|
+
if (isDashboardCommonDateFilter(b)) {
|
|
99
|
+
return {
|
|
100
|
+
type: "dateFilter",
|
|
101
|
+
common: true,
|
|
102
|
+
all: isAllTimeDashboardDateFilter(b),
|
|
103
|
+
id: b.dateFilter.localIdentifier ?? "dateFilter:common",
|
|
104
|
+
title: commonDateFilterTitle || intl.formatMessage({ id: "dateFilterDropdown.title" }),
|
|
105
|
+
subtitle,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
else if (isDashboardArbitraryAttributeFilter(filter)) {
|
|
111
|
+
const { values, negativeSelection, displayForm } = filter.arbitraryAttributeFilter;
|
|
112
|
+
const filterDisplayForm = getAttributeFilterDisplayFormFromMap(displayForm);
|
|
113
|
+
if (!filterDisplayForm) {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const attribute = getCatalogAttributeByRef(filterDisplayForm.attribute);
|
|
117
|
+
if (!attribute) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
const operator = values.length === 0 && negativeSelection ? "all" : negativeSelection ? "isNot" : "is";
|
|
121
|
+
const subtitle = getTextFilterStateText(operator, values, "", intl);
|
|
122
|
+
const title = dashboardAttributeFilterItemTitle(filter) ?? attribute.attribute.title;
|
|
123
|
+
return {
|
|
124
|
+
type: "attributeFilter",
|
|
125
|
+
all: values.length === 0 && negativeSelection,
|
|
126
|
+
id: dashboardAttributeFilterItemLocalIdentifier(filter),
|
|
127
|
+
title,
|
|
128
|
+
subtitle,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
else if (isDashboardMeasureValueFilter(filter)) {
|
|
132
|
+
const { measure, localIdentifier, title: customTitle, conditions, } = filter.dashboardMeasureValueFilter;
|
|
133
|
+
const catalogMetric = measures.find((m) => areObjRefsEqual(m.measure.ref, measure));
|
|
134
|
+
const defaultTitle = catalogMetric?.measure.title ?? objRefToString(measure);
|
|
135
|
+
const title = customTitle ?? defaultTitle;
|
|
136
|
+
const format = catalogMetric?.measure.format;
|
|
137
|
+
const usePercentage = isPercentageFormat(format);
|
|
138
|
+
const subtitle = getMeasureValueFilterConditionLabel(intl, conditions, {
|
|
139
|
+
usePercentage,
|
|
140
|
+
separators,
|
|
141
|
+
});
|
|
142
|
+
return {
|
|
143
|
+
type: "measureValueFilter",
|
|
144
|
+
all: !conditions || conditions.length === 0,
|
|
145
|
+
id: localIdentifier,
|
|
146
|
+
title,
|
|
147
|
+
subtitle,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
else if (isDashboardMatchAttributeFilter(filter)) {
|
|
151
|
+
const { operator: matchOperator, literal, negativeSelection, displayForm, } = filter.matchAttributeFilter;
|
|
152
|
+
const filterDisplayForm = getAttributeFilterDisplayFormFromMap(displayForm);
|
|
153
|
+
if (!filterDisplayForm) {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
const attribute = getCatalogAttributeByRef(filterDisplayForm.attribute);
|
|
157
|
+
if (!attribute) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
const isNegative = negativeSelection ?? false;
|
|
161
|
+
const operatorMap = {
|
|
162
|
+
contains: isNegative ? "doesNotContain" : "contains",
|
|
163
|
+
startsWith: isNegative ? "doesNotStartWith" : "startsWith",
|
|
164
|
+
endsWith: isNegative ? "doesNotEndWith" : "endsWith",
|
|
165
|
+
};
|
|
166
|
+
const operator = operatorMap[matchOperator] ?? "contains";
|
|
167
|
+
const subtitle = getTextFilterStateText(operator, [], literal, intl);
|
|
168
|
+
const title = dashboardAttributeFilterItemTitle(filter) ?? attribute.attribute.title;
|
|
169
|
+
return {
|
|
170
|
+
type: "attributeFilter",
|
|
171
|
+
all: false,
|
|
172
|
+
id: dashboardAttributeFilterItemLocalIdentifier(filter),
|
|
173
|
+
title,
|
|
174
|
+
subtitle,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
export function useFiltersNamings(filtersToDisplay) {
|
|
183
|
+
const deps = useFilterNamingDependencies(filtersToDisplay);
|
|
184
|
+
return transformFiltersToNamings(filtersToDisplay, deps);
|
|
185
|
+
}
|
|
186
|
+
export function useFiltersByTabNamings(tabFilters) {
|
|
187
|
+
// Collect all filters from all tabs for titles lookup
|
|
188
|
+
const allFilters = Object.values(tabFilters).flat();
|
|
189
|
+
const deps = useFilterNamingDependencies(allFilters);
|
|
190
|
+
// Process each tab's filters separately using the shared transformation function
|
|
191
|
+
const result = {};
|
|
192
|
+
Object.entries(tabFilters).forEach(([tabId, filters]) => {
|
|
193
|
+
result[tabId] = transformFiltersToNamings(filters, deps);
|
|
194
|
+
});
|
|
195
|
+
return result;
|
|
196
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type FilterContextItem, type IAutomationMetadataObject, type IAutomationMetadataObjectDefinition, type IAutomationRecipient, type IExportDefinitionMetadataObject, type IExportDefinitionMetadataObjectDefinition, type IFilter, type IUser, type IWorkspaceUser } from "@gooddata/sdk-model";
|
|
2
|
+
export declare const isDashboardAutomation: (automation: IAutomationMetadataObject | IAutomationMetadataObjectDefinition | undefined) => boolean;
|
|
3
|
+
export declare const isVisualisationAutomation: (automation: IAutomationMetadataObject | IAutomationMetadataObjectDefinition | undefined) => boolean;
|
|
4
|
+
export declare const isCsvVisualizationAutomation: (automation: IAutomationMetadataObject | IAutomationMetadataObjectDefinition | undefined) => boolean;
|
|
5
|
+
export declare const isCsvVisualizationExportDefinition: (exportDefinition: IExportDefinitionMetadataObject | IExportDefinitionMetadataObjectDefinition | undefined) => boolean;
|
|
6
|
+
export declare const isXlsxVisualizationAutomation: (automation: IAutomationMetadataObject | IAutomationMetadataObjectDefinition | undefined) => boolean;
|
|
7
|
+
export declare const isXlsxVisualizationExportDefinition: (exportDefinition: IExportDefinitionMetadataObject | IExportDefinitionMetadataObjectDefinition | undefined) => boolean;
|
|
8
|
+
export declare const getAutomationDashboardFilters: (automation: IAutomationMetadataObject | IAutomationMetadataObjectDefinition | undefined) => FilterContextItem[] | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Extracts dashboard filters structured by tab from automation metadata object.
|
|
11
|
+
* Returns filtersByTab from the first dashboard export definition.
|
|
12
|
+
*/
|
|
13
|
+
export declare const getAutomationDashboardFiltersByTab: (automation: IAutomationMetadataObject | IAutomationMetadataObjectDefinition | undefined) => Record<string, FilterContextItem[]> | undefined;
|
|
14
|
+
export declare const getAutomationVisualizationFilters: (automation: IAutomationMetadataObject | IAutomationMetadataObjectDefinition | undefined) => {
|
|
15
|
+
executionFilters: IFilter[] | undefined;
|
|
16
|
+
filterContextItems: FilterContextItem[] | undefined;
|
|
17
|
+
};
|
|
18
|
+
export declare const getAutomationAlertFilters: (automation: IAutomationMetadataObject | IAutomationMetadataObjectDefinition | undefined) => IFilter[] | undefined;
|
|
19
|
+
export declare const areAutomationsEqual: (originalAutomation: IAutomationMetadataObjectDefinition, updatedAutomation: IAutomationMetadataObjectDefinition) => boolean;
|
|
20
|
+
export declare const convertCurrentUserToAutomationRecipient: (users: IWorkspaceUser[], user: IUser) => IAutomationRecipient;
|
|
21
|
+
export declare const convertCurrentUserToWorkspaceUser: (users: IWorkspaceUser[], user: IUser) => IWorkspaceUser;
|
|
22
|
+
export declare const convertUserToAutomationRecipient: (user: IUser) => IAutomationRecipient;
|
|
23
|
+
export declare const convertExternalRecipientToAutomationRecipient: (externalRecipient: string) => IAutomationRecipient;
|
|
24
|
+
//# sourceMappingURL=automationUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"automationUtils.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/automations/shared/utils/automationUtils.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,mCAAmC,EACxC,KAAK,oBAAoB,EAEzB,KAAK,+BAA+B,EACpC,KAAK,yCAAyC,EAE9C,KAAK,OAAO,EACZ,KAAK,KAAK,EACV,KAAK,cAAc,EAKtB,MAAM,qBAAqB,CAAC;AAE7B,eAAO,MAAM,qBAAqB,sGAYjC,CAAC;AAEF,eAAO,MAAM,yBAAyB,sGAYrC,CAAC;AAEF,eAAO,MAAM,4BAA4B,sGAQxC,CAAC;AAEF,eAAO,MAAM,kCAAkC,wHAW9C,CAAC;AAEF,eAAO,MAAM,6BAA6B,sGAQzC,CAAC;AAEF,eAAO,MAAM,mCAAmC,wHAW/C,CAAC;AAEF,eAAO,MAAM,6BAA6B,8HAYzC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kCAAkC,8IAY9C,CAAC;AAEF,eAAO,MAAM,iCAAiC;;;CAuB7C,CAAC;AAEF,eAAO,MAAM,yBAAyB,oHAQrC,CAAC;AAOF,eAAO,MAAM,mBAAmB,8HAqB/B,CAAC;AAEF,eAAO,MAAM,uCAAuC,gEAOnD,CAAC;AAEF,eAAO,MAAM,iCAAiC,0DAe7C,CAAC;AAEF,eAAO,MAAM,gCAAgC,uCAO5C,CAAC;AAEF,eAAO,MAAM,6CAA6C,qDASzD,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// (C) 2024-2026 GoodData Corporation
|
|
2
|
+
import { isEqual, omit, pick } from "lodash-es";
|
|
3
|
+
import { isExportDefinitionDashboardRequestPayload, isExportDefinitionVisualizationObjectRequestPayload, isFilter, isFilterContextItem, } from "@gooddata/sdk-model";
|
|
4
|
+
export const isDashboardAutomation = (automation) => {
|
|
5
|
+
if (!automation) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
return (automation.exportDefinitions?.some((exportDefinition) => {
|
|
9
|
+
return isExportDefinitionDashboardRequestPayload(exportDefinition.requestPayload);
|
|
10
|
+
}) ?? false);
|
|
11
|
+
};
|
|
12
|
+
export const isVisualisationAutomation = (automation) => {
|
|
13
|
+
if (!automation) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
return (automation.exportDefinitions?.some((exportDefinition) => {
|
|
17
|
+
return isExportDefinitionVisualizationObjectRequestPayload(exportDefinition.requestPayload);
|
|
18
|
+
}) ?? false);
|
|
19
|
+
};
|
|
20
|
+
export const isCsvVisualizationAutomation = (automation) => {
|
|
21
|
+
if (!automation) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return automation.exportDefinitions?.some(isCsvVisualizationExportDefinition) ?? false;
|
|
25
|
+
};
|
|
26
|
+
export const isCsvVisualizationExportDefinition = (exportDefinition) => {
|
|
27
|
+
if (!exportDefinition) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return (isExportDefinitionVisualizationObjectRequestPayload(exportDefinition.requestPayload) &&
|
|
31
|
+
exportDefinition.requestPayload.format === "CSV");
|
|
32
|
+
};
|
|
33
|
+
export const isXlsxVisualizationAutomation = (automation) => {
|
|
34
|
+
if (!automation) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
return automation.exportDefinitions?.some(isXlsxVisualizationExportDefinition) ?? false;
|
|
38
|
+
};
|
|
39
|
+
export const isXlsxVisualizationExportDefinition = (exportDefinition) => {
|
|
40
|
+
if (!exportDefinition) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return (isExportDefinitionVisualizationObjectRequestPayload(exportDefinition.requestPayload) &&
|
|
44
|
+
exportDefinition.requestPayload.format === "XLSX");
|
|
45
|
+
};
|
|
46
|
+
export const getAutomationDashboardFilters = (automation) => {
|
|
47
|
+
if (!automation) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
return automation.exportDefinitions?.find((exportDefinition) => {
|
|
51
|
+
return isExportDefinitionDashboardRequestPayload(exportDefinition.requestPayload);
|
|
52
|
+
})?.requestPayload?.content.filters?.filter((f) => isFilterContextItem(f));
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Extracts dashboard filters structured by tab from automation metadata object.
|
|
56
|
+
* Returns filtersByTab from the first dashboard export definition.
|
|
57
|
+
*/
|
|
58
|
+
export const getAutomationDashboardFiltersByTab = (automation) => {
|
|
59
|
+
if (!automation) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
return automation.exportDefinitions?.find((exportDefinition) => {
|
|
63
|
+
return isExportDefinitionDashboardRequestPayload(exportDefinition.requestPayload);
|
|
64
|
+
})?.requestPayload?.content.filtersByTab;
|
|
65
|
+
};
|
|
66
|
+
export const getAutomationVisualizationFilters = (automation) => {
|
|
67
|
+
if (!automation) {
|
|
68
|
+
return { executionFilters: undefined, filterContextItems: undefined };
|
|
69
|
+
}
|
|
70
|
+
const executionFilters = automation.exportDefinitions?.find((exportDefinition) => {
|
|
71
|
+
return isExportDefinitionVisualizationObjectRequestPayload(exportDefinition.requestPayload);
|
|
72
|
+
})?.requestPayload?.content.filters?.filter((f) => isFilter(f));
|
|
73
|
+
const filterContextItems = automation.exportDefinitions?.find((exportDefinition) => {
|
|
74
|
+
return isExportDefinitionVisualizationObjectRequestPayload(exportDefinition.requestPayload);
|
|
75
|
+
})?.requestPayload?.content.filters?.filter((f) => isFilterContextItem(f));
|
|
76
|
+
return {
|
|
77
|
+
executionFilters: (executionFilters ?? []).length > 0 ? executionFilters : undefined,
|
|
78
|
+
filterContextItems: (filterContextItems ?? []).length > 0 ? filterContextItems : undefined,
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
export const getAutomationAlertFilters = (automation) => {
|
|
82
|
+
if (!automation) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
return automation.alert?.execution?.filters?.filter(isFilter);
|
|
86
|
+
};
|
|
87
|
+
const sortByFormat = (a, b) => a.requestPayload.format.localeCompare(b.requestPayload.format);
|
|
88
|
+
export const areAutomationsEqual = (originalAutomation, updatedAutomation) => {
|
|
89
|
+
const automationWithoutExportDefinitions = omit(updatedAutomation, "exportDefinitions");
|
|
90
|
+
const origAutomationWithoutExportDefinitions = omit(originalAutomation, "exportDefinitions");
|
|
91
|
+
// We only want to compare requestPayload and title of exportDefinitions, rest may be omitted as it is just arbitrary
|
|
92
|
+
// metadata that is not relevant for the comparison and causes false positive results when comparing new and old def.
|
|
93
|
+
// Sorting is done just to avoid false positive result of different order of export definitions.
|
|
94
|
+
const automationExportDefinitions = updatedAutomation.exportDefinitions
|
|
95
|
+
?.map((exportDefinition) => pick(exportDefinition, ["requestPayload", "title"]))
|
|
96
|
+
.sort(sortByFormat);
|
|
97
|
+
const origAutomationExportDefinitions = originalAutomation.exportDefinitions
|
|
98
|
+
?.map((exportDefinition) => pick(exportDefinition, ["requestPayload", "title"]))
|
|
99
|
+
.sort(sortByFormat);
|
|
100
|
+
return (isEqual(automationWithoutExportDefinitions, origAutomationWithoutExportDefinitions) &&
|
|
101
|
+
isEqual(automationExportDefinitions, origAutomationExportDefinitions));
|
|
102
|
+
};
|
|
103
|
+
export const convertCurrentUserToAutomationRecipient = (users, user) => {
|
|
104
|
+
const foundUser = users.find((u) => u.login === user.login);
|
|
105
|
+
return convertUserToAutomationRecipient(foundUser ?? user);
|
|
106
|
+
};
|
|
107
|
+
export const convertCurrentUserToWorkspaceUser = (users, user) => {
|
|
108
|
+
const foundUser = users.find((u) => u.login === user.login);
|
|
109
|
+
return (foundUser ?? {
|
|
110
|
+
email: user.email ?? "",
|
|
111
|
+
fullName: user.fullName,
|
|
112
|
+
status: "ENABLED",
|
|
113
|
+
login: user.login,
|
|
114
|
+
lastName: user.lastName,
|
|
115
|
+
firstName: user.firstName,
|
|
116
|
+
uri: user.login,
|
|
117
|
+
ref: user.ref,
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
export const convertUserToAutomationRecipient = (user) => {
|
|
121
|
+
return {
|
|
122
|
+
id: user.login,
|
|
123
|
+
email: user.email,
|
|
124
|
+
name: user.fullName,
|
|
125
|
+
type: "user",
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
export const convertExternalRecipientToAutomationRecipient = (externalRecipient) => {
|
|
129
|
+
return {
|
|
130
|
+
id: externalRecipient,
|
|
131
|
+
email: externalRecipient,
|
|
132
|
+
name: externalRecipient,
|
|
133
|
+
type: "externalUser",
|
|
134
|
+
};
|
|
135
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type FilterContextItem } from "@gooddata/sdk-model";
|
|
2
|
+
import { type IDashboardFilter } from "../../../../types.js";
|
|
3
|
+
export declare function dashboardFilterToFilterContextItem(filter: IDashboardFilter, keepDatasets: boolean): FilterContextItem | undefined;
|
|
4
|
+
//# sourceMappingURL=filterContextUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filterContextUtils.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/automations/shared/utils/filterContextUtils.ts"],"names":[],"mappings":"AAKA,OAAO,EAEH,KAAK,iBAAiB,EAmBzB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,wBAAgB,kCAAkC,CAC9C,MAAM,EAAE,gBAAgB,EACxB,YAAY,EAAE,OAAO,GACtB,iBAAiB,GAAG,SAAS,CA8E/B"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// (C) 2021-2026 GoodData Corporation
|
|
2
|
+
// Derived from _staging/dashboard/dashboardFilterContext.ts
|
|
3
|
+
import { NotSupported } from "@gooddata/sdk-backend-spi";
|
|
4
|
+
import { filterAttributeElements, filterLocalIdentifier, filterObjRef, isAbsoluteDateFilter, isAllTimeDateFilter, isArbitraryAttributeFilter, isAttributeFilterWithSelection, isMatchAttributeFilter, isMeasureValueFilter, isNegativeAttributeFilter, isObjRef, isRelativeBoundedDateFilter, isRelativeDateFilter, measureValueFilterConditions, measureValueFilterMeasure, newAbsoluteDashboardDateFilter, newAllTimeDashboardDateFilter, newRelativeDashboardDateFilter, } from "@gooddata/sdk-model";
|
|
5
|
+
export function dashboardFilterToFilterContextItem(filter, keepDatasets) {
|
|
6
|
+
if (isAttributeFilterWithSelection(filter)) {
|
|
7
|
+
return {
|
|
8
|
+
attributeFilter: {
|
|
9
|
+
negativeSelection: isNegativeAttributeFilter(filter),
|
|
10
|
+
displayForm: filterObjRef(filter),
|
|
11
|
+
attributeElements: filterAttributeElements(filter),
|
|
12
|
+
selectionMode: "multi",
|
|
13
|
+
localIdentifier: filterLocalIdentifier(filter),
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
else if (isArbitraryAttributeFilter(filter)) {
|
|
18
|
+
return {
|
|
19
|
+
arbitraryAttributeFilter: {
|
|
20
|
+
displayForm: filterObjRef(filter),
|
|
21
|
+
values: filter.arbitraryAttributeFilter.values,
|
|
22
|
+
negativeSelection: filter.arbitraryAttributeFilter.negativeSelection ?? false,
|
|
23
|
+
localIdentifier: filterLocalIdentifier(filter),
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
else if (isMatchAttributeFilter(filter)) {
|
|
28
|
+
return {
|
|
29
|
+
matchAttributeFilter: {
|
|
30
|
+
displayForm: filterObjRef(filter),
|
|
31
|
+
operator: filter.matchAttributeFilter.operator,
|
|
32
|
+
literal: filter.matchAttributeFilter.literal,
|
|
33
|
+
caseSensitive: filter.matchAttributeFilter.caseSensitive,
|
|
34
|
+
negativeSelection: filter.matchAttributeFilter.negativeSelection,
|
|
35
|
+
localIdentifier: filterLocalIdentifier(filter),
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
else if (isAbsoluteDateFilter(filter)) {
|
|
40
|
+
return newAbsoluteDashboardDateFilter(filter.absoluteDateFilter.from, filter.absoluteDateFilter.to, keepDatasets ? filter.absoluteDateFilter.dataSet : undefined, filter.absoluteDateFilter.localIdentifier, filter.absoluteDateFilter.emptyValueHandling);
|
|
41
|
+
}
|
|
42
|
+
else if (isAllTimeDateFilter(filter)) {
|
|
43
|
+
return newAllTimeDashboardDateFilter(keepDatasets ? filter.relativeDateFilter.dataSet : undefined, filter.relativeDateFilter.localIdentifier, filter.relativeDateFilter.emptyValueHandling);
|
|
44
|
+
}
|
|
45
|
+
else if (isRelativeDateFilter(filter)) {
|
|
46
|
+
return newRelativeDashboardDateFilter(filter.relativeDateFilter.granularity, filter.relativeDateFilter.from, filter.relativeDateFilter.to, keepDatasets ? filter.relativeDateFilter.dataSet : undefined, filter.relativeDateFilter.localIdentifier, isRelativeBoundedDateFilter(filter) ? filter.relativeDateFilter.boundedFilter : undefined, filter.relativeDateFilter.emptyValueHandling);
|
|
47
|
+
}
|
|
48
|
+
else if (isMeasureValueFilter(filter)) {
|
|
49
|
+
const measure = measureValueFilterMeasure(filter);
|
|
50
|
+
// Dashboard MVFs always reference the measure by ObjRef. Insight MVFs use LocalIdRef
|
|
51
|
+
// (bucket localId) and have no honest representation in the dashboard filter context —
|
|
52
|
+
// they reach this converter only because automation execution filters mix dashboard and
|
|
53
|
+
// insight filters. Caller is responsible for dropping these undefined entries.
|
|
54
|
+
if (!isObjRef(measure)) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
const conditions = measureValueFilterConditions(filter);
|
|
58
|
+
return {
|
|
59
|
+
dashboardMeasureValueFilter: {
|
|
60
|
+
measure,
|
|
61
|
+
localIdentifier: filter.measureValueFilter.localIdentifier ?? `mvf:${JSON.stringify(measure)}`,
|
|
62
|
+
...(conditions ? { conditions } : {}),
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
throw new NotSupported(`Unsupported filter type! Please provide valid dashboard filter. Filter: ${JSON.stringify(filter)}`);
|
|
67
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDependentDateFilterConfigurationState.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/filterBar/attributeFilter/dashboardDropdownBody/configuration/hooks/useDependentDateFilterConfigurationState.ts"],"names":[],"mappings":"AAMA,OAAO,EACH,KAAK,+BAA+B,EACpC,KAAK,oBAAoB,
|
|
1
|
+
{"version":3,"file":"useDependentDateFilterConfigurationState.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/filterBar/attributeFilter/dashboardDropdownBody/configuration/hooks/useDependentDateFilterConfigurationState.ts"],"names":[],"mappings":"AAMA,OAAO,EACH,KAAK,+BAA+B,EACpC,KAAK,oBAAoB,EAG5B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,KAAK,6BAA6B,EAAE,MAAM,kDAAkD,CAAC;AAEtG;;GAEG;AACH,wBAAgB,wCAAwC,CACpD,eAAe,EAAE,oBAAoB,EAAE,EACvC,gBAAgB,CAAC,EAAE,oBAAoB,EACvC,oBAAoB,CAAC,EAAE,+BAA+B,EAAE,mCAyE3D;AAED,wBAAgB,8CAA8C,CAC1D,gBAAgB,CAAC,EAAE,oBAAoB,GACxC,oBAAoB,CAWtB"}
|
|
@@ -8,12 +8,22 @@ import { isUriRef, } from "@gooddata/sdk-model";
|
|
|
8
8
|
export function useDependentDateFilterConfigurationState(neighborFilters, commonDateFilter, filterElementsByDate) {
|
|
9
9
|
const neighborDateFiltersWithDimensions = useMemo(() => {
|
|
10
10
|
return neighborFilters.map((neighborFilter) => {
|
|
11
|
-
const
|
|
12
|
-
invariant(!isUriRef(
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
const neighborDataSet = neighborFilter.dateFilter.dataSet;
|
|
12
|
+
invariant(!isUriRef(neighborDataSet));
|
|
13
|
+
// Prefer the filter's own localIdentifier over the dataset identifier so that multiple date
|
|
14
|
+
// filters backed by the same dataset can be told apart. Falls back to the dataset identifier
|
|
15
|
+
// for date filters that don't carry a localIdentifier (e.g. older backend records).
|
|
16
|
+
const filterLocalIdentifier = neighborFilter.dateFilter.localIdentifier ?? neighborDataSet?.identifier;
|
|
17
|
+
const isSelected = filterElementsByDate?.some((by) =>
|
|
18
|
+
// Match against both the new (localIdentifier) and legacy (dataset identifier)
|
|
19
|
+
// formats: dashboards saved before this change store the dataset identifier in
|
|
20
|
+
// filterLocalIdentifier, so we must accept either form to stay backwards compatible.
|
|
21
|
+
(by.filterLocalIdentifier === filterLocalIdentifier ||
|
|
22
|
+
by.filterLocalIdentifier === neighborDataSet?.identifier) &&
|
|
23
|
+
!by.isCommonDate) || false;
|
|
24
|
+
invariant(filterLocalIdentifier, "Cannot initialize the attribute filter configuration panel, neighbor date filter has missing 'localIdentifier' property.");
|
|
15
25
|
return {
|
|
16
|
-
localIdentifier:
|
|
26
|
+
localIdentifier: filterLocalIdentifier,
|
|
17
27
|
isSelected,
|
|
18
28
|
dataSet: neighborFilter.dateFilter.dataSet,
|
|
19
29
|
from: neighborFilter.dateFilter.from,
|
|
@@ -28,19 +38,27 @@ export function useDependentDateFilterConfigurationState(neighborFilters, common
|
|
|
28
38
|
const commonDate = parseCommonDateFilter(commonDateFilter);
|
|
29
39
|
return (filterElementsByDate ?? [])
|
|
30
40
|
.filter((parent) => parent.isCommonDate)
|
|
31
|
-
.map((parent) =>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
dataSet
|
|
41
|
+
.map((parent) => {
|
|
42
|
+
// Resolve the target dimension. New format: the explicit `dataSet` field carries it
|
|
43
|
+
// (filterLocalIdentifier references the common date filter itself). Legacy format: no
|
|
44
|
+
// `dataSet`, so the dimension identifier was stored directly in filterLocalIdentifier.
|
|
45
|
+
// The config item is keyed by the dimension so it matches the per-dimension picker items.
|
|
46
|
+
const dimension = parent.dataSet ?? {
|
|
35
47
|
identifier: parent.filterLocalIdentifier,
|
|
36
48
|
type: "dataSet",
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
};
|
|
50
|
+
invariant(!isUriRef(dimension));
|
|
51
|
+
return {
|
|
52
|
+
localIdentifier: dimension.identifier,
|
|
53
|
+
isSelected: true,
|
|
54
|
+
dataSet: dimension,
|
|
55
|
+
from: commonDate.from,
|
|
56
|
+
to: commonDate.to,
|
|
57
|
+
granularity: commonDate.granularity,
|
|
58
|
+
type: commonDate.type,
|
|
59
|
+
isCommonDate: true,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
44
62
|
}, [filterElementsByDate, commonDateFilter]);
|
|
45
63
|
return [...neighborDateFiltersWithDimensions, ...commonDateFilters];
|
|
46
64
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDependentDateFiltersConfiguration.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/filterBar/attributeFilter/dashboardDropdownBody/configuration/hooks/useDependentDateFiltersConfiguration.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useDependentDateFiltersConfiguration.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/filterBar/attributeFilter/dashboardDropdownBody/configuration/hooks/useDependentDateFiltersConfiguration.ts"],"names":[],"mappings":"AAQA,OAAO,EACH,KAAK,yBAAyB,EAE9B,KAAK,oBAAoB,EAE5B,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAE,KAAK,6BAA6B,EAAE,MAAM,kDAAkD,CAAC;AAOtG,wBAAgB,oCAAoC,CAChD,mBAAmB,EAAE,oBAAoB,EAAE,EAC3C,aAAa,EAAE,yBAAyB,EACxC,gBAAgB,CAAC,EAAE,oBAAoB;;;;;;;EAqH1C"}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import { useCallback, useMemo, useState } from "react";
|
|
3
3
|
import { isEqual } from "lodash-es";
|
|
4
4
|
import { invariant } from "ts-invariant";
|
|
5
|
-
import {
|
|
5
|
+
import { generateDateFilterLocalIdentifier } from "@gooddata/sdk-backend-base";
|
|
6
|
+
import { isUriRef, } from "@gooddata/sdk-model";
|
|
6
7
|
import { setAttributeFilterDependentDateFilters } from "../../../../../../model/commands/filters.js";
|
|
7
8
|
import { useDispatchDashboardCommand } from "../../../../../../model/react/useDispatchDashboardCommand.js";
|
|
8
9
|
import { useDependentCommonDateFilterConfigurationState, useDependentDateFilterConfigurationState, } from "./useDependentDateFilterConfigurationState.js";
|
|
@@ -15,9 +16,11 @@ export function useDependentDateFiltersConfiguration(neighborDateFilters, curren
|
|
|
15
16
|
const [dependentDateFilters, setDependentDateFilters] = useState(originalState);
|
|
16
17
|
const [dependentCommonDateFilter, setDependentCommonDateFilter] = useState(originalCommonDateFilterState);
|
|
17
18
|
const onDependentDateFiltersSelect = (item, isSelected, isCommonDate) => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
invariant(!isUriRef(item.dataSet));
|
|
20
|
+
// Match on item.localIdentifier rather than item.dataSet?.identifier (the dataset identifier):
|
|
21
|
+
// state entries now store dateFilter.localIdentifier as their key, which matches item.localIdentifier
|
|
22
|
+
// since both come from the same useDependentDateFilterConfigurationState initializer.
|
|
23
|
+
const changedParentIndex = dependentDateFilters.findIndex((dependentDateFilter) => dependentDateFilter.localIdentifier === item.localIdentifier &&
|
|
21
24
|
dependentDateFilter.isCommonDate === isCommonDate);
|
|
22
25
|
if (changedParentIndex === -1) {
|
|
23
26
|
setDependentDateFilters([...dependentDateFilters, item]);
|
|
@@ -44,18 +47,30 @@ export function useDependentDateFiltersConfiguration(neighborDateFilters, curren
|
|
|
44
47
|
const onDependentDateFiltersChange = useCallback(() => {
|
|
45
48
|
// dispatch the command only if the configuration changed
|
|
46
49
|
if (onDependentDateFiltersConfigurationChanged) {
|
|
50
|
+
// Common date filter has no dimension of its own, so we reference it by its own
|
|
51
|
+
// localIdentifier (falling back to the canonical common-date id) and carry the chosen
|
|
52
|
+
// dimension in the separate `dataSet` field. Specific date filters are referenced by their
|
|
53
|
+
// localIdentifier and need no dataSet (it is derived from the referenced filter).
|
|
54
|
+
const commonDateLocalId = commonDateFilter?.dateFilter.localIdentifier ?? generateDateFilterLocalIdentifier(0);
|
|
47
55
|
const dateFilters = dependentDateFilters
|
|
48
56
|
.filter((filter) => filter.isSelected)
|
|
49
|
-
.map((filter) =>
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
.map((filter) => filter.isCommonDate
|
|
58
|
+
? {
|
|
59
|
+
filterLocalIdentifier: commonDateLocalId,
|
|
60
|
+
isCommonDate: true,
|
|
61
|
+
dataSet: filter.dataSet,
|
|
62
|
+
}
|
|
63
|
+
: {
|
|
64
|
+
filterLocalIdentifier: filter.localIdentifier,
|
|
65
|
+
isCommonDate: false,
|
|
66
|
+
});
|
|
53
67
|
saveDependentDateFilterCommand(currentFilter.attributeFilter.localIdentifier, dateFilters);
|
|
54
68
|
}
|
|
55
69
|
}, [
|
|
56
70
|
dependentDateFilters,
|
|
57
71
|
onDependentDateFiltersConfigurationChanged,
|
|
58
72
|
currentFilter,
|
|
73
|
+
commonDateFilter,
|
|
59
74
|
saveDependentDateFilterCommand,
|
|
60
75
|
]);
|
|
61
76
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDependentDateFilters.d.ts","sourceRoot":"","sources":["../../../../src/presentation/filterBar/attributeFilter/useDependentDateFilters.ts"],"names":[],"mappings":"AAMA,OAAO,EACH,KAAK,4BAA4B,
|
|
1
|
+
{"version":3,"file":"useDependentDateFilters.d.ts","sourceRoot":"","sources":["../../../../src/presentation/filterBar/attributeFilter/useDependentDateFilters.ts"],"names":[],"mappings":"AAMA,OAAO,EACH,KAAK,4BAA4B,EAMpC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAe1E;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,yBAAyB,EAAE,sBAAsB,CAAC,CAAC;AAE7F;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,8FAiFnC,CAAC"}
|
|
@@ -34,23 +34,34 @@ export const useDependentDateFilters = (filter, tabId) => {
|
|
|
34
34
|
const dependentDateFilters = useMemo(() => {
|
|
35
35
|
return filterElementsByDate?.map((dependentDateFilter) => {
|
|
36
36
|
if (dependentDateFilter.isCommonDate) {
|
|
37
|
+
// The dimension to apply the common date range through.
|
|
38
|
+
// New format: the explicit `dataSet` field (filterLocalIdentifier references the common
|
|
39
|
+
// date filter itself). Legacy format: no `dataSet` field, so the dataset identifier was
|
|
40
|
+
// stored directly in filterLocalIdentifier.
|
|
41
|
+
const dataSet = dependentDateFilter.dataSet ?? {
|
|
42
|
+
identifier: dependentDateFilter.filterLocalIdentifier,
|
|
43
|
+
type: "dataSet",
|
|
44
|
+
};
|
|
37
45
|
const commonDashboardDateFilter = {
|
|
38
46
|
dateFilter: {
|
|
39
47
|
type: commonDateFilterWithAllTime?.dateFilter.type,
|
|
40
48
|
granularity: commonDateFilterWithAllTime?.dateFilter.granularity,
|
|
41
49
|
from: commonDateFilterWithAllTime?.dateFilter.from,
|
|
42
50
|
to: commonDateFilterWithAllTime?.dateFilter.to,
|
|
43
|
-
dataSet
|
|
44
|
-
identifier: dependentDateFilter.filterLocalIdentifier,
|
|
45
|
-
type: "dataSet",
|
|
46
|
-
},
|
|
51
|
+
dataSet,
|
|
47
52
|
},
|
|
48
53
|
};
|
|
49
54
|
return commonDashboardDateFilter;
|
|
50
55
|
}
|
|
51
56
|
else {
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
// Try localIdentifier first (new format), then fall back to dataset identifier
|
|
58
|
+
// (legacy format) for dashboards saved before the localIdentifier-based approach.
|
|
59
|
+
// NOTE: If a filter's localIdentifier happens to equal another filter's dataset
|
|
60
|
+
// identifier the wrong filter could be matched — this is an accepted theoretical
|
|
61
|
+
// risk given the practical namespace separation between the two.
|
|
62
|
+
const matchingFilter = allDateFilters.find((filter) => filter.dateFilter.localIdentifier === dependentDateFilter.filterLocalIdentifier ||
|
|
63
|
+
objRefToString(filter.dateFilter.dataSet) ===
|
|
64
|
+
dependentDateFilter.filterLocalIdentifier);
|
|
54
65
|
invariant(matchingFilter); // if this blows up, the state is inconsistent
|
|
55
66
|
return matchingFilter;
|
|
56
67
|
}
|
|
@@ -236,5 +236,5 @@ function MenuItem({ menuItem, selectedMenuItem, setMenuItemRef, setSelectedMenuI
|
|
|
236
236
|
});
|
|
237
237
|
}
|
|
238
238
|
function renderMenuItemWarning(info, suppressHover) {
|
|
239
|
-
return (_jsx("span", { className: "gd-list-icon gd-list-icon-right", children: _jsx(UiTooltip, { triggerBy: ["hover"], disabled: suppressHover, arrowPlacement: "left", optimalPlacement: true, content: info, anchor: _jsx(UiIcon, { type: "warning", size: 16, color: "warning", accessibilityConfig: { ariaHidden: true } }) }) }));
|
|
239
|
+
return (_jsx("span", { className: "gd-list-icon gd-list-icon-right", "data-testid": "menu-item-info-icon", children: _jsx(UiTooltip, { triggerBy: ["hover"], disabled: suppressHover, arrowPlacement: "left", optimalPlacement: true, content: info, anchor: _jsx(UiIcon, { type: "warning", size: 16, color: "warning", accessibilityConfig: { ariaHidden: true } }) }) }));
|
|
240
240
|
}
|