@edifice.io/react 2.5.4-zookeeper.20251211100517 → 2.5.5-develop-b2school.20251218094734

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 (51) hide show
  1. package/dist/components/AppIcon/index.d.ts +1 -0
  2. package/dist/components/Divider/Divider.d.ts +38 -0
  3. package/dist/components/Divider/Divider.js +11 -0
  4. package/dist/components/Divider/index.d.ts +2 -0
  5. package/dist/components/Flex/Flex.js +1 -1
  6. package/dist/components/Menu/components/MenuButton.d.ts +2 -0
  7. package/dist/components/Menu/components/MenuButton.js +13 -4
  8. package/dist/components/SegmentedControl/SegmentedControl.d.ts +59 -0
  9. package/dist/components/SegmentedControl/SegmentedControl.js +21 -0
  10. package/dist/components/SegmentedControl/index.d.ts +2 -0
  11. package/dist/components/Select/Select.d.ts +6 -2
  12. package/dist/components/Select/Select.js +10 -4
  13. package/dist/components/index.d.ts +2 -0
  14. package/dist/editor.js +40 -36
  15. package/dist/hooks/index.d.ts +1 -0
  16. package/dist/hooks/useInfiniteScroll/index.d.ts +1 -0
  17. package/dist/hooks/useInfiniteScroll/useInfiniteScroll.d.ts +33 -0
  18. package/dist/hooks/useInfiniteScroll/useInfiniteScroll.js +20 -0
  19. package/dist/icons.js +300 -298
  20. package/dist/index.js +180 -170
  21. package/dist/modals.js +8 -6
  22. package/dist/modules/comments/components/Comment.js +4 -2
  23. package/dist/modules/comments/components/CommentList.js +1 -1
  24. package/dist/modules/comments/components/DeleteModal.js +14 -8
  25. package/dist/modules/editor/components/Editor/EditorPreview.d.ts +14 -0
  26. package/dist/modules/editor/components/Editor/EditorPreview.js +56 -0
  27. package/dist/modules/editor/components/Editor/EditorPreviewSkeleton.d.ts +8 -0
  28. package/dist/modules/editor/components/Editor/EditorPreviewSkeleton.js +24 -0
  29. package/dist/modules/editor/components/Editor/index.d.ts +2 -0
  30. package/dist/modules/icons/components/IconClockAlert.d.ts +7 -0
  31. package/dist/modules/icons/components/IconClockAlert.js +17 -0
  32. package/dist/modules/icons/components/index.d.ts +1 -0
  33. package/dist/modules/modals/ShareModal/ShareBookmark.d.ts +1 -1
  34. package/dist/modules/modals/ShareModal/ShareBookmark.js +5 -2
  35. package/dist/modules/modals/ShareModal/ShareModal.d.ts +1 -11
  36. package/dist/modules/modals/ShareModal/ShareModal.js +13 -105
  37. package/dist/modules/modals/ShareModal/ShareResources.d.ts +174 -0
  38. package/dist/modules/modals/ShareModal/ShareResources.js +137 -0
  39. package/dist/modules/modals/ShareModal/hooks/useSearch.d.ts +2 -1
  40. package/dist/modules/modals/ShareModal/hooks/useSearch.js +3 -2
  41. package/dist/modules/modals/ShareModal/hooks/useShare.d.ts +12 -5
  42. package/dist/modules/modals/ShareModal/hooks/useShare.js +20 -13
  43. package/dist/modules/modals/ShareModal/hooks/useShareBookmark.d.ts +1 -1
  44. package/dist/modules/modals/ShareModal/hooks/useShareBookmark.js +1 -1
  45. package/dist/modules/modals/ShareModal/index.d.ts +3 -1
  46. package/dist/style.css +1 -1
  47. package/dist/utilities/index.d.ts +1 -0
  48. package/dist/utilities/react-query/index.d.ts +1 -0
  49. package/dist/utilities/react-query/react-query-utils.d.ts +21 -0
  50. package/dist/utilities/react-query/react-query-utils.js +13 -0
  51. package/package.json +6 -6
@@ -0,0 +1,24 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import clsx from "clsx";
3
+ import TextSkeleton from "../../../../components/Skeleton/TextSkeleton.js";
4
+ import Image from "../../../../components/Image/Image.js";
5
+ const EditorPreview = ({
6
+ variant = "outline"
7
+ }) => {
8
+ const borderClass = clsx(variant === "outline" && "border rounded-3"), contentClass = clsx("mt-16", variant === "outline" && "my-12 mx-16");
9
+ return /* @__PURE__ */ jsx("div", { className: borderClass, "data-testid": "editor-preview", children: /* @__PURE__ */ jsxs("div", { className: contentClass, children: [
10
+ /* @__PURE__ */ jsx(TextSkeleton, { className: "col-12" }),
11
+ /* @__PURE__ */ jsx(TextSkeleton, { className: "col-12" }),
12
+ /* @__PURE__ */ jsxs("div", { className: "d-flex justify-content-center gap-24 px-32 pt-16", children: [
13
+ /* @__PURE__ */ jsx("div", { style: {
14
+ maxWidth: "150px"
15
+ }, className: "col-12 col-md-4", children: /* @__PURE__ */ jsx(Image, { alt: "", objectFit: "cover", ratio: "16", className: "rounded placeholder", src: "", sizes: "" }) }),
16
+ /* @__PURE__ */ jsx("div", { style: {
17
+ maxWidth: "150px"
18
+ }, className: "col-12 col-md-4", children: /* @__PURE__ */ jsx(Image, { alt: "", objectFit: "cover", ratio: "16", className: "rounded placeholder", src: "", sizes: "" }) })
19
+ ] })
20
+ ] }) });
21
+ };
22
+ export {
23
+ EditorPreview as default
24
+ };
@@ -1,3 +1,5 @@
1
1
  export * from './Editor';
2
2
  export { default as Editor } from './Editor';
3
+ export { default as EditorPreview } from './EditorPreview';
4
+ export { default as EditorPreviewSkeleton } from './EditorPreviewSkeleton';
3
5
  export { default as EditorSkeleton } from './EditorSkeleton';
@@ -0,0 +1,7 @@
1
+ import { SVGProps } from 'react';
2
+ interface SVGRProps {
3
+ title?: string;
4
+ titleId?: string;
5
+ }
6
+ declare const SvgIconClockAlert: ({ title, titleId, ...props }: SVGProps<SVGSVGElement> & SVGRProps) => import("react/jsx-runtime").JSX.Element;
7
+ export default SvgIconClockAlert;
@@ -0,0 +1,17 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ const SvgIconClockAlert = ({
3
+ title,
4
+ titleId,
5
+ ...props
6
+ }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", fill: "none", viewBox: "0 0 24 24", "aria-hidden": "true", "aria-labelledby": titleId, ...props, children: [
7
+ title ? /* @__PURE__ */ jsx("title", { id: titleId, children: title }) : null,
8
+ /* @__PURE__ */ jsxs("g", { fill: "currentColor", clipPath: "url(#icon-clock-alert_svg__a)", children: [
9
+ /* @__PURE__ */ jsx("path", { d: "M0 10.075C0 4.51 4.51 0 10.075 0c4.573 0 8.431 3.046 9.663 7.217a1 1 0 0 1-1.918.566A8.075 8.075 0 1 0 7.783 17.82a1 1 0 0 1-.566 1.918C3.046 18.506 0 14.648 0 10.075" }),
10
+ /* @__PURE__ */ jsx("path", { d: "M10.075 4.108a1 1 0 0 1 1 1v5.43a1 1 0 0 1-.357.767L7.83 13.728a1 1 0 1 1-1.286-1.532l2.53-2.123V5.108a1 1 0 0 1 1-1M17 13.3a1 1 0 0 1 1 1v2.2a1 1 0 1 1-2 0v-2.2a1 1 0 0 1 1-1M17 18.4a1 1 0 1 0 0 2h.006a1 1 0 1 0 0-2z" }),
11
+ /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M17 10a7 7 0 1 0 0 14 7 7 0 0 0 0-14m-5 7a5 5 0 1 1 10 0 5 5 0 0 1-10 0", clipRule: "evenodd" })
12
+ ] }),
13
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", { id: "icon-clock-alert_svg__a", children: /* @__PURE__ */ jsx("path", { fill: "#fff", d: "M0 0h24v24H0z" }) }) })
14
+ ] });
15
+ export {
16
+ SvgIconClockAlert as default
17
+ };
@@ -24,6 +24,7 @@ export { default as IconCantoo } from './IconCantoo';
24
24
  export { default as IconCenter } from './IconCenter';
25
25
  export { default as IconCheck } from './IconCheck';
26
26
  export { default as IconChecklist } from './IconChecklist';
27
+ export { default as IconClockAlert } from './IconClockAlert';
27
28
  export { default as IconClock } from './IconClock';
28
29
  export { default as IconCloseFullScreen } from './IconCloseFullScreen';
29
30
  export { default as IconClose } from './IconClose';
@@ -4,5 +4,5 @@ export declare const ShareBookmark: ({ bookmark, refBookmark, onBookmarkChange,
4
4
  bookmark: BookmarkProps;
5
5
  refBookmark: Ref<HTMLInputElement>;
6
6
  onBookmarkChange: () => void;
7
- onSave: () => void;
7
+ onSave: () => Promise<void>;
8
8
  }) => import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,5 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
2
3
  import { useTranslation } from "react-i18next";
3
4
  import SvgIconSave from "../../icons/components/IconSave.js";
4
5
  import FormControl from "../../../components/Form/FormControl.js";
@@ -11,10 +12,12 @@ const ShareBookmark = ({
11
12
  }) => {
12
13
  const {
13
14
  t
14
- } = useTranslation();
15
+ } = useTranslation(), [isSaving, setIsSaving] = useState(!1), handleSaveClick = async () => {
16
+ setIsSaving(!0), await onSave(), setIsSaving(!1);
17
+ };
15
18
  return /* @__PURE__ */ jsx("div", { className: "mt-16", children: /* @__PURE__ */ jsxs(FormControl, { id: "bookmarkName", className: "d-flex flex-wrap align-items-center gap-16", children: [
16
19
  /* @__PURE__ */ jsx("div", { className: "flex-fill", children: /* @__PURE__ */ jsx(FormControl.Input, { ref: refBookmark, onChange: onBookmarkChange, placeholder: t("explorer.modal.share.sharebookmark.placeholder"), size: "sm", type: "text" }, bookmark.id) }),
17
- /* @__PURE__ */ jsx(Button, { type: "button", color: "primary", variant: "ghost", disabled: bookmark.name.length === 0, leftIcon: /* @__PURE__ */ jsx(SvgIconSave, {}), onClick: onSave, className: "text-nowrap", children: t("explorer.modal.share.sharebookmark.save") })
20
+ /* @__PURE__ */ jsx(Button, { type: "button", color: "primary", variant: "ghost", disabled: bookmark.name.length === 0 || isSaving, leftIcon: /* @__PURE__ */ jsx(SvgIconSave, {}), onClick: handleSaveClick, className: "text-nowrap", isLoading: isSaving, children: t("explorer.modal.share.sharebookmark.save") })
18
21
  ] }) });
19
22
  };
20
23
  export {
@@ -1,15 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
- import { ID, PutShareResponse, RightStringified, ShareRight } from '@edifice.io/client';
3
- import { UseMutationResult } from '../../../node_modules/@tanstack/react-query';
4
- export type ShareOptions = {
5
- resourceId: ID;
6
- resourceRights: RightStringified[];
7
- resourceCreatorId: string;
8
- };
9
- export type ShareResourceMutation = UseMutationResult<PutShareResponse, unknown, {
10
- resourceId: string;
11
- rights: ShareRight[];
12
- }, unknown>;
2
+ import { ShareOptions, ShareResourceMutation } from './ShareResources';
13
3
  interface ShareResourceModalProps {
14
4
  /** Handle open/close state */
15
5
  isOpen: boolean;
@@ -1,25 +1,11 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
- import { useState } from "react";
2
+ import { useRef, useState } from "react";
3
3
  import { createPortal } from "react-dom";
4
4
  import { useTranslation } from "react-i18next";
5
- import SvgIconBookmark from "../../icons/components/IconBookmark.js";
6
- import SvgIconInfoCircle from "../../icons/components/IconInfoCircle.js";
7
- import SvgIconRafterDown from "../../icons/components/IconRafterDown.js";
8
- import { ShareBookmark } from "./ShareBookmark.js";
9
- import { ShareBookmarkLine } from "./ShareBookmarkLine.js";
10
- import { useSearch } from "./hooks/useSearch.js";
11
- import useShare from "./hooks/useShare.js";
12
- import { useShareBookmark } from "./hooks/useShareBookmark.js";
5
+ import ShareResources from "./ShareResources.js";
13
6
  import Modal from "../../../components/Modal/Modal.js";
14
7
  import Alert from "../../../components/Alert/Alert.js";
15
- import Heading from "../../../components/Heading/Heading.js";
16
- import LoadingScreen from "../../../components/LoadingScreen/LoadingScreen.js";
17
- import VisuallyHidden from "../../../components/VisuallyHidden/VisuallyHidden.js";
18
- import Avatar from "../../../components/Avatar/Avatar.js";
19
- import Checkbox from "../../../components/Checkbox/Checkbox.js";
20
8
  import Button from "../../../components/Button/Button.js";
21
- import Tooltip from "../../../components/Tooltip/Tooltip.js";
22
- import Combobox from "../../../components/Combobox/Combobox.js";
23
9
  function ShareResourceModal({
24
10
  isOpen,
25
11
  shareOptions,
@@ -28,104 +14,26 @@ function ShareResourceModal({
28
14
  onSuccess,
29
15
  onCancel
30
16
  }) {
31
- const {
32
- resourceId,
33
- resourceCreatorId,
34
- resourceRights
35
- } = shareOptions, [isLoading, setIsLoading] = useState(!0), {
36
- state: {
37
- isSharing,
38
- shareRights,
39
- shareRightActions
40
- },
41
- dispatch: shareDispatch,
42
- myAvatar,
43
- currentIsAuthor,
44
- handleShare,
45
- toggleRight,
46
- handleDeleteRow
47
- } = useShare({
48
- resourceId,
49
- resourceCreatorId,
50
- resourceRights,
51
- shareResource,
52
- setIsLoading,
53
- onSuccess
54
- }), {
55
- state: {
56
- searchResults,
57
- searchInputValue
58
- },
59
- showSearchAdmlHint,
60
- showSearchLoading,
61
- showSearchNoResults,
62
- getSearchMinLength,
63
- handleSearchInputChange,
64
- handleSearchResultsChange
65
- } = useSearch({
66
- resourceId,
67
- resourceCreatorId,
68
- shareRights,
69
- shareDispatch
70
- }), {
71
- refBookmark,
72
- showBookmark,
73
- handleBookmarkChange,
74
- toggleBookmark,
75
- bookmark,
76
- handleOnSave,
77
- showBookmarkInput,
78
- toggleBookmarkInput
79
- } = useShareBookmark({
80
- shareRights,
81
- shareDispatch
82
- }), {
17
+ const refShareResources = useRef(null), handleShare = () => {
18
+ var _a;
19
+ (_a = refShareResources.current) == null || _a.handleShare();
20
+ }, [isSaving, setIsSaving] = useState(!1), {
83
21
  t
84
- } = useTranslation(), searchPlaceholder = showSearchAdmlHint() ? t("explorer.search.adml.hint") : t("explorer.modal.share.search.placeholder");
22
+ } = useTranslation(), onSaving = (isSaving2) => {
23
+ setIsSaving(isSaving2);
24
+ };
85
25
  return /* @__PURE__ */ createPortal(/* @__PURE__ */ jsxs(Modal, { id: "share_modal", size: "lg", isOpen, onModalClose: onCancel, children: [
86
26
  /* @__PURE__ */ jsx(Modal.Header, { onModalClose: onCancel, children: t("share.title") }),
87
27
  /* @__PURE__ */ jsxs(Modal.Body, { children: [
88
28
  /* @__PURE__ */ jsx(Alert, { type: "info", className: "mb-16", children: t("explorer.modal.share.alert.community") }),
89
- /* @__PURE__ */ jsx(Heading, { headingStyle: "h4", level: "h3", className: "mb-16", children: t("explorer.modal.share.usersWithAccess") }),
90
- /* @__PURE__ */ jsx("div", { className: "table-responsive", children: isLoading ? /* @__PURE__ */ jsx(LoadingScreen, {}) : /* @__PURE__ */ jsxs("table", { className: "table border align-middle mb-0", children: [
91
- /* @__PURE__ */ jsx("thead", { className: "bg-secondary", children: /* @__PURE__ */ jsxs("tr", { children: [
92
- /* @__PURE__ */ jsx("th", { scope: "col", className: "w-32", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: t("explorer.modal.share.avatar.shared.alt") }) }),
93
- /* @__PURE__ */ jsx("th", { scope: "col", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: t("explorer.modal.share.search.placeholder") }) }),
94
- shareRightActions.map((shareRightAction) => /* @__PURE__ */ jsx("th", { scope: "col", className: "text-center text-white", children: t(shareRightAction.displayName) }, shareRightAction.displayName)),
95
- /* @__PURE__ */ jsx("th", { scope: "col", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: t("close") }) })
96
- ] }) }),
97
- /* @__PURE__ */ jsxs("tbody", { children: [
98
- currentIsAuthor() && /* @__PURE__ */ jsxs("tr", { children: [
99
- /* @__PURE__ */ jsx("th", { scope: "row", children: /* @__PURE__ */ jsx(Avatar, { alt: t("explorer.modal.share.avatar.me.alt"), size: "xs", src: myAvatar, variant: "circle" }) }),
100
- /* @__PURE__ */ jsx("td", { children: t("share.me") }),
101
- shareRightActions.map((shareRightAction) => /* @__PURE__ */ jsx("td", { style: {
102
- width: "80px"
103
- }, className: "text-center text-white", children: /* @__PURE__ */ jsx(Checkbox, { checked: !0, disabled: !0 }) }, shareRightAction.displayName)),
104
- /* @__PURE__ */ jsx("td", {})
105
- ] }),
106
- /* @__PURE__ */ jsx(ShareBookmarkLine, { showBookmark, shareRightActions, shareRights, onDeleteRow: handleDeleteRow, toggleRight, toggleBookmark })
107
- ] })
108
- ] }) }),
109
- /* @__PURE__ */ jsxs("div", { className: "mt-16", children: [
110
- /* @__PURE__ */ jsx(Button, { color: "tertiary", leftIcon: /* @__PURE__ */ jsx(SvgIconBookmark, {}), rightIcon: /* @__PURE__ */ jsx(SvgIconRafterDown, { title: t("show"), className: "w-16 min-w-0", style: {
111
- transition: "rotate 0.2s ease-out",
112
- rotate: showBookmarkInput ? "-180deg" : "0deg"
113
- } }), type: "button", variant: "ghost", className: "fw-normal", onClick: () => toggleBookmarkInput(!showBookmarkInput), children: t("share.save.sharebookmark") }),
114
- showBookmarkInput && /* @__PURE__ */ jsx(ShareBookmark, { refBookmark, bookmark, onBookmarkChange: handleBookmarkChange, onSave: handleOnSave })
115
- ] }),
116
- /* @__PURE__ */ jsx("hr", {}),
117
- /* @__PURE__ */ jsxs(Heading, { headingStyle: "h4", level: "h3", className: "mb-16 d-flex align-items-center", children: [
118
- /* @__PURE__ */ jsx("div", { className: "me-8", children: t("explorer.modal.share.search") }),
119
- /* @__PURE__ */ jsx(Tooltip, { message: "Vos favoris de partage s’affichent en priorité dans votre liste lorsque vous recherchez un groupe ou une personne, vous pouvez les retrouver dans l’annuaire.", placement: "top", children: /* @__PURE__ */ jsx(SvgIconInfoCircle, { className: "c-pointer", height: "18" }) })
120
- ] }),
121
- /* @__PURE__ */ jsx("div", { className: "row", children: /* @__PURE__ */ jsx("div", { className: "col-10", children: /* @__PURE__ */ jsx(Combobox, { value: searchInputValue, placeholder: searchPlaceholder, isLoading: showSearchLoading(), noResult: showSearchNoResults(), options: searchResults, searchMinLength: getSearchMinLength(), onSearchInputChange: handleSearchInputChange, onSearchResultsChange: handleSearchResultsChange }) }) }),
29
+ /* @__PURE__ */ jsx(ShareResources, { shareOptions, shareResource, ref: refShareResources, onSuccess, onSubmit: onSaving, classNameSearchInput: "flex-fill" }),
122
30
  children
123
31
  ] }),
124
32
  /* @__PURE__ */ jsxs(Modal.Footer, { children: [
125
- /* @__PURE__ */ jsx(Button, { type: "button", color: "tertiary", variant: "ghost", onClick: onCancel, children: t("explorer.cancel") }),
126
- /* @__PURE__ */ jsx(Button, { type: "button", color: "primary", variant: "filled", isLoading: isSharing, onClick: handleShare, disabled: isSharing, children: t("share") })
33
+ /* @__PURE__ */ jsx(Button, { type: "button", color: "tertiary", variant: "ghost", onClick: onCancel, disabled: isSaving, children: t("explorer.cancel") }),
34
+ /* @__PURE__ */ jsx(Button, { type: "button", color: "primary", variant: "filled", isLoading: isSaving, onClick: handleShare, disabled: isSaving, children: t("share") })
127
35
  ] })
128
- ] }), document.getElementById("portal"));
36
+ ] }), document.getElementById("portal") || document.body);
129
37
  }
130
38
  export {
131
39
  ShareResourceModal as default
@@ -0,0 +1,174 @@
1
+ import { ID, PutShareResponse, RightStringified, ShareRight, ShareRightActionDisplayName, ShareUrls } from '@edifice.io/client';
2
+ import { UseMutationResult } from '../../../node_modules/@tanstack/react-query';
3
+ /**
4
+ * Configuration options for sharing a resource
5
+ *
6
+ * @typedef {Object} ShareOptions
7
+ * @property {ID} resourceId - Unique identifier of the resource to share
8
+ * @property {RightStringified[]} resourceRights - Current rights assigned to the resource
9
+ * @property {string} resourceCreatorId - User ID of the resource creator
10
+ * @property {ShareRightActionDisplayName[]} [filteredActions] - Optional list of allowed actions to display
11
+ * @property {ShareUrls} [shareUrls] - Optional custom URLs for API endpoints related to sharing operations default endpoints are used if not provided
12
+ * default: {
13
+ * getResourceRights: `/${app}/share/json/${resourceId}?search=`,
14
+ * saveResourceRights: `/${app}/share/resource/${resourceId}`,
15
+ * getShareMapping: `/${app}/rights/sharing`
16
+ * }
17
+ *
18
+ * @example Example related to sharing thread resources:
19
+ * ```ts
20
+ * const shareOptions: ShareOptions = {
21
+ * resourceId: '12345',
22
+ * resourceRights: [],
23
+ * resourceCreatorId: 'user-67890',
24
+ * filteredActions: ['read', 'contrib'],
25
+ * shareUrls: {
26
+ * getResourceRights: '/api/V1/thread/shares', (get endpoint)
27
+ * saveResourceRights: '/api/V1/thread/shares', (put endpoint)
28
+ * getShareMapping: '/api/V1/rights/sharing'
29
+ * }
30
+ * };
31
+ * ```
32
+ *
33
+ * @example Example related to sharing info resources:
34
+ * ```ts
35
+ * const shareOptions: ShareOptions = {
36
+ * resourceId: '12345',
37
+ * resourceRights: [],
38
+ * resourceCreatorId: 'user-67890',
39
+ * filteredActions: ['read', 'contrib'],
40
+ * shareUrls: {
41
+ * getResourceRights: '/api/V1/info/shares', (get endpoint)
42
+ * saveResourceRights: '/api/V1/info/shares', (put endpoint)
43
+ * getShareMapping: '/api/V1/rights/sharing'
44
+ * }
45
+ * };
46
+ * ```
47
+ */
48
+ export type ShareOptions = {
49
+ resourceId: ID;
50
+ resourceRights: RightStringified[];
51
+ resourceCreatorId: string;
52
+ filteredActions?: ShareRightActionDisplayName[];
53
+ shareUrls?: ShareUrls;
54
+ };
55
+ /**
56
+ * React Query mutation result for share operations
57
+ *
58
+ * @typedef {UseMutationResult<PutShareResponse, unknown, {resourceId: string; rights: ShareRight[]}, unknown>} ShareResourceMutation
59
+ */
60
+ export type ShareResourceMutation = UseMutationResult<PutShareResponse, unknown, {
61
+ resourceId: string;
62
+ rights: ShareRight[];
63
+ }, unknown>;
64
+ /**
65
+ * Props for the ShareResources component
66
+ *
67
+ * @interface ShareResourceProps
68
+ * @property {ShareOptions} shareOptions - Configuration for the resource being shared
69
+ * @property {ShareResourceMutation} [shareResource] - Optional React Query mutation for optimistic UI updates
70
+ * @property {() => void} [onSuccess] - Callback fired after successful share operation
71
+ * @property {(shareRights: ShareRight[], isDirty: boolean) => void} [onChange] - Callback fired when share rights change
72
+ * @property {(isSubmitting: boolean) => void} [onSubmit] - Callback fired when share operation is submitting
73
+ * @property {string} [classNameSearchInput] - Optional CSS class for the search input wrapper (default: 'col-6')
74
+ */
75
+ interface ShareResourceProps {
76
+ /**
77
+ * Expect resourceId,
78
+ * new rights array (replace shared array),
79
+ * creatorId
80
+ * of a resource */
81
+ shareOptions: ShareOptions;
82
+ /**
83
+ * Use the `shareResource` props when you need to do Optimistic UI
84
+ * otherwise ShareModal handles everything
85
+ * Must use React Query */
86
+ shareResource?: ShareResourceMutation;
87
+ /**
88
+ * onSuccess callback when a resource is successfully shared
89
+ */
90
+ onSuccess?: () => void;
91
+ /**
92
+ * Callback when share rights change
93
+ */
94
+ onChange?: (shareRights: ShareRight[], isDirty: boolean) => void;
95
+ /**
96
+ * Callback when ShareResources component is submitting share rights or bookmark changes
97
+ */
98
+ onSubmit?: (isSubmitting: boolean) => void;
99
+ /**
100
+ * Optional className for the search input wrapper (default: 'col-6')
101
+ */
102
+ classNameSearchInput?: string;
103
+ }
104
+ /**
105
+ * Ref interface exposed by ShareResources component
106
+ *
107
+ * @interface ShareResourcesRef
108
+ * @property {() => void} handleShare - Method to trigger the share operation
109
+ *
110
+ * @example
111
+ * ```tsx
112
+ * const ref = useRef<ShareResourcesRef>(null);
113
+ *
114
+ * // Trigger share programmatically
115
+ * ref.current?.handleShare();
116
+ *
117
+ * // Check sharing status
118
+ * const sharing = ref.current?.isSharing();
119
+ * ```
120
+ */
121
+ export interface ShareResourcesRef {
122
+ handleShare: (notify?: boolean) => void;
123
+ }
124
+ /**
125
+ * ShareResources Component
126
+ *
127
+ * A component for managing resource sharing permissions with users and groups.
128
+ * Provides search functionality, bookmark management, and granular rights control.
129
+ *
130
+ * @example
131
+ * ```tsx
132
+ * import { useRef } from 'react';
133
+ * import ShareResources, { ShareResourcesRef, ShareOptions } from './ShareResources';
134
+ *
135
+ * function MyComponent() {
136
+ * const shareRef = useRef<ShareResourcesRef>(null);
137
+ *
138
+ * const shareOptions: ShareOptions = {
139
+ * resourceId: '123',
140
+ * resourceRights: [],
141
+ * resourceCreatorId: 'user-456',
142
+ * filteredActions: ['read', 'contrib'],
143
+ * urls: {
144
+ * getResourceRights: '/api/share/rights',
145
+ * putResourceRights: '/api/share/update'
146
+ * }
147
+ * };
148
+ *
149
+ * const handleSave = () => {
150
+ * if (shareRef.current) {
151
+ * shareRef.current.handleShare();
152
+ * }
153
+ * };
154
+ *
155
+ * return (
156
+ * <>
157
+ * <ShareResources
158
+ * ref={shareRef}
159
+ * shareOptions={shareOptions}
160
+ * onSuccess={() => console.log('Shared successfully')}
161
+ * onChange={(rights, isDirty) => console.log('Rights changed:', isDirty)}
162
+ * onSubmit={(isSubmitting) => console.log('Submitting share...', isSubmitting)}
163
+ * />
164
+ * <button onClick={handleSave}>Save Changes</button>
165
+ * </>
166
+ * );
167
+ * }
168
+ * ```
169
+ *
170
+ * @component
171
+ * @forwardRef
172
+ */
173
+ declare const ShareResources: import('react').ForwardRefExoticComponent<ShareResourceProps & import('react').RefAttributes<ShareResourcesRef>>;
174
+ export default ShareResources;
@@ -0,0 +1,137 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { forwardRef, useState, useImperativeHandle, useEffect } from "react";
3
+ import { useTranslation } from "react-i18next";
4
+ import SvgIconBookmark from "../../icons/components/IconBookmark.js";
5
+ import SvgIconInfoCircle from "../../icons/components/IconInfoCircle.js";
6
+ import SvgIconRafterDown from "../../icons/components/IconRafterDown.js";
7
+ import { ShareBookmark } from "./ShareBookmark.js";
8
+ import { ShareBookmarkLine } from "./ShareBookmarkLine.js";
9
+ import { useSearch } from "./hooks/useSearch.js";
10
+ import useShare from "./hooks/useShare.js";
11
+ import { useShareBookmark } from "./hooks/useShareBookmark.js";
12
+ import Heading from "../../../components/Heading/Heading.js";
13
+ import Tooltip from "../../../components/Tooltip/Tooltip.js";
14
+ import Combobox from "../../../components/Combobox/Combobox.js";
15
+ import LoadingScreen from "../../../components/LoadingScreen/LoadingScreen.js";
16
+ import VisuallyHidden from "../../../components/VisuallyHidden/VisuallyHidden.js";
17
+ import Avatar from "../../../components/Avatar/Avatar.js";
18
+ import Checkbox from "../../../components/Checkbox/Checkbox.js";
19
+ import Button from "../../../components/Button/Button.js";
20
+ const ShareResources = /* @__PURE__ */ forwardRef(({
21
+ shareOptions,
22
+ shareResource,
23
+ onSuccess = () => {
24
+ },
25
+ onChange = () => {
26
+ },
27
+ onSubmit = () => {
28
+ },
29
+ classNameSearchInput = "col-6"
30
+ }, ref) => {
31
+ const {
32
+ resourceId,
33
+ resourceCreatorId,
34
+ resourceRights,
35
+ filteredActions,
36
+ shareUrls
37
+ } = shareOptions, [isLoading, setIsLoading] = useState(!0), [isSavingBookmark, setIsSavingBookmark] = useState(!1), {
38
+ state: {
39
+ isSharing,
40
+ shareRights,
41
+ shareRightActions
42
+ },
43
+ dispatch: shareDispatch,
44
+ myAvatar,
45
+ currentIsAuthor,
46
+ toggleRight,
47
+ handleShare,
48
+ handleDeleteRow,
49
+ isDirty
50
+ } = useShare({
51
+ resourceId,
52
+ resourceCreatorId,
53
+ resourceRights,
54
+ shareResource,
55
+ setIsLoading,
56
+ onSuccess,
57
+ filteredActions,
58
+ shareUrls
59
+ }), {
60
+ state: {
61
+ searchResults,
62
+ searchInputValue
63
+ },
64
+ showSearchAdmlHint,
65
+ showSearchLoading,
66
+ showSearchNoResults,
67
+ getSearchMinLength,
68
+ handleSearchInputChange,
69
+ handleSearchResultsChange
70
+ } = useSearch({
71
+ resourceId,
72
+ resourceCreatorId,
73
+ shareRights,
74
+ shareDispatch,
75
+ urlResourceRights: shareUrls == null ? void 0 : shareUrls.getResourceRights
76
+ }), {
77
+ refBookmark,
78
+ showBookmark,
79
+ handleBookmarkChange,
80
+ toggleBookmark,
81
+ bookmark,
82
+ handleOnSave,
83
+ showBookmarkInput,
84
+ toggleBookmarkInput
85
+ } = useShareBookmark({
86
+ shareRights,
87
+ shareDispatch
88
+ }), handleOnSaveBookmark = () => (setIsSavingBookmark(!0), handleOnSave().then(() => {
89
+ setIsSavingBookmark(!1);
90
+ }));
91
+ useImperativeHandle(ref, () => ({
92
+ handleShare
93
+ }), [handleShare]), useEffect(() => {
94
+ onChange(shareRights.rights, isDirty);
95
+ }, [isDirty, shareRights.rights, onChange]), useEffect(() => {
96
+ onSubmit(isSavingBookmark || isSharing);
97
+ }, [isSavingBookmark, isSharing, onSubmit]);
98
+ const {
99
+ t
100
+ } = useTranslation(), searchPlaceholder = showSearchAdmlHint() ? t("explorer.search.adml.hint") : t("explorer.modal.share.search.placeholder");
101
+ return /* @__PURE__ */ jsxs("div", { children: [
102
+ /* @__PURE__ */ jsxs(Heading, { headingStyle: "h4", level: "h3", className: "mb-16 d-flex align-items-center", children: [
103
+ /* @__PURE__ */ jsx("div", { className: "me-8", children: t("explorer.modal.share.search") }),
104
+ /* @__PURE__ */ jsx(Tooltip, { message: "Vos favoris de partage s’affichent en priorité dans votre liste lorsque vous recherchez un groupe ou une personne, vous pouvez les retrouver dans l’annuaire.", placement: "top", children: /* @__PURE__ */ jsx(SvgIconInfoCircle, { className: "c-pointer", height: "18" }) })
105
+ ] }),
106
+ /* @__PURE__ */ jsx("div", { className: "row mb-16", children: /* @__PURE__ */ jsx("div", { className: classNameSearchInput, children: /* @__PURE__ */ jsx(Combobox, { value: searchInputValue, placeholder: searchPlaceholder, isLoading: showSearchLoading(), noResult: showSearchNoResults(), options: searchResults, searchMinLength: getSearchMinLength(), onSearchInputChange: handleSearchInputChange, onSearchResultsChange: handleSearchResultsChange }) }) }),
107
+ /* @__PURE__ */ jsx("div", { className: "table-responsive", children: isLoading ? /* @__PURE__ */ jsx(LoadingScreen, {}) : /* @__PURE__ */ jsxs("table", { className: "table border align-middle mb-0 rounded-3", children: [
108
+ /* @__PURE__ */ jsx("thead", { className: "bg-blue-200", children: /* @__PURE__ */ jsxs("tr", { children: [
109
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "w-32", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: t("explorer.modal.share.avatar.shared.alt") }) }),
110
+ /* @__PURE__ */ jsx("th", { scope: "col", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: t("explorer.modal.share.search.placeholder") }) }),
111
+ shareRightActions.map((shareRightAction) => /* @__PURE__ */ jsx("th", { scope: "col", className: "text-center text-gray-800", children: t(shareRightAction.displayName) }, shareRightAction.displayName)),
112
+ /* @__PURE__ */ jsx("th", { scope: "col", children: /* @__PURE__ */ jsx(VisuallyHidden, { children: t("close") }) })
113
+ ] }) }),
114
+ /* @__PURE__ */ jsxs("tbody", { children: [
115
+ currentIsAuthor() && /* @__PURE__ */ jsxs("tr", { children: [
116
+ /* @__PURE__ */ jsx("th", { scope: "row", children: /* @__PURE__ */ jsx(Avatar, { alt: t("explorer.modal.share.avatar.me.alt"), size: "xs", src: myAvatar, variant: "circle" }) }),
117
+ /* @__PURE__ */ jsx("td", { children: t("share.me") }),
118
+ shareRightActions.map((shareRightAction) => /* @__PURE__ */ jsx("td", { style: {
119
+ width: "80px"
120
+ }, className: "text-center text-white", children: /* @__PURE__ */ jsx(Checkbox, { checked: !0, disabled: !0 }) }, shareRightAction.displayName)),
121
+ /* @__PURE__ */ jsx("td", {})
122
+ ] }),
123
+ /* @__PURE__ */ jsx(ShareBookmarkLine, { showBookmark, shareRightActions, shareRights, onDeleteRow: handleDeleteRow, toggleRight, toggleBookmark })
124
+ ] })
125
+ ] }) }),
126
+ /* @__PURE__ */ jsxs("div", { className: "mt-16", children: [
127
+ /* @__PURE__ */ jsx(Button, { color: "tertiary", leftIcon: /* @__PURE__ */ jsx(SvgIconBookmark, {}), rightIcon: /* @__PURE__ */ jsx(SvgIconRafterDown, { title: t("show"), className: "w-16 min-w-0", style: {
128
+ transition: "rotate 0.2s ease-out",
129
+ rotate: showBookmarkInput ? "-180deg" : "0deg"
130
+ } }), type: "button", variant: "ghost", className: "fw-normal", onClick: () => toggleBookmarkInput(!showBookmarkInput), children: t("share.save.sharebookmark") }),
131
+ showBookmarkInput && /* @__PURE__ */ jsx(ShareBookmark, { refBookmark, bookmark, onBookmarkChange: handleBookmarkChange, onSave: handleOnSaveBookmark })
132
+ ] })
133
+ ] });
134
+ });
135
+ export {
136
+ ShareResources as default
137
+ };
@@ -3,11 +3,12 @@ import { ShareRightWithVisibles, ShareSubject } from '@edifice.io/client';
3
3
  import { OptionListItemType } from '../../../../components';
4
4
  import { ShareOptions } from '../ShareModal';
5
5
  import { ShareAction } from './useShare';
6
- export declare const useSearch: ({ resourceId, resourceCreatorId, shareRights, shareDispatch, }: {
6
+ export declare const useSearch: ({ resourceId, resourceCreatorId, shareRights, shareDispatch, urlResourceRights, }: {
7
7
  resourceId: ShareOptions["resourceCreatorId"];
8
8
  resourceCreatorId: ShareOptions["resourceCreatorId"];
9
9
  shareRights: ShareRightWithVisibles;
10
10
  shareDispatch: Dispatch<ShareAction>;
11
+ urlResourceRights?: string;
11
12
  }) => {
12
13
  state: {
13
14
  searchInputValue: string;
@@ -58,7 +58,8 @@ const defaultActions = [{
58
58
  resourceId,
59
59
  resourceCreatorId,
60
60
  shareRights,
61
- shareDispatch
61
+ shareDispatch,
62
+ urlResourceRights
62
63
  }) => {
63
64
  const [state, dispatch] = useReducer(reducer, initialState), debouncedSearchInputValue = useDebounce(state.searchInputValue, 500), {
64
65
  isAdml
@@ -82,7 +83,7 @@ const defaultActions = [{
82
83
  type: "isSearching",
83
84
  payload: !0
84
85
  }), !isAdml && debouncedSearchInputValue2.length >= 1 || isAdml && debouncedSearchInputValue2.length >= 3) {
85
- const resSearchShareSubjects = await odeServices.share().searchShareSubjects(appCode, resourceId, debouncedSearchInputValue2);
86
+ const resSearchShareSubjects = await odeServices.share().searchShareSubjects(appCode, resourceId, debouncedSearchInputValue2, urlResourceRights);
86
87
  dispatch({
87
88
  type: "addApiResult",
88
89
  payload: resSearchShareSubjects
@@ -1,5 +1,5 @@
1
- import { ShareRight, ShareRightAction, ShareRightActionDisplayName, ShareRightWithVisibles } from '@edifice.io/client';
2
- import { ShareOptions, ShareResourceMutation } from '../ShareModal';
1
+ import { ShareRight, ShareRightAction, ShareRightActionDisplayName, ShareRightWithVisibles, ShareUrls } from '@edifice.io/client';
2
+ import { ShareOptions, ShareResourceMutation } from '../ShareResources';
3
3
  interface UseShareResourceModalProps {
4
4
  /**
5
5
  * Resource ID (assetId)
@@ -15,10 +15,15 @@ interface UseShareResourceModalProps {
15
15
  resourceCreatorId: ShareOptions['resourceCreatorId'];
16
16
  shareResource?: ShareResourceMutation;
17
17
  onSuccess: () => void;
18
- setIsLoading: (value: boolean) => void;
18
+ setIsLoading?: (value: boolean) => void;
19
+ resourceShareRights?: ShareRightWithVisibles;
20
+ resourceShareRightActions?: ShareRightAction[];
21
+ filteredActions?: ShareRightActionDisplayName[];
22
+ shareUrls?: ShareUrls;
19
23
  }
20
24
  type State = {
21
25
  isSharing: boolean;
26
+ isDirty?: boolean;
22
27
  shareRights: ShareRightWithVisibles;
23
28
  shareRightActions: ShareRightAction[];
24
29
  };
@@ -38,9 +43,10 @@ export type ShareAction = {
38
43
  type: 'isSharing';
39
44
  payload: boolean;
40
45
  };
41
- export default function useShare({ resourceId, resourceRights, resourceCreatorId, shareResource, setIsLoading, onSuccess, }: UseShareResourceModalProps): {
46
+ export default function useShare({ resourceId, resourceRights, resourceCreatorId, shareResource, setIsLoading, onSuccess, filteredActions, shareUrls, }: UseShareResourceModalProps): {
42
47
  state: {
43
48
  isSharing: boolean;
49
+ isDirty?: boolean;
44
50
  shareRights: ShareRightWithVisibles;
45
51
  shareRightActions: ShareRightAction[];
46
52
  };
@@ -48,7 +54,8 @@ export default function useShare({ resourceId, resourceRights, resourceCreatorId
48
54
  currentIsAuthor: () => boolean;
49
55
  myAvatar: string;
50
56
  handleDeleteRow: (shareRight: ShareRight) => void;
51
- handleShare: () => Promise<void>;
57
+ handleShare: (notify?: boolean) => Promise<void>;
52
58
  toggleRight: (shareRight: ShareRight, actionName: ShareRightActionDisplayName) => void;
59
+ isDirty: boolean;
53
60
  };
54
61
  export {};