mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-09 23:49:27 +08:00
* test(e2e): better locators for designer buttons * fix: make test passing * refactor: remove DesignerControl * chore: better locators * fix: should not disable add-menu-item * chore: better test id for block * chore: optimize Action * chore: remove role in BlockItem * feat: improve locators * chore: menu & add block * chore: initializer * chore: testid -> aria label * chore: tabs * chore: designers * refactor: optimize schemaInitializer * refactor: rename * chore: add collectionName * chore: block item * chore: action * fix: avoid crashting * chore(e2e): add __E2E__ * chore: all dialog * chore: add aria-label for block menu * Revert "chore: add aria-label for block menu" This reverts commit 6a840ef816ee1095484dc268b5dfa1bbe6cd8cbe. * chore: optimize aria-label of Action * chore: schema-initializer * chore(e2e): increase timeout * chore: schema settings * chore: optimize table * chore: workflow * chore: plugin manager * chore: collection manager and workflow * chore: details of workflow * chore: remove testid of Select * test: fix unit-tests * test: fix unit-tests * test(e2e): passing tests * test: fix unit test * chore: should use hover * test: passing tests * chore: passing tests * chore: fix CI * chore: fix CI * chore: increase timeout in CI --------- Co-authored-by: chenos <chenlinxh@gmail.com>
163 lines
5.1 KiB
TypeScript
163 lines
5.1 KiB
TypeScript
import { ArrayField } from '@formily/core';
|
|
import { Schema, useField, useFieldSchema } from '@formily/react';
|
|
import { Spin } from 'antd';
|
|
import uniq from 'lodash/uniq';
|
|
import React, { createContext, useContext, useEffect } from 'react';
|
|
import { useACLRoleContext } from '../acl';
|
|
import { useCollection, useCollectionManager } from '../collection-manager';
|
|
import { FixedBlockWrapper } from '../schema-component';
|
|
import { toColumns } from '../schema-component/antd/kanban/Kanban';
|
|
import { BlockProvider, useBlockRequestContext } from './BlockProvider';
|
|
|
|
export const KanbanBlockContext = createContext<any>({});
|
|
|
|
const useGroupField = (props) => {
|
|
const { getField } = useCollection();
|
|
const { groupField } = props;
|
|
if (typeof groupField === 'string') {
|
|
return getField(groupField);
|
|
}
|
|
if (groupField?.name) {
|
|
return getField(groupField?.name);
|
|
}
|
|
};
|
|
|
|
const InternalKanbanBlockProvider = (props) => {
|
|
const field = useField<any>();
|
|
const { resource, service } = useBlockRequestContext();
|
|
const groupField = useGroupField(props);
|
|
if (!groupField) {
|
|
return null;
|
|
}
|
|
if (service.loading && !field.loaded) {
|
|
return <Spin />;
|
|
}
|
|
field.loaded = true;
|
|
return (
|
|
<FixedBlockWrapper>
|
|
<KanbanBlockContext.Provider
|
|
value={{
|
|
props: {
|
|
resource: props.resource,
|
|
},
|
|
field,
|
|
service,
|
|
resource,
|
|
groupField,
|
|
fixedBlock: field?.decoratorProps?.fixedBlock,
|
|
}}
|
|
>
|
|
{props.children}
|
|
</KanbanBlockContext.Provider>
|
|
</FixedBlockWrapper>
|
|
);
|
|
};
|
|
|
|
const recursiveProperties = (schema: Schema, component = 'CollectionField', associationFields, appends: any = []) => {
|
|
schema.mapProperties((s: any) => {
|
|
const name = s.name.toString();
|
|
if (s['x-component'] === component && !appends.includes(name)) {
|
|
// 关联字段和关联的关联字段
|
|
const [firstName] = name.split('.');
|
|
if (associationFields.has(name)) {
|
|
appends.push(name);
|
|
} else if (associationFields.has(firstName) && !appends.includes(firstName)) {
|
|
appends.push(firstName);
|
|
}
|
|
} else {
|
|
recursiveProperties(s, component, associationFields, appends);
|
|
}
|
|
});
|
|
};
|
|
|
|
const useAssociationNames = (collection) => {
|
|
const { getCollectionFields } = useCollectionManager();
|
|
const collectionFields = getCollectionFields(collection);
|
|
const associationFields = new Set();
|
|
for (const collectionField of collectionFields) {
|
|
if (collectionField.target) {
|
|
associationFields.add(collectionField.name);
|
|
const fields = getCollectionFields(collectionField.target);
|
|
for (const field of fields) {
|
|
if (field.target) {
|
|
associationFields.add(`${collectionField.name}.${field.name}`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const fieldSchema = useFieldSchema();
|
|
const kanbanSchema = fieldSchema.reduceProperties((buf, schema) => {
|
|
if (schema['x-component'].startsWith('Kanban')) {
|
|
return schema;
|
|
}
|
|
return buf;
|
|
}, new Schema({}));
|
|
const gridSchema: any = kanbanSchema?.properties?.card?.properties?.grid;
|
|
const appends = [];
|
|
if (gridSchema) {
|
|
recursiveProperties(gridSchema, 'CollectionField', associationFields, appends);
|
|
}
|
|
|
|
return uniq(appends);
|
|
};
|
|
|
|
export const KanbanBlockProvider = (props) => {
|
|
const params = { ...props.params };
|
|
const appends = useAssociationNames(props.collection);
|
|
if (!Object.keys(params).includes('appends')) {
|
|
params['appends'] = appends;
|
|
}
|
|
return (
|
|
<BlockProvider name="kanban" {...props} params={params}>
|
|
<InternalKanbanBlockProvider {...props} params={params} />
|
|
</BlockProvider>
|
|
);
|
|
};
|
|
|
|
export const useKanbanBlockContext = () => {
|
|
return useContext(KanbanBlockContext);
|
|
};
|
|
|
|
const useDisableCardDrag = () => {
|
|
const ctx = useKanbanBlockContext();
|
|
const { allowAll, allowConfigure, parseAction } = useACLRoleContext();
|
|
if (allowAll || allowConfigure) {
|
|
return false;
|
|
}
|
|
const result = parseAction(`${ctx?.props?.resource}:update`, { ignoreScope: true });
|
|
return !result;
|
|
};
|
|
|
|
export const useKanbanBlockProps = () => {
|
|
const field = useField<ArrayField>();
|
|
const ctx = useKanbanBlockContext();
|
|
useEffect(() => {
|
|
if (!ctx?.service?.loading) {
|
|
field.value = toColumns(ctx.groupField, ctx?.service?.data?.data);
|
|
}
|
|
// field.loading = ctx?.service?.loading;
|
|
}, [ctx?.service?.loading]);
|
|
return {
|
|
groupField: ctx.groupField,
|
|
disableCardDrag: useDisableCardDrag(),
|
|
async onCardDragEnd({ columns, groupField }, { fromColumnId, fromPosition }, { toColumnId, toPosition }) {
|
|
const sourceColumn = columns.find((column) => column.id === fromColumnId);
|
|
const destinationColumn = columns.find((column) => column.id === toColumnId);
|
|
const sourceCard = sourceColumn?.cards?.[fromPosition];
|
|
const targetCard = destinationColumn?.cards?.[toPosition];
|
|
const values = {
|
|
sourceId: sourceCard.id,
|
|
sortField: `${groupField.name}_sort`,
|
|
};
|
|
if (targetCard) {
|
|
values['targetId'] = targetCard.id;
|
|
} else {
|
|
values['targetScope'] = {
|
|
[groupField.name]: toColumnId,
|
|
};
|
|
}
|
|
await ctx.resource.move(values);
|
|
},
|
|
};
|
|
};
|