feat: disassociate action (#3759)

* feat: disassociate action

* chore: compat old initializer

* chore: add translation

* chore: add translation

* fix: acl

---------

Co-authored-by: Zeke Zhang <958414905@qq.com>
This commit is contained in:
chenos 2024-03-20 09:30:10 +08:00 committed by GitHub
parent 599a1aa0c6
commit 54f6597b9d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 171 additions and 169 deletions

View File

@ -1,4 +1,6 @@
import { Field, Form } from '@formily/core';
import { SchemaExpressionScopeContext, useField, useFieldSchema, useForm } from '@formily/react';
import { untracked } from '@formily/reactive';
import { isURL, parse } from '@nocobase/utils/client';
import { App, message } from 'antd';
import _ from 'lodash';
@ -23,6 +25,7 @@ import { useFilterBlock } from '../../filter-provider/FilterProvider';
import { mergeFilter, transformToFilter } from '../../filter-provider/utils';
import { useRecord } from '../../record-provider';
import { removeNullCondition, useActionContext, useCompile } from '../../schema-component';
import { isSubMode } from '../../schema-component/antd/association-field/util';
import { useCurrentUserContext } from '../../user';
import { useLocalVariables, useVariables } from '../../variables';
import { isVariable } from '../../variables/utils/isVariable';
@ -30,9 +33,6 @@ import { transformVariableValue } from '../../variables/utils/transformVariableV
import { useBlockRequestContext, useFilterByTk, useParamsFromRecord } from '../BlockProvider';
import { useDetailsBlockContext } from '../DetailsBlockProvider';
import { TableFieldResource } from '../TableFieldProvider';
import { Field, Form } from '@formily/core';
import { untracked } from '@formily/reactive';
import { isSubMode } from '../../schema-component/antd/association-field/util';
export * from './useFormActiveFields';
export * from './useParsedFilter';
@ -965,6 +965,34 @@ export const useRemoveActionProps = (associationName) => {
};
};
export const useDisassociateActionProps = () => {
const filterByTk = useFilterByTk();
const { resource, service, block, __parent } = useBlockRequestContext();
const { setVisible } = useActionContext();
return {
async onClick() {
await resource.remove({
values: [filterByTk],
});
const { count = 0, page = 0, pageSize = 0 } = service?.data?.meta || {};
if (count % pageSize === 1 && page !== 1) {
service.run({
...service?.params?.[0],
page: page - 1,
});
} else {
service?.refresh?.();
}
if (block && block !== 'TableField') {
__parent?.service?.refresh?.();
setVisible?.(false);
}
},
};
};
export const useDetailPrintActionProps = () => {
const { formBlockRef } = useFormBlockContext();

View File

@ -53,6 +53,9 @@
"Insert right": "Insert right",
"Insert inner": "Insert inner",
"Delete": "Delete",
"Disassociate": "Disassociate",
"Disassociate record": "Disassociate record",
"Are you sure you want to disassociate it?": "Are you sure you want to disassociate it?",
"UI editor": "UI editor",
"Collection": "Collection",
"Collection selector": "Collection selector",

View File

@ -52,6 +52,9 @@
"Insert right": "Insertar a la derecha",
"Insert inner": "Insertar al interior",
"Delete": "Borrar",
"Disassociate": "Desasociar",
"Disassociate record": "Desasociar registro",
"Are you sure you want to disassociate it?": "¿Seguro que quieres desasociarlo?",
"UI editor": "IU editor",
"Collection": "Colección",
"Collections & Fields": "Colección & Campos",

View File

@ -52,6 +52,9 @@
"Insert right": "Insérer à droite",
"Insert inner": "Insérer à l'intérieur",
"Delete": "Supprimer",
"Disassociate": "Dissocier",
"Disassociate record": "Dissocier l'enregistrement",
"Are you sure you want to disassociate it?": "Êtes-vous sûr de vouloir le dissocier ?",
"UI editor": "Éditeur d'interface utilisateur",
"Collection": "Collection",
"Collections & Fields": "Collections et champs",

View File

@ -52,6 +52,9 @@
"Insert right": "右に挿入",
"Insert inner": "中に挿入",
"Delete": "削除",
"Disassociate": "関連付けを解除",
"Disassociate record": "レコードの関連付けを解除",
"Are you sure you want to disassociate it?": "本当に関連付けを解除しますか?",
"UI editor": "UI エディタ",
"Collection": "コレクション",
"Enable child collections": "启用子表",

View File

@ -60,6 +60,9 @@
"Insert right": "오른쪽에 삽입",
"Insert inner": "내부에 삽입",
"Delete": "삭제",
"Disassociate": "연결 해제",
"Disassociate record": "레코드 연결 해제",
"Are you sure you want to disassociate it?": "정말로 연결을 해제하시겠습니까?",
"UI editor": "UI 편집기",
"Collection": "컬렉션",
"Collection selector": "컬렉션 선택기",

View File

@ -32,6 +32,9 @@
"Insert right": "Inserir à direita",
"Insert inner": "Inserir interno",
"Delete": "Excluir",
"Disassociate": "Desassociar",
"Disassociate record": "Desassociar registro",
"Are you sure you want to disassociate it?": "Tem certeza de que deseja desassociá-lo?",
"UI editor": "Editor de UI",
"Collection": "Coleção",
"Collections & Fields": "Coleções e campos",

View File

@ -52,6 +52,9 @@
"Insert right": "Вставить справа",
"Insert inner": "Вставить внутрь",
"Delete": "Удалить",
"Disassociate": "Разъединить",
"Disassociate record": "Разъединить запись",
"Are you sure you want to disassociate it?": "Вы уверены, что хотите разъединить это?",
"UI editor": "UI редактор",
"Collection": "Коллекция",
"Collections & Fields": "Коллекции & Поля",

View File

@ -52,6 +52,9 @@
"Insert right": "Sağa yerleştir",
"Insert inner": "İçine yerleştir",
"Delete": "Sil",
"Disassociate": "Bağlantıyı kes",
"Disassociate record": "Kaydı bağlantıyı kes",
"Are you sure you want to disassociate it?": "Bağlantıyı kesmek istediğinizden emin misiniz?",
"UI editor": "UI editor",
"Collection": "Koleksiyonlar",
"Collections & Fields": "Koleksiyonlar & Alanlar",

View File

@ -52,6 +52,9 @@
"Insert right": "Вставити справа",
"Insert inner": "Вставити всередину",
"Delete": "Видалити",
"Disassociate": "Роз'єднати",
"Disassociate record": "Роз'єднати запис",
"Are you sure you want to disassociate it?": "Ви впевнені, що хочете роз'єднати це?",
"UI editor": "Редактор UI",
"Collection": "Колекція",
"Collections & Fields": "Колекції та поля",

View File

@ -60,6 +60,9 @@
"Insert right": "在右边插入",
"Insert inner": "在里面插入",
"Delete": "删除",
"Disassociate": "解除关联",
"Disassociate record": "解除关联记录",
"Are you sure you want to disassociate it?": "你确定要解除关联吗?",
"UI editor": "界面配置",
"Collection": "数据表",
"Collection selector": "数据表选择器",

View File

@ -60,6 +60,9 @@
"Insert right": "從右邊插入",
"Insert inner": "從裡面插入",
"Delete": "刪除",
"Disassociate": "解除關聯",
"Disassociate record": "解除關聯記錄",
"Are you sure you want to disassociate it?": "你確定要解除關聯嗎?",
"UI editor": "介面編輯",
"Collection": "資料表",
"Collection selector": "資料表選擇器",

View File

@ -0,0 +1,25 @@
import React from 'react';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
export const DisassociateActionInitializer = (props) => {
const schema = {
title: '{{ t("Disassociate") }}',
'x-action': 'disassociate',
'x-component': 'Action',
'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:disassociate',
'x-component-props': {
icon: 'DeleteOutlined',
confirm: {
title: "{{t('Disassociate record')}}",
content: "{{t('Are you sure you want to disassociate it?')}}",
},
useProps: '{{ useDisassociateActionProps }}',
},
'x-action-settings': {
triggerWorkflows: [],
},
};
return <ActionInitializer {...props} schema={schema} />;
};

View File

@ -0,0 +1,39 @@
import { useSchemaToolbar } from '../../../application';
import { SchemaSettings } from '../../../application/schema-settings/SchemaSettings';
import { useCollection_deprecated } from '../../../collection-manager';
import { ButtonEditor, SecondConFirm } from '../../../schema-component/antd/action/Action.Designer';
import { SchemaSettingsLinkageRules } from '../../../schema-settings';
export const disassociateActionSettings = new SchemaSettings({
name: 'actionSettings:disassociate',
items: [
{
name: 'editButton',
Component: ButtonEditor,
useComponentProps() {
const { buttonEditorProps } = useSchemaToolbar();
return buttonEditorProps;
},
},
{
name: 'linkageRules',
Component: SchemaSettingsLinkageRules,
useComponentProps() {
const { name } = useCollection_deprecated();
const { linkageRulesProps } = useSchemaToolbar();
return {
...linkageRulesProps,
collectionName: name,
};
},
},
{
name: 'secondConFirm',
Component: SecondConFirm,
},
{
name: 'delete',
type: 'remove',
},
],
});

View File

@ -4,13 +4,14 @@ import _ from 'lodash';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useAPIClient } from '../../../../api-client';
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
import { SchemaInitializerActionModal } from '../../../../application/schema-initializer/components/SchemaInitializerActionModal';
import { SchemaInitializerItem } from '../../../../application/schema-initializer/components/SchemaInitializerItem';
import { useSchemaInitializer } from '../../../../application/schema-initializer/context';
import { useCollection_deprecated } from '../../../../collection-manager';
import { useDataBlockProps } from '../../../../data-source';
import { createDesignable, useDesignable } from '../../../../schema-component';
import { useGetAriaLabelOfDesigner } from '../../../../schema-settings/hooks/useGetAriaLabelOfDesigner';
import { SchemaInitializerActionModal } from '../../../../application/schema-initializer/components/SchemaInitializerActionModal';
import { useSchemaInitializer } from '../../../../application/schema-initializer/context';
import { SchemaInitializerItem } from '../../../../application/schema-initializer/components/SchemaInitializerItem';
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
export const Resizable = () => {
const { t } = useTranslation();
@ -65,11 +66,7 @@ export const Resizable = () => {
);
};
/**
* @deprecated
*/
export const tableActionColumnInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'TableActionColumnInitializers',
const commonOptions = {
insertPosition: 'beforeEnd',
useInsert: function useInsert() {
const { refresh } = useDesignable();
@ -156,6 +153,27 @@ export const tableActionColumnInitializers_deprecated = new CompatibleSchemaInit
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
type: 'item',
title: '{{t("Disassociate")}}',
name: 'disassociate',
Component: 'DisassociateActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'disassociate',
'x-acl-action': 'destroy',
'x-decorator': 'ACLActionProvider',
},
useVisible() {
const props = useDataBlockProps();
const collection = useCollection_deprecated();
return (
!!props?.association &&
(collection.template !== 'view' || collection?.writableView) &&
collection.template !== 'sql'
);
},
},
{
type: 'item',
title: '{{t("Add child")}}',
@ -225,166 +243,20 @@ export const tableActionColumnInitializers_deprecated = new CompatibleSchemaInit
Component: Resizable,
},
],
};
/**
* @deprecated
*/
export const tableActionColumnInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'TableActionColumnInitializers',
...commonOptions,
});
export const tableActionColumnInitializers = new CompatibleSchemaInitializer(
{
name: 'table:configureItemActions',
insertPosition: 'beforeEnd',
useInsert: function useInsert() {
const { refresh } = useDesignable();
const fieldSchema = useFieldSchema();
const api = useAPIClient();
const { t } = useTranslation();
return function insert(schema) {
const spaceSchema = fieldSchema.reduceProperties((buf, schema) => {
if (schema['x-component'] === 'Space') {
return schema;
}
return buf;
}, null);
if (!spaceSchema) {
return;
}
_.set(schema, 'x-designer-props.linkageAction', true);
const dn = createDesignable({
t,
api,
refresh,
current: spaceSchema,
});
dn.loadAPIClientEvents();
dn.insertBeforeEnd(schema);
};
},
Component: (props: any) => {
const { getAriaLabel } = useGetAriaLabelOfDesigner();
return (
<MenuOutlined
{...props}
role="button"
aria-label={getAriaLabel('schema-settings')}
style={{ cursor: 'pointer' }}
/>
);
},
items: [
{
type: 'itemGroup',
name: 'actions',
title: '{{t("Enable actions")}}',
children: [
{
type: 'item',
title: '{{t("View")}}',
name: 'view',
Component: 'ViewActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'view',
'x-decorator': 'ACLActionProvider',
},
},
{
type: 'item',
name: 'edit',
title: '{{t("Edit")}}',
Component: 'UpdateActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'update',
'x-decorator': 'ACLActionProvider',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
type: 'item',
title: '{{t("Delete")}}',
name: 'delete',
Component: 'DestroyActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'destroy',
'x-decorator': 'ACLActionProvider',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
type: 'item',
title: '{{t("Add child")}}',
name: 'addChildren',
Component: 'CreateChildInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'create',
'x-decorator': 'ACLActionProvider',
},
useVisible() {
const fieldSchema = useFieldSchema();
const collection = useCollection_deprecated();
const { treeTable } = fieldSchema?.parent?.parent['x-decorator-props'] || {};
return collection.tree && treeTable !== false;
},
},
],
},
{
name: 'divider',
type: 'divider',
},
{
type: 'subMenu',
title: '{{t("Customize")}}',
name: 'customize',
children: [
{
type: 'item',
title: '{{t("Popup")}}',
name: 'popup',
Component: 'PopupActionInitializer',
},
{
type: 'item',
title: '{{t("Update record")}}',
name: 'updateRecord',
Component: 'UpdateRecordActionInitializer',
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
schema: {
'x-action': 'customize:table:request',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
],
},
{
name: 'divider2',
type: 'divider',
},
{
type: 'item',
name: 'columnWidth',
title: 't("Column width")',
Component: Resizable,
},
],
...commonOptions,
},
tableActionColumnInitializers_deprecated,
);

View File

@ -12,6 +12,7 @@ import {
} from '../modules/actions/add-record/customizeCreateFormBlockInitializers';
import { BulkDestroyActionInitializer } from '../modules/actions/bulk-destroy/BulkDestroyActionInitializer';
import { DestroyActionInitializer } from '../modules/actions/delete/DestroyActionInitializer';
import { DisassociateActionInitializer } from '../modules/actions/disassociate/DisassociateActionInitializer';
import { ExpandableActionInitializer } from '../modules/actions/expand-collapse/ExpandableActionInitializer';
import { FilterActionInitializer } from '../modules/actions/filter/FilterActionInitializer';
import { RefreshActionInitializer } from '../modules/actions/refresh/RefreshActionInitializer';
@ -121,10 +122,10 @@ import * as items from './items';
export * from './buttons';
export * from './items';
export {
createDetailsBlockSchema,
createFilterFormBlockSchema,
createFormBlockSchema,
createReadPrettyFormBlockSchema,
createDetailsBlockSchema,
createTableBlockSchema,
gridRowColWrap,
itemsMerge,
@ -144,6 +145,7 @@ export class SchemaInitializerPlugin extends Plugin {
this.app.addComponents({
...initializerComponents,
...items,
DestroyActionInitializer,
CreateFormBlockInitializer,
FormBlockInitializer,
RecordFormBlockInitializer,
@ -171,7 +173,7 @@ export class SchemaInitializerPlugin extends Plugin {
UpdateSubmitActionInitializer,
BulkDestroyActionInitializer,
ExpandableActionInitializer,
DestroyActionInitializer,
DisassociateActionInitializer,
FilterActionInitializer,
RefreshActionInitializer,
} as any);

View File

@ -4,6 +4,7 @@ import { addNewActionSettings } from '../modules/actions/add-new/addNewActionSet
import { customizeAddRecordActionSettings } from '../modules/actions/add-record/customizeAddRecordActionSettings';
import { bulkDeleteActionSettings } from '../modules/actions/bulk-destroy/bulkDeleteActionSettings';
import { deleteActionSettings } from '../modules/actions/delete/deleteActionSettings';
import { disassociateActionSettings } from '../modules/actions/disassociate/disassociateActionSettings';
import { expendableActionSettings } from '../modules/actions/expand-collapse/expendableActionSettings';
import { filterActionSettings } from '../modules/actions/filter/filterActionSettings';
import { refreshActionSettings } from '../modules/actions/refresh/refreshActionSettings';
@ -68,6 +69,7 @@ export class SchemaSettingsPlugin extends Plugin {
this.schemaSettingsManager.add(viewActionSettings);
this.schemaSettingsManager.add(editActionSettings);
this.schemaSettingsManager.add(deleteActionSettings);
this.schemaSettingsManager.add(disassociateActionSettings);
this.schemaSettingsManager.add(bulkDeleteActionSettings);
this.schemaSettingsManager.add(customizeAddRecordActionSettings);
this.schemaSettingsManager.add(customizePopupActionSettings);

View File

@ -34,6 +34,7 @@ const availableActions: {
},
destroy: {
displayName: '{{t("Delete")}}',
aliases: ['destroy', 'remove'],
type: 'old-data',
},
};