mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 07:15:36 +00:00
feat(client): give more reasonable names
This commit is contained in:
parent
441a7aecf2
commit
620b2b463e
@ -75,7 +75,7 @@ const useCurrentFieldSchema = (path: string) => {
|
||||
schema &&
|
||||
remove(schema, {
|
||||
removeParentsIfNoChildren: true,
|
||||
breakSchema: (s) => {
|
||||
breakRemoveOn: (s) => {
|
||||
return s['x-component'] === 'Grid';
|
||||
},
|
||||
});
|
||||
|
@ -1,15 +1,18 @@
|
||||
import { DndContext as DndKitContext, DragEndEvent, rectIntersection } from '@dnd-kit/core';
|
||||
import { observer } from '@formily/react';
|
||||
import React from 'react';
|
||||
import { useAPIClient } from '../../../';
|
||||
import { createDesignable, useDesignable } from '../../hooks';
|
||||
|
||||
const useDragEnd = () => {
|
||||
const { refresh } = useDesignable();
|
||||
const api = useAPIClient();
|
||||
|
||||
return ({ active, over }: DragEndEvent) => {
|
||||
const activeSchema = active?.data?.current?.schema;
|
||||
const overSchema = over?.data?.current?.schema;
|
||||
const insertAdjacent = over?.data?.current?.insertAdjacent;
|
||||
const breakRemoveOn = over?.data?.current?.breakRemoveOn;
|
||||
const wrapSchema = over?.data?.current?.wrapSchema;
|
||||
|
||||
if (!activeSchema || !overSchema) {
|
||||
@ -21,11 +24,12 @@ const useDragEnd = () => {
|
||||
}
|
||||
|
||||
const dn = createDesignable({
|
||||
api,
|
||||
refresh,
|
||||
current: overSchema,
|
||||
});
|
||||
|
||||
dn.on('afterInsertAdjacent', refresh);
|
||||
dn.on('afterRemove', refresh);
|
||||
dn.loadAPIClientEvents();
|
||||
|
||||
if (activeSchema.parent === overSchema.parent) {
|
||||
return dn.insertBeforeBeginOrAfterEnd(activeSchema);
|
||||
@ -34,6 +38,7 @@ const useDragEnd = () => {
|
||||
if (insertAdjacent) {
|
||||
dn.insertAdjacent(insertAdjacent, activeSchema, {
|
||||
wrap: wrapSchema,
|
||||
breakRemoveOn,
|
||||
removeParentsIfNoChildren: true,
|
||||
});
|
||||
return;
|
||||
|
@ -217,14 +217,14 @@ describe('createDesignable', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeIfNoChildren', () => {
|
||||
describe('recursiveRemoveIfNoChildren', () => {
|
||||
test('has child nodes', () => {
|
||||
dn.removeIfNoChildren(schema.properties.current);
|
||||
dn.recursiveRemoveIfNoChildren(schema.properties.current);
|
||||
expect(schema.properties.current).toBeDefined();
|
||||
});
|
||||
|
||||
test('no child nodes', () => {
|
||||
dn.removeIfNoChildren(schema.properties.current.properties.child);
|
||||
dn.recursiveRemoveIfNoChildren(schema.properties.current.properties.child);
|
||||
expect(schema.properties.current?.properties?.child).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@ -241,20 +241,20 @@ describe('createDesignable', () => {
|
||||
expect(schema.properties.current?.properties?.child).toBeUndefined();
|
||||
});
|
||||
|
||||
test('removeParentsIfNoChildren + breakSchema json', () => {
|
||||
test('removeParentsIfNoChildren + breakRemoveOn json', () => {
|
||||
dn.remove(schema.properties.current.properties.child, {
|
||||
removeParentsIfNoChildren: true,
|
||||
breakSchema: {
|
||||
breakRemoveOn: {
|
||||
'x-uid': 'global',
|
||||
},
|
||||
});
|
||||
expect(schema?.properties?.current).toBeUndefined();
|
||||
});
|
||||
|
||||
test('removeParentsIfNoChildren + breakSchema function', () => {
|
||||
test('removeParentsIfNoChildren + breakRemoveOn function', () => {
|
||||
dn.remove(schema.properties.current.properties.child, {
|
||||
removeParentsIfNoChildren: true,
|
||||
breakSchema: (s) => s['x-uid'] === 'global',
|
||||
breakRemoveOn: (s) => s['x-uid'] === 'global',
|
||||
});
|
||||
expect(schema?.properties?.current).toBeUndefined();
|
||||
});
|
||||
@ -486,6 +486,6 @@ describe('parentsIn', () => {
|
||||
dn.on('error', callback);
|
||||
dn.insertAfterBegin(schema.properties.menu);
|
||||
expect(schema.properties.menu).toBeDefined();
|
||||
expect(callback.mock.calls[0][1].code).toBe('parent_is_not_allowed');
|
||||
expect(callback.mock.calls[0][0].code).toBe('parent_is_not_allowed');
|
||||
});
|
||||
});
|
||||
|
@ -3,11 +3,13 @@ import { uid } from '@formily/shared';
|
||||
import get from 'lodash/get';
|
||||
import set from 'lodash/set';
|
||||
import React, { useContext } from 'react';
|
||||
import { useAPIClient } from '../../api-client';
|
||||
import { APIClient, useAPIClient } from '../../api-client';
|
||||
import { SchemaComponentContext } from '../context';
|
||||
|
||||
interface CreateDesignableProps {
|
||||
current: Schema;
|
||||
api?: APIClient;
|
||||
refresh?: () => void;
|
||||
}
|
||||
|
||||
export function createDesignable(options: CreateDesignableProps) {
|
||||
@ -22,13 +24,18 @@ type Position = 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd';
|
||||
interface InsertAdjacentOptions {
|
||||
wrap?: (s: ISchema) => ISchema;
|
||||
removeParentsIfNoChildren?: boolean;
|
||||
breakRemoveOn?: ISchema | BreakFn;
|
||||
}
|
||||
|
||||
type BreakFn = (s: ISchema) => boolean;
|
||||
|
||||
interface RemoveOptions {
|
||||
removeParentsIfNoChildren?: boolean;
|
||||
breakSchema?: ISchema | BreakFn;
|
||||
breakRemoveOn?: ISchema | BreakFn;
|
||||
}
|
||||
|
||||
interface RecursiveRemoveOptions {
|
||||
breakRemoveOn?: ISchema | BreakFn;
|
||||
}
|
||||
|
||||
const generateUid = (s: ISchema) => {
|
||||
@ -42,13 +49,59 @@ const generateUid = (s: ISchema) => {
|
||||
|
||||
const defaultWrap = (s: ISchema) => s;
|
||||
|
||||
const matchSchema = (source: ISchema, target: ISchema) => {
|
||||
if (!source || !target) {
|
||||
return;
|
||||
}
|
||||
for (const key in target) {
|
||||
if (Object.prototype.hasOwnProperty.call(target, key)) {
|
||||
const value = target[key];
|
||||
if (value !== source?.[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
export class Designable {
|
||||
current: Schema;
|
||||
|
||||
options: CreateDesignableProps;
|
||||
events = {};
|
||||
|
||||
constructor({ current }) {
|
||||
this.current = current;
|
||||
constructor(options: CreateDesignableProps) {
|
||||
this.options = options;
|
||||
this.current = options.current;
|
||||
}
|
||||
|
||||
loadAPIClientEvents() {
|
||||
const { refresh, api } = this.options;
|
||||
if (!api) {
|
||||
return;
|
||||
}
|
||||
this.on('insertAdjacent', async ({ current, position, schema, removed }) => {
|
||||
refresh();
|
||||
await api.request({
|
||||
url: `/ui_schemas:insertAdjacent/${current['x-uid']}?position=${position}`,
|
||||
method: 'post',
|
||||
data: schema.toJSON(),
|
||||
});
|
||||
if (removed?.['x-uid']) {
|
||||
await api.request({
|
||||
url: `/ui_schemas:remove/${removed['x-uid']}`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
});
|
||||
this.on('remove', async ({ removed }) => {
|
||||
refresh();
|
||||
if (removed?.['x-uid']) {
|
||||
await api.request({
|
||||
url: `/ui_schemas:remove/${removed['x-uid']}`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prepareProperty(schema: ISchema) {
|
||||
@ -68,18 +121,19 @@ export class Designable {
|
||||
generateUid(schema);
|
||||
}
|
||||
|
||||
on(name: 'afterInsertAdjacent' | 'afterRemove' | 'error', listener: any) {
|
||||
on(name: 'insertAdjacent' | 'remove' | 'error', listener: any) {
|
||||
if (!this.events[name]) {
|
||||
this.events[name] = [];
|
||||
}
|
||||
this.events[name].push(listener);
|
||||
}
|
||||
|
||||
emit(name: 'afterInsertAdjacent' | 'afterRemove' | 'error', ...args) {
|
||||
emit(name: 'insertAdjacent' | 'remove' | 'error', ...args) {
|
||||
if (!this.events[name]) {
|
||||
return;
|
||||
}
|
||||
this.events[name].forEach((fn) => fn.bind(this)(this.current, ...args));
|
||||
const [opts, ...others] = args;
|
||||
this.events[name].forEach((fn) => fn.bind(this)({ current: this.current, ...opts }, ...others));
|
||||
}
|
||||
|
||||
parentsIn(schema: Schema) {
|
||||
@ -112,69 +166,46 @@ export class Designable {
|
||||
}
|
||||
}
|
||||
|
||||
removeIfNoChildren(schema?: Schema) {
|
||||
recursiveRemoveIfNoChildren(schema?: Schema, options?: RecursiveRemoveOptions) {
|
||||
if (!schema) {
|
||||
return;
|
||||
}
|
||||
let s = schema;
|
||||
const count = Object.keys(s.properties || {}).length;
|
||||
if (count > 0) {
|
||||
return;
|
||||
}
|
||||
let removed: Schema;
|
||||
while (s.parent) {
|
||||
removed = s.parent.removeProperty(s.name);
|
||||
const count = Object.keys(s.parent.properties || {}).length;
|
||||
const breakRemoveOn = options?.breakRemoveOn;
|
||||
while (s) {
|
||||
if (typeof breakRemoveOn === 'function') {
|
||||
if (breakRemoveOn(s)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (matchSchema(s, breakRemoveOn)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const count = Object.keys(s.properties || {}).length;
|
||||
if (count > 0) {
|
||||
break;
|
||||
}
|
||||
if (s.parent) {
|
||||
removed = s.parent.removeProperty(s.name);
|
||||
}
|
||||
s = s.parent;
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
remove(schema?: Schema, options: RemoveOptions = {}) {
|
||||
const { removeParentsIfNoChildren, breakSchema } = options;
|
||||
const { breakRemoveOn, removeParentsIfNoChildren } = options;
|
||||
let s = schema || this.current;
|
||||
let removed;
|
||||
const matchSchema = (source: ISchema, target: ISchema) => {
|
||||
if (!source || !target) {
|
||||
return;
|
||||
let removed = s.parent.removeProperty(s.name);
|
||||
if (removeParentsIfNoChildren) {
|
||||
const parent = this.recursiveRemoveIfNoChildren(s.parent, { breakRemoveOn });
|
||||
if (parent) {
|
||||
removed = parent;
|
||||
}
|
||||
for (const key in target) {
|
||||
if (Object.prototype.hasOwnProperty.call(target, key)) {
|
||||
const value = target[key];
|
||||
if (value !== source?.[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
while (s.parent) {
|
||||
removed = s.parent.removeProperty(s.name);
|
||||
if (!removeParentsIfNoChildren) {
|
||||
break;
|
||||
}
|
||||
if (typeof breakSchema === 'function') {
|
||||
if (breakSchema(s?.parent)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (matchSchema(s?.parent, breakSchema)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s?.parent?.['x-component'] === breakSchema) {
|
||||
break;
|
||||
}
|
||||
const count = Object.keys(s.parent.properties || {}).length;
|
||||
if (count > 0) {
|
||||
break;
|
||||
}
|
||||
s = s.parent;
|
||||
}
|
||||
this.emit('afterRemove', removed, options);
|
||||
this.emit('remove', { removed });
|
||||
}
|
||||
|
||||
insertBeforeBeginOrAfterEnd(schema: ISchema, options: InsertAdjacentOptions = {}) {
|
||||
@ -208,7 +239,7 @@ export class Designable {
|
||||
return;
|
||||
}
|
||||
const opts = {};
|
||||
const { wrap = defaultWrap, removeParentsIfNoChildren } = options;
|
||||
const { wrap = defaultWrap, breakRemoveOn, removeParentsIfNoChildren } = options;
|
||||
if (Schema.isSchemaInstance(schema)) {
|
||||
if (this.parentsIn(schema)) {
|
||||
this.emit('error', {
|
||||
@ -219,7 +250,7 @@ export class Designable {
|
||||
}
|
||||
schema.parent.removeProperty(schema.name);
|
||||
if (removeParentsIfNoChildren) {
|
||||
opts['removed'] = this.removeIfNoChildren(schema.parent);
|
||||
opts['removed'] = this.recursiveRemoveIfNoChildren(schema.parent, { breakRemoveOn });
|
||||
}
|
||||
}
|
||||
const properties = {};
|
||||
@ -245,7 +276,11 @@ export class Designable {
|
||||
s['x-index'] = newOrder;
|
||||
s.parent = this.current.parent;
|
||||
this.current.parent.setProperties(properties);
|
||||
this.emit('afterInsertAdjacent', 'beforeBegin', s, opts);
|
||||
this.emit('insertAdjacent', {
|
||||
position: 'beforeBegin',
|
||||
schema: s,
|
||||
...opts,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -259,7 +294,7 @@ export class Designable {
|
||||
return;
|
||||
}
|
||||
const opts = {};
|
||||
const { wrap = defaultWrap, removeParentsIfNoChildren } = options;
|
||||
const { wrap = defaultWrap, breakRemoveOn, removeParentsIfNoChildren } = options;
|
||||
if (Schema.isSchemaInstance(schema)) {
|
||||
if (this.parentsIn(schema)) {
|
||||
this.emit('error', {
|
||||
@ -270,7 +305,7 @@ export class Designable {
|
||||
}
|
||||
schema.parent.removeProperty(schema.name);
|
||||
if (removeParentsIfNoChildren) {
|
||||
opts['removed'] = this.removeIfNoChildren(schema.parent);
|
||||
opts['removed'] = this.recursiveRemoveIfNoChildren(schema.parent, { breakRemoveOn });
|
||||
}
|
||||
}
|
||||
const properties = {};
|
||||
@ -287,7 +322,11 @@ export class Designable {
|
||||
s['x-index'] = 0;
|
||||
s.parent = this.current;
|
||||
this.current.setProperties(properties);
|
||||
this.emit('afterInsertAdjacent', 'afterBegin', s, opts);
|
||||
this.emit('insertAdjacent', {
|
||||
position: 'afterBegin',
|
||||
schema: s,
|
||||
...opts,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -301,7 +340,7 @@ export class Designable {
|
||||
return;
|
||||
}
|
||||
const opts = {};
|
||||
const { wrap = defaultWrap, removeParentsIfNoChildren } = options;
|
||||
const { wrap = defaultWrap, breakRemoveOn, removeParentsIfNoChildren } = options;
|
||||
if (Schema.isSchemaInstance(schema)) {
|
||||
if (this.parentsIn(schema)) {
|
||||
this.emit('error', {
|
||||
@ -312,14 +351,18 @@ export class Designable {
|
||||
}
|
||||
schema.parent.removeProperty(schema.name);
|
||||
if (removeParentsIfNoChildren) {
|
||||
opts['removed'] = this.removeIfNoChildren(schema.parent);
|
||||
opts['removed'] = this.recursiveRemoveIfNoChildren(schema.parent, { breakRemoveOn });
|
||||
}
|
||||
}
|
||||
this.prepareProperty(schema);
|
||||
const wrapped = wrap(schema);
|
||||
const s = this.current.addProperty(wrapped.name || uid(), wrapped);
|
||||
s.parent = this.current;
|
||||
this.emit('afterInsertAdjacent', 'beforeEnd', s, opts);
|
||||
this.emit('insertAdjacent', {
|
||||
position: 'beforeEnd',
|
||||
schema: s,
|
||||
...opts,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -330,7 +373,7 @@ export class Designable {
|
||||
return;
|
||||
}
|
||||
const opts = {};
|
||||
const { wrap = defaultWrap, removeParentsIfNoChildren } = options;
|
||||
const { wrap = defaultWrap, breakRemoveOn, removeParentsIfNoChildren } = options;
|
||||
if (Schema.isSchemaInstance(schema)) {
|
||||
if (this.parentsIn(schema)) {
|
||||
this.emit('error', {
|
||||
@ -341,7 +384,7 @@ export class Designable {
|
||||
}
|
||||
schema.parent.removeProperty(schema.name);
|
||||
if (removeParentsIfNoChildren) {
|
||||
opts['removed'] = this.removeIfNoChildren(schema.parent);
|
||||
opts['removed'] = this.recursiveRemoveIfNoChildren(schema.parent, { breakRemoveOn });
|
||||
}
|
||||
schema.parent = null;
|
||||
}
|
||||
@ -371,7 +414,11 @@ export class Designable {
|
||||
s.parent = this.current.parent;
|
||||
s['x-index'] = newOrder;
|
||||
this.current.parent.setProperties(properties);
|
||||
this.emit('afterInsertAdjacent', 'afterEnd', s, opts);
|
||||
this.emit('insertAdjacent', {
|
||||
position: 'afterEnd',
|
||||
schema: s,
|
||||
...opts,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -384,18 +431,9 @@ export function useDesignable() {
|
||||
};
|
||||
const field = useField();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const dn = createDesignable({ current: fieldSchema });
|
||||
const api = useAPIClient();
|
||||
dn.on('afterInsertAdjacent', async (current, position, schema) => {
|
||||
refresh();
|
||||
// await api.request({
|
||||
// url: `/ui_schemas:insertAdjacent/${current['x-uid']}?position=${position}`,
|
||||
// method: 'post',
|
||||
// data: schema.toJSON(),
|
||||
// });
|
||||
// console.log(current, position, schema);
|
||||
});
|
||||
dn.on('afterRemove', refresh);
|
||||
const dn = createDesignable({ api, refresh, current: fieldSchema });
|
||||
dn.loadAPIClientEvents();
|
||||
return {
|
||||
designable,
|
||||
reset,
|
||||
|
Loading…
Reference in New Issue
Block a user