From ad837a9bf1f378d8464a886e00545ac478beff11 Mon Sep 17 00:00:00 2001 From: Milos Petrovic Date: Tue, 4 Aug 2026 19:41:28 +0200 Subject: [PATCH 1/6] Add space management UI: rename and delete --- .../app/components/library/library-layout.tsx | 91 ++++++++++-- .../app/components/library/space-card.tsx | 76 +++++++++-- .../app/components/library/space-dialogs.tsx | 129 ++++++++++++++++++ templates/clips/app/hooks/use-library.ts | 4 +- .../clips/app/routes/_app.spaces._index.tsx | 4 +- 5 files changed, 274 insertions(+), 30 deletions(-) create mode 100644 templates/clips/app/components/library/space-dialogs.tsx diff --git a/templates/clips/app/components/library/library-layout.tsx b/templates/clips/app/components/library/library-layout.tsx index ccf8733e2f..71b14d2422 100644 --- a/templates/clips/app/components/library/library-layout.tsx +++ b/templates/clips/app/components/library/library-layout.tsx @@ -34,6 +34,8 @@ import { IconSearch, IconUpload, IconLink, + IconDots, + IconEdit, } from "@tabler/icons-react"; import { ReactNode, useEffect, useMemo, useState } from "react"; import { NavLink, useLocation, useParams } from "react-router"; @@ -53,6 +55,12 @@ import { AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; import { Tooltip, TooltipContent, @@ -74,6 +82,7 @@ import { CreateSpaceDialog } from "./create-space-dialog"; import { FolderTree, type FolderNode } from "./folder-tree"; import { PageHeaderSlotProvider } from "./page-header"; import { SearchBar } from "./search-bar"; +import { SpaceDialogs } from "./space-dialogs"; interface LibraryLayoutProps { children: ReactNode; @@ -124,7 +133,7 @@ export function LibraryLayout({ children }: LibraryLayoutProps) { const currentOrganizationId = organizations?.currentId ?? organizations?.organizations?.[0]?.id; - const { data: spaces } = useSpaces(currentOrganizationId, { + const { data: spaces, refetch: refetchSpaces } = useSpaces(currentOrganizationId, { enabled: hasActiveOrg && Boolean(currentOrganizationId), }); const { data: libFolders } = useFolders( @@ -241,6 +250,10 @@ export function LibraryLayout({ children }: LibraryLayoutProps) { const [newFolderOpen, setNewFolderOpen] = useState(false); const [newFolderName, setNewFolderName] = useState(""); const [newSpaceOpen, setNewSpaceOpen] = useState(false); + const [deleteSpaceId, setDeleteSpaceId] = useState(null); + const [deleteSpaceName, setDeleteSpaceName] = useState(""); + const [renameSpaceId, setRenameSpaceId] = useState(null); + const [renameSpaceValue, setRenameSpaceValue] = useState(""); const createFolder = useCreateFolder(); const navItems: { @@ -579,26 +592,64 @@ export function LibraryLayout({ children }: LibraryLayoutProps) { const active = spaceId === s.id; return (
  • - -
    - {s.iconEmoji ?? s.name.slice(0, 1).toUpperCase()} -
    - {s.name} -
    +
    + {s.iconEmoji ?? + s.name.slice(0, 1).toUpperCase()} +
    + {s.name} + + + + + + + { + setRenameSpaceValue(s.name); + setRenameSpaceId(s.id); + }} + > + + Rename + + { + setDeleteSpaceId(s.id); + setDeleteSpaceName(s.name); + }} + className="text-destructive" + > + + Delete + + + +
  • ); })} @@ -821,6 +872,18 @@ export function LibraryLayout({ children }: LibraryLayoutProps) { onOpenChange={setNewSpaceOpen} organizationId={currentOrganizationId} /> + + refetchSpaces?.()} + /> ); } diff --git a/templates/clips/app/components/library/space-card.tsx b/templates/clips/app/components/library/space-card.tsx index dbe9916633..90562bbf63 100644 --- a/templates/clips/app/components/library/space-card.tsx +++ b/templates/clips/app/components/library/space-card.tsx @@ -1,7 +1,15 @@ -import { IconUsersGroup, IconVideo } from "@tabler/icons-react"; +import { IconUsersGroup, IconVideo, IconTrash, IconEdit } from "@tabler/icons-react"; import { Link } from "react-router"; +import { useState } from "react"; import { cn } from "@/lib/utils"; +import { + ContextMenu, + ContextMenuContent, + ContextMenuItem, + ContextMenuTrigger, +} from "@/components/ui/context-menu"; +import { SpaceDialogs } from "./space-dialogs"; export interface SpaceCardData { id: string; @@ -16,23 +24,30 @@ export interface SpaceCardData { interface SpaceCardProps { space: SpaceCardData; className?: string; + onMutationSuccess?: () => void; } -export function SpaceCard({ space, className }: SpaceCardProps) { +export function SpaceCard({ space, className, onMutationSuccess }: SpaceCardProps) { const color = space.color || "hsl(var(--primary))"; const members = space.memberEmails ?? []; const initial = (space.name.trim().slice(0, 1) || "S").toUpperCase(); + const [renameSpaceId, setRenameSpaceId] = useState(null); + const [renameValue, setRenameValue] = useState(""); + const [deleteSpaceId, setDeleteSpaceId] = useState(null); return ( - + <> + + +
    )}
    - + +
    + + { + e.preventDefault(); + setRenameValue(space.name); + setRenameSpaceId(space.id); + }} + > + + Rename + + { + e.preventDefault(); + setDeleteSpaceId(space.id); + }} + className="text-destructive focus:text-destructive" + > + + Delete space + + +
    + + + ); } diff --git a/templates/clips/app/components/library/space-dialogs.tsx b/templates/clips/app/components/library/space-dialogs.tsx new file mode 100644 index 0000000000..dde43ee794 --- /dev/null +++ b/templates/clips/app/components/library/space-dialogs.tsx @@ -0,0 +1,129 @@ +import { useState } from "react"; +import { useActionMutation } from "@agent-native/core/client/hooks"; +import { toast } from "sonner"; + +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogTitle, +} from "@/components/ui/alert-dialog"; + +interface SpaceDialogsProps { + renameSpaceId: string | null; + renameSpaceName: string; + setRenameSpaceId: (id: string | null) => void; + renameValue: string; + setRenameValue: (value: string) => void; + deleteSpaceId: string | null; + deleteSpaceName: string; + setDeleteSpaceId: (id: string | null) => void; + onMutationSuccess?: () => void; +} + +export function SpaceDialogs({ + renameSpaceId, + renameSpaceName, + setRenameSpaceId, + renameValue, + setRenameValue, + deleteSpaceId, + deleteSpaceName, + setDeleteSpaceId, + onMutationSuccess, +}: SpaceDialogsProps) { + const renameSpace = useActionMutation("rename-space"); + const deleteSpace = useActionMutation("delete-space"); + + const handleRename = async () => { + if (!renameSpaceId) return; + try { + await renameSpace.mutateAsync({ + id: renameSpaceId, + name: renameValue.trim(), + }); + toast.success("Space renamed"); + setRenameSpaceId(null); + setRenameValue(""); + onMutationSuccess?.(); + } catch (err) { + toast.error( + err instanceof Error ? err.message : "Failed to rename space" + ); + } + }; + + const handleDelete = async () => { + if (!deleteSpaceId) return; + try { + await deleteSpace.mutateAsync({ id: deleteSpaceId }); + toast.success(`Deleted "${deleteSpaceName}"`); + setDeleteSpaceId(null); + onMutationSuccess?.(); + } catch (err) { + toast.error(err instanceof Error ? err.message : "Failed to delete space"); + } + }; + + return ( + <> + {/* Rename space dialog */} + { + if (!open) { + setRenameSpaceId(null); + setRenameValue(""); + } + }} + > + + Rename space + setRenameValue(e.target.value)} + className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-primary/30" + /> +
    + Cancel + + {renameSpace.isPending ? "Renaming..." : "Rename"} + +
    +
    +
    + + {/* Delete space dialog */} + { + if (!open) setDeleteSpaceId(null); + }} + > + + Delete "{deleteSpaceName}"? + + This will delete the space and remove it from all recordings. This + action cannot be undone. + +
    + Cancel + + {deleteSpace.isPending ? "Deleting..." : "Delete"} + +
    +
    +
    + + ); +} diff --git a/templates/clips/app/hooks/use-library.ts b/templates/clips/app/hooks/use-library.ts index 8356a57e35..91252264ff 100644 --- a/templates/clips/app/hooks/use-library.ts +++ b/templates/clips/app/hooks/use-library.ts @@ -240,11 +240,11 @@ export function useSpaces( organizationId?: string, options: { enabled?: boolean } = {}, ) { - const { data, isLoading } = useOrganizationState(organizationId, { + const { data, isLoading, refetch } = useOrganizationState(organizationId, { enabled: options.enabled ?? Boolean(organizationId), }); const spaces = Array.isArray(data?.spaces) ? (data.spaces as any[]) : []; - return { data: { spaces }, isLoading }; + return { data: { spaces }, isLoading, refetch }; } export function useOrganizations(options: { enabled?: boolean } = {}) { diff --git a/templates/clips/app/routes/_app.spaces._index.tsx b/templates/clips/app/routes/_app.spaces._index.tsx index 2fe0b88e45..35a5357c5d 100644 --- a/templates/clips/app/routes/_app.spaces._index.tsx +++ b/templates/clips/app/routes/_app.spaces._index.tsx @@ -34,7 +34,7 @@ export default function SpacesIndexRoute() { const { data: organizations } = useOrganizations(); const currentOrganizationId = organizations?.currentId ?? organizations?.organizations?.[0]?.id; - const { data, isLoading } = useSpaces(currentOrganizationId); + const { data, isLoading, refetch } = useSpaces(currentOrganizationId); const spaces: SpaceCardData[] = (data?.spaces ?? []).map((s: any) => ({ id: s.id, @@ -80,7 +80,7 @@ export default function SpacesIndexRoute() { ) : (
    {spaces.map((s) => ( - + refetch?.()} /> ))}
    )} From 1973e2f2f45c41332299a5f086852e558aa17e64 Mon Sep 17 00:00:00 2001 From: Milos Petrovic Date: Tue, 4 Aug 2026 20:00:51 +0200 Subject: [PATCH 2/6] fix --- .../app/components/library/library-layout.tsx | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/templates/clips/app/components/library/library-layout.tsx b/templates/clips/app/components/library/library-layout.tsx index 71b14d2422..6dc961af7c 100644 --- a/templates/clips/app/components/library/library-layout.tsx +++ b/templates/clips/app/components/library/library-layout.tsx @@ -133,9 +133,12 @@ export function LibraryLayout({ children }: LibraryLayoutProps) { const currentOrganizationId = organizations?.currentId ?? organizations?.organizations?.[0]?.id; - const { data: spaces, refetch: refetchSpaces } = useSpaces(currentOrganizationId, { - enabled: hasActiveOrg && Boolean(currentOrganizationId), - }); + const { data: spaces, refetch: refetchSpaces } = useSpaces( + currentOrganizationId, + { + enabled: hasActiveOrg && Boolean(currentOrganizationId), + }, + ); const { data: libFolders } = useFolders( { organizationId: currentOrganizationId, @@ -630,8 +633,10 @@ export function LibraryLayout({ children }: LibraryLayoutProps) { { - setRenameSpaceValue(s.name); - setRenameSpaceId(s.id); + setTimeout(() => { + setRenameSpaceValue(s.name); + setRenameSpaceId(s.id); + }, 0); }} > @@ -639,8 +644,10 @@ export function LibraryLayout({ children }: LibraryLayoutProps) { { - setDeleteSpaceId(s.id); - setDeleteSpaceName(s.name); + setTimeout(() => { + setDeleteSpaceId(s.id); + setDeleteSpaceName(s.name); + }, 0); }} className="text-destructive" > From 69143a73509d89599718f4254b8c5ea624b8bcfa Mon Sep 17 00:00:00 2001 From: Milos Petrovic Date: Wed, 5 Aug 2026 11:07:05 +0200 Subject: [PATCH 3/6] feedback --- .../app/components/library/library-layout.tsx | 86 +++++---- .../app/components/library/space-card.tsx | 178 ++++++++++-------- .../app/components/library/space-dialogs.tsx | 12 +- 3 files changed, 151 insertions(+), 125 deletions(-) diff --git a/templates/clips/app/components/library/library-layout.tsx b/templates/clips/app/components/library/library-layout.tsx index 6dc961af7c..f58870f0f8 100644 --- a/templates/clips/app/components/library/library-layout.tsx +++ b/templates/clips/app/components/library/library-layout.tsx @@ -38,7 +38,7 @@ import { IconEdit, } from "@tabler/icons-react"; import { ReactNode, useEffect, useMemo, useState } from "react"; -import { NavLink, useLocation, useParams } from "react-router"; +import { NavLink, useLocation, useNavigate, useParams } from "react-router"; import { toast } from "sonner"; import { @@ -108,6 +108,7 @@ function ClipsAgentToggleButton() { export function LibraryLayout({ children }: LibraryLayoutProps) { const location = useLocation(); + const navigate = useNavigate(); const t = useT(); // Bind chat to the currently-open recording (`/r/:id`). Library, spaces, // meetings, dictate, and settings stay unscoped — those are list-y views @@ -619,43 +620,45 @@ export function LibraryLayout({ children }: LibraryLayoutProps) { {s.name} - - - - - - { - setTimeout(() => { - setRenameSpaceValue(s.name); - setRenameSpaceId(s.id); - }, 0); - }} - > - - Rename - - { - setTimeout(() => { - setDeleteSpaceId(s.id); - setDeleteSpaceName(s.name); - }, 0); - }} - className="text-destructive" - > - - Delete - - - + {canManageOrg && ( + + + + + + { + setTimeout(() => { + setRenameSpaceValue(s.name); + setRenameSpaceId(s.id); + }, 0); + }} + > + + Rename + + { + setTimeout(() => { + setDeleteSpaceId(s.id); + setDeleteSpaceName(s.name); + }, 0); + }} + className="text-destructive" + > + + Delete + + + + )} ); @@ -889,7 +892,12 @@ export function LibraryLayout({ children }: LibraryLayoutProps) { deleteSpaceId={deleteSpaceId} deleteSpaceName={deleteSpaceName} setDeleteSpaceId={setDeleteSpaceId} - onMutationSuccess={() => refetchSpaces?.()} + onMutationSuccess={(deletedSpaceId) => { + if (deletedSpaceId && spaceId === deletedSpaceId) { + navigate("/spaces"); + } + refetchSpaces?.(); + }} /> ); diff --git a/templates/clips/app/components/library/space-card.tsx b/templates/clips/app/components/library/space-card.tsx index 90562bbf63..cc8f835e84 100644 --- a/templates/clips/app/components/library/space-card.tsx +++ b/templates/clips/app/components/library/space-card.tsx @@ -1,14 +1,21 @@ -import { IconUsersGroup, IconVideo, IconTrash, IconEdit } from "@tabler/icons-react"; -import { Link } from "react-router"; +import { useOrgRole } from "@agent-native/core/client/org"; +import { + IconUsersGroup, + IconVideo, + IconTrash, + IconEdit, +} from "@tabler/icons-react"; import { useState } from "react"; +import { Link } from "react-router"; -import { cn } from "@/lib/utils"; import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger, } from "@/components/ui/context-menu"; +import { cn } from "@/lib/utils"; + import { SpaceDialogs } from "./space-dialogs"; export interface SpaceCardData { @@ -27,7 +34,12 @@ interface SpaceCardProps { onMutationSuccess?: () => void; } -export function SpaceCard({ space, className, onMutationSuccess }: SpaceCardProps) { +export function SpaceCard({ + space, + className, + onMutationSuccess, +}: SpaceCardProps) { + const { canManageOrg } = useOrgRole(); const color = space.color || "hsl(var(--primary))"; const members = space.memberEmails ?? []; const initial = (space.name.trim().slice(0, 1) || "S").toUpperCase(); @@ -48,87 +60,91 @@ export function SpaceCard({ space, className, onMutationSuccess }: SpaceCardProp className, )} > -
    - {space.iconEmoji ? ( - {space.iconEmoji} - ) : ( - {initial} - )} -
    -
    -

    - {space.name} -

    -
    -
    - - - {space.memberCount ?? members.length} member - {(space.memberCount ?? members.length) === 1 ? "" : "s"} - -
    -
    - - - {space.recordingCount ?? 0} recording - {(space.recordingCount ?? 0) === 1 ? "" : "s"} - -
    -
    - - {members.length > 0 && ( -
    - {members.slice(0, 5).map((email) => { - const initials = (email.split("@")[0] || "?") - .slice(0, 2) - .toUpperCase(); - return ( -
    - {initials} +
    + {space.iconEmoji ? ( + {space.iconEmoji} + ) : ( + + {initial} + + )} +
    +
    +

    + {space.name} +

    +
    +
    + + + {space.memberCount ?? members.length} member + {(space.memberCount ?? members.length) === 1 ? "" : "s"} + +
    +
    + + + {space.recordingCount ?? 0} recording + {(space.recordingCount ?? 0) === 1 ? "" : "s"} +
    - ); - })} - {members.length > 5 && ( -
    - +{members.length - 5}
    - )} -
    - )} -
    + + {members.length > 0 && ( +
    + {members.slice(0, 5).map((email) => { + const initials = (email.split("@")[0] || "?") + .slice(0, 2) + .toUpperCase(); + return ( +
    + {initials} +
    + ); + })} + {members.length > 5 && ( +
    + +{members.length - 5} +
    + )} +
    + )} +
    - - { - e.preventDefault(); - setRenameValue(space.name); - setRenameSpaceId(space.id); - }} - > - - Rename - - { - e.preventDefault(); - setDeleteSpaceId(space.id); - }} - className="text-destructive focus:text-destructive" - > - - Delete space - - + {canManageOrg && ( + + { + e.preventDefault(); + setRenameValue(space.name); + setRenameSpaceId(space.id); + }} + > + + Rename + + { + e.preventDefault(); + setDeleteSpaceId(space.id); + }} + className="text-destructive focus:text-destructive" + > + + Delete space + + + )} void; - onMutationSuccess?: () => void; + onMutationSuccess?: (deletedSpaceId?: string) => void; } export function SpaceDialogs({ @@ -50,7 +50,7 @@ export function SpaceDialogs({ onMutationSuccess?.(); } catch (err) { toast.error( - err instanceof Error ? err.message : "Failed to rename space" + err instanceof Error ? err.message : "Failed to rename space", ); } }; @@ -61,9 +61,11 @@ export function SpaceDialogs({ await deleteSpace.mutateAsync({ id: deleteSpaceId }); toast.success(`Deleted "${deleteSpaceName}"`); setDeleteSpaceId(null); - onMutationSuccess?.(); + onMutationSuccess?.(deleteSpaceId); } catch (err) { - toast.error(err instanceof Error ? err.message : "Failed to delete space"); + toast.error( + err instanceof Error ? err.message : "Failed to delete space", + ); } }; From 1f1f6a4dff9b8d32e1c6930e936144959da6e7af Mon Sep 17 00:00:00 2001 From: Milos Petrovic Date: Wed, 5 Aug 2026 11:35:34 +0200 Subject: [PATCH 4/6] fmtg --- templates/clips/app/routes/_app.spaces._index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/templates/clips/app/routes/_app.spaces._index.tsx b/templates/clips/app/routes/_app.spaces._index.tsx index 35a5357c5d..31a04fcd9f 100644 --- a/templates/clips/app/routes/_app.spaces._index.tsx +++ b/templates/clips/app/routes/_app.spaces._index.tsx @@ -80,7 +80,11 @@ export default function SpacesIndexRoute() { ) : (
    {spaces.map((s) => ( - refetch?.()} /> + refetch?.()} + /> ))}
    )} From 11e26c1229270f77ad01bbaa56062b788c0e7602 Mon Sep 17 00:00:00 2001 From: Milos Petrovic Date: Wed, 5 Aug 2026 11:47:08 +0200 Subject: [PATCH 5/6] add translations --- .../app/components/library/space-card.tsx | 6 ++-- .../app/components/library/space-dialogs.tsx | 31 ++++++++++++------- templates/clips/app/i18n/ar-SA.ts | 13 ++++++++ templates/clips/app/i18n/de-DE.ts | 13 ++++++++ templates/clips/app/i18n/en-US.ts | 13 ++++++++ templates/clips/app/i18n/es-ES.ts | 13 ++++++++ templates/clips/app/i18n/fr-FR.ts | 13 ++++++++ templates/clips/app/i18n/hi-IN.ts | 13 ++++++++ templates/clips/app/i18n/ja-JP.ts | 13 ++++++++ templates/clips/app/i18n/ko-KR.ts | 13 ++++++++ templates/clips/app/i18n/pt-BR.ts | 13 ++++++++ templates/clips/app/i18n/zh-CN.ts | 12 +++++++ templates/clips/app/i18n/zh-TW.ts | 12 +++++++ 13 files changed, 164 insertions(+), 14 deletions(-) diff --git a/templates/clips/app/components/library/space-card.tsx b/templates/clips/app/components/library/space-card.tsx index cc8f835e84..8408ce5b86 100644 --- a/templates/clips/app/components/library/space-card.tsx +++ b/templates/clips/app/components/library/space-card.tsx @@ -1,3 +1,4 @@ +import { useT } from "@agent-native/core/client/i18n"; import { useOrgRole } from "@agent-native/core/client/org"; import { IconUsersGroup, @@ -39,6 +40,7 @@ export function SpaceCard({ className, onMutationSuccess, }: SpaceCardProps) { + const t = useT(); const { canManageOrg } = useOrgRole(); const color = space.color || "hsl(var(--primary))"; const members = space.memberEmails ?? []; @@ -131,7 +133,7 @@ export function SpaceCard({ }} > - Rename + {t("spaceDialog.renameSpace")} { @@ -141,7 +143,7 @@ export function SpaceCard({ className="text-destructive focus:text-destructive" > - Delete space + {t("spaceDialog.deleteSpace")} )} diff --git a/templates/clips/app/components/library/space-dialogs.tsx b/templates/clips/app/components/library/space-dialogs.tsx index 70e4f9e224..88a9ed0b7e 100644 --- a/templates/clips/app/components/library/space-dialogs.tsx +++ b/templates/clips/app/components/library/space-dialogs.tsx @@ -1,4 +1,5 @@ import { useActionMutation } from "@agent-native/core/client/hooks"; +import { useT } from "@agent-native/core/client/i18n"; import { useState } from "react"; import { toast } from "sonner"; @@ -34,6 +35,7 @@ export function SpaceDialogs({ setDeleteSpaceId, onMutationSuccess, }: SpaceDialogsProps) { + const t = useT(); const renameSpace = useActionMutation("rename-space"); const deleteSpace = useActionMutation("delete-space"); @@ -44,13 +46,13 @@ export function SpaceDialogs({ id: renameSpaceId, name: renameValue.trim(), }); - toast.success("Space renamed"); + toast.success(t("spaceDialog.renamed")); setRenameSpaceId(null); setRenameValue(""); onMutationSuccess?.(); } catch (err) { toast.error( - err instanceof Error ? err.message : "Failed to rename space", + err instanceof Error ? err.message : t("spaceDialog.renameFailed"), ); } }; @@ -59,12 +61,12 @@ export function SpaceDialogs({ if (!deleteSpaceId) return; try { await deleteSpace.mutateAsync({ id: deleteSpaceId }); - toast.success(`Deleted "${deleteSpaceName}"`); + toast.success(t("spaceDialog.deleted", { name: deleteSpaceName })); setDeleteSpaceId(null); onMutationSuccess?.(deleteSpaceId); } catch (err) { toast.error( - err instanceof Error ? err.message : "Failed to delete space", + err instanceof Error ? err.message : t("spaceDialog.deleteFailed"), ); } }; @@ -82,7 +84,7 @@ export function SpaceDialogs({ }} > - Rename space + {t("spaceDialog.renameSpace")}
    - Cancel + {t("common.cancel")} - {renameSpace.isPending ? "Renaming..." : "Rename"} + {renameSpace.isPending + ? t("spaceDialog.renaming") + : t("spaceDialog.renameSpace")}
    @@ -109,19 +113,22 @@ export function SpaceDialogs({ }} > - Delete "{deleteSpaceName}"? + + {t("spaceDialog.deleteTitle", { name: deleteSpaceName })} + - This will delete the space and remove it from all recordings. This - action cannot be undone. + {t("spaceDialog.deleteDescription")}
    - Cancel + {t("common.cancel")} - {deleteSpace.isPending ? "Deleting..." : "Delete"} + {deleteSpace.isPending + ? t("spaceDialog.deleting") + : t("spaceDialog.deleteSpace")}
    diff --git a/templates/clips/app/i18n/ar-SA.ts b/templates/clips/app/i18n/ar-SA.ts index ddc020ab29..cc570ccdf1 100644 --- a/templates/clips/app/i18n/ar-SA.ts +++ b/templates/clips/app/i18n/ar-SA.ts @@ -1113,6 +1113,19 @@ const messages = { spaceCreated: "تم إنشاء المساحة", createFailed: "تعذر إنشاء المساحة", }, + spaceDialog: { + deleteSpace: "حذف المساحة", + renameSpace: "إعادة تسمية المساحة", + deleteTitle: 'حذف "{{name}}"؟', + deleteDescription: + "سيؤدي ذلك إلى حذف المساحة وإزالتها من جميع التسجيلات. لا يمكن التراجع عن هذا الإجراء.", + renamed: "تمت إعادة تسمية المساحة", + deleted: 'تم حذف "{{name}}"', + renameFailed: "فشلت إعادة تسمية المساحة", + deleteFailed: "فشل حذف المساحة", + renaming: "جارٍ إعادة التسمية...", + deleting: "جارٍ الحذف...", + }, signInPrompt: { title: "سجّل الدخول من أجل {{intent}}", description: diff --git a/templates/clips/app/i18n/de-DE.ts b/templates/clips/app/i18n/de-DE.ts index a31d489ec4..fde25a8e51 100644 --- a/templates/clips/app/i18n/de-DE.ts +++ b/templates/clips/app/i18n/de-DE.ts @@ -1136,6 +1136,19 @@ Alle sichtbaren Änderungen für Clips-Nutzer werden hier dokumentiert. Du kanns spaceCreated: "Bereich erstellt", createFailed: "Bereich konnte nicht erstellt werden", }, + spaceDialog: { + deleteSpace: "Bereich löschen", + renameSpace: "Bereich umbenennen", + deleteTitle: "„{{name}}“ löschen?", + deleteDescription: + "Dadurch wird der Bereich gelöscht und aus allen Aufnahmen entfernt. Diese Aktion kann nicht rückgängig gemacht werden.", + renamed: "Bereich umbenannt", + deleted: "„{{name}}“ gelöscht", + renameFailed: "Bereich konnte nicht umbenannt werden", + deleteFailed: "Bereich konnte nicht gelöscht werden", + renaming: "Wird umbenannt...", + deleting: "Wird gelöscht...", + }, signInPrompt: { title: "Anmelden, um {{intent}}", description: diff --git a/templates/clips/app/i18n/en-US.ts b/templates/clips/app/i18n/en-US.ts index 3b96b947a1..9fef6d45cc 100644 --- a/templates/clips/app/i18n/en-US.ts +++ b/templates/clips/app/i18n/en-US.ts @@ -1101,6 +1101,19 @@ All notable user-facing changes to Clips are documented here. Open it any time f spaceCreated: "Space created", createFailed: "Could not create space", }, + spaceDialog: { + deleteSpace: "Delete space", + renameSpace: "Rename space", + deleteTitle: 'Delete "{{name}}"?', + deleteDescription: + "This will delete the space and remove it from all recordings. This action cannot be undone.", + renamed: "Space renamed", + deleted: 'Deleted "{{name}}"', + renameFailed: "Failed to rename space", + deleteFailed: "Failed to delete space", + renaming: "Renaming...", + deleting: "Deleting...", + }, signInPrompt: { title: "Sign in to {{intent}}", description: diff --git a/templates/clips/app/i18n/es-ES.ts b/templates/clips/app/i18n/es-ES.ts index 78aa6e7e9d..f1045ee727 100644 --- a/templates/clips/app/i18n/es-ES.ts +++ b/templates/clips/app/i18n/es-ES.ts @@ -1129,6 +1129,19 @@ Todos los cambios visibles para los usuarios de Clips se documentan aquí. Puede spaceCreated: "Espacio creado", createFailed: "No se pudo crear el espacio", }, + spaceDialog: { + deleteSpace: "Eliminar espacio", + renameSpace: "Renombrar espacio", + deleteTitle: "¿Eliminar «{{name}}»?", + deleteDescription: + "Esto eliminará el espacio y lo quitará de todas las grabaciones. Esta acción no se puede deshacer.", + renamed: "Espacio renombrado", + deleted: "Se eliminó «{{name}}»", + renameFailed: "No se pudo renombrar el espacio", + deleteFailed: "No se pudo eliminar el espacio", + renaming: "Renombrando...", + deleting: "Eliminando...", + }, signInPrompt: { title: "Inicia sesión para {{intent}}", description: diff --git a/templates/clips/app/i18n/fr-FR.ts b/templates/clips/app/i18n/fr-FR.ts index a9779f3b47..3a172b98a7 100644 --- a/templates/clips/app/i18n/fr-FR.ts +++ b/templates/clips/app/i18n/fr-FR.ts @@ -1131,6 +1131,19 @@ Tous les changements visibles par les utilisateurs de Clips sont documentés ici spaceCreated: "Espace créé", createFailed: "Impossible de créer l’espace", }, + spaceDialog: { + deleteSpace: "Supprimer l’espace", + renameSpace: "Renommer l’espace", + deleteTitle: "Supprimer « {{name}} » ?", + deleteDescription: + "Cette action supprimera l’espace et le retirera de tous les enregistrements. Elle est irréversible.", + renamed: "Espace renommé", + deleted: "« {{name}} » supprimé", + renameFailed: "Échec du renommage de l’espace", + deleteFailed: "Échec de la suppression de l’espace", + renaming: "Renommage...", + deleting: "Suppression...", + }, signInPrompt: { title: "Connectez-vous pour {{intent}}", description: diff --git a/templates/clips/app/i18n/hi-IN.ts b/templates/clips/app/i18n/hi-IN.ts index 78ad5f34c1..54ae57f451 100644 --- a/templates/clips/app/i18n/hi-IN.ts +++ b/templates/clips/app/i18n/hi-IN.ts @@ -1091,6 +1091,19 @@ Clips में उपयोगकर्ताओं को दिखने व spaceCreated: "स्पेस बनाई गई", createFailed: "स्पेस नहीं बनाई जा सकी", }, + spaceDialog: { + deleteSpace: "स्पेस हटाएं", + renameSpace: "स्पेस का नाम बदलें", + deleteTitle: '"{{name}}" हटाएं?', + deleteDescription: + "यह स्पेस को हटा देगा और सभी रिकॉर्डिंग से निकाल देगा। इस कार्रवाई को पूर्ववत नहीं किया जा सकता।", + renamed: "स्पेस का नाम बदल दिया गया", + deleted: '"{{name}}" हटा दिया गया', + renameFailed: "स्पेस का नाम बदलना विफल", + deleteFailed: "स्पेस हटाना विफल", + renaming: "नाम बदला जा रहा है...", + deleting: "हटाया जा रहा है...", + }, signInPrompt: { title: "{{intent}} के लिए साइन इन करें", description: diff --git a/templates/clips/app/i18n/ja-JP.ts b/templates/clips/app/i18n/ja-JP.ts index e715788248..b1bb97738c 100644 --- a/templates/clips/app/i18n/ja-JP.ts +++ b/templates/clips/app/i18n/ja-JP.ts @@ -1114,6 +1114,19 @@ Clips のユーザー向けの主な変更はここに記録されます。コ spaceCreated: "スペースを作成しました", createFailed: "スペースを作成できませんでした", }, + spaceDialog: { + deleteSpace: "スペースを削除", + renameSpace: "スペース名を変更", + deleteTitle: "「{{name}}」を削除しますか?", + deleteDescription: + "スペースを削除し、すべての録画から削除します。この操作は元に戻せません。", + renamed: "スペース名を変更しました", + deleted: "「{{name}}」を削除しました", + renameFailed: "スペース名の変更に失敗しました", + deleteFailed: "スペースの削除に失敗しました", + renaming: "名前を変更中...", + deleting: "削除中...", + }, signInPrompt: { title: "{{intent}}するにはログイン", description: diff --git a/templates/clips/app/i18n/ko-KR.ts b/templates/clips/app/i18n/ko-KR.ts index ca9671de0d..eb1430fa80 100644 --- a/templates/clips/app/i18n/ko-KR.ts +++ b/templates/clips/app/i18n/ko-KR.ts @@ -1102,6 +1102,19 @@ Clips의 모든 사용자 대상 변경 사항은 여기에 기록됩니다. 명 spaceCreated: "공간이 생성되었습니다", createFailed: "공간을 만들 수 없습니다", }, + spaceDialog: { + deleteSpace: "스페이스 삭제", + renameSpace: "스페이스 이름 변경", + deleteTitle: "“{{name}}”을(를) 삭제할까요?", + deleteDescription: + "스페이스가 삭제되고 모든 녹화에서 제거됩니다. 이 작업은 취소할 수 없습니다.", + renamed: "스페이스 이름이 변경됨", + deleted: "“{{name}}” 삭제됨", + renameFailed: "스페이스 이름 변경 실패", + deleteFailed: "스페이스 삭제 실패", + renaming: "이름 변경 중...", + deleting: "삭제 중...", + }, signInPrompt: { title: "{{intent}}하려면 로그인", description: diff --git a/templates/clips/app/i18n/pt-BR.ts b/templates/clips/app/i18n/pt-BR.ts index d08ec9675e..ea2127cdbe 100644 --- a/templates/clips/app/i18n/pt-BR.ts +++ b/templates/clips/app/i18n/pt-BR.ts @@ -1126,6 +1126,19 @@ Todas as mudanças visíveis para usuários do Clips são documentadas aqui. Voc spaceCreated: "Espaço criado", createFailed: "Não foi possível criar o espaço", }, + spaceDialog: { + deleteSpace: "Excluir espaço", + renameSpace: "Renomear espaço", + deleteTitle: 'Excluir "{{name}}"?', + deleteDescription: + "Isso excluirá o espaço e o removerá de todas as gravações. Esta ação não pode ser desfeita.", + renamed: "Espaço renomeado", + deleted: '"{{name}}" excluído', + renameFailed: "Falha ao renomear o espaço", + deleteFailed: "Falha ao excluir o espaço", + renaming: "Renomeando...", + deleting: "Excluindo...", + }, signInPrompt: { title: "Entre para {{intent}}", description: diff --git a/templates/clips/app/i18n/zh-CN.ts b/templates/clips/app/i18n/zh-CN.ts index bd9fff0c34..1f8505ff98 100644 --- a/templates/clips/app/i18n/zh-CN.ts +++ b/templates/clips/app/i18n/zh-CN.ts @@ -1060,6 +1060,18 @@ Clips 中所有面向用户的重要更改都会记录在这里。你可以随 spaceCreated: "空间已创建", createFailed: "无法创建空间", }, + spaceDialog: { + deleteSpace: "删除空间", + renameSpace: "重命名空间", + deleteTitle: "删除“{{name}}”?", + deleteDescription: "这将删除空间,并将其从所有录音中移除。此操作无法撤销。", + renamed: "空间已重命名", + deleted: "已删除“{{name}}”", + renameFailed: "重命名空间失败", + deleteFailed: "删除空间失败", + renaming: "正在重命名...", + deleting: "正在删除...", + }, signInPrompt: { title: "登录以{{intent}}", description: diff --git a/templates/clips/app/i18n/zh-TW.ts b/templates/clips/app/i18n/zh-TW.ts index 8f967dfcd9..eb46d20970 100644 --- a/templates/clips/app/i18n/zh-TW.ts +++ b/templates/clips/app/i18n/zh-TW.ts @@ -1054,6 +1054,18 @@ const messages = { spaceCreated: "空間已建立", createFailed: "無法建立空間", }, + spaceDialog: { + deleteSpace: "刪除空間", + renameSpace: "重新命名空間", + deleteTitle: "要刪除「{{name}}」嗎?", + deleteDescription: "這會刪除空間,並將其從所有錄影中移除。此操作無法復原。", + renamed: "空間已重新命名", + deleted: "已刪除「{{name}}」", + renameFailed: "重新命名空間失敗", + deleteFailed: "刪除空間失敗", + renaming: "正在重新命名...", + deleting: "正在刪除...", + }, signInPrompt: { title: "登入以{{intent}}", description: From 9f0049ff42fb5784c7691f4af552c54e68ab1b8c Mon Sep 17 00:00:00 2001 From: Milos Petrovic Date: Wed, 5 Aug 2026 12:51:25 +0200 Subject: [PATCH 6/6] update --- .../app/components/library/library-layout.tsx | 4 ++-- .../clips/app/components/library/space-card.tsx | 14 +++++++------- .../clips/app/components/library/space-dialogs.tsx | 10 ++++++++-- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/templates/clips/app/components/library/library-layout.tsx b/templates/clips/app/components/library/library-layout.tsx index 609b115700..1ec0d24b61 100644 --- a/templates/clips/app/components/library/library-layout.tsx +++ b/templates/clips/app/components/library/library-layout.tsx @@ -603,7 +603,7 @@ export function LibraryLayout({ children }: LibraryLayoutProps) { }} > - Rename + {t("spaceDialog.renameSpace")} { @@ -615,7 +615,7 @@ export function LibraryLayout({ children }: LibraryLayoutProps) { className="text-destructive" > - Delete + {t("spaceDialog.deleteSpace")} diff --git a/templates/clips/app/components/library/space-card.tsx b/templates/clips/app/components/library/space-card.tsx index 8408ce5b86..20c12a6ee8 100644 --- a/templates/clips/app/components/library/space-card.tsx +++ b/templates/clips/app/components/library/space-card.tsx @@ -126,19 +126,19 @@ export function SpaceCard({ {canManageOrg && ( { - e.preventDefault(); - setRenameValue(space.name); - setRenameSpaceId(space.id); + onSelect={() => { + setTimeout(() => { + setRenameValue(space.name); + setRenameSpaceId(space.id); + }, 0); }} > {t("spaceDialog.renameSpace")} { - e.preventDefault(); - setDeleteSpaceId(space.id); + onSelect={() => { + setTimeout(() => setDeleteSpaceId(space.id), 0); }} className="text-destructive focus:text-destructive" > diff --git a/templates/clips/app/components/library/space-dialogs.tsx b/templates/clips/app/components/library/space-dialogs.tsx index 88a9ed0b7e..643e9689ec 100644 --- a/templates/clips/app/components/library/space-dialogs.tsx +++ b/templates/clips/app/components/library/space-dialogs.tsx @@ -94,7 +94,10 @@ export function SpaceDialogs({
    {t("common.cancel")} { + event.preventDefault(); + void handleRename(); + }} disabled={renameSpace.isPending || !renameValue.trim()} > {renameSpace.isPending @@ -122,7 +125,10 @@ export function SpaceDialogs({
    {t("common.cancel")} { + event.preventDefault(); + void handleDelete(); + }} disabled={deleteSpace.isPending} className="bg-destructive text-destructive-foreground hover:bg-destructive/90" >