diff --git a/packages/plugins/@hera/plugin-approval/src/client/configuration/trigger/Approval.trigger.tsx b/packages/plugins/@hera/plugin-approval/src/client/configuration/trigger/Approval.trigger.tsx
index 967174181..aa25021a6 100644
--- a/packages/plugins/@hera/plugin-approval/src/client/configuration/trigger/Approval.trigger.tsx
+++ b/packages/plugins/@hera/plugin-approval/src/client/configuration/trigger/Approval.trigger.tsx
@@ -172,11 +172,6 @@ export class ApprovalTrigger extends Trigger {
compile,
getCollectionFields,
});
- console.log(
- '%c Line:176 🍷 collectionFieldOptions',
- 'font-size:18px;color:#33a5ff;background:#3f7cff',
- collectionFieldOptions,
- );
return collectionFieldOptions;
}
diff --git a/packages/plugins/@hera/plugin-approval/src/client/usage/approval-block/ApprovalBlock.provider.tsx b/packages/plugins/@hera/plugin-approval/src/client/usage/approval-block/ApprovalBlock.provider.tsx
index fa74b5718..3504618da 100644
--- a/packages/plugins/@hera/plugin-approval/src/client/usage/approval-block/ApprovalBlock.provider.tsx
+++ b/packages/plugins/@hera/plugin-approval/src/client/usage/approval-block/ApprovalBlock.provider.tsx
@@ -1,5 +1,6 @@
-import { ExtendCollectionsProvider, TableBlockProvider, useRecord } from '@tachybase/client';
import React from 'react';
+import { ExtendCollectionsProvider, TableBlockProvider, useRecord } from '@tachybase/client';
+
import { CollectionApprovalTodos } from '../../common/Cn.ApprovalTodos';
import { CollectionApprovals } from '../approval-common/Approvals.collection';
import { CollectionFlowNodes } from '../approval-common/FlowNodes.collection';
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/.npmignore b/packages/plugins/@tachybase/plugin-workflow-notice/.npmignore
new file mode 100644
index 000000000..65f5e8779
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/.npmignore
@@ -0,0 +1,2 @@
+/node_modules
+/src
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/README.md b/packages/plugins/@tachybase/plugin-workflow-notice/README.md
new file mode 100644
index 000000000..f7ffdf277
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/README.md
@@ -0,0 +1 @@
+# @tachybase/plugin-workflow-notice
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/client.d.ts b/packages/plugins/@tachybase/plugin-workflow-notice/client.d.ts
new file mode 100644
index 000000000..6c459cbac
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/client.d.ts
@@ -0,0 +1,2 @@
+export * from './dist/client';
+export { default } from './dist/client';
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/client.js b/packages/plugins/@tachybase/plugin-workflow-notice/client.js
new file mode 100644
index 000000000..b6e3be70e
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/client.js
@@ -0,0 +1 @@
+module.exports = require('./dist/client/index.js');
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/package.json b/packages/plugins/@tachybase/plugin-workflow-notice/package.json
new file mode 100644
index 000000000..e19c99454
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "@tachybase/plugin-workflow-notice",
+ "displayName": "Workflow: Notice",
+ "version": "0.21.32",
+ "description": "A powerful BPM tool that provides foundational support for business automation, with the capability to extend unlimited triggers and nodes.",
+ "keywords": [
+ "Workflow",
+ "Notice"
+ ],
+ "main": "dist/server/index.js",
+ "devDependencies": {
+ "@ant-design/icons": "5.x",
+ "@tachybase/actions": "workspace:*",
+ "@tachybase/components": "workspace:*",
+ "@tachybase/data-source-manager": "workspace:*",
+ "@tachybase/database": "workspace:*",
+ "@tachybase/plugin-ui-schema-storage": "workspace:*",
+ "@tachybase/schema": "workspace:*",
+ "@tachybase/utils": "workspace:*",
+ "antd": "5.16.1",
+ "lodash": "^4.17.21",
+ "react": "18.x",
+ "react-i18next": "^11.15.1",
+ "sequelize": "^6.26.0"
+ },
+ "peerDependencies": {
+ "@tachybase/client": "workspace:*",
+ "@tachybase/plugin-workflow": "workspace:*",
+ "@tachybase/server": "workspace:*",
+ "@tachybase/test": "workspace:*"
+ },
+ "description.zh-CN": "工作流节点, 通知。",
+ "displayName.zh-CN": "工作流: 通知"
+}
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/server.d.ts b/packages/plugins/@tachybase/plugin-workflow-notice/server.d.ts
new file mode 100644
index 000000000..c41081ddc
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/server.d.ts
@@ -0,0 +1,2 @@
+export * from './dist/server';
+export { default } from './dist/server';
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/server.js b/packages/plugins/@tachybase/plugin-workflow-notice/server.js
new file mode 100644
index 000000000..972842039
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/server.js
@@ -0,0 +1 @@
+module.exports = require('./dist/server/index.js');
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/src/client/common/flowNodes.collection.ts b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/common/flowNodes.collection.ts
new file mode 100644
index 000000000..6f397decb
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/common/flowNodes.collection.ts
@@ -0,0 +1,42 @@
+import { tval } from '../locale';
+
+export const CollectionFlowNodes = {
+ title: tval('Node'),
+ name: 'flow_nodes',
+ fields: [
+ {
+ type: 'bigInt',
+ name: 'id',
+ interface: 'm2o',
+ uiSchema: {
+ type: 'number',
+ title: 'ID',
+ 'x-component': 'RemoteSelect',
+ 'x-component-props': {
+ fieldNames: {
+ label: 'title',
+ value: 'id',
+ },
+ service: {
+ resource: 'flow_nodes',
+ params: {
+ filter: {
+ type: 'manual',
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ type: 'string',
+ name: 'title',
+ interface: 'input',
+ uiSchema: {
+ type: 'string',
+ title: '{{t("Title")}}',
+ 'x-component': 'Input',
+ },
+ },
+ ],
+};
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/src/client/common/notice.collection.ts b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/common/notice.collection.ts
new file mode 100644
index 000000000..bed7bbbd2
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/common/notice.collection.ts
@@ -0,0 +1,144 @@
+import { COLLECTION_NOTICE_NAME } from '../../common/constants';
+import { NAMESPACE, tval } from '../locale';
+import { approvalStatusOptions } from '../usage/column/column.status';
+
+export const CollectionWorkflowNotice = {
+ title: tval('Notice Center'),
+ name: COLLECTION_NOTICE_NAME,
+ fields: [
+ {
+ type: 'bigInt',
+ name: 'id',
+ interface: 'number',
+ uiSchema: {
+ type: 'number',
+ title: 'ID',
+ 'x-component': 'InputNumber',
+ },
+ },
+ {
+ type: 'belongsTo',
+ name: 'user',
+ target: 'users',
+ foreignKey: 'userId',
+ interface: 'm2o',
+ uiSchema: {
+ type: 'number',
+ title: tval('The Notified Person'),
+ 'x-component': 'RemoteSelect',
+ 'x-component-props': {
+ fieldNames: {
+ label: 'nickname',
+ value: 'id',
+ },
+ service: { resource: 'users' },
+ },
+ },
+ },
+ {
+ type: 'belongsTo',
+ name: 'node',
+ target: 'flow_nodes',
+ foreignKey: 'nodeId',
+ interface: 'm2o',
+ isAssociation: true,
+ uiSchema: {
+ type: 'number',
+ title: `{{t("Task node", { ns: "${NAMESPACE}" })}}`,
+ 'x-component': 'RemoteSelect',
+ 'x-component-props': {
+ fieldNames: {
+ label: 'title',
+ value: 'id',
+ },
+ service: {
+ resource: 'flow_nodes',
+ },
+ },
+ },
+ },
+ {
+ type: 'belongsTo',
+ name: 'workflow',
+ target: 'workflows',
+ foreignKey: 'workflowId',
+ interface: 'm2o',
+ uiSchema: {
+ type: 'number',
+ title: '{{t("Workflow", { ns: "workflow" })}}',
+ 'x-component': 'RemoteSelect',
+ 'x-component-props': {
+ fieldNames: {
+ label: 'title',
+ value: 'id',
+ },
+ service: { resource: 'workflows' },
+ },
+ },
+ },
+ {
+ type: 'integer',
+ name: 'status',
+ interface: 'select',
+ uiSchema: {
+ type: 'number',
+ title: '{{t("Status", { ns: "workflow" })}}',
+ 'x-component': 'Select',
+ enum: approvalStatusOptions,
+ },
+ },
+ {
+ type: 'text',
+ name: 'comment',
+ interface: 'markdown',
+ uiSchema: {
+ type: 'string',
+ 'x-component': 'Markdown',
+ title: `{{t("Comment", { ns: "${NAMESPACE}" })}}`,
+ },
+ },
+ {
+ name: 'createdAt',
+ type: 'date',
+ interface: 'createdAt',
+ uiSchema: {
+ type: 'datetime',
+ title: '{{t("Created at")}}',
+ 'x-component': 'DatePicker',
+ 'x-component-props': {
+ showTime: true,
+ },
+ },
+ },
+ {
+ name: 'updatedAt',
+ type: 'date',
+ interface: 'updatedAt',
+ uiSchema: {
+ type: 'datetime',
+ title: '{{t("Updated at")}}',
+ 'x-component': 'DatePicker',
+ 'x-component-props': {
+ showTime: true,
+ },
+ },
+ },
+ {
+ type: 'string',
+ name: 'summary',
+ interface: 'input',
+ uiSchema: {
+ type: 'string',
+ title: tval('Summary'),
+ 'x-component': 'ApprovalsSummary',
+ 'x-component-props': {
+ style: {
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ whiteSpace: 'nowrap',
+ },
+ },
+ },
+ },
+ ],
+};
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/src/client/common/workflow.collection.ts b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/common/workflow.collection.ts
new file mode 100644
index 000000000..c21f50dc1
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/common/workflow.collection.ts
@@ -0,0 +1,39 @@
+import { tval } from '../locale';
+
+export const CollectionWorkflows = {
+ title: tval('Workflow'),
+ name: 'workflows',
+ fields: [
+ {
+ type: 'string',
+ name: 'title',
+ interface: 'input',
+ uiSchema: {
+ title: '{{t("Name")}}',
+ type: 'string',
+ 'x-component': 'Input',
+ required: true,
+ },
+ },
+ {
+ type: 'boolean',
+ name: 'enabled',
+ interface: 'select',
+ uiSchema: {
+ type: 'boolean',
+ title: '{{t("Status", { ns: "workflow" })}}',
+ 'x-component': 'Select',
+ enum: [
+ {
+ label: '{{t("On", { ns: "workflow" })}}',
+ value: true,
+ },
+ {
+ label: '{{t("Off", { ns: "workflow" })}}',
+ value: false,
+ },
+ ],
+ },
+ },
+ ],
+};
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/Notice.instruction.ts b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/Notice.instruction.ts
new file mode 100644
index 000000000..217d2f23e
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/Notice.instruction.ts
@@ -0,0 +1,95 @@
+import { ArrayItems } from '@tachybase/components';
+import { Instruction } from '@tachybase/plugin-workflow/client';
+
+import { NOTICE_INSTRUCTION_NAMESPACE } from '../../common/constants';
+import { tval } from '../locale';
+import { AdditionNotifiedPerson } from './config-items/AddNotifiedPerson.view';
+import { ConfigButtonNotice } from './config-items/ConfigButtonNotice.view';
+import { SelectNotifiedPerson } from './config-items/SelectNotifiedPerson.view';
+import { NoticeDetailContainer } from './show-interface/NoticeDetailContainer.schema';
+import { configSytles } from './style';
+
+// group 的取值, 经查询猜测,可能为
+// 'control' 'collection' 'extended' 'manual' 'advanced'
+// TODO: 需要整理梳理 workflow, 将这个类型转移到 workflow 中去
+type GroupType = 'control' | 'collection' | 'extended' | 'manual' | 'advanced';
+
+export class NoticeInstruction extends Instruction {
+ title = tval('Notice');
+ type = NOTICE_INSTRUCTION_NAMESPACE;
+ group: GroupType = 'extended';
+ description = tval(
+ 'In the workflow, notification messages can be viewed by the notified person in the notification center.',
+ );
+ components = {
+ ArrayItems: ArrayItems,
+ SelectNotifiedPerson: SelectNotifiedPerson,
+ AdditionNotifiedPerson: AdditionNotifiedPerson,
+ ConfigButtonNotice: ConfigButtonNotice,
+ ShowNoticeDetail: NoticeDetailContainer,
+ };
+ fieldset = {
+ notifiedPerson: {
+ type: 'array',
+ title: tval('The Notified Person'),
+ required: true,
+ 'x-decorator': 'FormItem',
+ 'x-component': 'ArrayItems',
+ 'x-component-props': {
+ className: configSytles.ArrayItemsStyle,
+ },
+
+ items: {
+ type: 'void',
+ 'x-component': 'Space',
+ 'x-component-props': {
+ className: configSytles.SpaceStyle,
+ },
+ properties: {
+ sort: {
+ type: 'void',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'ArrayItems.SortHandle',
+ },
+ input: {
+ type: 'string',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'SelectNotifiedPerson',
+ },
+ remove: {
+ type: 'void',
+ 'x-decorator': 'FormItem',
+ 'x-component': 'ArrayItems.Remove',
+ },
+ },
+ },
+ properties: {
+ add: {
+ type: 'void',
+ title: tval('Add Notified Person'),
+ // HACK: 这里原本的框架逻辑, 解析竟然和 Addition 这个单词绑定, 奇怪
+ // 类似的还有, Index, Remove, MoveUp, MoveDown, Copy
+ // isOperationComponent() 针对这类操作组件, 做了特殊逻辑
+ 'x-component': 'AdditionNotifiedPerson',
+ },
+ },
+ },
+ showNoticeDetail: {
+ type: 'void',
+ title: tval('Show Notice Detail'),
+ required: true,
+ 'x-decorator': 'FormItem',
+ 'x-component': 'ConfigButtonNotice',
+ properties: {
+ showNoticeDetail: {
+ type: 'void',
+ 'x-component': 'ShowNoticeDetail',
+ },
+ },
+ },
+ };
+
+ isAvailable(params) {
+ return true;
+ }
+}
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/config-items/AddNotifiedPerson.view.tsx b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/config-items/AddNotifiedPerson.view.tsx
new file mode 100644
index 000000000..5b4b28064
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/config-items/AddNotifiedPerson.view.tsx
@@ -0,0 +1,58 @@
+// import { PlusOutlined } from '@ant-design/icons';
+import React, { useCallback, useState } from 'react';
+import { ArrayItems } from '@tachybase/components';
+import { useWorkflowExecuted } from '@tachybase/plugin-workflow/client';
+
+import { Button, Popover, Space } from 'antd';
+
+import { useTranslation } from '../../locale';
+
+export const AdditionNotifiedPerson = () => {
+ const isWorkflowExecuted = useWorkflowExecuted();
+ const array = ArrayItems.useArray() || { field: [] };
+ const { t } = useTranslation();
+ const [isOpen, setIsOpen] = useState(false);
+
+ const onSlecet = useCallback(() => {
+ array.field.push('');
+ setIsOpen(false);
+ }, [array.field]);
+
+ const onQuery = useCallback(() => {
+ array.field.push({ filter: {} });
+ setIsOpen(false);
+ }, [array.field]);
+
+ return (
+ }
+ >
+ }
+ type="dashed"
+ block={true}
+ disabled={isWorkflowExecuted}
+ >
+ {t('Add Notified Person')}
+
+
+ );
+};
+
+// Child Component
+const PopoverContent = ({ onSlecet, onQuery }) => {
+ const { t } = useTranslation();
+ return (
+
+
+
+
+ );
+};
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/config-items/ConfigButtonNotice.view.tsx b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/config-items/ConfigButtonNotice.view.tsx
new file mode 100644
index 000000000..a86cf07ad
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/config-items/ConfigButtonNotice.view.tsx
@@ -0,0 +1,26 @@
+import React, { useCallback, useState } from 'react';
+import { ActionContextProvider } from '@tachybase/client';
+
+import { Button } from 'antd';
+
+import { useTranslation } from '../../locale';
+
+export const ConfigButtonNotice = (props) => {
+ const { t } = useTranslation();
+ const [visible, setVisible] = useState(false);
+
+ const handleButtonClick = useCallback(() => {
+ setVisible(true);
+ }, [setVisible]);
+
+ return (
+ <>
+
+
+ {props.children}
+
+ >
+ );
+};
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/config-items/SelectNotifiedPerson.view.tsx b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/config-items/SelectNotifiedPerson.view.tsx
new file mode 100644
index 000000000..a211e53fb
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/config-items/SelectNotifiedPerson.view.tsx
@@ -0,0 +1,62 @@
+import { RemoteSelect, SchemaComponent, Variable, useCollectionFilterOptions, useToken } from '@tachybase/client';
+import { FilterDynamicComponent, useWorkflowVariableOptions } from '@tachybase/plugin-workflow/client';
+import { useField } from '@tachybase/schema';
+import React from 'react';
+
+// TODO: 可以将这个选择组件封装为一个通用组件, 放在 workflow 下提供使用
+export const SelectNotifiedPerson = (props) => {
+ if (props.value && typeof props.value === 'object') {
+ return ;
+ } else {
+ return ;
+ }
+};
+
+const SelectNotifiedPersonNormal = ({ value, onChange }) => {
+ const scope = useWorkflowVariableOptions({ types: [isUserKeyField] });
+ return (
+
+
+
+ );
+};
+
+const SelectNotifiedPersonCustom = () => {
+ const field = useField();
+ const currentFormFields = useCollectionFilterOptions('users');
+ const { token } = useToken();
+ return (
+
+
+
+ );
+};
+
+function isUserKeyField(field) {
+ if (field.isForeignKey) {
+ return field.target === 'users';
+ } else {
+ return field.collectionName === 'users' && field.name === 'id';
+ }
+}
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/kit.ts b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/kit.ts
new file mode 100644
index 000000000..957bb852d
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/kit.ts
@@ -0,0 +1,24 @@
+import { Plugin } from '@tachybase/client';
+import PluginWorkflow from '@tachybase/plugin-workflow/client';
+import { NoticeInstruction } from './Notice.instruction';
+import { NOTICE_INSTRUCTION_NAMESPACE } from '../../common/constants';
+import { SCNoticeDetail } from './show-interface/NoticeDetail.schema';
+import { ArrayItems } from '@tachybase/components';
+
+// NOTE: 试着用一种新的约束规则去声明文件属于哪种功能. 比如 kit.ts 导出的是单个 Plugin 下的功能集成
+// 注册一个节点
+export class KitConfiguration extends Plugin {
+ async afterAdd() {
+ await this.app.pm.add(SCNoticeDetail);
+ }
+
+ async load() {
+ const pluginWorkflow = this.app.pm.get(PluginWorkflow);
+ pluginWorkflow.registerInstruction(NOTICE_INSTRUCTION_NAMESPACE, NoticeInstruction);
+ this.app.addComponents({
+ ArrayItems,
+ });
+ // this.app.schemaInitializerManager.add(ApproverActionConfigInitializer);
+ // this.app.schemaInitializerManager.add(ApproverAddBlockInitializer);
+ }
+}
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/show-interface/NoticeDetail.block.tsx b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/show-interface/NoticeDetail.block.tsx
new file mode 100644
index 000000000..9f9578106
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/show-interface/NoticeDetail.block.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import {
+ createReadPrettyFormBlockSchema,
+ parseCollectionName,
+ SchemaInitializerItem,
+ useRecordCollectionDataSourceItems,
+ useSchemaInitializer,
+ useSchemaInitializerItem,
+ useSchemaTemplateManager,
+} from '@tachybase/client';
+import { useFlowContext } from '@tachybase/plugin-workflow/client';
+
+import _ from 'lodash';
+
+export const NoticeDetailAddBlock = () => {
+ const { workflow } = useFlowContext();
+ const [dataSourceName, collection] = parseCollectionName(workflow.config?.collection);
+ const itemConfig = useSchemaInitializerItem();
+ const { insert } = useSchemaInitializer();
+ const { getTemplateSchemaByMode } = useSchemaTemplateManager();
+ const items = useRecordCollectionDataSourceItems('FormItem');
+ const handleClick = async ({ item }) => {
+ const template = item.template ? await getTemplateSchemaByMode(item) : null;
+ const schema = createReadPrettyFormBlockSchema({
+ actionInitializers: null,
+ resource: collection,
+ collection,
+ dataSource: dataSourceName,
+ template,
+ settings: 'blockSettings:details',
+ });
+
+ const shcemaWithPatch = {};
+
+ // REVIEW: 删除这个属性的必要性, 需要再思考下
+ _.unset(schema, ['x-acl-action', 'x-acl-action-props']);
+
+ const [childSchemaKey] = Object.keys(schema.properties);
+
+ _.set(schema.properties[childSchemaKey], 'x-component-props.useProps', 'usePropsNoticeDetail');
+
+ insert(schema);
+ };
+ return ;
+};
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/show-interface/NoticeDetail.initializer.tsx b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/show-interface/NoticeDetail.initializer.tsx
new file mode 100644
index 000000000..972c9ca92
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/show-interface/NoticeDetail.initializer.tsx
@@ -0,0 +1,78 @@
+import { SchemaInitializer, gridRowColWrap, usePlugin } from '@tachybase/client';
+import PluginWorkflow, {
+ useAvailableUpstreams,
+ useFlowContext,
+ useNodeContext,
+ useTrigger,
+} from '@tachybase/plugin-workflow/client';
+import { tval } from '../../locale';
+import { NoticeDetailAddBlock } from './NoticeDetail.block';
+// import { ApproverAddBlockComponent } from './VC.ApproverAddBlock';
+// import { ApproverAddBlockKit } from './VC.ApproverAddBlockKit';
+
+export const NoticeDetailInitializer = new SchemaInitializer({
+ name: 'NoticeDetailInitializer',
+ wrap: gridRowColWrap,
+ title: "{{t('Add block')}}",
+ items: [
+ {
+ name: 'notice',
+ type: 'itemGroup',
+ title: tval('Notice blocks'),
+ children: [
+ {
+ name: 'detail',
+ type: 'item',
+ title: '{{t("Details")}}',
+ Component: NoticeDetailAddBlock,
+ },
+ ],
+ },
+ {
+ type: 'itemGroup',
+ name: 'dataBlocks',
+ title: '{{t("Data blocks")}}',
+ checkChildrenLength: true,
+ useChildren() {
+ const workflowPlugin = usePlugin(PluginWorkflow);
+ const { workflow } = useFlowContext();
+ const trigger = useTrigger();
+ const currentNodeContext = useNodeContext();
+ const nodes = useAvailableUpstreams(currentNodeContext);
+ const triggerInitializers = [trigger.useInitializers?.call(trigger, workflow.config)].filter(Boolean);
+ const nodeBlockInitializers = nodes
+ .map((node) => {
+ const instruction = workflowPlugin.instructions.get(node.type);
+ return instruction?.useInitializers?.call(instruction, node);
+ })
+ .filter(Boolean);
+ return [
+ ...triggerInitializers,
+ ...(nodeBlockInitializers.length
+ ? [
+ {
+ name: 'nodes',
+ type: 'subMenu',
+ title: '{{t("Node result", { ns: "workflow" })}}',
+ children: nodeBlockInitializers,
+ },
+ ]
+ : []),
+ ].filter(Boolean);
+ },
+ },
+ {
+ name: 'others',
+ type: 'itemGroup',
+ title: '{{t("Other blocks")}}',
+ children: [
+ {
+ name: 'markdown',
+ type: 'item',
+ title: '{{t("Markdown")}}',
+ component: 'MarkdownBlockInitializer',
+ },
+ ],
+ },
+ ],
+});
diff --git a/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/show-interface/NoticeDetail.schema.tsx b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/show-interface/NoticeDetail.schema.tsx
new file mode 100644
index 000000000..d1aa38645
--- /dev/null
+++ b/packages/plugins/@tachybase/plugin-workflow-notice/src/client/configuration/show-interface/NoticeDetail.schema.tsx
@@ -0,0 +1,86 @@
+import React from 'react';
+import { Plugin, SchemaComponent, useAPIClient, useRequest } from '@tachybase/client';
+import { useForm } from '@tachybase/schema';
+import { uid } from '@tachybase/utils/client';
+
+import { Spin } from 'antd';
+
+import { NoticeDetailInitializer } from './NoticeDetail.initializer';
+
+export class SCNoticeDetail extends Plugin {
+ async load() {
+ this.app.schemaInitializerManager.add(NoticeDetailInitializer);
+ }
+}
+
+function createNewSchema(id) {
+ return {
+ type: 'void',
+ name: id,
+ 'x-uid': id,
+ 'x-component': 'Grid',
+ 'x-initializer': 'NoticeDetailInitializer',
+ };
+}
+
+export const NoticeDetail = (props) => {
+ const { schemaData, loading, handleChange } = useAction(props);
+ if (loading) {
+ return ;
+ }
+ return (
+ {
+ // return { run() {} };
+ // },
+ // useApprovalFormBlockProps,
+ // useDetailsBlockProps: useFormBlockContext,
+ }
+ }
+ components={{}}
+ schema={schemaData as any}
+ onChange={handleChange}
+ />
+ );
+};
+
+function useAction(props) {
+ const { value: srcID, onChange } = props;
+ const apiClient = useAPIClient();
+ const { values, setValuesIn } = useForm();
+ const { data: schemaData, loading } = useRequest(async () => {
+ if (srcID) {
+ const remoteSchema = await fetchSchema(apiClient, srcID);
+ if (remoteSchema['x-uid'] === srcID) {
+ return remoteSchema;
+ }
+ }
+ const id = srcID ?? uid();
+ const newSchema = createNewSchema(id);
+ await instertSchema(apiClient, newSchema);
+ onChange(id);
+ return newSchema;
+ });
+
+ const handleChange = (data) => {};
+
+ return {
+ schemaData,
+ loading,
+ handleChange,
+ };
+}
+
+async function fetchSchema(apiClient, srcID): Promise