@edifice.io/react 2.2.3-develop-b2school.20250418102516 → 2.2.3-develop-b2school.20250418160001

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.
@@ -25,7 +25,7 @@ export interface ButtonProps extends React.ComponentPropsWithRef<'button'> {
25
25
  /**
26
26
  * Does it has a text ?
27
27
  */
28
- children: ReactNode;
28
+ children?: ReactNode;
29
29
  /**
30
30
  * Display Icon Component to the left
31
31
  */
@@ -19,7 +19,6 @@ const Tree = ({
19
19
  const {
20
20
  selectedNodeId,
21
21
  expandedNodes,
22
- siblingsNodes,
23
22
  handleItemClick,
24
23
  handleFoldUnfold
25
24
  } = useTree({
@@ -31,7 +30,7 @@ const Tree = ({
31
30
  onTreeItemFold,
32
31
  onTreeItemUnfold
33
32
  });
34
- return /* @__PURE__ */ jsx("div", { className: "treeview", children: /* @__PURE__ */ jsx("ul", { role: "tree", className: "m-0 p-0", children: Array.isArray(nodes) ? nodes.map((node) => /* @__PURE__ */ jsx(TreeNode, { node, showIcon, selectedNodeId, expandedNodes, siblingsNodes, onTreeItemClick: handleItemClick, onToggleNode: handleFoldUnfold, renderNode }, node.id)) : /* @__PURE__ */ jsx(TreeNode, { node: nodes, selectedNodeId, expandedNodes, siblingsNodes, showIcon, onTreeItemClick: handleItemClick, onToggleNode: handleFoldUnfold }) }) });
33
+ return /* @__PURE__ */ jsx("div", { className: "treeview", children: /* @__PURE__ */ jsx("ul", { role: "tree", className: "m-0 p-0", children: Array.isArray(nodes) ? nodes.map((node) => /* @__PURE__ */ jsx(TreeNode, { node, showIcon, selectedNodeId, expandedNodes, onTreeItemClick: handleItemClick, onToggleNode: handleFoldUnfold, renderNode }, node.id)) : /* @__PURE__ */ jsx(TreeNode, { node: nodes, selectedNodeId, expandedNodes, showIcon, onTreeItemClick: handleItemClick, onToggleNode: handleFoldUnfold }) }) });
35
34
  }, TreeNode = /* @__PURE__ */ forwardRef(({
36
35
  node,
37
36
  selectedNodeId,
@@ -23,7 +23,6 @@ export declare const useTree: ({ data, externalSelectedNodeId, draggedNode, shou
23
23
  }) => {
24
24
  selectedNodeId: string | null | undefined;
25
25
  expandedNodes: Set<string>;
26
- siblingsNodes: import('react').MutableRefObject<Set<string>>;
27
26
  draggedNodeId: string | undefined;
28
27
  handleItemClick: (nodeId: string) => void;
29
28
  handleFoldUnfold: (nodeId: string) => void;
@@ -1,4 +1,4 @@
1
- import { useState, useRef, useEffect } from "react";
1
+ import { useState, useEffect } from "react";
2
2
  import { findNodeById, findPathById } from "../utilities/tree.js";
3
3
  const useTree = ({
4
4
  data,
@@ -9,33 +9,11 @@ const useTree = ({
9
9
  onTreeItemFold,
10
10
  onTreeItemClick
11
11
  }) => {
12
- const [internalSelectedNodeId, setInternalSelectedNodeId] = useState(void 0), [expandedNodes, setExpandedNodes] = useState(/* @__PURE__ */ new Set()), siblingsNodes = useRef(/* @__PURE__ */ new Set()), [draggedNodeId, setDraggedNodeId] = useState(void 0), selectedNodeId = internalSelectedNodeId ?? externalSelectedNodeId;
13
- function addNodesWithSiblingHavingChildren(data2) {
14
- var _a;
15
- Array.isArray(data2) ? data2.forEach((node) => {
16
- const resultSet = new Set(siblingsNodes.current);
17
- data2.filter(({
18
- id
19
- }) => id !== node.id).some((sibling) => sibling.children && sibling.children.length > 0) && resultSet.add(node.id), node.children && node.children.length > 0 && node.children.forEach((child) => {
20
- var _a2;
21
- const childSiblings = (_a2 = node.children) == null ? void 0 : _a2.filter(({
22
- id
23
- }) => id !== child.id);
24
- (childSiblings == null ? void 0 : childSiblings.some((sibling) => sibling.children && sibling.children.length > 0)) && resultSet.add(child.id), addNodesWithSiblingHavingChildren(child);
25
- });
26
- }) : (_a = data2.children) == null || _a.forEach((child) => {
27
- var _a2;
28
- const resultSet = new Set(siblingsNodes.current), siblings = (_a2 = data2.children) == null ? void 0 : _a2.filter((c) => c.id !== child.id);
29
- (siblings == null ? void 0 : siblings.some((sibling) => sibling.children && sibling.children.length > 0)) && (resultSet.add(child.id), siblingsNodes.current = resultSet), addNodesWithSiblingHavingChildren(child);
30
- });
31
- }
32
- const expandAllNodes = (shouldExpandAllNodes2) => {
12
+ const [internalSelectedNodeId, setInternalSelectedNodeId] = useState(void 0), [expandedNodes, setExpandedNodes] = useState(/* @__PURE__ */ new Set()), [draggedNodeId, setDraggedNodeId] = useState(void 0), selectedNodeId = internalSelectedNodeId ?? externalSelectedNodeId, expandAllNodes = (shouldExpandAllNodes2) => {
33
13
  const initExpandedNodes = new Set("");
34
14
  data && Array.isArray(data) && shouldExpandAllNodes2 && (data.forEach((node) => initExpandedNodes.add(node.id)), setExpandedNodes(initExpandedNodes));
35
15
  };
36
16
  useEffect(() => {
37
- data && addNodesWithSiblingHavingChildren(data);
38
- }, [data]), useEffect(() => {
39
17
  draggedNode != null && draggedNode.isOver && draggedNode.isTreeview ? (draggedNode.overId && handleItemDrag(draggedNode.overId), setDraggedNodeId(draggedNode.overId)) : setDraggedNodeId(void 0);
40
18
  }, [draggedNode]), useEffect(() => {
41
19
  shouldExpandAllNodes && expandAllNodes(shouldExpandAllNodes);
@@ -73,7 +51,6 @@ const useTree = ({
73
51
  return {
74
52
  selectedNodeId,
75
53
  expandedNodes,
76
- siblingsNodes,
77
54
  draggedNodeId,
78
55
  handleItemClick,
79
56
  handleFoldUnfold,
@@ -115,10 +115,6 @@ export interface TreeNodeProps extends ComponentPropsWithRef<'li'>, SharedTreePr
115
115
  * Nodes expanded (opened)
116
116
  */
117
117
  expandedNodes: Set<string>;
118
- /**
119
- * Siblings nodes
120
- */
121
- siblingsNodes?: React.MutableRefObject<Set<string>>;
122
118
  /**
123
119
  * Node is a child
124
120
  */
@@ -24,5 +24,10 @@ declare function useWorkspaceFolders(): {
24
24
  })[];
25
25
  setSearchQuery: import('react').Dispatch<import('react').SetStateAction<string>>;
26
26
  user: IUserInfo | undefined;
27
+ createFolderMutation: import('../../node_modules/@tanstack/react-query').UseMutationResult<any, Error, {
28
+ folderName: string;
29
+ folderParentId?: string;
30
+ }, unknown>;
31
+ isLoading: boolean;
27
32
  };
28
33
  export default useWorkspaceFolders;
@@ -1,5 +1,5 @@
1
1
  import { odeServices } from "@edifice.io/client";
2
- import { useQuery } from "@tanstack/react-query";
2
+ import { useQueryClient, useQuery, useMutation } from "@tanstack/react-query";
3
3
  import { useState, useMemo } from "react";
4
4
  import { useTranslation } from "react-i18next";
5
5
  import { useEdificeClient } from "../../providers/EdificeClientProvider/EdificeClientProvider.hook.js";
@@ -9,16 +9,28 @@ function useWorkspaceFolders() {
9
9
  t
10
10
  } = useTranslation(), {
11
11
  user
12
- } = useEdificeClient(), {
13
- data: ownerWorkspaceData = []
12
+ } = useEdificeClient(), queryClient = useQueryClient(), {
13
+ data: ownerWorkspaceData = [],
14
+ isLoading: isLoadingOwner
14
15
  } = useQuery({
15
- queryKey: ["workspace-owner-folders"],
16
+ queryKey: ["workspace", "folders", "owner"],
16
17
  queryFn: () => odeServices.workspace().listOwnerFolders(!0)
17
18
  }), {
18
- data: sharedWorkspaceData = []
19
+ data: sharedWorkspaceData = [],
20
+ isLoading: isLoadingShared
19
21
  } = useQuery({
20
- queryKey: ["workspace-shared-folders"],
22
+ queryKey: ["workspace", "folders", "shared"],
21
23
  queryFn: () => odeServices.workspace().listSharedFolders(!0)
24
+ }), createFolderMutation = useMutation({
25
+ mutationFn: ({
26
+ folderName,
27
+ folderParentId
28
+ }) => odeServices.workspace().createFolder(folderName, folderParentId),
29
+ onSuccess: () => {
30
+ queryClient.invalidateQueries({
31
+ queryKey: ["workspace", "folders"]
32
+ });
33
+ }
22
34
  }), [searchQuery, setSearchQuery] = useState("");
23
35
  return {
24
36
  folderTree: useMemo(() => {
@@ -37,7 +49,9 @@ function useWorkspaceFolders() {
37
49
  return buildWorkspaceTree(searchQuery ? filterTree(ownerFolders, searchQuery) : ownerFolders, searchQuery ? filterTree(sharedFolders, searchQuery) : sharedFolders);
38
50
  }, [ownerWorkspaceData, sharedWorkspaceData, searchQuery, user]),
39
51
  setSearchQuery,
40
- user
52
+ user,
53
+ createFolderMutation,
54
+ isLoading: isLoadingOwner || isLoadingShared
41
55
  };
42
56
  }
43
57
  const buildTree = (workspaceData, user) => {
@@ -48,7 +62,8 @@ const buildTree = (workspaceData, user) => {
48
62
  id: item._id,
49
63
  name: item.name,
50
64
  children: [],
51
- canCopyFileInto
65
+ canCopyFileInto,
66
+ expandedNodes: ["0576e0dd-129b-4244-b36a-49bda713d273", "50c1b81b-d8b7-4474-9d69-b5e441b31a8c", "a1aac5c0-6bfe-4308-8c43-812378e2d9bf"]
52
67
  });
53
68
  }), workspaceData.forEach((item) => {
54
69
  var _a;
@@ -1,9 +1,13 @@
1
- import { jsxs, jsx } from "react/jsx-runtime";
1
+ import { jsx, Fragment, jsxs } from "react/jsx-runtime";
2
2
  import { useState } from "react";
3
3
  import { useTranslation } from "react-i18next";
4
- import useWorkspaceFolders, { WORKSPACE_OWNER_FOLDER_ID, WORKSPACE_SHARED_FOLDER_ID } from "../../../hooks/useWorkspaceFolders/useWorkspaceFolders.js";
4
+ import SvgIconFolderAdd from "../../icons/components/IconFolderAdd.js";
5
+ import NewFolderForm from "./components/NewFolderForm.js";
6
+ import useWorkspaceFolders, { WORKSPACE_SHARED_FOLDER_ID, WORKSPACE_OWNER_FOLDER_ID } from "../../../hooks/useWorkspaceFolders/useWorkspaceFolders.js";
5
7
  import SearchBar from "../../../components/SearchBar/SearchBar.js";
8
+ import Loading from "../../../components/Loading/Loading.js";
6
9
  import Tree from "../../../components/Tree/components/Tree.js";
10
+ import Button from "../../../components/Button/Button.js";
7
11
  function WorkspaceFolders({
8
12
  onFolderSelected
9
13
  }) {
@@ -11,20 +15,29 @@ function WorkspaceFolders({
11
15
  t
12
16
  } = useTranslation(), {
13
17
  folderTree,
14
- setSearchQuery
15
- } = useWorkspaceFolders(), [shouldExpandAllNodes, setShouldExpandAllNodes] = useState(!1), [searchValue, setSearchValue] = useState(""), handleSearchChange = (e) => {
18
+ setSearchQuery,
19
+ isLoading
20
+ } = useWorkspaceFolders(), [shouldExpandAllNodes, setShouldExpandAllNodes] = useState(!1), [searchValue, setSearchValue] = useState(""), [selectedFolderId, setSelectedFolderId] = useState(void 0), [showNewFolderForm, setShowNewFolderForm] = useState(!1), handleSearchChange = (e) => {
16
21
  setSearchValue(e.target.value);
17
22
  }, handleSearchSubmit = () => {
18
23
  setSearchQuery(searchValue), setShouldExpandAllNodes(searchValue !== "");
19
24
  }, handleFolderSelected = (folderId) => {
20
- const selectedFolderId = folderId === WORKSPACE_OWNER_FOLDER_ID ? "" : folderId, canCopyFileInto = folderId != WORKSPACE_SHARED_FOLDER_ID;
21
- onFolderSelected(selectedFolderId, canCopyFileInto);
25
+ const newSelectedFolderId = folderId === WORKSPACE_OWNER_FOLDER_ID ? "" : folderId, canCopyFileInto = folderId != WORKSPACE_SHARED_FOLDER_ID;
26
+ onFolderSelected(newSelectedFolderId, canCopyFileInto), setSelectedFolderId(newSelectedFolderId);
27
+ }, handleNewFolderClick = () => {
28
+ setShowNewFolderForm(!0);
22
29
  };
23
- return /* @__PURE__ */ jsxs("div", { className: "d-flex flex-column gap-12", children: [
30
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: "d-flex flex-column gap-12", children: [
24
31
  /* @__PURE__ */ jsx("p", { children: t("attachments.add.to.folder.modal.description") }),
25
32
  /* @__PURE__ */ jsx(SearchBar, { onChange: handleSearchChange, isVariant: !1, placeholder: t("search"), onClick: handleSearchSubmit }),
26
- /* @__PURE__ */ jsx("div", { className: "border border-gray-400 rounded", children: /* @__PURE__ */ jsx("div", { className: "p-12", children: /* @__PURE__ */ jsx(Tree, { nodes: folderTree, onTreeItemClick: handleFolderSelected, shouldExpandAllNodes }) }) })
27
- ] });
33
+ /* @__PURE__ */ jsxs("div", { className: "border border-gray-400 rounded", children: [
34
+ /* @__PURE__ */ jsx("div", { className: "p-12", children: isLoading ? /* @__PURE__ */ jsx(Loading, { isLoading: !0, className: "justify-content-center" }) : /* @__PURE__ */ jsx(Tree, { nodes: folderTree, onTreeItemClick: handleFolderSelected, shouldExpandAllNodes }) }),
35
+ /* @__PURE__ */ jsxs("div", { className: "d-flex justify-content-end border-top border-gray-400 px-8 py-4 ", children: [
36
+ !showNewFolderForm && /* @__PURE__ */ jsx(Button, { color: "primary", variant: "ghost", leftIcon: /* @__PURE__ */ jsx(SvgIconFolderAdd, {}), onClick: handleNewFolderClick, disabled: [WORKSPACE_SHARED_FOLDER_ID, void 0].includes(selectedFolderId), children: t("workspace.folder.create") }),
37
+ selectedFolderId != null && showNewFolderForm && /* @__PURE__ */ jsx(NewFolderForm, { onClose: () => setShowNewFolderForm(!1), folderParentId: selectedFolderId })
38
+ ] })
39
+ ] })
40
+ ] }) });
28
41
  }
29
42
  export {
30
43
  WorkspaceFolders as default
@@ -0,0 +1,12 @@
1
+ type Props = {
2
+ /**
3
+ * Function called when the modal is closed
4
+ */
5
+ onClose: () => void;
6
+ /**
7
+ * Parent folder ID where the new folder will be created
8
+ */
9
+ folderParentId: string;
10
+ };
11
+ export default function NewFolderForm({ onClose, folderParentId }: Props): import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -0,0 +1,38 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useRef, useEffect } from "react";
3
+ import { useTranslation } from "react-i18next";
4
+ import SvgIconSave from "../../../icons/components/IconSave.js";
5
+ import useWorkspaceFolders from "../../../../hooks/useWorkspaceFolders/useWorkspaceFolders.js";
6
+ import FormControl from "../../../../components/Form/FormControl.js";
7
+ import Button from "../../../../components/Button/Button.js";
8
+ function NewFolderForm({
9
+ onClose,
10
+ folderParentId
11
+ }) {
12
+ const {
13
+ t
14
+ } = useTranslation(), refInputName = useRef(null), {
15
+ createFolderMutation
16
+ } = useWorkspaceFolders();
17
+ return useEffect(() => {
18
+ refInputName.current && refInputName.current.focus();
19
+ }, []), /* @__PURE__ */ jsx("form", { id: "modalWorkspaceNewFolderForm", onSubmit: async (event) => {
20
+ var _a;
21
+ event.preventDefault();
22
+ const folderName = (_a = refInputName.current) == null ? void 0 : _a.value;
23
+ folderName && createFolderMutation.mutate({
24
+ folderName,
25
+ folderParentId
26
+ }, {
27
+ onSuccess: () => {
28
+ onClose();
29
+ }
30
+ });
31
+ }, children: /* @__PURE__ */ jsxs("div", { className: "d-flex gap-4 flex-row", children: [
32
+ /* @__PURE__ */ jsx(FormControl, { id: "modalWorkspaceNewFolderForm", isRequired: !0, children: /* @__PURE__ */ jsx(FormControl.Input, { ref: refInputName, size: "md", type: "text", placeholder: t("folder.new.name.label") }) }),
33
+ /* @__PURE__ */ jsx(Button, { type: "submit", color: "primary", variant: "ghost", isLoading: createFolderMutation.isPending, leftIcon: /* @__PURE__ */ jsx(SvgIconSave, {}) })
34
+ ] }) });
35
+ }
36
+ export {
37
+ NewFolderForm as default
38
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edifice.io/react",
3
- "version": "2.2.3-develop-b2school.20250418102516",
3
+ "version": "2.2.3-develop-b2school.20250418160001",
4
4
  "description": "Edifice React Library",
5
5
  "keywords": [
6
6
  "react",
@@ -118,9 +118,9 @@
118
118
  "react-slugify": "^3.0.3",
119
119
  "swiper": "^10.1.0",
120
120
  "ua-parser-js": "^1.0.36",
121
- "@edifice.io/bootstrap": "2.2.3-develop-b2school.20250418102516",
122
- "@edifice.io/tiptap-extensions": "2.2.3-develop-b2school.20250418102516",
123
- "@edifice.io/utilities": "2.2.3-develop-b2school.20250418102516"
121
+ "@edifice.io/bootstrap": "2.2.3-develop-b2school.20250418160001",
122
+ "@edifice.io/tiptap-extensions": "2.2.3-develop-b2school.20250418160001",
123
+ "@edifice.io/utilities": "2.2.3-develop-b2school.20250418160001"
124
124
  },
125
125
  "devDependencies": {
126
126
  "@babel/plugin-transform-react-pure-annotations": "^7.23.3",
@@ -151,8 +151,8 @@
151
151
  "vite": "^5.4.11",
152
152
  "vite-plugin-dts": "^4.1.0",
153
153
  "vite-tsconfig-paths": "^5.0.1",
154
- "@edifice.io/client": "2.2.3-develop-b2school.20250418102516",
155
- "@edifice.io/config": "2.2.3-develop-b2school.20250418102516"
154
+ "@edifice.io/client": "2.2.3-develop-b2school.20250418160001",
155
+ "@edifice.io/config": "2.2.3-develop-b2school.20250418160001"
156
156
  },
157
157
  "peerDependencies": {
158
158
  "@react-spring/web": "^9.7.5",