Skip to content

Vector dimension reset #594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 24, 2024
54 changes: 32 additions & 22 deletions frontend/src/components/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useCredentials } from '../context/UserCredentials';
import { useFileContext } from '../context/UsersFiles';
import CustomAlert from './UI/Alert';
import { extractAPI } from '../utils/FileAPI';
import { ContentProps, CustomFile, OptionType, UserCredentials, alertStateType } from '../types';
import { ContentProps, CustomFile, OptionType, UserCredentials, alertStateType, connectionState } from '../types';
import deleteAPI from '../services/DeleteFiles';
import { postProcessing } from '../services/PostProcessing';
import DeletePopUp from './Popups/DeletePopUp/DeletePopUp';
Expand All @@ -33,7 +33,11 @@ const Content: React.FC<ContentProps> = ({
closeSettingModal,
}) => {
const [init, setInit] = useState<boolean>(false);
const [openConnection, setOpenConnection] = useState<boolean>(false);
const [openConnection, setOpenConnection] = useState<connectionState>({
isvectorIndexMatch: true,
openPopUp: false,
novectorindexInDB: true,
});
const [openGraphView, setOpenGraphView] = useState<boolean>(false);
const [inspectedName, setInspectedName] = useState<string>('');
const [connectionStatus, setConnectionStatus] = useState<boolean>(false);
Expand Down Expand Up @@ -108,11 +112,11 @@ const Content: React.FC<ContentProps> = ({
port: neo4jConnection.uri.split(':')[2],
});
} else {
setOpenConnection(true);
setOpenConnection((prev) => ({ ...prev, openPopUp: true }));
}
setInit(true);
} else {
setOpenConnection(true);
setOpenConnection((prev) => ({ ...prev, openPopUp: true }));
}
}, []);

Expand Down Expand Up @@ -273,11 +277,7 @@ const Content: React.FC<ContentProps> = ({
};

const handleClose = () => {
setalertDetails({
showAlert: false,
alertType: 'info',
alertMessage: '',
});
setalertDetails((prev) => ({ ...prev, showAlert: false, alertMessage: '' }));
};

const handleOpenGraphClick = () => {
Expand Down Expand Up @@ -340,14 +340,6 @@ const Content: React.FC<ContentProps> = ({
[selectedfileslength, completedfileNo]
);

// const processingCheck = () => {
// const processingFiles = filesData.some((file) => file.status === 'Processing');
// const selectedRowProcessing = childRef.current?.getSelectedRows().some((row) =>
// filesData.some((file) => file.name === row && file.status === 'Processing')
// );
// return processingFiles || selectedRowProcessing;
// };

const filesForProcessing = useMemo(() => {
let newstatusfiles: CustomFile[] = [];
if (childRef.current?.getSelectedRows().length) {
Expand Down Expand Up @@ -411,10 +403,26 @@ const Content: React.FC<ContentProps> = ({
console.log(parsedData.uri);
const response = await connectAPI(parsedData.uri, parsedData.user, parsedData.password, parsedData.database);
if (response?.data?.status === 'Success') {
setConnectionStatus(true);
setOpenConnection(false);
localStorage.setItem(
'neo4j.connection',
JSON.stringify({
...parsedData,
userDbVectorIndex: response.data.data.db_vector_dimension,
})
);
if (response.data.data.application_dimension === response.data.data.db_vector_dimension) {
setConnectionStatus(true);
setOpenConnection((prev) => ({ ...prev, openPopUp: false }));
} else {
setOpenConnection({
isvectorIndexMatch: false,
openPopUp: true,
novectorindexInDB: response.data.data.db_vector_dimension === 0,
});
setConnectionStatus(false);
}
} else {
setOpenConnection(true);
setOpenConnection((prev) => ({ ...prev, openPopUp: true }));
setConnectionStatus(false);
}
})();
Expand Down Expand Up @@ -518,9 +526,11 @@ const Content: React.FC<ContentProps> = ({
<div className={`n-bg-palette-neutral-bg-default ${classNameCheck}`}>
<Flex className='w-full' alignItems='center' justifyContent='space-between' flexDirection='row'>
<ConnectionModal
open={openConnection}
open={openConnection.openPopUp}
setOpenConnection={setOpenConnection}
setConnectionStatus={setConnectionStatus}
isVectorIndexMatch={openConnection.isvectorIndexMatch}
noVectorIndexFound={openConnection.novectorindexInDB}
/>
<div className='connectionstatus__container'>
<span className='h6 px-1'>Neo4j connection</span>
Expand Down Expand Up @@ -564,7 +574,7 @@ const Content: React.FC<ContentProps> = ({
Graph Enhancement
</ButtonWithToolTip>
{!connectionStatus ? (
<Button className='mr-2.5' onClick={() => setOpenConnection(true)}>
<Button className='mr-2.5' onClick={() => setOpenConnection((prev) => ({ ...prev, openPopUp: true }))}>
{buttonCaptions.connectToNeo4j}
</Button>
) : (
Expand Down
6 changes: 1 addition & 5 deletions frontend/src/components/DataSources/Local/DropZone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,7 @@ const DropZone: FunctionComponent = () => {
};

const handleClose = () => {
setalertDetails({
showAlert: false,
alertMessage: '',
alertType: 'error',
});
setalertDetails((prev) => ({ ...prev, showAlert: false, alertMessage: '' }));
};

useEffect(() => {
Expand Down
6 changes: 1 addition & 5 deletions frontend/src/components/Layout/PageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,7 @@ export default function PageLayoutNew({
});
};
const handleClose = () => {
setalertDetails({
showAlert: false,
alertType: 'info',
alertMessage: '',
});
setalertDetails((prev) => ({ ...prev, showAlert: false, alertMessage: '' }));
};

return (
Expand Down
133 changes: 114 additions & 19 deletions frontend/src/components/Popups/ConnectionModal/ConnectionModal.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,43 @@
import { Button, Dialog, TextInput, Dropdown, Banner, Dropzone, Typography, TextLink } from '@neo4j-ndl/react';
import { Button, Dialog, TextInput, Dropdown, Banner, Dropzone, Typography, TextLink, Flex } from '@neo4j-ndl/react';
import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useState } from 'react';
import connectAPI from '../../../services/ConnectAPI';
import { useCredentials } from '../../../context/UserCredentials';
import { useSearchParams } from 'react-router-dom';
import { buttonCaptions } from '../../../utils/Constants';
import { createVectorIndex } from '../../../services/vectorIndexCreation';
import { connectionState, UserCredentials } from '../../../types';
import VectorIndexMisMatchAlert from './VectorIndexMisMatchAlert';

interface Message {
type: 'success' | 'info' | 'warning' | 'danger' | 'unknown';
content: string;
content: string | React.ReactNode;
}

interface ConnectionModalProps {
open: boolean;
setOpenConnection: Dispatch<SetStateAction<boolean>>;
setOpenConnection: Dispatch<SetStateAction<connectionState>>;
setConnectionStatus: Dispatch<SetStateAction<boolean>>;
isVectorIndexMatch: boolean;
noVectorIndexFound: boolean;
}

export default function ConnectionModal({ open, setOpenConnection, setConnectionStatus }: ConnectionModalProps) {
export default function ConnectionModal({
open,
setOpenConnection,
setConnectionStatus,
isVectorIndexMatch,
noVectorIndexFound,
}: ConnectionModalProps) {
let prefilledconnection = localStorage.getItem('neo4j.connection');
let initialuri;
let initialdb;
let initialusername;
let initialport;
let initialprotocol;
let initialuserdbvectorindex;
if (prefilledconnection) {
let parsedcontent = JSON.parse(prefilledconnection);
initialuserdbvectorindex = parsedcontent.userDbVectorIndex;
let urisplit = parsedcontent?.uri?.split('://');
initialuri = urisplit[1];
initialdb = parsedcontent?.database;
Expand All @@ -40,9 +53,11 @@ export default function ConnectionModal({ open, setOpenConnection, setConnection
const [username, setUsername] = useState<string>(initialusername ?? 'neo4j');
const [password, setPassword] = useState<string>('');
const [connectionMessage, setMessage] = useState<Message | null>({ type: 'unknown', content: '' });
const { setUserCredentials } = useCredentials();
const { setUserCredentials, userCredentials } = useCredentials();
const [isLoading, setIsLoading] = useState<boolean>(false);
const [searchParams, setSearchParams] = useSearchParams();
const [userDbVectorIndex, setUserDbVectorIndex] = useState<number | undefined>(initialuserdbvectorindex ?? undefined);
const [vectorIndexLoading, setVectorIndexLoading] = useState<boolean>(false);

useEffect(() => {
if (searchParams.has('connectURL')) {
Expand All @@ -51,8 +66,66 @@ export default function ConnectionModal({ open, setOpenConnection, setConnection
searchParams.delete('connectURL');
setSearchParams(searchParams);
}
return () => {
setUserDbVectorIndex(undefined);
};
}, [open]);

const recreateVectorIndex = useCallback(
async (isNewVectorIndex: boolean) => {
try {
setVectorIndexLoading(true);
const response = await createVectorIndex(userCredentials as UserCredentials, isNewVectorIndex);
setVectorIndexLoading(false);
if (response.data.status === 'Failed') {
throw new Error(response.data.error);
} else {
setMessage({
type: 'success',
content: 'Successfully created the vector index',
});
setConnectionStatus(true);
localStorage.setItem(
'neo4j.connection',
JSON.stringify({
uri: userCredentials?.uri,
user: userCredentials?.userName,
password: userCredentials?.password,
database: userCredentials?.database,
userDbVectorIndex: 384,
})
);
}
} catch (error) {
setVectorIndexLoading(false);
if (error instanceof Error) {
console.log('Error in recreating the vector index', error.message);
setMessage({ type: 'danger', content: error.message });
}
}
setTimeout(() => {
setMessage({ type: 'unknown', content: '' });
setOpenConnection((prev) => ({ ...prev, openPopUp: false }));
}, 3000);
},
[userCredentials, userDbVectorIndex]
);
useEffect(() => {
if (!isVectorIndexMatch) {
setMessage({
type: 'danger',
content: (
<VectorIndexMisMatchAlert
vectorIndexLoading={vectorIndexLoading}
recreateVectorIndex={() => recreateVectorIndex(!noVectorIndexFound)}
isVectorIndexAlreadyExists={!noVectorIndexFound}
userVectorIndexDimension={JSON.parse(localStorage.getItem('neo4j.connection') ?? 'null').userDbVectorIndex}
/>
),
});
}
}, [isVectorIndexMatch, vectorIndexLoading, noVectorIndexFound]);

const parseAndSetURI = (uri: string, urlparams = false) => {
const uriParts: string[] = uri.split('://');
let uriHost: string[] | string;
Expand Down Expand Up @@ -132,27 +205,47 @@ export default function ConnectionModal({ open, setOpenConnection, setConnection
setIsLoading(true);
const response = await connectAPI(connectionURI, username, password, database);
if (response?.data?.status === 'Success') {
setUserDbVectorIndex(response.data.data.db_vector_dimension);
if (response.data.data.db_vector_dimension === response.data.data.application_dimension) {
setConnectionStatus(true);
setOpenConnection((prev) => ({ ...prev, openPopUp: false }));
setMessage({
type: 'success',
content: response.data.data.message,
});
} else {
setMessage({
type: 'danger',
content: (
<VectorIndexMisMatchAlert
vectorIndexLoading={vectorIndexLoading}
recreateVectorIndex={() => recreateVectorIndex(response.data.data.db_vector_dimension === 0)}
isVectorIndexAlreadyExists={response.data.data.db_vector_dimension != 0}
userVectorIndexDimension={response.data.data.db_vector_dimension}
/>
),
});
}
localStorage.setItem(
'neo4j.connection',
JSON.stringify({ uri: connectionURI, user: username, password: password, database: database })
JSON.stringify({
uri: connectionURI,
user: username,
password: password,
database: database,
userDbVectorIndex,
})
);
setConnectionStatus(true);
setMessage({
type: 'success',
content: response.data.message,
});
setOpenConnection(false);
} else {
setMessage({ type: 'danger', content: response.data.error });
setOpenConnection(true);
setOpenConnection((prev) => ({ ...prev, openPopUp: true }));
setPassword('');
setConnectionStatus(false);
}
setIsLoading(false);
setTimeout(() => {
setMessage({ type: 'unknown', content: '' });
setPassword('');
}, 3000);
}, 10000);
};

const onClose = useCallback(() => {
Expand All @@ -168,7 +261,7 @@ export default function ConnectionModal({ open, setOpenConnection, setConnection
open={open}
aria-labelledby='form-dialog-title'
onClose={() => {
setOpenConnection(false);
setOpenConnection((prev) => ({ ...prev, openPopUp: false }));
setMessage({ type: 'unknown', content: '' });
}}
>
Expand Down Expand Up @@ -275,9 +368,11 @@ export default function ConnectionModal({ open, setOpenConnection, setConnection
/>
</div>
</div>
<Button loading={isLoading} disabled={isDisabled} onClick={() => submitConnection()}>
{buttonCaptions.connect}
</Button>
<Flex flexDirection='row' justifyContent='flex-end'>
<Button loading={isLoading} disabled={isDisabled} onClick={() => submitConnection()}>
{buttonCaptions.connect}
</Button>
</Flex>
</Dialog.Content>
</Dialog>
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Box, Flex } from '@neo4j-ndl/react';
import Markdown from 'react-markdown';
import ButtonWithToolTip from '../../UI/ButtonWithToolTip';

export default function VectorIndexMisMatchAlert({
vectorIndexLoading,
recreateVectorIndex,
isVectorIndexAlreadyExists,
userVectorIndexDimension,
}: {
vectorIndexLoading: boolean;
recreateVectorIndex: () => Promise<void>;
isVectorIndexAlreadyExists: boolean;
userVectorIndexDimension: number;
}) {
return (
<Flex>
<Box>
<Markdown className='whitespace-pre-wrap'>
{isVectorIndexAlreadyExists
? `**Vector Index Incompatibility**
The existing Neo4j vector index dimension (${userVectorIndexDimension}) is incompatible with the supported dimension (384) for this application.
To proceed, please choose one of the following options:
1.**Recreate Vector Index:** Click "Re-Create Vector Index" to generate a compatible vector index.
2.**Use a Different Instance:** Connect to a Neo4j instance with a compatible vector index configuration `
: `**Vector index not found**.
To leverage AI-powered search, please create a vector index.This will enable efficient similarity search within your Neo4j database`}
</Markdown>
</Box>
<Box className='n-size-full n-flex n-flex-col n-items-center n-justify-center'>
<ButtonWithToolTip
text='creates the supported vector index'
label='creates the supported vector index'
placement='top'
loading={vectorIndexLoading}
onClick={() => recreateVectorIndex()}
className='!w-full'
color='danger'
>
{isVectorIndexAlreadyExists ? 'Re-Create Vector Index' : 'Create Vector Index'}
</ButtonWithToolTip>
</Box>
</Flex>
);
}
Loading