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

feat(console): group connectors in add modal ()

This commit is contained in:
Wang Sijie 2022-06-06 11:36:58 +08:00 committed by GitHub
parent 79ea8b2c68
commit fa420c9fcb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 132 additions and 26 deletions
packages
console/src
phrases/src/locales

View file

@ -113,5 +113,18 @@
}
}
}
&.disabled {
cursor: not-allowed;
color: var(--color-disabled);
.indicator {
border-color: var(--color-disabled);
&::before {
background: var(--color-layer-1);
}
}
}
}
}

View file

@ -1,4 +1,4 @@
import { I18nKey } from '@logto/phrases';
import { AdminConsoleKey, I18nKey } from '@logto/phrases';
import { ConnectorPlatform, ConnectorType } from '@logto/schemas';
import emailConnectorIcon from '@/assets/images/connector-email.svg';
@ -26,11 +26,11 @@ export const connectorIconPlaceHolder: IconPlaceHolder = Object.freeze({
});
type ConnectorPlatformLabel = {
[key in ConnectorPlatform]: I18nKey;
[key in ConnectorPlatform]: AdminConsoleKey;
};
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',
[ConnectorPlatform.Native]: 'connectors.platform.native',
[ConnectorPlatform.Universal]: 'connectors.platform.universal',
[ConnectorPlatform.Web]: 'connectors.platform.web',
});

View file

@ -1,4 +1,4 @@
import { ConnectorDTO } from '@logto/schemas';
import { ConnectorDTO, ConnectorType } from '@logto/schemas';
import { useMemo } from 'react';
import useSWR from 'swr';
@ -15,7 +15,10 @@ const useConnectorGroups = () => {
}
return data.reduce<ConnectorGroup[]>((previous, item) => {
const groupIndex = previous.findIndex(({ target }) => target === item.target);
const groupIndex = previous.findIndex(
// Only group social connectors
({ target }) => target === item.target && item.type === ConnectorType.Social
);
if (groupIndex === -1) {
return [
@ -24,6 +27,7 @@ const useConnectorGroups = () => {
id: item.id, // Take first connector's id as groupId, only used for indexing.
name: item.name,
logo: item.logo,
description: item.description,
target: item.target,
type: item.type,
enabled: item.enabled,
@ -50,6 +54,7 @@ const useConnectorGroups = () => {
return {
...rest,
data: groups,
connectors: data,
};
};

View file

@ -0,0 +1,10 @@
@use '@/scss/underscore' as _;
.platforms {
margin-top: _.unit(6);
.title {
font: var(--font-subhead-2);
margin-bottom: _.unit(3);
}
}

View file

@ -0,0 +1,47 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import RadioGroup, { Radio } from '@/components/RadioGroup';
import UnnamedTrans from '@/components/UnnamedTrans';
import { connectorPlatformLabel } from '@/consts/connectors';
import { ConnectorGroup } from '@/types/connector';
import * as styles from './PlatformSelector.module.scss';
type Props = {
connectorGroup: ConnectorGroup;
connectorId?: string;
onConnectorIdChange: (value: string) => void;
};
const PlatformSelector = ({ connectorGroup, connectorId, onConnectorIdChange }: Props) => {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
if (connectorGroup.connectors.length <= 1) {
return null;
}
return (
<div className={styles.platforms}>
<div className={styles.title}>
<UnnamedTrans resource={connectorGroup.name} />
{t('connectors.add_multi_platform')}
</div>
<RadioGroup type="plain" name="connector" value={connectorId} onChange={onConnectorIdChange}>
{connectorGroup.connectors.map(
({ platform, id, enabled }) =>
platform && (
<Radio
key={id}
value={id}
title={connectorPlatformLabel[platform]}
isDisabled={enabled}
/>
)
)}
</RadioGroup>
</div>
);
};
export default PlatformSelector;

View file

@ -1,16 +1,16 @@
import { ConnectorDTO, ConnectorType } from '@logto/schemas';
import { ConnectorType } from '@logto/schemas';
import React, { useMemo, useState } from 'react';
import Modal from 'react-modal';
import useSWR from 'swr';
import Button from '@/components/Button';
import ModalLayout from '@/components/ModalLayout';
import RadioGroup, { Radio } from '@/components/RadioGroup';
import UnnamedTrans from '@/components/UnnamedTrans';
import { RequestError } from '@/hooks/use-api';
import useConnectorGroups from '@/hooks/use-connector-groups';
import * as modalStyles from '@/scss/modal.module.scss';
import GuideModal from '../GuideModal';
import PlatformSelector from './PlatformSelector';
import * as styles from './index.module.scss';
type Props = {
@ -20,14 +20,20 @@ type Props = {
};
const CreateForm = ({ onClose, isOpen: isFormOpen, type }: Props) => {
const { data, error } = useSWR<ConnectorDTO[], RequestError>('/api/connectors');
const isLoading = !data && !error;
const { data: allGroups, connectors, error } = useConnectorGroups();
const isLoading = !allGroups && !connectors && !error;
const [activeGroupId, setActiveGroupId] = useState<string>();
const [activeConnectorId, setActiveConnectorId] = useState<string>();
const [isGetStartedModalOpen, setIsGetStartedModalOpen] = useState(false);
const connectors = useMemo(
() => data?.filter((connector) => connector.type === type),
[data, type]
const groups = useMemo(
() => allGroups?.filter((group) => group.type === type),
[allGroups, type]
);
const activeGroup = useMemo(
() => groups?.find(({ id }) => id === activeGroupId),
[activeGroupId, groups]
);
const activeConnector = useMemo(
@ -47,6 +53,24 @@ const CreateForm = ({ onClose, isOpen: isFormOpen, type }: Props) => {
return 'connectors.setup_title.social';
}, [type]);
const handleGroupChange = (groupId: string) => {
if (!groups) {
return;
}
setActiveGroupId(groupId);
const group = groups.find(({ id }) => id === groupId);
if (!group) {
return;
}
const firstAvailableConnector = group.connectors.find(({ enabled }) => !enabled);
setActiveConnectorId(firstAvailableConnector?.id);
};
const closeModal = () => {
setIsGetStartedModalOpen(false);
onClose?.();
@ -76,18 +100,13 @@ const CreateForm = ({ onClose, isOpen: isFormOpen, type }: Props) => {
>
{isLoading && 'Loading...'}
{error && error}
{connectors && (
<RadioGroup
name="connector"
value={activeConnectorId}
type="card"
onChange={setActiveConnectorId}
>
{connectors.map(({ id, name, logo, description, enabled }) => (
{groups && (
<RadioGroup name="group" value={activeGroupId} type="card" onChange={handleGroupChange}>
{groups.map(({ id, name, logo, description, connectors }) => (
<Radio
key={id}
value={id}
isDisabled={enabled}
isDisabled={connectors.every(({ enabled }) => enabled)}
className={styles.connector}
disabledLabel="connectors.added"
>
@ -97,7 +116,7 @@ const CreateForm = ({ onClose, isOpen: isFormOpen, type }: Props) => {
<div className={styles.name}>
<UnnamedTrans resource={name} />
</div>
<div className={styles.connectorId}>{id}</div>
{type !== ConnectorType.Social && <div className={styles.connectorId}>{id}</div>}
<div className={styles.description}>
<UnnamedTrans resource={description} />
</div>
@ -105,6 +124,13 @@ const CreateForm = ({ onClose, isOpen: isFormOpen, type }: Props) => {
))}
</RadioGroup>
)}
{activeGroup && (
<PlatformSelector
connectorGroup={activeGroup}
connectorId={activeConnectorId}
onConnectorIdChange={setActiveConnectorId}
/>
)}
{activeConnector && (
<GuideModal
connector={activeConnector}

View file

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

View file

@ -268,6 +268,7 @@ const translation = {
web: 'Web',
native: 'Native',
},
add_multi_platform: ' supports multiple platform, select a platform to continue',
},
connector_details: {
back_to_connectors: 'Back to Connectors',

View file

@ -264,6 +264,7 @@ const translation = {
web: '网页',
native: '原生',
},
add_multi_platform: ' 支持多平台,请选择一个平台继续',
},
connector_details: {
back_to_connectors: '返回连接器',