mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
feat(console): connector details header (#348)
This commit is contained in:
parent
6fcc682f4f
commit
dab3c12bea
11 changed files with 158 additions and 49 deletions
|
@ -12,8 +12,8 @@ import initI18n from './i18n/init';
|
||||||
import ApiResources from './pages/ApiResources';
|
import ApiResources from './pages/ApiResources';
|
||||||
import ApplicationDetails from './pages/ApplicationDetails';
|
import ApplicationDetails from './pages/ApplicationDetails';
|
||||||
import Applications from './pages/Applications';
|
import Applications from './pages/Applications';
|
||||||
|
import ConnectorDetails from './pages/ConnectorDetails';
|
||||||
import Connectors from './pages/Connectors';
|
import Connectors from './pages/Connectors';
|
||||||
import Connector from './pages/Connectors/Connector';
|
|
||||||
import { fetcher } from './swr';
|
import { fetcher } from './swr';
|
||||||
|
|
||||||
const isBasenameNeeded = process.env.NODE_ENV !== 'development' || process.env.PORT === '5002';
|
const isBasenameNeeded = process.env.NODE_ENV !== 'development' || process.env.PORT === '5002';
|
||||||
|
@ -46,7 +46,7 @@ const Main = () => {
|
||||||
<Route path="connectors">
|
<Route path="connectors">
|
||||||
<Route index element={<Connectors />} />
|
<Route index element={<Connectors />} />
|
||||||
<Route path="social" element={<Connectors />} />
|
<Route path="social" element={<Connectors />} />
|
||||||
<Route path=":connectorId" element={<Connector />} />
|
<Route path=":connectorId" element={<ConnectorDetails />} />
|
||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Routes>
|
||||||
</Content>
|
</Content>
|
||||||
|
|
14
packages/console/src/components/BackLink/index.module.scss
Normal file
14
packages/console/src/components/BackLink/index.module.scss
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
@use '@/scss/underscore' as _;
|
||||||
|
|
||||||
|
.button {
|
||||||
|
padding-left: 0;
|
||||||
|
|
||||||
|
.body {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> *:not(:first-child) {
|
||||||
|
margin-left: _.unit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
packages/console/src/components/BackLink/index.tsx
Normal file
24
packages/console/src/components/BackLink/index.tsx
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import React, { ReactNode } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import * as buttonStyles from '@/components/TextButton/index.module.scss';
|
||||||
|
|
||||||
|
import Back from './Back';
|
||||||
|
import * as styles from './index.module.scss';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
to: string;
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const BackLink = ({ to, children }: Props) => (
|
||||||
|
<Link to={to} className={classNames(buttonStyles.button, styles.button)}>
|
||||||
|
<div className={styles.body}>
|
||||||
|
<Back />
|
||||||
|
<div>{children}</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default BackLink;
|
|
@ -6,19 +6,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
|
||||||
padding-left: 0;
|
|
||||||
|
|
||||||
.body {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
> *:not(:first-child) {
|
|
||||||
margin-left: _.unit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.container .header {
|
.container .header {
|
||||||
padding: _.unit(8);
|
padding: _.unit(8);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
import { Application } from '@logto/schemas';
|
import { Application } from '@logto/schemas';
|
||||||
import classNames from 'classnames';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Link, useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
|
|
||||||
|
import BackLink from '@/components/BackLink';
|
||||||
import Card from '@/components/Card';
|
import Card from '@/components/Card';
|
||||||
import CopyToClipboard from '@/components/CopyToClipboard';
|
import CopyToClipboard from '@/components/CopyToClipboard';
|
||||||
import ImagePlaceholder from '@/components/ImagePlaceholder';
|
import ImagePlaceholder from '@/components/ImagePlaceholder';
|
||||||
import * as buttonStyles from '@/components/TextButton/index.module.scss';
|
|
||||||
import { RequestError } from '@/swr';
|
import { RequestError } from '@/swr';
|
||||||
import { applicationTypeI18nKey } from '@/types/applications';
|
import { applicationTypeI18nKey } from '@/types/applications';
|
||||||
|
|
||||||
import Back from './icons/Back';
|
|
||||||
import * as styles from './index.module.scss';
|
import * as styles from './index.module.scss';
|
||||||
|
|
||||||
const ApplicationDetails = () => {
|
const ApplicationDetails = () => {
|
||||||
|
@ -23,12 +21,7 @@ const ApplicationDetails = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<Link to="/applications" className={classNames(buttonStyles.button, styles.button)}>
|
<BackLink to="/applications">{t('application_details.back_to_applications')}</BackLink>
|
||||||
<div className={styles.body}>
|
|
||||||
<Back />
|
|
||||||
<div>{t('application_details.back_to_applications')}</div>
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
{isLoading && <div>loading</div>}
|
{isLoading && <div>loading</div>}
|
||||||
{error && <div>{`error occurred: ${error.metadata.code}`}</div>}
|
{error && <div>{`error occurred: ${error.metadata.code}`}</div>}
|
||||||
{data && (
|
{data && (
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
@use '@/scss/underscore' as _;
|
||||||
|
|
||||||
|
.container {
|
||||||
|
> *:not(:first-child) {
|
||||||
|
margin-top: _.unit(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container .header {
|
||||||
|
padding: _.unit(8);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
> *:not(:first-child) {
|
||||||
|
margin-left: _.unit(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: _.unit(19);
|
||||||
|
height: _.unit(19);
|
||||||
|
border-radius: _.unit(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.metadata {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: _.unit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
> *:not(:first-child) {
|
||||||
|
margin-left: _.unit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font: var(--font-title-large);
|
||||||
|
color: var(--color-component-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.id {
|
||||||
|
font: var(--font-subhead-2);
|
||||||
|
color: var(--color-component-caption);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
packages/console/src/pages/ConnectorDetails/index.tsx
Normal file
58
packages/console/src/pages/ConnectorDetails/index.tsx
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import { ConnectorDTO } from '@logto/schemas';
|
||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import useSWR from 'swr';
|
||||||
|
|
||||||
|
import BackLink from '@/components/BackLink';
|
||||||
|
import Card from '@/components/Card';
|
||||||
|
import ImagePlaceholder from '@/components/ImagePlaceholder';
|
||||||
|
import Status from '@/components/Status';
|
||||||
|
import { RequestError } from '@/swr';
|
||||||
|
|
||||||
|
import * as styles from './index.module.scss';
|
||||||
|
|
||||||
|
const ConnectorDetails = () => {
|
||||||
|
const { connectorId } = useParams();
|
||||||
|
const {
|
||||||
|
t,
|
||||||
|
i18n: { language },
|
||||||
|
} = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||||
|
const { data, error } = useSWR<ConnectorDTO, RequestError>(
|
||||||
|
connectorId && `/api/connectors/${connectorId}`
|
||||||
|
);
|
||||||
|
const isLoading = !data && !error;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<BackLink to="/connectors">{t('connector_details.back_to_connectors')}</BackLink>
|
||||||
|
{isLoading && <div>loading</div>}
|
||||||
|
{error && <div>{`error occurred: ${error.metadata.code}`}</div>}
|
||||||
|
{data && (
|
||||||
|
<Card className={styles.header}>
|
||||||
|
{data.metadata.logo.startsWith('http') ? (
|
||||||
|
<img src={data.metadata.logo} className={styles.logo} />
|
||||||
|
) : (
|
||||||
|
<ImagePlaceholder size={76} borderRadius={16} />
|
||||||
|
)}
|
||||||
|
<div className={styles.metadata}>
|
||||||
|
<div>
|
||||||
|
<div className={styles.name}>{data.metadata.name[language]}</div>
|
||||||
|
<div className={styles.id}>{data.id}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Status status={data.enabled ? 'operational' : 'offline'}>
|
||||||
|
{t('connectors.connector_status', {
|
||||||
|
context: data.enabled ? 'enabled' : 'disabled',
|
||||||
|
})}
|
||||||
|
</Status>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>action</div>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ConnectorDetails;
|
|
@ -1,24 +0,0 @@
|
||||||
import { ConnectorDTO } from '@logto/schemas';
|
|
||||||
import React from 'react';
|
|
||||||
import { useParams } from 'react-router-dom';
|
|
||||||
import useSWR from 'swr';
|
|
||||||
|
|
||||||
import Card from '@/components/Card';
|
|
||||||
import { RequestError } from '@/swr';
|
|
||||||
|
|
||||||
const Connector = () => {
|
|
||||||
const { connectorId } = useParams();
|
|
||||||
const { data, error } = useSWR<ConnectorDTO, RequestError>(
|
|
||||||
connectorId && `/api/connectors/${connectorId}`
|
|
||||||
);
|
|
||||||
const isLoading = !data && !error;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
{isLoading && 'loading'}
|
|
||||||
{error && error}
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Connector;
|
|
|
@ -101,6 +101,9 @@ const translation = {
|
||||||
application_details: {
|
application_details: {
|
||||||
back_to_applications: 'Back to Applications',
|
back_to_applications: 'Back to Applications',
|
||||||
},
|
},
|
||||||
|
connector_details: {
|
||||||
|
back_to_connectors: 'Back to Connectors',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,9 @@ const translation = {
|
||||||
application_details: {
|
application_details: {
|
||||||
back_to_applications: '返回应用集',
|
back_to_applications: '返回应用集',
|
||||||
},
|
},
|
||||||
|
connector_details: {
|
||||||
|
back_to_connectors: '返回连接器',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue