refactor: migrate @emotion/css to antd-style (#1043)
Reviewed-on: daoyoucloud/tachybase#1043
This commit is contained in:
parent
63c351ea1a
commit
f2a2cc228f
@ -1,8 +1,10 @@
|
|||||||
import Icon, { RightOutlined } from '@ant-design/icons';
|
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { uid } from '@tachybase/schema';
|
|
||||||
import { Menu, MenuProps, theme } from 'antd';
|
|
||||||
import React, { FC, ReactNode, useMemo } from 'react';
|
import React, { FC, ReactNode, useMemo } from 'react';
|
||||||
|
import { uid } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import Icon, { RightOutlined } from '@ant-design/icons';
|
||||||
|
import { Menu, MenuProps, theme } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
import { useCompile } from '../../../schema-component';
|
import { useCompile } from '../../../schema-component';
|
||||||
import { useSchemaInitializerItem } from '../context';
|
import { useSchemaInitializerItem } from '../context';
|
||||||
import { useSchemaInitializerMenuItems } from '../hooks';
|
import { useSchemaInitializerMenuItems } from '../hooks';
|
||||||
@ -18,6 +20,30 @@ export interface SchemaInitializerSubMenuProps {
|
|||||||
children?: SchemaInitializerOptions['items'];
|
children?: SchemaInitializerOptions['items'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css, token }) => {
|
||||||
|
return {
|
||||||
|
menu: css`
|
||||||
|
box-shadow: none !important;
|
||||||
|
border-inline-end: 0 !important;
|
||||||
|
.ant-menu-sub {
|
||||||
|
max-height: 50vh !important;
|
||||||
|
}
|
||||||
|
.ant-menu-item {
|
||||||
|
margin-block: 0;
|
||||||
|
}
|
||||||
|
.ant-menu-root {
|
||||||
|
margin: 0 -${token.margin}px;
|
||||||
|
.ant-menu-submenu-title,
|
||||||
|
.ant-menu-item-only-child {
|
||||||
|
margin-inline: 0;
|
||||||
|
margin-block: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const SchemaInitializerSubMenuContext = React.createContext<{ isInMenu?: true }>({});
|
const SchemaInitializerSubMenuContext = React.createContext<{ isInMenu?: true }>({});
|
||||||
const SchemaInitializerMenuProvider = (props) => {
|
const SchemaInitializerMenuProvider = (props) => {
|
||||||
return (
|
return (
|
||||||
@ -34,6 +60,7 @@ export const SchemaInitializerMenu: FC<MenuProps> = (props) => {
|
|||||||
const { componentCls, hashId } = useSchemaInitializerStyles();
|
const { componentCls, hashId } = useSchemaInitializerStyles();
|
||||||
const { items, ...others } = props;
|
const { items, ...others } = props;
|
||||||
const { token } = theme.useToken();
|
const { token } = theme.useToken();
|
||||||
|
const { styles } = useStyles();
|
||||||
const itemsWithPopupClass = useMemo(
|
const itemsWithPopupClass = useMemo(
|
||||||
() => items.map((item) => ({ ...item, popupClassName: `${hashId} ${componentCls}-menu-sub` })),
|
() => items.map((item) => ({ ...item, popupClassName: `${hashId} ${componentCls}-menu-sub` })),
|
||||||
[componentCls, hashId, items],
|
[componentCls, hashId, items],
|
||||||
@ -44,25 +71,7 @@ export const SchemaInitializerMenu: FC<MenuProps> = (props) => {
|
|||||||
<Menu
|
<Menu
|
||||||
selectable={false}
|
selectable={false}
|
||||||
expandIcon={<RightOutlined style={{ fontSize: token.fontSizeSM, color: token.colorTextDescription }} />}
|
expandIcon={<RightOutlined style={{ fontSize: token.fontSizeSM, color: token.colorTextDescription }} />}
|
||||||
rootClassName={css`
|
rootClassName={styles.menu}
|
||||||
box-shadow: none !important;
|
|
||||||
border-inline-end: 0 !important;
|
|
||||||
.ant-menu-sub {
|
|
||||||
max-height: 50vh !important;
|
|
||||||
}
|
|
||||||
.ant-menu-item {
|
|
||||||
margin-block: 0;
|
|
||||||
}
|
|
||||||
.ant-menu-root {
|
|
||||||
margin: 0 -${token.margin}px;
|
|
||||||
.ant-menu-submenu-title,
|
|
||||||
.ant-menu-item-only-child {
|
|
||||||
margin-inline: 0;
|
|
||||||
margin-block: 0;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
items={itemsWithPopupClass}
|
items={itemsWithPopupClass}
|
||||||
{...others}
|
{...others}
|
||||||
/>
|
/>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { ISchema, observer } from '@tachybase/schema';
|
|
||||||
import { ConfigProvider, Popover, theme } from 'antd';
|
|
||||||
import React, { ComponentType, useCallback, useMemo, useState } from 'react';
|
import React, { ComponentType, useCallback, useMemo, useState } from 'react';
|
||||||
|
import { ISchema, observer } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { ConfigProvider, Popover, theme } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { useNiceDropdownMaxHeight } from '../../../common/useNiceDropdownHeight';
|
import { useNiceDropdownMaxHeight } from '../../../common/useNiceDropdownHeight';
|
||||||
import { useFlag } from '../../../flag-provider';
|
import { useFlag } from '../../../flag-provider';
|
||||||
import { useDesignable } from '../../../schema-component';
|
import { useDesignable } from '../../../schema-component';
|
||||||
@ -11,6 +12,18 @@ import { SchemaInitializerContext } from '../context';
|
|||||||
import { SchemaInitializerOptions } from '../types';
|
import { SchemaInitializerOptions } from '../types';
|
||||||
|
|
||||||
const defaultWrap = (s: ISchema) => s;
|
const defaultWrap = (s: ISchema) => s;
|
||||||
|
const useStyles = createStyles(({ css, token }) => {
|
||||||
|
return {
|
||||||
|
popover: css`
|
||||||
|
.ant-popover-inner {
|
||||||
|
padding: ${`${token.paddingXXS}px 0`};
|
||||||
|
.ant-menu-submenu-title {
|
||||||
|
margin-block: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export function withInitializer<T>(C: ComponentType<T>) {
|
export function withInitializer<T>(C: ComponentType<T>) {
|
||||||
const WithInitializer = observer(
|
const WithInitializer = observer(
|
||||||
@ -47,6 +60,7 @@ export function withInitializer<T>(C: ComponentType<T>) {
|
|||||||
const { wrapSSR, hashId, componentCls } = useSchemaInitializerStyles();
|
const { wrapSSR, hashId, componentCls } = useSchemaInitializerStyles();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const { token } = theme.useToken();
|
const { token } = theme.useToken();
|
||||||
|
const { styles } = useStyles();
|
||||||
const dropdownMaxHeight = useNiceDropdownMaxHeight([visible]);
|
const dropdownMaxHeight = useNiceDropdownMaxHeight([visible]);
|
||||||
|
|
||||||
const cProps = useMemo(
|
const cProps = useMemo(
|
||||||
@ -79,14 +93,7 @@ export function withInitializer<T>(C: ComponentType<T>) {
|
|||||||
placement={'bottomLeft'}
|
placement={'bottomLeft'}
|
||||||
{...popoverProps}
|
{...popoverProps}
|
||||||
arrow={false}
|
arrow={false}
|
||||||
overlayClassName={css`
|
overlayClassName={styles.popover}
|
||||||
.ant-popover-inner {
|
|
||||||
padding: ${`${token.paddingXXS}px 0`};
|
|
||||||
.ant-menu-submenu-title {
|
|
||||||
margin-block: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
open={visible}
|
open={visible}
|
||||||
onOpenChange={setVisible}
|
onOpenChange={setVisible}
|
||||||
content={wrapSSR(
|
content={wrapSSR(
|
||||||
|
@ -1,28 +1,31 @@
|
|||||||
import { css } from '@emotion/css';
|
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
||||||
import { Field, GeneralField } from '@tachybase/schema';
|
import { Field, GeneralField, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
import { RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import { Col, Row } from 'antd';
|
import { Col, Row } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import merge from 'deepmerge';
|
import merge from 'deepmerge';
|
||||||
import template from 'lodash/template';
|
import template from 'lodash/template';
|
||||||
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DataBlockProvider,
|
DataBlockProvider,
|
||||||
TableFieldResource,
|
TableFieldResource,
|
||||||
WithoutTableFieldResource,
|
useCollectionManager,
|
||||||
useCollectionParentRecord,
|
useCollectionParentRecord,
|
||||||
|
useCollectionParentRecordData,
|
||||||
useCollectionRecord,
|
useCollectionRecord,
|
||||||
useDataBlockProps,
|
useDataBlockProps,
|
||||||
useDataBlockRequest,
|
useDataBlockRequest,
|
||||||
useDataBlockResource,
|
useDataBlockResource,
|
||||||
useDesignable,
|
useDesignable,
|
||||||
useRecord,
|
useRecord,
|
||||||
|
WithoutTableFieldResource,
|
||||||
} from '../';
|
} from '../';
|
||||||
import { ACLCollectionProvider } from '../acl/ACLProvider';
|
import { ACLCollectionProvider } from '../acl/ACLProvider';
|
||||||
import {
|
import {
|
||||||
CollectionProvider_deprecated,
|
CollectionProvider_deprecated,
|
||||||
useCollectionManager_deprecated,
|
|
||||||
useCollection_deprecated,
|
useCollection_deprecated,
|
||||||
|
useCollectionManager_deprecated,
|
||||||
} from '../collection-manager';
|
} from '../collection-manager';
|
||||||
import { DataBlockCollector } from '../filter-provider/FilterProvider';
|
import { DataBlockCollector } from '../filter-provider/FilterProvider';
|
||||||
import { RecordProvider, useRecordIndex } from '../record-provider';
|
import { RecordProvider, useRecordIndex } from '../record-provider';
|
||||||
@ -119,9 +122,31 @@ export const useBlockRequestContext = () => {
|
|||||||
return useContext(BlockRequestContext_deprecated);
|
return useContext(BlockRequestContext_deprecated);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
row: css`
|
||||||
|
height: 100%;
|
||||||
|
`,
|
||||||
|
left: css`
|
||||||
|
width: 200px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
`,
|
||||||
|
right: css`
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
`,
|
||||||
|
rightContainer: css`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const RenderChildrenWithAssociationFilter: React.FC<any> = (props) => {
|
export const RenderChildrenWithAssociationFilter: React.FC<any> = (props) => {
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { findComponent } = useDesignable();
|
const { findComponent } = useDesignable();
|
||||||
|
const { styles } = useStyles();
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const Component = findComponent(field.component?.[0]) || React.Fragment;
|
const Component = findComponent(field.component?.[0]) || React.Fragment;
|
||||||
const associationFilterSchema = fieldSchema.reduceProperties((buf, s) => {
|
const associationFilterSchema = fieldSchema.reduceProperties((buf, s) => {
|
||||||
@ -134,39 +159,16 @@ export const RenderChildrenWithAssociationFilter: React.FC<any> = (props) => {
|
|||||||
if (associationFilterSchema) {
|
if (associationFilterSchema) {
|
||||||
return (
|
return (
|
||||||
<Component {...field.componentProps}>
|
<Component {...field.componentProps}>
|
||||||
<Row
|
<Row className={styles.row} gutter={16} wrap={false}>
|
||||||
className={css`
|
<Col className={styles.left} style={props.associationFilterStyle}>
|
||||||
height: 100%;
|
|
||||||
`}
|
|
||||||
gutter={16}
|
|
||||||
wrap={false}
|
|
||||||
>
|
|
||||||
<Col
|
|
||||||
className={css`
|
|
||||||
width: 200px;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
`}
|
|
||||||
style={props.associationFilterStyle}
|
|
||||||
>
|
|
||||||
<RecursionField
|
<RecursionField
|
||||||
schema={fieldSchema}
|
schema={fieldSchema}
|
||||||
onlyRenderProperties
|
onlyRenderProperties
|
||||||
filterProperties={(s) => s['x-component'] === 'AssociationFilter'}
|
filterProperties={(s) => s['x-component'] === 'AssociationFilter'}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col
|
<Col className={styles.right}>
|
||||||
className={css`
|
<div className={styles.rightContainer}>
|
||||||
flex: 1 1 auto;
|
|
||||||
min-width: 0;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={css`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<RecursionField
|
<RecursionField
|
||||||
schema={fieldSchema}
|
schema={fieldSchema}
|
||||||
onlyRenderProperties
|
onlyRenderProperties
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { DeleteOutlined, ExclamationCircleFilled } from '@ant-design/icons';
|
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { useForm } from '@tachybase/schema';
|
|
||||||
import { Button, message } from 'antd';
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import { useForm } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { DeleteOutlined, ExclamationCircleFilled } from '@ant-design/icons';
|
||||||
|
import { Button, message } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useActionContext,
|
useActionContext,
|
||||||
useCollectionManager_deprecated,
|
useCollectionManager_deprecated,
|
||||||
@ -54,6 +56,20 @@ export const useDestroyAction = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
modal: css`
|
||||||
|
.ant-modal-body {
|
||||||
|
margin-left: 35px;
|
||||||
|
margin-bottom: 35px;
|
||||||
|
.ant-checkbox-wrapper {
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const useBulkDestroyAction = () => {
|
export const useBulkDestroyAction = () => {
|
||||||
const { state, setState, refresh } = useResourceActionContext();
|
const { state, setState, refresh } = useResourceActionContext();
|
||||||
const { resource } = useResourceContext();
|
const { resource } = useResourceContext();
|
||||||
@ -80,6 +96,7 @@ export const useBulkDestroyAction = () => {
|
|||||||
export const DeleteCollectionAction = (props) => {
|
export const DeleteCollectionAction = (props) => {
|
||||||
const { scope, getContainer, item: record, children, isBulk, useAction, ...otherProps } = props;
|
const { scope, getContainer, item: record, children, isBulk, useAction, ...otherProps } = props;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { styles } = useStyles();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const getDestroyCollectionAction = () => {
|
const getDestroyCollectionAction = () => {
|
||||||
if (isBulk) {
|
if (isBulk) {
|
||||||
@ -124,15 +141,7 @@ export const DeleteCollectionAction = (props) => {
|
|||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
width: 520,
|
width: 520,
|
||||||
getContainer: '{{ getContainer }}',
|
getContainer: '{{ getContainer }}',
|
||||||
className: css`
|
className: styles.modal,
|
||||||
.ant-modal-body {
|
|
||||||
margin-left: 35px;
|
|
||||||
margin-bottom: 35px;
|
|
||||||
.ant-checkbox-wrapper {
|
|
||||||
height: 25px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
info: {
|
info: {
|
||||||
|
@ -1,16 +1,29 @@
|
|||||||
import { useField, useForm } from '@tachybase/schema';
|
|
||||||
import { useAsyncData } from '../../../../async-data-provider';
|
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { Input, SchemaComponent } from '../../../../schema-component';
|
import { Field, useField } from '@tachybase/schema';
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { Button } from 'antd';
|
|
||||||
import { EditOutlined, RightSquareOutlined } from '@ant-design/icons';
|
import { EditOutlined, RightSquareOutlined } from '@ant-design/icons';
|
||||||
|
import { Button } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Field } from '@tachybase/schema';
|
|
||||||
|
import { useAsyncData } from '../../../../async-data-provider';
|
||||||
|
import { Input } from '../../../../schema-component';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
input: css`
|
||||||
|
position: relative;
|
||||||
|
.ant-input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const SQLInput = ({ disabled }) => {
|
export const SQLInput = ({ disabled }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { run, loading, error } = useAsyncData();
|
const { run, loading, error } = useAsyncData();
|
||||||
|
const { styles } = useStyles();
|
||||||
const field = useField<Field>();
|
const field = useField<Field>();
|
||||||
const execute = () => {
|
const execute = () => {
|
||||||
if (!field.value) {
|
if (!field.value) {
|
||||||
@ -39,14 +52,7 @@ export const SQLInput = ({ disabled }) => {
|
|||||||
}, [field, error]);
|
}, [field, error]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={styles.input}>
|
||||||
className={css`
|
|
||||||
position: relative;
|
|
||||||
.ant-input {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<Input.TextArea value={field.value} disabled={disabled} onChange={(e) => (field.value = e.target.value)} />
|
<Input.TextArea value={field.value} disabled={disabled} onChange={(e) => (field.value = e.target.value)} />
|
||||||
<Button.Group>
|
<Button.Group>
|
||||||
<Button onClick={toggleEditing} ghost size="small" type="primary" icon={<EditOutlined />}>
|
<Button onClick={toggleEditing} ghost size="small" type="primary" icon={<EditOutlined />}>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { PresetFields } from '../components/PresetFields';
|
import { PresetFields } from '../components/PresetFields';
|
||||||
|
|
||||||
export const defaultConfigurableProperties = {
|
export const defaultConfigurableProperties = {
|
||||||
@ -56,13 +55,6 @@ export const defaultConfigurableProperties = {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-visible': '{{ createOnly }}',
|
'x-visible': '{{ createOnly }}',
|
||||||
'x-decorator-props': {
|
|
||||||
className: css`
|
|
||||||
.ant-formily-item {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
'x-component': PresetFields,
|
'x-component': PresetFields,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { ThemeConfig as _ThemeConfig } from 'antd';
|
import type { ThemeConfig as _ThemeConfig } from 'antd';
|
||||||
import { AliasToken } from 'antd/es/theme/internal';
|
import { AliasToken } from 'antd/es/theme/internal';
|
||||||
|
|
||||||
export interface CustomToken extends AliasToken {
|
export interface TachybaseToken {
|
||||||
/** 顶部导航栏主色 */
|
/** 顶部导航栏主色 */
|
||||||
colorPrimaryHeader: string;
|
colorPrimaryHeader: string;
|
||||||
/** 导航栏背景色 */
|
/** 导航栏背景色 */
|
||||||
@ -25,7 +25,14 @@ export interface CustomToken extends AliasToken {
|
|||||||
colorBorderSettingsHover: string;
|
colorBorderSettingsHover: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CustomToken extends AliasToken, TachybaseToken {}
|
||||||
|
|
||||||
export interface ThemeConfig extends _ThemeConfig {
|
export interface ThemeConfig extends _ThemeConfig {
|
||||||
name?: string;
|
name?: string;
|
||||||
token?: Partial<CustomToken>;
|
token?: Partial<CustomToken>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module 'antd-style' {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||||
|
export interface CustomToken extends TachybaseToken {}
|
||||||
|
}
|
||||||
|
@ -7,7 +7,6 @@ import 'dayjs/plugin/localeData';
|
|||||||
import 'dayjs/plugin/quarterOfYear';
|
import 'dayjs/plugin/quarterOfYear';
|
||||||
import 'dayjs/plugin/utc';
|
import 'dayjs/plugin/utc';
|
||||||
import 'dayjs/plugin/weekday';
|
import 'dayjs/plugin/weekday';
|
||||||
|
|
||||||
// 重置浏览器样式
|
// 重置浏览器样式
|
||||||
import 'antd/dist/reset.css';
|
import 'antd/dist/reset.css';
|
||||||
import './global.less';
|
import './global.less';
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { DisconnectOutlined, LoadingOutlined } from '@ant-design/icons';
|
import React, { FC } from 'react';
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { observer } from '@tachybase/schema';
|
import { observer } from '@tachybase/schema';
|
||||||
import { getSubAppName } from '@tachybase/sdk';
|
import { getSubAppName } from '@tachybase/sdk';
|
||||||
|
|
||||||
|
import { DisconnectOutlined, LoadingOutlined } from '@ant-design/icons';
|
||||||
import { Button, Modal, Result, Spin } from 'antd';
|
import { Button, Modal, Result, Spin } from 'antd';
|
||||||
import React, { FC } from 'react';
|
import { createStyles } from 'antd-style';
|
||||||
import { Navigate, useNavigate } from 'react-router-dom';
|
import { Navigate, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { ACLPlugin } from '../acl';
|
import { ACLPlugin } from '../acl';
|
||||||
import { useAPIClient } from '../api-client';
|
import { useAPIClient } from '../api-client';
|
||||||
import { Application } from '../application';
|
import { Application } from '../application';
|
||||||
@ -30,6 +32,17 @@ const AppSpin = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
modal: css`
|
||||||
|
top: 50%;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
transform: translate(0, -50%);
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const useErrorProps = (app: Application, error: any) => {
|
const useErrorProps = (app: Application, error: any) => {
|
||||||
const api = useAPIClient();
|
const api = useAPIClient();
|
||||||
if (!error) {
|
if (!error) {
|
||||||
@ -68,15 +81,11 @@ const useErrorProps = (app: Application, error: any) => {
|
|||||||
const AppError: FC<{ error: Error; app: Application }> = observer(
|
const AppError: FC<{ error: Error; app: Application }> = observer(
|
||||||
({ app, error }) => {
|
({ app, error }) => {
|
||||||
const props = useErrorProps(app, error);
|
const props = useErrorProps(app, error);
|
||||||
|
const { styles } = useStyles();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Result
|
<Result
|
||||||
className={css`
|
className={styles.modal}
|
||||||
top: 50%;
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
transform: translate(0, -50%);
|
|
||||||
`}
|
|
||||||
status="error"
|
status="error"
|
||||||
title={app.i18n.t('App error')}
|
title={app.i18n.t('App error')}
|
||||||
subTitle={app.i18n.t(error?.message)}
|
subTitle={app.i18n.t(error?.message)}
|
||||||
@ -201,15 +210,11 @@ const getProps = (app: Application) => {
|
|||||||
const AppMaintaining: FC<{ app: Application; error: Error }> = observer(
|
const AppMaintaining: FC<{ app: Application; error: Error }> = observer(
|
||||||
({ app }) => {
|
({ app }) => {
|
||||||
const { icon, status, title, subTitle } = getProps(app);
|
const { icon, status, title, subTitle } = getProps(app);
|
||||||
|
const { styles } = useStyles();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Result
|
<Result
|
||||||
className={css`
|
className={styles.modal}
|
||||||
top: 50%;
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
transform: translate(0, -50%);
|
|
||||||
`}
|
|
||||||
icon={icon}
|
icon={icon}
|
||||||
status={status}
|
status={status}
|
||||||
title={app.i18n.t(title)}
|
title={app.i18n.t(title)}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { SchemaOptionsContext } from '@tachybase/schema';
|
|
||||||
import { get } from 'lodash';
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
|
import { SchemaOptionsContext } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import { get } from 'lodash';
|
||||||
|
|
||||||
import { useACLRoleContext } from '../acl/ACLProvider';
|
import { useACLRoleContext } from '../acl/ACLProvider';
|
||||||
import { PinnedPluginListContext } from './context';
|
import { PinnedPluginListContext } from './context';
|
||||||
|
|
||||||
export const PinnedPluginListProvider: React.FC<{ items: any }> = (props) => {
|
export const PinnedPluginListProvider = (props: { items: any; children: React.ReactNode }) => {
|
||||||
const { children, items } = props;
|
const { children, items } = props;
|
||||||
const ctx = useContext(PinnedPluginListContext);
|
const ctx = useContext(PinnedPluginListContext);
|
||||||
return (
|
return (
|
||||||
@ -15,30 +17,35 @@ export const PinnedPluginListProvider: React.FC<{ items: any }> = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
display: inline-block;
|
||||||
|
.ant-btn {
|
||||||
|
border: 0;
|
||||||
|
height: 46px;
|
||||||
|
width: 46px;
|
||||||
|
border-radius: 0;
|
||||||
|
background: none;
|
||||||
|
color: rgba(255, 255, 255, 0.65);
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.1) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const PinnedPluginList = () => {
|
export const PinnedPluginList = () => {
|
||||||
const { allowAll, snippets } = useACLRoleContext();
|
const { allowAll, snippets } = useACLRoleContext();
|
||||||
const getSnippetsAllow = (aclKey) => {
|
const getSnippetsAllow = (aclKey) => {
|
||||||
return allowAll || snippets?.includes(aclKey);
|
return allowAll || snippets?.includes(aclKey);
|
||||||
};
|
};
|
||||||
|
const { styles } = useStyles();
|
||||||
const ctx = useContext(PinnedPluginListContext);
|
const ctx = useContext(PinnedPluginListContext);
|
||||||
const { components } = useContext(SchemaOptionsContext);
|
const { components } = useContext(SchemaOptionsContext);
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={styles.container}>
|
||||||
className={css`
|
|
||||||
.ant-btn {
|
|
||||||
border: 0;
|
|
||||||
height: 46px;
|
|
||||||
width: 46px;
|
|
||||||
border-radius: 0;
|
|
||||||
background: none;
|
|
||||||
color: rgba(255, 255, 255, 0.65);
|
|
||||||
&:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.1) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
style={{ display: 'inline-block' }}
|
|
||||||
>
|
|
||||||
{Object.keys(ctx.items)
|
{Object.keys(ctx.items)
|
||||||
.sort((a, b) => ctx.items[a].order - ctx.items[b].order)
|
.sort((a, b) => ctx.items[a].order - ctx.items[b].order)
|
||||||
.filter((key) => getSnippetsAllow(ctx.items[key].snippet))
|
.filter((key) => getSnippetsAllow(ctx.items[key].snippet))
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import { App, Card, Divider, Popconfirm, Space, Switch, Typography, message } from 'antd';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
import React, { FC, useState } from 'react';
|
import React, { FC, useState } from 'react';
|
||||||
|
|
||||||
|
import { ClockCircleOutlined, DeleteOutlined, ReadOutlined, ReloadOutlined, SettingOutlined } from '@ant-design/icons';
|
||||||
|
import { App, Card, Divider, message, Popconfirm, Space, Switch, Typography } from 'antd';
|
||||||
|
import classnames from 'classnames';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { DeleteOutlined, ReadOutlined, ReloadOutlined, SettingOutlined, ClockCircleOutlined } from '@ant-design/icons';
|
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { useAPIClient } from '../api-client';
|
import { useAPIClient } from '../api-client';
|
||||||
import { useApp } from '../application';
|
import { useApp } from '../application';
|
||||||
import { PluginDetail } from './PluginDetail';
|
import { PluginDetail } from './PluginDetail';
|
||||||
|
import { NPM_REGISTRY_ADDRESS } from './PluginForm/form/PluginNpmForm';
|
||||||
import { PluginUpgradeModal } from './PluginForm/modal/PluginUpgradeModal';
|
import { PluginUpgradeModal } from './PluginForm/modal/PluginUpgradeModal';
|
||||||
import { useStyles } from './style';
|
import { useStyles } from './style';
|
||||||
import type { IPluginData } from './types';
|
import type { IPluginData } from './types';
|
||||||
import { NPM_REGISTRY_ADDRESS } from './PluginForm/form/PluginNpmForm';
|
|
||||||
|
|
||||||
interface IPluginInfo extends IPluginCard {
|
interface IPluginInfo extends IPluginCard {
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
@ -111,28 +111,7 @@ function PluginInfo(props: IPluginInfo) {
|
|||||||
// style={{ marginBottom: theme.marginLG }}
|
// style={{ marginBottom: theme.marginLG }}
|
||||||
title={<div>{title}</div>}
|
title={<div>{title}</div>}
|
||||||
hoverable
|
hoverable
|
||||||
className={css`
|
className={styles.card}
|
||||||
.ant-card-actions {
|
|
||||||
li .ant-space {
|
|
||||||
gap: 2px !important;
|
|
||||||
}
|
|
||||||
li a {
|
|
||||||
.anticon {
|
|
||||||
margin-right: 3px;
|
|
||||||
/* display: none; */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
li:last-child {
|
|
||||||
width: 20% !important;
|
|
||||||
}
|
|
||||||
li:first-child {
|
|
||||||
width: 80% !important;
|
|
||||||
border-inline-end: 0;
|
|
||||||
text-align: left;
|
|
||||||
padding-left: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
actions={[
|
actions={[
|
||||||
<Space split={<Divider type="vertical" />} key={'1'}>
|
<Space split={<Divider type="vertical" />} key={'1'}>
|
||||||
<a
|
<a
|
||||||
|
@ -1,39 +1,22 @@
|
|||||||
export * from './PluginManagerLink';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import type { TableProps } from 'antd';
|
import { fuzzysearch } from '@tachybase/utils/client';
|
||||||
|
|
||||||
import { PageHeader } from '@ant-design/pro-layout';
|
import { PageHeader } from '@ant-design/pro-layout';
|
||||||
import { useDebounce } from 'ahooks';
|
import { useDebounce } from 'ahooks';
|
||||||
import {
|
import { Card, Form, Input, Radio, Result, Select, Space, Spin, Table, Tag, type TableProps } from 'antd';
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
Col,
|
|
||||||
Divider,
|
|
||||||
Input,
|
|
||||||
List,
|
|
||||||
Result,
|
|
||||||
Row,
|
|
||||||
Space,
|
|
||||||
Spin,
|
|
||||||
Tabs,
|
|
||||||
Table,
|
|
||||||
Tag,
|
|
||||||
Radio,
|
|
||||||
Form,
|
|
||||||
Select,
|
|
||||||
} from 'antd';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useEffect, useMemo, useState } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { useACLRoleContext } from '../acl/ACLProvider';
|
import { useACLRoleContext } from '../acl/ACLProvider';
|
||||||
import { useRequest } from '../api-client';
|
import { useRequest } from '../api-client';
|
||||||
|
import { i18n } from '../i18n';
|
||||||
import { useToken } from '../style';
|
import { useToken } from '../style';
|
||||||
import { PluginCard, SwitchAction } from './PluginCard';
|
import { SwitchAction } from './PluginCard';
|
||||||
import { useStyles } from './style';
|
import { useStyles } from './style';
|
||||||
import { IPluginData } from './types';
|
import { IPluginData } from './types';
|
||||||
import { fuzzysearch } from '@tachybase/utils/client';
|
|
||||||
import { i18n } from '../i18n';
|
export * from './PluginManagerLink';
|
||||||
|
|
||||||
export interface TData {
|
export interface TData {
|
||||||
data: IPluginData[];
|
data: IPluginData[];
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
import { ApiOutlined, SettingOutlined } from '@ant-design/icons';
|
import { ApiOutlined, SettingOutlined } from '@ant-design/icons';
|
||||||
import { css } from '@emotion/css';
|
import { Button, Dropdown, Tooltip } from 'antd';
|
||||||
import { Button, Card, Dropdown, Popover, Tooltip } from 'antd';
|
|
||||||
import React, { useState } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { useApp } from '../application';
|
import { useApp } from '../application';
|
||||||
import { ActionContextProvider, useCompile } from '../schema-component';
|
import { useCompile } from '../schema-component';
|
||||||
import { useToken } from '../style';
|
import { useToken } from '../style';
|
||||||
|
|
||||||
export const PluginManagerLink = () => {
|
export const PluginManagerLink = () => {
|
||||||
@ -27,14 +28,10 @@ export const PluginManagerLink = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const SettingsCenterDropdown = () => {
|
export const SettingsCenterDropdown = () => {
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const { t } = useTranslation();
|
|
||||||
const { token } = useToken();
|
const { token } = useToken();
|
||||||
const navigate = useNavigate();
|
|
||||||
const app = useApp();
|
const app = useApp();
|
||||||
const settings = app.pluginSettingsManager.getList();
|
const settings = app.pluginSettingsManager.getList();
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
menu={{
|
menu={{
|
||||||
@ -56,86 +53,7 @@ export const SettingsCenterDropdown = () => {
|
|||||||
<Button
|
<Button
|
||||||
data-testid="plugin-settings-button"
|
data-testid="plugin-settings-button"
|
||||||
icon={<SettingOutlined style={{ color: token.colorTextHeaderMenu }} />}
|
icon={<SettingOutlined style={{ color: token.colorTextHeaderMenu }} />}
|
||||||
// title={t('All plugin settings')}
|
|
||||||
/>
|
/>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
return (
|
|
||||||
settings.length > 0 && (
|
|
||||||
<ActionContextProvider value={{ visible, setVisible }}>
|
|
||||||
<Popover
|
|
||||||
open={open}
|
|
||||||
onOpenChange={(open) => {
|
|
||||||
setOpen(open);
|
|
||||||
}}
|
|
||||||
arrow={false}
|
|
||||||
content={
|
|
||||||
<div style={{ maxWidth: '21rem', overflow: 'auto', maxHeight: '50vh' }}>
|
|
||||||
<Card
|
|
||||||
bordered={false}
|
|
||||||
className={css`
|
|
||||||
box-shadow: none;
|
|
||||||
`}
|
|
||||||
style={{ boxShadow: 'none' }}
|
|
||||||
>
|
|
||||||
{settings
|
|
||||||
.filter((v) => v.isTopLevel !== false)
|
|
||||||
.map((setting) => (
|
|
||||||
<Card.Grid
|
|
||||||
style={{
|
|
||||||
width: settings.length === 1 ? '100%' : settings.length === 2 ? '50%' : '33.33%',
|
|
||||||
}}
|
|
||||||
className={css`
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0 !important;
|
|
||||||
box-shadow: none !important;
|
|
||||||
&:hover {
|
|
||||||
border-radius: ${token.borderRadius}px;
|
|
||||||
background: rgba(0, 0, 0, 0.045);
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
key={setting.name}
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
role="button"
|
|
||||||
aria-label={setting.name}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setOpen(false);
|
|
||||||
navigate(setting.path);
|
|
||||||
}}
|
|
||||||
title={compile(setting.title)}
|
|
||||||
style={{ display: 'block', color: 'inherit', minWidth: '4.5rem', padding: token.marginSM }}
|
|
||||||
href={setting.path}
|
|
||||||
>
|
|
||||||
<div style={{ fontSize: '1.2rem', textAlign: 'center', marginBottom: '0.3rem' }}>
|
|
||||||
{setting.icon || <SettingOutlined />}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
textAlign: 'center',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
overflow: 'hidden',
|
|
||||||
textOverflow: 'ellipsis',
|
|
||||||
fontSize: token.fontSizeSM,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{compile(setting.title)}
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</Card.Grid>
|
|
||||||
))}
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
data-testid="plugin-settings-button"
|
|
||||||
icon={<SettingOutlined style={{ color: token.colorTextHeaderMenu }} />}
|
|
||||||
// title={t('All plugin settings')}
|
|
||||||
/>
|
|
||||||
</Popover>
|
|
||||||
</ActionContextProvider>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { PageHeader } from '@ant-design/pro-layout';
|
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { Layout, Menu, Result } from 'antd';
|
|
||||||
import _, { get } from 'lodash';
|
|
||||||
import React, { createContext, useCallback, useMemo } from 'react';
|
import React, { createContext, useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
|
import { PageHeader } from '@ant-design/pro-layout';
|
||||||
|
import { Layout, Menu, Result } from 'antd';
|
||||||
|
import _ from 'lodash';
|
||||||
import { Navigate, Outlet, useLocation, useNavigate, useParams } from 'react-router-dom';
|
import { Navigate, Outlet, useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useStyles } from './style';
|
|
||||||
import { ADMIN_SETTINGS_PATH, PluginSettingsPageType, useApp } from '../application';
|
import { ADMIN_SETTINGS_PATH, PluginSettingsPageType, useApp } from '../application';
|
||||||
import { useCompile } from '../schema-component';
|
import { useCompile } from '../schema-component';
|
||||||
|
import { useStyles } from './style';
|
||||||
|
|
||||||
export const SettingsCenterContext = createContext<any>({});
|
export const SettingsCenterContext = createContext<any>({});
|
||||||
SettingsCenterContext.displayName = 'SettingsCenterContext';
|
SettingsCenterContext.displayName = 'SettingsCenterContext';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createStyles } from 'antd-style';
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
export const useStyles = createStyles(({ token }) => {
|
export const useStyles = createStyles(({ token, css }) => {
|
||||||
return {
|
return {
|
||||||
cardActionDisabled: {
|
cardActionDisabled: {
|
||||||
color: token.colorTextDisabled,
|
color: token.colorTextDisabled,
|
||||||
@ -55,5 +55,27 @@ export const useStyles = createStyles(({ token }) => {
|
|||||||
fontWeight: 'normal',
|
fontWeight: 'normal',
|
||||||
fontSize: token.fontSize,
|
fontSize: token.fontSize,
|
||||||
},
|
},
|
||||||
|
card: css`
|
||||||
|
.ant-card-actions {
|
||||||
|
li .ant-space {
|
||||||
|
gap: 2px !important;
|
||||||
|
}
|
||||||
|
li a {
|
||||||
|
.anticon {
|
||||||
|
margin-right: 3px;
|
||||||
|
/* display: none; */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
li:last-child {
|
||||||
|
width: 20% !important;
|
||||||
|
}
|
||||||
|
li:first-child {
|
||||||
|
width: 80% !important;
|
||||||
|
border-inline-end: 0;
|
||||||
|
text-align: left;
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -1,32 +1,154 @@
|
|||||||
import { css } from '@emotion/css';
|
import React, { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { useSessionStorageState } from 'ahooks';
|
import { useSessionStorageState } from 'ahooks';
|
||||||
import { App, ConfigProvider, Divider, Layout } from 'antd';
|
import { App, ConfigProvider, Divider, Layout } from 'antd';
|
||||||
import { createGlobalStyle } from 'antd-style';
|
import { createGlobalStyle, createStyles } from 'antd-style';
|
||||||
import React, { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
||||||
import { Link, Outlet, useLocation, useMatch, useNavigate, useParams } from 'react-router-dom';
|
import { Link, Outlet, useLocation, useMatch, useNavigate, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ACLRolesCheckProvider,
|
ACLRolesCheckProvider,
|
||||||
CurrentAppInfoProvider,
|
CurrentAppInfoProvider,
|
||||||
CurrentUser,
|
CurrentUser,
|
||||||
|
findByUid,
|
||||||
|
findMenuItem,
|
||||||
NavigateIfNotSignIn,
|
NavigateIfNotSignIn,
|
||||||
PinnedPluginList,
|
PinnedPluginList,
|
||||||
RemoteCollectionManagerProvider,
|
RemoteCollectionManagerProvider,
|
||||||
RemoteSchemaTemplateManagerPlugin,
|
RemoteSchemaTemplateManagerPlugin,
|
||||||
RemoteSchemaTemplateManagerProvider,
|
RemoteSchemaTemplateManagerProvider,
|
||||||
SchemaComponent,
|
SchemaComponent,
|
||||||
findByUid,
|
|
||||||
findMenuItem,
|
|
||||||
useACLRoleContext,
|
useACLRoleContext,
|
||||||
useAdminSchemaUid,
|
useAdminSchemaUid,
|
||||||
useDocumentTitle,
|
useDocumentTitle,
|
||||||
useRequest,
|
useRequest,
|
||||||
useSystemSettings,
|
useSystemSettings,
|
||||||
useToken,
|
|
||||||
} from '../../../';
|
} from '../../../';
|
||||||
import { Plugin } from '../../../application/Plugin';
|
|
||||||
import { useAppSpin } from '../../../application/hooks/useAppSpin';
|
import { useAppSpin } from '../../../application/hooks/useAppSpin';
|
||||||
|
import { Plugin } from '../../../application/Plugin';
|
||||||
import { VariablesProvider } from '../../../variables';
|
import { VariablesProvider } from '../../../variables';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css, token }) => {
|
||||||
|
return {
|
||||||
|
header: css`
|
||||||
|
.ant-menu.ant-menu-dark .ant-menu-item-selected,
|
||||||
|
.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected,
|
||||||
|
.ant-menu-submenu-horizontal.ant-menu-submenu-selected {
|
||||||
|
background-color: ${token.colorBgHeaderMenuActive} !important;
|
||||||
|
color: ${token.colorTextHeaderMenuActive} !important;
|
||||||
|
}
|
||||||
|
.ant-menu-submenu-horizontal.ant-menu-submenu-selected > .ant-menu-submenu-title {
|
||||||
|
color: ${token.colorTextHeaderMenuActive} !important;
|
||||||
|
}
|
||||||
|
.ant-menu-dark.ant-menu-horizontal > .ant-menu-item:hover {
|
||||||
|
background-color: ${token.colorBgHeaderMenuHover} !important;
|
||||||
|
color: ${token.colorTextHeaderMenuHover} !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: var(--nb-header-height);
|
||||||
|
line-height: var(--nb-header-height);
|
||||||
|
padding: 0;
|
||||||
|
z-index: 100;
|
||||||
|
background-color: ${token.colorBgHeader} !important;
|
||||||
|
|
||||||
|
.ant-menu {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-menu-item,
|
||||||
|
.ant-menu-submenu-horizontal {
|
||||||
|
color: ${token.colorTextHeaderMenu} !important;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
headerA: css`
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
`,
|
||||||
|
headerB: css`
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
`,
|
||||||
|
titleContainer: css`
|
||||||
|
display: inline-flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: #fff;
|
||||||
|
padding: 0;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 12px 0 12px;
|
||||||
|
`,
|
||||||
|
logo: css`
|
||||||
|
object-fit: contain;
|
||||||
|
height: 28px;
|
||||||
|
`,
|
||||||
|
title: css`
|
||||||
|
color: #fff;
|
||||||
|
height: 32px;
|
||||||
|
margin: 0 0 0 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 32px;
|
||||||
|
`,
|
||||||
|
right: css`
|
||||||
|
position: relative;
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 10;
|
||||||
|
`,
|
||||||
|
editor: css`
|
||||||
|
flex: 1 1 auto;
|
||||||
|
width: 0;
|
||||||
|
`,
|
||||||
|
sider: css`
|
||||||
|
height: 100%;
|
||||||
|
/* position: fixed; */
|
||||||
|
position: relative;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
background: rgba(0, 0, 0, 0);
|
||||||
|
z-index: 100;
|
||||||
|
.ant-layout-sider-children {
|
||||||
|
top: var(--nb-header-height);
|
||||||
|
position: fixed;
|
||||||
|
width: 200px;
|
||||||
|
height: calc(100vh - var(--nb-header-height));
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
main: css`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
overflow-y: auto;
|
||||||
|
height: 100vh;
|
||||||
|
max-height: 100vh;
|
||||||
|
> div {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.ant-layout-footer {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 0;
|
||||||
|
padding: 0px 50px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
mainHeader: css`
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: var(--nb-header-height);
|
||||||
|
line-height: var(--nb-header-height);
|
||||||
|
background: transparent;
|
||||||
|
pointer-events: none;
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const filterByACL = (schema, options) => {
|
const filterByACL = (schema, options) => {
|
||||||
const { allowAll, allowMenuItemIds = [] } = options;
|
const { allowAll, allowMenuItemIds = [] } = options;
|
||||||
if (allowAll) {
|
if (allowAll) {
|
||||||
@ -279,111 +401,24 @@ export const InternalAdminLayout = (props: any) => {
|
|||||||
const result = useSystemSettings();
|
const result = useSystemSettings();
|
||||||
// const { service } = useCollectionManager_deprecated();
|
// const { service } = useCollectionManager_deprecated();
|
||||||
const params = useParams<any>();
|
const params = useParams<any>();
|
||||||
const { token } = useToken();
|
const { styles } = useStyles();
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<GlobalStyleForAdminLayout />
|
<GlobalStyleForAdminLayout />
|
||||||
<Layout.Header
|
<Layout.Header className={styles.header}>
|
||||||
className={css`
|
<div className={styles.headerA}>
|
||||||
.ant-menu.ant-menu-dark .ant-menu-item-selected,
|
<div className={styles.headerB}>
|
||||||
.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected,
|
<div className={styles.titleContainer}>
|
||||||
.ant-menu-submenu-horizontal.ant-menu-submenu-selected {
|
<img className={styles.logo} src={result?.data?.data?.logo?.url} />
|
||||||
background-color: ${token.colorBgHeaderMenuActive} !important;
|
<h1 className={styles.title}>{result?.data?.data?.title}</h1>
|
||||||
color: ${token.colorTextHeaderMenuActive} !important;
|
|
||||||
}
|
|
||||||
.ant-menu-submenu-horizontal.ant-menu-submenu-selected > .ant-menu-submenu-title {
|
|
||||||
color: ${token.colorTextHeaderMenuActive} !important;
|
|
||||||
}
|
|
||||||
.ant-menu-dark.ant-menu-horizontal > .ant-menu-item:hover {
|
|
||||||
background-color: ${token.colorBgHeaderMenuHover} !important;
|
|
||||||
color: ${token.colorTextHeaderMenuHover} !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
height: var(--nb-header-height);
|
|
||||||
line-height: var(--nb-header-height);
|
|
||||||
padding: 0;
|
|
||||||
z-index: 100;
|
|
||||||
background-color: ${token.colorBgHeader} !important;
|
|
||||||
|
|
||||||
.ant-menu {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-menu-item,
|
|
||||||
.ant-menu-submenu-horizontal {
|
|
||||||
color: ${token.colorTextHeaderMenu} !important;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={css`
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={css`
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={css`
|
|
||||||
display: inline-flex;
|
|
||||||
flex-shrink: 0;
|
|
||||||
color: #fff;
|
|
||||||
padding: 0;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0 12px 0 12px;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
className={css`
|
|
||||||
object-fit: contain;
|
|
||||||
height: 28px;
|
|
||||||
`}
|
|
||||||
src={result?.data?.data?.logo?.url}
|
|
||||||
/>
|
|
||||||
<h1
|
|
||||||
className={css`
|
|
||||||
color: #fff;
|
|
||||||
height: 32px;
|
|
||||||
margin: 0 0 0 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 18px;
|
|
||||||
line-height: 32px;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
{result?.data?.data?.title}
|
|
||||||
</h1>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className={styles.editor}>
|
||||||
className={css`
|
|
||||||
flex: 1 1 auto;
|
|
||||||
width: 0;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<SetThemeOfHeaderSubmenu>
|
<SetThemeOfHeaderSubmenu>
|
||||||
<MenuEditor sideMenuRef={sideMenuRef} />
|
<MenuEditor sideMenuRef={sideMenuRef} />
|
||||||
</SetThemeOfHeaderSubmenu>
|
</SetThemeOfHeaderSubmenu>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className={styles.right}>
|
||||||
className={css`
|
|
||||||
position: relative;
|
|
||||||
flex-shrink: 0;
|
|
||||||
height: 100%;
|
|
||||||
z-index: 10;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<PinnedPluginList />
|
<PinnedPluginList />
|
||||||
<ConfigProvider
|
<ConfigProvider
|
||||||
theme={{
|
theme={{
|
||||||
@ -398,59 +433,10 @@ export const InternalAdminLayout = (props: any) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Layout.Header>
|
</Layout.Header>
|
||||||
{params.name && (
|
{params.name && <Layout.Sider className={styles.sider} theme={'light'} ref={sideMenuRef}></Layout.Sider>}
|
||||||
<Layout.Sider
|
<Layout.Content className={styles.main}>
|
||||||
className={css`
|
<header className={styles.mainHeader}></header>
|
||||||
height: 100%;
|
|
||||||
/* position: fixed; */
|
|
||||||
position: relative;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
background: rgba(0, 0, 0, 0);
|
|
||||||
z-index: 100;
|
|
||||||
.ant-layout-sider-children {
|
|
||||||
top: var(--nb-header-height);
|
|
||||||
position: fixed;
|
|
||||||
width: 200px;
|
|
||||||
height: calc(100vh - var(--nb-header-height));
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
theme={'light'}
|
|
||||||
ref={sideMenuRef}
|
|
||||||
></Layout.Sider>
|
|
||||||
)}
|
|
||||||
<Layout.Content
|
|
||||||
className={css`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
position: relative;
|
|
||||||
overflow-y: auto;
|
|
||||||
height: 100vh;
|
|
||||||
max-height: 100vh;
|
|
||||||
> div {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.ant-layout-footer {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 0;
|
|
||||||
padding: 0px 50px;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<header
|
|
||||||
className={css`
|
|
||||||
flex-shrink: 0;
|
|
||||||
height: var(--nb-header-height);
|
|
||||||
line-height: var(--nb-header-height);
|
|
||||||
background: transparent;
|
|
||||||
pointer-events: none;
|
|
||||||
`}
|
|
||||||
></header>
|
|
||||||
<Outlet />
|
<Outlet />
|
||||||
{/* {service.contentLoading ? render() : <Outlet />} */}
|
|
||||||
</Layout.Content>
|
</Layout.Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
@ -1,12 +1,30 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import { Modal, ModalProps } from 'antd';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { Modal, ModalProps } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { OpenSize, useActionContext } from '.';
|
import { OpenSize, useActionContext } from '.';
|
||||||
import { useSetAriaLabelForModal } from './hooks/useSetAriaLabelForModal';
|
import { useSetAriaLabelForModal } from './hooks/useSetAriaLabelForModal';
|
||||||
import { ComposedActionDrawer } from './types';
|
import { ComposedActionDrawer } from './types';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
&.nb-action-popup {
|
||||||
|
.ant-modal-header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-modal-content {
|
||||||
|
background: var(--nb-box-bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const openSizeWidthMap = new Map<OpenSize, string>([
|
const openSizeWidthMap = new Map<OpenSize, string>([
|
||||||
['small', '40%'],
|
['small', '40%'],
|
||||||
['middle', '60%'],
|
['middle', '60%'],
|
||||||
@ -15,6 +33,7 @@ const openSizeWidthMap = new Map<OpenSize, string>([
|
|||||||
export const ActionModal: ComposedActionDrawer<ModalProps> = observer(
|
export const ActionModal: ComposedActionDrawer<ModalProps> = observer(
|
||||||
(props) => {
|
(props) => {
|
||||||
const { footerNodeName = 'Action.Modal.Footer', width, ...others } = props;
|
const { footerNodeName = 'Action.Modal.Footer', width, ...others } = props;
|
||||||
|
const { styles } = useStyles();
|
||||||
const { visible, setVisible, openSize = 'middle', modalProps } = useActionContext();
|
const { visible, setVisible, openSize = 'middle', modalProps } = useActionContext();
|
||||||
const actualWidth = width ?? openSizeWidthMap.get(openSize);
|
const actualWidth = width ?? openSizeWidthMap.get(openSize);
|
||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
@ -43,21 +62,7 @@ export const ActionModal: ComposedActionDrawer<ModalProps> = observer(
|
|||||||
destroyOnClose
|
destroyOnClose
|
||||||
open={visible}
|
open={visible}
|
||||||
onCancel={() => setVisible(false, true)}
|
onCancel={() => setVisible(false, true)}
|
||||||
className={classNames(
|
className={classNames(others.className, modalProps?.className, styles.container)}
|
||||||
others.className,
|
|
||||||
modalProps?.className,
|
|
||||||
css`
|
|
||||||
&.nb-action-popup {
|
|
||||||
.ant-modal-header {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-modal-content {
|
|
||||||
background: var(--nb-box-bg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
footer={
|
footer={
|
||||||
footerSchema ? (
|
footerSchema ? (
|
||||||
<RecursionField
|
<RecursionField
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { observer, RecursionField, SchemaExpressionScopeContext, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
|
import { observer, RecursionField, SchemaExpressionScopeContext, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
|
|
||||||
import { useActionContext } from '.';
|
import { useActionContext } from '.';
|
||||||
import { ComposedActionDrawer } from './types';
|
import { ComposedActionDrawer } from './types';
|
||||||
|
|
||||||
@ -10,11 +12,24 @@ const useScope = (key: string) => {
|
|||||||
return scope[key];
|
return scope[key];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
.ant-btn {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const ActionPage: ComposedActionDrawer = observer(
|
export const ActionPage: ComposedActionDrawer = observer(
|
||||||
(props: any) => {
|
(props: any) => {
|
||||||
const { footerNodeName = 'Action.Page.Footer', ...others } = props;
|
const { footerNodeName = 'Action.Page.Footer', ...others } = props;
|
||||||
const { containerRefKey, visible, setVisible } = useActionContext();
|
const { containerRefKey, visible, setVisible } = useActionContext();
|
||||||
const containerRef = useScope(containerRefKey);
|
const containerRef = useScope(containerRefKey);
|
||||||
|
const { styles } = useStyles();
|
||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const footerSchema = schema.reduceProperties((buf, s) => {
|
const footerSchema = schema.reduceProperties((buf, s) => {
|
||||||
@ -38,17 +53,7 @@ export const ActionPage: ComposedActionDrawer = observer(
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{footerSchema && (
|
{footerSchema && (
|
||||||
<div
|
<div className={styles.container}>
|
||||||
className={css`
|
|
||||||
display: flex;
|
|
||||||
/* justify-content: flex-end; */
|
|
||||||
/* flex-direction: row-reverse; */
|
|
||||||
width: 100%;
|
|
||||||
.ant-btn {
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<RecursionField
|
<RecursionField
|
||||||
basePath={field.address}
|
basePath={field.address}
|
||||||
schema={schema}
|
schema={schema}
|
||||||
|
@ -1,13 +1,23 @@
|
|||||||
import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import { Button, Drawer, Space } from 'antd';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { OpenSize } from '.';
|
import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { Button, Drawer, Space } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { useStyles } from './Action.Drawer.style';
|
import { useStyles } from './Action.Drawer.style';
|
||||||
import { useActionContext } from './hooks';
|
import { useActionContext } from './hooks';
|
||||||
import { ComposedActionDrawer } from './types';
|
import { ComposedActionDrawer } from './types';
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
const useStyles2 = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
width: 100%;
|
||||||
|
justify-content: flex-end;
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const ActionSheet: ComposedActionDrawer = observer(
|
export const ActionSheet: ComposedActionDrawer = observer(
|
||||||
(props) => {
|
(props) => {
|
||||||
@ -17,6 +27,7 @@ export const ActionSheet: ComposedActionDrawer = observer(
|
|||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const { componentCls, hashId } = useStyles();
|
const { componentCls, hashId } = useStyles();
|
||||||
|
const { styles } = useStyles2();
|
||||||
const footerSchema = schema.reduceProperties((buf, s) => {
|
const footerSchema = schema.reduceProperties((buf, s) => {
|
||||||
if (s['x-component'] === footerNodeName) {
|
if (s['x-component'] === footerNodeName) {
|
||||||
return s;
|
return s;
|
||||||
@ -40,12 +51,7 @@ export const ActionSheet: ComposedActionDrawer = observer(
|
|||||||
onClose={() => setVisible(false, true)}
|
onClose={() => setVisible(false, true)}
|
||||||
rootClassName={classNames(componentCls, hashId, drawerProps?.className, others.className, 'reset')}
|
rootClassName={classNames(componentCls, hashId, drawerProps?.className, others.className, 'reset')}
|
||||||
footer={
|
footer={
|
||||||
<Space
|
<Space className={styles.container}>
|
||||||
className={css`
|
|
||||||
width: 100%;
|
|
||||||
justify-content: flex-end;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<Button type="primary" onClick={() => setVisible(false, true)}>
|
<Button type="primary" onClick={() => setVisible(false, true)}>
|
||||||
{t('Close')}
|
{t('Close')}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
import { cx } from '@emotion/css';
|
|
||||||
import { RecursionField, observer, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import { Space } from 'antd';
|
|
||||||
import React, { CSSProperties, useContext } from 'react';
|
import React, { CSSProperties, useContext } from 'react';
|
||||||
|
import { observer, RecursionField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { Space } from 'antd';
|
||||||
|
import cx from 'classnames';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { DndContext } from '../../common';
|
|
||||||
import { useDesignable, useProps } from '../../hooks';
|
|
||||||
import { useSchemaInitializerRender } from '../../../application';
|
import { useSchemaInitializerRender } from '../../../application';
|
||||||
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
||||||
|
import { DndContext } from '../../common';
|
||||||
|
import { useDesignable, useProps } from '../../hooks';
|
||||||
|
|
||||||
interface ActionBarContextForceProps {
|
interface ActionBarContextForceProps {
|
||||||
layout?: 'one-column' | 'tow-columns';
|
layout?: 'one-column' | 'tow-columns';
|
||||||
@ -35,7 +37,7 @@ export const useActionBarContext = () => {
|
|||||||
return useContext(ActionBarContext);
|
return useContext(ActionBarContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Portal: React.FC = (props) => {
|
const Portal = (props) => {
|
||||||
const filedSchema = useFieldSchema();
|
const filedSchema = useFieldSchema();
|
||||||
const { container, parentComponents = ['BlockItem', 'CardItem'] } = useActionBarContext();
|
const { container, parentComponents = ['BlockItem', 'CardItem'] } = useActionBarContext();
|
||||||
return (
|
return (
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
import { EditOutlined } from '@ant-design/icons';
|
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { observer, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import React, { useContext, useState } from 'react';
|
import React, { useContext, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { Field, observer, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
import { InternalSubTable } from './InternalSubTable';
|
|
||||||
|
import { EditOutlined } from '@ant-design/icons';
|
||||||
import { Button, Drawer } from 'antd';
|
import { Button, Drawer } from 'antd';
|
||||||
import { SubFormProvider, useAssociationFieldContext } from './hooks';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ActionContext, ActionContextProvider } from '../action/context';
|
|
||||||
import { ReadPrettyInternalViewer } from './InternalViewer';
|
|
||||||
import { useCollectionManager } from '../../../data-source';
|
import { useCollectionManager } from '../../../data-source';
|
||||||
import { FlagProvider } from '../../../flag-provider';
|
import { FlagProvider } from '../../../flag-provider';
|
||||||
|
import { ActionContext, ActionContextProvider } from '../action/context';
|
||||||
|
import { SubFormProvider, useAssociationFieldContext } from './hooks';
|
||||||
|
import { InternalSubTable } from './InternalSubTable';
|
||||||
|
import { ReadPrettyInternalViewer } from './InternalViewer';
|
||||||
|
|
||||||
export const InternaDrawerSubTable = observer(
|
export const InternaDrawerSubTable = observer(
|
||||||
(props) => {
|
(props) => {
|
||||||
@ -26,7 +27,7 @@ export const InternaDrawerSubTable = observer(
|
|||||||
enableLink: true,
|
enableLink: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const field = useField();
|
const field = useField<Field>();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const cm = useCollectionManager();
|
const cm = useCollectionManager();
|
||||||
|
|
||||||
@ -39,11 +40,7 @@ export const InternaDrawerSubTable = observer(
|
|||||||
setVisible(true);
|
setVisible(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div style={{ maxWidth: '95%' }}>
|
||||||
className={css`
|
|
||||||
max-width: 95%;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<ReadPrettyInternalViewer {...titleProps} />
|
<ReadPrettyInternalViewer {...titleProps} />
|
||||||
</div>
|
</div>
|
||||||
<EditOutlined style={{ display: 'inline-flex', marginLeft: '5px' }} />
|
<EditOutlined style={{ display: 'inline-flex', marginLeft: '5px' }} />
|
||||||
|
@ -1,12 +1,39 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
|
||||||
import { FormLayout } from '@tachybase/components';
|
|
||||||
import { RecursionField, useField, useFieldSchema, observer } from '@tachybase/schema';
|
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
import { FormLayout } from '@tachybase/components';
|
||||||
|
import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import cx from 'classnames';
|
||||||
|
|
||||||
|
import { ACLCollectionProvider, useACLActionParamsContext } from '../../../acl';
|
||||||
import { CollectionProvider_deprecated } from '../../../collection-manager';
|
import { CollectionProvider_deprecated } from '../../../collection-manager';
|
||||||
import { useAssociationFieldContext, useInsertSchema } from './hooks';
|
import { useAssociationFieldContext, useInsertSchema } from './hooks';
|
||||||
import { ACLCollectionProvider, useACLActionParamsContext } from '../../../acl';
|
|
||||||
import schema from './schema';
|
import schema from './schema';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
body: css`
|
||||||
|
& .ant-formily-item-layout-vertical {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.ant-card-body {
|
||||||
|
padding: 15px 20px 5px;
|
||||||
|
}
|
||||||
|
.ant-divider-horizontal {
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
showTitle: css`
|
||||||
|
.ant-card-body {
|
||||||
|
padding: 0px 20px 20px 0px;
|
||||||
|
}
|
||||||
|
> .ant-card-bordered {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const InternalNester = observer(
|
export const InternalNester = observer(
|
||||||
() => {
|
() => {
|
||||||
const field = useField();
|
const field = useField();
|
||||||
@ -15,6 +42,8 @@ export const InternalNester = observer(
|
|||||||
const { options: collectionField } = useAssociationFieldContext();
|
const { options: collectionField } = useAssociationFieldContext();
|
||||||
const showTitle = fieldSchema['x-decorator-props']?.showTitle ?? true;
|
const showTitle = fieldSchema['x-decorator-props']?.showTitle ?? true;
|
||||||
const { actionName } = useACLActionParamsContext();
|
const { actionName } = useACLActionParamsContext();
|
||||||
|
const { styles } = useStyles();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
insertNester(schema.Nester);
|
insertNester(schema.Nester);
|
||||||
}, []);
|
}, []);
|
||||||
@ -23,29 +52,9 @@ export const InternalNester = observer(
|
|||||||
<ACLCollectionProvider actionPath={`${collectionField.target}:${actionName}`}>
|
<ACLCollectionProvider actionPath={`${collectionField.target}:${actionName}`}>
|
||||||
<FormLayout layout={'vertical'}>
|
<FormLayout layout={'vertical'}>
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(styles.body, {
|
||||||
css`
|
[styles.showTitle]: showTitle === false,
|
||||||
& .ant-formily-item-layout-vertical {
|
})}
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.ant-card-body {
|
|
||||||
padding: 15px 20px 5px;
|
|
||||||
}
|
|
||||||
.ant-divider-horizontal {
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
{
|
|
||||||
[css`
|
|
||||||
.ant-card-body {
|
|
||||||
padding: 0px 20px 20px 0px;
|
|
||||||
}
|
|
||||||
> .ant-card-bordered {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
`]: showTitle === false,
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<RecursionField
|
<RecursionField
|
||||||
onlyRenderProperties
|
onlyRenderProperties
|
||||||
|
@ -1,18 +1,47 @@
|
|||||||
import { EditOutlined } from '@ant-design/icons';
|
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { observer, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import React, { useContext, useRef, useState } from 'react';
|
import React, { useContext, useRef, useState } from 'react';
|
||||||
|
import { observer, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { EditOutlined } from '@ant-design/icons';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { ActionContext, ActionContextProvider } from '../action/context';
|
import { ActionContext, ActionContextProvider } from '../action/context';
|
||||||
import { useGetAriaLabelOfPopover } from '../action/hooks/useGetAriaLabelOfPopover';
|
import { useGetAriaLabelOfPopover } from '../action/hooks/useGetAriaLabelOfPopover';
|
||||||
import { useSetAriaLabelForPopover } from '../action/hooks/useSetAriaLabelForPopover';
|
import { useSetAriaLabelForPopover } from '../action/hooks/useSetAriaLabelForPopover';
|
||||||
import { StablePopover } from '../popover';
|
import { StablePopover } from '../popover';
|
||||||
|
import { useAssociationFieldContext } from './hooks';
|
||||||
import { InternalNester } from './InternalNester';
|
import { InternalNester } from './InternalNester';
|
||||||
import { ReadPrettyInternalViewer } from './InternalViewer';
|
import { ReadPrettyInternalViewer } from './InternalViewer';
|
||||||
import { useAssociationFieldContext } from './hooks';
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
pretty: css`
|
||||||
|
max-width: 95%;
|
||||||
|
`,
|
||||||
|
mask: css`
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: transparent;
|
||||||
|
z-index: 9999;
|
||||||
|
`,
|
||||||
|
container: css`
|
||||||
|
min-width: 600px;
|
||||||
|
max-width: 800px;
|
||||||
|
max-height: 440px;
|
||||||
|
overflow: auto;
|
||||||
|
.ant-card {
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const InternaPopoverNester = observer(
|
export const InternaPopoverNester = observer(
|
||||||
(props) => {
|
(props) => {
|
||||||
|
const { styles } = useStyles();
|
||||||
const { options } = useAssociationFieldContext();
|
const { options } = useAssociationFieldContext();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -24,18 +53,7 @@ export const InternaPopoverNester = observer(
|
|||||||
shouldMountElement: true,
|
shouldMountElement: true,
|
||||||
};
|
};
|
||||||
const content = (
|
const content = (
|
||||||
<div
|
<div ref={ref} className={styles.container}>
|
||||||
ref={ref}
|
|
||||||
style={{ minWidth: '600px', maxWidth: '800px', maxHeight: '440px', overflow: 'auto' }}
|
|
||||||
className={css`
|
|
||||||
min-width: 600px;
|
|
||||||
max-height: 440px;
|
|
||||||
overflow: auto;
|
|
||||||
.ant-card {
|
|
||||||
border: 0px;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<InternalNester {...nesterProps} />
|
<InternalNester {...nesterProps} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -62,11 +80,7 @@ export const InternaPopoverNester = observer(
|
|||||||
title={t(options?.uiSchema?.rawTitle)}
|
title={t(options?.uiSchema?.rawTitle)}
|
||||||
>
|
>
|
||||||
<span style={{ cursor: 'pointer', display: 'flex' }}>
|
<span style={{ cursor: 'pointer', display: 'flex' }}>
|
||||||
<div
|
<div className={styles.pretty}>
|
||||||
className={css`
|
|
||||||
max-width: 95%;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<ReadPrettyInternalViewer {...props} />
|
<ReadPrettyInternalViewer {...props} />
|
||||||
</div>
|
</div>
|
||||||
<EditOutlined style={{ display: 'inline-flex', margin: '5px' }} />
|
<EditOutlined style={{ display: 'inline-flex', margin: '5px' }} />
|
||||||
@ -77,15 +91,7 @@ export const InternaPopoverNester = observer(
|
|||||||
role="button"
|
role="button"
|
||||||
aria-label={getAriaLabel('mask')}
|
aria-label={getAriaLabel('mask')}
|
||||||
onClick={() => setVisible(false)}
|
onClick={() => setVisible(false)}
|
||||||
className={css`
|
className={styles.mask}
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: transparent;
|
|
||||||
z-index: 9999;
|
|
||||||
`}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</ActionContextProvider>
|
</ActionContextProvider>
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { FormLayout } from '@tachybase/components';
|
|
||||||
import { RecursionField, SchemaOptionsContext, observer, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
import { FormLayout } from '@tachybase/components';
|
||||||
|
import { observer, RecursionField, SchemaOptionsContext, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
import { ACLCollectionProvider, useACLActionParamsContext } from '../../../acl';
|
import { ACLCollectionProvider, useACLActionParamsContext } from '../../../acl';
|
||||||
import { CollectionProvider_deprecated } from '../../../collection-manager';
|
import { CollectionProvider_deprecated } from '../../../collection-manager';
|
||||||
import { FormItem, useSchemaOptionsContext } from '../../../schema-component';
|
import { FormItem, useSchemaOptionsContext } from '../../../schema-component';
|
||||||
@ -9,8 +11,28 @@ import Select from '../select/Select';
|
|||||||
import { useAssociationFieldContext, useInsertSchema } from './hooks';
|
import { useAssociationFieldContext, useInsertSchema } from './hooks';
|
||||||
import schema from './schema';
|
import schema from './schema';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
.ant-formily-item-bordered-none {
|
||||||
|
.ant-input-number-group-addon {
|
||||||
|
border: none !important;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.ant-checkbox-wrapper {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
.ant-table {
|
||||||
|
margin: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const InternalSubTable = observer(
|
export const InternalSubTable = observer(
|
||||||
() => {
|
() => {
|
||||||
|
const { styles } = useStyles();
|
||||||
const field: any = useField();
|
const field: any = useField();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const insert = useInsertSchema('SubTable');
|
const insert = useInsertSchema('SubTable');
|
||||||
@ -36,24 +58,7 @@ export const InternalSubTable = observer(
|
|||||||
return (
|
return (
|
||||||
<CollectionProvider_deprecated name={options.target}>
|
<CollectionProvider_deprecated name={options.target}>
|
||||||
<ACLCollectionProvider actionPath={`${options.target}:${actionName || 'view'}`}>
|
<ACLCollectionProvider actionPath={`${options.target}:${actionName || 'view'}`}>
|
||||||
<FormLayout
|
<FormLayout className={styles.container} layout={'vertical'} bordered={false}>
|
||||||
className={css`
|
|
||||||
.ant-formily-item-bordered-none {
|
|
||||||
.ant-input-number-group-addon {
|
|
||||||
border: none !important;
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
.ant-checkbox-wrapper {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
.ant-table {
|
|
||||||
margin: 0px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
layout={'vertical'}
|
|
||||||
bordered={false}
|
|
||||||
>
|
|
||||||
<SchemaOptionsContext.Provider
|
<SchemaOptionsContext.Provider
|
||||||
value={{
|
value={{
|
||||||
scope: option.scope,
|
scope: option.scope,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import { toArr } from '@tachybase/schema';
|
|
||||||
import React, { Fragment, useRef, useState } from 'react';
|
import React, { Fragment, useRef, useState } from 'react';
|
||||||
|
import { observer, RecursionField, toArr, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
import { useDesignable } from '../../';
|
import { useDesignable } from '../../';
|
||||||
import { BlockAssociationContext, WithoutTableFieldResource } from '../../../block-provider';
|
import { BlockAssociationContext, WithoutTableFieldResource } from '../../../block-provider';
|
||||||
import { CollectionProvider_deprecated, useCollectionManager_deprecated } from '../../../collection-manager';
|
import { CollectionProvider_deprecated, useCollectionManager_deprecated } from '../../../collection-manager';
|
||||||
@ -27,7 +27,7 @@ const toValue = (value, placeholder) => {
|
|||||||
export function isObject(value) {
|
export function isObject(value) {
|
||||||
return typeof value === 'object' && value !== null;
|
return typeof value === 'object' && value !== null;
|
||||||
}
|
}
|
||||||
export const ReadPrettyInternalViewer: React.FC = observer(
|
export const ReadPrettyInternalViewer = observer(
|
||||||
(props: any) => {
|
(props: any) => {
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const recordCtx = useRecord();
|
const recordCtx = useRecord();
|
||||||
|
@ -1,31 +1,57 @@
|
|||||||
import { CloseOutlined, PlusOutlined } from '@ant-design/icons';
|
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { ArrayField } from '@tachybase/schema';
|
|
||||||
import { spliceArrayState } from '@tachybase/schema';
|
|
||||||
import { RecursionField, observer, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import { action } from '@tachybase/schema';
|
|
||||||
import { each } from '@tachybase/schema';
|
|
||||||
import { Button, Card, Divider, Tooltip } from 'antd';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import React, { useCallback, useContext } from 'react';
|
import React, { useCallback, useContext } from 'react';
|
||||||
|
import {
|
||||||
|
action,
|
||||||
|
ArrayField,
|
||||||
|
each,
|
||||||
|
observer,
|
||||||
|
RecursionField,
|
||||||
|
spliceArrayState,
|
||||||
|
useFieldSchema,
|
||||||
|
} from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { CloseOutlined, PlusOutlined } from '@ant-design/icons';
|
||||||
|
import { Button, Card, Divider, Tooltip } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import _ from 'lodash';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { FormActiveFieldsProvider } from '../../../block-provider';
|
import { FormActiveFieldsProvider } from '../../../block-provider';
|
||||||
|
import { useCollection } from '../../../data-source';
|
||||||
import {
|
import {
|
||||||
useCollectionRecord,
|
useCollectionRecord,
|
||||||
useCollectionRecordData,
|
useCollectionRecordData,
|
||||||
} from '../../../data-source/collection-record/CollectionRecordProvider';
|
} from '../../../data-source/collection-record/CollectionRecordProvider';
|
||||||
|
import { isNewRecord, markRecordAsNew } from '../../../data-source/collection-record/isNewRecord';
|
||||||
import { FlagProvider } from '../../../flag-provider';
|
import { FlagProvider } from '../../../flag-provider';
|
||||||
import { RecordIndexProvider, RecordProvider } from '../../../record-provider';
|
import { RecordIndexProvider, RecordProvider } from '../../../record-provider';
|
||||||
import { isPatternDisabled, isSystemField } from '../../../schema-settings';
|
import { isPatternDisabled, isSystemField } from '../../../schema-settings';
|
||||||
import {
|
import {
|
||||||
DefaultValueProvider,
|
DefaultValueProvider,
|
||||||
IsAllowToSetDefaultValueParams,
|
|
||||||
interfacesOfUnsupportedDefaultValue,
|
interfacesOfUnsupportedDefaultValue,
|
||||||
|
IsAllowToSetDefaultValueParams,
|
||||||
} from '../../../schema-settings/hooks/useIsAllowToSetDefaultValue';
|
} from '../../../schema-settings/hooks/useIsAllowToSetDefaultValue';
|
||||||
import { AssociationFieldContext } from './context';
|
import { AssociationFieldContext } from './context';
|
||||||
import { SubFormProvider, useAssociationFieldContext } from './hooks';
|
import { SubFormProvider, useAssociationFieldContext } from './hooks';
|
||||||
import { isNewRecord, markRecordAsNew } from '../../../data-source/collection-record/isNewRecord';
|
|
||||||
import { useCollection } from '../../../data-source';
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
input: css`
|
||||||
|
position: relative;
|
||||||
|
.ant-input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
card: css`
|
||||||
|
> .ant-card-body > .ant-divider:last-child {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
button: css`
|
||||||
|
border: 1px solid #f0f0f0 !important;
|
||||||
|
box-shadow: none;
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const Nester = (props) => {
|
export const Nester = (props) => {
|
||||||
const { options } = useContext(AssociationFieldContext);
|
const { options } = useContext(AssociationFieldContext);
|
||||||
@ -133,17 +159,10 @@ const ToManyNester = observer(
|
|||||||
!isSystemField(collectionField, getInterface)
|
!isSystemField(collectionField, getInterface)
|
||||||
);
|
);
|
||||||
}, []);
|
}, []);
|
||||||
|
const { styles } = useStyles();
|
||||||
|
|
||||||
return field.value.length > 0 ? (
|
return field.value.length > 0 ? (
|
||||||
<Card
|
<Card bordered={true} style={{ position: 'relative' }} className={styles.card}>
|
||||||
bordered={true}
|
|
||||||
style={{ position: 'relative' }}
|
|
||||||
className={css`
|
|
||||||
> .ant-card-body > .ant-divider:last-child {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
{field.value.map((value, index) => {
|
{field.value.map((value, index) => {
|
||||||
let allowed = allowDissociate;
|
let allowed = allowDissociate;
|
||||||
if (!allowDissociate) {
|
if (!allowDissociate) {
|
||||||
@ -221,10 +240,7 @@ const ToManyNester = observer(
|
|||||||
<Tooltip key={'add'} title={t('Add new')}>
|
<Tooltip key={'add'} title={t('Add new')}>
|
||||||
<Button
|
<Button
|
||||||
type={'default'}
|
type={'default'}
|
||||||
className={css`
|
className={styles.button}
|
||||||
border: 1px solid #f0f0f0 !important;
|
|
||||||
box-shadow: none;
|
|
||||||
`}
|
|
||||||
block
|
block
|
||||||
icon={<PlusOutlined />}
|
icon={<PlusOutlined />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { ArrayField } from '@tachybase/schema';
|
|
||||||
import { exchangeArrayState } from '@tachybase/schema';
|
|
||||||
import { observer, RecursionField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import { action } from '@tachybase/schema';
|
|
||||||
import { isArr } from '@tachybase/schema';
|
|
||||||
import { Button } from 'antd';
|
|
||||||
import { unionBy, uniqBy } from 'lodash';
|
|
||||||
import React, { useContext, useMemo, useState } from 'react';
|
import React, { useContext, useMemo, useState } from 'react';
|
||||||
|
import {
|
||||||
|
action,
|
||||||
|
ArrayField,
|
||||||
|
exchangeArrayState,
|
||||||
|
isArr,
|
||||||
|
observer,
|
||||||
|
RecursionField,
|
||||||
|
useFieldSchema,
|
||||||
|
} from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { Button } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import { unionBy, uniqBy } from 'lodash';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FormProvider,
|
FormProvider,
|
||||||
RecordPickerContext,
|
RecordPickerContext,
|
||||||
@ -20,6 +26,7 @@ import { FormActiveFieldsProvider } from '../../../block-provider/hooks/useFormA
|
|||||||
import { TableSelectorParamsProvider } from '../../../block-provider/TableSelectorProvider';
|
import { TableSelectorParamsProvider } from '../../../block-provider/TableSelectorProvider';
|
||||||
import { CollectionProvider_deprecated } from '../../../collection-manager';
|
import { CollectionProvider_deprecated } from '../../../collection-manager';
|
||||||
import { CollectionRecordProvider, useCollectionRecord } from '../../../data-source';
|
import { CollectionRecordProvider, useCollectionRecord } from '../../../data-source';
|
||||||
|
import { markRecordAsNew } from '../../../data-source/collection-record/isNewRecord';
|
||||||
import { FlagProvider } from '../../../flag-provider';
|
import { FlagProvider } from '../../../flag-provider';
|
||||||
import { useCompile } from '../../hooks';
|
import { useCompile } from '../../hooks';
|
||||||
import { ActionContextProvider } from '../action';
|
import { ActionContextProvider } from '../action';
|
||||||
@ -27,11 +34,69 @@ import { Table } from '../table-v2/Table';
|
|||||||
import { useAssociationFieldContext, useFieldNames } from './hooks';
|
import { useAssociationFieldContext, useFieldNames } from './hooks';
|
||||||
import { useTableSelectorProps } from './InternalPicker';
|
import { useTableSelectorProps } from './InternalPicker';
|
||||||
import { getLabelFormatValue, useLabelUiSchema } from './util';
|
import { getLabelFormatValue, useLabelUiSchema } from './util';
|
||||||
import { markRecordAsNew } from '../../../data-source/collection-record/isNewRecord';
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
addNew: css`
|
||||||
|
display: block;
|
||||||
|
border-radius: 0px;
|
||||||
|
border-right: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
|
`,
|
||||||
|
select: css`
|
||||||
|
display: block;
|
||||||
|
border-radius: 0px;
|
||||||
|
`,
|
||||||
|
table: css`
|
||||||
|
.ant-formily-item.ant-formily-item-feedback-layout-loose {
|
||||||
|
margin-bottom: 0px !important;
|
||||||
|
}
|
||||||
|
.ant-formily-editable {
|
||||||
|
vertical-align: sub;
|
||||||
|
}
|
||||||
|
.ant-table-footer {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
container: css`
|
||||||
|
.ant-table-footer {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
.ant-formily-item-error-help {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.ant-description-textarea {
|
||||||
|
line-height: 34px;
|
||||||
|
}
|
||||||
|
.ant-table-cell .ant-formily-item-error-help {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
font-size: 12px;
|
||||||
|
top: 100%;
|
||||||
|
background: #fff;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: -15px;
|
||||||
|
padding: 3px;
|
||||||
|
z-index: 1;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 0 0 10px #eee;
|
||||||
|
animation: none;
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
input: css`
|
||||||
|
position: relative;
|
||||||
|
.ant-input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const SubTable: any = observer(
|
export const SubTable: any = observer(
|
||||||
(props: any) => {
|
(props: any) => {
|
||||||
const { openSize } = props;
|
const { openSize } = props;
|
||||||
|
const { styles } = useStyles();
|
||||||
const { field, options: collectionField } = useAssociationFieldContext<ArrayField>();
|
const { field, options: collectionField } = useAssociationFieldContext<ArrayField>();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [visibleSelector, setVisibleSelector] = useState(false);
|
const [visibleSelector, setVisibleSelector] = useState(false);
|
||||||
@ -108,50 +173,12 @@ export const SubTable: any = observer(
|
|||||||
return filter;
|
return filter;
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={styles.container}>
|
||||||
className={css`
|
|
||||||
.ant-table-footer {
|
|
||||||
padding: 0 !important;
|
|
||||||
}
|
|
||||||
.ant-formily-item-error-help {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.ant-description-textarea {
|
|
||||||
line-height: 34px;
|
|
||||||
}
|
|
||||||
.ant-table-cell .ant-formily-item-error-help {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
font-size: 12px;
|
|
||||||
top: 100%;
|
|
||||||
background: #fff;
|
|
||||||
width: 100%;
|
|
||||||
margin-top: -15px;
|
|
||||||
padding: 3px;
|
|
||||||
z-index: 1;
|
|
||||||
border-radius: 3px;
|
|
||||||
box-shadow: 0 0 10px #eee;
|
|
||||||
animation: none;
|
|
||||||
transform: translateY(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<FlagProvider isInSubTable>
|
<FlagProvider isInSubTable>
|
||||||
<CollectionRecordProvider record={null} parentRecord={recordV2}>
|
<CollectionRecordProvider record={null} parentRecord={recordV2}>
|
||||||
<FormActiveFieldsProvider name="nester">
|
<FormActiveFieldsProvider name="nester">
|
||||||
<Table
|
<Table
|
||||||
className={css`
|
className={styles.table}
|
||||||
.ant-formily-item.ant-formily-item-feedback-layout-loose {
|
|
||||||
margin-bottom: 0px !important;
|
|
||||||
}
|
|
||||||
.ant-formily-editable {
|
|
||||||
vertical-align: sub;
|
|
||||||
}
|
|
||||||
.ant-table-footer {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
bordered
|
bordered
|
||||||
size={'small'}
|
size={'small'}
|
||||||
field={field}
|
field={field}
|
||||||
@ -167,11 +194,7 @@ export const SubTable: any = observer(
|
|||||||
<Button
|
<Button
|
||||||
type={'text'}
|
type={'text'}
|
||||||
block
|
block
|
||||||
className={css`
|
className={styles.addNew}
|
||||||
display: block;
|
|
||||||
border-radius: 0px;
|
|
||||||
border-right: 1px solid rgba(0, 0, 0, 0.06);
|
|
||||||
`}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
field.value = field.value || [];
|
field.value = field.value || [];
|
||||||
field.value.push(markRecordAsNew({}));
|
field.value.push(markRecordAsNew({}));
|
||||||
@ -184,10 +207,7 @@ export const SubTable: any = observer(
|
|||||||
<Button
|
<Button
|
||||||
type={'text'}
|
type={'text'}
|
||||||
block
|
block
|
||||||
className={css`
|
className={styles.select}
|
||||||
display: block;
|
|
||||||
border-radius: 0px;
|
|
||||||
`}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setVisibleSelector(true);
|
setVisibleSelector(true);
|
||||||
}}
|
}}
|
||||||
|
@ -1,86 +1,87 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { useFieldSchema } from '@tachybase/schema';
|
|
||||||
import cls from 'classnames';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useCollection_deprecated } from '../../../collection-manager';
|
import { useFieldSchema } from '@tachybase/schema';
|
||||||
import { DndContext, SortableItem } from '../../common';
|
|
||||||
import { useDesigner } from '../../hooks';
|
import { createStyles } from 'antd-style';
|
||||||
import { useToken } from '../__builtins__';
|
import cls from 'classnames';
|
||||||
import { AssociationFilterBlockDesigner } from './AssociationFilter.BlockDesigner';
|
|
||||||
import { AssociationFilterItem } from './AssociationFilter.Item';
|
|
||||||
import { AssociationFilterItemDesigner } from './AssociationFilter.Item.Designer';
|
|
||||||
import { AssociationFilterProvider } from './AssociationFilterProvider';
|
|
||||||
import { useSchemaInitializerRender } from '../../../application';
|
import { useSchemaInitializerRender } from '../../../application';
|
||||||
import { Plugin } from '../../../application/Plugin';
|
import { Plugin } from '../../../application/Plugin';
|
||||||
|
import { useCollection_deprecated } from '../../../collection-manager';
|
||||||
import {
|
import {
|
||||||
associationFilterFilterBlockInitializer,
|
associationFilterFilterBlockInitializer,
|
||||||
filterCollapseItemInitializer,
|
filterCollapseItemInitializer,
|
||||||
filterCollapseItemInitializer_deprecated,
|
filterCollapseItemInitializer_deprecated,
|
||||||
} from '../../../modules/blocks/filter-blocks/collapse/filterCollapseItemInitializer';
|
} from '../../../modules/blocks/filter-blocks/collapse/filterCollapseItemInitializer';
|
||||||
|
import { DndContext, SortableItem } from '../../common';
|
||||||
|
import { useDesigner } from '../../hooks';
|
||||||
|
import { AssociationFilterBlockDesigner } from './AssociationFilter.BlockDesigner';
|
||||||
import { associationFilterInitializer } from './AssociationFilter.Initializer';
|
import { associationFilterInitializer } from './AssociationFilter.Initializer';
|
||||||
|
import { AssociationFilterItem } from './AssociationFilter.Item';
|
||||||
|
import { AssociationFilterItemDesigner } from './AssociationFilter.Item.Designer';
|
||||||
|
import { AssociationFilterProvider } from './AssociationFilterProvider';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css, token }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
position: relative;
|
||||||
|
border-radius: ${token.borderRadiusLG}px;
|
||||||
|
&:hover {
|
||||||
|
> .general-schema-designer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.nb-form-item:hover {
|
||||||
|
> .general-schema-designer {
|
||||||
|
background: var(--colorBgSettingsHover) !important;
|
||||||
|
border: 0 !important;
|
||||||
|
top: -5px !important;
|
||||||
|
bottom: -5px !important;
|
||||||
|
left: -5px !important;
|
||||||
|
right: -5px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .general-schema-designer {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: none;
|
||||||
|
border: 2px solid var(--colorBorderSettingsHover);
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: var(--colorSettings);
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const AssociationFilter = (props) => {
|
export const AssociationFilter = (props) => {
|
||||||
const { token } = useToken();
|
|
||||||
const Designer = useDesigner();
|
const Designer = useDesigner();
|
||||||
const filedSchema = useFieldSchema();
|
const filedSchema = useFieldSchema();
|
||||||
|
const { styles } = useStyles();
|
||||||
|
|
||||||
const { render } = useSchemaInitializerRender(filedSchema['x-initializer'], filedSchema['x-initializer-props']);
|
const { render } = useSchemaInitializerRender(filedSchema['x-initializer'], filedSchema['x-initializer-props']);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DndContext>
|
<DndContext>
|
||||||
<SortableItem
|
<SortableItem className={cls('nb-block-item', props.className, styles.container)}>
|
||||||
className={cls(
|
|
||||||
'nb-block-item',
|
|
||||||
props.className,
|
|
||||||
css`
|
|
||||||
height: 100%;
|
|
||||||
overflow-y: auto;
|
|
||||||
position: relative;
|
|
||||||
border-radius: ${token.borderRadiusLG}px;
|
|
||||||
&:hover {
|
|
||||||
> .general-schema-designer {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.nb-form-item:hover {
|
|
||||||
> .general-schema-designer {
|
|
||||||
background: var(--colorBgSettingsHover) !important;
|
|
||||||
border: 0 !important;
|
|
||||||
top: -5px !important;
|
|
||||||
bottom: -5px !important;
|
|
||||||
left: -5px !important;
|
|
||||||
right: -5px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
> .general-schema-designer {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 999;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: none;
|
|
||||||
border: 2px solid var(--colorBorderSettingsHover);
|
|
||||||
pointer-events: none;
|
|
||||||
> .general-schema-designer-icons {
|
|
||||||
position: absolute;
|
|
||||||
right: 2px;
|
|
||||||
top: 2px;
|
|
||||||
line-height: 16px;
|
|
||||||
pointer-events: all;
|
|
||||||
.ant-space-item {
|
|
||||||
background-color: var(--colorSettings);
|
|
||||||
color: #fff;
|
|
||||||
line-height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
padding-left: 1px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Designer />
|
<Designer />
|
||||||
{props.children}
|
{props.children}
|
||||||
{render()}
|
{render()}
|
||||||
|
@ -1,15 +1,67 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import cls from 'classnames';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import cls from 'classnames';
|
||||||
|
|
||||||
|
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
||||||
import { SortableItem } from '../../common';
|
import { SortableItem } from '../../common';
|
||||||
import { useDesigner, useProps } from '../../hooks';
|
import { useDesigner, useProps } from '../../hooks';
|
||||||
import { useGetAriaLabelOfBlockItem } from './hooks/useGetAriaLabelOfBlockItem';
|
import { useGetAriaLabelOfBlockItem } from './hooks/useGetAriaLabelOfBlockItem';
|
||||||
import { useFieldSchema } from '@tachybase/schema';
|
|
||||||
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
position: relative;
|
||||||
|
&:hover {
|
||||||
|
> .general-schema-designer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.nb-form-item:hover {
|
||||||
|
> .general-schema-designer {
|
||||||
|
background: var(--colorBgSettingsHover) !important;
|
||||||
|
border: 0 !important;
|
||||||
|
top: -5px !important;
|
||||||
|
bottom: -5px !important;
|
||||||
|
left: -5px !important;
|
||||||
|
right: -5px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .general-schema-designer {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: none;
|
||||||
|
border: 2px solid var(--colorBorderSettingsHover);
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: var(--colorSettings);
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const BlockItem: React.FC<any> = withDynamicSchemaProps((props) => {
|
export const BlockItem: React.FC<any> = withDynamicSchemaProps((props) => {
|
||||||
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||||
const { className, children } = useProps(props);
|
const { className, children } = useProps(props);
|
||||||
|
const { styles } = useStyles();
|
||||||
|
|
||||||
const Designer = useDesigner();
|
const Designer = useDesigner();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
@ -19,54 +71,7 @@ export const BlockItem: React.FC<any> = withDynamicSchemaProps((props) => {
|
|||||||
<SortableItem
|
<SortableItem
|
||||||
role="button"
|
role="button"
|
||||||
aria-label={getAriaLabel()}
|
aria-label={getAriaLabel()}
|
||||||
className={cls(
|
className={cls('nb-block-item', className, styles.container)}
|
||||||
'nb-block-item',
|
|
||||||
className,
|
|
||||||
css`
|
|
||||||
position: relative;
|
|
||||||
&:hover {
|
|
||||||
> .general-schema-designer {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.nb-form-item:hover {
|
|
||||||
> .general-schema-designer {
|
|
||||||
background: var(--colorBgSettingsHover) !important;
|
|
||||||
border: 0 !important;
|
|
||||||
top: -5px !important;
|
|
||||||
bottom: -5px !important;
|
|
||||||
left: -5px !important;
|
|
||||||
right: -5px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
> .general-schema-designer {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 999;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: none;
|
|
||||||
border: 2px solid var(--colorBorderSettingsHover);
|
|
||||||
pointer-events: none;
|
|
||||||
> .general-schema-designer-icons {
|
|
||||||
position: absolute;
|
|
||||||
right: 2px;
|
|
||||||
top: 2px;
|
|
||||||
line-height: 16px;
|
|
||||||
pointer-events: all;
|
|
||||||
.ant-space-item {
|
|
||||||
background-color: var(--colorSettings);
|
|
||||||
color: #fff;
|
|
||||||
line-height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
padding-left: 1px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<Designer {...fieldSchema['x-toolbar-props']} />
|
<Designer {...fieldSchema['x-toolbar-props']} />
|
||||||
{children}
|
{children}
|
||||||
|
@ -1,9 +1,21 @@
|
|||||||
import { css } from '@emotion/css';
|
import React from 'react';
|
||||||
import { usePrefixCls } from '@tachybase/components';
|
import { usePrefixCls } from '@tachybase/components';
|
||||||
import { connect, mapProps, mapReadPretty } from '@tachybase/schema';
|
import { connect, mapProps, mapReadPretty } from '@tachybase/schema';
|
||||||
|
|
||||||
import { ColorPicker as AntdColorPicker } from 'antd';
|
import { ColorPicker as AntdColorPicker } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import React from 'react';
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
color: css`
|
||||||
|
display: inline-flex;
|
||||||
|
.ant-color-picker-trigger-disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const ColorPicker = connect(
|
export const ColorPicker = connect(
|
||||||
(props) => {
|
(props) => {
|
||||||
@ -48,20 +60,12 @@ export const ColorPicker = connect(
|
|||||||
}),
|
}),
|
||||||
mapReadPretty((props) => {
|
mapReadPretty((props) => {
|
||||||
const prefixCls = usePrefixCls('description-color-picker', props);
|
const prefixCls = usePrefixCls('description-color-picker', props);
|
||||||
|
const { styles } = useStyles();
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="color-picker-read-pretty"
|
aria-label="color-picker-read-pretty"
|
||||||
className={cls(
|
className={cls(prefixCls, styles.color, props.className)}
|
||||||
prefixCls,
|
|
||||||
css`
|
|
||||||
display: inline-flex;
|
|
||||||
.ant-color-picker-trigger-disabled {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
props.className,
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<AntdColorPicker disabled value={props.value} size="small" {...props} />
|
<AntdColorPicker disabled value={props.value} size="small" {...props} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,36 +1,44 @@
|
|||||||
import { css } from '@emotion/css';
|
import React, { useMemo } from 'react';
|
||||||
import { connect, mapReadPretty } from '@tachybase/schema';
|
import { connect, mapReadPretty } from '@tachybase/schema';
|
||||||
import { error } from '@tachybase/utils/client';
|
import { error } from '@tachybase/utils/client';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import cronstrue from 'cronstrue';
|
import cronstrue from 'cronstrue';
|
||||||
import React, { useMemo } from 'react';
|
|
||||||
import { CronProps, Cron as ReactCron } from 'react-js-cron';
|
import { CronProps, Cron as ReactCron } from 'react-js-cron';
|
||||||
import 'react-js-cron/dist/styles.css';
|
|
||||||
import { useAPIClient } from '../../../api-client';
|
import { useAPIClient } from '../../../api-client';
|
||||||
|
|
||||||
|
import 'react-js-cron/dist/styles.css';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
input: css`
|
||||||
|
.react-js-cron {
|
||||||
|
padding: 0.5em 0.5em 0 0.5em;
|
||||||
|
border: 1px dashed #ccc;
|
||||||
|
.react-js-cron-field {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin: 0 0.5em 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .react-js-cron-select {
|
||||||
|
margin: 0 0.5em 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const Input = (props: Omit<CronProps, 'setValue'> & { onChange: (value: string) => void }) => {
|
const Input = (props: Omit<CronProps, 'setValue'> & { onChange: (value: string) => void }) => {
|
||||||
const { onChange, ...rest } = props;
|
const { onChange, ...rest } = props;
|
||||||
|
const { styles } = useStyles();
|
||||||
return (
|
return (
|
||||||
<fieldset
|
<fieldset className={styles.input}>
|
||||||
className={css`
|
|
||||||
.react-js-cron {
|
|
||||||
padding: 0.5em 0.5em 0 0.5em;
|
|
||||||
border: 1px dashed #ccc;
|
|
||||||
.react-js-cron-field {
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
|
|
||||||
> span {
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin: 0 0.5em 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .react-js-cron-select {
|
|
||||||
margin: 0 0.5em 0 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<ReactCron setValue={onChange} locale={window['cronLocale']} {...rest} />
|
<ReactCron setValue={onChange} locale={window['cronLocale']} {...rest} />
|
||||||
</fieldset>
|
</fieldset>
|
||||||
);
|
);
|
||||||
|
@ -1,54 +1,57 @@
|
|||||||
import { css } from '@emotion/css';
|
import React, { createRef, forwardRef } from 'react';
|
||||||
import { useFieldSchema } from '@tachybase/schema';
|
import { useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
import { Button } from 'antd';
|
import { Button } from 'antd';
|
||||||
import React, { forwardRef, createRef } from 'react';
|
import { createStyles } from 'antd-style';
|
||||||
import { composeRef } from 'rc-util/lib/ref';
|
import { composeRef } from 'rc-util/lib/ref';
|
||||||
import { useCompile } from '../../hooks';
|
|
||||||
import { useTableBlockContext, useTableSelectorContext } from '../../../block-provider';
|
import { useTableBlockContext, useTableSelectorContext } from '../../../block-provider';
|
||||||
import { Icon } from '../../../icon';
|
import { Icon } from '../../../icon';
|
||||||
|
import { useCompile } from '../../hooks';
|
||||||
|
|
||||||
const actionDesignerCss = css`
|
const useStyles = createStyles(({ css }) => {
|
||||||
position: relative;
|
return {
|
||||||
&:hover {
|
designer: css`
|
||||||
.general-schema-designer {
|
position: relative;
|
||||||
display: block;
|
&:hover {
|
||||||
}
|
.general-schema-designer {
|
||||||
}
|
display: block;
|
||||||
.general-schema-designer {
|
}
|
||||||
position: absolute;
|
|
||||||
z-index: 999;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: none;
|
|
||||||
background: var(--colorBgSettingsHover);
|
|
||||||
border: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
> .general-schema-designer-icons {
|
|
||||||
position: absolute;
|
|
||||||
right: 2px;
|
|
||||||
top: 2px;
|
|
||||||
line-height: 16px;
|
|
||||||
pointer-events: all;
|
|
||||||
.ant-space-item {
|
|
||||||
background-color: var(--colorSettings);
|
|
||||||
color: #fff;
|
|
||||||
line-height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
padding-left: 1px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
}
|
||||||
}
|
.general-schema-designer {
|
||||||
}
|
position: absolute;
|
||||||
`;
|
z-index: 999;
|
||||||
|
display: none;
|
||||||
|
background: var(--colorBgSettingsHover);
|
||||||
|
border: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: var(--colorSettings);
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const InternalExpandAction = (props, ref) => {
|
const InternalExpandAction = (props, ref) => {
|
||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
|
const { styles } = useStyles();
|
||||||
const ctxSelector = useTableSelectorContext();
|
const ctxSelector = useTableSelectorContext();
|
||||||
const ctxBlock = useTableBlockContext();
|
const ctxBlock = useTableBlockContext();
|
||||||
const isTableSelector = schema.parent?.parent?.['x-decorator'] === 'TableSelectorProvider';
|
const isTableSelector = schema.parent?.parent?.['x-decorator'] === 'TableSelectorProvider';
|
||||||
@ -59,7 +62,7 @@ const InternalExpandAction = (props, ref) => {
|
|||||||
const buttonRef = composeRef(ref, internalRef);
|
const buttonRef = composeRef(ref, internalRef);
|
||||||
return (
|
return (
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
<div className={actionDesignerCss} ref={buttonRef as React.Ref<HTMLButtonElement>}>
|
<div className={styles.designer} ref={buttonRef as React.Ref<HTMLButtonElement>}>
|
||||||
{ctx?.params['tree'] && (
|
{ctx?.params['tree'] && (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -1,22 +1,38 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { createForm, Field, Form } from '@tachybase/schema';
|
|
||||||
import { observer, useField, useFieldSchema, useForm } from '@tachybase/schema';
|
|
||||||
import { flatten, unflatten } from '@tachybase/utils/client';
|
|
||||||
import { Button, Space } from 'antd';
|
|
||||||
import React, { createContext, useCallback, useContext, useMemo, useState } from 'react';
|
import React, { createContext, useCallback, useContext, useMemo, useState } from 'react';
|
||||||
|
import { createForm, Field, Form, observer, useField, useFieldSchema, useForm } from '@tachybase/schema';
|
||||||
|
import { flatten, unflatten } from '@tachybase/utils/client';
|
||||||
|
|
||||||
|
import { Button, Space } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
||||||
import { FormProvider, SchemaComponent } from '../../core';
|
import { FormProvider, SchemaComponent } from '../../core';
|
||||||
import { useDesignable } from '../../hooks';
|
import { useDesignable } from '../../hooks';
|
||||||
import { useProps } from '../../hooks/useProps';
|
import { useProps } from '../../hooks/useProps';
|
||||||
import { Action } from '../action';
|
import { Action } from '../action';
|
||||||
import { StablePopover } from '../popover';
|
import { StablePopover } from '../popover';
|
||||||
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
|
||||||
|
|
||||||
export const FilterActionContext = createContext<any>(null);
|
export const FilterActionContext = createContext<any>(null);
|
||||||
FilterActionContext.displayName = 'FilterActionContext';
|
FilterActionContext.displayName = 'FilterActionContext';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
width: 100%;
|
||||||
|
`,
|
||||||
|
button: css`
|
||||||
|
border-color: var(--colorSettings);
|
||||||
|
color: var(--colorSettings);
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const FilterAction = withDynamicSchemaProps(
|
export const FilterAction = withDynamicSchemaProps(
|
||||||
observer((props: any) => {
|
observer((props: any) => {
|
||||||
|
const { styles } = useStyles();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const field = useField<Field>();
|
const field = useField<Field>();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
@ -55,13 +71,7 @@ export const FilterAction = withDynamicSchemaProps(
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div
|
<div className={styles.container}>
|
||||||
className={css`
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
width: 100%;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<Space>
|
<Space>
|
||||||
<SaveConditions />
|
<SaveConditions />
|
||||||
<Button
|
<Button
|
||||||
@ -104,16 +114,14 @@ const SaveConditions = () => {
|
|||||||
const { fieldSchema, field, designable, dn } = useContext(FilterActionContext);
|
const { fieldSchema, field, designable, dn } = useContext(FilterActionContext);
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { styles } = useStyles();
|
||||||
if (!designable) {
|
if (!designable) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
type={'dashed'}
|
type={'dashed'}
|
||||||
className={css`
|
className={styles.button}
|
||||||
border-color: var(--colorSettings);
|
|
||||||
color: var(--colorSettings);
|
|
||||||
`}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const defaultValue = { ...form.values.filter };
|
const defaultValue = { ...form.values.filter };
|
||||||
fieldSchema.default = defaultValue;
|
fieldSchema.default = defaultValue;
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { CloseCircleOutlined } from '@ant-design/icons';
|
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { observer } from '@tachybase/schema';
|
|
||||||
import { Cascader, Select, Space } from 'antd';
|
|
||||||
import React, { useCallback, useContext, useMemo } from 'react';
|
import React, { useCallback, useContext, useMemo } from 'react';
|
||||||
|
import { observer } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { CloseCircleOutlined } from '@ant-design/icons';
|
||||||
|
import { Cascader, Select, Space } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { useCompile } from '../..';
|
import { useCompile } from '../..';
|
||||||
import { DynamicComponent } from './DynamicComponent';
|
|
||||||
import { RemoveConditionContext } from './context';
|
import { RemoveConditionContext } from './context';
|
||||||
|
import { DynamicComponent } from './DynamicComponent';
|
||||||
import { useValues } from './useValues';
|
import { useValues } from './useValues';
|
||||||
|
|
||||||
export const FilterItem = observer(
|
export const FilterItem = observer(
|
||||||
@ -55,12 +56,8 @@ export const FilterItem = observer(
|
|||||||
<div style={style} className="nc-filter-item">
|
<div style={style} className="nc-filter-item">
|
||||||
<Space>
|
<Space>
|
||||||
<Cascader
|
<Cascader
|
||||||
// @ts-ignore
|
|
||||||
role="button"
|
|
||||||
data-testid="select-filter-field"
|
data-testid="select-filter-field"
|
||||||
className={css`
|
style={{ width: '160px' }}
|
||||||
width: 160px;
|
|
||||||
`}
|
|
||||||
fieldNames={fieldNames}
|
fieldNames={fieldNames}
|
||||||
changeOnSelect={false}
|
changeOnSelect={false}
|
||||||
value={dataIndex}
|
value={dataIndex}
|
||||||
@ -69,12 +66,8 @@ export const FilterItem = observer(
|
|||||||
placeholder={t('Select field')}
|
placeholder={t('Select field')}
|
||||||
/>
|
/>
|
||||||
<Select
|
<Select
|
||||||
// @ts-ignore
|
|
||||||
role="button"
|
|
||||||
data-testid="select-filter-operator"
|
data-testid="select-filter-operator"
|
||||||
className={css`
|
style={{ minWidth: '110px' }}
|
||||||
min-width: 110px;
|
|
||||||
`}
|
|
||||||
popupMatchSelectWidth={false}
|
popupMatchSelectWidth={false}
|
||||||
value={operator?.value}
|
value={operator?.value}
|
||||||
options={compile(operators)}
|
options={compile(operators)}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { useFieldSchema, useForm } from '@tachybase/schema';
|
|
||||||
import { Button } from 'antd';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useFieldSchema, useForm } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { Button } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { useDesignable } from '../../hooks';
|
import { useDesignable } from '../../hooks';
|
||||||
|
|
||||||
export const SaveDefaultValue = (props) => {
|
export const SaveDefaultValue = (props) => {
|
||||||
@ -15,10 +16,10 @@ export const SaveDefaultValue = (props) => {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className={css`
|
style={{
|
||||||
border-color: var(--colorSettings);
|
borderColor: 'var(--colorSettings)',
|
||||||
color: var(--colorSettings);
|
color: 'var(--colorSettings)',
|
||||||
`}
|
}}
|
||||||
type={'dashed'}
|
type={'dashed'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const filterSchema = fieldSchema?.parent?.parent?.parent?.properties?.filter;
|
const filterSchema = fieldSchema?.parent?.parent?.parent?.properties?.filter;
|
||||||
@ -34,7 +35,6 @@ export const SaveDefaultValue = (props) => {
|
|||||||
});
|
});
|
||||||
dn.refresh();
|
dn.refresh();
|
||||||
filterSchema.default = defaultValue;
|
filterSchema.default = defaultValue;
|
||||||
console.log('filterSchema', defaultValue);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('Save conditions')}
|
{t('Save conditions')}
|
||||||
|
@ -1,25 +1,47 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
|
||||||
import { FormItem as Item } from '@tachybase/components';
|
|
||||||
import { Field } from '@tachybase/schema';
|
|
||||||
import { observer, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import React, { useEffect, useMemo } from 'react';
|
import React, { useEffect, useMemo } from 'react';
|
||||||
|
import { FormItem as Item } from '@tachybase/components';
|
||||||
|
import { Field, observer, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import cx from 'classnames';
|
||||||
|
|
||||||
import { ACLCollectionFieldProvider } from '../../../acl/ACLProvider';
|
import { ACLCollectionFieldProvider } from '../../../acl/ACLProvider';
|
||||||
import { useApp } from '../../../application';
|
import { useApp } from '../../../application';
|
||||||
import { useFormActiveFields } from '../../../block-provider/hooks/useFormActiveFields';
|
import { useFormActiveFields } from '../../../block-provider/hooks/useFormActiveFields';
|
||||||
import { Collection_deprecated } from '../../../collection-manager';
|
import { Collection_deprecated } from '../../../collection-manager';
|
||||||
|
import { CollectionFieldProvider, useContextConfigSetting } from '../../../data-source';
|
||||||
import { GeneralSchemaDesigner } from '../../../schema-settings';
|
import { GeneralSchemaDesigner } from '../../../schema-settings';
|
||||||
import { useVariables } from '../../../variables';
|
import { useVariables } from '../../../variables';
|
||||||
import useContextVariable from '../../../variables/hooks/useContextVariable';
|
import useContextVariable from '../../../variables/hooks/useContextVariable';
|
||||||
import { BlockItem } from '../block-item';
|
import { BlockItem } from '../block-item';
|
||||||
import { HTMLEncode } from '../input/shared';
|
import { HTMLEncode } from '../input/shared';
|
||||||
import { FilterFormDesigner } from './FormItem.FilterFormDesigner';
|
import { FilterFormDesigner } from './FormItem.FilterFormDesigner';
|
||||||
import { useEnsureOperatorsValid } from './SchemaSettingOptions';
|
|
||||||
import useLazyLoadDisplayAssociationFieldsOfForm from './hooks/useLazyLoadDisplayAssociationFieldsOfForm';
|
import useLazyLoadDisplayAssociationFieldsOfForm from './hooks/useLazyLoadDisplayAssociationFieldsOfForm';
|
||||||
import useParseDefaultValue from './hooks/useParseDefaultValue';
|
import useParseDefaultValue from './hooks/useParseDefaultValue';
|
||||||
import { CollectionFieldProvider, useContextConfigSetting } from '../../../data-source';
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
space: css`
|
||||||
|
& .ant-space {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
hide: css`
|
||||||
|
> .ant-formily-item-label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
row: css`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: baseline;
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const FormItem: any = observer(
|
export const FormItem: any = observer(
|
||||||
(props: any) => {
|
(props: any) => {
|
||||||
|
const { styles } = useStyles();
|
||||||
const { layoutDirection: selfLayoutDirection } = props;
|
const { layoutDirection: selfLayoutDirection } = props;
|
||||||
const field = useField<Field>();
|
const field = useField<Field>();
|
||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
@ -57,24 +79,12 @@ export const FormItem: any = observer(
|
|||||||
}, [field.description]);
|
}, [field.description]);
|
||||||
const className = useMemo(() => {
|
const className = useMemo(() => {
|
||||||
return cx(
|
return cx(
|
||||||
css`
|
styles.space,
|
||||||
& .ant-space {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
{
|
{
|
||||||
[css`
|
[styles.hide]: showTitle === false,
|
||||||
> .ant-formily-item-label {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
`]: showTitle === false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
[css`
|
[styles.row]: finishLayoutDirection === 'row',
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: baseline;
|
|
||||||
`]: finishLayoutDirection === 'row',
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}, [showTitle]);
|
}, [showTitle]);
|
||||||
|
@ -1,14 +1,29 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { FormLayout } from '@tachybase/components';
|
|
||||||
import { createForm, Field, Form as FormilyForm, onFieldInit, onFormInputChange } from '@tachybase/schema';
|
|
||||||
import { FieldContext, FormContext, observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import { reaction } from '@tachybase/schema';
|
|
||||||
import { uid } from '@tachybase/schema';
|
|
||||||
import { getValuesByPath } from '@tachybase/utils/client';
|
|
||||||
import { ConfigProvider, Spin } from 'antd';
|
|
||||||
import React, { useEffect, useMemo } from 'react';
|
import React, { useEffect, useMemo } from 'react';
|
||||||
|
import { FormLayout } from '@tachybase/components';
|
||||||
|
import {
|
||||||
|
createForm,
|
||||||
|
Field,
|
||||||
|
FieldContext,
|
||||||
|
FormContext,
|
||||||
|
Form as FormilyForm,
|
||||||
|
observer,
|
||||||
|
onFieldInit,
|
||||||
|
onFormInputChange,
|
||||||
|
reaction,
|
||||||
|
RecursionField,
|
||||||
|
uid,
|
||||||
|
useField,
|
||||||
|
useFieldSchema,
|
||||||
|
} from '@tachybase/schema';
|
||||||
|
import { getValuesByPath } from '@tachybase/utils/client';
|
||||||
|
|
||||||
|
import { ConfigProvider, Spin } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
import { useActionContext } from '..';
|
import { useActionContext } from '..';
|
||||||
import { useAttach, useComponent } from '../..';
|
import { useAttach, useComponent } from '../..';
|
||||||
|
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
||||||
|
import { useTemplateBlockContext } from '../../../block-provider/TemplateBlockProvider';
|
||||||
import { ActionType } from '../../../schema-settings/LinkageRules/type';
|
import { ActionType } from '../../../schema-settings/LinkageRules/type';
|
||||||
import { useLocalVariables, useVariables } from '../../../variables';
|
import { useLocalVariables, useVariables } from '../../../variables';
|
||||||
import { VariableOption, VariablesContextType } from '../../../variables/types';
|
import { VariableOption, VariablesContextType } from '../../../variables/types';
|
||||||
@ -18,13 +33,21 @@ import { isVariable, REGEX_OF_VARIABLE } from '../../../variables/utils/isVariab
|
|||||||
import { getInnermostKeyAndValue, getTargetField } from '../../common/utils/uitls';
|
import { getInnermostKeyAndValue, getTargetField } from '../../common/utils/uitls';
|
||||||
import { useProps } from '../../hooks/useProps';
|
import { useProps } from '../../hooks/useProps';
|
||||||
import { collectFieldStateOfLinkageRules, getTempFieldState } from './utils';
|
import { collectFieldStateOfLinkageRules, getTempFieldState } from './utils';
|
||||||
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
|
||||||
import { useTemplateBlockContext } from '../../../block-provider/TemplateBlockProvider';
|
|
||||||
|
|
||||||
export interface FormProps {
|
export interface FormProps {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
.ant-formily-item-feedback-layout-loose {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const FormComponent: React.FC<FormProps> = (props) => {
|
const FormComponent: React.FC<FormProps> = (props) => {
|
||||||
const { form, children, ...others } = props;
|
const { form, children, ...others } = props;
|
||||||
const field = useField();
|
const field = useField();
|
||||||
@ -203,6 +226,7 @@ export const Form: React.FC<FormProps> & {
|
|||||||
} = withDynamicSchemaProps(
|
} = withDynamicSchemaProps(
|
||||||
observer((props) => {
|
observer((props) => {
|
||||||
const field = useField<Field>();
|
const field = useField<Field>();
|
||||||
|
const { styles } = useStyles();
|
||||||
|
|
||||||
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||||
const { form, disabled, ...others } = useProps(props);
|
const { form, disabled, ...others } = useProps(props);
|
||||||
@ -210,14 +234,7 @@ export const Form: React.FC<FormProps> & {
|
|||||||
const formDisabled = disabled || field.disabled;
|
const formDisabled = disabled || field.disabled;
|
||||||
return (
|
return (
|
||||||
<ConfigProvider componentDisabled={formDisabled}>
|
<ConfigProvider componentDisabled={formDisabled}>
|
||||||
<form
|
<form onSubmit={(e) => e.preventDefault()} className={styles.container}>
|
||||||
onSubmit={(e) => e.preventDefault()}
|
|
||||||
className={css`
|
|
||||||
.ant-formily-item-feedback-layout-loose {
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<Spin spinning={field.loading || false}>
|
<Spin spinning={field.loading || false}>
|
||||||
{form ? (
|
{form ? (
|
||||||
<WithForm form={form} {...others} disabled={formDisabled} />
|
<WithForm form={form} {...others} disabled={formDisabled} />
|
||||||
|
@ -1,23 +1,39 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { useCollection } from '@tachybase/client';
|
|
||||||
import { ObjectField } from '@tachybase/schema';
|
|
||||||
import { useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import { Card } from 'antd';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useCollection } from '@tachybase/client';
|
||||||
|
import { ObjectField, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { Card } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
||||||
import { useCollectionParentRecordData } from '../../../data-source/collection-record/CollectionRecordProvider';
|
import { useCollectionParentRecordData } from '../../../data-source/collection-record/CollectionRecordProvider';
|
||||||
import { RecordProvider } from '../../../record-provider';
|
import { RecordProvider } from '../../../record-provider';
|
||||||
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import { useGridCardDetailUrl } from './hooks';
|
import { useGridCardDetailUrl } from './hooks';
|
||||||
|
|
||||||
const itemCss = css`
|
const useStyles = createStyles(({ css }) => {
|
||||||
display: flex;
|
return {
|
||||||
width: 100%;
|
itemCss: css`
|
||||||
height: 100%;
|
display: flex;
|
||||||
flex-direction: column;
|
width: 100%;
|
||||||
justify-content: space-between;
|
height: 100%;
|
||||||
gap: 8px;
|
flex-direction: column;
|
||||||
`;
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
`,
|
||||||
|
card: css`
|
||||||
|
/* background-color: re/d; */
|
||||||
|
height: 100%;
|
||||||
|
> .ant-card-body {
|
||||||
|
padding: 24px 24px 0px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.nb-action-bar {
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const GridCardItem = withDynamicSchemaProps((props) => {
|
export const GridCardItem = withDynamicSchemaProps((props) => {
|
||||||
const collection = useCollection();
|
const collection = useCollection();
|
||||||
@ -25,6 +41,7 @@ export const GridCardItem = withDynamicSchemaProps((props) => {
|
|||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const parentRecordData = useCollectionParentRecordData();
|
const parentRecordData = useCollectionParentRecordData();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { styles } = useStyles();
|
||||||
const detailUrl = useGridCardDetailUrl({ collection, field, fieldSchema });
|
const detailUrl = useGridCardDetailUrl({ collection, field, fieldSchema });
|
||||||
// XXX: 实现的有些丑陋, 需要想想有没有更好的办法
|
// XXX: 实现的有些丑陋, 需要想想有没有更好的办法
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
@ -37,23 +54,8 @@ export const GridCardItem = withDynamicSchemaProps((props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card role="button" aria-label="grid-card-item" className={styles.card} onClick={handleClick}>
|
||||||
role="button"
|
<div className={styles.itemCss}>
|
||||||
aria-label="grid-card-item"
|
|
||||||
className={css`
|
|
||||||
/* background-color: re/d; */
|
|
||||||
height: 100%;
|
|
||||||
> .ant-card-body {
|
|
||||||
padding: 24px 24px 0px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.nb-action-bar {
|
|
||||||
padding: 5px 0;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
onClick={handleClick}
|
|
||||||
>
|
|
||||||
<div className={itemCss}>
|
|
||||||
{/* @ts-ignore */}
|
{/* @ts-ignore */}
|
||||||
<RecordProvider record={field.value} parent={parentRecordData}>
|
<RecordProvider record={field.value} parent={parentRecordData}>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
|
||||||
import { ArrayField } from '@tachybase/schema';
|
|
||||||
import { RecursionField, Schema, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import { List as AntdList, Col, PaginationProps } from 'antd';
|
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { ArrayField, RecursionField, Schema, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { List as AntdList, Col, PaginationProps } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import cx from 'classnames';
|
||||||
|
|
||||||
|
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
||||||
import { SortableItem } from '../../common';
|
import { SortableItem } from '../../common';
|
||||||
|
import { InfiniteScroll } from '../../common/infinite-scroll/infinite-scroll';
|
||||||
import { SchemaComponentOptions } from '../../core';
|
import { SchemaComponentOptions } from '../../core';
|
||||||
import { useDesigner, useProps } from '../../hooks';
|
import { useDesigner, useProps } from '../../hooks';
|
||||||
import { GridCardBlockProvider, useGridCardBlockContext, useGridCardItemProps } from './GridCard.Decorator';
|
import { GridCardBlockProvider, useGridCardBlockContext, useGridCardItemProps } from './GridCard.Decorator';
|
||||||
@ -11,8 +15,6 @@ import { GridCardDesigner } from './GridCard.Designer';
|
|||||||
import { GridCardItem } from './GridCard.Item';
|
import { GridCardItem } from './GridCard.Item';
|
||||||
import { useGridCardActionBarProps } from './hooks';
|
import { useGridCardActionBarProps } from './hooks';
|
||||||
import { defaultColumnCount, pageSizeOptions } from './options';
|
import { defaultColumnCount, pageSizeOptions } from './options';
|
||||||
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
|
||||||
import { InfiniteScroll } from '../../common/infinite-scroll/infinite-scroll';
|
|
||||||
|
|
||||||
const rowGutter = {
|
const rowGutter = {
|
||||||
md: 12,
|
md: 12,
|
||||||
@ -20,46 +22,51 @@ const rowGutter = {
|
|||||||
xs: 5,
|
xs: 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
const designerCss = css`
|
const useStyles = createStyles(({ css }) => {
|
||||||
width: 100%;
|
return {
|
||||||
&:hover {
|
designer: css`
|
||||||
> .general-schema-designer {
|
width: 100%;
|
||||||
display: block;
|
&:hover {
|
||||||
}
|
> .general-schema-designer {
|
||||||
}
|
display: block;
|
||||||
|
}
|
||||||
> .general-schema-designer {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 999;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: none;
|
|
||||||
background: var(--colorBgSettingsHover);
|
|
||||||
border: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
> .general-schema-designer-icons {
|
|
||||||
position: absolute;
|
|
||||||
right: 2px;
|
|
||||||
top: 2px;
|
|
||||||
line-height: 16px;
|
|
||||||
pointer-events: all;
|
|
||||||
.ant-space-item {
|
|
||||||
background-color: var(--colorSettings);
|
|
||||||
color: #fff;
|
|
||||||
line-height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
padding-left: 1px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
> .general-schema-designer {
|
||||||
`;
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: none;
|
||||||
|
background: var(--colorBgSettingsHover);
|
||||||
|
border: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: var(--colorSettings);
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const InternalGridCard = (props) => {
|
const InternalGridCard = (props) => {
|
||||||
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||||
const { columnCount: columnCountProp, pagination } = useProps(props);
|
const { columnCount: columnCountProp, pagination } = useProps(props);
|
||||||
|
const { styles } = useStyles();
|
||||||
const { service, columnCount: _columnCount = defaultColumnCount, needInfiniteScroll } = useGridCardBlockContext();
|
const { service, columnCount: _columnCount = defaultColumnCount, needInfiniteScroll } = useGridCardBlockContext();
|
||||||
const columnCount = columnCountProp || _columnCount;
|
const columnCount = columnCountProp || _columnCount;
|
||||||
const { run, params } = service;
|
const { run, params } = service;
|
||||||
@ -132,7 +139,7 @@ const InternalGridCard = (props) => {
|
|||||||
useGridCardActionBarProps,
|
useGridCardActionBarProps,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SortableItem className={cx('nb-card-list', designerCss)}>
|
<SortableItem className={cx('nb-card-list', styles.designer)}>
|
||||||
<AntdList
|
<AntdList
|
||||||
pagination={
|
pagination={
|
||||||
!meta || meta.count <= meta.pageSize || needInfiniteScroll
|
!meta || meta.count <= meta.pageSize || needInfiniteScroll
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { Icon, icons } from '../../../icon';
|
|
||||||
import { Tooltip } from 'antd';
|
import { Tooltip } from 'antd';
|
||||||
import { css } from '@emotion/css';
|
|
||||||
|
import { Icon, icons } from '../../../icon';
|
||||||
|
|
||||||
export const IconFilterList = (props) => {
|
export const IconFilterList = (props) => {
|
||||||
const { currentKey, filterKey, onChange, changePop } = props;
|
const { currentKey, filterKey, onChange, changePop } = props;
|
||||||
@ -24,10 +25,12 @@ export const IconFilterList = (props) => {
|
|||||||
{[...iconKeysByFilter.keys()].map((key) => (
|
{[...iconKeysByFilter.keys()].map((key) => (
|
||||||
<span
|
<span
|
||||||
key={key}
|
key={key}
|
||||||
className={css`
|
style={{
|
||||||
background-color: ${currentKey == key ? '#9bb0d393' : ''};
|
fontSize: 18,
|
||||||
`}
|
marginRight: 10,
|
||||||
style={{ fontSize: 18, marginRight: 10, cursor: 'pointer' }}
|
cursor: 'pointer',
|
||||||
|
backgroundColor: currentKey == key ? '#9bb0d393' : '',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
destroyTooltipOnHide
|
destroyTooltipOnHide
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { Field } from '@tachybase/schema';
|
import React, { Ref, useEffect, useState } from 'react';
|
||||||
import { useField } from '@tachybase/schema';
|
import { Field, useField } from '@tachybase/schema';
|
||||||
|
|
||||||
import { Input } from 'antd';
|
import { Input } from 'antd';
|
||||||
import { TextAreaProps } from 'antd/es/input';
|
import { TextAreaProps } from 'antd/es/input';
|
||||||
import React, { useState, useEffect, Ref } from 'react';
|
|
||||||
import { cx, css } from '@emotion/css';
|
|
||||||
|
|
||||||
export type JSONTextAreaProps = TextAreaProps & { value?: string; space?: number };
|
export type JSONTextAreaProps = TextAreaProps & { value?: string; space?: number };
|
||||||
|
|
||||||
@ -25,13 +24,11 @@ export const Json = React.forwardRef<typeof Input.TextArea, JSONTextAreaProps>(
|
|||||||
return (
|
return (
|
||||||
<Input.TextArea
|
<Input.TextArea
|
||||||
{...props}
|
{...props}
|
||||||
className={cx(
|
style={{
|
||||||
css`
|
fontSize: '80%',
|
||||||
font-size: 80%;
|
fontFamily: "Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace",
|
||||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
...props.style,
|
||||||
`,
|
}}
|
||||||
props.className,
|
|
||||||
)}
|
|
||||||
ref={ref}
|
ref={ref}
|
||||||
value={text}
|
value={text}
|
||||||
onChange={(ev) => {
|
onChange={(ev) => {
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
import React from 'react';
|
||||||
|
import { usePrefixCls } from '@tachybase/components';
|
||||||
|
|
||||||
import { Typography } from 'antd';
|
import { Typography } from 'antd';
|
||||||
import { InputProps, TextAreaProps } from 'antd/es/input';
|
import { InputProps, TextAreaProps } from 'antd/es/input';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import React from 'react';
|
|
||||||
import { useCompile } from '../..';
|
import { useCompile } from '../..';
|
||||||
import { EllipsisWithTooltip } from './EllipsisWithTooltip';
|
import { EllipsisWithTooltip } from './EllipsisWithTooltip';
|
||||||
import { HTMLEncode } from './shared';
|
import { HTMLEncode } from './shared';
|
||||||
import { usePrefixCls } from '@tachybase/components';
|
|
||||||
|
|
||||||
export const ReadPretty = () => null;
|
export const ReadPretty = () => null;
|
||||||
|
|
||||||
@ -121,26 +122,6 @@ const _URL = (props: InputProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const _JSON = (props: TextAreaProps & { space: number }) => {
|
|
||||||
const prefixCls = usePrefixCls('json', props);
|
|
||||||
return (
|
|
||||||
<pre
|
|
||||||
className={cx(
|
|
||||||
prefixCls,
|
|
||||||
props.className,
|
|
||||||
css`
|
|
||||||
margin-bottom: 0;
|
|
||||||
line-height: 1.5;
|
|
||||||
font-size: 90%;
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
style={props.style}
|
|
||||||
>
|
|
||||||
{props.value != null ? JSON.stringify(props.value, null, props.space ?? 2) : ''}
|
|
||||||
</pre>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
ReadPretty.Input = _Input;
|
ReadPretty.Input = _Input;
|
||||||
ReadPretty.TextArea = _TextArea;
|
ReadPretty.TextArea = _TextArea;
|
||||||
ReadPretty.URL = _URL;
|
ReadPretty.URL = _URL;
|
||||||
|
@ -1,17 +1,32 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
|
||||||
import { FormLayout } from '@tachybase/components';
|
|
||||||
import { createForm } from '@tachybase/schema';
|
|
||||||
import { FormContext, useField } from '@tachybase/schema';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import React, { createContext, useContext, useEffect, useMemo } from 'react';
|
import React, { createContext, useContext, useEffect, useMemo } from 'react';
|
||||||
import { BlockProvider, useBlockRequestContext, useParsedFilter } from '../../../block-provider';
|
import { FormLayout } from '@tachybase/components';
|
||||||
|
import { createForm, FormContext, useField } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
||||||
|
import { BlockProvider, useBlockRequestContext, useParsedFilter } from '../../../block-provider';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
.ant-description-input {
|
||||||
|
line-height: 34px;
|
||||||
|
}
|
||||||
|
.ant-formily-item-feedback-layout-loose {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const ListBlockContext = createContext<any>({});
|
export const ListBlockContext = createContext<any>({});
|
||||||
ListBlockContext.displayName = 'ListBlockContext';
|
ListBlockContext.displayName = 'ListBlockContext';
|
||||||
|
|
||||||
const InternalListBlockProvider = (props) => {
|
const InternalListBlockProvider = (props) => {
|
||||||
const { resource, service } = useBlockRequestContext();
|
const { resource, service } = useBlockRequestContext();
|
||||||
|
const { styles } = useStyles();
|
||||||
|
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const form = useMemo(() => {
|
const form = useMemo(() => {
|
||||||
@ -35,18 +50,7 @@ const InternalListBlockProvider = (props) => {
|
|||||||
>
|
>
|
||||||
<FormContext.Provider value={form}>
|
<FormContext.Provider value={form}>
|
||||||
<FormLayout layout={'vertical'}>
|
<FormLayout layout={'vertical'}>
|
||||||
<div
|
<div className={styles.container}>{props.children}</div>
|
||||||
className={cx(css`
|
|
||||||
.ant-description-input {
|
|
||||||
line-height: 34px;
|
|
||||||
}
|
|
||||||
.ant-formily-item-feedback-layout-loose {
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
`)}
|
|
||||||
>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
</FormLayout>
|
</FormLayout>
|
||||||
</FormContext.Provider>
|
</FormContext.Provider>
|
||||||
</ListBlockContext.Provider>
|
</ListBlockContext.Provider>
|
||||||
|
@ -1,30 +1,32 @@
|
|||||||
import { ObjectField } from '@tachybase/schema';
|
|
||||||
import { useField } from '@tachybase/schema';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { css, cx } from '@emotion/css';
|
import { ObjectField, useField } from '@tachybase/schema';
|
||||||
import { useDesignable } from '../../hooks';
|
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
||||||
import { useCollectionParentRecordData } from '../../../data-source/collection-record/CollectionRecordProvider';
|
import { useCollectionParentRecordData } from '../../../data-source/collection-record/CollectionRecordProvider';
|
||||||
import { RecordProvider } from '../../../record-provider';
|
import { RecordProvider } from '../../../record-provider';
|
||||||
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
import { useDesignable } from '../../hooks';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }, props: { designable: boolean }) => {
|
||||||
|
return {
|
||||||
|
item: css`
|
||||||
|
.nb-action-bar {
|
||||||
|
gap: 20px !important;
|
||||||
|
margin-top: ${props.designable ? '20px' : '0px'};
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const ListItem = withDynamicSchemaProps((props) => {
|
export const ListItem = withDynamicSchemaProps((props) => {
|
||||||
const field = useField<ObjectField>();
|
const field = useField<ObjectField>();
|
||||||
const { designable } = useDesignable();
|
const { designable } = useDesignable();
|
||||||
|
const { styles } = useStyles({ designable });
|
||||||
const parentRecordData = useCollectionParentRecordData();
|
const parentRecordData = useCollectionParentRecordData();
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={classnames(props.className, ['itemCss', styles.item])}>
|
||||||
className={cx(classnames(props.className), [
|
|
||||||
'itemCss',
|
|
||||||
css`
|
|
||||||
.nb-action-bar {
|
|
||||||
gap: 20px !important;
|
|
||||||
margin-top: ${designable ? '20px' : '0px'};
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
])}
|
|
||||||
>
|
|
||||||
<RecordProvider record={field.value} parent={parentRecordData}>
|
<RecordProvider record={field.value} parent={parentRecordData}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</RecordProvider>
|
</RecordProvider>
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
import { cx } from '@emotion/css';
|
|
||||||
import { ArrayField } from '@tachybase/schema';
|
|
||||||
import { RecursionField, Schema, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import { List as AntdList, PaginationProps } from 'antd';
|
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
|
import { ArrayField, RecursionField, Schema, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { List as AntdList, PaginationProps } from 'antd';
|
||||||
|
import cx from 'classnames';
|
||||||
|
|
||||||
|
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
||||||
import { SortableItem } from '../../common';
|
import { SortableItem } from '../../common';
|
||||||
import { SchemaComponentOptions } from '../../core';
|
import { SchemaComponentOptions } from '../../core';
|
||||||
import { useDesigner } from '../../hooks';
|
import { useDesigner } from '../../hooks';
|
||||||
|
import { useListActionBarProps } from './hooks';
|
||||||
import { ListBlockProvider, useListBlockContext, useListItemProps } from './List.Decorator';
|
import { ListBlockProvider, useListBlockContext, useListItemProps } from './List.Decorator';
|
||||||
import { ListDesigner } from './List.Designer';
|
import { ListDesigner } from './List.Designer';
|
||||||
import { ListItem } from './List.Item';
|
import { ListItem } from './List.Item';
|
||||||
import useStyles from './List.style';
|
import useStyles from './List.style';
|
||||||
import { useListActionBarProps } from './hooks';
|
|
||||||
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
|
||||||
|
|
||||||
const InternalList = (props) => {
|
const InternalList = (props) => {
|
||||||
const { service } = useListBlockContext();
|
const { service } = useListBlockContext();
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import { TreeSelect } from '@tachybase/components';
|
|
||||||
import { Field, onFieldChange } from '@tachybase/schema';
|
|
||||||
import { ISchema, Schema, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { TreeSelect } from '@tachybase/components';
|
||||||
|
import { Field, ISchema, onFieldChange, Schema, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { message } from 'antd';
|
||||||
|
import { saveAs } from 'file-saver';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { findByUid } from '.';
|
import { findByUid } from '.';
|
||||||
import { createDesignable } from '../..';
|
import { createDesignable } from '../..';
|
||||||
import {
|
import {
|
||||||
@ -15,8 +18,6 @@ import {
|
|||||||
useAPIClient,
|
useAPIClient,
|
||||||
useDesignable,
|
useDesignable,
|
||||||
} from '../../../';
|
} from '../../../';
|
||||||
import { message } from 'antd';
|
|
||||||
import { saveAs } from 'file-saver';
|
|
||||||
|
|
||||||
const toItems = (properties = {}) => {
|
const toItems = (properties = {}) => {
|
||||||
const items = [];
|
const items = [];
|
||||||
|
@ -0,0 +1,160 @@
|
|||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
|
export const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
subMenuDesignerCss: css`
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: -24px;
|
||||||
|
margin-right: -34px;
|
||||||
|
padding: 0 34px 0 24px;
|
||||||
|
width: calc(100% + 58px);
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
&:hover {
|
||||||
|
> .general-schema-designer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.nb-action-link {
|
||||||
|
> .general-schema-designer {
|
||||||
|
top: -10px;
|
||||||
|
bottom: -10px;
|
||||||
|
left: -10px;
|
||||||
|
right: -10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .general-schema-designer {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: none;
|
||||||
|
background: var(--colorBgSettingsHover);
|
||||||
|
border: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: var(--colorSettings);
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
|
||||||
|
designerCss: css`
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: -20px;
|
||||||
|
margin-right: -20px;
|
||||||
|
padding: 0 20px;
|
||||||
|
width: calc(100% + 40px);
|
||||||
|
height: 100%;
|
||||||
|
&:hover {
|
||||||
|
> .general-schema-designer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.nb-action-link {
|
||||||
|
> .general-schema-designer {
|
||||||
|
top: -10px;
|
||||||
|
bottom: -10px;
|
||||||
|
left: -10px;
|
||||||
|
right: -10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .general-schema-designer {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: none;
|
||||||
|
background: var(--colorBgSettingsHover);
|
||||||
|
border: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: var(--colorSettings);
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
|
||||||
|
headerMenuClass: css`
|
||||||
|
.ant-menu-item:hover {
|
||||||
|
> .ant-menu-title-content > div {
|
||||||
|
.general-schema-designer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
|
||||||
|
sideMenuClass: css`
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
.ant-menu-item {
|
||||||
|
> .ant-menu-title-content {
|
||||||
|
height: 100%;
|
||||||
|
margin-left: -24px;
|
||||||
|
margin-right: -16px;
|
||||||
|
padding: 0 16px 0 24px;
|
||||||
|
> div {
|
||||||
|
> .general-schema-designer {
|
||||||
|
right: 6px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-menu-submenu-title {
|
||||||
|
.ant-menu-title-content {
|
||||||
|
height: 100%;
|
||||||
|
margin-left: -24px;
|
||||||
|
margin-right: -34px;
|
||||||
|
padding: 0 34px 0 24px;
|
||||||
|
> div {
|
||||||
|
> .general-schema-designer {
|
||||||
|
right: 6px !important;
|
||||||
|
}
|
||||||
|
> span.anticon {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
|
||||||
|
menuItemClass: css`
|
||||||
|
:active {
|
||||||
|
background: inherit;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
@ -1,182 +1,29 @@
|
|||||||
import { css } from '@emotion/css';
|
import React, { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
FieldContext,
|
FieldContext,
|
||||||
observer,
|
observer,
|
||||||
RecursionField,
|
RecursionField,
|
||||||
SchemaContext,
|
SchemaContext,
|
||||||
SchemaExpressionScopeContext,
|
SchemaExpressionScopeContext,
|
||||||
|
uid,
|
||||||
useField,
|
useField,
|
||||||
useFieldSchema,
|
useFieldSchema,
|
||||||
} from '@tachybase/schema';
|
} from '@tachybase/schema';
|
||||||
import { uid } from '@tachybase/schema';
|
|
||||||
import { error } from '@tachybase/utils/client';
|
import { error } from '@tachybase/utils/client';
|
||||||
|
|
||||||
import { Menu as AntdMenu, MenuProps } from 'antd';
|
import { Menu as AntdMenu, MenuProps } from 'antd';
|
||||||
import React, { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { createDesignable, DndContext, SortableItem, useDesignable, useDesigner } from '../..';
|
import { createDesignable, DndContext, SortableItem, useDesignable, useDesigner } from '../..';
|
||||||
import { Icon, useAPIClient, useSchemaInitializerRender } from '../../../';
|
import { Icon, useAPIClient, useSchemaInitializerRender } from '../../../';
|
||||||
import { useCollectMenuItems, useMenuItem } from '../../../hooks/useMenuItem';
|
import { useCollectMenuItems, useMenuItem } from '../../../hooks/useMenuItem';
|
||||||
import { useProps } from '../../hooks/useProps';
|
import { useProps } from '../../hooks/useProps';
|
||||||
import { useMenuTranslation } from './locale';
|
import { useMenuTranslation } from './locale';
|
||||||
import { MenuDesigner } from './Menu.Designer';
|
import { MenuDesigner } from './Menu.Designer';
|
||||||
|
import { useStyles } from './Menu.styles';
|
||||||
import { findKeysByUid, findMenuItem } from './util';
|
import { findKeysByUid, findMenuItem } from './util';
|
||||||
|
|
||||||
const subMenuDesignerCss = css`
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
margin-left: -24px;
|
|
||||||
margin-right: -34px;
|
|
||||||
padding: 0 34px 0 24px;
|
|
||||||
width: calc(100% + 58px);
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
&:hover {
|
|
||||||
> .general-schema-designer {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.nb-action-link {
|
|
||||||
> .general-schema-designer {
|
|
||||||
top: -10px;
|
|
||||||
bottom: -10px;
|
|
||||||
left: -10px;
|
|
||||||
right: -10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
> .general-schema-designer {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 999;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: none;
|
|
||||||
background: var(--colorBgSettingsHover);
|
|
||||||
border: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
> .general-schema-designer-icons {
|
|
||||||
position: absolute;
|
|
||||||
right: 2px;
|
|
||||||
top: 2px;
|
|
||||||
line-height: 16px;
|
|
||||||
pointer-events: all;
|
|
||||||
.ant-space-item {
|
|
||||||
background-color: var(--colorSettings);
|
|
||||||
color: #fff;
|
|
||||||
line-height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
padding-left: 1px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const designerCss = css`
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
margin-left: -20px;
|
|
||||||
margin-right: -20px;
|
|
||||||
padding: 0 20px;
|
|
||||||
width: calc(100% + 40px);
|
|
||||||
height: 100%;
|
|
||||||
&:hover {
|
|
||||||
> .general-schema-designer {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.nb-action-link {
|
|
||||||
> .general-schema-designer {
|
|
||||||
top: -10px;
|
|
||||||
bottom: -10px;
|
|
||||||
left: -10px;
|
|
||||||
right: -10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
> .general-schema-designer {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 999;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: none;
|
|
||||||
background: var(--colorBgSettingsHover);
|
|
||||||
border: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
> .general-schema-designer-icons {
|
|
||||||
position: absolute;
|
|
||||||
right: 2px;
|
|
||||||
top: 2px;
|
|
||||||
line-height: 16px;
|
|
||||||
pointer-events: all;
|
|
||||||
.ant-space-item {
|
|
||||||
background-color: var(--colorSettings);
|
|
||||||
color: #fff;
|
|
||||||
line-height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
padding-left: 1px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const headerMenuClass = css`
|
|
||||||
.ant-menu-item:hover {
|
|
||||||
> .ant-menu-title-content > div {
|
|
||||||
.general-schema-designer {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const sideMenuClass = css`
|
|
||||||
height: 100%;
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden;
|
|
||||||
.ant-menu-item {
|
|
||||||
> .ant-menu-title-content {
|
|
||||||
height: 100%;
|
|
||||||
margin-left: -24px;
|
|
||||||
margin-right: -16px;
|
|
||||||
padding: 0 16px 0 24px;
|
|
||||||
> div {
|
|
||||||
> .general-schema-designer {
|
|
||||||
right: 6px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ant-menu-submenu-title {
|
|
||||||
.ant-menu-title-content {
|
|
||||||
height: 100%;
|
|
||||||
margin-left: -24px;
|
|
||||||
margin-right: -34px;
|
|
||||||
padding: 0 34px 0 24px;
|
|
||||||
> div {
|
|
||||||
> .general-schema-designer {
|
|
||||||
right: 6px !important;
|
|
||||||
}
|
|
||||||
> span.anticon {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const menuItemClass = css`
|
|
||||||
:active {
|
|
||||||
background: inherit;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
type ComposedMenu = React.FC<any> & {
|
type ComposedMenu = React.FC<any> & {
|
||||||
Item?: React.FC<any>;
|
Item?: React.FC<any>;
|
||||||
URL?: React.FC<any>;
|
URL?: React.FC<any>;
|
||||||
@ -199,6 +46,7 @@ const HeaderMenu = ({
|
|||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
const { Component, getMenuItems } = useMenuItem();
|
const { Component, getMenuItems } = useMenuItem();
|
||||||
|
const { styles } = useStyles();
|
||||||
const items = useMemo(() => {
|
const items = useMemo(() => {
|
||||||
const designerBtn = {
|
const designerBtn = {
|
||||||
key: 'x-designer-button',
|
key: 'x-designer-button',
|
||||||
@ -225,7 +73,7 @@ const HeaderMenu = ({
|
|||||||
<Component />
|
<Component />
|
||||||
<AntdMenu
|
<AntdMenu
|
||||||
{...others}
|
{...others}
|
||||||
className={headerMenuClass}
|
className={styles.headerMenuClass}
|
||||||
onSelect={(info: any) => {
|
onSelect={(info: any) => {
|
||||||
const s = schema.properties?.[info.key];
|
const s = schema.properties?.[info.key];
|
||||||
|
|
||||||
@ -286,6 +134,7 @@ const SideMenu = ({
|
|||||||
designable,
|
designable,
|
||||||
}) => {
|
}) => {
|
||||||
const { Component, getMenuItems } = useMenuItem();
|
const { Component, getMenuItems } = useMenuItem();
|
||||||
|
const { styles } = useStyles();
|
||||||
|
|
||||||
// fix https://nocobase.height.app/T-3331/description
|
// fix https://nocobase.height.app/T-3331/description
|
||||||
// 使用 ref 用来防止闭包问题
|
// 使用 ref 用来防止闭包问题
|
||||||
@ -340,7 +189,7 @@ const SideMenu = ({
|
|||||||
onSelect={(info) => {
|
onSelect={(info) => {
|
||||||
onSelect?.(info);
|
onSelect?.(info);
|
||||||
}}
|
}}
|
||||||
className={sideMenuClass}
|
className={styles.sideMenuClass}
|
||||||
items={items as MenuProps['items']}
|
items={items as MenuProps['items']}
|
||||||
/>
|
/>
|
||||||
</MenuModeContext.Provider>,
|
</MenuModeContext.Provider>,
|
||||||
@ -488,12 +337,13 @@ Menu.Item = observer(
|
|||||||
const { pushMenuItem } = useCollectMenuItems();
|
const { pushMenuItem } = useCollectMenuItems();
|
||||||
const { icon, children, ...others } = props;
|
const { icon, children, ...others } = props;
|
||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
|
const { styles } = useStyles();
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const Designer = useContext(MenuItemDesignerContext);
|
const Designer = useContext(MenuItemDesignerContext);
|
||||||
const item = useMemo(() => {
|
const item = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
...others,
|
...others,
|
||||||
className: menuItemClass,
|
className: styles.menuItemClass,
|
||||||
key: schema.name,
|
key: schema.name,
|
||||||
eventKey: schema.name,
|
eventKey: schema.name,
|
||||||
schema,
|
schema,
|
||||||
@ -503,7 +353,7 @@ Menu.Item = observer(
|
|||||||
<SortableItem
|
<SortableItem
|
||||||
role="button"
|
role="button"
|
||||||
aria-label={t(field.title)}
|
aria-label={t(field.title)}
|
||||||
className={designerCss}
|
className={styles.designerCss}
|
||||||
removeParentsIfNoChildren={false}
|
removeParentsIfNoChildren={false}
|
||||||
>
|
>
|
||||||
<Icon type={icon} />
|
<Icon type={icon} />
|
||||||
@ -545,6 +395,7 @@ Menu.URL = observer(
|
|||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const Designer = useContext(MenuItemDesignerContext);
|
const Designer = useContext(MenuItemDesignerContext);
|
||||||
|
const { styles } = useStyles();
|
||||||
|
|
||||||
if (!pushMenuItem) {
|
if (!pushMenuItem) {
|
||||||
error('Menu.URL must be wrapped by GetMenuItemsContext.Provider');
|
error('Menu.URL must be wrapped by GetMenuItemsContext.Provider');
|
||||||
@ -554,7 +405,7 @@ Menu.URL = observer(
|
|||||||
const item = useMemo(() => {
|
const item = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
...others,
|
...others,
|
||||||
className: menuItemClass,
|
className: styles.menuItemClass,
|
||||||
key: schema.name,
|
key: schema.name,
|
||||||
eventKey: schema.name,
|
eventKey: schema.name,
|
||||||
schema,
|
schema,
|
||||||
@ -564,7 +415,11 @@ Menu.URL = observer(
|
|||||||
label: (
|
label: (
|
||||||
<SchemaContext.Provider value={schema}>
|
<SchemaContext.Provider value={schema}>
|
||||||
<FieldContext.Provider value={field}>
|
<FieldContext.Provider value={field}>
|
||||||
<SortableItem className={designerCss} removeParentsIfNoChildren={false} aria-label={t(field.title)}>
|
<SortableItem
|
||||||
|
className={styles.designerCss}
|
||||||
|
removeParentsIfNoChildren={false}
|
||||||
|
aria-label={t(field.title)}
|
||||||
|
>
|
||||||
<Icon type={icon} />
|
<Icon type={icon} />
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
@ -601,17 +456,18 @@ Menu.SubMenu = observer(
|
|||||||
const field = useField();
|
const field = useField();
|
||||||
const mode = useContext(MenuModeContext);
|
const mode = useContext(MenuModeContext);
|
||||||
const Designer = useContext(MenuItemDesignerContext);
|
const Designer = useContext(MenuItemDesignerContext);
|
||||||
|
const { styles } = useStyles();
|
||||||
const submenu = useMemo(() => {
|
const submenu = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
...others,
|
...others,
|
||||||
className: menuItemClass,
|
className: styles.menuItemClass,
|
||||||
key: schema.name,
|
key: schema.name,
|
||||||
eventKey: schema.name,
|
eventKey: schema.name,
|
||||||
label: (
|
label: (
|
||||||
<SchemaContext.Provider value={schema}>
|
<SchemaContext.Provider value={schema}>
|
||||||
<FieldContext.Provider value={field}>
|
<FieldContext.Provider value={field}>
|
||||||
<SortableItem
|
<SortableItem
|
||||||
className={subMenuDesignerCss}
|
className={styles.subMenuDesignerCss}
|
||||||
removeParentsIfNoChildren={false}
|
removeParentsIfNoChildren={false}
|
||||||
aria-label={t(field.title)}
|
aria-label={t(field.title)}
|
||||||
>
|
>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||||
import { useRecord } from '../../../record-provider';
|
import { useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
const FixedBlockContext = React.createContext<{
|
const FixedBlockContext = React.createContext<{
|
||||||
setFixedBlock: (value: string | false) => void;
|
setFixedBlock: (value: string | false) => void;
|
||||||
@ -37,7 +37,7 @@ export const useFixedBlock = () => {
|
|||||||
return useContext(FixedBlockContext);
|
return useContext(FixedBlockContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FixedBlockWrapper: React.FC = (props) => {
|
export const FixedBlockWrapper = (props) => {
|
||||||
const fixedBlock = useFixedSchema();
|
const fixedBlock = useFixedSchema();
|
||||||
const { height, fixedBlockUID } = useFixedBlock();
|
const { height, fixedBlockUID } = useFixedBlock();
|
||||||
/**
|
/**
|
||||||
@ -59,30 +59,36 @@ export const FixedBlockWrapper: React.FC = (props) => {
|
|||||||
|
|
||||||
interface FixedBlockProps {
|
interface FixedBlockProps {
|
||||||
height: number | string;
|
height: number | string;
|
||||||
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fixedBlockCss = css`
|
const useStyles = createStyles(({ css }) => {
|
||||||
overflow: hidden;
|
return {
|
||||||
position: relative;
|
fixedBlockCss: css`
|
||||||
.noco-card-item {
|
overflow: hidden;
|
||||||
height: 100%;
|
position: relative;
|
||||||
.ant-card {
|
.noco-card-item {
|
||||||
display: flex;
|
height: 100%;
|
||||||
flex-direction: column;
|
.ant-card {
|
||||||
height: 100%;
|
display: flex;
|
||||||
.ant-card-body {
|
flex-direction: column;
|
||||||
height: 1px;
|
height: 100%;
|
||||||
flex: 1;
|
.ant-card-body {
|
||||||
display: flex;
|
height: 1px;
|
||||||
flex-direction: column;
|
flex: 1;
|
||||||
overflow: hidden;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
`,
|
||||||
}
|
};
|
||||||
`;
|
});
|
||||||
|
|
||||||
const FixedBlock: React.FC<FixedBlockProps> = (props) => {
|
const FixedBlock = (props: FixedBlockProps) => {
|
||||||
const { height } = props;
|
const { height } = props;
|
||||||
|
const { styles } = useStyles();
|
||||||
const [fixedBlockUID, _setFixedBlock] = useState<false | string>(false);
|
const [fixedBlockUID, _setFixedBlock] = useState<false | string>(false);
|
||||||
const fixedBlockUIDRef = useRef(fixedBlockUID);
|
const fixedBlockUIDRef = useRef(fixedBlockUID);
|
||||||
const setFixedBlock = (v) => {
|
const setFixedBlock = (v) => {
|
||||||
@ -92,7 +98,7 @@ const FixedBlock: React.FC<FixedBlockProps> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<FixedBlockContext.Provider value={{ inFixedBlock: true, height, setFixedBlock, fixedBlockUID, fixedBlockUIDRef }}>
|
<FixedBlockContext.Provider value={{ inFixedBlock: true, height, setFixedBlock, fixedBlockUID, fixedBlockUIDRef }}>
|
||||||
<div
|
<div
|
||||||
className={fixedBlockUID ? fixedBlockCss : ''}
|
className={fixedBlockUID ? styles.fixedBlockCss : ''}
|
||||||
style={{
|
style={{
|
||||||
height: fixedBlockUID ? `calc(100vh - ${height})` : undefined,
|
height: fixedBlockUID ? `calc(100vh - ${height})` : undefined,
|
||||||
}}
|
}}
|
||||||
|
@ -1,16 +1,29 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { FormItem } from '@tachybase/components';
|
|
||||||
import { Field, createForm } from '@tachybase/schema';
|
|
||||||
import { FormContext, RecursionField, observer, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import React, { useMemo, useRef } from 'react';
|
import React, { useMemo, useRef } from 'react';
|
||||||
|
import { FormItem } from '@tachybase/components';
|
||||||
|
import { createForm, Field, FormContext, observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
import { useCollectionManager_deprecated } from '../../../collection-manager';
|
import { useCollectionManager_deprecated } from '../../../collection-manager';
|
||||||
import { StablePopover } from '../popover';
|
import { StablePopover } from '../popover';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
overlay: css`
|
||||||
|
padding-top: 0;
|
||||||
|
.ant-popover-arrow {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const Editable = observer(
|
export const Editable = observer(
|
||||||
(props) => {
|
(props) => {
|
||||||
const field: any = useField();
|
const field: any = useField();
|
||||||
const containerRef = useRef(null);
|
const containerRef = useRef(null);
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { styles } = useStyles();
|
||||||
const value = field.value;
|
const value = field.value;
|
||||||
const schema: any = {
|
const schema: any = {
|
||||||
name: fieldSchema.name,
|
name: fieldSchema.name,
|
||||||
@ -51,12 +64,7 @@ export const Editable = observer(
|
|||||||
}
|
}
|
||||||
trigger="click"
|
trigger="click"
|
||||||
placement={'bottomLeft'}
|
placement={'bottomLeft'}
|
||||||
overlayClassName={css`
|
overlayClassName={styles.overlay}
|
||||||
padding-top: 0;
|
|
||||||
.ant-popover-arrow {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
>
|
||||||
<div style={{ minHeight: 30, padding: '0 8px' }}>
|
<div style={{ minHeight: 30, padding: '0 8px' }}>
|
||||||
<FormContext.Provider value={form}>
|
<FormContext.Provider value={form}>
|
||||||
|
@ -1,59 +1,64 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { observer } from '@tachybase/schema';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { observer } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
import { SortableItem, useDesigner } from '../..';
|
import { SortableItem, useDesigner } from '../..';
|
||||||
import { useFlag } from '../../../flag-provider/hooks/useFlag';
|
import { useFlag } from '../../../flag-provider/hooks/useFlag';
|
||||||
|
|
||||||
export const designerCss = ({ margin = '-18px -16px', padding = '18px 16px' } = {}) => css`
|
export const useStyles = createStyles(({ css }, { margin = '-18px -16px', padding = '18px 16px' }) => {
|
||||||
position: relative;
|
return {
|
||||||
margin: ${margin};
|
designer: css`
|
||||||
padding: ${padding};
|
position: relative;
|
||||||
|
margin: ${margin};
|
||||||
|
padding: ${padding};
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
> .general-schema-designer {
|
> .general-schema-designer {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
> .general-schema-designer {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 999;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: none;
|
|
||||||
background: var(--colorBgSettingsHover) !important;
|
|
||||||
border: 0 !important;
|
|
||||||
pointer-events: none;
|
|
||||||
> .general-schema-designer-icons {
|
|
||||||
position: absolute;
|
|
||||||
right: 2px;
|
|
||||||
top: 2px;
|
|
||||||
line-height: 16px;
|
|
||||||
pointer-events: all;
|
|
||||||
.ant-space-item {
|
|
||||||
background-color: var(--colorSettings);
|
|
||||||
color: #fff;
|
|
||||||
line-height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
padding-left: 1px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
}
|
||||||
}
|
> .general-schema-designer {
|
||||||
}
|
position: absolute;
|
||||||
`;
|
z-index: 999;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: none;
|
||||||
|
background: var(--colorBgSettingsHover) !important;
|
||||||
|
border: 0 !important;
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: var(--colorSettings);
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const TableColumnActionBar = observer(
|
export const TableColumnActionBar = observer(
|
||||||
(props) => {
|
(props) => {
|
||||||
const Designer = useDesigner();
|
const Designer = useDesigner();
|
||||||
const { isInSubTable } = useFlag() || {};
|
const { isInSubTable } = useFlag() || {};
|
||||||
|
const { styles } = useStyles({
|
||||||
|
margin: isInSubTable ? '-12px -8px' : '-18px -16px',
|
||||||
|
padding: isInSubTable ? '12px 8px' : '18px 16px',
|
||||||
|
});
|
||||||
return (
|
return (
|
||||||
<SortableItem
|
<SortableItem className={styles.designer}>
|
||||||
className={designerCss({
|
|
||||||
margin: isInSubTable ? '-12px -8px' : '-18px -16px',
|
|
||||||
padding: isInSubTable ? '12px 8px' : '18px 16px',
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Designer />
|
<Designer />
|
||||||
{props.children}
|
{props.children}
|
||||||
</SortableItem>
|
</SortableItem>
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
import { useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import React, { useLayoutEffect } from 'react';
|
import React, { useLayoutEffect } from 'react';
|
||||||
|
import { useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
CollectionFieldContext,
|
||||||
SortableItem,
|
SortableItem,
|
||||||
useCollection_deprecated,
|
useCollection_deprecated,
|
||||||
useCollectionManager_deprecated,
|
useCollectionManager_deprecated,
|
||||||
useCompile,
|
useCompile,
|
||||||
useDesigner,
|
useDesigner,
|
||||||
CollectionFieldContext,
|
|
||||||
useFlag,
|
useFlag,
|
||||||
} from '../../../';
|
} from '../../../';
|
||||||
import { designerCss } from './Table.Column.ActionBar';
|
import { useStyles } from './Table.Column.ActionBar';
|
||||||
import { isCollectionFieldComponent } from './utils';
|
import { isCollectionFieldComponent } from './utils';
|
||||||
|
|
||||||
export const useColumnSchema = () => {
|
export const useColumnSchema = () => {
|
||||||
@ -33,10 +34,14 @@ export const useColumnSchema = () => {
|
|||||||
|
|
||||||
export const TableColumnDecorator = (props) => {
|
export const TableColumnDecorator = (props) => {
|
||||||
const Designer = useDesigner();
|
const Designer = useDesigner();
|
||||||
|
const { isInSubTable } = useFlag() || {};
|
||||||
|
const { styles } = useStyles({
|
||||||
|
margin: isInSubTable ? '-12px -8px' : '-18px -16px',
|
||||||
|
padding: isInSubTable ? '12px 8px' : '18px 16px',
|
||||||
|
});
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const { fieldSchema, uiSchema, collectionField } = useColumnSchema();
|
const { fieldSchema, uiSchema, collectionField } = useColumnSchema();
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const { isInSubTable } = useFlag() || {};
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (field.title) {
|
if (field.title) {
|
||||||
return;
|
return;
|
||||||
@ -49,12 +54,7 @@ export const TableColumnDecorator = (props) => {
|
|||||||
}
|
}
|
||||||
}, [uiSchema?.title]);
|
}, [uiSchema?.title]);
|
||||||
return (
|
return (
|
||||||
<SortableItem
|
<SortableItem className={styles.designer}>
|
||||||
className={designerCss({
|
|
||||||
margin: isInSubTable ? '-12px -8px' : '-18px -16px',
|
|
||||||
padding: isInSubTable ? '12px 8px' : '18px 16px',
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<CollectionFieldContext.Provider value={collectionField}>
|
<CollectionFieldContext.Provider value={collectionField}>
|
||||||
<Designer fieldSchema={fieldSchema} uiSchema={uiSchema} collectionField={collectionField} />
|
<Designer fieldSchema={fieldSchema} uiSchema={uiSchema} collectionField={collectionField} />
|
||||||
{/* <RecursionField name={columnSchema.name} schema={columnSchema}/> */}
|
{/* <RecursionField name={columnSchema.name} schema={columnSchema}/> */}
|
||||||
|
@ -0,0 +1,117 @@
|
|||||||
|
import { TinyColor } from '@ctrl/tinycolor';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
|
export const useStyles = createStyles(({ css, token }) => {
|
||||||
|
const borderColor = new TinyColor(token.colorSettings).setAlpha(0.6).toHex8String();
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
.ant-table-thead {
|
||||||
|
.ant-table-cell {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-table-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
.ant-spin-nested-loading {
|
||||||
|
height: 100%;
|
||||||
|
.ant-spin-container {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-table {
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
toolbar: css`
|
||||||
|
// 扩大 SchemaToolbar 的面积
|
||||||
|
.nb-action-link {
|
||||||
|
margin: -${token.paddingContentVerticalLG}px -${token.marginSM}px;
|
||||||
|
padding: ${token.paddingContentVerticalLG}px ${token.marginSM}px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
|
||||||
|
topActive: css`
|
||||||
|
& > td {
|
||||||
|
border-top: 2px solid ${borderColor} !important;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
bottomActive: css`
|
||||||
|
& > td {
|
||||||
|
border-bottom: 2px solid ${borderColor} !important;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
highlightRow: css`
|
||||||
|
& > td {
|
||||||
|
background-color: ${token.controlItemBgActiveHover} !important;
|
||||||
|
}
|
||||||
|
&:hover > td {
|
||||||
|
background-color: ${token.controlItemBgActiveHover} !important;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
headerCellDesigner: css`
|
||||||
|
max-width: 300px;
|
||||||
|
white-space: nowrap;
|
||||||
|
&:hover .general-schema-designer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
bodyCell: css`
|
||||||
|
max-width: 300px;
|
||||||
|
white-space: nowrap;
|
||||||
|
.nb-read-pretty-input-number {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.ant-color-picker-trigger {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
rowSelect: css`
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
float: left;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
padding-right: 8px;
|
||||||
|
.nb-table-index {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
&:not(.checked) {
|
||||||
|
.nb-table-index {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
rowSelectHover: css`
|
||||||
|
&:hover {
|
||||||
|
.nb-table-index {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.nb-origin-node {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
cellChecked: css`
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
`,
|
||||||
|
cellCheckedNode: css`
|
||||||
|
position: absolute;
|
||||||
|
right: 50%;
|
||||||
|
transform: translateX(50%);
|
||||||
|
&:not(.checked) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
@ -1,19 +1,26 @@
|
|||||||
import { DeleteOutlined, MenuOutlined, CopyOutlined } from '@ant-design/icons';
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { TinyColor } from '@ctrl/tinycolor';
|
import {
|
||||||
import { SortableContext, SortableContextProps, useSortable } from '@dnd-kit/sortable';
|
action,
|
||||||
import { css } from '@emotion/css';
|
ArrayField,
|
||||||
import { ArrayField } from '@tachybase/schema';
|
observer,
|
||||||
import { spliceArrayState } from '@tachybase/schema';
|
RecursionField,
|
||||||
import { RecursionField, Schema, observer, useField, useFieldSchema } from '@tachybase/schema';
|
Schema,
|
||||||
import { action } from '@tachybase/schema';
|
spliceArrayState,
|
||||||
import { uid } from '@tachybase/schema';
|
uid,
|
||||||
|
useField,
|
||||||
|
useFieldSchema,
|
||||||
|
} from '@tachybase/schema';
|
||||||
import { isPortalInBody } from '@tachybase/utils/client';
|
import { isPortalInBody } from '@tachybase/utils/client';
|
||||||
|
|
||||||
|
import { CopyOutlined, DeleteOutlined, MenuOutlined } from '@ant-design/icons';
|
||||||
|
import { SortableContext, SortableContextProps, useSortable } from '@dnd-kit/sortable';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { Table as AntdTable, TableColumnProps } from 'antd';
|
import { Table as AntdTable, TableColumnProps } from 'antd';
|
||||||
import { default as classNames, default as cls } from 'classnames';
|
import { default as classNames, default as cls } from 'classnames';
|
||||||
import _, { each } from 'lodash';
|
import _, { each } from 'lodash';
|
||||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { useToken } from '../__builtins__';
|
||||||
import { DndContext, useDesignable, useTableSize } from '../..';
|
import { DndContext, useDesignable, useTableSize } from '../..';
|
||||||
import {
|
import {
|
||||||
RecordIndexProvider,
|
RecordIndexProvider,
|
||||||
@ -25,13 +32,13 @@ import {
|
|||||||
useTableBlockContext,
|
useTableBlockContext,
|
||||||
useTableSelectorContext,
|
useTableSelectorContext,
|
||||||
} from '../../../';
|
} from '../../../';
|
||||||
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
|
||||||
import { useACLFieldWhitelist } from '../../../acl/ACLProvider';
|
import { useACLFieldWhitelist } from '../../../acl/ACLProvider';
|
||||||
import { useToken } from '../__builtins__';
|
import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps';
|
||||||
|
import { isNewRecord, markRecordAsNew } from '../../../data-source/collection-record/isNewRecord';
|
||||||
import { SubFormProvider } from '../association-field/hooks';
|
import { SubFormProvider } from '../association-field/hooks';
|
||||||
import { ColumnFieldProvider } from './components/ColumnFieldProvider';
|
import { ColumnFieldProvider } from './components/ColumnFieldProvider';
|
||||||
|
import { useStyles } from './Table.styles';
|
||||||
import { extractIndex, isCollectionFieldComponent, isColumnComponent } from './utils';
|
import { extractIndex, isCollectionFieldComponent, isColumnComponent } from './utils';
|
||||||
import { isNewRecord, markRecordAsNew } from '../../../data-source/collection-record/isNewRecord';
|
|
||||||
|
|
||||||
const useArrayField = (props) => {
|
const useArrayField = (props) => {
|
||||||
const field = useField<ArrayField>();
|
const field = useField<ArrayField>();
|
||||||
@ -40,6 +47,7 @@ const useArrayField = (props) => {
|
|||||||
|
|
||||||
const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) => {
|
const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) => {
|
||||||
const { token } = useToken();
|
const { token } = useToken();
|
||||||
|
const { styles } = useStyles();
|
||||||
const field = useArrayField(props);
|
const field = useArrayField(props);
|
||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
const { schemaInWhitelist } = useACLFieldWhitelist();
|
const { schemaInWhitelist } = useACLFieldWhitelist();
|
||||||
@ -77,16 +85,7 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) =>
|
|||||||
<RecordIndexProvider index={record.__index || index}>
|
<RecordIndexProvider index={record.__index || index}>
|
||||||
<RecordProvider isNew={isNewRecord(record)} record={record} parent={parentRecordData}>
|
<RecordProvider isNew={isNewRecord(record)} record={record} parent={parentRecordData}>
|
||||||
<ColumnFieldProvider schema={s} basePath={field.address.concat(record.__index || index)}>
|
<ColumnFieldProvider schema={s} basePath={field.address.concat(record.__index || index)}>
|
||||||
<span
|
<span role="button" className={styles.toolbar}>
|
||||||
role="button"
|
|
||||||
className={css`
|
|
||||||
// 扩大 SchemaToolbar 的面积
|
|
||||||
.nb-action-link {
|
|
||||||
margin: -${token.paddingContentVerticalLG}px -${token.marginSM}px;
|
|
||||||
padding: ${token.paddingContentVerticalLG}px ${token.marginSM}px;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<RecursionField
|
<RecursionField
|
||||||
basePath={field.address.concat(record.__index || index)}
|
basePath={field.address.concat(record.__index || index)}
|
||||||
schema={s}
|
schema={s}
|
||||||
@ -173,32 +172,16 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
const SortableRow = (props) => {
|
const SortableRow = (props) => {
|
||||||
const { token } = useToken();
|
const { styles } = useStyles();
|
||||||
const id = props['data-row-key']?.toString();
|
const id = props['data-row-key']?.toString();
|
||||||
const { setNodeRef, isOver, active, over } = useSortable({
|
const { setNodeRef, isOver, active, over } = useSortable({
|
||||||
id,
|
id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const classObj = useMemo(() => {
|
|
||||||
const borderColor = new TinyColor(token.colorSettings).setAlpha(0.6).toHex8String();
|
|
||||||
return {
|
|
||||||
topActiveClass: css`
|
|
||||||
& > td {
|
|
||||||
border-top: 2px solid ${borderColor} !important;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
bottomActiveClass: css`
|
|
||||||
& > td {
|
|
||||||
border-bottom: 2px solid ${borderColor} !important;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
};
|
|
||||||
}, [token.colorSettings]);
|
|
||||||
|
|
||||||
const className =
|
const className =
|
||||||
(active?.data.current?.sortable.index ?? -1) > (over?.data.current?.sortable?.index ?? -1)
|
(active?.data.current?.sortable.index ?? -1) > (over?.data.current?.sortable?.index ?? -1)
|
||||||
? classObj.topActiveClass
|
? styles.topActive
|
||||||
: classObj.bottomActiveClass;
|
: styles.bottomActive;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
@ -263,6 +246,7 @@ export const Table: any = withDynamicSchemaProps(
|
|||||||
isSubTable?: boolean;
|
isSubTable?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const { token } = useToken();
|
const { token } = useToken();
|
||||||
|
const { styles } = useStyles();
|
||||||
const { pagination: pagination1, useProps, ...others1 } = props;
|
const { pagination: pagination1, useProps, ...others1 } = props;
|
||||||
|
|
||||||
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||||
@ -309,14 +293,7 @@ export const Table: any = withDynamicSchemaProps(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
highlightRow = css`
|
highlightRow = styles.highlightRow;
|
||||||
& > td {
|
|
||||||
background-color: ${token.controlItemBgActiveHover} !important;
|
|
||||||
}
|
|
||||||
&:hover > td {
|
|
||||||
background-color: ${token.controlItemBgActiveHover} !important;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -338,21 +315,7 @@ export const Table: any = withDynamicSchemaProps(
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
cell: (props) => {
|
cell: (props) => {
|
||||||
return (
|
return <th {...props} className={cls(props.className, styles.headerCellDesigner)} />;
|
||||||
<th
|
|
||||||
{...props}
|
|
||||||
className={cls(
|
|
||||||
props.className,
|
|
||||||
css`
|
|
||||||
max-width: 300px;
|
|
||||||
white-space: nowrap;
|
|
||||||
&:hover .general-schema-designer {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
body: {
|
body: {
|
||||||
@ -379,26 +342,7 @@ export const Table: any = withDynamicSchemaProps(
|
|||||||
row: (props) => {
|
row: (props) => {
|
||||||
return <SortableRow {...props}></SortableRow>;
|
return <SortableRow {...props}></SortableRow>;
|
||||||
},
|
},
|
||||||
cell: (props) => (
|
cell: (props) => <td {...props} className={classNames(props.className, styles.bodyCell)} />,
|
||||||
<td
|
|
||||||
{...props}
|
|
||||||
className={classNames(
|
|
||||||
props.className,
|
|
||||||
css`
|
|
||||||
max-width: 300px;
|
|
||||||
white-space: nowrap;
|
|
||||||
.nb-read-pretty-input-number {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.ant-color-picker-trigger {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}, [field, onRowDragEnd, dragSort]);
|
}, [field, onRowDragEnd, dragSort]);
|
||||||
@ -470,67 +414,16 @@ export const Table: any = withDynamicSchemaProps(
|
|||||||
<div
|
<div
|
||||||
role="button"
|
role="button"
|
||||||
aria-label={`table-index-${index}`}
|
aria-label={`table-index-${index}`}
|
||||||
className={classNames(
|
className={classNames(checked ? 'checked' : null, styles.rowSelect, {
|
||||||
checked ? 'checked' : null,
|
[styles.rowSelectHover]: isRowSelect,
|
||||||
css`
|
})}
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
float: left;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-evenly;
|
|
||||||
padding-right: 8px;
|
|
||||||
.nb-table-index {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
&:not(.checked) {
|
|
||||||
.nb-table-index {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
{
|
|
||||||
[css`
|
|
||||||
&:hover {
|
|
||||||
.nb-table-index {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
.nb-origin-node {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`]: isRowSelect,
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<div
|
<div className={classNames(checked ? 'checked' : null, styles.cellChecked)}>
|
||||||
className={classNames(
|
|
||||||
checked ? 'checked' : null,
|
|
||||||
css`
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-evenly;
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{dragSort && <SortHandle id={getRowKey(record)} />}
|
{dragSort && <SortHandle id={getRowKey(record)} />}
|
||||||
{showIndex && <TableIndex index={index} />}
|
{showIndex && <TableIndex index={index} />}
|
||||||
</div>
|
</div>
|
||||||
{isRowSelect && (
|
{isRowSelect && (
|
||||||
<div
|
<div className={classNames('nb-origin-node', checked ? 'checked' : null, styles.cellCheckedNode)}>
|
||||||
className={classNames(
|
|
||||||
'nb-origin-node',
|
|
||||||
checked ? 'checked' : null,
|
|
||||||
css`
|
|
||||||
position: absolute;
|
|
||||||
right: 50%;
|
|
||||||
transform: translateX(50%);
|
|
||||||
&:not(.checked) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{originNode}
|
{originNode}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -541,7 +434,7 @@ export const Table: any = withDynamicSchemaProps(
|
|||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
};
|
};
|
||||||
const SortableWrapper = useCallback<React.FC>(
|
const SortableWrapper = useCallback(
|
||||||
({ children }) => {
|
({ children }) => {
|
||||||
return dragSort
|
return dragSort
|
||||||
? React.createElement<Omit<SortableContextProps, 'children'>>(
|
? React.createElement<Omit<SortableContextProps, 'children'>>(
|
||||||
@ -570,32 +463,7 @@ export const Table: any = withDynamicSchemaProps(
|
|||||||
};
|
};
|
||||||
}, [fixedBlock, tableHeight]);
|
}, [fixedBlock, tableHeight]);
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={styles.container}>
|
||||||
className={css`
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
.ant-table-thead {
|
|
||||||
.ant-table-cell {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ant-table-wrapper {
|
|
||||||
height: 100%;
|
|
||||||
.ant-spin-nested-loading {
|
|
||||||
height: 100%;
|
|
||||||
.ant-spin-container {
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ant-table {
|
|
||||||
overflow-x: auto;
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<SortableWrapper>
|
<SortableWrapper>
|
||||||
<AntdTable
|
<AntdTable
|
||||||
ref={tableSizeRefCallback}
|
ref={tableSizeRefCallback}
|
||||||
|
@ -1,19 +1,23 @@
|
|||||||
import { MenuOutlined } from '@ant-design/icons';
|
import React, { useContext, useMemo, useState } from 'react';
|
||||||
import { TinyColor } from '@ctrl/tinycolor';
|
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { ArrayField, Field } from '@tachybase/schema';
|
|
||||||
import {
|
import {
|
||||||
|
ArrayField,
|
||||||
|
Field,
|
||||||
|
observer,
|
||||||
RecursionField,
|
RecursionField,
|
||||||
Schema,
|
Schema,
|
||||||
SchemaExpressionScopeContext,
|
SchemaExpressionScopeContext,
|
||||||
observer,
|
|
||||||
useField,
|
useField,
|
||||||
useFieldSchema,
|
useFieldSchema,
|
||||||
} from '@tachybase/schema';
|
} from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { MenuOutlined } from '@ant-design/icons';
|
||||||
|
import { TinyColor } from '@ctrl/tinycolor';
|
||||||
import { Table, TableColumnProps } from 'antd';
|
import { Table, TableColumnProps } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import { default as classNames, default as cls } from 'classnames';
|
import { default as classNames, default as cls } from 'classnames';
|
||||||
import React, { useContext, useState } from 'react';
|
|
||||||
import ReactDragListView from 'react-drag-listview';
|
import ReactDragListView from 'react-drag-listview';
|
||||||
|
|
||||||
|
import { useToken } from '../__builtins__';
|
||||||
import { DndContext } from '../..';
|
import { DndContext } from '../..';
|
||||||
import {
|
import {
|
||||||
RecordIndexProvider,
|
RecordIndexProvider,
|
||||||
@ -23,7 +27,68 @@ import {
|
|||||||
useRequest,
|
useRequest,
|
||||||
useSchemaInitializerRender,
|
useSchemaInitializerRender,
|
||||||
} from '../../../';
|
} from '../../../';
|
||||||
import { useToken } from '../__builtins__';
|
|
||||||
|
const useStyles = createStyles(({ css, token }) => {
|
||||||
|
return {
|
||||||
|
drag: css`
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
`,
|
||||||
|
node: css`
|
||||||
|
position: absolute;
|
||||||
|
right: 50%;
|
||||||
|
transform: translateX(50%);
|
||||||
|
&:not(.checked) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
headerCell: css`
|
||||||
|
&:hover .general-schema-designer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
bodyCell: css`
|
||||||
|
max-width: 300px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
`,
|
||||||
|
cell: css`
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
padding-right: 8px;
|
||||||
|
.nb-table-index {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
&:not(.checked) {
|
||||||
|
.nb-table-index {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
.nb-table-index {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.nb-origin-node {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
table: css`
|
||||||
|
.ant-table {
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
line: css`
|
||||||
|
border-bottom: 2px solid ${new TinyColor(token.colorSettings).setAlpha(0.6).toHex8String()} !important;
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const isColumnComponent = (schema: Schema) => {
|
const isColumnComponent = (schema: Schema) => {
|
||||||
return schema['x-component']?.endsWith('.Column') > -1;
|
return schema['x-component']?.endsWith('.Column') > -1;
|
||||||
@ -36,6 +101,7 @@ const useTableColumns = () => {
|
|||||||
const scope = useContext(SchemaExpressionScopeContext);
|
const scope = useContext(SchemaExpressionScopeContext);
|
||||||
const parentRecordData = useCollectionParentRecordData();
|
const parentRecordData = useCollectionParentRecordData();
|
||||||
const recordData = useCollectionRecordData();
|
const recordData = useCollectionRecordData();
|
||||||
|
const { styles } = useStyles();
|
||||||
|
|
||||||
const columns = schema
|
const columns = schema
|
||||||
.reduceProperties((buf, s) => {
|
.reduceProperties((buf, s) => {
|
||||||
@ -73,59 +139,6 @@ const useTableColumns = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const components = {
|
|
||||||
header: {
|
|
||||||
wrapper: (props) => {
|
|
||||||
return (
|
|
||||||
<DndContext>
|
|
||||||
<thead {...props} />
|
|
||||||
</DndContext>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
cell: (props) => {
|
|
||||||
return (
|
|
||||||
<th
|
|
||||||
{...props}
|
|
||||||
className={cls(
|
|
||||||
props.className,
|
|
||||||
css`
|
|
||||||
&:hover .general-schema-designer {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
body: {
|
|
||||||
wrapper: (props) => {
|
|
||||||
return (
|
|
||||||
<DndContext>
|
|
||||||
<tbody {...props} />
|
|
||||||
</DndContext>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
row: (props) => {
|
|
||||||
return <tr {...props} />;
|
|
||||||
},
|
|
||||||
cell: (props) => (
|
|
||||||
<td
|
|
||||||
{...props}
|
|
||||||
className={classNames(
|
|
||||||
props.className,
|
|
||||||
css`
|
|
||||||
max-width: 300px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const useDef = () => {
|
const useDef = () => {
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
||||||
return [selectedRowKeys, setSelectedRowKeys];
|
return [selectedRowKeys, setSelectedRowKeys];
|
||||||
@ -174,6 +187,37 @@ export const TableArray: React.FC<any> = observer(
|
|||||||
...others
|
...others
|
||||||
} = props;
|
} = props;
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useSelectedRowKeys();
|
const [selectedRowKeys, setSelectedRowKeys] = useSelectedRowKeys();
|
||||||
|
const { styles } = useStyles();
|
||||||
|
const components = useMemo(
|
||||||
|
() => ({
|
||||||
|
header: {
|
||||||
|
wrapper: (props) => {
|
||||||
|
return (
|
||||||
|
<DndContext>
|
||||||
|
<thead {...props} />
|
||||||
|
</DndContext>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
cell: (props) => {
|
||||||
|
return <th {...props} className={cls(props.className, styles.headerCell)} />;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
wrapper: (props) => {
|
||||||
|
return (
|
||||||
|
<DndContext>
|
||||||
|
<tbody {...props} />
|
||||||
|
</DndContext>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
row: (props) => {
|
||||||
|
return <tr {...props} />;
|
||||||
|
},
|
||||||
|
cell: (props) => <td {...props} className={classNames(props.className, styles.bodyCell)} />,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[styles],
|
||||||
|
);
|
||||||
useDataSource({
|
useDataSource({
|
||||||
onSuccess(data) {
|
onSuccess(data) {
|
||||||
field.value = data?.data || [];
|
field.value = data?.data || [];
|
||||||
@ -200,64 +244,14 @@ export const TableArray: React.FC<any> = observer(
|
|||||||
index = index + (current - 1) * pageSize;
|
index = index + (current - 1) * pageSize;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={classNames(checked ? 'checked' : null, styles.cell)}>
|
||||||
className={classNames(
|
<div className={classNames(checked ? 'checked' : null, styles.drag)}>
|
||||||
checked ? 'checked' : null,
|
|
||||||
css`
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-evenly;
|
|
||||||
padding-right: 8px;
|
|
||||||
.nb-table-index {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
&:not(.checked) {
|
|
||||||
.nb-table-index {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
.nb-table-index {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
.nb-origin-node {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
checked ? 'checked' : null,
|
|
||||||
css`
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-evenly;
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{dragSort && <SortHandle role="button" aria-label={`sort-handle-${record?.name || index}`} />}
|
{dragSort && <SortHandle role="button" aria-label={`sort-handle-${record?.name || index}`} />}
|
||||||
{showIndex && (
|
{showIndex && (
|
||||||
<TableIndex role="button" aria-label={`table-index-${record?.name || index}`} index={index} />
|
<TableIndex role="button" aria-label={`table-index-${record?.name || index}`} index={index} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className={classNames('nb-origin-node', checked ? 'checked' : null, styles.node)}>
|
||||||
className={classNames(
|
|
||||||
'nb-origin-node',
|
|
||||||
checked ? 'checked' : null,
|
|
||||||
css`
|
|
||||||
position: absolute;
|
|
||||||
right: 50%;
|
|
||||||
transform: translateX(50%);
|
|
||||||
&:not(.checked) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{originNode}
|
{originNode}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -273,14 +267,8 @@ export const TableArray: React.FC<any> = observer(
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={styles.table}>
|
||||||
className={css`
|
{/* @ts-ignore */}
|
||||||
.ant-table {
|
|
||||||
overflow-x: auto;
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<ReactDragListView
|
<ReactDragListView
|
||||||
handleSelector={'.drag-handle'}
|
handleSelector={'.drag-handle'}
|
||||||
onDragEnd={async (fromIndex, toIndex) => {
|
onDragEnd={async (fromIndex, toIndex) => {
|
||||||
@ -289,9 +277,7 @@ export const TableArray: React.FC<any> = observer(
|
|||||||
field.move(fromIndex, toIndex);
|
field.move(fromIndex, toIndex);
|
||||||
await move(from, to);
|
await move(from, to);
|
||||||
}}
|
}}
|
||||||
lineClassName={css`
|
lineClassName={styles.line}
|
||||||
border-bottom: 2px solid ${new TinyColor(token.colorSettings).setAlpha(0.6).toHex8String()} !important;
|
|
||||||
`}
|
|
||||||
>
|
>
|
||||||
<Table
|
<Table
|
||||||
rowKey={defaultRowKey}
|
rowKey={defaultRowKey}
|
||||||
|
@ -1,53 +1,56 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { observer } from '@tachybase/schema';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { observer } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
import { SortableItem, useDesigner } from '../..';
|
import { SortableItem, useDesigner } from '../..';
|
||||||
|
|
||||||
export const designerCss = css`
|
export const useStyles = createStyles(({ css }) => {
|
||||||
position: relative;
|
return {
|
||||||
&:hover {
|
designer: css`
|
||||||
> .general-schema-designer {
|
position: relative;
|
||||||
display: block;
|
&:hover {
|
||||||
}
|
> .general-schema-designer {
|
||||||
}
|
display: block;
|
||||||
> .general-schema-designer {
|
}
|
||||||
position: absolute;
|
|
||||||
z-index: 999;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: none;
|
|
||||||
background: var(--colorBgSettingsHover) !important;
|
|
||||||
border: 0 !important;
|
|
||||||
top: -16px !important;
|
|
||||||
bottom: -16px !important;
|
|
||||||
left: -16px !important;
|
|
||||||
right: -16px !important;
|
|
||||||
pointer-events: none;
|
|
||||||
> .general-schema-designer-icons {
|
|
||||||
position: absolute;
|
|
||||||
right: 2px;
|
|
||||||
top: 2px;
|
|
||||||
line-height: 16px;
|
|
||||||
pointer-events: all;
|
|
||||||
.ant-space-item {
|
|
||||||
background-color: var(--colorSettings);
|
|
||||||
color: #fff;
|
|
||||||
line-height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
padding-left: 1px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
}
|
||||||
}
|
> .general-schema-designer {
|
||||||
}
|
position: absolute;
|
||||||
`;
|
z-index: 999;
|
||||||
|
display: none;
|
||||||
|
background: var(--colorBgSettingsHover) !important;
|
||||||
|
border: 0 !important;
|
||||||
|
top: -16px !important;
|
||||||
|
bottom: -16px !important;
|
||||||
|
left: -16px !important;
|
||||||
|
right: -16px !important;
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: var(--colorSettings);
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const TableColumnActionBar = observer(
|
export const TableColumnActionBar = observer(
|
||||||
(props) => {
|
(props) => {
|
||||||
|
const { styles } = useStyles();
|
||||||
const Designer = useDesigner();
|
const Designer = useDesigner();
|
||||||
return (
|
return (
|
||||||
<SortableItem className={designerCss}>
|
<SortableItem className={styles.designer}>
|
||||||
<Designer />
|
<Designer />
|
||||||
{props.children}
|
{props.children}
|
||||||
</SortableItem>
|
</SortableItem>
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import React, { useLayoutEffect } from 'react';
|
import React, { useLayoutEffect } from 'react';
|
||||||
|
import { useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
import { SortableItem, useCollection_deprecated, useCompile, useDesignable, useDesigner } from '../../../';
|
import { SortableItem, useCollection_deprecated, useCompile, useDesignable, useDesigner } from '../../../';
|
||||||
import { designerCss } from './Table.Column.ActionBar';
|
import { useStyles } from './Table.Column.ActionBar';
|
||||||
|
|
||||||
export const useColumnSchema = () => {
|
export const useColumnSchema = () => {
|
||||||
const { getField } = useCollection_deprecated();
|
const { getField } = useCollection_deprecated();
|
||||||
@ -24,6 +25,7 @@ export const TableColumnDecorator = (props) => {
|
|||||||
const Designer = useDesigner();
|
const Designer = useDesigner();
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const { fieldSchema, uiSchema, collectionField } = useColumnSchema();
|
const { fieldSchema, uiSchema, collectionField } = useColumnSchema();
|
||||||
|
const { styles } = useStyles();
|
||||||
const { refresh } = useDesignable();
|
const { refresh } = useDesignable();
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
@ -38,7 +40,7 @@ export const TableColumnDecorator = (props) => {
|
|||||||
}
|
}
|
||||||
}, [uiSchema?.title]);
|
}, [uiSchema?.title]);
|
||||||
return (
|
return (
|
||||||
<SortableItem className={designerCss}>
|
<SortableItem className={styles.designer}>
|
||||||
<Designer fieldSchema={fieldSchema} uiSchema={uiSchema} collectionField={collectionField} />
|
<Designer fieldSchema={fieldSchema} uiSchema={uiSchema} collectionField={collectionField} />
|
||||||
{/* <RecursionField name={columnSchema.name} schema={columnSchema}/> */}
|
{/* <RecursionField name={columnSchema.name} schema={columnSchema}/> */}
|
||||||
{field.title || compile(uiSchema?.title)}
|
{field.title || compile(uiSchema?.title)}
|
||||||
|
@ -1,14 +1,68 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import { Tabs as AntdTabs, TabPaneProps, TabsProps } from 'antd';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
|
import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { Tabs as AntdTabs, TabPaneProps, TabsProps } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { useSchemaInitializerRender } from '../../../application';
|
||||||
import { Icon } from '../../../icon';
|
import { Icon } from '../../../icon';
|
||||||
import { DndContext, SortableItem } from '../../common';
|
import { DndContext, SortableItem } from '../../common';
|
||||||
import { useDesigner } from '../../hooks/useDesigner';
|
import { useDesigner } from '../../hooks/useDesigner';
|
||||||
import { useTabsContext } from './context';
|
import { useTabsContext } from './context';
|
||||||
import { TabsDesigner } from './Tabs.Designer';
|
import { TabsDesigner } from './Tabs.Designer';
|
||||||
import { useSchemaInitializerRender } from '../../../application';
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
designer: css`
|
||||||
|
position: relative;
|
||||||
|
&:hover {
|
||||||
|
> .general-schema-designer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.nb-action-link {
|
||||||
|
> .general-schema-designer {
|
||||||
|
top: -10px;
|
||||||
|
bottom: -10px;
|
||||||
|
left: -10px;
|
||||||
|
right: -10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .general-schema-designer {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: none;
|
||||||
|
background: var(--colorBgSettingsHover);
|
||||||
|
border: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: var(--colorSettings);
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const Tabs: any = observer(
|
export const Tabs: any = observer(
|
||||||
(props: TabsProps) => {
|
(props: TabsProps) => {
|
||||||
@ -48,60 +102,13 @@ export const Tabs: any = observer(
|
|||||||
{ displayName: 'Tabs' },
|
{ displayName: 'Tabs' },
|
||||||
);
|
);
|
||||||
|
|
||||||
const designerCss = css`
|
|
||||||
position: relative;
|
|
||||||
&:hover {
|
|
||||||
> .general-schema-designer {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.nb-action-link {
|
|
||||||
> .general-schema-designer {
|
|
||||||
top: -10px;
|
|
||||||
bottom: -10px;
|
|
||||||
left: -10px;
|
|
||||||
right: -10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
> .general-schema-designer {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 999;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: none;
|
|
||||||
background: var(--colorBgSettingsHover);
|
|
||||||
border: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
> .general-schema-designer-icons {
|
|
||||||
position: absolute;
|
|
||||||
right: 2px;
|
|
||||||
top: 2px;
|
|
||||||
line-height: 16px;
|
|
||||||
pointer-events: all;
|
|
||||||
.ant-space-item {
|
|
||||||
background-color: var(--colorSettings);
|
|
||||||
color: #fff;
|
|
||||||
line-height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
padding-left: 1px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
Tabs.TabPane = observer(
|
Tabs.TabPane = observer(
|
||||||
(props: TabPaneProps & { icon?: any }) => {
|
(props: TabPaneProps & { icon?: any }) => {
|
||||||
|
const { styles } = useStyles();
|
||||||
const Designer = useDesigner();
|
const Designer = useDesigner();
|
||||||
const field = useField();
|
const field = useField();
|
||||||
return (
|
return (
|
||||||
<SortableItem className={classNames('nb-action-link', designerCss, props.className)}>
|
<SortableItem className={classNames('nb-action-link', styles.designer, props.className)}>
|
||||||
{props.icon && <Icon style={{ marginRight: 2 }} type={props.icon} />} {props.tab || field.title}
|
{props.icon && <Icon style={{ marginRight: 2 }} type={props.icon} />} {props.tab || field.title}
|
||||||
<Designer />
|
<Designer />
|
||||||
</SortableItem>
|
</SortableItem>
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
import { CloseCircleFilled } from '@ant-design/icons';
|
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||||
import { css, cx } from '@emotion/css';
|
|
||||||
import { useForm } from '@tachybase/schema';
|
import { useForm } from '@tachybase/schema';
|
||||||
import { error } from '@tachybase/utils/client';
|
import { error } from '@tachybase/utils/client';
|
||||||
|
|
||||||
|
import { CloseCircleFilled } from '@ant-design/icons';
|
||||||
import { Input as AntInput, Cascader, DatePicker, InputNumber, Select, Space, Tag } from 'antd';
|
import { Input as AntInput, Cascader, DatePicker, InputNumber, Select, Space, Tag } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import useAntdInputStyle from 'antd/es/input/style';
|
import useAntdInputStyle from 'antd/es/input/style';
|
||||||
import type { DefaultOptionType } from 'antd/lib/cascader';
|
import type { DefaultOptionType } from 'antd/lib/cascader';
|
||||||
|
import cx from 'classnames';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { useCompile } from '../../hooks';
|
import { useCompile } from '../../hooks';
|
||||||
import { XButton } from './XButton';
|
|
||||||
import { useStyles } from './style';
|
import { useStyles } from './style';
|
||||||
|
import { XButton } from './XButton';
|
||||||
|
|
||||||
const JT_VALUE_RE = /^\s*{{\s*([^{}]+)\s*}}\s*$/;
|
const JT_VALUE_RE = /^\s*{{\s*([^{}]+)\s*}}\s*$/;
|
||||||
|
|
||||||
@ -129,6 +132,39 @@ function getTypedConstantOption(type: string, types: true | string[], fieldNames
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useStyles2 = createStyles(({ css }, { props: { disabled: boolean } }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
position: relative;
|
||||||
|
line-height: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.clear-button {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-input {
|
||||||
|
overflow: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
${disabled ? '' : 'padding-right: 28px;'}
|
||||||
|
|
||||||
|
.ant-tag {
|
||||||
|
display: inline;
|
||||||
|
line-height: 19px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 2px 7px;
|
||||||
|
border-radius: 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
button: css`
|
||||||
|
margin-left: -1px;
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export function Input(props) {
|
export function Input(props) {
|
||||||
const {
|
const {
|
||||||
value = '',
|
value = '',
|
||||||
@ -259,40 +295,12 @@ export function Input(props) {
|
|||||||
}, [variable, options.length]);
|
}, [variable, options.length]);
|
||||||
|
|
||||||
const disabled = props.disabled || form.disabled;
|
const disabled = props.disabled || form.disabled;
|
||||||
|
const { styles: styles2 } = useStyles2({ disabled });
|
||||||
|
|
||||||
return wrapSSR(
|
return wrapSSR(
|
||||||
<Space.Compact style={style} className={classNames(componentCls, hashId, className)}>
|
<Space.Compact style={style} className={classNames(componentCls, hashId, className)}>
|
||||||
{variable ? (
|
{variable ? (
|
||||||
<div
|
<div className={cx('variable', styles2.container)}>
|
||||||
className={cx(
|
|
||||||
'variable',
|
|
||||||
css`
|
|
||||||
position: relative;
|
|
||||||
line-height: 0;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.clear-button {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-input {
|
|
||||||
overflow: auto;
|
|
||||||
white-space: nowrap;
|
|
||||||
${disabled ? '' : 'padding-right: 28px;'}
|
|
||||||
|
|
||||||
.ant-tag {
|
|
||||||
display: inline;
|
|
||||||
line-height: 19px;
|
|
||||||
margin: 0;
|
|
||||||
padding: 2px 7px;
|
|
||||||
border-radius: 10px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="variable-tag"
|
aria-label="variable-tag"
|
||||||
@ -341,14 +349,7 @@ export function Input(props) {
|
|||||||
fieldNames={fieldNames}
|
fieldNames={fieldNames}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{button ?? (
|
{button ?? <XButton className={styles2.button} type={variable ? 'primary' : 'default'} />}
|
||||||
<XButton
|
|
||||||
className={css(`
|
|
||||||
margin-left: -1px;
|
|
||||||
`)}
|
|
||||||
type={variable ? 'primary' : 'default'}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Cascader>
|
</Cascader>
|
||||||
</Space.Compact>,
|
</Space.Compact>,
|
||||||
);
|
);
|
||||||
|
@ -1,21 +1,23 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
import { Input } from '../input';
|
import { Input } from '../input';
|
||||||
import { RawTextArea } from './RawTextArea';
|
import { RawTextArea } from './RawTextArea';
|
||||||
import { css } from '@emotion/css';
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
button: css`
|
||||||
|
&:not(:hover) {
|
||||||
|
border-right-color: transparent;
|
||||||
|
border-top-color: transparent;
|
||||||
|
}
|
||||||
|
background-color: transparent;
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export function JSONInput(props) {
|
export function JSONInput(props) {
|
||||||
return (
|
const { styles } = useStyles();
|
||||||
<RawTextArea
|
return <RawTextArea buttonClass={styles.button} {...props} component={Input.JSON} />;
|
||||||
buttonClass={css`
|
|
||||||
&:not(:hover) {
|
|
||||||
border-right-color: transparent;
|
|
||||||
border-top-color: transparent;
|
|
||||||
}
|
|
||||||
background-color: transparent;
|
|
||||||
`}
|
|
||||||
{...props}
|
|
||||||
component={Input.JSON}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React, { useRef, useState } from 'react';
|
import React, { useRef, useState } from 'react';
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { Button, Input } from 'antd';
|
import { Button, Input } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
|
|
||||||
import { VariableSelect } from './VariableSelect';
|
import { VariableSelect } from './VariableSelect';
|
||||||
@ -16,11 +17,38 @@ function setNativeInputValue(input, value) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
position: relative;
|
||||||
|
.ant-input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
group: css`
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
.ant-btn-sm {
|
||||||
|
font-size: 85%;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
select: css`
|
||||||
|
&:not(:hover) {
|
||||||
|
border-right-color: transparent;
|
||||||
|
border-top-color: transparent;
|
||||||
|
}
|
||||||
|
background-color: transparent;
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export function RawTextArea(props): JSX.Element {
|
export function RawTextArea(props): JSX.Element {
|
||||||
const inputRef = useRef<any>(null);
|
const inputRef = useRef<any>(null);
|
||||||
const { changeOnSelect, component: Component = Input.TextArea, ...others } = props;
|
const { changeOnSelect, component: Component = Input.TextArea, ...others } = props;
|
||||||
const scope = typeof props.scope === 'function' ? props.scope() : props.scope;
|
const scope = typeof props.scope === 'function' ? props.scope() : props.scope;
|
||||||
const [options, setOptions] = useState(scope ? cloneDeep(scope) : []);
|
const [options, setOptions] = useState(scope ? cloneDeep(scope) : []);
|
||||||
|
const { styles } = useStyles();
|
||||||
|
|
||||||
function onInsert(selected) {
|
function onInsert(selected) {
|
||||||
if (!inputRef.current) {
|
if (!inputRef.current) {
|
||||||
@ -38,36 +66,11 @@ export function RawTextArea(props): JSX.Element {
|
|||||||
textArea.focus();
|
textArea.focus();
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={styles.container}>
|
||||||
className={css`
|
|
||||||
position: relative;
|
|
||||||
.ant-input {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<Component {...others} ref={inputRef} />
|
<Component {...others} ref={inputRef} />
|
||||||
<Button.Group
|
<Button.Group className={styles.group}>
|
||||||
className={css`
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
.ant-btn-sm {
|
|
||||||
font-size: 85%;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<VariableSelect
|
<VariableSelect
|
||||||
className={
|
className={props.buttonClass ?? styles.select}
|
||||||
props.buttonClass ??
|
|
||||||
css`
|
|
||||||
&:not(:hover) {
|
|
||||||
border-right-color: transparent;
|
|
||||||
border-top-color: transparent;
|
|
||||||
}
|
|
||||||
background-color: transparent;
|
|
||||||
`
|
|
||||||
}
|
|
||||||
fieldNames={props.fieldNames}
|
fieldNames={props.fieldNames}
|
||||||
options={options}
|
options={options}
|
||||||
setOptions={setOptions}
|
setOptions={setOptions}
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
|
||||||
import { useForm } from '@tachybase/schema';
|
|
||||||
import { Input, Space } from 'antd';
|
|
||||||
import { cloneDeep } from 'lodash';
|
|
||||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import sanitizeHTML from 'sanitize-html';
|
import { useForm } from '@tachybase/schema';
|
||||||
|
|
||||||
import { error } from '@tachybase/utils/client';
|
import { error } from '@tachybase/utils/client';
|
||||||
|
|
||||||
|
import { Space } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import cx from 'classnames';
|
||||||
|
import { cloneDeep } from 'lodash';
|
||||||
|
import sanitizeHTML from 'sanitize-html';
|
||||||
|
|
||||||
import { EllipsisWithTooltip } from '../..';
|
import { EllipsisWithTooltip } from '../..';
|
||||||
import { VariableSelect } from './VariableSelect';
|
|
||||||
import { useStyles } from './style';
|
import { useStyles } from './style';
|
||||||
|
import { VariableSelect } from './VariableSelect';
|
||||||
|
|
||||||
type RangeIndexes = [number, number, number, number];
|
type RangeIndexes = [number, number, number, number];
|
||||||
|
|
||||||
@ -187,12 +188,60 @@ function getCurrentRange(element: HTMLElement): RangeIndexes {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useStyles2 = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
&.ant-input-group.ant-input-group-compact {
|
||||||
|
display: flex;
|
||||||
|
.ant-input {
|
||||||
|
flex-grow: 1;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
.ant-input-disabled {
|
||||||
|
.ant-tag {
|
||||||
|
color: #bfbfbf;
|
||||||
|
border-color: #d9d9d9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .x-button {
|
||||||
|
height: min-content;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
button: css`
|
||||||
|
overflow: auto;
|
||||||
|
white-space: ${multiline ? 'normal' : 'nowrap'};
|
||||||
|
|
||||||
|
.ant-tag {
|
||||||
|
display: inline;
|
||||||
|
line-height: 19px;
|
||||||
|
margin: 0 0.5em;
|
||||||
|
padding: 2px 7px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
pretty: css`
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
.ant-tag {
|
||||||
|
display: inline;
|
||||||
|
line-height: 19px;
|
||||||
|
margin: 0 0.25em;
|
||||||
|
padding: 2px 7px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export function TextArea(props) {
|
export function TextArea(props) {
|
||||||
const { wrapSSR, hashId, componentCls } = useStyles();
|
const { wrapSSR, hashId, componentCls } = useStyles();
|
||||||
const { value = '', scope, onChange, multiline = true, changeOnSelect } = props;
|
const { value = '', scope, onChange, multiline = true, changeOnSelect } = props;
|
||||||
const inputRef = useRef<HTMLDivElement>(null);
|
const inputRef = useRef<HTMLDivElement>(null);
|
||||||
const [options, setOptions] = useState([]);
|
const [options, setOptions] = useState([]);
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
|
const { styles } = useStyles2();
|
||||||
const keyLabelMap = useMemo(() => createOptionsValueLabelMap(options), [options]);
|
const keyLabelMap = useMemo(() => createOptionsValueLabelMap(options), [options]);
|
||||||
const [ime, setIME] = useState<boolean>(false);
|
const [ime, setIME] = useState<boolean>(false);
|
||||||
const [changed, setChanged] = useState(false);
|
const [changed, setChanged] = useState(false);
|
||||||
@ -360,31 +409,7 @@ export function TextArea(props) {
|
|||||||
const disabled = props.disabled || form.disabled;
|
const disabled = props.disabled || form.disabled;
|
||||||
|
|
||||||
return wrapSSR(
|
return wrapSSR(
|
||||||
<Space.Compact
|
<Space.Compact className={cx(componentCls, hashId, styles.container)}>
|
||||||
className={cx(
|
|
||||||
componentCls,
|
|
||||||
hashId,
|
|
||||||
css`
|
|
||||||
&.ant-input-group.ant-input-group-compact {
|
|
||||||
display: flex;
|
|
||||||
.ant-input {
|
|
||||||
flex-grow: 1;
|
|
||||||
min-width: 200px;
|
|
||||||
}
|
|
||||||
.ant-input-disabled {
|
|
||||||
.ant-tag {
|
|
||||||
color: #bfbfbf;
|
|
||||||
border-color: #d9d9d9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .x-button {
|
|
||||||
height: min-content;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="textbox"
|
aria-label="textbox"
|
||||||
@ -394,23 +419,7 @@ export function TextArea(props) {
|
|||||||
onPaste={onPaste}
|
onPaste={onPaste}
|
||||||
onCompositionStart={onCompositionStart}
|
onCompositionStart={onCompositionStart}
|
||||||
onCompositionEnd={onCompositionEnd}
|
onCompositionEnd={onCompositionEnd}
|
||||||
className={cx(
|
className={cx(hashId, 'ant-input', { 'ant-input-disabled': disabled }, styles.button)}
|
||||||
hashId,
|
|
||||||
'ant-input',
|
|
||||||
{ 'ant-input-disabled': disabled },
|
|
||||||
css`
|
|
||||||
overflow: auto;
|
|
||||||
white-space: ${multiline ? 'normal' : 'nowrap'};
|
|
||||||
|
|
||||||
.ant-tag {
|
|
||||||
display: inline;
|
|
||||||
line-height: 19px;
|
|
||||||
margin: 0 0.5em;
|
|
||||||
padding: 2px 7px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
contentEditable={!disabled}
|
contentEditable={!disabled}
|
||||||
dangerouslySetInnerHTML={{ __html: html }}
|
dangerouslySetInnerHTML={{ __html: html }}
|
||||||
@ -458,12 +467,13 @@ async function preloadOptions(scope, value) {
|
|||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextArea.ReadPretty = function ReadPretty(props): JSX.Element {
|
TextArea.ReadPretty = function ReadPretty(props) {
|
||||||
const { value } = props;
|
const { value } = props;
|
||||||
const scope = typeof props.scope === 'function' ? props.scope() : props.scope;
|
const scope = typeof props.scope === 'function' ? props.scope() : props.scope;
|
||||||
|
|
||||||
const [options, setOptions] = useState([]);
|
const [options, setOptions] = useState([]);
|
||||||
const keyLabelMap = useMemo(() => createOptionsValueLabelMap(options), [options]);
|
const keyLabelMap = useMemo(() => createOptionsValueLabelMap(options), [options]);
|
||||||
|
const { styles } = useStyles2();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
preloadOptions(scope, value)
|
preloadOptions(scope, value)
|
||||||
@ -474,22 +484,7 @@ TextArea.ReadPretty = function ReadPretty(props): JSX.Element {
|
|||||||
}, [scope, value]);
|
}, [scope, value]);
|
||||||
const html = renderHTML(value ?? '', keyLabelMap);
|
const html = renderHTML(value ?? '', keyLabelMap);
|
||||||
|
|
||||||
const content = (
|
const content = <span dangerouslySetInnerHTML={{ __html: html }} className={styles.pretty} />;
|
||||||
<span
|
|
||||||
dangerouslySetInnerHTML={{ __html: html }}
|
|
||||||
className={css`
|
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
.ant-tag {
|
|
||||||
display: inline;
|
|
||||||
line-height: 19px;
|
|
||||||
margin: 0 0.25em;
|
|
||||||
padding: 2px 7px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EllipsisWithTooltip ellipsis popoverContent={content}>
|
<EllipsisWithTooltip ellipsis popoverContent={content}>
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { cx } from '@emotion/css';
|
|
||||||
import { Cascader } from 'antd';
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
import { Cascader } from 'antd';
|
||||||
|
import cx from 'classnames';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { useToken } from '../__builtins__';
|
import { useToken } from '../__builtins__';
|
||||||
import useStyles from './VariableSelect.style';
|
import useStyles from './VariableSelect.style';
|
||||||
import { XButton } from './XButton';
|
import { XButton } from './XButton';
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
import React, { createContext, HTMLAttributes, useContext, useMemo } from 'react';
|
||||||
|
import { observer, Schema, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
import { TinyColor } from '@ctrl/tinycolor';
|
import { TinyColor } from '@ctrl/tinycolor';
|
||||||
import { useDraggable, useDroppable } from '@dnd-kit/core';
|
import { useDraggable, useDroppable } from '@dnd-kit/core';
|
||||||
import { cx } from '@emotion/css';
|
import cx from 'classnames';
|
||||||
import { Schema, observer, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import React, { HTMLAttributes, createContext, useContext, useMemo } from 'react';
|
|
||||||
import { useToken } from '../../antd/__builtins__';
|
import { useToken } from '../../antd/__builtins__';
|
||||||
|
|
||||||
export const DraggableContext = createContext(null);
|
export const DraggableContext = createContext(null);
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { DownOutlined } from '@ant-design/icons';
|
import React, { createRef, forwardRef, useEffect, useMemo, useState } from 'react';
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { observer, RecursionField, useField, useFieldSchema, useForm } from '@tachybase/schema';
|
import { observer, RecursionField, useField, useFieldSchema, useForm } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { DownOutlined } from '@ant-design/icons';
|
||||||
import { Button, Dropdown, MenuProps } from 'antd';
|
import { Button, Dropdown, MenuProps } from 'antd';
|
||||||
import React, { useEffect, useMemo, useState, forwardRef, createRef } from 'react';
|
import { createStyles } from 'antd-style';
|
||||||
import { composeRef } from 'rc-util/lib/ref';
|
import { composeRef } from 'rc-util/lib/ref';
|
||||||
|
|
||||||
import { useDesignable } from '../../';
|
import { useDesignable } from '../../';
|
||||||
import { useACLRolesCheck, useRecordPkValue } from '../../acl/ACLProvider';
|
import { useACLRolesCheck, useRecordPkValue } from '../../acl/ACLProvider';
|
||||||
import {
|
import {
|
||||||
@ -17,45 +19,45 @@ import { linkageAction } from '../../schema-component/antd/action/utils';
|
|||||||
import { parseVariables } from '../../schema-component/common/utils/uitls';
|
import { parseVariables } from '../../schema-component/common/utils/uitls';
|
||||||
import { useLocalVariables, useVariables } from '../../variables';
|
import { useLocalVariables, useVariables } from '../../variables';
|
||||||
|
|
||||||
export const actionDesignerCss = css`
|
const useStyles = createStyles(({ css }) => {
|
||||||
position: relative;
|
return {
|
||||||
&:hover {
|
designer: css`
|
||||||
.general-schema-designer {
|
position: relative;
|
||||||
display: block;
|
&:hover {
|
||||||
}
|
.general-schema-designer {
|
||||||
}
|
display: block;
|
||||||
.general-schema-designer {
|
}
|
||||||
position: absolute;
|
|
||||||
z-index: 999;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: none;
|
|
||||||
background: var(--colorBgSettingsHover);
|
|
||||||
border: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
> .general-schema-designer-icons {
|
|
||||||
position: absolute;
|
|
||||||
right: 2px;
|
|
||||||
top: 2px;
|
|
||||||
line-height: 16px;
|
|
||||||
pointer-events: all;
|
|
||||||
.ant-space-item {
|
|
||||||
background-color: var(--colorSettings);
|
|
||||||
color: #fff;
|
|
||||||
line-height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
padding-left: 1px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
}
|
||||||
}
|
.general-schema-designer {
|
||||||
}
|
position: absolute;
|
||||||
`;
|
z-index: 999;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: none;
|
||||||
|
background: var(--colorBgSettingsHover);
|
||||||
|
border: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: var(--colorSettings);
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export function useAclCheck(actionPath) {
|
export function useAclCheck(actionPath) {
|
||||||
const aclCheck = useAclCheckFn();
|
const aclCheck = useAclCheckFn();
|
||||||
@ -108,6 +110,7 @@ const InternalCreateRecordAction = (props: any, ref) => {
|
|||||||
const values = useRecord();
|
const values = useRecord();
|
||||||
const ctx = useActionContext();
|
const ctx = useActionContext();
|
||||||
const variables = useVariables();
|
const variables = useVariables();
|
||||||
|
const { styles } = useStyles();
|
||||||
const localVariables = useLocalVariables({ currentForm: { values } as any });
|
const localVariables = useLocalVariables({ currentForm: { values } as any });
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
field.stateOfLinkageRules = {};
|
field.stateOfLinkageRules = {};
|
||||||
@ -129,7 +132,7 @@ const InternalCreateRecordAction = (props: any, ref) => {
|
|||||||
const buttonRef = composeRef(ref, internalRef);
|
const buttonRef = composeRef(ref, internalRef);
|
||||||
return (
|
return (
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
<div className={actionDesignerCss} ref={buttonRef as React.Ref<HTMLButtonElement>}>
|
<div className={styles.actionDesignerCss} ref={buttonRef as React.Ref<HTMLButtonElement>}>
|
||||||
<ActionContextProvider value={{ ...ctx, visible, setVisible }}>
|
<ActionContextProvider value={{ ...ctx, visible, setVisible }}>
|
||||||
<CreateAction
|
<CreateAction
|
||||||
{...props}
|
{...props}
|
||||||
@ -201,6 +204,7 @@ export const CreateAction = observer(
|
|||||||
const localVariables = useLocalVariables({ currentForm: { values } as any });
|
const localVariables = useLocalVariables({ currentForm: { values } as any });
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const { designable } = useDesignable();
|
const { designable } = useDesignable();
|
||||||
|
const { styles } = useStyles();
|
||||||
const icon = props.icon || null;
|
const icon = props.icon || null;
|
||||||
const menuItems = useMemo<MenuProps['items']>(() => {
|
const menuItems = useMemo<MenuProps['items']>(() => {
|
||||||
return inheritsCollections.map((option) => ({
|
return inheritsCollections.map((option) => ({
|
||||||
@ -233,7 +237,7 @@ export const CreateAction = observer(
|
|||||||
});
|
});
|
||||||
}, [field, linkageRules, localVariables, variables]);
|
}, [field, linkageRules, localVariables, variables]);
|
||||||
return (
|
return (
|
||||||
<div className={actionDesignerCss}>
|
<div className={styles.actionDesignerCss}>
|
||||||
<FinallyButton
|
<FinallyButton
|
||||||
{...{
|
{...{
|
||||||
inheritsCollections,
|
inheritsCollections,
|
||||||
|
@ -1,51 +1,20 @@
|
|||||||
import { DragOutlined, MenuOutlined, PlusOutlined } from '@ant-design/icons';
|
import React, { FC, PropsWithChildren, useEffect, useMemo, useRef } from 'react';
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { useField, useFieldSchema } from '@tachybase/schema';
|
import { useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { DragOutlined, MenuOutlined, PlusOutlined } from '@ant-design/icons';
|
||||||
import { Space } from 'antd';
|
import { Space } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { FC, PropsWithChildren, useEffect, useMemo, useRef } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { SchemaToolbarProvider, useSchemaInitializerRender, useSchemaSettingsRender } from '../application';
|
import { SchemaToolbarProvider, useSchemaInitializerRender, useSchemaSettingsRender } from '../application';
|
||||||
import { useDataSourceManager } from '../data-source/data-source/DataSourceManagerProvider';
|
import { useDataSourceManager } from '../data-source/data-source/DataSourceManagerProvider';
|
||||||
import { useDataSource } from '../data-source/data-source/DataSourceProvider';
|
import { useDataSource } from '../data-source/data-source/DataSourceProvider';
|
||||||
import { DragHandler, useCompile, useDesignable, useGridContext, useGridRowContext } from '../schema-component';
|
import { DragHandler, useCompile, useDesignable, useGridContext, useGridRowContext } from '../schema-component';
|
||||||
import { gridRowColWrap } from '../schema-initializer/utils';
|
import { gridRowColWrap } from '../schema-initializer/utils';
|
||||||
import { SchemaSettingsDropdown } from './SchemaSettings';
|
|
||||||
import { useGetAriaLabelOfDesigner } from './hooks/useGetAriaLabelOfDesigner';
|
import { useGetAriaLabelOfDesigner } from './hooks/useGetAriaLabelOfDesigner';
|
||||||
|
import { SchemaSettingsDropdown } from './SchemaSettings';
|
||||||
import { useStyles } from './styles';
|
import { useStyles } from './styles';
|
||||||
|
|
||||||
const titleCss = css`
|
|
||||||
pointer-events: none;
|
|
||||||
position: absolute;
|
|
||||||
font-size: 12px;
|
|
||||||
/* background: var(--colorSettings);
|
|
||||||
color: #fff; */
|
|
||||||
padding: 0;
|
|
||||||
line-height: 16px;
|
|
||||||
height: 16px;
|
|
||||||
border-bottom-right-radius: 2px;
|
|
||||||
border-radius: 2px;
|
|
||||||
top: 2px;
|
|
||||||
left: 2px;
|
|
||||||
.title-tag {
|
|
||||||
padding: 0 3px;
|
|
||||||
border-radius: 2px;
|
|
||||||
background: var(--colorSettings);
|
|
||||||
color: #fff;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const overrideAntdCSS = css`
|
|
||||||
& .ant-space-item .anticon {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
display: block !important;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export interface GeneralSchemaDesignerProps {
|
export interface GeneralSchemaDesignerProps {
|
||||||
disableInitializer?: boolean;
|
disableInitializer?: boolean;
|
||||||
title?: string;
|
title?: string;
|
||||||
@ -89,6 +58,7 @@ export const GeneralSchemaDesigner: FC<PropsWithChildren<GeneralSchemaDesignerPr
|
|||||||
);
|
);
|
||||||
const rowCtx = useGridRowContext();
|
const rowCtx = useGridRowContext();
|
||||||
const ctx = useGridContext();
|
const ctx = useGridContext();
|
||||||
|
const { styles } = useStyles();
|
||||||
const dm = useDataSourceManager();
|
const dm = useDataSourceManager();
|
||||||
const dataSources = dm?.getDataSources();
|
const dataSources = dm?.getDataSources();
|
||||||
const dataSourceContext = useDataSource();
|
const dataSourceContext = useDataSource();
|
||||||
@ -116,9 +86,9 @@ export const GeneralSchemaDesigner: FC<PropsWithChildren<GeneralSchemaDesignerPr
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<SchemaToolbarProvider {...contextValue}>
|
<SchemaToolbarProvider {...contextValue}>
|
||||||
<div className={classNames('general-schema-designer', overrideAntdCSS)}>
|
<div className={classNames('general-schema-designer', styles.overrideAntdCSS)}>
|
||||||
{title && (
|
{title && (
|
||||||
<div className={classNames('general-schema-designer-title', titleCss)}>
|
<div className={classNames('general-schema-designer-title', styles.titleCss)}>
|
||||||
<Space size={2}>
|
<Space size={2}>
|
||||||
<span className={'title-tag'}>
|
<span className={'title-tag'}>
|
||||||
{showDataSource && dataSource
|
{showDataSource && dataSource
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createStyles } from 'antd-style';
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
export const useStyles = createStyles(() => {
|
export const useStyles = createStyles(({ css }) => {
|
||||||
return {
|
return {
|
||||||
toolbar: {
|
toolbar: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@ -52,5 +52,35 @@ export const useStyles = createStyles(() => {
|
|||||||
alignSelf: 'stretch',
|
alignSelf: 'stretch',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
titleCss: css`
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
font-size: 12px;
|
||||||
|
/* background: var(--colorSettings);
|
||||||
|
color: #fff; */
|
||||||
|
padding: 0;
|
||||||
|
line-height: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-bottom-right-radius: 2px;
|
||||||
|
border-radius: 2px;
|
||||||
|
top: 2px;
|
||||||
|
left: 2px;
|
||||||
|
.title-tag {
|
||||||
|
padding: 0 3px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: var(--colorSettings);
|
||||||
|
color: #fff;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
overrideAntdCSS: css`
|
||||||
|
& .ant-space-item .anticon {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user