@gooddata/sdk-ui-dashboard 11.54.0-alpha.4 → 11.54.0-alpha.5
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 +92923 -17333
- package/esm/__version.d.ts +1 -1
- package/esm/__version.js +1 -1
- package/esm/_staging/automation/index.d.ts +6 -0
- package/esm/_staging/automation/index.d.ts.map +1 -1
- package/esm/_staging/automation/index.js +7 -0
- package/esm/_staging/layout/coordinates.mock.d.ts +17 -0
- package/esm/_staging/layout/coordinates.mock.d.ts.map +1 -0
- package/esm/_staging/layout/coordinates.mock.js +103 -0
- package/esm/index.d.ts +2 -2
- package/esm/index.d.ts.map +1 -1
- package/esm/model/DashboardTester.d.ts +150 -0
- package/esm/model/DashboardTester.d.ts.map +1 -0
- package/esm/model/DashboardTester.js +208 -0
- package/esm/model/commandHandlers/dashboard/initializeDashboardHandler/index.d.ts.map +1 -1
- package/esm/model/commandHandlers/dashboard/initializeDashboardHandler/index.js +27 -1
- package/esm/model/commandHandlers/dashboard/initializeDashboardHandler/loadAutomationTimezone.d.ts +9 -0
- package/esm/model/commandHandlers/dashboard/initializeDashboardHandler/loadAutomationTimezone.d.ts.map +1 -0
- package/esm/model/commandHandlers/dashboard/initializeDashboardHandler/loadAutomationTimezone.js +27 -0
- package/esm/model/commandHandlers/timezone/changeDashboardTimezoneOverrideHandler.d.ts.map +1 -1
- package/esm/model/commandHandlers/timezone/changeDashboardTimezoneOverrideHandler.js +2 -11
- package/esm/model/commands/timezone.d.ts +10 -2
- package/esm/model/commands/timezone.d.ts.map +1 -1
- package/esm/model/commands/timezone.js +5 -2
- package/esm/model/fixtures/CatalogAvailability.fixtures.d.ts +14 -0
- package/esm/model/fixtures/CatalogAvailability.fixtures.d.ts.map +1 -0
- package/esm/model/fixtures/CatalogAvailability.fixtures.js +57 -0
- package/esm/model/fixtures/ComplexDashboard.fixtures.d.ts +56 -0
- package/esm/model/fixtures/ComplexDashboard.fixtures.d.ts.map +1 -0
- package/esm/model/fixtures/ComplexDashboard.fixtures.js +71 -0
- package/esm/model/fixtures/Dashboard.fixtures.d.ts +10 -0
- package/esm/model/fixtures/Dashboard.fixtures.d.ts.map +1 -0
- package/esm/model/fixtures/Dashboard.fixtures.js +13 -0
- package/esm/model/fixtures/Insights.fixtures.d.ts +6 -0
- package/esm/model/fixtures/Insights.fixtures.d.ts.map +1 -0
- package/esm/model/fixtures/Insights.fixtures.js +11 -0
- package/esm/model/fixtures/Layout.fixtures.d.ts +14 -0
- package/esm/model/fixtures/Layout.fixtures.d.ts.map +1 -0
- package/esm/model/fixtures/Layout.fixtures.js +115 -0
- package/esm/model/fixtures/SimpleDashboard.fixtures.d.ts +46 -0
- package/esm/model/fixtures/SimpleDashboard.fixtures.d.ts.map +1 -0
- package/esm/model/fixtures/SimpleDashboard.fixtures.js +315 -0
- package/esm/model/fixtures/SimpleDashboardNoDrills.fixtures.d.ts +28 -0
- package/esm/model/fixtures/SimpleDashboardNoDrills.fixtures.d.ts.map +1 -0
- package/esm/model/fixtures/SimpleDashboardNoDrills.fixtures.js +40 -0
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/AlertingDialogDestination.d.ts +6 -0
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/AlertingDialogDestination.d.ts.map +1 -0
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/AlertingDialogDestination.js +13 -0
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/AlertingDialogRecipients.d.ts +7 -0
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/AlertingDialogRecipients.d.ts.map +1 -0
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/AlertingDialogRecipients.js +12 -0
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/DefaultAlertingDialog.d.ts.map +1 -1
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/DefaultAlertingDialog.js +25 -13
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/FormField.d.ts +8 -0
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/FormField.d.ts.map +1 -0
- package/esm/presentation/automations/alerting/DefaultAlertingDialog/FormField.js +8 -0
- package/esm/presentation/automations/alerting/state/fixtures.d.ts +13 -0
- package/esm/presentation/automations/alerting/state/fixtures.d.ts.map +1 -0
- package/esm/presentation/automations/alerting/state/fixtures.js +37 -0
- package/esm/presentation/automations/alerting/types.d.ts +42 -2
- package/esm/presentation/automations/alerting/types.d.ts.map +1 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/DefaultScheduledEmailDialog.d.ts.map +1 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/DefaultScheduledEmailDialog.js +24 -5
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelect.d.ts +1 -5
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelect.d.ts.map +1 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelect.js +2 -2
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelectRenderer.d.ts +0 -4
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelectRenderer.d.ts.map +1 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/ScheduledEmailDialogDestination.d.ts +6 -0
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/ScheduledEmailDialogDestination.d.ts.map +1 -0
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/ScheduledEmailDialogDestination.js +10 -0
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/ScheduledEmailDialogRecipients.d.ts +6 -0
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/ScheduledEmailDialogRecipients.d.ts.map +1 -0
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/ScheduledEmailDialogRecipients.js +8 -0
- package/esm/presentation/automations/scheduledEmail/state/fixtures.d.ts +18 -0
- package/esm/presentation/automations/scheduledEmail/state/fixtures.d.ts.map +1 -0
- package/esm/presentation/automations/scheduledEmail/state/fixtures.js +105 -0
- package/esm/presentation/automations/scheduledEmail/types.d.ts +52 -3
- package/esm/presentation/automations/scheduledEmail/types.d.ts.map +1 -1
- package/esm/presentation/automations/shared/automationFilters/parameterFixtures.d.ts +5 -0
- package/esm/presentation/automations/shared/automationFilters/parameterFixtures.d.ts.map +1 -0
- package/esm/presentation/automations/shared/automationFilters/parameterFixtures.js +22 -0
- package/esm/presentation/automations/shared/slots/types.d.ts +67 -1
- package/esm/presentation/automations/shared/slots/types.d.ts.map +1 -1
- package/esm/presentation/automations/shared/test/fixtures.d.ts +9 -0
- package/esm/presentation/automations/shared/test/fixtures.d.ts.map +1 -0
- package/esm/presentation/automations/shared/test/fixtures.js +101 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayout.d.ts +17 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayout.d.ts.map +1 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayout.js +18 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutItemRenderer.d.ts +12 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutItemRenderer.d.ts.map +1 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutItemRenderer.js +26 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutMocks.d.ts +20 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutMocks.d.ts.map +1 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutMocks.js +95 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutRowRenderer.d.ts +14 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutRowRenderer.d.ts.map +1 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutRowRenderer.js +9 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionBorder.d.ts +9 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionBorder.d.ts.map +1 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionBorder.js +17 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionBorderMarker.d.ts +6 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionBorderMarker.d.ts.map +1 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionBorderMarker.js +10 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionHeader.d.ts +9 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionHeader.d.ts.map +1 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionHeader.js +14 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionHeaderRenderer.d.ts +8 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionHeaderRenderer.d.ts.map +1 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionHeaderRenderer.js +49 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionRenderer.d.ts +7 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionRenderer.d.ts.map +1 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutSectionRenderer.js +33 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutTypes.d.ts +62 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutTypes.d.ts.map +1 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutTypes.js +2 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutWidget.d.ts +11 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutWidget.d.ts.map +1 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutWidget.js +4 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutWidgetRenderer.d.ts +8 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutWidgetRenderer.d.ts.map +1 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/DashboardEditLayoutWidgetRenderer.js +28 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/LayoutTypes.d.ts +26 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/LayoutTypes.d.ts.map +1 -0
- package/esm/presentation/flexibleLayout/useInKD/DashboardEditLayout/LayoutTypes.js +21 -0
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/EditAlert.d.ts.map +1 -1
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/EditAlert.js +1 -1
- package/esm/sdk-ui-dashboard.d.ts +172 -5
- package/package.json +21 -21
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// (C) 2021-2026 GoodData Corporation
|
|
2
|
+
import { ReferenceRecordings } from "@gooddata/reference-workspace";
|
|
3
|
+
import { defaultRecordedBackendCapabilities, objRefsToStringKey, recordedBackend, } from "@gooddata/sdk-backend-mockingbird";
|
|
4
|
+
import { idRef } from "@gooddata/sdk-model";
|
|
5
|
+
import { newRenderingWorker } from "./commandHandlers/render/renderingWorker.js";
|
|
6
|
+
import { initializeDashboard } from "./commands/dashboard.js";
|
|
7
|
+
import { isDashboardCommandStarted, isDashboardQueryCompleted, isDashboardQueryStarted, } from "./events/general.js";
|
|
8
|
+
import { HeadlessDashboard } from "./headlessDashboard/HeadlessDashboard.js";
|
|
9
|
+
export class DashboardTester extends HeadlessDashboard {
|
|
10
|
+
constructor(ctx, config) {
|
|
11
|
+
const headlessDahboardConfig = {
|
|
12
|
+
queryServices: config?.queryServices,
|
|
13
|
+
backgroundWorkers: [newRenderingWorker(config?.renderingWorkerConfig || {})],
|
|
14
|
+
customizationFns: config?.customizationFns,
|
|
15
|
+
};
|
|
16
|
+
super(ctx, headlessDahboardConfig);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates an instance of DashboardTester set up to run tests on top of a dashboard with the provided
|
|
20
|
+
* identifier. The dashboard will be loaded from recorded backend, from its reference workspace.
|
|
21
|
+
*
|
|
22
|
+
* You may additionally influence how the different query services behave (typically to stub/mock the service)
|
|
23
|
+
*/
|
|
24
|
+
static forRecording(identifier, testerConfig, backendConfig, customCapabilities) {
|
|
25
|
+
const ctx = {
|
|
26
|
+
backend: recordedBackend(ReferenceRecordings.Recordings, {
|
|
27
|
+
...backendConfig,
|
|
28
|
+
getCommonAttributesResponses: {
|
|
29
|
+
...commonAttributeResponses,
|
|
30
|
+
...(backendConfig?.getCommonAttributesResponses || {}),
|
|
31
|
+
},
|
|
32
|
+
}, {
|
|
33
|
+
...defaultRecordedBackendCapabilities,
|
|
34
|
+
...customCapabilities,
|
|
35
|
+
}),
|
|
36
|
+
workspace: "reference-workspace",
|
|
37
|
+
dashboardRef: idRef(identifier),
|
|
38
|
+
};
|
|
39
|
+
return new DashboardTester(ctx, testerConfig);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Creates an instance of DashboardTester set up to run tests on top of an empty, freshly initialized dashboard.
|
|
43
|
+
*
|
|
44
|
+
* You may additionally influence how the different query services behave (typically to stub/mock the service)
|
|
45
|
+
*/
|
|
46
|
+
static forNewDashboard(testerConfig, backendConfig) {
|
|
47
|
+
const ctx = {
|
|
48
|
+
backend: recordedBackend(ReferenceRecordings.Recordings, {
|
|
49
|
+
...backendConfig,
|
|
50
|
+
getCommonAttributesResponses: {
|
|
51
|
+
...commonAttributeResponses,
|
|
52
|
+
...(backendConfig?.getCommonAttributesResponses || {}),
|
|
53
|
+
},
|
|
54
|
+
}),
|
|
55
|
+
workspace: "reference-workspace",
|
|
56
|
+
};
|
|
57
|
+
return new DashboardTester(ctx, testerConfig);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Wait the specified time.
|
|
61
|
+
*
|
|
62
|
+
* @param timeout - timeout after which the wait will be resolved
|
|
63
|
+
* @returns promise
|
|
64
|
+
*/
|
|
65
|
+
wait(timeout) {
|
|
66
|
+
return new Promise((resolve) => {
|
|
67
|
+
setTimeout(() => {
|
|
68
|
+
resolve();
|
|
69
|
+
}, timeout);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Returns all actions that were dispatched since the tester was created or since it was last reset.
|
|
74
|
+
*/
|
|
75
|
+
dispatchedActions() {
|
|
76
|
+
return this.capturedActions.slice();
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Wait for all of the listed actions to occur. The wait is bounded by a timeout that is 1s by default.
|
|
80
|
+
*
|
|
81
|
+
* This is useful when testing commands that emit multiple events and you need to verify that all of the
|
|
82
|
+
* events happened. This function does not care about the order in which the events occurred.
|
|
83
|
+
*
|
|
84
|
+
* @param actionTypes - action types to wait for
|
|
85
|
+
* @param timeout - timeout after which the wait fails
|
|
86
|
+
*/
|
|
87
|
+
waitForAll(actionTypes, timeout = 1000) {
|
|
88
|
+
return Promise.race([
|
|
89
|
+
Promise.all(actionTypes.map((actionType) => this.getOrCreateMonitoredAction(actionType).promise)),
|
|
90
|
+
new Promise((_, reject) => {
|
|
91
|
+
setTimeout(() => {
|
|
92
|
+
reject(new Error(`Wait for all actions '${actionTypes.join(", ")}' timed out after ${timeout}ms`));
|
|
93
|
+
}, timeout);
|
|
94
|
+
}),
|
|
95
|
+
]);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Returns all events that were emitted during execution. Events are a sub-type of actions - they are
|
|
99
|
+
* actions that are suitable for external consumption and describe what has happened in the dashboard.
|
|
100
|
+
*
|
|
101
|
+
* The events are accumulated during test run. You may reset them using `resetMonitors`
|
|
102
|
+
*/
|
|
103
|
+
emittedEvents() {
|
|
104
|
+
return this.capturedEvents.slice();
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Resets internal state of the tester's monitors. The captured actions will be cleared up as part
|
|
108
|
+
* of this.
|
|
109
|
+
*/
|
|
110
|
+
resetMonitors() {
|
|
111
|
+
this.capturedActions = [];
|
|
112
|
+
this.capturedEvents = [];
|
|
113
|
+
this.monitoredActions = {};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Returns dashboard state.
|
|
117
|
+
*/
|
|
118
|
+
state() {
|
|
119
|
+
return super.state();
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Returns digests of all events that were emitted during execution. Digest contains just the event
|
|
123
|
+
* type and the correlation id of the event. The payload is discarded.
|
|
124
|
+
*
|
|
125
|
+
* This is useful for snapshotting event sequence.
|
|
126
|
+
*/
|
|
127
|
+
emittedEventsDigest() {
|
|
128
|
+
return this.emittedEvents().map((evt) => {
|
|
129
|
+
if (isDashboardQueryStarted(evt) || isDashboardQueryCompleted(evt)) {
|
|
130
|
+
return {
|
|
131
|
+
type: evt.type,
|
|
132
|
+
correlationId: evt.correlationId,
|
|
133
|
+
queryType: evt.payload.query.type,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (isDashboardCommandStarted(evt)) {
|
|
137
|
+
return {
|
|
138
|
+
type: evt.type,
|
|
139
|
+
correlationId: evt.correlationId,
|
|
140
|
+
commandType: evt.payload.command.type,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
type: evt.type,
|
|
145
|
+
correlationId: evt.correlationId,
|
|
146
|
+
};
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* This factory will return a function that can be integrated into vitest's `beforeAll` or `beforeEach` statements. That returned
|
|
152
|
+
* function will drive initialization of the dashboard tester and will tell vitest it's `done` or it will `fail`.
|
|
153
|
+
*
|
|
154
|
+
* When successfully loaded, the returned function will call the `onLoaded` callback
|
|
155
|
+
*
|
|
156
|
+
* An example usage:
|
|
157
|
+
*
|
|
158
|
+
* ```
|
|
159
|
+
* let Tester: DashboardTester;
|
|
160
|
+
*
|
|
161
|
+
* beforeEach(async ()=> {
|
|
162
|
+
* await preloadedTesterFactory2((tester) => {
|
|
163
|
+
* Tester = tester;
|
|
164
|
+
* }, SimpleDashboardIdentifier);
|
|
165
|
+
* });
|
|
166
|
+
*
|
|
167
|
+
* it("should do xyz", () => {
|
|
168
|
+
*
|
|
169
|
+
* })
|
|
170
|
+
* ```
|
|
171
|
+
*
|
|
172
|
+
* Obvious warning: beforeAll creates one instance for all tests and is therefore not safe when some tests do modifications of
|
|
173
|
+
* the dashboard. Use beforeEach in that case.
|
|
174
|
+
*
|
|
175
|
+
* Note: before sending the instance of dashboard tester, the function will ensure all the event monitors are reset so
|
|
176
|
+
* that the captured events related to load do not interfere with the test itself.
|
|
177
|
+
*
|
|
178
|
+
* @param onLoaded - function to call when the dashboard is successfully loaded
|
|
179
|
+
* @param identifier - identifier of the dashboard to load
|
|
180
|
+
* @param options - options influencing how the tester is created
|
|
181
|
+
*/
|
|
182
|
+
export async function preloadedTesterFactory(onLoaded, identifier, options = {}) {
|
|
183
|
+
const { initCommand = initializeDashboard(), queryServices, backendConfig, customCapabilities, customizationFns, } = options;
|
|
184
|
+
const tester = identifier
|
|
185
|
+
? DashboardTester.forRecording(identifier, { queryServices, customizationFns }, {
|
|
186
|
+
...backendConfig,
|
|
187
|
+
}, {
|
|
188
|
+
...customCapabilities,
|
|
189
|
+
})
|
|
190
|
+
: DashboardTester.forNewDashboard({ queryServices, customizationFns }, {
|
|
191
|
+
...backendConfig,
|
|
192
|
+
});
|
|
193
|
+
tester.dispatch(initCommand);
|
|
194
|
+
await tester
|
|
195
|
+
.waitFor("GDC.DASH/EVT.INITIALIZED")
|
|
196
|
+
.then(() => Promise.resolve(onLoaded(tester)).then(() => tester.resetMonitors()))
|
|
197
|
+
.catch((err) => {
|
|
198
|
+
throw `DashboardTester failed to load dashboard: ${err.message}`;
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
const commonAttributeResponses = {
|
|
202
|
+
[objRefsToStringKey([idRef("obj_1054"), idRef("obj_1086")])]: [idRef("obj_1057")],
|
|
203
|
+
[objRefsToStringKey([idRef("obj_1054"), idRef("obj_1088")])]: [idRef("obj_1057")],
|
|
204
|
+
[objRefsToStringKey([idRef("obj_1054"), idRef("obj_1070")])]: [idRef("obj_1057")],
|
|
205
|
+
[objRefsToStringKey([idRef("obj_1070"), idRef("obj_1088")])]: [idRef("obj_1057")],
|
|
206
|
+
[objRefsToStringKey([idRef("obj_1086"), idRef("obj_1088")])]: [idRef("obj_1057")],
|
|
207
|
+
[objRefsToStringKey([idRef("obj_1070"), idRef("obj_1086")])]: [idRef("obj_1057")],
|
|
208
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/dashboard/initializeDashboardHandler/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAgB,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EAAiC,KAAK,iBAAiB,EAAc,MAAM,2BAA2B,CAAC;AAC9G,OAAO,EACH,KAAK,UAAU,EAIf,KAAK,sBAAsB,EAW9B,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/dashboard/initializeDashboardHandler/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAgB,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EAAiC,KAAK,iBAAiB,EAAc,MAAM,2BAA2B,CAAC;AAC9G,OAAO,EACH,KAAK,UAAU,EAIf,KAAK,sBAAsB,EAW9B,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAsB1E,OAAO,EACH,KAAK,gBAAgB,EAGxB,MAAM,+BAA+B,CAAC;AAwcvC,wBAAiB,cAAc,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,mBAAmB;;;yDAgB9E;AAkCD,wBAAiB,2BAA2B,CAAC,GAAG,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU;;;0EAKxF;AAED,wBAAiB,qBAAqB,CAAC,GAAG,EAAE,gBAAgB,sNAW3D;AAoCD,wBAAiB,0BAA0B,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,mBAAmB,GAAG,YAAY,CAoCzG"}
|
|
@@ -5,6 +5,7 @@ import { all, call, put, spawn } from "redux-saga/effects";
|
|
|
5
5
|
import { walkLayout } from "@gooddata/sdk-backend-spi";
|
|
6
6
|
import { areObjRefsEqual, isDrillToInsight, isInsightWidget, isVisualizationSwitcherWidget, serializeObjRef, } from "@gooddata/sdk-model";
|
|
7
7
|
import { createDisplayFormMap, createDisplayFormMapFromCatalog, } from "../../../../_staging/catalog/displayFormMap.js";
|
|
8
|
+
import { changeDashboardTimezoneOverride } from "../../../commands/timezone.js";
|
|
8
9
|
import { dashboardInitialized } from "../../../events/dashboard.js";
|
|
9
10
|
import { getPrivateContext } from "../../../store/_infra/contexts.js";
|
|
10
11
|
import { accessibleDashboardsActions } from "../../../store/accessibleDashboards/index.js";
|
|
@@ -25,8 +26,10 @@ import { tabsActions } from "../../../store/tabs/index.js";
|
|
|
25
26
|
import { DEFAULT_TAB_ID } from "../../../store/tabs/tabsState.js";
|
|
26
27
|
import { uiActions } from "../../../store/ui/index.js";
|
|
27
28
|
import { userActions } from "../../../store/user/index.js";
|
|
29
|
+
import { changeDashboardTimezoneOverrideHandler } from "../../timezone/changeDashboardTimezoneOverrideHandler.js";
|
|
28
30
|
import { applyDefaultFilterView } from "../common/filterViews.js";
|
|
29
31
|
import { actionsToInitializeExistingDashboard, actionsToInitializeNewDashboard, } from "../common/stateInitializers.js";
|
|
32
|
+
import { loadAutomationTimezone } from "./loadAutomationTimezone.js";
|
|
30
33
|
import { loadCatalog } from "./loadCatalog.js";
|
|
31
34
|
import { loadDashboardList } from "./loadDashboardList.js";
|
|
32
35
|
import { loadDashboardParameters } from "./loadDashboardParameters.js";
|
|
@@ -175,8 +178,9 @@ function* loadExistingDashboard(ctx, cmd, dashboardRef) {
|
|
|
175
178
|
call(loadDateHierarchyTemplates, ctx),
|
|
176
179
|
call(loadFilterViews, ctx),
|
|
177
180
|
call(loadExportTimezone, ctx),
|
|
181
|
+
call(loadAutomationTimezone, ctx),
|
|
178
182
|
];
|
|
179
|
-
const [dashboardWithReferences, { resolvedConfig: config, additionalData: { workspaceAutomationsCount, notificationChannelsCount }, }, permissions, entitlements, user, dashboardPermissions, dateHierarchyTemplates, filterViews, exportTimezone,] = yield all(calls);
|
|
183
|
+
const [dashboardWithReferences, { resolvedConfig: config, additionalData: { workspaceAutomationsCount, notificationChannelsCount }, }, permissions, entitlements, user, dashboardPermissions, dateHierarchyTemplates, filterViews, exportTimezone, automationTimezone,] = yield all(calls);
|
|
180
184
|
const { dashboard: loadedDashboard, references: { insights }, } = dashboardWithReferences;
|
|
181
185
|
const dashboardWithFilterView = applyDefaultFilterView(loadedDashboard, filterViews, config.exportId);
|
|
182
186
|
// Resolve active tab: URL's initialTabId takes precedence, otherwise default to first tab
|
|
@@ -221,6 +225,8 @@ function* loadExistingDashboard(ctx, cmd, dashboardRef) {
|
|
|
221
225
|
return {
|
|
222
226
|
batch,
|
|
223
227
|
event,
|
|
228
|
+
// an export render takes its timezone from the export itself
|
|
229
|
+
automationTimezone: exportTimezone ? undefined : automationTimezone,
|
|
224
230
|
};
|
|
225
231
|
}
|
|
226
232
|
function* initializeNewDashboard(ctx, cmd) {
|
|
@@ -339,6 +345,20 @@ function* advancedLoader(ctx, cmd, dashboard) {
|
|
|
339
345
|
call(requestDashboardsList, ctx),
|
|
340
346
|
]);
|
|
341
347
|
}
|
|
348
|
+
/**
|
|
349
|
+
* Applies a deep-linked automation's timezone as the dashboard's timezone override. A rejection
|
|
350
|
+
* (feature disabled, invalid stored timezone) leaves the dashboard on its own timezone rather
|
|
351
|
+
* than failing the initialization.
|
|
352
|
+
*/
|
|
353
|
+
function* restoreAutomationTimezone(ctx, timezoneId, correlationId) {
|
|
354
|
+
try {
|
|
355
|
+
const event = yield call(changeDashboardTimezoneOverrideHandler, ctx, changeDashboardTimezoneOverride(timezoneId, correlationId, true));
|
|
356
|
+
yield put(event);
|
|
357
|
+
}
|
|
358
|
+
catch (reason) {
|
|
359
|
+
console.error(`Restoring the timezone "${timezoneId}" of the deep-linked automation failed`, reason);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
342
362
|
export function* initializeDashboardHandler(ctx, cmd) {
|
|
343
363
|
const { dashboardRef } = ctx;
|
|
344
364
|
try {
|
|
@@ -351,6 +371,12 @@ export function* initializeDashboardHandler(ctx, cmd) {
|
|
|
351
371
|
result = (yield call(initializeNewDashboard, ctx, cmd));
|
|
352
372
|
}
|
|
353
373
|
yield put(result.batch);
|
|
374
|
+
// before the loading success that lets the widgets render and execute, so the notification
|
|
375
|
+
// recipient never sees the dashboard's own timezone first. The view-mode override check is
|
|
376
|
+
// bypassed: the automation was evaluated in this timezone, whatever the dashboard says now.
|
|
377
|
+
if (result.automationTimezone) {
|
|
378
|
+
yield call(restoreAutomationTimezone, ctx, result.automationTimezone, cmd.correlationId);
|
|
379
|
+
}
|
|
354
380
|
yield put(loadingActions.setLoadingSuccess());
|
|
355
381
|
yield put(result.event);
|
|
356
382
|
if (dashboardRef) {
|
package/esm/model/commandHandlers/dashboard/initializeDashboardHandler/loadAutomationTimezone.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type DashboardContext } from "../../../types/commonTypes.js";
|
|
2
|
+
/**
|
|
3
|
+
* Loads the timezone baked into the automation the dashboard is deep-linked to (the focus
|
|
4
|
+
* object's `automationId`, as used by the links in alert and scheduled-export notifications).
|
|
5
|
+
* Restoring it is what makes the dashboard match the numbers the recipient was mailed.
|
|
6
|
+
* Undefined means the dashboard's own (or workspace/organization) timezone applies.
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadAutomationTimezone(ctx: DashboardContext): Promise<string | undefined>;
|
|
9
|
+
//# sourceMappingURL=loadAutomationTimezone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadAutomationTimezone.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/dashboard/initializeDashboardHandler/loadAutomationTimezone.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEtE;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAmB/F"}
|
package/esm/model/commandHandlers/dashboard/initializeDashboardHandler/loadAutomationTimezone.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { getAutomationTimezone } from "../../../../_staging/automation/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Loads the timezone baked into the automation the dashboard is deep-linked to (the focus
|
|
5
|
+
* object's `automationId`, as used by the links in alert and scheduled-export notifications).
|
|
6
|
+
* Restoring it is what makes the dashboard match the numbers the recipient was mailed.
|
|
7
|
+
* Undefined means the dashboard's own (or workspace/organization) timezone applies.
|
|
8
|
+
*/
|
|
9
|
+
export async function loadAutomationTimezone(ctx) {
|
|
10
|
+
const { automationId } = ctx.config?.focusObject ?? {};
|
|
11
|
+
if (!automationId) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
// the service getter itself throws on backends without automation support
|
|
16
|
+
const automation = await ctx.backend
|
|
17
|
+
.workspace(ctx.workspace)
|
|
18
|
+
.automations()
|
|
19
|
+
.getAutomation(automationId);
|
|
20
|
+
return getAutomationTimezone(automation);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
// a missing or inaccessible automation must not fail the dashboard load
|
|
24
|
+
console.error("Loading of the automation timezone failed", error);
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"changeDashboardTimezoneOverrideHandler.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/timezone/changeDashboardTimezoneOverrideHandler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAK/C,OAAO,EAAE,KAAK,gCAAgC,EAAE,MAAM,4BAA4B,CAAC;AAEnF,OAAO,EACH,KAAK,iCAAiC,EAEzC,MAAM,0BAA0B,CAAC;AAOlC,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"changeDashboardTimezoneOverrideHandler.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/timezone/changeDashboardTimezoneOverrideHandler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAK/C,OAAO,EAAE,KAAK,gCAAgC,EAAE,MAAM,4BAA4B,CAAC;AAEnF,OAAO,EACH,KAAK,iCAAiC,EAEzC,MAAM,0BAA0B,CAAC;AAOlC,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,wBAAiB,sCAAsC,CACnD,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,gCAAgC,GACtC,YAAY,CAAC,iCAAiC,CAAC,CAuCjD"}
|
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
// (C) 2026 GoodData Corporation
|
|
2
2
|
import { put, select } from "redux-saga/effects";
|
|
3
|
-
import { resolveTimezoneId } from "@gooddata/sdk-model";
|
|
3
|
+
import { isValidIanaTimezoneId, resolveTimezoneId } from "@gooddata/sdk-model";
|
|
4
4
|
import { invalidArgumentsProvided } from "../../events/general.js";
|
|
5
5
|
import { dashboardTimezoneOverrideChanged, } from "../../events/timezone.js";
|
|
6
6
|
import { selectEnableTimezoneChange } from "../../store/config/configSelectors.js";
|
|
7
7
|
import { selectDashboardTimezoneConfig, selectEffectiveDashboardTimezone, } from "../../store/meta/metaSelectors.js";
|
|
8
8
|
import { uiActions } from "../../store/ui/index.js";
|
|
9
|
-
function isValidIanaTimezoneId(timezoneId) {
|
|
10
|
-
try {
|
|
11
|
-
new Intl.DateTimeFormat(undefined, { timeZone: timezoneId });
|
|
12
|
-
return true;
|
|
13
|
-
}
|
|
14
|
-
catch {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
9
|
export function* changeDashboardTimezoneOverrideHandler(ctx, cmd) {
|
|
19
10
|
// the gating protects paths that arrive from outside the UI (e.g. the embedding
|
|
20
11
|
// setTimezone postMessage), which do not go through the menu-item visibility checks
|
|
@@ -23,7 +14,7 @@ export function* changeDashboardTimezoneOverrideHandler(ctx, cmd) {
|
|
|
23
14
|
throw invalidArgumentsProvided(ctx, cmd, "Cannot change the timezone override: the dashboard timezone feature is disabled.");
|
|
24
15
|
}
|
|
25
16
|
const timezoneConfig = yield select(selectDashboardTimezoneConfig);
|
|
26
|
-
if (timezoneConfig?.allowUserOverrideInViewMode !== true) {
|
|
17
|
+
if (!cmd.payload.bypassUserOverrideCheck && timezoneConfig?.allowUserOverrideInViewMode !== true) {
|
|
27
18
|
throw invalidArgumentsProvided(ctx, cmd, "Cannot change the timezone override: the dashboard's timezone configuration does not allow user overrides in view mode.");
|
|
28
19
|
}
|
|
29
20
|
// the model layer is the single resolution point of the browser-detected sentinel for the
|
|
@@ -11,6 +11,12 @@ export interface IChangeDashboardTimezoneOverridePayload {
|
|
|
11
11
|
* the dashboard/workspace configuration applies again.
|
|
12
12
|
*/
|
|
13
13
|
readonly timezoneId: string | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Skips the check that the dashboard's timezone configuration allows user overrides in view
|
|
16
|
+
* mode, for restoring a timezone the platform already committed to (an export render, an
|
|
17
|
+
* automation deep link). The dashboard timezone feature flag is still honored.
|
|
18
|
+
*/
|
|
19
|
+
readonly bypassUserOverrideCheck?: boolean;
|
|
14
20
|
}
|
|
15
21
|
/**
|
|
16
22
|
* @alpha
|
|
@@ -29,14 +35,16 @@ export interface IChangeDashboardTimezoneOverride extends IDashboardCommand {
|
|
|
29
35
|
*
|
|
30
36
|
* The command is rejected when the ad-hoc override is not allowed: the dashboard timezone
|
|
31
37
|
* feature is disabled or the dashboard's timezone configuration does not allow user overrides
|
|
32
|
-
* in view mode
|
|
38
|
+
* in view mode — the latter bypassable via `bypassUserOverrideCheck`.
|
|
33
39
|
*
|
|
34
40
|
* @param timezoneId - concrete IANA timezone id, the BROWSER_DETECTED sentinel (resolved to the
|
|
35
41
|
* viewer's browser timezone by the handler), or undefined to clear the override
|
|
36
42
|
* @param correlationId - specify correlation id to use for this command. this will be included in all
|
|
37
43
|
* events that will be emitted during the command processing
|
|
44
|
+
* @param bypassUserOverrideCheck - see
|
|
45
|
+
* {@link IChangeDashboardTimezoneOverridePayload.bypassUserOverrideCheck}
|
|
38
46
|
*
|
|
39
47
|
* @alpha
|
|
40
48
|
*/
|
|
41
|
-
export declare function changeDashboardTimezoneOverride(timezoneId: string | undefined, correlationId?: string): IChangeDashboardTimezoneOverride;
|
|
49
|
+
export declare function changeDashboardTimezoneOverride(timezoneId: string | undefined, correlationId?: string, bypassUserOverrideCheck?: boolean): IChangeDashboardTimezoneOverride;
|
|
42
50
|
//# sourceMappingURL=timezone.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timezone.d.ts","sourceRoot":"","sources":["../../../src/model/commands/timezone.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD;;;;GAIG;AACH,MAAM,WAAW,uCAAuC;IACpD;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"timezone.d.ts","sourceRoot":"","sources":["../../../src/model/commands/timezone.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD;;;;GAIG;AACH,MAAM,WAAW,uCAAuC;IACpD;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAExC;;;;OAIG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAC9C;AAED;;GAEG;AACH,MAAM,WAAW,gCAAiC,SAAQ,iBAAiB;IACvE,QAAQ,CAAC,IAAI,EAAE,uCAAuC,CAAC;IACvD,QAAQ,CAAC,OAAO,EAAE,uCAAuC,CAAC;CAC7D;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,+BAA+B,CAC3C,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,aAAa,CAAC,EAAE,MAAM,EACtB,uBAAuB,CAAC,EAAE,OAAO,GAClC,gCAAgC,CASlC"}
|
|
@@ -9,21 +9,24 @@
|
|
|
9
9
|
*
|
|
10
10
|
* The command is rejected when the ad-hoc override is not allowed: the dashboard timezone
|
|
11
11
|
* feature is disabled or the dashboard's timezone configuration does not allow user overrides
|
|
12
|
-
* in view mode
|
|
12
|
+
* in view mode — the latter bypassable via `bypassUserOverrideCheck`.
|
|
13
13
|
*
|
|
14
14
|
* @param timezoneId - concrete IANA timezone id, the BROWSER_DETECTED sentinel (resolved to the
|
|
15
15
|
* viewer's browser timezone by the handler), or undefined to clear the override
|
|
16
16
|
* @param correlationId - specify correlation id to use for this command. this will be included in all
|
|
17
17
|
* events that will be emitted during the command processing
|
|
18
|
+
* @param bypassUserOverrideCheck - see
|
|
19
|
+
* {@link IChangeDashboardTimezoneOverridePayload.bypassUserOverrideCheck}
|
|
18
20
|
*
|
|
19
21
|
* @alpha
|
|
20
22
|
*/
|
|
21
|
-
export function changeDashboardTimezoneOverride(timezoneId, correlationId) {
|
|
23
|
+
export function changeDashboardTimezoneOverride(timezoneId, correlationId, bypassUserOverrideCheck) {
|
|
22
24
|
return {
|
|
23
25
|
type: "GDC.DASH/CMD.CHANGE_TIMEZONE_OVERRIDE",
|
|
24
26
|
correlationId,
|
|
25
27
|
payload: {
|
|
26
28
|
timezoneId,
|
|
29
|
+
...(bypassUserOverrideCheck ? { bypassUserOverrideCheck } : {}),
|
|
27
30
|
},
|
|
28
31
|
};
|
|
29
32
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ICatalogDateDataset } from "@gooddata/sdk-model";
|
|
2
|
+
/**
|
|
3
|
+
* given all available datasets, this availability mock will pick 2 by name and associate relevance so that second one has more relevance
|
|
4
|
+
*
|
|
5
|
+
* Timeline date has greater relevance; see TimelineDateDatasetRef
|
|
6
|
+
* Activity date has lower relevance; see ActivityDateDatasetRef
|
|
7
|
+
*/
|
|
8
|
+
export declare const MockAvailabilityWithDifferentRelevance: (datasets: ICatalogDateDataset[]) => ICatalogDateDataset[];
|
|
9
|
+
/**
|
|
10
|
+
* given all available datasets, this mock will pick 2 by name and ensure they have same relevance
|
|
11
|
+
*/
|
|
12
|
+
export declare const MockAvailabilityWithSameRelevance: (datasets: ICatalogDateDataset[]) => ICatalogDateDataset[];
|
|
13
|
+
export declare const ActivityDateDatasetRef: import("@gooddata/sdk-model").IdentifierRef;
|
|
14
|
+
//# sourceMappingURL=CatalogAvailability.fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CatalogAvailability.fixtures.d.ts","sourceRoot":"","sources":["../../../src/model/fixtures/CatalogAvailability.fixtures.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,mBAAmB,EAAS,MAAM,qBAAqB,CAAC;AAuBtE;;;;;GAKG;AACH,eAAO,MAAM,sCAAsC,4DAclD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iCAAiC,4DAY7C,CAAC;AAEF,eAAO,MAAM,sBAAsB,6CAA4C,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// (C) 2021-2026 GoodData Corporation
|
|
2
|
+
import { invariant } from "ts-invariant";
|
|
3
|
+
import { idRef } from "@gooddata/sdk-model";
|
|
4
|
+
/*
|
|
5
|
+
* The catalog availability mocks for date dataset queries.
|
|
6
|
+
*
|
|
7
|
+
* Normally the recorded backend from mockingbird returns all data sets available in the catalog as available. Mockingbird
|
|
8
|
+
* allows to customize filtering functions to 'simulate' the availability.
|
|
9
|
+
*
|
|
10
|
+
* Here are a couple of functions that you can use.
|
|
11
|
+
*
|
|
12
|
+
* To set up DashboardTester you can do something like:
|
|
13
|
+
*
|
|
14
|
+
* const Tester = DashboardTester.forRecording(
|
|
15
|
+
* ComplexDashboardIdentifier,
|
|
16
|
+
* {},
|
|
17
|
+
* {
|
|
18
|
+
* catalogAvailability: {
|
|
19
|
+
* availableDateDatasets: MockAvailabilityWithDifferentRelevance,
|
|
20
|
+
* },
|
|
21
|
+
* },
|
|
22
|
+
* );
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* given all available datasets, this availability mock will pick 2 by name and associate relevance so that second one has more relevance
|
|
26
|
+
*
|
|
27
|
+
* Timeline date has greater relevance; see TimelineDateDatasetRef
|
|
28
|
+
* Activity date has lower relevance; see ActivityDateDatasetRef
|
|
29
|
+
*/
|
|
30
|
+
export const MockAvailabilityWithDifferentRelevance = (datasets) => {
|
|
31
|
+
const available = datasets
|
|
32
|
+
.filter((d) => ["Activity", "Timeline"].includes(d.dataSet.title))
|
|
33
|
+
.map((d) => {
|
|
34
|
+
return {
|
|
35
|
+
...d,
|
|
36
|
+
relevance: d.dataSet.title === "Timeline" ? 1 : 0,
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
invariant(available.length === 2, "unexpected mock");
|
|
40
|
+
return available;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* given all available datasets, this mock will pick 2 by name and ensure they have same relevance
|
|
44
|
+
*/
|
|
45
|
+
export const MockAvailabilityWithSameRelevance = (datasets) => {
|
|
46
|
+
const available = datasets
|
|
47
|
+
.filter((d) => ["Activity", "Timeline"].includes(d.dataSet.title))
|
|
48
|
+
.map((d) => {
|
|
49
|
+
return {
|
|
50
|
+
...d,
|
|
51
|
+
relevance: 1,
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
invariant(available.length === 2, "unexpected mock");
|
|
55
|
+
return available;
|
|
56
|
+
};
|
|
57
|
+
export const ActivityDateDatasetRef = idRef("dt_activity_timestamp", "dataSet");
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type IDashboardWithReferences } from "@gooddata/sdk-backend-spi";
|
|
2
|
+
import { type IDashboardAttributeFilter, type IDashboardDateFilter, type IFilterContext, type IInsightWidget, type IKpiWidget, type IListedDashboard } from "@gooddata/sdk-model";
|
|
3
|
+
/**
|
|
4
|
+
* A more complex dashboard that has 3 sections (rows).
|
|
5
|
+
*
|
|
6
|
+
* Two attribute filters: Region & Product
|
|
7
|
+
* First row: 6 KPIs, first three without date filtering, second three with full filtering
|
|
8
|
+
* Second row: two tables; same tables, each with 3 measures. first without any filtering whatsoever but with all drills; second with date filter and no attribute filtering, no drills
|
|
9
|
+
* Third row: single heatmap with all filters applied
|
|
10
|
+
*/
|
|
11
|
+
export declare const ComplexDashboardIdentifier = "e6473e57-1914-46ec-9cb9-5611f1298100";
|
|
12
|
+
export declare const ComplexDashboardWithReferences: IDashboardWithReferences;
|
|
13
|
+
export declare const ComplexDashboardFilterContext: IFilterContext;
|
|
14
|
+
/**
|
|
15
|
+
* Contains breakdown of the complex dashboard's filters context. There is date filter and
|
|
16
|
+
* two attribute filters. For each attribute filter the entry contains both the full filter
|
|
17
|
+
* definition and then uriRef and idRef of the display form used in the attribute filter.
|
|
18
|
+
*/
|
|
19
|
+
export declare const ComplexDashboardFilters: {
|
|
20
|
+
Date: IDashboardDateFilter;
|
|
21
|
+
FirstAttribute: {
|
|
22
|
+
filter: IDashboardAttributeFilter;
|
|
23
|
+
idRef: import("@gooddata/sdk-model").IdentifierRef;
|
|
24
|
+
sampleElementValue: string;
|
|
25
|
+
};
|
|
26
|
+
SecondAttribute: {
|
|
27
|
+
filter: IDashboardAttributeFilter;
|
|
28
|
+
idRef: import("@gooddata/sdk-model").IdentifierRef;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
export declare const ComplexDashboardLayout: import("@gooddata/sdk-model").IDashboardLayout<import("@gooddata/sdk-model").IDashboardWidget>;
|
|
32
|
+
export declare const ComplexDashboardWidgets: {
|
|
33
|
+
FirstSection: {
|
|
34
|
+
/**
|
|
35
|
+
* KPI with date filter disabled
|
|
36
|
+
*/
|
|
37
|
+
FirstKpi: IKpiWidget;
|
|
38
|
+
/**
|
|
39
|
+
* KPI with all filters disabled
|
|
40
|
+
*/
|
|
41
|
+
ThirdKpi: IKpiWidget;
|
|
42
|
+
/**
|
|
43
|
+
* KPI with all filters enabled
|
|
44
|
+
*/
|
|
45
|
+
LastKpi: IKpiWidget;
|
|
46
|
+
};
|
|
47
|
+
SecondSection: {
|
|
48
|
+
FirstTable: IInsightWidget;
|
|
49
|
+
SecondTable: IInsightWidget;
|
|
50
|
+
};
|
|
51
|
+
ThirdSection: {
|
|
52
|
+
Heatmap: IInsightWidget;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
export declare const ComplexDashboardListed: IListedDashboard;
|
|
56
|
+
//# sourceMappingURL=ComplexDashboard.fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComplexDashboard.fixtures.d.ts","sourceRoot":"","sources":["../../../src/model/fixtures/ComplexDashboard.fixtures.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,EACH,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,gBAAgB,EAExB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,yCAAyC,CAAC;AACjF,eAAO,MAAM,8BAA8B,0BAEV,CAAC;AAClC,eAAO,MAAM,6BAA6B,gBACL,CAAC;AAEtC;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;CAWnC,CAAC;AAEF,eAAO,MAAM,sBAAsB,gGAAmD,CAAC;AAEvF,eAAO,MAAM,uBAAuB;;QAE5B;;WAEG;;QAEH;;WAEG;;QAEH;;WAEG;;;;;;;;;;CAaV,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,gBAWpC,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// (C) 2021-2026 GoodData Corporation
|
|
2
|
+
import { ReferenceRecordings } from "@gooddata/reference-workspace";
|
|
3
|
+
import { idRef, } from "@gooddata/sdk-model";
|
|
4
|
+
/**
|
|
5
|
+
* A more complex dashboard that has 3 sections (rows).
|
|
6
|
+
*
|
|
7
|
+
* Two attribute filters: Region & Product
|
|
8
|
+
* First row: 6 KPIs, first three without date filtering, second three with full filtering
|
|
9
|
+
* Second row: two tables; same tables, each with 3 measures. first without any filtering whatsoever but with all drills; second with date filter and no attribute filtering, no drills
|
|
10
|
+
* Third row: single heatmap with all filters applied
|
|
11
|
+
*/
|
|
12
|
+
export const ComplexDashboardIdentifier = "e6473e57-1914-46ec-9cb9-5611f1298100";
|
|
13
|
+
export const ComplexDashboardWithReferences = ReferenceRecordings.Recordings.metadata?.dashboards?.["dash_e6473e57_1914_46ec_9cb9_5611f1298100"].obj;
|
|
14
|
+
export const ComplexDashboardFilterContext = ComplexDashboardWithReferences.dashboard
|
|
15
|
+
.filterContext;
|
|
16
|
+
/**
|
|
17
|
+
* Contains breakdown of the complex dashboard's filters context. There is date filter and
|
|
18
|
+
* two attribute filters. For each attribute filter the entry contains both the full filter
|
|
19
|
+
* definition and then uriRef and idRef of the display form used in the attribute filter.
|
|
20
|
+
*/
|
|
21
|
+
export const ComplexDashboardFilters = {
|
|
22
|
+
Date: ComplexDashboardFilterContext.filters[0],
|
|
23
|
+
FirstAttribute: {
|
|
24
|
+
filter: ComplexDashboardFilterContext.filters[1],
|
|
25
|
+
idRef: idRef("f_owner.region_id"),
|
|
26
|
+
sampleElementValue: "East Coast",
|
|
27
|
+
},
|
|
28
|
+
SecondAttribute: {
|
|
29
|
+
filter: ComplexDashboardFilterContext.filters[2],
|
|
30
|
+
idRef: idRef("attr.f_product.product"),
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
export const ComplexDashboardLayout = ComplexDashboardWithReferences.dashboard.layout;
|
|
34
|
+
export const ComplexDashboardWidgets = {
|
|
35
|
+
FirstSection: {
|
|
36
|
+
/**
|
|
37
|
+
* KPI with date filter disabled
|
|
38
|
+
*/
|
|
39
|
+
FirstKpi: ComplexDashboardWithReferences.dashboard.layout.sections[0].items[0].widget,
|
|
40
|
+
/**
|
|
41
|
+
* KPI with all filters disabled
|
|
42
|
+
*/
|
|
43
|
+
ThirdKpi: ComplexDashboardWithReferences.dashboard.layout.sections[0].items[2].widget,
|
|
44
|
+
/**
|
|
45
|
+
* KPI with all filters enabled
|
|
46
|
+
*/
|
|
47
|
+
LastKpi: ComplexDashboardWithReferences.dashboard.layout.sections[0].items[5].widget,
|
|
48
|
+
},
|
|
49
|
+
SecondSection: {
|
|
50
|
+
FirstTable: ComplexDashboardWithReferences.dashboard.layout.sections[1].items[0]
|
|
51
|
+
.widget,
|
|
52
|
+
SecondTable: ComplexDashboardWithReferences.dashboard.layout.sections[1].items[1]
|
|
53
|
+
.widget,
|
|
54
|
+
},
|
|
55
|
+
ThirdSection: {
|
|
56
|
+
Heatmap: ComplexDashboardWithReferences.dashboard.layout.sections[2].items[0]
|
|
57
|
+
.widget,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
export const ComplexDashboardListed = {
|
|
61
|
+
ref: ComplexDashboardWithReferences.dashboard.ref,
|
|
62
|
+
identifier: ComplexDashboardWithReferences.dashboard.identifier,
|
|
63
|
+
uri: ComplexDashboardWithReferences.dashboard.uri,
|
|
64
|
+
title: ComplexDashboardWithReferences.dashboard.title,
|
|
65
|
+
description: ComplexDashboardWithReferences.dashboard.description,
|
|
66
|
+
updated: ComplexDashboardWithReferences.dashboard.updated,
|
|
67
|
+
created: ComplexDashboardWithReferences.dashboard.created,
|
|
68
|
+
tags: ComplexDashboardWithReferences.dashboard.tags,
|
|
69
|
+
shareStatus: ComplexDashboardWithReferences.dashboard.shareStatus,
|
|
70
|
+
availability: "full",
|
|
71
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type IDashboardWithReferences } from "@gooddata/sdk-backend-spi";
|
|
2
|
+
export declare const TestCorrelation = "testCorrelationId";
|
|
3
|
+
export declare const TestStash = "testStash";
|
|
4
|
+
export declare const BeforeTestCorrelation = "beforeTestId";
|
|
5
|
+
/**
|
|
6
|
+
* Empty dashboard. No filter context, empty layout.
|
|
7
|
+
*/
|
|
8
|
+
export declare const EmptyDashboardIdentifier = "emptyDashboard";
|
|
9
|
+
export declare const EmptyDashboardWithReferences: IDashboardWithReferences;
|
|
10
|
+
//# sourceMappingURL=Dashboard.fixtures.d.ts.map
|