@gooddata/sdk-ui-dashboard 11.39.0-alpha.3 → 11.39.0
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 +3 -3
- package/esm/__version.d.ts +1 -1
- package/esm/__version.js +1 -1
- package/esm/converters/filterConverters.d.ts +3 -2
- package/esm/converters/filterConverters.js +5 -3
- package/esm/index.d.ts +2 -2
- package/esm/index.js +2 -2
- package/esm/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.js +6 -0
- package/esm/model/commandHandlers/filterContext/measureValueFilter/changeMeasureValueFilterDimensionalityHandler.d.ts +4 -0
- package/esm/model/commandHandlers/filterContext/measureValueFilter/changeMeasureValueFilterDimensionalityHandler.js +24 -0
- package/esm/model/commandHandlers/index.js +2 -0
- package/esm/model/commands/base.d.ts +1 -1
- package/esm/model/commands/filters.d.ts +35 -0
- package/esm/model/commands/filters.js +19 -0
- package/esm/model/commands/index.d.ts +2 -2
- package/esm/model/events/base.d.ts +1 -1
- package/esm/model/events/filters.d.ts +36 -0
- package/esm/model/events/filters.js +19 -0
- package/esm/model/events/index.d.ts +2 -2
- package/esm/model/queryServices/queryWidgetFilters.js +10 -2
- package/esm/model/react/useDashboardCommand.d.ts +2 -1
- package/esm/model/react/useDashboardCommandProcessing.d.ts +8 -0
- package/esm/model/store/tabs/filterContext/filterContextReducers.d.ts +8 -0
- package/esm/model/store/tabs/filterContext/filterContextReducers.js +22 -0
- package/esm/model/store/tabs/filterContext/filterContextState.d.ts +2 -1
- package/esm/model/store/tabs/index.d.ts +7 -0
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/DefaultAlertingDialog.js +11 -7
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/components/AlertAttributeSelect.d.ts +2 -1
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/components/AlertAttributeSelect.js +3 -3
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/components/AlertComparisonPeriodSelect.d.ts +4 -3
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/components/AlertComparisonPeriodSelect.js +56 -25
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/components/AlertMeasureSelect.d.ts +2 -1
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/components/AlertMeasureSelect.js +2 -2
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/hooks/useAlertValidation.js +3 -1
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/hooks/useEditAlert.d.ts +4 -2
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/hooks/useEditAlert.js +10 -5
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/utils/getters.js +8 -1
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/utils/items.d.ts +6 -3
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/utils/items.js +235 -127
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/utils/transformation.d.ts +3 -2
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/utils/transformation.js +5 -2
- package/esm/presentation/filterBar/measureValueFilter/DefaultDashboardMeasureValueFilter.js +40 -7
- package/esm/presentation/filterBar/measureValueFilter/MeasureValueFilterConfiguration.d.ts +7 -2
- package/esm/presentation/filterBar/measureValueFilter/MeasureValueFilterConfiguration.js +7 -3
- package/esm/presentation/filterBar/measureValueFilter/useDashboardMeasureValueFilterData.d.ts +9 -0
- package/esm/presentation/filterBar/measureValueFilter/useDashboardMeasureValueFilterData.js +125 -6
- package/esm/presentation/localization/bundles/de-DE.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/de-DE.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/en-AU.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/en-AU.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/en-GB.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/en-GB.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/en-US.localization-bundle.d.ts +8 -0
- package/esm/presentation/localization/bundles/en-US.localization-bundle.js +9 -1
- package/esm/presentation/localization/bundles/es-419.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/es-419.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/es-ES.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/es-ES.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/fi-FI.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/fi-FI.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/fr-CA.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/fr-CA.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/fr-FR.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/fr-FR.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/id-ID.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/id-ID.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/it-IT.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/it-IT.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/ja-JP.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/ja-JP.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/ko-KR.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/ko-KR.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/nl-NL.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/nl-NL.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/pl-PL.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/pl-PL.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/pt-BR.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/pt-BR.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/pt-PT.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/pt-PT.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/ru-RU.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/ru-RU.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/sl-SI.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/sl-SI.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/th-TH.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/th-TH.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/tr-TR.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/tr-TR.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/uk-UA.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/uk-UA.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/vi-VN.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/vi-VN.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/zh-HK.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/zh-HK.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.js +2 -1
- package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.d.ts +1 -0
- package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.js +2 -1
- package/esm/presentation/widget/common/configuration/FilterConfiguration.js +5 -2
- package/esm/presentation/widget/common/configuration/MeasureValueFilterConfigurationItem.d.ts +2 -1
- package/esm/presentation/widget/common/configuration/MeasureValueFilterConfigurationItem.js +9 -6
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/EditAlert.js +2 -2
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useEditAlert.d.ts +2 -2
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useEditAlert.js +2 -2
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useInsightWidgetAlerting.js +1 -1
- package/esm/sdk-ui-dashboard.d.ts +96 -4
- package/package.json +20 -20
- package/styles/css/dashboard.css +30 -2
- package/styles/css/dashboard.css.map +1 -1
- package/styles/css/main.css +247 -2
- package/styles/css/main.css.map +1 -1
- package/styles/css/notifications_channels_dialog.css +30 -2
- package/styles/css/notifications_channels_dialog.css.map +1 -1
- package/styles/scss/notifications_channels_dialog.scss +46 -5
|
@@ -159,8 +159,12 @@ export declare const useDashboardCommandProcessing: <TCommand extends DashboardC
|
|
|
159
159
|
type: TSuccessEventType;
|
|
160
160
|
}> | Extract<import("../events/filters.js").IDashboardMeasureValueFilterAdded, {
|
|
161
161
|
type: TSuccessEventType;
|
|
162
|
+
}> | Extract<import("../events/filters.js").IDashboardMeasureValueFilterConditionChanged, {
|
|
163
|
+
type: TSuccessEventType;
|
|
162
164
|
}> | Extract<import("../events/filters.js").IDashboardMeasureValueFilterConfigModeChanged, {
|
|
163
165
|
type: TSuccessEventType;
|
|
166
|
+
}> | Extract<import("../events/filters.js").IDashboardMeasureValueFilterDimensionalityChanged, {
|
|
167
|
+
type: TSuccessEventType;
|
|
164
168
|
}> | Extract<import("../events/filters.js").IDashboardMeasureValueFilterMoved, {
|
|
165
169
|
type: TSuccessEventType;
|
|
166
170
|
}> | Extract<import("../events/filters.js").IDashboardMeasureValueFilterRemoved, {
|
|
@@ -398,8 +402,12 @@ export declare const useDashboardCommandProcessing: <TCommand extends DashboardC
|
|
|
398
402
|
type: TErrorEventType;
|
|
399
403
|
}> | Extract<import("../events/filters.js").IDashboardMeasureValueFilterAdded, {
|
|
400
404
|
type: TErrorEventType;
|
|
405
|
+
}> | Extract<import("../events/filters.js").IDashboardMeasureValueFilterConditionChanged, {
|
|
406
|
+
type: TErrorEventType;
|
|
401
407
|
}> | Extract<import("../events/filters.js").IDashboardMeasureValueFilterConfigModeChanged, {
|
|
402
408
|
type: TErrorEventType;
|
|
409
|
+
}> | Extract<import("../events/filters.js").IDashboardMeasureValueFilterDimensionalityChanged, {
|
|
410
|
+
type: TErrorEventType;
|
|
403
411
|
}> | Extract<import("../events/filters.js").IDashboardMeasureValueFilterMoved, {
|
|
404
412
|
type: TErrorEventType;
|
|
405
413
|
}> | Extract<import("../events/filters.js").IDashboardMeasureValueFilterRemoved, {
|
|
@@ -247,6 +247,10 @@ type IChangeMeasureValueFilterTitleReducerPayload = {
|
|
|
247
247
|
readonly filterLocalId: string;
|
|
248
248
|
readonly title?: string;
|
|
249
249
|
};
|
|
250
|
+
type ISetMeasureValueFilterDimensionalityReducerPayload = {
|
|
251
|
+
readonly localIdentifier: string;
|
|
252
|
+
readonly dimensionality?: ObjRef[];
|
|
253
|
+
};
|
|
250
254
|
export declare const filterContextReducers: {
|
|
251
255
|
setFilterContext: FilterContextReducer<{
|
|
252
256
|
payload: SetFilterContextPayload;
|
|
@@ -372,6 +376,10 @@ export declare const filterContextReducers: {
|
|
|
372
376
|
payload: IChangeMeasureValueFilterConditionReducerPayload;
|
|
373
377
|
type: string;
|
|
374
378
|
}>;
|
|
379
|
+
setMeasureValueFilterDimensionality: FilterContextReducer<{
|
|
380
|
+
payload: ISetMeasureValueFilterDimensionalityReducerPayload;
|
|
381
|
+
type: string;
|
|
382
|
+
}>;
|
|
375
383
|
changeMeasureValueFilterTitle: FilterContextReducer<{
|
|
376
384
|
payload: IChangeMeasureValueFilterTitleReducerPayload;
|
|
377
385
|
type: string;
|
|
@@ -866,6 +866,27 @@ const changeMeasureValueFilterCondition = (state, action) => {
|
|
|
866
866
|
},
|
|
867
867
|
};
|
|
868
868
|
};
|
|
869
|
+
const setMeasureValueFilterDimensionality = (state, action) => {
|
|
870
|
+
const activeTab = getActiveTab(state);
|
|
871
|
+
if (!activeTab) {
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
invariant(activeTab.filterContext?.filterContextDefinition?.filters, "Attempt to edit uninitialized filter context");
|
|
875
|
+
const filters = activeTab.filterContext.filterContextDefinition.filters;
|
|
876
|
+
const index = filters.findIndex((item) => isDashboardMeasureValueFilter(item) &&
|
|
877
|
+
dashboardFilterLocalIdentifier(item) === action.payload.localIdentifier);
|
|
878
|
+
invariant(index >= 0, `Attempt to change dimensionality of measure value filter ${action.payload.localIdentifier} that does not exist`);
|
|
879
|
+
const filter = filters[index];
|
|
880
|
+
const dimensionality = action.payload.dimensionality && action.payload.dimensionality.length > 0
|
|
881
|
+
? action.payload.dimensionality
|
|
882
|
+
: undefined;
|
|
883
|
+
filters[index] = {
|
|
884
|
+
dashboardMeasureValueFilter: {
|
|
885
|
+
...filter.dashboardMeasureValueFilter,
|
|
886
|
+
dimensionality,
|
|
887
|
+
},
|
|
888
|
+
};
|
|
889
|
+
};
|
|
869
890
|
const changeMeasureValueFilterTitle = (state, action) => {
|
|
870
891
|
const activeTab = getActiveTab(state);
|
|
871
892
|
if (!activeTab) {
|
|
@@ -919,5 +940,6 @@ export const filterContextReducers = {
|
|
|
919
940
|
resetWorkingSelection,
|
|
920
941
|
setDefaultFilterOverrides,
|
|
921
942
|
changeMeasureValueFilterCondition,
|
|
943
|
+
setMeasureValueFilterDimensionality,
|
|
922
944
|
changeMeasureValueFilterTitle,
|
|
923
945
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type IAttributeWithReferences } from "@gooddata/sdk-backend-spi";
|
|
2
|
-
import { type FilterContextItem, type IAttributeDisplayFormMetadataObject, type IDashboardAttributeFilter, type IDashboardDateFilter, type IDashboardObjectIdentity, type IFilterContextDefinition, type MeasureValueFilterCondition } from "@gooddata/sdk-model";
|
|
2
|
+
import { type FilterContextItem, type IAttributeDisplayFormMetadataObject, type IDashboardAttributeFilter, type IDashboardDateFilter, type IDashboardObjectIdentity, type IFilterContextDefinition, type MeasureValueFilterCondition, type ObjRef } from "@gooddata/sdk-model";
|
|
3
3
|
/**
|
|
4
4
|
* Partial working attribute filter used in working filter context.
|
|
5
5
|
*
|
|
@@ -17,6 +17,7 @@ export type WorkingDashboardMeasureValueFilter = {
|
|
|
17
17
|
dashboardMeasureValueFilter: {
|
|
18
18
|
localIdentifier: string;
|
|
19
19
|
conditions?: MeasureValueFilterCondition[];
|
|
20
|
+
dimensionality?: ObjRef[];
|
|
20
21
|
};
|
|
21
22
|
};
|
|
22
23
|
/**
|
|
@@ -238,6 +238,13 @@ export declare const tabsActions: import("@reduxjs/toolkit").CaseReducerActions<
|
|
|
238
238
|
payload: import("./filterContext/filterContextReducers.js").IChangeMeasureValueFilterConditionReducerPayload;
|
|
239
239
|
type: string;
|
|
240
240
|
}) => void | import("./tabsState.js").ITabsState | import("immer").WritableDraft<import("./tabsState.js").ITabsState>;
|
|
241
|
+
readonly setMeasureValueFilterDimensionality: (state: import("immer").WritableDraft<import("./tabsState.js").ITabsState>, action: {
|
|
242
|
+
payload: {
|
|
243
|
+
readonly localIdentifier: string;
|
|
244
|
+
readonly dimensionality?: import("@gooddata/sdk-model").ObjRef[] | undefined;
|
|
245
|
+
};
|
|
246
|
+
type: string;
|
|
247
|
+
}) => void | import("./tabsState.js").ITabsState | import("immer").WritableDraft<import("./tabsState.js").ITabsState>;
|
|
241
248
|
readonly changeMeasureValueFilterTitle: (state: import("immer").WritableDraft<import("./tabsState.js").ITabsState>, action: {
|
|
242
249
|
payload: {
|
|
243
250
|
readonly filterLocalId: string;
|
package/esm/presentation/automations/alerting/DefaultAlertingDialog/DefaultAlertingDialog.js
CHANGED
|
@@ -63,7 +63,7 @@ export function AlertingDialogRenderer({ alertToEdit, users, usersError, notific
|
|
|
63
63
|
automationToEdit: alertToEdit,
|
|
64
64
|
widget,
|
|
65
65
|
});
|
|
66
|
-
const { onTitleChange, onRecipientsChange, onFiltersChange, onApplyCurrentFilters, onMeasureChange, getAttributeValues, onAttributeChange, onComparisonOperatorChange, onRelativeOperatorChange, onAnomalyDetectionChange, onChange, onBlur, onComparisonTypeChange, onDestinationChange, onTriggerModeChange, onTriggerIntervalChange, selectedMeasure, supportedMeasures, canManageAttributes, selectedAttribute, selectedValue, supportedAttributes, catalogAttributes, catalogDateDatasets, isResultLoading, selectedComparisonOperator, selectedRelativeOperator, selectedAiOperator, value, selectedComparator, selectedSensitivity, onSensitivityChange, selectedGranularity, onGranularityChange, canManageComparison, separators, defaultUser, originalAutomation, editedAutomation, allowOnlyLoggedUserRecipients, allowExternalRecipients, warningMessage, validationErrorMessage, isSubmitDisabled, isParentValid, thresholdErrorMessage, allowHourlyRecurrence, } = useEditAlert({
|
|
66
|
+
const { onTitleChange, onRecipientsChange, onFiltersChange, onApplyCurrentFilters, onMeasureChange, getAttributeValues, onAttributeChange, onComparisonOperatorChange, onRelativeOperatorChange, onAnomalyDetectionChange, onChange, onBlur, onComparisonTypeChange, onDestinationChange, onTriggerModeChange, onTriggerIntervalChange, selectedMeasure, canChangeMeasure, supportedMeasures, canManageAttributes, selectedAttribute, selectedValue, supportedAttributes, catalogAttributes, catalogDateDatasets, isResultLoading, selectedComparisonOperator, selectedRelativeOperator, selectedAiOperator, value, selectedComparator, selectedSensitivity, onSensitivityChange, selectedGranularity, onGranularityChange, canManageComparison, separators, defaultUser, originalAutomation, editedAutomation, allowOnlyLoggedUserRecipients, allowExternalRecipients, warningMessage, validationErrorMessage, isInvalidConnectionToInsight, isSubmitDisabled, isParentValid, thresholdErrorMessage, allowHourlyRecurrence, } = useEditAlert({
|
|
67
67
|
insight,
|
|
68
68
|
widget,
|
|
69
69
|
alertToEdit,
|
|
@@ -118,10 +118,14 @@ export function AlertingDialogRenderer({ alertToEdit, users, usersError, notific
|
|
|
118
118
|
const invalidDatapoints = getInvalidDatapoints();
|
|
119
119
|
useEffect(() => {
|
|
120
120
|
setInvalidDatapoints(() => [
|
|
121
|
-
!!validationErrorMessage &&
|
|
121
|
+
!!validationErrorMessage &&
|
|
122
|
+
createInvalidDatapoint({
|
|
123
|
+
message: validationErrorMessage,
|
|
124
|
+
severity: isInvalidConnectionToInsight ? "error" : "warning",
|
|
125
|
+
}),
|
|
122
126
|
!!thresholdErrorMessage && createInvalidDatapoint({ message: thresholdErrorMessage }),
|
|
123
127
|
]);
|
|
124
|
-
}, [validationErrorMessage, thresholdErrorMessage, setInvalidDatapoints]);
|
|
128
|
+
}, [validationErrorMessage, thresholdErrorMessage, isInvalidConnectionToInsight, setInvalidDatapoints]);
|
|
125
129
|
const helpTextId = isMobileView()
|
|
126
130
|
? defineMessage({ id: "dialogs.alerting.footer.title.short" }).id
|
|
127
131
|
: defineMessage({ id: "dialogs.alerting.footer.title" }).id;
|
|
@@ -164,10 +168,10 @@ export function AlertingDialogRenderer({ alertToEdit, users, usersError, notific
|
|
|
164
168
|
_jsx("div", { className: "gd-divider-with-margin" }), _jsxs(_Fragment, { children: [
|
|
165
169
|
_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" })
|
|
166
170
|
] }), _jsxs(FormFieldGroup, { label: _jsx(FormattedMessage, { id: "insightAlert.config.when" }), children: [
|
|
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) &&
|
|
171
|
+
_jsx(FormField, { label: intl.formatMessage({ id: "insightAlert.config.metric" }), htmlFor: "alert.measure", children: _jsx(AlertMeasureSelect, { selectedMeasure: selectedMeasure, onMeasureChange: onMeasureChange, measures: supportedMeasures, disabled: !canChangeMeasure, overlayPositionType: OVERLAY_POSITION_TYPE, id: "alert.measure", closeOnParentScroll: CLOSE_ON_PARENT_SCROLL }) }), Boolean(canManageAttributes) &&
|
|
168
172
|
supportedAttributes.filter((a) => a.type === "attribute").length >
|
|
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) => {
|
|
170
|
-
onComparisonTypeChange(selectedMeasure, selectedRelativeOperator, comparisonType);
|
|
173
|
+
0 && (_jsx(FormField, { label: _jsx(FormattedMessage, { id: "insightAlert.config.for" }), htmlFor: "alert.attribute", children: _jsx(AlertAttributeSelect, { id: "alert.attribute", disabled: !canChangeMeasure, 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, selectedGranularity: selectedComparator?.granularity, onComparisonChange: (comparisonType, granularity) => {
|
|
174
|
+
onComparisonTypeChange(selectedMeasure, selectedRelativeOperator, comparisonType, granularity);
|
|
171
175
|
}, overlayPositionType: OVERLAY_POSITION_TYPE, canManageComparison: canManageComparison, closeOnParentScroll: CLOSE_ON_PARENT_SCROLL }) })), isAnomalyDetection(editedAutomation?.alert) && (_jsxs(_Fragment, { children: [
|
|
172
176
|
_jsx(FormField, { label: _jsx(FormattedMessage, { id: "insightAlert.config.sensitivity" }), htmlFor: "alert.sensitivity", children: _jsx(AlertSensitivitySelect, { id: "alert.sensitivity", selectedSensitivity: selectedSensitivity, onSensitivityChange: onSensitivityChange, overlayPositionType: OVERLAY_POSITION_TYPE, closeOnParentScroll: CLOSE_ON_PARENT_SCROLL }) }), _jsx(FormField, { label: _jsxs("div", { className: "gd-dashboard-alerting-dialog-form-field__content-container-tooltip", children: [
|
|
173
177
|
_jsx(FormattedMessage, { id: "insightAlert.config.granularity" }), _jsx(UiTooltip, { anchor: _jsx(UiIconButton, { icon: "question", variant: "tertiary", size: "xsmall", accessibilityConfig: {
|
|
@@ -185,7 +189,7 @@ export function AlertingDialogRenderer({ alertToEdit, users, usersError, notific
|
|
|
185
189
|
}),
|
|
186
190
|
} }), content: _jsx(FormattedMessage, { id: "insightAlert.config.interval.tooltip" }), arrowPlacement: "left", optimalPlacement: true, offset: 10, width: 280, triggerBy: ["hover", "click"] })
|
|
187
191
|
] }), htmlFor: "alert.interval", children: _jsx(AlertTriggerIntervalSelect, { id: "alert.interval", selectedTriggerInterval: editedAutomation?.alert?.trigger.interval ?? "DAY", onTriggerIntervalChange: onTriggerIntervalChange, overlayPositionType: OVERLAY_POSITION_TYPE, closeOnParentScroll: CLOSE_ON_PARENT_SCROLL }) })) : null, _jsx(FormField, { label: _jsx(FormattedMessage, { id: "insightAlert.config.recipients" }), htmlFor: "alert.recipients", fullWidth: true, children: _jsx(RecipientsSelect, { id: "alert.recipients", loggedUser: defaultUser, users: users, usersError: usersError, value: editedAutomation?.recipients ?? [], originalValue: originalAutomation?.recipients || [], onChange: onRecipientsChange, allowEmptySelection: true, allowOnlyLoggedUserRecipients: allowOnlyLoggedUserRecipients, allowExternalRecipients: allowExternalRecipients, maxRecipients: maxAutomationsRecipients, notificationChannels: notificationChannels, notificationChannelId: editedAutomation?.notificationChannel, showLabel: false, externalRecipientOverride: externalRecipientOverride }) })
|
|
188
|
-
] }), warningMessage ? (_jsx(Message, { type: "warning", className: "gd-notifications-channels-dialog-error", children: warningMessage })) : null, invalidDatapoints.map((datapoint) => (_jsx(Message, { type: "
|
|
192
|
+
] }), warningMessage ? (_jsx(Message, { type: "warning", className: "gd-notifications-channels-dialog-error", children: warningMessage })) : null, invalidDatapoints.map((datapoint) => (_jsx(Message, { id: datapoint.id, type: datapoint.severity === "info" ? "progress" : datapoint.severity, className: "gd-notifications-channels-dialog-error gd-notifications-channels-dialog-error-scrollable", children: datapoint.message }, datapoint.id)))] })
|
|
189
193
|
] }) }) }) }), alertToDelete ? (_jsx(DeleteAlertConfirmDialog, { alert: alertToDelete, onCancel: () => setAlertToDelete(null), onSuccess: handleAlertDeleteSuccess, onError: onDeleteError })) : null] }));
|
|
190
194
|
}
|
|
191
195
|
/**
|
|
@@ -3,6 +3,7 @@ import { type AlertAttribute } from "../../types.js";
|
|
|
3
3
|
import { type AttributeValue } from "../hooks/useAttributeValuesFromExecResults.js";
|
|
4
4
|
export interface IAlertAttributeSelectProps {
|
|
5
5
|
id: string;
|
|
6
|
+
disabled?: boolean;
|
|
6
7
|
selectedAttribute: AlertAttribute | undefined;
|
|
7
8
|
selectedValue: string | null | undefined;
|
|
8
9
|
onAttributeChange: (attribute: AlertAttribute | undefined, value: AttributeValue | undefined) => void;
|
|
@@ -14,4 +15,4 @@ export interface IAlertAttributeSelectProps {
|
|
|
14
15
|
showLabel?: boolean;
|
|
15
16
|
closeOnParentScroll?: boolean;
|
|
16
17
|
}
|
|
17
|
-
export declare function AlertAttributeSelect({ id, selectedAttribute: selectedAttributeProp, getAttributeValues, isResultLoading, selectedValue, onAttributeChange, attributes, catalogAttributes, catalogDateDatasets, showLabel, closeOnParentScroll }: IAlertAttributeSelectProps): import("react/jsx-runtime").JSX.Element | null;
|
|
18
|
+
export declare function AlertAttributeSelect({ id, disabled, selectedAttribute: selectedAttributeProp, getAttributeValues, isResultLoading, selectedValue, onAttributeChange, attributes, catalogAttributes, catalogDateDatasets, showLabel, closeOnParentScroll }: IAlertAttributeSelectProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -54,7 +54,7 @@ function AttributeValuesSearchContent({ attribute, values, isSelected, selectedA
|
|
|
54
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
55
|
] }));
|
|
56
56
|
}
|
|
57
|
-
export function AlertAttributeSelect({ id, selectedAttribute: selectedAttributeProp, getAttributeValues, isResultLoading, selectedValue, onAttributeChange, attributes, catalogAttributes, catalogDateDatasets, showLabel = true, closeOnParentScroll, }) {
|
|
57
|
+
export function AlertAttributeSelect({ id, disabled, selectedAttribute: selectedAttributeProp, getAttributeValues, isResultLoading, selectedValue, onAttributeChange, attributes, catalogAttributes, catalogDateDatasets, showLabel = true, closeOnParentScroll, }) {
|
|
58
58
|
const intl = useIntl();
|
|
59
59
|
const availableAttributes = useMemo(() => {
|
|
60
60
|
return attributes.filter((attr) => attr.type === "attribute");
|
|
@@ -135,10 +135,10 @@ export function AlertAttributeSelect({ id, selectedAttribute: selectedAttributeP
|
|
|
135
135
|
return (_jsx(DropdownButton, { id: id, className: cx("gd-alert-attribute-select__button", {
|
|
136
136
|
"is-active": isOpen,
|
|
137
137
|
}), value: buttonValue, iconLeft: "gd-icon-attribute", onClick: () => {
|
|
138
|
-
if (!isResultLoading) {
|
|
138
|
+
if (!isResultLoading && !disabled) {
|
|
139
139
|
toggleDropdown();
|
|
140
140
|
}
|
|
141
|
-
}, disabled: isResultLoading, buttonRef: buttonRef, dropdownId: dropdownId, isOpen: isOpen, accessibilityConfig: {
|
|
141
|
+
}, disabled: isResultLoading || disabled, buttonRef: buttonRef, dropdownId: dropdownId, isOpen: isOpen, accessibilityConfig: {
|
|
142
142
|
ariaExpanded: isOpen,
|
|
143
143
|
popupType: "menu",
|
|
144
144
|
} }));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type IAutomationMetadataObject } from "@gooddata/sdk-model";
|
|
1
|
+
import { type DateAttributeGranularity, type IAutomationMetadataObject } from "@gooddata/sdk-model";
|
|
2
2
|
import { type OverlayPositionType } from "@gooddata/sdk-ui-kit";
|
|
3
3
|
import { type AlertMetric, AlertMetricComparatorType } from "../../types.js";
|
|
4
4
|
export interface IAlertComparisonPeriodSelectProps {
|
|
@@ -6,9 +6,10 @@ export interface IAlertComparisonPeriodSelectProps {
|
|
|
6
6
|
measure: AlertMetric | undefined;
|
|
7
7
|
overlayPositionType?: OverlayPositionType;
|
|
8
8
|
selectedComparison?: AlertMetricComparatorType;
|
|
9
|
-
|
|
9
|
+
selectedGranularity?: DateAttributeGranularity;
|
|
10
|
+
onComparisonChange: (comparison: AlertMetricComparatorType, granularity?: DateAttributeGranularity) => void;
|
|
10
11
|
canManageComparison: boolean;
|
|
11
12
|
id: string;
|
|
12
13
|
closeOnParentScroll?: boolean;
|
|
13
14
|
}
|
|
14
|
-
export declare function AlertComparisonPeriodSelect({ alert, measure, overlayPositionType, selectedComparison, canManageComparison, onComparisonChange, id, closeOnParentScroll }: IAlertComparisonPeriodSelectProps): import("react/jsx-runtime").JSX.Element | null;
|
|
15
|
+
export declare function AlertComparisonPeriodSelect({ alert, measure, overlayPositionType, selectedComparison, selectedGranularity, canManageComparison, onComparisonChange, id, closeOnParentScroll }: IAlertComparisonPeriodSelectProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -3,43 +3,73 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { useMemo } from "react";
|
|
4
4
|
import cx from "classnames";
|
|
5
5
|
import { useIntl } from "react-intl";
|
|
6
|
-
import { DateGranularity } from "@gooddata/sdk-model";
|
|
6
|
+
import { DateGranularity, } from "@gooddata/sdk-model";
|
|
7
7
|
import { Dropdown, DropdownButton, SingleSelectListItem, UiListbox, } from "@gooddata/sdk-ui-kit";
|
|
8
8
|
import { AlertMetricComparatorType } from "../../types.js";
|
|
9
9
|
import { translateGranularity } from "../utils/granularity.js";
|
|
10
10
|
import { isChangeOrDifferenceOperator } from "../utils/guards.js";
|
|
11
|
-
export function AlertComparisonPeriodSelect({ alert, measure, overlayPositionType, selectedComparison, canManageComparison, onComparisonChange, id, closeOnParentScroll, }) {
|
|
11
|
+
export function AlertComparisonPeriodSelect({ alert, measure, overlayPositionType, selectedComparison, selectedGranularity, canManageComparison, onComparisonChange, id, closeOnParentScroll, }) {
|
|
12
12
|
const intl = useIntl();
|
|
13
13
|
const selectedOperator = useMemo(() => {
|
|
14
|
-
return measure?.comparators.find((a) => a.comparator === selectedComparison
|
|
15
|
-
|
|
14
|
+
return measure?.comparators.find((a) => a.comparator === selectedComparison &&
|
|
15
|
+
(selectedGranularity ? selectedGranularity === a.granularity : true));
|
|
16
|
+
}, [measure?.comparators, selectedComparison, selectedGranularity]);
|
|
16
17
|
const comparisons = useMemo(() => {
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
const sps = measure?.comparators.filter((a) => a.comparator === AlertMetricComparatorType.SamePeriodPreviousYear) ?? [];
|
|
19
|
+
const pps = measure?.comparators.filter((a) => a.comparator === AlertMetricComparatorType.PreviousPeriod) ??
|
|
20
|
+
[];
|
|
21
|
+
const items = [];
|
|
22
|
+
// Iterate over SamePeriodPreviousYear comparators
|
|
23
|
+
sps.forEach((sp) => {
|
|
24
|
+
const pp = pps.find((pp) => pp.granularity === sp.granularity);
|
|
25
|
+
// Has granularity set and previous period is not year
|
|
26
|
+
if (sp.granularity) {
|
|
27
|
+
if (pp?.granularity === DateGranularity["year"]) {
|
|
28
|
+
items.push({
|
|
29
|
+
title: intl.formatMessage({ id: "insightAlert.config.compare_with_sp" }),
|
|
30
|
+
type: AlertMetricComparatorType.SamePeriodPreviousYear,
|
|
31
|
+
granularity: sp.granularity,
|
|
32
|
+
});
|
|
26
33
|
}
|
|
27
|
-
|
|
34
|
+
else {
|
|
35
|
+
items.push({
|
|
36
|
+
title: intl.formatMessage({ id: "insightAlert.config.compare_with_sp_granularity" }, {
|
|
37
|
+
period: translateGranularity(intl, sp.granularity),
|
|
38
|
+
}),
|
|
39
|
+
type: AlertMetricComparatorType.SamePeriodPreviousYear,
|
|
40
|
+
granularity: sp.granularity,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
items.push({
|
|
28
46
|
title: intl.formatMessage({ id: "insightAlert.config.compare_with_sp" }),
|
|
29
47
|
type: AlertMetricComparatorType.SamePeriodPreviousYear,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
48
|
+
granularity: undefined,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
// Iterate over PreviousPeriod comparators
|
|
53
|
+
pps.forEach((pp) => {
|
|
54
|
+
// Previous period has granularity set
|
|
55
|
+
if (pp.granularity) {
|
|
56
|
+
items.push({
|
|
33
57
|
title: intl.formatMessage({ id: "insightAlert.config.compare_with_pp_granularity" }, {
|
|
34
58
|
period: translateGranularity(intl, pp.granularity),
|
|
35
59
|
}),
|
|
36
60
|
type: AlertMetricComparatorType.PreviousPeriod,
|
|
37
|
-
|
|
38
|
-
|
|
61
|
+
granularity: pp.granularity,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
items.push({
|
|
39
66
|
title: intl.formatMessage({ id: "insightAlert.config.compare_with_pp" }),
|
|
40
67
|
type: AlertMetricComparatorType.PreviousPeriod,
|
|
41
|
-
|
|
42
|
-
|
|
68
|
+
granularity: undefined,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
return items;
|
|
43
73
|
}, [intl, measure?.comparators]);
|
|
44
74
|
// If alert is not defined or the measure does not have any comparators, return null
|
|
45
75
|
if (!alert || !isChangeOrDifferenceOperator(alert.alert)) {
|
|
@@ -62,13 +92,14 @@ export function AlertComparisonPeriodSelect({ alert, measure, overlayPositionTyp
|
|
|
62
92
|
}, renderBody: ({ closeDropdown, ariaAttributes }) => {
|
|
63
93
|
const listboxItems = comparisons.map((comparison) => ({
|
|
64
94
|
type: "interactive",
|
|
65
|
-
id: comparison.type.
|
|
95
|
+
id: `${comparison.type}-${comparison.granularity ?? "none"}`,
|
|
66
96
|
stringTitle: comparison.title,
|
|
67
97
|
data: comparison,
|
|
68
98
|
}));
|
|
69
|
-
return (_jsx(UiListbox, { shouldKeyboardActionStopPropagation: true, shouldKeyboardActionPreventDefault: true, dataTestId: "s-alert-comparison-select-list", items: listboxItems, selectedItemId: selectedComparison
|
|
70
|
-
if (item.data.type !== selectedComparison
|
|
71
|
-
|
|
99
|
+
return (_jsx(UiListbox, { shouldKeyboardActionStopPropagation: true, shouldKeyboardActionPreventDefault: true, dataTestId: "s-alert-comparison-select-list", items: listboxItems, selectedItemId: `${selectedComparison ?? "none"}-${selectedGranularity ?? "none"}`, onSelect: (item) => {
|
|
100
|
+
if (item.data.type !== selectedComparison ||
|
|
101
|
+
item.data.granularity !== selectedGranularity) {
|
|
102
|
+
onComparisonChange(item.data.type, item.data.granularity);
|
|
72
103
|
}
|
|
73
104
|
}, onClose: closeDropdown, ariaAttributes: ariaAttributes, InteractiveItemComponent: ({ item, isSelected, onSelect, isFocused }) => {
|
|
74
105
|
return (_jsx(SingleSelectListItem, { title: item.stringTitle, isSelected: isSelected, isFocused: isFocused, onClick: onSelect, className: "gd-alert-comparison-select__list-item" }));
|
|
@@ -2,10 +2,11 @@ import { type OverlayPositionType } from "@gooddata/sdk-ui-kit";
|
|
|
2
2
|
import { type AlertMetric } from "../../types.js";
|
|
3
3
|
export interface IAlertMetricSelectProps {
|
|
4
4
|
id?: string;
|
|
5
|
+
disabled?: boolean;
|
|
5
6
|
selectedMeasure: AlertMetric | undefined;
|
|
6
7
|
onMeasureChange: (measure: AlertMetric) => void;
|
|
7
8
|
measures: AlertMetric[];
|
|
8
9
|
overlayPositionType?: OverlayPositionType;
|
|
9
10
|
closeOnParentScroll?: boolean;
|
|
10
11
|
}
|
|
11
|
-
export declare function AlertMeasureSelect({ id, selectedMeasure, onMeasureChange, measures, overlayPositionType, closeOnParentScroll }: IAlertMetricSelectProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function AlertMeasureSelect({ id, disabled, selectedMeasure, onMeasureChange, measures, overlayPositionType, closeOnParentScroll }: IAlertMetricSelectProps): import("react/jsx-runtime").JSX.Element;
|
package/esm/presentation/automations/alerting/DefaultAlertingDialog/components/AlertMeasureSelect.js
CHANGED
|
@@ -6,7 +6,7 @@ import { useIntl } from "react-intl";
|
|
|
6
6
|
import { Dropdown, DropdownButton, SingleSelectListItem, UiListbox, } from "@gooddata/sdk-ui-kit";
|
|
7
7
|
import { getMeasureTitle } from "../utils/getters.js";
|
|
8
8
|
const measureIcon = _jsx("div", { className: "gd-alert-measure-select__icon gd-icon-metric" });
|
|
9
|
-
export function AlertMeasureSelect({ id, selectedMeasure, onMeasureChange, measures, overlayPositionType, closeOnParentScroll, }) {
|
|
9
|
+
export function AlertMeasureSelect({ id, disabled, selectedMeasure, onMeasureChange, measures, overlayPositionType, closeOnParentScroll, }) {
|
|
10
10
|
const intl = useIntl();
|
|
11
11
|
const ref = useRef(null);
|
|
12
12
|
const selectedMeasureTitle = selectedMeasure
|
|
@@ -15,7 +15,7 @@ export function AlertMeasureSelect({ id, selectedMeasure, onMeasureChange, measu
|
|
|
15
15
|
return (_jsx(Dropdown, { closeOnParentScroll: closeOnParentScroll, overlayPositionType: overlayPositionType, autofocusOnOpen: true, renderButton: ({ isOpen, toggleDropdown, buttonRef, dropdownId }) => {
|
|
16
16
|
return (_jsx("div", { ref: (item) => {
|
|
17
17
|
ref.current = item;
|
|
18
|
-
}, children: _jsx(DropdownButton, { id: id, className: cx("gd-alert-measure-select__button s-alert-measure-select"), value: selectedMeasureTitle, iconLeft: selectedMeasure ? "gd-icon-metric" : undefined, onClick: toggleDropdown, buttonRef: buttonRef, dropdownId: dropdownId, isOpen: isOpen, accessibilityConfig: {
|
|
18
|
+
}, children: _jsx(DropdownButton, { id: id, disabled: disabled, className: cx("gd-alert-measure-select__button s-alert-measure-select"), value: selectedMeasureTitle, iconLeft: selectedMeasure ? "gd-icon-metric" : undefined, onClick: toggleDropdown, buttonRef: buttonRef, dropdownId: dropdownId, isOpen: isOpen, accessibilityConfig: {
|
|
19
19
|
ariaExpanded: isOpen,
|
|
20
20
|
popupType: "listbox",
|
|
21
21
|
} }) }));
|
package/esm/presentation/automations/alerting/DefaultAlertingDialog/hooks/useAlertValidation.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// (C) 2024-2026 GoodData Corporation
|
|
2
2
|
import { useDashboardSelector } from "../../../../../model/react/DashboardStoreProvider.js";
|
|
3
3
|
import { selectCatalogDateDatasets } from "../../../../../model/store/catalog/catalogSelectors.js";
|
|
4
|
+
import { selectEnableComparisonInAlerting } from "../../../../../model/store/config/configSelectors.js";
|
|
4
5
|
import { selectInsightByWidgetRef } from "../../../../../model/store/insights/insightsSelectors.js";
|
|
5
6
|
import { selectWidgetByRef } from "../../../../../model/store/tabs/layout/layoutSelectors.js";
|
|
6
7
|
import { getAlertMeasure } from "../utils/getters.js";
|
|
@@ -8,10 +9,11 @@ import { getSupportedInsightMeasuresByInsight } from "../utils/items.js";
|
|
|
8
9
|
export const useAlertValidation = (alert, isNewAlert) => {
|
|
9
10
|
const widgetLocalId = alert?.metadata?.widget;
|
|
10
11
|
const widgetRef = widgetLocalId ? { identifier: widgetLocalId } : undefined;
|
|
12
|
+
const canManageComparison = useDashboardSelector(selectEnableComparisonInAlerting);
|
|
11
13
|
const widget = useDashboardSelector(selectWidgetByRef(widgetRef));
|
|
12
14
|
const insight = useDashboardSelector(selectInsightByWidgetRef(widget?.ref));
|
|
13
15
|
const dateDatasets = useDashboardSelector(selectCatalogDateDatasets);
|
|
14
|
-
const supportedMeasures = getSupportedInsightMeasuresByInsight(insight, dateDatasets);
|
|
16
|
+
const supportedMeasures = getSupportedInsightMeasuresByInsight(insight, dateDatasets, canManageComparison, alert);
|
|
15
17
|
const selectedMeasureExists = alert ? getAlertMeasure(supportedMeasures, alert.alert) : undefined;
|
|
16
18
|
const isValid = isNewAlert || Boolean(!!widget && selectedMeasureExists);
|
|
17
19
|
let invalidityReason = undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type FilterContextItem, type IAlertAnomalyDetectionGranularity, type IAlertAnomalyDetectionSensitivity, type IAlertComparisonOperator, type IAlertRelativeArithmeticOperator, type IAlertRelativeOperator, type IAlertTriggerInterval, type IAlertTriggerMode, type IAutomationMetadataObject, type IAutomationMetadataObjectDefinition, type IAutomationRecipient, type IAutomationVisibleFilter, type IInsight, type INotificationChannelIdentifier, type INotificationChannelMetadataObject } from "@gooddata/sdk-model";
|
|
1
|
+
import { type DateAttributeGranularity, type FilterContextItem, type IAlertAnomalyDetectionGranularity, type IAlertAnomalyDetectionSensitivity, type IAlertComparisonOperator, type IAlertRelativeArithmeticOperator, type IAlertRelativeOperator, type IAlertTriggerInterval, type IAlertTriggerMode, type IAutomationMetadataObject, type IAutomationMetadataObjectDefinition, type IAutomationRecipient, type IAutomationVisibleFilter, type IInsight, type INotificationChannelIdentifier, type INotificationChannelMetadataObject } from "@gooddata/sdk-model";
|
|
2
2
|
import type { ExtendedDashboardWidget } from "../../../../../model/types/layoutTypes.js";
|
|
3
3
|
import { type AlertAttribute, type AlertMetric, type AlertMetricComparatorType } from "../../types.js";
|
|
4
4
|
export interface IUseEditAlertProps {
|
|
@@ -32,11 +32,12 @@ export declare function useEditAlert({ alertToEdit, notificationChannels, insigh
|
|
|
32
32
|
onGranularityChange: (measure: AlertMetric | undefined, granularity: IAlertAnomalyDetectionGranularity) => void;
|
|
33
33
|
onChange: (e: string | number, event?: import("react").ChangeEvent<HTMLInputElement> | undefined) => void;
|
|
34
34
|
onBlur: (event: import("react").FocusEvent<HTMLInputElement, Element>) => void;
|
|
35
|
-
onComparisonTypeChange: (measure: AlertMetric | undefined, relativeOperator: [IAlertRelativeOperator, IAlertRelativeArithmeticOperator] | undefined, comparisonType: AlertMetricComparatorType) => void;
|
|
35
|
+
onComparisonTypeChange: (measure: AlertMetric | undefined, relativeOperator: [IAlertRelativeOperator, IAlertRelativeArithmeticOperator] | undefined, comparisonType: AlertMetricComparatorType, granularity?: DateAttributeGranularity | undefined) => void;
|
|
36
36
|
onDestinationChange: (destinationId: string) => void;
|
|
37
37
|
onTriggerModeChange: (triggerMode: IAlertTriggerMode) => void;
|
|
38
38
|
onTriggerIntervalChange: (triggerInterval: IAlertTriggerInterval, dirty?: boolean) => void;
|
|
39
39
|
selectedMeasure: AlertMetric | undefined;
|
|
40
|
+
canChangeMeasure: boolean;
|
|
40
41
|
supportedMeasures: AlertMetric[];
|
|
41
42
|
canManageAttributes: boolean;
|
|
42
43
|
selectedAttribute: AlertAttribute | undefined;
|
|
@@ -45,6 +46,7 @@ export declare function useEditAlert({ alertToEdit, notificationChannels, insigh
|
|
|
45
46
|
catalogAttributes: import("@gooddata/sdk-model").ICatalogAttribute[];
|
|
46
47
|
catalogDateDatasets: import("@gooddata/sdk-model").ICatalogDateDataset[];
|
|
47
48
|
isResultLoading: boolean;
|
|
49
|
+
isInvalidConnectionToInsight: "" | boolean | undefined;
|
|
48
50
|
selectedAiOperator: "AI.ANOMALY_DETECTION" | undefined;
|
|
49
51
|
selectedSensitivity: IAlertAnomalyDetectionSensitivity | undefined;
|
|
50
52
|
selectedGranularity: IAlertAnomalyDetectionGranularity | undefined;
|
|
@@ -47,6 +47,7 @@ export function useEditAlert({ alertToEdit, notificationChannels, insight, widge
|
|
|
47
47
|
const commonDateFilterId = useDashboardSelector(selectAutomationCommonDateFilterId);
|
|
48
48
|
const weekStart = useDashboardSelector(selectWeekStart);
|
|
49
49
|
const timezone = useDashboardSelector(selectTimezone);
|
|
50
|
+
const isInvalidConnectionToInsight = alertToEdit?.metadata?.widget && !insight;
|
|
50
51
|
const minimumRecurrenceMinutesEntitlement = useDashboardSelector(selectEntitlementMinimumRecurrenceMinutes);
|
|
51
52
|
const allowHourlyRecurrence = parseInt(minimumRecurrenceMinutesEntitlement?.value ?? DEFAULT_MIN_RECURRENCE_MINUTES, 10) === 60;
|
|
52
53
|
const widgetTabMap = useDashboardSelector(selectWidgetLocalIdToTabIdMap);
|
|
@@ -63,8 +64,8 @@ export function useEditAlert({ alertToEdit, notificationChannels, insight, widge
|
|
|
63
64
|
const measureFormatMap = useMemo(() => {
|
|
64
65
|
return getMeasureFormatsFromExecution(execResult?.executionResult);
|
|
65
66
|
}, [execResult?.executionResult]);
|
|
66
|
-
const supportedMeasures = useMemo(() => getSupportedInsightMeasuresByInsight(effectiveInsight, catalogDateDatasets, canManageComparison), [effectiveInsight, catalogDateDatasets, canManageComparison]);
|
|
67
|
-
const supportedAttributes = useMemo(() => getSupportedInsightAttributesByInsight(insight, catalogDateDatasets), [insight, catalogDateDatasets]);
|
|
67
|
+
const supportedMeasures = useMemo(() => getSupportedInsightMeasuresByInsight(effectiveInsight, catalogDateDatasets, canManageComparison, alertToEdit), [effectiveInsight, catalogDateDatasets, canManageComparison, alertToEdit]);
|
|
68
|
+
const supportedAttributes = useMemo(() => getSupportedInsightAttributesByInsight(insight, catalogAttributes, catalogDateDatasets, alertToEdit), [insight, catalogDateDatasets, catalogAttributes, alertToEdit]);
|
|
68
69
|
const { isResultLoading, getAttributeValues, getMetricValue } = useAttributeValuesFromExecResults(execResult);
|
|
69
70
|
// Default values
|
|
70
71
|
const defaultMeasure = supportedMeasures[0];
|
|
@@ -158,13 +159,13 @@ export function useEditAlert({ alertToEdit, notificationChannels, insight, widge
|
|
|
158
159
|
setTriggerIntervalDirty(false);
|
|
159
160
|
setEditedAutomation((alert) => transformAlertByAnomalyDetection(supportedMeasures, alert, measure, weekStart, timezone, enableAlertOncePerInterval));
|
|
160
161
|
}, [supportedMeasures, weekStart, timezone, enableAlertOncePerInterval]);
|
|
161
|
-
const onComparisonTypeChange = useCallback((measure, relativeOperator, comparisonType) => {
|
|
162
|
+
const onComparisonTypeChange = useCallback((measure, relativeOperator, comparisonType, granularity) => {
|
|
162
163
|
if (!measure || !relativeOperator || !relativeOperator) {
|
|
163
164
|
return;
|
|
164
165
|
}
|
|
165
166
|
const [relativeOperatorValue, arithmeticOperator] = relativeOperator;
|
|
166
167
|
setEditedAutomation((alert) => alert
|
|
167
|
-
? transformAlertByRelativeOperator(supportedMeasures, alert, measure, relativeOperatorValue, arithmeticOperator, measureFormatMap, comparisonType)
|
|
168
|
+
? transformAlertByRelativeOperator(supportedMeasures, alert, measure, relativeOperatorValue, arithmeticOperator, measureFormatMap, comparisonType, granularity)
|
|
168
169
|
: undefined);
|
|
169
170
|
}, [measureFormatMap, supportedMeasures]);
|
|
170
171
|
const onSensitivityChange = useCallback((sensitivity) => {
|
|
@@ -283,7 +284,9 @@ export function useEditAlert({ alertToEdit, notificationChannels, insight, widge
|
|
|
283
284
|
const hasValidThreshold = isAlertValueDefined(editedAutomation?.alert);
|
|
284
285
|
const validationErrorMessage = isOriginalAutomationValid
|
|
285
286
|
? undefined
|
|
286
|
-
:
|
|
287
|
+
: isInvalidConnectionToInsight
|
|
288
|
+
? intl.formatMessage({ id: "insightAlert.config.invalidWidget" })
|
|
289
|
+
: intl.formatMessage({ id: "insightAlert.config.unusedWidget" });
|
|
287
290
|
const hasRecipients = (editedAutomation?.recipients?.length ?? 0) > 0;
|
|
288
291
|
const hasValidExternalRecipients = allowExternalRecipients
|
|
289
292
|
? true
|
|
@@ -327,6 +330,7 @@ export function useEditAlert({ alertToEdit, notificationChannels, insight, widge
|
|
|
327
330
|
onTriggerModeChange,
|
|
328
331
|
onTriggerIntervalChange,
|
|
329
332
|
selectedMeasure,
|
|
333
|
+
canChangeMeasure: !!insight,
|
|
330
334
|
supportedMeasures,
|
|
331
335
|
canManageAttributes,
|
|
332
336
|
selectedAttribute,
|
|
@@ -335,6 +339,7 @@ export function useEditAlert({ alertToEdit, notificationChannels, insight, widge
|
|
|
335
339
|
catalogAttributes,
|
|
336
340
|
catalogDateDatasets,
|
|
337
341
|
isResultLoading,
|
|
342
|
+
isInvalidConnectionToInsight,
|
|
338
343
|
selectedAiOperator,
|
|
339
344
|
selectedSensitivity,
|
|
340
345
|
selectedGranularity,
|
|
@@ -212,7 +212,14 @@ export function getSelectedCatalogAttributeValue(attribute, getAttributeValue, s
|
|
|
212
212
|
}
|
|
213
213
|
const values = getAttributeValue(attribute);
|
|
214
214
|
return (values.find((value) => value.name === selectedValue) ??
|
|
215
|
-
values.find((value) => value.value === selectedValue)
|
|
215
|
+
values.find((value) => value.value === selectedValue) ??
|
|
216
|
+
(selectedValue
|
|
217
|
+
? {
|
|
218
|
+
title: selectedValue,
|
|
219
|
+
value: selectedValue,
|
|
220
|
+
name: selectedValue,
|
|
221
|
+
}
|
|
222
|
+
: undefined));
|
|
216
223
|
}
|
|
217
224
|
/**
|
|
218
225
|
* @internal
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import { type ICatalogDateDataset, type IInsight } from "@gooddata/sdk-model";
|
|
1
|
+
import { type IAutomationMetadataObject, type ICatalogAttribute, type ICatalogDateDataset, type IInsight } from "@gooddata/sdk-model";
|
|
2
2
|
import { type AlertAttribute, type AlertMetric } from "../../types.js";
|
|
3
3
|
/**
|
|
4
4
|
* Get supported insight measures by insight
|
|
5
5
|
* @param insight - insight to get supported measures for
|
|
6
6
|
* @param dateDatasets - date datasets to filter out date attributes
|
|
7
7
|
* @param canManageComparison - flag if user can manage comparison
|
|
8
|
+
* @param alert - alert to get supported measures for
|
|
8
9
|
*/
|
|
9
|
-
export declare function getSupportedInsightMeasuresByInsight(insight: IInsight | null | undefined, dateDatasets?: ICatalogDateDataset[], canManageComparison?: boolean): AlertMetric[];
|
|
10
|
+
export declare function getSupportedInsightMeasuresByInsight(insight: IInsight | null | undefined, dateDatasets?: ICatalogDateDataset[], canManageComparison?: boolean, alert?: IAutomationMetadataObject): AlertMetric[];
|
|
10
11
|
/**
|
|
11
12
|
* Get supported insight attributes by insight
|
|
12
13
|
* @param insight - insight to get supported attributes for
|
|
14
|
+
* @param attributes - attributes to filter out date attributes
|
|
13
15
|
* @param dateDatasets - date datasets to filter out date attributes
|
|
16
|
+
* @param alert - alert metadata object
|
|
14
17
|
*/
|
|
15
|
-
export declare function getSupportedInsightAttributesByInsight(insight: IInsight | null | undefined, dateDatasets?: ICatalogDateDataset[]): AlertAttribute[];
|
|
18
|
+
export declare function getSupportedInsightAttributesByInsight(insight: IInsight | null | undefined, attributes: ICatalogAttribute[], dateDatasets?: ICatalogDateDataset[], alert?: IAutomationMetadataObject): AlertAttribute[];
|