mirror of
https://github.com/umami-software/umami.git
synced 2026-02-08 22:57:12 +01:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
d62dd3be44
7 changed files with 182 additions and 19 deletions
|
|
@ -0,0 +1,49 @@
|
|||
import { useMessages, useModified } from 'components/hooks';
|
||||
import { Button, Icon, Icons, Modal, ModalTrigger, Text, useToasts } from 'react-basics';
|
||||
import TeamMemberEditForm from './TeamMemberEditForm';
|
||||
|
||||
export function TeamMemberEditButton({
|
||||
teamId,
|
||||
userId,
|
||||
role,
|
||||
onSave,
|
||||
}: {
|
||||
teamId: string;
|
||||
userId: string;
|
||||
role: string;
|
||||
onSave?: () => void;
|
||||
}) {
|
||||
const { formatMessage, labels, messages } = useMessages();
|
||||
const { showToast } = useToasts();
|
||||
const { touch } = useModified();
|
||||
|
||||
const handleSave = () => {
|
||||
showToast({ message: formatMessage(messages.saved), variant: 'success' });
|
||||
touch('teams:members');
|
||||
onSave?.();
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalTrigger>
|
||||
<Button variant="quiet">
|
||||
<Icon>
|
||||
<Icons.Edit />
|
||||
</Icon>
|
||||
<Text>{formatMessage(labels.edit)}</Text>
|
||||
</Button>
|
||||
<Modal title={formatMessage(labels.editMember)}>
|
||||
{(close: () => void) => (
|
||||
<TeamMemberEditForm
|
||||
teamId={teamId}
|
||||
userId={userId}
|
||||
role={role}
|
||||
onSave={handleSave}
|
||||
onClose={close}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
</ModalTrigger>
|
||||
);
|
||||
}
|
||||
|
||||
export default TeamMemberEditButton;
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
import { useApi, useMessages } from 'components/hooks';
|
||||
import { ROLES } from 'lib/constants';
|
||||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
Form,
|
||||
FormButtons,
|
||||
FormInput,
|
||||
FormRow,
|
||||
Item,
|
||||
SubmitButton,
|
||||
} from 'react-basics';
|
||||
|
||||
export function UserAddForm({
|
||||
teamId,
|
||||
userId,
|
||||
role,
|
||||
onSave,
|
||||
onClose,
|
||||
}: {
|
||||
teamId: string;
|
||||
userId: string;
|
||||
role: string;
|
||||
onSave?: () => void;
|
||||
onClose?: () => void;
|
||||
}) {
|
||||
const { post, useMutation } = useApi();
|
||||
const { mutate, error, isPending } = useMutation({
|
||||
mutationFn: (data: any) => post(`/teams/${teamId}/users/${userId}`, data),
|
||||
});
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
const handleSubmit = async (data: any) => {
|
||||
mutate(data, {
|
||||
onSuccess: async () => {
|
||||
onSave();
|
||||
onClose();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const renderValue = (value: string) => {
|
||||
if (value === ROLES.teamMember) {
|
||||
return formatMessage(labels.teamMember);
|
||||
}
|
||||
if (value === ROLES.teamViewOnly) {
|
||||
return formatMessage(labels.viewOnly);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form onSubmit={handleSubmit} error={error} values={{ role }}>
|
||||
<FormRow label={formatMessage(labels.role)}>
|
||||
<FormInput name="role" rules={{ required: formatMessage(labels.required) }}>
|
||||
<Dropdown
|
||||
renderValue={renderValue}
|
||||
style={{
|
||||
minWidth: '250px',
|
||||
}}
|
||||
>
|
||||
<Item key={ROLES.teamMember}>{formatMessage(labels.teamMember)}</Item>
|
||||
<Item key={ROLES.teamViewOnly}>{formatMessage(labels.viewOnly)}</Item>
|
||||
</Dropdown>
|
||||
</FormInput>
|
||||
</FormRow>
|
||||
<FormButtons flex>
|
||||
<SubmitButton variant="primary" disabled={false}>
|
||||
{formatMessage(labels.save)}
|
||||
</SubmitButton>
|
||||
<Button disabled={isPending} onClick={onClose}>
|
||||
{formatMessage(labels.cancel)}
|
||||
</Button>
|
||||
</FormButtons>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
export default UserAddForm;
|
||||
|
|
@ -1,44 +1,64 @@
|
|||
import ConfirmationForm from 'components/common/ConfirmationForm';
|
||||
import { useApi, useMessages, useModified } from 'components/hooks';
|
||||
import { Icon, Icons, LoadingButton, Text } from 'react-basics';
|
||||
import { messages } from 'components/messages';
|
||||
import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
export function TeamMemberRemoveButton({
|
||||
teamId,
|
||||
userId,
|
||||
disabled,
|
||||
userName,
|
||||
onSave,
|
||||
}: {
|
||||
teamId: string;
|
||||
userId: string;
|
||||
userName: string;
|
||||
disabled?: boolean;
|
||||
onSave?: () => void;
|
||||
}) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { del, useMutation } = useApi();
|
||||
const { mutate, isPending } = useMutation({
|
||||
const { mutate, isPending, error } = useMutation({
|
||||
mutationFn: () => del(`/teams/${teamId}/users/${userId}`),
|
||||
});
|
||||
const { touch } = useModified();
|
||||
|
||||
const handleRemoveTeamMember = () => {
|
||||
const handleConfirm = (close: () => void) => {
|
||||
mutate(null, {
|
||||
onSuccess: () => {
|
||||
touch('teams:members');
|
||||
onSave?.();
|
||||
close();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<LoadingButton
|
||||
onClick={() => handleRemoveTeamMember()}
|
||||
disabled={disabled}
|
||||
isLoading={isPending}
|
||||
>
|
||||
<Icon>
|
||||
<Icons.Close />
|
||||
</Icon>
|
||||
<Text>{formatMessage(labels.remove)}</Text>
|
||||
</LoadingButton>
|
||||
<ModalTrigger>
|
||||
<Button variant="quiet">
|
||||
<Icon>
|
||||
<Icons.Close />
|
||||
</Icon>
|
||||
<Text>{formatMessage(labels.remove)}</Text>
|
||||
</Button>
|
||||
<Modal title={formatMessage(labels.removeMember)}>
|
||||
{(close: () => void) => (
|
||||
<ConfirmationForm
|
||||
message={
|
||||
<FormattedMessage
|
||||
{...messages.confirmRemove}
|
||||
values={{ target: <b>{userName}</b> }}
|
||||
/>
|
||||
}
|
||||
isLoading={isPending}
|
||||
error={error}
|
||||
onConfirm={handleConfirm.bind(null, close)}
|
||||
onClose={close}
|
||||
buttonLabel={formatMessage(labels.remove)}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
</ModalTrigger>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { GridColumn, GridTable, useBreakpoint } from 'react-basics';
|
|||
import { useMessages, useLogin } from 'components/hooks';
|
||||
import { ROLES } from 'lib/constants';
|
||||
import TeamMemberRemoveButton from './TeamMemberRemoveButton';
|
||||
import TeamMemberEditButton from './TeamMemberEditButton';
|
||||
|
||||
export function TeamMembersTable({
|
||||
data = [],
|
||||
|
|
@ -19,6 +20,7 @@ export function TeamMembersTable({
|
|||
const roles = {
|
||||
[ROLES.teamOwner]: formatMessage(labels.teamOwner),
|
||||
[ROLES.teamMember]: formatMessage(labels.teamMember),
|
||||
[ROLES.teamViewOnly]: formatMessage(labels.viewOnly),
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -35,7 +37,14 @@ export function TeamMembersTable({
|
|||
allowEdit &&
|
||||
row?.role !== ROLES.teamOwner &&
|
||||
user?.id !== row?.id && (
|
||||
<TeamMemberRemoveButton teamId={teamId} userId={row?.user?.id} />
|
||||
<>
|
||||
<TeamMemberEditButton teamId={teamId} userId={row?.user?.id} role={row?.role} />
|
||||
<TeamMemberRemoveButton
|
||||
teamId={teamId}
|
||||
userId={row?.user?.id}
|
||||
userName={row?.user?.username}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
);
|
||||
}}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue