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