refactor: workflow/webhook/department (#1207)

Reviewed-on: daoyoucloud/tachybase#1207
This commit is contained in:
sealday 2024-06-19 13:23:49 +08:00
parent 509bcc29a8
commit 35f23d4b7c
190 changed files with 1203 additions and 3244 deletions

View File

@ -10,26 +10,26 @@ export class RedisBloomFilter implements BloomFilter {
}
getStore() {
return this.cache.store.store as RedisStore;
return this.cache.store.store;
}
async reserve(key: string, errorRate: number, capacity: number) {
const store = this.getStore();
const store = this.getStore() as RedisStore;
await store.client.bf.reserve(key, errorRate, capacity);
}
async add(key: string, value: string) {
const store = this.getStore();
const store = this.getStore() as RedisStore;
await store.client.bf.add(key, value);
}
async mAdd(key: string, values: string[]) {
const store = this.getStore();
const store = this.getStore() as RedisStore;
await store.client.bf.mAdd(key, values);
}
async exists(key: string, value: string) {
const store = this.getStore();
const store = this.getStore() as RedisStore;
return await store.client.bf.exists(key, value);
}
}

View File

@ -1,13 +1,3 @@
import { Plugin } from '@tachybase/client';
import KitApprovalConfiguration from './configuration/plugin';
import { KitApprovalUsage } from './usage/plugin';
export default class PluginApproval extends Plugin {
async afterAdd() {
this.pm.add(KitApprovalConfiguration);
this.pm.add(KitApprovalUsage);
}
async beforeLoad() {}
async load() {}
}
export default class PluginApproval extends Plugin {}

View File

@ -1,46 +1,5 @@
import path from 'path';
import WorkflowPlugin from '@tachybase/plugin-workflow';
import { Plugin } from '@tachybase/server';
import { init } from './actions';
import ApprovalInstruction from './ApprovalInstruction';
import ApprovalTrigger from './ApprovalTrigger';
export class PluginWorkflowApproval extends Plugin {
workflow;
afterAdd() {}
beforeLoad() {
this.app.on('afterLoadPlugin', (plugin) => {
if (!(plugin instanceof WorkflowPlugin)) {
return;
}
this.workflow = plugin;
plugin.triggers.register('approval', new ApprovalTrigger(plugin));
plugin.instructions.register('approval', new ApprovalInstruction(plugin));
});
}
async load() {
const { db } = this;
db.addMigrations({
namespace: 'approval',
directory: path.resolve(__dirname, 'migrations'),
context: {
plugin: this,
},
});
await db.import({
directory: path.resolve(__dirname, 'collections'),
});
init(this);
this.app.acl.allow('workflows', ['listApprovalFlows'], 'loggedIn');
this.app.acl.allow('approvals', '*', 'loggedIn');
this.app.acl.allow('approvalExecutions', ['get'], 'loggedIn');
this.app.acl.allow('approvalRecords', ['get', 'list', 'listCentralized', 'submit'], 'loggedIn');
}
async install(options) {}
async afterEnable() {}
async afterDisable() {}
async remove() {}
}
export class PluginWorkflowApproval extends Plugin {}
export default PluginWorkflowApproval;

View File

@ -1,10 +0,0 @@
// 1. 拆解 refined 文件, 根据归类原则
// 2. 反编译文件
// 3. 根据功能进行归类, 根据就近原则
## 1. 拆解 refined 文件, 根据归类原则
// 完成
## 2. 反编译文件
// 正在进行中
// 备份代码, 可查看标签 backup-dev-20240527-departments
## 3. 根据功能进行归类, 根据就近原则

View File

@ -1,8 +1,6 @@
import React, { Fragment, useContext, useEffect, useMemo } from 'react';
import React, { useContext, useEffect, useMemo } from 'react';
import { SchemaComponent, useResourceActionContext } from '@tachybase/client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { useTranslation } from '../../../locale';
import { DepartmentsContext } from '../context/DepartmentsContext';
import { useBulkRemoveMembersAction } from '../hooks/useBulkRemoveMembersAction';
@ -15,7 +13,7 @@ import { schemaZe } from '../schema/schemaZe';
import { useFilterActionPropsZ } from '../scopes/useFilterActionPropsZ';
import { AddMembers } from './AddMembers';
import { DepartmentFieldYe } from './DepartmentFieldYe';
import { IsOwnerFieldQe } from './IsOwnerFieldQe';
import { IsOwnerField } from './IsOwnerField';
import { UserDepartmentsFieldOot } from './UserDepartmentsFieldOot';
export const ComponentIit = () => {
@ -58,39 +56,11 @@ export const ComponentIit = () => {
AddMembers: AddMembers,
RowRemoveAction: RowRemoveAction,
DepartmentField: DepartmentFieldYe,
IsOwnerField: IsOwnerFieldQe,
IsOwnerField: IsOwnerField,
UserDepartmentsField: UserDepartmentsFieldOot,
}}
schema={schema}
/>
</>
);
// return jsxs(Fragment, {
// children: [
// o
// ? jsx('h2', { children: e('Search results') })
// : jsx('h2', {
// children: e((t == null ? void 0 : t.title) || 'All users'),
// }),
// jsx(SchemaComponent, {
// scope: {
// useBulkRemoveMembersAction: useBulkRemoveMembersAction,
// useMembersDataSource: useMembersDataSource,
// t: e,
// useShowTotal: useShowTotal,
// useFilterActionProps: useFilterActionPropsZ,
// },
// components: {
// MemberActions: c,
// AddMembers: AddMembersNnt,
// RowRemoveAction: i,
// DepartmentField: DepartmentFieldYe,
// IsOwnerField: IsOwnerFieldQe,
// UserDepartmentsField: UserDepartmentsFieldOot,
// },
// schema: x,
// }),
// ],
// });
};

View File

@ -1,3 +0,0 @@
import React from 'react';
export const ContextR = React.createContext({});

View File

@ -4,10 +4,10 @@ import { uid } from '@tachybase/schema';
import { DepartmentManagement } from './DepartmentManagement';
export const MmtComponent = () => {
export const DepartmentManagementComponent = () => {
return (
<SchemaComponent
components={{ DepartmentManagement: DepartmentManagement }}
components={{ DepartmentManagement }}
schema={{
type: 'void',
properties: {
@ -20,16 +20,4 @@ export const MmtComponent = () => {
}}
/>
);
// return jsx(SchemaComponent, {
// components: {
// DepartmentManagement: DepartmentManagement,
// },
// schema: {
// type: 'void',
// properties: {
// [uid()]: { type: 'void', 'x-decorator': 'CardItem', 'x-component': 'DepartmentManagement' },
// },
// },
// });
};

View File

@ -4,9 +4,9 @@ import { RolesManagerContext } from '@tachybase/plugin-acl/client';
import { useTranslation } from '../../../locale';
import { collectionDepartments } from '../collections/departments.collection';
import { useAddDepartmentsGgt } from '../hooks/useAddDepartmentsGgt';
import { useAddDepartments } from '../hooks/useAddDepartments';
import { useBulkRemoveDepartmentsYyt } from '../hooks/useBulkRemoveDepartmentsYyt';
import { useDataSourceFt } from '../hooks/useDataSourceFt';
import { useDataSource2 } from '../hooks/useDataSource2';
import { useDisabledVvt } from '../hooks/useDisabledVvt';
import { useRemoveDepartmentXxt } from '../hooks/useRemoveDepartmentXxt';
import { getSchemaDdt } from '../schema/getSchemaDdt';
@ -40,9 +40,9 @@ export const Departments = () => {
t,
useRemoveDepartment: useRemoveDepartmentXxt,
useBulkRemoveDepartments: useBulkRemoveDepartmentsYyt,
useDataSource: useDataSourceFt,
useDataSource: useDataSource2,
useDisabled: useDisabledVvt,
useAddDepartments: useAddDepartmentsGgt,
useAddDepartments,
}}
></SchemaComponent>
</CollectionProvider_deprecated>

View File

@ -10,7 +10,7 @@ import { useDepTree2 } from '../hooks/useDepTree2';
import { T } from '../others/T';
import { y } from '../others/y';
import { getDepartmentStr } from '../utils/getDepartmentStr';
import { ContextR } from './ContextR';
import { FilterKeysContext } from '../context/FilterKeysContext';
const Ze = () => ({ disabled: () => false });
export const InternalDepartmentTableRe = ({ useDisabled: e = Ze }) => {
@ -22,7 +22,7 @@ export const InternalDepartmentTableRe = ({ useDisabled: e = Ze }) => {
{ treeData: d, initData: A, loadData: b } = useDepTree2({ resource: x, resourceOf: m, params: g }),
h = useField(),
{ disabled: F } = e(),
{ hasFilter: C, expandedKeys: v, setExpandedKeys: l } = useContext(ContextR);
{ hasFilter: C, expandedKeys: v, setExpandedKeys: l } = useContext(FilterKeysContext);
useEffect(() => {
C || A(r == null ? void 0 : r.data);
}, [r, A, c, C]);

View File

@ -0,0 +1,10 @@
import React, { useContext } from 'react';
import { Checkbox, useRecord } from '@tachybase/client';
import { DepartmentsContext } from '../context/DepartmentsContext';
export const IsOwnerField = () => {
const { department } = useContext(DepartmentsContext);
const dep = useRecord().departments?.find((d) => d?.id === department?.id);
return <Checkbox.ReadPretty value={dep?.departmentsUsers.isOwner} />;
};

View File

@ -1,12 +0,0 @@
import { useContext } from 'react';
import { Checkbox, useRecord } from '@tachybase/client';
import { jsx } from 'react/jsx-runtime';
import { DepartmentsContext } from '../context/DepartmentsContext';
export const IsOwnerFieldQe = () => {
const { department: e } = useContext(DepartmentsContext),
o = (useRecord().departments || []).find((a) => (a == null ? void 0 : a.id) === (e == null ? void 0 : e.id));
return jsx(Checkbox.ReadPretty, { value: o == null ? void 0 : o.departmentsUsers.isOwner });
};

View File

@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import { CollectionProvider_deprecated, ResourceActionContext } from '@tachybase/client';
import { collectionDepartments } from '../collections/departments.collection';
import { ContextR } from './ContextR';
import { FilterKeysContext } from '../context/FilterKeysContext';
export const RequestProvider = (prop) => {
const [expandedKeys, setExpandedKeys] = useState([]);
@ -15,9 +15,9 @@ export const RequestProvider = (prop) => {
return (
<ResourceActionContext.Provider value={service}>
<CollectionProvider_deprecated collection={collectionDepartments}>
<ContextR.Provider value={{ expandedKeys, setExpandedKeys, hasFilter, setHasFilter }}>
<FilterKeysContext.Provider value={{ expandedKeys, setExpandedKeys, hasFilter, setHasFilter }}>
{prop.children}
</ContextR.Provider>
</FilterKeysContext.Provider>
</CollectionProvider_deprecated>
</ResourceActionContext.Provider>
);

View File

@ -1,4 +1,4 @@
import { Fragment, useState } from 'react';
import React, { Fragment, useState } from 'react';
import {
ActionContextProvider,
SchemaComponent,
@ -7,14 +7,14 @@ import {
useRequest,
useResourceActionContext,
} from '@tachybase/client';
import { useField, useForm } from '@tachybase/schema';
import { Field, useField, useForm } from '@tachybase/schema';
import { MoreOutlined, PlusOutlined } from '@ant-design/icons';
import { App, Button, Dropdown, Tag } from 'antd';
import { jsx, jsxs } from 'react/jsx-runtime';
import { useTranslation } from '../../../locale';
import { useDataSourceTtt } from '../hooks/useDataSourceTtt';
import { useDataSource } from '../hooks/useDataSource';
import { k } from '../others/k';
import { T } from '../others/T';
import { y } from '../others/y';
@ -23,129 +23,128 @@ import { getDepartmentStr } from '../utils/getDepartmentStr';
import { DepartmentTablePpe } from './DepartmentTablePpe';
export const UserDepartmentsFieldOot = () => {
const { modal: e, message: t } = App.useApp(),
{ t: o } = useTranslation(),
[a, r] = useState(false),
c = useRecord(),
i = useField(),
{ refresh: x } = useResourceActionContext(),
m = (l) =>
l != null && l.length
? l.map((u) => {
var f, S;
return T(y({}, u), {
isMain: (f = u.departmentsUsers) == null ? void 0 : f.isMain,
isOwner: (S = u.departmentsUsers) == null ? void 0 : S.isOwner,
title: getDepartmentStr(u),
});
})
: [],
g = useAPIClient();
const { modal, message } = App.useApp();
const { t } = useTranslation();
const [visible, setVisible] = useState(false);
const user = useRecord();
const field = useField<Field>();
const { refresh: x } = useResourceActionContext();
const m = (l) =>
l != null && l.length
? l.map((u) => {
return {
...u,
isMain: u.departmentsUsers?.isMain,
isOwner: u.departmentsUsers?.isOwner,
title: getDepartmentStr(u),
};
})
: [];
const api = useAPIClient();
useRequest(
() =>
g
.resource('users.departments', c.id)
api
.resource('users.departments', user.id)
.list({ appends: ['parent(recursively=true)'], pagination: false })
.then((l) => {
var f;
const u = m((f = l == null ? void 0 : l.data) == null ? void 0 : f.data);
i.setValue(u);
.then((result) => {
const u = m(result?.data?.data);
field.setValue(u);
}),
{ ready: c.id },
{ ready: user.id },
);
const d = () => {
const l = useAPIClient(),
u = useForm(),
{ departments: f } = u.values || {};
return {
run() {
return k(this, null, function* () {
yield l.resource('users.departments', c.id).add({ values: f.map((O) => O.id) }),
u.reset(),
i.setValue([
...i.value,
...f.map((O, $) =>
T(y({}, O), { isMain: $ === 0 && i.value.length === 0, title: getDepartmentStr(O) }),
),
]),
r(false),
x();
});
},
};
},
A = (l) => {
e.confirm({
title: o('Remove department'),
content: o('Are you sure you want to remove it?'),
onOk: () =>
k(this, null, function* () {
yield g.resource('users.departments', c.id).remove({ values: [l.id] }),
t.success(o('Deleted successfully')),
i.setValue(
i.value
.filter((u) => u.id !== l.id)
.map((u, f) => T(y({}, u), { isMain: (l.isMain && f === 0) || u.isMain })),
const useAddDepartments = () => {
const api = useAPIClient();
const form = useForm();
const { departments: f } = form.values || {};
return {
run() {
return k(this, null, function* () {
yield api.resource('users.departments', user.id).add({ values: f.map((O) => O.id) }),
form.reset(),
field.setValue([
...field.value,
...f.map((O, $) =>
T(y({}, O), { isMain: $ === 0 && field.value.length === 0, title: getDepartmentStr(O) }),
),
x();
}),
});
},
b = (l) =>
k(this, null, function* () {
yield g.resource('users').setMainDepartment({ values: { userId: c.id, departmentId: l.id } }),
t.success(o('Set successfully')),
i.setValue(i.value.map((u) => T(y({}, u), { isMain: u.id === l.id }))),
x();
}),
h = (l) =>
k(this, null, function* () {
yield g.resource('departments').setOwner({ values: { userId: c.id, departmentId: l.id } }),
t.success(o('Set successfully')),
i.setValue(i.value.map((u) => T(y({}, u), { isOwner: u.id === l.id ? true : u.isOwner }))),
x();
}),
F = (l) =>
k(this, null, function* () {
yield g.resource('departments').removeOwner({ values: { userId: c.id, departmentId: l.id } }),
t.success(o('Set successfully')),
i.setValue(i.value.map((u) => T(y({}, u), { isOwner: u.id === l.id ? false : u.isOwner }))),
x();
}),
C = (l, u) => {
switch (l) {
case 'setMain':
b(u);
break;
case 'setOwner':
h(u);
break;
case 'removeOwner':
F(u);
break;
case 'remove':
A(u);
}
},
v = () => ({ disabled: (l) => i.value.some((u) => u.id === l.id) });
]),
setVisible(false),
x();
});
},
};
};
const A = (l) => {
modal.confirm({
title: t('Remove department'),
content: t('Are you sure you want to remove it?'),
onOk: () =>
k(this, null, function* () {
yield api.resource('users.departments', user.id).remove({ values: [l.id] }),
message.success(t('Deleted successfully')),
field.setValue(
field.value
.filter((u) => u.id !== l.id)
.map((u, f) => T(y({}, u), { isMain: (l.isMain && f === 0) || u.isMain })),
),
x();
}),
});
};
const b = (l) =>
k(this, null, function* () {
yield api.resource('users').setMainDepartment({ values: { userId: user.id, departmentId: l.id } }),
message.success(t('Set successfully')),
field.setValue(field.value.map((u) => T(y({}, u), { isMain: u.id === l.id }))),
x();
});
const h = (l) =>
k(this, null, function* () {
yield api.resource('departments').setOwner({ values: { userId: user.id, departmentId: l.id } }),
message.success(t('Set successfully')),
field.setValue(field.value.map((u) => T(y({}, u), { isOwner: u.id === l.id ? true : u.isOwner }))),
x();
});
const F = (l) =>
k(this, null, function* () {
yield api.resource('departments').removeOwner({ values: { userId: user.id, departmentId: l.id } }),
message.success(t('Set successfully')),
field.setValue(field.value.map((u) => T(y({}, u), { isOwner: u.id === l.id ? false : u.isOwner }))),
x();
});
const C = (l, u) => {
switch (l) {
case 'setMain':
b(u);
break;
case 'setOwner':
h(u);
break;
case 'removeOwner':
F(u);
break;
case 'remove':
A(u);
}
};
const useDisabled = () => ({ disabled: (l) => field.value.some((u) => u.id === l.id) });
return jsxs(ActionContextProvider, {
value: { visible: a, setVisible: r },
value: { visible: visible, setVisible: setVisible },
children: [
jsxs(Fragment, {
children: [
((i == null ? void 0 : i.value) || []).map((l) =>
(field?.value || []).map((l) =>
jsxs(
Tag,
{
style: { padding: '5px 8px', background: 'transparent', marginBottom: '5px' },
children: [
jsx('span', { style: { marginRight: '5px' }, children: l.title }),
l.isMain ? jsx(Tag, { color: 'processing', bordered: false, children: o('Main') }) : '',
l.isMain ? jsx(Tag, { color: 'processing', bordered: false, children: t('Main') }) : '',
jsx(Dropdown, {
menu: {
items: [
...(l.isMain ? [] : [{ label: o('Set as main department'), key: 'setMain' }]),
{ label: o('Remove'), key: 'remove' },
...(l.isMain ? [] : [{ label: t('Set as main department'), key: 'setMain' }]),
{ label: t('Remove'), key: 'remove' },
],
onClick: ({ key: u }) => C(u, l),
},
@ -159,21 +158,22 @@ export const UserDepartmentsFieldOot = () => {
l.id,
),
),
jsx(Button, { icon: jsx(PlusOutlined, {}), onClick: () => r(true) }),
<Button key={1} icon={<PlusOutlined />} onClick={() => setVisible(true)} />,
],
}),
jsx(SchemaComponent, {
schema: schemaJe,
components: {
<SchemaComponent
key={2}
schema={schemaJe}
components={{
DepartmentTable: DepartmentTablePpe,
},
scope: {
user: c,
useDataSource: useDataSourceTtt,
useAddDepartments: d,
useDisabled: v,
},
}),
}}
scope={{
user,
useDataSource,
useAddDepartments,
useDisabled,
}}
/>,
],
});
};

View File

@ -0,0 +1,10 @@
import React from 'react';
export interface FilterKeysContextProps {
expandedKeys: any[];
setExpandedKeys: any;
hasFilter: any;
setHasFilter: any;
}
export const FilterKeysContext = React.createContext<Partial<FilterKeysContextProps>>({});

View File

@ -0,0 +1,21 @@
import { useContext } from 'react';
import { useActionContext, useAPIClient, useResourceActionContext } from '@tachybase/client';
import { RolesManagerContext } from '@tachybase/plugin-acl/client';
import { useForm } from '@tachybase/schema';
export const useAddDepartments = () => {
const { role } = useContext(RolesManagerContext);
const api = useAPIClient();
const form = useForm();
const { setVisible } = useActionContext();
const { refresh } = useResourceActionContext();
const { departments: departments } = form.values || {};
return {
async run() {
await api.resource('roles.departments', role.name).add({ values: departments.map((dep) => dep.id) });
form.reset();
setVisible(false);
refresh();
},
};
};

View File

@ -1,22 +0,0 @@
import { useContext } from 'react';
import { useActionContext, useAPIClient, useResourceActionContext } from '@tachybase/client';
import { RolesManagerContext } from '@tachybase/plugin-acl/client';
import { useForm } from '@tachybase/schema';
import { k } from '../others/k';
export const useAddDepartmentsGgt = () => {
const { role: e } = useContext(RolesManagerContext),
t = useAPIClient(),
o = useForm(),
{ setVisible: a } = useActionContext(),
{ refresh: r } = useResourceActionContext(),
{ departments: c } = o.values || {};
return {
run() {
return k(this, null, function* () {
yield t.resource('roles.departments', e.name).add({ values: c.map((x) => x.id) }), o.reset(), a(false), r();
});
},
};
};

View File

@ -0,0 +1,11 @@
import { useRequest } from '@tachybase/client';
export const useDataSource = (props) => {
const params = {
resource: 'departments',
action: 'list',
params: { appends: ['parent(recursively=true)'], sort: ['createdAt'] },
};
const service = useRequest(params, props);
return { ...service, defaultRequest: params };
};

View File

@ -0,0 +1,11 @@
import { useRequest } from '@tachybase/client';
export const useDataSource2 = (props) => {
const params = {
resource: 'departments',
action: 'list',
params: { appends: ['roles', 'parent(recursively=true)'], sort: ['createdAt'] },
};
const service = useRequest(params, props);
return { ...service, defaultRequest: params };
};

View File

@ -1,14 +0,0 @@
import { useRequest } from '@tachybase/client';
import { T } from '../others/T';
import { y } from '../others/y';
export const useDataSourceFt = (e) => {
const t = {
resource: 'departments',
action: 'list',
params: { appends: ['roles', 'parent(recursively=true)'], sort: ['createdAt'] },
},
o = useRequest(t, e);
return T(y({}, o), { defaultRequest: t });
};

View File

@ -1,14 +0,0 @@
import { useRequest } from '@tachybase/client';
import { T } from '../others/T';
import { y } from '../others/y';
export const useDataSourceTtt = (e) => {
const t = {
resource: 'departments',
action: 'list',
params: { appends: ['parent(recursively=true)'], sort: ['createdAt'] },
},
o = useRequest(t, e);
return T(y({}, o), { defaultRequest: t });
};

View File

@ -1,11 +1,11 @@
import React from 'react';
import { Plugin, SchemaComponentContext, useSchemaComponentContext } from '@tachybase/client';
import PluginACLClient from '@tachybase/plugin-acl/client';
import { PluginACLClient } from '@tachybase/plugin-acl/client';
import { tval } from '../../locale';
import { Departments } from './components/Departments';
import { DepartmentsProvider } from './components/DepartmentsProvider';
import { MmtComponent } from './components/MmtComponent';
import { DepartmentManagementComponent } from './components/DepartmentManagementComponent';
import { UserDepartmentsField } from './components/UserDepartmentsField';
import { DepartmentOwnersFieldSetting } from './settings/DepartmentOwnersFieldSetting';
import { UserDepartmentsFieldSetting } from './settings/UserDepartmentsFieldSetting';
@ -29,7 +29,7 @@ export class DepartmentsPlugin extends Plugin {
return (
<SchemaComponentContext.Provider value={{ ...context, designable: false }}>
<DepartmentsProvider>
<MmtComponent />
<DepartmentManagementComponent />
</DepartmentsProvider>
</SchemaComponentContext.Provider>
);

View File

@ -9,10 +9,10 @@ import {
import { useField } from '@tachybase/schema';
import { useTranslation } from '../../../locale';
import { ContextR } from '../components/ContextR';
import { FilterKeysContext } from '../context/FilterKeysContext';
export const useFilterActionPropsXe = () => {
const { setHasFilter, setExpandedKeys } = useContext(ContextR);
const { setHasFilter, setExpandedKeys } = useContext(FilterKeysContext);
const { t } = useTranslation();
const collection = useContext(CollectionContext);
const options = useFilterFieldOptions(collection.fields);

View File

@ -310,12 +310,21 @@ export const InternalAdminLayout = () => {
</div>
</Layout.Header>
{params.name && (
<Layout.Sider theme={'light'} ref={sideMenuRef} style={{ height: '100vh' }}>
<Layout.Sider
theme={'light'}
ref={sideMenuRef}
style={{ height: '100vh' }}
className={css`
.ant-layout-sider-children {
display: flex;
flex-direction: column;
}
`}
>
<header
className={css`
flex-shrink: 0;
height: var(--tb-header-height);
line-height: var(--tb-header-height);
width: 100%;
background: transparent;
pointer-events: none;
`}

View File

@ -3,7 +3,6 @@ import { Application } from '@tachybase/client';
import { tval } from '../locale';
import { LinkManager } from './LinkManager';
import { Configuration } from './TokenConfiguration';
import { WebhookManager } from './WebhookManager';
export * from './LinkManager';
export * from './TokenConfiguration';
@ -15,11 +14,6 @@ export class PluginSettingsHelper {
title: tval('Hera integration'),
icon: 'HomeOutlined',
});
this.app.pluginSettingsManager.add('hera.webhook', {
title: tval('Webhook manager'),
icon: 'ShareAltOutlined',
Component: WebhookManager,
});
this.app.pluginSettingsManager.add('hera.token', {
title: tval('Third-party integration configuration'),
icon: 'ShareAltOutlined',

View File

@ -5,4 +5,3 @@ export * from './link-manager-controller';
export * from './system-message-controller';
export * from './departments';
export * from './users';
export * from './webhooks';

View File

@ -3,7 +3,6 @@ import { Plugin } from '@tachybase/server';
export class GraphCollectionManagerPlugin extends Plugin {
async load() {
await this.importCollections(path.resolve(__dirname, 'collections'));
this.app.acl.allow('graphPositions', '*');
}
}

View File

@ -1,13 +1,5 @@
import { Plugin } from '@tachybase/client';
import { KitConfiguration } from './configuration/kit';
import { KitUsage } from './usage/kit';
class PluginWorkflowNoticeClient extends Plugin {
async afterAdd() {
await this.app.pm.add(KitConfiguration);
await this.app.pm.add(KitUsage);
}
}
class PluginWorkflowNoticeClient extends Plugin {}
export default PluginWorkflowNoticeClient;

View File

@ -1,49 +1,5 @@
import path from 'path';
import WorkflowPlugin from '@tachybase/plugin-workflow';
import { Plugin } from '@tachybase/server';
import { COLLECTION_NOTICE_NAME, NOTICE_INSTRUCTION_NAMESPACE } from '../common/constants';
import { init } from './actions';
import { COLLECTION_WORKFLOWS_NAME } from './collections/workflowNotice';
import NoticeInstruction from './NoticeInstruction';
export class PluginWorkflowNoticeServer extends Plugin {
workflow;
async afterAdd() {}
async beforeLoad() {
this.app.on('afterLoadPlugin', (plugin) => {
if (!(plugin instanceof WorkflowPlugin)) {
return;
}
this.workflow = plugin;
plugin.instructions.register(NOTICE_INSTRUCTION_NAMESPACE, new NoticeInstruction(plugin));
});
}
async load() {
const { db } = this;
db.addMigrations({
namespace: NOTICE_INSTRUCTION_NAMESPACE,
directory: path.resolve(__dirname, 'migrations'),
context: {
plugin: this,
},
});
await db.import({
directory: path.resolve(__dirname, 'collections'),
});
init(this);
this.app.acl.allow(COLLECTION_WORKFLOWS_NAME, ['listWorkflowNoticeFlows'], 'loggedIn');
this.app.acl.allow(COLLECTION_NOTICE_NAME, ['get', 'list', 'listCentralized', 'submit'], 'loggedIn');
}
async install() {}
async afterEnable() {}
async afterDisable() {}
async remove() {}
}
export class PluginWorkflowNoticeServer extends Plugin {}
export default PluginWorkflowNoticeServer;

View File

@ -17,11 +17,14 @@
},
"devDependencies": {
"@ant-design/icons": "~5.3.7",
"@codemirror/autocomplete": "^6.16.2",
"@codemirror/lang-javascript": "^6.2.2",
"@tachybase/components": "workspace:*",
"@tachybase/plugin-workflow-test": "workspace:*",
"@types/ejs": "^3.1.1",
"@types/file-saver": "^2.0.7",
"@types/lodash": "^4.17.5",
"@uiw/react-codemirror": "^4.22.2",
"antd": "5.18.1",
"axios": "^1.6.2",
"cron-parser": "4.4.0",

View File

@ -6,6 +6,7 @@ import { ExecutionPage } from './ExecutionPage';
import { PluginActionTrigger } from './features/action-trigger';
import { PluginAggregate } from './features/aggregate';
import { PluginAPIRegularClient } from './features/api-regular';
import PluginApproval from './features/approval';
import { PluginDelay } from './features/delay';
import { PluginDaynamicCalculation } from './features/dynamic-calculation';
import { PluginWorkflowInterceptor } from './features/interceptor';
@ -13,6 +14,7 @@ import PluginWorkflowJSParseClient from './features/js-parse';
import PluginWorkflowJsonParseClient from './features/json-parse';
import { PluginLoop } from './features/loop';
import { PluginManual } from './features/manual';
import PluginWorkflowNoticeClient from './features/notice';
import { PluginOmniTrigger } from './features/omni-trigger';
import { PluginParallel } from './features/parallel';
import { PluginRequest } from './features/request';
@ -20,6 +22,7 @@ import { PluginResponse } from './features/response';
import { PluginSql } from './features/sql';
import { PluginTriggerInstruction } from './features/trigger-instruction/plugin';
import { PluginVariables } from './features/variables';
import { PluginWebhook } from './features/webhook/plugin';
import { NAMESPACE } from './locale';
import { Instruction } from './nodes';
import CalculationInstruction from './nodes/calculation';
@ -91,6 +94,9 @@ export class PluginWorkflow extends Plugin {
await this.pm.add(PluginResponse);
await this.pm.add(PluginOmniTrigger);
await this.pm.add(PluginTriggerInstruction);
await this.pm.add(PluginApproval);
await this.pm.add(PluginWorkflowNoticeClient);
await this.pm.add(PluginWebhook);
}
async load() {

View File

@ -0,0 +1,95 @@
import React from 'react';
import { connect } from '@tachybase/schema';
import { autocompletion } from '@codemirror/autocomplete';
import { javascript } from '@codemirror/lang-javascript';
import CM from '@uiw/react-codemirror';
// 定义全局对象和子对象的补全项
const globalVariables = [
{
label: 'ctx',
type: 'variable',
info: 'Global context object',
apply: (view, completion, from, to) => {
view.dispatch({
changes: { from, to, insert: completion.label },
selection: { anchor: from + completion.label.length },
});
},
},
];
const ctxProperties = [
{ label: 'body', type: 'variable', info: 'pass to workflow or response to user' },
{ label: 'request', type: 'variable', info: 'ctx.request' },
{ label: 'action', type: 'variable', info: 'ctx.action' },
];
const requestProperties = [
{ label: 'header', type: 'variable', info: 'ctx.request.header' },
{ label: 'query', type: 'variable', info: 'ctx.request.query' },
{ label: 'body', type: 'variable', info: 'ctx.request.body' },
{ label: 'method', type: 'variable', info: 'ctx.request.method' },
];
const actionProperties = [
{ label: 'filter', type: 'variable', info: 'ctx.action.filter' },
{ label: 'fields', type: 'variable', info: 'ctx.action.fields' },
{ label: 'except', type: 'variable', info: 'ctx.action.except' },
{ label: 'appends', type: 'variable', info: 'ctx.action.appends' },
{ label: 'sort', type: 'variable', info: 'ctx.action.sort' },
{ label: 'paginate', type: 'variable', info: 'ctx.action.paginate' },
{ label: 'page', type: 'variable', info: 'ctx.action.page' },
{ label: 'pageSize', type: 'variable', info: 'ctx.action.pageSize' },
];
const completionSource = (context) => {
const word = context.matchBefore(/\w*/);
if (word.from === word.to && !context.explicit) return null;
if (context.state.sliceDoc(word.from - 4, word.from) === 'ctx.') {
return {
from: word.from,
options: ctxProperties,
validFor: /^\w*$/,
};
} else if (context.state.sliceDoc(word.from - 8, word.from) === 'ctx.request.') {
return {
from: word.from,
options: requestProperties,
validFor: /^\w*$/,
};
} else if (context.state.sliceDoc(word.from - 7, word.from) === 'ctx.action.') {
return {
from: word.from,
options: actionProperties,
validFor: /^\w*$/,
};
} else if (context.explicit && word.text.length === 0) {
return {
from: word.from,
options: globalVariables,
validFor: /^\w*$/,
};
}
return null;
};
export const CodeMirror = connect(({ value, onChange, ...otherProps }) => {
return (
<CM
value={value || ''}
onChange={onChange}
{...otherProps}
extensions={[
javascript({ jsx: true }),
autocompletion({
override: [completionSource],
}),
]}
height="300px"
></CM>
);
});

View File

@ -1,9 +1,12 @@
import React from 'react';
import { useCompile } from '@tachybase/client';
import { Branch, NodeDefaultView, useFlowContext, useStyles } from '@tachybase/plugin-workflow/client';
import { Tag } from 'antd';
import { Branch } from '../../../../Branch';
import { useFlowContext } from '../../../../FlowContext';
import { NodeDefaultView } from '../../../../nodes';
import useStyles from '../../../../style';
import { APPROVAL_ACTION_STATUS, approvalStatusConfigObj } from '../../constants';
// 审批节点组件

View File

@ -1,10 +1,10 @@
import React, { useCallback, useState } from 'react';
import { ArrayItems } from '@tachybase/components';
import { useWorkflowExecuted } from '@tachybase/plugin-workflow/client';
import { PlusOutlined } from '@ant-design/icons';
import { Button, Popover, Space } from 'antd';
import { useWorkflowExecuted } from '../../../../../hooks';
import { useTranslation } from '../../../locale';
// 添加审批人(选择/查询)

View File

@ -1,8 +1,10 @@
import { default as React } from 'react';
import { RemoteSelect, SchemaComponent, useCollectionFilterOptions, useToken, Variable } from '@tachybase/client';
import { FilterDynamicComponent, useWorkflowVariableOptions } from '@tachybase/plugin-workflow/client';
import { useField } from '@tachybase/schema';
import { FilterDynamicComponent } from '../../../../../components';
import { useWorkflowVariableOptions } from '../../../../../variable';
// 添加审批人-选择器
export const AssigneesSelect = (props) => {
if (typeof props.value === 'object' && props.value) {

View File

@ -1,11 +1,9 @@
import { gridRowColWrap, SchemaInitializer, usePlugin } from '@tachybase/client';
import PluginWorkflow, {
useAvailableUpstreams,
useFlowContext,
useNodeContext,
useTrigger,
} from '@tachybase/plugin-workflow/client';
import { useFlowContext } from '../../../../../FlowContext';
import { useAvailableUpstreams, useNodeContext } from '../../../../../nodes';
import { PluginWorkflow } from '../../../../../Plugin';
import { useTrigger } from '../../../../../triggers';
import { NAMESPACE } from '../../../locale';
import { ApproverAddBlockComponent } from './VC.ApproverAddBlock';
import { ApproverAddBlockKit } from './VC.ApproverAddBlockKit';

View File

@ -8,10 +8,11 @@ import {
useSchemaInitializerItem,
useSchemaTemplateManager,
} from '@tachybase/client';
import { useFlowContext } from '@tachybase/plugin-workflow/client';
import _ from 'lodash';
import { useFlowContext } from '../../../../../FlowContext';
export const ApproverAddBlockComponent = () => {
const { workflow } = useFlowContext();
const [dataSourceName, collection] = parseCollectionName(workflow.config.collection);

View File

@ -1,11 +1,11 @@
import { default as React, useCallback, useContext } from 'react';
import { SchemaComponent, useAPIClient, useFormBlockContext, useRequest } from '@tachybase/client';
import { DetailsBlockProvider, SimpleDesigner } from '@tachybase/plugin-workflow/client';
import { useForm } from '@tachybase/schema';
import { uid } from '@tachybase/utils/client';
import { Spin } from 'antd';
import { DetailsBlockProvider, SimpleDesigner } from '../../../../../components';
import { FormBlockProvider } from '../../../common/Pd.FormBlock';
import { flatSchemaArray } from '../../../constants';
import { ContextApproverConfig } from '../Pd.ContextApproverConfig';

View File

@ -6,9 +6,9 @@ import {
SchemaComponent,
SchemaComponentContext,
} from '@tachybase/client';
import { useFlowContext } from '@tachybase/plugin-workflow/client';
import { uid } from '@tachybase/utils/client';
import { useFlowContext } from '../../../../../FlowContext';
import { CollectionApprovalTodos } from '../../../common/Cn.ApprovalTodos';
import { NAMESPACE } from '../../../locale';
import { ApproverBlock } from './VC.ApproverBlock';

View File

@ -1,9 +1,10 @@
import React from 'react';
import { css } from '@tachybase/client';
import { ArrayItems } from '@tachybase/components';
import { Instruction, RadioWithTooltip } from '@tachybase/plugin-workflow/client';
import { uid } from '@tachybase/utils/client';
import { RadioWithTooltip } from '../../../../components';
import { Instruction } from '../../../../nodes';
import { APPROVAL_ACTION_STATUS } from '../../constants';
import { NAMESPACE } from '../../locale';
import { AssigneesAddition } from './approval-config/VC.AssigneesAddition';

View File

@ -1,6 +1,6 @@
import { Plugin } from '@tachybase/client';
import PluginWorkflow from '@tachybase/plugin-workflow/client';
import { PluginWorkflow } from '../../../../Plugin';
import { ApproverActionConfigInitializer } from './approver-interface/Iz.ApproverActionConfig';
import { ApproverAddBlockInitializer } from './approver-interface/Iz.ApproverAddBlock';
import { ApprovalInstruction } from './node.ApprovalInstruction';

View File

@ -1,14 +1,10 @@
import { SchemaInitializerItemType, useCollectionManager_deprecated, useCompile } from '@tachybase/client';
import {
CollectionBlockInitializer,
getCollectionFieldOptions,
RadioWithTooltip,
Trigger,
UseVariableOptions,
useWorkflowAnyExecuted,
} from '@tachybase/plugin-workflow/client';
import { useForm } from '@tachybase/schema';
import { CollectionBlockInitializer, RadioWithTooltip } from '../../../../components';
import { useWorkflowAnyExecuted } from '../../../../hooks';
import { Trigger } from '../../../../triggers';
import { getCollectionFieldOptions, UseVariableOptions } from '../../../../variable';
import { NAMESPACE, tval, usePluginTranslation } from '../../locale';
import { ConfigButtonView } from './ConfigButton.view';
import { LauncherInterface } from './launcher-interface/LauncherInterface.schema';

View File

@ -7,11 +7,12 @@ import {
useFormBlockProps,
useRequest,
} from '@tachybase/client';
import { useFlowContext } from '@tachybase/plugin-workflow/client';
import { uid } from '@tachybase/utils/client';
import { Spin } from 'antd';
import { useFlowContext } from '../../../../../FlowContext';
// 发起人操作界面-创建区块
export const SchemaAddBlock = ({ value, onChange }) => {
const api = useAPIClient();

View File

@ -1,6 +1,6 @@
import { Plugin } from '@tachybase/client';
import PluginWorkflow from '@tachybase/plugin-workflow/client';
import { PluginWorkflow } from '../../../../Plugin';
import { ApprovalTrigger } from './Approval.trigger';
import { LauncherActionConfigInitializer } from './launcher-interface/LauncherActionConfig.initializer';
import { LauncherAddBlockButtonIntializer } from './launcher-interface/LauncherAddBlockButton.initializer';

View File

@ -1,5 +1,4 @@
import { JOB_STATUS } from '@tachybase/plugin-workflow/client';
import { JOB_STATUS } from '../../constants';
import { lang, NAMESPACE } from './locale';
// 审批状态

View File

@ -0,0 +1,15 @@
import { Plugin } from '@tachybase/client';
import KitApprovalConfiguration from './configuration/plugin';
import { KitApprovalUsage } from './usage/plugin';
export class PluginApproval extends Plugin {
async afterAdd() {
this.pm.add(KitApprovalConfiguration);
this.pm.add(KitApprovalUsage);
}
async beforeLoad() {}
async load() {}
}
export default PluginApproval;

View File

@ -1,6 +1,6 @@
import { i18n, tval as nTval } from '@tachybase/client';
export const NAMESPACE = '@hera/plugin-approval';
export const NAMESPACE = 'workflow';
export function usePluginTranslation(): any {
return useTranslation();

View File

@ -1,9 +1,6 @@
import React, { useContext } from 'react';
import { FlowContext } from '@tachybase/plugin-workflow/client';
import React from 'react';
export function useFlowContext() {
return useContext(FlowContext);
}
import { FlowContext } from '../../../../../FlowContext';
export function FlowContextProvider({ workflow = undefined, children, value }) {
return <FlowContext.Provider value={{ workflow, ...value }}>{children}</FlowContext.Provider>;

View File

@ -1,7 +1,7 @@
import React, { createContext, useContext } from 'react';
import { useCurrentUserContext } from '@tachybase/client';
import { useFlowContext } from '@tachybase/plugin-workflow/client';
import { useFlowContext } from '../../../../../FlowContext';
import { APPROVAL_STATUS } from '../../../constants';
import { useApproval } from '../../approval-common/ApprovalData.provider';

View File

@ -1,6 +1,6 @@
import { useCurrentUserContext } from '@tachybase/client';
import { useFlowContext } from '@tachybase/plugin-workflow/client';
import { useFlowContext } from '../../../../../FlowContext';
import { APPROVAL_STATUS } from '../../../constants';
import { useApproval } from '../../approval-common/ApprovalData.provider';

View File

@ -7,11 +7,11 @@ import {
useRecord,
useRequest,
} from '@tachybase/client';
import { DetailsBlockProvider, FlowContext } from '@tachybase/plugin-workflow/client';
import { useForm } from '@tachybase/schema';
import { Result, Spin } from 'antd';
import { DetailsBlockProvider } from '../../../../../components';
import { FormBlockProvider } from '../../../common/Pd.FormBlock';
import { NAMESPACE } from '../../../locale';
import { ApprovalContext } from '../../approval-common/ApprovalData.provider';

View File

@ -5,9 +5,9 @@ import {
useBlockRequestContext,
useCollection_deprecated,
} from '@tachybase/client';
import { useFlowContext } from '@tachybase/plugin-workflow/client';
import { useField, useForm } from '@tachybase/schema';
import { useFlowContext } from '../../../../../../../FlowContext';
import { useContextApprovalStatus } from '../Pd.ActionStatus';
export function useSubmit() {

View File

@ -1,8 +1,8 @@
import { useEffect } from 'react';
import { useCurrentUserContext } from '@tachybase/client';
import { useFlowContext } from '@tachybase/plugin-workflow/client';
import { useForm } from '@tachybase/schema';
import { useFlowContext } from '../../../../../../FlowContext';
import { ApprovalStatusEnumDict } from '../../../../constants';
import { useApproval } from '../../../approval-common/ApprovalData.provider';
import { useContextApprovalExecution } from '../../common/ApprovalExecution.provider';

View File

@ -1,9 +1,9 @@
import { useActionContext, useAPIClient } from '@tachybase/client';
import { useFlowContext } from '@tachybase/plugin-workflow/client';
import { useField, useForm } from '@tachybase/schema';
import _ from 'lodash';
import { useFlowContext } from '../../../../../../FlowContext';
import { useApproval } from '../../../approval-common/ApprovalData.provider';
import { useContextApprovalStatus } from '../Pd.ApplyActionStatus';

View File

@ -11,11 +11,11 @@ import {
useCurrentUserContext,
useDesignable,
} from '@tachybase/client';
import { useFlowContext } from '@tachybase/plugin-workflow/client';
import { createForm, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
import _ from 'lodash';
import { useFlowContext } from '../../../../../FlowContext';
import { useContextApprovalExecutions } from './Pd.ApprovalExecutions';
export function ApprovalFormBlockDecorator(props) {

Some files were not shown because too many files have changed in this diff Show More