0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-04-07 23:01:25 -05:00

feat(console): connector groups table (#962)

This commit is contained in:
Wang Sijie 2022-05-30 13:51:11 +08:00 committed by GitHub
parent fb49b4e100
commit eb3f0cbf5b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 105 additions and 38 deletions

View file

@ -3,7 +3,7 @@
.status {
display: flex;
align-items: center;
font: var(--font-label-medium);
font: var(--font-body-medium);
.icon {
width: 10px;
@ -23,6 +23,7 @@
padding: _.unit(0.5) _.unit(2);
border-radius: 10px;
background: var(--color-success-99);
font: var(--font-label-medium);
&.disabled {
background: var(--color-neutral-variant-95);

View file

@ -1,5 +1,5 @@
import { I18nKey } from '@logto/phrases';
import { ConnectorType } from '@logto/schemas';
import { ConnectorPlatform, ConnectorType } from '@logto/schemas';
import emailConnectorIcon from '@/assets/images/connector-email.svg';
import smsConnectorIcon from '@/assets/images/connector-sms.svg';
@ -24,3 +24,13 @@ export const connectorIconPlaceHolder: IconPlaceHolder = Object.freeze({
// Note: we don't need icon placeholder for social connector
[ConnectorType.Social]: '',
});
type ConnectorPlatformLabel = {
[key in ConnectorPlatform]: I18nKey;
};
export const connectorPlatformLabel: ConnectorPlatformLabel = Object.freeze({
[ConnectorPlatform.Native]: 'admin_console.connectors.platform.native',
[ConnectorPlatform.Universal]: 'admin_console.connectors.platform.universal',
[ConnectorPlatform.Web]: 'admin_console.connectors.platform.web',
});

View file

@ -21,6 +21,7 @@ const useConnectorGroups = () => {
return [
...previous,
{
id: item.id, // Take first connector's id as groupId, only used for indexing.
name: item.name,
logo: item.logo,
target: item.target,

View file

@ -1,4 +1,5 @@
import { ConnectorDTO, ConnectorType } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
@ -12,9 +13,10 @@ import * as styles from './index.module.scss';
type Props = {
type: ConnectorType;
connector?: ConnectorDTO;
isShowId?: boolean;
};
const ConnectorName = ({ type, connector }: Props) => {
const ConnectorName = ({ type, connector, isShowId = false }: Props) => {
const { t } = useTranslation(undefined);
if (!connector) {
@ -30,7 +32,7 @@ const ConnectorName = ({ type, connector }: Props) => {
<Link to={`/connectors/${connector.id}`} className={styles.link}>
<ItemPreview
title={<UnnamedTrans resource={connector.name} />}
subtitle={connector.id}
subtitle={conditional(isShowId && connector.id)}
icon={<img className={styles.logo} src={connector.logo} />}
/>
</Link>

View file

@ -0,0 +1,23 @@
@use '@/scss/underscore' as _;
.statusItems {
display: flex;
.statusItem {
display: flex;
align-items: center;
&:not(:last-child) {
.line {
margin: 0 _.unit(2);
height: 16px;
@include _.vertical-bar;
}
}
.platform {
margin-left: _.unit(1);
color: var(--color-caption);
}
}
}

View file

@ -4,39 +4,54 @@ import { useTranslation } from 'react-i18next';
import Button from '@/components/Button';
import Status from '@/components/Status';
import { connectorTitlePlaceHolder } from '@/consts/connectors';
import { connectorPlatformLabel, connectorTitlePlaceHolder } from '@/consts/connectors';
import ConnectorName from '../ConnectorName';
import * as styles from './index.module.scss';
type Props = {
type: ConnectorType;
connector?: ConnectorDTO;
connectors: ConnectorDTO[];
onClickSetup?: () => void;
};
const ConnectorRow = ({ type, connector, onClickSetup }: Props) => {
const ConnectorRow = ({ type, connectors, onClickSetup }: Props) => {
const { t } = useTranslation(undefined);
return (
<tr>
<td>
<ConnectorName type={type} connector={connector} />
<ConnectorName
type={type}
connector={connectors[0]}
isShowId={type !== ConnectorType.Social}
/>
</td>
<td>{t(connectorTitlePlaceHolder[type])}</td>
<td>
{type === ConnectorType.Social && (
<Status status={connector?.enabled ? 'enabled' : 'disabled'}>
{t(
connector?.enabled
? 'admin_console.connectors.connector_status_enabled'
: 'admin_console.connectors.connector_status_disabled'
)}
</Status>
<div className={styles.statusItems}>
{connectors.map(({ id, enabled, platform }) => {
const status = enabled ? 'enabled' : 'disabled';
return (
<div key={id} className={styles.statusItem}>
<Status status={enabled ? 'enabled' : 'disabled'}>
{t(`admin_console.connectors.connector_status_${status}`)}
</Status>
<div className={styles.platform}>
{platform && t(connectorPlatformLabel[platform])}
</div>
<div className={styles.line} />
</div>
);
})}
</div>
)}
{type !== ConnectorType.Social && connector && (
{type !== ConnectorType.Social && connectors[0] && (
<Status status="enabled">{t('admin_console.connectors.connector_status_enabled')}</Status>
)}
{type !== ConnectorType.Social && !connector && (
{type !== ConnectorType.Social && !connectors[0] && (
<Button
title="admin_console.connectors.set_up"
type="outline"

View file

@ -1,9 +1,8 @@
import { ConnectorDTO, ConnectorType } from '@logto/schemas';
import { ConnectorType } from '@logto/schemas';
import classNames from 'classnames';
import React, { useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
import useSWR from 'swr';
import Button from '@/components/Button';
import Card from '@/components/Card';
@ -12,7 +11,7 @@ import TabNav, { TabNavItem } from '@/components/TabNav';
import TableEmpty from '@/components/Table/TableEmpty';
import TableError from '@/components/Table/TableError';
import TableLoading from '@/components/Table/TableLoading';
import { RequestError } from '@/hooks/use-api';
import useConnectorGroups from '@/hooks/use-connector-groups';
import Plus from '@/icons/Plus';
import * as tableStyles from '@/scss/table.module.scss';
@ -25,20 +24,26 @@ const Connectors = () => {
const isSocial = location.pathname === '/connectors/social';
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const [createType, setCreateType] = useState<ConnectorType>();
const { data, error, mutate } = useSWR<ConnectorDTO[], RequestError>('/api/connectors');
const { data, error, mutate } = useConnectorGroups();
const isLoading = !data && !error;
const emailConnector = useMemo(
() => data?.find((connector) => connector.enabled && connector.type === ConnectorType.Email),
[data]
);
const emailConnector = useMemo(() => {
const emailConnectorGroup = data?.find(
(connector) => connector.enabled && connector.type === ConnectorType.Email
);
const smsConnector = useMemo(
() => data?.find((connector) => connector.enabled && connector.type === ConnectorType.SMS),
[data]
);
return emailConnectorGroup?.connectors[0];
}, [data]);
const socialConnectors = useMemo(() => {
const smsConnector = useMemo(() => {
const smsConnectorGroup = data?.find(
(connector) => connector.enabled && connector.type === ConnectorType.SMS
);
return smsConnectorGroup?.connectors[0];
}, [data]);
const socialConnectorGroups = useMemo(() => {
if (!isSocial) {
return;
}
@ -89,7 +94,7 @@ const Connectors = () => {
/>
)}
{isLoading && <TableLoading columns={3} />}
{socialConnectors?.length === 0 && (
{socialConnectorGroups?.length === 0 && (
<TableEmpty
columns={3}
title={t('connectors.type.social')}
@ -100,7 +105,7 @@ const Connectors = () => {
)}
{!isLoading && !isSocial && (
<ConnectorRow
connector={emailConnector}
connectors={emailConnector ? [emailConnector] : []}
type={ConnectorType.Email}
onClickSetup={() => {
setCreateType(ConnectorType.Email);
@ -108,14 +113,13 @@ const Connectors = () => {
/>
)}
{!isLoading && !isSocial && (
<ConnectorRow connector={smsConnector} type={ConnectorType.SMS} />
)}
{socialConnectors?.map((connector) => (
<ConnectorRow
key={connector.id}
connector={connector}
type={ConnectorType.Social}
connectors={smsConnector ? [smsConnector] : []}
type={ConnectorType.SMS}
/>
)}
{socialConnectorGroups?.map(({ connectors, id }) => (
<ConnectorRow key={id} connectors={connectors} type={ConnectorType.Social} />
))}
</tbody>
</table>

View file

@ -1,6 +1,7 @@
import { ConnectorDTO } from '@logto/schemas';
export type ConnectorGroup = Pick<ConnectorDTO, 'name' | 'logo' | 'target' | 'type'> & {
id: string;
enabled: boolean;
connectors: ConnectorDTO[];
};

View file

@ -257,6 +257,11 @@ const translation = {
subtitle:
'A step by step guide to integrate your connector or get a sample configured with your account settings',
},
platform: {
universal: 'Universal',
web: 'Web',
native: 'Native',
},
},
connector_details: {
back_to_connectors: 'Back to Connectors',

View file

@ -255,6 +255,11 @@ const translation = {
guide: {
subtitle: '请参考下列分步指南,配置您的 connector或点击按钮获取示例配置文件',
},
platform: {
universal: '通用',
web: '网页',
native: '原生',
},
},
connector_details: {
back_to_connectors: '返回连接器',