fix: bulk update keys should obtained when clicked (#1040)
Reviewed-on: daoyoucloud/tachybase#1040
This commit is contained in:
parent
057e8d4aa8
commit
b1dfce33cd
@ -1,15 +1,23 @@
|
|||||||
import { Field, Form } from '@tachybase/schema';
|
import { ChangeEvent, useCallback, useContext, useEffect, useMemo } from 'react';
|
||||||
import { SchemaExpressionScopeContext, useField, useFieldSchema, useForm } from '@tachybase/schema';
|
import {
|
||||||
import { untracked } from '@tachybase/schema';
|
Field,
|
||||||
|
Form,
|
||||||
|
SchemaExpressionScopeContext,
|
||||||
|
untracked,
|
||||||
|
useField,
|
||||||
|
useFieldSchema,
|
||||||
|
useForm,
|
||||||
|
} from '@tachybase/schema';
|
||||||
import { isURL, parse } from '@tachybase/utils/client';
|
import { isURL, parse } from '@tachybase/utils/client';
|
||||||
|
|
||||||
import { App, message } from 'antd';
|
import { App, message } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import omit from 'lodash/omit';
|
import omit from 'lodash/omit';
|
||||||
import { ChangeEvent, useCallback, useContext, useEffect, useMemo } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useReactToPrint } from 'react-to-print';
|
import { useReactToPrint } from 'react-to-print';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AssociationFilter,
|
AssociationFilter,
|
||||||
useCollectionRecord,
|
useCollectionRecord,
|
||||||
@ -20,7 +28,7 @@ import {
|
|||||||
useTableBlockContext,
|
useTableBlockContext,
|
||||||
} from '../..';
|
} from '../..';
|
||||||
import { useAPIClient, useRequest } from '../../api-client';
|
import { useAPIClient, useRequest } from '../../api-client';
|
||||||
import { useCollectionManager_deprecated, useCollection_deprecated } from '../../collection-manager';
|
import { useCollection_deprecated, useCollectionManager_deprecated } from '../../collection-manager';
|
||||||
import { useFilterBlock } from '../../filter-provider/FilterProvider';
|
import { useFilterBlock } from '../../filter-provider/FilterProvider';
|
||||||
import { mergeFilter, transformToFilter } from '../../filter-provider/utils';
|
import { mergeFilter, transformToFilter } from '../../filter-provider/utils';
|
||||||
import { useRecord } from '../../record-provider';
|
import { useRecord } from '../../record-provider';
|
||||||
@ -592,123 +600,6 @@ export const useCustomizeUpdateActionProps = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useCustomizeBulkUpdateActionProps = () => {
|
|
||||||
const { field, resource, __parent, service } = useBlockRequestContext();
|
|
||||||
const expressionScope = useContext(SchemaExpressionScopeContext);
|
|
||||||
const actionSchema = useFieldSchema();
|
|
||||||
const tableBlockContext = useTableBlockContext();
|
|
||||||
const { rowKey } = tableBlockContext;
|
|
||||||
const selectedRecordKeys =
|
|
||||||
tableBlockContext.field?.data?.selectedRowKeys ?? expressionScope?.selectedRecordKeys ?? {};
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const compile = useCompile();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const actionField = useField();
|
|
||||||
const { modal } = App.useApp();
|
|
||||||
const variables = useVariables();
|
|
||||||
const record = useRecord();
|
|
||||||
const { name, getField } = useCollection_deprecated();
|
|
||||||
const localVariables = useLocalVariables();
|
|
||||||
|
|
||||||
return {
|
|
||||||
async onClick() {
|
|
||||||
const {
|
|
||||||
assignedValues: originalAssignedValues = {},
|
|
||||||
onSuccess,
|
|
||||||
updateMode,
|
|
||||||
} = actionSchema?.['x-action-settings'] ?? {};
|
|
||||||
actionField.data = field.data || {};
|
|
||||||
actionField.data.loading = true;
|
|
||||||
|
|
||||||
const assignedValues = {};
|
|
||||||
const waitList = Object.keys(originalAssignedValues).map(async (key) => {
|
|
||||||
const value = originalAssignedValues[key];
|
|
||||||
const collectionField = getField(key);
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
|
||||||
if (!collectionField) {
|
|
||||||
throw new Error(`useCustomizeBulkUpdateActionProps: field "${key}" not found in collection "${name}"`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isVariable(value)) {
|
|
||||||
const result = await variables?.parseVariable(value, localVariables);
|
|
||||||
if (result) {
|
|
||||||
assignedValues[key] = transformVariableValue(result, { targetCollectionField: collectionField });
|
|
||||||
}
|
|
||||||
} else if (value != null && value !== '') {
|
|
||||||
assignedValues[key] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
await Promise.all(waitList);
|
|
||||||
|
|
||||||
modal.confirm({
|
|
||||||
title: t('Bulk update'),
|
|
||||||
content: updateMode === 'selected' ? t('Update selected data?') : t('Update all data?'),
|
|
||||||
async onOk() {
|
|
||||||
const { filter } = service.params?.[0] ?? {};
|
|
||||||
const updateData: { filter?: any; values: any; forceUpdate: boolean } = {
|
|
||||||
values: { ...assignedValues },
|
|
||||||
filter,
|
|
||||||
forceUpdate: false,
|
|
||||||
};
|
|
||||||
if (updateMode === 'selected') {
|
|
||||||
if (!selectedRecordKeys?.length) {
|
|
||||||
message.error(t('Please select the records to be updated'));
|
|
||||||
actionField.data.loading = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
updateData.filter = { $and: [{ [rowKey || 'id']: { $in: selectedRecordKeys } }] };
|
|
||||||
}
|
|
||||||
if (!updateData.filter) {
|
|
||||||
updateData.forceUpdate = true;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await resource.update(updateData);
|
|
||||||
} catch (error) {
|
|
||||||
/* empty */
|
|
||||||
} finally {
|
|
||||||
actionField.data.loading = false;
|
|
||||||
}
|
|
||||||
service?.refresh?.();
|
|
||||||
if (!(resource instanceof TableFieldResource)) {
|
|
||||||
__parent?.service?.refresh?.();
|
|
||||||
}
|
|
||||||
if (!onSuccess?.successMessage) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (onSuccess?.manualClose) {
|
|
||||||
modal.success({
|
|
||||||
title: compile(onSuccess?.successMessage),
|
|
||||||
onOk: async () => {
|
|
||||||
if (onSuccess?.redirecting && onSuccess?.redirectTo) {
|
|
||||||
if (isURL(onSuccess.redirectTo)) {
|
|
||||||
window.location.href = onSuccess.redirectTo;
|
|
||||||
} else {
|
|
||||||
navigate(onSuccess.redirectTo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
message.success(compile(onSuccess?.successMessage));
|
|
||||||
if (onSuccess?.redirecting && onSuccess?.redirectTo) {
|
|
||||||
if (isURL(onSuccess.redirectTo)) {
|
|
||||||
window.location.href = onSuccess.redirectTo;
|
|
||||||
} else {
|
|
||||||
navigate(onSuccess.redirectTo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async onCancel() {
|
|
||||||
actionField.data.loading = false;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useCustomizeRequestActionProps = () => {
|
export const useCustomizeRequestActionProps = () => {
|
||||||
const apiClient = useAPIClient();
|
const apiClient = useAPIClient();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
import React, { createContext, ReactNode, useCallback, useContext, useRef } from 'react';
|
||||||
|
|
||||||
import { MenuProps } from 'antd';
|
import { MenuProps } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { createContext, ReactNode, useCallback, useContext, useRef } from 'react';
|
|
||||||
|
|
||||||
type Item = MenuProps['items'][0] & {
|
type Item = MenuProps['items'][0] & {
|
||||||
/** 在清空数组时,如果该字段为 true 则保留该选项 */
|
/** 在清空数组时,如果该字段为 true 则保留该选项 */
|
||||||
@ -35,7 +36,7 @@ export const useMenuItem = () => {
|
|||||||
const renderItems = useRef<() => JSX.Element>(null);
|
const renderItems = useRef<() => JSX.Element>(null);
|
||||||
const shouldRerender = useRef(false);
|
const shouldRerender = useRef(false);
|
||||||
|
|
||||||
const Component = useCallback(({ limitCount }) => {
|
const Component = useCallback(({ limitCount }: { limitCount?: number }) => {
|
||||||
if (!shouldRerender.current) {
|
if (!shouldRerender.current) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useToken } from '../style';
|
|
||||||
|
import { createStyles } from '../style';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css, token }) => {
|
||||||
|
return {
|
||||||
|
powerBy: css`
|
||||||
|
text-align: center;
|
||||||
|
color: ${token.colorTextDescription};
|
||||||
|
a {
|
||||||
|
color: ${token.colorTextDescription};
|
||||||
|
&:hover {
|
||||||
|
color: ${token.colorText};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const PoweredByV2 = () => {
|
export const PoweredByV2 = () => {
|
||||||
const { token } = useToken();
|
const { styles } = useStyles();
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
const year = date.getFullYear();
|
const year = date.getFullYear();
|
||||||
return (
|
return <div className={styles.powerBy}>©2023-{year} TachyBase Team</div>;
|
||||||
<div
|
|
||||||
className={css`
|
|
||||||
text-align: center;
|
|
||||||
color: ${token.colorTextDescription};
|
|
||||||
a {
|
|
||||||
color: ${token.colorTextDescription};
|
|
||||||
&:hover {
|
|
||||||
color: ${token.colorText};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
©2023-{year} TachyBase Team
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext } from 'react';
|
||||||
|
|
||||||
import { useCollection_deprecated } from '../collection-manager';
|
import { useCollection_deprecated } from '../collection-manager';
|
||||||
import { CollectionRecordProvider } from '../data-source';
|
import { CollectionRecordProvider } from '../data-source';
|
||||||
import { useCurrentUserContext } from '../user';
|
import { useCurrentUserContext } from '../user';
|
||||||
@ -11,12 +12,13 @@ RecordIndexContext.displayName = 'RecordIndexContext';
|
|||||||
/**
|
/**
|
||||||
* @deprecated use `CollectionRecordProvider` instead
|
* @deprecated use `CollectionRecordProvider` instead
|
||||||
*/
|
*/
|
||||||
export const RecordProvider: React.FC<{
|
export const RecordProvider = (props: {
|
||||||
record: any;
|
record: any;
|
||||||
parent?: any;
|
parent?: any;
|
||||||
isNew?: boolean;
|
isNew?: boolean;
|
||||||
collectionName?: string;
|
collectionName?: string;
|
||||||
}> = (props) => {
|
children: React.ReactNode;
|
||||||
|
}) => {
|
||||||
const { record, children, parent, isNew } = props;
|
const { record, children, parent, isNew } = props;
|
||||||
const { name: __collectionName } = useCollection_deprecated();
|
const { name: __collectionName } = useCollection_deprecated();
|
||||||
const value = { ...record };
|
const value = { ...record };
|
||||||
@ -31,11 +33,11 @@ export const RecordProvider: React.FC<{
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RecordSimpleProvider: React.FC<{ value: Record<string, any>; children: React.ReactNode }> = (props) => {
|
export const RecordSimpleProvider = (props: { value: Record<string, any>; children: React.ReactNode }) => {
|
||||||
return <RecordContext_deprecated.Provider {...props} />;
|
return <RecordContext_deprecated.Provider {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RecordIndexProvider: React.FC<{ index: any }> = (props) => {
|
export const RecordIndexProvider = (props: { index: any; children: React.ReactNode }) => {
|
||||||
const { index, children } = props;
|
const { index, children } = props;
|
||||||
return <RecordIndexContext.Provider value={index}>{children}</RecordIndexContext.Provider>;
|
return <RecordIndexContext.Provider value={index}>{children}</RecordIndexContext.Provider>;
|
||||||
};
|
};
|
||||||
|
@ -1,20 +1,25 @@
|
|||||||
import { css } from '@emotion/css';
|
import React, { useState } from 'react';
|
||||||
import dayjs from 'dayjs';
|
|
||||||
|
|
||||||
import { connect, mapProps } from '@tachybase/schema';
|
import { connect, mapProps } from '@tachybase/schema';
|
||||||
|
|
||||||
import { useBoolean } from 'ahooks';
|
import { useBoolean } from 'ahooks';
|
||||||
import { Input, Radio, Space } from 'antd';
|
import { Input, Radio, Space } from 'antd';
|
||||||
import React, { useState } from 'react';
|
import { createStyles } from 'antd-style';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
import { useToken } from '../../';
|
import { useToken } from '../../';
|
||||||
|
|
||||||
const date = dayjs();
|
const date = dayjs();
|
||||||
|
|
||||||
const spaceCSS = css`
|
const useStyles = createStyles(({ css }) => {
|
||||||
width: 100%;
|
return {
|
||||||
& > .ant-space-item {
|
space: css`
|
||||||
flex: 1;
|
width: 100%;
|
||||||
}
|
& > .ant-space-item {
|
||||||
`;
|
flex: 1;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
export const DateFormatCom = (props?) => {
|
export const DateFormatCom = (props?) => {
|
||||||
const date = dayjs();
|
const date = dayjs();
|
||||||
return (
|
return (
|
||||||
@ -44,6 +49,7 @@ const DateTimeFormatPreview = ({ content }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const InternalExpiresRadio = (props) => {
|
const InternalExpiresRadio = (props) => {
|
||||||
|
const { styles } = useStyles();
|
||||||
const { onChange, defaultValue, formats, timeFormat } = props;
|
const { onChange, defaultValue, formats, timeFormat } = props;
|
||||||
const [isCustom, { setFalse, setTrue }] = useBoolean(props.value && !formats.includes(props.value));
|
const [isCustom, { setFalse, setTrue }] = useBoolean(props.value && !formats.includes(props.value));
|
||||||
const targetValue = props.value && !formats.includes(props.value) ? props.value : defaultValue;
|
const targetValue = props.value && !formats.includes(props.value) ? props.value : defaultValue;
|
||||||
@ -58,7 +64,7 @@ const InternalExpiresRadio = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Space className={spaceCSS}>
|
<Space className={styles.space}>
|
||||||
<Radio.Group value={isCustom ? 'custom' : props.value} onChange={onSelectChange}>
|
<Radio.Group value={isCustom ? 'custom' : props.value} onChange={onSelectChange}>
|
||||||
<Space direction="vertical">
|
<Space direction="vertical">
|
||||||
{props.options.map((v) => {
|
{props.options.map((v) => {
|
||||||
|
@ -1,13 +1,28 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { observer, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import React, { useEffect, useMemo } from 'react';
|
import React, { useEffect, useMemo } from 'react';
|
||||||
|
import { observer, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
import { useCompile } from '../../schema-component';
|
import { useCompile } from '../../schema-component';
|
||||||
import { Variable } from '.././../schema-component';
|
import { Variable } from '.././../schema-component';
|
||||||
import { useCurrentFormVariable } from '../VariableInput/hooks/useFormVariable';
|
import { useCurrentFormVariable } from '../VariableInput/hooks/useFormVariable';
|
||||||
import { useCurrentObjectVariable } from '../VariableInput/hooks/useIterationVariable';
|
import { useCurrentObjectVariable } from '../VariableInput/hooks/useIterationVariable';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
variableInput: css`
|
||||||
|
min-width: 400px;
|
||||||
|
margin-right: 15;
|
||||||
|
.ant-input {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const ChildDynamicComponent = observer(
|
export const ChildDynamicComponent = observer(
|
||||||
(props: { rootCollection: string; onChange; value; default; collectionField }) => {
|
(props: { rootCollection: string; onChange; value; default; collectionField }) => {
|
||||||
|
const { styles } = useStyles();
|
||||||
const { rootCollection, onChange, value, collectionField } = props;
|
const { rootCollection, onChange, value, collectionField } = props;
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { currentFormSettings } = useCurrentFormVariable({
|
const { currentFormSettings } = useCurrentFormVariable({
|
||||||
@ -28,19 +43,7 @@ export const ChildDynamicComponent = observer(
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onChange(fieldSchema.default);
|
onChange(fieldSchema.default);
|
||||||
}, []);
|
}, []);
|
||||||
return (
|
return <Variable.Input value={value} onChange={onChange} scope={scope} className={styles.variableInput} />;
|
||||||
<Variable.Input
|
|
||||||
value={value}
|
|
||||||
onChange={(v) => onChange(v)}
|
|
||||||
scope={scope}
|
|
||||||
style={{ minWidth: '400px', marginRight: 15 }}
|
|
||||||
className={css`
|
|
||||||
.ant-input {
|
|
||||||
width: 100% !important;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
{ displayName: 'ChildDynamicComponent' },
|
{ displayName: 'ChildDynamicComponent' },
|
||||||
);
|
);
|
||||||
|
@ -1,21 +1,50 @@
|
|||||||
import { CloseCircleOutlined } from '@ant-design/icons';
|
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { TreeSelect } from '@tachybase/components';
|
|
||||||
import { observer } from '@tachybase/schema';
|
|
||||||
import { uid } from '@tachybase/schema';
|
|
||||||
import { Select, Space } from 'antd';
|
|
||||||
import React, { useCallback, useContext, useMemo, useState } from 'react';
|
import React, { useCallback, useContext, useMemo, useState } from 'react';
|
||||||
|
import { TreeSelect } from '@tachybase/components';
|
||||||
|
import { observer, uid } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { CloseCircleOutlined } from '@ant-design/icons';
|
||||||
|
import { Select, Space } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { useCompile } from '../..';
|
import { useCompile } from '../..';
|
||||||
import { DynamicComponent } from './DynamicComponent';
|
|
||||||
import { ValueDynamicComponent } from './ValueDynamicComponent';
|
|
||||||
import { LinkageLogicContext, RemoveActionContext } from './context';
|
import { LinkageLogicContext, RemoveActionContext } from './context';
|
||||||
|
import { DynamicComponent } from './DynamicComponent';
|
||||||
import { ActionType } from './type';
|
import { ActionType } from './type';
|
||||||
import { useValues } from './useValues';
|
import { useValues } from './useValues';
|
||||||
|
import { ValueDynamicComponent } from './ValueDynamicComponent';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
.ant-space {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
item: css`
|
||||||
|
.ant-space {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.ant-space-item {
|
||||||
|
max-width: 95%;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 2px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
select: css`
|
||||||
|
min-width: 120px;
|
||||||
|
`,
|
||||||
|
tree: css`
|
||||||
|
min-width: 160px;
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const FormFieldLinkageRuleAction = observer(
|
export const FormFieldLinkageRuleAction = observer(
|
||||||
(props: any) => {
|
(props: any) => {
|
||||||
const { value, options, collectionName } = props;
|
const { value, options, collectionName } = props;
|
||||||
|
const { styles } = useStyles();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const remove = useContext(RemoveActionContext);
|
const remove = useContext(RemoveActionContext);
|
||||||
@ -31,34 +60,13 @@ export const FormFieldLinkageRuleAction = observer(
|
|||||||
} = useValues(options);
|
} = useValues(options);
|
||||||
return (
|
return (
|
||||||
<LinkageLogicContext.Provider value={uid()}>
|
<LinkageLogicContext.Provider value={uid()}>
|
||||||
<div
|
<div style={{ marginBottom: 8 }} className={styles.container}>
|
||||||
style={{ marginBottom: 8 }}
|
<Space className={styles.item}>
|
||||||
className={css`
|
|
||||||
.ant-space {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<Space
|
|
||||||
className={css`
|
|
||||||
.ant-space {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
.ant-space-item {
|
|
||||||
max-width: 95%;
|
|
||||||
display: inline-block;
|
|
||||||
margin: 2px;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<TreeSelect
|
<TreeSelect
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
role="button"
|
role="button"
|
||||||
data-testid="select-linkage-property-field"
|
data-testid="select-linkage-property-field"
|
||||||
className={css`
|
className={styles.tree}
|
||||||
min-width: 160px;
|
|
||||||
`}
|
|
||||||
fieldNames={{
|
fieldNames={{
|
||||||
label: 'title',
|
label: 'title',
|
||||||
value: 'name',
|
value: 'name',
|
||||||
@ -80,9 +88,7 @@ export const FormFieldLinkageRuleAction = observer(
|
|||||||
data-testid="select-linkage-action-field"
|
data-testid="select-linkage-action-field"
|
||||||
popupMatchSelectWidth={false}
|
popupMatchSelectWidth={false}
|
||||||
value={operator}
|
value={operator}
|
||||||
className={css`
|
className={styles.select}
|
||||||
min-width: 120px;
|
|
||||||
`}
|
|
||||||
options={compile(operators)}
|
options={compile(operators)}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
setOperator(value);
|
setOperator(value);
|
||||||
|
@ -1,41 +1,38 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { Form } from '@tachybase/schema';
|
|
||||||
import { observer, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
|
import { observer, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
|
import { withDynamicSchemaProps } from '../../application/hoc/withDynamicSchemaProps';
|
||||||
import { FormBlockContext } from '../../block-provider';
|
import { FormBlockContext } from '../../block-provider';
|
||||||
import { useCollectionManager_deprecated } from '../../collection-manager';
|
import { useCollectionManager_deprecated } from '../../collection-manager';
|
||||||
import { useCollectionParentRecordData } from '../../data-source/collection-record/CollectionRecordProvider';
|
import { useCollectionParentRecordData } from '../../data-source/collection-record/CollectionRecordProvider';
|
||||||
import { RecordProvider } from '../../record-provider';
|
import { RecordProvider } from '../../record-provider';
|
||||||
import { SchemaComponent, useProps } from '../../schema-component';
|
import { SchemaComponent, useProps } from '../../schema-component';
|
||||||
import { DynamicComponentProps } from '../../schema-component/antd/filter/DynamicComponent';
|
|
||||||
import { FilterContext } from '../../schema-component/antd/filter/context';
|
import { FilterContext } from '../../schema-component/antd/filter/context';
|
||||||
import { VariableOption, VariablesContextType } from '../../variables/types';
|
import { DynamicComponentProps } from '../../schema-component/antd/filter/DynamicComponent';
|
||||||
import { VariableInput, getShouldChange } from '../VariableInput/VariableInput';
|
import { getShouldChange, VariableInput } from '../VariableInput/VariableInput';
|
||||||
import { LinkageRuleActionGroup } from './LinkageRuleActionGroup';
|
|
||||||
import { EnableLinkage } from './components/EnableLinkage';
|
import { EnableLinkage } from './components/EnableLinkage';
|
||||||
import { ArrayCollapse } from './components/LinkageHeader';
|
import { ArrayCollapse } from './components/LinkageHeader';
|
||||||
import { withDynamicSchemaProps } from '../../application/hoc/withDynamicSchemaProps';
|
import { LinkageRuleActionGroup } from './LinkageRuleActionGroup';
|
||||||
|
|
||||||
interface usePropsReturn {
|
|
||||||
options: any;
|
|
||||||
defaultValues: any[];
|
|
||||||
collectionName: string;
|
|
||||||
form: Form;
|
|
||||||
variables: VariablesContextType;
|
|
||||||
localVariables: VariableOption | VariableOption[];
|
|
||||||
record: Record<string, any>;
|
|
||||||
/**
|
|
||||||
* create 表示创建表单,update 表示更新表单
|
|
||||||
*/
|
|
||||||
formBlockType: 'create' | 'update';
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
dynamicComponent: any;
|
dynamicComponent: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
filter: css`
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
margin-left: 10px;
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const FormLinkageRules = withDynamicSchemaProps(
|
export const FormLinkageRules = withDynamicSchemaProps(
|
||||||
observer((props: Props) => {
|
observer((props: Props) => {
|
||||||
|
const { styles } = useStyles();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const {
|
const {
|
||||||
options,
|
options,
|
||||||
@ -91,11 +88,7 @@ export const FormLinkageRules = withDynamicSchemaProps(
|
|||||||
'x-use-component-props': () => {
|
'x-use-component-props': () => {
|
||||||
return {
|
return {
|
||||||
options,
|
options,
|
||||||
className: css`
|
className: styles.filter,
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
margin-left: 10px;
|
|
||||||
`,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
|
@ -1,10 +1,30 @@
|
|||||||
import { css } from '@emotion/css';
|
import React, {
|
||||||
|
createContext,
|
||||||
|
FC,
|
||||||
|
ReactNode,
|
||||||
|
useCallback,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
// @ts-ignore
|
||||||
|
useTransition as useReactTransition,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
import { ArrayCollapse, ArrayItems, FormItem, FormLayout, Input } from '@tachybase/components';
|
import { ArrayCollapse, ArrayItems, FormItem, FormLayout, Input } from '@tachybase/components';
|
||||||
import { Field, GeneralField, createForm } from '@tachybase/schema';
|
import {
|
||||||
import { ISchema, Schema, SchemaOptionsContext, useField, useFieldSchema, useForm } from '@tachybase/schema';
|
createForm,
|
||||||
import { uid } from '@tachybase/schema';
|
Field,
|
||||||
|
GeneralField,
|
||||||
|
ISchema,
|
||||||
|
Schema,
|
||||||
|
SchemaOptionsContext,
|
||||||
|
uid,
|
||||||
|
useField,
|
||||||
|
useFieldSchema,
|
||||||
|
useForm,
|
||||||
|
} from '@tachybase/schema';
|
||||||
import { error } from '@tachybase/utils/client';
|
import { error } from '@tachybase/utils/client';
|
||||||
import type { DropdownProps } from 'antd';
|
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
App,
|
App,
|
||||||
@ -20,44 +40,37 @@ import {
|
|||||||
ModalFuncProps,
|
ModalFuncProps,
|
||||||
Space,
|
Space,
|
||||||
Switch,
|
Switch,
|
||||||
|
type DropdownProps,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import _, { cloneDeep, get, set } from 'lodash';
|
import _, { cloneDeep, get, set } from 'lodash';
|
||||||
import React, {
|
|
||||||
FC,
|
|
||||||
ReactNode,
|
|
||||||
createContext,
|
|
||||||
useCallback,
|
|
||||||
useContext,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
// @ts-ignore
|
|
||||||
useTransition as useReactTransition,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Router } from 'react-router-dom';
|
import { Router } from 'react-router-dom';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
APIClientProvider,
|
|
||||||
ActionContextProvider,
|
ActionContextProvider,
|
||||||
|
APIClientProvider,
|
||||||
|
ApplicationContext,
|
||||||
AssociationOrCollectionProvider,
|
AssociationOrCollectionProvider,
|
||||||
CollectionFieldOptions_deprecated,
|
CollectionFieldOptions_deprecated,
|
||||||
CollectionRecordProvider,
|
CollectionRecordProvider,
|
||||||
|
createDesignable,
|
||||||
DataSourceApplicationProvider,
|
DataSourceApplicationProvider,
|
||||||
Designable,
|
Designable,
|
||||||
|
findFormBlock,
|
||||||
FormDialog,
|
FormDialog,
|
||||||
FormProvider,
|
FormProvider,
|
||||||
RemoteSchemaComponent,
|
RemoteSchemaComponent,
|
||||||
SchemaComponent,
|
SchemaComponent,
|
||||||
SchemaComponentContext,
|
SchemaComponentContext,
|
||||||
SchemaComponentOptions,
|
SchemaComponentOptions,
|
||||||
createDesignable,
|
|
||||||
findFormBlock,
|
|
||||||
useAPIClient,
|
useAPIClient,
|
||||||
|
useApp,
|
||||||
useBlockRequestContext,
|
useBlockRequestContext,
|
||||||
|
useCollection_deprecated,
|
||||||
useCollectionManager_deprecated,
|
useCollectionManager_deprecated,
|
||||||
useCollectionRecord,
|
useCollectionRecord,
|
||||||
useCollection_deprecated,
|
|
||||||
useCompile,
|
useCompile,
|
||||||
useDataBlockProps,
|
useDataBlockProps,
|
||||||
useDesignable,
|
useDesignable,
|
||||||
@ -67,8 +80,6 @@ import {
|
|||||||
useRecord,
|
useRecord,
|
||||||
useSchemaSettingsItem,
|
useSchemaSettingsItem,
|
||||||
useSortFields,
|
useSortFields,
|
||||||
useApp,
|
|
||||||
ApplicationContext,
|
|
||||||
} from '..';
|
} from '..';
|
||||||
import {
|
import {
|
||||||
BlockRequestContext_deprecated,
|
BlockRequestContext_deprecated,
|
||||||
@ -78,8 +89,8 @@ import {
|
|||||||
useTableBlockContext,
|
useTableBlockContext,
|
||||||
} from '../block-provider';
|
} from '../block-provider';
|
||||||
import {
|
import {
|
||||||
FormActiveFieldsProvider,
|
|
||||||
findFilterTargets,
|
findFilterTargets,
|
||||||
|
FormActiveFieldsProvider,
|
||||||
updateFilterTargets,
|
updateFilterTargets,
|
||||||
useFormActiveFields,
|
useFormActiveFields,
|
||||||
} from '../block-provider/hooks';
|
} from '../block-provider/hooks';
|
||||||
@ -142,8 +153,31 @@ interface SchemaSettingsProviderProps {
|
|||||||
template?: any;
|
template?: any;
|
||||||
collectionName?: any;
|
collectionName?: any;
|
||||||
designer?: any;
|
designer?: any;
|
||||||
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
menu: css`
|
||||||
|
.ant-dropdown-menu-item-group-list {
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
modal: css`
|
||||||
|
// screen > 576px
|
||||||
|
@media (min-width: 576px) {
|
||||||
|
min-width: 520px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// screen <= 576px
|
||||||
|
@media (max-width: 576px) {
|
||||||
|
min-width: 320px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const SchemaSettingsProvider: React.FC<SchemaSettingsProviderProps> = (props) => {
|
export const SchemaSettingsProvider: React.FC<SchemaSettingsProviderProps> = (props) => {
|
||||||
const { children, fieldSchema, ...others } = props;
|
const { children, fieldSchema, ...others } = props;
|
||||||
const { getTemplateBySchema } = useSchemaTemplateManager();
|
const { getTemplateBySchema } = useSchemaTemplateManager();
|
||||||
@ -158,6 +192,7 @@ export const SchemaSettingsProvider: React.FC<SchemaSettingsProviderProps> = (pr
|
|||||||
|
|
||||||
export const SchemaSettingsDropdown: React.FC<SchemaSettingsProps> = (props) => {
|
export const SchemaSettingsDropdown: React.FC<SchemaSettingsProps> = (props) => {
|
||||||
const { title, dn, ...others } = props;
|
const { title, dn, ...others } = props;
|
||||||
|
const { styles } = useStyles();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const { Component, getMenuItems } = useMenuItem();
|
const { Component, getMenuItems } = useMenuItem();
|
||||||
const [, startTransition] = useReactTransition();
|
const [, startTransition] = useReactTransition();
|
||||||
@ -180,12 +215,7 @@ export const SchemaSettingsDropdown: React.FC<SchemaSettingsProps> = (props) =>
|
|||||||
<Dropdown
|
<Dropdown
|
||||||
open={visible}
|
open={visible}
|
||||||
onOpenChange={changeMenu}
|
onOpenChange={changeMenu}
|
||||||
overlayClassName={css`
|
overlayClassName={styles.menu}
|
||||||
.ant-dropdown-menu-item-group-list {
|
|
||||||
max-height: 300px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
menu={{ items, style: { maxHeight: dropdownMaxHeight, overflowY: 'auto' } }}
|
menu={{ items, style: { maxHeight: dropdownMaxHeight, overflowY: 'auto' } }}
|
||||||
>
|
>
|
||||||
<div data-testid={props['data-testid']}>{typeof title === 'string' ? <span>{title}</span> : title}</div>
|
<div data-testid={props['data-testid']}>{typeof title === 'string' ? <span>{title}</span> : title}</div>
|
||||||
@ -978,6 +1008,7 @@ export const SchemaSettingsModalItem: FC<SchemaSettingsModalItemProps> = (props)
|
|||||||
...others
|
...others
|
||||||
} = props;
|
} = props;
|
||||||
const options = useContext(SchemaOptionsContext);
|
const options = useContext(SchemaOptionsContext);
|
||||||
|
const { styles } = useStyles();
|
||||||
const collection = useCollection_deprecated();
|
const collection = useCollection_deprecated();
|
||||||
const apiClient = useAPIClient();
|
const apiClient = useAPIClient();
|
||||||
const { theme } = useGlobalTheme();
|
const { theme } = useGlobalTheme();
|
||||||
@ -1025,20 +1056,7 @@ export const SchemaSettingsModalItem: FC<SchemaSettingsModalItemProps> = (props)
|
|||||||
association={association}
|
association={association}
|
||||||
>
|
>
|
||||||
<SchemaComponentOptions scope={options.scope} components={options.components}>
|
<SchemaComponentOptions scope={options.scope} components={options.components}>
|
||||||
<FormLayout
|
<FormLayout layout={'vertical'} className={styles.modal}>
|
||||||
layout={'vertical'}
|
|
||||||
className={css`
|
|
||||||
// screen > 576px
|
|
||||||
@media (min-width: 576px) {
|
|
||||||
min-width: 520px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// screen <= 576px
|
|
||||||
@media (max-width: 576px) {
|
|
||||||
min-width: 320px;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<APIClientProvider apiClient={apiClient}>
|
<APIClientProvider apiClient={apiClient}>
|
||||||
<ConfigProvider locale={locale}>
|
<ConfigProvider locale={locale}>
|
||||||
<SchemaComponent components={components} scope={scope} schema={schema} />
|
<SchemaComponent components={components} scope={scope} schema={schema} />
|
||||||
@ -1474,12 +1492,6 @@ export function SchemaSettingsEnableChildCollections(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultInputStyle = css`
|
|
||||||
& > .nb-form-item {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const findParentFieldSchema = (fieldSchema: Schema) => {
|
export const findParentFieldSchema = (fieldSchema: Schema) => {
|
||||||
let parent = fieldSchema.parent;
|
let parent = fieldSchema.parent;
|
||||||
while (parent) {
|
while (parent) {
|
||||||
|
@ -1,12 +1,36 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { ISchema, Schema, useField } from '@tachybase/schema';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { ISchema, Schema, useField } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { useCollectionManager_deprecated, useDesignable } from '..';
|
import { useCollectionManager_deprecated, useDesignable } from '..';
|
||||||
import { DateFormatCom, ExpiresRadio } from './DateFormat/ExpiresRadio';
|
import { DateFormatCom, ExpiresRadio } from './DateFormat/ExpiresRadio';
|
||||||
import { SchemaSettingsModalItem } from './SchemaSettings';
|
import { SchemaSettingsModalItem } from './SchemaSettings';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
radio: css`
|
||||||
|
.ant-radio-wrapper {
|
||||||
|
display: flex;
|
||||||
|
margin: 5px 0px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
margin: css`
|
||||||
|
margin-bottom: 0px;
|
||||||
|
`,
|
||||||
|
redRadio: css`
|
||||||
|
color: red;
|
||||||
|
.ant-radio-wrapper {
|
||||||
|
display: flex;
|
||||||
|
margin: 5px 0px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const SchemaSettingsDateFormat = function DateFormatConfig(props: { fieldSchema: Schema }) {
|
export const SchemaSettingsDateFormat = function DateFormatConfig(props: { fieldSchema: Schema }) {
|
||||||
|
const { styles } = useStyles();
|
||||||
const { fieldSchema } = props;
|
const { fieldSchema } = props;
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
@ -36,12 +60,7 @@ export const SchemaSettingsDateFormat = function DateFormatConfig(props: { field
|
|||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-decorator-props': {},
|
'x-decorator-props': {},
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
className: css`
|
className: styles.radio,
|
||||||
.ant-radio-wrapper {
|
|
||||||
display: flex;
|
|
||||||
margin: 5px 0px;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
defaultValue: 'dddd',
|
defaultValue: 'dddd',
|
||||||
formats: ['MMMM Do YYYY', 'YYYY-MM-DD', 'MM/DD/YY', 'YYYY/MM/DD', 'DD/MM/YYYY'],
|
formats: ['MMMM Do YYYY', 'YYYY-MM-DD', 'MM/DD/YY', 'YYYY/MM/DD', 'DD/MM/YYYY'],
|
||||||
},
|
},
|
||||||
@ -94,18 +113,10 @@ export const SchemaSettingsDateFormat = function DateFormatConfig(props: { field
|
|||||||
'x-component': ExpiresRadio,
|
'x-component': ExpiresRadio,
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-decorator-props': {
|
'x-decorator-props': {
|
||||||
className: css`
|
className: styles.margin,
|
||||||
margin-bottom: 0px;
|
|
||||||
`,
|
|
||||||
},
|
},
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
className: css`
|
className: styles.redRadio,
|
||||||
color: red;
|
|
||||||
.ant-radio-wrapper {
|
|
||||||
display: flex;
|
|
||||||
margin: 5px 0px;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
defaultValue: 'h:mm a',
|
defaultValue: 'h:mm a',
|
||||||
formats: ['hh:mm:ss a', 'HH:mm:ss'],
|
formats: ['hh:mm:ss a', 'HH:mm:ss'],
|
||||||
timeFormat: true,
|
timeFormat: true,
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
import { Field } from '@tachybase/schema';
|
|
||||||
import { ISchema, Schema, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
|
import { ArrayCollapse, FormLayout } from '@tachybase/components';
|
||||||
|
import { Field, ISchema, Schema, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import _ from 'lodash';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FormProvider,
|
FormProvider,
|
||||||
SchemaComponent,
|
SchemaComponent,
|
||||||
useActionContext,
|
useActionContext,
|
||||||
useCollectionManager_deprecated,
|
|
||||||
useCollection_deprecated,
|
useCollection_deprecated,
|
||||||
|
useCollectionManager_deprecated,
|
||||||
useDesignable,
|
useDesignable,
|
||||||
useRecord,
|
useRecord,
|
||||||
} from '..';
|
} from '..';
|
||||||
@ -17,18 +20,23 @@ import { useCollectionFilterOptionsV2 } from '../collection-manager/action-hooks
|
|||||||
import { FlagProvider, useFlag } from '../flag-provider';
|
import { FlagProvider, useFlag } from '../flag-provider';
|
||||||
import { useLocalVariables, useVariables } from '../variables';
|
import { useLocalVariables, useVariables } from '../variables';
|
||||||
import { isVariable } from '../variables/utils/isVariable';
|
import { isVariable } from '../variables/utils/isVariable';
|
||||||
import { VariableInput, getShouldChange } from './VariableInput/VariableInput';
|
import { findParentFieldSchema, getFieldDefaultValue, SchemaSettingsModalItem } from './SchemaSettings';
|
||||||
import { Option } from './VariableInput/type';
|
import { Option } from './VariableInput/type';
|
||||||
import { formatVariableScop } from './VariableInput/utils/formatVariableScop';
|
import { formatVariableScop } from './VariableInput/utils/formatVariableScop';
|
||||||
import {
|
import { getShouldChange, VariableInput } from './VariableInput/VariableInput';
|
||||||
findParentFieldSchema,
|
|
||||||
defaultInputStyle,
|
const useStyles = createStyles(({ css }) => {
|
||||||
getFieldDefaultValue,
|
return {
|
||||||
SchemaSettingsModalItem,
|
defaultInput: css`
|
||||||
} from './SchemaSettings';
|
& > .nb-form-item {
|
||||||
import { ArrayCollapse, FormLayout } from '@tachybase/components';
|
flex: 1;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const SchemaSettingsDefaultValue = function DefaultValueConfigure(props: { fieldSchema?: Schema }) {
|
export const SchemaSettingsDefaultValue = function DefaultValueConfigure(props: { fieldSchema?: Schema }) {
|
||||||
|
const { styles } = useStyles();
|
||||||
const currentSchema = useFieldSchema();
|
const currentSchema = useFieldSchema();
|
||||||
const fieldSchema = props?.fieldSchema ?? currentSchema;
|
const fieldSchema = props?.fieldSchema ?? currentSchema;
|
||||||
const field: Field = useField();
|
const field: Field = useField();
|
||||||
@ -112,7 +120,7 @@ export const SchemaSettingsDefaultValue = function DefaultValueConfigure(props:
|
|||||||
contextCollectionName: isAllowContextVariable && tableCtx.collection,
|
contextCollectionName: isAllowContextVariable && tableCtx.collection,
|
||||||
schema: collectionField?.uiSchema,
|
schema: collectionField?.uiSchema,
|
||||||
targetFieldSchema: fieldSchema,
|
targetFieldSchema: fieldSchema,
|
||||||
className: defaultInputStyle,
|
className: styles.defaultInput,
|
||||||
form,
|
form,
|
||||||
record,
|
record,
|
||||||
returnScope,
|
returnScope,
|
||||||
@ -191,6 +199,7 @@ export const SchemaSettingsDefaultValue = function DefaultValueConfigure(props:
|
|||||||
tableCtx.collection,
|
tableCtx.collection,
|
||||||
targetField,
|
targetField,
|
||||||
variables,
|
variables,
|
||||||
|
styles,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleSubmit: (values: any) => void = useCallback(
|
const handleSubmit: (values: any) => void = useCallback(
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import { ISchema, Schema, useField, useForm } from '@tachybase/schema';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { ISchema, Schema, useField, useForm } from '@tachybase/schema';
|
||||||
|
|
||||||
import { Select } from 'antd';
|
import { Select } from 'antd';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { useCollectionManager_deprecated, useDesignable } from '..';
|
import { useCollectionManager_deprecated, useDesignable } from '..';
|
||||||
import { SchemaSettingsModalItem } from './SchemaSettings';
|
import { SchemaSettingsModalItem } from './SchemaSettings';
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { theme } from 'antd';
|
import { theme } from 'antd';
|
||||||
|
|
||||||
import { CustomToken } from '../global-theme';
|
import { CustomToken } from '../global-theme';
|
||||||
|
|
||||||
interface Result extends ReturnType<typeof theme.useToken> {
|
interface Result extends ReturnType<typeof theme.useToken> {
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { UserOutlined } from '@ant-design/icons';
|
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { error } from '@tachybase/utils/client';
|
|
||||||
import { App, Dropdown, Menu, MenuProps } from 'antd';
|
|
||||||
import React, { createContext, useCallback, useMemo as useEffect, useState } from 'react';
|
import React, { createContext, useCallback, useMemo as useEffect, useState } from 'react';
|
||||||
|
import { error } from '@tachybase/utils/client';
|
||||||
|
|
||||||
|
import { UserOutlined } from '@ant-design/icons';
|
||||||
|
import { App, Dropdown, Menu, MenuProps } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { useACLRoleContext, useAPIClient, useCurrentUserContext, useToken } from '..';
|
import { useACLRoleContext, useAPIClient, useCurrentUserContext, useToken } from '..';
|
||||||
import { useChangePassword } from './ChangePassword';
|
import { useChangePassword } from './ChangePassword';
|
||||||
import { useCurrentUserSettingsMenu } from './CurrentUserSettingsMenuProvider';
|
import { useCurrentUserSettingsMenu } from './CurrentUserSettingsMenuProvider';
|
||||||
@ -164,22 +166,37 @@ export const SettingsMenu: React.FC<{
|
|||||||
export const DropdownVisibleContext = createContext(null);
|
export const DropdownVisibleContext = createContext(null);
|
||||||
DropdownVisibleContext.displayName = 'DropdownVisibleContext';
|
DropdownVisibleContext.displayName = 'DropdownVisibleContext';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css, token }) => {
|
||||||
|
return {
|
||||||
|
dropdown: css`
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
width: 46px;
|
||||||
|
height: 46px;
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.1) !important;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
button: css`
|
||||||
|
max-width: 160px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 12px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: '16px';
|
||||||
|
color: ${token.colorTextHeaderMenu};
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const CurrentUser = () => {
|
export const CurrentUser = () => {
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const { token } = useToken();
|
const { styles } = useStyles();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={styles.dropdown}>
|
||||||
className={css`
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
width: 46px;
|
|
||||||
height: 46px;
|
|
||||||
&:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.1) !important;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<DropdownVisibleContext.Provider value={{ visible, setVisible }}>
|
<DropdownVisibleContext.Provider value={{ visible, setVisible }}>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
open={visible}
|
open={visible}
|
||||||
@ -190,18 +207,7 @@ export const CurrentUser = () => {
|
|||||||
return <SettingsMenu />;
|
return <SettingsMenu />;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span data-testid="user-center-button" className={styles.button}>
|
||||||
data-testid="user-center-button"
|
|
||||||
className={css`
|
|
||||||
max-width: 160px;
|
|
||||||
overflow: hidden;
|
|
||||||
display: inline-block;
|
|
||||||
line-height: 12px;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
`}
|
|
||||||
style={{ cursor: 'pointer', padding: '16px', color: token.colorTextHeaderMenu }}
|
|
||||||
>
|
|
||||||
<UserOutlined />
|
<UserOutlined />
|
||||||
</span>
|
</span>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
@ -1,13 +1,24 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { useAPIClient } from '../api-client';
|
|
||||||
import { useForm } from '@tachybase/schema';
|
import { useForm } from '@tachybase/schema';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
|
||||||
import { Button, Input, message } from 'antd';
|
import { Button, Input, message } from 'antd';
|
||||||
import React from 'react';
|
import { createStyles } from 'antd-style';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { useAPIClient } from '../api-client';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
field: css`
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5em;
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export default function VerificationCode({ targetFieldName = 'phone', actionType, value, onChange }) {
|
export default function VerificationCode({ targetFieldName = 'phone', actionType, value, onChange }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { styles } = useStyles();
|
||||||
const api = useAPIClient();
|
const api = useAPIClient();
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
|
|
||||||
@ -48,12 +59,7 @@ export default function VerificationCode({ targetFieldName = 'phone', actionType
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<fieldset
|
<fieldset className={styles.field}>
|
||||||
className={css`
|
|
||||||
display: flex;
|
|
||||||
gap: 0.5em;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<Input value={value} onChange={onChange} placeholder={t('Verification code')} />
|
<Input value={value} onChange={onChange} placeholder={t('Verification code')} />
|
||||||
<Button onClick={onGetCode} disabled={count > 0}>
|
<Button onClick={onGetCode} disabled={count > 0}>
|
||||||
{count > 0 ? t('Retry after {{count}} seconds', { count }) : t('Send code')}
|
{count > 0 ? t('Retry after {{count}} seconds', { count }) : t('Send code')}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import { useCompile, useCollectionManager_deprecated, useCollectionDataSource } from '@tachybase/client';
|
import { useCollectionDataSource, useCollectionManager_deprecated, useCompile } from '@tachybase/client';
|
||||||
import { lang, tval } from '../../locale';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Trigger,
|
|
||||||
CollectionBlockInitializer,
|
|
||||||
getCollectionFieldOptions,
|
|
||||||
FieldsSelect,
|
|
||||||
RadioWithTooltip,
|
|
||||||
CheckboxGroupWithTooltip,
|
CheckboxGroupWithTooltip,
|
||||||
|
CollectionBlockInitializer,
|
||||||
|
FieldsSelect,
|
||||||
|
getCollectionFieldOptions,
|
||||||
|
RadioWithTooltip,
|
||||||
|
Trigger,
|
||||||
} from '@tachybase/plugin-workflow/client';
|
} from '@tachybase/plugin-workflow/client';
|
||||||
|
|
||||||
|
import { lang, tval } from '../../locale';
|
||||||
|
|
||||||
const enum ACTION_TYPES {
|
const enum ACTION_TYPES {
|
||||||
CREATE = 'create',
|
CREATE = 'create',
|
||||||
UPDATE = 'update',
|
UPDATE = 'update',
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
useSchemaToolbar,
|
useSchemaToolbar,
|
||||||
} from '@tachybase/client';
|
} from '@tachybase/client';
|
||||||
import { useFieldSchema } from '@tachybase/schema';
|
import { useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const schemaSettingsItems: SchemaSettingsItemType[] = [
|
const schemaSettingsItems: SchemaSettingsItemType[] = [
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { BlockInitializer, useSchemaInitializerItem } from '@tachybase/client';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { BlockInitializer, useSchemaInitializerItem } from '@tachybase/client';
|
||||||
|
|
||||||
import { tval } from '../../locale';
|
import { tval } from '../../locale';
|
||||||
|
|
||||||
export const BulkWorkflowActionInitializer = () => {
|
export const BulkWorkflowActionInitializer = () => {
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import { BlockInitializer, useSchemaInitializerItem } from '@tachybase/client';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
export const CustomizeActionInitializer = () => {
|
|
||||||
const itemConfig = useSchemaInitializerItem();
|
|
||||||
return <BlockInitializer {...itemConfig} item={itemConfig} />;
|
|
||||||
};
|
|
@ -1,21 +1,21 @@
|
|||||||
import { Plugin, useCollection } from '@tachybase/client';
|
import { Plugin, useCollection } from '@tachybase/client';
|
||||||
import { tval } from '../../locale';
|
|
||||||
import { BulkWorkflowActionInitializer } from './BulkUpdateActionInitializer';
|
|
||||||
import { bulkWorkflowActionSettings } from './BulkUpdateAction.Settings';
|
|
||||||
import { CustomizeActionInitializer } from './CustomizeActionInitializer';
|
|
||||||
import { useCustomizeBulkWorkflowActionProps } from './utils';
|
|
||||||
import PluginWorkflow from '@tachybase/plugin-workflow/client';
|
import PluginWorkflow from '@tachybase/plugin-workflow/client';
|
||||||
|
|
||||||
|
import { tval } from '../../locale';
|
||||||
import { ApiTrigger } from './ApiTrigger';
|
import { ApiTrigger } from './ApiTrigger';
|
||||||
|
import { bulkWorkflowActionSettings } from './BulkUpdateAction.Settings';
|
||||||
|
import { BulkWorkflowActionInitializer } from './BulkUpdateActionInitializer';
|
||||||
|
import { useCustomizeBulkWorkflowActionProps } from './utils';
|
||||||
|
|
||||||
export class PluginWorkflowBulk extends Plugin {
|
export class PluginWorkflowBulk extends Plugin {
|
||||||
async load() {
|
async load() {
|
||||||
this.app.addComponents({ CustomizeActionInitializer });
|
this.app.addComponents({ BulkWorkflowActionInitializer });
|
||||||
this.app.addScopes({ useCustomizeBulkWorkflowActionProps });
|
this.app.addScopes({ useCustomizeBulkWorkflowActionProps });
|
||||||
this.app.schemaSettingsManager.add(bulkWorkflowActionSettings);
|
this.app.schemaSettingsManager.add(bulkWorkflowActionSettings);
|
||||||
|
|
||||||
const initializerData = {
|
const initializerData = {
|
||||||
title: tval('Bulk workflow'),
|
title: tval('Bulk workflow'),
|
||||||
Component: BulkWorkflowActionInitializer,
|
Component: 'BulkWorkflowActionInitializer',
|
||||||
name: 'bulkWorkflow',
|
name: 'bulkWorkflow',
|
||||||
useVisible() {
|
useVisible() {
|
||||||
const collection = useCollection();
|
const collection = useCollection();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { SchemaExpressionScopeContext, useField, useFieldSchema } from '@tachybase/schema';
|
import { useContext } from 'react';
|
||||||
import {
|
import {
|
||||||
isVariable,
|
isVariable,
|
||||||
transformVariableValue,
|
transformVariableValue,
|
||||||
@ -11,9 +11,11 @@ import {
|
|||||||
useTableBlockContext,
|
useTableBlockContext,
|
||||||
useVariables,
|
useVariables,
|
||||||
} from '@tachybase/client';
|
} from '@tachybase/client';
|
||||||
|
import { SchemaExpressionScopeContext, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
import { App } from 'antd';
|
import { App } from 'antd';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { useTranslation } from '../../locale';
|
import { useTranslation } from '../../locale';
|
||||||
|
|
||||||
export const useCustomizeBulkWorkflowActionProps = () => {
|
export const useCustomizeBulkWorkflowActionProps = () => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { SchemaExpressionScopeContext, useField, useFieldSchema } from '@tachybase/schema';
|
import { useContext } from 'react';
|
||||||
import {
|
import {
|
||||||
TableFieldResource,
|
|
||||||
isVariable,
|
isVariable,
|
||||||
|
TableFieldResource,
|
||||||
transformVariableValue,
|
transformVariableValue,
|
||||||
useBlockRequestContext,
|
useBlockRequestContext,
|
||||||
useCollection_deprecated,
|
useCollection_deprecated,
|
||||||
@ -11,10 +11,12 @@ import {
|
|||||||
useTableBlockContext,
|
useTableBlockContext,
|
||||||
useVariables,
|
useVariables,
|
||||||
} from '@tachybase/client';
|
} from '@tachybase/client';
|
||||||
|
import { SchemaExpressionScopeContext, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
import { isURL } from '@tachybase/utils/client';
|
import { isURL } from '@tachybase/utils/client';
|
||||||
|
|
||||||
import { App, message } from 'antd';
|
import { App, message } from 'antd';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { useBulkUpdateTranslation } from './locale';
|
import { useBulkUpdateTranslation } from './locale';
|
||||||
|
|
||||||
export const useCustomizeBulkUpdateActionProps = () => {
|
export const useCustomizeBulkUpdateActionProps = () => {
|
||||||
@ -23,8 +25,6 @@ export const useCustomizeBulkUpdateActionProps = () => {
|
|||||||
const actionSchema = useFieldSchema();
|
const actionSchema = useFieldSchema();
|
||||||
const tableBlockContext = useTableBlockContext();
|
const tableBlockContext = useTableBlockContext();
|
||||||
const { rowKey } = tableBlockContext;
|
const { rowKey } = tableBlockContext;
|
||||||
const selectedRecordKeys =
|
|
||||||
tableBlockContext.field?.data?.selectedRowKeys ?? expressionScope?.selectedRecordKeys ?? {};
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const { t } = useBulkUpdateTranslation();
|
const { t } = useBulkUpdateTranslation();
|
||||||
@ -44,6 +44,8 @@ export const useCustomizeBulkUpdateActionProps = () => {
|
|||||||
} = actionSchema?.['x-action-settings'] ?? {};
|
} = actionSchema?.['x-action-settings'] ?? {};
|
||||||
actionField.data = field.data || {};
|
actionField.data = field.data || {};
|
||||||
actionField.data.loading = true;
|
actionField.data.loading = true;
|
||||||
|
const selectedRecordKeys =
|
||||||
|
tableBlockContext.field?.data?.selectedRowKeys ?? expressionScope?.selectedRecordKeys ?? {};
|
||||||
|
|
||||||
const assignedValues = {};
|
const assignedValues = {};
|
||||||
const waitList = Object.keys(originalAssignedValues).map(async (key) => {
|
const waitList = Object.keys(originalAssignedValues).map(async (key) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user