0
Fork 0
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:
Xiao Yijun 2022-03-15 12:42:42 +08:00 committed by GitHub
parent f25cb8adae
commit 22a6278a9b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 176 additions and 20 deletions

View file

@ -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 />} />

View file

@ -12,6 +12,7 @@
.row {
display: flex;
align-items: center;
justify-content: space-between;
cursor: text;
> svg {

View file

@ -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;
}
}
}
}

View file

@ -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>
);

View file

@ -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',

View file

@ -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',