Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import Modal from "@/src/components/shared/modal/Modal";
import { selectModal } from "@/src/reduxStore/states/modal";
import { selectKnowledgeGraphsAll } from "@/src/reduxStore/states/pages/knowledge-graphs";
import { selectProjectId } from "@/src/reduxStore/states/project";
import { deleteKnowledgeGraphById } from "@/src/services/base/knowledge-graphs";
import { DeleteKnowledgeGraphModalProps } from "@/src/types/components/projects/projectId/knowledge-graphs/knowledge-graphs";
import { ModalButton, ModalEnum } from "@/src/types/shared/modal";
import { useCallback, useEffect, useState } from "react";
import { useSelector } from "react-redux";

const ABORT_BUTTON = { buttonCaption: "Delete", useButton: true, disabled: false };

export default function DeleteKnowledgeGraphModal(props: DeleteKnowledgeGraphModalProps) {
const projectId = useSelector(selectProjectId);
const modalDelete = useSelector(selectModal(ModalEnum.DELETE_KNOWLEDGE_GRAPH));
const knowledgeGraphs = useSelector(selectKnowledgeGraphsAll);

const [abortButton, setAbortButton] = useState<ModalButton>(ABORT_BUTTON);

const deleteKnowledgeGraphs = useCallback(() => {
knowledgeGraphs.forEach((knowledgeGraph) => {
if (knowledgeGraph.selected) {
deleteKnowledgeGraphById(projectId, knowledgeGraph.id, (res) => {
props.refetch();
})
}
});
}, [modalDelete]);

useEffect(() => {
setAbortButton({ ...ABORT_BUTTON, emitFunction: deleteKnowledgeGraphs });
}, [modalDelete]);

return (<Modal modalName={ModalEnum.DELETE_KNOWLEDGE_GRAPH} abortButton={abortButton}>
<h1 className="text-lg text-gray-900 mb-2">Warning</h1>
<div className="text-sm text-gray-500 my-2 flex flex-col">
<span>Are you sure you want to delete selected {props.countSelected <= 1 ? 'knowledge graph' : 'knowledge graphs'}?</span>
<span>Currently selected {props.countSelected <= 1 ? 'is' : 'are'}:</span>
<span className="whitespace-pre-line font-semibold">{props.selectionList}</span>
</div>
</Modal>)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useSelector } from "react-redux";
import { KnowledgeGraph } from "@/src/types/components/projects/projectId/knowledge-graphs/knowledge-graphs";
import { selectKnowledgeGraphsAll } from "@/src/reduxStore/states/pages/knowledge-graphs";

export default function KnowledgeGraphsGridCards() {
const knowledgeGraphs = useSelector(selectKnowledgeGraphsAll);
return (<>
{knowledgeGraphs.map((knowledgeGraph: KnowledgeGraph, index: number) => (<div key={knowledgeGraph.id}>
<div className="relative flex space-x-3 items-center rounded-lg border border-gray-300 bg-white px-6 py-5 shadow-sm hover:border-gray-400">
<div className="h-full flex flex-col gap-2 items-center self-start">
{/* TODO: add data */}
</div>

<div className="flex-1 min-w-0 text-sm leading-5">
<div className="flow-root font-medium">
<div className="text-gray-900 float-left"> {knowledgeGraph.name}</div>
</div>
<div className="flow-root font-normal">
<div className="text-gray-500 float-left line-clamp-3" style={{ maxWidth: '250px' }}>
{knowledgeGraph.description}
</div>
</div>
</div>
</div>
</div >))
}
</ >);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { openModal, selectModal } from '@/src/reduxStore/states/modal';
import style from '@/src/styles/components/projects/projectId/heuristics/heuristics.module.css';
import { ModalEnum } from '@/src/types/shared/modal';
import { TOOLTIPS_DICT } from '@/src/util/tooltip-constants';
import { Tooltip } from '@nextui-org/react';
import { useCallback, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import KernDropdown from '@/submodules/react-components/components/KernDropdown';
import KernButton from "@/submodules/react-components/components/kern-button/KernButton";
import { ChevronDownIcon } from "@heroicons/react/20/solid";
import DeleteKnowledgeGraphModal from './DeleteKnowledgeGraphModal';
import { KnowledgeGraphsHeaderProps, KnowledgeGraphType } from '@/src/types/components/projects/projectId/knowledge-graphs/knowledge-graphs';
import { selectKnowledgeGraphsAll, setKnowledgeGraphType } from '@/src/reduxStore/states/pages/knowledge-graphs';

const KNOWLEDGE_GRAPHS_TYPES = Object.values(KnowledgeGraphType);
const ACTIONS_DROPDOWN_OPTIONS = ['Select all', 'Deselect all', 'Delete selected'];

export default function KnowledgeGraphsHeader(props: KnowledgeGraphsHeaderProps) {
const dispatch = useDispatch();

const knowledgeGraphs = useSelector(selectKnowledgeGraphsAll);
const modalDelete = useSelector(selectModal(ModalEnum.DELETE_KNOWLEDGE_GRAPH));

const [selectionList, setSelectionList] = useState('');
const [countSelected, setCountSelected] = useState(0);

useEffect(() => {
if (!modalDelete) return;
prepareSelectionList();
}, [modalDelete]);

const executeOption = useCallback((option: string) => {
switch (option) {
case KnowledgeGraphType.LIVE:
dispatch(setKnowledgeGraphType(KnowledgeGraphType.LIVE));
break;
case KnowledgeGraphType.STABLE:
dispatch(setKnowledgeGraphType(KnowledgeGraphType.STABLE));
break;
case 'Select all':
selectKnowledgeGraphs(true);
break;
case 'Deselect all':
selectKnowledgeGraphs(false);
break;
case 'Delete selected':
prepareSelectionList();
dispatch(openModal(ModalEnum.DELETE_KNOWLEDGE_GRAPH));
break;
}
}, []);

const selectKnowledgeGraphs = useCallback((checked: boolean) => {
knowledgeGraphs.forEach((knowledgeGraph, index) => {
knowledgeGraphs[index].selected = checked;
});
prepareSelectionList();
}, [knowledgeGraphs]);

const prepareSelectionList = useCallback(() => {
let selectionListFinal = '';
let countSelected = 0;
knowledgeGraphs.forEach((knowledgeGraph, index) => {
if (knowledgeGraph.selected) {
selectionListFinal += knowledgeGraphs[index].name;
selectionListFinal += '\n';
countSelected++;
}
});
setCountSelected(countSelected)
setSelectionList(selectionListFinal);
}, [knowledgeGraphs]);

return (
<div className="flex-shrink-0 flex justify-end items-center">
<div className="grid grid-cols-1 gap-4 xs:flex xs:gap-0 flex-row items-center mt-2 xl:mt-0 justify-end">
<KernDropdown options={KNOWLEDGE_GRAPHS_TYPES} buttonName="New knowledge graph"
selectedOption={(option: string) => executeOption(option)} buttonClasses={`${style.actionsHeight} text-xs whitespace-nowrap`} dropdownClasses="mr-3" dropdownItemsWidth='w-48' dropdownWidth='w-48'
iconsArray={['IconCode', 'IconBolt']} useFillForIcons={[false, true]} />

{knowledgeGraphs && knowledgeGraphs.length > 0 ? (
<KernDropdown options={ACTIONS_DROPDOWN_OPTIONS} buttonName="Actions" disabledOptions={[false, false, knowledgeGraphs.every((checked) => !checked.selected)]}
selectedOption={(option: string) => executeOption(option)} dropdownClasses="mr-3" buttonClasses={`${style.actionsHeight} text-xs`} dropdownItemsWidth='w-40' dropdownWidth='w-32'
iconsArray={['IconSquareCheck', 'IconSquare', 'IconTrash']} />
) : (
<KernButton
className="mr-3"
disabled={true}
text="Actions"
tooltipPlacement="top"
icon={ChevronDownIcon}
/>
)}
</div>

<DeleteKnowledgeGraphModal selectionList={selectionList} countSelected={countSelected} refetch={props.refetch} />
</div >
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { selectProjectId } from "@/src/reduxStore/states/project";
import { useDispatch, useSelector } from "react-redux";
import { useCallback } from "react";
import { selectOrganizationId } from "@/src/reduxStore/states/general";
import { useWebsocket } from "@/submodules/react-components/hooks/web-socket/useWebsocket";
import { Application, CurrentPage } from "@/submodules/react-components/hooks/web-socket/constants";
import { selectKnowledgeGraphsAll, setAllKnowledgeGraphs } from "@/src/reduxStore/states/pages/knowledge-graphs";
import KnowledgeGraphsHeader from "./KnowledgeGraphsHeader";
import { getKnowledgeGraphs } from "@/src/services/base/knowledge-graphs";
import KnowledgeGraphsGridCards from "./KnowledgeGraphsGridCards";

export function KnowledgeGraphsOverview() {
const dispatch = useDispatch();

const projectId = useSelector(selectProjectId);
const knowledgeGraphs = useSelector(selectKnowledgeGraphsAll);

const refetchKnowledgeGraphs = useCallback(() => {
getKnowledgeGraphs(projectId, (res) => {
dispatch(setAllKnowledgeGraphs(res));
});
}, [projectId]);
const handleWebsocketNotification = useCallback((msgParts: string[]) => {
if (['knowledge_graphs_created', 'knowledge_graphs_updated', 'knowledge_graphs_deleted'].includes(msgParts[1])) {
refetchKnowledgeGraphs();
}
}, [projectId]);

const orgId = useSelector(selectOrganizationId);
useWebsocket(orgId, Application.REFINERY, CurrentPage.KNOWLEDGE_GRAPHS, handleWebsocketNotification, projectId);

return (projectId && <div className="p-4 bg-gray-100 h-full flex-1 flex flex-col">
<div className="w-full h-full -mr-4">
<KnowledgeGraphsHeader refetch={refetchKnowledgeGraphs} />

{knowledgeGraphs && knowledgeGraphs.length == 0 ? (
<div>
<div className="text-gray-500 font-normal mt-8">
<p className="text-sm leading-7">Seems like your project has no knowledge graphs yet.</p>
</div>
</div>
) : (<>
<div className="overflow-y-auto">
<div className="mt-8 grid gap-6 grid-cols-3">
<KnowledgeGraphsGridCards />
</div>
</div>
</>)}
</div >
</div >)
}
23 changes: 17 additions & 6 deletions src/components/shared/sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { CacheEnum, selectCachedValue } from '@/src/reduxStore/states/cachedValu
import VersionOverviewModal from './VersionOverviewModal';
import { setProjectIdSampleProject } from '@/src/reduxStore/states/tmp';
import { getHasUpdates } from '@/src/services/base/misc';
import { MemoIconAlertCircle, MemoIconBulb, MemoIconChartPie, MemoIconMaximize, MemoIconMinimize, MemoIconSettings, MemoIconTag, MemoIconTriangleSquareCircle } from '@/submodules/react-components/components/kern-icons/icons';
import { MemoIconAlertCircle, MemoIconBulb, MemoIconChartPie, MemoIconMaximize, MemoIconMinimize, MemoIconSettings, MemoIconSitemapFilled, MemoIconTag, MemoIconTriangleSquareCircle } from '@/submodules/react-components/components/kern-icons/icons';

export default function Sidebar() {
const router = useRouter();
Expand Down Expand Up @@ -93,7 +93,7 @@ export default function Sidebar() {
{user.role === UserRole.ENGINEER && <div
className="flex items-center justify-center overflow-visible">
<Tooltip placement="right" trigger="hover" color="invert" content={TOOLTIPS_DICT.SIDEBAR.OVERVIEW} className={`${project.numDataScaleUploaded == 0 ? 'pointer-events-none cursor-not-allowed' : 'cursor-pointer'}`}>
<div className={`relative z-50`}>
<div className="relative z-50">
<a href={`/refinery/projects/${project.id}/overview`} onClick={(e: any) => { e.preventDefault(); router.push(`/projects/${project.id}/overview`) }}
className={`${project.numDataScaleUploaded == 0 ? 'opacity-50 cursor-not-allowed' : 'opacity-100 cursor-pointer'} circle ${routeColor.overview.active ? 'text-kernpurple' : 'text-white'}`}>
<MemoIconChartPie className="w-6 h-6" />
Expand All @@ -104,7 +104,7 @@ export default function Sidebar() {
{user.role === UserRole.ENGINEER && <div
className="flex items-center justify-center overflow-visible mt-9 2xl:mt-12">
<Tooltip placement="right" trigger="hover" color="invert" content={TOOLTIPS_DICT.SIDEBAR.DATA_BROWSER} className={`${project.numDataScaleUploaded == 0 ? 'pointer-events-none cursor-not-allowed' : 'cursor-pointer'}`}>
<div className={`relative z-50`}>
<div className="relative z-50">
<a href={`/refinery/projects/${project.id}/data-browser`} onClick={(e: any) => { e.preventDefault(); router.push(`/projects/${project.id}/data-browser`) }}
className={`${project.numDataScaleUploaded == 0 ? 'opacity-50 cursor-not-allowed' : 'opacity-100 cursor-pointer'} circle ${routeColor.data.active ? 'text-kernpurple' : 'text-white'}`}>
<MemoIconTriangleSquareCircle className="w-6 h-6" />
Expand All @@ -114,7 +114,7 @@ export default function Sidebar() {
</div>}
<div className={`flex items-center justify-center overflow-visible ${user?.role == 'ENGINEER' ? 'mt-9 2xl:mt-12' : ''}`}>
<Tooltip placement="right" trigger="hover" color="invert" content={TOOLTIPS_DICT.SIDEBAR.LABELING} className={`${project.numDataScaleUploaded == 0 ? 'pointer-events-none cursor-not-allowed' : 'cursor-pointer'}`}>
<div className={`relative z-50`}>
<div className="relative z-50">
<a href={`/refinery/projects/${project.id}/labeling`} onClick={(e: any) => { e.preventDefault(); router.push(`/projects/${project.id}/labeling`) }}
className={`${project.numDataScaleUploaded == 0 ? 'opacity-50 cursor-not-allowed' : 'opacity-100 cursor-pointer'} circle ${routeColor.labeling.active ? 'text-kernpurple' : 'text-white'}`}>
<MemoIconTag className="w-6 h-6" />
Expand All @@ -125,7 +125,7 @@ export default function Sidebar() {
{user.role === UserRole.ENGINEER && <div
className="flex items-center justify-center overflow-visible mt-9 2xl:mt-12">
<Tooltip placement="right" trigger="hover" color="invert" content={TOOLTIPS_DICT.SIDEBAR.HEURISTICS} className={`${project.numDataScaleUploaded == 0 ? 'pointer-events-none cursor-not-allowed' : 'cursor-pointer'}`}>
<div className={`relative z-50`}>
<div className="relative z-50">
<a href={`/refinery/projects/${project.id}/heuristics`} onClick={(e: any) => { e.preventDefault(); router.push(`/projects/${project.id}/heuristics`) }}
className={`${project.numDataScaleUploaded == 0 ? 'opacity-50 cursor-not-allowed' : 'opacity-100 cursor-pointer'} circle ${routeColor.heuristics.active ? 'text-kernpurple' : 'text-white'}`}>
<MemoIconBulb className="w-6 h-6" />
Expand All @@ -136,14 +136,25 @@ export default function Sidebar() {
{user.role === UserRole.ENGINEER && <div
className="flex items-center justify-center overflow-visible mt-9 2xl:mt-12">
<Tooltip placement="right" trigger="hover" color="invert" content={TOOLTIPS_DICT.SIDEBAR.SETTINGS}>
<div className={`relative z-50`}>
<div className="relative z-50">
<a href={`/refinery/projects/${project.id}/settings`} onClick={(e: any) => { e.preventDefault(); router.push(`/projects/${project.id}/settings`) }}
className={`circle ${routeColor.settings.active ? 'text-kernpurple' : 'text-white'}`}>
<MemoIconSettings className="w-6 h-6" />
</a>
</div>
</Tooltip>
</div>}
{user.role === UserRole.ENGINEER && <div
className="flex items-center justify-center overflow-visible mt-9 2xl:mt-12">
<Tooltip placement="right" trigger="hover" color="invert" content={TOOLTIPS_DICT.SIDEBAR.KNOWLEDGE_GRAPHS}>
<div className="relative z-50">
<a href={`/refinery/projects/${project.id}/knowledge-graphs`} onClick={(e: any) => { e.preventDefault(); router.push(`/projects/${project.id}/knowledge-graphs`) }}
className={`circle ${routeColor.knowledgeGraphs.active ? 'text-kernpurple' : 'text-white'}`}>
<MemoIconSitemapFilled className="w-6 h-6" />
</a>
</div>
</Tooltip>
</div>}
{user.role == UserRole.ENGINEER && <div
className="flex items-center justify-center overflow-visible my-6 text-white">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="20px" fill="none"
Expand Down
18 changes: 18 additions & 0 deletions src/pages/projects/[projectId]/knowledge-graphs/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { KnowledgeGraphsOverview } from "@/src/components/projects/projectId/knowledge-graphs/KnowledgeGraphsOverview";
import { setCurrentPage, setDisplayIconComments } from "@/src/reduxStore/states/general";
import { CurrentPage } from "@/submodules/react-components/hooks/web-socket/constants";
import { useEffect } from "react";
import { useDispatch } from "react-redux";

export default function KnowledgeGraphsPage() {
const dispatch = useDispatch();

useEffect(() => {
dispatch(setCurrentPage(CurrentPage.KNOWLEDGE_GRAPHS));
dispatch(setDisplayIconComments(false));
}, []);

return (
<KnowledgeGraphsOverview />
)
}
Loading