mirror of
https://github.com/logto-io/logto.git
synced 2025-01-20 21:32:31 -05:00
refactor(console): combine steps in connector guide
This commit is contained in:
parent
f53aceff6f
commit
2312df059b
12 changed files with 236 additions and 182 deletions
|
@ -47,5 +47,10 @@
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textarea,
|
||||||
|
pre {
|
||||||
|
min-height: 20px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,60 @@
|
||||||
|
@use '@/scss/underscore' as _;
|
||||||
|
|
||||||
.markdown {
|
.markdown {
|
||||||
font: var(--font-body-medium);
|
li {
|
||||||
|
font: var(--font-body-medium);
|
||||||
|
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
padding-inline-start: 1ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding-inline-start: 4ch;
|
||||||
|
|
||||||
|
> li {
|
||||||
|
margin-block-start: _.unit(2);
|
||||||
|
margin-block-end: _.unit(2);
|
||||||
|
padding-inline-start: _.unit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
padding-inline-start: 2ch;
|
||||||
|
|
||||||
|
> li {
|
||||||
|
margin-block-start: _.unit(3);
|
||||||
|
margin-block-end: _.unit(3);
|
||||||
|
padding-inline-start: _.unit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font: var(--font-body-medium);
|
||||||
|
color: var(--color-text-link);
|
||||||
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font: var(--font-title-large);
|
font: var(--font-title-large);
|
||||||
|
margin: _.unit(6) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font: var(--font-title-medium);
|
font: var(--font-title-medium);
|
||||||
}
|
color: var(--color-caption);
|
||||||
|
margin: _.unit(6) 0 _.unit(3);
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5 {
|
|
||||||
font: var(--font-title-small);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
font: var(--font-body-medium);
|
font: var(--font-body-medium);
|
||||||
|
margin: _.unit(3) 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inlineCode {
|
||||||
|
background: var(--color-layer-2);
|
||||||
|
font: var(--font-body-medium);
|
||||||
|
padding: _.unit(1) _.unit(1);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
|
@ -1,15 +1,34 @@
|
||||||
|
import classNames from 'classnames';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import remarkGfm from 'remark-gfm';
|
import remarkGfm from 'remark-gfm';
|
||||||
|
|
||||||
|
import CodeEditor from '../CodeEditor';
|
||||||
import * as styles from './index.module.scss';
|
import * as styles from './index.module.scss';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
className?: string;
|
||||||
children: string;
|
children: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Markdown = ({ children }: Props) => (
|
const Markdown = ({ className, children }: Props) => (
|
||||||
<ReactMarkdown remarkPlugins={[remarkGfm]} className={styles.markdown}>
|
<ReactMarkdown
|
||||||
|
remarkPlugins={[remarkGfm]}
|
||||||
|
className={classNames(styles.markdown, className)}
|
||||||
|
components={{
|
||||||
|
code: ({ node, inline, className, children, ...props }) => {
|
||||||
|
const [, codeBlockType] = /language-(\w+)/.exec(className ?? '') ?? [];
|
||||||
|
|
||||||
|
return inline ? (
|
||||||
|
<code className={styles.inlineCode} {...props}>
|
||||||
|
{children}
|
||||||
|
</code>
|
||||||
|
) : (
|
||||||
|
<CodeEditor isReadonly language={codeBlockType} value={String(children)} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
);
|
);
|
||||||
|
|
|
@ -19,6 +19,8 @@ type Props = PropsWithChildren<{
|
||||||
index: number;
|
index: number;
|
||||||
activeIndex: number;
|
activeIndex: number;
|
||||||
buttonText?: I18nKey;
|
buttonText?: I18nKey;
|
||||||
|
buttonHtmlType?: 'submit' | 'button';
|
||||||
|
isLoading?: boolean;
|
||||||
onButtonClick?: () => void;
|
onButtonClick?: () => void;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
@ -29,6 +31,8 @@ const Step = ({
|
||||||
index,
|
index,
|
||||||
activeIndex,
|
activeIndex,
|
||||||
buttonText = 'general.next',
|
buttonText = 'general.next',
|
||||||
|
buttonHtmlType = 'button',
|
||||||
|
isLoading,
|
||||||
onButtonClick,
|
onButtonClick,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [isExpanded, setIsExpanded] = useState(false);
|
const [isExpanded, setIsExpanded] = useState(false);
|
||||||
|
@ -73,7 +77,14 @@ const Step = ({
|
||||||
<div className={classNames(styles.content, isExpanded && styles.expanded)}>
|
<div className={classNames(styles.content, isExpanded && styles.expanded)}>
|
||||||
{children}
|
{children}
|
||||||
<div className={styles.buttonWrapper}>
|
<div className={styles.buttonWrapper}>
|
||||||
<Button type="outline" size="large" title={buttonText} onClick={onButtonClick} />
|
<Button
|
||||||
|
type="outline"
|
||||||
|
size="large"
|
||||||
|
isLoading={isLoading}
|
||||||
|
htmlType={buttonHtmlType}
|
||||||
|
title={buttonText}
|
||||||
|
onClick={onButtonClick}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
@ -157,7 +157,7 @@ const ConnectorDetails = () => {
|
||||||
setIsReadMeOpen(false);
|
setIsReadMeOpen(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Markdown>{data.readme}</Markdown>
|
<Markdown className={styles.readme}>{data.readme}</Markdown>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
<ActionMenu
|
<ActionMenu
|
||||||
buttonProps={{ icon: <More className={styles.moreIcon} />, size: 'large' }}
|
buttonProps={{ icon: <More className={styles.moreIcon} />, size: 'large' }}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import UnnamedTrans from '@/components/UnnamedTrans';
|
||||||
import useConnectorGroups from '@/hooks/use-connector-groups';
|
import useConnectorGroups from '@/hooks/use-connector-groups';
|
||||||
import * as modalStyles from '@/scss/modal.module.scss';
|
import * as modalStyles from '@/scss/modal.module.scss';
|
||||||
|
|
||||||
import GuideModal from '../GuideModal';
|
import Guide from '../Guide';
|
||||||
import PlatformSelector from './PlatformSelector';
|
import PlatformSelector from './PlatformSelector';
|
||||||
import * as styles from './index.module.scss';
|
import * as styles from './index.module.scss';
|
||||||
|
|
||||||
|
@ -132,11 +132,9 @@ const CreateForm = ({ onClose, isOpen: isFormOpen, type }: Props) => {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{activeConnector && (
|
{activeConnector && (
|
||||||
<GuideModal
|
<Modal isOpen={isGetStartedModalOpen} className={modalStyles.fullScreen}>
|
||||||
connector={activeConnector}
|
<Guide connector={activeConnector} onClose={closeModal} />
|
||||||
isOpen={isGetStartedModalOpen}
|
</Modal>
|
||||||
onClose={closeModal}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</ModalLayout>
|
</ModalLayout>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background-color: var(--color-surface-1);
|
background-color: var(--color-base);
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
|
@ -37,15 +37,13 @@
|
||||||
> * {
|
> * {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin: 0 12px;
|
margin: 0 12px;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.readme {
|
.readme {
|
||||||
background-color: var(--color-surface-variant);
|
background-color: var(--color-layer-1);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
padding: _.unit(6);
|
padding: 0 _.unit(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
form + div {
|
form + div {
|
||||||
|
@ -53,3 +51,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.editor,
|
||||||
|
.tester {
|
||||||
|
margin-top: _.unit(6);
|
||||||
|
}
|
136
packages/console/src/pages/Connectors/components/Guide/index.tsx
Normal file
136
packages/console/src/pages/Connectors/components/Guide/index.tsx
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
import { ConnectorDTO, ConnectorType } from '@logto/schemas';
|
||||||
|
import { conditional } from '@silverhand/essentials';
|
||||||
|
import i18next from 'i18next';
|
||||||
|
import React from 'react';
|
||||||
|
import { Controller, FormProvider, useForm } from 'react-hook-form';
|
||||||
|
import { toast } from 'react-hot-toast';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import CardTitle from '@/components/CardTitle';
|
||||||
|
import CodeEditor from '@/components/CodeEditor';
|
||||||
|
import DangerousRaw from '@/components/DangerousRaw';
|
||||||
|
import IconButton from '@/components/IconButton';
|
||||||
|
import Markdown from '@/components/Markdown';
|
||||||
|
import useApi from '@/hooks/use-api';
|
||||||
|
import useSettings from '@/hooks/use-settings';
|
||||||
|
import Close from '@/icons/Close';
|
||||||
|
import Step from '@/mdx-components/Step';
|
||||||
|
import SenderTester from '@/pages/ConnectorDetails/components/SenderTester';
|
||||||
|
import { GuideForm } from '@/types/guide';
|
||||||
|
|
||||||
|
import * as styles from './index.module.scss';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
connector: ConnectorDTO;
|
||||||
|
onClose: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Guide = ({ connector, onClose }: Props) => {
|
||||||
|
const api = useApi();
|
||||||
|
const { updateSettings } = useSettings();
|
||||||
|
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||||
|
const { id: connectorId, type: connectorType, name, configTemplate, readme } = connector;
|
||||||
|
|
||||||
|
const locale = i18next.language;
|
||||||
|
// TODO: LOG-2393 should fix name[locale] syntax error
|
||||||
|
const foundName = Object.entries(name).find(([lang]) => lang === locale);
|
||||||
|
const connectorName = foundName ? foundName[1] : name.en;
|
||||||
|
const isSocialConnector =
|
||||||
|
connectorType !== ConnectorType.SMS && connectorType !== ConnectorType.Email;
|
||||||
|
const methods = useForm<GuideForm>({ reValidateMode: 'onBlur' });
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
formState: { isSubmitting },
|
||||||
|
handleSubmit,
|
||||||
|
watch,
|
||||||
|
} = methods;
|
||||||
|
|
||||||
|
const onSubmit = handleSubmit(async ({ connectorConfigJson }) => {
|
||||||
|
if (isSubmitting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const config = JSON.parse(connectorConfigJson) as JSON;
|
||||||
|
await api
|
||||||
|
.patch(`/api/connectors/${connectorId}`, {
|
||||||
|
json: { config },
|
||||||
|
})
|
||||||
|
.json<ConnectorDTO>();
|
||||||
|
await api
|
||||||
|
.patch(`/api/connectors/${connectorId}/enabled`, {
|
||||||
|
json: { enabled: true },
|
||||||
|
})
|
||||||
|
.json<ConnectorDTO>();
|
||||||
|
|
||||||
|
await updateSettings({
|
||||||
|
...conditional(!isSocialConnector && { configurePasswordless: true }),
|
||||||
|
...conditional(isSocialConnector && { configureSocialSignIn: true }),
|
||||||
|
});
|
||||||
|
|
||||||
|
onClose();
|
||||||
|
toast.success(t('connector_details.save_success'));
|
||||||
|
} catch (error: unknown) {
|
||||||
|
if (error instanceof SyntaxError) {
|
||||||
|
toast.error(t('connector_details.save_error_json_parse_error'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<div className={styles.header}>
|
||||||
|
<IconButton size="large" onClick={onClose}>
|
||||||
|
<Close className={styles.closeIcon} />
|
||||||
|
</IconButton>
|
||||||
|
<div className={styles.separator} />
|
||||||
|
<CardTitle
|
||||||
|
size="small"
|
||||||
|
title={<DangerousRaw>{connectorName}</DangerousRaw>}
|
||||||
|
subtitle="connectors.guide.subtitle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.content}>
|
||||||
|
<Markdown className={styles.readme}>{readme}</Markdown>
|
||||||
|
<div>
|
||||||
|
<FormProvider {...methods}>
|
||||||
|
<form onSubmit={onSubmit}>
|
||||||
|
<Step
|
||||||
|
title="Enter your json here"
|
||||||
|
subtitle="Lorem ipsum dolor sit amet, consectetuer adipiscing elit."
|
||||||
|
index={0}
|
||||||
|
activeIndex={0}
|
||||||
|
buttonText="admin_console.connectors.save_and_done"
|
||||||
|
buttonHtmlType="submit"
|
||||||
|
isLoading={isSubmitting}
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="connectorConfigJson"
|
||||||
|
control={control}
|
||||||
|
defaultValue={configTemplate}
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<CodeEditor
|
||||||
|
className={styles.editor}
|
||||||
|
language="json"
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{!isSocialConnector && (
|
||||||
|
<SenderTester
|
||||||
|
className={styles.tester}
|
||||||
|
connectorType={connectorType}
|
||||||
|
config={watch('connectorConfigJson')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Step>
|
||||||
|
</form>
|
||||||
|
</FormProvider>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Guide;
|
|
@ -1,160 +0,0 @@
|
||||||
import { ConnectorDTO, ConnectorType } from '@logto/schemas';
|
|
||||||
import { conditional } from '@silverhand/essentials';
|
|
||||||
import i18next from 'i18next';
|
|
||||||
import React, { useState } from 'react';
|
|
||||||
import { Controller, FormProvider, useForm } from 'react-hook-form';
|
|
||||||
import { toast } from 'react-hot-toast';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import ReactMarkdown from 'react-markdown';
|
|
||||||
import Modal from 'react-modal';
|
|
||||||
|
|
||||||
import CardTitle from '@/components/CardTitle';
|
|
||||||
import CodeEditor from '@/components/CodeEditor';
|
|
||||||
import DangerousRaw from '@/components/DangerousRaw';
|
|
||||||
import IconButton from '@/components/IconButton';
|
|
||||||
import useApi from '@/hooks/use-api';
|
|
||||||
import useSettings from '@/hooks/use-settings';
|
|
||||||
import Close from '@/icons/Close';
|
|
||||||
import Step from '@/mdx-components/Step';
|
|
||||||
import SenderTester from '@/pages/ConnectorDetails/components/SenderTester';
|
|
||||||
import * as modalStyles from '@/scss/modal.module.scss';
|
|
||||||
import { GuideForm } from '@/types/guide';
|
|
||||||
|
|
||||||
import * as styles from './index.module.scss';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
connector: ConnectorDTO;
|
|
||||||
isOpen: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
onComplete?: (data: GuideForm) => Promise<void>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const GuideModal = ({ connector, isOpen, onClose }: Props) => {
|
|
||||||
const api = useApi();
|
|
||||||
const { updateSettings } = useSettings();
|
|
||||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
|
||||||
const { id: connectorId, type: connectorType, name, configTemplate, readme } = connector;
|
|
||||||
|
|
||||||
const locale = i18next.language;
|
|
||||||
// TODO: LOG-2393 should fix name[locale] syntax error
|
|
||||||
const foundName = Object.entries(name).find(([lang]) => lang === locale);
|
|
||||||
const connectorName = foundName ? foundName[1] : name.en;
|
|
||||||
const isSocialConnector =
|
|
||||||
connectorType !== ConnectorType.SMS && connectorType !== ConnectorType.Email;
|
|
||||||
const [activeStepIndex, setActiveStepIndex] = useState<number>(0);
|
|
||||||
const steps = isSocialConnector ? 1 : 2;
|
|
||||||
const methods = useForm<GuideForm>({ reValidateMode: 'onBlur' });
|
|
||||||
const {
|
|
||||||
control,
|
|
||||||
formState: { isSubmitting },
|
|
||||||
handleSubmit,
|
|
||||||
} = methods;
|
|
||||||
|
|
||||||
const onSubmit = handleSubmit(async ({ connectorConfigJson }) => {
|
|
||||||
if (isSubmitting) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const config = JSON.parse(connectorConfigJson) as JSON;
|
|
||||||
await api
|
|
||||||
.patch(`/api/connectors/${connectorId}`, {
|
|
||||||
json: { config },
|
|
||||||
})
|
|
||||||
.json<ConnectorDTO>();
|
|
||||||
await api
|
|
||||||
.patch(`/api/connectors/${connectorId}/enabled`, {
|
|
||||||
json: { enabled: true },
|
|
||||||
})
|
|
||||||
.json<ConnectorDTO>();
|
|
||||||
|
|
||||||
await updateSettings({
|
|
||||||
...conditional(!isSocialConnector && { configurePasswordless: true }),
|
|
||||||
...conditional(isSocialConnector && { configureSocialSignIn: true }),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (activeStepIndex === steps - 1) {
|
|
||||||
onClose();
|
|
||||||
} else {
|
|
||||||
setActiveStepIndex(activeStepIndex + 1);
|
|
||||||
}
|
|
||||||
toast.success(t('connector_details.save_success'));
|
|
||||||
} catch (error: unknown) {
|
|
||||||
if (error instanceof SyntaxError) {
|
|
||||||
toast.error(t('connector_details.save_error_json_parse_error'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal isOpen={isOpen} className={modalStyles.fullScreen}>
|
|
||||||
<div className={styles.container}>
|
|
||||||
<div className={styles.header}>
|
|
||||||
<IconButton size="large" onClick={onClose}>
|
|
||||||
<Close className={styles.closeIcon} />
|
|
||||||
</IconButton>
|
|
||||||
<div className={styles.separator} />
|
|
||||||
<CardTitle
|
|
||||||
size="small"
|
|
||||||
title={<DangerousRaw>{connectorName}</DangerousRaw>}
|
|
||||||
subtitle="connectors.guide.subtitle"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={styles.content}>
|
|
||||||
<ReactMarkdown
|
|
||||||
className={styles.readme}
|
|
||||||
components={{
|
|
||||||
code: ({ node, inline, className, children, ...props }) => {
|
|
||||||
const [, codeBlockType] = /language-(\w+)/.exec(className ?? '') ?? [];
|
|
||||||
|
|
||||||
return inline ? (
|
|
||||||
<code {...props}>{children}</code>
|
|
||||||
) : (
|
|
||||||
<CodeEditor isReadonly language={codeBlockType} value={String(children)} />
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{readme}
|
|
||||||
</ReactMarkdown>
|
|
||||||
<div>
|
|
||||||
<FormProvider {...methods}>
|
|
||||||
<form onSubmit={onSubmit}>
|
|
||||||
<Step
|
|
||||||
title="Enter your json here"
|
|
||||||
subtitle="Lorem ipsum dolor sit amet, consectetuer adipiscing elit."
|
|
||||||
index={0}
|
|
||||||
activeIndex={activeStepIndex}
|
|
||||||
buttonText={steps === 1 ? 'general.done' : undefined}
|
|
||||||
>
|
|
||||||
<Controller
|
|
||||||
name="connectorConfigJson"
|
|
||||||
control={control}
|
|
||||||
defaultValue={configTemplate}
|
|
||||||
render={({ field: { onChange, value } }) => (
|
|
||||||
<CodeEditor language="json" value={value} onChange={onChange} />
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Step>
|
|
||||||
</form>
|
|
||||||
</FormProvider>
|
|
||||||
{!isSocialConnector && (
|
|
||||||
<Step
|
|
||||||
title="Test your message"
|
|
||||||
subtitle="Lorem ipsum dolor sit amet, consectetuer adipiscing elit."
|
|
||||||
index={1}
|
|
||||||
activeIndex={activeStepIndex}
|
|
||||||
buttonText="general.done"
|
|
||||||
onButtonClick={onClose}
|
|
||||||
>
|
|
||||||
<SenderTester connectorType={connectorType} />
|
|
||||||
</Step>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default GuideModal;
|
|
|
@ -134,6 +134,7 @@ const Connectors = () => {
|
||||||
type={createType}
|
type={createType}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setCreateType(undefined);
|
setCreateType(undefined);
|
||||||
|
void mutate();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -253,6 +253,7 @@ const translation = {
|
||||||
connector_status_not_in_use: 'Not in use',
|
connector_status_not_in_use: 'Not in use',
|
||||||
social_connector_eg: 'e.g.: Google, Facebook, Twitter',
|
social_connector_eg: 'e.g.: Google, Facebook, Twitter',
|
||||||
next: 'Next',
|
next: 'Next',
|
||||||
|
save_and_done: 'Save and done',
|
||||||
type: {
|
type: {
|
||||||
email: 'Email sender',
|
email: 'Email sender',
|
||||||
sms: 'SMS sender',
|
sms: 'SMS sender',
|
||||||
|
|
|
@ -249,6 +249,7 @@ const translation = {
|
||||||
connector_status_not_in_use: '未使用',
|
connector_status_not_in_use: '未使用',
|
||||||
social_connector_eg: '如: 微信登录,支付宝登录,微博登录',
|
social_connector_eg: '如: 微信登录,支付宝登录,微博登录',
|
||||||
next: '下一步',
|
next: '下一步',
|
||||||
|
save_and_done: '保存并完成',
|
||||||
type: {
|
type: {
|
||||||
email: '邮件服务商',
|
email: '邮件服务商',
|
||||||
sms: '短信服务商',
|
sms: '短信服务商',
|
||||||
|
|
Loading…
Add table
Reference in a new issue