feat/feat-apiselected (#1132)
Reviewed-on: daoyoucloud/tachybase#1132 Co-authored-by: bai.zixv <bai.zixv@foxmail.com> Co-committed-by: bai.zixv <bai.zixv@foxmail.com>
This commit is contained in:
parent
6df452378f
commit
03a1dfdf1e
@ -32,17 +32,17 @@ export const ActionAreaStub = () => {
|
|||||||
|
|
||||||
export const ActionAreaPlayer = ({ children }) => {
|
export const ActionAreaPlayer = ({ children }) => {
|
||||||
const { visible, setVisible } = useActionContext();
|
const { visible, setVisible } = useActionContext();
|
||||||
const { prevSetVisible, setPrevSetVisible, ref } = useContext(ActionAreaContext);
|
const { prevSetVisible, setPrevSetVisible, ref = { current: null } } = useContext(ActionAreaContext);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
setPrevSetVisible(() => {
|
setPrevSetVisible?.(() => {
|
||||||
prevSetVisible?.(false);
|
prevSetVisible?.(false);
|
||||||
return setVisible;
|
return setVisible;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [visible]);
|
}, [visible]);
|
||||||
|
|
||||||
return visible ? createPortal(children, ref.current) : null;
|
return visible && ref.current ? createPortal(children, ref.current) : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ActionArea: ComposedActionDrawer = observer(
|
export const ActionArea: ComposedActionDrawer = observer(
|
||||||
|
@ -19,9 +19,9 @@ const schema = {
|
|||||||
'x-acl-action-props': {
|
'x-acl-action-props': {
|
||||||
skipScopeCheck: true,
|
skipScopeCheck: true,
|
||||||
},
|
},
|
||||||
'x-action': 'customize:APIRegular',
|
|
||||||
'x-toolbar': 'ActionSchemaToolbar',
|
'x-toolbar': 'ActionSchemaToolbar',
|
||||||
'x-settings': 'actionSettings:APIRegular',
|
'x-settings': 'actionSettings:APIRegular',
|
||||||
|
'x-action': 'customize:APIRegular',
|
||||||
'x-action-settings': {
|
'x-action-settings': {
|
||||||
bindWorkflow: false,
|
bindWorkflow: false,
|
||||||
updateMode: 'selected',
|
updateMode: 'selected',
|
||||||
|
@ -54,6 +54,12 @@ export const usePropsAPIRegular = () => {
|
|||||||
updateMode,
|
updateMode,
|
||||||
} = actionSchema?.['x-action-settings'] ?? {};
|
} = actionSchema?.['x-action-settings'] ?? {};
|
||||||
|
|
||||||
|
const isUpdateSelected = updateMode === 'selected';
|
||||||
|
const updateData = {
|
||||||
|
primaryKey: rowKey || 'id',
|
||||||
|
targetKeys: selectedRecordKeys,
|
||||||
|
};
|
||||||
|
|
||||||
actionField.data = field.data || {};
|
actionField.data = field.data || {};
|
||||||
actionField.data.loading = true;
|
actionField.data.loading = true;
|
||||||
|
|
||||||
@ -86,15 +92,14 @@ export const usePropsAPIRegular = () => {
|
|||||||
await Promise.all(waitList);
|
await Promise.all(waitList);
|
||||||
|
|
||||||
modal.confirm({
|
modal.confirm({
|
||||||
title: lang('Bulk update', { ns: 'client' }),
|
title: lang('Confirm', { ns: 'client' }),
|
||||||
content:
|
content: lang('Trigger workflow?', { ns: 'client' }),
|
||||||
updateMode === 'selected'
|
|
||||||
? lang('Update selected data?', { ns: 'client' })
|
|
||||||
: lang('Update all data?', { ns: 'client' }),
|
|
||||||
async onOk() {
|
async onOk() {
|
||||||
run({
|
const params = {
|
||||||
filterByTk: bindWorkflow,
|
filterByTk: bindWorkflow,
|
||||||
});
|
updateData: encodeURIComponent(JSON.stringify(updateData)),
|
||||||
|
};
|
||||||
|
run(params);
|
||||||
actionField.data.loading = false;
|
actionField.data.loading = false;
|
||||||
},
|
},
|
||||||
async onCancel() {
|
async onCancel() {
|
||||||
@ -104,21 +109,3 @@ export const usePropsAPIRegular = () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateData() {
|
|
||||||
// const updateData: { filter?: any; values: any; forceUpdate: boolean } = {
|
|
||||||
// values,
|
|
||||||
// filter,
|
|
||||||
// forceUpdate: false,
|
|
||||||
// };
|
|
||||||
// if (updateMode === 'selected') {
|
|
||||||
// if (!selectedRecordKeys?.length) {
|
|
||||||
// message.error(t('Please select the records to be updated'));
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// updateData.filter = { $and: [{ [rowKey || 'id']: { $in: selectedRecordKeys } }] };
|
|
||||||
// }
|
|
||||||
// if (!updateData.filter) {
|
|
||||||
// updateData.forceUpdate = true;
|
|
||||||
// }
|
|
||||||
}
|
|
@ -2,8 +2,8 @@ import { Plugin, useCollection } from '@tachybase/client';
|
|||||||
|
|
||||||
import { tval } from '../../../locale';
|
import { tval } from '../../../locale';
|
||||||
import { APIRegularInitializer } from './APIRegular.schema';
|
import { APIRegularInitializer } from './APIRegular.schema';
|
||||||
import { APIRegularActionSettings } from './BulkUpdateAction.Settings';
|
import { APIRegularActionSettings } from './APIRegular.setting';
|
||||||
import { usePropsAPIRegular } from './utils';
|
import { usePropsAPIRegular } from './hooks';
|
||||||
|
|
||||||
export class KitAPIRegularUsage extends Plugin {
|
export class KitAPIRegularUsage extends Plugin {
|
||||||
async load() {
|
async load() {
|
||||||
|
@ -77,7 +77,8 @@ function useUpdateAction() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
ctx.setFormValueChanged(false);
|
ctx.setFormValueChanged(false);
|
||||||
ctx.setVisible(false);
|
// ctx.setVisible(false);
|
||||||
|
message.success('success');
|
||||||
refresh();
|
refresh();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -410,7 +411,7 @@ export function NodeDefaultView(props) {
|
|||||||
? null
|
? null
|
||||||
: {
|
: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Action.Drawer.Footer',
|
'x-component': 'ActionArea.Footer',
|
||||||
properties: {
|
properties: {
|
||||||
cancel: {
|
cancel: {
|
||||||
title: '{{t("Cancel")}}',
|
title: '{{t("Cancel")}}',
|
||||||
|
@ -42,6 +42,7 @@ const useStyles = createStyles(({ css, token }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.workflow-operator-area {
|
.workflow-operator-area {
|
||||||
|
overflow-y: scroll;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
width: 800px;
|
width: 800px;
|
||||||
|
@ -46,7 +46,8 @@ function useUpdateConfigAction() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
ctx.setFormValueChanged(false);
|
ctx.setFormValueChanged(false);
|
||||||
ctx.setVisible(false);
|
// ctx.setVisible(false);
|
||||||
|
message.success('success');
|
||||||
refresh();
|
refresh();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -298,7 +299,7 @@ export const TriggerConfig = () => {
|
|||||||
? {}
|
? {}
|
||||||
: {
|
: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Action.Drawer.Footer',
|
'x-component': 'ActionArea.Footer',
|
||||||
properties: {
|
properties: {
|
||||||
cancel: {
|
cancel: {
|
||||||
title: '{{t("Cancel")}}',
|
title: '{{t("Cancel")}}',
|
||||||
|
@ -164,10 +164,17 @@ export async function sync(context: Context, next) {
|
|||||||
export async function trigger(ctx: Context) {
|
export async function trigger(ctx: Context) {
|
||||||
const plugin = ctx.app.getPlugin(Plugin) as Plugin;
|
const plugin = ctx.app.getPlugin(Plugin) as Plugin;
|
||||||
const workflow = (await ctx.db.getRepository('workflows').findById(ctx.action.params.filterByTk)) as WorkflowModel;
|
const workflow = (await ctx.db.getRepository('workflows').findById(ctx.action.params.filterByTk)) as WorkflowModel;
|
||||||
|
// NOTE: 这里的updateData是通过前端传过来的,需要 decodeURIComponent,
|
||||||
|
// updateData 的约定结构是形如: updateData: { primaryKey: "id", targetKeys: []}
|
||||||
|
const updateData = JSON.parse(decodeURIComponent(ctx.action.params?.updateData || ''));
|
||||||
plugin.trigger(
|
plugin.trigger(
|
||||||
workflow,
|
workflow,
|
||||||
{
|
{
|
||||||
data: {},
|
data: {
|
||||||
|
updateData,
|
||||||
|
httpContext: ctx,
|
||||||
|
user: ctx?.auth?.user,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{ httpContext: ctx },
|
{ httpContext: ctx },
|
||||||
);
|
);
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { get } from 'lodash';
|
import { Context as ActionContext, Next } from '@tachybase/actions';
|
||||||
import { BelongsTo, HasOne } from 'sequelize';
|
import { parseCollectionName } from '@tachybase/data-source-manager';
|
||||||
import { Model, modelAssociationByKey } from '@tachybase/database';
|
import { Model, modelAssociationByKey } from '@tachybase/database';
|
||||||
import Application, { DefaultContext } from '@tachybase/server';
|
import Application, { DefaultContext } from '@tachybase/server';
|
||||||
import { Context as ActionContext, Next } from '@tachybase/actions';
|
|
||||||
|
|
||||||
import WorkflowPlugin, { Trigger, WorkflowModel, toJSON } from '../..';
|
import { get } from 'lodash';
|
||||||
import { parseCollectionName } from '@tachybase/data-source-manager';
|
import { BelongsTo, HasOne } from 'sequelize';
|
||||||
|
|
||||||
|
import WorkflowPlugin, { toJSON, Trigger, WorkflowModel } from '../..';
|
||||||
|
|
||||||
interface Context extends ActionContext, DefaultContext {}
|
interface Context extends ActionContext, DefaultContext {}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ interface Context extends ActionContext, DefaultContext {}
|
|||||||
export class APIRegularTrigger extends Trigger {
|
export class APIRegularTrigger extends Trigger {
|
||||||
constructor(workflow: WorkflowPlugin) {
|
constructor(workflow: WorkflowPlugin) {
|
||||||
super(workflow);
|
super(workflow);
|
||||||
workflow.app.use(this.middleware, { after: 'dataSource' });
|
// workflow.app.use(this.middleware, { after: 'dataSource' });
|
||||||
}
|
}
|
||||||
|
|
||||||
async middleware(context: Context, next: Next) {
|
async middleware(context: Context, next: Next) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import axios, { AxiosRequestConfig } from 'axios';
|
import axios, { AxiosRequestConfig } from 'axios';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
import { FlowNodeModel, Instruction, JOB_STATUS, Processor } from '../..';
|
import { FlowNodeModel, Instruction, JOB_STATUS, Processor } from '../..';
|
||||||
|
|
||||||
@ -12,10 +13,14 @@ export type RequestConfig = Pick<AxiosRequestConfig, 'url' | 'method' | 'params'
|
|||||||
ignoreFail: boolean;
|
ignoreFail: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function request(config) {
|
async function request(config, context) {
|
||||||
// default headers
|
// default headers
|
||||||
const { url, method = 'POST', data, timeout = 5000 } = config;
|
const { token, origin } = context;
|
||||||
const headers = (config.headers ?? []).reduce((result, header) => {
|
const { url: originUrl, method = 'POST', data, timeout = 5000 } = config;
|
||||||
|
|
||||||
|
const url = originUrl.startsWith('http') ? originUrl : `${origin}${originUrl}`;
|
||||||
|
|
||||||
|
let headers = (config.headers ?? []).reduce((result, header) => {
|
||||||
if (header.name.toLowerCase() === 'content-type') {
|
if (header.name.toLowerCase() === 'content-type') {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -29,6 +34,11 @@ async function request(config) {
|
|||||||
// TODO(feat): only support JSON type for now, should support others in future
|
// TODO(feat): only support JSON type for now, should support others in future
|
||||||
headers['Content-Type'] = 'application/json';
|
headers['Content-Type'] = 'application/json';
|
||||||
|
|
||||||
|
// let temp = context.get('headers');
|
||||||
|
headers = {
|
||||||
|
Authorization: 'Bearer ' + token,
|
||||||
|
...headers,
|
||||||
|
};
|
||||||
return axios.request({
|
return axios.request({
|
||||||
url,
|
url,
|
||||||
method,
|
method,
|
||||||
@ -41,13 +51,19 @@ async function request(config) {
|
|||||||
|
|
||||||
export default class extends Instruction {
|
export default class extends Instruction {
|
||||||
async run(node: FlowNodeModel, prevJob, processor: Processor) {
|
async run(node: FlowNodeModel, prevJob, processor: Processor) {
|
||||||
|
const httpContext = _.get(processor, 'execution.dataValues.context.data.httpContext', {});
|
||||||
|
const userId = _.get(processor, 'execution.dataValues.context.data.user.id', 1);
|
||||||
|
const origin = _.get(httpContext, 'request.header.origin', '');
|
||||||
|
const token = this.workflow.app.authManager.jwt.sign({ userId });
|
||||||
|
const context = { token, origin };
|
||||||
|
|
||||||
const config = processor.getParsedValue(node.config, node.id) as RequestConfig;
|
const config = processor.getParsedValue(node.config, node.id) as RequestConfig;
|
||||||
const { workflow } = processor.execution;
|
const { workflow } = processor.execution;
|
||||||
const sync = this.workflow.isWorkflowSync(workflow);
|
const sync = this.workflow.isWorkflowSync(workflow);
|
||||||
|
|
||||||
if (sync) {
|
if (sync) {
|
||||||
try {
|
try {
|
||||||
const response = await request(config);
|
const response = await request(config, context);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: JOB_STATUS.RESOLVED,
|
status: JOB_STATUS.RESOLVED,
|
||||||
@ -69,7 +85,7 @@ export default class extends Instruction {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// eslint-disable-next-line promise/catch-or-return
|
// eslint-disable-next-line promise/catch-or-return
|
||||||
request(config)
|
request(config, context)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
job.set({
|
job.set({
|
||||||
status: JOB_STATUS.RESOLVED,
|
status: JOB_STATUS.RESOLVED,
|
||||||
|
Loading…
Reference in New Issue
Block a user