fix(client): fix variable component read pretty mode (#1673)
This commit is contained in:
parent
13b74bde3f
commit
93348c9ce6
@ -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,
|
||||||
|
@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user