feat: kanban (#230)

* feat: kanban

* feat(client): improve kanban

* fix: unknown group
This commit is contained in:
chenos 2022-03-10 23:52:44 +08:00 committed by GitHub
parent ffe3463dc2
commit 3d5817e0b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 542 additions and 126 deletions

View File

@ -12,7 +12,8 @@ function Card({ children, index, renderCard, disableCardDrag }) {
{...provided.dragHandleProps}
data-testid={`card-${children.id}`}
>
<div style={{ display: 'inline-block', whiteSpace: 'normal' }}>{renderCard(isDragging)}</div>
{renderCard(isDragging)}
{/* <div style={{ display: 'inline-block', whiteSpace: 'normal' }}></div> */}
</div>
);
}}

View File

@ -46,16 +46,18 @@ function Column({
{cardAdderPosition === 'top' && allowAddCard && renderCardAdder({ column: children, onConfirm: onCardNew })}
<DroppableColumn droppableId={String(children.id)}>
{children?.cards?.length ? (
children.cards.map((card, index) => (
<Card
key={card.id}
index={index}
renderCard={(dragging) => renderCard(children, card, dragging)}
disableCardDrag={disableCardDrag}
>
{card}
</Card>
))
<div className="react-kanban-card-skeleton">
{children.cards.map((card, index) => (
<Card
key={card.id}
index={index}
renderCard={(dragging) => renderCard(children, card, dragging)}
disableCardDrag={disableCardDrag}
>
{card}
</Card>
))}
</div>
) : (
<div className="react-kanban-card-skeleton" />
)}

View File

@ -1,5 +1,6 @@
.react-kanban-board {
padding: 5px;
// padding: 5px;
margin-bottom: 24px;
}
.react-kanban-card {
@ -14,8 +15,19 @@
.react-kanban-card-skeleton {
box-sizing: border-box;
max-width: 250px;
min-width: 250px;
max-width: 300px;
min-width: 300px;
height: 70vh;
overflow-x: hidden;
overflow-y: auto;
padding: 0 12px;
margin-bottom: 12px;
> div {
margin-bottom: 12px;
}
+ div {
display: none !important;
}
}
.react-kanban-card--dragging {
@ -35,15 +47,16 @@
}
.react-kanban-column {
// padding: 15px 0;
// border-radius: 2px;
background-color: #f9f9f9;
margin-right: 15px;
padding-bottom: 15px;
width: 300px;
}
.react-kanban-column-header {
padding: 15px;
border-radius: 2px;
background-color: #eee;
margin: 5px;
input {
&:focus {
outline: none;
}
}
}
.react-kanban-card-adder-form {
@ -114,14 +127,7 @@
}
.react-kanban-column-header {
padding-bottom: 10px;
font-weight: bold;
input {
&:focus {
outline: none;
}
}
}
.react-kanban-column-header__button {

View File

@ -28,6 +28,30 @@ export const useCancelFilterAction = () => {
};
};
export const useKanbanEvents = () => {
const { resource } = useCollection();
return {
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 resource.move(values);
},
};
};
export const useSortFields = (collectionName: string) => {
const { getCollectionFields, getInterface } = useCollectionManager();
const fields = getCollectionFields(collectionName);

View File

@ -6,7 +6,7 @@ import React from 'react';
import { useTranslation } from 'react-i18next';
import { useCompile, useDesignable } from '../../../schema-component';
import { SchemaInitializer } from '../../../schema-initializer';
import { useCardItemInitializerFields } from './hoooks';
import { useFormItemInitializerFields } from '../../../schema-initializer/Initializers/utils';
const titleCss = css`
pointer-events: none;
@ -23,6 +23,15 @@ const titleCss = css`
left: 2px;
`;
export const removeGridFormItem = (schema, cb) => {
cb(schema, {
removeParentsIfNoChildren: true,
breakRemoveOn: {
'x-component': 'Kanban.Card',
},
});
};
export const KanbanCardDesigner = (props: any) => {
const { dn, designable } = useDesignable();
const { t } = useTranslation();
@ -34,6 +43,7 @@ export const KanbanCardDesigner = (props: any) => {
field,
fieldSchema,
};
const fields = useFormItemInitializerFields();
if (!designable) {
return null;
}
@ -42,11 +52,21 @@ export const KanbanCardDesigner = (props: any) => {
<div className={'general-schema-designer-icons'}>
<Space size={2} align={'center'}>
<SchemaInitializer.Button
wrap={(s) => {
s['type'] = 'string';
s['x-read-pretty'] = true;
return s;
}}
items={[
{
type: 'itemGroup',
title: t('Display fields'),
children: useCardItemInitializerFields(),
children: fields.map((field) => {
return {
...field,
remove: removeGridFormItem,
};
}),
},
]}
component={<MenuOutlined style={{ cursor: 'pointer', fontSize: 12 }} />}

View File

@ -1,27 +1,72 @@
import { createForm } from '@formily/core';
import { FieldContext, FormContext, observer } from '@formily/react';
import { css } from '@emotion/css';
import { observer, RecursionField, useFieldSchema } from '@formily/react';
import { Card } from 'antd';
import React, { useContext, useMemo } from 'react';
import { BlockItem } from '../block-item';
import { CardContext } from './context';
import React, { useContext, useState } from 'react';
import { ActionContext, BlockItem } from '..';
import { DndContext } from '../..';
import { RecordProvider } from '../../../record-provider';
import { SchemaComponentOptions } from '../../core/SchemaComponentOptions';
import { KanbanCardContext } from './context';
const FormItem = observer((props) => {
return <BlockItem {...props} />;
});
export const KanbanCard: any = observer((props: any) => {
const { allowRemoveCard, onCardRemove, children } = props;
const { card, dragging } = useContext(CardContext);
const form = useMemo(
() =>
createForm({
values: { card: { ...card } },
}),
[card],
);
const { setDisableCardDrag, cardViewerSchema, card, cardField, columnIndex, cardIndex } =
useContext(KanbanCardContext);
const fieldSchema = useFieldSchema();
const [visible, setVisible] = useState(false);
return (
<BlockItem className={'noco-card-item'}>
<FieldContext.Provider value={undefined}>
<FormContext.Provider value={form}>
<Card style={{ width: 220, marginBottom: 15, cursor: 'pointer' }}>{children}</Card>
</FormContext.Provider>
</FieldContext.Provider>
</BlockItem>
<>
<Card
onClick={(e) => {
setVisible(true);
}}
className={css`
/* .ant-description-input {
line-height: 1.15;
} */
.ant-formily-item-label {
display: none;
}
.ant-formily-item-feedback-layout-loose {
margin-bottom: 12px;
}
.nb-block-item:last-child {
.ant-formily-item {
margin-bottom: 0;
}
}
`}
bordered={false}
hoverable
style={{ cursor: 'pointer', overflow: 'hidden' }}
>
<SchemaComponentOptions components={{}}>
<DndContext
onDragStart={() => {
setDisableCardDrag(true);
}}
onDragEnd={() => {
setDisableCardDrag(false);
}}
>
<RecursionField
basePath={cardField.address.concat(`${columnIndex}.cards.${cardIndex}`)}
schema={fieldSchema}
onlyRenderProperties
/>
</DndContext>
</SchemaComponentOptions>
</Card>
{cardViewerSchema && (
<ActionContext.Provider value={{ openMode: 'drawer', visible, setVisible }}>
<RecordProvider record={card}>
<RecursionField name={cardViewerSchema.name} schema={cardViewerSchema} onlyRenderProperties />
</RecordProvider>
</ActionContext.Provider>
)}
</>
);
});

View File

@ -1,11 +1,54 @@
import { ISchema, useField, useFieldSchema } from '@formily/react';
import React from 'react';
import { useCollection } from '../../../collection-manager';
import { useTranslation } from 'react-i18next';
import { useCollection, useResourceActionContext } from '../../../collection-manager';
import { useCollectionFilterOptions } from '../../../collection-manager/action-hooks';
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
import { useDesignable } from '../../hooks';
export const KanbanDesigner = () => {
const { name, title } = useCollection();
const field = useField();
const fieldSchema = useFieldSchema();
const dataSource = useCollectionFilterOptions(name);
const ctx = useResourceActionContext();
const { t } = useTranslation();
const { dn } = useDesignable();
const defaultFilter = fieldSchema?.['x-decorator-props']?.request?.params?.filter || {};
return (
<GeneralSchemaDesigner title={title || name}>
<SchemaSettings.ModalItem
title={'设置数据范围'}
schema={
{
type: 'object',
title: '设置数据范围',
properties: {
filter: {
default: defaultFilter,
title: '数据范围',
enum: dataSource,
'x-component': 'Filter',
'x-component-props': {},
},
},
} as ISchema
}
onSubmit={({ filter }) => {
const params = field.decoratorProps.request.params || {};
params.filter = filter;
field.decoratorProps.request.params = params;
fieldSchema['x-decorator-props']['request']['params'] = params;
ctx.run({ ...ctx.params?.[0], filter });
dn.emit('patch', {
schema: {
['x-uid']: fieldSchema['x-uid'],
'x-decorator-props': fieldSchema['x-decorator-props'],
},
});
}}
/>
<SchemaSettings.Divider />
<SchemaSettings.Remove
removeParentsIfNoChildren
breakRemoveOn={{

View File

@ -1,13 +1,14 @@
import { ArrayField } from '@formily/core';
import { observer, RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
import { uid } from '@formily/shared';
import { Card } from 'antd';
import React, { useState } from 'react';
import { SchemaComponent } from '../..';
import { Spin, Tag } from 'antd';
import React, { useContext, useState } from 'react';
import { SchemaComponentOptions } from '../..';
import { AsyncDataProvider, RecordProvider, useRequest } from '../../../';
import { Board } from '../../../board';
import { Action, ActionContext } from '../action';
import { CardContext, ColumnContext } from './context';
import '../../../board/style.less';
import { Action } from '../action';
import { KanbanCardContext, KanbanColumnContext } from './context';
import { KanbanCard } from './Kanban.Card';
import { KanbanCardDesigner } from './Kanban.Card.Designer';
import { KanbanCardViewer } from './Kanban.CardViewer';
import { KanbanDesigner } from './Kanban.Designer';
@ -29,14 +30,31 @@ const useDefDataSource = (options, props) => {
return useRequest(useRequestProps(props), options);
};
const useCreateKanbanCardValues = (options) => {
const { column, groupField } = useContext(KanbanColumnContext);
return useRequest(
() =>
Promise.resolve({
data: {
[groupField.name]: column.id === '__unknown__' ? undefined : column.id,
},
}),
{
...options,
refreshDeps: [column.id],
},
);
};
export const Kanban: ComposedKanban = observer((props: any) => {
const { useDataSource = useDefDataSource, groupField, useDragEndAction, ...restProps } = props;
const { useDataSource = useDefDataSource, groupField, useEvents, ...restProps } = props;
const field = useField<ArrayField>();
const fieldSchema = useFieldSchema();
const [board, setBoard] = useState<any>({ columns: [] });
const [visible, setVisible] = useState(false);
const [record, setRecord] = useState<any>({});
const { run: runDragEnd } = useDragEndAction?.() ?? {};
const { onCardDragEnd } = useEvents?.() ?? {};
const [disableCardDrag, setDisableCardDrag] = useState(false);
const result = useDataSource(
{
uid: fieldSchema['x-uid'],
@ -55,7 +73,6 @@ export const Kanban: ComposedKanban = observer((props: any) => {
}
return buf;
}, null);
console.log('board', board);
const cardAdderSchema: Schema = fieldSchema.reduceProperties((buf, current) => {
if (current['x-component'] === 'Kanban.CardAdder') {
return current;
@ -74,58 +91,68 @@ export const Kanban: ComposedKanban = observer((props: any) => {
field.value = updatedBoard.columns;
};
const cardDragEndHandler = (card, fromColumn, toColumn) => {
onCardDragEnd?.({ columns: field.value, groupField }, fromColumn, toColumn);
const updatedBoard = Board.moveCard({ columns: field.value }, fromColumn, toColumn);
field.value = updatedBoard.columns;
runDragEnd?.(card, fromColumn, toColumn);
};
return (
<AsyncDataProvider value={result}>
{cardViewerSchema && (
<ActionContext.Provider value={{ visible, setVisible }}>
<RecordProvider record={record}>
<SchemaComponent name={record.id} schema={cardViewerSchema as any} onlyRenderProperties />
</RecordProvider>
</ActionContext.Provider>
)}
<Board
onCardRemove={cardRemoveHandler}
onCardDragEnd={cardDragEndHandler}
renderCard={(card, { column, dragging }) => {
const columnIndex = field.value?.indexOf(column);
const cardIndex = column?.cards?.indexOf(card);
return (
<RecordProvider record={card}>
<CardContext.Provider value={{ card, column, dragging }}>
<Card style={{ width: 220, marginBottom: 15, cursor: 'pointer' }}>
<RecursionField name={`${columnIndex}.cards.${cardIndex}`} schema={cardSchema} onlyRenderProperties />
</Card>
</CardContext.Provider>
</RecordProvider>
);
}}
renderCardAdder={({ column }) => {
return (
<ColumnContext.Provider value={{ column }}>
<SchemaComponent memoized name={uid()} schema={cardAdderSchema as any} />
</ColumnContext.Provider>
);
}}
{...restProps}
>
{{
columns: field.value?.slice() || [],
}}
</Board>
</AsyncDataProvider>
<Spin spinning={result.loading}>
<AsyncDataProvider value={result}>
<Board
disableCardDrag={disableCardDrag}
onCardRemove={cardRemoveHandler}
onCardDragEnd={cardDragEndHandler}
renderColumnHeader={({ title, color }) => (
<div className={'react-kanban-column-header'}>
<Tag color={color}>{title}</Tag>
</div>
)}
renderCard={(card, { column, dragging }) => {
const columnIndex = field.value?.indexOf(column);
const cardIndex = column?.cards?.indexOf(card);
return (
cardSchema && (
<RecordProvider record={card}>
<KanbanCardContext.Provider
value={{
setDisableCardDrag,
cardViewerSchema,
cardField: field,
card,
column,
dragging,
columnIndex,
cardIndex,
}}
>
<RecursionField name={cardSchema.name} schema={cardSchema} />
</KanbanCardContext.Provider>
</RecordProvider>
)
);
}}
renderCardAdder={({ column }) => {
return (
<KanbanColumnContext.Provider value={{ column, groupField }}>
<SchemaComponentOptions scope={{ useCreateKanbanCardValues }}>
<RecursionField name={cardAdderSchema.name} schema={cardAdderSchema} />
</SchemaComponentOptions>
</KanbanColumnContext.Provider>
);
}}
{...restProps}
>
{{
columns: field.value?.slice() || [],
}}
</Board>
</AsyncDataProvider>
</Spin>
);
});
Kanban.Card = () => null;
Kanban.Card = KanbanCard;
Kanban.CardAdder = Action;
Kanban.CardViewer = KanbanCardViewer;
Kanban.Card.Designer = KanbanCardDesigner;
Kanban.Designer = KanbanDesigner;

View File

@ -1,4 +1,4 @@
import { createContext } from 'react';
export const CardContext = createContext(null);
export const ColumnContext = createContext(null);
export const KanbanCardContext = createContext(null);
export const KanbanColumnContext = createContext(null);

View File

@ -1,6 +1,6 @@
interface IGroupField {
name: string;
enum: Array<{ label: string; value: string; index: number }>;
enum: Array<{ label: string; value: string; color?: string; }>;
}
interface IBoard {

View File

@ -2,20 +2,29 @@ export const toGroupDataSource = (groupField: IGroupField, dataSource: Array<any
if (dataSource.length === 0) {
return { columns: [] };
}
const groupDataSource = [];
groupField.enum.forEach((item, index) => {
groupDataSource.push({
const groupDataSource = {
__unknown__: {
id: '__unknown__',
title: 'Unknown',
color: 'default',
cards: [],
},
};
groupField.enum.forEach((item) => {
groupDataSource[item.value] = {
id: item.value,
title: item.label,
index: item.index,
color: item.color,
cards: [],
});
};
});
dataSource.forEach((ds) => {
const group = groupDataSource.find((g) => g.id === ds[groupField.name]);
if (group) {
group.cards.push(ds);
const value = ds[groupField.name];
if (value && groupDataSource[value]) {
groupDataSource[value].cards.push(ds);
} else {
groupDataSource.__unknown__.cards.push(ds);
}
});
return { columns: groupDataSource };
return { columns: Object.values(groupDataSource) };
};

View File

@ -13,8 +13,8 @@ const useLabelFields = (collectionName?: any) => {
const { getCollectionFields } = useCollectionManager();
const targetFields = getCollectionFields(collectionName);
return targetFields
?.filter((field) => !field?.target && field.type !== 'boolean')
?.map((field) => {
?.filter?.((field) => !field?.target && field.type !== 'boolean')
?.map?.((field) => {
return {
value: field.name,
label: compile(field?.uiSchema?.title || field.name),
@ -30,7 +30,7 @@ export const TableColumnDeigner = (props) => {
const initialValue = {
title: columnSchema?.title,
};
const options = useLabelFields(collectionField.target);
const options = useLabelFields(collectionField?.target);
return (
<GeneralSchemaDesigner>
<SchemaSettings.PopupItem

View File

@ -1,14 +1,16 @@
import { DndContext as DndKitContext, DragEndEvent, DragOverlay, rectIntersection } from '@dnd-kit/core';
import { Props } from '@dnd-kit/core/dist/components/DndContext/DndContext';
import { observer } from '@formily/react';
import React from 'react';
import { useAPIClient } from '../../../';
import { createDesignable, useDesignable } from '../../hooks';
const useDragEnd = () => {
const useDragEnd = (props?: any) => {
const { refresh } = useDesignable();
const api = useAPIClient();
return ({ active, over }: DragEndEvent) => {
return (event: DragEndEvent) => {
const { active, over } = event;
const activeSchema = active?.data?.current?.schema;
const overSchema = over?.data?.current?.schema;
const insertAdjacent = over?.data?.current?.insertAdjacent;
@ -16,10 +18,12 @@ const useDragEnd = () => {
const wrapSchema = over?.data?.current?.wrapSchema;
if (!activeSchema || !overSchema) {
props?.onDragEnd?.(event);
return;
}
if (activeSchema === overSchema) {
props?.onDragEnd?.(event);
return;
}
@ -32,7 +36,9 @@ const useDragEnd = () => {
dn.loadAPIClientEvents();
if (activeSchema.parent === overSchema.parent) {
return dn.insertBeforeBeginOrAfterEnd(activeSchema);
dn.insertBeforeBeginOrAfterEnd(activeSchema);
props?.onDragEnd?.(event);
return;
}
if (insertAdjacent) {
@ -41,14 +47,15 @@ const useDragEnd = () => {
breakRemoveOn,
removeParentsIfNoChildren: true,
});
props?.onDragEnd?.(event);
return;
}
};
};
export const DndContext = observer((props) => {
export const DndContext = observer((props: Props) => {
return (
<DndKitContext collisionDetection={rectIntersection} onDragEnd={useDragEnd()}>
<DndKitContext collisionDetection={rectIntersection} {...props} onDragEnd={useDragEnd(props)}>
<DragOverlay
dropAnimation={{
duration: 10,

View File

@ -24,6 +24,11 @@ export const BlockInitializers = {
title: 'Calendar',
component: 'CalendarBlockInitializer',
},
{
type: 'item',
title: 'Kanban',
component: 'KanbanBlockInitializer',
},
],
},
{

View File

@ -0,0 +1,226 @@
import { FormOutlined } from '@ant-design/icons';
import { FormDialog, FormLayout } from '@formily/antd';
import { ISchema, SchemaOptionsContext } from '@formily/react';
import React, { useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { useAPIClient } from '../../../api-client';
import { useCollectionManager } from '../../../collection-manager';
import { SchemaComponent, SchemaComponentOptions } from '../../../schema-component';
import { SchemaInitializer } from '../../SchemaInitializer';
const createSchema = (collectionName, { groupField, sortName }) => {
const schema: ISchema = {
type: 'void',
'x-collection': 'collections',
'x-decorator': 'ResourceActionProvider',
'x-decorator-props': {
collection: collectionName,
request: {
resource: collectionName,
action: 'list',
params: {
paginate: false,
sort: [sortName],
},
},
},
'x-designer': 'Kanban.Designer',
'x-component': 'BlockItem',
properties: {
kanban: {
type: 'array',
name: 'kanban',
'x-component': 'Kanban',
'x-component-props': {
useDataSource: '{{ cm.useDataSourceFromRAC }}',
groupField: groupField?.uiSchema,
cardAdderPosition: 'bottom',
allowAddCard: { on: 'bottom' },
disableColumnDrag: true,
useEvents: '{{ cm.useKanbanEvents }}',
},
properties: {
card: {
type: 'void',
name: 'card',
'x-component': 'Kanban.Card',
'x-decorator': 'BlockItem',
'x-designer': 'Kanban.Card.Designer',
'x-read-pretty': true,
properties: {},
},
cardAdder: {
type: 'void',
'x-component': 'Kanban.CardAdder',
'x-designer': 'Action.Designer',
'x-component-props': {
type: 'text',
openMode: 'drawer',
},
title: '添加卡片',
properties: {
drawer: {
type: 'void',
title: '{{ t("Add new record") }}',
'x-component': 'Action.Container',
'x-component-props': {},
'x-decorator': 'Form',
'x-decorator-props': {
useValues: '{{useCreateKanbanCardValues}}',
},
properties: {
grid: {
type: 'void',
'x-component': 'Grid',
'x-initializer': 'GridFormItemInitializers',
properties: {},
},
footer: {
type: 'void',
'x-component': 'Action.Container.Footer',
properties: {
actions: {
type: 'void',
'x-initializer': 'PopupFormActionInitializers',
'x-decorator': 'DndContext',
'x-component': 'ActionBar',
'x-component-props': {
layout: 'one-column',
},
properties: {},
},
},
},
},
},
},
},
cardViewer: {
type: 'void',
'x-component': 'Kanban.CardViewer',
properties: {
drawer: {
type: 'void',
'x-component': 'Action.Container',
'x-component-props': {
className: 'nb-action-popup',
},
title: '{{ t("View record") }}',
properties: {
tabs: {
type: 'void',
'x-component': 'Tabs',
'x-component-props': {},
'x-initializer': 'TabPaneInitializers',
properties: {
tab1: {
type: 'void',
title: '详情',
'x-component': 'Tabs.TabPane',
'x-designer': 'Tabs.Designer',
'x-component-props': {},
properties: {
grid: {
type: 'void',
'x-component': 'Grid',
'x-initializer': 'RecordBlockInitializers',
properties: {},
},
},
},
},
},
},
},
},
},
},
},
},
};
return schema;
};
export const KanbanBlockInitializer = (props) => {
const { insert } = props;
const { collections, getCollection } = useCollectionManager();
const { t } = useTranslation();
const options = useContext(SchemaOptionsContext);
const api = useAPIClient();
return (
<SchemaInitializer.Item
{...props}
icon={<FormOutlined />}
onClick={async ({ item }) => {
const collection = getCollection(item.name);
const fields = collection?.fields
?.filter((field) => ['select', 'radioGroup'].includes(field.interface))
?.map((field) => {
return {
label: field?.uiSchema?.title,
value: field.name,
uiSchema: {
...field.uiSchema,
name: field.name,
},
};
});
const values = await FormDialog('创建看板区块', () => {
return (
<SchemaComponentOptions scope={options.scope} components={{ ...options.components }}>
<FormLayout layout={'vertical'}>
<SchemaComponent
schema={{
properties: {
groupField: {
title: '分组字段',
enum: fields,
required: true,
'x-component': 'Select',
'x-component-props': {
objectValue: true,
fieldNames: { label: 'label', value: 'value' },
},
'x-decorator': 'FormItem',
},
},
}}
/>
</FormLayout>
</SchemaComponentOptions>
);
}).open({
initialValues: {},
});
const sortName = `${values.groupField.value}_sort`;
const exists = collection?.fields?.find((field) => field.name === sortName);
if (!exists) {
await api.resource('collections.fields', item.name).create({
values: {
type: 'sort',
name: sortName,
hidden: true,
scopeKey: values.groupField.value,
},
});
}
insert(createSchema(item.name, { ...values, sortName }));
}}
items={[
{
type: 'itemGroup',
title: t('Select data source'),
children: collections
?.filter((item) => !item.inherit)
?.map((item) => {
return {
type: 'item',
name: item.name,
title: item.title,
};
}),
},
]}
/>
);
};

View File

@ -5,6 +5,7 @@ export * from './CollectionFieldInitializer';
export * from './FilterActionInitializer';
export * from './FormBlockInitializer';
export * from './GeneralInitializer';
export * from './KanbanBlockInitializer';
export * from './LinkToCollectionFieldInitializer';
export * from './MarkdownBlockInitializer';
export * from './RecordDetailsBlockInitializer';