From c20c380aae756e64bb02c46812d30fe372fb4b21 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Mon, 27 Jan 2025 10:11:12 +0000 Subject: [PATCH 1/2] read only route for unauthenticated users --- docker-compose.yml | 2 +- frontend/src/App.tsx | 1 + .../src/components/ChatBot/ChatInfoModal.tsx | 7 +---- frontend/src/components/Content.tsx | 3 ++- frontend/src/components/Layout/PageLayout.tsx | 26 ++++++++++--------- .../Popups/GraphEnhancementDialog/index.tsx | 1 - frontend/src/context/UserCredentials.tsx | 10 +++++-- .../src/services/GetNodeLabelsRelTypes.ts | 2 +- frontend/src/services/GetOrphanNodes.ts | 2 +- 9 files changed, 29 insertions(+), 25 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index d3fe710f1..6f1b4174e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -65,7 +65,7 @@ services: - VITE_LLM_MODELS_PROD=${VITE_LLM_MODELS_PROD-openai_gpt_4o,openai_gpt_4o_mini,diffbot,gemini_1.5_flash} - VITE_AUTH0_DOMAIN=${VITE_AUTH0_DOMAIN-} - VITE_AUTH0_CLIENT_ID=${VITE_AUTH0_CLIENT_ID-} - - VITE_SKIP_AUTH=$VITE_SKIP_AUTH-true} + - VITE_SKIP_AUTH=${VITE_SKIP_AUTH-true} - DEPLOYMENT_ENV=local volumes: - ./frontend:/app diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6a7ce0948..f975e5c52 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -8,6 +8,7 @@ const App = () => { return ( : }> + }> }> ); diff --git a/frontend/src/components/ChatBot/ChatInfoModal.tsx b/frontend/src/components/ChatBot/ChatInfoModal.tsx index 779b591f9..5d2ff914f 100644 --- a/frontend/src/components/ChatBot/ChatInfoModal.tsx +++ b/frontend/src/components/ChatBot/ChatInfoModal.tsx @@ -141,12 +141,7 @@ const ChatInfoModal: React.FC = ({ (async () => { toggleInfoLoading(); try { - const response = await chunkEntitiesAPI( - userCredentials?.database, - nodeDetails, - entities_ids, - mode - ); + const response = await chunkEntitiesAPI(userCredentials?.database, nodeDetails, entities_ids, mode); if (response.data.status === 'Failure') { throw new Error(response.data.error); } diff --git a/frontend/src/components/Content.tsx b/frontend/src/components/Content.tsx index d83599f36..bd129074f 100644 --- a/frontend/src/components/Content.tsx +++ b/frontend/src/components/Content.tsx @@ -703,7 +703,8 @@ const Content: React.FC = ({ const selectedRows = childRef.current?.getSelectedRows(); if (selectedRows?.length) { const expiredFilesExists = selectedRows.some( - (c) => isFileReadyToProcess(c, true) && isExpired((c?.createdAt as Date) ?? new Date())); + (c) => isFileReadyToProcess(c, true) && isExpired((c?.createdAt as Date) ?? new Date()) + ); const largeFileExists = selectedRows.some( (c) => isFileReadyToProcess(c, true) && typeof c.size === 'number' && c.size > largeFileSize ); diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index f92ddc77c..5573dcaf3 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -28,7 +28,20 @@ const PageLayout: React.FC = () => { chunksExistsWithDifferentDimension: false, }); const isLargeDesktop = useMediaQuery(`(min-width:1440px )`); - const { userCredentials, connectionStatus, setIsReadOnlyUser } = useCredentials(); + const { + userCredentials, + connectionStatus, + setIsReadOnlyUser, + setConnectionStatus, + setGdsActive, + setIsBackendConnected, + setUserCredentials, + setErrorMessage, + setShowDisconnectButton, + showDisconnectButton, + setIsGCSActive, + setChunksToBeProces, + } = useCredentials(); const [isLeftExpanded, setIsLeftExpanded] = useState(Boolean(isLargeDesktop)); const [isRightExpanded, setIsRightExpanded] = useState(Boolean(isLargeDesktop)); const [showChatBot, setShowChatBot] = useState(false); @@ -57,17 +70,6 @@ const PageLayout: React.FC = () => { const { messages, setClearHistoryData, clearHistoryData, setMessages, setIsDeleteChatLoading } = useMessageContext(); const { setShowTextFromSchemaDialog, showTextFromSchemaDialog } = useFileContext(); - const { - setConnectionStatus, - setGdsActive, - setIsBackendConnected, - setUserCredentials, - setErrorMessage, - setShowDisconnectButton, - showDisconnectButton, - setIsGCSActive, - setChunksToBeProces, - } = useCredentials(); const { cancel } = useSpeechSynthesis(); useEffect(() => { diff --git a/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx b/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx index d0daee0e8..db389bc39 100644 --- a/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx +++ b/frontend/src/components/Popups/GraphEnhancementDialog/index.tsx @@ -134,7 +134,6 @@ export default function GraphEnhancementDialog({ open, onClose }: { open: boolea - ); diff --git a/frontend/src/context/UserCredentials.tsx b/frontend/src/context/UserCredentials.tsx index 0bb8b4c83..061c63e78 100644 --- a/frontend/src/context/UserCredentials.tsx +++ b/frontend/src/context/UserCredentials.tsx @@ -1,5 +1,6 @@ -import { createContext, useState, useContext, FunctionComponent, ReactNode } from 'react'; +import { createContext, useState, useContext, FunctionComponent, ReactNode, useEffect } from 'react'; import { ContextProps, UserCredentials } from '../types'; +import { useLocation } from 'react-router'; type Props = { children: ReactNode; @@ -59,7 +60,12 @@ const UserCredentialsWrapper: FunctionComponent = (props) => { chunksToBeProces, setChunksToBeProces, }; - + const { pathname } = useLocation(); + useEffect(() => { + if (pathname === '/readonly') { + setIsReadOnlyUser(true); + } + }, [pathname]); return {props.children}; }; export default UserCredentialsWrapper; diff --git a/frontend/src/services/GetNodeLabelsRelTypes.ts b/frontend/src/services/GetNodeLabelsRelTypes.ts index 2f1eec685..61e6e126c 100644 --- a/frontend/src/services/GetNodeLabelsRelTypes.ts +++ b/frontend/src/services/GetNodeLabelsRelTypes.ts @@ -4,7 +4,7 @@ import api from '../API/Index'; export const getNodeLabelsAndRelTypes = async () => { const formData = new FormData(); try { - const response = await api.post(`/schema`,formData); + const response = await api.post(`/schema`, formData); return response; } catch (error) { console.log(error); diff --git a/frontend/src/services/GetOrphanNodes.ts b/frontend/src/services/GetOrphanNodes.ts index 5056e166b..e49f40ab9 100644 --- a/frontend/src/services/GetOrphanNodes.ts +++ b/frontend/src/services/GetOrphanNodes.ts @@ -4,7 +4,7 @@ import api from '../API/Index'; export const getOrphanNodes = async () => { const formData = new FormData(); try { - const response = await api.post(`/get_unconnected_nodes_list`,formData); + const response = await api.post(`/get_unconnected_nodes_list`, formData); return response; } catch (error) { console.log(error); From 28a9c1cd37f842440f8832172533a40cf9c1d7f0 Mon Sep 17 00:00:00 2001 From: kartikpersistent <101251502+kartikpersistent@users.noreply.github.com> Date: Tue, 28 Jan 2025 07:38:52 +0000 Subject: [PATCH 2/2] Login Modal For Read Only Mode --- frontend/src/components/Auth/Auth.tsx | 1 + frontend/src/components/FileTable.tsx | 12 +++++++++++- frontend/src/components/Layout/DrawerChatbot.tsx | 7 ++++++- frontend/src/components/Layout/PageLayout.tsx | 7 ++++++- frontend/src/components/Login/Index.tsx | 9 ++++----- frontend/src/components/User/Profile.tsx | 2 +- frontend/src/context/UserCredentials.tsx | 1 + 7 files changed, 30 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/Auth/Auth.tsx b/frontend/src/components/Auth/Auth.tsx index a9fdc568b..30849d4da 100644 --- a/frontend/src/components/Auth/Auth.tsx +++ b/frontend/src/components/Auth/Auth.tsx @@ -7,6 +7,7 @@ const Auth0ProviderWithHistory: React.FC<{ children: React.ReactNode }> = ({ chi const navigate = useNavigate(); function onRedirectCallback(appState?: AppState) { + localStorage.removeItem('isReadOnlyMode'); navigate(appState?.returnTo || window.location.pathname, { state: appState }); } diff --git a/frontend/src/components/FileTable.tsx b/frontend/src/components/FileTable.tsx index 0decbbd53..b40bfe5ab 100644 --- a/frontend/src/components/FileTable.tsx +++ b/frontend/src/components/FileTable.tsx @@ -10,6 +10,7 @@ import { useCopyToClipboard, Checkbox, useMediaQuery, + Dialog, } from '@neo4j-ndl/react'; import { forwardRef, @@ -66,6 +67,8 @@ import { showErrorToast, showNormalToast } from '../utils/toasts'; import { ThemeWrapperContext } from '../context/ThemeWrapper'; import BreakDownPopOver from './BreakDownPopOver'; import { InformationCircleIconOutline } from '@neo4j-ndl/react/icons'; +import { useLocation } from 'react-router'; +import Login from './Login/Index'; let onlyfortheFirstRender = true; @@ -86,7 +89,7 @@ const FileTable: ForwardRefRenderFunction = (props, re const { colorMode } = useContext(ThemeWrapperContext); const [copyRow, setCopyRow] = useState(false); const islargeDesktop = useMediaQuery(`(min-width:1440px )`); - + const { pathname } = useLocation(); const tableRef = useRef(null); const { updateStatusForLargeFiles } = useServerSideEvent( @@ -999,6 +1002,13 @@ const FileTable: ForwardRefRenderFunction = (props, re <> {filesData ? ( <> + {filesData.length === 0 && pathname === '/readonly' && ( + + + + + + )} = ({ isExpanded, clearHistoryD useEffect(() => { if (location && location.state && Array.isArray(location.state)) { setMessages(location.state); - } else if (location && location.state && Object.prototype.toString.call(location.state) === '[object Object]') { + } else if ( + location && + location.state && + typeof location.state === 'object' && + Object.keys(location.state).length > 1 + ) { setUserCredentials(location.state.credential); setIsGCSActive(location.state.isGCSActive); setGdsActive(location.state.isgdsActive); diff --git a/frontend/src/components/Layout/PageLayout.tsx b/frontend/src/components/Layout/PageLayout.tsx index 5573dcaf3..bbe6f9e3e 100644 --- a/frontend/src/components/Layout/PageLayout.tsx +++ b/frontend/src/components/Layout/PageLayout.tsx @@ -118,6 +118,7 @@ const PageLayout: React.FC = () => { } try { const parsedConnection = JSON.parse(neo4jConnection); + const readonlymode = JSON.parse(localStorage.getItem('isReadOnlyMode') ?? 'null'); if (parsedConnection.uri && parsedConnection.user && parsedConnection.password && parsedConnection.database) { const credentials = { uri: parsedConnection.uri, @@ -126,10 +127,14 @@ const PageLayout: React.FC = () => { database: parsedConnection.database, email: parsedConnection.email, }; + if (readonlymode !== null) { + setIsReadOnlyUser(readonlymode); + } else { + setIsReadOnlyUser(parsedConnection.isReadOnlyUser); + } setUserCredentials(credentials); createDefaultFormData(credentials); setGdsActive(parsedConnection.isgdsActive); - setIsReadOnlyUser(parsedConnection.isReadOnlyUser); setIsGCSActive(parsedConnection.isGCSActive); } else { console.error('Invalid parsed session data:', parsedConnection); diff --git a/frontend/src/components/Login/Index.tsx b/frontend/src/components/Login/Index.tsx index 7d155334f..f62f0ad68 100644 --- a/frontend/src/components/Login/Index.tsx +++ b/frontend/src/components/Login/Index.tsx @@ -1,17 +1,16 @@ import { useAuth0 } from '@auth0/auth0-react'; -import Neo4jLogoColor from '../../logo-color.svg'; import { Button, Flex, Typography } from '@neo4j-ndl/react'; export default function Login() { const { loginWithRedirect } = useAuth0(); return ( -
-
+
+
- - Turn unstructured information into to rich insightful Knowledge Graph + It seems like you haven't ingested any data yet. To begin building your knowledge graph, you'll need to log + in to the main application.
diff --git a/frontend/src/components/User/Profile.tsx b/frontend/src/components/User/Profile.tsx index 25c4d9318..dd614ef1f 100644 --- a/frontend/src/components/User/Profile.tsx +++ b/frontend/src/components/User/Profile.tsx @@ -12,7 +12,7 @@ export default function Profile() { { title: 'Logout', onClick: () => { - logout({ logoutParams: { returnTo: window.location.origin } }); + logout({ logoutParams: { returnTo: `${window.location.origin}/readonly` } }); }, }, ], diff --git a/frontend/src/context/UserCredentials.tsx b/frontend/src/context/UserCredentials.tsx index 061c63e78..581280fac 100644 --- a/frontend/src/context/UserCredentials.tsx +++ b/frontend/src/context/UserCredentials.tsx @@ -64,6 +64,7 @@ const UserCredentialsWrapper: FunctionComponent = (props) => { useEffect(() => { if (pathname === '/readonly') { setIsReadOnlyUser(true); + localStorage.setItem('isReadOnlyMode', 'true'); } }, [pathname]); return {props.children};