mirror of
https://github.com/logto-io/logto.git
synced 2025-02-17 22:04:19 -05:00
feat(console): retrieve applications from api (#320)
* feat(console): retrieve applications from api * fix(console): i18n key * fix(console): update per review
This commit is contained in:
parent
06fd253754
commit
bb1d3c0a37
11 changed files with 116 additions and 31 deletions
|
@ -25,7 +25,8 @@
|
|||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-i18next": "^11.15.4",
|
||||
"react-router-dom": "^6.2.2"
|
||||
"react-router-dom": "^6.2.2",
|
||||
"swr": "^1.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@parcel/core": "^2.3.1",
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { BrowserRouter, Route, Routes, useLocation, useNavigate } from 'react-router-dom';
|
||||
|
||||
import { SWRConfig } from 'swr';
|
||||
import './scss/normalized.scss';
|
||||
|
||||
import * as styles from './App.module.scss';
|
||||
import AppContent from './components/AppContent';
|
||||
import Content from './components/Content';
|
||||
|
@ -10,6 +11,7 @@ import Topbar from './components/Topbar';
|
|||
import initI18n from './i18n/init';
|
||||
import ApiResources from './pages/ApiResources';
|
||||
import Applications from './pages/Applications';
|
||||
import { fetcher } from './swr';
|
||||
|
||||
const isBasenameNeeded = process.env.NODE_ENV !== 'development' || process.env.PORT === '5002';
|
||||
|
||||
|
@ -26,6 +28,7 @@ const Main = () => {
|
|||
}, [location.pathname, navigate]);
|
||||
|
||||
return (
|
||||
<SWRConfig value={{ fetcher }}>
|
||||
<AppContent theme="light">
|
||||
<Topbar />
|
||||
<div className={styles.content}>
|
||||
|
@ -38,6 +41,7 @@ const Main = () => {
|
|||
</Content>
|
||||
</div>
|
||||
</AppContent>
|
||||
</SWRConfig>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ const ItemPreview = ({ title, subtitle, icon }: Props) => {
|
|||
{icon}
|
||||
<div>
|
||||
<div className={styles.title}>{title}</div>
|
||||
{subtitle && <div className={styles.subtitle}>{subtitle}</div>}
|
||||
{subtitle && <div className={styles.subtitle}>{String(subtitle)}</div>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
margin-top: _.unit(6);
|
||||
width: 100%;
|
||||
|
||||
tbody tr {
|
||||
tbody tr.clickable {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import { Application } from '@logto/schemas';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import Button from '@/components/Button';
|
||||
import Card from '@/components/Card';
|
||||
|
@ -6,10 +9,16 @@ import CardTitle from '@/components/CardTitle';
|
|||
import CopyToClipboard from '@/components/CopyToClipboard';
|
||||
import ImagePlaceholder from '@/components/ImagePlaceholder';
|
||||
import ItemPreview from '@/components/ItemPreview';
|
||||
import { RequestError } from '@/swr';
|
||||
import { applicationTypeI18nKey } from '@/types/applications';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
const Applications = () => {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const { data, error } = useSWR<Application[], RequestError>('/api/applications');
|
||||
const isLoading = !data && !error;
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<div className={styles.headline}>
|
||||
|
@ -19,23 +28,35 @@ const Applications = () => {
|
|||
<table className={styles.table}>
|
||||
<thead>
|
||||
<tr>
|
||||
<td className={styles.applicationName}>Application Name</td>
|
||||
<td>Client ID</td>
|
||||
<td className={styles.applicationName}>{t('applications.application_name')}</td>
|
||||
<td>{t('applications.client_id')}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{error && (
|
||||
<tr>
|
||||
<td colSpan={2}>error occurred: {error.metadata.code}</td>
|
||||
</tr>
|
||||
)}
|
||||
{isLoading && (
|
||||
<tr>
|
||||
<td colSpan={2}>loading</td>
|
||||
</tr>
|
||||
)}
|
||||
{data?.map(({ id, name, type }) => (
|
||||
<tr key={id}>
|
||||
<td>
|
||||
<ItemPreview
|
||||
title="Default App"
|
||||
subtitle="Single Page Application"
|
||||
title={name}
|
||||
subtitle={String(t(applicationTypeI18nKey[type]))}
|
||||
icon={<ImagePlaceholder />}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<CopyToClipboard value="RUMatENw0rFWO5aGbMI8tY2Qol50eOg3" />
|
||||
<CopyToClipboard value={id} />
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</Card>
|
||||
|
|
22
packages/console/src/swr/index.ts
Normal file
22
packages/console/src/swr/index.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { RequestErrorMetadata } from '@logto/schemas';
|
||||
import { BareFetcher } from 'swr';
|
||||
|
||||
export class RequestError extends Error {
|
||||
metadata: RequestErrorMetadata;
|
||||
|
||||
constructor(metadata: RequestErrorMetadata) {
|
||||
super('Request error occurred.');
|
||||
this.metadata = metadata;
|
||||
}
|
||||
}
|
||||
|
||||
export const fetcher: BareFetcher = async (resource, init) => {
|
||||
const response = await fetch(resource, init);
|
||||
|
||||
if (!response.ok) {
|
||||
const metadata = (await response.json()) as RequestErrorMetadata;
|
||||
throw new RequestError(metadata);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
};
|
8
packages/console/src/types/applications.ts
Normal file
8
packages/console/src/types/applications.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { AdminConsoleKey } from '@logto/phrases';
|
||||
import { ApplicationType } from '@logto/schemas';
|
||||
|
||||
export const applicationTypeI18nKey: Record<ApplicationType, AdminConsoleKey> = {
|
||||
[ApplicationType.Native]: 'applications.type.native',
|
||||
[ApplicationType.SPA]: 'applications.type.spa',
|
||||
[ApplicationType.Traditional]: 'applications.type.tranditional',
|
||||
};
|
7
packages/core/src/include.d/koa.d.ts
vendored
7
packages/core/src/include.d/koa.d.ts
vendored
|
@ -1,4 +1,4 @@
|
|||
import { DefaultState, DefaultContext, ParameterizedContext, Next } from 'koa';
|
||||
import { DefaultState, DefaultContext, ParameterizedContext, Next, BaseRequest } from 'koa';
|
||||
|
||||
declare module 'koa' {
|
||||
// Have to do this patch since `compose.Middleware` returns `any`.
|
||||
|
@ -10,4 +10,9 @@ declare module 'koa' {
|
|||
ResponseBodyT = any,
|
||||
NextT = void
|
||||
> = KoaMiddleware<ParameterizedContext<StateT, ContextT, ResponseBodyT>, NextT>;
|
||||
|
||||
interface Request extends BaseRequest {
|
||||
body?: any;
|
||||
files?: Files;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,13 @@ const translation = {
|
|||
subtitle:
|
||||
'Setup a mobile, single page or traditional application to use Logto for authentication.',
|
||||
create: 'Create Application',
|
||||
application_name: 'Application Name',
|
||||
client_id: 'Client ID',
|
||||
type: {
|
||||
native: 'Native App',
|
||||
spa: 'Single Page App',
|
||||
tranditional: 'Tranditional Web App',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -40,6 +40,13 @@ const translation = {
|
|||
subtitle:
|
||||
'Setup a mobile, single page or traditional application to use Logto for authentication.',
|
||||
create: 'Create Application',
|
||||
application_name: 'Application Name',
|
||||
client_id: 'Client ID',
|
||||
type: {
|
||||
native: 'Native App',
|
||||
spa: 'Single Page App',
|
||||
tranditional: 'Tranditional Web App',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
|
@ -46,6 +46,7 @@ importers:
|
|||
react-i18next: ^11.15.4
|
||||
react-router-dom: ^6.2.2
|
||||
stylelint: ^13.13.1
|
||||
swr: ^1.2.2
|
||||
typescript: ^4.5.5
|
||||
dependencies:
|
||||
'@logto/phrases': link:../phrases
|
||||
|
@ -58,6 +59,7 @@ importers:
|
|||
react-dom: 17.0.2_react@17.0.2
|
||||
react-i18next: 11.15.4_2c37a602a29bb6bd53f3de707a8cfcc5
|
||||
react-router-dom: 6.2.2_react-dom@17.0.2+react@17.0.2
|
||||
swr: 1.2.2_react@17.0.2
|
||||
devDependencies:
|
||||
'@parcel/core': 2.3.1
|
||||
'@parcel/transformer-sass': 2.3.1_@parcel+core@2.3.1
|
||||
|
@ -12547,6 +12549,14 @@ packages:
|
|||
stable: 0.1.8
|
||||
dev: true
|
||||
|
||||
/swr/1.2.2_react@17.0.2:
|
||||
resolution: {integrity: sha512-ky0BskS/V47GpW8d6RU7CPsr6J8cr7mQD6+do5eky3bM0IyJaoi3vO8UhvrzJaObuTlGhPl2szodeB2dUd76Xw==}
|
||||
peerDependencies:
|
||||
react: ^16.11.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
react: 17.0.2
|
||||
dev: false
|
||||
|
||||
/symbol-tree/3.2.4:
|
||||
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
|
||||
dev: true
|
||||
|
|
Loading…
Add table
Reference in a new issue