Browse Source

Support Context menu on the tree (#654)

* WIP

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* finish UI part

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* finish style

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* refactor

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* adjust todo context

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* WIP

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* finish context menu

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

---------

Signed-off-by: ryjiang <jiangruiyi@gmail.com>
ryjiang 9 months ago
parent
commit
1605e2986d

+ 15 - 0
client/src/i18n/cn/action.ts

@@ -0,0 +1,15 @@
+const actionTrans = {
+  createCollection: '创建 Collection',
+  dropCollection: '删除 Collection',
+  loadCollection: '加载 Collection',
+  renameCollection: '重命名 Collection',
+  releaseCollection: '释放 Collection',
+  dropDatabase: '删除 Database',
+  createDatabase: '创建 Database',
+  emptyCollection: '清空 Collection',
+  flushCollection: '数据落盘 (Flush)',
+  importFile: '导入文件',
+  insertSampleData: '插入示例数据',
+};
+
+export default actionTrans;

+ 15 - 0
client/src/i18n/en/action.ts

@@ -0,0 +1,15 @@
+const actionTrans = {
+  createCollection: 'Create Collection',
+  dropCollection: 'Drop Collection',
+  loadCollection: 'Load Collection',
+  renameCollection: 'Rename Collection',
+  releaseCollection: 'Release Collection',
+  dropDatabase: 'Drop Database',
+  createDatabase: 'Create Database',
+  emptyCollection: 'Empty Collection',
+  flushCollection: 'Flush Collection',
+  importFile: 'Import File',
+  insertSampleData: 'Insert Sample Data',
+};
+
+export default actionTrans;

+ 4 - 0
client/src/i18n/index.ts

@@ -36,6 +36,8 @@ import prometheusTransEn from './en/prometheus';
 import prometheusTransCn from './cn/prometheus';
 import prometheusTransCn from './cn/prometheus';
 import propertiesEn from './en/properties';
 import propertiesEn from './en/properties';
 import propertiesCn from './cn/properties';
 import propertiesCn from './cn/properties';
+import actionEn from './en/action';
+import actionCn from './cn/action';
 
 
 export const resources = {
 export const resources = {
   'zh-CN': {
   'zh-CN': {
@@ -56,6 +58,7 @@ export const resources = {
     database: databaseTransCn,
     database: databaseTransCn,
     prometheus: prometheusTransCn,
     prometheus: prometheusTransCn,
     properties: propertiesCn,
     properties: propertiesCn,
+    action: actionCn,
   },
   },
   en: {
   en: {
     translation: commonEn,
     translation: commonEn,
@@ -75,6 +78,7 @@ export const resources = {
     database: databaseTransEn,
     database: databaseTransEn,
     prometheus: prometheusTransEn,
     prometheus: prometheusTransEn,
     properties: propertiesEn,
     properties: propertiesEn,
+    action: actionEn,
   },
   },
 };
 };
 
 

+ 0 - 5
client/src/pages/databases/collections/data/CollectionData.tsx

@@ -240,11 +240,6 @@ const CollectionData = (props: CollectionDataProps) => {
             component: (
             component: (
               <EmptyDataDialog
               <EmptyDataDialog
                 cb={async () => {
                 cb={async () => {
-                  openSnackBar(
-                    successTrans('empty', {
-                      name: collectionTrans('collection'),
-                    })
-                  );
                   await onDelete();
                   await onDelete();
                 }}
                 }}
                 collection={collection!}
                 collection={collection!}

+ 221 - 0
client/src/pages/databases/tree/TreeContextMenu.tsx

@@ -0,0 +1,221 @@
+import { useContext } from 'react';
+import { useTranslation } from 'react-i18next';
+import { rootContext, dataContext } from '@/context';
+import CreateCollectionDialog from '@/pages/dialogs/CreateCollectionDialog';
+import LoadCollectionDialog from '@/pages/dialogs/LoadCollectionDialog';
+import ReleaseCollectionDialog from '@/pages/dialogs/ReleaseCollectionDialog';
+import DropCollectionDialog from '@/pages/dialogs/DropCollectionDialog';
+import RenameCollectionDialog from '@/pages/dialogs/RenameCollectionDialog';
+import InsertDialog from '@/pages/dialogs/insert/Dialog';
+import ImportSampleDialog from '@/pages/dialogs/ImportSampleDialog';
+import EmptyDataDialog from '@/pages/dialogs/EmptyDataDialog';
+import { MenuItem, Divider } from '@mui/material';
+import { ContextMenu } from './types';
+import { useStyles } from './style';
+import { CollectionObject } from '@server/types';
+
+export const TreeContextMenu = (props: {
+  onClick: Function;
+  contextMenu: ContextMenu;
+}) => {
+  // hooks
+  const { setDialog } = useContext(rootContext);
+  const { fetchCollection } = useContext(dataContext);
+  const classes = useStyles();
+  // props
+  const { contextMenu, onClick } = props;
+  // i18n
+  const { t: actionTrans } = useTranslation('action');
+
+  // render menu
+  if (!contextMenu) {
+    return null;
+  }
+
+  switch (contextMenu.nodeType) {
+    case 'db':
+      return (
+        <>
+          <MenuItem
+            className={classes.menuItem}
+            onClick={() => {
+              setDialog({
+                open: true,
+                type: 'custom',
+                params: {
+                  component: <CreateCollectionDialog />,
+                },
+              });
+            }}
+          >
+            {actionTrans('createCollection')}
+          </MenuItem>
+          {/* 
+          <MenuItem
+            className={classes.menuItem}
+            disabled={true}
+            onClick={() => handleMenuClick('Delete')}
+          >
+            {actionTrans('dropDatabase')}
+          </MenuItem> */}
+        </>
+      );
+
+    case 'collection':
+      return (
+        <>
+          <MenuItem
+            className={classes.menuItem}
+            onClick={() => {
+              setDialog({
+                open: true,
+                type: 'custom',
+                params: {
+                  component: (
+                    <LoadCollectionDialog
+                      collection={contextMenu.object as CollectionObject}
+                      onLoad={async () => {}}
+                    />
+                  ),
+                },
+              });
+            }}
+          >
+            {actionTrans('loadCollection')}
+          </MenuItem>
+          <MenuItem
+            className={classes.menuItem}
+            onClick={() => {
+              setDialog({
+                open: true,
+                type: 'custom',
+                params: {
+                  component: (
+                    <ReleaseCollectionDialog
+                      collection={contextMenu.object as CollectionObject}
+                      onRelease={async () => {}}
+                    />
+                  ),
+                },
+              });
+            }}
+          >
+            {actionTrans('releaseCollection')}
+          </MenuItem>
+          <MenuItem
+            className={classes.menuItem}
+            onClick={() => {
+              setDialog({
+                open: true,
+                type: 'custom',
+                params: {
+                  component: (
+                    <RenameCollectionDialog
+                      collection={contextMenu.object as CollectionObject}
+                      cb={async () => {}}
+                    />
+                  ),
+                },
+              });
+            }}
+          >
+            {actionTrans('renameCollection')}
+          </MenuItem>
+
+          <MenuItem
+            className={classes.menuItem}
+            onClick={() => {
+              setDialog({
+                open: true,
+                type: 'custom',
+                params: {
+                  component: (
+                    <DropCollectionDialog
+                      collections={[contextMenu.object] as CollectionObject[]}
+                      onDelete={async () => {}}
+                    />
+                  ),
+                },
+              });
+            }}
+          >
+            {actionTrans('dropCollection')}
+          </MenuItem>
+
+          <Divider />
+
+          <MenuItem
+            className={classes.menuItem}
+            onClick={() => {
+              const collection = contextMenu.object as CollectionObject;
+              setDialog({
+                open: true,
+                type: 'custom',
+                params: {
+                  component: (
+                    <InsertDialog
+                      defaultSelectedCollection={collection.collection_name}
+                      // user can't select partition on collection page, so default value is ''
+                      defaultSelectedPartition={''}
+                      collections={[collection!]}
+                      onInsert={async () => {
+                        fetchCollection(collection.collection_name);
+                      }}
+                    />
+                  ),
+                },
+              });
+            }}
+          >
+            {actionTrans('importFile')}
+          </MenuItem>
+
+          <MenuItem
+            className={classes.menuItem}
+            onClick={() => {
+              const collection = contextMenu.object as CollectionObject;
+              setDialog({
+                open: true,
+                type: 'custom',
+                params: {
+                  component: (
+                    <ImportSampleDialog
+                      collection={collection}
+                      cb={async () => {
+                        fetchCollection(collection.collection_name);
+                      }}
+                    />
+                  ),
+                },
+              });
+            }}
+          >
+            {actionTrans('insertSampleData')}
+          </MenuItem>
+
+          <MenuItem
+            className={classes.menuItem}
+            onClick={() => {
+              const collection = contextMenu.object as CollectionObject;
+              setDialog({
+                open: true,
+                type: 'custom',
+                params: {
+                  component: (
+                    <EmptyDataDialog
+                      collection={collection}
+                      cb={async () => {
+                        fetchCollection(collection.collection_name);
+                      }}
+                    />
+                  ),
+                },
+              });
+            }}
+          >
+            {actionTrans('emptyCollection')}
+          </MenuItem>
+        </>
+      );
+  }
+};

+ 119 - 161
client/src/pages/databases/tree/index.tsx

@@ -1,29 +1,21 @@
+import { useState, useEffect } from 'react';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
 import { SimpleTreeView, TreeItem } from '@mui/x-tree-view';
 import { SimpleTreeView, TreeItem } from '@mui/x-tree-view';
 import icons from '@/components/icons/Icons';
 import icons from '@/components/icons/Icons';
-import { Theme, Tooltip, Typography } from '@mui/material';
-import { useNavigate, Params } from 'react-router-dom';
+import { Tooltip, Typography, Grow, Popover } from '@mui/material';
+import { useNavigate } from 'react-router-dom';
 import { CollectionObject } from '@server/types';
 import { CollectionObject } from '@server/types';
 import clcx from 'clsx';
 import clcx from 'clsx';
 import { formatNumber } from '@/utils';
 import { formatNumber } from '@/utils';
-import { makeStyles } from '@mui/styles';
-
-export type TreeNodeType = 'db' | 'collection' | 'partition' | 'segment';
-
-export interface DatabaseTreeItem {
-  children?: DatabaseTreeItem[];
-  id: string;
-  name: string;
-  type: TreeNodeType;
-  expanded?: boolean;
-  data?: CollectionObject;
-}
-
-interface DatabaseToolProps {
-  database: string;
-  collections: CollectionObject[];
-  params: Readonly<Params<string>>;
-}
+import { useStyles } from './style';
+import {
+  DatabaseTreeItem,
+  TreeNodeType,
+  DatabaseToolProps,
+  ContextMenu,
+  TreeNodeObject,
+} from './types';
+import { TreeContextMenu } from './TreeContextMenu';
 
 
 // get expanded nodes from data
 // get expanded nodes from data
 const getExpanded = (nodes: DatabaseTreeItem[]) => {
 const getExpanded = (nodes: DatabaseTreeItem[]) => {
@@ -39,107 +31,6 @@ const getExpanded = (nodes: DatabaseTreeItem[]) => {
   return expanded;
   return expanded;
 };
 };
 
 
-const useStyles = makeStyles((theme: Theme) => ({
-  root: {
-    fontSize: '15px',
-    color: theme.palette.text.primary,
-    backgroundColor: theme.palette.background.default,
-    '& .MuiTreeItem-iconContainer': {
-      width: 'auto',
-    },
-    '& .MuiTreeItem-group': {
-      marginLeft: 0,
-      '& .MuiTreeItem-content': {
-        padding: '0 0 0 8px',
-      },
-    },
-    '& .MuiTreeItem-label:hover': {
-      backgroundColor: 'none',
-    },
-    '& .MuiTreeItem-content': {
-      width: 'auto',
-      padding: '0',
-
-      '&:hover': {
-        backgroundColor: 'rgba(10, 206, 130, 0.08)',
-      },
-      '& .MuiTreeItem-label': {
-        background: 'none',
-      },
-    },
-    '& .Mui-selected': {
-      '& > .MuiTreeItem-content': {
-        backgroundColor: 'rgba(10, 206, 130, 0.08)',
-
-        '& .MuiTreeItem-label': {
-          background: 'none',
-        },
-      },
-      '&:focus': {
-        '& .MuiTreeItem-content': {
-          '& .MuiTreeItem-label': {
-            background: 'none',
-          },
-        },
-      },
-    },
-  },
-  treeItem: {
-    '& .MuiTreeItem-iconContainer': {
-      color: '#888',
-    },
-  },
-  collectionNode: {
-    minHeight: '24px',
-    lineHeight: '24px',
-    position: 'relative',
-  },
-  collectionName: {
-    display: 'flex',
-    alignItems: 'center',
-    width: 'calc(100% - 45px)',
-    '& .collectionName': {
-      minWidth: 36,
-    },
-  },
-  dbName: {
-    width: 'calc(100% - 30px)',
-  },
-  count: {
-    fontSize: '13px',
-    fontWeight: 500,
-    marginLeft: theme.spacing(0.5),
-    color: theme.palette.text.secondary,
-    pointerEvents: 'none',
-  },
-  dot: {
-    width: '8px',
-    height: '8px',
-    borderRadius: '50%',
-    position: 'absolute',
-    left: 160,
-    top: 8,
-    zIndex: 1,
-    pointerEvents: 'none',
-  },
-  loaded: {
-    border: `1px solid ${theme.palette.primary.main}`,
-    backgroundColor: theme.palette.primary.main,
-  },
-  unloaded: {
-    border: `1px solid ${theme.palette.primary.main}`,
-    background: '#fff !important',
-  },
-  loading: {
-    border: `1px solid ${theme.palette.primary.light}`,
-    backgroundColor: `${theme.palette.primary.light} !important`,
-  },
-  noIndex: {
-    border: `1px solid ${theme.palette.text.disabled}`,
-    backgroundColor: theme.palette.text.disabled,
-  },
-}));
-
 const CollectionNode: React.FC<{ data: CollectionObject }> = ({ data }) => {
 const CollectionNode: React.FC<{ data: CollectionObject }> = ({ data }) => {
   // i18n collectionTrans
   // i18n collectionTrans
   const { t: commonTrans } = useTranslation();
   const { t: commonTrans } = useTranslation();
@@ -184,6 +75,8 @@ const CollectionNode: React.FC<{ data: CollectionObject }> = ({ data }) => {
 };
 };
 
 
 const DatabaseTree: React.FC<DatabaseToolProps> = props => {
 const DatabaseTree: React.FC<DatabaseToolProps> = props => {
+  // state
+  const [contextMenu, setContextMenu] = useState<ContextMenu | null>(null);
   // props
   // props
   const { database, collections, params } = props;
   const { database, collections, params } = props;
 
 
@@ -223,6 +116,31 @@ const DatabaseTree: React.FC<DatabaseToolProps> = props => {
             params.collectionPage || 'overview'
             params.collectionPage || 'overview'
           }`
           }`
     );
     );
+    // close context menu
+    setContextMenu(null);
+  };
+
+  const handleContextMenu = (
+    event: any,
+    nodeId: string,
+    nodeType: string,
+    object: TreeNodeObject
+  ) => {
+    // prevent default
+    event.preventDefault();
+    event.stopPropagation();
+
+    setContextMenu({
+      mouseX: event.clientX - 2,
+      mouseY: event.clientY - 4,
+      nodeId,
+      nodeType: nodeType as TreeNodeType,
+      object: object,
+    });
+  };
+
+  const handleClose = () => {
+    setContextMenu(null);
   };
   };
 
 
   // render children
   // render children
@@ -237,7 +155,9 @@ const DatabaseTree: React.FC<DatabaseToolProps> = props => {
               icon: CollectionIcon,
               icon: CollectionIcon,
             }}
             }}
             label={node.name}
             label={node.name}
-            className={classes.treeItem}
+            className={clcx(classes.treeItem, {
+              ['right-selected-on']: contextMenu?.nodeId === node.id,
+            })}
             onClick={(event: any) => {
             onClick={(event: any) => {
               event.stopPropagation();
               event.stopPropagation();
               if (onNodeClick) {
               if (onNodeClick) {
@@ -258,7 +178,12 @@ const DatabaseTree: React.FC<DatabaseToolProps> = props => {
             icon: CollectionIcon,
             icon: CollectionIcon,
           }}
           }}
           label={<CollectionNode data={node.data!} />}
           label={<CollectionNode data={node.data!} />}
-          className={classes.treeItem}
+          onContextMenu={event =>
+            handleContextMenu(event, node.id, node.type, node.data!)
+          }
+          className={clcx(classes.treeItem, {
+            ['right-selected-on']: contextMenu?.nodeId === node.id,
+          })}
           onClick={(event: any) => {
           onClick={(event: any) => {
             event.stopPropagation();
             event.stopPropagation();
             if (onNodeClick) {
             if (onNodeClick) {
@@ -270,46 +195,79 @@ const DatabaseTree: React.FC<DatabaseToolProps> = props => {
     });
     });
   };
   };
 
 
+  // useEffect
+  useEffect(() => {
+    // register click event on document, close context menu if click outside
+    document.addEventListener('click', handleClose);
+
+    return () => {
+      document.removeEventListener('click', handleClose);
+    };
+  }, []);
+
   return (
   return (
-    <SimpleTreeView
-      expandedItems={[database]}
-      multiSelect={false}
-      disableSelection={false}
-      selectedItems={
-        params.collectionName
-          ? `c_${params.collectionName}`
-          : params.databaseName
-      }
-      className={classes.root}
-    >
-      {
-        <TreeItem
-          key={tree.id}
-          itemId={tree.id}
-          label={
-            <Tooltip title={tree.name}>
-              <Typography noWrap className={classes.dbName}>
-                {tree.name}
-              </Typography>
-            </Tooltip>
-          }
-          className={classes.treeItem}
-          slots={{
-            icon: DatabaseIcon,
-          }}
-          onClick={(event: any) => {
-            event.stopPropagation();
-            if (onNodeClick) {
-              onNodeClick(tree);
+    <>
+      <SimpleTreeView
+        expandedItems={[database]}
+        multiSelect={false}
+        disableSelection={false}
+        selectedItems={
+          params.collectionName
+            ? `c_${params.collectionName}`
+            : params.databaseName
+        }
+        className={classes.root}
+      >
+        {
+          <TreeItem
+            key={tree.id}
+            itemId={tree.id}
+            label={
+              <Tooltip title={tree.name}>
+                <Typography noWrap className={classes.dbName}>
+                  {tree.name}
+                </Typography>
+              </Tooltip>
             }
             }
-          }}
-        >
-          {tree.children && tree.children.length > 0
-            ? renderTree(tree.children)
-            : [<div key="stub" />]}
-        </TreeItem>
-      }
-    </SimpleTreeView>
+            className={classes.treeItem}
+            slots={{
+              icon: DatabaseIcon,
+            }}
+            onClick={(event: any) => {
+              event.stopPropagation();
+              if (onNodeClick) {
+                onNodeClick(tree);
+              }
+            }}
+            onContextMenu={event =>
+              handleContextMenu(event, tree.id, tree.type, null)
+            }
+          >
+            {tree.children && tree.children.length > 0
+              ? renderTree(tree.children)
+              : [<div key="stub" />]}
+          </TreeItem>
+        }
+      </SimpleTreeView>
+      <Popover
+        open={Boolean(contextMenu)}
+        onClose={handleClose}
+        anchorReference="anchorPosition"
+        anchorPosition={
+          contextMenu !== null
+            ? { top: contextMenu.mouseY, left: contextMenu.mouseX }
+            : undefined
+        }
+        TransitionComponent={Grow}
+        transitionDuration={0}
+        sx={{ pointerEvents: 'none' }}
+        PaperProps={{
+          sx: { pointerEvents: 'auto', boxShadow: 4, borderRadius: 2 },
+        }}
+      >
+        <TreeContextMenu onClick={handleClose} contextMenu={contextMenu!} />
+      </Popover>
+    </>
   );
   );
 };
 };
 
 

+ 108 - 0
client/src/pages/databases/tree/style.ts

@@ -0,0 +1,108 @@
+import { makeStyles } from '@mui/styles';
+import { Theme } from '@mui/material';
+
+export const useStyles = makeStyles((theme: Theme) => ({
+  root: {
+    fontSize: '15px',
+    color: theme.palette.text.primary,
+    backgroundColor: theme.palette.background.default,
+    '& .MuiTreeItem-iconContainer': {
+      width: 'auto',
+    },
+    '& .MuiTreeItem-group': {
+      marginLeft: 0,
+      '& .MuiTreeItem-content': {
+        padding: '0 0 0 8px',
+      },
+    },
+    '& .MuiTreeItem-label:hover': {
+      backgroundColor: 'none',
+    },
+    '& .MuiTreeItem-content': {
+      width: 'auto',
+      padding: '0',
+      '&.Mui-focused': {
+        backgroundColor: 'rgba(10, 206, 130, 0.08)',
+      },
+      '&.Mui-selected': {
+        backgroundColor: 'rgba(10, 206, 130, 0.28)',
+      },
+      '&.Mui-focused.Mui-selected': {
+        backgroundColor: 'rgba(10, 206, 130, 0.28) !important',
+      },
+
+      '&:hover': {
+        backgroundColor: 'rgba(10, 206, 130, 0.08)',
+      },
+      '& .MuiTreeItem-label': {
+        background: 'none',
+      },
+    },
+  },
+  treeItem: {
+    '& .MuiTreeItem-iconContainer': {
+      color: '#666',
+    },
+    '& .right-selected-on': {
+      '& .MuiTreeItem-content': {
+        backgroundColor: 'rgba(10, 206, 130, 0.08)',
+        '&.Mui-selected': {
+          backgroundColor: 'rgba(10, 206, 130, 0.28) !important',
+        },
+      },
+    },
+  },
+  collectionNode: {
+    minHeight: '24px',
+    lineHeight: '24px',
+    position: 'relative',
+  },
+  collectionName: {
+    display: 'flex',
+    alignItems: 'center',
+    width: 'calc(100% - 45px)',
+    '& .collectionName': {
+      minWidth: 36,
+    },
+  },
+  dbName: {
+    width: 'calc(100% - 30px)',
+  },
+  count: {
+    fontSize: '13px',
+    fontWeight: 500,
+    marginLeft: theme.spacing(0.5),
+    color: theme.palette.text.secondary,
+    pointerEvents: 'none',
+  },
+  dot: {
+    width: '8px',
+    height: '8px',
+    borderRadius: '50%',
+    position: 'absolute',
+    left: 160,
+    top: 8,
+    zIndex: 1,
+    pointerEvents: 'none',
+  },
+  loaded: {
+    border: `1px solid ${theme.palette.primary.main}`,
+    backgroundColor: theme.palette.primary.main,
+  },
+  unloaded: {
+    border: `1px solid ${theme.palette.primary.main}`,
+    background: '#fff !important',
+  },
+  loading: {
+    border: `1px solid ${theme.palette.primary.light}`,
+    backgroundColor: `${theme.palette.primary.light} !important`,
+  },
+  noIndex: {
+    border: `1px solid ${theme.palette.text.disabled}`,
+    backgroundColor: theme.palette.text.disabled,
+  },
+  menuItem: {
+    fontSize: '14px',
+    boderBottom: `1px solid ${theme.palette.divider}`,
+  },
+}));

+ 28 - 0
client/src/pages/databases/tree/types.ts

@@ -0,0 +1,28 @@
+import { CollectionObject, DatabaseObject } from '@server/types';
+import { Params } from 'react-router-dom';
+
+export type TreeNodeType = 'db' | 'collection' | 'partition' | 'segment';
+export type TreeNodeObject = CollectionObject | DatabaseObject | null;
+
+export interface DatabaseTreeItem {
+  children?: DatabaseTreeItem[];
+  id: string;
+  name: string;
+  type: TreeNodeType;
+  expanded?: boolean;
+  data?: CollectionObject;
+}
+
+export interface DatabaseToolProps {
+  database: string;
+  collections: CollectionObject[];
+  params: Readonly<Params<string>>;
+}
+
+export type ContextMenu = {
+  mouseX: number; // x position
+  mouseY: number; // y position
+  nodeId: string | null; // node id
+  nodeType: TreeNodeType; // node type
+  object: TreeNodeObject; // object
+};

+ 8 - 0
client/src/pages/dialogs/EmptyDataDialog.tsx

@@ -12,15 +12,23 @@ export interface EmptyDataProps {
 
 
 const EmptyDataDialog: FC<EmptyDataProps> = props => {
 const EmptyDataDialog: FC<EmptyDataProps> = props => {
   const { cb, collection } = props;
   const { cb, collection } = props;
+  // UI functions
+  const { openSnackBar } = useContext(rootContext);
 
 
   const { handleCloseDialog } = useContext(rootContext);
   const { handleCloseDialog } = useContext(rootContext);
   const { t: dialogTrans } = useTranslation('dialog');
   const { t: dialogTrans } = useTranslation('dialog');
   const { t: collectionTrans } = useTranslation('collection');
   const { t: collectionTrans } = useTranslation('collection');
   const { t: btnTrans } = useTranslation('btn');
   const { t: btnTrans } = useTranslation('btn');
+  const { t: successTrans } = useTranslation('success');
 
 
   const handleDelete = async () => {
   const handleDelete = async () => {
     // duplicate
     // duplicate
     await DataService.emptyData(collection.collection_name);
     await DataService.emptyData(collection.collection_name);
+    openSnackBar(
+      successTrans('empty', {
+        name: collectionTrans('collection'),
+      })
+    );
     // close dialog
     // close dialog
     handleCloseDialog();
     handleCloseDialog();
     cb && cb();
     cb && cb();