@gooddata/sdk-ui-dashboard 11.66.0-alpha.1 → 11.66.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +262 -343
- package/esm/__version.d.ts +1 -1
- package/esm/__version.d.ts.map +1 -1
- package/esm/__version.js +1 -1
- package/esm/_staging/dashboard/dashboardTitle.d.ts +7 -0
- package/esm/_staging/dashboard/dashboardTitle.d.ts.map +1 -0
- package/esm/_staging/dashboard/dashboardTitle.js +21 -0
- package/esm/internal.d.ts +1 -1
- package/esm/internal.d.ts.map +1 -1
- package/esm/internal.js +1 -1
- package/esm/model/commandHandlers/dashboard/saveAsDashboardHandler.d.ts.map +1 -1
- package/esm/model/commandHandlers/dashboard/saveAsDashboardHandler.js +3 -1
- package/esm/model/commandHandlers/drill/keyDriverAnalysisHandler.js +1 -1
- package/esm/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.d.ts.map +1 -1
- package/esm/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.js +3 -3
- package/esm/model/commandHandlers/filterContext/filterViewHandler.js +3 -3
- package/esm/model/commandHandlers/parameters/changeParameterValuesHandler.js +2 -2
- package/esm/model/commands/dashboard.d.ts +3 -1
- package/esm/model/commands/dashboard.d.ts.map +1 -1
- package/esm/model/commands/dashboard.js +2 -1
- package/esm/model/commands/filters.d.ts +18 -4
- package/esm/model/commands/filters.d.ts.map +1 -1
- package/esm/model/commands/filters.js +3 -2
- package/esm/model/commands/parameters.d.ts +4 -4
- package/esm/model/commands/parameters.d.ts.map +1 -1
- package/esm/model/commands/parameters.js +2 -2
- package/esm/model/store/tabs/layout/layoutSelectors.d.ts +7 -0
- package/esm/model/store/tabs/layout/layoutSelectors.d.ts.map +1 -1
- package/esm/model/store/tabs/layout/layoutSelectors.js +7 -0
- package/esm/model/store/topBar/topBarSelectors.d.ts +7 -0
- package/esm/model/store/topBar/topBarSelectors.d.ts.map +1 -1
- package/esm/model/store/topBar/topBarSelectors.js +10 -1
- package/esm/model/store/widgetDrills/widgetDrillSelectors.d.ts +2 -1
- package/esm/model/store/widgetDrills/widgetDrillSelectors.d.ts.map +1 -1
- package/esm/model/store/widgetDrills/widgetDrillSelectors.js +1 -1
- package/esm/presentation/automations/alerting/utils/transformation.d.ts.map +1 -1
- package/esm/presentation/automations/alerting/utils/transformation.js +5 -3
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/SubjectForm/SubjectForm.d.ts.map +1 -1
- package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/SubjectForm/SubjectForm.js +2 -4
- package/esm/presentation/drill/DrillSelect/DrillSelectDropdown.d.ts.map +1 -1
- package/esm/presentation/drill/DrillSelect/DrillSelectDropdown.js +4 -2
- package/esm/presentation/drill/utils/kdaUtils.d.ts +1 -1
- package/esm/presentation/drill/utils/kdaUtils.d.ts.map +1 -1
- package/esm/presentation/drill/utils/kdaUtils.js +25 -26
- package/esm/presentation/saveAs/DefaultSaveAsDialog/SaveAsDialogRenderer.d.ts.map +1 -1
- package/esm/presentation/saveAs/DefaultSaveAsDialog/SaveAsDialogRenderer.js +7 -4
- package/esm/presentation/saveAs/DefaultSaveAsDialog/useSaveAs.d.ts.map +1 -1
- package/esm/presentation/saveAs/DefaultSaveAsDialog/useSaveAs.js +3 -1
- package/esm/presentation/topBar/buttonBar/button/saveAsButton/DefaultSaveAsNewButton.d.ts.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/saveAsButton/DefaultSaveAsNewButton.js +3 -2
- package/esm/presentation/topBar/menuButton/useDefaultMenuItems.d.ts.map +1 -1
- package/esm/presentation/topBar/menuButton/useDefaultMenuItems.js +2 -4
- package/esm/presentation/topBar/title/EditableTitle.js +1 -1
- package/esm/sdk-ui-dashboard.d.ts +26 -10
- package/package.json +24 -24
- package/styles/css/main.css +1 -1
- package/esm/presentation/constants/dashboard.d.ts +0 -2
- package/esm/presentation/constants/dashboard.d.ts.map +0 -1
- package/esm/presentation/constants/dashboard.js +0 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type IAttributeDescriptor, type ICatalogAttribute, type ICatalogDateAttribute, type IDrillDownReference, type ObjRef } from "@gooddata/sdk-model";
|
|
1
|
+
import { type IAttributeDescriptor, type ICatalogAttribute, type ICatalogDateAttribute, type IDrillDownReference, type IInsight, type ObjRef } from "@gooddata/sdk-model";
|
|
2
2
|
import { type ExplicitDrill, type IAvailableDrillTargets, type IHeaderPredicate } from "@gooddata/sdk-ui";
|
|
3
3
|
import { type ObjRefMap } from "../../../_staging/metadata/objRefMap.js";
|
|
4
4
|
import { type DashboardDrillDefinition, type IDrillToUrlAttributeDefinition, type IGlobalDrillDownAttributeHierarchyDefinition } from "../../../types.js";
|
|
@@ -83,4 +83,5 @@ export declare const selectImplicitDrillsByAvailableDrillTargets: (availableDril
|
|
|
83
83
|
* @internal
|
|
84
84
|
*/
|
|
85
85
|
export declare const selectDrillableItemsByAvailableDrillTargets: (availableDrillTargets: IAvailableDrillTargets | undefined, ignoredDrillDownHierarchies: IDrillDownReference[] | undefined, disableDrillIntoURL: boolean | undefined, disableDrillDown?: boolean) => DashboardSelector<IHeaderPredicate[]>;
|
|
86
|
+
export declare function getMetricDisabled(insight: IInsight | undefined | null, localIdentifier: string): boolean;
|
|
86
87
|
//# sourceMappingURL=widgetDrillSelectors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widgetDrillSelectors.d.ts","sourceRoot":"","sources":["../../../../src/model/store/widgetDrills/widgetDrillSelectors.ts"],"names":[],"mappings":"AAMA,OAAO,EAIH,KAAK,oBAAoB,EAEzB,KAAK,iBAAiB,EAEtB,KAAK,qBAAqB,EAE1B,KAAK,mBAAmB,
|
|
1
|
+
{"version":3,"file":"widgetDrillSelectors.d.ts","sourceRoot":"","sources":["../../../../src/model/store/widgetDrills/widgetDrillSelectors.ts"],"names":[],"mappings":"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"}
|
|
@@ -515,6 +515,6 @@ export const selectDrillableItemsByAvailableDrillTargets = createMemoizedSelecto
|
|
|
515
515
|
...restrictedDrillDownPredicates(restrictedDrillDowns),
|
|
516
516
|
];
|
|
517
517
|
}));
|
|
518
|
-
function getMetricDisabled(insight, localIdentifier) {
|
|
518
|
+
export function getMetricDisabled(insight, localIdentifier) {
|
|
519
519
|
return (insight?.insight.properties?.["controls"]?.["disableKeyDriveAnalysisOn"]?.[localIdentifier] ?? false);
|
|
520
520
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transformation.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/automations/alerting/utils/transformation.ts"],"names":[],"mappings":"AAKA,OAAO,EACH,KAAK,wBAAwB,EAC7B,KAAK,iCAAiC,EACtC,KAAK,iCAAiC,EACtC,KAAK,wBAAwB,EAC7B,KAAK,gCAAgC,EACrC,KAAK,sBAAsB,EAG3B,KAAK,yBAAyB,EAC9B,KAAK,mCAAmC,EAGxC,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EAKzB,KAAK,SAAS,EAOjB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACH,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC1B,yBAAyB,EAC5B,MAAM,aAAa,CAAC;AAGrB,OAAO,EACH,KAAK,iBAAiB,
|
|
1
|
+
{"version":3,"file":"transformation.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/automations/alerting/utils/transformation.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import { isArithmeticMeasure, isLocalIdRef, isMeasureValueFilter, isRankingFilte
|
|
|
5
5
|
import { ARITHMETIC_OPERATORS, COMPARISON_OPERATORS, RELATIVE_OPERATORS } from "@gooddata/sdk-ui-ext";
|
|
6
6
|
import { AlertMetricComparatorType, } from "../types.js";
|
|
7
7
|
import { createCronFromGranularity } from "./cron.js";
|
|
8
|
-
import { getAttributeRelatedFilterInfo, getMeasureFormat, getMeasureTitle, } from "./getters.js";
|
|
8
|
+
import { getAlertComparison, getAttributeRelatedFilterInfo, getMeasureFormat, getMeasureTitle, } from "./getters.js";
|
|
9
9
|
//alerts transformations
|
|
10
10
|
/**
|
|
11
11
|
* This function transforms alert by metric. It changes title, condition and execution based on selected metric.
|
|
@@ -17,8 +17,10 @@ import { getAttributeRelatedFilterInfo, getMeasureFormat, getMeasureTitle, } fro
|
|
|
17
17
|
* @param timezone - timezone for relative date filter
|
|
18
18
|
*/
|
|
19
19
|
export function transformAlertByMetric(metrics, alert, measure, measureFormatMap, weekStart, timezone) {
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
// filter changes call this with the same metric, so keep the alert's comparison
|
|
21
|
+
const periodMeasure = getAlertComparison(measure, alert.alert) ??
|
|
22
|
+
measure.comparators.find((c) => c.comparator === AlertMetricComparatorType.PreviousPeriod ||
|
|
23
|
+
c.comparator === AlertMetricComparatorType.SamePeriodPreviousYear);
|
|
22
24
|
if (alert.alert?.condition.type === "anomalyDetection" && periodMeasure?.dataset) {
|
|
23
25
|
const cond = transformToAnomalyDetectionCondition(alert.alert.condition, periodMeasure);
|
|
24
26
|
const condition = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubjectForm.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/SubjectForm/SubjectForm.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,iCAAiC,EAAE,MAAM,mBAAmB,CAAC;AAK3E,wBAAgB,WAAW,CAAC,EACxB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,QAAQ,EACR,eAAe,GAClB,EAAE,iCAAiC,
|
|
1
|
+
{"version":3,"file":"SubjectForm.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/SubjectForm/SubjectForm.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,iCAAiC,EAAE,MAAM,mBAAmB,CAAC;AAK3E,wBAAgB,WAAW,CAAC,EACxB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,QAAQ,EACR,eAAe,GAClB,EAAE,iCAAiC,2CA0FnC"}
|
|
@@ -4,7 +4,7 @@ import { useCallback } from "react";
|
|
|
4
4
|
import { useIntl } from "react-intl";
|
|
5
5
|
import { ValidationContextStore, createInvalidDatapoint, createInvalidNode, useValidationContextValue, } from "@gooddata/sdk-ui";
|
|
6
6
|
import { Input, useIdPrefixed } from "@gooddata/sdk-ui-kit";
|
|
7
|
-
import {
|
|
7
|
+
import { truncateDashboardTitle } from "../../../../../../_staging/dashboard/dashboardTitle.js";
|
|
8
8
|
import { ErrorWrapper } from "../ErrorWrapper/ErrorWrapper.js";
|
|
9
9
|
const MAX_SUBJECT_LENGTH = 255;
|
|
10
10
|
export function SubjectForm({ dashboardTitle, editedAutomation, isSubmitDisabled, onChange, onKeyDownSubmit, }) {
|
|
@@ -39,9 +39,7 @@ export function SubjectForm({ dashboardTitle, editedAutomation, isSubmitDisabled
|
|
|
39
39
|
const handleOnBlur = useCallback((e) => {
|
|
40
40
|
setHasError(!isValueValid(e.target.value));
|
|
41
41
|
}, [isValueValid, setHasError]);
|
|
42
|
-
return (_jsx(ValidationContextStore, { value: validationContextValue, children: _jsx(ErrorWrapper, { errorId: errorId, errorMessage: invalidDatapoint?.message ?? null, label: formatMessage({ id: "dialogs.schedule.email.subject.label" }), labelId: labelId, className: "gd-input-component gd-notifications-channels-dialog-subject s-gd-notifications-channels-dialog-subject", labelWrapperClassName: "gd-notifications-channels-dialog-subject-wrapper", errorClassName: "gd-notifications-channels-dialog-subject-error", children: _jsx(Input, { id: labelId, hasError: !isValid, maxlength: 300, type: "text", placeholder: dashboardTitle.
|
|
43
|
-
? dashboardTitle.substring(0, DASHBOARD_TITLE_MAX_LENGTH)
|
|
44
|
-
: dashboardTitle, value: editedAutomation.details?.subject ?? "", onChange:
|
|
42
|
+
return (_jsx(ValidationContextStore, { value: validationContextValue, children: _jsx(ErrorWrapper, { errorId: errorId, errorMessage: invalidDatapoint?.message ?? null, label: formatMessage({ id: "dialogs.schedule.email.subject.label" }), labelId: labelId, className: "gd-input-component gd-notifications-channels-dialog-subject s-gd-notifications-channels-dialog-subject", labelWrapperClassName: "gd-notifications-channels-dialog-subject-wrapper", errorClassName: "gd-notifications-channels-dialog-subject-error", children: _jsx(Input, { id: labelId, hasError: !isValid, maxlength: 300, type: "text", placeholder: truncateDashboardTitle(dashboardTitle), value: editedAutomation.details?.subject ?? "", onChange:
|
|
45
43
|
// as any, the value will indeed always be string
|
|
46
44
|
// TODO improve typings of Input in ui-kit to have properly typed the onChange related to the input type
|
|
47
45
|
handleOnChange, onEnterKeyPress: () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DrillSelectDropdown.d.ts","sourceRoot":"","sources":["../../../../src/presentation/drill/DrillSelect/DrillSelectDropdown.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,SAAS,EAAW,MAAM,YAAY,CAAC;AAGrD,OAAO,EACH,KAAK,mCAAmC,EACxC,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,OAAO,
|
|
1
|
+
{"version":3,"file":"DrillSelectDropdown.d.ts","sourceRoot":"","sources":["../../../../src/presentation/drill/DrillSelect/DrillSelectDropdown.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,SAAS,EAAW,MAAM,YAAY,CAAC;AAGrD,OAAO,EACH,KAAK,mCAAmC,EACxC,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,OAAO,EAgBf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,WAAW,EAAsB,MAAM,kBAAkB,CAAC;AAIxE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAazE,OAAO,EAAE,KAAK,wBAAwB,EAAyB,MAAM,mBAAmB,CAAC;AAazF,OAAO,EAEH,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EAExB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,yBAA0B,SAAQ,mBAAmB;IAClE,mBAAmB,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,wBAAwB,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACxE;AAED,wBAAgB,mBAAmB,CAAC,EAChC,MAAM,EACN,mBAAmB,EACnB,OAAO,EACP,kBAAkB,EAClB,QAAQ,EACR,gBAAgB,EAChB,oBAAoB,EACpB,UAAU,GACb,EAAE,yBAAyB,kDA+K3B;AAgGD,eAAO,MAAM,sBAAsB,kKAWhC;IACC,iBAAiB,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,OAAO,CAAC;IAChE,gBAAgB,EAAE,wBAAwB,EAAE,CAAC;IAC7C,UAAU,EAAE,WAAW,CAAC;IACxB,QAAQ,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC9B,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,mCAAmC,CAAC,CAAC;IAC3E,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACvC,KAAG,gBAAgB,EA2JnB,CAAC"}
|
|
@@ -5,7 +5,7 @@ import stringify from "json-stable-stringify";
|
|
|
5
5
|
import { compact, groupBy, uniqBy } from "lodash-es";
|
|
6
6
|
import { useIntl } from "react-intl";
|
|
7
7
|
import { invariant } from "ts-invariant";
|
|
8
|
-
import { areObjRefsEqual, insightTitle, isAttributeDescriptor, isCrossFiltering, isDrillFromAttribute, isDrillToAttributeUrl, isDrillToCustomUrl, isDrillToDashboard, isDrillToInsight, isDrillToLegacyDashboard, isIdentifierRef, isKeyDriveAnalysis, objRefToString, } from "@gooddata/sdk-model";
|
|
8
|
+
import { areObjRefsEqual, insightTitle, isAttributeDescriptor, isCrossFiltering, isDrillFromAttribute, isDrillToAttributeUrl, isDrillToCustomUrl, isDrillToDashboard, isDrillToInsight, isDrillToLegacyDashboard, isIdentifierRef, isInsightWidget, isKeyDriveAnalysis, objRefToString, } from "@gooddata/sdk-model";
|
|
9
9
|
import { UnexpectedSdkError } from "@gooddata/sdk-ui";
|
|
10
10
|
import { Overlay, UiFocusManager, UiMenu } from "@gooddata/sdk-ui-kit";
|
|
11
11
|
import { getDrillOriginLocalIdentifier } from "../../../_staging/drills/drillingUtils.js";
|
|
@@ -17,6 +17,7 @@ import { selectInsightsMap } from "../../../model/store/insights/insightsSelecto
|
|
|
17
17
|
import { selectDashboardTitle } from "../../../model/store/meta/metaSelectors.js";
|
|
18
18
|
import { selectWidgetByRef } from "../../../model/store/tabs/layout/layoutSelectors.js";
|
|
19
19
|
import { selectIsDrillRestricted } from "../../../model/store/widgetDrills/drillRestrictionSelectors.js";
|
|
20
|
+
import { getMetricDisabled, } from "../../../model/store/widgetDrills/widgetDrillSelectors.js";
|
|
20
21
|
import { isDrillDownDefinition } from "../../../types.js";
|
|
21
22
|
import { useDrillSelectDropdownMenuItems } from "../hooks/useDrillSelectDropdownMenuItems.js";
|
|
22
23
|
import { isDrillToUrl } from "../types.js";
|
|
@@ -325,7 +326,8 @@ export const createDrillSelectItems = ({ drillDefinitions, drillEvent, insights,
|
|
|
325
326
|
};
|
|
326
327
|
}
|
|
327
328
|
if (isKeyDriveAnalysis(drillDefinition)) {
|
|
328
|
-
const
|
|
329
|
+
const widgetInsight = isInsightWidget(widget) ? insights.get(widget.insight) : undefined;
|
|
330
|
+
const items = getKdaKeyDriverCombinations(drillDefinition, drillEvent, enableSecondGranularities, (localIdentifier) => getMetricDisabled(widgetInsight, localIdentifier));
|
|
329
331
|
return items.map((item) => {
|
|
330
332
|
return {
|
|
331
333
|
name: getKeyDriverCombinationItemTitle(intl, item),
|
|
@@ -5,7 +5,7 @@ import type { IDashboardKeyDriverCombinationItem } from "../../../model/events/d
|
|
|
5
5
|
/**
|
|
6
6
|
* @internal
|
|
7
7
|
*/
|
|
8
|
-
export declare function getKdaKeyDriverCombinations(drillDefinition: IKeyDriveAnalysis, drillEvent: IDrillEvent, enableSecondGranularities?: boolean): IDashboardKeyDriverCombinationItem[];
|
|
8
|
+
export declare function getKdaKeyDriverCombinations(drillDefinition: IKeyDriveAnalysis, drillEvent: IDrillEvent, enableSecondGranularities?: boolean, isMeasureDisabled?: (localIdentifier: string) => boolean): IDashboardKeyDriverCombinationItem[];
|
|
9
9
|
/**
|
|
10
10
|
* @internal
|
|
11
11
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kdaUtils.d.ts","sourceRoot":"","sources":["../../../../src/presentation/drill/utils/kdaUtils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAEH,KAAK,iBAAiB,
|
|
1
|
+
{"version":3,"file":"kdaUtils.d.ts","sourceRoot":"","sources":["../../../../src/presentation/drill/utils/kdaUtils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAEH,KAAK,iBAAiB,EASzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAGH,KAAK,WAAW,EAgBnB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,gCAAgC,CAAC;AAGzF;;GAEG;AACH,wBAAgB,2BAA2B,CACvC,eAAe,EAAE,iBAAiB,EAClC,UAAU,EAAE,WAAW,EACvB,yBAAyB,UAAQ,EACjC,iBAAiB,GAAE,CAAC,eAAe,EAAE,MAAM,KAAK,OAAqB,GACtE,kCAAkC,EAAE,CAkEtC;AA2UD;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,kCAAkC,UAsCzG"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// (C) 2025-2026 GoodData Corporation
|
|
2
|
-
import { isAttributeDescriptor, isMeasureDescriptor, isMeasureGroupDescriptor, isYearGranularity, } from "@gooddata/sdk-model";
|
|
3
|
-
import { DataViewFacade, isAttributeScope, isDrillIntersectionAttributeItem, isDrillIntersectionDateAttributeItem, isMeasureScope, isTableMeasureValue, isValueColumnDefinition, isValueRowDefinition, } from "@gooddata/sdk-ui";
|
|
2
|
+
import { bucketMeasures, bucketsFind, isAttributeDescriptor, isMeasureDescriptor, isMeasureGroupDescriptor, isYearGranularity, measureLocalId, } from "@gooddata/sdk-model";
|
|
3
|
+
import { BucketNames, DataViewFacade, isAttributeScope, isDrillIntersectionAttributeItem, isDrillIntersectionDateAttributeItem, isMeasureScope, isTableMeasureValue, isValueColumnDefinition, isValueRowDefinition, } from "@gooddata/sdk-ui";
|
|
4
4
|
import { getKeyDriverAnalysisSupportedStringGranularities } from "../../../model/store/keyDriverAnalysis/const.js";
|
|
5
5
|
/**
|
|
6
6
|
* @internal
|
|
7
7
|
*/
|
|
8
|
-
export function getKdaKeyDriverCombinations(drillDefinition, drillEvent, enableSecondGranularities = false) {
|
|
8
|
+
export function getKdaKeyDriverCombinations(drillDefinition, drillEvent, enableSecondGranularities = false, isMeasureDisabled = () => false) {
|
|
9
9
|
//TODO: Special implementation for headline
|
|
10
10
|
const dv = DataViewFacade.for(drillEvent.dataView);
|
|
11
|
-
const combinations = findHeadersCombinations(dv, drillDefinition, drillEvent);
|
|
11
|
+
const combinations = findHeadersCombinations(dv, drillDefinition, drillEvent, isMeasureDisabled);
|
|
12
12
|
// No relevant headers
|
|
13
13
|
if (!combinations.dateHeader || !combinations.metricHeader) {
|
|
14
14
|
return [];
|
|
@@ -26,13 +26,10 @@ export function getKdaKeyDriverCombinations(drillDefinition, drillEvent, enableS
|
|
|
26
26
|
const filteredRows = filterRows(table.rowDefinitions, dimScopedValues[0], dateId);
|
|
27
27
|
const exactColumn = filterExactColumn(filteredColumns, dimScopedValues[1]);
|
|
28
28
|
const exactRow = filterExactRow(filteredRows, dimScopedValues[0]);
|
|
29
|
-
const isFirstColumn = exactColumn === filteredColumns[0];
|
|
30
|
-
const isFirstRow = exactRow === filteredRows[0];
|
|
31
|
-
const isLastColumn = exactColumn === filteredColumns[filteredColumns.length - 1];
|
|
32
|
-
const isLastRow = exactRow === filteredRows[filteredRows.length - 1];
|
|
33
29
|
const current = getCurrentValue(table.data, dateId, exactRow, exactColumn);
|
|
34
|
-
const
|
|
35
|
-
const
|
|
30
|
+
const getNeighbourValue = (direction) => getDirectionValue(table.data, dateId, current, direction, filteredRows, filteredColumns, exactRow, exactColumn);
|
|
31
|
+
const previous = getNeighbourValue(-1);
|
|
32
|
+
const next = getNeighbourValue(1);
|
|
36
33
|
const res = [];
|
|
37
34
|
// There is a previous value in graph
|
|
38
35
|
const before = createBefore(combinations, current, previous);
|
|
@@ -174,23 +171,15 @@ function getCurrentValue(data, dateId, row, column) {
|
|
|
174
171
|
const res = data[row.rowIndex]?.[column.columnIndex];
|
|
175
172
|
return mapToCurrentValue(res, dateId, row.rowIndex, column.columnIndex);
|
|
176
173
|
}
|
|
177
|
-
function getDirectionValue(data, dateId, current, direction,
|
|
178
|
-
if (!current) {
|
|
174
|
+
function getDirectionValue(data, dateId, current, direction, rows, columns, row, column) {
|
|
175
|
+
if (!current || !row || !column) {
|
|
179
176
|
return null;
|
|
180
177
|
}
|
|
181
178
|
if (current.direction === "row") {
|
|
182
|
-
|
|
183
|
-
return null;
|
|
184
|
-
}
|
|
185
|
-
const res = data[current.row + direction]?.[current.column];
|
|
186
|
-
return mapToCurrentValue(res, dateId, current.row + direction, current.column);
|
|
179
|
+
return getCurrentValue(data, dateId, rows[rows.indexOf(row) + direction], column);
|
|
187
180
|
}
|
|
188
181
|
if (current.direction === "column") {
|
|
189
|
-
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
const res = data[current.row]?.[current.column + direction];
|
|
193
|
-
return mapToCurrentValue(res, dateId, current.row, current.column + direction);
|
|
182
|
+
return getCurrentValue(data, dateId, row, columns[columns.indexOf(column) + direction]);
|
|
194
183
|
}
|
|
195
184
|
return null;
|
|
196
185
|
}
|
|
@@ -331,7 +320,7 @@ export function getKeyDriverCombinationItemTitle(intl, item) {
|
|
|
331
320
|
return intl.formatMessage({ id: "drill.kda.year_to_year" });
|
|
332
321
|
}
|
|
333
322
|
}
|
|
334
|
-
function findHeadersCombinations(dv, drillDefinition, drillEvent) {
|
|
323
|
+
function findHeadersCombinations(dv, drillDefinition, drillEvent, isMeasureDisabled) {
|
|
335
324
|
if (drillDefinition.transition !== "in-place") {
|
|
336
325
|
return {
|
|
337
326
|
dateHeader: undefined,
|
|
@@ -344,9 +333,12 @@ function findHeadersCombinations(dv, drillDefinition, drillEvent) {
|
|
|
344
333
|
const dateHeader = intersections
|
|
345
334
|
.map((intersectionElement) => intersectionElement.header)
|
|
346
335
|
.filter(isDrillIntersectionDateAttributeItem)[0];
|
|
347
|
-
const
|
|
336
|
+
const measureHeaders = intersections
|
|
348
337
|
.map((intersectionElement) => intersectionElement.header)
|
|
349
|
-
.filter(isMeasureDescriptor)
|
|
338
|
+
.filter(isMeasureDescriptor)
|
|
339
|
+
.filter((header) => !isMeasureDisabled(header.measureHeaderItem.localIdentifier));
|
|
340
|
+
const preferredMeasureIds = getPreferredMeasureIds(drillEvent);
|
|
341
|
+
const metricHeader = measureHeaders.find((header) => preferredMeasureIds.includes(header.measureHeaderItem.localIdentifier)) ?? measureHeaders[0];
|
|
350
342
|
const attributeHeaders = intersections
|
|
351
343
|
.map((intersectionElement) => intersectionElement.header)
|
|
352
344
|
.filter(isDrillIntersectionAttributeItem)
|
|
@@ -366,7 +358,7 @@ function findHeadersCombinations(dv, drillDefinition, drillEvent) {
|
|
|
366
358
|
});
|
|
367
359
|
}
|
|
368
360
|
if (isMeasureGroupDescriptor(h)) {
|
|
369
|
-
return intersections.find((i) =>
|
|
361
|
+
return intersections.find((i) => i.header === metricHeader);
|
|
370
362
|
}
|
|
371
363
|
return undefined;
|
|
372
364
|
})
|
|
@@ -378,6 +370,13 @@ function findHeadersCombinations(dv, drillDefinition, drillEvent) {
|
|
|
378
370
|
attributeHeaders,
|
|
379
371
|
};
|
|
380
372
|
}
|
|
373
|
+
function getPreferredMeasureIds(drillEvent) {
|
|
374
|
+
if (drillEvent.drillContext.type !== "mekko") {
|
|
375
|
+
return [];
|
|
376
|
+
}
|
|
377
|
+
const heightBucket = bucketsFind(drillEvent.dataView.definition.buckets, BucketNames.SECONDARY_MEASURES);
|
|
378
|
+
return heightBucket ? bucketMeasures(heightBucket).map(measureLocalId) : [];
|
|
379
|
+
}
|
|
381
380
|
function getPreviousYear(currentYear) {
|
|
382
381
|
const split = currentYear.uri.split("-");
|
|
383
382
|
split[0] = (parseInt(split[0]) - 1).toString();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SaveAsDialogRenderer.d.ts","sourceRoot":"","sources":["../../../../src/presentation/saveAs/DefaultSaveAsDialog/SaveAsDialogRenderer.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SaveAsDialogRenderer.d.ts","sourceRoot":"","sources":["../../../../src/presentation/saveAs/DefaultSaveAsDialog/SaveAsDialogRenderer.tsx"],"names":[],"mappings":"AAkBA,MAAM,WAAW,6BAA6B;IAC1C,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,EAAE,wBAAwB,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9F,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED;;GAEG;AACH,eAAO,MAAM,wBAAwB,4KAQlC,6BAA6B,6CAkF9B,CAAC;AAEH,eAAO,MAAM,wBAAwB,4KApFlC,6BAA6B,6CAoFgC,CAAC;AAEjE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,6BAA6B,2CAMxE"}
|
|
@@ -2,19 +2,22 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
// (C) 2020-2026 GoodData Corporation
|
|
3
3
|
import { memo, useCallback, useState } from "react";
|
|
4
4
|
import { compact } from "lodash-es";
|
|
5
|
-
import { useIntl } from "react-intl";
|
|
5
|
+
import { defineMessage, useIntl } from "react-intl";
|
|
6
6
|
import { ConfirmDialog, Input, Message, Typography } from "@gooddata/sdk-ui-kit";
|
|
7
|
+
import { DASHBOARD_TITLE_MAX_LENGTH, truncateDashboardTitle, } from "../../../_staging/dashboard/dashboardTitle.js";
|
|
7
8
|
import { messages } from "../../../locales.js";
|
|
8
|
-
import { DASHBOARD_TITLE_MAX_LENGTH } from "../../constants/dashboard.js";
|
|
9
9
|
import { IntlWrapper } from "../../localization/IntlWrapper.js";
|
|
10
|
+
const defaultTitleMessage = defineMessage({ id: "dialogs.save.as.new.default.title" });
|
|
10
11
|
/**
|
|
11
12
|
* @internal
|
|
12
13
|
*/
|
|
13
14
|
export const SaveAsNewDashboardDialog = memo(function SaveAsNewDashboardDialog({ onCancel = () => { }, isDashboardLoaded, isDashboardSaving, dashboardTitle: dashboardTitleProp, onSubmit, isInEditMode, isKpiWidgetEnabled, }) {
|
|
14
15
|
const intl = useIntl();
|
|
15
16
|
const getDefaultDashboardTitle = useCallback(() => {
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
// shorten only the original title so the localized "Copy of" text stays whole
|
|
18
|
+
const affixLength = intl.formatMessage(defaultTitleMessage, { title: "" }).length;
|
|
19
|
+
return intl.formatMessage(defaultTitleMessage, {
|
|
20
|
+
title: truncateDashboardTitle(dashboardTitleProp, DASHBOARD_TITLE_MAX_LENGTH - affixLength),
|
|
18
21
|
});
|
|
19
22
|
}, [dashboardTitleProp, intl]);
|
|
20
23
|
const [dashboardTitle, setDashboardTitle] = useState(getDefaultDashboardTitle());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSaveAs.d.ts","sourceRoot":"","sources":["../../../../src/presentation/saveAs/DefaultSaveAsDialog/useSaveAs.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"useSaveAs.d.ts","sourceRoot":"","sources":["../../../../src/presentation/saveAs/DefaultSaveAsDialog/useSaveAs.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAKhD,OAAO,EACH,KAAK,uBAAuB,EAE/B,MAAM,uDAAuD,CAAC;AAO/D,UAAU,gBAAgB;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IAEtB;;;;;;OAMG;IACH,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAE9D;;OAEG;IACH,YAAY,CAAC,EAAE,uBAAuB,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAE3D;;OAEG;IACH,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,IAAI,CAAC;IAElD;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,SAAS,UAAW,eAAe,KAAG,gBA8ClD,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// (C) 2019-2026 GoodData Corporation
|
|
2
2
|
import { useCallback } from "react";
|
|
3
|
+
import { truncateDashboardTitle } from "../../../_staging/dashboard/dashboardTitle.js";
|
|
3
4
|
import { saveDashboardAs } from "../../../model/commands/dashboard.js";
|
|
4
5
|
import { useDashboardSelector } from "../../../model/react/DashboardStoreProvider.js";
|
|
5
6
|
import { useDashboardCommandProcessing, } from "../../../model/react/useDashboardCommandProcessing.js";
|
|
@@ -30,7 +31,8 @@ export const useSaveAs = (props) => {
|
|
|
30
31
|
},
|
|
31
32
|
});
|
|
32
33
|
const handleSaveAs = useCallback((title, switchToDashboard = false, useOriginalFilterContext = true) => {
|
|
33
|
-
|
|
34
|
+
// cut here too so onSubmit reports the title that gets saved
|
|
35
|
+
saveAsCommandProcessing.run(title && truncateDashboardTitle(title), switchToDashboard, useOriginalFilterContext);
|
|
34
36
|
},
|
|
35
37
|
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
|
36
38
|
[]);
|
package/esm/presentation/topBar/buttonBar/button/saveAsButton/DefaultSaveAsNewButton.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultSaveAsNewButton.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/topBar/buttonBar/button/saveAsButton/DefaultSaveAsNewButton.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DefaultSaveAsNewButton.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/topBar/buttonBar/button/saveAsButton/DefaultSaveAsNewButton.tsx"],"names":[],"mappings":"AAqBA,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,qBAAqB,CAgB/D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,EAAE,qBAAqB,kDAsBvG"}
|
|
@@ -6,7 +6,7 @@ import { useIntl } from "react-intl";
|
|
|
6
6
|
import { Button } from "@gooddata/sdk-ui-kit";
|
|
7
7
|
import { useDashboardDispatch, useDashboardSelector, } from "../../../../../model/react/DashboardStoreProvider.js";
|
|
8
8
|
import { selectIsAiBuilding, selectIsAiLoading } from "../../../../../model/store/config/configSelectors.js";
|
|
9
|
-
import { selectIsSaveAsNewButtonVisible } from "../../../../../model/store/topBar/topBarSelectors.js";
|
|
9
|
+
import { selectIsSaveAsNewButtonVisible, selectIsSaveAsNewEnabled, } from "../../../../../model/store/topBar/topBarSelectors.js";
|
|
10
10
|
import { uiActions } from "../../../../../model/store/ui/index.js";
|
|
11
11
|
import { selectDashboardDensity } from "../../../../../model/store/ui/uiSelectors.js";
|
|
12
12
|
/**
|
|
@@ -15,6 +15,7 @@ import { selectDashboardDensity } from "../../../../../model/store/ui/uiSelector
|
|
|
15
15
|
export function useSaveAsNewButtonProps() {
|
|
16
16
|
const dashboardDispatch = useDashboardDispatch();
|
|
17
17
|
const isVisible = useDashboardSelector(selectIsSaveAsNewButtonVisible);
|
|
18
|
+
const isSaveAsNewEnabled = useDashboardSelector(selectIsSaveAsNewEnabled);
|
|
18
19
|
const isAiLoading = useDashboardSelector(selectIsAiLoading);
|
|
19
20
|
const isAiBuilding = useDashboardSelector(selectIsAiBuilding);
|
|
20
21
|
const onSaveAsNewClick = useCallback(() => {
|
|
@@ -22,7 +23,7 @@ export function useSaveAsNewButtonProps() {
|
|
|
22
23
|
}, [dashboardDispatch]);
|
|
23
24
|
return {
|
|
24
25
|
isVisible,
|
|
25
|
-
isEnabled: !isAiLoading && !isAiBuilding,
|
|
26
|
+
isEnabled: isSaveAsNewEnabled && !isAiLoading && !isAiBuilding,
|
|
26
27
|
onSaveAsNewClick,
|
|
27
28
|
};
|
|
28
29
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDefaultMenuItems.d.ts","sourceRoot":"","sources":["../../../../src/presentation/topBar/menuButton/useDefaultMenuItems.tsx"],"names":[],"mappings":"AAgDA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AA8BlD;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"useDefaultMenuItems.d.ts","sourceRoot":"","sources":["../../../../src/presentation/topBar/menuButton/useDefaultMenuItems.tsx"],"names":[],"mappings":"AAgDA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AA8BlD;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,eAAe,EAAE,CA4avD"}
|
|
@@ -12,8 +12,7 @@ import { selectHasAnyExecutionResultLimitBreaks } from "../../../model/store/exe
|
|
|
12
12
|
import { selectDashboardTimezoneConfig, selectDashboardTitle, selectIsNewDashboard, } from "../../../model/store/meta/metaSelectors.js";
|
|
13
13
|
import { selectCanCreateAutomation, selectCanExportPdf, selectCanExportTabular, } from "../../../model/store/permissions/permissionsSelectors.js";
|
|
14
14
|
import { selectIsInEditMode, selectIsInViewMode, } from "../../../model/store/renderMode/renderModeSelectors.js";
|
|
15
|
-
import {
|
|
16
|
-
import { selectDeleteVisible, selectFilterViewsVisible, selectPdfExportVisible, selectSaveAsVisible, selectSettingsVisible, selectSlideShowExportVisible, } from "../../../model/store/topBar/topBarSelectors.js";
|
|
15
|
+
import { selectDeleteVisible, selectFilterViewsVisible, selectIsSaveAsNewEnabled, selectPdfExportVisible, selectSaveAsVisible, selectSettingsVisible, selectSlideShowExportVisible, } from "../../../model/store/topBar/topBarSelectors.js";
|
|
17
16
|
import { uiActions } from "../../../model/store/ui/index.js";
|
|
18
17
|
import { selectMenuButtonItemsVisibility } from "../../../model/store/ui/uiSelectors.js";
|
|
19
18
|
import { useExportXlsxDialogContext } from "../../dashboardContexts/ExportXlsxDialogContext.js";
|
|
@@ -50,7 +49,6 @@ export function useDefaultMenuItems() {
|
|
|
50
49
|
const isMobile = useMediaQuery("mobileDevice");
|
|
51
50
|
const isSmall = useMediaQuery("<=md");
|
|
52
51
|
const isNewDashboard = useDashboardSelector(selectIsNewDashboard);
|
|
53
|
-
const isEmptyLayout = !useDashboardSelector(selectLayoutHasAnalyticalWidgets); // we need at least one non-custom widget there
|
|
54
52
|
const settings = useDashboardSelector(selectSettings);
|
|
55
53
|
const dashboardTitle = useDashboardSelector(selectDashboardTitle);
|
|
56
54
|
const hasAnyLimitBreaks = useDashboardSelector(selectHasAnyExecutionResultLimitBreaks);
|
|
@@ -160,7 +158,7 @@ export function useDefaultMenuItems() {
|
|
|
160
158
|
const openTimezoneDialog = useCallback(() => dispatch(uiActions.openTimezoneDialog()), [dispatch]);
|
|
161
159
|
// Do not show save as new button in menu item when it is already shown as a standalone top bar button.
|
|
162
160
|
const isSaveAsVisible = useDashboardSelector(selectSaveAsVisible);
|
|
163
|
-
const isSaveAsDisabled =
|
|
161
|
+
const isSaveAsDisabled = !useDashboardSelector(selectIsSaveAsNewEnabled);
|
|
164
162
|
const isSettingsVisible = useDashboardSelector(selectSettingsVisible);
|
|
165
163
|
const isSettingsDisabled = isReadOnly;
|
|
166
164
|
const isInProgress = exportDashboardToPdfStatus === "running" ||
|
|
@@ -2,10 +2,10 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
// (C) 2021-2026 GoodData Corporation
|
|
3
3
|
import { defineMessage, useIntl } from "react-intl";
|
|
4
4
|
import { EditableLabel } from "@gooddata/sdk-ui-kit";
|
|
5
|
+
import { DASHBOARD_TITLE_MAX_LENGTH } from "../../../_staging/dashboard/dashboardTitle.js";
|
|
5
6
|
import { useDashboardSelector } from "../../../model/react/DashboardStoreProvider.js";
|
|
6
7
|
import { selectIsAiLoading } from "../../../model/store/config/configSelectors.js";
|
|
7
8
|
import { selectDashboardTitle } from "../../../model/store/meta/metaSelectors.js";
|
|
8
|
-
import { DASHBOARD_TITLE_MAX_LENGTH } from "../../constants/dashboard.js";
|
|
9
9
|
import { DefaultTitle } from "./DefaultTitle.js";
|
|
10
10
|
import { TitleWrapper } from "./TitleWrapper.js";
|
|
11
11
|
const placeholderMessage = defineMessage({ id: "untitled" });
|
|
@@ -1615,7 +1615,7 @@ export declare function changeFilterContextSelection(filters: (IDashboardFilter
|
|
|
1615
1615
|
* TODO: next major release can remove ByParams suffix and use this implementation instead of original cmd creator + other creators can be rewritten to use params object
|
|
1616
1616
|
* https://gooddata.atlassian.net/browse/STL-700
|
|
1617
1617
|
*/
|
|
1618
|
-
export declare function changeFilterContextSelectionByParams({ filters, attributeFilterConfigs, resetOthers, correlationId, tabLocalIdentifier, matchByLocalIdentifier, restorePerTabOriginals,
|
|
1618
|
+
export declare function changeFilterContextSelectionByParams({ filters, attributeFilterConfigs, resetOthers, correlationId, tabLocalIdentifier, matchByLocalIdentifier, restorePerTabOriginals, setAsOriginalToo, skipSync, }: ChangeFilterContextSelectionParams): ChangeFilterContextSelection;
|
|
1619
1619
|
|
|
1620
1620
|
/**
|
|
1621
1621
|
* Params for {@link changeFilterContextSelectionByParams} command.
|
|
@@ -1648,11 +1648,18 @@ export declare type ChangeFilterContextSelectionParams = {
|
|
|
1648
1648
|
restorePerTabOriginals?: boolean;
|
|
1649
1649
|
/**
|
|
1650
1650
|
* When true, the applied values become the initial state a reset restores.
|
|
1651
|
-
* See {@link ChangeFilterContextSelectionPayload.
|
|
1651
|
+
* See {@link ChangeFilterContextSelectionPayload.setAsOriginalToo}.
|
|
1652
1652
|
*
|
|
1653
1653
|
* @internal
|
|
1654
1654
|
*/
|
|
1655
|
-
|
|
1655
|
+
setAsOriginalToo?: boolean;
|
|
1656
|
+
/**
|
|
1657
|
+
* When true, only the addressed tab is changed.
|
|
1658
|
+
* See {@link ChangeFilterContextSelectionPayload.skipSync}.
|
|
1659
|
+
*
|
|
1660
|
+
* @internal
|
|
1661
|
+
*/
|
|
1662
|
+
skipSync?: boolean;
|
|
1656
1663
|
};
|
|
1657
1664
|
|
|
1658
1665
|
/**
|
|
@@ -1711,7 +1718,14 @@ export declare type ChangeFilterContextSelectionPayload = {
|
|
|
1711
1718
|
*
|
|
1712
1719
|
* @internal
|
|
1713
1720
|
*/
|
|
1714
|
-
|
|
1721
|
+
setAsOriginalToo?: boolean;
|
|
1722
|
+
/**
|
|
1723
|
+
* When true, only the tab this command addresses is changed, even when filters persist across
|
|
1724
|
+
* tabs. Used when restoring a state that was saved separately for each tab.
|
|
1725
|
+
*
|
|
1726
|
+
* @internal
|
|
1727
|
+
*/
|
|
1728
|
+
skipSync?: boolean;
|
|
1715
1729
|
};
|
|
1716
1730
|
|
|
1717
1731
|
/**
|
|
@@ -2050,7 +2064,7 @@ export declare function changeNestedLayoutSectionHeader(index: ILayoutSectionPat
|
|
|
2050
2064
|
* @param params - params for the command creator
|
|
2051
2065
|
* @internal
|
|
2052
2066
|
*/
|
|
2053
|
-
export declare function changeParameterValues({ parameters, tabLocalIdentifier, correlationId, restorePerTabOriginals,
|
|
2067
|
+
export declare function changeParameterValues({ parameters, tabLocalIdentifier, correlationId, restorePerTabOriginals, setAsOriginalToo, }: ChangeParameterValuesParams): IChangeParameterValues;
|
|
2054
2068
|
|
|
2055
2069
|
/**
|
|
2056
2070
|
* Params for {@link changeParameterValues} command.
|
|
@@ -2069,9 +2083,9 @@ export declare type ChangeParameterValuesParams = {
|
|
|
2069
2083
|
*/
|
|
2070
2084
|
restorePerTabOriginals?: boolean;
|
|
2071
2085
|
/**
|
|
2072
|
-
* See {@link IChangeParameterValuesPayload.
|
|
2086
|
+
* See {@link IChangeParameterValuesPayload.setAsOriginalToo}.
|
|
2073
2087
|
*/
|
|
2074
|
-
|
|
2088
|
+
setAsOriginalToo?: boolean;
|
|
2075
2089
|
};
|
|
2076
2090
|
|
|
2077
2091
|
/**
|
|
@@ -6341,7 +6355,7 @@ export declare function getFilterIdentifier(filter: FilterContextItem): string;
|
|
|
6341
6355
|
/**
|
|
6342
6356
|
* @internal
|
|
6343
6357
|
*/
|
|
6344
|
-
export declare function getKdaKeyDriverCombinations(drillDefinition: IKeyDriveAnalysis, drillEvent: IDrillEvent, enableSecondGranularities?: boolean): IDashboardKeyDriverCombinationItem[];
|
|
6358
|
+
export declare function getKdaKeyDriverCombinations(drillDefinition: IKeyDriveAnalysis, drillEvent: IDrillEvent, enableSecondGranularities?: boolean, isMeasureDisabled?: (localIdentifier: string) => boolean): IDashboardKeyDriverCombinationItem[];
|
|
6345
6359
|
|
|
6346
6360
|
/**
|
|
6347
6361
|
* Returns KDA-supported date granularities, including second when the feature flag is on.
|
|
@@ -9364,7 +9378,7 @@ export declare interface IChangeParameterValuesPayload {
|
|
|
9364
9378
|
* When true, the values this command writes become the values a reset restores, on this tab and
|
|
9365
9379
|
* on every tab they are synced to. Used when a default filter view initializes the shared state.
|
|
9366
9380
|
*/
|
|
9367
|
-
readonly
|
|
9381
|
+
readonly setAsOriginalToo?: boolean;
|
|
9368
9382
|
}
|
|
9369
9383
|
|
|
9370
9384
|
/**
|
|
@@ -27341,7 +27355,8 @@ export declare type SaveDashboardAs = IDashboardCommand & {
|
|
|
27341
27355
|
* Upon success, a copy of the dashboard will be persisted on the backend. The context of the dashboard component
|
|
27342
27356
|
* that processed the command is unchanged - it still works with the original dashboard.
|
|
27343
27357
|
*
|
|
27344
|
-
* @param title - new title for the dashboard; if not specified, the title of original dashboard will be used
|
|
27358
|
+
* @param title - new title for the dashboard; if not specified, the title of original dashboard will be used.
|
|
27359
|
+
* A title longer than 255 characters is shortened to at most 255 characters.
|
|
27345
27360
|
* @param switchToCopy - indicate whether the dashboard component should switch to the dashboard that will
|
|
27346
27361
|
* be created during save-as; the default is false
|
|
27347
27362
|
* @param correlationId - specify correlation id to use for this command. this will be included in all
|
|
@@ -27359,6 +27374,7 @@ export declare function saveDashboardAs(title?: string, switchToCopy?: boolean,
|
|
|
27359
27374
|
export declare type SaveDashboardAsPayload = {
|
|
27360
27375
|
/**
|
|
27361
27376
|
* Specify new title for the dashboard that will be created during the Save As operation.
|
|
27377
|
+
* A title longer than 255 characters is shortened to at most 255 characters.
|
|
27362
27378
|
*/
|
|
27363
27379
|
readonly title?: string;
|
|
27364
27380
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-ui-dashboard",
|
|
3
|
-
"version": "11.66.0
|
|
3
|
+
"version": "11.66.0",
|
|
4
4
|
"description": "GoodData SDK - Dashboard Component",
|
|
5
5
|
"license": "LicenseRef-LICENSE",
|
|
6
6
|
"author": "GoodData Corporation",
|
|
@@ -60,22 +60,22 @@
|
|
|
60
60
|
"ts-invariant": "0.10.3",
|
|
61
61
|
"tslib": "2.8.1",
|
|
62
62
|
"uuid": "11.1.1",
|
|
63
|
-
"@gooddata/sdk-backend-base": "11.66.0
|
|
64
|
-
"@gooddata/sdk-backend-spi": "11.66.0
|
|
65
|
-
"@gooddata/sdk-embedding": "11.66.0
|
|
66
|
-
"@gooddata/sdk-
|
|
67
|
-
"@gooddata/sdk-ui": "11.66.0
|
|
68
|
-
"@gooddata/sdk-ui-
|
|
69
|
-
"@gooddata/sdk-
|
|
70
|
-
"@gooddata/sdk-ui-ext": "11.66.0
|
|
71
|
-
"@gooddata/sdk-ui-filters": "11.66.0
|
|
72
|
-
"@gooddata/sdk-ui-geo": "11.66.0
|
|
73
|
-
"@gooddata/sdk-ui-
|
|
74
|
-
"@gooddata/sdk-ui-
|
|
75
|
-
"@gooddata/sdk-ui-
|
|
76
|
-
"@gooddata/sdk-ui-
|
|
77
|
-
"@gooddata/sdk-ui-
|
|
78
|
-
"@gooddata/util": "11.66.0
|
|
63
|
+
"@gooddata/sdk-backend-base": "11.66.0",
|
|
64
|
+
"@gooddata/sdk-backend-spi": "11.66.0",
|
|
65
|
+
"@gooddata/sdk-embedding": "11.66.0",
|
|
66
|
+
"@gooddata/sdk-ui": "11.66.0",
|
|
67
|
+
"@gooddata/sdk-ui-analytical-designer": "11.66.0",
|
|
68
|
+
"@gooddata/sdk-ui-charts": "11.66.0",
|
|
69
|
+
"@gooddata/sdk-model": "11.66.0",
|
|
70
|
+
"@gooddata/sdk-ui-ext": "11.66.0",
|
|
71
|
+
"@gooddata/sdk-ui-filters": "11.66.0",
|
|
72
|
+
"@gooddata/sdk-ui-geo": "11.66.0",
|
|
73
|
+
"@gooddata/sdk-ui-kit": "11.66.0",
|
|
74
|
+
"@gooddata/sdk-ui-pivot": "11.66.0",
|
|
75
|
+
"@gooddata/sdk-ui-theme-provider": "11.66.0",
|
|
76
|
+
"@gooddata/sdk-ui-vis-commons": "11.66.0",
|
|
77
|
+
"@gooddata/sdk-ui-semantic-search": "11.66.0",
|
|
78
|
+
"@gooddata/util": "11.66.0"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@microsoft/api-documenter": "7.30.16",
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
"eslint-plugin-no-only-tests": "3.3.0",
|
|
104
104
|
"eslint-plugin-react": "7.37.5",
|
|
105
105
|
"eslint-plugin-sonarjs": "3.0.6",
|
|
106
|
-
"happy-dom": "
|
|
106
|
+
"happy-dom": "21.0.4",
|
|
107
107
|
"npm-run-all": "4.1.5",
|
|
108
108
|
"oxfmt": "0.68.0",
|
|
109
109
|
"oxlint": "1.83.0",
|
|
@@ -117,12 +117,12 @@
|
|
|
117
117
|
"svgo": "2.8.4",
|
|
118
118
|
"typescript": "7.0.2",
|
|
119
119
|
"vitest": "5.0.4",
|
|
120
|
-
"@gooddata/
|
|
121
|
-
"@gooddata/
|
|
122
|
-
"@gooddata/
|
|
123
|
-
"@gooddata/
|
|
124
|
-
"@gooddata/
|
|
125
|
-
"@gooddata/
|
|
120
|
+
"@gooddata/eslint-config": "11.66.0",
|
|
121
|
+
"@gooddata/reference-workspace": "11.66.0",
|
|
122
|
+
"@gooddata/sdk-backend-mockingbird": "11.66.0",
|
|
123
|
+
"@gooddata/stylelint-config": "11.66.0",
|
|
124
|
+
"@gooddata/i18n-toolkit": "11.66.0",
|
|
125
|
+
"@gooddata/oxlint-config": "11.66.0"
|
|
126
126
|
},
|
|
127
127
|
"peerDependencies": {
|
|
128
128
|
"react": "^18.0.0 || ^19.0.0",
|
package/styles/css/main.css
CHANGED
|
@@ -10738,7 +10738,7 @@ a.gd-button-link:hover .gd-button-text, a.gd-button-link-dimmed:hover .gd-button
|
|
|
10738
10738
|
========================================================================== */
|
|
10739
10739
|
.modalityPlugin-mask {
|
|
10740
10740
|
position: fixed;
|
|
10741
|
-
z-index:
|
|
10741
|
+
z-index: 5001;
|
|
10742
10742
|
top: 0;
|
|
10743
10743
|
left: 0;
|
|
10744
10744
|
display: none;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../../src/presentation/constants/dashboard.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,0BAA0B,MAAM,CAAC"}
|