@gooddata/sdk-ui-catalog 11.48.0-alpha.0 → 11.48.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/AnalyticsCatalogDetail.d.ts.map +1 -1
- package/esm/AnalyticsCatalogDetail.js +3 -3
- package/esm/asCode/AsCodeCreateDialog.d.ts +17 -0
- package/esm/asCode/AsCodeCreateDialog.d.ts.map +1 -0
- package/esm/asCode/AsCodeCreateDialog.js +51 -0
- package/esm/asCode/AsCodeDeleteDialog.d.ts +17 -0
- package/esm/asCode/AsCodeDeleteDialog.d.ts.map +1 -0
- package/esm/asCode/AsCodeDeleteDialog.js +55 -0
- package/esm/asCode/AsCodeDetailActions.d.ts +27 -0
- package/esm/asCode/AsCodeDetailActions.d.ts.map +1 -0
- package/esm/asCode/AsCodeDetailActions.js +66 -0
- package/esm/asCode/AsCodeDialog.d.ts +24 -0
- package/esm/asCode/AsCodeDialog.d.ts.map +1 -0
- package/esm/asCode/AsCodeDialog.js +94 -0
- package/esm/asCode/AsCodeEditDialog.d.ts +18 -0
- package/esm/asCode/AsCodeEditDialog.d.ts.map +1 -0
- package/esm/asCode/AsCodeEditDialog.js +38 -0
- package/esm/asCode/AsCodeEditorBody.d.ts +16 -0
- package/esm/asCode/AsCodeEditorBody.d.ts.map +1 -0
- package/esm/asCode/AsCodeEditorBody.js +10 -0
- package/esm/asCode/AsCodeMutationContext.d.ts +24 -0
- package/esm/asCode/AsCodeMutationContext.d.ts.map +1 -0
- package/esm/asCode/AsCodeMutationContext.js +40 -0
- package/esm/asCode/copy.d.ts +18 -0
- package/esm/asCode/copy.d.ts.map +1 -0
- package/esm/asCode/copy.js +58 -0
- package/esm/asCode/descriptor.d.ts +160 -0
- package/esm/asCode/descriptor.d.ts.map +1 -0
- package/esm/asCode/descriptor.js +8 -0
- package/esm/asCode/gate.d.ts +7 -0
- package/esm/asCode/gate.d.ts.map +1 -0
- package/esm/asCode/gate.js +11 -0
- package/esm/asCode/useAsCodeBase.d.ts +18 -0
- package/esm/asCode/useAsCodeBase.d.ts.map +1 -0
- package/esm/asCode/useAsCodeBase.js +27 -0
- package/esm/asCode/validateYaml.d.ts +39 -0
- package/esm/asCode/validateYaml.d.ts.map +1 -0
- package/esm/asCode/validateYaml.js +28 -0
- package/esm/asCodeRegistry.d.ts +20 -0
- package/esm/asCodeRegistry.d.ts.map +1 -0
- package/esm/asCodeRegistry.js +36 -0
- package/esm/catalog/Catalog.d.ts.map +1 -1
- package/esm/catalog/Catalog.js +4 -4
- package/esm/catalogDetail/CatalogDetailActions.d.ts +4 -2
- package/esm/catalogDetail/CatalogDetailActions.d.ts.map +1 -1
- package/esm/catalogDetail/CatalogDetailActions.js +22 -78
- package/esm/catalogDetail/CatalogDetailContent.d.ts.map +1 -1
- package/esm/catalogDetail/CatalogDetailContent.js +1 -3
- package/esm/catalogItem/query.d.ts +4 -2
- package/esm/catalogItem/query.d.ts.map +1 -1
- package/esm/catalogItem/query.js +6 -6
- package/esm/header/CreateObjectButton.d.ts.map +1 -1
- package/esm/header/CreateObjectButton.js +29 -28
- package/esm/localization/bundles/en-US.localization-bundle.d.ts +16 -24
- package/esm/localization/bundles/en-US.localization-bundle.d.ts.map +1 -1
- package/esm/localization/bundles/en-US.localization-bundle.js +16 -24
- package/esm/metric/gate.d.ts +3 -4
- package/esm/metric/gate.d.ts.map +1 -1
- package/esm/metric/gate.js +5 -10
- package/esm/metric/metricCopy.d.ts +0 -1
- package/esm/metric/metricCopy.d.ts.map +1 -1
- package/esm/metric/metricCopy.js +3 -45
- package/esm/metric/metricDescriptor.d.ts +7 -0
- package/esm/metric/metricDescriptor.d.ts.map +1 -0
- package/esm/metric/metricDescriptor.js +74 -0
- package/esm/metric/metricMutationPort.d.ts +7 -10
- package/esm/metric/metricMutationPort.d.ts.map +1 -1
- package/esm/metric/metricMutationPort.js +15 -17
- package/esm/metric/metricValidation.d.ts.map +1 -1
- package/esm/metric/metricValidation.js +13 -32
- package/esm/metric/tests/metricMutationPort.test.utils.js +1 -1
- package/esm/parameter/gate.d.ts +3 -0
- package/esm/parameter/gate.d.ts.map +1 -1
- package/esm/parameter/gate.js +7 -5
- package/esm/parameter/parameterCopy.d.ts +0 -1
- package/esm/parameter/parameterCopy.d.ts.map +1 -1
- package/esm/parameter/parameterCopy.js +4 -41
- package/esm/parameter/parameterDescriptor.d.ts +7 -0
- package/esm/parameter/parameterDescriptor.d.ts.map +1 -0
- package/esm/parameter/parameterDescriptor.js +91 -0
- package/esm/parameter/parameterMutationPort.d.ts +5 -6
- package/esm/parameter/parameterMutationPort.d.ts.map +1 -1
- package/esm/parameter/parameterMutationPort.js +15 -2
- package/package.json +15 -15
- package/esm/metric/MetricCreateDialog.d.ts +0 -11
- package/esm/metric/MetricCreateDialog.d.ts.map +0 -1
- package/esm/metric/MetricCreateDialog.js +0 -55
- package/esm/metric/MetricDeleteDialog.d.ts +0 -9
- package/esm/metric/MetricDeleteDialog.d.ts.map +0 -1
- package/esm/metric/MetricDeleteDialog.js +0 -68
- package/esm/metric/MetricDetailActions.d.ts +0 -23
- package/esm/metric/MetricDetailActions.d.ts.map +0 -1
- package/esm/metric/MetricDetailActions.js +0 -101
- package/esm/metric/MetricDialog.d.ts +0 -14
- package/esm/metric/MetricDialog.d.ts.map +0 -1
- package/esm/metric/MetricDialog.js +0 -100
- package/esm/metric/MetricEditDialog.d.ts +0 -11
- package/esm/metric/MetricEditDialog.d.ts.map +0 -1
- package/esm/metric/MetricEditDialog.js +0 -51
- package/esm/metric/MetricMutationContext.d.ts +0 -16
- package/esm/metric/MetricMutationContext.d.ts.map +0 -1
- package/esm/metric/MetricMutationContext.js +0 -32
- package/esm/metric/MetricYamlEditor.d.ts +0 -8
- package/esm/metric/MetricYamlEditor.d.ts.map +0 -1
- package/esm/metric/MetricYamlEditor.js +0 -12
- package/esm/parameter/ParameterCreateDialog.d.ts +0 -9
- package/esm/parameter/ParameterCreateDialog.d.ts.map +0 -1
- package/esm/parameter/ParameterCreateDialog.js +0 -56
- package/esm/parameter/ParameterDeleteDialog.d.ts +0 -9
- package/esm/parameter/ParameterDeleteDialog.d.ts.map +0 -1
- package/esm/parameter/ParameterDeleteDialog.js +0 -39
- package/esm/parameter/ParameterDialog.d.ts +0 -13
- package/esm/parameter/ParameterDialog.d.ts.map +0 -1
- package/esm/parameter/ParameterDialog.js +0 -106
- package/esm/parameter/ParameterEditDialog.d.ts +0 -11
- package/esm/parameter/ParameterEditDialog.d.ts.map +0 -1
- package/esm/parameter/ParameterEditDialog.js +0 -35
- package/esm/parameter/ParameterMutationContext.d.ts +0 -16
- package/esm/parameter/ParameterMutationContext.d.ts.map +0 -1
- package/esm/parameter/ParameterMutationContext.js +0 -32
- package/esm/parameter/ParameterYamlEditor.d.ts +0 -10
- package/esm/parameter/ParameterYamlEditor.d.ts.map +0 -1
- package/esm/parameter/ParameterYamlEditor.js +0 -16
|
@@ -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;AAMpE,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,14 +1,14 @@
|
|
|
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";
|
|
4
6
|
import { CatalogDetail } from "./catalogDetail/CatalogDetail.js";
|
|
5
7
|
import { CatalogDetailContent, } from "./catalogDetail/CatalogDetailContent.js";
|
|
6
8
|
import { CatalogResourceProvider } from "./catalogResource/CatalogResourceProvider.js";
|
|
7
9
|
import { IntlWrapper } from "./localization/IntlWrapper.js";
|
|
8
|
-
import { MetricMutationProvider } from "./metric/MetricMutationContext.js";
|
|
9
10
|
import {} from "./objectType/types.js";
|
|
10
11
|
import { OverlayProvider } from "./overlay/OverlayProvider.js";
|
|
11
|
-
import { ParameterMutationProvider } from "./parameter/ParameterMutationContext.js";
|
|
12
12
|
import { PermissionsProvider } from "./permission/PermissionsContext.js";
|
|
13
13
|
import { usePermissionsQuery } from "./permission/usePermissionsQuery.js";
|
|
14
14
|
import { QualityProvider } from "./quality/QualityContext.js";
|
|
@@ -28,5 +28,5 @@ function Providers(props) {
|
|
|
28
28
|
const backend = useBackendStrict(props.backend);
|
|
29
29
|
const workspace = useWorkspaceStrict(props.workspace);
|
|
30
30
|
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: _jsx(
|
|
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: _jsx(AsCodeMutationProvider, { descriptors: asCodeDescriptors, children: props.children }) }) }) }) }) }) }) }) }));
|
|
32
32
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ICatalogItem } from "../catalogItem/types.js";
|
|
2
|
+
import type { IAsCodeDefinition, IAsCodeDescriptor } from "./descriptor.js";
|
|
3
|
+
type Props = {
|
|
4
|
+
descriptor: IAsCodeDescriptor;
|
|
5
|
+
duplicateOf?: ICatalogItem;
|
|
6
|
+
duplicateSource?: IAsCodeDefinition;
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
onCreated?: (item: ICatalogItem) => void;
|
|
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
|
+
*/
|
|
15
|
+
export declare function AsCodeCreateDialog({ descriptor, duplicateOf, duplicateSource, onClose, onCreated }: Props): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=AsCodeCreateDialog.d.ts.map
|
|
@@ -0,0 +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,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAG5E,KAAK,KAAK,GAAG;IACT,UAAU,EAAE,iBAAiB,CAAC;IAE9B,WAAW,CAAC,EAAE,YAAY,CAAC;IAG3B,eAAe,CAAC,EAAE,iBAAiB,CAAC;IACpC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CAC5C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,KAAK,2CA8DzG"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { useCallback, useMemo } from "react";
|
|
4
|
+
import { useIntl } from "react-intl";
|
|
5
|
+
import { useToastMessage } from "@gooddata/sdk-ui-kit";
|
|
6
|
+
import { AsCodeDialog } from "./AsCodeDialog.js";
|
|
7
|
+
import { isDuplicateIdError } from "./copy.js";
|
|
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
|
+
*/
|
|
14
|
+
export function AsCodeCreateDialog({ descriptor, duplicateOf, duplicateSource, onClose, onCreated }) {
|
|
15
|
+
const intl = useIntl();
|
|
16
|
+
const { addSuccess, addError } = useToastMessage();
|
|
17
|
+
const { base: loadedSource, isLoading, port, } = useAsCodeBase(descriptor, duplicateOf, () => {
|
|
18
|
+
if (descriptor.messages.loadError) {
|
|
19
|
+
addError(descriptor.messages.loadError);
|
|
20
|
+
}
|
|
21
|
+
onClose();
|
|
22
|
+
});
|
|
23
|
+
const source = duplicateSource ?? loadedSource;
|
|
24
|
+
const copied = useMemo(() => (source === undefined ? undefined : descriptor.toCopy(source)), [descriptor, source]);
|
|
25
|
+
const initialDefinition = useMemo(() => copied ?? descriptor.emptyDefinition(intl.formatMessage(descriptor.messages.createDefaultTitle)), [copied, descriptor, intl]);
|
|
26
|
+
const copiedId = copied?.id;
|
|
27
|
+
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
|
+
let created;
|
|
33
|
+
try {
|
|
34
|
+
created = await port.create(toPersist);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
// The copied identity collided; let the backend derive a fresh one by dropping the id.
|
|
38
|
+
if (copiedId !== undefined && toPersist.id === copiedId && isDuplicateIdError(error)) {
|
|
39
|
+
const { id: _id, ...withoutId } = toPersist;
|
|
40
|
+
created = await port.create(withoutId);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
onCreated?.(created);
|
|
47
|
+
onClose();
|
|
48
|
+
addSuccess(descriptor.messages.createSuccess);
|
|
49
|
+
}, [addSuccess, copied, copiedId, descriptor, onClose, onCreated, port]);
|
|
50
|
+
return (_jsx(AsCodeDialog, { descriptor: descriptor, mode: "create", isLoading: isLoading, initialDefinition: isLoading ? undefined : initialDefinition, onClose: onClose, onSubmit: handleSubmit }));
|
|
51
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ICatalogItem } from "../catalogItem/types.js";
|
|
2
|
+
import type { IAsCodeDescriptor } from "./descriptor.js";
|
|
3
|
+
type Props = {
|
|
4
|
+
descriptor: IAsCodeDescriptor;
|
|
5
|
+
item: ICatalogItem;
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
onDeleted: () => void;
|
|
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
|
+
*/
|
|
15
|
+
export declare function AsCodeDeleteDialog({ descriptor, item, onClose, onDeleted }: Props): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=AsCodeDeleteDialog.d.ts.map
|
|
@@ -0,0 +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;AAG5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAMzD,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;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,KAAK,2CAkEjF"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { useCallback, useState } from "react";
|
|
4
|
+
import { FormattedMessage, defineMessages, useIntl } from "react-intl";
|
|
5
|
+
import { useCancelablePromise } from "@gooddata/sdk-ui";
|
|
6
|
+
import { ConfirmDialog, useToastMessage } from "@gooddata/sdk-ui-kit";
|
|
7
|
+
import { useAsCodePort } from "./AsCodeMutationContext.js";
|
|
8
|
+
const messages = defineMessages({
|
|
9
|
+
cancel: { id: "analyticsCatalog.asCode.dialog.cancel" },
|
|
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
|
+
*/
|
|
17
|
+
export function AsCodeDeleteDialog({ descriptor, item, onClose, onDeleted }) {
|
|
18
|
+
const intl = useIntl();
|
|
19
|
+
const { addSuccess, addError } = useToastMessage();
|
|
20
|
+
const port = useAsCodePort(descriptor.objectType);
|
|
21
|
+
const { messages: msg } = descriptor;
|
|
22
|
+
const [isDeleting, setIsDeleting] = useState(false);
|
|
23
|
+
// For a type with a usage lookup, withhold deletion until it resolves so the dependent-object
|
|
24
|
+
// warning can surface first; a type without one has nothing to wait for, so starts unblocked.
|
|
25
|
+
const lookup = port.getReferencingObjectsCount;
|
|
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;
|
|
32
|
+
const displayName = item.title || item.identifier;
|
|
33
|
+
const handleDelete = useCallback(async () => {
|
|
34
|
+
setIsDeleting(true);
|
|
35
|
+
try {
|
|
36
|
+
await port.delete(item);
|
|
37
|
+
onDeleted();
|
|
38
|
+
onClose();
|
|
39
|
+
addSuccess(msg.deleteSuccess);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
addError(msg.deleteError);
|
|
43
|
+
setIsDeleting(false);
|
|
44
|
+
}
|
|
45
|
+
}, [addError, addSuccess, item, msg, onClose, onDeleted, port]);
|
|
46
|
+
const handleClose = useCallback(() => {
|
|
47
|
+
if (!isDeleting) {
|
|
48
|
+
onClose();
|
|
49
|
+
}
|
|
50
|
+
}, [isDeleting, onClose]);
|
|
51
|
+
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
|
+
name: displayName,
|
|
53
|
+
b: (chunks) => _jsx("b", { children: chunks }),
|
|
54
|
+
} }), referencingCount && msg.deleteUsageWarning ? (_jsx("div", { children: _jsx(FormattedMessage, { ...msg.deleteUsageWarning, values: { count: referencingCount } }) })) : null] }));
|
|
55
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type MouseEvent } from "react";
|
|
2
|
+
import type { OpenHandlerEvent } from "../catalogDetail/types.js";
|
|
3
|
+
import type { ICatalogItem, ICatalogItemRef } from "../catalogItem/types.js";
|
|
4
|
+
import type { IAsCodeDescriptor } from "./descriptor.js";
|
|
5
|
+
/**
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export interface IAsCodeDetailActionsProps {
|
|
9
|
+
descriptor: IAsCodeDescriptor;
|
|
10
|
+
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
|
+
onOpen?: (event: MouseEvent, openEvent: OpenHandlerEvent) => void;
|
|
14
|
+
canShare?: boolean;
|
|
15
|
+
onShare?: () => void;
|
|
16
|
+
onCatalogItemCreate?: (item: ICatalogItem) => void;
|
|
17
|
+
onCatalogItemUpdate?: (item: ICatalogItem) => void;
|
|
18
|
+
onCatalogItemDelete?: (ref: ICatalogItemRef) => void;
|
|
19
|
+
}
|
|
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
|
+
*/
|
|
26
|
+
export declare function AsCodeDetailActions({ descriptor, item, onOpen, canShare, onShare, onCatalogItemCreate, onCatalogItemUpdate, onCatalogItemDelete }: IAsCodeDetailActionsProps): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
//# sourceMappingURL=AsCodeDetailActions.d.ts.map
|
|
@@ -0,0 +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;AAS5F,OAAO,KAAK,EAAwB,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxF,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAK7E,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAY5E;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACtC,UAAU,EAAE,iBAAiB,CAAC;IAC9B,IAAI,EAAE,YAAY,CAAC;IACnB;+FAC2F;IAC3F,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;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,EAChC,UAAU,EACV,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,OAAO,EACP,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACtB,EAAE,yBAAyB,2CAgG3B"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { useCallback, useMemo, useState } from "react";
|
|
4
|
+
import { useIntl } from "react-intl";
|
|
5
|
+
import { useWorkspaceStrict } from "@gooddata/sdk-ui";
|
|
6
|
+
import { catalogDetailActionDelete, catalogDetailActionDuplicate } from "../automation/testIds.js";
|
|
7
|
+
import { CatalogDetailActionBar } from "../catalogDetail/CatalogDetailActionBar.js";
|
|
8
|
+
import { ShareButton } from "../catalogDetail/share/ShareButton.js";
|
|
9
|
+
import { AsCodeCreateDialog } from "./AsCodeCreateDialog.js";
|
|
10
|
+
import { AsCodeDeleteDialog } from "./AsCodeDeleteDialog.js";
|
|
11
|
+
import { AsCodeEditDialog } from "./AsCodeEditDialog.js";
|
|
12
|
+
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
|
+
*/
|
|
19
|
+
export function AsCodeDetailActions({ descriptor, item, onOpen, canShare, onShare, onCatalogItemCreate, onCatalogItemUpdate, onCatalogItemDelete, }) {
|
|
20
|
+
const intl = useIntl();
|
|
21
|
+
const workspaceId = useWorkspaceStrict();
|
|
22
|
+
const [dialog, setDialog] = useState(undefined);
|
|
23
|
+
const actions = useMemo(() => {
|
|
24
|
+
const result = [];
|
|
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
|
+
if (onOpen && descriptor.openAction) {
|
|
28
|
+
result.push({ id: OPEN_ACTION_ID, label: intl.formatMessage(descriptor.openAction) });
|
|
29
|
+
}
|
|
30
|
+
result.push({
|
|
31
|
+
id: "duplicate",
|
|
32
|
+
label: intl.formatMessage(descriptor.messages.duplicate),
|
|
33
|
+
dataTestId: catalogDetailActionDuplicate,
|
|
34
|
+
}, {
|
|
35
|
+
id: "delete",
|
|
36
|
+
label: intl.formatMessage(descriptor.messages.deleteSubmit),
|
|
37
|
+
isDestructive: true,
|
|
38
|
+
dataTestId: catalogDetailActionDelete,
|
|
39
|
+
});
|
|
40
|
+
return result;
|
|
41
|
+
}, [descriptor, intl, onOpen]);
|
|
42
|
+
const closeDialog = useCallback(() => setDialog(undefined), []);
|
|
43
|
+
const handleEditOpen = useCallback(() => setDialog({ kind: "edit", item }), [item]);
|
|
44
|
+
const handleActionsMenuSelect = useCallback((actionId, event) => {
|
|
45
|
+
if (actionId === OPEN_ACTION_ID) {
|
|
46
|
+
onOpen?.(event, {
|
|
47
|
+
item,
|
|
48
|
+
workspaceId,
|
|
49
|
+
newTab: event.metaKey || event.ctrlKey,
|
|
50
|
+
preventDefault: event.preventDefault.bind(event),
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (actionId === "delete") {
|
|
55
|
+
setDialog({ kind: "delete", item });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (actionId === "duplicate") {
|
|
59
|
+
setDialog({ kind: "duplicate", duplicateOf: item });
|
|
60
|
+
}
|
|
61
|
+
}, [item, onOpen, workspaceId]);
|
|
62
|
+
const handleEditDuplicate = useCallback((source) => {
|
|
63
|
+
setDialog({ kind: "duplicate", duplicateSource: source });
|
|
64
|
+
}, []);
|
|
65
|
+
return (_jsxs(_Fragment, { children: [_jsx(CatalogDetailActionBar, { item: item, workspaceId: workspaceId, actions: actions, 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] }));
|
|
66
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { IAsCodeDefinition, IAsCodeDescriptor } from "./descriptor.js";
|
|
2
|
+
/** Whether the dialog creates a new object or edits an existing one. */
|
|
3
|
+
type AsCodeDialogMode = "create" | "edit";
|
|
4
|
+
type Props = {
|
|
5
|
+
descriptor: IAsCodeDescriptor;
|
|
6
|
+
mode: AsCodeDialogMode;
|
|
7
|
+
initialDefinition?: IAsCodeDefinition;
|
|
8
|
+
isLoading?: boolean;
|
|
9
|
+
fixedIdentifier?: string;
|
|
10
|
+
onClose: () => void;
|
|
11
|
+
onSubmit: (definition: IAsCodeDefinition) => Promise<void>;
|
|
12
|
+
onDuplicate?: (definition: IAsCodeDefinition) => void;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Generic create/edit dialog for an as-code object, entity-agnostic via its `descriptor`: it renders
|
|
16
|
+
* the shared editor chrome and delegates serialization, validation, and copy to the descriptor. The
|
|
17
|
+
* caller owns loading and persistence (passes `initialDefinition`, handles `onSubmit`); this component
|
|
18
|
+
* owns only the editing surface.
|
|
19
|
+
*
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export declare function AsCodeDialog(props: Props): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=AsCodeDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AsCodeDialog.d.ts","sourceRoot":"","sources":["../../src/asCode/AsCodeDialog.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAa5E,wEAAwE;AACxE,KAAK,gBAAgB,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE1C,KAAK,KAAK,GAAG;IACT,UAAU,EAAE,iBAAiB,CAAC;IAC9B,IAAI,EAAE,gBAAgB,CAAC;IAIvB,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,UAAU,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,iBAAiB,KAAK,IAAI,CAAC;CACzD,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,2CAyKxC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { Suspense, lazy, useCallback, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { FormattedMessage, defineMessages, useIntl } from "react-intl";
|
|
5
|
+
import { LoadingComponent } from "@gooddata/sdk-ui";
|
|
6
|
+
import { ConfirmDialog, UiButton, UiIcon, UiLink, UiTooltip } from "@gooddata/sdk-ui-kit";
|
|
7
|
+
import { useIsWhiteLabeled } from "../permission/PermissionsContext.js";
|
|
8
|
+
import { extractBackendErrorDetail } from "../utils/backendError.js";
|
|
9
|
+
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
|
+
const messages = defineMessages({
|
|
12
|
+
createSubmit: { id: "analyticsCatalog.asCode.dialog.create.submit" },
|
|
13
|
+
editSubmit: { id: "analyticsCatalog.asCode.dialog.edit.submit" },
|
|
14
|
+
cancel: { id: "analyticsCatalog.asCode.dialog.cancel" },
|
|
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
|
+
*/
|
|
24
|
+
export function AsCodeDialog(props) {
|
|
25
|
+
const { descriptor, mode, initialDefinition, isLoading = false, fixedIdentifier } = props;
|
|
26
|
+
const { onClose, onSubmit, onDuplicate } = props;
|
|
27
|
+
const intl = useIntl();
|
|
28
|
+
const isEdit = mode === "edit";
|
|
29
|
+
const isWhiteLabeled = useIsWhiteLabeled();
|
|
30
|
+
// The descriptor is fixed for the dialog's lifetime (one dialog edits one entity type), so calling
|
|
31
|
+
// its `useEditing` hook here is unconditional and stable — the rules of hooks hold.
|
|
32
|
+
const editing = descriptor.useEditing();
|
|
33
|
+
const { serialize, validate, completionSource, syntaxErrorMessage } = editing;
|
|
34
|
+
const initialYaml = useMemo(() => (initialDefinition === undefined ? "" : serialize(initialDefinition)), [initialDefinition, serialize]);
|
|
35
|
+
// The user's edits; `null` until they type. Submit falls back to `initialYaml`, so the editor
|
|
36
|
+
// mounts once with real data and is the single source of truth — no re-seed effect needed.
|
|
37
|
+
const yamlValue = useRef(null);
|
|
38
|
+
const [validationError, setValidationError] = useState(null);
|
|
39
|
+
const [submitError, setSubmitError] = useState(null);
|
|
40
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
41
|
+
const [isDirty, setIsDirty] = useState(false);
|
|
42
|
+
const headlineMessage = intl.formatMessage(isEdit ? descriptor.messages.editTitle : descriptor.messages.createTitle);
|
|
43
|
+
const submitMessage = intl.formatMessage(isEdit ? messages.editSubmit : messages.createSubmit);
|
|
44
|
+
const cancelMessage = intl.formatMessage(messages.cancel);
|
|
45
|
+
const handleClose = useCallback(() => {
|
|
46
|
+
if (!isSubmitting) {
|
|
47
|
+
onClose();
|
|
48
|
+
}
|
|
49
|
+
}, [isSubmitting, onClose]);
|
|
50
|
+
const handleChange = useCallback((nextValue) => {
|
|
51
|
+
yamlValue.current = nextValue;
|
|
52
|
+
setIsDirty(true);
|
|
53
|
+
setSubmitError(null);
|
|
54
|
+
setValidationError(null);
|
|
55
|
+
}, []);
|
|
56
|
+
const handleSubmit = useCallback(async () => {
|
|
57
|
+
const result = validate(yamlValue.current ?? initialYaml, { fixedIdentifier });
|
|
58
|
+
if (!result.isValid) {
|
|
59
|
+
setValidationError(result.error);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
setIsSubmitting(true);
|
|
63
|
+
setSubmitError(null);
|
|
64
|
+
try {
|
|
65
|
+
await onSubmit(result.definition);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
setSubmitError(extractBackendErrorDetail(error) ?? intl.formatMessage(descriptor.messages.submitError));
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
setIsSubmitting(false);
|
|
72
|
+
}
|
|
73
|
+
}, [descriptor, fixedIdentifier, initialYaml, intl, onSubmit, validate]);
|
|
74
|
+
const handleDuplicate = useCallback(() => {
|
|
75
|
+
if (!onDuplicate) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
setSubmitError(null);
|
|
79
|
+
// A duplicate is a fresh object, so identity is not fixed even though we started from an edit.
|
|
80
|
+
const result = validate(yamlValue.current ?? initialYaml, { fixedIdentifier: undefined });
|
|
81
|
+
if (!result.isValid) {
|
|
82
|
+
setValidationError(result.error);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
onDuplicate(result.definition);
|
|
86
|
+
}, [initialYaml, onDuplicate, validate]);
|
|
87
|
+
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 || isLoading, onClick: handleDuplicate })) : null] })), [descriptor, handleDuplicate, intl, isEdit, isLoading, isSubmitting, isWhiteLabeled, onDuplicate]);
|
|
89
|
+
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 || isLoading || (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: isLoading ? (bodySpinner) : (_jsxs(_Fragment, { children: [
|
|
91
|
+
_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: [
|
|
93
|
+
_jsx("span", { className: "gd-ascode-dialog-error-label", children: _jsx(FormattedMessage, { id: "analyticsCatalog.dialog.error.label" }) }), " ", validationError ?? submitError] })) : null] })) }) }) }));
|
|
94
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ICatalogItem } from "../catalogItem/types.js";
|
|
2
|
+
import type { IAsCodeDefinition, IAsCodeDescriptor } from "./descriptor.js";
|
|
3
|
+
type Props = {
|
|
4
|
+
descriptor: IAsCodeDescriptor;
|
|
5
|
+
item: ICatalogItem;
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
onSaved?: (item: ICatalogItem) => void;
|
|
8
|
+
onDuplicate?: (source: IAsCodeDefinition) => void;
|
|
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
|
+
*/
|
|
16
|
+
export declare function AsCodeEditDialog({ descriptor, item, onClose, onSaved, onDuplicate }: Props): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=AsCodeEditDialog.d.ts.map
|
|
@@ -0,0 +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,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAG5E,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;IAGvC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CACrD,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,KAAK,2CA6C1F"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { useCallback } from "react";
|
|
4
|
+
import { useToastMessage } from "@gooddata/sdk-ui-kit";
|
|
5
|
+
import { AsCodeDialog } from "./AsCodeDialog.js";
|
|
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
|
+
*/
|
|
13
|
+
export function AsCodeEditDialog({ descriptor, item, onClose, onSaved, onDuplicate }) {
|
|
14
|
+
const { addSuccess, addError } = useToastMessage();
|
|
15
|
+
const { base, isLoading, port } = useAsCodeBase(descriptor, item, () => {
|
|
16
|
+
if (descriptor.messages.loadError) {
|
|
17
|
+
addError(descriptor.messages.loadError);
|
|
18
|
+
}
|
|
19
|
+
onClose();
|
|
20
|
+
});
|
|
21
|
+
const handleSubmit = useCallback(async (definition) => {
|
|
22
|
+
if (base === undefined) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const saved = await port.update(base, definition);
|
|
26
|
+
onSaved?.(saved);
|
|
27
|
+
onClose();
|
|
28
|
+
addSuccess(descriptor.messages.updateSuccess);
|
|
29
|
+
}, [addSuccess, base, descriptor, onClose, onSaved, port]);
|
|
30
|
+
const handleDuplicate = useCallback((edited) => {
|
|
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 }));
|
|
38
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CompletionSource } from "@codemirror/autocomplete";
|
|
2
|
+
type Props = {
|
|
3
|
+
initialValue: string;
|
|
4
|
+
onChange: (value: string) => void;
|
|
5
|
+
disabled: boolean;
|
|
6
|
+
completionSource: CompletionSource;
|
|
7
|
+
syntaxErrorMessage: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* The editor half of {@link AsCodeDialog}, split into its own module so the dialog can `lazy()`-load
|
|
11
|
+
* it: this keeps CodeMirror out of the eager catalog bundle. The completion source and syntax-error
|
|
12
|
+
* copy come from the entity's descriptor, so this stays entity-agnostic.
|
|
13
|
+
*/
|
|
14
|
+
export declare function AsCodeEditorBody({ initialValue, onChange, disabled, completionSource, syntaxErrorMessage }: Props): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=AsCodeEditorBody.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AsCodeEditorBody.d.ts","sourceRoot":"","sources":["../../src/asCode/AsCodeEditorBody.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAIjE,KAAK,KAAK,GAAG;IACT,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,OAAO,CAAC;IAClB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,kBAAkB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAC7B,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,EACrB,EAAE,KAAK,2CAUP"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { YamlEditor } from "@gooddata/sdk-ui-kit";
|
|
3
|
+
/**
|
|
4
|
+
* The editor half of {@link AsCodeDialog}, split into its own module so the dialog can `lazy()`-load
|
|
5
|
+
* it: this keeps CodeMirror out of the eager catalog bundle. The completion source and syntax-error
|
|
6
|
+
* copy come from the entity's descriptor, so this stays entity-agnostic.
|
|
7
|
+
*/
|
|
8
|
+
export function AsCodeEditorBody({ initialValue, onChange, disabled, completionSource, syntaxErrorMessage, }) {
|
|
9
|
+
return (_jsx(YamlEditor, { initialValue: initialValue, onChange: onChange, disabled: disabled, completionSource: completionSource, syntaxErrorMessage: syntaxErrorMessage }));
|
|
10
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type PropsWithChildren } from "react";
|
|
2
|
+
import type { ObjectType } from "../objectType/types.js";
|
|
3
|
+
import type { AsCodeObjectType, IAsCodeDescriptor, IAsCodeMutationPort } from "./descriptor.js";
|
|
4
|
+
type AsCodeMutations = Partial<Record<AsCodeObjectType, IAsCodeMutationPort>>;
|
|
5
|
+
type ProviderProps = PropsWithChildren<{
|
|
6
|
+
/** Descriptors for each as-code capable object type; used to build adapters. */
|
|
7
|
+
descriptors?: Record<AsCodeObjectType, IAsCodeDescriptor>;
|
|
8
|
+
/** Per-type port overrides for tests. */
|
|
9
|
+
ports?: AsCodeMutations;
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* Builds and provides one mutation port per supplied descriptor. Must be placed inside `BackendProvider`
|
|
13
|
+
* and `WorkspaceProvider`.
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export declare function AsCodeMutationProvider({ children, descriptors, ports }: ProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
/**
|
|
18
|
+
* The mutation port for one as-code type. Throws for a non-as-code type (a caller should only reach
|
|
19
|
+
* this via a resolved descriptor) or when the provider is missing.
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export declare function useAsCodePort(type: ObjectType): IAsCodeMutationPort;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=AsCodeMutationContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AsCodeMutationContext.d.ts","sourceRoot":"","sources":["../../src/asCode/AsCodeMutationContext.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,iBAAiB,EAAsC,MAAM,OAAO,CAAC;AAInF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEhG,KAAK,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC,CAAC;AAI9E,KAAK,aAAa,GAAG,iBAAiB,CAAC;IACnC,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC;IAC1D,yCAAyC;IACzC,KAAK,CAAC,EAAE,eAAe,CAAC;CAC3B,CAAC,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,aAAa,2CAerF;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,mBAAmB,CAUnE"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { createContext, useContext, useMemo } from "react";
|
|
4
|
+
import { useBackendStrict, useWorkspaceStrict } from "@gooddata/sdk-ui";
|
|
5
|
+
const AsCodeMutationContext = createContext(null);
|
|
6
|
+
/**
|
|
7
|
+
* Builds and provides one mutation port per supplied descriptor. Must be placed inside `BackendProvider`
|
|
8
|
+
* and `WorkspaceProvider`.
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export function AsCodeMutationProvider({ children, descriptors, ports }) {
|
|
12
|
+
const backend = useBackendStrict();
|
|
13
|
+
const workspace = useWorkspaceStrict();
|
|
14
|
+
const mutations = useMemo(() => {
|
|
15
|
+
const built = {};
|
|
16
|
+
// Object.entries widens the key to string; the map's own type guarantees it is an AsCodeObjectType.
|
|
17
|
+
const entries = Object.entries(descriptors ?? {});
|
|
18
|
+
for (const [type, descriptor] of entries) {
|
|
19
|
+
built[type] = descriptor.createMutationPort(backend, workspace);
|
|
20
|
+
}
|
|
21
|
+
return { ...built, ...ports };
|
|
22
|
+
}, [backend, workspace, descriptors, ports]);
|
|
23
|
+
return _jsx(AsCodeMutationContext.Provider, { value: mutations, children: children });
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The mutation port for one as-code type. Throws for a non-as-code type (a caller should only reach
|
|
27
|
+
* this via a resolved descriptor) or when the provider is missing.
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
export function useAsCodePort(type) {
|
|
31
|
+
const mutations = useContext(AsCodeMutationContext);
|
|
32
|
+
if (!mutations) {
|
|
33
|
+
throw new Error("useAsCodePort must be used within AsCodeMutationProvider");
|
|
34
|
+
}
|
|
35
|
+
const port = mutations[type];
|
|
36
|
+
if (!port) {
|
|
37
|
+
throw new Error(`No as-code mutation port is registered for object type "${type}".`);
|
|
38
|
+
}
|
|
39
|
+
return port;
|
|
40
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derives the identity (id + title) of a copied as-code object from the original; the remaining
|
|
3
|
+
* fields are copied by each type.
|
|
4
|
+
*
|
|
5
|
+
* The title gains a ` (2)` suffix, or increments an existing ` (N)`. The id is re-derived from that
|
|
6
|
+
* title or dropped (see `shouldOmitCopiedId`). Absent fields are left off so a spread does not
|
|
7
|
+
* introduce them.
|
|
8
|
+
*/
|
|
9
|
+
export declare function deriveCopyIdentity(source: {
|
|
10
|
+
id?: string;
|
|
11
|
+
title?: string;
|
|
12
|
+
}): {
|
|
13
|
+
id?: string;
|
|
14
|
+
title?: string;
|
|
15
|
+
};
|
|
16
|
+
/** A create failed because the chosen id already exists (backend responds with HTTP 409). */
|
|
17
|
+
export declare function isDuplicateIdError(error: unknown): boolean;
|
|
18
|
+
//# sourceMappingURL=copy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../../src/asCode/copy.ts"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IACzE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB,CAOA;AAwCD,6FAA6F;AAC7F,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE1D"}
|