fix: remove temp doc (#3603)

* fix: remove temp doc

* refactor: moment => dayjs

---------

Co-authored-by: katherinehhh <katherine_15995@163.com>
This commit is contained in:
jack zhang 2024-03-05 12:34:20 +08:00 committed by GitHub
parent b545c6ccc3
commit b1a49f0d06
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 4 additions and 9599 deletions

View File

@ -179,12 +179,8 @@ export default defineConfig({
title: 'DataBlock',
type: 'group',
children: [
// {
// title: '临时',
// link: '/core/data-block/tmp',
// },
{
title: 'Record',
title: 'CollectionRecord',
link: '/core/data-block/collection-record',
},
{

View File

@ -1,128 +0,0 @@
export const mainCollections = [
{
name: 'users',
title: 'Users',
fields: [
{
key: 'id',
name: 'id',
interface: 'id',
primaryKey: true,
uiSchema: {
type: 'number',
title: 'ID',
'x-component': 'InputNumber',
'x-read-pretty': true,
rawTitle: 'ID',
},
},
{
uiSchema: {
type: 'string',
title: 'Nickname',
'x-component': 'Input',
},
name: 'nickname',
type: 'string',
interface: 'input',
},
{
uiSchema: {
type: 'string',
title: 'Email',
'x-component': 'Input',
required: true,
},
key: 'rrskwjl5wt1',
name: 'email',
type: 'string',
interface: 'email',
unique: true,
},
{
name: 'favoriteColor',
type: 'string',
interface: 'color',
uiSchema: {
type: 'string',
'x-component': 'ColorPicker',
default: '#1677FF',
title: 'Favorite Color',
},
},
],
},
{
name: 'roles',
title: 'Roles',
fields: [
{
uiSchema: {
type: 'string',
title: 'Role UID',
'x-component': 'Input',
},
name: 'name',
type: 'uid',
interface: 'input',
primaryKey: true,
},
{
uiSchema: {
type: 'string',
title: 'Role name',
'x-component': 'Input',
},
name: 'title',
type: 'string',
interface: 'input',
},
{
name: 'description',
type: 'string',
},
],
},
];
export const TestDBCollections = [
{
name: 'test1',
title: 'Test1',
fields: [
{
name: 'id',
interface: 'id',
primaryKey: true,
uiSchema: {
type: 'number',
title: 'ID',
'x-component': 'InputNumber',
'x-read-pretty': true,
},
},
{
name: 'field1',
interface: 'input',
uiSchema: {
type: 'string',
'x-component': 'Input',
title: 'Field1',
},
},
{
name: 'field2',
interface: 'number',
uiSchema: {
'x-component-props': {
step: '1',
stringMode: true,
},
'x-component': 'InputNumber',
title: 'Field2',
},
defaultValue: 1,
},
],
},
];

View File

@ -1 +0,0 @@
import { Application } from '@nocobase/client';

View File

@ -1,41 +0,0 @@
import { Table } from 'antd';
import React from 'react';
const MyTable = () => {
const dataSource = [
{
key: '1',
name: 'Mike',
age: 32,
address: '10 Downing Street',
},
{
key: '2',
name: 'John',
age: 42,
address: '10 Downing Street',
},
];
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
];
return <Table dataSource={dataSource} columns={columns} />;
};
export default MyTable;

View File

@ -1,412 +0,0 @@
import { Button, Drawer, Space, Table, TableProps } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
SchemaSettings,
SchemaToolbar,
useCollection,
useCompile,
useDataBlock,
useDataBlockProps,
useDataBlockRequest,
useDataSourceManager,
useSchemaInitializer,
useSchemaInitializerRender,
useSchemaToolbar,
useSchemaToolbarRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, Schema, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' });
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
function useTableProps(): TableProps<any> {
const { tableProps } = useDataBlockProps();
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const collection = useCollection();
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useMemo(() => {
return collection.getFields().map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
title: <RecursionField name={collectionField.name} schema={tableFieldSchema} onlyRenderSelf />,
dataIndex: collectionField.name,
render(value, record, index) {
return (
<RecursionField basePath={field.address.concat(index)} onlyRenderProperties schema={tableFieldSchema} />
);
},
};
});
}, [collection]);
return {
...tableProps,
loading,
dataSource,
columns,
};
}
const myTableSettings = new SchemaSettings({
name: 'myTableSettings',
items: [
{
name: 'bordered',
type: 'switch',
useComponentProps() {
const { props: blockSettingsProps, dn } = useDataBlock();
return {
title: 'Bordered',
checked: !!blockSettingsProps.tableProps?.bordered,
onChange: (checked) => {
// 修改 schema
dn.deepMerge({ 'x-decorator-props': { tableProps: { bordered: checked } } });
},
};
},
},
{
type: 'remove',
name: 'remove',
},
],
});
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const CreateAction = () => {
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const compile = useCompile();
const collection = useCollection();
const title = compile(collection.title);
const fieldSchema = useFieldSchema();
const { render } = useSchemaToolbarRender(fieldSchema);
return (
<>
<div>
{render()}
<Button type="primary" onClick={showDrawer}>
Add New
</Button>
</div>
<Drawer title={`${title} | Add New`} onClose={onClose} open={open}>
<p>Some contents...</p>
</Drawer>
</>
);
};
const createActionSettings = new SchemaSettings({
name: 'createActionSettings',
items: [
{
type: 'remove',
name: 'remove',
},
],
});
const RefreshAction = () => {
const { refresh } = useDataBlockRequest();
return <Button onClick={refresh}>Refresh</Button>;
};
const ActionBar = ({ children }) => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: 'var(--nb-spacing)',
}}
>
<Space>
{children}
{render()}
</Space>
</div>
);
};
const CreateActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'CreateAction',
'x-settings': 'createActionSettings',
});
};
return <SchemaInitializerItem title={'Add New'} onClick={handleClick}></SchemaInitializerItem>;
};
const RefreshActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'RefreshAction',
});
};
return <SchemaInitializerItem title={'Refresh'} onClick={handleClick}></SchemaInitializerItem>;
};
const tableActionInitializers = new SchemaInitializer({
name: 'tableActionInitializers',
title: 'Configure actions',
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'item',
name: 'addNew',
Component: CreateActionInitializer,
},
{
type: 'item',
name: 'refresh',
Component: RefreshActionInitializer,
},
],
});
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'myTableSettings',
'x-decorator': 'DataBlockProvider',
'x-toolbar': 'MyToolbar',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
tableProps: {
bordered: true,
},
},
properties: {
actions: {
type: 'void',
'x-component': 'ActionBar',
'x-initializer': 'tableActionInitializers',
},
[uid()]: {
type: 'array',
'x-component': 'MyTable',
'x-use-component-props': 'useTableProps',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const MyToolbar = (props) => {
const collection = useCollection();
const compile = useCompile();
return <SchemaToolbar title={`${compile(collection.title)}`} {...props} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable, TableColumn, MyToolbar, ActionBar, CreateAction, RefreshAction });
this.app.schemaInitializerManager.add(myInitializer);
this.app.schemaSettingsManager.add(myTableSettings);
this.app.schemaSettingsManager.add(createActionSettings);
this.app.addScopes({ useTableProps });
this.app.schemaInitializerManager.add(tableActionInitializers);
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,492 +0,0 @@
import { Button, Drawer, Space, Table, TableProps } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
SchemaInitializerSwitch,
SchemaSettings,
SchemaToolbar,
useCollection,
useCompile,
useCurrentSchema,
useDataBlock,
useDataBlockProps,
useDataBlockRequest,
useDataSourceManager,
useDesignable,
useSchemaInitializer,
useSchemaInitializerItem,
useSchemaInitializerRender,
useSchemaToolbarRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' });
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
function useTableColumns() {
const schema = useFieldSchema();
const filed = useField();
const { designable } = useDesignable();
const { render } = useSchemaInitializerRender(schema['x-initializer'], schema['x-initializer-props']);
const columns = schema.mapProperties((tableField: any, name) => {
return {
title: <RecursionField name={tableField.name} schema={tableField} onlyRenderSelf />,
dataIndex: name,
key: name,
width: 200,
render(value, record, index) {
return <RecursionField basePath={filed.address.concat(index)} onlyRenderProperties schema={tableField} />;
},
};
});
const tableColumns = useMemo(() => {
return [
...columns,
{
title: render(),
dataIndex: 'TABLE_COLUMN_INITIALIZER',
key: 'TABLE_COLUMN_INITIALIZER',
width: 200,
render: designable ? () => <div style={{ minWidth: 300 }} /> : null,
},
];
}, [columns, render, designable]);
return tableColumns;
}
function useTableProps(): TableProps<any> {
const { tableProps } = useDataBlockProps();
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useTableColumns();
return {
...tableProps,
loading,
dataSource,
columns,
};
}
const myTableSettings = new SchemaSettings({
name: 'myTableSettings',
items: [
{
name: 'bordered',
type: 'switch',
useComponentProps() {
const { props: blockSettingsProps, dn } = useDataBlock();
return {
title: 'Bordered',
checked: !!blockSettingsProps.tableProps?.bordered,
onChange: (checked) => {
// 修改 schema
dn.deepMerge({ 'x-decorator-props': { tableProps: { bordered: checked } } });
},
};
},
},
{
type: 'remove',
name: 'remove',
},
],
});
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const CreateAction = () => {
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const compile = useCompile();
const collection = useCollection();
const title = compile(collection.title);
const fieldSchema = useFieldSchema();
const { render } = useSchemaToolbarRender(fieldSchema);
return (
<>
<div>
{render()}
<Button type="primary" onClick={showDrawer}>
Add New
</Button>
</div>
<Drawer title={`${title} | Add New`} onClose={onClose} open={open}>
<p>Some contents...</p>
</Drawer>
</>
);
};
const createActionSettings = new SchemaSettings({
name: 'createActionSettings',
items: [
{
type: 'remove',
name: 'remove',
},
],
});
const RefreshAction = () => {
const { refresh } = useDataBlockRequest();
return <Button onClick={refresh}>Refresh</Button>;
};
const ActionBar = ({ children }) => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: 'var(--nb-spacing)',
}}
>
<Space>
{children}
{render()}
</Space>
</div>
);
};
const CreateActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'CreateAction',
'x-settings': 'createActionSettings',
});
};
return <SchemaInitializerItem title={'Add New'} onClick={handleClick}></SchemaInitializerItem>;
};
const RefreshActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'RefreshAction',
});
};
return <SchemaInitializerItem title={'Refresh'} onClick={handleClick}></SchemaInitializerItem>;
};
const tableActionInitializers = new SchemaInitializer({
name: 'tableActionInitializers',
title: 'Configure actions',
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'item',
name: 'addNew',
Component: CreateActionInitializer,
},
{
type: 'item',
name: 'refresh',
Component: RefreshActionInitializer,
},
],
});
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'myTableSettings',
'x-decorator': 'DataBlockProvider',
'x-toolbar': 'MyToolbar',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
tableProps: {
bordered: true,
},
},
properties: {
actions: {
type: 'void',
'x-component': 'ActionBar',
'x-initializer': 'tableActionInitializers',
},
[uid()]: {
type: 'array',
'x-component': 'MyTable',
'x-use-component-props': 'useTableProps',
'x-initializer': 'tableColumnInitializers',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const useTableColumnInitializerFields = () => {
const collection = useCollection();
return collection.fields.map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
type: 'item',
name: collectionField.name,
title: collectionField?.uiSchema?.title || collectionField.name,
Component: 'TableCollectionFieldInitializer',
schema: tableFieldSchema,
};
});
};
export const TableCollectionFieldInitializer = () => {
const itemConfig = useSchemaInitializerItem();
const { insert } = useSchemaInitializer();
const { remove } = useDesignable();
const schema = useFieldSchema();
const exists = !!schema.properties?.[itemConfig.name];
return (
<SchemaInitializerSwitch
checked={exists}
title={itemConfig.title}
onClick={() => {
if (exists) {
return remove(schema.properties?.[itemConfig.name]);
}
insert(itemConfig.schema);
}}
/>
);
};
const tableColumnInitializers = new SchemaInitializer({
name: 'tableColumnInitializers',
insertPosition: 'beforeEnd',
icon: 'SettingOutlined',
title: 'Configure columns',
items: [
{
name: 'displayFields',
type: 'itemGroup',
title: 'Display fields',
useChildren: useTableColumnInitializerFields,
},
],
});
const MyToolbar = (props) => {
const collection = useCollection();
const compile = useCompile();
return <SchemaToolbar title={`${compile(collection.title)}`} {...props} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({
MyTable,
TableColumn,
MyToolbar,
ActionBar,
CreateAction,
RefreshAction,
TableCollectionFieldInitializer,
});
this.app.schemaInitializerManager.add(myInitializer);
this.app.schemaSettingsManager.add(myTableSettings);
this.app.addScopes({ useTableProps });
this.app.schemaInitializerManager.add(tableActionInitializers);
this.app.schemaInitializerManager.add(tableColumnInitializers);
this.app.schemaSettingsManager.add(createActionSettings);
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,532 +0,0 @@
import { Button, Drawer, Space, Table, TableProps } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
CollectionRecordProvider,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
SchemaInitializerSwitch,
SchemaSettings,
SchemaToolbar,
useCollection,
useCompile,
useCurrentSchema,
useDataBlock,
useDataBlockProps,
useDataBlockRequest,
useDataSource,
useDataSourceManager,
useDesignable,
useCollectionRecord,
useSchemaInitializer,
useSchemaInitializerItem,
useSchemaInitializerRender,
useSchemaToolbarRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' });
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
const ColumnView = observer(
() => {
const record = useCollectionRecord();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
return (
<>
<Button type="link" onClick={showDrawer}>
view
</Button>
<Drawer onClose={onClose} open={open}>
<pre>{JSON.stringify(record, null, 2)}</pre>
</Drawer>
</>
);
},
{ displayName: 'ColumnView' },
);
function useTableColumns() {
const schema = useFieldSchema();
const filed = useField();
const { designable } = useDesignable();
const { render } = useSchemaInitializerRender(schema['x-initializer'], schema['x-initializer-props']);
const columns = schema.mapProperties((tableField: any, name) => {
return {
title: <RecursionField name={tableField.name} schema={tableField} onlyRenderSelf />,
dataIndex: name,
key: name,
render(value, record, index) {
return <RecursionField basePath={filed.address.concat(index)} onlyRenderProperties schema={tableField} />;
},
};
});
const tableColumns = useMemo(() => {
return [
...columns,
{
title: 'Actions',
dataIndex: 'actions',
key: 'actions',
render: (value, record) => {
return (
<CollectionRecordProvider record={record}>
<Space>
<ColumnView />
</Space>
</CollectionRecordProvider>
);
},
},
{
title: render(),
dataIndex: 'TABLE_COLUMN_INITIALIZER',
key: 'TABLE_COLUMN_INITIALIZER',
render: designable ? () => <div style={{ minWidth: 300 }} /> : null,
},
];
}, [columns, render, designable]);
return tableColumns;
}
function useTableProps(): TableProps<any> {
const { tableProps } = useDataBlockProps();
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useTableColumns();
return {
...tableProps,
loading,
dataSource,
columns,
};
}
const myTableSettings = new SchemaSettings({
name: 'myTableSettings',
items: [
{
name: 'bordered',
type: 'switch',
useComponentProps() {
const { props: blockSettingsProps, dn } = useDataBlock();
return {
title: 'Bordered',
checked: !!blockSettingsProps.tableProps?.bordered,
onChange: (checked) => {
// 修改 schema
dn.deepMerge({ 'x-decorator-props': { tableProps: { bordered: checked } } });
},
};
},
},
{
type: 'remove',
name: 'remove',
},
],
});
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const CreateAction = () => {
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const compile = useCompile();
const collection = useCollection();
const title = compile(collection.title);
const fieldSchema = useFieldSchema();
const { render } = useSchemaToolbarRender(fieldSchema);
return (
<>
<div>
{render()}
<Button type="primary" onClick={showDrawer}>
Add New
</Button>
</div>
<Drawer title={`${title} | Add New`} onClose={onClose} open={open}>
<p>Some contents...</p>
</Drawer>
</>
);
};
const createActionSettings = new SchemaSettings({
name: 'createActionSettings',
items: [
{
type: 'remove',
name: 'remove',
},
],
});
const RefreshAction = () => {
const { refresh } = useDataBlockRequest();
return <Button onClick={refresh}>Refresh</Button>;
};
const ActionBar = ({ children }) => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: 'var(--nb-spacing)',
}}
>
<Space>
{children}
{render()}
</Space>
</div>
);
};
const CreateActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'CreateAction',
'x-settings': 'createActionSettings',
});
};
return <SchemaInitializerItem title={'Add New'} onClick={handleClick}></SchemaInitializerItem>;
};
const RefreshActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'RefreshAction',
});
};
return <SchemaInitializerItem title={'Refresh'} onClick={handleClick}></SchemaInitializerItem>;
};
const tableActionInitializers = new SchemaInitializer({
name: 'tableActionInitializers',
title: 'Configure actions',
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'item',
name: 'addNew',
Component: CreateActionInitializer,
},
{
type: 'item',
name: 'refresh',
Component: RefreshActionInitializer,
},
],
});
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'myTableSettings',
'x-decorator': 'DataBlockProvider',
'x-toolbar': 'MyToolbar',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
tableProps: {
bordered: true,
},
},
properties: {
actions: {
type: 'void',
'x-component': 'ActionBar',
'x-initializer': 'tableActionInitializers',
},
[uid()]: {
type: 'array',
'x-component': 'MyTable',
'x-use-component-props': 'useTableProps',
'x-initializer': 'tableColumnInitializers',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const useTableColumnInitializerFields = () => {
const collection = useCollection();
return collection.fields.map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
type: 'item',
name: collectionField.name,
title: collectionField?.uiSchema?.title || collectionField.name,
Component: 'TableCollectionFieldInitializer',
schema: tableFieldSchema,
};
});
};
export const TableCollectionFieldInitializer = () => {
const itemConfig = useSchemaInitializerItem();
const { insert } = useSchemaInitializer();
const { remove } = useDesignable();
const schema = useFieldSchema();
const exists = !!schema.properties?.[itemConfig.name];
return (
<SchemaInitializerSwitch
checked={exists}
title={itemConfig.title}
onClick={() => {
if (exists) {
return remove(schema.properties?.[itemConfig.name]);
}
insert(itemConfig.schema);
}}
/>
);
};
const tableColumnInitializers = new SchemaInitializer({
name: 'tableColumnInitializers',
insertPosition: 'beforeEnd',
icon: 'SettingOutlined',
title: 'Configure columns',
items: [
{
name: 'displayFields',
type: 'itemGroup',
title: 'Display fields',
useChildren: useTableColumnInitializerFields,
},
],
});
const MyToolbar = (props) => {
const collection = useCollection();
const compile = useCompile();
return <SchemaToolbar title={`${compile(collection.title)}`} {...props} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({
MyTable,
TableColumn,
MyToolbar,
ActionBar,
CreateAction,
RefreshAction,
TableCollectionFieldInitializer,
});
this.app.schemaInitializerManager.add(myInitializer);
this.app.schemaSettingsManager.add(myTableSettings);
this.app.addScopes({ useTableProps });
this.app.schemaInitializerManager.add(tableActionInitializers);
this.app.schemaInitializerManager.add(tableColumnInitializers);
this.app.schemaSettingsManager.add(createActionSettings);
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,82 +0,0 @@
import { Table } from 'antd';
import React from 'react';
import { CardItem, Plugin, SchemaComponent } from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
const MyTable = () => {
const dataSource = [
{
key: '1',
name: 'Mike',
age: 32,
address: '10 Downing Street',
},
{
key: '2',
name: 'John',
age: 42,
address: '10 Downing Street',
},
];
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
];
return <Table dataSource={dataSource} columns={columns} />;
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable });
}
}
const tableSchema = {
name: 'demo',
type: 'void',
'x-component': 'CardItem',
properties: {
[uid()]: {
type: 'array',
'x-component': 'MyTable',
},
},
};
const Root = () => {
return <SchemaComponent schema={tableSchema} />;
};
const app = new Application({
plugins: [MyPlugin],
components: {
CardItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
});
app.router.add('root', {
path: '/',
Component: Root,
});
export default app.getRootComponent();

View File

@ -1,147 +0,0 @@
import { Table } from 'antd';
import React, { useCallback } from 'react';
import {
CardItem,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
useSchemaInitializer,
useSchemaInitializerRender,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, observer, useFieldSchema } from '@formily/react';
const MyTable = () => {
const dataSource = [
{
key: '1',
name: 'Mike',
age: 32,
address: '10 Downing Street',
},
{
key: '2',
name: 'John',
age: 42,
address: '10 Downing Street',
},
];
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
];
return <Table dataSource={dataSource} columns={columns} />;
};
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = useCallback(
({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
properties: {
[uid()]: {
type: 'array',
'x-component': 'MyTable',
},
},
};
insert(tableSchema);
setVisible(false);
},
[insert, setVisible],
);
return <SchemaInitializerItem title={'Table'} onClick={handleClick} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable });
this.app.schemaInitializerManager.add(myInitializer);
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
});
app.router.add('home', {
path: '/',
Component: Root,
});
export default app.getRootComponent();

View File

@ -1,180 +0,0 @@
import { Table } from 'antd';
import React, { useMemo } from 'react';
import {
CardItem,
DataBlockProvider,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
useCollection,
useDataBlockRequest,
useDataSourceManager,
useSchemaInitializer,
useSchemaInitializerRender,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, observer, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = () => {
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const collection = useCollection();
const columns = useMemo(() => {
return collection.getFields().map((collectionField) => {
return {
title: collectionField.uiSchema?.title || collectionField.name,
dataIndex: collectionField.name,
};
});
}, [collection]);
return <Table loading={loading} rowKey="id" dataSource={dataSource} columns={columns} />;
};
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-decorator': 'DataBlockProvider',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
},
properties: {
[uid()]: {
type: 'array',
'x-component': 'MyTable',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable });
this.app.schemaInitializerManager.add(myInitializer);
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,236 +0,0 @@
import { Table } from 'antd';
import React, { useEffect, useMemo } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
useCollection,
useDataBlockRequest,
useDataSourceManager,
useSchemaInitializer,
useSchemaInitializerRender,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
const MyTable = () => {
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const collection = useCollection();
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useMemo(() => {
return collection.getFields().map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
title: <RecursionField name={collectionField.name} schema={tableFieldSchema} onlyRenderSelf />,
dataIndex: collectionField.name,
render(value, record, index) {
return (
<RecursionField basePath={field.address.concat(index)} onlyRenderProperties schema={tableFieldSchema} />
);
},
};
});
}, [collection]);
return <Table loading={loading} rowKey={'id'} dataSource={dataSource} columns={columns} />;
};
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-decorator': 'DataBlockProvider',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
},
properties: {
[uid()]: {
type: 'array',
'x-component': 'MyTable',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable, TableColumn });
this.app.schemaInitializerManager.add(myInitializer);
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,280 +0,0 @@
import { Table, TableProps } from 'antd';
import React, { useEffect, useMemo } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
SchemaSettings,
useCollection,
useDataBlock,
useDataBlockProps,
useDataBlockRequest,
useDataSourceManager,
useSchemaInitializer,
useSchemaInitializerRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' });
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
function useTableProps(): TableProps<any> {
const { tableProps } = useDataBlockProps();
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const collection = useCollection();
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useMemo(() => {
return collection.getFields().map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
title: <RecursionField name={collectionField.name} schema={tableFieldSchema} onlyRenderSelf />,
dataIndex: collectionField.name,
render(value, record, index) {
return (
<RecursionField basePath={field.address.concat(index)} onlyRenderProperties schema={tableFieldSchema} />
);
},
};
});
}, [collection]);
return {
...tableProps,
loading,
dataSource,
columns,
rowKey: 'id',
};
}
const myTableSettings = new SchemaSettings({
name: 'myTableSettings',
items: [
{
name: 'bordered',
type: 'switch',
useComponentProps() {
const { props: blockSettingsProps, dn } = useDataBlock();
return {
title: 'Bordered',
checked: !!blockSettingsProps.tableProps?.bordered,
onChange: (checked) => {
// 修改 schema
dn.deepMerge({ 'x-decorator-props': { tableProps: { bordered: checked } } });
},
};
},
},
{
type: 'remove',
name: 'remove',
},
],
});
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'myTableSettings',
'x-decorator': 'DataBlockProvider',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
tableProps: {
bordered: true,
},
},
properties: {
[uid()]: {
type: 'array',
'x-component': 'MyTable',
'x-use-component-props': 'useTableProps',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable, TableColumn });
this.app.schemaInitializerManager.add(myInitializer);
this.app.schemaSettingsManager.add(myTableSettings);
this.app.addScopes({ useTableProps });
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,291 +0,0 @@
import { Table, TableProps } from 'antd';
import React, { useEffect, useMemo } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
SchemaSettings,
SchemaToolbar,
useCollection,
useCompile,
useDataBlock,
useDataBlockProps,
useDataBlockRequest,
useDataSource,
useDataSourceManager,
useSchemaInitializer,
useSchemaInitializerRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' });
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
function useTableProps(): TableProps<any> {
const { tableProps } = useDataBlockProps();
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const collection = useCollection();
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useMemo(() => {
return collection.getFields().map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
title: <RecursionField name={collectionField.name} schema={tableFieldSchema} onlyRenderSelf />,
dataIndex: collectionField.name,
render(value, record, index) {
return (
<RecursionField basePath={field.address.concat(index)} onlyRenderProperties schema={tableFieldSchema} />
);
},
};
});
}, [collection]);
return {
...tableProps,
loading,
dataSource,
columns,
};
}
const myTableSettings = new SchemaSettings({
name: 'myTableSettings',
items: [
{
name: 'bordered',
type: 'switch',
useComponentProps() {
const { props: blockSettingsProps, dn } = useDataBlock();
return {
title: 'Bordered',
checked: !!blockSettingsProps.tableProps?.bordered,
onChange: (checked) => {
// 修改 schema
dn.deepMerge({ 'x-decorator-props': { tableProps: { bordered: checked } } });
},
};
},
},
{
type: 'remove',
name: 'remove',
},
],
});
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'myTableSettings',
'x-decorator': 'DataBlockProvider',
'x-toolbar': 'MyToolbar',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
tableProps: {
bordered: true,
},
},
properties: {
[uid()]: {
type: 'array',
'x-component': 'MyTable',
'x-use-component-props': 'useTableProps',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const MyToolbar = (props) => {
const collection = useCollection();
const compile = useCompile();
return <SchemaToolbar title={`${compile(collection.title)}`} {...props} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable, TableColumn, MyToolbar });
this.app.schemaInitializerManager.add(myInitializer);
this.app.schemaSettingsManager.add(myTableSettings);
this.app.addScopes({ useTableProps });
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,351 +0,0 @@
import { Button, Drawer, Space, Table, TableProps } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
SchemaSettings,
SchemaToolbar,
useCollection,
useCompile,
useDataBlock,
useDataBlockProps,
useDataBlockRequest,
useDataSource,
useDataSourceManager,
useSchemaInitializer,
useSchemaInitializerRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' });
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
function useTableProps(): TableProps<any> {
const { tableProps } = useDataBlockProps();
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const collection = useCollection();
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useMemo(() => {
return collection.getFields().map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
title: <RecursionField name={collectionField.name} schema={tableFieldSchema} onlyRenderSelf />,
dataIndex: collectionField.name,
render(value, record, index) {
return (
<RecursionField basePath={field.address.concat(index)} onlyRenderProperties schema={tableFieldSchema} />
);
},
};
});
}, [collection]);
return {
...tableProps,
loading,
dataSource,
columns,
};
}
const myTableSettings = new SchemaSettings({
name: 'myTableSettings',
items: [
{
name: 'bordered',
type: 'switch',
useComponentProps() {
const { props: blockSettingsProps, dn } = useDataBlock();
return {
title: 'Bordered',
checked: !!blockSettingsProps.tableProps?.bordered,
onChange: (checked) => {
// 修改 schema
dn.deepMerge({ 'x-decorator-props': { tableProps: { bordered: checked } } });
},
};
},
},
{
type: 'remove',
name: 'remove',
},
],
});
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const CreateAction = () => {
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const compile = useCompile();
const collection = useCollection();
const title = compile(collection.title);
return (
<>
<Button type="primary" onClick={showDrawer}>
Add New
</Button>
<Drawer title={`${title} | Add New`} onClose={onClose} open={open}>
<p>Some contents...</p>
</Drawer>
</>
);
};
const RefreshAction = () => {
const { refresh } = useDataBlockRequest();
return <Button onClick={refresh}>Refresh</Button>;
};
const ActionBar = () => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: 'var(--nb-spacing)',
}}
>
<Space>
<CreateAction></CreateAction>
<RefreshAction></RefreshAction>
{render()}
</Space>
</div>
);
};
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'myTableSettings',
'x-decorator': 'DataBlockProvider',
'x-toolbar': 'MyToolbar',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
tableProps: {
bordered: true,
},
},
properties: {
actions: {
type: 'void',
'x-component': 'ActionBar',
'x-initializer': 'tableActionInitializers',
},
[uid()]: {
type: 'array',
'x-component': 'MyTable',
'x-use-component-props': 'useTableProps',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const MyToolbar = (props) => {
const collection = useCollection();
const compile = useCompile();
return <SchemaToolbar title={`${compile(collection.title)}`} {...props} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable, TableColumn, MyToolbar, ActionBar });
this.app.schemaInitializerManager.add(myInitializer);
this.app.schemaSettingsManager.add(myTableSettings);
this.app.addScopes({ useTableProps });
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,394 +0,0 @@
import { Button, Drawer, Space, Table, TableProps } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
SchemaSettings,
SchemaToolbar,
useCollection,
useCompile,
useDataBlock,
useDataBlockProps,
useDataBlockRequest,
useDataSource,
useDataSourceManager,
useSchemaInitializer,
useSchemaInitializerRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' });
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
function useTableProps(): TableProps<any> {
const { tableProps } = useDataBlockProps();
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const collection = useCollection();
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useMemo(() => {
return collection.getFields().map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
title: <RecursionField name={collectionField.name} schema={tableFieldSchema} onlyRenderSelf />,
dataIndex: collectionField.name,
render(value, record, index) {
return (
<RecursionField basePath={field.address.concat(index)} onlyRenderProperties schema={tableFieldSchema} />
);
},
};
});
}, [collection]);
return {
...tableProps,
loading,
dataSource,
columns,
};
}
const myTableSettings = new SchemaSettings({
name: 'myTableSettings',
items: [
{
name: 'bordered',
type: 'switch',
useComponentProps() {
const { props: blockSettingsProps, dn } = useDataBlock();
return {
title: 'Bordered',
checked: !!blockSettingsProps.tableProps?.bordered,
onChange: (checked) => {
// 修改 schema
dn.deepMerge({ 'x-decorator-props': { tableProps: { bordered: checked } } });
},
};
},
},
{
type: 'remove',
name: 'remove',
},
],
});
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const CreateAction = () => {
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const compile = useCompile();
const collection = useCollection();
const title = compile(collection.title);
return (
<>
<Button type="primary" onClick={showDrawer}>
Add New
</Button>
<Drawer title={`${title} | Add New`} onClose={onClose} open={open}>
<p>Some contents...</p>
</Drawer>
</>
);
};
const RefreshAction = () => {
const { refresh } = useDataBlockRequest();
return <Button onClick={refresh}>Refresh</Button>;
};
const ActionBar = ({ children }) => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: 'var(--nb-spacing)',
}}
>
<Space>
{children}
{render()}
</Space>
</div>
);
};
const CreateActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'CreateAction',
});
};
return <SchemaInitializerItem title={'Add New'} onClick={handleClick}></SchemaInitializerItem>;
};
const RefreshActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'RefreshAction',
});
};
return <SchemaInitializerItem title={'Refresh'} onClick={handleClick}></SchemaInitializerItem>;
};
const tableActionInitializers = new SchemaInitializer({
name: 'tableActionInitializers',
title: 'Configure actions',
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'item',
name: 'addNew',
Component: CreateActionInitializer,
},
{
type: 'item',
name: 'refresh',
Component: RefreshActionInitializer,
},
],
});
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'myTableSettings',
'x-decorator': 'DataBlockProvider',
'x-toolbar': 'MyToolbar',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
tableProps: {
bordered: true,
},
},
properties: {
actions: {
type: 'void',
'x-component': 'ActionBar',
'x-initializer': 'tableActionInitializers',
},
[uid()]: {
type: 'array',
'x-component': 'MyTable',
'x-use-component-props': 'useTableProps',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const MyToolbar = (props) => {
const collection = useCollection();
const compile = useCompile();
return <SchemaToolbar title={`${compile(collection.title)}`} {...props} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable, TableColumn, MyToolbar, ActionBar, CreateAction, RefreshAction });
this.app.schemaInitializerManager.add(myInitializer);
this.app.schemaSettingsManager.add(myTableSettings);
this.app.addScopes({ useTableProps });
this.app.schemaInitializerManager.add(tableActionInitializers);
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,79 +0,0 @@
import type { Application } from '@nocobase/client';
import MockAdapter from 'axios-mock-adapter';
const mockData = {
'users:list': {
data: [
{
id: '1',
nickname: 'Jack Ma',
email: 'test@gmail.com',
favoriteColor: '#1677FF',
},
{
id: '2',
email: 'jim@gmail.com',
nickname: 'Jim Green',
favoriteColor: '#36C',
},
{
id: '3',
nickname: 'Tom Cat',
email: 'tom@gmail.com',
favoriteColor: '#F0F',
},
],
},
'users:destroy': {
result: 'ok',
},
'roles:list': {
data: [
{
name: 'root',
title: 'Root',
description: 'Root',
},
{
name: 'admin',
title: 'Admin',
description: 'Admin description',
},
],
},
'test1:list': {
data: [
{
id: '1',
field1: 'aaa',
field2: 1,
},
{
id: '2',
field1: 'bbb',
field2: 2,
},
{
id: '3',
field1: 'ccc',
field2: 3,
},
],
},
};
export function mock(app: Application) {
const mock = new MockAdapter(app.apiClient.axios);
Object.entries(mockData).forEach(([url, data]) => {
mock.onGet(url).reply(async (config) => {
return [200, data];
});
mock.onPost(url).reply(async (config) => {
return [200, data];
});
mock.onDelete(url).reply(async (config) => {
return [200, data];
});
});
}

File diff suppressed because it is too large Load Diff

View File

@ -1,128 +0,0 @@
export const mainCollections = [
{
name: 'users',
title: 'Users',
fields: [
{
key: 'id',
name: 'id',
interface: 'id',
primaryKey: true,
uiSchema: {
type: 'number',
title: 'ID',
'x-component': 'InputNumber',
'x-read-pretty': true,
rawTitle: 'ID',
},
},
{
uiSchema: {
type: 'string',
title: 'Nickname',
'x-component': 'Input',
},
name: 'nickname',
type: 'string',
interface: 'input',
},
{
uiSchema: {
type: 'string',
title: 'Email',
'x-component': 'Input',
required: true,
},
key: 'rrskwjl5wt1',
name: 'email',
type: 'string',
interface: 'email',
unique: true,
},
{
name: 'favoriteColor',
type: 'string',
interface: 'color',
uiSchema: {
type: 'string',
'x-component': 'ColorPicker',
default: '#1677FF',
title: 'Favorite Color',
},
},
],
},
{
name: 'roles',
title: 'Roles',
fields: [
{
uiSchema: {
type: 'string',
title: 'Role UID',
'x-component': 'Input',
},
name: 'name',
type: 'uid',
interface: 'input',
primaryKey: true,
},
{
uiSchema: {
type: 'string',
title: 'Role name',
'x-component': 'Input',
},
name: 'title',
type: 'string',
interface: 'input',
},
{
name: 'description',
type: 'string',
},
],
},
];
export const TestDBCollections = [
{
name: 'test1',
title: 'Test1',
fields: [
{
name: 'id',
interface: 'id',
primaryKey: true,
uiSchema: {
type: 'number',
title: 'ID',
'x-component': 'InputNumber',
'x-read-pretty': true,
},
},
{
name: 'field1',
interface: 'input',
uiSchema: {
type: 'string',
'x-component': 'Input',
title: 'Field1',
},
},
{
name: 'field2',
interface: 'number',
uiSchema: {
'x-component-props': {
step: '1',
stringMode: true,
},
'x-component': 'InputNumber',
title: 'Field2',
},
defaultValue: 1,
},
],
},
];

View File

@ -1 +0,0 @@
import { Application } from '@nocobase/client';

View File

@ -1,41 +0,0 @@
import { Table } from 'antd';
import React from 'react';
const MyTable = () => {
const dataSource = [
{
key: '1',
name: 'Mike',
age: 32,
address: '10 Downing Street',
},
{
key: '2',
name: 'John',
age: 42,
address: '10 Downing Street',
},
];
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
];
return <Table dataSource={dataSource} columns={columns} />;
};
export default MyTable;

View File

@ -1,412 +0,0 @@
import { Button, Drawer, Space, Table, TableProps } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
SchemaSettings,
SchemaToolbar,
useCollection,
useCompile,
useDataBlock,
useDataBlockProps,
useDataBlockRequest,
useDataSourceManager,
useSchemaInitializer,
useSchemaInitializerRender,
useSchemaToolbar,
useSchemaToolbarRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, Schema, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' });
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
function useTableProps(): TableProps<any> {
const { tableProps } = useDataBlockProps();
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const collection = useCollection();
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useMemo(() => {
return collection.getFields().map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
title: <RecursionField name={collectionField.name} schema={tableFieldSchema} onlyRenderSelf />,
dataIndex: collectionField.name,
render(value, record, index) {
return (
<RecursionField basePath={field.address.concat(index)} onlyRenderProperties schema={tableFieldSchema} />
);
},
};
});
}, [collection]);
return {
...tableProps,
loading,
dataSource,
columns,
};
}
const myTableSettings = new SchemaSettings({
name: 'myTableSettings',
items: [
{
name: 'bordered',
type: 'switch',
useComponentProps() {
const { props: blockSettingsProps, dn } = useDataBlock();
return {
title: 'Bordered',
checked: !!blockSettingsProps.tableProps?.bordered,
onChange: (checked) => {
// 修改 schema
dn.deepMerge({ 'x-decorator-props': { tableProps: { bordered: checked } } });
},
};
},
},
{
type: 'remove',
name: 'remove',
},
],
});
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const CreateAction = () => {
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const compile = useCompile();
const collection = useCollection();
const title = compile(collection.title);
const fieldSchema = useFieldSchema();
const { render } = useSchemaToolbarRender(fieldSchema);
return (
<>
<div>
{render()}
<Button type="primary" onClick={showDrawer}>
Add New
</Button>
</div>
<Drawer title={`${title} | Add New`} onClose={onClose} open={open}>
<p>Some contents...</p>
</Drawer>
</>
);
};
const createActionSettings = new SchemaSettings({
name: 'createActionSettings',
items: [
{
type: 'remove',
name: 'remove',
},
],
});
const RefreshAction = () => {
const { refresh } = useDataBlockRequest();
return <Button onClick={refresh}>Refresh</Button>;
};
const ActionBar = ({ children }) => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: 'var(--nb-spacing)',
}}
>
<Space>
{children}
{render()}
</Space>
</div>
);
};
const CreateActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'CreateAction',
'x-settings': 'createActionSettings',
});
};
return <SchemaInitializerItem title={'Add New'} onClick={handleClick}></SchemaInitializerItem>;
};
const RefreshActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'RefreshAction',
});
};
return <SchemaInitializerItem title={'Refresh'} onClick={handleClick}></SchemaInitializerItem>;
};
const tableActionInitializers = new SchemaInitializer({
name: 'tableActionInitializers',
title: 'Configure actions',
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'item',
name: 'addNew',
Component: CreateActionInitializer,
},
{
type: 'item',
name: 'refresh',
Component: RefreshActionInitializer,
},
],
});
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'myTableSettings',
'x-decorator': 'DataBlockProvider',
'x-toolbar': 'MyToolbar',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
tableProps: {
bordered: true,
},
},
properties: {
actions: {
type: 'void',
'x-component': 'ActionBar',
'x-initializer': 'tableActionInitializers',
},
[uid()]: {
type: 'array',
'x-component': 'MyTable',
'x-use-component-props': 'useTableProps',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const MyToolbar = (props) => {
const collection = useCollection();
const compile = useCompile();
return <SchemaToolbar title={`${compile(collection.title)}`} {...props} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable, TableColumn, MyToolbar, ActionBar, CreateAction, RefreshAction });
this.app.schemaInitializerManager.add(myInitializer);
this.app.schemaSettingsManager.add(myTableSettings);
this.app.schemaSettingsManager.add(createActionSettings);
this.app.addScopes({ useTableProps });
this.app.schemaInitializerManager.add(tableActionInitializers);
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,492 +0,0 @@
import { Button, Drawer, Space, Table, TableProps } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
SchemaInitializerSwitch,
SchemaSettings,
SchemaToolbar,
useCollection,
useCompile,
useCurrentSchema,
useDataBlock,
useDataBlockProps,
useDataBlockRequest,
useDataSourceManager,
useDesignable,
useSchemaInitializer,
useSchemaInitializerItem,
useSchemaInitializerRender,
useSchemaToolbarRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' });
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
function useTableColumns() {
const schema = useFieldSchema();
const filed = useField();
const { designable } = useDesignable();
const { render } = useSchemaInitializerRender(schema['x-initializer'], schema['x-initializer-props']);
const columns = schema.mapProperties((tableField: any, name) => {
return {
title: <RecursionField name={tableField.name} schema={tableField} onlyRenderSelf />,
dataIndex: name,
key: name,
width: 200,
render(value, record, index) {
return <RecursionField basePath={filed.address.concat(index)} onlyRenderProperties schema={tableField} />;
},
};
});
const tableColumns = useMemo(() => {
return [
...columns,
{
title: render(),
dataIndex: 'TABLE_COLUMN_INITIALIZER',
key: 'TABLE_COLUMN_INITIALIZER',
width: 200,
render: designable ? () => <div style={{ minWidth: 300 }} /> : null,
},
];
}, [columns, render, designable]);
return tableColumns;
}
function useTableProps(): TableProps<any> {
const { tableProps } = useDataBlockProps();
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useTableColumns();
return {
...tableProps,
loading,
dataSource,
columns,
};
}
const myTableSettings = new SchemaSettings({
name: 'myTableSettings',
items: [
{
name: 'bordered',
type: 'switch',
useComponentProps() {
const { props: blockSettingsProps, dn } = useDataBlock();
return {
title: 'Bordered',
checked: !!blockSettingsProps.tableProps?.bordered,
onChange: (checked) => {
// 修改 schema
dn.deepMerge({ 'x-decorator-props': { tableProps: { bordered: checked } } });
},
};
},
},
{
type: 'remove',
name: 'remove',
},
],
});
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const CreateAction = () => {
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const compile = useCompile();
const collection = useCollection();
const title = compile(collection.title);
const fieldSchema = useFieldSchema();
const { render } = useSchemaToolbarRender(fieldSchema);
return (
<>
<div>
{render()}
<Button type="primary" onClick={showDrawer}>
Add New
</Button>
</div>
<Drawer title={`${title} | Add New`} onClose={onClose} open={open}>
<p>Some contents...</p>
</Drawer>
</>
);
};
const createActionSettings = new SchemaSettings({
name: 'createActionSettings',
items: [
{
type: 'remove',
name: 'remove',
},
],
});
const RefreshAction = () => {
const { refresh } = useDataBlockRequest();
return <Button onClick={refresh}>Refresh</Button>;
};
const ActionBar = ({ children }) => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: 'var(--nb-spacing)',
}}
>
<Space>
{children}
{render()}
</Space>
</div>
);
};
const CreateActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'CreateAction',
'x-settings': 'createActionSettings',
});
};
return <SchemaInitializerItem title={'Add New'} onClick={handleClick}></SchemaInitializerItem>;
};
const RefreshActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'RefreshAction',
});
};
return <SchemaInitializerItem title={'Refresh'} onClick={handleClick}></SchemaInitializerItem>;
};
const tableActionInitializers = new SchemaInitializer({
name: 'tableActionInitializers',
title: 'Configure actions',
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'item',
name: 'addNew',
Component: CreateActionInitializer,
},
{
type: 'item',
name: 'refresh',
Component: RefreshActionInitializer,
},
],
});
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'myTableSettings',
'x-decorator': 'DataBlockProvider',
'x-toolbar': 'MyToolbar',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
tableProps: {
bordered: true,
},
},
properties: {
actions: {
type: 'void',
'x-component': 'ActionBar',
'x-initializer': 'tableActionInitializers',
},
[uid()]: {
type: 'array',
'x-component': 'MyTable',
'x-use-component-props': 'useTableProps',
'x-initializer': 'tableColumnInitializers',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const useTableColumnInitializerFields = () => {
const collection = useCollection();
return collection.fields.map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
type: 'item',
name: collectionField.name,
title: collectionField?.uiSchema?.title || collectionField.name,
Component: 'TableCollectionFieldInitializer',
schema: tableFieldSchema,
};
});
};
export const TableCollectionFieldInitializer = () => {
const itemConfig = useSchemaInitializerItem();
const { insert } = useSchemaInitializer();
const { remove } = useDesignable();
const schema = useFieldSchema();
const exists = !!schema.properties?.[itemConfig.name];
return (
<SchemaInitializerSwitch
checked={exists}
title={itemConfig.title}
onClick={() => {
if (exists) {
return remove(schema.properties?.[itemConfig.name]);
}
insert(itemConfig.schema);
}}
/>
);
};
const tableColumnInitializers = new SchemaInitializer({
name: 'tableColumnInitializers',
insertPosition: 'beforeEnd',
icon: 'SettingOutlined',
title: 'Configure columns',
items: [
{
name: 'displayFields',
type: 'itemGroup',
title: 'Display fields',
useChildren: useTableColumnInitializerFields,
},
],
});
const MyToolbar = (props) => {
const collection = useCollection();
const compile = useCompile();
return <SchemaToolbar title={`${compile(collection.title)}`} {...props} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({
MyTable,
TableColumn,
MyToolbar,
ActionBar,
CreateAction,
RefreshAction,
TableCollectionFieldInitializer,
});
this.app.schemaInitializerManager.add(myInitializer);
this.app.schemaSettingsManager.add(myTableSettings);
this.app.addScopes({ useTableProps });
this.app.schemaInitializerManager.add(tableActionInitializers);
this.app.schemaInitializerManager.add(tableColumnInitializers);
this.app.schemaSettingsManager.add(createActionSettings);
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,532 +0,0 @@
import { Button, Drawer, Space, Table, TableProps } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
CollectionRecordProvider,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
SchemaInitializerSwitch,
SchemaSettings,
SchemaToolbar,
useCollection,
useCompile,
useCurrentSchema,
useDataBlock,
useDataBlockProps,
useDataBlockRequest,
useDataSource,
useDataSourceManager,
useDesignable,
useCollectionRecord,
useSchemaInitializer,
useSchemaInitializerItem,
useSchemaInitializerRender,
useSchemaToolbarRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' });
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
const ColumnView = observer(
() => {
const record = useCollectionRecord();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
return (
<>
<Button type="link" onClick={showDrawer}>
view
</Button>
<Drawer onClose={onClose} open={open}>
<pre>{JSON.stringify(record, null, 2)}</pre>
</Drawer>
</>
);
},
{ displayName: 'ColumnView' },
);
function useTableColumns() {
const schema = useFieldSchema();
const filed = useField();
const { designable } = useDesignable();
const { render } = useSchemaInitializerRender(schema['x-initializer'], schema['x-initializer-props']);
const columns = schema.mapProperties((tableField: any, name) => {
return {
title: <RecursionField name={tableField.name} schema={tableField} onlyRenderSelf />,
dataIndex: name,
key: name,
render(value, record, index) {
return <RecursionField basePath={filed.address.concat(index)} onlyRenderProperties schema={tableField} />;
},
};
});
const tableColumns = useMemo(() => {
return [
...columns,
{
title: 'Actions',
dataIndex: 'actions',
key: 'actions',
render: (value, record) => {
return (
<CollectionRecordProvider record={record}>
<Space>
<ColumnView />
</Space>
</CollectionRecordProvider>
);
},
},
{
title: render(),
dataIndex: 'TABLE_COLUMN_INITIALIZER',
key: 'TABLE_COLUMN_INITIALIZER',
render: designable ? () => <div style={{ minWidth: 300 }} /> : null,
},
];
}, [columns, render, designable]);
return tableColumns;
}
function useTableProps(): TableProps<any> {
const { tableProps } = useDataBlockProps();
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useTableColumns();
return {
...tableProps,
loading,
dataSource,
columns,
};
}
const myTableSettings = new SchemaSettings({
name: 'myTableSettings',
items: [
{
name: 'bordered',
type: 'switch',
useComponentProps() {
const { props: blockSettingsProps, dn } = useDataBlock();
return {
title: 'Bordered',
checked: !!blockSettingsProps.tableProps?.bordered,
onChange: (checked) => {
// 修改 schema
dn.deepMerge({ 'x-decorator-props': { tableProps: { bordered: checked } } });
},
};
},
},
{
type: 'remove',
name: 'remove',
},
],
});
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const CreateAction = () => {
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const compile = useCompile();
const collection = useCollection();
const title = compile(collection.title);
const fieldSchema = useFieldSchema();
const { render } = useSchemaToolbarRender(fieldSchema);
return (
<>
<div>
{render()}
<Button type="primary" onClick={showDrawer}>
Add New
</Button>
</div>
<Drawer title={`${title} | Add New`} onClose={onClose} open={open}>
<p>Some contents...</p>
</Drawer>
</>
);
};
const createActionSettings = new SchemaSettings({
name: 'createActionSettings',
items: [
{
type: 'remove',
name: 'remove',
},
],
});
const RefreshAction = () => {
const { refresh } = useDataBlockRequest();
return <Button onClick={refresh}>Refresh</Button>;
};
const ActionBar = ({ children }) => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: 'var(--nb-spacing)',
}}
>
<Space>
{children}
{render()}
</Space>
</div>
);
};
const CreateActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'CreateAction',
'x-settings': 'createActionSettings',
});
};
return <SchemaInitializerItem title={'Add New'} onClick={handleClick}></SchemaInitializerItem>;
};
const RefreshActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'RefreshAction',
});
};
return <SchemaInitializerItem title={'Refresh'} onClick={handleClick}></SchemaInitializerItem>;
};
const tableActionInitializers = new SchemaInitializer({
name: 'tableActionInitializers',
title: 'Configure actions',
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'item',
name: 'addNew',
Component: CreateActionInitializer,
},
{
type: 'item',
name: 'refresh',
Component: RefreshActionInitializer,
},
],
});
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'myTableSettings',
'x-decorator': 'DataBlockProvider',
'x-toolbar': 'MyToolbar',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
tableProps: {
bordered: true,
},
},
properties: {
actions: {
type: 'void',
'x-component': 'ActionBar',
'x-initializer': 'tableActionInitializers',
},
[uid()]: {
type: 'array',
'x-component': 'MyTable',
'x-use-component-props': 'useTableProps',
'x-initializer': 'tableColumnInitializers',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const useTableColumnInitializerFields = () => {
const collection = useCollection();
return collection.fields.map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
type: 'item',
name: collectionField.name,
title: collectionField?.uiSchema?.title || collectionField.name,
Component: 'TableCollectionFieldInitializer',
schema: tableFieldSchema,
};
});
};
export const TableCollectionFieldInitializer = () => {
const itemConfig = useSchemaInitializerItem();
const { insert } = useSchemaInitializer();
const { remove } = useDesignable();
const schema = useFieldSchema();
const exists = !!schema.properties?.[itemConfig.name];
return (
<SchemaInitializerSwitch
checked={exists}
title={itemConfig.title}
onClick={() => {
if (exists) {
return remove(schema.properties?.[itemConfig.name]);
}
insert(itemConfig.schema);
}}
/>
);
};
const tableColumnInitializers = new SchemaInitializer({
name: 'tableColumnInitializers',
insertPosition: 'beforeEnd',
icon: 'SettingOutlined',
title: 'Configure columns',
items: [
{
name: 'displayFields',
type: 'itemGroup',
title: 'Display fields',
useChildren: useTableColumnInitializerFields,
},
],
});
const MyToolbar = (props) => {
const collection = useCollection();
const compile = useCompile();
return <SchemaToolbar title={`${compile(collection.title)}`} {...props} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({
MyTable,
TableColumn,
MyToolbar,
ActionBar,
CreateAction,
RefreshAction,
TableCollectionFieldInitializer,
});
this.app.schemaInitializerManager.add(myInitializer);
this.app.schemaSettingsManager.add(myTableSettings);
this.app.addScopes({ useTableProps });
this.app.schemaInitializerManager.add(tableActionInitializers);
this.app.schemaInitializerManager.add(tableColumnInitializers);
this.app.schemaSettingsManager.add(createActionSettings);
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,82 +0,0 @@
import { Table } from 'antd';
import React from 'react';
import { CardItem, Plugin, SchemaComponent } from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
const MyTable = () => {
const dataSource = [
{
key: '1',
name: 'Mike',
age: 32,
address: '10 Downing Street',
},
{
key: '2',
name: 'John',
age: 42,
address: '10 Downing Street',
},
];
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
];
return <Table dataSource={dataSource} columns={columns} />;
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable });
}
}
const tableSchema = {
name: 'demo',
type: 'void',
'x-component': 'CardItem',
properties: {
[uid()]: {
type: 'array',
'x-component': 'MyTable',
},
},
};
const Root = () => {
return <SchemaComponent schema={tableSchema} />;
};
const app = new Application({
plugins: [MyPlugin],
components: {
CardItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
});
app.router.add('root', {
path: '/',
Component: Root,
});
export default app.getRootComponent();

View File

@ -1,147 +0,0 @@
import { Table } from 'antd';
import React, { useCallback } from 'react';
import {
CardItem,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
useSchemaInitializer,
useSchemaInitializerRender,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, observer, useFieldSchema } from '@formily/react';
const MyTable = () => {
const dataSource = [
{
key: '1',
name: 'Mike',
age: 32,
address: '10 Downing Street',
},
{
key: '2',
name: 'John',
age: 42,
address: '10 Downing Street',
},
];
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
];
return <Table dataSource={dataSource} columns={columns} />;
};
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = useCallback(
({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
properties: {
[uid()]: {
type: 'array',
'x-component': 'MyTable',
},
},
};
insert(tableSchema);
setVisible(false);
},
[insert, setVisible],
);
return <SchemaInitializerItem title={'Table'} onClick={handleClick} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable });
this.app.schemaInitializerManager.add(myInitializer);
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
});
app.router.add('home', {
path: '/',
Component: Root,
});
export default app.getRootComponent();

View File

@ -1,180 +0,0 @@
import { Table } from 'antd';
import React, { useMemo } from 'react';
import {
CardItem,
DataBlockProvider,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
useCollection,
useDataBlockRequest,
useDataSourceManager,
useSchemaInitializer,
useSchemaInitializerRender,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, observer, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = () => {
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const collection = useCollection();
const columns = useMemo(() => {
return collection.getFields().map((collectionField) => {
return {
title: collectionField.uiSchema?.title || collectionField.name,
dataIndex: collectionField.name,
};
});
}, [collection]);
return <Table loading={loading} rowKey="id" dataSource={dataSource} columns={columns} />;
};
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-decorator': 'DataBlockProvider',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
},
properties: {
[uid()]: {
type: 'array',
'x-component': 'MyTable',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable });
this.app.schemaInitializerManager.add(myInitializer);
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,236 +0,0 @@
import { Table } from 'antd';
import React, { useEffect, useMemo } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
useCollection,
useDataBlockRequest,
useDataSourceManager,
useSchemaInitializer,
useSchemaInitializerRender,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
const MyTable = () => {
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const collection = useCollection();
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useMemo(() => {
return collection.getFields().map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
title: <RecursionField name={collectionField.name} schema={tableFieldSchema} onlyRenderSelf />,
dataIndex: collectionField.name,
render(value, record, index) {
return (
<RecursionField basePath={field.address.concat(index)} onlyRenderProperties schema={tableFieldSchema} />
);
},
};
});
}, [collection]);
return <Table loading={loading} rowKey={'id'} dataSource={dataSource} columns={columns} />;
};
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-decorator': 'DataBlockProvider',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
},
properties: {
[uid()]: {
type: 'array',
'x-component': 'MyTable',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable, TableColumn });
this.app.schemaInitializerManager.add(myInitializer);
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,280 +0,0 @@
import { Table, TableProps } from 'antd';
import React, { useEffect, useMemo } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
SchemaSettings,
useCollection,
useDataBlock,
useDataBlockProps,
useDataBlockRequest,
useDataSourceManager,
useSchemaInitializer,
useSchemaInitializerRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' });
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
function useTableProps(): TableProps<any> {
const { tableProps } = useDataBlockProps();
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const collection = useCollection();
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useMemo(() => {
return collection.getFields().map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
title: <RecursionField name={collectionField.name} schema={tableFieldSchema} onlyRenderSelf />,
dataIndex: collectionField.name,
render(value, record, index) {
return (
<RecursionField basePath={field.address.concat(index)} onlyRenderProperties schema={tableFieldSchema} />
);
},
};
});
}, [collection]);
return {
...tableProps,
loading,
dataSource,
columns,
rowKey: 'id',
};
}
const myTableSettings = new SchemaSettings({
name: 'myTableSettings',
items: [
{
name: 'bordered',
type: 'switch',
useComponentProps() {
const { props: blockSettingsProps, dn } = useDataBlock();
return {
title: 'Bordered',
checked: !!blockSettingsProps.tableProps?.bordered,
onChange: (checked) => {
// 修改 schema
dn.deepMerge({ 'x-decorator-props': { tableProps: { bordered: checked } } });
},
};
},
},
{
type: 'remove',
name: 'remove',
},
],
});
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'myTableSettings',
'x-decorator': 'DataBlockProvider',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
tableProps: {
bordered: true,
},
},
properties: {
[uid()]: {
type: 'array',
'x-component': 'MyTable',
'x-use-component-props': 'useTableProps',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable, TableColumn });
this.app.schemaInitializerManager.add(myInitializer);
this.app.schemaSettingsManager.add(myTableSettings);
this.app.addScopes({ useTableProps });
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,291 +0,0 @@
import { Table, TableProps } from 'antd';
import React, { useEffect, useMemo } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
SchemaSettings,
SchemaToolbar,
useCollection,
useCompile,
useDataBlock,
useDataBlockProps,
useDataBlockRequest,
useDataSource,
useDataSourceManager,
useSchemaInitializer,
useSchemaInitializerRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' });
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
function useTableProps(): TableProps<any> {
const { tableProps } = useDataBlockProps();
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const collection = useCollection();
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useMemo(() => {
return collection.getFields().map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
title: <RecursionField name={collectionField.name} schema={tableFieldSchema} onlyRenderSelf />,
dataIndex: collectionField.name,
render(value, record, index) {
return (
<RecursionField basePath={field.address.concat(index)} onlyRenderProperties schema={tableFieldSchema} />
);
},
};
});
}, [collection]);
return {
...tableProps,
loading,
dataSource,
columns,
};
}
const myTableSettings = new SchemaSettings({
name: 'myTableSettings',
items: [
{
name: 'bordered',
type: 'switch',
useComponentProps() {
const { props: blockSettingsProps, dn } = useDataBlock();
return {
title: 'Bordered',
checked: !!blockSettingsProps.tableProps?.bordered,
onChange: (checked) => {
// 修改 schema
dn.deepMerge({ 'x-decorator-props': { tableProps: { bordered: checked } } });
},
};
},
},
{
type: 'remove',
name: 'remove',
},
],
});
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'myTableSettings',
'x-decorator': 'DataBlockProvider',
'x-toolbar': 'MyToolbar',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
tableProps: {
bordered: true,
},
},
properties: {
[uid()]: {
type: 'array',
'x-component': 'MyTable',
'x-use-component-props': 'useTableProps',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const MyToolbar = (props) => {
const collection = useCollection();
const compile = useCompile();
return <SchemaToolbar title={`${compile(collection.title)}`} {...props} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable, TableColumn, MyToolbar });
this.app.schemaInitializerManager.add(myInitializer);
this.app.schemaSettingsManager.add(myTableSettings);
this.app.addScopes({ useTableProps });
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,351 +0,0 @@
import { Button, Drawer, Space, Table, TableProps } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
SchemaSettings,
SchemaToolbar,
useCollection,
useCompile,
useDataBlock,
useDataBlockProps,
useDataBlockRequest,
useDataSource,
useDataSourceManager,
useSchemaInitializer,
useSchemaInitializerRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' });
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
function useTableProps(): TableProps<any> {
const { tableProps } = useDataBlockProps();
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const collection = useCollection();
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useMemo(() => {
return collection.getFields().map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
title: <RecursionField name={collectionField.name} schema={tableFieldSchema} onlyRenderSelf />,
dataIndex: collectionField.name,
render(value, record, index) {
return (
<RecursionField basePath={field.address.concat(index)} onlyRenderProperties schema={tableFieldSchema} />
);
},
};
});
}, [collection]);
return {
...tableProps,
loading,
dataSource,
columns,
};
}
const myTableSettings = new SchemaSettings({
name: 'myTableSettings',
items: [
{
name: 'bordered',
type: 'switch',
useComponentProps() {
const { props: blockSettingsProps, dn } = useDataBlock();
return {
title: 'Bordered',
checked: !!blockSettingsProps.tableProps?.bordered,
onChange: (checked) => {
// 修改 schema
dn.deepMerge({ 'x-decorator-props': { tableProps: { bordered: checked } } });
},
};
},
},
{
type: 'remove',
name: 'remove',
},
],
});
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const CreateAction = () => {
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const compile = useCompile();
const collection = useCollection();
const title = compile(collection.title);
return (
<>
<Button type="primary" onClick={showDrawer}>
Add New
</Button>
<Drawer title={`${title} | Add New`} onClose={onClose} open={open}>
<p>Some contents...</p>
</Drawer>
</>
);
};
const RefreshAction = () => {
const { refresh } = useDataBlockRequest();
return <Button onClick={refresh}>Refresh</Button>;
};
const ActionBar = () => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: 'var(--nb-spacing)',
}}
>
<Space>
<CreateAction></CreateAction>
<RefreshAction></RefreshAction>
{render()}
</Space>
</div>
);
};
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'myTableSettings',
'x-decorator': 'DataBlockProvider',
'x-toolbar': 'MyToolbar',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
tableProps: {
bordered: true,
},
},
properties: {
actions: {
type: 'void',
'x-component': 'ActionBar',
'x-initializer': 'tableActionInitializers',
},
[uid()]: {
type: 'array',
'x-component': 'MyTable',
'x-use-component-props': 'useTableProps',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const MyToolbar = (props) => {
const collection = useCollection();
const compile = useCompile();
return <SchemaToolbar title={`${compile(collection.title)}`} {...props} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable, TableColumn, MyToolbar, ActionBar });
this.app.schemaInitializerManager.add(myInitializer);
this.app.schemaSettingsManager.add(myTableSettings);
this.app.addScopes({ useTableProps });
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,394 +0,0 @@
import { Button, Drawer, Space, Table, TableProps } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import {
CardItem,
CollectionField,
ColorFieldInterface,
ColorPicker,
DataBlockProvider,
EmailFieldInterface,
FormItem,
IdFieldInterface,
Input,
InputFieldInterface,
InputNumber,
NumberFieldInterface,
Plugin,
SchemaComponent,
SchemaInitializer,
SchemaInitializerItem,
SchemaSettings,
SchemaToolbar,
useCollection,
useCompile,
useDataBlock,
useDataBlockProps,
useDataBlockRequest,
useDataSource,
useDataSourceManager,
useSchemaInitializer,
useSchemaInitializerRender,
withDynamicSchemaProps,
} from '@nocobase/client';
import { Application } from '@nocobase/client';
import { uid } from '@formily/shared';
import { ISchema, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import { mainCollections, TestDBCollections } from './collections';
import { mock } from './mockData';
const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' });
const TableColumn = observer(() => {
const field = useField<any>();
return <div>{field.title}</div>;
});
function useTableProps(): TableProps<any> {
const { tableProps } = useDataBlockProps();
const { data, loading } = useDataBlockRequest<any[]>();
const dataSource = useMemo(() => data?.data || [], [data]);
const collection = useCollection();
const field = useField<any>();
useEffect(() => {
field.value = dataSource;
}, [dataSource]);
const columns = useMemo(() => {
return collection.getFields().map((collectionField) => {
const tableFieldSchema = {
name: collectionField.name,
type: 'void',
title: collectionField.uiSchema?.title || collectionField.name,
'x-component': 'TableColumn',
properties: {
[collectionField.name]: {
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
},
},
};
return {
title: <RecursionField name={collectionField.name} schema={tableFieldSchema} onlyRenderSelf />,
dataIndex: collectionField.name,
render(value, record, index) {
return (
<RecursionField basePath={field.address.concat(index)} onlyRenderProperties schema={tableFieldSchema} />
);
},
};
});
}, [collection]);
return {
...tableProps,
loading,
dataSource,
columns,
};
}
const myTableSettings = new SchemaSettings({
name: 'myTableSettings',
items: [
{
name: 'bordered',
type: 'switch',
useComponentProps() {
const { props: blockSettingsProps, dn } = useDataBlock();
return {
title: 'Bordered',
checked: !!blockSettingsProps.tableProps?.bordered,
onChange: (checked) => {
// 修改 schema
dn.deepMerge({ 'x-decorator-props': { tableProps: { bordered: checked } } });
},
};
},
},
{
type: 'remove',
name: 'remove',
},
],
});
const AddBlockButton = observer(
() => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return render();
},
{ displayName: 'AddBlockButton' },
);
const Page = observer(
(props) => {
return (
<div>
{props.children}
<AddBlockButton />
</div>
);
},
{ displayName: 'Page' },
);
function useCollectionMenuItems() {
const dataSourceManager = useDataSourceManager();
const allCollections = dataSourceManager.getAllCollections();
const menus = useMemo(
() =>
allCollections.map((item) => {
const { key, displayName, collections } = item;
return {
name: key,
label: displayName,
type: 'subMenu',
children: collections.map((collection) => {
return {
name: collection.name,
label: collection.title,
collection: collection.name,
dataSource: key,
};
}),
};
}),
[allCollections],
);
return menus;
}
const CreateAction = () => {
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const compile = useCompile();
const collection = useCollection();
const title = compile(collection.title);
return (
<>
<Button type="primary" onClick={showDrawer}>
Add New
</Button>
<Drawer title={`${title} | Add New`} onClose={onClose} open={open}>
<p>Some contents...</p>
</Drawer>
</>
);
};
const RefreshAction = () => {
const { refresh } = useDataBlockRequest();
return <Button onClick={refresh}>Refresh</Button>;
};
const ActionBar = ({ children }) => {
const fieldSchema = useFieldSchema();
const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']);
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: 'var(--nb-spacing)',
}}
>
<Space>
{children}
{render()}
</Space>
</div>
);
};
const CreateActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'CreateAction',
});
};
return <SchemaInitializerItem title={'Add New'} onClick={handleClick}></SchemaInitializerItem>;
};
const RefreshActionInitializer = () => {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'RefreshAction',
});
};
return <SchemaInitializerItem title={'Refresh'} onClick={handleClick}></SchemaInitializerItem>;
};
const tableActionInitializers = new SchemaInitializer({
name: 'tableActionInitializers',
title: 'Configure actions',
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'item',
name: 'addNew',
Component: CreateActionInitializer,
},
{
type: 'item',
name: 'refresh',
Component: RefreshActionInitializer,
},
],
});
const TableDataBlockInitializer = () => {
const { insert, setVisible } = useSchemaInitializer();
const handleClick = ({ item }) => {
const tableSchema = {
type: 'void',
'x-component': 'CardItem',
'x-settings': 'myTableSettings',
'x-decorator': 'DataBlockProvider',
'x-toolbar': 'MyToolbar',
'x-decorator-props': {
collection: item.collection,
dataSource: item.dataSource,
action: 'list',
tableProps: {
bordered: true,
},
},
properties: {
actions: {
type: 'void',
'x-component': 'ActionBar',
'x-initializer': 'tableActionInitializers',
},
[uid()]: {
type: 'array',
'x-component': 'MyTable',
'x-use-component-props': 'useTableProps',
},
},
};
insert(tableSchema);
setVisible(false);
};
const menuItems = useCollectionMenuItems();
return <SchemaInitializerItem title={'Table'} items={menuItems} onClick={handleClick} />;
};
const MyToolbar = (props) => {
const collection = useCollection();
const compile = useCompile();
return <SchemaToolbar title={`${compile(collection.title)}`} {...props} />;
};
const myInitializer = new SchemaInitializer({
name: 'myInitializer',
title: 'Add Block',
insertPosition: 'beforeEnd',
items: [
{
name: 'table',
Component: TableDataBlockInitializer,
},
],
});
const rootSchema: ISchema = {
type: 'void',
name: 'root',
'x-component': 'Page',
'x-initializer': 'myInitializer',
};
class MyPlugin extends Plugin {
async load() {
this.app.addComponents({ MyTable, TableColumn, MyToolbar, ActionBar, CreateAction, RefreshAction });
this.app.schemaInitializerManager.add(myInitializer);
this.app.schemaSettingsManager.add(myTableSettings);
this.app.addScopes({ useTableProps });
this.app.schemaInitializerManager.add(tableActionInitializers);
}
}
const Root = () => {
return <SchemaComponent schema={rootSchema}></SchemaComponent>;
};
const app = new Application({
plugins: [MyPlugin],
components: {
Page,
AddBlockButton,
CardItem,
DataBlockProvider,
InputNumber,
Input,
CollectionField,
ColorPicker,
FormItem,
},
router: {
type: 'memory',
initialEntries: ['/'],
},
designable: true,
dataSourceManager: {
collections: mainCollections,
dataSources: [
{
key: 'test-db',
displayName: 'TestDB',
collections: TestDBCollections,
},
],
fieldInterfaces: [
IdFieldInterface,
InputFieldInterface,
EmailFieldInterface,
ColorFieldInterface,
NumberFieldInterface,
],
},
apiClient: {
baseURL: 'http://localhost:8000',
},
});
app.router.add('home', {
path: '/',
Component: Root,
});
mock(app);
export default app.getRootComponent();

View File

@ -1,79 +0,0 @@
import type { Application } from '@nocobase/client';
import MockAdapter from 'axios-mock-adapter';
const mockData = {
'users:list': {
data: [
{
id: '1',
nickname: 'Jack Ma',
email: 'test@gmail.com',
favoriteColor: '#1677FF',
},
{
id: '2',
email: 'jim@gmail.com',
nickname: 'Jim Green',
favoriteColor: '#36C',
},
{
id: '3',
nickname: 'Tom Cat',
email: 'tom@gmail.com',
favoriteColor: '#F0F',
},
],
},
'users:destroy': {
result: 'ok',
},
'roles:list': {
data: [
{
name: 'root',
title: 'Root',
description: 'Root',
},
{
name: 'admin',
title: 'Admin',
description: 'Admin description',
},
],
},
'test1:list': {
data: [
{
id: '1',
field1: 'aaa',
field2: 1,
},
{
id: '2',
field1: 'bbb',
field2: 2,
},
{
id: '3',
field1: 'ccc',
field2: 3,
},
],
},
};
export function mock(app: Application) {
const mock = new MockAdapter(app.apiClient.axios);
Object.entries(mockData).forEach(([url, data]) => {
mock.onGet(url).reply(async (config) => {
return [200, data];
});
mock.onPost(url).reply(async (config) => {
return [200, data];
});
mock.onDelete(url).reply(async (config) => {
return [200, data];
});
});
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
import { css } from '@emotion/css';
import moment from 'moment';
import dayjs from 'dayjs';
import { connect, mapProps } from '@formily/react';
import { useBoolean } from 'ahooks';
@ -7,7 +7,7 @@ import { Input, Radio, Space } from 'antd';
import React, { useState } from 'react';
import { useToken } from '../../';
const date = moment();
const date = dayjs();
const spaceCSS = css`
width: 100%;
@ -16,7 +16,7 @@ const spaceCSS = css`
}
`;
export const DateFormatCom = (props?) => {
const date = moment();
const date = dayjs();
return (
<div style={{ display: 'inline-flex' }}>
<span>{props.format}</span>
@ -57,7 +57,6 @@ const InternalExpiresRadio = (props) => {
onChange(v.target.value);
}
};
return (
<Space className={spaceCSS}>
<Radio.Group value={isCustom ? 'custom' : props.value} onChange={onSelectChange}>