Skip to content

Commit

Permalink
[front] - fix(vault): allow to edit vault's name (#7442)
Browse files Browse the repository at this point in the history
* [front] - feature: enable updating vault name through API

 - Allow API clients to update the name of a vault by passing a new `name` field in the request body
 - Update the handler to support renaming a vault during a PATCH request

[types] - feature: extend PatchVaultRequestBodySchema with name field

 - Introduce optional `name` field to the vault patch request body schema to support vault renaming via API

* [front/lib/swr] - feature: enhance vault updating with name change support

 - Allow vault name updates along with member updates in a single operation
 - Execute multiple update requests concurrently and handle their responses collectively
 - Improve error handling and user notifications during vault updates
 - Ensure state revalidation by mutating vaults and vaults as admin after updates

* [front] - feature: add admin ability to update vault names

 - Ensure that only administrators can change the names of vaults
 - Check for name availability prior to updating a vault's name
 - Handle any errors that occur during the update process and return an appropriate message

* [front] - fix: enable vault name editing for existing vaults

 - Allow updating the vault name when editing an existing vault
 - Remove UI restrictions from input field for existing vault names

* [front/lib/resources] - refactor: streamline vault name update logic

 - Removed try-catch block around vault name update to simplify the function flow
 - Any errors during the update process are now handled externally

---------

Co-authored-by: Jules <[email protected]>
  • Loading branch information
JulesBelveze and Jules committed Sep 17, 2024
1 parent 4fbc2dd commit 3d3280a
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 36 deletions.
4 changes: 1 addition & 3 deletions front/components/vaults/CreateOrEditVaultModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ export function CreateOrEditVaultModal({
setIsSaving(true);

if (selectedMembers.length > 0 && vault) {
await doUpdate(vault, selectedMembers);
await doUpdate(vault, selectedMembers, vaultName);
} else if (!vault) {
const createdVault = await doCreate(vaultName, selectedMembers);
if (createdVault) {
Expand Down Expand Up @@ -247,10 +247,8 @@ export function CreateOrEditVaultModal({
placeholder="Vault's name"
value={vaultName}
name="vaultName"
className={vault ? "text-gray-300 hover:cursor-not-allowed" : ""}
size="sm"
onChange={(value) => setVaultName(value)}
disabled={!!vault}
/>
{!vault && (
<div className="flex gap-1 text-xs text-element-700">
Expand Down
18 changes: 18 additions & 0 deletions front/lib/resources/vault_resource.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ACLType, ModelId, Result, VaultType } from "@dust-tt/types";
import { Err } from "@dust-tt/types";
import { assertNever, Ok } from "@dust-tt/types";
import assert from "assert";
import type {
Expand Down Expand Up @@ -273,6 +274,23 @@ export class VaultResource extends BaseResource<VaultModel> {
});
}

async updateName(
auth: Authenticator,
newName: string
): Promise<Result<undefined, Error>> {
if (!auth.isAdmin()) {
return new Err(new Error("Only admins can update vault names."));
}

const nameAvailable = await VaultResource.isNameAvailable(auth, newName);
if (!nameAvailable) {
return new Err(new Error("This vault name is already used."));
}

await this.update({ name: newName });
return new Ok(undefined);
}

acl(): ACLType {
return {
aclEntries: this.groups.map((group) => ({
Expand Down
96 changes: 64 additions & 32 deletions front/lib/swr/vaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,46 +383,78 @@ export function useUpdateVault({ owner }: { owner: LightWorkspaceType }) {
disabled: true, // Needed just to mutate
});

const doUpdate = async (vault: VaultType, memberIds: string[] | null) => {
if (!vault || !memberIds || memberIds?.length < 1) {
const doUpdate = async (
vault: VaultType,
memberIds: string[] | null,
newName: string | null
) => {
if (!vault) {
return null;
}

// Note: we are directly updating the first group of the vault, maybe we want to hide this via a vault endpoint
const url = `/api/w/${owner.sId}/groups/${vault.groupIds[0]}`;
const res = await fetch(url, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
memberIds,
}),
});
const updatePromises: Promise<Response>[] = [];

// Prepare vault update request
if (newName) {
const vaultUrl = `/api/w/${owner.sId}/vaults/${vault.sId}`;
updatePromises.push(
fetch(vaultUrl, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: newName,
}),
})
);
}

if (!res.ok) {
const errorData = await res.json();
sendNotification({
type: "error",
title: "Error updating Vault",
description: `Error: ${errorData.message}`,
});
return null;
} else {
void mutateVaults();
void mutateVaultsAsAdmin();
// Prepare group members update request if provided
if (memberIds && memberIds.length > 0) {
const groupUrl = `/api/w/${owner.sId}/groups/${vault.groupIds[0]}`;
updatePromises.push(
fetch(groupUrl, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
memberIds,
}),
})
);
}

sendNotification({
type: "success",
title: "Successfully updated Vault",
description: "Vault was successfully updated.",
});
if (updatePromises.length === 0) {
return null;
}

const response: PatchVaultResponseBody = await res.json();
return response.vault;
const results = await Promise.all(updatePromises);

for (const res of results) {
if (!res.ok) {
const errorData = await res.json();
sendNotification({
type: "error",
title: "Error updating Vault",
description: `Error: ${errorData.message}`,
});
return null;
}
}
};
void mutateVaults();
void mutateVaultsAsAdmin();

sendNotification({
type: "success",
title: "Successfully updated Vault",
description: "Vault was successfully updated.",
});

const vaultResponse: PatchVaultResponseBody = await results[0].json();
return vaultResponse.vault;
};
return doUpdate;
}

Expand Down
5 changes: 4 additions & 1 deletion front/pages/api/w/[wId]/vaults/[vId]/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ async function handler(
});
}

const { content } = bodyValidation.right;
const { content, name } = bodyValidation.right;

if (content) {
const currentViews = await DataSourceViewResource.listByVault(
Expand Down Expand Up @@ -165,6 +165,9 @@ async function handler(
}
}
}
if (name) {
await vault.updateName(auth, name);
}
return res.status(200).json({ vault: vault.toJSON() });
}

Expand Down
1 change: 1 addition & 0 deletions types/src/front/api_handlers/public/vaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export type PostVaultRequestBodyType = t.TypeOf<
>;

export const PatchVaultRequestBodySchema = t.type({
name: t.union([t.string, t.undefined]),
memberIds: t.union([t.array(t.string), t.undefined]),
content: t.union([t.array(ContentSchema), t.undefined]),
});
Expand Down

0 comments on commit 3d3280a

Please sign in to comment.