feat(plugin-workflow): add sort and pagination to query node params (#2453)
* refactor(core): expose some utils and constants * feat(plugin-workfow): add sort and pagination to query node params * fix(plugin-workflow): fix job result json style * fix(plugin-workflow): fix sort param * fix(plugin-workflow): fix test cases
This commit is contained in:
		
							parent
							
								
									3baebf2a71
								
							
						
					
					
						commit
						dea4c6f9c7
					
				@ -1,22 +1,7 @@
 | 
				
			|||||||
import { assign } from '@nocobase/utils';
 | 
					import { assign } from '@nocobase/utils';
 | 
				
			||||||
import { Context } from '..';
 | 
					import { Context } from '..';
 | 
				
			||||||
import { getRepositoryFromParams } from '../utils';
 | 
					import { getRepositoryFromParams, pageArgsToLimitArgs } from '../utils';
 | 
				
			||||||
 | 
					import { DEFAULT_PAGE, DEFAULT_PER_PAGE } from '../constants';
 | 
				
			||||||
export const DEFAULT_PAGE = 1;
 | 
					 | 
				
			||||||
export const DEFAULT_PER_PAGE = 20;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function pageArgsToLimitArgs(
 | 
					 | 
				
			||||||
  page: number,
 | 
					 | 
				
			||||||
  pageSize: number,
 | 
					 | 
				
			||||||
): {
 | 
					 | 
				
			||||||
  offset: number;
 | 
					 | 
				
			||||||
  limit: number;
 | 
					 | 
				
			||||||
} {
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    offset: (page - 1) * pageSize,
 | 
					 | 
				
			||||||
    limit: pageSize,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
function totalPage(total, pageSize): number {
 | 
					function totalPage(total, pageSize): number {
 | 
				
			||||||
  return Math.ceil(total / pageSize);
 | 
					  return Math.ceil(total / pageSize);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								packages/core/actions/src/constants.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								packages/core/actions/src/constants.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					export const DEFAULT_PAGE = 1;
 | 
				
			||||||
 | 
					export const DEFAULT_PER_PAGE = 20;
 | 
				
			||||||
@ -7,6 +7,8 @@ import * as actions from './actions';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export * as utils from './utils';
 | 
					export * as utils from './utils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export * from './constants';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type Next = () => Promise<any>;
 | 
					export type Next = () => Promise<any>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface Context extends Koa.Context {
 | 
					export interface Context extends Koa.Context {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,19 @@
 | 
				
			|||||||
import { MultipleRelationRepository, Repository } from '@nocobase/database';
 | 
					import { MultipleRelationRepository, Repository } from '@nocobase/database';
 | 
				
			||||||
import { Context } from '.';
 | 
					import { Context } from '.';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function pageArgsToLimitArgs(
 | 
				
			||||||
 | 
					  page: number,
 | 
				
			||||||
 | 
					  pageSize: number,
 | 
				
			||||||
 | 
					): {
 | 
				
			||||||
 | 
					  offset: number;
 | 
				
			||||||
 | 
					  limit: number;
 | 
				
			||||||
 | 
					} {
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    offset: (page - 1) * pageSize,
 | 
				
			||||||
 | 
					    limit: pageSize,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function getRepositoryFromParams(ctx: Context) {
 | 
					export function getRepositoryFromParams(ctx: Context) {
 | 
				
			||||||
  const { resourceName, resourceOf } = ctx.action;
 | 
					  const { resourceName, resourceOf } = ctx.action;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,7 @@
 | 
				
			|||||||
export default {
 | 
					export default {
 | 
				
			||||||
  "Display <1><0>10</0><1>20</1><2>50</2><3>100</3></1> items per page": "每页显示 <1><0>10</0><1>20</1><2>50</2><3>100</3></1> 条",
 | 
					  "Display <1><0>10</0><1>20</1><2>50</2><3>100</3></1> items per page": "每页显示 <1><0>10</0><1>20</1><2>50</2><3>100</3></1> 条",
 | 
				
			||||||
 | 
					  "Page number": "页码",
 | 
				
			||||||
 | 
					  "Page size": "每页条数",
 | 
				
			||||||
  "Meet <1><0>All</0><1>Any</1></1> conditions in the group": "满足组内 <1><0>全部</0><1>任意</1></1> 条件",
 | 
					  "Meet <1><0>All</0><1>Any</1></1> conditions in the group": "满足组内 <1><0>全部</0><1>任意</1></1> 条件",
 | 
				
			||||||
  "Open in<1><0>Modal</0><1>Drawer</1><2>Window</2></1>": "在 <1><0>对话框</0><1>抽屉</1><2>窗口</2></1> 内打开",
 | 
					  "Open in<1><0>Modal</0><1>Drawer</1><2>Window</2></1>": "在 <1><0>对话框</0><1>抽屉</1><2>窗口</2></1> 内打开",
 | 
				
			||||||
  "{{count}} filter items": "{{count}} 个筛选项",
 | 
					  "{{count}} filter items": "{{count}} 个筛选项",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,5 @@
 | 
				
			|||||||
import { Context, Next } from '@nocobase/actions';
 | 
					import { Context, Next, DEFAULT_PAGE, DEFAULT_PER_PAGE } from '@nocobase/actions';
 | 
				
			||||||
import { Database, Model, Op } from '@nocobase/database';
 | 
					import { Database, Model, Op } from '@nocobase/database';
 | 
				
			||||||
import { DEFAULT_PAGE, DEFAULT_PER_PAGE } from '../constans';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const appendTranslations = async (db: Database, rows: Model[], locale: string): Promise<any[]> => {
 | 
					const appendTranslations = async (db: Database, rows: Model[], locale: string): Promise<any[]> => {
 | 
				
			||||||
  const texts = rows || [];
 | 
					  const texts = rows || [];
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1 @@
 | 
				
			|||||||
export const DEFAULT_PAGE = 1;
 | 
					 | 
				
			||||||
export const DEFAULT_PER_PAGE = 20;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const CACHE_KEY = 'localization:texts';
 | 
					export const CACHE_KEY = 'localization:texts';
 | 
				
			||||||
 | 
				
			|||||||
@ -95,10 +95,7 @@ function JobModal() {
 | 
				
			|||||||
                  'x-decorator': 'FormItem',
 | 
					                  'x-decorator': 'FormItem',
 | 
				
			||||||
                  'x-component': 'Input.JSON',
 | 
					                  'x-component': 'Input.JSON',
 | 
				
			||||||
                  'x-component-props': {
 | 
					                  'x-component-props': {
 | 
				
			||||||
                    className: css`
 | 
					                    className: styles.nodeJobResultClass,
 | 
				
			||||||
                      padding: 1em;
 | 
					 | 
				
			||||||
                      background-color: #eee;
 | 
					 | 
				
			||||||
                    `,
 | 
					 | 
				
			||||||
                  },
 | 
					                  },
 | 
				
			||||||
                  'x-read-pretty': true,
 | 
					                  'x-read-pretty': true,
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,19 @@
 | 
				
			|||||||
import { SchemaInitializerItemOptions, useCollectionDataSource, useCollectionManager, useCompile } from '@nocobase/client';
 | 
					import { ArrayItems } from '@formily/antd-v5';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { appends, collection, filter } from '../schemas/collection';
 | 
					import {
 | 
				
			||||||
 | 
					  SchemaComponentContext,
 | 
				
			||||||
 | 
					  SchemaInitializerItemOptions,
 | 
				
			||||||
 | 
					  useCollectionDataSource,
 | 
				
			||||||
 | 
					  useCollectionManager,
 | 
				
			||||||
 | 
					  useCompile,
 | 
				
			||||||
 | 
					} from '@nocobase/client';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { appends, collection, filter, pagination, sort } from '../schemas/collection';
 | 
				
			||||||
import { NAMESPACE } from '../locale';
 | 
					import { NAMESPACE } from '../locale';
 | 
				
			||||||
import { CollectionBlockInitializer } from '../components/CollectionBlockInitializer';
 | 
					import { CollectionBlockInitializer } from '../components/CollectionBlockInitializer';
 | 
				
			||||||
import { FilterDynamicComponent } from '../components/FilterDynamicComponent';
 | 
					import { FilterDynamicComponent } from '../components/FilterDynamicComponent';
 | 
				
			||||||
import { getCollectionFieldOptions } from '../variable';
 | 
					import { getCollectionFieldOptions, useWorkflowVariableOptions } from '../variable';
 | 
				
			||||||
import { FieldsSelect } from '../components/FieldsSelect';
 | 
					import { useForm } from '@formily/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  title: `{{t("Query record", { ns: "${NAMESPACE}" })}}`,
 | 
					  title: `{{t("Query record", { ns: "${NAMESPACE}" })}}`,
 | 
				
			||||||
@ -16,31 +24,70 @@ export default {
 | 
				
			|||||||
    collection,
 | 
					    collection,
 | 
				
			||||||
    multiple: {
 | 
					    multiple: {
 | 
				
			||||||
      type: 'boolean',
 | 
					      type: 'boolean',
 | 
				
			||||||
      title: `{{t("Allow multiple records as result", { ns: "${NAMESPACE}" })}}`,
 | 
					 | 
				
			||||||
      'x-decorator': 'FormItem',
 | 
					      'x-decorator': 'FormItem',
 | 
				
			||||||
      'x-component': 'Checkbox',
 | 
					      'x-component': 'Checkbox',
 | 
				
			||||||
 | 
					      'x-content': `{{t("Allow multiple records as result", { ns: "${NAMESPACE}" })}}`,
 | 
				
			||||||
      description: `{{t("If checked, when there are multiple records in the query result, an array will be returned as the result, which can be operated on one by one using a loop node. Otherwise, only one record will be returned.", { ns: "${NAMESPACE}" })}}`,
 | 
					      description: `{{t("If checked, when there are multiple records in the query result, an array will be returned as the result, which can be operated on one by one using a loop node. Otherwise, only one record will be returned.", { ns: "${NAMESPACE}" })}}`,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    params: {
 | 
					    params: {
 | 
				
			||||||
      type: 'object',
 | 
					      type: 'object',
 | 
				
			||||||
 | 
					      'x-component': 'fieldset',
 | 
				
			||||||
      properties: {
 | 
					      properties: {
 | 
				
			||||||
        filter,
 | 
					        filter,
 | 
				
			||||||
 | 
					        sort,
 | 
				
			||||||
 | 
					        pagination,
 | 
				
			||||||
        appends,
 | 
					        appends,
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					      'x-reactions': [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          dependencies: ['collection'],
 | 
				
			||||||
 | 
					          fulfill: {
 | 
				
			||||||
 | 
					            state: {
 | 
				
			||||||
 | 
					              visible: '{{$deps[0] != null}}',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    failOnEmpty: {
 | 
					    failOnEmpty: {
 | 
				
			||||||
      type: 'boolean',
 | 
					      type: 'boolean',
 | 
				
			||||||
      title: `{{t("Exit when query result is null", { ns: "${NAMESPACE}" })}}`,
 | 
					 | 
				
			||||||
      'x-decorator': 'FormItem',
 | 
					      'x-decorator': 'FormItem',
 | 
				
			||||||
      'x-component': 'Checkbox',
 | 
					      'x-component': 'Checkbox',
 | 
				
			||||||
 | 
					      'x-content': `{{t("Exit when query result is null", { ns: "${NAMESPACE}" })}}`,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  view: {},
 | 
					  view: {},
 | 
				
			||||||
  scope: {
 | 
					  scope: {
 | 
				
			||||||
    useCollectionDataSource,
 | 
					    useCollectionDataSource,
 | 
				
			||||||
 | 
					    useWorkflowVariableOptions,
 | 
				
			||||||
 | 
					    useSortableFields() {
 | 
				
			||||||
 | 
					      const compile = useCompile();
 | 
				
			||||||
 | 
					      const { getCollectionFields, getInterface } = useCollectionManager();
 | 
				
			||||||
 | 
					      const { values } = useForm();
 | 
				
			||||||
 | 
					      const fields = getCollectionFields(values.collection);
 | 
				
			||||||
 | 
					      return fields
 | 
				
			||||||
 | 
					        .filter((field: any) => {
 | 
				
			||||||
 | 
					          if (!field.interface) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          const fieldInterface = getInterface(field.interface);
 | 
				
			||||||
 | 
					          if (fieldInterface?.sortable) {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return false;
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .map((field: any) => {
 | 
				
			||||||
 | 
					          return {
 | 
				
			||||||
 | 
					            value: field.name,
 | 
				
			||||||
 | 
					            label: field?.uiSchema?.title ? compile(field?.uiSchema?.title) : field.name,
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  components: {
 | 
					  components: {
 | 
				
			||||||
 | 
					    ArrayItems,
 | 
				
			||||||
    FilterDynamicComponent,
 | 
					    FilterDynamicComponent,
 | 
				
			||||||
 | 
					    SchemaComponentContext,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  useVariables({ id, title, config }, options) {
 | 
					  useVariables({ id, title, config }, options) {
 | 
				
			||||||
    const compile = useCompile();
 | 
					    const compile = useCompile();
 | 
				
			||||||
 | 
				
			|||||||
@ -49,6 +49,123 @@ export const filter = {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const sort = {
 | 
				
			||||||
 | 
					  type: 'array',
 | 
				
			||||||
 | 
					  title: '{{t("Sort")}}',
 | 
				
			||||||
 | 
					  'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					  'x-component': 'ArrayItems',
 | 
				
			||||||
 | 
					  items: {
 | 
				
			||||||
 | 
					    type: 'object',
 | 
				
			||||||
 | 
					    properties: {
 | 
				
			||||||
 | 
					      space: {
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        'x-component': 'Space',
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          sort: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					            'x-component': 'ArrayItems.SortHandle',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          field: {
 | 
				
			||||||
 | 
					            type: 'string',
 | 
				
			||||||
 | 
					            enum: '{{useSortableFields()}}',
 | 
				
			||||||
 | 
					            required: true,
 | 
				
			||||||
 | 
					            'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					            'x-component': 'Select',
 | 
				
			||||||
 | 
					            'x-component-props': {
 | 
				
			||||||
 | 
					              style: {
 | 
				
			||||||
 | 
					                width: 260,
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          direction: {
 | 
				
			||||||
 | 
					            type: 'string',
 | 
				
			||||||
 | 
					            'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					            'x-component': 'Radio.Group',
 | 
				
			||||||
 | 
					            'x-component-props': {
 | 
				
			||||||
 | 
					              optionType: 'button',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            enum: [
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                label: '{{t("ASC")}}',
 | 
				
			||||||
 | 
					                value: 'asc',
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                label: '{{t("DESC")}}',
 | 
				
			||||||
 | 
					                value: 'desc',
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          remove: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					            'x-component': 'ArrayItems.Remove',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  properties: {
 | 
				
			||||||
 | 
					    add: {
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      title: '{{t("Add sort field")}}',
 | 
				
			||||||
 | 
					      'x-component': 'ArrayItems.Addition',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const pagination = {
 | 
				
			||||||
 | 
					  type: 'void',
 | 
				
			||||||
 | 
					  title: '{{t("Pagination")}}',
 | 
				
			||||||
 | 
					  'x-decorator': 'SchemaComponentContext.Provider',
 | 
				
			||||||
 | 
					  'x-decorator-props': {
 | 
				
			||||||
 | 
					    value: { designable: false },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  'x-component': 'Grid',
 | 
				
			||||||
 | 
					  properties: {
 | 
				
			||||||
 | 
					    row: {
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      'x-component': 'Grid.Row',
 | 
				
			||||||
 | 
					      properties: {
 | 
				
			||||||
 | 
					        page: {
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            page: {
 | 
				
			||||||
 | 
					              type: 'number',
 | 
				
			||||||
 | 
					              title: '{{t("Page number")}}',
 | 
				
			||||||
 | 
					              'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					              'x-component': 'Variable.Input',
 | 
				
			||||||
 | 
					              'x-component-props': {
 | 
				
			||||||
 | 
					                scope: '{{useWorkflowVariableOptions()}}',
 | 
				
			||||||
 | 
					                useTypedConstant: ['number', 'null'],
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              default: 1,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        pageSize: {
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-component': 'Grid.Col',
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            pageSize: {
 | 
				
			||||||
 | 
					              type: 'number',
 | 
				
			||||||
 | 
					              title: '{{t("Page size")}}',
 | 
				
			||||||
 | 
					              'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					              'x-component': 'InputNumber',
 | 
				
			||||||
 | 
					              'x-component-props': {
 | 
				
			||||||
 | 
					                min: 1,
 | 
				
			||||||
 | 
					                max: 100,
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              default: 20,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const appends = {
 | 
					export const appends = {
 | 
				
			||||||
  type: 'array',
 | 
					  type: 'array',
 | 
				
			||||||
  title: `{{t("Preload associations", { ns: "${NAMESPACE}" })}}`,
 | 
					  title: `{{t("Preload associations", { ns: "${NAMESPACE}" })}}`,
 | 
				
			||||||
 | 
				
			|||||||
@ -320,6 +320,11 @@ const useStyles = createStyles(({ css, token }) => {
 | 
				
			|||||||
      align-items: center;
 | 
					      align-items: center;
 | 
				
			||||||
    `,
 | 
					    `,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nodeJobResultClass: css`
 | 
				
			||||||
 | 
					      padding: 1em;
 | 
				
			||||||
 | 
					      background-color: ${token.colorBgContainer};
 | 
				
			||||||
 | 
					    `,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    addButtonClass: css`
 | 
					    addButtonClass: css`
 | 
				
			||||||
      flex-shrink: 0;
 | 
					      flex-shrink: 0;
 | 
				
			||||||
      padding: 2em 0;
 | 
					      padding: 2em 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -226,7 +226,7 @@ describe('workflow > instructions > query', () => {
 | 
				
			|||||||
        config: {
 | 
					        config: {
 | 
				
			||||||
          collection: 'posts',
 | 
					          collection: 'posts',
 | 
				
			||||||
          params: {
 | 
					          params: {
 | 
				
			||||||
            sort: 'id',
 | 
					            sort: [{ field: 'id', direction: 'asc' }],
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
@ -313,6 +313,31 @@ describe('workflow > instructions > query', () => {
 | 
				
			|||||||
      const [job] = await execution.getJobs();
 | 
					      const [job] = await execution.getJobs();
 | 
				
			||||||
      expect(job.result.length).toBe(0);
 | 
					      expect(job.result.length).toBe(0);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('params.sort & params.page & params.pageSize', async () => {
 | 
				
			||||||
 | 
					      const n1 = await workflow.createNode({
 | 
				
			||||||
 | 
					        type: 'query',
 | 
				
			||||||
 | 
					        config: {
 | 
				
			||||||
 | 
					          collection: 'posts',
 | 
				
			||||||
 | 
					          multiple: true,
 | 
				
			||||||
 | 
					          params: {
 | 
				
			||||||
 | 
					            sort: [{ field: 'id', direction: 'asc' }],
 | 
				
			||||||
 | 
					            page: 1,
 | 
				
			||||||
 | 
					            pageSize: 1,
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const p1 = await PostRepo.create({ values: { title: 't1' } });
 | 
				
			||||||
 | 
					      const p2 = await PostRepo.create({ values: { title: 't2' } });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await sleep(500);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const [execution] = await workflow.getExecutions();
 | 
				
			||||||
 | 
					      const [job] = await execution.getJobs();
 | 
				
			||||||
 | 
					      expect(job.result.length).toBe(1);
 | 
				
			||||||
 | 
					      expect(job.result[0].title).toBe(p1.title);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe('failOnEmpty', () => {
 | 
					  describe('failOnEmpty', () => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					import { DEFAULT_PAGE, DEFAULT_PER_PAGE, utils } from '@nocobase/actions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Processor from '../Processor';
 | 
					import Processor from '../Processor';
 | 
				
			||||||
import { JOB_STATUS } from '../constants';
 | 
					import { JOB_STATUS } from '../constants';
 | 
				
			||||||
import { toJSON } from '../utils';
 | 
					import { toJSON } from '../utils';
 | 
				
			||||||
@ -8,7 +10,12 @@ export default {
 | 
				
			|||||||
    const { collection, multiple, params = {}, failOnEmpty = false } = node.config;
 | 
					    const { collection, multiple, params = {}, failOnEmpty = false } = node.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const repo = (<typeof FlowNodeModel>node.constructor).database.getRepository(collection);
 | 
					    const repo = (<typeof FlowNodeModel>node.constructor).database.getRepository(collection);
 | 
				
			||||||
    const options = processor.getParsedValue(params, node);
 | 
					    const {
 | 
				
			||||||
 | 
					      page = DEFAULT_PAGE,
 | 
				
			||||||
 | 
					      pageSize = DEFAULT_PER_PAGE,
 | 
				
			||||||
 | 
					      sort = [],
 | 
				
			||||||
 | 
					      ...options
 | 
				
			||||||
 | 
					    } = processor.getParsedValue(params, node);
 | 
				
			||||||
    const appends = options.appends
 | 
					    const appends = options.appends
 | 
				
			||||||
      ? Array.from(
 | 
					      ? Array.from(
 | 
				
			||||||
          options.appends.reduce((set, field) => {
 | 
					          options.appends.reduce((set, field) => {
 | 
				
			||||||
@ -20,7 +27,11 @@ export default {
 | 
				
			|||||||
      : options.appends;
 | 
					      : options.appends;
 | 
				
			||||||
    const result = await (multiple ? repo.find : repo.findOne).call(repo, {
 | 
					    const result = await (multiple ? repo.find : repo.findOne).call(repo, {
 | 
				
			||||||
      ...options,
 | 
					      ...options,
 | 
				
			||||||
      appends: appends,
 | 
					      ...utils.pageArgsToLimitArgs(page, pageSize),
 | 
				
			||||||
 | 
					      sort: sort
 | 
				
			||||||
 | 
					        .filter((item) => item.field)
 | 
				
			||||||
 | 
					        .map((item) => `${item.direction?.toLowerCase() === 'desc' ? '-' : ''}${item.field}`),
 | 
				
			||||||
 | 
					      appends,
 | 
				
			||||||
      transaction: processor.transaction,
 | 
					      transaction: processor.transaction,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user