fix(client): fix variable component read pretty mode (#1673)

This commit is contained in:
Junyi 2023-04-08 13:40:18 +07:00 committed by GitHub
parent 13b74bde3f
commit 93348c9ce6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 113 additions and 71 deletions

View File

@ -13,7 +13,7 @@ function useOptions({ filter }: CollectionSelectProps) {
const compile = useCompile(); const compile = useCompile();
const { collections = [] } = useCollectionManager(); const { collections = [] } = useCollectionManager();
const filtered = typeof filter === 'function' ? collections.filter(filter) : collections; const filtered = typeof filter === 'function' ? collections.filter(filter) : collections;
return filtered.map(item => ({ return filtered.filter(item => !item.hidden).map(item => ({
label: compile(item.title), label: compile(item.title),
value: item.name, value: item.name,
color: item.category?.color, color: item.category?.color,

View File

@ -1,11 +1,12 @@
import React, { useState, useEffect, useRef, useMemo } from 'react'; import React, { useState, useEffect, useRef, useMemo } from 'react';
import { Input, Cascader, Button } from 'antd'; import { Input, Cascader, Button, Tag } from 'antd';
import { useForm } from '@formily/react'; import { useForm } from '@formily/react';
import { cx, css } from '@emotion/css'; import { cx, css } from '@emotion/css';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import * as sanitizeHTML from 'sanitize-html'; import * as sanitizeHTML from 'sanitize-html';
import { useCompile } from '../..'; import { EllipsisWithTooltip, useCompile } from '../..';
import { useRecord } from '../../../record-provider';
type RangeIndexes = [number, number, number, number]; type RangeIndexes = [number, number, number, number];
@ -380,61 +381,97 @@ export function TextArea(props) {
contentEditable={!disabled} contentEditable={!disabled}
dangerouslySetInnerHTML={{ __html: html }} dangerouslySetInnerHTML={{ __html: html }}
/> />
<Button className={cx('x-button', css` {!disabled
position: relative; ? (
`)}> <Button className={cx('x-button', css`
<span position: relative;
className={css` `)}>
font-style: italic; <span
font-family: "New York", "Times New Roman", Times, serif; className={css`
`} font-style: italic;
>x</span> font-family: "New York", "Times New Roman", Times, serif;
<Cascader `}
placeholder={t('Select a variable')} >x</span>
value={[]} <Cascader
options={options} placeholder={t('Select a variable')}
onChange={(keyPaths = [], selectedOptions = []) => { value={[]}
setSelectedVar(keyPaths as string[]); options={options}
if (!keyPaths.length) { onChange={(keyPaths = [], selectedOptions = []) => {
return; setSelectedVar(keyPaths as string[]);
} if (!keyPaths.length) {
const option = selectedOptions[selectedOptions.length - 1]; return;
if (!option?.children?.length) { }
onInsert(keyPaths); const option = selectedOptions[selectedOptions.length - 1];
} if (!option?.children?.length) {
}} onInsert(keyPaths);
changeOnSelect }
onClick={(e: any) => { }}
if (e.detail !== 2) { changeOnSelect
return; onClick={(e: any) => {
} if (e.detail !== 2) {
for (let n = e.target; n && n !== e.currentTarget; n = n.parentNode) { return;
if (Array.from(n.classList ?? []).includes('ant-cascader-menu-item')) { }
onInsert(selectedVar); for (let n = e.target; n && n !== e.currentTarget; n = n.parentNode) {
} if (Array.from(n.classList ?? []).includes('ant-cascader-menu-item')) {
} onInsert(selectedVar);
}} }
dropdownClassName={css` }
.ant-cascader-menu{ }}
margin-bottom: 0; dropdownClassName={css`
} .ant-cascader-menu{
`} margin-bottom: 0;
dropdownRender={(menu) => ( }
<> `}
{menu} dropdownRender={(menu) => (
<div <>
className={css` {menu}
padding: .5em; <div
border-top: 1px solid rgba(0, 0, 0, .06); className={css`
color: rgba(0, 0, 0, .45); padding: .5em;
`} border-top: 1px solid rgba(0, 0, 0, .06);
> color: rgba(0, 0, 0, .45);
{t('Double click to choose entire object')} `}
</div> >
</> {t('Double click to choose entire object')}
)} </div>
/> </>
</Button> )}
/>
</Button>
)
: null
}
</Input.Group> </Input.Group>
); );
} }
TextArea.ReadPretty = (props) => {
const { value, multiline = true, scope } = props;
const compile = useCompile();
const options = compile((typeof scope === 'function' ? scope() : scope) ?? []);
const keyLabelMap = useMemo(() => createOptionsValueLabelMap(options), [scope]);
const html = renderHTML(value ?? '', keyLabelMap);
const content = (
<span
dangerouslySetInnerHTML={{ __html: html }}
className={css`
overflow: auto;
.ant-tag {
display: inline;
line-height: 19px;
margin: 0 .25em;
padding: 2px 7px;
border-radius: 10px;
}
`}
/>
);
return (
<EllipsisWithTooltip ellipsis popoverContent={content}>
{content}
</EllipsisWithTooltip>
);
}

View File

@ -1,4 +1,4 @@
import { connect } from '@formily/react'; import { connect, mapReadPretty } from '@formily/react';
import { Input } from "./Input"; import { Input } from "./Input";
import { TextArea } from "./TextArea"; import { TextArea } from "./TextArea";
@ -12,7 +12,7 @@ export function Variable() {
Variable.Input = connect(Input); Variable.Input = connect(Input);
Variable.TextArea = connect(TextArea); Variable.TextArea = connect(TextArea, mapReadPretty(TextArea.ReadPretty));
Variable.JSON = connect(JSONInput); Variable.JSON = connect(JSONInput);

View File

@ -1,10 +1,10 @@
import React, { useState } from "react"; import React, { useState, useMemo } from "react";
import { onFieldInputValueChange } from '@formily/core'; import { onFieldInputValueChange, onFormInitialValuesChange } from '@formily/core';
import { observer, connect, mapReadPretty, useFormEffects } from '@formily/react'; import { useForm, observer, connect, mapReadPretty, useFormEffects } from '@formily/react';
import { Tag } from 'antd'; import { Tag } from 'antd';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Variable } from "@nocobase/client"; import { useRecord, Variable } from "@nocobase/client";
import { NAMESPACE } from "../locale"; import { NAMESPACE } from "../locale";
import { useCollectionFieldOptions } from "../variable"; import { useCollectionFieldOptions } from "../variable";
@ -12,10 +12,14 @@ import { useCollectionFieldOptions } from "../variable";
const InternalExpression = observer((props: any) => { const InternalExpression = observer((props: any) => {
const { value, onChange } = props; const { onChange } = props;
const [collection, setCollection] = useState(null); const { values } = useForm();
const [collection, setCollection] = useState(values?.sourceCollection);
useFormEffects(() => { useFormEffects(() => {
onFormInitialValuesChange(form => {
setCollection(form.values.sourceCollection);
});
onFieldInputValueChange('sourceCollection', (f) => { onFieldInputValueChange('sourceCollection', (f) => {
setCollection(f.value); setCollection(f.value);
onChange(null); onChange(null);
@ -26,17 +30,18 @@ const InternalExpression = observer((props: any) => {
return ( return (
<Variable.TextArea <Variable.TextArea
value={value} {...props}
onChange={onChange}
scope={options} scope={options}
/> />
); );
}); });
function Result({ value }) { function Result(props) {
const { t } = useTranslation(); const { t } = useTranslation();
return value const values = useRecord();
? <Tag color="purple">{t('Expression')}</Tag> const options = useMemo(() => useCollectionFieldOptions({ collection: values.sourceCollection }), [values.sourceCollection, values.sourceCollection]);
return props.value
? <Variable.TextArea {...props} scope={options} />
: <Tag>{t('Unconfigured', { ns: NAMESPACE })}</Tag>; : <Tag>{t('Unconfigured', { ns: NAMESPACE })}</Tag>;
} }