mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
feat(console): group connector form items (#3115)
This commit is contained in:
parent
43ecf01ce8
commit
fd1f81cbe9
8 changed files with 106 additions and 72 deletions
|
@ -0,0 +1,9 @@
|
||||||
|
@use '@/scss/underscore' as _;
|
||||||
|
|
||||||
|
.configForm {
|
||||||
|
margin-top: _.unit(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.senderTest {
|
||||||
|
margin-top: _.unit(6);
|
||||||
|
}
|
|
@ -10,13 +10,14 @@ import FormCard from '@/components/FormCard';
|
||||||
import UnsavedChangesAlertModal from '@/components/UnsavedChangesAlertModal';
|
import UnsavedChangesAlertModal from '@/components/UnsavedChangesAlertModal';
|
||||||
import useApi from '@/hooks/use-api';
|
import useApi from '@/hooks/use-api';
|
||||||
import useDocumentationUrl from '@/hooks/use-documentation-url';
|
import useDocumentationUrl from '@/hooks/use-documentation-url';
|
||||||
import ConnectorForm from '@/pages/Connectors/components/ConnectorForm';
|
import BasicForm from '@/pages/Connectors/components/ConnectorForm/BasicForm';
|
||||||
|
import ConfigForm from '@/pages/Connectors/components/ConnectorForm/ConfigForm';
|
||||||
import { useConfigParser } from '@/pages/Connectors/components/ConnectorForm/hooks';
|
import { useConfigParser } from '@/pages/Connectors/components/ConnectorForm/hooks';
|
||||||
import { initFormData, parseFormConfig } from '@/pages/Connectors/components/ConnectorForm/utils';
|
import { initFormData, parseFormConfig } from '@/pages/Connectors/components/ConnectorForm/utils';
|
||||||
import type { ConnectorFormType } from '@/pages/Connectors/types';
|
import type { ConnectorFormType } from '@/pages/Connectors/types';
|
||||||
import { SyncProfileMode } from '@/pages/Connectors/types';
|
import { SyncProfileMode } from '@/pages/Connectors/types';
|
||||||
|
|
||||||
import * as styles from '../index.module.scss';
|
import * as styles from './ConnectorContent.module.scss';
|
||||||
import SenderTester from './SenderTester';
|
import SenderTester from './SenderTester';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -99,12 +100,12 @@ const ConnectorContent = ({ isDeleted, connectorData, onConnectorUpdated }: Prop
|
||||||
description="connector_details.settings_description"
|
description="connector_details.settings_description"
|
||||||
learnMoreLink={getDocumentationUrl('/docs/references/connectors')}
|
learnMoreLink={getDocumentationUrl('/docs/references/connectors')}
|
||||||
>
|
>
|
||||||
<ConnectorForm
|
<BasicForm
|
||||||
connectorType={connectorData.type}
|
connectorType={connectorData.type}
|
||||||
isStandard={connectorData.isStandard}
|
isStandard={connectorData.isStandard}
|
||||||
isDarkDefaultVisible={Boolean(connectorData.metadata.logoDark)}
|
isDarkDefaultVisible={Boolean(connectorData.metadata.logoDark)}
|
||||||
formItems={connectorData.formItems}
|
|
||||||
/>
|
/>
|
||||||
|
<ConfigForm className={styles.configForm} formItems={connectorData.formItems} />
|
||||||
{connectorData.type !== ConnectorType.Social && (
|
{connectorData.type !== ConnectorType.Social && (
|
||||||
<SenderTester
|
<SenderTester
|
||||||
className={styles.senderTest}
|
className={styles.senderTest}
|
||||||
|
|
|
@ -89,10 +89,6 @@
|
||||||
margin-bottom: _.unit(6);
|
margin-bottom: _.unit(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.senderTest {
|
|
||||||
margin-top: _.unit(6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.resetIcon {
|
.resetIcon {
|
||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import type { ConnectorConfigFormItem } from '@logto/connector-kit';
|
import { ConnectorType } from '@logto/connector-kit';
|
||||||
import type { ConnectorFactoryResponse } from '@logto/schemas';
|
|
||||||
import { ConnectorType } from '@logto/schemas';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Controller, useFormContext } from 'react-hook-form';
|
import { Controller, useFormContext } from 'react-hook-form';
|
||||||
import { Trans, useTranslation } from 'react-i18next';
|
import { Trans, useTranslation } from 'react-i18next';
|
||||||
|
@ -8,35 +6,29 @@ import { Trans, useTranslation } from 'react-i18next';
|
||||||
import CaretDown from '@/assets/images/caret-down.svg';
|
import CaretDown from '@/assets/images/caret-down.svg';
|
||||||
import CaretUp from '@/assets/images/caret-up.svg';
|
import CaretUp from '@/assets/images/caret-up.svg';
|
||||||
import Button from '@/components/Button';
|
import Button from '@/components/Button';
|
||||||
import CodeEditor from '@/components/CodeEditor';
|
|
||||||
import FormField from '@/components/FormField';
|
import FormField from '@/components/FormField';
|
||||||
import Select from '@/components/Select';
|
import Select from '@/components/Select';
|
||||||
import TextInput from '@/components/TextInput';
|
import TextInput from '@/components/TextInput';
|
||||||
import TextLink from '@/components/TextLink';
|
import TextLink from '@/components/TextLink';
|
||||||
import useDocumentationUrl from '@/hooks/use-documentation-url';
|
import useDocumentationUrl from '@/hooks/use-documentation-url';
|
||||||
import { uriValidator, jsonValidator } from '@/utils/validator';
|
import { uriValidator } from '@/utils/validator';
|
||||||
|
|
||||||
import type { ConnectorFormType } from '../../types';
|
import type { ConnectorFormType } from '../../types';
|
||||||
import { SyncProfileMode } from '../../types';
|
import { SyncProfileMode } from '../../types';
|
||||||
import ConfigForm from '../ConfigForm';
|
import * as styles from './BasicForm.module.scss';
|
||||||
import * as styles from './index.module.scss';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
connectorType: ConnectorType;
|
|
||||||
isStandard: ConnectorFactoryResponse['isStandard'];
|
|
||||||
configTemplate?: ConnectorFactoryResponse['configTemplate'];
|
|
||||||
isAllowEditTarget?: boolean;
|
isAllowEditTarget?: boolean;
|
||||||
isDarkDefaultVisible?: boolean;
|
isDarkDefaultVisible?: boolean;
|
||||||
formItems?: ConnectorConfigFormItem[];
|
isStandard?: boolean;
|
||||||
|
connectorType: ConnectorType;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ConnectorForm = ({
|
const BasicForm = ({
|
||||||
configTemplate,
|
|
||||||
isStandard,
|
|
||||||
isAllowEditTarget,
|
isAllowEditTarget,
|
||||||
isDarkDefaultVisible,
|
isDarkDefaultVisible,
|
||||||
connectorType,
|
connectorType,
|
||||||
formItems,
|
isStandard,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||||
const { getDocumentationUrl } = useDocumentationUrl();
|
const { getDocumentationUrl } = useDocumentationUrl();
|
||||||
|
@ -136,29 +128,6 @@ const ConnectorForm = ({
|
||||||
</FormField>
|
</FormField>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{formItems ? (
|
|
||||||
<ConfigForm formItems={formItems} />
|
|
||||||
) : (
|
|
||||||
<FormField title="connectors.guide.config">
|
|
||||||
<Controller
|
|
||||||
name="config"
|
|
||||||
control={control}
|
|
||||||
defaultValue={configTemplate}
|
|
||||||
rules={{
|
|
||||||
validate: (value) => jsonValidator(value) || t('errors.invalid_json_format'),
|
|
||||||
}}
|
|
||||||
render={({ field: { onChange, value } }) => (
|
|
||||||
<CodeEditor
|
|
||||||
hasError={Boolean(errors.config)}
|
|
||||||
errorMessage={errors.config?.message}
|
|
||||||
language="json"
|
|
||||||
value={value}
|
|
||||||
onChange={onChange}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</FormField>
|
|
||||||
)}
|
|
||||||
{connectorType === ConnectorType.Social && (
|
{connectorType === ConnectorType.Social && (
|
||||||
<FormField title="connectors.guide.sync_profile">
|
<FormField title="connectors.guide.sync_profile">
|
||||||
<Controller
|
<Controller
|
||||||
|
@ -176,4 +145,4 @@ const ConnectorForm = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ConnectorForm;
|
export default BasicForm;
|
|
@ -0,0 +1,55 @@
|
||||||
|
import type { ConnectorConfigFormItem } from '@logto/connector-kit';
|
||||||
|
import type { ConnectorFactoryResponse } from '@logto/schemas';
|
||||||
|
import { Controller, useFormContext } from 'react-hook-form';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import CodeEditor from '@/components/CodeEditor';
|
||||||
|
import FormField from '@/components/FormField';
|
||||||
|
import { jsonValidator } from '@/utils/validator';
|
||||||
|
|
||||||
|
import type { ConnectorFormType } from '../../types';
|
||||||
|
import ConfigFormItems from '../ConfigForm';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
configTemplate?: ConnectorFactoryResponse['configTemplate'];
|
||||||
|
formItems?: ConnectorConfigFormItem[];
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ConfigForm = ({ configTemplate, formItems, className }: Props) => {
|
||||||
|
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
formState: { errors },
|
||||||
|
} = useFormContext<ConnectorFormType>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
{formItems ? (
|
||||||
|
<ConfigFormItems formItems={formItems} />
|
||||||
|
) : (
|
||||||
|
<FormField title="connectors.guide.config">
|
||||||
|
<Controller
|
||||||
|
name="config"
|
||||||
|
control={control}
|
||||||
|
defaultValue={configTemplate}
|
||||||
|
rules={{
|
||||||
|
validate: (value) => jsonValidator(value) || t('errors.invalid_json_format'),
|
||||||
|
}}
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<CodeEditor
|
||||||
|
hasError={Boolean(errors.config)}
|
||||||
|
errorMessage={errors.config?.message}
|
||||||
|
language="json"
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormField>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ConfigForm;
|
|
@ -46,14 +46,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.setup {
|
.setup {
|
||||||
background-color: var(--color-layer-1);
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 0 _.unit(6) _.unit(6);
|
|
||||||
margin: _.unit(6) _.unit(18) _.unit(6) _.unit(3);
|
margin: _.unit(6) _.unit(18) _.unit(6) _.unit(3);
|
||||||
|
|
||||||
.title {
|
.block {
|
||||||
font: var(--font-title-1);
|
background-color: var(--color-layer-1);
|
||||||
margin: _.unit(6) 0;
|
border-radius: 16px;
|
||||||
|
padding: _.unit(6);
|
||||||
|
margin-bottom: _.unit(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
|
@ -68,7 +67,3 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tester {
|
|
||||||
margin-top: _.unit(6);
|
|
||||||
}
|
|
||||||
|
|
|
@ -21,7 +21,8 @@ import SenderTester from '@/pages/ConnectorDetails/components/SenderTester';
|
||||||
|
|
||||||
import type { ConnectorFormType } from '../../types';
|
import type { ConnectorFormType } from '../../types';
|
||||||
import { SyncProfileMode } from '../../types';
|
import { SyncProfileMode } from '../../types';
|
||||||
import ConnectorForm from '../ConnectorForm';
|
import BasicForm from '../ConnectorForm/BasicForm';
|
||||||
|
import ConfigForm from '../ConnectorForm/ConfigForm';
|
||||||
import { useConfigParser } from '../ConnectorForm/hooks';
|
import { useConfigParser } from '../ConnectorForm/hooks';
|
||||||
import { initFormData, parseFormConfig } from '../ConnectorForm/utils';
|
import { initFormData, parseFormConfig } from '../ConnectorForm/utils';
|
||||||
import * as styles from './index.module.scss';
|
import * as styles from './index.module.scss';
|
||||||
|
@ -117,23 +118,31 @@ const Guide = ({ connector, onClose }: Props) => {
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<Markdown className={styles.readme}>{readme}</Markdown>
|
<Markdown className={styles.readme}>{readme}</Markdown>
|
||||||
<div className={styles.setup}>
|
<div className={styles.setup}>
|
||||||
<div className={styles.title}>{t('connectors.guide.connector_setting')}</div>
|
|
||||||
<FormProvider {...methods}>
|
<FormProvider {...methods}>
|
||||||
<form onSubmit={onSubmit}>
|
<form onSubmit={onSubmit}>
|
||||||
<ConnectorForm
|
{isSocialConnector && (
|
||||||
isAllowEditTarget
|
<div className={styles.block}>
|
||||||
connectorType={connector.type}
|
<BasicForm
|
||||||
configTemplate={connector.configTemplate}
|
isAllowEditTarget
|
||||||
isStandard={connector.isStandard}
|
connectorType={connector.type}
|
||||||
formItems={connector.formItems}
|
isStandard={connector.isStandard}
|
||||||
/>
|
/>
|
||||||
{!isSocialConnector && (
|
</div>
|
||||||
<SenderTester
|
)}
|
||||||
className={styles.tester}
|
<div className={styles.block}>
|
||||||
connectorId={connectorId}
|
<ConfigForm
|
||||||
connectorType={connectorType}
|
configTemplate={connector.configTemplate}
|
||||||
config={watch('config')}
|
formItems={connector.formItems}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
{!isSocialConnector && (
|
||||||
|
<div className={styles.block}>
|
||||||
|
<SenderTester
|
||||||
|
connectorId={connectorId}
|
||||||
|
connectorType={connectorType}
|
||||||
|
config={watch('config')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={styles.footer}>
|
<div className={styles.footer}>
|
||||||
<Button
|
<Button
|
||||||
|
|
Loading…
Reference in a new issue