0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-31 22:51:25 -05:00

refactor(console): connector details page (#2465)

This commit is contained in:
Xiao Yijun 2022-11-21 17:17:08 +08:00 committed by GitHub
parent add9fb12c2
commit 146de08c9b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 75 additions and 57 deletions

View file

@ -1,16 +1,17 @@
import type { Connector, ConnectorResponse, ConnectorMetadata } from '@logto/schemas';
import { ConnectorType } from '@logto/schemas';
import { useMemo } from 'react';
import { useEffect, useMemo } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom';
import Button from '@/components/Button';
import CodeEditor from '@/components/CodeEditor';
import DetailsForm from '@/components/DetailsForm';
import FormCard from '@/components/FormCard';
import FormField from '@/components/FormField';
import UnsavedChangesAlertModal from '@/components/UnsavedChangesAlertModal';
import useApi from '@/hooks/use-api';
import * as detailsStyles from '@/scss/details.module.scss';
import { safeParseJson } from '@/utilities/json';
import * as styles from '../index.module.scss';
@ -24,15 +25,15 @@ type Props = {
const ConnectorContent = ({ isDeleted, connectorData, onConnectorUpdated }: Props) => {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const { connectorId } = useParams();
const api = useApi();
const methods = useForm<{ configJson: string }>({ reValidateMode: 'onBlur' });
const {
control,
formState: { isSubmitting, isDirty },
handleSubmit,
watch,
reset,
} = methods;
} = useForm<{ configJson: string }>({ reValidateMode: 'onBlur' });
const defaultConfig = useMemo(() => {
const hasData = Object.keys(connectorData.config).length > 0;
@ -40,6 +41,10 @@ const ConnectorContent = ({ isDeleted, connectorData, onConnectorUpdated }: Prop
return hasData ? JSON.stringify(connectorData.config, null, 2) : connectorData.configTemplate;
}, [connectorData]);
useEffect(() => {
reset();
}, [connectorId, reset]);
const onSubmit = handleSubmit(async ({ configJson }) => {
if (!configJson) {
toast.error(t('connector_details.save_error_empty_config'));
@ -66,8 +71,16 @@ const ConnectorContent = ({ isDeleted, connectorData, onConnectorUpdated }: Prop
return (
<>
<div className={styles.main}>
<form {...methods}>
<DetailsForm
isDirty={isDirty}
isSubmitting={isSubmitting}
onDiscard={reset}
onSubmit={onSubmit}
>
<FormCard
title="connector_details.settings"
description="connector_details.settings_description"
>
<Controller
name="configJson"
control={control}
@ -83,26 +96,16 @@ const ConnectorContent = ({ isDeleted, connectorData, onConnectorUpdated }: Prop
</FormField>
)}
/>
</form>
{connectorData.type !== ConnectorType.Social && (
<SenderTester
connectorId={connectorData.id}
connectorType={connectorData.type}
config={watch('configJson')}
/>
)}
</div>
<div className={detailsStyles.footer}>
<div className={detailsStyles.footerMain}>
<Button
type="primary"
size="large"
title="general.save_changes"
isLoading={isSubmitting}
onClick={onSubmit}
/>
</div>
</div>
{connectorData.type !== ConnectorType.Social && (
<SenderTester
className={styles.senderTest}
connectorId={connectorData.id}
connectorType={connectorData.type}
config={watch('configJson')}
/>
)}
</FormCard>
</DetailsForm>
<UnsavedChangesAlertModal hasUnsavedChanges={!isDeleted && isDirty} />
</>
);

View file

@ -57,6 +57,7 @@ const SenderTester = ({ connectorId, connectorType, config, className }: Props)
const onSubmit = handleSubmit(async (formData) => {
const { sendTo } = formData;
const result = safeParseJson(config);
if (!result.success) {
@ -73,7 +74,7 @@ const SenderTester = ({ connectorId, connectorType, config, className }: Props)
});
return (
<form className={className}>
<div className={className}>
<div className={styles.fields}>
<FormField
isRequired
@ -120,7 +121,7 @@ const SenderTester = ({ connectorId, connectorType, config, className }: Props)
<div className={classNames(inputError?.message ? styles.error : styles.description)}>
{inputError?.message ?? t('connector_details.test_sender_description')}
</div>
</form>
</div>
);
};

View file

@ -76,18 +76,12 @@
}
}
.body {
> :not(:first-child) {
margin-top: _.unit(4);
}
.codeEditor {
margin-bottom: _.unit(6);
}
.main {
flex: 1;
.codeEditor {
margin-bottom: _.unit(6);
}
}
.senderTest {
margin-top: _.unit(6);
}
.resetIcon {

View file

@ -1,6 +1,5 @@
import type { ConnectorResponse } from '@logto/schemas';
import { AppearanceMode, ConnectorType } from '@logto/schemas';
import classNames from 'classnames';
import { useState } from 'react';
import { toast } from 'react-hot-toast';
import { Trans, useTranslation } from 'react-i18next';
@ -73,11 +72,12 @@ const ConnectorDetails = () => {
json: { enabled: false },
})
.json<ConnectorResponse>();
toast.success(t('connector_details.connector_deleted'));
await mutateGlobal('/api/connectors');
setIsDeleted(true);
toast.success(t('connector_details.connector_deleted'));
await mutateGlobal('/api/connectors');
if (isSocial) {
navigate(`/connectors/social`, { replace: true });
} else {
@ -178,21 +178,19 @@ const ConnectorDetails = () => {
</div>
</Card>
)}
<TabNav>
<TabNavItem href={`/connectors/${connectorId ?? ''}`}>
{t('general.settings_nav')}
</TabNavItem>
</TabNav>
{data && (
<Card className={classNames(styles.body, detailsStyles.body)}>
<TabNav>
<TabNavItem href={`/connectors/${connectorId ?? ''}`}>
{t('general.settings_nav')}
</TabNavItem>
</TabNav>
<ConnectorContent
isDeleted={isDeleted}
connectorData={data}
onConnectorUpdated={(connector) => {
void mutate(connector);
}}
/>
</Card>
<ConnectorContent
isDeleted={isDeleted}
connectorData={data}
onConnectorUpdated={(connector) => {
void mutate(connector);
}}
/>
)}
{data && (
<ConfirmModal

View file

@ -2,6 +2,7 @@
.container {
width: 100%;
padding-bottom: _.unit(6);
@include _.flex-column;
padding-bottom: _.unit(6);

View file

@ -1,6 +1,9 @@
const connector_details = {
back_to_connectors: 'Zurück zu Connectoren',
check_readme: 'Zur README',
settings: 'Settings', // UNTRANSLATED
settings_description:
'It real sent your at. Amounted all shy set why followed declared. Repeated of endeavor mr position kindness offering ignorant so up. Simplicity are melancholy preference considered saw companions.', // UNTRANSLATED
save_error_empty_config: 'Bitte fülle die Konfiguration aus',
send: 'Senden',
send_error_invalid_format: 'Ungültige Eingabe',

View file

@ -1,6 +1,9 @@
const connector_details = {
back_to_connectors: 'Back to Connectors',
check_readme: 'Check README',
settings: 'Settings',
settings_description:
'It real sent your at. Amounted all shy set why followed declared. Repeated of endeavor mr position kindness offering ignorant so up. Simplicity are melancholy preference considered saw companions.', // UNTRANSLATED
save_error_empty_config: 'Please enter config',
send: 'Send',
send_error_invalid_format: 'Invalid input',

View file

@ -1,6 +1,9 @@
const connector_details = {
back_to_connectors: 'Retour à Connecteurs',
check_readme: 'Vérifier le README',
settings: 'Settings', // UNTRANSLATED
settings_description:
'It real sent your at. Amounted all shy set why followed declared. Repeated of endeavor mr position kindness offering ignorant so up. Simplicity are melancholy preference considered saw companions.', // UNTRANSLATED
save_error_empty_config: 'Veuillez entrer la configuration',
send: 'Envoyer',
send_error_invalid_format: 'Entrée non valide',

View file

@ -1,6 +1,9 @@
const connector_details = {
back_to_connectors: '연동으로 돌아가기',
check_readme: 'README 확인',
settings: 'Settings', // UNTRANSLATED
settings_description:
'It real sent your at. Amounted all shy set why followed declared. Repeated of endeavor mr position kindness offering ignorant so up. Simplicity are melancholy preference considered saw companions.', // UNTRANSLATED
save_error_empty_config: '설정을 입력해주세요.',
send: '보내기',
send_error_invalid_format: '유효하지 않은 입력',

View file

@ -1,6 +1,9 @@
const connector_details = {
back_to_connectors: 'Voltar para Conectores',
check_readme: 'Verifique o README',
settings: 'Settings', // UNTRANSLATED
settings_description:
'It real sent your at. Amounted all shy set why followed declared. Repeated of endeavor mr position kindness offering ignorant so up. Simplicity are melancholy preference considered saw companions.', // UNTRANSLATED
save_error_empty_config: 'Por favor, insira a configuração',
send: 'Enviar',
send_error_invalid_format: 'Entrada inválida',

View file

@ -1,6 +1,9 @@
const connector_details = {
back_to_connectors: 'Connectorlara dön',
check_readme: 'READMEye göz at',
settings: 'Settings', // UNTRANSLATED
settings_description:
'It real sent your at. Amounted all shy set why followed declared. Repeated of endeavor mr position kindness offering ignorant so up. Simplicity are melancholy preference considered saw companions.', // UNTRANSLATED
save_error_empty_config: 'Lütfen yapılandırmayı girin',
send: 'Gönder',
send_error_invalid_format: 'Geçersiz input',

View file

@ -1,6 +1,9 @@
const connector_details = {
back_to_connectors: '返回连接器',
check_readme: '查看 README',
settings: '设置',
settings_description:
'It real sent your at. Amounted all shy set why followed declared. Repeated of endeavor mr position kindness offering ignorant so up. Simplicity are melancholy preference considered saw companions.', // UNTRANSLATED
save_error_empty_config: '请输入配置内容',
send: '发送',
send_error_invalid_format: '无效输入',