@gooddata/sdk-ui-catalog 11.43.0-alpha.2 → 11.43.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 (101) hide show
  1. package/esm/catalogDetail/CatalogDetailActions.d.ts +1 -3
  2. package/esm/catalogDetail/CatalogDetailActions.d.ts.map +1 -1
  3. package/esm/catalogDetail/CatalogDetailActions.js +6 -2
  4. package/esm/catalogDetail/CatalogDetailContent.d.ts.map +1 -1
  5. package/esm/catalogDetail/CatalogDetailContent.js +33 -54
  6. package/esm/catalogDetail/CatalogDetailTabMetadata.d.ts +5 -10
  7. package/esm/catalogDetail/CatalogDetailTabMetadata.d.ts.map +1 -1
  8. package/esm/catalogDetail/CatalogDetailTabMetadata.js +3 -7
  9. package/esm/catalogDetail/hooks/useCatalogItemLoad.d.ts.map +1 -1
  10. package/esm/catalogDetail/hooks/useCatalogItemLoad.js +8 -2
  11. package/esm/catalogDetail/share/CatalogItemAccessRow.d.ts +10 -0
  12. package/esm/catalogDetail/share/CatalogItemAccessRow.d.ts.map +1 -0
  13. package/esm/catalogDetail/share/CatalogItemAccessRow.js +29 -0
  14. package/esm/catalogDetail/share/CatalogItemShareDialog.d.ts +10 -0
  15. package/esm/catalogDetail/share/CatalogItemShareDialog.d.ts.map +1 -0
  16. package/esm/catalogDetail/share/CatalogItemShareDialog.js +29 -0
  17. package/esm/catalogDetail/share/CatalogItemShareDialogInner.d.ts +10 -0
  18. package/esm/catalogDetail/share/CatalogItemShareDialogInner.d.ts.map +1 -0
  19. package/esm/catalogDetail/share/CatalogItemShareDialogInner.js +20 -0
  20. package/esm/catalogDetail/share/CatalogItemShareProvider.d.ts +71 -0
  21. package/esm/catalogDetail/share/CatalogItemShareProvider.d.ts.map +1 -0
  22. package/esm/catalogDetail/share/CatalogItemShareProvider.js +83 -0
  23. package/esm/localization/bundles/de-DE.localization-bundle.d.ts +11 -0
  24. package/esm/localization/bundles/de-DE.localization-bundle.d.ts.map +1 -1
  25. package/esm/localization/bundles/de-DE.localization-bundle.js +12 -1
  26. package/esm/localization/bundles/en-AU.localization-bundle.d.ts +11 -0
  27. package/esm/localization/bundles/en-AU.localization-bundle.d.ts.map +1 -1
  28. package/esm/localization/bundles/en-AU.localization-bundle.js +12 -1
  29. package/esm/localization/bundles/en-GB.localization-bundle.d.ts +11 -0
  30. package/esm/localization/bundles/en-GB.localization-bundle.d.ts.map +1 -1
  31. package/esm/localization/bundles/en-GB.localization-bundle.js +12 -1
  32. package/esm/localization/bundles/es-419.localization-bundle.d.ts +11 -0
  33. package/esm/localization/bundles/es-419.localization-bundle.d.ts.map +1 -1
  34. package/esm/localization/bundles/es-419.localization-bundle.js +12 -1
  35. package/esm/localization/bundles/es-ES.localization-bundle.d.ts +11 -0
  36. package/esm/localization/bundles/es-ES.localization-bundle.d.ts.map +1 -1
  37. package/esm/localization/bundles/es-ES.localization-bundle.js +12 -1
  38. package/esm/localization/bundles/fi-FI.localization-bundle.d.ts +11 -0
  39. package/esm/localization/bundles/fi-FI.localization-bundle.d.ts.map +1 -1
  40. package/esm/localization/bundles/fi-FI.localization-bundle.js +12 -1
  41. package/esm/localization/bundles/fr-CA.localization-bundle.d.ts +11 -0
  42. package/esm/localization/bundles/fr-CA.localization-bundle.d.ts.map +1 -1
  43. package/esm/localization/bundles/fr-CA.localization-bundle.js +12 -1
  44. package/esm/localization/bundles/fr-FR.localization-bundle.d.ts +11 -0
  45. package/esm/localization/bundles/fr-FR.localization-bundle.d.ts.map +1 -1
  46. package/esm/localization/bundles/fr-FR.localization-bundle.js +12 -1
  47. package/esm/localization/bundles/id-ID.localization-bundle.d.ts +11 -0
  48. package/esm/localization/bundles/id-ID.localization-bundle.d.ts.map +1 -1
  49. package/esm/localization/bundles/id-ID.localization-bundle.js +12 -1
  50. package/esm/localization/bundles/it-IT.localization-bundle.d.ts +11 -0
  51. package/esm/localization/bundles/it-IT.localization-bundle.d.ts.map +1 -1
  52. package/esm/localization/bundles/it-IT.localization-bundle.js +12 -1
  53. package/esm/localization/bundles/ja-JP.localization-bundle.d.ts +11 -0
  54. package/esm/localization/bundles/ja-JP.localization-bundle.d.ts.map +1 -1
  55. package/esm/localization/bundles/ja-JP.localization-bundle.js +12 -1
  56. package/esm/localization/bundles/ko-KR.localization-bundle.d.ts +11 -0
  57. package/esm/localization/bundles/ko-KR.localization-bundle.d.ts.map +1 -1
  58. package/esm/localization/bundles/ko-KR.localization-bundle.js +12 -1
  59. package/esm/localization/bundles/nl-NL.localization-bundle.d.ts +11 -0
  60. package/esm/localization/bundles/nl-NL.localization-bundle.d.ts.map +1 -1
  61. package/esm/localization/bundles/nl-NL.localization-bundle.js +13 -2
  62. package/esm/localization/bundles/pl-PL.localization-bundle.d.ts +11 -0
  63. package/esm/localization/bundles/pl-PL.localization-bundle.d.ts.map +1 -1
  64. package/esm/localization/bundles/pl-PL.localization-bundle.js +12 -1
  65. package/esm/localization/bundles/pt-BR.localization-bundle.d.ts +11 -0
  66. package/esm/localization/bundles/pt-BR.localization-bundle.d.ts.map +1 -1
  67. package/esm/localization/bundles/pt-BR.localization-bundle.js +12 -1
  68. package/esm/localization/bundles/pt-PT.localization-bundle.d.ts +11 -0
  69. package/esm/localization/bundles/pt-PT.localization-bundle.d.ts.map +1 -1
  70. package/esm/localization/bundles/pt-PT.localization-bundle.js +12 -1
  71. package/esm/localization/bundles/ru-RU.localization-bundle.d.ts +11 -0
  72. package/esm/localization/bundles/ru-RU.localization-bundle.d.ts.map +1 -1
  73. package/esm/localization/bundles/ru-RU.localization-bundle.js +12 -1
  74. package/esm/localization/bundles/sl-SI.localization-bundle.d.ts +11 -0
  75. package/esm/localization/bundles/sl-SI.localization-bundle.d.ts.map +1 -1
  76. package/esm/localization/bundles/sl-SI.localization-bundle.js +12 -1
  77. package/esm/localization/bundles/th-TH.localization-bundle.d.ts +11 -0
  78. package/esm/localization/bundles/th-TH.localization-bundle.d.ts.map +1 -1
  79. package/esm/localization/bundles/th-TH.localization-bundle.js +12 -1
  80. package/esm/localization/bundles/tr-TR.localization-bundle.d.ts +11 -0
  81. package/esm/localization/bundles/tr-TR.localization-bundle.d.ts.map +1 -1
  82. package/esm/localization/bundles/tr-TR.localization-bundle.js +12 -1
  83. package/esm/localization/bundles/uk-UA.localization-bundle.d.ts +11 -0
  84. package/esm/localization/bundles/uk-UA.localization-bundle.d.ts.map +1 -1
  85. package/esm/localization/bundles/uk-UA.localization-bundle.js +12 -1
  86. package/esm/localization/bundles/vi-VN.localization-bundle.d.ts +11 -0
  87. package/esm/localization/bundles/vi-VN.localization-bundle.d.ts.map +1 -1
  88. package/esm/localization/bundles/vi-VN.localization-bundle.js +12 -1
  89. package/esm/localization/bundles/zh-HK.localization-bundle.d.ts +11 -0
  90. package/esm/localization/bundles/zh-HK.localization-bundle.d.ts.map +1 -1
  91. package/esm/localization/bundles/zh-HK.localization-bundle.js +12 -1
  92. package/esm/localization/bundles/zh-Hans.localization-bundle.d.ts +11 -0
  93. package/esm/localization/bundles/zh-Hans.localization-bundle.d.ts.map +1 -1
  94. package/esm/localization/bundles/zh-Hans.localization-bundle.js +12 -1
  95. package/esm/localization/bundles/zh-Hant.localization-bundle.d.ts +11 -0
  96. package/esm/localization/bundles/zh-Hant.localization-bundle.d.ts.map +1 -1
  97. package/esm/localization/bundles/zh-Hant.localization-bundle.js +12 -1
  98. package/package.json +14 -14
  99. package/styles/css/main.css +3 -3
  100. package/styles/css/main.css.map +1 -1
  101. package/styles/scss/main.scss +7 -1
@@ -11,11 +11,9 @@ export interface ICatalogDetailActionsProps {
11
11
  onCatalogItemCreate?: (item: ICatalogItem) => void;
12
12
  onCatalogItemUpdate?: (item: ICatalogItem) => void;
13
13
  onCatalogItemDelete?: (ref: ICatalogItemRef) => void;
14
- /** When set, a Share button is shown next to Open. Undefined hides it (not shareable / flag off). */
15
- onShareClick?: () => void;
16
14
  }
17
15
  /**
18
16
  * @internal
19
17
  */
20
- export declare function CatalogDetailActions({ item, canEdit, onOpen, onCatalogItemCreate, onCatalogItemUpdate, onCatalogItemDelete, onShareClick }: ICatalogDetailActionsProps): import("react/jsx-runtime").JSX.Element | null;
18
+ export declare function CatalogDetailActions({ item, canEdit, onOpen, onCatalogItemCreate, onCatalogItemUpdate, onCatalogItemDelete }: ICatalogDetailActionsProps): import("react/jsx-runtime").JSX.Element | null;
21
19
  //# sourceMappingURL=CatalogDetailActions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CatalogDetailActions.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailActions.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAkC,MAAM,OAAO,CAAC;AAUxE,OAAO,KAAK,EAAE,YAAY,EAAyB,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAOpG,OAAO,KAAK,EAAwB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAczE;;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;IACrD,qGAAqG;IACrG,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,IAAI,EACJ,OAAO,EACP,MAAM,EACN,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACf,EAAE,0BAA0B,kDA2I5B"}
1
+ {"version":3,"file":"CatalogDetailActions.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailActions.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAkC,MAAM,OAAO,CAAC;AAUxE,OAAO,KAAK,EAAE,YAAY,EAAyB,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAQpG,OAAO,KAAK,EAAwB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAczE;;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;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,IAAI,EACJ,OAAO,EACP,MAAM,EACN,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACtB,EAAE,0BAA0B,kDA8I5B"}
@@ -10,6 +10,7 @@ import { ParameterCreateDialog } from "../parameter/ParameterCreateDialog.js";
10
10
  import { ParameterDeleteDialog } from "../parameter/ParameterDeleteDialog.js";
11
11
  import { ParameterEditDialog } from "../parameter/ParameterEditDialog.js";
12
12
  import { CatalogDetailActionBar } from "./CatalogDetailActionBar.js";
13
+ import { useCatalogItemShareActions } from "./share/CatalogItemShareProvider.js";
13
14
  import { ShareButton } from "./share/ShareButton.js";
14
15
  const messages = defineMessages({
15
16
  parameterDuplicate: { id: "analyticsCatalog.parameter.dialog.edit.duplicate" },
@@ -18,10 +19,13 @@ const messages = defineMessages({
18
19
  /**
19
20
  * @internal
20
21
  */
21
- export function CatalogDetailActions({ item, canEdit, onOpen, onCatalogItemCreate, onCatalogItemUpdate, onCatalogItemDelete, onShareClick, }) {
22
+ export function CatalogDetailActions({ item, canEdit, onOpen, onCatalogItemCreate, onCatalogItemUpdate, onCatalogItemDelete, }) {
22
23
  const intl = useIntl();
23
24
  const workspaceId = useWorkspaceStrict();
24
25
  const [dialog, setDialog] = useState(undefined);
26
+ // The Share button reads the share context directly (actions only), so it never
27
+ // re-renders as access is edited and is shown only when sharing is available.
28
+ const share = useCatalogItemShareActions();
25
29
  const parameterActions = useMemo(() => [
26
30
  {
27
31
  id: "duplicate",
@@ -83,7 +87,7 @@ export function CatalogDetailActions({ item, canEdit, onOpen, onCatalogItemCreat
83
87
  return (_jsxs(_Fragment, { children: [
84
88
  _jsx(CatalogDetailActionBar, { item: item, workspaceId: workspaceId, actions: parameterActions, onEditClick: handleEditOpen, onActionsMenuSelect: handleActionsMenuSelect }), dialog?.kind === "edit" ? (_jsx(ParameterEditDialog, { item: dialog.item, onClose: closeDialog, onSaved: handleSaved, onDuplicate: handleEditDuplicate })) : null, dialog?.kind === "duplicate" ? (_jsx(ParameterCreateDialog, { sourceItem: dialog.item, onClose: closeDialog, onCreated: handleCreated })) : null, dialog?.kind === "delete" ? (_jsx(ParameterDeleteDialog, { item: dialog.item, onClose: closeDialog, onDeleted: handleDeleted })) : null] }));
85
89
  }
86
- return (_jsxs("div", { className: "gd-analytics-catalog-detail__header-actions", children: [onShareClick ? _jsx(ShareButton, { onClick: onShareClick }) : null, _jsx(UiButton, { label: intl.formatMessage({ id: "analyticsCatalog.catalogItem.open" }), variant: "primary", accessibilityConfig: { role: "link" }, onClick: (event) => {
90
+ 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) => {
87
91
  onOpen?.(event, {
88
92
  item,
89
93
  workspaceId,
@@ -1 +1 @@
1
- {"version":3,"file":"CatalogDetailContent.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailContent.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAA0C,MAAM,OAAO,CAAC;AAWhF,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAGlF,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAezD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AASnD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;OAEG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B;;OAEG;IACH,gBAAgB,CAAC,EAAE,eAAe,GAAG,YAAY,GAAG,IAAI,CAAC;IACzD;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5E;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;OAEG;IACH,uBAAuB,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IAC5E;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IACrD;;OAEG;IACH,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACrD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EAC1B,EAAE,0BAA0B,2CAwP5B"}
1
+ {"version":3,"file":"CatalogDetailContent.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailContent.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAgC,MAAM,OAAO,CAAC;AAUtE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAGlF,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAkBzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AASnD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;OAEG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B;;OAEG;IACH,gBAAgB,CAAC,EAAE,eAAe,GAAG,YAAY,GAAG,IAAI,CAAC;IACzD;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5E;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;OAEG;IACH,uBAAuB,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IAC5E;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IACrD;;OAEG;IACH,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACrD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EAC1B,EAAE,0BAA0B,2CAoN5B"}
@@ -1,11 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // (C) 2025-2026 GoodData Corporation
3
- import { useCallback, useMemo, useRef, useState } from "react";
3
+ import { useCallback, useMemo, useRef } from "react";
4
4
  import cx from "classnames";
5
5
  import { useIntl } from "react-intl";
6
6
  import {} from "@gooddata/sdk-model";
7
7
  import { useLocalStorage } from "@gooddata/sdk-ui";
8
- import { ObjectShareDialog, useObjectShare } from "@gooddata/sdk-ui-ext";
9
8
  import { UiSkeleton, UiTabs } from "@gooddata/sdk-ui-kit";
10
9
  import { canEditCatalogItem } from "../catalogItem/permission.js";
11
10
  import {} from "../catalogItem/types.js";
@@ -23,6 +22,9 @@ import { CatalogDetailTabLineage } from "./CatalogDetailTabLineage.js";
23
22
  import { CatalogDetailTabMetadata } from "./CatalogDetailTabMetadata.js";
24
23
  import { CatalogDetailTabQuality } from "./CatalogDetailTabQuality.js";
25
24
  import { useCatalogItemUpdate } from "./hooks/useCatalogItemUpdate.js";
25
+ import { CatalogItemAccessRow } from "./share/CatalogItemAccessRow.js";
26
+ import { CatalogItemShareDialog } from "./share/CatalogItemShareDialog.js";
27
+ import { CatalogItemShareProvider } from "./share/CatalogItemShareProvider.js";
26
28
  import { isShareableCatalogItem, toShareTarget } from "./share/guards.js";
27
29
  import { useShareableLabels } from "./share/useShareableLabels.js";
28
30
  const Tabs = {
@@ -52,33 +54,9 @@ export function CatalogDetailContent({ objectId, objectType, objectDefinition, o
52
54
  const enableColumnLevelPermissions = Boolean(settings?.enableColumnLevelPermissions);
53
55
  const shareableItem = item && enableColumnLevelPermissions && isShareableCatalogItem(item) ? item : undefined;
54
56
  const shareTarget = useMemo(() => (shareableItem ? toShareTarget(shareableItem) : undefined), [shareableItem]);
55
- // Labels of the shared attribute drive the per-grantee label-scope picker.
57
+ // Labels of the shared attribute drive both the header info row and the per-grantee
58
+ // label-scope picker; fetched once here and passed to the share provider.
56
59
  const shareLabels = useShareableLabels(shareableItem);
57
- // One controller drives both the dialog and the inline access row; the row
58
- // reads `state.summary`, so a save inside the dialog refreshes it too.
59
- // `labelsLoading`/`labelsError` keep the controller label-unresolved while labels
60
- // are still pending, disabling every access-changing control (a write would
61
- // otherwise diff against an empty label set and orphan real per-label grants).
62
- const shareController = useObjectShare(shareTarget, {
63
- labels: shareLabels.labels,
64
- labelsError: shareLabels.error,
65
- labelsLoading: shareLabels.loading,
66
- });
67
- const [isShareOpen, setIsShareOpen] = useState(false);
68
- // The detail view is reused as the user navigates between objects, so reset the
69
- // open dialog when the shareable target changes (or becomes non-shareable) —
70
- // otherwise it would linger open on the next object. Reset during render (React's
71
- // "adjust state on prop change" idiom) rather than in an effect.
72
- const shareTargetKey = shareableItem?.identifier;
73
- const [openForKey, setOpenForKey] = useState(undefined);
74
- if (isShareOpen && openForKey !== shareTargetKey) {
75
- setIsShareOpen(false);
76
- }
77
- const openShare = useCallback(() => {
78
- setOpenForKey(shareTargetKey);
79
- setIsShareOpen(true);
80
- }, [shareTargetKey]);
81
- const closeShare = useCallback(() => setIsShareOpen(false), []);
82
60
  const separators = settings?.separators;
83
61
  const enableMetricFormatOverrides = Boolean(settings?.["enableMetricFormatOverrides"]);
84
62
  const currencyFormatOverride = settings?.currencyFormatOverride ?? null;
@@ -132,32 +110,33 @@ export function CatalogDetailContent({ objectId, objectType, objectDefinition, o
132
110
  return tabs;
133
111
  }, [intl, isCertificationVisible, isQualityVisible, isLineageVisible, issueCount]);
134
112
  const [selectedTabId, setSelectedTabId] = useSelectedTabId(tabs);
135
- return (_jsxs("div", { className: "gd-analytics-catalog-detail", children: [
136
- _jsx(CatalogDetailStatus, { status: status, error: error, children: item ? (_jsxs("div", { className: cx("gd-analytics-catalog-detail__content", {
137
- lineage: selectedTabId === Tabs.LINEAGE,
138
- }), children: [
139
- _jsx(CatalogDetailHeader, { item: item, canEdit: canEdit, updateItemTitle: updateItemTitle, updateItemDescription: updateItemDescription, isDescriptionGenerationEnabled: isDescriptionGenerationEnabled, headerRef: headerRef, labels: shareableItem ? shareLabels.labels : undefined, labelsLoading: shareableItem ? shareLabels.loading : false, showInfoRow: enableColumnLevelPermissions, actions: _jsx(CatalogDetailActions, { item: item, canEdit: canEdit, onOpen: onOpenClick, onCatalogItemCreate: onCatalogItemCreate, onCatalogItemUpdate: applyItemUpdate, onCatalogItemDelete: applyItemDelete, onShareClick: shareableItem ? openShare : undefined }) }), _jsx(UiTabs, { size: "large", tabs: tabs, onTabSelect: (tab) => setSelectedTabId(tab.id), selectedTabId: selectedTabId }), selectedTabId === Tabs.METADATA && (_jsx(CatalogDetailTabMetadata, { item: item, canEdit: canEdit,
140
- // With OLP off the dataset isn't relocated to the header,
141
- // so keep the Dataset row in the metadata tab.
142
- showDatasetRow: !enableColumnLevelPermissions, onTagClick: (tag) => {
143
- onTagClick?.(tag.label);
144
- }, onTagAdd: (tag) => {
145
- // Adding unique tags only
146
- updateItemTags([...new Set([...item.tags, tag.label])]);
147
- }, onTagRemove: (tag) => {
148
- updateItemTags(item.tags.filter((t) => t !== tag.label));
149
- }, onIsHiddenChange: (isHidden) => {
150
- updateItemIsHidden(isHidden);
151
- }, onIsHiddenFromKdaChange: (isHiddenFromKda) => {
152
- updateItemIsHiddenFromKda(isHiddenFromKda);
153
- }, onMetricTypeChange: (metricType) => {
154
- updateItemMetricType(metricType);
155
- }, onFormatChange: (format) => {
156
- updateItemFormat(format);
157
- }, separators: separators, currencyFormatOverride: enableMetricFormatOverrides ? currencyFormatOverride : undefined, enableMetricFormatOverrides: enableMetricFormatOverrides, accessSummary: shareableItem ? shareController.state.summary : undefined, accessUnavailable: shareableItem ? shareController.state.status !== "success" : false, onAccessOpen: shareableItem ? openShare : undefined })), selectedTabId === Tabs.CERTIFICATION && isCertificationVisible ? (_jsx(CatalogDetailTabCertification, { item: item, canEdit: canEdit, onCertificationChange: (certification) => {
158
- updateItemCertification(certification);
159
- } })) : null, selectedTabId === Tabs.QUALITY &&
160
- (isQualityLoading ? (_jsx(UiSkeleton, { itemsCount: 2, itemHeight: 65, itemsGap: 10 })) : (_jsx(CatalogDetailTabQuality, { item: item, issues: issues, canEdit: canEdit, onEditClick: handleEditClick, onCatalogItemNavigation: onCatalogItemNavigation }))), selectedTabId === Tabs.LINEAGE && _jsx(CatalogDetailTabLineage, { item: item })] })) : null }), shareableItem ? (_jsx(ObjectShareDialog, { target: shareTarget, objectTitle: shareableItem.title, isOpen: isShareOpen, onClose: closeShare, labelsLoading: shareLabels.loading, controller: shareController })) : null] }));
113
+ return (_jsx(CatalogItemShareProvider, { shareableItem: shareableItem, target: shareTarget, labels: shareLabels, children: _jsxs("div", { className: "gd-analytics-catalog-detail", children: [
114
+ _jsx(CatalogDetailStatus, { status: status, error: error, children: item ? (_jsxs("div", { className: cx("gd-analytics-catalog-detail__content", {
115
+ lineage: selectedTabId === Tabs.LINEAGE,
116
+ }), children: [
117
+ _jsx(CatalogDetailHeader, { item: item, canEdit: canEdit, updateItemTitle: updateItemTitle, updateItemDescription: updateItemDescription, isDescriptionGenerationEnabled: isDescriptionGenerationEnabled, headerRef: headerRef, labels: shareableItem ? shareLabels.labels : undefined, labelsLoading: shareableItem ? shareLabels.loading : false, showInfoRow: enableColumnLevelPermissions, actions: _jsx(CatalogDetailActions, { item: item, canEdit: canEdit, onOpen: onOpenClick, onCatalogItemCreate: onCatalogItemCreate, onCatalogItemUpdate: applyItemUpdate, onCatalogItemDelete: applyItemDelete }) }), _jsx(UiTabs, { size: "large", tabs: tabs, onTabSelect: (tab) => setSelectedTabId(tab.id), selectedTabId: selectedTabId }), selectedTabId === Tabs.METADATA && (_jsx(CatalogDetailTabMetadata, { item: item, canEdit: canEdit,
118
+ // With OLP off the dataset isn't relocated to the header,
119
+ // so keep the Dataset row in the metadata tab.
120
+ showDatasetRow: !enableColumnLevelPermissions, onTagClick: (tag) => {
121
+ onTagClick?.(tag.label);
122
+ }, onTagAdd: (tag) => {
123
+ // Adding unique tags only
124
+ updateItemTags([...new Set([...item.tags, tag.label])]);
125
+ }, onTagRemove: (tag) => {
126
+ updateItemTags(item.tags.filter((t) => t !== tag.label));
127
+ }, onIsHiddenChange: (isHidden) => {
128
+ updateItemIsHidden(isHidden);
129
+ }, onIsHiddenFromKdaChange: (isHiddenFromKda) => {
130
+ updateItemIsHiddenFromKda(isHiddenFromKda);
131
+ }, onMetricTypeChange: (metricType) => {
132
+ updateItemMetricType(metricType);
133
+ }, onFormatChange: (format) => {
134
+ updateItemFormat(format);
135
+ }, separators: separators, currencyFormatOverride: enableMetricFormatOverrides ? currencyFormatOverride : undefined, enableMetricFormatOverrides: enableMetricFormatOverrides, accessRow: _jsx(CatalogItemAccessRow, {}) })), selectedTabId === Tabs.CERTIFICATION && isCertificationVisible ? (_jsx(CatalogDetailTabCertification, { item: item, canEdit: canEdit, onCertificationChange: (certification) => {
136
+ updateItemCertification(certification);
137
+ } })) : null, selectedTabId === Tabs.QUALITY &&
138
+ (isQualityLoading ? (_jsx(UiSkeleton, { itemsCount: 2, itemHeight: 65, itemsGap: 10 })) : (_jsx(CatalogDetailTabQuality, { item: item, issues: issues, canEdit: canEdit, onEditClick: handleEditClick, onCatalogItemNavigation: onCatalogItemNavigation }))), selectedTabId === Tabs.LINEAGE && _jsx(CatalogDetailTabLineage, { item: item })] })) : null }), _jsx(CatalogItemShareDialog, {})
139
+ ] }) }));
161
140
  }
162
141
  /**
163
142
  * Hook for managing the currently selected tab ID with persistent storage.
@@ -1,5 +1,5 @@
1
+ import type { ReactNode } from "react";
1
2
  import type { ISeparators, MetricType } from "@gooddata/sdk-model";
2
- import type { IObjectAccessSummary } from "@gooddata/sdk-ui-ext";
3
3
  import { type IUiTagDef } from "@gooddata/sdk-ui-kit";
4
4
  import { type ICatalogItem } from "../catalogItem/types.js";
5
5
  type Props = {
@@ -15,22 +15,17 @@ type Props = {
15
15
  separators?: ISeparators;
16
16
  currencyFormatOverride?: string | null;
17
17
  enableMetricFormatOverrides?: boolean;
18
- /** Access summary for the inline row. Undefined when sharing is unavailable for this item. */
19
- accessSummary?: IObjectAccessSummary;
20
18
  /**
21
- * True while the access summary isn't available yet (loading or load error) for a
22
- * shareable item. The Access row then shows a placeholder instead of vanishing —
23
- * the row must stay because Share is still reachable for the object.
19
+ * Inline access row rendered at the top of the list. Self-contained (reads the
20
+ * share context); undefined / nothing rendered when sharing is unavailable.
24
21
  */
25
- accessUnavailable?: boolean;
26
- /** Opens the share dialog from the access row. Required for the row to render. */
27
- onAccessOpen?: () => void;
22
+ accessRow?: ReactNode;
28
23
  /**
29
24
  * Show the Dataset row here. True when object-level permissions are off — with
30
25
  * the flag on the dataset is relocated to the header info row instead.
31
26
  */
32
27
  showDatasetRow?: boolean;
33
28
  };
34
- export declare function CatalogDetailTabMetadata({ item, canEdit, onTagClick, onTagAdd, onTagRemove, onIsHiddenChange, onIsHiddenFromKdaChange, onMetricTypeChange, onFormatChange, separators, currencyFormatOverride, enableMetricFormatOverrides, accessSummary, accessUnavailable, onAccessOpen, showDatasetRow }: Props): import("react/jsx-runtime").JSX.Element;
29
+ export declare function CatalogDetailTabMetadata({ item, canEdit, onTagClick, onTagAdd, onTagRemove, onIsHiddenChange, onIsHiddenFromKdaChange, onMetricTypeChange, onFormatChange, separators, currencyFormatOverride, enableMetricFormatOverrides, accessRow, showDatasetRow }: Props): import("react/jsx-runtime").JSX.Element;
35
30
  export {};
36
31
  //# sourceMappingURL=CatalogDetailTabMetadata.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CatalogDetailTabMetadata.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailTabMetadata.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,KAAK,SAAS,EAAyC,MAAM,sBAAsB,CAAC;AAS7F,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAQ5D,KAAK,KAAK,GAAG;IACT,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACnC,WAAW,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACtC,gBAAgB,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,uBAAuB,EAAE,CAAC,eAAe,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5D,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,KAAK,IAAI,CAAC;IAClE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,8FAA8F;IAC9F,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,EACrC,IAAI,EACJ,OAAO,EACP,UAAU,EACV,QAAQ,EACR,WAAW,EACX,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,sBAAsB,EACtB,2BAA2B,EAC3B,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACjB,EAAE,KAAK,2CA0JP"}
1
+ {"version":3,"file":"CatalogDetailTabMetadata.d.ts","sourceRoot":"","sources":["../../src/catalogDetail/CatalogDetailTabMetadata.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,KAAK,SAAS,EAA6B,MAAM,sBAAsB,CAAC;AASjF,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAO5D,KAAK,KAAK,GAAG;IACT,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACnC,WAAW,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACtC,gBAAgB,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,uBAAuB,EAAE,CAAC,eAAe,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5D,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,KAAK,IAAI,CAAC;IAClE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,EACrC,IAAI,EACJ,OAAO,EACP,UAAU,EACV,QAAQ,EACR,WAAW,EACX,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,sBAAsB,EACtB,2BAA2B,EAC3B,SAAS,EACT,cAAc,EACjB,EAAE,KAAK,2CAiJP"}
@@ -2,24 +2,20 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
2
2
  // (C) 2025-2026 GoodData Corporation
3
3
  import cx from "classnames";
4
4
  import { FormattedMessage, useIntl } from "react-intl";
5
- import { UiDate, UiIcon, UiSkeleton, UiTooltip } from "@gooddata/sdk-ui-kit";
5
+ import { UiDate, UiIcon, UiTooltip } from "@gooddata/sdk-ui-kit";
6
6
  import { isCatalogItemAttribute, isCatalogItemDataSet, isCatalogItemFact, isCatalogItemHidable, isCatalogItemMeasure, } from "../catalogItem/guards.js";
7
7
  import {} from "../catalogItem/types.js";
8
8
  import { CatalogDetailContentRow } from "./CatalogDetailContentRow.js";
9
9
  import { CatalogDetailGranularities } from "./CatalogDetailGranularities.js";
10
10
  import { CatalogDetailMetricSettings } from "./CatalogDetailMetricSettings.js";
11
11
  import { CatalogDetailTags } from "./CatalogDetailTags.js";
12
- import { CatalogDetailAccessRow } from "./share/CatalogDetailAccessRow.js";
13
- export function CatalogDetailTabMetadata({ item, canEdit, onTagClick, onTagAdd, onTagRemove, onIsHiddenChange, onIsHiddenFromKdaChange, onMetricTypeChange, onFormatChange, separators, currencyFormatOverride, enableMetricFormatOverrides, accessSummary, accessUnavailable, onAccessOpen, showDatasetRow, }) {
12
+ export function CatalogDetailTabMetadata({ item, canEdit, onTagClick, onTagAdd, onTagRemove, onIsHiddenChange, onIsHiddenFromKdaChange, onMetricTypeChange, onFormatChange, separators, currencyFormatOverride, enableMetricFormatOverrides, accessRow, showDatasetRow, }) {
14
13
  const intl = useIntl();
15
14
  const isMeasure = isCatalogItemMeasure(item);
16
15
  const isDataSet = isCatalogItemDataSet(item);
17
16
  const granularities = isDataSet ? (item.dataSet.attributes ?? []) : [];
18
17
  const datasetTitle = isCatalogItemAttribute(item) || isCatalogItemFact(item) ? item.dataSet?.title : undefined;
19
- return (_jsxs("dl", { className: "gd-analytics-catalog-detail__tab-content", children: [accessSummary && onAccessOpen ? (_jsx(CatalogDetailAccessRow, { summary: accessSummary, onOpen: onAccessOpen })) : accessUnavailable && onAccessOpen ? (
20
- // Summary not available yet (loading or load error). Keep the row —
21
- // Share is still reachable — with a placeholder rather than omitting it.
22
- _jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.share.access.row.label" }), content: _jsx(UiSkeleton, { itemWidth: 200, itemHeight: 20 }) })) : null, showDatasetRow && datasetTitle ? (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.dataSet" }), content: datasetTitle })) : null, isDataSet && granularities.length > 0 ? (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.granularities" }), content: _jsx(CatalogDetailGranularities, { granularities: granularities }) })) : null, _jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.createdBy" }), content: item.createdBy ?? undefined }), _jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.createdAt" }), content: item.createdAt ? _jsx(UiDate, { date: item.createdAt, locale: intl.locale }) : undefined }), item.createdBy === item.updatedBy && !item.updatedBy ? null : (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.updatedBy" }), content: item.updatedBy ?? undefined })), item.createdAt?.getTime() === item.updatedAt?.getTime() ? null : (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.updatedAt" }), content: item.updatedAt ? _jsx(UiDate, { date: item.updatedAt, locale: intl.locale }) : undefined })), isCatalogItemHidable(item) ? (_jsx(CatalogDetailContentRow, { title: _jsxs(_Fragment, { children: [
18
+ return (_jsxs("dl", { className: "gd-analytics-catalog-detail__tab-content", children: [accessRow, showDatasetRow && datasetTitle ? (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.dataSet" }), content: datasetTitle })) : null, isDataSet && granularities.length > 0 ? (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.granularities" }), content: _jsx(CatalogDetailGranularities, { granularities: granularities }) })) : null, _jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.createdBy" }), content: item.createdBy ?? undefined }), _jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.createdAt" }), content: item.createdAt ? _jsx(UiDate, { date: item.createdAt, locale: intl.locale }) : undefined }), item.createdBy === item.updatedBy && !item.updatedBy ? null : (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.updatedBy" }), content: item.updatedBy ?? undefined })), item.createdAt?.getTime() === item.updatedAt?.getTime() ? null : (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.updatedAt" }), content: item.updatedAt ? _jsx(UiDate, { date: item.updatedAt, locale: intl.locale }) : undefined })), isCatalogItemHidable(item) ? (_jsx(CatalogDetailContentRow, { title: _jsxs(_Fragment, { children: [
23
19
  _jsx(FormattedMessage, { id: "analyticsCatalog.column.title.isHidden" }), _jsx(UiTooltip, { anchor: _jsx(UiIcon, { type: "question", size: 12, color: "complementary-6" }), content: _jsx(FormattedMessage, { id: "analyticsCatalog.column.isHidden.field.tooltip" }), arrowPlacement: "left", optimalPlacement: true, offset: 10, width: 280, triggerBy: ["hover", "click"] })
24
20
  ] }), content: _jsxs("label", { className: "input-checkbox-toggle", children: [
25
21
  _jsx("input", { type: "checkbox", checked: item.isHidden !== true, disabled: !canEdit, "aria-label": intl.formatMessage({
@@ -1 +1 @@
1
- {"version":3,"file":"useCatalogItemLoad.d.ts","sourceRoot":"","sources":["../../../src/catalogDetail/hooks/useCatalogItemLoad.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACrF,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,WAAW,mBAAmB;IAChC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,gBAAgB,CAAC,EAAE,eAAe,GAAG,YAAY,GAAG,IAAI,CAAC;CAC5D;AAED,wBAAgB,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,mBAAmB,GAAG;IACjG,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IACpD,IAAI,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAC;CACjB,CA6CA"}
1
+ {"version":3,"file":"useCatalogItemLoad.d.ts","sourceRoot":"","sources":["../../../src/catalogDetail/hooks/useCatalogItemLoad.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACrF,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,WAAW,mBAAmB;IAChC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,gBAAgB,CAAC,EAAE,eAAe,GAAG,YAAY,GAAG,IAAI,CAAC;CAC5D;AAED,wBAAgB,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,mBAAmB,GAAG;IACjG,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IACpD,IAAI,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAC;CACjB,CAmDA"}
@@ -1,5 +1,5 @@
1
1
  // (C) 2025-2026 GoodData Corporation
2
- import { useBackendStrict, useCancelablePromise, useWorkspaceStrict } from "@gooddata/sdk-ui";
2
+ import { convertError, isNotFound, useBackendStrict, useCancelablePromise, useWorkspaceStrict, } from "@gooddata/sdk-ui";
3
3
  import { convertAttributeToCatalogItem, convertDashboardToCatalogItem, convertDataSetToCatalogItem, convertFactToCatalogItem, convertInsightToCatalogItem, convertMeasureToCatalogItem, convertParameterToCatalogItem, } from "../../catalogItem/converter.js";
4
4
  import { isCatalogItemLoaded } from "../../catalogItem/guards.js";
5
5
  import {} from "../../catalogItem/types.js";
@@ -20,7 +20,13 @@ export function useCatalogItemLoad({ objectDefinition, objectId, objectType }) {
20
20
  if (filled) {
21
21
  return Promise.resolve(objectDefinition);
22
22
  }
23
- return loadObjectDefinition(backend.workspace(workspace), id, type);
23
+ // A 404 must reach CatalogDetailStatus as a NotFoundSdkError so isNotFound() shows
24
+ // the not-found page; convertError maps it. Other errors are rethrown untouched so
25
+ // their original status/message survives in the generic error description.
26
+ return loadObjectDefinition(backend.workspace(workspace), id, type).catch((e) => {
27
+ const converted = convertError(e);
28
+ throw isNotFound(converted) ? converted : e;
29
+ });
24
30
  },
25
31
  }, [backend, workspace, id, type, filled]);
26
32
  // Object id is required
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Inline access row for the metadata tab, wired to the share context. Renders the
3
+ * current access summary, or a placeholder while it loads (the row stays because
4
+ * Share is still reachable for the object), or nothing when sharing is unavailable.
5
+ * Self-subscribing so it re-renders on access edits without re-rendering the tab.
6
+ *
7
+ * @internal
8
+ */
9
+ export declare function CatalogItemAccessRow(): import("react/jsx-runtime").JSX.Element | null;
10
+ //# sourceMappingURL=CatalogItemAccessRow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CatalogItemAccessRow.d.ts","sourceRoot":"","sources":["../../../src/catalogDetail/share/CatalogItemAccessRow.tsx"],"names":[],"mappings":"AAWA;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,mDAoBnC"}
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // (C) 2026 GoodData Corporation
3
+ import { FormattedMessage } from "react-intl";
4
+ import { UiSkeleton } from "@gooddata/sdk-ui-kit";
5
+ import { CatalogDetailContentRow } from "../CatalogDetailContentRow.js";
6
+ import { CatalogDetailAccessRow } from "./CatalogDetailAccessRow.js";
7
+ import { useCatalogItemShareActions, useCatalogItemShareState } from "./CatalogItemShareProvider.js";
8
+ /**
9
+ * Inline access row for the metadata tab, wired to the share context. Renders the
10
+ * current access summary, or a placeholder while it loads (the row stays because
11
+ * Share is still reachable for the object), or nothing when sharing is unavailable.
12
+ * Self-subscribing so it re-renders on access edits without re-rendering the tab.
13
+ *
14
+ * @internal
15
+ */
16
+ export function CatalogItemAccessRow() {
17
+ const { active, controller } = useCatalogItemShareState();
18
+ const { open } = useCatalogItemShareActions();
19
+ if (!active || !controller) {
20
+ return null;
21
+ }
22
+ const summary = controller.state.summary;
23
+ if (summary) {
24
+ return _jsx(CatalogDetailAccessRow, { summary: summary, onOpen: open });
25
+ }
26
+ // Summary not available yet (loading or load error). Keep the row — Share is
27
+ // still reachable — with a placeholder rather than omitting it.
28
+ return (_jsx(CatalogDetailContentRow, { title: _jsx(FormattedMessage, { id: "analyticsCatalog.share.access.row.label" }), content: _jsx(UiSkeleton, { itemWidth: 200, itemHeight: 20 }) }));
29
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Lazy boundary for the catalog item's share dialog. Renders nothing until the
3
+ * dialog is first opened; from then on it stays mounted (so close/reopen is
4
+ * instant) and the dialog's own `isOpen` drives visibility. No-ops when sharing
5
+ * is unavailable.
6
+ *
7
+ * @internal
8
+ */
9
+ export declare function CatalogItemShareDialog(): import("react/jsx-runtime").JSX.Element | null;
10
+ //# sourceMappingURL=CatalogItemShareDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CatalogItemShareDialog.d.ts","sourceRoot":"","sources":["../../../src/catalogDetail/share/CatalogItemShareDialog.tsx"],"names":[],"mappings":"AAaA;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,mDAkBrC"}
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // (C) 2026 GoodData Corporation
3
+ import { Suspense, lazy, useState } from "react";
4
+ import { useCatalogItemShareState } from "./CatalogItemShareProvider.js";
5
+ // Code-split the dialog (and the heavy kit dialog chrome it pulls from
6
+ // @gooddata/sdk-ui-ext) into its own chunk, loaded on first open rather than with
7
+ // the catalog bundle. The always-visible inline access row stays in the main chunk.
8
+ const CatalogItemShareDialogInner = lazy(() => import("./CatalogItemShareDialogInner.js").then((m) => ({ default: m.CatalogItemShareDialogInner })));
9
+ /**
10
+ * Lazy boundary for the catalog item's share dialog. Renders nothing until the
11
+ * dialog is first opened; from then on it stays mounted (so close/reopen is
12
+ * instant) and the dialog's own `isOpen` drives visibility. No-ops when sharing
13
+ * is unavailable.
14
+ *
15
+ * @internal
16
+ */
17
+ export function CatalogItemShareDialog() {
18
+ const { active, isOpen } = useCatalogItemShareState();
19
+ // Latch: once opened, keep the lazy dialog mounted so reopening doesn't reload
20
+ // the chunk or lose the dialog's transient state.
21
+ const [everOpened, setEverOpened] = useState(false);
22
+ if (isOpen && !everOpened) {
23
+ setEverOpened(true);
24
+ }
25
+ if (!active || !everOpened) {
26
+ return null;
27
+ }
28
+ return (_jsx(Suspense, { fallback: null, children: _jsx(CatalogItemShareDialogInner, {}) }));
29
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The connected share dialog, split into its own module so it (and the heavy kit
3
+ * dialog chrome it pulls from `@gooddata/sdk-ui-ext`) is code-split out of the main
4
+ * catalog chunk and loaded only when the dialog is first opened. Reads the shared
5
+ * controller from context so it and the inline access row use one access-list fetch.
6
+ *
7
+ * @internal
8
+ */
9
+ export declare function CatalogItemShareDialogInner(): import("react/jsx-runtime").JSX.Element | null;
10
+ //# sourceMappingURL=CatalogItemShareDialogInner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CatalogItemShareDialogInner.d.ts","sourceRoot":"","sources":["../../../src/catalogDetail/share/CatalogItemShareDialogInner.tsx"],"names":[],"mappings":"AAMA;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,mDAkB1C"}
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // (C) 2026 GoodData Corporation
3
+ import { ObjectShareDialog } from "@gooddata/sdk-ui-ext";
4
+ import { useCatalogItemShareActions, useCatalogItemShareState } from "./CatalogItemShareProvider.js";
5
+ /**
6
+ * The connected share dialog, split into its own module so it (and the heavy kit
7
+ * dialog chrome it pulls from `@gooddata/sdk-ui-ext`) is code-split out of the main
8
+ * catalog chunk and loaded only when the dialog is first opened. Reads the shared
9
+ * controller from context so it and the inline access row use one access-list fetch.
10
+ *
11
+ * @internal
12
+ */
13
+ export function CatalogItemShareDialogInner() {
14
+ const { controller, target, objectTitle, isOpen, labelsLoading } = useCatalogItemShareState();
15
+ const { close } = useCatalogItemShareActions();
16
+ if (!controller) {
17
+ return null;
18
+ }
19
+ return (_jsx(ObjectShareDialog, { target: target, objectTitle: objectTitle, isOpen: isOpen, onClose: close, labelsLoading: labelsLoading, controller: controller }));
20
+ }
@@ -0,0 +1,71 @@
1
+ import { type ReactNode } from "react";
2
+ import type { IObjectPermissionsObject } from "@gooddata/sdk-backend-spi";
3
+ import { type IObjectShareController } from "@gooddata/sdk-ui-ext";
4
+ import type { ShareableCatalogItem } from "./types.js";
5
+ import type { IShareableLabels } from "./useShareableLabels.js";
6
+ /**
7
+ * Live share state for the catalog item. Consumed by the inline access row and the
8
+ * share dialog, which re-render as the controller's state changes. `active` is false
9
+ * when the item can't be shared (flag off / not a shareable kind), so consumers can
10
+ * render nothing without conditional hooks.
11
+ */
12
+ interface ICatalogItemShareState {
13
+ active: boolean;
14
+ controller: IObjectShareController | undefined;
15
+ target: IObjectPermissionsObject | undefined;
16
+ objectTitle: string;
17
+ /** Whether the share dialog is open. */
18
+ isOpen: boolean;
19
+ /** Whether the item's labels are still loading (passed to the dialog). */
20
+ labelsLoading: boolean;
21
+ }
22
+ /**
23
+ * Stable open/close actions for the share dialog. Split from the state so an
24
+ * actions-only consumer (the Share button) never re-renders on a state tick.
25
+ */
26
+ interface ICatalogItemShareActions {
27
+ active: boolean;
28
+ open: () => void;
29
+ close: () => void;
30
+ }
31
+ /**
32
+ * @internal
33
+ */
34
+ export interface ICatalogItemShareProviderProps {
35
+ /** The shareable item, or undefined when sharing is unavailable (flag off / not shareable). */
36
+ shareableItem: ShareableCatalogItem | undefined;
37
+ /** Backend share target for {@link shareableItem}. */
38
+ target: IObjectPermissionsObject | undefined;
39
+ /** Labels of the shared attribute (already fetched by the parent, reused here). */
40
+ labels: IShareableLabels;
41
+ children: ReactNode;
42
+ }
43
+ /**
44
+ * Owns the share controller, its single access-list fetch and the dialog open
45
+ * state for one catalog item, and exposes them through two contexts (state +
46
+ * actions). Because it renders `children` and the live state is read only by the
47
+ * leaf components that need it (access row, dialog), the surrounding detail
48
+ * subtree — header, tabs, status — does not re-render as access is edited.
49
+ *
50
+ * No-ops cleanly when the item can't be shared: the contexts then carry an
51
+ * inactive value and the hooks below report `active: false`.
52
+ *
53
+ * @internal
54
+ */
55
+ export declare function CatalogItemShareProvider({ shareableItem, target, labels, children }: ICatalogItemShareProviderProps): import("react/jsx-runtime").JSX.Element;
56
+ /**
57
+ * Live share state (controller, summary, open flag) for the current catalog item.
58
+ * Reports `active: false` when sharing is unavailable.
59
+ *
60
+ * @internal
61
+ */
62
+ export declare function useCatalogItemShareState(): ICatalogItemShareState;
63
+ /**
64
+ * Stable share actions (open/close the dialog) for the current catalog item.
65
+ * Reading this instead of the state keeps a consumer from re-rendering on state ticks.
66
+ *
67
+ * @internal
68
+ */
69
+ export declare function useCatalogItemShareActions(): ICatalogItemShareActions;
70
+ export {};
71
+ //# sourceMappingURL=CatalogItemShareProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CatalogItemShareProvider.d.ts","sourceRoot":"","sources":["../../../src/catalogDetail/share/CatalogItemShareProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAA6D,MAAM,OAAO,CAAC;AAElG,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,EAAE,KAAK,sBAAsB,EAAkB,MAAM,sBAAsB,CAAC;AAEnF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE;;;;;GAKG;AACH,UAAU,sBAAsB;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,sBAAsB,GAAG,SAAS,CAAC;IAC/C,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,MAAM,EAAE,OAAO,CAAC;IAChB,0EAA0E;IAC1E,aAAa,EAAE,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,UAAU,wBAAwB;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;CACrB;AAiBD;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC3C,+FAA+F;IAC/F,aAAa,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAChD,sDAAsD;IACtD,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAC7C,mFAAmF;IACnF,MAAM,EAAE,gBAAgB,CAAC;IACzB,QAAQ,EAAE,SAAS,CAAC;CACvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,EACrC,aAAa,EACb,MAAM,EACN,MAAM,EACN,QAAQ,EACX,EAAE,8BAA8B,2CAmDhC;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,sBAAsB,CAEjE;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,IAAI,wBAAwB,CAErE"}
@@ -0,0 +1,83 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // (C) 2026 GoodData Corporation
3
+ import { createContext, useCallback, useContext, useMemo, useState } from "react";
4
+ import { useObjectShare } from "@gooddata/sdk-ui-ext";
5
+ const INACTIVE_STATE = {
6
+ active: false,
7
+ controller: undefined,
8
+ target: undefined,
9
+ objectTitle: "",
10
+ isOpen: false,
11
+ labelsLoading: false,
12
+ };
13
+ const noop = () => { };
14
+ const INACTIVE_ACTIONS = { active: false, open: noop, close: noop };
15
+ const ShareStateContext = createContext(INACTIVE_STATE);
16
+ const ShareActionsContext = createContext(INACTIVE_ACTIONS);
17
+ /**
18
+ * Owns the share controller, its single access-list fetch and the dialog open
19
+ * state for one catalog item, and exposes them through two contexts (state +
20
+ * actions). Because it renders `children` and the live state is read only by the
21
+ * leaf components that need it (access row, dialog), the surrounding detail
22
+ * subtree — header, tabs, status — does not re-render as access is edited.
23
+ *
24
+ * No-ops cleanly when the item can't be shared: the contexts then carry an
25
+ * inactive value and the hooks below report `active: false`.
26
+ *
27
+ * @internal
28
+ */
29
+ export function CatalogItemShareProvider({ shareableItem, target, labels, children, }) {
30
+ // One controller drives both the dialog and the inline access row; the row reads
31
+ // `state.summary`, so a save inside the dialog refreshes it too. labelsLoading/
32
+ // labelsError keep the controller label-unresolved while labels are pending.
33
+ const controller = useObjectShare(target, {
34
+ labels: labels.labels,
35
+ labelsError: labels.error,
36
+ labelsLoading: labels.loading,
37
+ });
38
+ const [isOpen, setIsOpen] = useState(false);
39
+ // The detail view is reused as the user navigates between objects, so close an
40
+ // open dialog when the shareable target changes (or becomes non-shareable) —
41
+ // otherwise it would linger open on the next object. Reset during render (React's
42
+ // "adjust state on prop change" idiom) rather than in an effect.
43
+ const targetKey = shareableItem?.identifier;
44
+ const [openForKey, setOpenForKey] = useState(undefined);
45
+ if (isOpen && openForKey !== targetKey) {
46
+ setIsOpen(false);
47
+ }
48
+ const open = useCallback(() => {
49
+ setOpenForKey(targetKey);
50
+ setIsOpen(true);
51
+ }, [targetKey]);
52
+ const close = useCallback(() => setIsOpen(false), []);
53
+ const state = useMemo(() => shareableItem
54
+ ? {
55
+ active: true,
56
+ controller,
57
+ target,
58
+ objectTitle: shareableItem.title,
59
+ isOpen,
60
+ labelsLoading: labels.loading,
61
+ }
62
+ : INACTIVE_STATE, [shareableItem, controller, target, isOpen, labels.loading]);
63
+ const actions = useMemo(() => (shareableItem ? { active: true, open, close } : INACTIVE_ACTIONS), [shareableItem, open, close]);
64
+ return (_jsx(ShareActionsContext.Provider, { value: actions, children: _jsx(ShareStateContext.Provider, { value: state, children: children }) }));
65
+ }
66
+ /**
67
+ * Live share state (controller, summary, open flag) for the current catalog item.
68
+ * Reports `active: false` when sharing is unavailable.
69
+ *
70
+ * @internal
71
+ */
72
+ export function useCatalogItemShareState() {
73
+ return useContext(ShareStateContext);
74
+ }
75
+ /**
76
+ * Stable share actions (open/close the dialog) for the current catalog item.
77
+ * Reading this instead of the state keeps a consumer from re-rendering on state ticks.
78
+ *
79
+ * @internal
80
+ */
81
+ export function useCatalogItemShareActions() {
82
+ return useContext(ShareActionsContext);
83
+ }
@@ -58,6 +58,7 @@ export declare const de_DE: {
58
58
  "analyticsCatalog.filter.reset": string;
59
59
  "analyticsCatalog.column.title.label": string;
60
60
  "analyticsCatalog.column.title.dataSet": string;
61
+ "analyticsCatalog.column.title.labels": string;
61
62
  "analyticsCatalog.column.title.createdBy": string;
62
63
  "analyticsCatalog.column.title.createdAt": string;
63
64
  "analyticsCatalog.column.title.tags": string;
@@ -191,5 +192,15 @@ export declare const de_DE: {
191
192
  "analyticsCatalog.parameter.dialog.delete.submit": string;
192
193
  "analyticsCatalog.parameter.delete.success": string;
193
194
  "analyticsCatalog.parameter.delete.error": string;
195
+ "analyticsCatalog.share.button": string;
196
+ "analyticsCatalog.share.access.row.label": string;
197
+ "analyticsCatalog.share.access.row.restricted": string;
198
+ "analyticsCatalog.share.access.row.workspace.view": string;
199
+ "analyticsCatalog.share.access.row.workspace.share": string;
200
+ "analyticsCatalog.share.access.row.sharedWith": string;
201
+ "analyticsCatalog.labels.more": string;
202
+ "analyticsCatalog.labels.trigger.ariaLabel": string;
203
+ "analyticsCatalog.labels.popup.title": string;
204
+ "analyticsCatalog.labels.popup.close": string;
194
205
  };
195
206
  //# sourceMappingURL=de-DE.localization-bundle.d.ts.map