mirror of
https://github.com/Mintplex-Labs/vector-admin.git
synced 2026-07-01 18:20:51 -04:00
Merge branch 'ui-v2' of github.com:Mintplex-Labs/vector-admin into v2-tools-subpages
This commit is contained in:
@@ -30,6 +30,12 @@ jobs:
|
||||
shell: bash
|
||||
run: echo "repo=${GITHUB_REPOSITORY,,}" >> $GITHUB_OUTPUT
|
||||
id: lowercase_repo
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
|
||||
@@ -57,7 +63,7 @@ jobs:
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
platforms: linux/amd64
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
${{ steps.meta.outputs.tags }}
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ app
|
||||
await systemInit();
|
||||
setupDebugger(apiRouter);
|
||||
console.log(
|
||||
`Example app listening on port ${process.env.SERVER_PORT || 3001}`
|
||||
`Backend server listening on port ${process.env.SERVER_PORT || 3001}`
|
||||
);
|
||||
})
|
||||
.on("error", function (err) {
|
||||
|
||||
+12
-7
@@ -19,9 +19,14 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
|
||||
curl -LO https://github.com/yarnpkg/yarn/releases/download/v1.22.19/yarn_1.22.19_all.deb \
|
||||
&& dpkg -i yarn_1.22.19_all.deb \
|
||||
&& rm yarn_1.22.19_all.deb && \
|
||||
curl -LO https://github.com/jgm/pandoc/releases/download/3.1.3/pandoc-3.1.3-1-amd64.deb \
|
||||
&& dpkg -i pandoc-3.1.3-1-amd64.deb \
|
||||
&& rm pandoc-3.1.3-1-amd64.deb && \
|
||||
if [ "$(uname -m)" = "aarch64" ] || [ "$(uname -m)" = "arm64" ] || [ "$(uname -m)" = "armv7l" ]; \
|
||||
then \
|
||||
curl -L https://github.com/jgm/pandoc/releases/download/3.1.3/pandoc-3.1.3-1-arm64.deb > pandoc-3.1.3-1.deb; \
|
||||
else \
|
||||
curl -L https://github.com/jgm/pandoc/releases/download/3.1.3/pandoc-3.1.3-1-amd64.deb > pandoc-3.1.3-1.deb; \
|
||||
fi \
|
||||
&& dpkg -i pandoc-3.1.3-1.deb \
|
||||
&& rm pandoc-3.1.3-1.deb && \
|
||||
rm -rf /var/lib/apt/lists/* /usr/share/icons && \
|
||||
dpkg-reconfigure -f noninteractive tzdata && \
|
||||
python3 -m pip install --no-cache-dir virtualenv
|
||||
@@ -43,12 +48,12 @@ USER root
|
||||
# Install frontend dependencies
|
||||
FROM base as frontend-deps
|
||||
COPY ./frontend/package.json ./frontend/yarn.lock ./frontend/
|
||||
RUN cd ./frontend/ && yarn install && yarn cache clean
|
||||
RUN cd ./frontend/ && yarn install --network-timeout 100000 && yarn cache clean
|
||||
|
||||
# Install server dependencies
|
||||
FROM base as server-deps
|
||||
COPY ./backend/package.json ./backend/yarn.lock ./backend/
|
||||
RUN cd ./backend/ && yarn install --production && yarn cache clean
|
||||
RUN cd ./backend/ && yarn install --production --network-timeout 100000 && yarn cache clean
|
||||
|
||||
# Build the frontend
|
||||
FROM frontend-deps as build-stage
|
||||
@@ -67,9 +72,9 @@ COPY ./workers/ ./workers/
|
||||
|
||||
# Install worker dependencies
|
||||
RUN cd /app/workers && \
|
||||
yarn install --production && \
|
||||
yarn install --production --network-timeout 100000 && \
|
||||
yarn cache clean && \
|
||||
yarn add global inngest-cli
|
||||
yarn add global inngest-cli --network-timeout 100000
|
||||
|
||||
# Copy the document-processor
|
||||
COPY ./document-processor/ ./document-processor/
|
||||
|
||||
@@ -12,6 +12,8 @@ type ConnectVectorDBProps = {
|
||||
organization: any;
|
||||
setLoading: (loading: boolean) => void;
|
||||
setConnector: (connector: any) => void;
|
||||
stepIdx: number;
|
||||
stepCount: number;
|
||||
};
|
||||
|
||||
export default function ConnectVectorDB({
|
||||
@@ -19,6 +21,8 @@ export default function ConnectVectorDB({
|
||||
organization,
|
||||
setLoading,
|
||||
setConnector,
|
||||
stepIdx,
|
||||
stepCount,
|
||||
}: ConnectVectorDBProps) {
|
||||
const [vectorDB, setVectorDB] = useState('chroma');
|
||||
|
||||
@@ -48,9 +52,11 @@ export default function ConnectVectorDB({
|
||||
);
|
||||
|
||||
if (connector) {
|
||||
showToast('Vector database connected successfully', 'success');
|
||||
showToast('Vector database connected successfully', 'success', {
|
||||
clear: true,
|
||||
});
|
||||
setConnector(connector);
|
||||
setCurrentStep('sync_vector_db');
|
||||
setCurrentStep('survey');
|
||||
} else {
|
||||
showToast(`Error connecting vector database: ${error}`, 'error');
|
||||
}
|
||||
@@ -61,8 +67,8 @@ export default function ConnectVectorDB({
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-8 font-semibold uppercase text-white">
|
||||
Step 04/
|
||||
<span className="text-white text-opacity-40">05</span>
|
||||
Step 0{stepIdx}/
|
||||
<span className="text-white text-opacity-40">0{stepCount}</span>
|
||||
</div>
|
||||
<div className="mb-5 text-2xl font-medium text-white">
|
||||
Connect your vector database
|
||||
|
||||
@@ -6,12 +6,16 @@ type CreateOrganizationProps = {
|
||||
setCurrentStep: (step: string) => void;
|
||||
setOrganization: (organization: any) => void;
|
||||
setLoading: (loading: boolean) => void;
|
||||
stepIdx: number;
|
||||
stepCount: number;
|
||||
};
|
||||
|
||||
export default function CreateOrganization({
|
||||
setCurrentStep,
|
||||
setOrganization,
|
||||
setLoading,
|
||||
stepIdx,
|
||||
stepCount,
|
||||
}: CreateOrganizationProps) {
|
||||
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
@@ -22,7 +26,9 @@ export default function CreateOrganization({
|
||||
|
||||
const { organization, error } = await Organization.create(name);
|
||||
if (organization) {
|
||||
showToast('Organization created successfully', 'success');
|
||||
showToast('Organization created successfully', 'success', {
|
||||
clear: true,
|
||||
});
|
||||
setOrganization(organization);
|
||||
setCurrentStep('connect_vector_db');
|
||||
} else {
|
||||
@@ -34,8 +40,8 @@ export default function CreateOrganization({
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-8 font-semibold uppercase text-white">
|
||||
Step 03/
|
||||
<span className="text-white text-opacity-40">05</span>
|
||||
Step 0{stepIdx}/
|
||||
<span className="text-white text-opacity-40">0{stepCount}</span>
|
||||
</div>
|
||||
<div className="mb-3 text-2xl font-medium text-white">
|
||||
Create an organization
|
||||
|
||||
@@ -6,11 +6,15 @@ import { STORE_TOKEN, STORE_USER } from '../../../../utils/constants';
|
||||
type CustomLoginProps = {
|
||||
setCurrentStep: (step: string) => void;
|
||||
setLoading: (loading: boolean) => void;
|
||||
stepIdx: number;
|
||||
stepCount: number;
|
||||
};
|
||||
|
||||
export default function CustomLogin({
|
||||
setCurrentStep,
|
||||
setLoading,
|
||||
stepIdx,
|
||||
stepCount,
|
||||
}: CustomLoginProps) {
|
||||
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
@@ -29,7 +33,7 @@ export default function CustomLogin({
|
||||
if (!!token) {
|
||||
window.localStorage.setItem(STORE_USER, JSON.stringify(user));
|
||||
window.localStorage.setItem(STORE_TOKEN, token);
|
||||
showToast('Login created successfully', 'success');
|
||||
showToast('Login created successfully', 'success', { clear: true });
|
||||
setCurrentStep('security_settings');
|
||||
} else {
|
||||
showToast(`Error creating login: ${error}`, 'error');
|
||||
@@ -40,8 +44,8 @@ export default function CustomLogin({
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-8 font-semibold uppercase text-white">
|
||||
Step 01/
|
||||
<span className="text-white text-opacity-40">05</span>
|
||||
Step 0{stepIdx}/
|
||||
<span className="text-white text-opacity-40">0{stepCount}</span>
|
||||
</div>
|
||||
<div className="mb-3 text-2xl font-medium text-white">
|
||||
Create your custom login
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
import { FormEvent, useState } from 'react';
|
||||
import { COMPLETE_QUESTIONNAIRE } from '../../../../utils/constants';
|
||||
|
||||
type OnboardingSurveyProps = {
|
||||
setCurrentStep: (step: string) => void;
|
||||
setLoading: (loading: boolean) => void;
|
||||
stepIdx: number;
|
||||
stepCount: number;
|
||||
};
|
||||
|
||||
async function sendQuestionnaire({
|
||||
email,
|
||||
useCase,
|
||||
comment,
|
||||
}: {
|
||||
email: string;
|
||||
useCase: string;
|
||||
comment?: string | null;
|
||||
}) {
|
||||
if (import.meta.env.DEV) return;
|
||||
return fetch(`https://onboarding-wxich7363q-uc.a.run.app`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
useCase,
|
||||
comment,
|
||||
sourceId: '7DaBbrMSn8zE4eBN++F18BT5zs+BPENi',
|
||||
}),
|
||||
})
|
||||
.then(() => {
|
||||
window.localStorage.setItem(COMPLETE_QUESTIONNAIRE, 'true');
|
||||
console.log(`✅ Questionnaire responses sent.`);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(`sendQuestionnaire`, error.message);
|
||||
});
|
||||
}
|
||||
|
||||
export default function OnboardingSurvey({
|
||||
setCurrentStep,
|
||||
stepIdx,
|
||||
stepCount,
|
||||
}: OnboardingSurveyProps) {
|
||||
const [selectedOption, setSelectedOption] = useState('');
|
||||
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(e.currentTarget);
|
||||
await sendQuestionnaire({
|
||||
email: formData.get('email') as string,
|
||||
useCase: (formData.get('use_case') || 'other') as string,
|
||||
comment: (formData.get('comment') as string) || null,
|
||||
});
|
||||
setCurrentStep('sync_vector_db');
|
||||
};
|
||||
|
||||
function skipSurvey() {
|
||||
setCurrentStep('sync_vector_db');
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-8 font-semibold uppercase text-white">
|
||||
Step 0{stepIdx}/
|
||||
<span className="text-white text-opacity-40">0{stepCount}</span>
|
||||
</div>
|
||||
<div className="mb-3 text-2xl font-medium text-white">
|
||||
Help us improve VectorAdmin
|
||||
</div>
|
||||
<div className="w-[300px] text-sm font-light text-white text-opacity-90">
|
||||
This optional survey helps us build VectorAdmin with the features you
|
||||
need.
|
||||
</div>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="mb-3.5 mt-7 flex flex-col gap-y-1">
|
||||
<label htmlFor="email" className="text-base font-medium text-white">
|
||||
What's your email?{' '}
|
||||
</label>
|
||||
<input
|
||||
required={true}
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="you@gmail.com"
|
||||
className="h-11 w-[300px] rounded-lg bg-neutral-800/60 p-2.5 text-sm text-white shadow-lg transition-all duration-300 focus:scale-105"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className=" mb-3.5 mt-7">
|
||||
<label
|
||||
className="text-base font-medium text-white"
|
||||
htmlFor="use_case"
|
||||
>
|
||||
What will you use VectorAdmin for?{' '}
|
||||
</label>
|
||||
<div className="mt-2 flex flex-col gap-y-3">
|
||||
<label
|
||||
className={`flex h-11 w-full cursor-pointer items-center justify-start gap-2.5 rounded-lg border border-transparent bg-white/10 p-2.5 transition-all duration-300 ${
|
||||
selectedOption === 'business'
|
||||
? 'border-white border-opacity-40'
|
||||
: ''
|
||||
} hover:border-white/60`}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="use_case"
|
||||
value={'business'}
|
||||
checked={selectedOption === 'business'}
|
||||
onChange={(e) => setSelectedOption(e.target.value)}
|
||||
className="hidden"
|
||||
/>
|
||||
<div
|
||||
className={`mr-2 h-4 w-4 rounded-full border-2 border-white ${
|
||||
selectedOption === 'business' ? 'bg-white' : ''
|
||||
}`}
|
||||
></div>
|
||||
<div className="font-['Plus Jakarta Sans'] text-sm font-medium leading-tight text-white">
|
||||
For my business
|
||||
</div>
|
||||
</label>
|
||||
<label
|
||||
className={`flex h-11 w-full cursor-pointer items-center justify-start gap-2.5 rounded-lg border border-transparent bg-white/10 p-2.5 transition-all duration-300 ${
|
||||
selectedOption === 'personal'
|
||||
? 'border-white border-opacity-40'
|
||||
: ''
|
||||
} hover:border-white/60`}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="use_case"
|
||||
value={'personal'}
|
||||
checked={selectedOption === 'personal'}
|
||||
onChange={(e) => setSelectedOption(e.target.value)}
|
||||
className="hidden"
|
||||
/>
|
||||
<div
|
||||
className={`mr-2 h-4 w-4 rounded-full border-2 border-white ${
|
||||
selectedOption === 'personal' ? 'bg-white' : ''
|
||||
}`}
|
||||
></div>
|
||||
<div className="font-['Plus Jakarta Sans'] text-sm font-medium leading-tight text-white">
|
||||
For personal use
|
||||
</div>
|
||||
</label>
|
||||
<label
|
||||
className={`flex h-11 w-full cursor-pointer items-center justify-start gap-2.5 rounded-lg border border-transparent bg-white/10 p-2.5 transition-all duration-300 ${
|
||||
selectedOption === 'job' ? 'border-white border-opacity-40' : ''
|
||||
} hover:border-white/60`}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="use_case"
|
||||
value={'job'}
|
||||
checked={selectedOption === 'job'}
|
||||
onChange={(e) => setSelectedOption(e.target.value)}
|
||||
className="hidden"
|
||||
/>
|
||||
<div
|
||||
className={`mr-2 h-4 w-4 rounded-full border-2 border-white ${
|
||||
selectedOption === 'job' ? 'bg-white' : ''
|
||||
}`}
|
||||
></div>
|
||||
<div className="font-['Plus Jakarta Sans'] text-sm font-medium leading-tight text-white">
|
||||
For my job
|
||||
</div>
|
||||
</label>
|
||||
<label
|
||||
className={`flex h-11 w-full cursor-pointer items-center justify-start gap-2.5 rounded-lg border border-transparent bg-white/10 p-2.5 transition-all duration-300 ${
|
||||
selectedOption === 'other'
|
||||
? 'border-white border-opacity-40'
|
||||
: ''
|
||||
} hover:border-white/60`}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="use_case"
|
||||
value={'other'}
|
||||
checked={selectedOption === 'other'}
|
||||
onChange={(e) => setSelectedOption(e.target.value)}
|
||||
className="hidden"
|
||||
/>
|
||||
<div
|
||||
className={`mr-2 h-4 w-4 rounded-full border-2 border-white ${
|
||||
selectedOption === 'other' ? 'bg-white' : ''
|
||||
}`}
|
||||
></div>
|
||||
<div className="font-['Plus Jakarta Sans'] text-sm font-medium leading-tight text-white">
|
||||
Other
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-3.5 mt-7 flex flex-col gap-y-1">
|
||||
<label htmlFor="comment" className="text-base font-medium text-white">
|
||||
Any comments for the team?{' '}
|
||||
<span className="text-base font-light text-neutral-400">
|
||||
(Optional)
|
||||
</span>
|
||||
</label>
|
||||
<textarea
|
||||
required={true}
|
||||
name="comment"
|
||||
rows={8}
|
||||
wrap="soft"
|
||||
autoComplete="off"
|
||||
placeholder="If you have any questions or comments right now, you can leave them here and we will get back to you. You can also email team@mintplexlabs.com"
|
||||
className="min-h-[60px] w-full rounded-lg bg-neutral-800/60 p-2.5 text-sm text-white shadow-lg transition-all duration-300 focus:scale-105"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex w-full items-center justify-center">
|
||||
<button
|
||||
type="submit"
|
||||
className="h-11 w-full items-center rounded-lg bg-white p-2 text-center text-sm font-bold text-neutral-700 shadow-lg transition-all duration-300 hover:scale-105 hover:bg-opacity-90"
|
||||
>
|
||||
Submit Response
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="mb-5 flex w-full items-center justify-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={skipSurvey}
|
||||
className="mt-8 text-base font-medium text-white text-opacity-30 hover:text-opacity-100"
|
||||
>
|
||||
Skip Survey
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -5,11 +5,15 @@ import showToast from '../../../../utils/toast';
|
||||
type SecuritySettingsProps = {
|
||||
setCurrentStep: (step: string) => void;
|
||||
setLoading: (loading: boolean) => void;
|
||||
stepIdx: number;
|
||||
stepCount: number;
|
||||
};
|
||||
|
||||
export default function SecuritySettings({
|
||||
setCurrentStep,
|
||||
setLoading,
|
||||
stepIdx,
|
||||
stepCount,
|
||||
}: SecuritySettingsProps) {
|
||||
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
@@ -23,7 +27,9 @@ export default function SecuritySettings({
|
||||
const { success, error } = await System.updateSettings(data);
|
||||
|
||||
if (success) {
|
||||
showToast('Security settings saved successfully', 'success');
|
||||
showToast('Security settings saved successfully', 'success', {
|
||||
clear: true,
|
||||
});
|
||||
setCurrentStep('create_organization');
|
||||
} else {
|
||||
showToast(`Error setting security settings: ${error}`, 'error');
|
||||
@@ -35,8 +41,8 @@ export default function SecuritySettings({
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-8 font-semibold uppercase text-white">
|
||||
Step 02/
|
||||
<span className="text-white text-opacity-40">05</span>
|
||||
Step 0{stepIdx}/
|
||||
<span className="text-white text-opacity-40">0{stepCount}</span>
|
||||
</div>
|
||||
<div className="mb-3 text-2xl font-medium text-white">
|
||||
Security Settings
|
||||
|
||||
@@ -9,12 +9,16 @@ type SyncVectorDBProps = {
|
||||
connector: any;
|
||||
organization: any;
|
||||
setLoading: (loading: boolean) => void;
|
||||
stepIdx: number;
|
||||
stepCount: number;
|
||||
};
|
||||
|
||||
export default function SyncVectorDB({
|
||||
connector,
|
||||
organization,
|
||||
setLoading,
|
||||
stepIdx,
|
||||
stepCount,
|
||||
}: SyncVectorDBProps) {
|
||||
const [canSync, setCanSync] = useState(false);
|
||||
const [remoteCount, setRemoteCount] = useState(0);
|
||||
@@ -58,7 +62,8 @@ export default function SyncVectorDB({
|
||||
if (job) {
|
||||
showToast(
|
||||
'Syncing vector database and taking you to dashboard...',
|
||||
'success'
|
||||
'success',
|
||||
{ clear: true }
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
window.location.replace(paths.organization({ slug: organization.slug }));
|
||||
@@ -71,8 +76,8 @@ export default function SyncVectorDB({
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-8 font-semibold uppercase text-white">
|
||||
Step 05/
|
||||
<span className="text-white text-opacity-40">05</span>
|
||||
Step 0{stepIdx}/
|
||||
<span className="text-white text-opacity-40">0{stepCount}</span>
|
||||
</div>
|
||||
<div className="mb-3 text-2xl font-medium text-white">
|
||||
Your vector database is connected
|
||||
@@ -100,8 +105,8 @@ export default function SyncVectorDB({
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-8 font-semibold uppercase text-white">
|
||||
Step 05/
|
||||
<span className="text-white text-opacity-40">05</span>
|
||||
Step 0{stepIdx}/
|
||||
<span className="text-white text-opacity-40">0{stepCount}</span>
|
||||
</div>
|
||||
<div className="mb-3 text-2xl font-medium text-white">
|
||||
Sync your connection
|
||||
|
||||
@@ -8,6 +8,7 @@ import SecuritySettings from './Steps/SecuritySettings';
|
||||
import CreateOrganization from './Steps/CreateOrganization';
|
||||
import ConnectVectorDB from './Steps/ConnectVectorDB';
|
||||
import SyncVectorDB from './Steps/SyncVectorDB';
|
||||
import OnboardingSurvey from './Steps/OnboardingSurvey';
|
||||
|
||||
type Step = {
|
||||
title: string;
|
||||
@@ -43,6 +44,11 @@ const STEPS: Steps = {
|
||||
description: '',
|
||||
component: ConnectVectorDB,
|
||||
},
|
||||
survey: {
|
||||
title: 'Help us make VectorAdmin better',
|
||||
description: 'This optional survey helps us build VectorAdmin.',
|
||||
component: OnboardingSurvey,
|
||||
},
|
||||
sync_vector_db: {
|
||||
title: 'Sync your vector database',
|
||||
description:
|
||||
@@ -60,6 +66,7 @@ const OnboardingFlow = () => {
|
||||
const [connector, setConnector] = useState();
|
||||
|
||||
const CurrentStep = STEPS[currentStep].component;
|
||||
const stepIdx = Object.keys(STEPS).indexOf(currentStep) + 1;
|
||||
|
||||
return (
|
||||
<DefaultLayout>
|
||||
@@ -98,6 +105,8 @@ const OnboardingFlow = () => {
|
||||
setLoading={setLoading}
|
||||
connector={connector}
|
||||
setConnector={setConnector}
|
||||
stepIdx={stepIdx}
|
||||
stepCount={Object.keys(STEPS).length}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@ export const API_BASE = import.meta.env.VITE_API_BASE || '/api';
|
||||
export const APP_NAME = import.meta.env.VITE_APP_NAME || 'VDMS';
|
||||
export const STORE_USER = 'vdms_user';
|
||||
export const STORE_TOKEN = 'vdms_authToken';
|
||||
export const COMPLETE_QUESTIONNAIRE = 'vectoradmin_completed_questionnaire';
|
||||
export const SUPPORTED_VECTOR_DBS = [
|
||||
'pinecone',
|
||||
'chroma',
|
||||
|
||||
Reference in New Issue
Block a user