Implement settings dropdown for container nodes

This commit is contained in:
Hakan Shehu
2024-10-28 11:00:56 +01:00
parent 781351ce6f
commit 2cebec1aaf
13 changed files with 585 additions and 2 deletions

View File

@@ -0,0 +1,65 @@
import React from 'react';
import {
AlertDialog,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/renderer/components/ui/alert-dialog';
import { Button } from '@/renderer/components/ui/button';
import { useMutation } from '@/renderer/hooks/use-mutation';
import { useWorkspace } from '@/renderer/contexts/workspace';
interface ChannelDeleteDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
nodeId: string;
}
export const ChannelDeleteDialog = ({
nodeId,
open,
onOpenChange,
}: ChannelDeleteDialogProps) => {
const workspace = useWorkspace();
const { mutate, isPending } = useMutation();
return (
<AlertDialog open={open} onOpenChange={onOpenChange}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
Are you sure you want delete this channel?
</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This channel will no longer be
accessible by you or others you&apos;ve shared it with.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<Button
variant="destructive"
disabled={isPending}
onClick={() => {
mutate({
input: {
type: 'node_delete',
nodeId,
userId: workspace.userId,
},
onSuccess() {
onOpenChange(false);
},
});
}}
>
Delete
</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
};

View File

@@ -0,0 +1,46 @@
import React from 'react';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/renderer/components/ui/dropdown-menu';
import { Copy, Settings, Trash2 } from 'lucide-react';
import { ChannelDeleteDialog } from '@/renderer/components/channels/channel-delete-dialog';
interface ChannelSettingsProps {
nodeId: string;
}
export const ChannelSettings = ({ nodeId }: ChannelSettingsProps) => {
const [showDeleteModal, setShowDeleteModal] = React.useState(false);
return (
<React.Fragment>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Settings className="size-5 cursor-pointer text-muted-foreground hover:text-foreground" />
</DropdownMenuTrigger>
<DropdownMenuContent side="bottom" className="mr-2 w-56">
<DropdownMenuItem className="flex items-center gap-2" disabled>
<Copy className="size-4" />
Duplicate
</DropdownMenuItem>
<DropdownMenuItem
className="flex items-center gap-2"
onClick={() => {
setShowDeleteModal(true);
}}
>
<Trash2 className="size-4" />
Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<ChannelDeleteDialog
nodeId={nodeId}
open={showDeleteModal}
onOpenChange={setShowDeleteModal}
/>
</React.Fragment>
);
};

View File

@@ -17,7 +17,7 @@ export const NodeCollaboratorsPopover = ({
return (
<Popover>
<PopoverTrigger asChild>
<UserRoundPlus className="size-4 cursor-pointer text-muted-foreground hover:text-foreground" />
<UserRoundPlus className="size-5 cursor-pointer text-muted-foreground hover:text-foreground" />
</PopoverTrigger>
<PopoverContent className="mr-2 max-h-128 w-128 overflow-auto">
<NodeCollaborators nodeId={nodeId} />

View File

@@ -0,0 +1,65 @@
import React from 'react';
import {
AlertDialog,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/renderer/components/ui/alert-dialog';
import { Button } from '@/renderer/components/ui/button';
import { useMutation } from '@/renderer/hooks/use-mutation';
import { useWorkspace } from '@/renderer/contexts/workspace';
interface DatabaseDeleteDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
nodeId: string;
}
export const DatabaseDeleteDialog = ({
nodeId,
open,
onOpenChange,
}: DatabaseDeleteDialogProps) => {
const workspace = useWorkspace();
const { mutate, isPending } = useMutation();
return (
<AlertDialog open={open} onOpenChange={onOpenChange}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
Are you sure you want delete this database?
</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This database will no longer be
accessible by you or others you&apos;ve shared it with.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<Button
variant="destructive"
disabled={isPending}
onClick={() => {
mutate({
input: {
type: 'node_delete',
nodeId,
userId: workspace.userId,
},
onSuccess() {
onOpenChange(false);
},
});
}}
>
Delete
</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
};

View File

@@ -0,0 +1,46 @@
import React from 'react';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/renderer/components/ui/dropdown-menu';
import { Copy, Settings, Trash2 } from 'lucide-react';
import { DatabaseDeleteDialog } from '@/renderer/components/databases/database-delete-dialog';
interface DatabaseSettingsProps {
nodeId: string;
}
export const DatabaseSettings = ({ nodeId }: DatabaseSettingsProps) => {
const [showDeleteModal, setShowDeleteModal] = React.useState(false);
return (
<React.Fragment>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Settings className="size-5 cursor-pointer text-muted-foreground hover:text-foreground" />
</DropdownMenuTrigger>
<DropdownMenuContent side="bottom" className="mr-2 w-56">
<DropdownMenuItem className="flex items-center gap-2" disabled>
<Copy className="size-4" />
Duplicate
</DropdownMenuItem>
<DropdownMenuItem
className="flex items-center gap-2"
onClick={() => {
setShowDeleteModal(true);
}}
>
<Trash2 className="size-4" />
Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<DatabaseDeleteDialog
nodeId={nodeId}
open={showDeleteModal}
onOpenChange={setShowDeleteModal}
/>
</React.Fragment>
);
};

View File

@@ -0,0 +1,65 @@
import React from 'react';
import {
AlertDialog,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/renderer/components/ui/alert-dialog';
import { Button } from '@/renderer/components/ui/button';
import { useMutation } from '@/renderer/hooks/use-mutation';
import { useWorkspace } from '@/renderer/contexts/workspace';
interface FolderDeleteDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
nodeId: string;
}
export const FolderDeleteDialog = ({
nodeId,
open,
onOpenChange,
}: FolderDeleteDialogProps) => {
const workspace = useWorkspace();
const { mutate, isPending } = useMutation();
return (
<AlertDialog open={open} onOpenChange={onOpenChange}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
Are you sure you want delete this folder?
</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This folder will no longer be
accessible by you or others you&apos;ve shared it with.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<Button
variant="destructive"
disabled={isPending}
onClick={() => {
mutate({
input: {
type: 'node_delete',
nodeId,
userId: workspace.userId,
},
onSuccess() {
onOpenChange(false);
},
});
}}
>
Delete
</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
};

View File

@@ -0,0 +1,46 @@
import React from 'react';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/renderer/components/ui/dropdown-menu';
import { Copy, Settings, Trash2 } from 'lucide-react';
import { PageDeleteDialog } from '@/renderer/components/pages/page-delete-dialog';
interface FolderSettingsProps {
nodeId: string;
}
export const FolderSettings = ({ nodeId }: FolderSettingsProps) => {
const [showDeleteModal, setShowDeleteModal] = React.useState(false);
return (
<React.Fragment>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Settings className="size-5 cursor-pointer text-muted-foreground hover:text-foreground" />
</DropdownMenuTrigger>
<DropdownMenuContent side="bottom" className="mr-2 w-56">
<DropdownMenuItem className="flex items-center gap-2" disabled>
<Copy className="size-4" />
Duplicate
</DropdownMenuItem>
<DropdownMenuItem
className="flex items-center gap-2"
onClick={() => {
setShowDeleteModal(true);
}}
>
<Trash2 className="size-4" />
Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<PageDeleteDialog
nodeId={nodeId}
open={showDeleteModal}
onOpenChange={setShowDeleteModal}
/>
</React.Fragment>
);
};

View File

@@ -0,0 +1,65 @@
import React from 'react';
import {
AlertDialog,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/renderer/components/ui/alert-dialog';
import { Button } from '@/renderer/components/ui/button';
import { useMutation } from '@/renderer/hooks/use-mutation';
import { useWorkspace } from '@/renderer/contexts/workspace';
interface PageDeleteDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
nodeId: string;
}
export const PageDeleteDialog = ({
nodeId,
open,
onOpenChange,
}: PageDeleteDialogProps) => {
const workspace = useWorkspace();
const { mutate, isPending } = useMutation();
return (
<AlertDialog open={open} onOpenChange={onOpenChange}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
Are you sure you want delete this page?
</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This page will no longer be accessible
by you or others you&apos;ve shared it with.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<Button
variant="destructive"
disabled={isPending}
onClick={() => {
mutate({
input: {
type: 'node_delete',
nodeId,
userId: workspace.userId,
},
onSuccess() {
onOpenChange(false);
},
});
}}
>
Delete
</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
};

View File

@@ -0,0 +1,46 @@
import React from 'react';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/renderer/components/ui/dropdown-menu';
import { Copy, Settings, Trash2 } from 'lucide-react';
import { PageDeleteDialog } from '@/renderer/components/pages/page-delete-dialog';
interface PageSettingsProps {
nodeId: string;
}
export const PageSettings = ({ nodeId }: PageSettingsProps) => {
const [showDeleteModal, setShowDeleteModal] = React.useState(false);
return (
<React.Fragment>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Settings className="size-5 cursor-pointer text-muted-foreground hover:text-foreground" />
</DropdownMenuTrigger>
<DropdownMenuContent side="bottom" className="mr-2 w-56">
<DropdownMenuItem className="flex items-center gap-2" disabled>
<Copy className="size-4" />
Duplicate
</DropdownMenuItem>
<DropdownMenuItem
className="flex items-center gap-2"
onClick={() => {
setShowDeleteModal(true);
}}
>
<Trash2 className="size-4" />
Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<PageDeleteDialog
nodeId={nodeId}
open={showDeleteModal}
onOpenChange={setShowDeleteModal}
/>
</React.Fragment>
);
};

View File

@@ -0,0 +1,65 @@
import React from 'react';
import {
AlertDialog,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/renderer/components/ui/alert-dialog';
import { Button } from '@/renderer/components/ui/button';
import { useMutation } from '@/renderer/hooks/use-mutation';
import { useWorkspace } from '@/renderer/contexts/workspace';
interface RecordDeleteDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
nodeId: string;
}
export const RecordDeleteDialog = ({
nodeId,
open,
onOpenChange,
}: RecordDeleteDialogProps) => {
const workspace = useWorkspace();
const { mutate, isPending } = useMutation();
return (
<AlertDialog open={open} onOpenChange={onOpenChange}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
Are you sure you want delete this record?
</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This record will no longer be
accessible by you or others you&apos;ve shared it with.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<Button
variant="destructive"
disabled={isPending}
onClick={() => {
mutate({
input: {
type: 'node_delete',
nodeId,
userId: workspace.userId,
},
onSuccess() {
onOpenChange(false);
},
});
}}
>
Delete
</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
};

View File

@@ -0,0 +1,46 @@
import React from 'react';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/renderer/components/ui/dropdown-menu';
import { Copy, Settings, Trash2 } from 'lucide-react';
import { RecordDeleteDialog } from '@/renderer/components/records/record-delete-dialog';
interface RecordSettingsProps {
nodeId: string;
}
export const RecordSettings = ({ nodeId }: RecordSettingsProps) => {
const [showDeleteModal, setShowDeleteModal] = React.useState(false);
return (
<React.Fragment>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Settings className="size-5 cursor-pointer text-muted-foreground hover:text-foreground" />
</DropdownMenuTrigger>
<DropdownMenuContent side="bottom" className="mr-2 w-56">
<DropdownMenuItem className="flex items-center gap-2" disabled>
<Copy className="size-4" />
Duplicate
</DropdownMenuItem>
<DropdownMenuItem
className="flex items-center gap-2"
onClick={() => {
setShowDeleteModal(true);
}}
>
<Trash2 className="size-4" />
Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<RecordDeleteDialog
nodeId={nodeId}
open={showDeleteModal}
onOpenChange={setShowDeleteModal}
/>
</React.Fragment>
);
};

View File

@@ -5,6 +5,7 @@ import { ChatBreadcrumb } from '@/renderer/components/workspaces/containers/chat
import { NodeCollaboratorsPopover } from '@/renderer/components/collaborators/node-collaborators-popover';
import { SidebarTrigger } from '@/renderer/components/ui/sidebar';
import { Separator } from '@/renderer/components/ui/separator';
import { ContainerSettings } from '@/renderer/components/workspaces/containers/container-settings';
interface ContainerHeaderProps {
nodeId: string;
@@ -25,7 +26,10 @@ export const ContainerHeader = ({ nodeId }: ContainerHeaderProps) => {
)}
</div>
<NodeCollaboratorsPopover nodeId={nodeId} />
<div className="flex items-center gap-2">
<NodeCollaboratorsPopover nodeId={nodeId} />
<ContainerSettings nodeId={nodeId} />
</div>
</div>
</header>
);

View File

@@ -0,0 +1,24 @@
import React from 'react';
import { IdType } from '@/lib/id';
import { getIdType } from '@/lib/id';
import { match } from 'ts-pattern';
import { ChannelSettings } from '@/renderer/components/channels/channel-settings';
import { PageSettings } from '@/renderer/components/pages/page-settings';
import { DatabaseSettings } from '@/renderer/components/databases/database-settings';
import { RecordSettings } from '@/renderer/components/records/record-settings';
import { FolderSettings } from '@/renderer/components/folders/folder-settings';
interface ContainerSettingsProps {
nodeId: string;
}
export const ContainerSettings = ({ nodeId }: ContainerSettingsProps) => {
const idType = getIdType(nodeId);
return match(idType)
.with(IdType.Channel, () => <ChannelSettings nodeId={nodeId} />)
.with(IdType.Page, () => <PageSettings nodeId={nodeId} />)
.with(IdType.Database, () => <DatabaseSettings nodeId={nodeId} />)
.with(IdType.Record, () => <RecordSettings nodeId={nodeId} />)
.with(IdType.Folder, () => <FolderSettings nodeId={nodeId} />)
.otherwise(() => null);
};