mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-07-02 03:02:19 +08:00
Merge branch '2.0' of github.com:nocobase/nocobase into 2.0
This commit is contained in:
commit
cec9b5ccf4
@ -6,13 +6,16 @@
|
|||||||
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
import { tval } from '@nocobase/utils/client';
|
||||||
import { APIResource, BaseRecordResource, Collection, DefaultStructure, FlowModel } from '@nocobase/flow-engine';
|
import { APIResource, BaseRecordResource, Collection, DefaultStructure, FlowModel } from '@nocobase/flow-engine';
|
||||||
import { Card } from 'antd';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { BlockItemCard } from '../common/BlockItemCard';
|
||||||
|
|
||||||
export class BlockModel<T = DefaultStructure> extends FlowModel<T> {
|
export class BlockModel<T = DefaultStructure> extends FlowModel<T> {
|
||||||
decoratorProps: Record<string, any> = {};
|
decoratorProps: Record<string, any> = {};
|
||||||
|
setDecoratorProps(props) {
|
||||||
|
this.decoratorProps = { ...this.decoratorProps, ...props };
|
||||||
|
}
|
||||||
|
|
||||||
renderComponent() {
|
renderComponent() {
|
||||||
throw new Error('renderComponent method must be implemented in subclasses of BlockModel');
|
throw new Error('renderComponent method must be implemented in subclasses of BlockModel');
|
||||||
@ -20,10 +23,92 @@ export class BlockModel<T = DefaultStructure> extends FlowModel<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <Card {...this.decoratorProps}>{this.renderComponent()}</Card>;
|
return <BlockItemCard {...this.decoratorProps}>{this.renderComponent()}</BlockItemCard>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const HeightMode = {
|
||||||
|
DEFAULT: 'defaultHeight',
|
||||||
|
SPECIFY_VALUE: 'specifyValue',
|
||||||
|
FULL_HEIGHT: 'fullHeight',
|
||||||
|
};
|
||||||
|
|
||||||
|
BlockModel.registerFlow({
|
||||||
|
key: 'blockProps',
|
||||||
|
title: tval('Basic configuration'),
|
||||||
|
auto: true,
|
||||||
|
steps: {
|
||||||
|
editBlockTitleAndDescription: {
|
||||||
|
title: tval('Edit block title & description'),
|
||||||
|
uiSchema: {
|
||||||
|
title: {
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
title: tval('Title'),
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
'x-component': 'Input.TextArea',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
title: tval('Description'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
handler(ctx, params) {
|
||||||
|
const title = ctx.globals.flowEngine.translate(params.title);
|
||||||
|
const description = ctx.globals.flowEngine.translate(params.description);
|
||||||
|
ctx.model.setDecoratorProps({ title: title, description: description });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setBlockHeight: {
|
||||||
|
title: tval('Set block height'),
|
||||||
|
uiSchema: {
|
||||||
|
heightMode: {
|
||||||
|
type: 'string',
|
||||||
|
enum: [
|
||||||
|
{ label: tval('Default'), value: HeightMode.DEFAULT },
|
||||||
|
{ label: tval('Specify height'), value: HeightMode.SPECIFY_VALUE },
|
||||||
|
{ label: tval('Full height'), value: HeightMode.FULL_HEIGHT },
|
||||||
|
],
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Radio.Group',
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
title: tval('Height'),
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'NumberPicker',
|
||||||
|
'x-component-props': {
|
||||||
|
addonAfter: 'px',
|
||||||
|
},
|
||||||
|
'x-validator': [
|
||||||
|
{
|
||||||
|
minimum: 40,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'x-reactions': {
|
||||||
|
dependencies: ['heightMode'],
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
hidden: '{{ $deps[0]==="fullHeight"||$deps[0]==="defaultHeight"}}',
|
||||||
|
value: '{{$deps[0]!=="specifyValue"?null:$self.value}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultParams: () => {
|
||||||
|
return {
|
||||||
|
heightMode: HeightMode.DEFAULT,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
handler(ctx, params) {
|
||||||
|
ctx.model.setProps('heightMode', params.heightMode);
|
||||||
|
ctx.model.setProps('height', params.height);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
export class DataBlockModel<T = DefaultStructure> extends BlockModel<T> {
|
export class DataBlockModel<T = DefaultStructure> extends BlockModel<T> {
|
||||||
resource: APIResource;
|
resource: APIResource;
|
||||||
collection: Collection;
|
collection: Collection;
|
||||||
|
@ -8,20 +8,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
import { Input } from '@formily/antd-v5';
|
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import {
|
import { AddBlockButton, FlowModel, FlowModelRenderer, FlowSettingsButton } from '@nocobase/flow-engine';
|
||||||
AddBlockButton,
|
|
||||||
FlowModel,
|
|
||||||
FlowModelRenderer,
|
|
||||||
FlowSettingsButton,
|
|
||||||
FlowsFloatContextMenu,
|
|
||||||
useStepSettingContext,
|
|
||||||
} from '@nocobase/flow-engine';
|
|
||||||
import { tval } from '@nocobase/utils/client';
|
import { tval } from '@nocobase/utils/client';
|
||||||
import { Alert, Space } from 'antd';
|
import { Space } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
import { Grid } from '../../components/Grid';
|
import { Grid } from '../../components/Grid';
|
||||||
import JsonEditor from '../../components/JsonEditor';
|
import JsonEditor from '../../components/JsonEditor';
|
||||||
import { SkeletonFallback } from '../../components/SkeletonFallback';
|
import { SkeletonFallback } from '../../components/SkeletonFallback';
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { theme, Card } from 'antd';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { NAMESPACE_UI_SCHEMA } from '../../../i18n/constant';
|
||||||
|
import { MarkdownReadPretty } from '../fields/EditableField/MarkdownEditableFieldModel';
|
||||||
|
|
||||||
|
export const BlockItemCard = (props) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { token } = theme.useToken();
|
||||||
|
const { title: blockTitle, description, children } = props;
|
||||||
|
const title = (blockTitle || description) && (
|
||||||
|
<div style={{ padding: '8px 0px 8px' }}>
|
||||||
|
<span> {t(blockTitle, { ns: NAMESPACE_UI_SCHEMA })}</span>
|
||||||
|
{description && (
|
||||||
|
<MarkdownReadPretty
|
||||||
|
value={t(description, { ns: NAMESPACE_UI_SCHEMA })}
|
||||||
|
style={{
|
||||||
|
overflowWrap: 'break-word',
|
||||||
|
whiteSpace: 'normal',
|
||||||
|
fontWeight: 400,
|
||||||
|
color: token.colorTextDescription,
|
||||||
|
borderRadius: '4px',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
title={title}
|
||||||
|
style={{ display: 'flex', flexDirection: 'column', height: '100%' }}
|
||||||
|
bodyStyle={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
@ -12,7 +12,6 @@ import { createForm, Form } from '@formily/core';
|
|||||||
import { FormProvider } from '@formily/react';
|
import { FormProvider } from '@formily/react';
|
||||||
import { AddActionButton, AddFieldButton, FlowModelRenderer, SingleRecordResource } from '@nocobase/flow-engine';
|
import { AddActionButton, AddFieldButton, FlowModelRenderer, SingleRecordResource } from '@nocobase/flow-engine';
|
||||||
import { tval } from '@nocobase/utils/client';
|
import { tval } from '@nocobase/utils/client';
|
||||||
import { Card } from 'antd';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { DataBlockModel } from '../../base/BlockModel';
|
import { DataBlockModel } from '../../base/BlockModel';
|
||||||
import { EditableFieldModel } from '../../fields/EditableField/EditableFieldModel';
|
import { EditableFieldModel } from '../../fields/EditableField/EditableFieldModel';
|
||||||
@ -21,10 +20,8 @@ export class FormModel extends DataBlockModel {
|
|||||||
form: Form;
|
form: Form;
|
||||||
declare resource: SingleRecordResource;
|
declare resource: SingleRecordResource;
|
||||||
|
|
||||||
render() {
|
renderComponent() {
|
||||||
console.log(this);
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
|
||||||
<FormProvider form={this.form}>
|
<FormProvider form={this.form}>
|
||||||
<FormLayout layout={'vertical'}>
|
<FormLayout layout={'vertical'}>
|
||||||
{this.mapSubModels('fields', (field) => (
|
{this.mapSubModels('fields', (field) => (
|
||||||
@ -68,7 +65,6 @@ export class FormModel extends DataBlockModel {
|
|||||||
<AddActionButton model={this} subModelBaseClass="FormActionModel" />
|
<AddActionButton model={this} subModelBaseClass="FormActionModel" />
|
||||||
</FormButtonGroup>
|
</FormButtonGroup>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
</Card>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,11 @@ import {
|
|||||||
useFlowEngine,
|
useFlowEngine,
|
||||||
} from '@nocobase/flow-engine';
|
} from '@nocobase/flow-engine';
|
||||||
import { tval } from '@nocobase/utils/client';
|
import { tval } from '@nocobase/utils/client';
|
||||||
import { Card, Space, Spin, Table } from 'antd';
|
import { Space, Spin, Table } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { t } from 'i18next';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
|
import { BlockItemCard } from '../../common/BlockItemCard';
|
||||||
import { ActionModel } from '../../base/ActionModel';
|
import { ActionModel } from '../../base/ActionModel';
|
||||||
import { DataBlockModel } from '../../base/BlockModel';
|
import { DataBlockModel } from '../../base/BlockModel';
|
||||||
import { QuickEditForm } from '../form/QuickEditForm';
|
import { QuickEditForm } from '../form/QuickEditForm';
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
import { connect, mapProps, mapReadPretty } from '@formily/react';
|
import { connect, mapProps, mapReadPretty } from '@formily/react';
|
||||||
import { Select } from 'antd';
|
import { Select } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { castArray } from 'lodash';
|
||||||
import { useFlowModel, FlowModel } from '@nocobase/flow-engine';
|
import { useFlowModel, FlowModel } from '@nocobase/flow-engine';
|
||||||
import { tval } from '@nocobase/utils/client';
|
import { tval } from '@nocobase/utils/client';
|
||||||
import { AssociationFieldEditableFieldModel } from './AssociationFieldEditableFieldModel';
|
import { AssociationFieldEditableFieldModel } from './AssociationFieldEditableFieldModel';
|
||||||
@ -82,7 +83,42 @@ const AssociationSelect = connect(
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
mapReadPretty((props) => {
|
mapReadPretty((props) => {
|
||||||
return props.value;
|
const currentModel: any = useFlowModel();
|
||||||
|
|
||||||
|
const { fieldNames, value } = props;
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const field = currentModel.subModels.field as FlowModel;
|
||||||
|
const key = value?.[fieldNames.value];
|
||||||
|
const fieldModel = field.createFork({}, key);
|
||||||
|
fieldModel.setSharedContext({
|
||||||
|
value: value?.[fieldNames.label],
|
||||||
|
currentRecord: value,
|
||||||
|
});
|
||||||
|
const arrayValue = castArray(value);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{arrayValue.map((v, index) => {
|
||||||
|
const key = `${index}`;
|
||||||
|
const fieldModel = field.createFork({}, key);
|
||||||
|
fieldModel.setSharedContext({
|
||||||
|
index,
|
||||||
|
value: v?.[fieldNames.label],
|
||||||
|
currentRecord: v,
|
||||||
|
});
|
||||||
|
|
||||||
|
const content = v?.[fieldNames.label] ? fieldModel.render() : tval('N/A');
|
||||||
|
return (
|
||||||
|
<React.Fragment key={index}>
|
||||||
|
{index > 0 && ', '}
|
||||||
|
{content}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -160,7 +196,7 @@ AssociationSelectEditableFieldModel.registerFlow({
|
|||||||
steps: {
|
steps: {
|
||||||
step1: {
|
step1: {
|
||||||
async handler(ctx, params) {
|
async handler(ctx, params) {
|
||||||
const { target } = ctx.model.collectionField.options;
|
const { target } = ctx.model.collectionField;
|
||||||
const apiClient = ctx.app.apiClient;
|
const apiClient = ctx.app.apiClient;
|
||||||
const response = await apiClient.request({
|
const response = await apiClient.request({
|
||||||
url: `/${target}:list`,
|
url: `/${target}:list`,
|
||||||
@ -244,9 +280,7 @@ AssociationSelectEditableFieldModel.registerFlow({
|
|||||||
async handler(ctx, params) {
|
async handler(ctx, params) {
|
||||||
try {
|
try {
|
||||||
const collectionField = ctx.model.collectionField;
|
const collectionField = ctx.model.collectionField;
|
||||||
const collectionManager = collectionField.collection.collectionManager;
|
const targetCollection = ctx.model.collectionField.targetCollection;
|
||||||
const targetCollection = collectionManager.getCollection(collectionField.options.target);
|
|
||||||
|
|
||||||
const labelFieldName = ctx.model.field.componentProps.fieldNames.label;
|
const labelFieldName = ctx.model.field.componentProps.fieldNames.label;
|
||||||
const targetLabelField = targetCollection.getField(labelFieldName);
|
const targetLabelField = targetCollection.getField(labelFieldName);
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ EditableFieldModel.registerFlow({
|
|||||||
if (collectionField.enum.length) {
|
if (collectionField.enum.length) {
|
||||||
ctx.model.setDataSource(collectionField.enum);
|
ctx.model.setDataSource(collectionField.enum);
|
||||||
}
|
}
|
||||||
const validator = collectionField.options.uiSchema?.['x-validator'];
|
const validator = collectionField.uiSchema?.['x-validator'];
|
||||||
if (validator) {
|
if (validator) {
|
||||||
ctx.model.setValidator(validator);
|
ctx.model.setValidator(validator);
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ export const MarkdownReadPretty = (props) => {
|
|||||||
<div
|
<div
|
||||||
className={` ${markdownClass} nb-markdown nb-markdown-default nb-markdown-table`}
|
className={` ${markdownClass} nb-markdown nb-markdown-default nb-markdown-table`}
|
||||||
dangerouslySetInnerHTML={{ __html: html }}
|
dangerouslySetInnerHTML={{ __html: html }}
|
||||||
|
style={props.style}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import { customAlphabet as Alphabet } from 'nanoid';
|
|||||||
import { EditableFieldModel } from './EditableFieldModel';
|
import { EditableFieldModel } from './EditableFieldModel';
|
||||||
|
|
||||||
export class NanoIDEditableFieldModel extends EditableFieldModel {
|
export class NanoIDEditableFieldModel extends EditableFieldModel {
|
||||||
static supportedFieldInterfaces = ['nanoID'];
|
static supportedFieldInterfaces = ['nanoid'];
|
||||||
|
|
||||||
get component() {
|
get component() {
|
||||||
return [Input, {}];
|
return [Input, {}];
|
||||||
@ -22,7 +22,7 @@ export class NanoIDEditableFieldModel extends EditableFieldModel {
|
|||||||
NanoIDEditableFieldModel.registerFlow({
|
NanoIDEditableFieldModel.registerFlow({
|
||||||
key: 'initialValue',
|
key: 'initialValue',
|
||||||
auto: true,
|
auto: true,
|
||||||
sort: 5,
|
sort: 1000,
|
||||||
steps: {
|
steps: {
|
||||||
initialValue: {
|
initialValue: {
|
||||||
handler(ctx, params) {
|
handler(ctx, params) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user