Skip to content

Commit

Permalink
Merge pull request #2876 from glific/manage-docs
Browse files Browse the repository at this point in the history
Feature: Managing knowledge base documents
  • Loading branch information
mdshamoon authored Apr 26, 2024
2 parents 2fb9bec + 6465c2a commit 28af743
Show file tree
Hide file tree
Showing 19 changed files with 906 additions and 19 deletions.
17 changes: 17 additions & 0 deletions src/assets/images/icons/SideDrawer/KnowledgeBaseIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const SvgComponent = ({ color }: { color: string }) => (
<svg
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
width="18"
height="18"
viewBox="0,0,256,256"
>
<g fill={color}>
<g transform="scale(9.84615,9.84615)">
<path d="M7,0c-2.20312,0 -4,1.79688 -4,4v18c0,2.20313 1.79688,4 4,4h12c2.20313,0 4,-1.79687 4,-4v-14c0,-1.0625 -0.97266,-2.07031 -2.71875,-3.78125c-0.24219,-0.23828 -0.50391,-0.50391 -0.75,-0.75c-0.24609,-0.24609 -0.51172,-0.47656 -0.75,-0.71875c-1.71094,-1.74609 -2.71875,-2.75 -3.78125,-2.75zM7,2h7.28125c0.72266,0.18359 0.71875,1.05078 0.71875,1.9375v3.0625c0,0.55078 0.44922,1 1,1h3c0.99609,0 2,0.00391 2,1v13c0,1.10547 -0.89453,2 -2,2h-12c-1.10547,0 -2,-0.89453 -2,-2v-18c0,-1.10547 0.89453,-2 2,-2zM7.8125,10c-0.55078,0.05078 -0.95703,0.54297 -0.90625,1.09375c0.05078,0.55078 0.54297,0.95703 1.09375,0.90625h10c0.35938,0.00391 0.69531,-0.18359 0.87891,-0.49609c0.17969,-0.3125 0.17969,-0.69531 0,-1.00781c-0.18359,-0.3125 -0.51953,-0.5 -0.87891,-0.49609h-10c-0.03125,0 -0.0625,0 -0.09375,0c-0.03125,0 -0.0625,0 -0.09375,0zM7.8125,14c-0.55078,0.05078 -0.95703,0.54297 -0.90625,1.09375c0.05078,0.55078 0.54297,0.95703 1.09375,0.90625h8c0.35938,0.00391 0.69531,-0.18359 0.87891,-0.49609c0.17969,-0.3125 0.17969,-0.69531 0,-1.00781c-0.18359,-0.3125 -0.51953,-0.5 -0.87891,-0.49609h-8c-0.03125,0 -0.0625,0 -0.09375,0c-0.03125,0 -0.0625,0 -0.09375,0zM7.8125,18c-0.55078,0.05078 -0.95703,0.54297 -0.90625,1.09375c0.05078,0.55078 0.54297,0.95703 1.09375,0.90625h10c0.35938,0.00391 0.69531,-0.18359 0.87891,-0.49609c0.17969,-0.3125 0.17969,-0.69531 0,-1.00781c-0.18359,-0.3125 -0.51953,-0.5 -0.87891,-0.49609h-10c-0.03125,0 -0.0625,0 -0.09375,0c-0.03125,0 -0.0625,0 -0.09375,0z"></path>
</g>
</g>
</svg>
);
export default SvgComponent;
8 changes: 8 additions & 0 deletions src/assets/images/icons/UploadIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/components/UI/ListIcon/ListIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import ConsultingIcon from 'assets/images/icons/SideDrawer/ConsultingIcon';
import WaChatIcon from 'assets/images/icons/SideDrawer/WaGroupChat';
import WaCollectionIcon from 'assets/images/icons/SideDrawer/WaGroupCollection';
import WaGroupIcon from 'assets/images/icons/SideDrawer/WhatsAppGroupIcon';
import KnowledgeBaseIcon from 'assets/images/icons/SideDrawer/KnowledgeBaseIcon';
import styles from './ListIcon.module.css';
import FiberNewIcon from '@mui/icons-material/FiberNew';
import { Badge } from '@mui/material';
Expand Down Expand Up @@ -71,6 +72,7 @@ export const ListIcon = ({ icon = '', selected = false, count }: ListIconProps)
waGroupCollection: WaCollectionIcon,
waGroupChat: WaChatIcon,
waGroup: WaGroupIcon,
knowledgeBase: KnowledgeBaseIcon,
};

const iconImage = stringsToIcons[icon] && (
Expand Down
14 changes: 13 additions & 1 deletion src/components/UI/Pager/Pager.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@
align-items: center;
}

.BodyFull {
height: 100%;
}

.RowStyle {
padding: 15px 20px 15px 25px;
}
Expand All @@ -97,13 +101,21 @@
}

.StyleForContainer {
height: calc(100% - 50px);
background: #fff;
overflow-y: scroll;
scrollbar-width: none;
border-radius: 10px 10px 0 0;
}

.HeightFull {
height: 100%;
border-radius: 10px;
}

.HeightShort {
height: calc(100% - 50px);
}

.Skeleton {
margin: 10px;
}
16 changes: 11 additions & 5 deletions src/components/UI/Pager/Pager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ interface PagerProps {
loadingList?: boolean;
collapseRow: string | undefined;
noItemsText?: any;
showPagination?: boolean;
}

// TODO: cleanup the translations code
Expand Down Expand Up @@ -191,14 +192,17 @@ export const Pager = ({
collapseRow,
loadingList = false,
noItemsText,
showPagination = true,
}: PagerProps) => {
const rows = createRows(data, columnStyles, collapseRow, collapseOpen);
const tableHead = tableHeadColumns(columnNames, columnStyles, tableVals, handleTableChange);
const tablePagination = pagination(columnNames, totalRows, handleTableChange, tableVals);

return (
<div className={styles.TableContainer}>
<TableContainer className={styles.StyleForContainer}>
<TableContainer
className={`${styles.StyleForContainer} ${!showPagination ? styles.HeightFull : styles.HeightShort}`}
>
<Table stickyHeader aria-label="sticky table" data-testid="table">
<TableHead data-testid="tableHead">{tableHead}</TableHead>
<TableBody data-testid="tableBody">{!loadingList && data.length > 0 && rows}</TableBody>
Expand All @@ -216,11 +220,13 @@ export const Pager = ({
))}
</div>
)}
{!loadingList && data.length == 0 && <div className={styles.Body}>{noItemsText}</div>}
{!loadingList && data.length == 0 && <div className={`${styles.Body} `}>{noItemsText}</div>}
</TableContainer>
<div className={styles.TableFooter} data-testid="tableFooter">
<div>{tablePagination}</div>
</div>
{showPagination && (
<div className={styles.TableFooter} data-testid="tableFooter">
<div>{tablePagination}</div>
</div>
)}
</div>
);
};
Expand Down
8 changes: 8 additions & 0 deletions src/config/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,14 @@ const menus = (): Menu[] => [
icon: 'consulting',
roles: ['Glific_admin'],
},
{
title: 'Knowledge base',
path: '/knowledge-base',
type: 'sideDrawer',
icon: 'knowledgeBase',
roles: allRoles,
show: !getOrganizationServices('llm4devEnabled'),
},
],
},

Expand Down
177 changes: 177 additions & 0 deletions src/containers/KnowledgeBase/KnowledgeBase.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { List } from 'containers/List/List';
import { useTranslation } from 'react-i18next';
import CollectionIcon from 'assets/images/icons/Collection/Dark.svg?react';
import DeleteIcon from 'assets/images/icons/Delete/Red.svg?react';
import CopyIcon from 'assets/images/icons/Flow/Copy.svg?react';
import { GET_KNOWLEDGE_BASE } from 'graphql/queries/KnowledgeBase';
import styles from './Knowledgebase.module.css';
import { useState } from 'react';
import { DialogBox } from 'components/UI/DialogBox/DialogBox';
import { UploadFile } from 'containers/KnowledgeBase/UploadFile/UploadFile';
import { copyToClipboard } from 'common/utils';
import { useMutation } from '@apollo/client';
import { DELETE_KNOWLEDGE_BASE, UPLOAD_KNOWLEDGE_BASE } from 'graphql/mutations/KnowledgeBase';
import { setNotification } from 'common/notification';

export const KnowledgeBase = () => {
const queries = {
filterItemsQuery: GET_KNOWLEDGE_BASE,
deleteItemQuery: DELETE_KNOWLEDGE_BASE,
};

const [dialogOpen, setDialogOpen] = useState(false);
const [deleteItemId, setDeleteItemID] = useState<string | null>(null);
const [file, setFile] = useState<null | string>(null);
const [category, setCategory] = useState<null | string>(null);
const [uploading, setUploading] = useState(false);

const { t } = useTranslation();

const [uploadMedia] = useMutation(UPLOAD_KNOWLEDGE_BASE, {
onCompleted: (data: any) => {
setNotification('Successfully uploaded the file!', 'success');
handleClose();
},
onError: () => {
setFile(null);
setUploading(false);
setNotification(t('An error occured while uploading the file'), 'warning');
},
});

const [deleteKnowledgeBase, { loading: deleteLoading }] = useMutation(DELETE_KNOWLEDGE_BASE, {
onCompleted: (data: any) => {
setNotification('Successfully deleted the knowledge base!', 'success');
setDeleteItemID(null);
},
onError: () => {
setNotification('An error occured while deleteing the knowledge base.', 'warning');
setDeleteItemID(null);
},
});

const getLabel = (label: string) => <div className={styles.Label}>{label}</div>;
const getId = (category: any) => (
<div className={styles.ID}>
<div className={styles.IdContainer}>
<span>{category?.id}</span>
<div onClick={() => copyToClipboard(category.id)}>
<CopyIcon data-testid="copy-icon" className={styles.CopyIcon} />
</div>
</div>
</div>
);
const getCategory = (category: any) => <div className={styles.Category}>{category?.name}</div>;

const getColumns = ({ name, category, id }: any) => {
return {
title: getLabel(name),
category: getCategory(category),
uuid: getId(category),
};
};

const columnAttributes = {
columns: getColumns,
columnStyles: [styles.Label, styles.Category, styles.ID, styles.Actions],
};
const collectionIcon = <CollectionIcon />;

const uploadFile = async () => {
if (file && category) {
setUploading(true);
await uploadMedia({
variables: {
categoryId: category,
media: file,
},
});
}
};

const handleClose = () => {
setFile(null);
setCategory(null);
setDialogOpen(false);
setUploading(false);
};

const handleDelete = () => {
deleteKnowledgeBase({
variables: {
uuid: deleteItemId,
},
});
};

const dialog = (
<DialogBox
title={'Upload Document'}
handleCancel={handleClose}
handleOk={uploadFile}
buttonOk={t('Upload')}
buttonOkLoading={uploading}
alignButtons="center"
>
<div className={styles.DialogBox} data-testid="upload-dialog">
<UploadFile file={file} setCategory={setCategory} category={category} setFile={setFile} />
</div>
</DialogBox>
);

const Deletedialog = (
<DialogBox
title={'Do you want to delete this knowledge base?'}
handleOk={handleDelete}
handleCancel={() => setDeleteItemID(null)}
alignButtons="center"
buttonOkLoading={deleteLoading}
>
<p data-testid="delete-dialog" className={styles.DialogText}>
{'This knowledge base will be deleted permanently.'}
</p>
</DialogBox>
);

const additionalAction = () => [
{
label: t('Delete'),
icon: <DeleteIcon data-testid="delete-icon" />,
parameter: 'id',
dialog: (id: any) => setDeleteItemID(id),
insideMore: false,
},
];

const restrictedAction = () => ({ delete: false, edit: false });

return (
<>
<List
title={'Knowledge base'}
listItem="knowledgeBases"
columnNames={[
{ label: t('Title') },
{ label: t('Category') },
{ label: 'Category ID' },
{ label: t('Actions') },
]}
listItemName="knowledgeBases"
button={{ show: true, label: 'Upload', action: () => setDialogOpen(true) }}
filters={{}}
pageLink={`knowledge-base`}
additionalAction={additionalAction}
listIcon={collectionIcon}
editSupport={false}
showSearch={false}
restrictedAction={restrictedAction}
{...queries}
{...columnAttributes}
/>
{dialogOpen && dialog}
{deleteItemId !== null && Deletedialog}
</>
);
};

export default KnowledgeBase;
54 changes: 54 additions & 0 deletions src/containers/KnowledgeBase/Knowledgebase.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.ID {
color: #555;
font-size: 13px;
font-weight: 500;
width: 14%;
min-width: 200px;
}

.IdContainer {
display: flex;
align-items: flex-start;
column-gap: 0.5rem;
}

.Actions {
width: 15%;
min-width: 200px;
text-align: end;
color: #555;
font-size: 13px;
font-weight: 500;
margin-bottom: 6px;
}

.Label,
.Category {
color: #555;
font-size: 13px;
font-weight: 500;
margin-bottom: 6px;
width: 40%;
min-width: 200px;
}

.CopyIcon {
color: #555;
width: 1rem;
height: 1rem;
cursor: pointer;
}

.DialogBox {
display: flex;
/* align-items: center; */
justify-content: center;
width: 100%;
}

.DialogText {
margin-top: 0px;
text-align: center;
font-size: 14px;
color: #073f24;
}
Loading

0 comments on commit 28af743

Please sign in to comment.