mirror of
https://github.com/Mintplex-Labs/vector-admin.git
synced 2026-07-21 00:15:23 -04:00
Merge pull request #31 from Mintplex-Labs/30-edit-org-display-name
add ability to update org display names from settings page
This commit is contained in:
@@ -135,6 +135,41 @@ function organizationEndpoints(app) {
|
||||
}
|
||||
);
|
||||
|
||||
app.post(
|
||||
"/v1/org/:slug",
|
||||
[validSessionForUser],
|
||||
async function (request, response) {
|
||||
try {
|
||||
const { slug } = request.params;
|
||||
const { updates = {} } = reqBody(request);
|
||||
const user = await userFromSession(request);
|
||||
if (!user) {
|
||||
response.sendStatus(403).end();
|
||||
return;
|
||||
}
|
||||
const organization = await Organization.getWithOwner(
|
||||
user.id,
|
||||
`slug = '${slug}'`
|
||||
);
|
||||
if (!organization) {
|
||||
response
|
||||
.status(200)
|
||||
.json({ success: false, error: "No org by that slug." });
|
||||
return;
|
||||
}
|
||||
|
||||
const updateResponse = await Organization.update(
|
||||
organization.id,
|
||||
updates
|
||||
);
|
||||
response.status(200).json(updateResponse);
|
||||
} catch (e) {
|
||||
console.log(e.message, e);
|
||||
response.sendStatus(500).end();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
app.get(
|
||||
"/v1/org/:slug/api-key",
|
||||
[validSessionForUser],
|
||||
|
||||
@@ -6,6 +6,7 @@ const { OrganizationApiKey } = require("./organizationApiKey");
|
||||
|
||||
const Organization = {
|
||||
tablename: "organizations",
|
||||
writable: ["name"],
|
||||
colsInit: `
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
@@ -81,6 +82,32 @@ const Organization = {
|
||||
await OrganizationApiKey.create(organization.id);
|
||||
return { organization, message: null };
|
||||
},
|
||||
update: async function (orgId = null, updates = {}) {
|
||||
if (!orgId) throw new Error("No workspace id provided for update");
|
||||
|
||||
const validKeys = Object.keys(updates).filter((key) =>
|
||||
this.writable.includes(key)
|
||||
);
|
||||
const values = Object.values(updates);
|
||||
if (validKeys.length === 0 || validKeys.length !== values.length)
|
||||
return { success: false, error: "No valid fields to update!" };
|
||||
|
||||
const template = `UPDATE ${this.tablename} SET ${validKeys.map((key) => {
|
||||
return `${key}=?`;
|
||||
})} WHERE id = ?`;
|
||||
const db = await this.db();
|
||||
const { success, error } = await db
|
||||
.run(template, [...values, orgId])
|
||||
.then(() => {
|
||||
return { success: true, error: null };
|
||||
})
|
||||
.catch((error) => {
|
||||
return { success: false, error: error.message };
|
||||
});
|
||||
|
||||
await db.close();
|
||||
return { success, error };
|
||||
},
|
||||
get: async function (clause = "") {
|
||||
const db = await this.db();
|
||||
const result = await db
|
||||
|
||||
@@ -26,6 +26,19 @@ const Organization = {
|
||||
if (!organization) return { organization: null, error };
|
||||
return { organization, error: null };
|
||||
},
|
||||
update: async (slug: string, updates: object = {}) => {
|
||||
return await fetch(`${API_BASE}/v1/org/${slug}`, {
|
||||
method: 'POST',
|
||||
cache: 'no-cache',
|
||||
body: JSON.stringify({ updates }),
|
||||
headers: baseHeaders(),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
return { success: false, error: e.message };
|
||||
});
|
||||
},
|
||||
bySlug: async (slug: string) => {
|
||||
const organization = await fetch(`${API_BASE}/v1/org/${slug}`, {
|
||||
method: 'GET',
|
||||
|
||||
@@ -224,7 +224,8 @@ const FullTextWindow = memo(
|
||||
<dialog id={`${fragment.id}-text`} className="w-1/2 rounded-lg">
|
||||
<div className="flex flex-col overflow-y-scroll p-[20px]">
|
||||
<pre className="font-mono whitespace-pre-line rounded-lg bg-slate-100 p-2">
|
||||
{data?.metadata?.text || '[ERROR] Could not parse text key from embedding'}
|
||||
{data?.metadata?.text ||
|
||||
'[ERROR] Could not parse text key from embedding'}
|
||||
</pre>
|
||||
<div className="mt-4 flex flex-col gap-y-2">
|
||||
<button
|
||||
|
||||
@@ -3,8 +3,16 @@ import { APP_NAME } from '../../../utils/constants';
|
||||
import System from '../../../models/system';
|
||||
import { ExternalLink, Eye, EyeOff } from 'react-feather';
|
||||
import paths from '../../../utils/paths';
|
||||
import Organization from '../../../models/organization';
|
||||
|
||||
export default function Settings({ settings }: { settings: any[] }) {
|
||||
export default function Settings({
|
||||
settings,
|
||||
organization,
|
||||
}: {
|
||||
settings: any[];
|
||||
organization: any;
|
||||
}) {
|
||||
const [hasOrgChanges, setHasOrgChanges] = useState(false);
|
||||
const [result, setResult] = useState<{
|
||||
show: boolean;
|
||||
success: boolean;
|
||||
@@ -28,6 +36,21 @@ export default function Settings({ settings }: { settings: any[] }) {
|
||||
const { success, error } = await System.updateSettings(data);
|
||||
setResult({ show: true, success, error });
|
||||
};
|
||||
const handleOrgUpdate = async (e: any) => {
|
||||
e.preventDefault();
|
||||
setResult({ show: false, success: false, error: null });
|
||||
const form = new FormData(e.target);
|
||||
const newOrgName =
|
||||
(form.get('organization_name') as string) || organization?.name;
|
||||
const data = { name: newOrgName };
|
||||
|
||||
const { success, error } = await Organization.update(
|
||||
organization.slug,
|
||||
data
|
||||
);
|
||||
setResult({ show: true, success, error });
|
||||
success && setHasOrgChanges(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="col-span-12 flex-1 rounded-sm bg-white pb-6 xl:col-span-4">
|
||||
@@ -54,6 +77,38 @@ export default function Settings({ settings }: { settings: any[] }) {
|
||||
</>
|
||||
)}
|
||||
|
||||
<form
|
||||
onChange={() => setHasOrgChanges(true)}
|
||||
onSubmit={handleOrgUpdate}
|
||||
className="border-b border-gray-200 pb-4"
|
||||
>
|
||||
<div className="my-4">
|
||||
<label className=" block flex items-center gap-x-1 font-medium text-black dark:text-white">
|
||||
Organization name
|
||||
</label>
|
||||
<p className="mb-2.5 text-sm text-slate-600">
|
||||
This will only change the display name of the organization.
|
||||
</p>
|
||||
<div className="relative flex w-1/2 items-center gap-x-4">
|
||||
<input
|
||||
type="text"
|
||||
name="organization_name"
|
||||
placeholder="My Organization"
|
||||
defaultValue={organization.name}
|
||||
required={true}
|
||||
className="w-full rounded-lg border border-stroke bg-transparent py-4 pl-6 pr-10 outline-none focus:border-primary focus-visible:shadow-none dark:border-form-strokedark dark:bg-form-input dark:focus:border-primary"
|
||||
/>
|
||||
<button
|
||||
hidden={!hasOrgChanges}
|
||||
type="submit"
|
||||
className="rounded-lg border border-primary px-8 py-3 text-lg text-blue-500 transition-all duration-300 hover:bg-primary hover:text-white"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="my-4">
|
||||
<label className=" block flex items-center gap-x-1 font-medium text-black dark:text-white">
|
||||
|
||||
@@ -73,7 +73,7 @@ export default function SystemSettingsView() {
|
||||
>
|
||||
<div className="mt-4 grid grid-cols-12 gap-4 md:mt-6 md:gap-6 2xl:mt-7.5 2xl:gap-7.5">
|
||||
<div className="col-span-12 xl:col-span-12">
|
||||
<Settings settings={settings} />
|
||||
<Settings settings={settings} organization={organization} />
|
||||
</div>
|
||||
</div>
|
||||
</AppLayout>
|
||||
|
||||
@@ -69,8 +69,9 @@ const syncChromaInstance = InngestClient.createFunction(
|
||||
}
|
||||
|
||||
result = {
|
||||
message: `Chroma instance vector data has been synced for ${collections.length
|
||||
} of ${collections.length - failedToSync.length} collections.`,
|
||||
message: `Chroma instance vector data has been synced for ${
|
||||
collections.length
|
||||
} of ${collections.length - failedToSync.length} collections.`,
|
||||
failedToSync,
|
||||
};
|
||||
await Queue.updateJob(jobId, Queue.status.complete, result);
|
||||
|
||||
@@ -69,8 +69,9 @@ const syncPineconeIndex = InngestClient.createFunction(
|
||||
}
|
||||
|
||||
result = {
|
||||
message: `Pinecone instance vector data has been synced for ${collections.length
|
||||
} of ${collections.length - failedToSync.length} namespaces.`,
|
||||
message: `Pinecone instance vector data has been synced for ${
|
||||
collections.length
|
||||
} of ${collections.length - failedToSync.length} namespaces.`,
|
||||
failedToSync,
|
||||
};
|
||||
await Queue.updateJob(jobId, Queue.status.complete, result);
|
||||
|
||||
Reference in New Issue
Block a user