feat: allow rename workspace
This commit is contained in:
parent
7c271dc3c1
commit
63e6bfe0d1
@ -3,7 +3,11 @@ import { createFileRoute } from '@tanstack/react-router';
|
||||
import { useTranslation } from '@i18next-toolkit/react';
|
||||
import { CommonWrapper } from '@/components/CommonWrapper';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { useCurrentWorkspace, useHasAdminPermission } from '../../store/user';
|
||||
import {
|
||||
useCurrentWorkspace,
|
||||
useHasAdminPermission,
|
||||
useUserStore,
|
||||
} from '../../store/user';
|
||||
import { CommonHeader } from '@/components/CommonHeader';
|
||||
import {
|
||||
Card,
|
||||
@ -40,6 +44,7 @@ import { z } from 'zod';
|
||||
import { AlertConfirm } from '@/components/AlertConfirm';
|
||||
import { ROLES } from '@tianji/shared';
|
||||
import { cn } from '@/utils/style';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
|
||||
export const Route = createFileRoute('/settings/workspace')({
|
||||
beforeLoad: routeAuthBeforeLoad,
|
||||
@ -63,6 +68,9 @@ function PageComponent() {
|
||||
trpc.workspace.members.useQuery({
|
||||
workspaceId,
|
||||
});
|
||||
const updateCurrentWorkspaceName = useUserStore(
|
||||
(state) => state.updateCurrentWorkspaceName
|
||||
);
|
||||
const form = useForm<InviteFormValues>({
|
||||
resolver: zodResolver(inviteFormSchema),
|
||||
defaultValues: {
|
||||
@ -73,12 +81,26 @@ function PageComponent() {
|
||||
onSuccess: defaultSuccessHandler,
|
||||
onError: defaultErrorHandler,
|
||||
});
|
||||
const renameWorkspaceMutation = trpc.workspace.rename.useMutation({
|
||||
onSuccess: defaultSuccessHandler,
|
||||
onError: defaultErrorHandler,
|
||||
});
|
||||
const deleteWorkspaceMutation = trpc.workspace.delete.useMutation({
|
||||
onSuccess: defaultSuccessHandler,
|
||||
onError: defaultErrorHandler,
|
||||
});
|
||||
|
||||
const [handleInvite, isLoading] = useEventWithLoading(
|
||||
const [renameWorkspaceName, setRenameWorkspaceName] = useState('');
|
||||
const [handleRename, isRenameLoading] = useEventWithLoading(async () => {
|
||||
await renameWorkspaceMutation.mutateAsync({
|
||||
workspaceId,
|
||||
name: renameWorkspaceName,
|
||||
});
|
||||
|
||||
updateCurrentWorkspaceName(renameWorkspaceName);
|
||||
});
|
||||
|
||||
const [handleInvite, isInviteLoading] = useEventWithLoading(
|
||||
async (values: InviteFormValues) => {
|
||||
await inviteMutation.mutateAsync({
|
||||
workspaceId,
|
||||
@ -177,7 +199,7 @@ function PageComponent() {
|
||||
<CardFooter>
|
||||
<Button
|
||||
type="submit"
|
||||
loading={isLoading}
|
||||
loading={isInviteLoading}
|
||||
disabled={!hasAdminPermission}
|
||||
>
|
||||
{t('Invite')}
|
||||
@ -203,6 +225,33 @@ function PageComponent() {
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div>
|
||||
<div className="flex items-center gap-2 text-left">
|
||||
<Input
|
||||
className="w-60"
|
||||
placeholder={t('New Workspace Name')}
|
||||
value={renameWorkspaceName}
|
||||
onChange={(e) => setRenameWorkspaceName(e.target.value)}
|
||||
/>
|
||||
|
||||
<AlertConfirm
|
||||
title={'Confirm to rename this workspace?'}
|
||||
description={`${name} => ${renameWorkspaceName}`}
|
||||
onConfirm={handleRename}
|
||||
>
|
||||
<Button
|
||||
type="button"
|
||||
loading={isRenameLoading}
|
||||
disabled={
|
||||
!renameWorkspaceName || name === renameWorkspaceName
|
||||
}
|
||||
>
|
||||
{t('Rename')}
|
||||
</Button>
|
||||
</AlertConfirm>
|
||||
</div>
|
||||
|
||||
<Separator className="my-4" />
|
||||
|
||||
<AlertConfirm
|
||||
title={'Confirm to delete this workspace'}
|
||||
description={t(
|
||||
|
@ -3,17 +3,31 @@ import { createWithEqualityFn } from 'zustand/traditional';
|
||||
import { createSocketIOClient } from '../api/socketio';
|
||||
import { AppRouterOutput } from '../api/trpc';
|
||||
import { ROLES } from '@tianji/shared';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
export type UserLoginInfo = NonNullable<AppRouterOutput['user']['info']>;
|
||||
|
||||
interface UserState {
|
||||
info: UserLoginInfo | null;
|
||||
updateCurrentWorkspaceName: (name: string) => void;
|
||||
}
|
||||
|
||||
export const useUserStore = createWithEqualityFn<UserState>(
|
||||
() => ({
|
||||
export const useUserStore = createWithEqualityFn<UserState>()(
|
||||
immer((set) => ({
|
||||
info: null,
|
||||
}),
|
||||
updateCurrentWorkspaceName: (name) => {
|
||||
const currentUserInfo = useUserStore.getState().info;
|
||||
if (!currentUserInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
set((state) => {
|
||||
for (const workspace of state.info?.workspaces ?? []) {
|
||||
workspace.workspace.name = name;
|
||||
}
|
||||
});
|
||||
},
|
||||
})),
|
||||
shallow
|
||||
);
|
||||
|
||||
|
@ -12,6 +12,7 @@ import { prisma } from '../../model/_client.js';
|
||||
import {
|
||||
userInfoSchema,
|
||||
workspaceDashboardLayoutSchema,
|
||||
workspaceSchema,
|
||||
} from '../../model/_schema/index.js';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { OPENAPI_TAG } from '../../utils/const.js';
|
||||
@ -124,6 +125,33 @@ export const workspaceRouter = router({
|
||||
|
||||
return userInfo;
|
||||
}),
|
||||
rename: workspaceOwnerProcedure
|
||||
.meta(
|
||||
buildWorkspaceOpenapi({
|
||||
method: 'PATCH',
|
||||
path: '/rename',
|
||||
})
|
||||
)
|
||||
.input(
|
||||
z.object({
|
||||
name: z.string().max(60).min(4),
|
||||
})
|
||||
)
|
||||
.output(workspaceSchema)
|
||||
.mutation(async ({ input }) => {
|
||||
const { workspaceId, name } = input;
|
||||
|
||||
const workspace = await prisma.workspace.update({
|
||||
where: {
|
||||
id: workspaceId,
|
||||
},
|
||||
data: {
|
||||
name,
|
||||
},
|
||||
});
|
||||
|
||||
return workspace;
|
||||
}),
|
||||
delete: workspaceOwnerProcedure
|
||||
.meta(
|
||||
buildWorkspaceOpenapi({
|
||||
|
Loading…
Reference in New Issue
Block a user