Changes
4 changed files (+85/-21)
-
-
@@ -1,7 +1,7 @@// SPDX-FileCopyrightText: 2025 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only import { Button, Flex, Heading, Switch, TextField } from "@radix-ui/themes"; import { Button, Flex, Heading, Select, Switch, TextField } from "@radix-ui/themes"; import { type User } from "@yamori/proto/yamori/workspace/v2/user_pb.js"; import { type FC, type FormEventHandler, type ReactElement, type ReactNode } from "react"; import { Controller, useForm, type UseFormReturn } from "react-hook-form";
-
@@ -11,6 +11,7 @@export interface UpdateFields { name: string; displayName: string; isAdmin: boolean; canAddUser: boolean; canDeleteRegularUser: boolean; canReadOtherUserProfile: boolean;
-
@@ -45,10 +46,17 @@ children?: ReactElement;disabled?: boolean; loginUser: User; form: UseFormReturn<UpdateFields, any, undefined>; } const ProfileFields: FC<ProfileFieldsProps> = ({ children, disabled, form }) => { const ProfileFields: FC<ProfileFieldsProps> = ({ children, disabled, loginUser, form, }) => { return ( <> <Heading as="h2">基本情報</Heading>
-
@@ -92,6 +100,35 @@ 他のユーザも閲覧可能な画面上の表示名です。未指定の場合はユーザ名が設定されます。 前後の空白は無視されます。 </FormField.Description> </FormField.Root> <FormField.Root> <FormField.Label htmlFor="c_role">ユーザ種別</FormField.Label> <Controller control={form.control} name="isAdmin" render={({ field: { onChange: _onChange, value, ...field } }) => { return ( <Select.Root disabled={!loginUser.isAdmin || disabled} value={value ? "admin" : "regular"} onValueChange={(value) => void form.setValue(field.name, value === "admin") } > <Select.Trigger id="c_role"></Select.Trigger> <Select.Content> <Select.Item value="regular">一般ユーザ</Select.Item> <Select.Item value="admin">管理者</Select.Item> </Select.Content> </Select.Root> ); }} /> {!loginUser.isAdmin && ( <FormField.Description> 一般ユーザは管理者の作成・変更を行えません。 </FormField.Description> )} </FormField.Root> {children} </> );
-
@@ -138,6 +175,8 @@ form: UseFormReturn<UpdateFields>;} const PermissionFields: FC<PermissionFieldsProps> = ({ loginUser, disabled, form }) => { const isAdmin = form.watch("isAdmin"); return ( <> <Heading as="h2">権限</Heading>
-
@@ -151,8 +190,10 @@ name="canUpdateSelfProfile"render={({ field: { onChange: _onChange, value, ...field } }) => ( <Switch id="c_canUpdateSelfProfile" disabled={disabled || !loginUser.permissions?.canUpdateSelfProfile} checked={value} disabled={ disabled || isAdmin || !loginUser.permissions?.canUpdateSelfProfile } checked={isAdmin || value} onCheckedChange={(newValue) => { form.setValue(field.name, newValue); }}
-
@@ -172,8 +213,8 @@ name="canAddUser"render={({ field: { onChange: _onChange, value, ...field } }) => ( <Switch id="c_canAddUser" disabled={disabled || !loginUser.permissions?.canAddUser} checked={value} disabled={disabled || isAdmin || !loginUser.permissions?.canAddUser} checked={isAdmin || value} onCheckedChange={(newValue) => { form.setValue(field.name, newValue); }}
-
@@ -194,8 +235,10 @@ name="canDeleteRegularUser"render={({ field: { onChange: _onChange, value, ...field } }) => ( <Switch id="c_canDeleteRegularUser" disabled={disabled || !loginUser.permissions?.canDeleteRegularUser} checked={value} disabled={ disabled || isAdmin || !loginUser.permissions?.canDeleteRegularUser } checked={isAdmin || value} onCheckedChange={(newValue) => { form.setValue(field.name, newValue); }}
-
@@ -217,8 +260,10 @@ name="canReadOtherUserProfile"render={({ field: { onChange: _onChange, value, ...field } }) => ( <Switch id="c_canReadOtherUserProfile" disabled={disabled || !loginUser.permissions?.canReadOtherUserProfile} checked={value} disabled={ disabled || isAdmin || !loginUser.permissions?.canReadOtherUserProfile } checked={isAdmin || value} onCheckedChange={(newValue) => { form.setValue(field.name, newValue); }}
-
@@ -241,9 +286,11 @@ render={({ field: { onChange: _onChange, value, ...field } }) => (<Switch id="c_canUpdateOtherRegularUserProfile" disabled={ disabled || !loginUser.permissions?.canUpdateOtherRegularUserProfile disabled || isAdmin || !loginUser.permissions?.canUpdateOtherRegularUserProfile } checked={value} checked={isAdmin || value} onCheckedChange={(newValue) => { form.setValue(field.name, newValue); }}
-
@@ -267,9 +314,11 @@ render={({ field: { onChange: _onChange, value, ...field } }) => (<Switch id="c_canUpdateOtherRegularUserLoginMethod" disabled={ disabled || !loginUser.permissions?.canUpdateOtherRegularUserLoginMethod disabled || isAdmin || !loginUser.permissions?.canUpdateOtherRegularUserLoginMethod } checked={value} checked={isAdmin || value} onCheckedChange={(newValue) => { form.setValue(field.name, newValue); }}
-
@@ -292,8 +341,8 @@ name="canUpdateWorkspace"render={({ field: { onChange: _onChange, value, ...field } }) => ( <Switch id="c_canUpdateWorkspace" disabled={disabled || !loginUser.permissions?.canUpdateWorkspace} checked={value} disabled={disabled || isAdmin || !loginUser.permissions?.canUpdateWorkspace} checked={isAdmin || value} onCheckedChange={(newValue) => { form.setValue(field.name, newValue); }}
-
@@ -346,6 +395,7 @@ disabled={pending}// @ts-expect-error react-hook-form における型設計ミス // https://github.com/react-hook-form/react-hook-form/issues/6726 form={form} loginUser={loginUser} > <PasswordField disabled={pending} form={form} /> </ProfileFields>
-
@@ -381,6 +431,7 @@ const form = useForm<UpdateFields>({defaultValues: { name: user.name, displayName: user.displayName, isAdmin: user.isAdmin, canAddUser: !!user.permissions?.canAddUser, canDeleteRegularUser: !!user.permissions?.canDeleteRegularUser, canReadOtherUserProfile: !!user.permissions?.canReadOtherUserProfile,
-
@@ -400,7 +451,7 @@ onSubmit={form.handleSubmit((values) => {onUpdate?.(values); })} > <ProfileFields disabled={pending} form={form} /> <ProfileFields disabled={pending} form={form} loginUser={loginUser} /> <PermissionFields disabled={pending} form={form} loginUser={loginUser} /> <Button loading={pending}>更新</Button> </Root>
-
-
-
@@ -114,8 +114,14 @@ )}<CreateForm pending={creation.isPending} loginUser={loginUser} onCreate={({ name, displayName, loginPassword, ...permissions }) => { creation.mutate({ name, displayName, password: loginPassword, permissions }); onCreate={({ name, displayName, isAdmin, loginPassword, ...permissions }) => { creation.mutate({ name, displayName, isAdmin, password: loginPassword, permissions, }); }} /> </Box>
-
-
-
@@ -38,6 +38,13 @@ await userEvent.click(canvas.getByRole("button", { name: "更新" }));}, }; export const Admin: Story = { args: { user: alice, }, decorators: [withMockedBackend([UpdateUser()])], }; export const NoPermission: Story = { args: { loginUser: bob,
-
-
-
@@ -125,8 +125,8 @@ <UpdateFormpending={update.isPending} loginUser={loginUser} user={user} onUpdate={({ name, displayName, ...permissions }) => { update.mutate({ id: user.id, name, displayName, permissions }); onUpdate={({ name, displayName, isAdmin, ...permissions }) => { update.mutate({ id: user.id, name, displayName, isAdmin, permissions }); }} /> </Box>
-