@gooddata/sdk-ui-catalog 11.50.0-alpha.2 → 11.50.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) 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/package.json +15 -15
  100. package/esm/asCode/AsCodeMutationContext.d.ts +0 -24
  101. package/esm/asCode/AsCodeMutationContext.d.ts.map +0 -1
  102. package/esm/asCode/AsCodeMutationContext.js +0 -40
  103. package/esm/asCode/gate.d.ts +0 -7
  104. package/esm/asCode/gate.d.ts.map +0 -1
  105. package/esm/asCode/gate.js +0 -11
@@ -1,32 +1,24 @@
1
1
  // (C) 2026 GoodData Corporation
2
+ import { useMemo } from "react";
3
+ import { visualizationDescriptor } from "./insight/insightDescriptor.js";
2
4
  import { metricDescriptor } from "./metric/metricDescriptor.js";
3
5
  import { ObjectTypes } from "./objectType/constants.js";
4
6
  import { parameterDescriptor } from "./parameter/parameterDescriptor.js";
5
- import { useFeatureFlags } from "./permission/PermissionsContext.js";
6
- /**
7
- * Every as-code descriptor, keyed by type — the one place the concrete descriptors are registered. The
8
- * key is the full `AsCodeObjectType` union, so a missing type is a compile error.
9
- * @internal
10
- */
7
+ import { useFeatureFlags, useWorkspacePermission } from "./permission/PermissionsContext.js";
8
+ /** @internal */
11
9
  export const asCodeDescriptors = {
12
10
  [ObjectTypes.METRIC]: metricDescriptor,
13
11
  [ObjectTypes.PARAMETER]: parameterDescriptor,
12
+ [ObjectTypes.VISUALIZATION]: visualizationDescriptor,
14
13
  };
15
14
  function isAsCodeObjectType(type) {
16
15
  return Object.prototype.hasOwnProperty.call(asCodeDescriptors, type);
17
16
  }
18
- /**
19
- * The as-code descriptor for a catalog object type, or `undefined` if the type is not editable as code.
20
- * @internal
21
- */
17
+ /** @internal */
22
18
  export function getAsCodeDescriptor(type) {
23
19
  return isAsCodeObjectType(type) ? asCodeDescriptors[type] : undefined;
24
20
  }
25
- /**
26
- * Whether this descriptor's editor is enabled by the feature flags. A descriptor with no `featureFlag`
27
- * is always editable; `undefined` (not an as-code type) never is.
28
- * @internal
29
- */
21
+ /** A descriptor with no `featureFlag` is always editable; `undefined` (not an as-code type) never is. @internal */
30
22
  export function useIsAsCodeTypeEditable(descriptor) {
31
23
  const flags = useFeatureFlags();
32
24
  if (descriptor === undefined) {
@@ -34,3 +26,25 @@ export function useIsAsCodeTypeEditable(descriptor) {
34
26
  }
35
27
  return descriptor.featureFlag === undefined || Boolean(flags?.[descriptor.featureFlag]);
36
28
  }
29
+ function useIsAsCodeTypeCreatable(descriptor) {
30
+ const isTypeEditable = useIsAsCodeTypeEditable(descriptor);
31
+ const canManageProject = useWorkspacePermission("canManageProject");
32
+ const createGate = descriptor.useCreateGate?.() ?? true;
33
+ return isTypeEditable && canManageProject && createGate;
34
+ }
35
+ /** @internal */
36
+ export function useCreatableObjectTypes() {
37
+ // One unconditional hook call per registered type (fixed count for the rules of hooks).
38
+ const metric = useIsAsCodeTypeCreatable(asCodeDescriptors[ObjectTypes.METRIC]);
39
+ const parameter = useIsAsCodeTypeCreatable(asCodeDescriptors[ObjectTypes.PARAMETER]);
40
+ const visualization = useIsAsCodeTypeCreatable(asCodeDescriptors[ObjectTypes.VISUALIZATION]);
41
+ return useMemo(() => {
42
+ // The `Record<AsCodeObjectType, …>` makes a newly registered type a compile error until listed here.
43
+ const creatable = {
44
+ [ObjectTypes.METRIC]: metric,
45
+ [ObjectTypes.PARAMETER]: parameter,
46
+ [ObjectTypes.VISUALIZATION]: visualization,
47
+ };
48
+ return new Set(Object.keys(creatable).filter((type) => creatable[type]));
49
+ }, [metric, parameter, visualization]);
50
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"Catalog.d.ts","sourceRoot":"","sources":["../../src/catalog/Catalog.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AAIxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAMpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAM/D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAWtE,KAAK,KAAK,GAAG;IACT,OAAO,EAAE,kBAAkB,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,eAAe,CAAC;IACrC,sBAAsB,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACnF,uBAAuB,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IAC/E,qBAAqB,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IACvD,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,uBAAuB,KAAK,IAAI,CAAC;CAClE,CAAC;AAEF,wBAAgB,OAAO,CAAC,EACpB,kBAAkB,EAClB,OAAO,EACP,SAAS,EACT,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACjB,EAAE,KAAK,2CAsEP"}
1
+ {"version":3,"file":"Catalog.d.ts","sourceRoot":"","sources":["../../src/catalog/Catalog.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AAIxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAIpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAK/D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAUtE,KAAK,KAAK,GAAG;IACT,OAAO,EAAE,kBAAkB,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,eAAe,CAAC;IACrC,sBAAsB,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACnF,uBAAuB,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IAC/E,qBAAqB,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IACvD,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,uBAAuB,KAAK,IAAI,CAAC;CAClE,CAAC;AAEF,wBAAgB,OAAO,CAAC,EACpB,kBAAkB,EAClB,OAAO,EACP,SAAS,EACT,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACjB,EAAE,KAAK,2CA4DP"}
@@ -4,16 +4,12 @@ import {} from "react";
4
4
  import { useIntl } from "react-intl";
5
5
  import { ErrorComponent } from "@gooddata/sdk-ui";
6
6
  import { LoadingMask } from "@gooddata/sdk-ui-kit";
7
- import { AsCodeMutationProvider } from "../asCode/AsCodeMutationContext.js";
8
- import { asCodeDescriptors } from "../asCodeRegistry.js";
9
7
  import { CatalogFeedProvider } from "../catalogItem/CatalogFeedContext.js";
10
8
  import {} from "../catalogItem/types.js";
11
9
  import { CreateObjectButton } from "../header/CreateObjectButton.js";
12
10
  import { Header } from "../header/Header.js";
13
11
  import { useCatalogItemOpen } from "../main/hooks/useCatalogItemOpen.js";
14
12
  import { Main } from "../main/Main.js";
15
- import { useCanManageMetric } from "../metric/gate.js";
16
- import { useCanManageParameter } from "../parameter/gate.js";
17
13
  import { PermissionsGate } from "../permission/PermissionsGate.js";
18
14
  import { useIsCatalogQualityEnabled } from "../quality/gate.js";
19
15
  import { QualityScoreCard } from "../quality/QualityScoreCard.js";
@@ -23,8 +19,6 @@ import { useIsCatalogTrendingObjectsEnabled } from "../tabs/gate.js";
23
19
  import { Layout } from "./Layout.js";
24
20
  export function Catalog({ openCatalogItemRef, backend, workspace, onCatalogItemOpenClick, onCatalogItemNavigation, onCatalogDetailOpened, onCatalogDetailClosed, onCreateObject, }) {
25
21
  const intl = useIntl();
26
- const showParameter = useCanManageParameter();
27
- const showMetricEditor = useCanManageMetric();
28
22
  const isTrendingEnabled = useIsCatalogTrendingObjectsEnabled();
29
23
  const isQualityEnabled = useIsCatalogQualityEnabled();
30
24
  const { open, openedItem, setItemOpened, onOpenDetail, onCloseDetail, onOpenClick } = useCatalogItemOpen(onCatalogItemOpenClick, onCatalogDetailOpened, onCatalogDetailClosed, openCatalogItemRef);
@@ -32,6 +26,6 @@ export function Catalog({ openCatalogItemRef, backend, workspace, onCatalogItemO
32
26
  id: "analyticsCatalog.error.unknown.description",
33
27
  }) }), unauthorizedNode: _jsx(ErrorComponent, { message: intl.formatMessage({ id: "analyticsCatalog.error.unauthorized.message" }), description: intl.formatMessage({
34
28
  id: "analyticsCatalog.error.unauthorized.description",
35
- }) }), children: _jsx(CatalogFeedProvider, { backend: backend, workspace: workspace, children: _jsxs(AsCodeMutationProvider, { descriptors: asCodeDescriptors, children: [_jsx(Header, { searchNode: _jsx(FullTextSearchInput, {}), createNode: onCreateObject ? (_jsx(CreateObjectButton, { onCreateObject: onCreateObject, showParameter: showParameter, showMetricEditor: showMetricEditor })) : null }), isTrendingEnabled ? (_jsx(CatalogTabs, { onItemClick: onOpenDetail })) : isQualityEnabled ? (_jsx(QualityScoreCard, {})) : null, _jsx(Main, { workspace: workspace, backend: backend, open: open, openedItem: openedItem, setItemOpened: setItemOpened, onOpenDetail: onOpenDetail, onCloseDetail: onCloseDetail, onOpenClick: onOpenClick, onCatalogItemNavigation: onCatalogItemNavigation })
36
- ] }) }) }) }));
29
+ }) }), children: _jsxs(CatalogFeedProvider, { backend: backend, workspace: workspace, children: [_jsx(Header, { searchNode: _jsx(FullTextSearchInput, {}), createNode: onCreateObject ? _jsx(CreateObjectButton, { onCreateObject: onCreateObject }) : null }), isTrendingEnabled ? (_jsx(CatalogTabs, { onItemClick: onOpenDetail })) : isQualityEnabled ? (_jsx(QualityScoreCard, {})) : null, _jsx(Main, { workspace: workspace, backend: backend, open: open, openedItem: openedItem, setItemOpened: setItemOpened, onOpenDetail: onOpenDetail, onCloseDetail: onCloseDetail, onOpenClick: onOpenClick, onCatalogItemNavigation: onCatalogItemNavigation })
30
+ ] }) }) }));
37
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CatalogDetailActionBar.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailActionBar.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAW,MAAM,OAAO,CAAC;AAOrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAUzE,MAAM,MAAM,4BAA4B,GAAG;IACvC,IAAI,EAAE,YAAY,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,YAAY,EAAE,oBAAoB,EAAE,EAAE,CAAC;IACvC,6DAA6D;IAC7D,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5E,mBAAmB,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,aAAa,KAAK,IAAI,CAAC;CACtF,CAAC;AAEF;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,EACnC,IAAI,EACJ,WAAW,EACX,YAAY,EACZ,cAAc,EACd,WAAW,EACX,mBAAmB,EACtB,EAAE,4BAA4B,2CA+E9B"}
1
+ {"version":3,"file":"CatalogDetailActionBar.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailActionBar.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAW,MAAM,OAAO,CAAC;AAOrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAUzE,MAAM,MAAM,4BAA4B,GAAG;IACvC,IAAI,EAAE,YAAY,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,YAAY,EAAE,oBAAoB,EAAE,EAAE,CAAC;IACvC,6DAA6D;IAC7D,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5E,mBAAmB,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,aAAa,KAAK,IAAI,CAAC;CACtF,CAAC;AAEF;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,EACnC,IAAI,EACJ,WAAW,EACX,YAAY,EACZ,cAAc,EACd,WAAW,EACX,mBAAmB,EACtB,EAAE,4BAA4B,2CA8E9B"}
@@ -4,6 +4,7 @@ import { useMemo } from "react";
4
4
  import { defineMessages, useIntl } from "react-intl";
5
5
  import { Dropdown, UiButton, UiIconButton, UiMenu } from "@gooddata/sdk-ui-kit";
6
6
  import { catalogDetailActionsTrigger } from "../automation/testIds.js";
7
+ import { toOpenHandlerEvent } from "./openHandlerEvent.js";
7
8
  const messages = defineMessages({
8
9
  actionsMenuAriaLabel: { id: "analyticsCatalog.catalogItem.actionsMenu.ariaLabel" },
9
10
  });
@@ -22,14 +23,9 @@ export function CatalogDetailActionBar({ item, workspaceId, actionGroups, leadin
22
23
  }));
23
24
  return groupIndex > 0 ? [{ type: "separator" }, ...items] : items;
24
25
  }), [actionGroups]);
25
- return (_jsxs("div", { className: "gd-analytics-catalog-detail__detail-actions", children: [leadingActions, _jsx(UiButton, { label: intl.formatMessage({ id: "analyticsCatalog.edit" }), variant: "primary", size: "medium", onClick: (event) => {
26
- onEditClick?.(event, {
27
- item,
28
- workspaceId,
29
- newTab: event.metaKey || event.ctrlKey,
30
- preventDefault: event.preventDefault.bind(event),
31
- });
32
- } }), _jsx(Dropdown, { alignPoints: [{ align: "br tr" }], renderButton: ({ toggleDropdown, buttonRef, ariaAttributes, accessibilityConfig }) => (_jsx(UiIconButton, { ref: (element) => {
26
+ return (_jsxs("div", { className: "gd-analytics-catalog-detail__detail-actions", children: [leadingActions, onEditClick ? (_jsx(UiButton, { label: intl.formatMessage({ id: "analyticsCatalog.edit" }), variant: "primary", size: "medium", onClick: (event) => {
27
+ onEditClick(event, toOpenHandlerEvent(event, item, workspaceId));
28
+ } })) : null, _jsx(Dropdown, { alignPoints: [{ align: "br tr" }], renderButton: ({ toggleDropdown, buttonRef, ariaAttributes, accessibilityConfig }) => (_jsx(UiIconButton, { ref: (element) => {
33
29
  buttonRef.current = element;
34
30
  }, icon: "ellipsis", variant: "secondary", size: "medium", onClick: toggleDropdown, dataTestId: catalogDetailActionsTrigger, accessibilityConfig: {
35
31
  ...accessibilityConfig,
@@ -1 +1 @@
1
- {"version":3,"file":"CatalogDetailActions.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailActions.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AASxC,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClE,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,oBAAoB,CAAC,EACjC,IAAI,EACJ,OAAO,EACP,MAAM,EACN,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACtB,EAAE,0BAA0B,kDAqD5B"}
1
+ {"version":3,"file":"CatalogDetailActions.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailActions.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AASxC,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAK7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClE,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,oBAAoB,CAAC,EACjC,IAAI,EACJ,OAAO,EACP,MAAM,EACN,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACtB,EAAE,0BAA0B,kDAgD5B"}
@@ -6,6 +6,7 @@ import { useWorkspaceStrict } from "@gooddata/sdk-ui";
6
6
  import { UiButton } from "@gooddata/sdk-ui-kit";
7
7
  import { AsCodeDetailActions } from "../asCode/AsCodeDetailActions.js";
8
8
  import { getAsCodeDescriptor, useIsAsCodeTypeEditable } from "../asCodeRegistry.js";
9
+ import { toOpenHandlerEvent } from "./openHandlerEvent.js";
9
10
  import { useCatalogItemShareActions } from "./share/CatalogItemShareProvider.js";
10
11
  import { ShareButton } from "./share/ShareButton.js";
11
12
  /**
@@ -36,12 +37,7 @@ export function CatalogDetailActions({ item, canEdit, onOpen, onCatalogItemCreat
36
37
  return null;
37
38
  }
38
39
  return (_jsxs("div", { className: "gd-analytics-catalog-detail__header-actions", children: [share.active ? _jsx(ShareButton, { onClick: share.open }) : null, _jsx(UiButton, { label: intl.formatMessage({ id: "analyticsCatalog.catalogItem.open" }), variant: "primary", accessibilityConfig: { role: "link" }, onClick: (event) => {
39
- onOpen?.(event, {
40
- item,
41
- workspaceId,
42
- newTab: event.metaKey || event.ctrlKey,
43
- preventDefault: event.preventDefault.bind(event),
44
- });
40
+ onOpen?.(event, toOpenHandlerEvent(event, item, workspaceId));
45
41
  } })
46
42
  ] }));
47
43
  }
@@ -0,0 +1,6 @@
1
+ import type { MouseEvent } from "react";
2
+ import type { ICatalogItem } from "../catalogItem/types.js";
3
+ import type { OpenHandlerEvent } from "./types.js";
4
+ /** @internal */
5
+ export declare function toOpenHandlerEvent(event: MouseEvent, item: ICatalogItem, workspaceId: string): OpenHandlerEvent;
6
+ //# sourceMappingURL=openHandlerEvent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openHandlerEvent.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/openHandlerEvent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,gBAAgB;AAChB,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,YAAY,EAClB,WAAW,EAAE,MAAM,GACpB,gBAAgB,CAOlB"}
@@ -0,0 +1,10 @@
1
+ // (C) 2026 GoodData Corporation
2
+ /** @internal */
3
+ export function toOpenHandlerEvent(event, item, workspaceId) {
4
+ return {
5
+ item,
6
+ workspaceId,
7
+ newTab: event.metaKey || event.ctrlKey,
8
+ preventDefault: event.preventDefault.bind(event),
9
+ };
10
+ }
@@ -1,9 +1,7 @@
1
1
  import type { CatalogCreateObjectType } from "../objectType/types.js";
2
2
  type Props = {
3
3
  onCreateObject: (objectType: CatalogCreateObjectType) => void;
4
- showParameter?: boolean;
5
- showMetricEditor?: boolean;
6
4
  };
7
- export declare function CreateObjectButton({ onCreateObject, showParameter, showMetricEditor }: Props): import("react/jsx-runtime").JSX.Element;
5
+ export declare function CreateObjectButton({ onCreateObject }: Props): import("react/jsx-runtime").JSX.Element;
8
6
  export {};
9
7
  //# sourceMappingURL=CreateObjectButton.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CreateObjectButton.d.ts","sourceRoot":"","sources":["../../src/header/CreateObjectButton.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAatE,KAAK,KAAK,GAAG;IACT,cAAc,EAAE,CAAC,UAAU,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAC9D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,EAAE,cAAc,EAAE,aAAa,EAAE,gBAAgB,EAAE,EAAE,KAAK,2CAkH5F"}
1
+ {"version":3,"file":"CreateObjectButton.d.ts","sourceRoot":"","sources":["../../src/header/CreateObjectButton.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAatE,KAAK,KAAK,GAAG;IACT,cAAc,EAAE,CAAC,UAAU,EAAE,uBAAuB,KAAK,IAAI,CAAC;CACjE,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,EAAE,cAAc,EAAE,EAAE,KAAK,2CAsG3D"}
@@ -4,7 +4,7 @@ import { useCallback, useMemo, useState } from "react";
4
4
  import { useIntl } from "react-intl";
5
5
  import { Dropdown, UiButton, UiIcon, UiMenu, } from "@gooddata/sdk-ui-kit";
6
6
  import { AsCodeCreateDialog } from "../asCode/AsCodeCreateDialog.js";
7
- import { getAsCodeDescriptor } from "../asCodeRegistry.js";
7
+ import { getAsCodeDescriptor, useCreatableObjectTypes } from "../asCodeRegistry.js";
8
8
  import { useCatalogFeedActions } from "../catalogItem/CatalogFeedContext.js";
9
9
  import { ObjectTypes } from "../objectType/constants.js";
10
10
  import { getObjectTypeLabel } from "../objectType/labels.js";
@@ -14,23 +14,12 @@ const icons = {
14
14
  [ObjectTypes.METRIC]: "metric",
15
15
  [ObjectTypes.PARAMETER]: "parameter",
16
16
  };
17
- export function CreateObjectButton({ onCreateObject, showParameter, showMetricEditor }) {
17
+ export function CreateObjectButton({ onCreateObject }) {
18
18
  const intl = useIntl();
19
19
  const { refetchObjectType } = useCatalogFeedActions();
20
- // The type whose create dialog is open, or undefined when none is. One state for every as-code
21
- // type, since they all open the same generic dialog.
22
20
  const [openType, setOpenType] = useState(undefined);
23
- // The types created inline in a catalog dialog (the rest redirect to a standalone editor).
24
- const inCatalogTypes = useMemo(() => {
25
- const types = new Set();
26
- if (showMetricEditor) {
27
- types.add(ObjectTypes.METRIC);
28
- }
29
- if (showParameter) {
30
- types.add(ObjectTypes.PARAMETER);
31
- }
32
- return types;
33
- }, [showMetricEditor, showParameter]);
21
+ // Widened to the full create-menu vocabulary so redirect-only types can be membership-tested.
22
+ const inCatalogTypes = useCreatableObjectTypes();
34
23
  const items = useMemo(() => {
35
24
  const externalLinkIcon = _jsx(MenuItemIcon, { type: "externalLink" });
36
25
  const interactiveItem = (type, redirects) => ({
@@ -38,21 +27,20 @@ export function CreateObjectButton({ onCreateObject, showParameter, showMetricEd
38
27
  id: type,
39
28
  stringTitle: getObjectTypeLabel(intl, type),
40
29
  iconLeft: _jsx(MenuItemIcon, { type: icons[type] }),
41
- // A redirect create leaves the catalog for the standalone editor; an in-catalog create
42
- // opens a dialog and needs no external-link affordance.
43
30
  iconRight: redirects ? externalLinkIcon : undefined,
44
31
  data: type,
45
32
  });
46
- // A separator divides creates that redirect to a standalone editor from those handled inline
47
- // in a catalog dialog. Metric switches sides: it redirects unless its in-catalog editor is on.
33
+ // Metric and visualization redirect to a standalone editor unless their in-catalog editor is on.
48
34
  return [
49
35
  interactiveItem(ObjectTypes.DASHBOARD, true),
50
- interactiveItem(ObjectTypes.VISUALIZATION, true),
51
- ...(showMetricEditor ? [] : [interactiveItem(ObjectTypes.METRIC, true)]),
36
+ ...(inCatalogTypes.has(ObjectTypes.VISUALIZATION)
37
+ ? []
38
+ : [interactiveItem(ObjectTypes.VISUALIZATION, true)]),
39
+ ...(inCatalogTypes.has(ObjectTypes.METRIC) ? [] : [interactiveItem(ObjectTypes.METRIC, true)]),
52
40
  { type: "separator" },
53
41
  ...[...inCatalogTypes].map((type) => interactiveItem(type, false)),
54
42
  ];
55
- }, [intl, inCatalogTypes, showMetricEditor]);
43
+ }, [intl, inCatalogTypes]);
56
44
  const handleSelect = useCallback((item, _event) => {
57
45
  if (inCatalogTypes.has(item.data)) {
58
46
  setOpenType(item.data);
package/esm/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export { AnalyticsCatalog, type IAnalyticsCatalogProps } from "./AnalyticsCatalog.js";
2
2
  export { AnalyticsCatalogDetail, type IAnalyticsCatalogDetailProps, AnalyticsCatalogDetailContent, type IAnalyticsCatalogDetailContentProps, } from "./AnalyticsCatalogDetail.js";
3
3
  export { AnalyticsCatalogFilter, type IAnalyticsCatalogFilterProps } from "./AnalyticsCatalogFilter.js";
4
+ export { InsightCodecProvider, type IInsightCodec, type VisualizationTypePredicate, } from "./insight/insightCodecContext.js";
5
+ export type { IAsCodeEditing, AsCodeValidation, AsCodeValidationContext } from "./asCode/descriptor.js";
4
6
  export type { ICatalogDetailProps } from "./catalogDetail/CatalogDetail.js";
5
7
  export type { EditHandlerEvent, OpenHandlerEvent } from "./catalogDetail/types.js";
6
8
  export type { ICatalogDetailContentProps } from "./catalogDetail/CatalogDetailContent.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACtF,OAAO,EACH,sBAAsB,EACtB,KAAK,4BAA4B,EACjC,6BAA6B,EAC7B,KAAK,mCAAmC,GAC3C,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,sBAAsB,EAAE,KAAK,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AAMxG,YAAY,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACnF,YAAY,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAC;AAC1F,YAAY,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACjF,YAAY,EACR,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,GACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACH,sBAAsB,EACtB,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,GACzB,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACtF,OAAO,EACH,sBAAsB,EACtB,KAAK,4BAA4B,EACjC,6BAA6B,EAC7B,KAAK,mCAAmC,GAC3C,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,sBAAsB,EAAE,KAAK,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AAMxG,OAAO,EACH,oBAAoB,EACpB,KAAK,aAAa,EAClB,KAAK,0BAA0B,GAClC,MAAM,kCAAkC,CAAC;AAE1C,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAMxG,YAAY,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACnF,YAAY,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAC;AAC1F,YAAY,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACjF,YAAY,EACR,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,GACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACH,sBAAsB,EACtB,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,GACzB,MAAM,yBAAyB,CAAC"}
package/esm/index.js CHANGED
@@ -6,4 +6,9 @@
6
6
  export { AnalyticsCatalog } from "./AnalyticsCatalog.js";
7
7
  export { AnalyticsCatalogDetail, AnalyticsCatalogDetailContent, } from "./AnalyticsCatalogDetail.js";
8
8
  export { AnalyticsCatalogFilter } from "./AnalyticsCatalogFilter.js";
9
+ /*
10
+ * Visualization as-code codec injection. The host supplies the Tiger-coupled AAC codec so this package
11
+ * stays backend-agnostic; without it, visualizations fall back to Analytical Designer.
12
+ */
13
+ export { InsightCodecProvider, } from "./insight/insightCodecContext.js";
9
14
  export { isCatalogItemAttribute, isCatalogItemDashboard, isCatalogItemDataSet, isCatalogItemFact, isCatalogItemInsight, isCatalogItemMeasure, isCatalogItemParameter, } from "./catalogItem/guards.js";
@@ -0,0 +1,4 @@
1
+ /** The flag gating the in-catalog visualization editor, referenced by
2
+ * `visualizationDescriptor.featureFlag`. */
3
+ export declare const VISUALIZATION_EDITOR_FEATURE_FLAG = "enableAnalyticalCatalogVisualizationEditor";
4
+ //# sourceMappingURL=gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../src/insight/gate.ts"],"names":[],"mappings":"AAEA;6CAC6C;AAC7C,eAAO,MAAM,iCAAiC,+CAA+C,CAAC"}
@@ -0,0 +1,4 @@
1
+ // (C) 2026 GoodData Corporation
2
+ /** The flag gating the in-catalog visualization editor, referenced by
3
+ * `visualizationDescriptor.featureFlag`. */
4
+ export const VISUALIZATION_EDITOR_FEATURE_FLAG = "enableAnalyticalCatalogVisualizationEditor";
@@ -0,0 +1,22 @@
1
+ import { type PropsWithChildren } from "react";
2
+ import type { IInsightDefinition } from "@gooddata/sdk-model";
3
+ import type { IAsCodeEditing } from "../asCode/descriptor.js";
4
+ /** @internal */
5
+ export type IInsightCodec = IAsCodeEditing<IInsightDefinition>;
6
+ /** @internal */
7
+ export type VisualizationTypePredicate = (visualizationType: string) => boolean;
8
+ /** Injects the host-built visualization codec, keeping this package free of the Tiger-coupled convertors. @internal */
9
+ export declare function InsightCodecProvider({ codec, requestLoad, isVisualizationTypeEditable, children }: PropsWithChildren<{
10
+ codec?: IInsightCodec;
11
+ requestLoad: () => Promise<void>;
12
+ isVisualizationTypeEditable?: VisualizationTypePredicate;
13
+ }>): import("react/jsx-runtime").JSX.Element;
14
+ /** Whether a host injected the codec machinery; entry points gate on this since without a host the codec never resolves. @internal */
15
+ export declare function useHasInsightCodecHost(): boolean;
16
+ /** The injected codec, or `null` while loading — a pure read; the load is driven by {@link useRequestInsightCodec}. @internal */
17
+ export declare function useInsightCodec(): IInsightCodec | null;
18
+ /** The host's codec-load request lever (contract on {@link InsightCodecContextValue}). @internal */
19
+ export declare function useRequestInsightCodec(): () => Promise<void>;
20
+ /** Per-chart-type editability from the host: false with no host, else its predicate (absent predicate ⇒ all editable). @internal */
21
+ export declare function useIsVisualizationTypeEditable(): VisualizationTypePredicate;
22
+ //# sourceMappingURL=insightCodecContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insightCodecContext.d.ts","sourceRoot":"","sources":["../../src/insight/insightCodecContext.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,iBAAiB,EAAmD,MAAM,OAAO,CAAC;AAEhG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,gBAAgB;AAChB,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,kBAAkB,CAAC,CAAC;AAE/D,gBAAgB;AAChB,MAAM,MAAM,0BAA0B,GAAG,CAAC,iBAAiB,EAAE,MAAM,KAAK,OAAO,CAAC;AAchF,uHAAuH;AACvH,wBAAgB,oBAAoB,CAAC,EACjC,KAAK,EACL,WAAW,EACX,2BAA2B,EAC3B,QAAQ,EACX,EAAE,iBAAiB,CAAC;IACjB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,2BAA2B,CAAC,EAAE,0BAA0B,CAAC;CAC5D,CAAC,2CAMD;AAED,sIAAsI;AACtI,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED,mIAAiI;AACjI,wBAAgB,eAAe,IAAI,aAAa,GAAG,IAAI,CAEtD;AAKD,oGAAoG;AACpG,wBAAgB,sBAAsB,IAAI,MAAM,OAAO,CAAC,IAAI,CAAC,CAE5D;AAED,sIAAoI;AACpI,wBAAgB,8BAA8B,IAAI,0BAA0B,CAQ3E"}
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // (C) 2026 GoodData Corporation
3
+ import { createContext, useCallback, useContext, useMemo } from "react";
4
+ const InsightCodecContext = createContext(null);
5
+ /** Injects the host-built visualization codec, keeping this package free of the Tiger-coupled convertors. @internal */
6
+ export function InsightCodecProvider({ codec, requestLoad, isVisualizationTypeEditable, children, }) {
7
+ const value = useMemo(() => ({ codec, requestLoad, isVisualizationTypeEditable }), [codec, requestLoad, isVisualizationTypeEditable]);
8
+ return _jsx(InsightCodecContext.Provider, { value: value, children: children });
9
+ }
10
+ /** Whether a host injected the codec machinery; entry points gate on this since without a host the codec never resolves. @internal */
11
+ export function useHasInsightCodecHost() {
12
+ return useContext(InsightCodecContext) !== null;
13
+ }
14
+ /** The injected codec, or `null` while loading — a pure read; the load is driven by {@link useRequestInsightCodec}. @internal */
15
+ export function useInsightCodec() {
16
+ return useContext(InsightCodecContext)?.codec ?? null;
17
+ }
18
+ // No host: a resolved no-op so the (gated-unreachable) request effect neither fetches nor crashes.
19
+ const noCodecHost = () => Promise.resolve();
20
+ /** The host's codec-load request lever (contract on {@link InsightCodecContextValue}). @internal */
21
+ export function useRequestInsightCodec() {
22
+ return useContext(InsightCodecContext)?.requestLoad ?? noCodecHost;
23
+ }
24
+ /** Per-chart-type editability from the host: false with no host, else its predicate (absent predicate ⇒ all editable). @internal */
25
+ export function useIsVisualizationTypeEditable() {
26
+ const context = useContext(InsightCodecContext);
27
+ const hasHost = context !== null;
28
+ const isVisualizationTypeEditable = context?.isVisualizationTypeEditable;
29
+ return useCallback((visualizationType) => hasHost && (isVisualizationTypeEditable?.(visualizationType) ?? true), [hasHost, isVisualizationTypeEditable]);
30
+ }
@@ -0,0 +1,4 @@
1
+ import type { IInsightDefinition } from "@gooddata/sdk-model";
2
+ /** Duplicate: bump the title, copy only author-owned fields — the source's identity/audit fields must not reach create. */
3
+ export declare function createCopiedInsight(source: IInsightDefinition): IInsightDefinition;
4
+ //# sourceMappingURL=insightCopy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insightCopy.d.ts","sourceRoot":"","sources":["../../src/insight/insightCopy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAI9D,6HAA2H;AAC3H,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,GAAG,kBAAkB,CAqBlF"}
@@ -0,0 +1,25 @@
1
+ // (C) 2026 GoodData Corporation
2
+ import { deriveCopyIdentity } from "../asCode/copy.js";
3
+ /** Duplicate: bump the title, copy only author-owned fields — the source's identity/audit fields must not reach create. */
4
+ export function createCopiedInsight(source) {
5
+ const { insight } = source;
6
+ const { title } = deriveCopyIdentity({ title: insight.title });
7
+ return {
8
+ insight: {
9
+ title: title ?? insight.title,
10
+ visualizationUrl: insight.visualizationUrl,
11
+ buckets: insight.buckets,
12
+ filters: insight.filters,
13
+ sorts: insight.sorts,
14
+ properties: insight.properties,
15
+ ...(insight.tags === undefined ? {} : { tags: insight.tags }),
16
+ ...(insight.summary === undefined ? {} : { summary: insight.summary }),
17
+ ...(insight.attributeFilterConfigs === undefined
18
+ ? {}
19
+ : { attributeFilterConfigs: insight.attributeFilterConfigs }),
20
+ ...(insight.parameters === undefined ? {} : { parameters: insight.parameters }),
21
+ ...(insight.layers === undefined ? {} : { layers: insight.layers }),
22
+ ...(insight.isHidden === undefined ? {} : { isHidden: insight.isHidden }),
23
+ },
24
+ };
25
+ }
@@ -0,0 +1,7 @@
1
+ import type { IInsightDefinition } from "@gooddata/sdk-model";
2
+ import type { ICatalogItemInsight } from "../catalogItem/types.js";
3
+ /**
4
+ * @internal
5
+ */
6
+ export declare const visualizationDescriptor: import("../asCode/descriptor.js").IAsCodeDescriptor<IInsightDefinition, ICatalogItemInsight>;
7
+ //# sourceMappingURL=insightDescriptor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insightDescriptor.d.ts","sourceRoot":"","sources":["../../src/insight/insightDescriptor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAG9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AA+CnE;;GAEG;AACH,eAAO,MAAM,uBAAuB,8FA6BlC,CAAC"}
@@ -0,0 +1,69 @@
1
+ // (C) 2026 GoodData Corporation
2
+ import { defineMessages } from "react-intl";
3
+ import { defineAsCodeDescriptor } from "../asCode/descriptor.js";
4
+ import { ObjectTypes } from "../objectType/constants.js";
5
+ import { VISUALIZATION_EDITOR_FEATURE_FLAG } from "./gate.js";
6
+ import { useHasInsightCodecHost, useInsightCodec, useIsVisualizationTypeEditable, useRequestInsightCodec, } from "./insightCodecContext.js";
7
+ import { createCopiedInsight } from "./insightCopy.js";
8
+ import { countInsightReferences, createInsightMutationAdapter, loadInsight } from "./insightMutationPort.js";
9
+ const VISUALIZATION_DOCS_URL = "https://www.gooddata.ai/docs/cloud/api-and-sdk/vs-code-extension/structures/#visualisation";
10
+ const messages = defineMessages({
11
+ createTitle: { id: "analyticsCatalog.visualization.dialog.create.title" },
12
+ editTitle: { id: "analyticsCatalog.visualization.dialog.edit.title" },
13
+ duplicate: { id: "analyticsCatalog.visualization.dialog.edit.duplicate" },
14
+ createDefaultTitle: { id: "analyticsCatalog.visualization.create.defaultTitle" },
15
+ createSuccess: { id: "analyticsCatalog.visualization.create.success" },
16
+ updateSuccess: { id: "analyticsCatalog.visualization.update.success" },
17
+ sectionHeader: { id: "analyticsCatalog.visualization.dialog.sectionHeader" },
18
+ sectionHeaderTooltip: { id: "analyticsCatalog.visualization.dialog.sectionHeader.tooltip" },
19
+ help: { id: "analyticsCatalog.visualization.dialog.help" },
20
+ submitError: { id: "analyticsCatalog.visualization.dialog.submit.error" },
21
+ deleteTitle: { id: "analyticsCatalog.visualization.dialog.delete.title" },
22
+ deleteBody: { id: "analyticsCatalog.visualization.dialog.delete.body" },
23
+ deleteSubmit: { id: "analyticsCatalog.visualization.dialog.delete.submit" },
24
+ deleteSuccess: { id: "analyticsCatalog.visualization.delete.success" },
25
+ deleteError: { id: "analyticsCatalog.visualization.delete.error" },
26
+ });
27
+ const capabilityMessages = defineMessages({
28
+ loadError: { id: "analyticsCatalog.visualization.load.error" },
29
+ deleteUsageWarning: { id: "analyticsCatalog.visualization.dialog.delete.usageWarning" },
30
+ });
31
+ const actionMessages = defineMessages({
32
+ openInAnalyticalDesigner: { id: "analyticsCatalog.visualization.actions.openInAnalyticalDesigner" },
33
+ });
34
+ function useIsInsightItemEditable(item) {
35
+ return useIsVisualizationTypeEditable()(item.visualizationType);
36
+ }
37
+ /**
38
+ * @internal
39
+ */
40
+ export const visualizationDescriptor = defineAsCodeDescriptor({
41
+ objectType: ObjectTypes.VISUALIZATION,
42
+ docsUrl: VISUALIZATION_DOCS_URL,
43
+ featureFlag: VISUALIZATION_EDITOR_FEATURE_FLAG,
44
+ messages,
45
+ useEditing: useInsightCodec,
46
+ useRequestEditing: useRequestInsightCodec,
47
+ useIsItemEditable: useIsInsightItemEditable,
48
+ // Without a host-injected codec the editor can never resolve, so creation falls back to Analytical Designer.
49
+ useCreateGate: useHasInsightCodecHost,
50
+ createMutationPort: createInsightMutationAdapter,
51
+ emptyDefinition: (defaultTitle) => ({
52
+ insight: {
53
+ title: defaultTitle,
54
+ visualizationUrl: "local:table",
55
+ buckets: [],
56
+ filters: [],
57
+ sorts: [],
58
+ properties: {},
59
+ },
60
+ }),
61
+ seed: { load: loadInsight, loadError: capabilityMessages.loadError },
62
+ referenceCounted: {
63
+ count: countInsightReferences,
64
+ usageWarning: capabilityMessages.deleteUsageWarning,
65
+ },
66
+ // No identity: an insight definition has no id field, and creates never carry one (backend-assigned).
67
+ toCopy: createCopiedInsight,
68
+ openAction: actionMessages.openInAnalyticalDesigner,
69
+ });
@@ -0,0 +1,13 @@
1
+ import type { IAnalyticalBackend } from "@gooddata/sdk-backend-spi";
2
+ import { type IInsightDefinition } from "@gooddata/sdk-model";
3
+ import type { IAsCodeMutationPort } from "../asCode/descriptor.js";
4
+ import type { ICatalogItemInsight } from "../catalogItem/types.js";
5
+ /** @internal */
6
+ export type IInsightMutationPort = IAsCodeMutationPort<IInsightDefinition, ICatalogItemInsight>;
7
+ /** Fetches the full insight for editing (the catalog item carries only metadata). @internal */
8
+ export declare function loadInsight(backend: IAnalyticalBackend, workspace: string, item: ICatalogItemInsight): Promise<IInsightDefinition>;
9
+ /** Counts the dashboards referencing an insight. @internal */
10
+ export declare function countInsightReferences(backend: IAnalyticalBackend, workspace: string, item: ICatalogItemInsight): Promise<number>;
11
+ /** @internal */
12
+ export declare function createInsightMutationAdapter(backend: IAnalyticalBackend, workspace: string): IInsightMutationPort;
13
+ //# sourceMappingURL=insightMutationPort.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insightMutationPort.d.ts","sourceRoot":"","sources":["../../src/insight/insightMutationPort.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAiB,KAAK,kBAAkB,EAAoB,MAAM,qBAAqB,CAAC;AAE/F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAGnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAEnE,gBAAgB;AAChB,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,CAAC;AAEhG,+FAA+F;AAC/F,wBAAgB,WAAW,CACvB,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,mBAAmB,GAC1B,OAAO,CAAC,kBAAkB,CAAC,CAO7B;AAED,8DAA8D;AAC9D,wBAAsB,sBAAsB,CACxC,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,mBAAmB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAMjB;AAoBD,gBAAgB;AAChB,wBAAgB,4BAA4B,CACxC,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,MAAM,GAClB,oBAAoB,CAsBtB"}
@@ -0,0 +1,59 @@
1
+ // (C) 2026 GoodData Corporation
2
+ import { idRef, isInsight } from "@gooddata/sdk-model";
3
+ import { convertInsightToCatalogItem } from "../catalogItem/converter.js";
4
+ /** Fetches the full insight for editing (the catalog item carries only metadata). @internal */
5
+ export function loadInsight(backend, workspace, item) {
6
+ // loadUserData so the base carries createdBy/updatedBy: updateInsight echoes its input rather than
7
+ // the server response, so without them the saved catalog item shows blank authors.
8
+ return backend
9
+ .workspace(workspace)
10
+ .insights()
11
+ .getInsight(idRef(item.identifier, "insight"), { loadUserData: true });
12
+ }
13
+ /** Counts the dashboards referencing an insight. @internal */
14
+ export async function countInsightReferences(backend, workspace, item) {
15
+ const referencing = await backend
16
+ .workspace(workspace)
17
+ .insights()
18
+ .getInsightReferencingObjects(idRef(item.identifier, "insight"));
19
+ return referencing.analyticalDashboards?.length ?? 0;
20
+ }
21
+ function pickInsightIdentity(insight) {
22
+ const { identifier, uri, ref, isLocked, certification } = insight;
23
+ const { created, updated, createdBy, updatedBy } = insight;
24
+ return {
25
+ identifier,
26
+ uri,
27
+ ref,
28
+ isLocked,
29
+ certification,
30
+ created,
31
+ updated,
32
+ createdBy,
33
+ updatedBy,
34
+ };
35
+ }
36
+ /** @internal */
37
+ export function createInsightMutationAdapter(backend, workspace) {
38
+ const insights = () => backend.workspace(workspace).insights();
39
+ return {
40
+ async create(definition) {
41
+ return convertInsightToCatalogItem(await insights().createInsight(definition));
42
+ },
43
+ async update(base, definition) {
44
+ if (!isInsight(base) || !base.insight.identifier) {
45
+ throw new Error("Visualization update requires the loaded insight as base.");
46
+ }
47
+ // Definition is authoritative for content (already reconciled); re-attach only identity — a
48
+ // base overlay would revert a field the editor cleared.
49
+ const saved = await insights().updateInsight({
50
+ ...base,
51
+ insight: { ...definition.insight, ...pickInsightIdentity(base.insight) },
52
+ });
53
+ return convertInsightToCatalogItem(saved);
54
+ },
55
+ async delete(ref) {
56
+ await insights().deleteInsight(idRef(ref.identifier, "insight"));
57
+ },
58
+ };
59
+ }