@gooddata/sdk-ui-catalog 11.50.0-alpha.1 → 11.50.0-alpha.3

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.
Files changed (106) hide show
  1. package/esm/AnalyticsCatalogDetail.d.ts.map +1 -1
  2. package/esm/AnalyticsCatalogDetail.js +1 -3
  3. package/esm/asCode/AsCodeCreateDialog.d.ts +3 -7
  4. package/esm/asCode/AsCodeCreateDialog.d.ts.map +1 -1
  5. package/esm/asCode/AsCodeCreateDialog.js +13 -23
  6. package/esm/asCode/AsCodeDeleteDialog.d.ts +1 -6
  7. package/esm/asCode/AsCodeDeleteDialog.d.ts.map +1 -1
  8. package/esm/asCode/AsCodeDeleteDialog.js +11 -20
  9. package/esm/asCode/AsCodeDetailActions.d.ts +2 -11
  10. package/esm/asCode/AsCodeDetailActions.d.ts.map +1 -1
  11. package/esm/asCode/AsCodeDetailActions.js +16 -22
  12. package/esm/asCode/AsCodeDialog.d.ts +12 -17
  13. package/esm/asCode/AsCodeDialog.d.ts.map +1 -1
  14. package/esm/asCode/AsCodeDialog.js +59 -27
  15. package/esm/asCode/AsCodeEditDialog.d.ts +3 -8
  16. package/esm/asCode/AsCodeEditDialog.d.ts.map +1 -1
  17. package/esm/asCode/AsCodeEditDialog.js +4 -21
  18. package/esm/asCode/descriptor.d.ts +78 -104
  19. package/esm/asCode/descriptor.d.ts.map +1 -1
  20. package/esm/asCode/descriptor.js +13 -4
  21. package/esm/asCode/serverIdentity.d.ts +7 -0
  22. package/esm/asCode/serverIdentity.d.ts.map +1 -0
  23. package/esm/asCode/serverIdentity.js +2 -0
  24. package/esm/asCode/tests/withMutationPort.d.ts +4 -0
  25. package/esm/asCode/tests/withMutationPort.d.ts.map +1 -0
  26. package/esm/asCode/tests/withMutationPort.js +5 -0
  27. package/esm/asCode/useAsCodeBase.d.ts +5 -8
  28. package/esm/asCode/useAsCodeBase.d.ts.map +1 -1
  29. package/esm/asCode/useAsCodeBase.js +20 -18
  30. package/esm/asCode/useAsCodeLoadFailure.d.ts +8 -0
  31. package/esm/asCode/useAsCodeLoadFailure.d.ts.map +1 -0
  32. package/esm/asCode/useAsCodeLoadFailure.js +21 -0
  33. package/esm/asCode/useMutationPort.d.ts +4 -0
  34. package/esm/asCode/useMutationPort.d.ts.map +1 -0
  35. package/esm/asCode/useMutationPort.js +9 -0
  36. package/esm/asCode/validateYaml.d.ts +16 -12
  37. package/esm/asCode/validateYaml.d.ts.map +1 -1
  38. package/esm/asCode/validateYaml.js +8 -9
  39. package/esm/asCodeRegistry.d.ts +5 -14
  40. package/esm/asCodeRegistry.d.ts.map +1 -1
  41. package/esm/asCodeRegistry.js +29 -15
  42. package/esm/catalog/Catalog.d.ts.map +1 -1
  43. package/esm/catalog/Catalog.js +2 -8
  44. package/esm/catalogDetail/CatalogDetailActionBar.d.ts.map +1 -1
  45. package/esm/catalogDetail/CatalogDetailActionBar.js +4 -8
  46. package/esm/catalogDetail/CatalogDetailActions.d.ts.map +1 -1
  47. package/esm/catalogDetail/CatalogDetailActions.js +2 -6
  48. package/esm/catalogDetail/openHandlerEvent.d.ts +6 -0
  49. package/esm/catalogDetail/openHandlerEvent.d.ts.map +1 -0
  50. package/esm/catalogDetail/openHandlerEvent.js +10 -0
  51. package/esm/header/CreateObjectButton.d.ts +1 -3
  52. package/esm/header/CreateObjectButton.d.ts.map +1 -1
  53. package/esm/header/CreateObjectButton.js +10 -22
  54. package/esm/index.d.ts +2 -0
  55. package/esm/index.d.ts.map +1 -1
  56. package/esm/index.js +5 -0
  57. package/esm/insight/gate.d.ts +4 -0
  58. package/esm/insight/gate.d.ts.map +1 -0
  59. package/esm/insight/gate.js +4 -0
  60. package/esm/insight/insightCodecContext.d.ts +22 -0
  61. package/esm/insight/insightCodecContext.d.ts.map +1 -0
  62. package/esm/insight/insightCodecContext.js +30 -0
  63. package/esm/insight/insightCopy.d.ts +4 -0
  64. package/esm/insight/insightCopy.d.ts.map +1 -0
  65. package/esm/insight/insightCopy.js +25 -0
  66. package/esm/insight/insightDescriptor.d.ts +7 -0
  67. package/esm/insight/insightDescriptor.d.ts.map +1 -0
  68. package/esm/insight/insightDescriptor.js +69 -0
  69. package/esm/insight/insightMutationPort.d.ts +13 -0
  70. package/esm/insight/insightMutationPort.d.ts.map +1 -0
  71. package/esm/insight/insightMutationPort.js +59 -0
  72. package/esm/localization/bundles/en-US.localization-bundle.d.ts +72 -0
  73. package/esm/localization/bundles/en-US.localization-bundle.d.ts.map +1 -1
  74. package/esm/localization/bundles/en-US.localization-bundle.js +72 -0
  75. package/esm/metric/gate.d.ts +1 -6
  76. package/esm/metric/gate.d.ts.map +1 -1
  77. package/esm/metric/gate.js +1 -9
  78. package/esm/metric/metricConverter.d.ts +8 -17
  79. package/esm/metric/metricConverter.d.ts.map +1 -1
  80. package/esm/metric/metricConverter.js +10 -24
  81. package/esm/metric/metricDescriptor.d.ts.map +1 -1
  82. package/esm/metric/metricDescriptor.js +19 -8
  83. package/esm/metric/metricMutationPort.d.ts +5 -3
  84. package/esm/metric/metricMutationPort.d.ts.map +1 -1
  85. package/esm/metric/metricMutationPort.js +21 -14
  86. package/esm/metric/metricValidation.d.ts.map +1 -1
  87. package/esm/metric/metricValidation.js +7 -4
  88. package/esm/metric/tests/metricMutationPort.test.utils.d.ts +1 -4
  89. package/esm/metric/tests/metricMutationPort.test.utils.d.ts.map +1 -1
  90. package/esm/metric/tests/metricMutationPort.test.utils.js +1 -19
  91. package/esm/parameter/gate.d.ts +1 -5
  92. package/esm/parameter/gate.d.ts.map +1 -1
  93. package/esm/parameter/gate.js +1 -8
  94. package/esm/parameter/parameterDescriptor.d.ts.map +1 -1
  95. package/esm/parameter/parameterDescriptor.js +22 -13
  96. package/esm/parameter/parameterValidation.d.ts.map +1 -1
  97. package/esm/parameter/parameterValidation.js +11 -23
  98. package/esm/sdk-ui-catalog.d.ts +49 -0
  99. package/esm/tsdoc-metadata.json +1 -1
  100. package/package.json +15 -15
  101. package/esm/asCode/AsCodeMutationContext.d.ts +0 -24
  102. package/esm/asCode/AsCodeMutationContext.d.ts.map +0 -1
  103. package/esm/asCode/AsCodeMutationContext.js +0 -40
  104. package/esm/asCode/gate.d.ts +0 -7
  105. package/esm/asCode/gate.d.ts.map +0 -1
  106. 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;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
+ {"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: _jsx(AsCodeMutationProvider, { descriptors: asCodeDescriptors, children: props.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 { IAsCodeDefinition, IAsCodeDescriptor } from "./descriptor.js";
2
+ import type { IAsCodeDescriptor } from "./descriptor.js";
3
3
  type Props = {
4
4
  descriptor: IAsCodeDescriptor;
5
5
  duplicateOf?: ICatalogItem;
6
- duplicateSource?: IAsCodeDefinition;
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,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"}
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, 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
- });
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 copiedId = copied?.id;
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(toPersist);
22
+ created = await port.create(definition);
35
23
  }
36
24
  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);
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, copied, copiedId, descriptor, onClose, onCreated, port]);
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;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"}
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 { useAsCodePort } from "./AsCodeMutationContext.js";
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 port = useAsCodePort(descriptor.objectType);
21
- const { messages: msg } = descriptor;
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
- // 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;
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 && msg.deleteUsageWarning ? (_jsx("div", { children: _jsx(FormattedMessage, { ...msg.deleteUsageWarning, values: { count: referencingCount } }) })) : null] }));
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;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,2CAkG3B"}
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
- mainGroup.push({
31
- id: "duplicate",
32
- label: intl.formatMessage(descriptor.messages.duplicate),
33
- dataTestId: catalogDetailActionDuplicate,
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 { IAsCodeDefinition, IAsCodeDescriptor } from "./descriptor.js";
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
- mode: AsCodeDialogMode;
7
- initialDefinition?: IAsCodeDefinition;
4
+ initialDefinition?: unknown;
8
5
  isLoading?: boolean;
9
- fixedIdentifier?: string;
10
6
  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
- */
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,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"}
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
- // 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.
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 { 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.
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
- const result = validate(yamlValue.current ?? initialYaml, { fixedIdentifier });
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(result.definition);
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, validate]);
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
- // 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 });
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, validate]);
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 || isLoading, onClick: handleDuplicate })) : null] })), [descriptor, handleDuplicate, intl, isEdit, isLoading, isSubmitting, isWhiteLabeled, onDuplicate]);
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 || 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: [
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 { IAsCodeDefinition, IAsCodeDescriptor } from "./descriptor.js";
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: IAsCodeDefinition) => void;
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,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"}
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, addError } = useToastMessage();
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
- 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 }));
20
+ return (_jsx(AsCodeDialog, { descriptor: descriptor, mode: "edit", isLoading: isLoading, initialDefinition: base, fixedIdentifier: item.identifier, onClose: onClose, onSubmit: handleSubmit, onDuplicate: onDuplicate }));
38
21
  }