mirror of
https://github.com/logto-io/logto.git
synced 2025-03-17 22:31:28 -05:00
feat(console): application details settings (#381)
This commit is contained in:
parent
f25cb8adae
commit
22a6278a9b
6 changed files with 176 additions and 20 deletions
|
@ -1,5 +1,5 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { BrowserRouter, Route, Routes, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { BrowserRouter, Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { SWRConfig } from 'swr';
|
||||
import './scss/normalized.scss';
|
||||
|
||||
|
@ -44,7 +44,11 @@ const Main = () => {
|
|||
<Routes>
|
||||
<Route path="applications">
|
||||
<Route index element={<Applications />} />
|
||||
<Route path=":id" element={<ApplicationDetails />} />
|
||||
<Route path=":id">
|
||||
<Route index element={<Navigate to="settings" />} />
|
||||
<Route path="settings" element={<ApplicationDetails />} />
|
||||
<Route path="advanced-settings" element={<ApplicationDetails />} />
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="api-resources">
|
||||
<Route index element={<ApiResources />} />
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
cursor: text;
|
||||
|
||||
> svg {
|
||||
|
|
|
@ -59,3 +59,34 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container .body {
|
||||
> :not(:first-child) {
|
||||
margin-top: _.unit(6);
|
||||
}
|
||||
|
||||
.tabContent {
|
||||
form {
|
||||
>:not(:first-child) {
|
||||
margin-top: _.unit(6);
|
||||
}
|
||||
|
||||
.fields {
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
padding-bottom: _.unit(6);
|
||||
|
||||
> div {
|
||||
@include _.form-text-field;
|
||||
}
|
||||
|
||||
.copy {
|
||||
@include _.form-text-field;
|
||||
}
|
||||
}
|
||||
|
||||
.submit {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,46 +1,140 @@
|
|||
import { Application } from '@logto/schemas';
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import BackLink from '@/components/BackLink';
|
||||
import Button from '@/components/Button';
|
||||
import Card from '@/components/Card';
|
||||
import CopyToClipboard from '@/components/CopyToClipboard';
|
||||
import FormField from '@/components/FormField';
|
||||
import ImagePlaceholder from '@/components/ImagePlaceholder';
|
||||
import TabNav, { TabNavLink } from '@/components/TabNav';
|
||||
import TextInput from '@/components/TextInput';
|
||||
import { RequestError } from '@/swr';
|
||||
import { applicationTypeI18nKey } from '@/types/applications';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
type OidcConfig = {
|
||||
authorization_endpoint: string;
|
||||
userinfo_endpoint: string;
|
||||
token_endpoint: string;
|
||||
};
|
||||
|
||||
const ApplicationDetails = () => {
|
||||
const { id } = useParams();
|
||||
const location = useLocation();
|
||||
|
||||
const { data, error } = useSWR<Application, RequestError>(id && `/api/applications/${id}`);
|
||||
const { data: oidcConfig, error: fetchOidcConfigError } = useSWR<OidcConfig, RequestError>(
|
||||
'/oidc/.well-known/openid-configuration'
|
||||
);
|
||||
const isLoading = !data && !error && !fetchOidcConfigError;
|
||||
const dataFetched = data && oidcConfig;
|
||||
|
||||
const { handleSubmit, register, reset } = useForm<Application>({
|
||||
defaultValues: data,
|
||||
});
|
||||
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const isLoading = !data && !error;
|
||||
|
||||
const isAdvancedSettings = location.pathname.includes('advanced-settings');
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
reset(data);
|
||||
}, [data, reset]);
|
||||
|
||||
const onSubmit = handleSubmit((formData) => {
|
||||
console.log(formData);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<BackLink to="/applications">{t('application_details.back_to_applications')}</BackLink>
|
||||
{isLoading && <div>loading</div>}
|
||||
{error && <div>{`error occurred: ${error.metadata.code}`}</div>}
|
||||
{data && (
|
||||
<Card className={styles.header}>
|
||||
<ImagePlaceholder size={76} borderRadius={16} />
|
||||
<div className={styles.metadata}>
|
||||
<div className={styles.name}>{data.name}</div>
|
||||
<div>
|
||||
<div className={styles.type}>{t(`${applicationTypeI18nKey[data.type]}.title`)}</div>
|
||||
<div className={styles.verticalBar} />
|
||||
<div className={styles.text}>App ID</div>
|
||||
<CopyToClipboard value={data.id} className={styles.copy} />
|
||||
{dataFetched && (
|
||||
<>
|
||||
<Card className={styles.header}>
|
||||
<ImagePlaceholder size={76} borderRadius={16} />
|
||||
<div className={styles.metadata}>
|
||||
<div className={styles.name}>{data.name}</div>
|
||||
<div>
|
||||
<div className={styles.type}>{t(`${applicationTypeI18nKey[data.type]}.title`)}</div>
|
||||
<div className={styles.verticalBar} />
|
||||
<div className={styles.text}>App ID</div>
|
||||
<CopyToClipboard value={data.id} className={styles.copy} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Button title="admin_console.application_details.check_help_guide" />
|
||||
</div>
|
||||
</Card>
|
||||
<div>
|
||||
<Button title="admin_console.application_details.check_help_guide" />
|
||||
</div>
|
||||
</Card>
|
||||
<Card className={styles.body}>
|
||||
<TabNav>
|
||||
<TabNavLink href={`/applications/${data.id}/settings`}>
|
||||
{t('application_details.settings')}
|
||||
</TabNavLink>
|
||||
<TabNavLink href={`/applications/${data.id}/advanced-settings`}>
|
||||
{t('application_details.advanced_settings')}
|
||||
</TabNavLink>
|
||||
</TabNav>
|
||||
<div className={styles.tabContent}>
|
||||
<form onSubmit={onSubmit}>
|
||||
<div className={styles.fields}>
|
||||
{!isAdvancedSettings && (
|
||||
<>
|
||||
<FormField
|
||||
isRequired
|
||||
title="admin_console.application_details.application_name"
|
||||
>
|
||||
<TextInput {...register('name', { required: true })} />
|
||||
</FormField>
|
||||
<FormField title="admin_console.application_details.description">
|
||||
<TextInput {...register('description')} />
|
||||
</FormField>
|
||||
<FormField title="admin_console.application_details.authorization_endpoint">
|
||||
<CopyToClipboard
|
||||
className={styles.copy}
|
||||
value={oidcConfig.authorization_endpoint}
|
||||
/>
|
||||
</FormField>
|
||||
</>
|
||||
)}
|
||||
{isAdvancedSettings && (
|
||||
<>
|
||||
<FormField title="admin_console.application_details.token_endpoint">
|
||||
<CopyToClipboard
|
||||
className={styles.copy}
|
||||
value={oidcConfig.token_endpoint}
|
||||
/>
|
||||
</FormField>
|
||||
<FormField title="admin_console.application_details.user_info_endpoint">
|
||||
<CopyToClipboard
|
||||
className={styles.copy}
|
||||
value={oidcConfig.userinfo_endpoint}
|
||||
/>
|
||||
</FormField>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.submit}>
|
||||
<Button
|
||||
htmlType="submit"
|
||||
type="primary"
|
||||
title="admin_console.application_details.save_changes"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -80,6 +80,19 @@ const translation = {
|
|||
application_details: {
|
||||
back_to_applications: 'Back to Applications',
|
||||
check_help_guide: 'Check Help Guide',
|
||||
settings: 'Settings',
|
||||
advanced_settings: 'Advanced Settings',
|
||||
application_name: 'Application Name',
|
||||
description: 'Description',
|
||||
authorization_endpoint: 'Authorization Endpiont',
|
||||
redirect_uri: 'Redirect URI',
|
||||
post_sign_out_redirect_uri: 'Post Sign Out Redirect URI',
|
||||
add_another: 'Add another',
|
||||
id_token_expiration: 'ID Token Expiration',
|
||||
refresh_token_expiration: 'Refresh Token Expiration',
|
||||
token_endpoint: 'Token Endpoint',
|
||||
user_info_endpoint: 'User Info Endpoint',
|
||||
save_changes: 'Save Changes',
|
||||
},
|
||||
api_resources: {
|
||||
title: 'API Resources',
|
||||
|
|
|
@ -82,6 +82,19 @@ const translation = {
|
|||
application_details: {
|
||||
back_to_applications: '返回应用集',
|
||||
check_help_guide: 'Check Help Guide',
|
||||
settings: 'Settings',
|
||||
advanced_settings: 'Advanced Settings',
|
||||
application_name: 'Application Name',
|
||||
description: 'Description',
|
||||
authorization_endpoint: 'Authorization Endpiont',
|
||||
redirect_uri: 'Redirect URI',
|
||||
post_sign_out_redirect_uri: 'Post Sign Out Redirect URI',
|
||||
add_another: 'Add another',
|
||||
id_token_expiration: 'ID Token Expiration',
|
||||
refresh_token_expiration: 'Refresh Token Expiration',
|
||||
token_endpoint: 'Token Endpoint',
|
||||
user_info_endpoint: 'User Info Endpoint',
|
||||
save_changes: 'Save Changes',
|
||||
},
|
||||
api_resources: {
|
||||
title: 'API Resources',
|
||||
|
|
Loading…
Add table
Reference in a new issue