@gooddata/sdk-ui-dashboard 11.44.0-alpha.0 → 11.44.0-alpha.2
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 +75 -75
- package/esm/__version.d.ts +1 -1
- package/esm/__version.js +1 -1
- package/esm/index.d.ts +1 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -1
- package/esm/kdaDialog/dialog/KdaDialog.d.ts.map +1 -1
- package/esm/kdaDialog/dialog/KdaDialog.js +2 -1
- package/esm/kdaDialog/dialog/KdaDialogActionButtons.d.ts +2 -1
- package/esm/kdaDialog/dialog/KdaDialogActionButtons.d.ts.map +1 -1
- package/esm/kdaDialog/dialog/KdaDialogActionButtons.js +9 -6
- package/esm/kdaDialog/dialog/KdaDialogFloatingStatusBar.d.ts +4 -2
- package/esm/kdaDialog/dialog/KdaDialogFloatingStatusBar.d.ts.map +1 -1
- package/esm/kdaDialog/dialog/KdaDialogFloatingStatusBar.js +4 -4
- package/esm/kdaDialog/dialog/hooks/useKdaDialogAccessibility.d.ts +1 -0
- package/esm/kdaDialog/dialog/hooks/useKdaDialogAccessibility.d.ts.map +1 -1
- package/esm/kdaDialog/dialog/hooks/useKdaDialogAccessibility.js +6 -4
- package/esm/model/commandHandlers/dashboard/common/parameterHydration.js +2 -2
- package/esm/model/commands/executionResults.d.ts +18 -0
- package/esm/model/commands/executionResults.d.ts.map +1 -1
- package/esm/model/commands/executionResults.js +22 -0
- package/esm/model/react/useWidgetExecutionsHandler.d.ts.map +1 -1
- package/esm/model/react/useWidgetExecutionsHandler.js +18 -3
- package/esm/model/store/tabs/parameters/parametersHelpers.d.ts +58 -6
- package/esm/model/store/tabs/parameters/parametersHelpers.d.ts.map +1 -1
- package/esm/model/store/tabs/parameters/parametersHelpers.js +114 -22
- package/esm/model/store/tabs/parameters/parametersSelectors.d.ts +16 -1
- package/esm/model/store/tabs/parameters/parametersSelectors.d.ts.map +1 -1
- package/esm/model/store/tabs/parameters/parametersSelectors.js +51 -19
- package/esm/presentation/automations/connectors/ScheduledEmailConnector.d.ts +27 -0
- package/esm/presentation/automations/connectors/ScheduledEmailConnector.d.ts.map +1 -0
- package/esm/presentation/automations/connectors/ScheduledEmailConnector.js +107 -0
- package/esm/presentation/automations/connectors/hooks/useBuildAlertingDialogContext.d.ts.map +1 -1
- package/esm/presentation/automations/connectors/hooks/useBuildAlertingDialogContext.js +16 -55
- package/esm/presentation/automations/connectors/hooks/useBuildAutomationsContext.d.ts.map +1 -1
- package/esm/presentation/automations/connectors/hooks/useBuildAutomationsContext.js +7 -1
- package/esm/presentation/automations/connectors/hooks/useBuildAutomationsContext.test.js +15 -0
- package/esm/presentation/automations/connectors/hooks/useBuildScheduledEmailDialogContext.d.ts +8 -0
- package/esm/presentation/automations/connectors/hooks/useBuildScheduledEmailDialogContext.d.ts.map +1 -0
- package/esm/presentation/automations/connectors/hooks/useBuildScheduledEmailDialogContext.js +102 -0
- package/esm/presentation/automations/connectors/hooks/useBuildScheduledEmailDialogContext.test.d.ts +2 -0
- package/esm/presentation/automations/connectors/hooks/useBuildScheduledEmailDialogContext.test.d.ts.map +1 -0
- package/esm/presentation/automations/connectors/hooks/useBuildScheduledEmailDialogContext.test.js +156 -0
- package/esm/presentation/automations/connectors/hooks/useCommandAsPromise.d.ts +26 -0
- package/esm/presentation/automations/connectors/hooks/useCommandAsPromise.d.ts.map +1 -0
- package/esm/presentation/automations/connectors/hooks/useCommandAsPromise.js +47 -0
- package/esm/presentation/automations/contexts/AutomationsContext.d.ts +2 -0
- package/esm/presentation/automations/contexts/AutomationsContext.d.ts.map +1 -1
- package/esm/presentation/automations/contexts/ScheduledEmailDialogContext.d.ts +54 -0
- package/esm/presentation/automations/contexts/ScheduledEmailDialogContext.d.ts.map +1 -0
- package/esm/presentation/automations/contexts/ScheduledEmailDialogContext.js +11 -0
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/DefaultScheduledEmailDialog.d.ts.map +1 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/DefaultScheduledEmailDialog.js +11 -37
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useEditScheduledEmail.d.ts +6 -5
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useEditScheduledEmail.d.ts.map +1 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useEditScheduledEmail.js +7 -23
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useFiltersForDashboardScheduledExportInfo.d.ts.map +1 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useFiltersForDashboardScheduledExportInfo.js +2 -7
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useSaveScheduledEmailToBackend.d.ts.map +1 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useSaveScheduledEmailToBackend.js +37 -37
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useScheduleValidation.d.ts.map +1 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useScheduleValidation.js +3 -4
- package/esm/presentation/automations/scheduledEmail/types.d.ts +5 -3
- package/esm/presentation/automations/scheduledEmail/types.d.ts.map +1 -1
- package/esm/presentation/automations/shared/automationFilters/components/AutomationDateFilter.test.js +2 -0
- package/esm/presentation/dashboard/DashboardHeader/DashboardHeader.d.ts.map +1 -1
- package/esm/presentation/dashboard/DashboardHeader/DashboardHeader.js +2 -2
- package/esm/presentation/dashboard/components/ToastMessages.d.ts.map +1 -1
- package/esm/presentation/dashboard/components/ToastMessages.js +3 -1
- package/esm/presentation/filterBar/filterBar/filterViews/FilterViewsList.d.ts.map +1 -1
- package/esm/presentation/filterBar/filterBar/filterViews/FilterViewsList.js +3 -2
- package/esm/presentation/filterBar/parameterFilter/useParameterToastMessages.d.ts +12 -0
- package/esm/presentation/filterBar/parameterFilter/useParameterToastMessages.d.ts.map +1 -0
- package/esm/presentation/filterBar/parameterFilter/useParameterToastMessages.js +51 -0
- package/esm/presentation/localization/bundles/de-DE.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/de-DE.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/de-DE.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/en-AU.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/en-AU.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/en-AU.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/en-GB.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/en-GB.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/en-GB.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/en-US.localization-bundle.d.ts +12 -0
- package/esm/presentation/localization/bundles/en-US.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/en-US.localization-bundle.js +12 -0
- package/esm/presentation/localization/bundles/es-419.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/es-419.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/es-419.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/es-ES.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/es-ES.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/es-ES.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/fi-FI.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/fi-FI.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/fi-FI.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/fr-CA.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/fr-CA.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/fr-CA.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/fr-FR.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/fr-FR.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/fr-FR.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/id-ID.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/id-ID.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/id-ID.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/it-IT.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/it-IT.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/it-IT.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/ja-JP.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/ja-JP.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/ja-JP.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/ko-KR.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/ko-KR.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/ko-KR.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/nl-NL.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/nl-NL.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/nl-NL.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/pl-PL.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/pl-PL.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/pl-PL.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/pt-BR.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/pt-BR.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/pt-BR.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/pt-PT.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/pt-PT.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/pt-PT.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/ru-RU.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/ru-RU.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/ru-RU.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/sl-SI.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/sl-SI.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/sl-SI.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/th-TH.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/th-TH.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/th-TH.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/tr-TR.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/tr-TR.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/tr-TR.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/uk-UA.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/uk-UA.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/uk-UA.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/vi-VN.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/vi-VN.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/vi-VN.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/zh-HK.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/zh-HK.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/zh-HK.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.js +4 -0
- package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.d.ts +4 -0
- package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.js +4 -0
- package/esm/sdk-ui-dashboard.d.ts +23 -1
- package/package.json +20 -20
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useCreateScheduledEmail.d.ts +0 -11
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useCreateScheduledEmail.d.ts.map +0 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useCreateScheduledEmail.js +0 -27
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useUpdateScheduledEmail.d.ts +0 -11
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useUpdateScheduledEmail.d.ts.map +0 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useUpdateScheduledEmail.js +0 -27
- package/esm/presentation/automations/scheduledEmail/hooks/useWidgetAutomationFilters.d.ts +0 -3
- package/esm/presentation/automations/scheduledEmail/hooks/useWidgetAutomationFilters.d.ts.map +0 -1
- package/esm/presentation/automations/scheduledEmail/hooks/useWidgetAutomationFilters.js +0 -5
- package/esm/presentation/dashboard/DashboardHeader/ScheduledEmailDialogProvider.d.ts +0 -2
- package/esm/presentation/dashboard/DashboardHeader/ScheduledEmailDialogProvider.d.ts.map +0 -1
- package/esm/presentation/dashboard/DashboardHeader/ScheduledEmailDialogProvider.js +0 -45
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { isWidget } from "@gooddata/sdk-model";
|
|
3
|
+
import { getAutomationDashboardFilters, getAutomationVisualizationFilters, } from "../../../_staging/automation/index.js";
|
|
4
|
+
import { useDashboardSelector } from "../../../model/react/DashboardStoreProvider.js";
|
|
5
|
+
import { useDashboardScheduledEmails } from "../../../model/react/useDasboardScheduledEmails/useDashboardScheduledEmails.js";
|
|
6
|
+
import { useWorkspaceUsers } from "../../../model/react/useWorkspaceUsers.js";
|
|
7
|
+
import { selectAutomationDefaultSelectedFilters, selectDashboardHiddenFilters, } from "../../../model/store/filtering/dashboardFilterSelectors.js";
|
|
8
|
+
import { AutomationsContextProvider } from "../contexts/AutomationsContext.js";
|
|
9
|
+
import { ScheduledEmailDialogContextProvider } from "../contexts/ScheduledEmailDialogContext.js";
|
|
10
|
+
import { ScheduledEmailDialog } from "../scheduledEmail/ScheduledEmailDialog.js";
|
|
11
|
+
import { ScheduledEmailManagementDialog } from "../scheduledEmail/ScheduledEmailManagementDialog.js";
|
|
12
|
+
import { getAppliedDashboardFilters } from "../scheduledEmail/utils/filters.js";
|
|
13
|
+
import { useBuildAutomationsContext } from "./hooks/useBuildAutomationsContext.js";
|
|
14
|
+
import { useBuildScheduledEmailDialogContext } from "./hooks/useBuildScheduledEmailDialogContext.js";
|
|
15
|
+
import { useWidgetAutomationFilters } from "./hooks/useWidgetAutomationFilters.js";
|
|
16
|
+
/**
|
|
17
|
+
* Provides AutomationsContext to its children, built from dashboard Redux state.
|
|
18
|
+
* Wraps the scheduled-email dialog subtree (both the create/edit and management dialogs reach
|
|
19
|
+
* AutomationsContext through this provider).
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export function ScheduledEmailAutomationsProvider({ children }) {
|
|
24
|
+
const automationsCtx = useBuildAutomationsContext();
|
|
25
|
+
return _jsx(AutomationsContextProvider, { value: automationsCtx, children: children });
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Connector component that reads from the dashboard Redux store and wires up
|
|
29
|
+
* the scheduled-email dialog tree (create/edit and management) via context providers.
|
|
30
|
+
*
|
|
31
|
+
* This is the primary bridge between dashboard store state and the scheduled-email
|
|
32
|
+
* dialog tree. The dialog still reads the store directly at this point —
|
|
33
|
+
* contexts are provided but not yet consumed. Store reads migrate off the dialog
|
|
34
|
+
* in subsequent Phase 2 tasks (A2/A3).
|
|
35
|
+
*
|
|
36
|
+
* AutomationsContext is provided by ScheduledEmailAutomationsProvider, which wraps this
|
|
37
|
+
* connector (see ScheduledEmailAutomationsProvider in DashboardHeader).
|
|
38
|
+
*
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
export function ScheduledEmailConnector() {
|
|
42
|
+
const se = useDashboardScheduledEmails();
|
|
43
|
+
if (!se.isInitialized) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return _jsx(ScheduledEmailConnectorInitialized, { ...se });
|
|
47
|
+
}
|
|
48
|
+
function ScheduledEmailConnectorInitialized(se) {
|
|
49
|
+
const { isScheduleEmailingDialogOpen, isScheduleEmailingManagementDialogOpen } = se;
|
|
50
|
+
// Defer store reads and user loading until at least one dialog is open.
|
|
51
|
+
// This is a deliberate behavior alignment with AlertingConnector (GDP-3167).
|
|
52
|
+
if (!isScheduleEmailingDialogOpen && !isScheduleEmailingManagementDialogOpen) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
return _jsx(ScheduledEmailConnectorWithData, { se: se });
|
|
56
|
+
}
|
|
57
|
+
function ScheduledEmailConnectorWithData({ se }) {
|
|
58
|
+
const {
|
|
59
|
+
// Shared Local State
|
|
60
|
+
scheduledExportToEdit,
|
|
61
|
+
// Data
|
|
62
|
+
automations, automationsError, automationsLoading, notificationChannels,
|
|
63
|
+
// Single Schedule Dialog
|
|
64
|
+
isScheduleEmailingDialogOpen, onScheduleEmailingCancel, onScheduleEmailingBack, onScheduleEmailingCreateSuccess, onScheduleEmailingCreateError, onScheduleEmailingSaveSuccess, onScheduleEmailingSaveError,
|
|
65
|
+
// Management / List Dialog
|
|
66
|
+
isScheduleEmailingManagementDialogOpen, onScheduleEmailingManagementClose, onScheduleEmailingManagementAdd, onScheduleEmailingManagementEdit, onScheduleEmailingManagementDeleteSuccess, onScheduleEmailingManagementDeleteError, widget, insight, } = se;
|
|
67
|
+
// Filter computation — moved verbatim from ScheduledEmailDialogProvider
|
|
68
|
+
const automationDefaultSelectedFilters = useDashboardSelector(selectAutomationDefaultSelectedFilters);
|
|
69
|
+
const dashboardHiddenFilters = useDashboardSelector(selectDashboardHiddenFilters);
|
|
70
|
+
const { executionFilters: savedWidgetFilters } = getAutomationVisualizationFilters(scheduledExportToEdit);
|
|
71
|
+
const savedDashboardFilters = getAutomationDashboardFilters(scheduledExportToEdit);
|
|
72
|
+
const { result: liveWidgetFilters, status: widgetFiltersStatus, error: widgetFiltersError, } = useWidgetAutomationFilters(widget, insight);
|
|
73
|
+
const widgetFilters = savedWidgetFilters ?? liveWidgetFilters;
|
|
74
|
+
const shouldLoadWidgetFilters = !!widget && !savedWidgetFilters;
|
|
75
|
+
const dashboardFilters = savedDashboardFilters ??
|
|
76
|
+
getAppliedDashboardFilters(automationDefaultSelectedFilters, dashboardHiddenFilters, true);
|
|
77
|
+
const isLoading = automationsLoading ||
|
|
78
|
+
(shouldLoadWidgetFilters && (widgetFiltersStatus === "pending" || widgetFiltersStatus === "running"));
|
|
79
|
+
const loadingError = (shouldLoadWidgetFilters ? widgetFiltersError : undefined) ?? automationsError;
|
|
80
|
+
const insightWidget = isWidget(widget) ? widget : undefined;
|
|
81
|
+
const seCtx = useBuildScheduledEmailDialogContext({
|
|
82
|
+
widget: insightWidget,
|
|
83
|
+
insight,
|
|
84
|
+
});
|
|
85
|
+
return (_jsxs(ScheduledEmailDialogContextProvider, { value: seCtx, children: [isScheduleEmailingManagementDialogOpen ? (
|
|
86
|
+
// TODO(GDP-3167 phase3): automations, notificationChannels, and scheduleDataError
|
|
87
|
+
// are still prop-threaded here because DefaultScheduledEmailManagementDialog reads
|
|
88
|
+
// them from props, not from AutomationsContext. Once all dialog fields are migrated
|
|
89
|
+
// to read from context, remove these props and the corresponding prop types.
|
|
90
|
+
_jsx(ScheduledEmailManagementDialog, { automations: automations, notificationChannels: notificationChannels, scheduleDataError: loadingError, isLoadingScheduleData: isLoading, onAdd: onScheduleEmailingManagementAdd, onEdit: onScheduleEmailingManagementEdit, onClose: onScheduleEmailingManagementClose, onDeleteSuccess: onScheduleEmailingManagementDeleteSuccess, onDeleteError: onScheduleEmailingManagementDeleteError })) : null, isScheduleEmailingDialogOpen ? (
|
|
91
|
+
// TODO(GDP-3167 phase3): notificationChannels, users, usersError, widgetFilters,
|
|
92
|
+
// dashboardFilters, and isLoading are still prop-threaded here because
|
|
93
|
+
// DefaultScheduledEmailDialog reads them from props, not from context.
|
|
94
|
+
// Once all dialog fields are migrated to read from context, remove these props
|
|
95
|
+
// and the corresponding prop types.
|
|
96
|
+
_jsx(ScheduledEmailDialogWithUsers, { scheduledExportToEdit: scheduledExportToEdit, notificationChannels: notificationChannels, widget: insightWidget, insight: insight, widgetFilters: widgetFilters, dashboardFilters: dashboardFilters, isLoading: isLoading, onBack: onScheduleEmailingBack, onCancel: onScheduleEmailingCancel, onError: onScheduleEmailingCreateError, onSuccess: onScheduleEmailingCreateSuccess, onSaveError: onScheduleEmailingSaveError, onSaveSuccess: onScheduleEmailingSaveSuccess, onDeleteSuccess: onScheduleEmailingManagementDeleteSuccess, onDeleteError: onScheduleEmailingManagementDeleteError })) : null] }));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Loads workspace users only while the create/edit dialog is mounted. Keeping the
|
|
100
|
+
* `useWorkspaceUsers()` call in this child (rather than in ScheduledEmailConnectorWithData)
|
|
101
|
+
* means that opening only the management dialog — which does not consume users — never
|
|
102
|
+
* dispatches the workspace-users load, matching the pre-separation behavior.
|
|
103
|
+
*/
|
|
104
|
+
function ScheduledEmailDialogWithUsers(props) {
|
|
105
|
+
const { users, status: usersStatus, usersError } = useWorkspaceUsers();
|
|
106
|
+
return (_jsx(ScheduledEmailDialog, { ...props, users: users ?? [], usersError: usersError, isLoading: props.isLoading || usersStatus === "pending" || usersStatus === "loading" }));
|
|
107
|
+
}
|
package/esm/presentation/automations/connectors/hooks/useBuildAlertingDialogContext.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBuildAlertingDialogContext.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/automations/connectors/hooks/useBuildAlertingDialogContext.ts"],"names":[],"mappings":"AAKA,OAAO,
|
|
1
|
+
{"version":3,"file":"useBuildAlertingDialogContext.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/automations/connectors/hooks/useBuildAlertingDialogContext.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,OAAO,EAAmB,MAAM,qBAAqB,CAAC;AAiBnF,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yCAAyC,CAAC;AAI3F,MAAM,WAAW,kCAAkC;IAC/C,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,QAAQ,CAAC;CACtB;AAED,wBAAgB,6BAA6B,CACzC,IAAI,EAAE,kCAAkC,GACzC,2BAA2B,CA4F7B"}
|
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
// (C) 2026 GoodData Corporation
|
|
2
2
|
import { useCallback, useMemo, useRef } from "react";
|
|
3
|
-
import { serializeObjRef
|
|
4
|
-
import {
|
|
5
|
-
import { createAlert, saveAlert } from "../../../../model/commands/alerts.js";
|
|
3
|
+
import { serializeObjRef } from "@gooddata/sdk-model";
|
|
4
|
+
import { createAlert as createAlertCmd, saveAlert as saveAlertCmd, } from "../../../../model/commands/alerts.js";
|
|
6
5
|
import { useDashboardSelector } from "../../../../model/react/DashboardStoreProvider.js";
|
|
7
|
-
import { useDashboardCommandProcessing } from "../../../../model/react/useDashboardCommandProcessing.js";
|
|
8
6
|
import { selectExecutionResultEntities } from "../../../../model/store/executionResults/executionResultsSelectors.js";
|
|
9
7
|
import { selectAutomationCommonDateFilterId, selectAutomationDefaultSelectedFilters, selectDashboardHiddenFilters, } from "../../../../model/store/filtering/dashboardFilterSelectors.js";
|
|
10
8
|
import { selectDashboardId, selectEvaluationFrequency } from "../../../../model/store/meta/metaSelectors.js";
|
|
11
9
|
import { selectWidgetLocalIdToTabIdMap } from "../../../../model/store/tabs/layout/layoutSelectors.js";
|
|
12
10
|
import { selectEffectiveParameterValuesForWidget } from "../../../../model/store/tabs/parameters/parametersSelectors.js";
|
|
13
11
|
import { getWidgetTitle } from "../../../../model/utils/dashboardItemUtils.js";
|
|
14
|
-
import {
|
|
12
|
+
import { useCommandAsPromise, useDeleteAutomation } from "./useCommandAsPromise.js";
|
|
15
13
|
export function useBuildAlertingDialogContext(opts) {
|
|
16
14
|
const { mode, widget, insight } = opts;
|
|
17
|
-
const backend = useBackendStrict();
|
|
18
|
-
const workspace = useWorkspaceStrict();
|
|
19
15
|
const dashboardFilters = useDashboardSelector(selectAutomationDefaultSelectedFilters);
|
|
20
16
|
const hiddenFilters = useDashboardSelector(selectDashboardHiddenFilters);
|
|
21
17
|
const dashboardId = useDashboardSelector(selectDashboardId);
|
|
@@ -46,52 +42,17 @@ export function useBuildAlertingDialogContext(opts) {
|
|
|
46
42
|
// alerting dialog Overlay from ever stabilizing (it stays hidden).
|
|
47
43
|
return executionResultEntitiesRef.current[key];
|
|
48
44
|
}, []);
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
commandCreator: createAlert,
|
|
52
|
-
errorEvent: "GDC.DASH/EVT.COMMAND.FAILED",
|
|
45
|
+
const createAlert = useCommandAsPromise({
|
|
46
|
+
commandCreator: createAlertCmd,
|
|
53
47
|
successEvent: "GDC.DASH/EVT.ALERT.CREATED",
|
|
54
|
-
|
|
55
|
-
createPendingRef.current?.resolve(event.payload.alert);
|
|
56
|
-
createPendingRef.current = null;
|
|
57
|
-
},
|
|
58
|
-
onError: (event) => {
|
|
59
|
-
const error = event.payload.error ?? new Error(event.payload.message);
|
|
60
|
-
createPendingRef.current?.reject(error);
|
|
61
|
-
createPendingRef.current = null;
|
|
62
|
-
},
|
|
48
|
+
resolveWith: (event) => event.payload.alert,
|
|
63
49
|
});
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
createPendingRef.current = { resolve, reject };
|
|
67
|
-
runCreate(sanitizeAutomationForSave(alert));
|
|
68
|
-
});
|
|
69
|
-
}, [runCreate]);
|
|
70
|
-
const savePendingRef = useRef(null);
|
|
71
|
-
const { run: runSave } = useDashboardCommandProcessing({
|
|
72
|
-
commandCreator: saveAlert,
|
|
73
|
-
errorEvent: "GDC.DASH/EVT.COMMAND.FAILED",
|
|
50
|
+
const saveAlert = useCommandAsPromise({
|
|
51
|
+
commandCreator: saveAlertCmd,
|
|
74
52
|
successEvent: "GDC.DASH/EVT.ALERT.SAVED",
|
|
75
|
-
|
|
76
|
-
savePendingRef.current?.resolve(event.payload.alert);
|
|
77
|
-
savePendingRef.current = null;
|
|
78
|
-
},
|
|
79
|
-
onError: (event) => {
|
|
80
|
-
const error = event.payload.error ?? new Error(event.payload.message);
|
|
81
|
-
savePendingRef.current?.reject(error);
|
|
82
|
-
savePendingRef.current = null;
|
|
83
|
-
},
|
|
53
|
+
resolveWith: (event) => event.payload.alert,
|
|
84
54
|
});
|
|
85
|
-
const
|
|
86
|
-
return new Promise((resolve, reject) => {
|
|
87
|
-
savePendingRef.current = { resolve, reject };
|
|
88
|
-
runSave(sanitizeAutomationForSave(alert));
|
|
89
|
-
});
|
|
90
|
-
}, [runSave]);
|
|
91
|
-
const deleteAlertFn = useCallback(async (alert) => {
|
|
92
|
-
const automationService = backend.workspace(workspace).automations();
|
|
93
|
-
await automationService.deleteAutomation(alert.id);
|
|
94
|
-
}, [backend, workspace]);
|
|
55
|
+
const deleteAlert = useDeleteAutomation();
|
|
95
56
|
return useMemo(() => ({
|
|
96
57
|
mode,
|
|
97
58
|
widget,
|
|
@@ -105,9 +66,9 @@ export function useBuildAlertingDialogContext(opts) {
|
|
|
105
66
|
parameterValues,
|
|
106
67
|
commonDateFilterId,
|
|
107
68
|
dashboardEvaluationFrequency,
|
|
108
|
-
createAlert
|
|
109
|
-
saveAlert
|
|
110
|
-
deleteAlert
|
|
69
|
+
createAlert,
|
|
70
|
+
saveAlert,
|
|
71
|
+
deleteAlert,
|
|
111
72
|
}), [
|
|
112
73
|
mode,
|
|
113
74
|
widget,
|
|
@@ -121,8 +82,8 @@ export function useBuildAlertingDialogContext(opts) {
|
|
|
121
82
|
parameterValues,
|
|
122
83
|
commonDateFilterId,
|
|
123
84
|
dashboardEvaluationFrequency,
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
85
|
+
createAlert,
|
|
86
|
+
saveAlert,
|
|
87
|
+
deleteAlert,
|
|
127
88
|
]);
|
|
128
89
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBuildAutomationsContext.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/automations/connectors/hooks/useBuildAutomationsContext.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useBuildAutomationsContext.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/automations/connectors/hooks/useBuildAutomationsContext.ts"],"names":[],"mappings":"AA4EA,OAAO,KAAK,EACR,wBAAwB,EAE3B,MAAM,sCAAsC,CAAC;AAI9C,wBAAgB,0BAA0B,IAAI,wBAAwB,CAqMrE"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { useCallback, useMemo } from "react";
|
|
3
3
|
import { useDashboardSelector } from "../../../../model/react/DashboardStoreProvider.js";
|
|
4
4
|
import { selectAllCatalogAttributesMap, selectAllCatalogDisplayFormsMap, selectCatalogAttributes, selectCatalogDateDatasets, selectCatalogMeasures, } from "../../../../model/store/catalog/catalogSelectors.js";
|
|
5
|
-
import { selectEnableAlertAttributes, selectEnableAlertOncePerInterval, selectEnableAnomalyDetectionAlert, selectEnableAutomationManagement, selectEnableComparisonInAlerting, selectEnableExternalRecipients, selectEnableNewScheduledExport, selectExternalRecipient, selectIsWhiteLabeled, selectLocale, selectSeparators, selectSettings, selectTimezone, selectWeekStart, } from "../../../../model/store/config/configSelectors.js";
|
|
5
|
+
import { selectEnableAlertAttributes, selectEnableAlertOncePerInterval, selectEnableAnomalyDetectionAlert, selectEnableAutomationEvaluationMode, selectEnableAutomationManagement, selectEnableComparisonInAlerting, selectEnableCustomizableCsvDelimiter, selectEnableExternalRecipients, selectEnableNewScheduledExport, selectExternalRecipient, selectIsWhiteLabeled, selectLocale, selectSeparators, selectSettings, selectTimezone, selectWeekStart, } from "../../../../model/store/config/configSelectors.js";
|
|
6
6
|
import { selectEntitlementMinimumRecurrenceMinutes, selectMaxAutomationRecipients, } from "../../../../model/store/entitlements/entitlementsSelectors.js";
|
|
7
7
|
import { selectAutomationAvailableDashboardFilters, selectAutomationCommonDateFilterId, selectAutomationDefaultSelectedFilters, selectAutomationFiltersByTab, selectDashboardFiltersWithoutCrossFiltering, selectDashboardHiddenFilters, selectDashboardLockedFilters, } from "../../../../model/store/filtering/dashboardFilterSelectors.js";
|
|
8
8
|
import { selectPersistedDashboardFilterContextDateFilterConfig } from "../../../../model/store/meta/metaSelectors.js";
|
|
@@ -63,6 +63,8 @@ export function useBuildAutomationsContext() {
|
|
|
63
63
|
const enableComparisonInAlerting = useDashboardSelector(selectEnableComparisonInAlerting);
|
|
64
64
|
const enableExternalRecipients = useDashboardSelector(selectEnableExternalRecipients);
|
|
65
65
|
const enableAlertAttributes = useDashboardSelector(selectEnableAlertAttributes);
|
|
66
|
+
const enableCustomizableCsvDelimiter = useDashboardSelector(selectEnableCustomizableCsvDelimiter);
|
|
67
|
+
const enableAutomationEvaluationMode = useDashboardSelector(selectEnableAutomationEvaluationMode);
|
|
66
68
|
const maxAutomationsRecipients = useDashboardSelector(selectMaxAutomationRecipients);
|
|
67
69
|
const minimumRecurrenceMinutesEntitlement = useDashboardSelector(selectEntitlementMinimumRecurrenceMinutes);
|
|
68
70
|
const allowHourlyRecurrence = parseInt(minimumRecurrenceMinutesEntitlement?.value ?? DEFAULT_MIN_RECURRENCE_MINUTES, 10) === 60;
|
|
@@ -86,6 +88,8 @@ export function useBuildAutomationsContext() {
|
|
|
86
88
|
enableExternalRecipients,
|
|
87
89
|
enableAlertAttributes,
|
|
88
90
|
canManageWorkspace,
|
|
91
|
+
enableCustomizableCsvDelimiter,
|
|
92
|
+
enableAutomationEvaluationMode,
|
|
89
93
|
}), [
|
|
90
94
|
canCreateAutomation,
|
|
91
95
|
enableAlertOncePerInterval,
|
|
@@ -96,6 +100,8 @@ export function useBuildAutomationsContext() {
|
|
|
96
100
|
enableExternalRecipients,
|
|
97
101
|
enableAlertAttributes,
|
|
98
102
|
canManageWorkspace,
|
|
103
|
+
enableCustomizableCsvDelimiter,
|
|
104
|
+
enableAutomationEvaluationMode,
|
|
99
105
|
]);
|
|
100
106
|
return useMemo(() => ({
|
|
101
107
|
locale,
|
|
@@ -44,11 +44,14 @@ vi.mock("../../../../model/store/catalog/catalogSelectors.js", () => ({
|
|
|
44
44
|
selectCatalogMeasures: () => [],
|
|
45
45
|
}));
|
|
46
46
|
vi.mock("../../../../model/store/config/configSelectors.js", () => ({
|
|
47
|
+
selectDateFormat: () => "MM/dd/yyyy",
|
|
47
48
|
selectEnableAlertAttributes: () => false,
|
|
48
49
|
selectEnableAlertOncePerInterval: () => false,
|
|
49
50
|
selectEnableAnomalyDetectionAlert: () => false,
|
|
51
|
+
selectEnableAutomationEvaluationMode: () => false,
|
|
50
52
|
selectEnableAutomationManagement: () => false,
|
|
51
53
|
selectEnableComparisonInAlerting: () => false,
|
|
54
|
+
selectEnableCustomizableCsvDelimiter: () => false,
|
|
52
55
|
selectEnableExternalRecipients: () => false,
|
|
53
56
|
selectEnableNewScheduledExport: () => false,
|
|
54
57
|
selectExternalRecipient: () => undefined,
|
|
@@ -59,6 +62,12 @@ vi.mock("../../../../model/store/config/configSelectors.js", () => ({
|
|
|
59
62
|
selectTimezone: () => undefined,
|
|
60
63
|
selectWeekStart: () => "Sunday",
|
|
61
64
|
}));
|
|
65
|
+
vi.mock("../../../../model/store/drill/drillSelectors.js", () => ({
|
|
66
|
+
selectIsCrossFiltering: () => false,
|
|
67
|
+
}));
|
|
68
|
+
vi.mock("../../../../model/store/tabs/tabsSelectors.js", () => ({
|
|
69
|
+
selectTabs: () => [],
|
|
70
|
+
}));
|
|
62
71
|
vi.mock("../../../../model/store/permissions/permissionsSelectors.js", () => ({
|
|
63
72
|
selectCanCreateAutomation: () => true,
|
|
64
73
|
selectCanManageWorkspace: () => false,
|
|
@@ -87,17 +96,20 @@ vi.mock("../../../../model/store/tabs/attributeFilterConfigs/attributeFilterConf
|
|
|
87
96
|
selectAttributeFilterConfigsOverridesByTab: () => ({}),
|
|
88
97
|
selectAttributeFilterConfigsSelectionTypeMap: () => new Map(),
|
|
89
98
|
selectAttributeFilterConfigsSelectionTypeMapByTab: () => ({}),
|
|
99
|
+
selectEffectiveAttributeFiltersModeMap: () => new Map(),
|
|
90
100
|
}));
|
|
91
101
|
vi.mock("../../../../model/store/tabs/dateFilterConfig/dateFilterConfigSelectors.js", () => ({
|
|
92
102
|
selectDateFilterConfigOverridesByTab: () => ({}),
|
|
93
103
|
selectEffectiveDateFilterAvailableGranularities: () => selectors.availableGranularities,
|
|
94
104
|
selectEffectiveDateFilterGranularitiesPerTab: () => selectors.granularitiesPerTab,
|
|
105
|
+
selectEffectiveDateFilterMode: () => "active",
|
|
95
106
|
selectEffectiveDateFilterOptions: () => selectors.dateFilterOptions,
|
|
96
107
|
selectEffectiveDateFilterOptionsPerTab: () => selectors.optionsPerTab,
|
|
97
108
|
}));
|
|
98
109
|
vi.mock("../../../../model/store/tabs/dateFilterConfigs/dateFilterConfigsSelectors.js", () => ({
|
|
99
110
|
selectDateFilterConfigsOverrides: () => [],
|
|
100
111
|
selectDateFilterConfigsOverridesByTab: () => ({}),
|
|
112
|
+
selectEffectiveDateFiltersModeMap: () => new Map(),
|
|
101
113
|
}));
|
|
102
114
|
vi.mock("../../../../model/store/tabs/filterContext/filterContextSelectors.js", () => ({
|
|
103
115
|
selectAttributeFilterDisplayFormsMap: () => new Map(),
|
|
@@ -113,6 +125,9 @@ vi.mock("../../../../model/store/tabs/measureValueFilterConfigs/measureValueFilt
|
|
|
113
125
|
selectMeasureValueFilterConfigsOverrides: () => [],
|
|
114
126
|
selectMeasureValueFilterConfigsOverridesByTab: () => ({}),
|
|
115
127
|
}));
|
|
128
|
+
vi.mock("../../../../model/store/tabs/layout/layoutSelectors.js", () => ({
|
|
129
|
+
selectWidgetsMap: () => ({ get: () => undefined }),
|
|
130
|
+
}));
|
|
116
131
|
import { useBuildAutomationsContext } from "./useBuildAutomationsContext.js";
|
|
117
132
|
describe("useBuildAutomationsContext", () => {
|
|
118
133
|
it("preserves per-tab date filter configuration in the automations context bridge", () => {
|
package/esm/presentation/automations/connectors/hooks/useBuildScheduledEmailDialogContext.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type IInsight, type IWidget } from "@gooddata/sdk-model";
|
|
2
|
+
import type { IScheduledEmailDialogContextValue } from "../../contexts/ScheduledEmailDialogContext.js";
|
|
3
|
+
export interface IUseBuildScheduledEmailDialogContextOpts {
|
|
4
|
+
widget?: IWidget;
|
|
5
|
+
insight?: IInsight;
|
|
6
|
+
}
|
|
7
|
+
export declare function useBuildScheduledEmailDialogContext(opts: IUseBuildScheduledEmailDialogContextOpts): IScheduledEmailDialogContextValue;
|
|
8
|
+
//# sourceMappingURL=useBuildScheduledEmailDialogContext.d.ts.map
|
package/esm/presentation/automations/connectors/hooks/useBuildScheduledEmailDialogContext.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBuildScheduledEmailDialogContext.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/automations/connectors/hooks/useBuildScheduledEmailDialogContext.ts"],"names":[],"mappings":"AAIA,OAAO,EAEH,KAAK,QAAQ,EACb,KAAK,OAAO,EAGf,MAAM,qBAAqB,CAAC;AA2B7B,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,+CAA+C,CAAC;AAIvG,MAAM,WAAW,wCAAwC;IACrD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,QAAQ,CAAC;CACtB;AAED,wBAAgB,mCAAmC,CAC/C,IAAI,EAAE,wCAAwC,GAC/C,iCAAiC,CAmGnC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { useCallback, useMemo } from "react";
|
|
3
|
+
import { objRefToString, } from "@gooddata/sdk-model";
|
|
4
|
+
import { createScheduledEmail as createScheduledEmailCmd, saveScheduledEmail as saveScheduledEmailCmd, } from "../../../../model/commands/scheduledEmail.js";
|
|
5
|
+
import { useDashboardSelector } from "../../../../model/react/DashboardStoreProvider.js";
|
|
6
|
+
import { useExportTemplates } from "../../../../model/react/useExportTemplates.js";
|
|
7
|
+
import { selectDateFormat } from "../../../../model/store/config/configSelectors.js";
|
|
8
|
+
import { selectIsCrossFiltering } from "../../../../model/store/drill/drillSelectors.js";
|
|
9
|
+
import { selectAutomationCommonDateFilterId, selectAutomationDefaultSelectedFilters, selectDashboardHiddenFilters, } from "../../../../model/store/filtering/dashboardFilterSelectors.js";
|
|
10
|
+
import { selectDashboardId, selectDashboardTitle } from "../../../../model/store/meta/metaSelectors.js";
|
|
11
|
+
import { selectEffectiveAttributeFiltersModeMap } from "../../../../model/store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
|
|
12
|
+
import { selectEffectiveDateFilterMode } from "../../../../model/store/tabs/dateFilterConfig/dateFilterConfigSelectors.js";
|
|
13
|
+
import { selectEffectiveDateFiltersModeMap } from "../../../../model/store/tabs/dateFilterConfigs/dateFilterConfigsSelectors.js";
|
|
14
|
+
import { selectWidgetLocalIdToTabIdMap, selectWidgetsMap, } from "../../../../model/store/tabs/layout/layoutSelectors.js";
|
|
15
|
+
import { selectExportEffectiveParameters } from "../../../../model/store/tabs/parameters/parametersSelectors.js";
|
|
16
|
+
import { selectTabs } from "../../../../model/store/tabs/tabsSelectors.js";
|
|
17
|
+
import { getWidgetTitle } from "../../../../model/utils/dashboardItemUtils.js";
|
|
18
|
+
import { useCommandAsPromise, useDeleteAutomation } from "./useCommandAsPromise.js";
|
|
19
|
+
export function useBuildScheduledEmailDialogContext(opts) {
|
|
20
|
+
const { widget, insight } = opts;
|
|
21
|
+
const dashboardFilters = useDashboardSelector(selectAutomationDefaultSelectedFilters);
|
|
22
|
+
const hiddenFilters = useDashboardSelector(selectDashboardHiddenFilters);
|
|
23
|
+
const dashboardId = useDashboardSelector(selectDashboardId);
|
|
24
|
+
const dashboardTitle = useDashboardSelector(selectDashboardTitle);
|
|
25
|
+
const widgetLocalIdToTabIdMap = useDashboardSelector(selectWidgetLocalIdToTabIdMap);
|
|
26
|
+
const commonDateFilterId = useDashboardSelector(selectAutomationCommonDateFilterId);
|
|
27
|
+
const exportParametersByTab = useDashboardSelector(selectExportEffectiveParameters(widget ? [objRefToString(widget.ref)] : undefined));
|
|
28
|
+
const exportTemplates = useExportTemplates();
|
|
29
|
+
const dateFormat = useDashboardSelector(selectDateFormat);
|
|
30
|
+
const isCrossFiltering = useDashboardSelector(selectIsCrossFiltering);
|
|
31
|
+
const tabs = useDashboardSelector(selectTabs);
|
|
32
|
+
const hasMultipleTabs = (tabs?.length ?? 0) > 1;
|
|
33
|
+
const widgetsMap = useDashboardSelector(selectWidgetsMap);
|
|
34
|
+
const commonDateFilterMode = useDashboardSelector(selectEffectiveDateFilterMode);
|
|
35
|
+
const dateFiltersModeMap = useDashboardSelector(selectEffectiveDateFiltersModeMap);
|
|
36
|
+
const attributeFiltersModeMap = useDashboardSelector(selectEffectiveAttributeFiltersModeMap);
|
|
37
|
+
const widgetTitle = useMemo(() => {
|
|
38
|
+
if (widget) {
|
|
39
|
+
return getWidgetTitle(widget);
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}, [widget]);
|
|
43
|
+
const widgetExistsByRef = useCallback((ref) => {
|
|
44
|
+
return !!ref && widgetsMap.get(ref) !== undefined;
|
|
45
|
+
}, [widgetsMap]);
|
|
46
|
+
const createScheduledEmail = useCommandAsPromise({
|
|
47
|
+
commandCreator: createScheduledEmailCmd,
|
|
48
|
+
successEvent: "GDC.DASH/EVT.SCHEDULED_EMAIL.CREATED",
|
|
49
|
+
resolveWith: (event) => event.payload.scheduledEmail,
|
|
50
|
+
});
|
|
51
|
+
const saveScheduledEmail = useCommandAsPromise({
|
|
52
|
+
commandCreator: saveScheduledEmailCmd,
|
|
53
|
+
successEvent: "GDC.DASH/EVT.SCHEDULED_EMAIL.SAVED",
|
|
54
|
+
resolveWith: (_event, input) => input,
|
|
55
|
+
});
|
|
56
|
+
const deleteScheduledEmail = useDeleteAutomation();
|
|
57
|
+
return useMemo(() => ({
|
|
58
|
+
widget,
|
|
59
|
+
insight,
|
|
60
|
+
widgetTitle,
|
|
61
|
+
dashboardId,
|
|
62
|
+
dashboardTitle,
|
|
63
|
+
dashboardFilters,
|
|
64
|
+
hiddenFilters,
|
|
65
|
+
widgetLocalIdToTabIdMap,
|
|
66
|
+
commonDateFilterId,
|
|
67
|
+
exportParametersByTab,
|
|
68
|
+
exportTemplates,
|
|
69
|
+
dateFormat,
|
|
70
|
+
isCrossFiltering,
|
|
71
|
+
hasMultipleTabs,
|
|
72
|
+
widgetExistsByRef,
|
|
73
|
+
commonDateFilterMode,
|
|
74
|
+
dateFiltersModeMap,
|
|
75
|
+
attributeFiltersModeMap,
|
|
76
|
+
createScheduledEmail,
|
|
77
|
+
saveScheduledEmail,
|
|
78
|
+
deleteScheduledEmail,
|
|
79
|
+
}), [
|
|
80
|
+
widget,
|
|
81
|
+
insight,
|
|
82
|
+
widgetTitle,
|
|
83
|
+
dashboardId,
|
|
84
|
+
dashboardTitle,
|
|
85
|
+
dashboardFilters,
|
|
86
|
+
hiddenFilters,
|
|
87
|
+
widgetLocalIdToTabIdMap,
|
|
88
|
+
commonDateFilterId,
|
|
89
|
+
exportParametersByTab,
|
|
90
|
+
exportTemplates,
|
|
91
|
+
dateFormat,
|
|
92
|
+
isCrossFiltering,
|
|
93
|
+
hasMultipleTabs,
|
|
94
|
+
widgetExistsByRef,
|
|
95
|
+
commonDateFilterMode,
|
|
96
|
+
dateFiltersModeMap,
|
|
97
|
+
attributeFiltersModeMap,
|
|
98
|
+
createScheduledEmail,
|
|
99
|
+
saveScheduledEmail,
|
|
100
|
+
deleteScheduledEmail,
|
|
101
|
+
]);
|
|
102
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBuildScheduledEmailDialogContext.test.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/automations/connectors/hooks/useBuildScheduledEmailDialogContext.test.tsx"],"names":[],"mappings":""}
|
package/esm/presentation/automations/connectors/hooks/useBuildScheduledEmailDialogContext.test.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { act, renderHook } from "@testing-library/react";
|
|
3
|
+
import { describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { idRef, } from "@gooddata/sdk-model";
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Hoisted mocks — must be before any import that resolves these modules
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
const runCreateMock = vi.fn();
|
|
9
|
+
const runSaveMock = vi.fn();
|
|
10
|
+
vi.mock("@gooddata/sdk-ui", () => ({
|
|
11
|
+
useBackendStrict: vi.fn(() => ({ workspace: () => ({ automations: () => ({}) }) })),
|
|
12
|
+
useWorkspaceStrict: vi.fn(() => "workspace"),
|
|
13
|
+
}));
|
|
14
|
+
vi.mock("../../../../model/react/DashboardStoreProvider.js", () => ({
|
|
15
|
+
useDashboardSelector: vi.fn((selector) => selector()),
|
|
16
|
+
}));
|
|
17
|
+
vi.mock("../../../../model/react/useDashboardCommandProcessing.js", () => ({
|
|
18
|
+
useDashboardCommandProcessing: vi.fn(({ commandCreator, successEvent, onSuccess, onError, }) => {
|
|
19
|
+
const run = successEvent === "GDC.DASH/EVT.SCHEDULED_EMAIL.CREATED" ? runCreateMock : runSaveMock;
|
|
20
|
+
// Simulate the real useDashboardCommandProcessing: invoke commandCreator when run is called
|
|
21
|
+
// so that sanitizeAutomationForSave (called inside commandCreator) fires.
|
|
22
|
+
run.mockImplementation((input) => commandCreator(input));
|
|
23
|
+
run.__onSuccess = onSuccess;
|
|
24
|
+
run.__onError = onError;
|
|
25
|
+
return { run };
|
|
26
|
+
}),
|
|
27
|
+
}));
|
|
28
|
+
vi.mock("../../../../model/commands/scheduledEmail.js", () => ({
|
|
29
|
+
createScheduledEmail: vi.fn((se) => ({ type: "CREATE", se })),
|
|
30
|
+
saveScheduledEmail: vi.fn((se) => ({ type: "SAVE", se })),
|
|
31
|
+
}));
|
|
32
|
+
vi.mock("../../../../model/store/filtering/dashboardFilterSelectors.js", () => ({
|
|
33
|
+
selectAutomationCommonDateFilterId: () => "common-date-id",
|
|
34
|
+
selectAutomationDefaultSelectedFilters: () => [{ id: "filter-1" }],
|
|
35
|
+
selectDashboardHiddenFilters: () => [],
|
|
36
|
+
}));
|
|
37
|
+
vi.mock("../../../../model/store/meta/metaSelectors.js", () => ({
|
|
38
|
+
selectDashboardId: () => "dashboard-1",
|
|
39
|
+
selectDashboardTitle: () => "My Dashboard",
|
|
40
|
+
}));
|
|
41
|
+
vi.mock("../../../../model/store/config/configSelectors.js", () => ({
|
|
42
|
+
selectDateFormat: () => "MM/dd/yyyy",
|
|
43
|
+
}));
|
|
44
|
+
vi.mock("../../../../model/store/drill/drillSelectors.js", () => ({
|
|
45
|
+
selectIsCrossFiltering: () => false,
|
|
46
|
+
}));
|
|
47
|
+
vi.mock("../../../../model/store/tabs/layout/layoutSelectors.js", () => ({
|
|
48
|
+
selectWidgetLocalIdToTabIdMap: () => ({ widgetId: "tab-1" }),
|
|
49
|
+
selectWidgetsMap: () => ({ get: () => undefined }),
|
|
50
|
+
}));
|
|
51
|
+
vi.mock("../../../../model/store/tabs/dateFilterConfig/dateFilterConfigSelectors.js", () => ({
|
|
52
|
+
selectEffectiveDateFilterMode: () => "active",
|
|
53
|
+
}));
|
|
54
|
+
vi.mock("../../../../model/store/tabs/dateFilterConfigs/dateFilterConfigsSelectors.js", () => ({
|
|
55
|
+
selectEffectiveDateFiltersModeMap: () => new Map(),
|
|
56
|
+
}));
|
|
57
|
+
vi.mock("../../../../model/store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js", () => ({
|
|
58
|
+
selectEffectiveAttributeFiltersModeMap: () => new Map(),
|
|
59
|
+
}));
|
|
60
|
+
vi.mock("../../../../model/store/tabs/tabsSelectors.js", () => ({
|
|
61
|
+
selectTabs: () => [],
|
|
62
|
+
}));
|
|
63
|
+
vi.mock("../../../../model/store/tabs/parameters/parametersSelectors.js", () => ({
|
|
64
|
+
selectExportEffectiveParameters: () => () => ({}),
|
|
65
|
+
}));
|
|
66
|
+
vi.mock("../../../../model/react/useExportTemplates.js", () => ({
|
|
67
|
+
useExportTemplates: () => [],
|
|
68
|
+
}));
|
|
69
|
+
vi.mock("../../../../model/utils/dashboardItemUtils.js", () => ({
|
|
70
|
+
getWidgetTitle: () => "widget title",
|
|
71
|
+
}));
|
|
72
|
+
vi.mock("./sanitizeAutomationForSave.js", () => ({
|
|
73
|
+
sanitizeAutomationForSave: vi.fn((automation) => ({
|
|
74
|
+
...automation,
|
|
75
|
+
__sanitized: true,
|
|
76
|
+
})),
|
|
77
|
+
}));
|
|
78
|
+
import { createScheduledEmail as createScheduledEmailCmd, saveScheduledEmail as saveScheduledEmailCmd, } from "../../../../model/commands/scheduledEmail.js";
|
|
79
|
+
import { sanitizeAutomationForSave } from "./sanitizeAutomationForSave.js";
|
|
80
|
+
import { useBuildScheduledEmailDialogContext } from "./useBuildScheduledEmailDialogContext.js";
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// Tests
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
describe("useBuildScheduledEmailDialogContext", () => {
|
|
85
|
+
it("exposes dashboardId, dashboardTitle, and dashboardFilters from the store selectors", () => {
|
|
86
|
+
const { result } = renderHook(() => useBuildScheduledEmailDialogContext({}));
|
|
87
|
+
expect(result.current.dashboardId).toBe("dashboard-1");
|
|
88
|
+
expect(result.current.dashboardTitle).toBe("My Dashboard");
|
|
89
|
+
expect(result.current.dashboardFilters).toEqual([{ id: "filter-1" }]);
|
|
90
|
+
});
|
|
91
|
+
it("createScheduledEmail applies sanitizeAutomationForSave before dispatching the command", async () => {
|
|
92
|
+
const { result } = renderHook(() => useBuildScheduledEmailDialogContext({}));
|
|
93
|
+
const draft = {
|
|
94
|
+
type: "automation",
|
|
95
|
+
title: "New Schedule",
|
|
96
|
+
};
|
|
97
|
+
// Kick off the create (do not await yet)
|
|
98
|
+
let promise;
|
|
99
|
+
act(() => {
|
|
100
|
+
promise = result.current.createScheduledEmail(draft);
|
|
101
|
+
});
|
|
102
|
+
// sanitizeAutomationForSave must have been called with the raw draft
|
|
103
|
+
expect(sanitizeAutomationForSave).toHaveBeenCalledWith(draft);
|
|
104
|
+
// The command creator must have received the sanitized draft (sanitize runs inside commandCreator)
|
|
105
|
+
expect(createScheduledEmailCmd).toHaveBeenCalledWith(expect.objectContaining({ __sanitized: true }));
|
|
106
|
+
// Simulate the CREATED event resolving
|
|
107
|
+
const createdSE = {
|
|
108
|
+
type: "automation",
|
|
109
|
+
id: "se-1",
|
|
110
|
+
title: "New Schedule",
|
|
111
|
+
ref: idRef("se-1"),
|
|
112
|
+
};
|
|
113
|
+
act(() => {
|
|
114
|
+
runCreateMock.__onSuccess({
|
|
115
|
+
payload: { scheduledEmail: createdSE },
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
await expect(promise).resolves.toEqual(createdSE);
|
|
119
|
+
});
|
|
120
|
+
it("saveScheduledEmail applies sanitizeAutomationForSave before dispatching the command", async () => {
|
|
121
|
+
const { result } = renderHook(() => useBuildScheduledEmailDialogContext({}));
|
|
122
|
+
const existing = {
|
|
123
|
+
type: "automation",
|
|
124
|
+
id: "se-2",
|
|
125
|
+
title: "Existing Schedule",
|
|
126
|
+
ref: idRef("se-2"),
|
|
127
|
+
};
|
|
128
|
+
let promise;
|
|
129
|
+
act(() => {
|
|
130
|
+
promise = result.current.saveScheduledEmail(existing);
|
|
131
|
+
});
|
|
132
|
+
expect(sanitizeAutomationForSave).toHaveBeenCalledWith(existing);
|
|
133
|
+
expect(saveScheduledEmailCmd).toHaveBeenCalledWith(expect.objectContaining({ __sanitized: true }));
|
|
134
|
+
// Simulate SAVED event — no payload on the SE saved event, so resolve with input
|
|
135
|
+
act(() => {
|
|
136
|
+
runSaveMock.__onSuccess({});
|
|
137
|
+
});
|
|
138
|
+
await expect(promise).resolves.toEqual(existing);
|
|
139
|
+
});
|
|
140
|
+
it("createScheduledEmail rejects with error when the command fails", async () => {
|
|
141
|
+
const { result } = renderHook(() => useBuildScheduledEmailDialogContext({}));
|
|
142
|
+
const draft = {
|
|
143
|
+
type: "automation",
|
|
144
|
+
title: "Fail Schedule",
|
|
145
|
+
};
|
|
146
|
+
let promise;
|
|
147
|
+
act(() => {
|
|
148
|
+
promise = result.current.createScheduledEmail(draft);
|
|
149
|
+
});
|
|
150
|
+
const err = new Error("Backend failure");
|
|
151
|
+
act(() => {
|
|
152
|
+
runCreateMock.__onError({ payload: { error: err } });
|
|
153
|
+
});
|
|
154
|
+
await expect(promise).rejects.toThrow("Backend failure");
|
|
155
|
+
});
|
|
156
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { IAutomationMetadataObject, IAutomationMetadataObjectDefinition } from "@gooddata/sdk-model";
|
|
2
|
+
import type { DashboardCommands } from "../../../../model/commands/index.js";
|
|
3
|
+
import type { DashboardEventType } from "../../../../model/events/base.js";
|
|
4
|
+
import type { DashboardEvents } from "../../../../model/events/index.js";
|
|
5
|
+
type AutomationInput = IAutomationMetadataObjectDefinition | IAutomationMetadataObject;
|
|
6
|
+
/**
|
|
7
|
+
* Wraps a Redux dashboard command in a promise-based API using a single-slot pending ref.
|
|
8
|
+
* Sanitizes the input via sanitizeAutomationForSave before dispatching the command.
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export declare function useCommandAsPromise<TIn extends AutomationInput, TSuccessEventType extends DashboardEventType, TOut>({ commandCreator, successEvent, resolveWith }: {
|
|
13
|
+
commandCreator: (input: TIn) => DashboardCommands;
|
|
14
|
+
successEvent: TSuccessEventType;
|
|
15
|
+
resolveWith: (event: Extract<DashboardEvents, {
|
|
16
|
+
type: TSuccessEventType;
|
|
17
|
+
}>, input: TIn) => TOut;
|
|
18
|
+
}): (input: TIn) => Promise<TOut>;
|
|
19
|
+
/**
|
|
20
|
+
* Returns a stable callback that deletes an automation via the backend directly (no Redux command).
|
|
21
|
+
*
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
export declare function useDeleteAutomation(): (automation: IAutomationMetadataObject) => Promise<void>;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=useCommandAsPromise.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCommandAsPromise.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/automations/connectors/hooks/useCommandAsPromise.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,yBAAyB,EAAE,mCAAmC,EAAE,MAAM,qBAAqB,CAAC;AAG1G,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAKzE,KAAK,eAAe,GAAG,mCAAmC,GAAG,yBAAyB,CAAC;AAEvF;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAC/B,GAAG,SAAS,eAAe,EAC3B,iBAAiB,SAAS,kBAAkB,EAC5C,IAAI,EACN,EACE,cAAc,EACd,YAAY,EACZ,WAAW,EACd,EAAE;IACC,cAAc,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,iBAAiB,CAAC;IAClD,YAAY,EAAE,iBAAiB,CAAC;IAChC,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,eAAe,EAAE;QAAE,IAAI,EAAE,iBAAiB,CAAA;KAAE,CAAC,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;CACnG,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAgChC;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,CAAC,UAAU,EAAE,yBAAyB,KAAK,OAAO,CAAC,IAAI,CAAC,CAW9F"}
|