@gooddata/sdk-ui-catalog 11.57.0-alpha.4 → 11.57.0-alpha.6
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/esm/catalogDetail/CatalogDetailAttributeLabelsConditionalFormatting.d.ts +12 -0
- package/esm/catalogDetail/CatalogDetailAttributeLabelsConditionalFormatting.d.ts.map +1 -0
- package/esm/catalogDetail/CatalogDetailAttributeLabelsConditionalFormatting.js +18 -0
- package/esm/catalogDetail/CatalogDetailConditionalFormatting.d.ts +13 -3
- package/esm/catalogDetail/CatalogDetailConditionalFormatting.d.ts.map +1 -1
- package/esm/catalogDetail/CatalogDetailConditionalFormatting.js +49 -32
- package/esm/catalogDetail/CatalogDetailContent.d.ts.map +1 -1
- package/esm/catalogDetail/CatalogDetailContent.js +3 -1
- package/esm/catalogDetail/CatalogDetailTabMetadata.d.ts +3 -2
- package/esm/catalogDetail/CatalogDetailTabMetadata.d.ts.map +1 -1
- package/esm/catalogDetail/CatalogDetailTabMetadata.js +6 -4
- package/esm/catalogDetail/hooks/useCatalogItemLoad.d.ts.map +1 -1
- package/esm/catalogDetail/hooks/useCatalogItemLoad.js +12 -3
- package/esm/catalogDetail/hooks/useCatalogItemUpdate.d.ts +2 -1
- package/esm/catalogDetail/hooks/useCatalogItemUpdate.d.ts.map +1 -1
- package/esm/catalogDetail/hooks/useCatalogItemUpdate.js +53 -127
- package/esm/catalogItem/query.d.ts +3 -2
- package/esm/catalogItem/query.d.ts.map +1 -1
- package/esm/catalogItem/query.js +12 -2
- package/esm/catalogItem/testFixtures.d.ts +7 -0
- package/esm/catalogItem/testFixtures.d.ts.map +1 -0
- package/esm/catalogItem/testFixtures.js +21 -0
- package/esm/catalogItem/types.d.ts +6 -1
- package/esm/catalogItem/types.d.ts.map +1 -1
- package/esm/computedAttribute/computedAttributeDescriptor.js +3 -3
- package/esm/computedAttribute/computedAttributeMutationPort.d.ts +1 -1
- package/esm/computedAttribute/computedAttributeMutationPort.d.ts.map +1 -1
- package/esm/computedAttribute/computedAttributeMutationPort.js +3 -1
- package/esm/localization/bundles/de-DE.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/de-DE.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/de-DE.localization-bundle.js +5 -0
- package/esm/localization/bundles/en-AU.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/en-AU.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/en-AU.localization-bundle.js +5 -0
- package/esm/localization/bundles/en-GB.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/en-GB.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/en-GB.localization-bundle.js +5 -0
- package/esm/localization/bundles/en-US.localization-bundle.js +3 -3
- package/esm/localization/bundles/es-419.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/es-419.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/es-419.localization-bundle.js +5 -0
- package/esm/localization/bundles/es-ES.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/es-ES.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/es-ES.localization-bundle.js +5 -0
- package/esm/localization/bundles/fi-FI.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/fi-FI.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/fi-FI.localization-bundle.js +5 -0
- package/esm/localization/bundles/fr-CA.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/fr-CA.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/fr-CA.localization-bundle.js +5 -0
- package/esm/localization/bundles/fr-FR.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/fr-FR.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/fr-FR.localization-bundle.js +5 -0
- package/esm/localization/bundles/id-ID.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/id-ID.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/id-ID.localization-bundle.js +5 -0
- package/esm/localization/bundles/it-IT.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/it-IT.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/it-IT.localization-bundle.js +5 -0
- package/esm/localization/bundles/ja-JP.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/ja-JP.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/ja-JP.localization-bundle.js +5 -0
- package/esm/localization/bundles/ko-KR.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/ko-KR.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/ko-KR.localization-bundle.js +5 -0
- package/esm/localization/bundles/nl-NL.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/nl-NL.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/nl-NL.localization-bundle.js +5 -0
- package/esm/localization/bundles/pl-PL.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/pl-PL.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/pl-PL.localization-bundle.js +5 -0
- package/esm/localization/bundles/pt-BR.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/pt-BR.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/pt-BR.localization-bundle.js +5 -0
- package/esm/localization/bundles/pt-PT.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/pt-PT.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/pt-PT.localization-bundle.js +5 -0
- package/esm/localization/bundles/ru-RU.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/ru-RU.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/ru-RU.localization-bundle.js +5 -0
- package/esm/localization/bundles/sl-SI.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/sl-SI.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/sl-SI.localization-bundle.js +5 -0
- package/esm/localization/bundles/th-TH.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/th-TH.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/th-TH.localization-bundle.js +5 -0
- package/esm/localization/bundles/tr-TR.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/tr-TR.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/tr-TR.localization-bundle.js +5 -0
- package/esm/localization/bundles/uk-UA.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/uk-UA.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/uk-UA.localization-bundle.js +5 -0
- package/esm/localization/bundles/vi-VN.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/vi-VN.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/vi-VN.localization-bundle.js +5 -0
- package/esm/localization/bundles/zh-HK.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/zh-HK.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/zh-HK.localization-bundle.js +5 -0
- package/esm/localization/bundles/zh-Hans.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/zh-Hans.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/zh-Hans.localization-bundle.js +5 -0
- package/esm/localization/bundles/zh-Hant.localization-bundle.d.ts +5 -0
- package/esm/localization/bundles/zh-Hant.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/zh-Hant.localization-bundle.js +5 -0
- package/esm/sdk-ui-catalog.d.ts +6 -0
- package/package.json +19 -19
- package/styles/css/detail.css +11 -1
- package/styles/css/detail.css.map +1 -1
- package/styles/css/main.css +11 -1
- package/styles/css/main.css.map +1 -1
- package/styles/scss/detail.scss +13 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type IAttributeDisplayFormMetadataObject, type ISemanticConditionalFormatting, type ISeparators, type ObjRef } from "@gooddata/sdk-model";
|
|
2
|
+
export interface ICatalogDetailAttributeLabelsConditionalFormattingProps {
|
|
3
|
+
labels: IAttributeDisplayFormMetadataObject[];
|
|
4
|
+
canEdit: boolean;
|
|
5
|
+
onLabelConditionalFormattingChange: (labelRef: ObjRef, conditionalFormatting: ISemanticConditionalFormatting | undefined) => void;
|
|
6
|
+
separators?: ISeparators;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* One "Conditional formatting" row listing the attribute's labels, primary label first.
|
|
10
|
+
*/
|
|
11
|
+
export declare function CatalogDetailAttributeLabelsConditionalFormatting({ labels, canEdit, onLabelConditionalFormattingChange, separators, }: ICatalogDetailAttributeLabelsConditionalFormattingProps): import("react/jsx-runtime").JSX.Element | null;
|
|
12
|
+
//# sourceMappingURL=CatalogDetailAttributeLabelsConditionalFormatting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CatalogDetailAttributeLabelsConditionalFormatting.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailAttributeLabelsConditionalFormatting.tsx"],"names":[],"mappings":"AAIA,OAAO,EACH,KAAK,mCAAmC,EACxC,KAAK,8BAA8B,EACnC,KAAK,WAAW,EAChB,KAAK,MAAM,EACd,MAAM,qBAAqB,CAAC;AAS7B,MAAM,WAAW,uDAAuD;IACpE,MAAM,EAAE,mCAAmC,EAAE,CAAC;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,kCAAkC,EAAE,CAChC,QAAQ,EAAE,MAAM,EAChB,qBAAqB,EAAE,8BAA8B,GAAG,SAAS,KAChE,IAAI,CAAC;IACV,UAAU,CAAC,EAAE,WAAW,CAAC;CAC5B;AAED;;GAEG;AACH,wBAAgB,iDAAiD,CAAC,EAC9D,MAAM,EACN,OAAO,EACP,kCAAkC,EAClC,UAAU,GACb,EAAE,uDAAuD,kDA6BzD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { FormattedMessage } from "react-intl";
|
|
4
|
+
import {} from "@gooddata/sdk-model";
|
|
5
|
+
import { sortShareableLabels } from "@gooddata/sdk-ui-ext";
|
|
6
|
+
import { CatalogDetailConditionalFormattingControl, labelTargetOption, } from "./CatalogDetailConditionalFormatting.js";
|
|
7
|
+
import { CatalogDetailContentRow } from "./CatalogDetailContentRow.js";
|
|
8
|
+
/**
|
|
9
|
+
* One "Conditional formatting" row listing the attribute's labels, primary label first.
|
|
10
|
+
*/
|
|
11
|
+
export function CatalogDetailAttributeLabelsConditionalFormatting({ labels, canEdit, onLabelConditionalFormattingChange, separators, }) {
|
|
12
|
+
if (labels.length === 0) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
return (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.conditionalFormatting" }), alignTop: true, content: _jsx("div", { className: "gd-analytics-catalog-detail__cf-labels", children: sortShareableLabels(labels).map((label) => (_jsxs("div", { className: "gd-analytics-catalog-detail__cf-label", children: [_jsx("span", { className: "gd-analytics-catalog-detail__cf-label-title", children: label.title }), _jsx(CatalogDetailConditionalFormattingControl, { targetOption: labelTargetOption(label), conditionalFormatting: label.conditionalFormatting, canEdit: canEdit, onConditionalFormattingChange: (conditionalFormatting) => {
|
|
16
|
+
onLabelConditionalFormattingChange(label.ref, conditionalFormatting);
|
|
17
|
+
}, separators: separators })] }, label.id))) }) }));
|
|
18
|
+
}
|
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
import { type ISemanticConditionalFormatting, type ISeparators } from "@gooddata/sdk-model";
|
|
2
|
-
|
|
1
|
+
import { type IAttributeDisplayFormMetadataObject, type ISemanticConditionalFormatting, type ISeparators } from "@gooddata/sdk-model";
|
|
2
|
+
import { type ITargetOption } from "@gooddata/sdk-ui-ext";
|
|
3
|
+
export declare function measureTargetOption(measure: {
|
|
3
4
|
identifier: string;
|
|
4
5
|
title: string;
|
|
5
6
|
format?: string | null;
|
|
7
|
+
}): ITargetOption;
|
|
8
|
+
export declare function labelTargetOption(label: IAttributeDisplayFormMetadataObject): ITargetOption;
|
|
9
|
+
export interface ICatalogDetailConditionalFormattingProps {
|
|
10
|
+
targetOption: ITargetOption;
|
|
6
11
|
conditionalFormatting?: ISemanticConditionalFormatting;
|
|
7
12
|
canEdit: boolean;
|
|
8
13
|
onConditionalFormattingChange: (conditionalFormatting: ISemanticConditionalFormatting | undefined) => void;
|
|
9
14
|
separators?: ISeparators;
|
|
10
15
|
}
|
|
11
|
-
|
|
16
|
+
/**
|
|
17
|
+
* The toggle, button and dialog for one catalog object, without a row around it.
|
|
18
|
+
*/
|
|
19
|
+
export declare function CatalogDetailConditionalFormattingControl({ targetOption, conditionalFormatting, canEdit, onConditionalFormattingChange, separators, }: ICatalogDetailConditionalFormattingProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
/** {@link CatalogDetailConditionalFormattingControl} in a row titled "Conditional formatting". */
|
|
21
|
+
export declare function CatalogDetailConditionalFormatting(props: ICatalogDetailConditionalFormattingProps): import("react/jsx-runtime").JSX.Element;
|
|
12
22
|
//# sourceMappingURL=CatalogDetailConditionalFormatting.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CatalogDetailConditionalFormatting.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailConditionalFormatting.tsx"],"names":[],"mappings":"AAOA,OAAO,EACH,KAAK,8BAA8B,EACnC,KAAK,WAAW,EAEnB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"CatalogDetailConditionalFormatting.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailConditionalFormatting.tsx"],"names":[],"mappings":"AAOA,OAAO,EACH,KAAK,mCAAmC,EACxC,KAAK,8BAA8B,EACnC,KAAK,WAAW,EAEnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEH,KAAK,aAAa,EAIrB,MAAM,sBAAsB,CAAC;AAW9B,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GAAG,aAAa,CAOhB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,mCAAmC,GAAG,aAAa,CAM3F;AAED,MAAM,WAAW,wCAAwC;IACrD,YAAY,EAAE,aAAa,CAAC;IAC5B,qBAAqB,CAAC,EAAE,8BAA8B,CAAC;IACvD,OAAO,EAAE,OAAO,CAAC;IACjB,6BAA6B,EAAE,CAC3B,qBAAqB,EAAE,8BAA8B,GAAG,SAAS,KAChE,IAAI,CAAC;IACV,UAAU,CAAC,EAAE,WAAW,CAAC;CAC5B;AAED;;GAEG;AACH,wBAAgB,yCAAyC,CAAC,EACtD,YAAY,EACZ,qBAAqB,EACrB,OAAO,EACP,6BAA6B,EAC7B,UAAU,GACb,EAAE,wCAAwC,2CA2E1C;AAED,kGAAkG;AAClG,wBAAgB,kCAAkC,CAAC,KAAK,EAAE,wCAAwC,2CAOjG"}
|
|
@@ -5,48 +5,65 @@ import cx from "classnames";
|
|
|
5
5
|
import { FormattedMessage, defineMessages, useIntl } from "react-intl";
|
|
6
6
|
import { isSemanticConditionalFormattingEnabled, } from "@gooddata/sdk-model";
|
|
7
7
|
import { ConditionalFormattingDialog, isPercentFormat, newRule, semanticRuleFor, } from "@gooddata/sdk-ui-ext";
|
|
8
|
-
import { UiButton } from "@gooddata/sdk-ui-kit";
|
|
8
|
+
import { UiButton, useId } from "@gooddata/sdk-ui-kit";
|
|
9
9
|
import { CatalogDetailContentRow } from "./CatalogDetailContentRow.js";
|
|
10
10
|
const messages = defineMessages({
|
|
11
11
|
toggleAriaLabel: { id: "analyticsCatalog.conditionalFormatting.toggleAriaLabel" },
|
|
12
12
|
edit: { id: "analyticsCatalog.conditionalFormatting.edit" },
|
|
13
13
|
add: { id: "analyticsCatalog.conditionalFormatting.add" },
|
|
14
14
|
});
|
|
15
|
-
export function
|
|
15
|
+
export function measureTargetOption(measure) {
|
|
16
|
+
return {
|
|
17
|
+
value: `measure:${measure.identifier}`,
|
|
18
|
+
title: measure.title,
|
|
19
|
+
target: { kind: "measure", measureIdentifier: measure.identifier },
|
|
20
|
+
isPercent: isPercentFormat(measure.format ?? undefined),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function labelTargetOption(label) {
|
|
24
|
+
return {
|
|
25
|
+
value: `attribute:${label.id}`,
|
|
26
|
+
title: label.title,
|
|
27
|
+
target: { kind: "attribute", attributeIdentifier: label.id },
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The toggle, button and dialog for one catalog object, without a row around it.
|
|
32
|
+
*/
|
|
33
|
+
export function CatalogDetailConditionalFormattingControl({ targetOption, conditionalFormatting, canEdit, onConditionalFormattingChange, separators, }) {
|
|
16
34
|
const intl = useIntl();
|
|
17
35
|
const [isOpen, setIsOpen] = useState(false);
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
title,
|
|
21
|
-
target: { kind: "measure", measureIdentifier: identifier },
|
|
22
|
-
isPercent: isPercentFormat(format ?? undefined),
|
|
23
|
-
};
|
|
36
|
+
const anchorId = useId();
|
|
37
|
+
const anchorElementId = `s-cf-catalog-popover-anchor-${anchorId}`;
|
|
24
38
|
// A stored value with no conditions counts as no rule.
|
|
25
39
|
const authored = conditionalFormatting?.conditions.length ? conditionalFormatting : undefined;
|
|
26
40
|
const isEnabled = authored !== undefined && isSemanticConditionalFormattingEnabled(authored);
|
|
27
41
|
const rule = authored ? semanticRuleFor(targetOption, authored) : newRule(targetOption);
|
|
28
|
-
return (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
42
|
+
return (_jsxs(_Fragment, { children: [authored ? (_jsxs("label", { className: "input-checkbox-toggle gd-analytics-catalog-detail__cf-toggle s-cf-catalog-toggle-label", children: [_jsx("input", { type: "checkbox", checked: isEnabled, disabled: !canEdit, "aria-label": intl.formatMessage(messages.toggleAriaLabel, {
|
|
43
|
+
title: targetOption.title,
|
|
44
|
+
}), onChange: (event) => {
|
|
45
|
+
onConditionalFormattingChange({ ...authored, enabled: event.target.checked });
|
|
46
|
+
}, className: cx("s-checkbox-toggle", canEdit ? "s-enabled" : "s-disabled") }), _jsx("span", { className: "input-label-text" })] })) : null, _jsx(UiButton, { dataTestId: "cf-catalog-open", size: "small", variant: "tertiary", iconBefore: authored ? undefined : "plus", label: intl.formatMessage(authored ? messages.edit : messages.add), isDisabled: !canEdit, onClick: () => setIsOpen(true) }), _jsx("span", { id: anchorElementId, className: "s-cf-catalog-popover-anchor" }), isOpen ? (_jsx(ConditionalFormattingDialog, { rule: rule, isNew: !authored, fixedTarget: true, targetOptions: [targetOption], separators: separators, alignTo: `#${anchorElementId}`, onDelete: authored
|
|
47
|
+
? () => {
|
|
48
|
+
onConditionalFormattingChange(undefined);
|
|
49
|
+
setIsOpen(false);
|
|
50
|
+
}
|
|
51
|
+
: undefined, onSubmit: (intent) => {
|
|
52
|
+
// "inherited" needs the semanticByTarget fallback, which this usage never passes.
|
|
53
|
+
if (intent.mode !== "custom") {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
onConditionalFormattingChange({
|
|
57
|
+
...(conditionalFormatting?.version
|
|
58
|
+
? { version: conditionalFormatting.version }
|
|
59
|
+
: {}),
|
|
60
|
+
conditions: intent.rule.conditions,
|
|
61
|
+
// A new rule takes effect immediately; an edit keeps the row's toggle state.
|
|
62
|
+
enabled: authored ? isEnabled : true,
|
|
63
|
+
});
|
|
64
|
+
}, onClose: () => setIsOpen(false) })) : null] }));
|
|
65
|
+
}
|
|
66
|
+
/** {@link CatalogDetailConditionalFormattingControl} in a row titled "Conditional formatting". */
|
|
67
|
+
export function CatalogDetailConditionalFormatting(props) {
|
|
68
|
+
return (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.conditionalFormatting" }), content: _jsx(CatalogDetailConditionalFormattingControl, { ...props }) }));
|
|
52
69
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CatalogDetailContent.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailContent.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAgC,MAAM,OAAO,CAAC;AAUtE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAGlF,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAkBzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AASnD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;OAEG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B;;OAEG;IACH,gBAAgB,CAAC,EAAE,eAAe,GAAG,YAAY,GAAG,IAAI,CAAC;IACzD;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5E;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;OAEG;IACH,uBAAuB,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IAC5E;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IACrD;;OAEG;IACH,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACrD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,GAC1B,EAAE,0BAA0B,
|
|
1
|
+
{"version":3,"file":"CatalogDetailContent.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailContent.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAgC,MAAM,OAAO,CAAC;AAUtE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAGlF,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAkBzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AASnD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;OAEG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B;;OAEG;IACH,gBAAgB,CAAC,EAAE,eAAe,GAAG,YAAY,GAAG,IAAI,CAAC;IACzD;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5E;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;OAEG;IACH,uBAAuB,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IAC5E;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IACrD;;OAEG;IACH,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACrD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,GAC1B,EAAE,0BAA0B,2CA4N5B"}
|
|
@@ -39,7 +39,7 @@ const Tabs = {
|
|
|
39
39
|
export function CatalogDetailContent({ objectId, objectType, objectDefinition, onOpenClick, onTagClick, onCatalogItemCreate, onCatalogItemUpdate, onCatalogItemDelete, onCatalogItemUpdateError, onCatalogItemNavigation, }) {
|
|
40
40
|
const intl = useIntl();
|
|
41
41
|
const { result: { user: currentUser, permissions, settings } = {} } = usePermissionsState();
|
|
42
|
-
const { item, status, error, updateItemTitle, updateItemDescription, updateItemTags, updateItemIsHidden, updateItemIsHiddenFromKda, updateItemMetricType, updateItemFormat, updateItemConditionalFormatting, updateItemCertification, applyItemUpdate, applyItemDelete, } = useCatalogItemUpdate({
|
|
42
|
+
const { item, status, error, updateItemTitle, updateItemDescription, updateItemTags, updateItemIsHidden, updateItemIsHiddenFromKda, updateItemMetricType, updateItemFormat, updateItemConditionalFormatting, updateItemLabelConditionalFormatting, updateItemCertification, applyItemUpdate, applyItemDelete, } = useCatalogItemUpdate({
|
|
43
43
|
currentUser,
|
|
44
44
|
objectId,
|
|
45
45
|
objectType,
|
|
@@ -132,6 +132,8 @@ export function CatalogDetailContent({ objectId, objectType, objectDefinition, o
|
|
|
132
132
|
updateItemFormat(format);
|
|
133
133
|
}, onConditionalFormattingChange: (conditionalFormatting) => {
|
|
134
134
|
updateItemConditionalFormatting(conditionalFormatting);
|
|
135
|
+
}, onLabelConditionalFormattingChange: (labelRef, conditionalFormatting) => {
|
|
136
|
+
updateItemLabelConditionalFormatting(labelRef, conditionalFormatting);
|
|
135
137
|
}, separators: separators, currencyFormatOverride: enableMetricFormatOverrides ? currencyFormatOverride : undefined, enableMetricFormatOverrides: enableMetricFormatOverrides, accessRow: _jsx(CatalogItemAccessRow, {}) })), selectedTabId === Tabs.CERTIFICATION && isCertificationVisible ? (_jsx(CatalogDetailTabCertification, { item: item, canEdit: canEdit, onCertificationChange: (certification) => {
|
|
136
138
|
updateItemCertification(certification);
|
|
137
139
|
} })) : null, selectedTabId === Tabs.QUALITY &&
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
-
import type { ISemanticConditionalFormatting, ISeparators, MetricType } from "@gooddata/sdk-model";
|
|
2
|
+
import type { ISemanticConditionalFormatting, ISeparators, MetricType, ObjRef } from "@gooddata/sdk-model";
|
|
3
3
|
import { type IUiTagDef } from "@gooddata/sdk-ui-kit";
|
|
4
4
|
import { type ICatalogItem } from "../catalogItem/types.js";
|
|
5
5
|
type Props = {
|
|
@@ -13,6 +13,7 @@ type Props = {
|
|
|
13
13
|
onMetricTypeChange?: (metricType: MetricType | undefined) => void;
|
|
14
14
|
onFormatChange?: (format: string | null) => void;
|
|
15
15
|
onConditionalFormattingChange?: (conditionalFormatting: ISemanticConditionalFormatting | undefined) => void;
|
|
16
|
+
onLabelConditionalFormattingChange?: (labelRef: ObjRef, conditionalFormatting: ISemanticConditionalFormatting | undefined) => void;
|
|
16
17
|
separators?: ISeparators;
|
|
17
18
|
currencyFormatOverride?: string | null;
|
|
18
19
|
enableMetricFormatOverrides?: boolean;
|
|
@@ -27,6 +28,6 @@ type Props = {
|
|
|
27
28
|
*/
|
|
28
29
|
showDatasetRow?: boolean;
|
|
29
30
|
};
|
|
30
|
-
export declare function CatalogDetailTabMetadata({ item, canEdit, onTagClick, onTagAdd, onTagRemove, onIsHiddenChange, onIsHiddenFromKdaChange, onMetricTypeChange, onFormatChange, onConditionalFormattingChange, separators, currencyFormatOverride, enableMetricFormatOverrides, accessRow, showDatasetRow, }: Props): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export declare function CatalogDetailTabMetadata({ item, canEdit, onTagClick, onTagAdd, onTagRemove, onIsHiddenChange, onIsHiddenFromKdaChange, onMetricTypeChange, onFormatChange, onConditionalFormattingChange, onLabelConditionalFormattingChange, separators, currencyFormatOverride, enableMetricFormatOverrides, accessRow, showDatasetRow, }: Props): import("react/jsx-runtime").JSX.Element;
|
|
31
32
|
export {};
|
|
32
33
|
//# sourceMappingURL=CatalogDetailTabMetadata.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CatalogDetailTabMetadata.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailTabMetadata.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,8BAA8B,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"CatalogDetailTabMetadata.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailTabMetadata.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,8BAA8B,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC3G,OAAO,EAAE,KAAK,SAAS,EAA6B,MAAM,sBAAsB,CAAC;AAUjF,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAc5D,KAAK,KAAK,GAAG;IACT,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACnC,WAAW,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACtC,gBAAgB,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,uBAAuB,EAAE,CAAC,eAAe,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5D,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,KAAK,IAAI,CAAC;IAClE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,6BAA6B,CAAC,EAAE,CAC5B,qBAAqB,EAAE,8BAA8B,GAAG,SAAS,KAChE,IAAI,CAAC;IACV,kCAAkC,CAAC,EAAE,CACjC,QAAQ,EAAE,MAAM,EAChB,qBAAqB,EAAE,8BAA8B,GAAG,SAAS,KAChE,IAAI,CAAC;IACV,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,EACrC,IAAI,EACJ,OAAO,EACP,UAAU,EACV,QAAQ,EACR,WAAW,EACX,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,cAAc,EACd,6BAA6B,EAC7B,kCAAkC,EAClC,UAAU,EACV,sBAAsB,EACtB,2BAA2B,EAC3B,SAAS,EACT,cAAc,GACjB,EAAE,KAAK,2CAqKP"}
|
|
@@ -7,18 +7,20 @@ import { getVisualizationType, isCatalogItemAttribute, isCatalogItemDataSet, isC
|
|
|
7
7
|
import {} from "../catalogItem/types.js";
|
|
8
8
|
import { getObjectTypeLabel } from "../objectType/labels.js";
|
|
9
9
|
import { useFeatureFlag } from "../permission/PermissionsContext.js";
|
|
10
|
-
import {
|
|
10
|
+
import { CatalogDetailAttributeLabelsConditionalFormatting } from "./CatalogDetailAttributeLabelsConditionalFormatting.js";
|
|
11
|
+
import { CatalogDetailConditionalFormatting, measureTargetOption, } from "./CatalogDetailConditionalFormatting.js";
|
|
11
12
|
import { CatalogDetailContentRow } from "./CatalogDetailContentRow.js";
|
|
12
13
|
import { CatalogDetailGranularities } from "./CatalogDetailGranularities.js";
|
|
13
14
|
import { CatalogDetailMetricSettings } from "./CatalogDetailMetricSettings.js";
|
|
14
15
|
import { CatalogDetailTags } from "./CatalogDetailTags.js";
|
|
15
|
-
export function CatalogDetailTabMetadata({ item, canEdit, onTagClick, onTagAdd, onTagRemove, onIsHiddenChange, onIsHiddenFromKdaChange, onMetricTypeChange, onFormatChange, onConditionalFormattingChange, separators, currencyFormatOverride, enableMetricFormatOverrides, accessRow, showDatasetRow, }) {
|
|
16
|
+
export function CatalogDetailTabMetadata({ item, canEdit, onTagClick, onTagAdd, onTagRemove, onIsHiddenChange, onIsHiddenFromKdaChange, onMetricTypeChange, onFormatChange, onConditionalFormattingChange, onLabelConditionalFormattingChange, separators, currencyFormatOverride, enableMetricFormatOverrides, accessRow, showDatasetRow, }) {
|
|
16
17
|
const enableSemanticConditionalFormatting = useFeatureFlag("enableSemanticConditionalFormatting");
|
|
17
18
|
const intl = useIntl();
|
|
18
19
|
const isMeasure = isCatalogItemMeasure(item);
|
|
20
|
+
const isAttribute = isCatalogItemAttribute(item);
|
|
19
21
|
const isDataSet = isCatalogItemDataSet(item);
|
|
20
22
|
const granularities = isDataSet ? (item.dataSet.attributes ?? []) : [];
|
|
21
|
-
const datasetTitle =
|
|
23
|
+
const datasetTitle = isAttribute || isCatalogItemFact(item) ? item.dataSet?.title : undefined;
|
|
22
24
|
return (_jsxs("dl", { className: "gd-analytics-catalog-detail__tab-content", children: [_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.type" }), content: getObjectTypeLabel(intl, item.type, getVisualizationType(item)) }), showDatasetRow && datasetTitle ? (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.dataSet" }), content: datasetTitle })) : null, isDataSet && granularities.length > 0 ? (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.granularities" }), content: _jsx(CatalogDetailGranularities, { granularities: granularities }) })) : null, _jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.createdBy" }), content: item.createdBy ?? undefined }), _jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.createdAt" }), content: item.createdAt ? _jsx(UiDate, { date: item.createdAt, locale: intl.locale }) : undefined }), item.createdBy === item.updatedBy && !item.updatedBy ? null : (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.updatedBy" }), content: item.updatedBy ?? undefined })), item.createdAt?.getTime() === item.updatedAt?.getTime() ? null : (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.updatedAt" }), content: item.updatedAt ? _jsx(UiDate, { date: item.updatedAt, locale: intl.locale }) : undefined })), isCatalogItemHidable(item) ? (_jsx(CatalogDetailContentRow, { title: _jsxs(_Fragment, { children: [_jsx(FormattedMessage, { id: "analyticsCatalog.column.title.isHidden" }), _jsx(UiTooltip, { anchor: _jsx(UiIcon, { type: "question", size: 12, color: "complementary-6" }), content: _jsx(FormattedMessage, { id: "analyticsCatalog.column.isHidden.field.tooltip" }), arrowPlacement: "left", optimalPlacement: true, offset: 10, triggerBy: ["hover", "click"] })] }), content: _jsxs("label", { className: "input-checkbox-toggle", children: [_jsx("input", { type: "checkbox", checked: item.isHidden !== true, disabled: !canEdit, "aria-label": intl.formatMessage({
|
|
23
25
|
id: "analyticsCatalog.column.title.isHidden",
|
|
24
26
|
}), onChange: (event) => {
|
|
@@ -27,5 +29,5 @@ export function CatalogDetailTabMetadata({ item, canEdit, onTagClick, onTagAdd,
|
|
|
27
29
|
id: "analyticsCatalog.column.title.isHiddenFromKda",
|
|
28
30
|
}), onChange: (event) => {
|
|
29
31
|
onIsHiddenFromKdaChange(!event.target.checked);
|
|
30
|
-
}, className: cx("s-checkbox-toggle", canEdit ? "s-enabled" : "s-disabled") }), _jsx("span", { className: "input-label-text" })] }) })) : null, isMeasure && enableMetricFormatOverrides ? (_jsx(CatalogDetailMetricSettings, { metricType: item.metricType, format: item.format, canEdit: canEdit, separators: separators, currencyFormatOverride: currencyFormatOverride, onMetricTypeChange: onMetricTypeChange, onFormatChange: onFormatChange, enableMetricFormatOverrides: enableMetricFormatOverrides })) : null, isMeasure && enableSemanticConditionalFormatting && onConditionalFormattingChange ? (_jsx(CatalogDetailConditionalFormatting, {
|
|
32
|
+
}, className: cx("s-checkbox-toggle", canEdit ? "s-enabled" : "s-disabled") }), _jsx("span", { className: "input-label-text" })] }) })) : null, isMeasure && enableMetricFormatOverrides ? (_jsx(CatalogDetailMetricSettings, { metricType: item.metricType, format: item.format, canEdit: canEdit, separators: separators, currencyFormatOverride: currencyFormatOverride, onMetricTypeChange: onMetricTypeChange, onFormatChange: onFormatChange, enableMetricFormatOverrides: enableMetricFormatOverrides })) : null, isMeasure && enableSemanticConditionalFormatting && onConditionalFormattingChange ? (_jsx(CatalogDetailConditionalFormatting, { targetOption: measureTargetOption(item), conditionalFormatting: item.conditionalFormatting, canEdit: canEdit, onConditionalFormattingChange: onConditionalFormattingChange, separators: separators })) : null, isAttribute && enableSemanticConditionalFormatting && onLabelConditionalFormattingChange ? (_jsx(CatalogDetailAttributeLabelsConditionalFormatting, { labels: item.labels ?? [], canEdit: canEdit, onLabelConditionalFormattingChange: onLabelConditionalFormattingChange, separators: separators })) : null, accessRow, _jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.tags" }), content: _jsx(CatalogDetailTags, { tags: item.tags, canEdit: canEdit, onTagClick: onTagClick, onTagAdd: onTagAdd, onTagRemove: onTagRemove }) })] }));
|
|
31
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCatalogItemLoad.d.ts","sourceRoot":"","sources":["../../../src/catalogDetail/hooks/useCatalogItemLoad.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useCatalogItemLoad.d.ts","sourceRoot":"","sources":["../../../src/catalogDetail/hooks/useCatalogItemLoad.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACrF,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAG5D,MAAM,WAAW,mBAAmB;IAChC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,gBAAgB,CAAC,EAAE,eAAe,GAAG,YAAY,GAAG,IAAI,CAAC;CAC5D;AAED,wBAAgB,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,mBAAmB,GAAG;IACjG,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IACpD,IAAI,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAC;CACjB,CAyDA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// (C) 2025-2026 GoodData Corporation
|
|
2
2
|
import { convertError, isNotFound, useBackendStrict, useCancelablePromise, useWorkspaceStrict, } from "@gooddata/sdk-ui";
|
|
3
3
|
import { convertAttributeToCatalogItem, convertComputedAttributeToCatalogItem, convertDashboardToCatalogItem, convertDataSetToCatalogItem, convertFactToCatalogItem, convertInsightToCatalogItem, convertMeasureToCatalogItem, convertParameterToCatalogItem, } from "../../catalogItem/converter.js";
|
|
4
|
-
import { isCatalogItemLoaded, isCatalogItemMeasure } from "../../catalogItem/guards.js";
|
|
4
|
+
import { isCatalogItemAttribute, isCatalogItemLoaded, isCatalogItemMeasure, } from "../../catalogItem/guards.js";
|
|
5
5
|
import {} from "../../catalogItem/types.js";
|
|
6
6
|
import {} from "../../objectType/types.js";
|
|
7
7
|
import { useFeatureFlag } from "../../permission/PermissionsContext.js";
|
|
@@ -11,7 +11,9 @@ export function useCatalogItemLoad({ objectDefinition, objectId, objectType }) {
|
|
|
11
11
|
const backend = useBackendStrict();
|
|
12
12
|
const workspace = useWorkspaceStrict();
|
|
13
13
|
const loadPermissions = useFeatureFlag("enableMetricPermissions");
|
|
14
|
-
const filled = isCatalogItemLoaded(objectDefinition) &&
|
|
14
|
+
const filled = isCatalogItemLoaded(objectDefinition) &&
|
|
15
|
+
!awaitsPermissions(objectDefinition, loadPermissions) &&
|
|
16
|
+
!awaitsLabels(objectDefinition);
|
|
15
17
|
const { status, error, result } = useCancelablePromise({
|
|
16
18
|
promise: () => {
|
|
17
19
|
// Object id and type are required
|
|
@@ -56,6 +58,10 @@ export function useCatalogItemLoad({ objectDefinition, objectId, objectType }) {
|
|
|
56
58
|
function awaitsPermissions(item, loadPermissions) {
|
|
57
59
|
return loadPermissions && isCatalogItemMeasure(item) && item.permissions === undefined;
|
|
58
60
|
}
|
|
61
|
+
// List queries don't include labels; only the detail fetch below does.
|
|
62
|
+
function awaitsLabels(item) {
|
|
63
|
+
return isCatalogItemAttribute(item) && item.labels === undefined;
|
|
64
|
+
}
|
|
59
65
|
async function loadObjectDefinition(workspace, id, type, loadPermissions) {
|
|
60
66
|
switch (type) {
|
|
61
67
|
case "attribute":
|
|
@@ -67,7 +73,10 @@ async function loadObjectDefinition(workspace, id, type, loadPermissions) {
|
|
|
67
73
|
}, {
|
|
68
74
|
include: ["dataset"],
|
|
69
75
|
})
|
|
70
|
-
.then(
|
|
76
|
+
.then((attribute) => ({
|
|
77
|
+
...convertAttributeToCatalogItem(attribute),
|
|
78
|
+
labels: attribute.displayForms,
|
|
79
|
+
}));
|
|
71
80
|
case "dataSet":
|
|
72
81
|
return workspace
|
|
73
82
|
.datasets()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type IUser, type MetricType } from "@gooddata/sdk-model";
|
|
1
|
+
import { type ISemanticConditionalFormatting, type IUser, type MetricType, type ObjRef } from "@gooddata/sdk-model";
|
|
2
2
|
import { type ICatalogItem, type ICatalogItemMeasure, type ICatalogItemRef } from "../../catalogItem/types.js";
|
|
3
3
|
import { type ObjectType } from "../../objectType/types.js";
|
|
4
4
|
export interface IUseCatalogItemUpdate {
|
|
@@ -22,6 +22,7 @@ export declare function useCatalogItemUpdate({ currentUser, objectId, objectType
|
|
|
22
22
|
updateItemMetricType: (metricType: MetricType | undefined) => void;
|
|
23
23
|
updateItemFormat: (format: string | null) => void;
|
|
24
24
|
updateItemConditionalFormatting: (conditionalFormatting: ICatalogItemMeasure["conditionalFormatting"]) => void;
|
|
25
|
+
updateItemLabelConditionalFormatting: (labelRef: ObjRef, conditionalFormatting: ISemanticConditionalFormatting | undefined) => void;
|
|
25
26
|
updateItemCertification: (certification: ICatalogItem["certification"]) => void;
|
|
26
27
|
applyItemUpdate: (updated: ICatalogItem) => void;
|
|
27
28
|
applyItemDelete: (ref: ICatalogItemRef) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCatalogItemUpdate.d.ts","sourceRoot":"","sources":["../../../src/catalogDetail/hooks/useCatalogItemUpdate.ts"],"names":[],"mappings":"AAOA,OAAO,
|
|
1
|
+
{"version":3,"file":"useCatalogItemUpdate.d.ts","sourceRoot":"","sources":["../../../src/catalogDetail/hooks/useCatalogItemUpdate.ts"],"names":[],"mappings":"AAOA,OAAO,EACH,KAAK,8BAA8B,EACnC,KAAK,KAAK,EACV,KAAK,UAAU,EACf,KAAK,MAAM,EAEd,MAAM,qBAAqB,CAAC;AAgB7B,OAAO,EACH,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACvB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAI5D,MAAM,WAAW,qBAAqB;IAClC,WAAW,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,gBAAgB,CAAC,EAAE,eAAe,GAAG,YAAY,GAAG,IAAI,CAAC;IACzD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IAC1C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACpC;AAID,wBAAgB,oBAAoB,CAAC,EACjC,WAAW,EACX,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,QAAQ,EACR,QAAQ,EACR,OAAO,GACV,EAAE,qBAAqB;;;;6BAyFR,MAAM;yCAIA,MAAM;2BAIb,MAAM,EAAE;mCAIJ,OAAO;iDAQA,OAAO;uCAQZ,UAAU,GAAG,SAAS;+BAY1B,MAAM,GAAG,IAAI;6DAYE,mBAAmB,CAAC,uBAAuB,CAAC;qDAYzD,MAAM,yBAAyB,8BAA8B,GAAG,SAAS;6CAqBpE,YAAY,CAAC,eAAe,CAAC;+BApInC,YAAY;2BAUhB,eAAe;EA6J5B"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// (C) 2025-2026 GoodData Corporation
|
|
2
2
|
import { useCallback, useEffect, useState } from "react";
|
|
3
3
|
import { isEqual } from "lodash-es";
|
|
4
|
-
import {} from "@gooddata/sdk-model";
|
|
4
|
+
import { areObjRefsEqual, } from "@gooddata/sdk-model";
|
|
5
5
|
import { useBackendStrict, useWorkspaceStrict } from "@gooddata/sdk-ui";
|
|
6
6
|
import { getDisplayName } from "../../catalogItem/converter.js";
|
|
7
|
-
import { isCatalogItemHidable, isCatalogItemLoaded, isCatalogItemMeasure } from "../../catalogItem/guards.js";
|
|
8
|
-
import { persistMeasureConditionalFormatting, updateCatalogItem, updateCatalogItemCertification, } from "../../catalogItem/query.js";
|
|
7
|
+
import { isCatalogItemAttribute, isCatalogItemHidable, isCatalogItemLoaded, isCatalogItemMeasure, } from "../../catalogItem/guards.js";
|
|
8
|
+
import { persistLabelConditionalFormatting, persistMeasureConditionalFormatting, updateCatalogItem, updateCatalogItemCertification, } from "../../catalogItem/query.js";
|
|
9
9
|
import {} from "../../catalogItem/types.js";
|
|
10
10
|
import { useMounted } from "../../hooks/useMounted.js";
|
|
11
11
|
import {} from "../../objectType/types.js";
|
|
@@ -48,142 +48,66 @@ export function useCatalogItemUpdate({ currentUser, objectId, objectType, object
|
|
|
48
48
|
setItem(null);
|
|
49
49
|
onDelete?.(ref);
|
|
50
50
|
}, [onDelete]);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}), (newItem) => {
|
|
51
|
+
// One optimistic update flow for every field: apply locally, persist, revert on failure.
|
|
52
|
+
const runUpdate = useCallback((target, updater, persist, options) => {
|
|
53
|
+
updateItem(backend, workspace, currentUser, target, status !== "success", updater, (newItem) => {
|
|
55
54
|
setItem(newItem);
|
|
56
55
|
onUpdate?.(newItem);
|
|
57
56
|
}, (err) => {
|
|
58
|
-
revertItemUpdate(err,
|
|
59
|
-
});
|
|
60
|
-
}, [backend, currentUser,
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}), (newItem) => {
|
|
65
|
-
setItem(newItem);
|
|
66
|
-
onUpdate?.(newItem);
|
|
67
|
-
}, (err) => {
|
|
68
|
-
revertItemUpdate(err, item);
|
|
69
|
-
});
|
|
70
|
-
}, [backend, currentUser, item, onUpdate, revertItemUpdate, status, workspace]);
|
|
71
|
-
const updateItemTags = useCallback((tags) => {
|
|
72
|
-
updateItem(backend, workspace, currentUser, item, status !== "success", () => ({
|
|
73
|
-
tags,
|
|
74
|
-
}), (newItem) => {
|
|
75
|
-
setItem(newItem);
|
|
76
|
-
onUpdate?.(newItem);
|
|
77
|
-
}, (err) => {
|
|
78
|
-
revertItemUpdate(err, item);
|
|
79
|
-
});
|
|
80
|
-
}, [backend, currentUser, item, onUpdate, revertItemUpdate, status, workspace]);
|
|
57
|
+
revertItemUpdate(err, target);
|
|
58
|
+
}, persist, options);
|
|
59
|
+
}, [backend, currentUser, onUpdate, revertItemUpdate, status, workspace]);
|
|
60
|
+
const updateItemTitle = useCallback((title) => runUpdate(item, () => ({ title })), [item, runUpdate]);
|
|
61
|
+
const updateItemDescription = useCallback((description) => runUpdate(item, () => ({ description })), [item, runUpdate]);
|
|
62
|
+
const updateItemTags = useCallback((tags) => runUpdate(item, () => ({ tags })), [item, runUpdate]);
|
|
81
63
|
const updateItemIsHidden = useCallback((isHidden) => {
|
|
82
|
-
if (
|
|
83
|
-
|
|
64
|
+
if (isCatalogItemHidable(item)) {
|
|
65
|
+
runUpdate(item, () => ({ isHidden }));
|
|
84
66
|
}
|
|
85
|
-
|
|
86
|
-
isHidden,
|
|
87
|
-
}), (newItem) => {
|
|
88
|
-
setItem(newItem);
|
|
89
|
-
onUpdate?.(newItem);
|
|
90
|
-
}, (err) => {
|
|
91
|
-
revertItemUpdate(err, item);
|
|
92
|
-
});
|
|
93
|
-
}, [backend, currentUser, item, onUpdate, revertItemUpdate, status, workspace]);
|
|
67
|
+
}, [item, runUpdate]);
|
|
94
68
|
const updateItemIsHiddenFromKda = useCallback((isHiddenFromKda) => {
|
|
95
|
-
if (
|
|
96
|
-
|
|
69
|
+
if (isCatalogItemMeasure(item)) {
|
|
70
|
+
runUpdate(item, () => ({ isHiddenFromKda }));
|
|
97
71
|
}
|
|
98
|
-
|
|
99
|
-
isHiddenFromKda,
|
|
100
|
-
}), (newItem) => {
|
|
101
|
-
setItem(newItem);
|
|
102
|
-
onUpdate?.(newItem);
|
|
103
|
-
}, (err) => {
|
|
104
|
-
revertItemUpdate(err, item);
|
|
105
|
-
});
|
|
106
|
-
}, [backend, currentUser, item, onUpdate, revertItemUpdate, status, workspace]);
|
|
107
|
-
const persistMeasureChanges = useCallback((nextItem) => persistMeasureMetadata(backend, workspace, nextItem), [backend, workspace]);
|
|
72
|
+
}, [item, runUpdate]);
|
|
108
73
|
const updateItemMetricType = useCallback((metricType) => {
|
|
109
|
-
if (
|
|
110
|
-
|
|
74
|
+
if (isCatalogItemMeasure(item)) {
|
|
75
|
+
runUpdate(item, () => ({ metricType }), (next) => persistMeasureMetadata(backend, workspace, next));
|
|
111
76
|
}
|
|
112
|
-
|
|
113
|
-
metricType,
|
|
114
|
-
}), (newItem) => {
|
|
115
|
-
setItem(newItem);
|
|
116
|
-
onUpdate?.(newItem);
|
|
117
|
-
}, (err) => {
|
|
118
|
-
revertItemUpdate(err, item);
|
|
119
|
-
}, persistMeasureChanges);
|
|
120
|
-
}, [backend, currentUser, item, onUpdate, persistMeasureChanges, revertItemUpdate, status, workspace]);
|
|
77
|
+
}, [backend, item, runUpdate, workspace]);
|
|
121
78
|
const updateItemFormat = useCallback((format) => {
|
|
122
|
-
if (
|
|
123
|
-
|
|
79
|
+
if (isCatalogItemMeasure(item)) {
|
|
80
|
+
runUpdate(item, () => ({ format }), (next) => persistMeasureMetadata(backend, workspace, next));
|
|
124
81
|
}
|
|
125
|
-
|
|
126
|
-
format,
|
|
127
|
-
}), (newItem) => {
|
|
128
|
-
setItem(newItem);
|
|
129
|
-
onUpdate?.(newItem);
|
|
130
|
-
}, (err) => {
|
|
131
|
-
revertItemUpdate(err, item);
|
|
132
|
-
}, persistMeasureChanges);
|
|
133
|
-
}, [backend, currentUser, item, onUpdate, persistMeasureChanges, revertItemUpdate, status, workspace]);
|
|
134
|
-
const persistMeasureConditionalFormattingChanges = useCallback((nextItem) => persistMeasureConditionalFormatting(backend, workspace, nextItem), [backend, workspace]);
|
|
82
|
+
}, [backend, item, runUpdate, workspace]);
|
|
135
83
|
const updateItemConditionalFormatting = useCallback((conditionalFormatting) => {
|
|
136
|
-
if (
|
|
84
|
+
if (isCatalogItemMeasure(item)) {
|
|
85
|
+
runUpdate(item, () => ({ conditionalFormatting }), (next) => persistMeasureConditionalFormatting(backend, workspace, next));
|
|
86
|
+
}
|
|
87
|
+
}, [backend, item, runUpdate, workspace]);
|
|
88
|
+
const updateItemLabelConditionalFormatting = useCallback((labelRef, conditionalFormatting) => {
|
|
89
|
+
if (!isCatalogItemAttribute(item)) {
|
|
137
90
|
return;
|
|
138
91
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
},
|
|
147
|
-
}, [
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const updateItemCertification = useCallback((certification) => {
|
|
159
|
-
updateItem(backend, workspace, currentUser, item, status !== "success", () => ({
|
|
160
|
-
certification: certification
|
|
161
|
-
? {
|
|
162
|
-
...certification,
|
|
163
|
-
...(certification.status === "CERTIFIED"
|
|
164
|
-
? {
|
|
165
|
-
certifiedAt: new Date(),
|
|
166
|
-
certifiedBy: getDisplayName(currentUser),
|
|
167
|
-
}
|
|
168
|
-
: {}),
|
|
169
|
-
}
|
|
170
|
-
: undefined,
|
|
171
|
-
}), (newItem) => {
|
|
172
|
-
setItem(newItem);
|
|
173
|
-
onUpdate?.(newItem);
|
|
174
|
-
}, (err) => {
|
|
175
|
-
revertItemUpdate(err, item);
|
|
176
|
-
}, persistCertificationChanges);
|
|
177
|
-
}, [
|
|
178
|
-
backend,
|
|
179
|
-
currentUser,
|
|
180
|
-
item,
|
|
181
|
-
onUpdate,
|
|
182
|
-
persistCertificationChanges,
|
|
183
|
-
revertItemUpdate,
|
|
184
|
-
status,
|
|
185
|
-
workspace,
|
|
186
|
-
]);
|
|
92
|
+
const label = item.labels?.find((candidate) => areObjRefsEqual(candidate.ref, labelRef));
|
|
93
|
+
if (!label) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const updatedLabel = { ...label, conditionalFormatting };
|
|
97
|
+
runUpdate(item, () => ({
|
|
98
|
+
labels: item.labels?.map((candidate) => (candidate === label ? updatedLabel : candidate)),
|
|
99
|
+
}), () => persistLabelConditionalFormatting(backend, workspace, updatedLabel), { touch: false });
|
|
100
|
+
}, [backend, item, runUpdate, workspace]);
|
|
101
|
+
const updateItemCertification = useCallback((certification) => runUpdate(item, () => ({
|
|
102
|
+
certification: certification
|
|
103
|
+
? {
|
|
104
|
+
...certification,
|
|
105
|
+
...(certification.status === "CERTIFIED"
|
|
106
|
+
? { certifiedAt: new Date(), certifiedBy: getDisplayName(currentUser) }
|
|
107
|
+
: {}),
|
|
108
|
+
}
|
|
109
|
+
: undefined,
|
|
110
|
+
}), (next) => updateCatalogItemCertification(backend, workspace, next)), [backend, currentUser, item, runUpdate, workspace]);
|
|
187
111
|
return {
|
|
188
112
|
item,
|
|
189
113
|
status,
|
|
@@ -196,12 +120,13 @@ export function useCatalogItemUpdate({ currentUser, objectId, objectType, object
|
|
|
196
120
|
updateItemMetricType,
|
|
197
121
|
updateItemFormat,
|
|
198
122
|
updateItemConditionalFormatting,
|
|
123
|
+
updateItemLabelConditionalFormatting,
|
|
199
124
|
updateItemCertification,
|
|
200
125
|
applyItemUpdate,
|
|
201
126
|
applyItemDelete,
|
|
202
127
|
};
|
|
203
128
|
}
|
|
204
|
-
function updateItem(backend, workspace, user, item, disabled, updater, onUpdate, onError, persist) {
|
|
129
|
+
function updateItem(backend, workspace, user, item, disabled, updater, onUpdate, onError, persist, options = {}) {
|
|
205
130
|
if (disabled || !item) {
|
|
206
131
|
return;
|
|
207
132
|
}
|
|
@@ -209,7 +134,8 @@ function updateItem(backend, workspace, user, item, disabled, updater, onUpdate,
|
|
|
209
134
|
if (!hasChanges(item, itemChanges)) {
|
|
210
135
|
return;
|
|
211
136
|
}
|
|
212
|
-
|
|
137
|
+
// A label patch does not touch the attribute itself, so it must not stamp updatedAt/updatedBy.
|
|
138
|
+
const newItem = options.touch === false ? { ...item, ...itemChanges } : makeUpdatedItem(user, item, itemChanges);
|
|
213
139
|
onUpdate(newItem);
|
|
214
140
|
const persistFn = persist ?? ((nextItem) => updateCatalogItem(backend, workspace, nextItem));
|
|
215
141
|
Promise.resolve(persistFn(newItem)).catch(onError);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IAnalyticalBackend } from "@gooddata/sdk-backend-spi";
|
|
2
|
-
import { type IMeasureMetadataObject, type IMeasureMetadataObjectDefinition, type IParameterMetadataObjectDefinition, type ObjRef } from "@gooddata/sdk-model";
|
|
2
|
+
import { type IAttributeDisplayFormMetadataObject, type IMeasureMetadataObject, type IMeasureMetadataObjectDefinition, type IParameterMetadataObjectDefinition, type ObjRef } from "@gooddata/sdk-model";
|
|
3
3
|
import type { ICatalogItem, ICatalogItemMeasure, ICatalogItemQueryOptions } from "./types.js";
|
|
4
4
|
export declare function getDashboardsQuery({ backend, workspace, search, origin, id, excludeId, createdBy, excludeCreatedBy, tags, excludeTags, isHidden, certification, pageSize, }: ICatalogItemQueryOptions): import("@gooddata/sdk-backend-spi").IDashboardsQuery;
|
|
5
5
|
export declare function getInsightsQuery({ backend, workspace, search, origin, id, excludeId, createdBy, excludeCreatedBy, tags, excludeTags, isHidden, certification, pageSize, }: ICatalogItemQueryOptions): import("@gooddata/sdk-backend-spi").IInsightsQuery;
|
|
@@ -10,7 +10,8 @@ export declare function getAttributesQuery({ backend, workspace, search, origin,
|
|
|
10
10
|
export declare function getFactsQuery({ backend, workspace, search, origin, id, excludeId, tags, excludeTags, isHidden, pageSize, }: ICatalogItemQueryOptions): import("@gooddata/sdk-backend-spi").IFactsQuery;
|
|
11
11
|
export declare function getDateDatasetsQuery({ backend, workspace, search, origin, id, excludeId, tags, excludeTags, isHidden, pageSize, }: ICatalogItemQueryOptions): import("@gooddata/sdk-backend-spi").IDatasetsQuery;
|
|
12
12
|
export declare function updateCatalogItem(backend: IAnalyticalBackend, workspace: string, item: ICatalogItem): Promise<import("@gooddata/sdk-model").IAttributeMetadataObject> | Promise<import("@gooddata/sdk-model").IDashboard<import("@gooddata/sdk-model").IDashboardWidget>> | Promise<import("@gooddata/sdk-model").IDataSetMetadataObject> | Promise<import("@gooddata/sdk-model").IFactMetadataObject> | Promise<import("@gooddata/sdk-model").IParameterMetadataObject> | Promise<import("@gooddata/sdk-model").IComputedAttributeMetadataObject> | Promise<import("@gooddata/sdk-model").IInsight> | Promise<IMeasureMetadataObject>;
|
|
13
|
-
export declare function persistMeasureConditionalFormatting(backend: IAnalyticalBackend, workspace: string, item: ICatalogItemMeasure): Promise<
|
|
13
|
+
export declare function persistMeasureConditionalFormatting(backend: IAnalyticalBackend, workspace: string, item: ICatalogItemMeasure): Promise<IMeasureMetadataObject>;
|
|
14
|
+
export declare function persistLabelConditionalFormatting(backend: IAnalyticalBackend, workspace: string, label: IAttributeDisplayFormMetadataObject): Promise<IAttributeDisplayFormMetadataObject>;
|
|
14
15
|
export declare function createParameterCatalogItem(backend: IAnalyticalBackend, workspace: string, parameter: IParameterMetadataObjectDefinition): Promise<import("@gooddata/sdk-model").IParameterMetadataObject>;
|
|
15
16
|
export declare function updateParameterCatalogItem(backend: IAnalyticalBackend, workspace: string, definition: IParameterMetadataObjectDefinition & {
|
|
16
17
|
id: string;
|