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:
Timothy Carambat
2023-08-08 13:41:41 -07:00
committed by GitHub
8 changed files with 140 additions and 7 deletions
@@ -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],
+27
View File
@@ -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
+13
View File
@@ -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">
+1 -1
View File
@@ -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>
+3 -2
View File
@@ -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);
+3 -2
View File
@@ -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);