mirror of
https://github.com/logto-io/logto.git
synced 2025-01-06 20:40:08 -05:00
fix(console): add json validator to connector config (#2774)
This commit is contained in:
parent
09b1fa370f
commit
2a723f01a3
4 changed files with 76 additions and 45 deletions
|
@ -57,3 +57,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.errorMessage {
|
||||
font: var(--font-body-medium);
|
||||
color: var(--color-error);
|
||||
margin-top: _.unit(1);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ type Props = {
|
|||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
tabSize?: number;
|
||||
hasError?: boolean;
|
||||
errorMessage?: string;
|
||||
};
|
||||
|
||||
const CodeEditor = ({
|
||||
|
@ -23,6 +25,8 @@ const CodeEditor = ({
|
|||
value = '',
|
||||
onChange,
|
||||
tabSize = 2,
|
||||
hasError,
|
||||
errorMessage,
|
||||
}: Props) => {
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
|
@ -49,49 +53,52 @@ const CodeEditor = ({
|
|||
};
|
||||
|
||||
return (
|
||||
<div className={classNames(styles.container, className)}>
|
||||
<CopyToClipboard value={value} variant="icon" className={styles.copy} />
|
||||
<div className={styles.editor}>
|
||||
{/* SyntaxHighlighter is a readonly component, so a transparent <textarea> layer is needed
|
||||
in order to support user interactions, such as code editing, copy-pasting, etc. */}
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
data-gramm="false"
|
||||
readOnly={isReadonly}
|
||||
spellCheck="false"
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeydown}
|
||||
/>
|
||||
{/* SyntaxHighlighter will generate a <pre> tag and a inner <code> tag. Both have
|
||||
inline-styles by default. Therefore, We can only use inline styles to customize them.
|
||||
Some styles have to be applied multiple times to each of them for the sake of consistency. */}
|
||||
<SyntaxHighlighter
|
||||
wrapLongLines
|
||||
codeTagProps={{
|
||||
style: {
|
||||
fontFamily: "'Roboto Mono', monospace", // Override default font-family of <code>
|
||||
},
|
||||
}}
|
||||
customStyle={{
|
||||
background: 'transparent',
|
||||
fontSize: '14px',
|
||||
margin: '0',
|
||||
padding: '0',
|
||||
borderRadius: '0',
|
||||
wordBreak: 'break-all',
|
||||
fontFamily: "'Roboto Mono', monospace", // Override default font-family of <pre>
|
||||
}}
|
||||
language={language}
|
||||
style={theme}
|
||||
>
|
||||
{value}
|
||||
</SyntaxHighlighter>
|
||||
<>
|
||||
<div className={classNames(styles.container, className)}>
|
||||
<CopyToClipboard value={value} variant="icon" className={styles.copy} />
|
||||
<div className={styles.editor}>
|
||||
{/* SyntaxHighlighter is a readonly component, so a transparent <textarea> layer is needed
|
||||
in order to support user interactions, such as code editing, copy-pasting, etc. */}
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
autoCapitalize="off"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
data-gramm="false"
|
||||
readOnly={isReadonly}
|
||||
spellCheck="false"
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeydown}
|
||||
/>
|
||||
{/* SyntaxHighlighter will generate a <pre> tag and a inner <code> tag. Both have
|
||||
inline-styles by default. Therefore, We can only use inline styles to customize them.
|
||||
Some styles have to be applied multiple times to each of them for the sake of consistency. */}
|
||||
<SyntaxHighlighter
|
||||
wrapLongLines
|
||||
codeTagProps={{
|
||||
style: {
|
||||
fontFamily: "'Roboto Mono', monospace", // Override default font-family of <code>
|
||||
},
|
||||
}}
|
||||
customStyle={{
|
||||
background: 'transparent',
|
||||
fontSize: '14px',
|
||||
margin: '0',
|
||||
padding: '0',
|
||||
borderRadius: '0',
|
||||
wordBreak: 'break-all',
|
||||
fontFamily: "'Roboto Mono', monospace", // Override default font-family of <pre>
|
||||
}}
|
||||
language={language}
|
||||
style={theme}
|
||||
>
|
||||
{value}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{hasError && errorMessage && <div className={styles.errorMessage}>{errorMessage}</div>}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import FormField from '@/components/FormField';
|
|||
import Select from '@/components/Select';
|
||||
import TextInput from '@/components/TextInput';
|
||||
import TextLink from '@/components/TextLink';
|
||||
import { uriValidator } from '@/utilities/validator';
|
||||
import { uriValidator, jsonValidator } from '@/utilities/validator';
|
||||
|
||||
import type { ConnectorFormType } from '../../types';
|
||||
import { SyncProfileMode } from '../../types';
|
||||
|
@ -127,9 +127,17 @@ const ConnectorForm = ({ connector, isAllowEditTarget }: Props) => {
|
|||
name="config"
|
||||
control={control}
|
||||
defaultValue={configTemplate}
|
||||
rules={{ required: true }}
|
||||
rules={{
|
||||
validate: (value) => jsonValidator(value) || t('errors.invalid_json_format'),
|
||||
}}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<CodeEditor language="json" value={value} onChange={onChange} />
|
||||
<CodeEditor
|
||||
hasError={Boolean(errors.config)}
|
||||
errorMessage={errors.config?.message}
|
||||
language="json"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</FormField>
|
||||
|
|
|
@ -16,3 +16,13 @@ export const uriOriginValidator = (value: string) => {
|
|||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const jsonValidator = (value: string) => {
|
||||
try {
|
||||
JSON.parse(value);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue