Skip to content

Commit

Permalink
FIX #790 - display a better confirm modal on deletion of team, api, p…
Browse files Browse the repository at this point in the history
…lan & user
  • Loading branch information
quentinovega committed Dec 20, 2024
1 parent 736775a commit 9559fa8
Show file tree
Hide file tree
Showing 11 changed files with 252 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -165,16 +165,41 @@ export const TeamList = () => {
};


const deleteTeam = (teamId: string) => {
confirm({ message: translate('delete team') })
.then((ok) => {
if (ok) {
Services.deleteTeam(teamId)
.then(() => {
queryClient.invalidateQueries({ queryKey: ['teams'] });
});
}
});
const deleteTeam = (team: ITeamFullGql) => {
openFormModal({
title: translate('Confirm'),
description: <div className="alert alert-danger" role="alert">
<h4 className="alert-heading">{translate('Warning')}</h4>
<p>{translate("delete.team.confirm.modal.description.1")}</p>
<ul>
<li>{translate("delete.team.confirm.modal.description.2")}</li>
<li>{translate("delete.team.confirm.modal.description.3")}</li>
<li>{translate("delete.team.confirm.modal.description.4")}</li>
</ul>
</div>,
schema: {
confirm: {
type: type.string,
label: translate({ key: 'delete.item.confirm.modal.confirm.label', replacements: [team.name] }),
constraints: [
constraints.oneOf(
[team.name],
translate({ key: 'constraints.type.api.name', replacements: [team.name] })
),
],
},
},
onSubmit: () => Services.deleteTeam(team._id)
.then((r) => {
if (isError(r)) {
toast.error(r.error)
} else {
queryClient.invalidateQueries({ queryKey: ['teams'] });
toast.success(translate({ key: 'team.deleted.success', replacements: [team.name] }))
}
}),
actionLabel: translate('Confirm')
})
};

const handleChange = (e) => {
Expand All @@ -196,7 +221,7 @@ export const TeamList = () => {
const actions = (team: ITeamFullGql) => {
const basicActions = [
{
action: () => deleteTeam(team._id),
action: () => deleteTeam(team),
variant: 'error',
iconClass: 'fas fa-trash delete-icon',
tooltip: translate('Delete team'),
Expand Down Expand Up @@ -251,7 +276,7 @@ export const TeamList = () => {
{
action: () => navigate(`/settings/teams/${team._humanReadableId}/members`),
iconClass: 'fas fa-users',
tooltip: translate({key: "Member", plural: true}),
tooltip: translate({ key: "Member", plural: true }),
},
];
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import { GlobalContext } from '../../../contexts/globalContext';
import * as Services from '../../../services';
import { IUserSimple, isError } from '../../../types';
import { AvatarWithAction, Can, PaginatedComponent, daikoku, manage } from '../../utils';
import { constraints, type } from '@maif/react-forms';

export const UserList = () => {
const { connectedUser } = useContext(GlobalContext);
useDaikokuBackOffice();

const { alert, confirm } = useContext(ModalContext);
const { alert, confirm, openFormModal } = useContext(ModalContext);

const [users, setUsers] = useState<Array<IUserSimple>>([]);
const [search, setSearch] = useState<string>();
Expand All @@ -36,16 +37,40 @@ export const UserList = () => {
};

const removeUser = (user: IUserSimple) => {
confirm({ message: translate('remove.user.confirm'), okLabel: translate('Yes') })
.then((ok) => {
if (ok) {
Services.deleteUserById(user._id)
.then(() => {
toast.info(translate({ key: 'remove.user.success', replacements: [user.name] }));
updateUsers();
});
}
});
openFormModal({
title: translate('Confirm'),
description: <div className="alert alert-danger" role="alert">
<h4 className="alert-heading">{translate('Warning')}</h4>
<p>{translate("delete.user.confirm.modal.description.1")}</p>
<ul>
<li>{translate("delete.user.confirm.modal.description.2")}</li>
<li>{translate("delete.user.confirm.modal.description.3")}</li>
<li>{translate("delete.user.confirm.modal.description.4")}</li>
</ul>
</div>,
schema: {
confirm: {
type: type.string,
label: translate({ key: 'delete.item.confirm.modal.confirm.label', replacements: [user.name] }),
constraints: [
constraints.oneOf(
[user.name],
translate({ key: 'constraints.type.api.name', replacements: [user.name] })
),
],
},
},
onSubmit: () => Services.deleteUserById(user._id)
.then((r) => {
if (isError(r)) {
toast.error(r.error)
} else {
toast.success(translate({ key: 'remove.user.success', replacements: [user.name] }));
updateUsers();
}
}),
actionLabel: translate('Confirm')
})
};

const toggleAdmin = (member: IUserSimple) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,13 @@ export const TeamApiKeysForApi = () => {
onSubmit: ({ choice, childId }) => openFormModal(
{
title: translate("apikeys.delete.confirm.modal.title"),
description: <div className="alert alert-danger" role="alert">
<h4 className="alert-heading">{translate('Warning')}</h4>
<p>{translate("delete.subscription.confirm.modal.description.1")}</p>
<ul>
<li>{translate("delete.subscription.confirm.modal.description.2")}</li>
</ul>
</div>,
schema: {
validation: {
type: type.string,
Expand All @@ -246,6 +253,13 @@ export const TeamApiKeysForApi = () => {
openFormModal(
{
title: translate("apikeys.delete.confirm.modal.title"),
description: <div className="alert alert-danger" role="alert">
<h4 className="alert-heading">{translate('Warning')}</h4>
<p>{translate("delete.subscription.confirm.modal.description.1")}</p>
<ul>
<li>{translate("delete.subscription.confirm.modal.description.2")}</li>
</ul>
</div>,
schema: {
validation: {
type: type.string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,17 +471,36 @@ const Card = ({
creation,
}: CardProps) => {
const { translate, Translation } = useContext(I18nContext);
const { confirm } = useContext(ModalContext);
const { openFormModal } = useContext(ModalContext);
const { tenant } = useContext(GlobalContext);

const pricing = renderPricing(plan, translate);

const deleteWithConfirm = () => {
confirm({ message: translate('delete.plan.confirm') }).then((ok) => {
if (ok) {
deletePlan();
}
});
openFormModal({
title: translate('Confirm'),
description: <div className="alert alert-danger" role="alert">
<h4 className="alert-heading">{translate('Warning')}</h4>
<p>{translate(`delete.${tenant.display === 'environment' ? 'envionment' : 'plan'}.confirm.modal.description.1`)}</p>
<ul>
<li>{translate(`delete.${tenant.display === 'environment' ? 'envionment' : 'plan'}.confirm.modal.description.2`)}</li>
</ul>
</div>,
schema: {
confirm: {
type: type.string,
label: translate({ key: 'delete.item.confirm.modal.confirm.label', replacements: [plan.customName || plan.type]}),
constraints: [
constraints.oneOf(
[plan.customName || plan.type],
translate({ key: 'constraints.type.api.name', replacements: [plan.customName || plan.type] })
),
],
},
},
onSubmit: () => deletePlan(),
actionLabel: translate('Confirm')
})
};

const noOtoroshi =
Expand Down
104 changes: 64 additions & 40 deletions daikoku/javascript/src/components/backoffice/apis/TeamApiSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ type TeamApiSettingsProps = {
export const TeamApiSettings = ({ api, currentTeam }: TeamApiSettingsProps) => {

const { translate } = useContext(I18nContext);
const { confirm } = useContext(ModalContext);
const { confirm, openFormModal } = useContext(ModalContext);
const navigate = useNavigate();

const transferOwnership = ({team}: {team: ITeamSimple}) => {
const transferOwnership = ({ team }: { team: ITeamSimple }) => {

Services.transferApiOwnership(team, api.team, api._id).then((r) => {
if (r.notify) {
Expand Down Expand Up @@ -66,47 +66,71 @@ export const TeamApiSettings = ({ api, currentTeam }: TeamApiSettingsProps) => {
};

const deleteApi = () => {
return confirm({ message: translate('delete.api.confirm') })
.then((ok) => {
if (ok) {
Services.deleteTeamApi(currentTeam._id, api._id)
.then(() => navigate(`/${currentTeam._humanReadableId}/settings/apis`))
.then(() => toast.success(translate('deletion successful')));
}
});
openFormModal({
title: translate('Confirm'),
description: <div className="alert alert-danger" role="alert">
<h4 className="alert-heading">{translate('Warning')}</h4>
<p>{translate("delete.api.confirm.modal.description.1")}</p>
<ul>
<li>{translate("delete.api.confirm.modal.description.2")}</li>
</ul>
</div>,
schema: {
confirm: {
type: type.string,
label: translate({ key: 'delete.item.confirm.modal.confirm.label', replacements: [api.name] }),
constraints: [
constraints.oneOf(
[api.name],
translate({ key: 'constraints.type.api.name', replacements: [api.name] })
),
],
},
},
onSubmit: () => Services.deleteTeamApi(currentTeam._id, api._id)
.then((r) => {
if (isError(r)) {
toast.error(r.error)
} else {
navigate(`/${currentTeam._humanReadableId}/settings/apis`)
toast.success(translate('deletion successful'))
}
}),
actionLabel: translate('Confirm')
})
};

return (
<div>
<div
className="action mb-3"
style={{ border: '1px solid tomato', borderRadius: '4px', padding: '5px' }}
>
<h3>{translate('transfer.api.ownership.title')}</h3>
<i>{translate('transfer.api.ownership.description')}</i>
<Form
schema={transferSchema}
onSubmit={transferOwnership}
options={{ actions: { submit: { label: translate('Transfer') } } }}
/>
return (
<div>
<div
className="action mb-3"
style={{ border: '1px solid tomato', borderRadius: '4px', padding: '5px' }}
>
<h3>{translate('transfer.api.ownership.title')}</h3>
<i>{translate('transfer.api.ownership.description')}</i>
<Form
schema={transferSchema}
onSubmit={transferOwnership}
options={{ actions: { submit: { label: translate('Transfer') } } }}
/>
</div>
<div
className="action d-flex flex-row align-items-center"
style={{ border: '1px solid tomato', borderRadius: '4px', padding: '5px' }}
>
<div>
<h3>{translate('delete.api.title')}</h3>
<i>{translate('delete.api.description')}</i>
</div>
<div
className="action d-flex flex-row align-items-center"
style={{ border: '1px solid tomato', borderRadius: '4px', padding: '5px' }}
>
<div>
<h3>{translate('delete.api.title')}</h3>
<i>{translate('delete.api.description')}</i>
</div>
<div className="flex-grow-1 text-end" style={{ paddingRight: '15px' }}>
<FeedbackButton
type="danger"
onPress={() => deleteApi()}
feedbackTimeout={1000}
disabled={false}
>{translate('Delete this Api')}</FeedbackButton>
</div>
<div className="flex-grow-1 text-end" style={{ paddingRight: '15px' }}>
<button
type="button"
className='btn btn-outline-danger me-2'
onClick={deleteApi}>
{translate('Delete')}
</button>
</div>
</div>
);
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export const TeamApis = () => {
key={`delete-${api._humanReadableId}`}
type="button"
className="btn btn-sm btn-outline-danger"
title="Delete this Api"
title={translate("Delete this Api")}
onClick={() => deleteApi(api)}
>
<i className="fas fa-trash" />
Expand Down
Loading

0 comments on commit 9559fa8

Please sign in to comment.