@gooddata/sdk-ui-catalog 11.50.0-alpha.2 → 11.50.0-alpha.4
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/AnalyticsCatalogDetail.d.ts.map +1 -1
- package/esm/AnalyticsCatalogDetail.js +1 -3
- package/esm/asCode/AsCodeCreateDialog.d.ts +3 -7
- package/esm/asCode/AsCodeCreateDialog.d.ts.map +1 -1
- package/esm/asCode/AsCodeCreateDialog.js +13 -23
- package/esm/asCode/AsCodeDeleteDialog.d.ts +1 -6
- package/esm/asCode/AsCodeDeleteDialog.d.ts.map +1 -1
- package/esm/asCode/AsCodeDeleteDialog.js +11 -20
- package/esm/asCode/AsCodeDetailActions.d.ts +2 -11
- package/esm/asCode/AsCodeDetailActions.d.ts.map +1 -1
- package/esm/asCode/AsCodeDetailActions.js +16 -22
- package/esm/asCode/AsCodeDialog.d.ts +12 -17
- package/esm/asCode/AsCodeDialog.d.ts.map +1 -1
- package/esm/asCode/AsCodeDialog.js +59 -27
- package/esm/asCode/AsCodeEditDialog.d.ts +3 -8
- package/esm/asCode/AsCodeEditDialog.d.ts.map +1 -1
- package/esm/asCode/AsCodeEditDialog.js +4 -21
- package/esm/asCode/descriptor.d.ts +78 -104
- package/esm/asCode/descriptor.d.ts.map +1 -1
- package/esm/asCode/descriptor.js +13 -4
- package/esm/asCode/serverIdentity.d.ts +7 -0
- package/esm/asCode/serverIdentity.d.ts.map +1 -0
- package/esm/asCode/serverIdentity.js +2 -0
- package/esm/asCode/tests/withMutationPort.d.ts +4 -0
- package/esm/asCode/tests/withMutationPort.d.ts.map +1 -0
- package/esm/asCode/tests/withMutationPort.js +5 -0
- package/esm/asCode/useAsCodeBase.d.ts +5 -8
- package/esm/asCode/useAsCodeBase.d.ts.map +1 -1
- package/esm/asCode/useAsCodeBase.js +20 -18
- package/esm/asCode/useAsCodeLoadFailure.d.ts +8 -0
- package/esm/asCode/useAsCodeLoadFailure.d.ts.map +1 -0
- package/esm/asCode/useAsCodeLoadFailure.js +21 -0
- package/esm/asCode/useMutationPort.d.ts +4 -0
- package/esm/asCode/useMutationPort.d.ts.map +1 -0
- package/esm/asCode/useMutationPort.js +9 -0
- package/esm/asCode/validateYaml.d.ts +16 -12
- package/esm/asCode/validateYaml.d.ts.map +1 -1
- package/esm/asCode/validateYaml.js +8 -9
- package/esm/asCodeRegistry.d.ts +5 -14
- package/esm/asCodeRegistry.d.ts.map +1 -1
- package/esm/asCodeRegistry.js +29 -15
- package/esm/catalog/Catalog.d.ts.map +1 -1
- package/esm/catalog/Catalog.js +2 -8
- package/esm/catalogDetail/CatalogDetailActionBar.d.ts.map +1 -1
- package/esm/catalogDetail/CatalogDetailActionBar.js +4 -8
- package/esm/catalogDetail/CatalogDetailActions.d.ts.map +1 -1
- package/esm/catalogDetail/CatalogDetailActions.js +2 -6
- package/esm/catalogDetail/openHandlerEvent.d.ts +6 -0
- package/esm/catalogDetail/openHandlerEvent.d.ts.map +1 -0
- package/esm/catalogDetail/openHandlerEvent.js +10 -0
- package/esm/header/CreateObjectButton.d.ts +1 -3
- package/esm/header/CreateObjectButton.d.ts.map +1 -1
- package/esm/header/CreateObjectButton.js +10 -22
- package/esm/index.d.ts +2 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +5 -0
- package/esm/insight/gate.d.ts +4 -0
- package/esm/insight/gate.d.ts.map +1 -0
- package/esm/insight/gate.js +4 -0
- package/esm/insight/insightCodecContext.d.ts +22 -0
- package/esm/insight/insightCodecContext.d.ts.map +1 -0
- package/esm/insight/insightCodecContext.js +30 -0
- package/esm/insight/insightCopy.d.ts +4 -0
- package/esm/insight/insightCopy.d.ts.map +1 -0
- package/esm/insight/insightCopy.js +25 -0
- package/esm/insight/insightDescriptor.d.ts +7 -0
- package/esm/insight/insightDescriptor.d.ts.map +1 -0
- package/esm/insight/insightDescriptor.js +69 -0
- package/esm/insight/insightMutationPort.d.ts +13 -0
- package/esm/insight/insightMutationPort.d.ts.map +1 -0
- package/esm/insight/insightMutationPort.js +59 -0
- package/esm/localization/bundles/en-US.localization-bundle.d.ts +72 -0
- package/esm/localization/bundles/en-US.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/en-US.localization-bundle.js +72 -0
- package/esm/metric/gate.d.ts +1 -6
- package/esm/metric/gate.d.ts.map +1 -1
- package/esm/metric/gate.js +1 -9
- package/esm/metric/metricConverter.d.ts +8 -17
- package/esm/metric/metricConverter.d.ts.map +1 -1
- package/esm/metric/metricConverter.js +10 -24
- package/esm/metric/metricDescriptor.d.ts.map +1 -1
- package/esm/metric/metricDescriptor.js +19 -8
- package/esm/metric/metricMutationPort.d.ts +5 -3
- package/esm/metric/metricMutationPort.d.ts.map +1 -1
- package/esm/metric/metricMutationPort.js +21 -14
- package/esm/metric/metricValidation.d.ts.map +1 -1
- package/esm/metric/metricValidation.js +7 -4
- package/esm/metric/tests/metricMutationPort.test.utils.d.ts +1 -4
- package/esm/metric/tests/metricMutationPort.test.utils.d.ts.map +1 -1
- package/esm/metric/tests/metricMutationPort.test.utils.js +1 -19
- package/esm/parameter/gate.d.ts +1 -5
- package/esm/parameter/gate.d.ts.map +1 -1
- package/esm/parameter/gate.js +1 -8
- package/esm/parameter/parameterDescriptor.d.ts.map +1 -1
- package/esm/parameter/parameterDescriptor.js +22 -13
- package/esm/parameter/parameterValidation.d.ts.map +1 -1
- package/esm/parameter/parameterValidation.js +11 -23
- package/esm/sdk-ui-catalog.d.ts +49 -0
- package/package.json +15 -15
- package/esm/asCode/AsCodeMutationContext.d.ts +0 -24
- package/esm/asCode/AsCodeMutationContext.d.ts.map +0 -1
- package/esm/asCode/AsCodeMutationContext.js +0 -40
- package/esm/asCode/gate.d.ts +0 -7
- package/esm/asCode/gate.d.ts.map +0 -1
- package/esm/asCode/gate.js +0 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyticsCatalogDetail.d.ts","sourceRoot":"","sources":["../src/AnalyticsCatalogDetail.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAqB,MAAM,OAAO,CAAC;AAE3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"AnalyticsCatalogDetail.d.ts","sourceRoot":"","sources":["../src/AnalyticsCatalogDetail.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAqB,MAAM,OAAO,CAAC;AAE3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAIpE,OAAO,EAAiB,KAAK,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC3F,OAAO,EAEH,KAAK,0BAA0B,EAClC,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAGjE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAMxD;;GAEG;AACH,MAAM,WAAW,4BAA6B,SAAQ,IAAI,CAAC,mBAAmB,EAAE,UAAU,GAAG,YAAY,CAAC;IACtG;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,UAAU,EAAE,UAAU,CAAC;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,EACnC,OAAO,EACP,SAAS,EACT,MAAM,EACN,GAAG,SAAS,EACf,EAAE,4BAA4B,2CAM9B;AAED;;GAEG;AACH,MAAM,WAAW,mCAAoC,SAAQ,IAAI,CAC7D,0BAA0B,EAC1B,UAAU,GAAG,YAAY,CAC5B;IACG;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,UAAU,EAAE,UAAU,CAAC;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,KAAK,IAAI,CAAC;CAC3E;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,EAC1C,OAAO,EACP,SAAS,EACT,MAAM,EACN,GAAG,SAAS,EACf,EAAE,mCAAmC,2CAMrC"}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { BackendProvider, WorkspaceProvider, useBackendStrict, useWorkspaceStrict } from "@gooddata/sdk-ui";
|
|
3
3
|
import { ToastsCenterContextProvider } from "@gooddata/sdk-ui-kit";
|
|
4
|
-
import { AsCodeMutationProvider } from "./asCode/AsCodeMutationContext.js";
|
|
5
|
-
import { asCodeDescriptors } from "./asCodeRegistry.js";
|
|
6
4
|
import { CatalogDetail } from "./catalogDetail/CatalogDetail.js";
|
|
7
5
|
import { CatalogDetailContent, } from "./catalogDetail/CatalogDetailContent.js";
|
|
8
6
|
import { CatalogResourceProvider } from "./catalogResource/CatalogResourceProvider.js";
|
|
@@ -28,5 +26,5 @@ function Providers(props) {
|
|
|
28
26
|
const backend = useBackendStrict(props.backend);
|
|
29
27
|
const workspace = useWorkspaceStrict(props.workspace);
|
|
30
28
|
const permissionsState = usePermissionsQuery({ backend, workspace });
|
|
31
|
-
return (_jsx(BackendProvider, { backend: backend, children: _jsx(WorkspaceProvider, { workspace: workspace, children: _jsx(IntlWrapper, { locale: props.locale, children: _jsx(ToastsCenterContextProvider, { children: _jsx(OverlayProvider, { children: _jsx(PermissionsProvider, { permissionsState: permissionsState, children: _jsx(QualityProvider, { backend: backend, workspace: workspace, children: _jsx(CatalogResourceProvider, { backend: backend, workspace: workspace, children:
|
|
29
|
+
return (_jsx(BackendProvider, { backend: backend, children: _jsx(WorkspaceProvider, { workspace: workspace, children: _jsx(IntlWrapper, { locale: props.locale, children: _jsx(ToastsCenterContextProvider, { children: _jsx(OverlayProvider, { children: _jsx(PermissionsProvider, { permissionsState: permissionsState, children: _jsx(QualityProvider, { backend: backend, workspace: workspace, children: _jsx(CatalogResourceProvider, { backend: backend, workspace: workspace, children: props.children }) }) }) }) }) }) }) }));
|
|
32
30
|
}
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import type { ICatalogItem } from "../catalogItem/types.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { IAsCodeDescriptor } from "./descriptor.js";
|
|
3
3
|
type Props = {
|
|
4
4
|
descriptor: IAsCodeDescriptor;
|
|
5
5
|
duplicateOf?: ICatalogItem;
|
|
6
|
-
duplicateSource?:
|
|
6
|
+
duplicateSource?: unknown;
|
|
7
7
|
onClose: () => void;
|
|
8
8
|
onCreated?: (item: ICatalogItem) => void;
|
|
9
9
|
};
|
|
10
|
-
/**
|
|
11
|
-
* Creates an as-code object — blank, or seeded from a copy source when duplicating. Generic over the
|
|
12
|
-
* entity type via its descriptor.
|
|
13
|
-
* @internal
|
|
14
|
-
*/
|
|
10
|
+
/** @internal */
|
|
15
11
|
export declare function AsCodeCreateDialog({ descriptor, duplicateOf, duplicateSource, onClose, onCreated }: Props): import("react/jsx-runtime").JSX.Element;
|
|
16
12
|
export {};
|
|
17
13
|
//# sourceMappingURL=AsCodeCreateDialog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AsCodeCreateDialog.d.ts","sourceRoot":"","sources":["../../src/asCode/AsCodeCreateDialog.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAI5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"AsCodeCreateDialog.d.ts","sourceRoot":"","sources":["../../src/asCode/AsCodeCreateDialog.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAI5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGzD,KAAK,KAAK,GAAG;IACT,UAAU,EAAE,iBAAiB,CAAC;IAC9B,WAAW,CAAC,EAAE,YAAY,CAAC;IAE3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CAC5C,CAAC;AAEF,gBAAgB;AAChB,wBAAgB,kBAAkB,CAAC,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,KAAK,2CAqDzG"}
|
|
@@ -6,38 +6,28 @@ import { useToastMessage } from "@gooddata/sdk-ui-kit";
|
|
|
6
6
|
import { AsCodeDialog } from "./AsCodeDialog.js";
|
|
7
7
|
import { isDuplicateIdError } from "./copy.js";
|
|
8
8
|
import { useAsCodeBase } from "./useAsCodeBase.js";
|
|
9
|
-
/**
|
|
10
|
-
* Creates an as-code object — blank, or seeded from a copy source when duplicating. Generic over the
|
|
11
|
-
* entity type via its descriptor.
|
|
12
|
-
* @internal
|
|
13
|
-
*/
|
|
9
|
+
/** @internal */
|
|
14
10
|
export function AsCodeCreateDialog({ descriptor, duplicateOf, duplicateSource, onClose, onCreated }) {
|
|
15
11
|
const intl = useIntl();
|
|
16
|
-
const { addSuccess
|
|
17
|
-
const { base: loadedSource, isLoading, port
|
|
18
|
-
if (descriptor.messages.loadError) {
|
|
19
|
-
addError(descriptor.messages.loadError);
|
|
20
|
-
}
|
|
21
|
-
onClose();
|
|
22
|
-
});
|
|
12
|
+
const { addSuccess } = useToastMessage();
|
|
13
|
+
const { base: loadedSource, isLoading, port } = useAsCodeBase(descriptor, duplicateOf, onClose);
|
|
23
14
|
const source = duplicateSource ?? loadedSource;
|
|
24
15
|
const copied = useMemo(() => (source === undefined ? undefined : descriptor.toCopy(source)), [descriptor, source]);
|
|
25
16
|
const initialDefinition = useMemo(() => copied ?? descriptor.emptyDefinition(intl.formatMessage(descriptor.messages.createDefaultTitle)), [copied, descriptor, intl]);
|
|
26
|
-
const
|
|
17
|
+
const identity = descriptor.identity;
|
|
18
|
+
const copiedId = copied === undefined ? undefined : identity?.read(copied);
|
|
27
19
|
const handleSubmit = useCallback(async (definition) => {
|
|
28
|
-
// A duplicate re-applies the copied source's non-YAML fields; otherwise persist the parsed YAML.
|
|
29
|
-
const toPersist = copied && descriptor.applyYamlEdits
|
|
30
|
-
? descriptor.applyYamlEdits(copied, definition)
|
|
31
|
-
: definition;
|
|
32
20
|
let created;
|
|
33
21
|
try {
|
|
34
|
-
created = await port.create(
|
|
22
|
+
created = await port.create(definition);
|
|
35
23
|
}
|
|
36
24
|
catch (error) {
|
|
37
|
-
// The copied
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
25
|
+
// The copied id collided; retry without it so the backend assigns a fresh one.
|
|
26
|
+
if (identity !== undefined &&
|
|
27
|
+
copiedId !== undefined &&
|
|
28
|
+
identity.read(definition) === copiedId &&
|
|
29
|
+
isDuplicateIdError(error)) {
|
|
30
|
+
created = await port.create(identity.strip(definition));
|
|
41
31
|
}
|
|
42
32
|
else {
|
|
43
33
|
throw error;
|
|
@@ -46,6 +36,6 @@ export function AsCodeCreateDialog({ descriptor, duplicateOf, duplicateSource, o
|
|
|
46
36
|
onCreated?.(created);
|
|
47
37
|
onClose();
|
|
48
38
|
addSuccess(descriptor.messages.createSuccess);
|
|
49
|
-
}, [addSuccess,
|
|
39
|
+
}, [addSuccess, copiedId, descriptor, identity, onClose, onCreated, port]);
|
|
50
40
|
return (_jsx(AsCodeDialog, { descriptor: descriptor, mode: "create", isLoading: isLoading, initialDefinition: isLoading ? undefined : initialDefinition, onClose: onClose, onSubmit: handleSubmit }));
|
|
51
41
|
}
|
|
@@ -6,12 +6,7 @@ type Props = {
|
|
|
6
6
|
onClose: () => void;
|
|
7
7
|
onDeleted: () => void;
|
|
8
8
|
};
|
|
9
|
-
/**
|
|
10
|
-
* Confirms deletion of an as-code object. A type that reports a referencing count (see
|
|
11
|
-
* `port.getReferencingObjectsCount`) withholds the confirm until the lookup resolves and warns when
|
|
12
|
-
* the object is in use; a type without one deletes straight away. Generic over the descriptor.
|
|
13
|
-
* @internal
|
|
14
|
-
*/
|
|
9
|
+
/** @internal */
|
|
15
10
|
export declare function AsCodeDeleteDialog({ descriptor, item, onClose, onDeleted }: Props): import("react/jsx-runtime").JSX.Element;
|
|
16
11
|
export {};
|
|
17
12
|
//# sourceMappingURL=AsCodeDeleteDialog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AsCodeDeleteDialog.d.ts","sourceRoot":"","sources":["../../src/asCode/AsCodeDeleteDialog.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"AsCodeDeleteDialog.d.ts","sourceRoot":"","sources":["../../src/asCode/AsCodeDeleteDialog.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAOzD,KAAK,KAAK,GAAG;IACT,UAAU,EAAE,iBAAiB,CAAC;IAC9B,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF,gBAAgB;AAChB,wBAAgB,kBAAkB,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,KAAK,2CAoEjF"}
|
|
@@ -2,33 +2,24 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
// (C) 2026 GoodData Corporation
|
|
3
3
|
import { useCallback, useState } from "react";
|
|
4
4
|
import { FormattedMessage, defineMessages, useIntl } from "react-intl";
|
|
5
|
-
import { useCancelablePromise } from "@gooddata/sdk-ui";
|
|
5
|
+
import { useBackendStrict, useCancelablePromise, useWorkspaceStrict } from "@gooddata/sdk-ui";
|
|
6
6
|
import { ConfirmDialog, useToastMessage } from "@gooddata/sdk-ui-kit";
|
|
7
|
-
import {
|
|
7
|
+
import { useMutationPort } from "./useMutationPort.js";
|
|
8
8
|
const messages = defineMessages({
|
|
9
9
|
cancel: { id: "analyticsCatalog.asCode.dialog.cancel" },
|
|
10
10
|
});
|
|
11
|
-
/**
|
|
12
|
-
* Confirms deletion of an as-code object. A type that reports a referencing count (see
|
|
13
|
-
* `port.getReferencingObjectsCount`) withholds the confirm until the lookup resolves and warns when
|
|
14
|
-
* the object is in use; a type without one deletes straight away. Generic over the descriptor.
|
|
15
|
-
* @internal
|
|
16
|
-
*/
|
|
11
|
+
/** @internal */
|
|
17
12
|
export function AsCodeDeleteDialog({ descriptor, item, onClose, onDeleted }) {
|
|
18
13
|
const intl = useIntl();
|
|
19
14
|
const { addSuccess, addError } = useToastMessage();
|
|
20
|
-
const
|
|
21
|
-
const
|
|
15
|
+
const backend = useBackendStrict();
|
|
16
|
+
const workspace = useWorkspaceStrict();
|
|
17
|
+
const port = useMutationPort(descriptor);
|
|
18
|
+
const { messages: msg, referenceCounted } = descriptor;
|
|
22
19
|
const [isDeleting, setIsDeleting] = useState(false);
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
const { result, status } = useCancelablePromise({ promise: lookup ? () => lookup(item) : undefined }, [
|
|
27
|
-
item,
|
|
28
|
-
port,
|
|
29
|
-
]);
|
|
30
|
-
// The lookup is advisory: no lookup or a failed one means no warning and nothing to wait for.
|
|
31
|
-
const referencingCount = !lookup || status === "error" ? 0 : result;
|
|
20
|
+
// Block deletion until the usage lookup resolves, so the dependent-object warning surfaces first.
|
|
21
|
+
const { result, status } = useCancelablePromise({ promise: referenceCounted ? () => referenceCounted.count(backend, workspace, item) : undefined }, [item, backend, workspace]);
|
|
22
|
+
const referencingCount = !referenceCounted || status === "error" ? 0 : result;
|
|
32
23
|
const displayName = item.title || item.identifier;
|
|
33
24
|
const handleDelete = useCallback(async () => {
|
|
34
25
|
setIsDeleting(true);
|
|
@@ -51,5 +42,5 @@ export function AsCodeDeleteDialog({ descriptor, item, onClose, onDeleted }) {
|
|
|
51
42
|
return (_jsxs(ConfirmDialog, { headline: intl.formatMessage(msg.deleteTitle), cancelButtonText: intl.formatMessage(messages.cancel), submitButtonText: intl.formatMessage(msg.deleteSubmit), isPositive: false, isSubmitDisabled: isDeleting || referencingCount === undefined, isCancelDisabled: isDeleting, showProgressIndicator: isDeleting, onCancel: handleClose, onClose: handleClose, onSubmit: handleDelete, displayCloseButton: !isDeleting, children: [_jsx(FormattedMessage, { ...msg.deleteBody, values: {
|
|
52
43
|
name: displayName,
|
|
53
44
|
b: (chunks) => _jsx("b", { children: chunks }),
|
|
54
|
-
} }), referencingCount &&
|
|
45
|
+
} }), referencingCount && referenceCounted ? (_jsx("div", { children: _jsx(FormattedMessage, { ...referenceCounted.usageWarning, values: { count: referencingCount } }) })) : null] }));
|
|
55
46
|
}
|
|
@@ -2,14 +2,10 @@ import { type MouseEvent } from "react";
|
|
|
2
2
|
import type { OpenHandlerEvent } from "../catalogDetail/types.js";
|
|
3
3
|
import type { ICatalogItem, ICatalogItemRef } from "../catalogItem/types.js";
|
|
4
4
|
import type { IAsCodeDescriptor } from "./descriptor.js";
|
|
5
|
-
/**
|
|
6
|
-
* @internal
|
|
7
|
-
*/
|
|
5
|
+
/** @internal */
|
|
8
6
|
export interface IAsCodeDetailActionsProps {
|
|
9
7
|
descriptor: IAsCodeDescriptor;
|
|
10
8
|
item: ICatalogItem;
|
|
11
|
-
/** When provided and the descriptor declares an `openAction` (e.g. "Open in metric editor"), that
|
|
12
|
-
* action opens the standalone editor through this handler; omitted, it is not offered. */
|
|
13
9
|
onOpen?: (event: MouseEvent, openEvent: OpenHandlerEvent) => void;
|
|
14
10
|
canShare?: boolean;
|
|
15
11
|
onShare?: () => void;
|
|
@@ -17,11 +13,6 @@ export interface IAsCodeDetailActionsProps {
|
|
|
17
13
|
onCatalogItemUpdate?: (item: ICatalogItem) => void;
|
|
18
14
|
onCatalogItemDelete?: (ref: ICatalogItemRef) => void;
|
|
19
15
|
}
|
|
20
|
-
/**
|
|
21
|
-
* Detail-panel actions for an as-code object: inline edit, duplicate, and delete via the shared
|
|
22
|
-
* dialogs, plus the Share button and the descriptor's open action if it declares one. Generic over the
|
|
23
|
-
* entity type via its descriptor.
|
|
24
|
-
* @internal
|
|
25
|
-
*/
|
|
16
|
+
/** @internal */
|
|
26
17
|
export declare function AsCodeDetailActions({ descriptor, item, onOpen, canShare, onShare, onCatalogItemCreate, onCatalogItemUpdate, onCatalogItemDelete }: IAsCodeDetailActionsProps): import("react/jsx-runtime").JSX.Element;
|
|
27
18
|
//# sourceMappingURL=AsCodeDetailActions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AsCodeDetailActions.d.ts","sourceRoot":"","sources":["../../src/asCode/AsCodeDetailActions.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,UAAU,EAAkC,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"AsCodeDetailActions.d.ts","sourceRoot":"","sources":["../../src/asCode/AsCodeDetailActions.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,UAAU,EAAkC,MAAM,OAAO,CAAC;AAU5F,OAAO,KAAK,EAAwB,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxF,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAK7E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAUzD,gBAAgB;AAChB,MAAM,WAAW,yBAAyB;IACtC,UAAU,EAAE,iBAAiB,CAAC;IAC9B,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;CACxD;AAED,gBAAgB;AAChB,wBAAgB,mBAAmB,CAAC,EAChC,UAAU,EACV,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,OAAO,EACP,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACtB,EAAE,yBAAyB,2CAgG3B"}
|
|
@@ -5,33 +5,32 @@ import { useIntl } from "react-intl";
|
|
|
5
5
|
import { useWorkspaceStrict } from "@gooddata/sdk-ui";
|
|
6
6
|
import { catalogDetailActionDelete, catalogDetailActionDuplicate } from "../automation/testIds.js";
|
|
7
7
|
import { CatalogDetailActionBar } from "../catalogDetail/CatalogDetailActionBar.js";
|
|
8
|
+
import { toOpenHandlerEvent } from "../catalogDetail/openHandlerEvent.js";
|
|
8
9
|
import { ShareButton } from "../catalogDetail/share/ShareButton.js";
|
|
9
10
|
import { AsCodeCreateDialog } from "./AsCodeCreateDialog.js";
|
|
10
11
|
import { AsCodeDeleteDialog } from "./AsCodeDeleteDialog.js";
|
|
11
12
|
import { AsCodeEditDialog } from "./AsCodeEditDialog.js";
|
|
12
13
|
const OPEN_ACTION_ID = "open";
|
|
13
|
-
/**
|
|
14
|
-
* Detail-panel actions for an as-code object: inline edit, duplicate, and delete via the shared
|
|
15
|
-
* dialogs, plus the Share button and the descriptor's open action if it declares one. Generic over the
|
|
16
|
-
* entity type via its descriptor.
|
|
17
|
-
* @internal
|
|
18
|
-
*/
|
|
14
|
+
/** @internal */
|
|
19
15
|
export function AsCodeDetailActions({ descriptor, item, onOpen, canShare, onShare, onCatalogItemCreate, onCatalogItemUpdate, onCatalogItemDelete, }) {
|
|
20
16
|
const intl = useIntl();
|
|
21
17
|
const workspaceId = useWorkspaceStrict();
|
|
18
|
+
// When false, edit and duplicate are withheld (both need the codec); delete, share, and open remain.
|
|
19
|
+
const canEditAsCode = descriptor.useIsItemEditable?.(item) ?? true;
|
|
22
20
|
const [dialog, setDialog] = useState(undefined);
|
|
23
21
|
const actionGroups = useMemo(() => {
|
|
24
22
|
const mainGroup = [];
|
|
25
|
-
// The open action reaches the standalone editor via onOpen, so it is offered only when the host
|
|
26
|
-
// provides that handler and the descriptor declares one; the menu then never shows a dead item.
|
|
27
23
|
if (onOpen && descriptor.openAction) {
|
|
28
24
|
mainGroup.push({ id: OPEN_ACTION_ID, label: intl.formatMessage(descriptor.openAction) });
|
|
29
25
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
if (canEditAsCode) {
|
|
27
|
+
mainGroup.push({
|
|
28
|
+
id: "duplicate",
|
|
29
|
+
label: intl.formatMessage(descriptor.messages.duplicate),
|
|
30
|
+
dataTestId: catalogDetailActionDuplicate,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
// Drop an empty main group so the menu opens without a stray leading divider.
|
|
35
34
|
return [
|
|
36
35
|
mainGroup,
|
|
37
36
|
[
|
|
@@ -42,18 +41,13 @@ export function AsCodeDetailActions({ descriptor, item, onOpen, canShare, onShar
|
|
|
42
41
|
dataTestId: catalogDetailActionDelete,
|
|
43
42
|
},
|
|
44
43
|
],
|
|
45
|
-
];
|
|
46
|
-
}, [descriptor, intl, onOpen]);
|
|
44
|
+
].filter((group) => group.length > 0);
|
|
45
|
+
}, [canEditAsCode, descriptor, intl, onOpen]);
|
|
47
46
|
const closeDialog = useCallback(() => setDialog(undefined), []);
|
|
48
47
|
const handleEditOpen = useCallback(() => setDialog({ kind: "edit", item }), [item]);
|
|
49
48
|
const handleActionsMenuSelect = useCallback((actionId, event) => {
|
|
50
49
|
if (actionId === OPEN_ACTION_ID) {
|
|
51
|
-
onOpen?.(event,
|
|
52
|
-
item,
|
|
53
|
-
workspaceId,
|
|
54
|
-
newTab: event.metaKey || event.ctrlKey,
|
|
55
|
-
preventDefault: event.preventDefault.bind(event),
|
|
56
|
-
});
|
|
50
|
+
onOpen?.(event, toOpenHandlerEvent(event, item, workspaceId));
|
|
57
51
|
return;
|
|
58
52
|
}
|
|
59
53
|
if (actionId === "delete") {
|
|
@@ -67,5 +61,5 @@ export function AsCodeDetailActions({ descriptor, item, onOpen, canShare, onShar
|
|
|
67
61
|
const handleEditDuplicate = useCallback((source) => {
|
|
68
62
|
setDialog({ kind: "duplicate", duplicateSource: source });
|
|
69
63
|
}, []);
|
|
70
|
-
return (_jsxs(_Fragment, { children: [_jsx(CatalogDetailActionBar, { item: item, workspaceId: workspaceId, actionGroups: actionGroups, leadingActions: canShare && onShare ? _jsx(ShareButton, { onClick: onShare }) : null, onEditClick: handleEditOpen, onActionsMenuSelect: handleActionsMenuSelect }), dialog?.kind === "edit" ? (_jsx(AsCodeEditDialog, { descriptor: descriptor, item: dialog.item, onClose: closeDialog, onSaved: onCatalogItemUpdate, onDuplicate: handleEditDuplicate })) : null, dialog?.kind === "duplicate" ? (_jsx(AsCodeCreateDialog, { descriptor: descriptor, duplicateOf: dialog.duplicateOf, duplicateSource: dialog.duplicateSource, onClose: closeDialog, onCreated: onCatalogItemCreate })) : null, dialog?.kind === "delete" ? (_jsx(AsCodeDeleteDialog, { descriptor: descriptor, item: dialog.item, onClose: closeDialog, onDeleted: () => onCatalogItemDelete?.(dialog.item) })) : null] }));
|
|
64
|
+
return (_jsxs(_Fragment, { children: [_jsx(CatalogDetailActionBar, { item: item, workspaceId: workspaceId, actionGroups: actionGroups, leadingActions: canShare && onShare ? _jsx(ShareButton, { onClick: onShare }) : null, onEditClick: canEditAsCode ? handleEditOpen : undefined, onActionsMenuSelect: handleActionsMenuSelect }), dialog?.kind === "edit" ? (_jsx(AsCodeEditDialog, { descriptor: descriptor, item: dialog.item, onClose: closeDialog, onSaved: onCatalogItemUpdate, onDuplicate: handleEditDuplicate })) : null, dialog?.kind === "duplicate" ? (_jsx(AsCodeCreateDialog, { descriptor: descriptor, duplicateOf: dialog.duplicateOf, duplicateSource: dialog.duplicateSource, onClose: closeDialog, onCreated: onCatalogItemCreate })) : null, dialog?.kind === "delete" ? (_jsx(AsCodeDeleteDialog, { descriptor: descriptor, item: dialog.item, onClose: closeDialog, onDeleted: () => onCatalogItemDelete?.(dialog.item) })) : null] }));
|
|
71
65
|
}
|
|
@@ -1,24 +1,19 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
/** Whether the dialog creates a new object or edits an existing one. */
|
|
3
|
-
type AsCodeDialogMode = "create" | "edit";
|
|
1
|
+
import type { IAsCodeDescriptor } from "./descriptor.js";
|
|
4
2
|
type Props = {
|
|
5
3
|
descriptor: IAsCodeDescriptor;
|
|
6
|
-
|
|
7
|
-
initialDefinition?: IAsCodeDefinition;
|
|
4
|
+
initialDefinition?: unknown;
|
|
8
5
|
isLoading?: boolean;
|
|
9
|
-
fixedIdentifier?: string;
|
|
10
6
|
onClose: () => void;
|
|
11
|
-
onSubmit: (definition:
|
|
12
|
-
onDuplicate?: (definition:
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
*/
|
|
7
|
+
onSubmit: (definition: unknown) => Promise<void>;
|
|
8
|
+
onDuplicate?: (definition: unknown) => void;
|
|
9
|
+
} & ({
|
|
10
|
+
mode: "create";
|
|
11
|
+
fixedIdentifier?: undefined;
|
|
12
|
+
} | {
|
|
13
|
+
mode: "edit";
|
|
14
|
+
fixedIdentifier: string;
|
|
15
|
+
});
|
|
16
|
+
/** @internal */
|
|
22
17
|
export declare function AsCodeDialog(props: Props): import("react/jsx-runtime").JSX.Element;
|
|
23
18
|
export {};
|
|
24
19
|
//# sourceMappingURL=AsCodeDialog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AsCodeDialog.d.ts","sourceRoot":"","sources":["../../src/asCode/AsCodeDialog.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"AsCodeDialog.d.ts","sourceRoot":"","sources":["../../src/asCode/AsCodeDialog.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAA2B,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAalF,KAAK,KAAK,GAAG;IACT,UAAU,EAAE,iBAAiB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/C,GAAG,CAAC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,eAAe,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAElG,gBAAgB;AAChB,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,2CAqNxC"}
|
|
@@ -1,39 +1,62 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// (C) 2026 GoodData Corporation
|
|
3
|
-
import { Suspense, lazy, useCallback, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { Suspense, lazy, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { FormattedMessage, defineMessages, useIntl } from "react-intl";
|
|
5
5
|
import { LoadingComponent } from "@gooddata/sdk-ui";
|
|
6
6
|
import { ConfirmDialog, UiButton, UiIcon, UiLink, UiTooltip } from "@gooddata/sdk-ui-kit";
|
|
7
7
|
import { useIsWhiteLabeled } from "../permission/PermissionsContext.js";
|
|
8
8
|
import { extractBackendErrorDetail } from "../utils/backendError.js";
|
|
9
|
+
import { useAsCodeLoadFailure } from "./useAsCodeLoadFailure.js";
|
|
9
10
|
const AsCodeEditorBody = lazy(() => import("./AsCodeEditorBody.js").then((m) => ({ default: m.AsCodeEditorBody })));
|
|
10
|
-
// Chrome shared by every as-code type; the entity-specific copy comes from `descriptor.messages`.
|
|
11
11
|
const messages = defineMessages({
|
|
12
12
|
createSubmit: { id: "analyticsCatalog.asCode.dialog.create.submit" },
|
|
13
13
|
editSubmit: { id: "analyticsCatalog.asCode.dialog.edit.submit" },
|
|
14
14
|
cancel: { id: "analyticsCatalog.asCode.dialog.cancel" },
|
|
15
15
|
});
|
|
16
|
-
/**
|
|
17
|
-
* Generic create/edit dialog for an as-code object, entity-agnostic via its `descriptor`: it renders
|
|
18
|
-
* the shared editor chrome and delegates serialization, validation, and copy to the descriptor. The
|
|
19
|
-
* caller owns loading and persistence (passes `initialDefinition`, handles `onSubmit`); this component
|
|
20
|
-
* owns only the editing surface.
|
|
21
|
-
*
|
|
22
|
-
* @internal
|
|
23
|
-
*/
|
|
16
|
+
/** @internal */
|
|
24
17
|
export function AsCodeDialog(props) {
|
|
25
18
|
const { descriptor, mode, initialDefinition, isLoading = false, fixedIdentifier } = props;
|
|
26
19
|
const { onClose, onSubmit, onDuplicate } = props;
|
|
27
20
|
const intl = useIntl();
|
|
28
21
|
const isEdit = mode === "edit";
|
|
29
22
|
const isWhiteLabeled = useIsWhiteLabeled();
|
|
30
|
-
//
|
|
31
|
-
//
|
|
23
|
+
// Descriptor is fixed per mount, so these hook calls are unconditional (rules of hooks). `useEditing`
|
|
24
|
+
// returns `null` while the async editing brain loads.
|
|
32
25
|
const editing = descriptor.useEditing();
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
//
|
|
36
|
-
//
|
|
26
|
+
const requestEditing = descriptor.useRequestEditing?.();
|
|
27
|
+
const fail = useAsCodeLoadFailure(descriptor, onClose);
|
|
28
|
+
// Displaying the dialog requests the brain; a rejection is this mount's own request, so only a
|
|
29
|
+
// still-mounted dialog reacts to it.
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
let disposed = false;
|
|
32
|
+
requestEditing?.().catch(() => {
|
|
33
|
+
if (!disposed) {
|
|
34
|
+
fail();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return () => {
|
|
38
|
+
disposed = true;
|
|
39
|
+
};
|
|
40
|
+
}, [requestEditing, fail]);
|
|
41
|
+
// Serialize runs during render, so a throw becomes `null` and routes to the close-on-failure effect.
|
|
42
|
+
const initialYaml = useMemo(() => {
|
|
43
|
+
if (initialDefinition === undefined || !editing) {
|
|
44
|
+
return "";
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
return editing.serialize(initialDefinition);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}, [initialDefinition, editing]);
|
|
53
|
+
const serializeFailed = initialYaml === null;
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (serializeFailed) {
|
|
56
|
+
fail();
|
|
57
|
+
}
|
|
58
|
+
}, [serializeFailed, fail]);
|
|
59
|
+
const loading = isLoading || editing === null || serializeFailed;
|
|
37
60
|
const yamlValue = useRef(null);
|
|
38
61
|
const [validationError, setValidationError] = useState(null);
|
|
39
62
|
const [submitError, setSubmitError] = useState(null);
|
|
@@ -53,16 +76,25 @@ export function AsCodeDialog(props) {
|
|
|
53
76
|
setSubmitError(null);
|
|
54
77
|
setValidationError(null);
|
|
55
78
|
}, []);
|
|
79
|
+
// Base is the loaded object (edit) or the copy source (duplicate); a blank create reconciles to a no-op.
|
|
80
|
+
const reconcileWithBase = useCallback((edited) => editing?.reconcile && initialDefinition !== undefined
|
|
81
|
+
? editing.reconcile(initialDefinition, edited)
|
|
82
|
+
: edited, [editing, initialDefinition]);
|
|
56
83
|
const handleSubmit = useCallback(async () => {
|
|
57
|
-
|
|
84
|
+
if (!editing || initialYaml === null) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const context = mode === "edit" ? { intent: "edit", fixedIdentifier } : { intent: "create" };
|
|
88
|
+
const result = editing.validate(yamlValue.current ?? initialYaml, context);
|
|
58
89
|
if (!result.isValid) {
|
|
59
90
|
setValidationError(result.error);
|
|
60
91
|
return;
|
|
61
92
|
}
|
|
93
|
+
const toPersist = reconcileWithBase(result.definition);
|
|
62
94
|
setIsSubmitting(true);
|
|
63
95
|
setSubmitError(null);
|
|
64
96
|
try {
|
|
65
|
-
await onSubmit(
|
|
97
|
+
await onSubmit(toPersist);
|
|
66
98
|
}
|
|
67
99
|
catch (error) {
|
|
68
100
|
setSubmitError(extractBackendErrorDetail(error) ?? intl.formatMessage(descriptor.messages.submitError));
|
|
@@ -70,25 +102,25 @@ export function AsCodeDialog(props) {
|
|
|
70
102
|
finally {
|
|
71
103
|
setIsSubmitting(false);
|
|
72
104
|
}
|
|
73
|
-
}, [descriptor, fixedIdentifier, initialYaml, intl, onSubmit,
|
|
105
|
+
}, [descriptor, editing, fixedIdentifier, initialYaml, intl, mode, onSubmit, reconcileWithBase]);
|
|
74
106
|
const handleDuplicate = useCallback(() => {
|
|
75
|
-
if (!onDuplicate) {
|
|
107
|
+
if (!onDuplicate || !editing || initialYaml === null) {
|
|
76
108
|
return;
|
|
77
109
|
}
|
|
78
110
|
setSubmitError(null);
|
|
79
|
-
//
|
|
80
|
-
const result = validate(yamlValue.current ?? initialYaml, {
|
|
111
|
+
// The document still carries the source id; `toCopy` derives fresh identity downstream.
|
|
112
|
+
const result = editing.validate(yamlValue.current ?? initialYaml, { intent: "duplicate" });
|
|
81
113
|
if (!result.isValid) {
|
|
82
114
|
setValidationError(result.error);
|
|
83
115
|
return;
|
|
84
116
|
}
|
|
85
|
-
onDuplicate(result.definition);
|
|
86
|
-
}, [initialYaml, onDuplicate,
|
|
117
|
+
onDuplicate(reconcileWithBase(result.definition));
|
|
118
|
+
}, [editing, initialYaml, onDuplicate, reconcileWithBase]);
|
|
87
119
|
const footerLeftRenderer = useCallback(() => (_jsxs("div", { className: "gd-ascode-dialog-footer-left", children: [isWhiteLabeled ? null : (_jsxs(UiLink, { variant: "secondary", href: descriptor.docsUrl, target: "_blank", rel: "noopener noreferrer", children: [
|
|
88
|
-
_jsx(UiIcon, { type: "question", size: 14, color: "complementary-6" }), intl.formatMessage(descriptor.messages.help)] })), isEdit && onDuplicate ? (_jsx(UiButton, { label: intl.formatMessage(descriptor.messages.duplicate), variant: "tertiary", isDisabled: isSubmitting ||
|
|
120
|
+
_jsx(UiIcon, { type: "question", size: 14, color: "complementary-6" }), intl.formatMessage(descriptor.messages.help)] })), isEdit && onDuplicate ? (_jsx(UiButton, { label: intl.formatMessage(descriptor.messages.duplicate), variant: "tertiary", isDisabled: isSubmitting || loading, onClick: handleDuplicate })) : null] })), [descriptor, handleDuplicate, intl, isEdit, loading, isSubmitting, isWhiteLabeled, onDuplicate]);
|
|
89
121
|
const bodySpinner = (_jsx("div", { className: "gd-ascode-dialog-loading", children: _jsx(LoadingComponent, {}) }));
|
|
90
|
-
return (_jsx(ConfirmDialog, { className: "gd-ascode-dialog", containerClassName: "gd-ascode-dialog-overlay", headline: headlineMessage, cancelButtonText: cancelMessage, submitButtonText: submitMessage, isPositive: true, isSubmitDisabled: isSubmitting ||
|
|
122
|
+
return (_jsx(ConfirmDialog, { className: "gd-ascode-dialog", containerClassName: "gd-ascode-dialog-overlay", headline: headlineMessage, cancelButtonText: cancelMessage, submitButtonText: submitMessage, isPositive: true, isSubmitDisabled: isSubmitting || loading || (isEdit && !isDirty), isCancelDisabled: isSubmitting, shouldCloseOnEscape: !isSubmitting, onCancel: handleClose, onClose: handleClose, onSubmit: handleSubmit, displayCloseButton: !isSubmitting, footerLeftRenderer: footerLeftRenderer, children: _jsx("div", { className: "gd-ascode-dialog-content", children: _jsx(Suspense, { fallback: bodySpinner, children: loading ? (bodySpinner) : (_jsxs(_Fragment, { children: [
|
|
91
123
|
_jsxs("div", { className: "gd-ascode-dialog-section-header", children: [intl.formatMessage(descriptor.messages.sectionHeader), _jsx(UiTooltip, { arrowPlacement: "top", optimalPlacement: true, triggerBy: ["hover", "click", "focus"], anchor: _jsx(UiIcon, { type: "question", size: 14, color: "complementary-6" }), content: intl.formatMessage(descriptor.messages.sectionHeaderTooltip) })
|
|
92
|
-
] }), _jsx("div", { className: "gd-ascode-dialog-editor", children: _jsx(AsCodeEditorBody, { initialValue: initialYaml, onChange: handleChange, disabled: isSubmitting, completionSource: completionSource, syntaxErrorMessage: syntaxErrorMessage }) }), validationError || submitError ? (_jsxs("div", { className: "gd-ascode-dialog-error", children: [
|
|
124
|
+
] }), _jsx("div", { className: "gd-ascode-dialog-editor", children: _jsx(AsCodeEditorBody, { initialValue: initialYaml, onChange: handleChange, disabled: isSubmitting, completionSource: editing.completionSource, syntaxErrorMessage: editing.syntaxErrorMessage }) }), validationError || submitError ? (_jsxs("div", { className: "gd-ascode-dialog-error", children: [
|
|
93
125
|
_jsx("span", { className: "gd-ascode-dialog-error-label", children: _jsx(FormattedMessage, { id: "analyticsCatalog.dialog.error.label" }) }), " ", validationError ?? submitError] })) : null] })) }) }) }));
|
|
94
126
|
}
|
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
import type { ICatalogItem } from "../catalogItem/types.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { IAsCodeDescriptor } from "./descriptor.js";
|
|
3
3
|
type Props = {
|
|
4
4
|
descriptor: IAsCodeDescriptor;
|
|
5
5
|
item: ICatalogItem;
|
|
6
6
|
onClose: () => void;
|
|
7
7
|
onSaved?: (item: ICatalogItem) => void;
|
|
8
|
-
onDuplicate?: (source:
|
|
8
|
+
onDuplicate?: (source: unknown) => void;
|
|
9
9
|
};
|
|
10
|
-
/**
|
|
11
|
-
* Edits an existing as-code object. Its editable definition is resolved by {@link useAsCodeBase} —
|
|
12
|
-
* fetched for a type with `port.load` (a metric's MAQL), or mapped from the item for one without.
|
|
13
|
-
* Generic over the entity type via its descriptor.
|
|
14
|
-
* @internal
|
|
15
|
-
*/
|
|
10
|
+
/** @internal */
|
|
16
11
|
export declare function AsCodeEditDialog({ descriptor, item, onClose, onSaved, onDuplicate }: Props): import("react/jsx-runtime").JSX.Element;
|
|
17
12
|
export {};
|
|
18
13
|
//# sourceMappingURL=AsCodeEditDialog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AsCodeEditDialog.d.ts","sourceRoot":"","sources":["../../src/asCode/AsCodeEditDialog.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"AsCodeEditDialog.d.ts","sourceRoot":"","sources":["../../src/asCode/AsCodeEditDialog.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGzD,KAAK,KAAK,GAAG;IACT,UAAU,EAAE,iBAAiB,CAAC;IAC9B,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAEvC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CAC3C,CAAC;AAEF,gBAAgB;AAChB,wBAAgB,gBAAgB,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,KAAK,2CA6B1F"}
|
|
@@ -4,20 +4,10 @@ import { useCallback } from "react";
|
|
|
4
4
|
import { useToastMessage } from "@gooddata/sdk-ui-kit";
|
|
5
5
|
import { AsCodeDialog } from "./AsCodeDialog.js";
|
|
6
6
|
import { useAsCodeBase } from "./useAsCodeBase.js";
|
|
7
|
-
/**
|
|
8
|
-
* Edits an existing as-code object. Its editable definition is resolved by {@link useAsCodeBase} —
|
|
9
|
-
* fetched for a type with `port.load` (a metric's MAQL), or mapped from the item for one without.
|
|
10
|
-
* Generic over the entity type via its descriptor.
|
|
11
|
-
* @internal
|
|
12
|
-
*/
|
|
7
|
+
/** @internal */
|
|
13
8
|
export function AsCodeEditDialog({ descriptor, item, onClose, onSaved, onDuplicate }) {
|
|
14
|
-
const { addSuccess
|
|
15
|
-
const { base, isLoading, port } = useAsCodeBase(descriptor, item,
|
|
16
|
-
if (descriptor.messages.loadError) {
|
|
17
|
-
addError(descriptor.messages.loadError);
|
|
18
|
-
}
|
|
19
|
-
onClose();
|
|
20
|
-
});
|
|
9
|
+
const { addSuccess } = useToastMessage();
|
|
10
|
+
const { base, isLoading, port } = useAsCodeBase(descriptor, item, onClose);
|
|
21
11
|
const handleSubmit = useCallback(async (definition) => {
|
|
22
12
|
if (base === undefined) {
|
|
23
13
|
return;
|
|
@@ -27,12 +17,5 @@ export function AsCodeEditDialog({ descriptor, item, onClose, onSaved, onDuplica
|
|
|
27
17
|
onClose();
|
|
28
18
|
addSuccess(descriptor.messages.updateSuccess);
|
|
29
19
|
}, [addSuccess, base, descriptor, onClose, onSaved, port]);
|
|
30
|
-
|
|
31
|
-
if (base === undefined || !onDuplicate) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
// Overlay the edits onto the loaded base so the copy keeps fields the YAML can't express.
|
|
35
|
-
onDuplicate(descriptor.applyYamlEdits ? descriptor.applyYamlEdits(base, edited) : edited);
|
|
36
|
-
}, [base, descriptor, onDuplicate]);
|
|
37
|
-
return (_jsx(AsCodeDialog, { descriptor: descriptor, mode: "edit", isLoading: isLoading, initialDefinition: base, fixedIdentifier: item.identifier, onClose: onClose, onSubmit: handleSubmit, onDuplicate: onDuplicate ? handleDuplicate : undefined }));
|
|
20
|
+
return (_jsx(AsCodeDialog, { descriptor: descriptor, mode: "edit", isLoading: isLoading, initialDefinition: base, fixedIdentifier: item.identifier, onClose: onClose, onSubmit: handleSubmit, onDuplicate: onDuplicate }));
|
|
38
21
|
}
|