0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

feat(console): delete application (#417)

This commit is contained in:
Xiao Yijun 2022-03-21 17:43:13 +08:00 committed by GitHub
parent 3e99ac172a
commit ec8ecf262a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 175 additions and 4 deletions

View file

@ -0,0 +1,24 @@
@use '@/scss/underscore' as _;
.content {
> :not(:first-child) {
margin-top: _.unit(6);
}
.description {
font: var(--font-body-2);
}
.hightlight {
color: var(--color-primary-50);
}
}
.actions {
display: flex;
justify-content: flex-end;
> :not(:first-child) {
margin-left: _.unit(4);
}
}

View file

@ -0,0 +1,85 @@
import React, { useState } from 'react';
import { toast } from 'react-hot-toast';
import { Trans, useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import Button from '@/components/Button';
import ModalLayout from '@/components/ModalLayout';
import TextInput from '@/components/TextInput';
import useApi from '@/hooks/use-api';
import * as styles from './index.module.scss';
type Props = {
id: string;
name: string;
onClose: () => void;
};
const DeleteForm = ({ id, name, onClose }: Props) => {
const api = useApi();
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const navigate = useNavigate();
const [inputName, setInputName] = useState('');
const [loading, setLoading] = useState(false);
const inputMismatched = inputName !== name;
const handleDelete = async () => {
setLoading(true);
try {
await api.delete(`/api/applications/${id}`);
onClose();
navigate(`/applications`);
toast.success(t('application_details.application_deleted', { name }));
} finally {
setLoading(false);
}
};
return (
<ModalLayout
title="application_details.reminder"
footer={
<div className={styles.actions}>
<Button
type="outline"
title="admin_console.application_details.cancel"
onClick={onClose}
/>
<Button
disabled={inputMismatched || loading}
type="danger"
title="admin_console.application_details.delete"
onClick={handleDelete}
/>
</div>
}
onClose={onClose}
>
<div className={styles.content}>
<div className={styles.description}>
<Trans
t={t}
i18nKey="application_details.delete_description"
values={{ name }}
components={{ span: <span className={styles.hightlight} /> }}
/>
</div>
<TextInput
value={inputName}
placeholder={t('application_details.enter_your_application_name')}
hasError={inputMismatched}
onChange={(event) => {
setInputName(event.currentTarget.value);
}}
/>
</div>
</ModalLayout>
);
};
export default DeleteForm;

View file

@ -21,6 +21,15 @@
margin-left: _.unit(6);
}
.operations {
display: flex;
align-items: center;
> :not(:first-child) {
margin-left: _.unit(3);
}
}
.metadata {
flex: 1;

View file

@ -1,10 +1,12 @@
import { Application } from '@logto/schemas';
import React, { useEffect, useMemo } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { useController, useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import Modal from 'react-modal';
import { useLocation, useParams } from 'react-router-dom';
import useSWR from 'swr';
import ActionMenu, { ActionMenuItem } from '@/components/ActionMenu';
import BackLink from '@/components/BackLink';
import Button from '@/components/Button';
import Card from '@/components/Card';
@ -15,8 +17,12 @@ import MultilineInput from '@/components/MultilineInput';
import TabNav, { TabNavLink } from '@/components/TabNav';
import TextInput from '@/components/TextInput';
import { RequestError } from '@/hooks/use-api';
import Delete from '@/icons/Delete';
import More from '@/icons/More';
import * as modalStyles from '@/scss/modal.module.scss';
import { applicationTypeI18nKey } from '@/types/applications';
import DeleteForm from './components/DeleteForm';
import * as styles from './index.module.scss';
// TODO LOG-1908: OidcConfig in Application Details
@ -38,6 +44,8 @@ const ApplicationDetails = () => {
);
const isLoading = !data && !error && !oidcConfig && !fetchOidcConfigError;
const [isDeleteFormOpen, setIsDeleteFormOpen] = useState(false);
const { control, handleSubmit, register, reset } = useForm<Application>();
useEffect(() => {
@ -147,8 +155,35 @@ const ApplicationDetails = () => {
<CopyToClipboard value={data.id} className={styles.copy} />
</div>
</div>
<div>
<div className={styles.operations}>
<Button title="admin_console.application_details.check_help_guide" />
<ActionMenu
buttonProps={{ icon: <More /> }}
title={t('application_details.more_options')}
>
<ActionMenuItem
icon={<Delete />}
type="danger"
onClick={() => {
setIsDeleteFormOpen(true);
}}
>
{t('application_details.options_delete')}
</ActionMenuItem>
</ActionMenu>
<Modal
isOpen={isDeleteFormOpen}
className={modalStyles.content}
overlayClassName={modalStyles.overlay}
>
<DeleteForm
id={data.id}
name={data.name}
onClose={() => {
setIsDeleteFormOpen(false);
}}
/>
</Modal>
</div>
</Card>
<Card className={styles.body}>

View file

@ -119,6 +119,15 @@ const translation = {
token_endpoint: 'Token Endpoint',
user_info_endpoint: 'User Info Endpoint',
save_changes: 'Save Changes',
more_options: 'More Options',
options_delete: 'Delete',
reminder: 'Reminder',
delete_description:
'This action cannot be undone. This will permanently delete the this application. Please enter the application name <span>{{name}}</span> to proceed.',
enter_your_application_name: 'Enter your application name',
cancel: 'Cancel',
delete: 'Delete',
application_deleted: 'The application {{name}} deleted.',
},
api_resources: {
title: 'API Resources',
@ -137,7 +146,7 @@ const translation = {
token_expiration_time_in_seconds: 'Token Expiration Time (in seconds)',
reminder: 'Reminder',
delete_description:
'This action cannot be undone. This will permanently delete the this application. Please enter the api resource name <span>{{name}}</span> to proceed.',
'This action cannot be undone. This will permanently delete the this API resource. Please enter the api resource name <span>{{name}}</span> to proceed.',
enter_your_api_resource_name: 'Enter your API resource name',
cancel: 'Cancel',
delete: 'Delete',

View file

@ -119,6 +119,15 @@ const translation = {
token_endpoint: 'Token Endpoint',
user_info_endpoint: 'User Info Endpoint',
save_changes: 'Save Changes',
more_options: 'More Options',
options_delete: 'Delete',
reminder: 'Reminder',
delete_description:
'This action cannot be undone. This will permanently delete the this application. Please enter the application name <span>{{name}}</span> to proceed.',
enter_your_application_name: 'Enter your application name',
cancel: 'Cancel',
delete: 'Delete',
application_deleted: 'The application {{name}} deleted.',
},
api_resources: {
title: 'API Resources',
@ -137,7 +146,7 @@ const translation = {
token_expiration_time_in_seconds: 'Token Expiration Time (in seconds)',
reminder: 'Reminder',
delete_description:
'This action cannot be undone. This will permanently delete the this application. Please enter the api resource name <span>{{name}}</span> to proceed.',
'This action cannot be undone. This will permanently delete the this API resource. Please enter the api resource name <span>{{name}}</span> to proceed.',
enter_your_api_resource_name: 'Enter your API resource name',
cancel: 'Cancel',
delete: 'Delete',