lots of updates

This commit is contained in:
chenos 2021-07-17 22:35:50 +08:00
parent 78740f9905
commit 057dc8406a
17 changed files with 467 additions and 243 deletions

View File

@ -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, {

View File

@ -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 (
<>
<Button
onClick={() => {
setVisible(true);
}}
type={'primary'}
>
<DatabaseOutlined />
</Button>
<Modal
title={
<>
<Dropdown
overlay={
<Menu
onClick={(info) => {
form.setValues({
title: `数据表${info.key}`,
});
}}
>
<Menu.Item key={1}>1</Menu.Item>
<Menu.Item key={2}>2</Menu.Item>
<Menu.Divider></Menu.Divider>
<Menu.Item key={5}></Menu.Item>
</Menu>
}
>
<span style={{cursor: 'pointer'}}>3</span>
</Dropdown>
</>
}
visible={visible}
onOk={async () => {
await form.submit();
setVisible(false);
}}
onCancel={() => {
setVisible(false);
}}
>
<SchemaRenderer form={form} schema={schema} />
</Modal>
</>
);
};

View File

@ -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;

View File

@ -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<any>();
@ -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),
}}
/>
<SchemaRenderer schema={datatable} />
<DataTableConfig />
</Layout.Header>
<Layout>
<Layout.Sider
@ -75,31 +82,7 @@ function Content({ activeKey }) {
return <Spin />;
}
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 <SchemaRenderer schema={schema} />;
return <SchemaRenderer schema={data} />;
}
export function AdminLayout({ route }: any) {

View File

@ -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;

View File

@ -38,7 +38,7 @@ const App = () => {
return (
<div>
<Router initialEntries={['/login']}>
<Router initialEntries={['/admin']}>
<RouteSwitch routes={data} />
</Router>
</div>

View File

@ -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 (
<Dropdown
overlay={
@ -108,7 +108,7 @@ AddNew.BlockItem = observer((props: any) => {
<Menu.Item></Menu.Item>
</Menu.SubMenu>
<Menu.Item
onClick={() => {
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);
}
}}
>

View File

@ -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) => {
<RowDivider
key={`${schema.name}_0`}
name={`${schema.name}_0`}
onDrop={(e) => {
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) => {
<RowDivider
key={`${schema.name}_${index + 1}`}
name={`${schema.name}_${index + 1}`}
onDrop={(e) => {
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) => {
<ColumnSizeContext.Provider value={len}>
<ColDivider
name={`${schema.name}_0`}
onDrop={(e) => {
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) => {
<ColDivider
name={`${schema.name}_${index + 1}`}
resizable={index < len - 1}
onDrop={(e) => {
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) => {
</div>
);
});
// 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 (
// <GridBlockContext.Provider value={{ dragRef }}>
// <div
// ref={mergeRefs([previewRef, dropRef])}
// className={cls('nb-grid-block', {
// 'top-half': onTopHalf,
// hover: isOver,
// dragging: isDragging,
// })}
// >
// {props.children}
// </div>
// </GridBlockContext.Provider>
// );
// });

View File

@ -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'],
}
},
});
}

View File

@ -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 <AntdInput.TextArea defaultValue={schema.name} {...props}/>
},
mapProps((props: any, field) => {
return {
...props,

View File

@ -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;

View File

@ -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 });
}}
>
<RecursionField schema={schema} onlyRenderProperties />
@ -120,8 +122,12 @@ export const Menu: any = observer((props: any) => {
<div ref={ref}>
<SideMenu
path={path}
onSelect={onSelect}
visible={mode === 'mix'}
onSelect={(info) => {
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 (
<AntdMenu.ItemGroup
className={'nb-menu-add-new'}
title={
<Dropdown
overlay={
<AntdMenu>
<AntdMenu.Item
onClick={async () => {
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(),
});
}
}}
>
</AntdMenu.Item>
<AntdMenu.Item
onClick={async () => {
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(),
});
}
}}
>
</AntdMenu.Item>
</AntdMenu>
}
>
<a>{props.children}</a>
</Dropdown>
}
/>
);
});
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 (
<AntdMenu.ItemGroup
className={'nb-menu-add-new'}
title={
<Dropdown
overlay={
<AntdMenu>
<AntdMenu.Item
onClick={async () => {
const data = appendChild({
...defaultSchemas['Menu.Link'],
title: uid(),
});
await createSchema(data);
}}
>
</AntdMenu.Item>
<AntdMenu.Item
onClick={async () => {
const data = appendChild({
...defaultSchemas['Menu.SubMenu'],
title: uid(),
});
await createSchema(data);
}}
>
</AntdMenu.Item>
</AntdMenu>
}
>
<a>{props.children}</a>
</Dropdown>
}
/>
);
});
Menu.DesignableBar = (props) => {
const field = useField();
const [visible, setVisible] = useState(false);
@ -328,51 +319,32 @@ Menu.DesignableBar = (props) => {
<AntdMenu.Item
onClick={async () => {
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);
}}
>
</AntdMenu.Item>
<AntdMenu.Item
onClick={async () => {
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);
}}
>
</AntdMenu.Item>
<AntdMenu.Item
onClick={async () => {
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);
},
});
}}

View File

@ -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();
}

View File

@ -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();
};

View File

@ -10,6 +10,11 @@ export default {
name: 'key',
primaryKey: true,
},
{
type: 'sort',
name: 'sort',
scope: ['parentKey'],
},
{
type: 'string',
name: 'name',

View File

@ -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();

View File

@ -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);
}