diff --git a/packages/actions/src/actions/common.ts b/packages/actions/src/actions/common.ts
index d5afaf2d1..de2e4233c 100644
--- a/packages/actions/src/actions/common.ts
+++ b/packages/actions/src/actions/common.ts
@@ -534,7 +534,7 @@ export async function sort(ctx: Context, next: Next) {
const Model = ctx.db.getModel(resourceName);
const table = ctx.db.getTable(resourceName);
- const { sticky, field, target } = values;
+ const { sticky, field, target, insertAfter } = values;
if (!values.field || typeof target === 'undefined') {
return next();
}
@@ -592,11 +592,11 @@ export async function sort(ctx: Context, next: Next) {
if (sameScope) {
const direction = source[sortAttr] < targetObject[sortAttr] ? {
sourceOp: Op.gt,
- targetOp: Op.lte,
+ targetOp: insertAfter ? Op.lt : Op.lte,
increment: -1
} : {
sourceOp: Op.lt,
- targetOp: Op.gte,
+ targetOp: insertAfter ? Op.gt : Op.gte,
increment: 1
};
@@ -617,6 +617,8 @@ export async function sort(ctx: Context, next: Next) {
});
}
+ console.log({ insertAfter, updateWhere })
+
await Model.increment(sortAttr, {
by: increment,
where: updateWhere,
@@ -624,7 +626,7 @@ export async function sort(ctx: Context, next: Next) {
});
Object.assign(updates, {
- [sortAttr]: targetObject[sortAttr]
+ [sortAttr]: insertAfter ? targetObject[sortAttr] + 1 : targetObject[sortAttr]
});
} else {
Object.assign(updates, {
diff --git a/packages/client/src/components/admin-layout/DataTableConfig/index.tsx b/packages/client/src/components/admin-layout/DataTableConfig/index.tsx
new file mode 100644
index 000000000..6a63344a0
--- /dev/null
+++ b/packages/client/src/components/admin-layout/DataTableConfig/index.tsx
@@ -0,0 +1,68 @@
+import { DatabaseOutlined } from '@ant-design/icons';
+import { SchemaRenderer } from '../../../';
+import Modal from 'antd/lib/modal/Modal';
+import React from 'react';
+import { useState } from 'react';
+import schema from './schema';
+import { Button, Dropdown, Menu } from 'antd';
+import { useMemo } from 'react';
+import { createForm } from '@formily/core';
+
+export default () => {
+ const form = useMemo(
+ () =>
+ createForm({
+ initialValues: {
+ title: '数据表名称',
+ },
+ }),
+ [],
+ );
+ const [visible, setVisible] = useState(false);
+ return (
+ <>
+
+
+ {
+ form.setValues({
+ title: `数据表${info.key}`,
+ });
+ }}
+ >
+ 数据表1
+ 数据表2
+
+ 新建数据表
+
+ }
+ >
+ 数据表3
+
+ >
+ }
+ visible={visible}
+ onOk={async () => {
+ await form.submit();
+ setVisible(false);
+ }}
+ onCancel={() => {
+ setVisible(false);
+ }}
+ >
+
+
+ >
+ );
+};
diff --git a/packages/client/src/components/admin-layout/DataTableConfig/schema.ts b/packages/client/src/components/admin-layout/DataTableConfig/schema.ts
new file mode 100644
index 000000000..66125906f
--- /dev/null
+++ b/packages/client/src/components/admin-layout/DataTableConfig/schema.ts
@@ -0,0 +1,49 @@
+import { ISchema } from "@formily/react";
+
+export default {
+ type: 'object',
+ properties: {
+ form: {
+ type: 'void',
+ "x-component": 'FormLayout',
+ "x-component-props": {
+ layout: 'vertical',
+ },
+ properties: {
+ title: {
+ type: 'string',
+ title: '数据表名称',
+ required: true,
+ 'x-decorator': 'FormItem',
+ 'x-component': 'Input',
+ },
+ fields: {
+ type: 'array',
+ title: '字段',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'DatabaseField',
+ default: [
+ {
+ id: 1,
+ interface: 'string',
+ dataType: 'string',
+ name: 'title',
+ ui: {
+ title: '标题',
+ },
+ },
+ {
+ id: 2,
+ dataType: 'text',
+ interface: 'textarea',
+ name: 'content',
+ ui: {
+ title: '内容',
+ },
+ },
+ ],
+ }
+ }
+ },
+ },
+} as ISchema;
\ No newline at end of file
diff --git a/packages/client/src/components/admin-layout/index.tsx b/packages/client/src/components/admin-layout/index.tsx
index 79b185b3b..1258cc3aa 100644
--- a/packages/client/src/components/admin-layout/index.tsx
+++ b/packages/client/src/components/admin-layout/index.tsx
@@ -23,7 +23,7 @@ import './style.less';
import { uid } from '@formily/shared';
import { ISchema } from '@formily/react';
-import datatable from './datatable';
+import DataTableConfig from './DataTableConfig';
function LayoutWithMenu({ schema }) {
const match = useRouteMatch();
@@ -31,8 +31,15 @@ function LayoutWithMenu({ schema }) {
const sideMenuRef = useRef();
const [activeKey, setActiveKey] = useState(match.params.name);
const onSelect = (info) => {
- console.log('LayoutWithMenu', schema);
- setActiveKey(info.key);
+ console.log('LayoutWithMenu', info);
+ if (!info.schema) {
+ setActiveKey(null);
+ } else if (info.schema['x-component'] === 'Menu.SubMenu') {
+ // 实际应该取第一个子元素
+ setActiveKey(null);
+ } else {
+ setActiveKey(info.schema.key);
+ }
};
console.log({ match });
return (
@@ -46,7 +53,7 @@ function LayoutWithMenu({ schema }) {
selectedKeys: [activeKey].filter(Boolean),
}}
/>
-
+
;
}
- const schema: ISchema = {
- type: 'void',
- name: uid(),
- 'x-component': 'Grid',
- properties: {
- [`row_${uid()}`]: {
- type: 'void',
- 'x-component': 'Grid.Row',
- properties: {
- [`col_${uid()}`]: {
- type: 'void',
- 'x-component': 'Grid.Col',
- properties: {
- [uid()]: {
- type: 'void',
- 'x-component': 'AddNew.BlockItem',
- },
- },
- },
- },
- },
- },
- };
-
- return ;
+ return ;
}
export function AdminLayout({ route }: any) {
diff --git a/packages/client/src/components/schema-renderer/index.tsx b/packages/client/src/components/schema-renderer/index.tsx
index d91b4814d..db8a78a30 100644
--- a/packages/client/src/components/schema-renderer/index.tsx
+++ b/packages/client/src/components/schema-renderer/index.tsx
@@ -154,14 +154,24 @@ export function addPropertyAfter(target: Schema, data: ISchema) {
});
}
+function setKeys(schema: ISchema, parentKey = null) {
+ if (!schema['key']) {
+ schema['key'] = uid();
+ }
+ if (parentKey && !schema['parentKey']) {
+ schema['parentKey'] = parentKey;
+ }
+ Object.keys(schema.properties || {}).forEach((name) => {
+ setKeys(schema.properties[name], schema['key']);
+ });
+}
+
export function useDesignable(path?: any) {
const { schema, refresh } = useContext(DesignableContext);
const schemaPath = path || useSchemaPath();
- console.log({ schemaPath });
const fieldSchema = useFieldSchema();
const currentSchema =
findPropertyByPath(schema, schemaPath) || ({} as Schema);
- console.log({ currentSchema });
// console.log('useDesignable', { schema, schemaPath, currentSchema });
const options = useContext(SchemaOptionsContext);
const DesignableBar =
@@ -184,9 +194,11 @@ export function useDesignable(path?: any) {
}
if (target['key']) {
property['parentKey'] = target['key'];
- if (!property['key']) {
- property['key'] = uid();
- }
+ setKeys(property);
+ property['__prepend__'] = true;
+ // if (!property['key']) {
+ // property['key'] = uid();
+ // }
}
const properties = {};
properties[property.name] = property;
@@ -214,9 +226,10 @@ export function useDesignable(path?: any) {
}
if (target['key']) {
property['parentKey'] = target['key'];
- if (!property['key']) {
- property['key'] = uid();
- }
+ // if (!property['key']) {
+ // property['key'] = uid();
+ // }
+ setKeys(property);
}
target.addProperty(property.name, property);
// BUG: 空 properties 时,addProperty 无反应。
@@ -241,9 +254,8 @@ export function useDesignable(path?: any) {
console.log('target.parentKey', target);
if (target['parentKey']) {
property['parentKey'] = target['parentKey'];
- if (!property['key']) {
- property['key'] = uid();
- }
+ setKeys(property);
+ property['__insertAfter__'] = target['key'];
}
addPropertyAfter(target, property);
refresh();
@@ -263,9 +275,8 @@ export function useDesignable(path?: any) {
}
if (target['parentKey']) {
property['parentKey'] = target['parentKey'];
- if (!property['key']) {
- property['key'] = uid();
- }
+ setKeys(property);
+ property['__insertBefore__'] = target['key'];
}
addPropertyBefore(target, property);
refresh();
@@ -280,17 +291,20 @@ export function useDesignable(path?: any) {
console.error('target schema does not exist.');
return;
}
+ const removed = [];
const remove = (s: Schema) => {
if (!s.parent) {
return;
}
s.parent.removeProperty(s.name);
+ removed.push(s);
if (Object.keys(s.parent.properties || {}).length === 0) {
remove(s.parent);
}
};
remove(target);
refresh();
+ return removed;
},
remove(targetPath?: any) {
let target = currentSchema;
diff --git a/packages/client/src/demos/demo1.tsx b/packages/client/src/demos/demo1.tsx
index 71abaa3b4..ce9d6b7ed 100644
--- a/packages/client/src/demos/demo1.tsx
+++ b/packages/client/src/demos/demo1.tsx
@@ -38,7 +38,7 @@ const App = () => {
return (
-
+
diff --git a/packages/client/src/schemas/add-new/index.tsx b/packages/client/src/schemas/add-new/index.tsx
index f2b242d8c..d47e69bd0 100644
--- a/packages/client/src/schemas/add-new/index.tsx
+++ b/packages/client/src/schemas/add-new/index.tsx
@@ -46,8 +46,9 @@ import {
DownOutlined,
DatabaseOutlined,
} from '@ant-design/icons';
-import { useDesignable, useSchemaPath } from '../';
+import { createSchema, useDesignable, useSchemaPath } from '../';
import { uid } from '@formily/shared';
+import { request } from '../../demos/api';
const generateGridBlock = (schema: ISchema) => {
const name = schema.name || uid();
@@ -88,7 +89,6 @@ AddNew.BlockItem = observer((props: any) => {
const { ghost, defaultAction } = props;
const { schema, insertBefore, insertAfter } = useDesignable();
const path = useSchemaPath();
-
return (
{
新增数据表
{
+ onClick={async () => {
let data: ISchema = {
type: 'void',
title: uid(),
@@ -116,6 +116,9 @@ AddNew.BlockItem = observer((props: any) => {
'x-decorator': 'BlockItem',
'x-component': 'Markdown',
};
+ if (schema['key']) {
+ data['key'] = uid();
+ }
console.log('isGridBlock(schema)', isGridBlock(schema));
if (isGridBlock(schema)) {
path.pop();
@@ -123,11 +126,13 @@ AddNew.BlockItem = observer((props: any) => {
data = generateGridBlock(data);
}
if (data) {
+ let s;
if (defaultAction === 'insertAfter') {
- insertAfter(data, [...path]);
+ s = insertAfter(data, [...path]);
} else {
- insertBefore(data, [...path]);
+ s = insertBefore(data, [...path]);
}
+ await createSchema(s);
}
}}
>
diff --git a/packages/client/src/schemas/grid/index.tsx b/packages/client/src/schemas/grid/index.tsx
index 13cc56895..1deab02e3 100644
--- a/packages/client/src/schemas/grid/index.tsx
+++ b/packages/client/src/schemas/grid/index.tsx
@@ -21,7 +21,7 @@ import {
import './style.less';
import cls from 'classnames';
-import { useDesignable, useSchemaPath } from '../';
+import { createSchema, useDesignable, useSchemaPath } from '../';
import {
useDrag,
useDrop,
@@ -93,10 +93,10 @@ export const Grid: any = observer((props) => {
{
+ onDrop={async (e) => {
const blockSchema = e.dragItem.schema;
const path = [...e.dragItem.path];
- prepend({
+ const data = prepend({
type: 'void',
'x-component': 'Grid.Row',
properties: {
@@ -109,6 +109,8 @@ export const Grid: any = observer((props) => {
},
},
});
+ await createSchema(data);
+ console.log('prepend', data);
deepRemove(path);
}}
/>
@@ -121,10 +123,10 @@ export const Grid: any = observer((props) => {
{
+ onDrop={async (e) => {
const blockSchema = e.dragItem.schema;
const path = [...e.dragItem.path];
- insertAfter(
+ const data = insertAfter(
{
type: 'void',
'x-component': 'Grid.Row',
@@ -140,6 +142,8 @@ export const Grid: any = observer((props) => {
},
[...gridPath, key],
);
+ await createSchema(data);
+ console.log('insertAfter', data);
deepRemove(path);
}}
/>
@@ -170,15 +174,16 @@ Grid.Row = observer((props) => {
{
+ onDrop={async (e) => {
const blockSchema = e.dragItem.schema;
- prepend({
+ const data = prepend({
type: 'void',
'x-component': 'Grid.Col',
properties: {
[blockSchema.name]: blockSchema,
},
});
+ await createSchema(data);
const path = [...e.dragItem.path];
deepRemove(path);
}}
@@ -190,9 +195,9 @@ Grid.Row = observer((props) => {
{
+ onDrop={async (e) => {
const blockSchema = e.dragItem.schema;
- insertAfter(
+ const data = insertAfter(
{
type: 'void',
'x-component': 'Grid.Col',
@@ -202,6 +207,8 @@ Grid.Row = observer((props) => {
},
[...rowPath, key],
);
+ console.log('ColDivider', data)
+ await createSchema(data);
const path = [...e.dragItem.path];
deepRemove(path);
}}
@@ -242,45 +249,3 @@ Grid.Col = observer((props) => {
);
});
-
-// Grid.Block = observer((props) => {
-// const schema = useFieldSchema();
-// const uid = useDragDropUID();
-// const path = useSchemaPath();
-// const { isDragging, dragRef, previewRef } = useDrag({
-// type: uid,
-// onDragStart() {
-// console.log('onDragStart');
-// },
-// onDragEnd(event) {
-// console.log('onDragEnd', event.data);
-// },
-// onDrag(event) {
-// // console.log('onDrag');
-// },
-// item: {
-// path,
-// schema: schema.toJSON(),
-// },
-// });
-// const { isOver, onTopHalf, dropRef } = useDrop({
-// uid: schema.name,
-// accept: uid,
-// data: {},
-// canDrop: !isDragging,
-// });
-// return (
-//
-//
-// {props.children}
-//
-//
-// );
-// });
diff --git a/packages/client/src/schemas/index.tsx b/packages/client/src/schemas/index.tsx
index 0a371888b..e95be4799 100644
--- a/packages/client/src/schemas/index.tsx
+++ b/packages/client/src/schemas/index.tsx
@@ -1,3 +1,4 @@
+import { ISchema } from '@formily/react';
import { createContext } from 'react';
export * from '../components/schema-renderer';
@@ -16,3 +17,28 @@ export const request = extend({
prefix: 'http://localhost:23003/api/',
timeout: 1000,
});
+
+
+export async function createSchema(schema: ISchema) {
+ if (!schema['key']) {
+ return;
+ }
+ return await request('ui_schemas:create', {
+ method: 'post',
+ data: schema.toJSON(),
+ });
+};
+
+export async function removeSchema(schema: ISchema) {
+ if (!schema['key']) {
+ return;
+ }
+ await request('ui_schemas:destroy', {
+ method: 'post',
+ params: {
+ filter: {
+ key: schema['key'],
+ }
+ },
+ });
+}
diff --git a/packages/client/src/schemas/markdown/index.tsx b/packages/client/src/schemas/markdown/index.tsx
index 33be81d82..797985fdb 100644
--- a/packages/client/src/schemas/markdown/index.tsx
+++ b/packages/client/src/schemas/markdown/index.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { connect, mapProps, mapReadPretty } from '@formily/react';
+import { connect, mapProps, mapReadPretty, useFieldSchema } from '@formily/react';
import { Input as AntdInput } from 'antd';
import { InputProps, TextAreaProps } from 'antd/lib/input';
import { Display } from '../display';
@@ -7,7 +7,10 @@ import { LoadingOutlined } from '@ant-design/icons';
import micromark from 'micromark';
export const Markdown = connect(
- AntdInput.TextArea,
+ (props) => {
+ const schema = useFieldSchema();
+ return
+ },
mapProps((props: any, field) => {
return {
...props,
diff --git a/packages/client/src/schemas/menu/defaultSchemas.ts b/packages/client/src/schemas/menu/defaultSchemas.ts
new file mode 100644
index 000000000..dc9fa6e30
--- /dev/null
+++ b/packages/client/src/schemas/menu/defaultSchemas.ts
@@ -0,0 +1,71 @@
+import { ISchema } from '@formily/react';
+import { uid } from '@formily/shared';
+
+export const defaultSchemas = {
+ MixMenu: {
+ type: 'void',
+ 'x-component': 'Menu',
+ 'x-designable-bar': 'Menu.DesignableBar',
+ 'x-component-props': {
+ sideMenuRef: '{{ sideMenuRef }}',
+ mode: 'mix',
+ theme: 'dark',
+ // onSelect: '{{ onSelect }}',
+ },
+ },
+ 'Menu.Item': {
+ type: 'void',
+ 'x-designable-bar': 'Menu.DesignableBar',
+ 'x-component': 'Menu.Item',
+ },
+ 'Menu.Link': {
+ type: 'void',
+ 'x-designable-bar': 'Menu.DesignableBar',
+ 'x-component': 'Menu.Link',
+ properties: {
+ [uid()]: {
+ type: 'void',
+ name: uid(),
+ 'x-component': 'Grid',
+ properties: {
+ [`row_${uid()}`]: {
+ type: 'void',
+ 'x-component': 'Grid.Row',
+ 'x-component-props': {
+ locked: true,
+ },
+ properties: {
+ [`col_${uid()}`]: {
+ type: 'void',
+ 'x-component': 'Grid.Col',
+ properties: {
+ [uid()]: {
+ type: 'void',
+ 'x-component': 'AddNew.BlockItem',
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+ }
+ },
+ 'Menu.URL': {
+ type: 'void',
+ 'x-designable-bar': 'Menu.DesignableBar',
+ 'x-component': 'Menu.URL',
+ },
+ 'Menu.SubMenu': {
+ type: 'void',
+ 'x-designable-bar': 'Menu.DesignableBar',
+ 'x-component': 'Menu.SubMenu',
+ },
+ 'Menu.Action': {
+ type: 'void',
+ 'x-designable-bar': 'Menu.DesignableBar',
+ 'x-component': 'Menu.Action',
+ },
+};
+
+export default defaultSchemas;
diff --git a/packages/client/src/schemas/menu/index.tsx b/packages/client/src/schemas/menu/index.tsx
index 15ddb5095..d26d227bd 100644
--- a/packages/client/src/schemas/menu/index.tsx
+++ b/packages/client/src/schemas/menu/index.tsx
@@ -35,21 +35,21 @@ import cls from 'classnames';
import { useDesignable } from '../../components/schema-renderer';
import { MenuOutlined, PlusOutlined } from '@ant-design/icons';
import { IconPicker } from '../../components/icon-picker';
-import { useDefaultAction, VisibleContext } from '..';
+import { createSchema, removeSchema, useDefaultAction, VisibleContext } from '..';
import { useMount } from 'ahooks';
import './style.less';
import { Link } from 'react-router-dom';
-import { useSchemaPath } from '@nocobase/client/lib';
+import { findPropertyByPath, useSchemaPath } from '@nocobase/client/lib';
import { request } from '../';
+import defaultSchemas from './defaultSchemas';
+import { get } from 'lodash';
export const MenuModeContext = createContext(null);
-function useSelectedKey() {}
-
const SideMenu = (props: any) => {
- const { visible, selectedKey, onSelect, path } = props;
+ const { selectedKey, onSelect, path } = props;
const { schema } = useDesignable();
- if (!selectedKey || !visible) {
+ if (!selectedKey) {
return null;
}
const child = schema.properties && schema.properties[selectedKey];
@@ -108,7 +108,9 @@ export const Menu: any = observer((props: any) => {
if (mode === 'mix') {
setSelectedKey(info.key);
}
- onSelect && onSelect(info);
+ const selectedSchema = schema.properties[info.key];
+ console.log({ selectedSchema })
+ onSelect && onSelect({ ...info, schema: selectedSchema });
}}
>
@@ -120,8 +122,12 @@ export const Menu: any = observer((props: any) => {
{
+ const keyPath = [selectedKey, ...info.keyPath];
+ const selectedSchema = findPropertyByPath(schema, keyPath);
+ console.log('keyPath', keyPath, selectedSchema);
+ onSelect && onSelect({ ...info, keyPath, schema: selectedSchema });
+ }}
selectedKey={selectedKey}
sideMenuRef={sideMenuRef}
/>
@@ -131,62 +137,6 @@ export const Menu: any = observer((props: any) => {
);
});
-Menu.AddNew = observer((props: any) => {
- const { appendChild } = useDesignable(props.path);
- return (
-
- {
- const data = appendChild({
- type: 'void',
- title: uid(),
- 'x-component': 'Menu.Item',
- 'x-designable-bar': 'Menu.DesignableBar',
- });
- if (data['key']) {
- await request('ui_schemas:create', {
- method: 'post',
- data: data.toJSON(),
- });
- }
- }}
- >
- 新建菜单
-
- {
- const data = appendChild({
- type: 'void',
- key: uid(),
- title: uid(),
- 'x-component': 'Menu.SubMenu',
- 'x-designable-bar': 'Menu.DesignableBar',
- });
- if (data['key']) {
- await request('ui_schemas:create', {
- method: 'post',
- data: data.toJSON(),
- });
- }
- }}
- >
- 新建菜单组
-
-
- }
- >
- {props.children}
-
- }
- />
- );
-});
-
Menu.Divider = observer(AntdMenu.Divider);
Menu.Item = observer((props: any) => {
@@ -288,6 +238,47 @@ Menu.SubMenu = observer((props: any) => {
);
});
+Menu.AddNew = observer((props: any) => {
+ const { appendChild } = useDesignable(props.path);
+ return (
+
+ {
+ const data = appendChild({
+ ...defaultSchemas['Menu.Link'],
+ title: uid(),
+ });
+ await createSchema(data);
+ }}
+ >
+ 新建菜单
+
+ {
+ const data = appendChild({
+ ...defaultSchemas['Menu.SubMenu'],
+ title: uid(),
+ });
+ await createSchema(data);
+ }}
+ >
+ 新建菜单组
+
+
+ }
+ >
+ {props.children}
+
+ }
+ />
+ );
+});
+
Menu.DesignableBar = (props) => {
const field = useField();
const [visible, setVisible] = useState(false);
@@ -328,51 +319,32 @@ Menu.DesignableBar = (props) => {
{
const s = insertAfter({
- type: 'void',
+ ...defaultSchemas['Menu.Link'],
title: uid(),
- 'x-component': 'Menu.SubMenu',
});
- console.log('s.s.s.s', s);
- if (s['key']) {
- await request('ui_schemas:create', {
- method: 'post',
- data: s.toJSON(),
- });
- }
+ await createSchema(s);
}}
>
- 新建分组
+ 新建菜单项
{
const s = insertAfter({
- type: 'void',
+ ...defaultSchemas['Menu.SubMenu'],
title: uid(),
- 'x-component': 'Menu.Item',
});
- if (s['key']) {
- await request('ui_schemas:create', {
- method: 'post',
- data: s.toJSON(),
- });
- }
+ await createSchema(s);
}}
>
- 新建菜单
+ 新建菜单分组
{
const s = appendChild({
- type: 'void',
+ ...defaultSchemas['Menu.Link'],
title: uid(),
- 'x-component': 'Menu.Item',
});
- if (s['key']) {
- await request('ui_schemas:create', {
- method: 'post',
- data: s.toJSON(),
- });
- }
+ await createSchema(s);
}}
>
在菜单组里新增
@@ -382,8 +354,9 @@ Menu.DesignableBar = (props) => {
Modal.confirm({
title: '删除菜单',
content: '确认删除此菜单项吗?',
- onOk: () => {
- remove();
+ onOk: async () => {
+ const target = remove();
+ await removeSchema(target);
},
});
}}
diff --git a/packages/plugin-ui-schema/src/actions/getTree.ts b/packages/plugin-ui-schema/src/actions/getTree.ts
deleted file mode 100644
index 7c207cd5b..000000000
--- a/packages/plugin-ui-schema/src/actions/getTree.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { Model, ModelCtor } from '@nocobase/database';
-import { actions } from '@nocobase/actions';
-
-export default async (ctx: actions.Context, next: actions.Next) => {
- const { resourceKey, filter } = ctx.action.params;
- const UISchema = ctx.db.getModel('ui_schemas');
- if (resourceKey) {
- const schema = await UISchema.findByPk(resourceKey);
- const property = schema.toProperty();
- const properties = await schema.getProperties();
- if (Object.keys(properties).length) {
- property.properties = properties;
- }
- ctx.body = property;
- } else {
- const schemas = await UISchema.findAll(UISchema.parseApiJson({
- filter,
- }));
- let properties = {};
- for (const schema of schemas) {
- const property = schema.toProperty();
- const properties = await schema.getProperties();
- if (Object.keys(properties).length) {
- property.properties = properties;
- }
- properties[property.name] = property;
- }
- ctx.body = {
- type: 'object',
- properties,
- }
- }
-
- await next();
-}
diff --git a/packages/plugin-ui-schema/src/actions/index.ts b/packages/plugin-ui-schema/src/actions/index.ts
new file mode 100644
index 000000000..3f0e0985a
--- /dev/null
+++ b/packages/plugin-ui-schema/src/actions/index.ts
@@ -0,0 +1,91 @@
+import { Model, ModelCtor } from '@nocobase/database';
+import { actions, middlewares } from '@nocobase/actions';
+import { sort } from '@nocobase/actions/src/actions/common';
+import { cloneDeep, omit } from 'lodash';
+
+export const create = async (ctx: actions.Context, next: actions.Next) => {
+ const values = cloneDeep(ctx.action.params.values);
+ ctx.action.mergeParams(
+ {
+ values: omit(values, [
+ '__insertAfter__',
+ '__insertBefore__',
+ '__prepend__',
+ '_isJSONSchemaObject',
+ ]),
+ },
+ {
+ payload: 'replace',
+ },
+ );
+ await actions.common.create(ctx, async () => {});
+ const targetKey = values['__insertAfter__'] || values['__insertBefore__'];
+ if (targetKey) {
+ console.log({
+ associatedKey: values.parentKey,
+ resourceKey: ctx.body.key,
+ values: {
+ field: 'sort',
+ target: {
+ key: targetKey,
+ },
+ },
+ });
+ ctx.action.mergeParams(
+ {
+ associatedKey: values.parentKey,
+ resourceKey: ctx.body.key,
+ values: {
+ field: 'sort',
+ insertAfter: !!values['__insertAfter__'],
+ target: {
+ key: targetKey,
+ },
+ },
+ },
+ {
+ payload: 'replace',
+ },
+ );
+ await middlewares.associated(ctx, async () => {});
+ await sort(ctx, async () => {});
+ }
+ await next();
+};
+
+export const getTree = async (ctx: actions.Context, next: actions.Next) => {
+ const { resourceKey, filter } = ctx.action.params;
+ const UISchema = ctx.db.getModel('ui_schemas');
+ if (resourceKey) {
+ const schema = await UISchema.findByPk(resourceKey);
+ const property = schema.toProperty();
+ const properties = await schema.getProperties();
+ if (Object.keys(properties).length) {
+ property.properties = properties;
+ }
+ ctx.body = property;
+ } else {
+ const schemas = await UISchema.findAll(
+ UISchema.parseApiJson({
+ filter,
+ sort: ['sort'],
+ }),
+ );
+ console.log({ schemas });
+ let properties = {};
+ for (const schema of schemas) {
+ const property = schema.toProperty();
+ const childProperties = await schema.getProperties();
+ if (Object.keys(childProperties).length) {
+ property.properties = childProperties;
+ }
+ properties[property.name] = property;
+ }
+ ctx.body = {
+ type: 'object',
+ properties,
+ };
+ }
+
+ await next();
+};
diff --git a/packages/plugin-ui-schema/src/collections/ui_schemas.ts b/packages/plugin-ui-schema/src/collections/ui_schemas.ts
index 4cce6c1bb..6783aaef6 100644
--- a/packages/plugin-ui-schema/src/collections/ui_schemas.ts
+++ b/packages/plugin-ui-schema/src/collections/ui_schemas.ts
@@ -10,6 +10,11 @@ export default {
name: 'key',
primaryKey: true,
},
+ {
+ type: 'sort',
+ name: 'sort',
+ scope: ['parentKey'],
+ },
{
type: 'string',
name: 'name',
diff --git a/packages/plugin-ui-schema/src/models/ui-schema.ts b/packages/plugin-ui-schema/src/models/ui-schema.ts
index b1db0f3ca..15d4bc610 100644
--- a/packages/plugin-ui-schema/src/models/ui-schema.ts
+++ b/packages/plugin-ui-schema/src/models/ui-schema.ts
@@ -7,6 +7,13 @@ export class UISchema extends Model {
const attributes = this.toAttributes(value);
// @ts-ignore
const model: Model = await super.create(attributes, options);
+ if (value['__prepend__']) {
+ console.log('__prepend__', model.parentKey);
+ } else if (value['__insertAfter__']) {
+ console.log('__insertAfter__', model.parentKey);
+ } else if (value['__insertBefore__']) {
+ console.log('__insertBefore__', model.parentKey);
+ }
if (!attributes.children) {
attributes.children = this.properties2children(attributes.properties);
await model.updateAssociation('children', attributes.children, options);
@@ -48,7 +55,9 @@ export class UISchema extends Model {
async getProperties() {
const properties = {};
- const children: UISchema[] = await this.getChildren();
+ const children: UISchema[] = await this.getChildren({
+ order: [['sort', 'asc']],
+ });
for (const child of children) {
const property = child.toProperty();
const childProperties = await child.getProperties();
diff --git a/packages/plugin-ui-schema/src/server.ts b/packages/plugin-ui-schema/src/server.ts
index 8318f9ff4..c0f74088b 100644
--- a/packages/plugin-ui-schema/src/server.ts
+++ b/packages/plugin-ui-schema/src/server.ts
@@ -2,7 +2,7 @@ import path from 'path';
import { Application } from '@nocobase/server';
import { registerModels, Table } from '@nocobase/database';
import * as models from './models';
-import getTree from './actions/getTree';
+import { create, getTree } from './actions';
export default async function (this: Application, options = {}) {
const database = this.database;
@@ -12,11 +12,6 @@ export default async function (this: Application, options = {}) {
directory: path.resolve(__dirname, 'collections'),
});
- // database.getModel('ui_schemas').beforeCreate((model) => {
- // if (!model.get('name')) {
- // model.set('name', model.get('key'));
- // }
- // });
-
+ this.resourcer.registerActionHandler('ui_schemas:create', create);
this.resourcer.registerActionHandler('ui_schemas:getTree', getTree);
}