1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import { difference, pipe, values, includes, __ } from 'lodash/fp';
6 import { createTree, setNode, TreeNodeStatus, TreeNode, Tree } from 'models/tree';
7 import { DataTableFilterItem, DataTableFilters } from 'components/data-table-filters/data-table-filters-tree';
8 import { ResourceKind } from 'models/resource';
9 import { FilterBuilder } from 'services/api/filter-builder';
10 import { getSelectedNodes } from 'models/tree';
11 import { CollectionType } from 'models/collection';
12 import { GroupContentsResourcePrefix } from 'services/groups-service/groups-service';
13 import { ContainerState } from 'models/container';
14 import { ContainerRequestState } from 'models/container-request';
16 export enum ProcessStatusFilter {
20 COMPLETED = 'Completed',
21 CANCELLED = 'Cancelled',
26 export enum ObjectTypeFilter {
29 COLLECTION = 'Data collection',
30 WORKFLOW = 'Workflow',
33 export enum GroupTypeFilter {
34 PROJECT = 'Project (normal)',
35 FILTER_GROUP = 'Filter group',
38 export enum CollectionTypeFilter {
39 GENERAL_COLLECTION = 'General',
40 OUTPUT_COLLECTION = 'Output',
41 LOG_COLLECTION = 'Log',
42 INTERMEDIATE_COLLECTION = 'Intermediate',
45 export enum ProcessTypeFilter {
46 MAIN_PROCESS = 'Main',
47 CHILD_PROCESS = 'Child',
50 const initFilter = (name: string, parent = '', isSelected?: boolean) =>
51 setNode<DataTableFilterItem>({
57 selected: isSelected !== undefined ? isSelected : true,
59 status: TreeNodeStatus.LOADED,
62 export const getSimpleObjectTypeFilters = pipe(
63 (): DataTableFilters => createTree<DataTableFilterItem>(),
64 initFilter(ObjectTypeFilter.PROJECT),
65 initFilter(ObjectTypeFilter.PROCESS),
66 initFilter(ObjectTypeFilter.COLLECTION),
67 initFilter(ObjectTypeFilter.WORKFLOW),
70 // Using pipe() with more than 7 arguments makes the return type be 'any',
71 // causing compile issues.
72 export const getInitialResourceTypeFilters = pipe(
73 (): DataTableFilters => createTree<DataTableFilterItem>(),
75 initFilter(ObjectTypeFilter.PROJECT),
76 initFilter(GroupTypeFilter.PROJECT, ObjectTypeFilter.PROJECT),
77 initFilter(GroupTypeFilter.FILTER_GROUP, ObjectTypeFilter.PROJECT),
80 initFilter(ObjectTypeFilter.PROCESS),
81 initFilter(ProcessTypeFilter.MAIN_PROCESS, ObjectTypeFilter.PROCESS),
82 initFilter(ProcessTypeFilter.CHILD_PROCESS, ObjectTypeFilter.PROCESS)
85 initFilter(ObjectTypeFilter.COLLECTION),
86 initFilter(CollectionTypeFilter.GENERAL_COLLECTION, ObjectTypeFilter.COLLECTION),
87 initFilter(CollectionTypeFilter.OUTPUT_COLLECTION, ObjectTypeFilter.COLLECTION),
88 initFilter(CollectionTypeFilter.INTERMEDIATE_COLLECTION, ObjectTypeFilter.COLLECTION),
89 initFilter(CollectionTypeFilter.LOG_COLLECTION, ObjectTypeFilter.COLLECTION),
91 initFilter(ObjectTypeFilter.WORKFLOW)
95 export const getInitialProcessTypeFilters = pipe(
96 (): DataTableFilters => createTree<DataTableFilterItem>(),
97 initFilter(ProcessTypeFilter.MAIN_PROCESS),
98 initFilter(ProcessTypeFilter.CHILD_PROCESS, '', false)
101 export const getInitialProcessStatusFilters = pipe(
102 (): DataTableFilters => createTree<DataTableFilterItem>(),
104 initFilter(ProcessStatusFilter.ALL, '', true),
105 initFilter(ProcessStatusFilter.ONHOLD, '', false),
106 initFilter(ProcessStatusFilter.QUEUED, '', false),
107 initFilter(ProcessStatusFilter.RUNNING, '', false),
108 initFilter(ProcessStatusFilter.COMPLETED, '', false),
109 initFilter(ProcessStatusFilter.CANCELLED, '', false),
110 initFilter(ProcessStatusFilter.FAILED, '', false),
114 export const getTrashPanelTypeFilters = pipe(
115 (): DataTableFilters => createTree<DataTableFilterItem>(),
116 initFilter(ObjectTypeFilter.PROJECT),
117 initFilter(ObjectTypeFilter.COLLECTION),
118 initFilter(CollectionTypeFilter.GENERAL_COLLECTION, ObjectTypeFilter.COLLECTION),
119 initFilter(CollectionTypeFilter.OUTPUT_COLLECTION, ObjectTypeFilter.COLLECTION),
120 initFilter(CollectionTypeFilter.INTERMEDIATE_COLLECTION, ObjectTypeFilter.COLLECTION),
121 initFilter(CollectionTypeFilter.LOG_COLLECTION, ObjectTypeFilter.COLLECTION),
124 const createFiltersBuilder = (filters: DataTableFilters) =>
125 ({ fb: new FilterBuilder(), selectedFilters: getSelectedNodes(filters) });
127 const getMatchingFilters = (values: string[], filters: TreeNode<DataTableFilterItem>[]) =>
130 .filter(includes(__, values));
132 const objectTypeToResourceKind = (type: ObjectTypeFilter) => {
134 case ObjectTypeFilter.PROJECT:
135 return ResourceKind.PROJECT;
136 case ObjectTypeFilter.PROCESS:
137 return ResourceKind.PROCESS;
138 case ObjectTypeFilter.COLLECTION:
139 return ResourceKind.COLLECTION;
140 case ObjectTypeFilter.WORKFLOW:
141 return ResourceKind.WORKFLOW;
145 const serializeObjectTypeFilters = ({ fb, selectedFilters }: ReturnType<typeof createFiltersBuilder>) => {
146 const groupFilters = getMatchingFilters(values(GroupTypeFilter), selectedFilters);
147 const collectionFilters = getMatchingFilters(values(CollectionTypeFilter), selectedFilters);
148 const processFilters = getMatchingFilters(values(ProcessTypeFilter), selectedFilters);
149 const typeFilters = pipe(
150 () => new Set(getMatchingFilters(values(ObjectTypeFilter), selectedFilters)),
151 set => groupFilters.length > 0
152 ? set.add(ObjectTypeFilter.PROJECT)
154 set => collectionFilters.length > 0
155 ? set.add(ObjectTypeFilter.COLLECTION)
157 set => processFilters.length > 0
158 ? set.add(ObjectTypeFilter.PROCESS)
160 set => Array.from(set)
164 fb: typeFilters.length > 0
165 ? fb.addIsA('uuid', typeFilters.map(objectTypeToResourceKind))
171 const collectionTypeToPropertyValue = (type: CollectionTypeFilter) => {
173 case CollectionTypeFilter.GENERAL_COLLECTION:
174 return CollectionType.GENERAL;
175 case CollectionTypeFilter.OUTPUT_COLLECTION:
176 return CollectionType.OUTPUT;
177 case CollectionTypeFilter.LOG_COLLECTION:
178 return CollectionType.LOG;
179 case CollectionTypeFilter.INTERMEDIATE_COLLECTION:
180 return CollectionType.INTERMEDIATE;
182 return CollectionType.GENERAL;
186 const serializeCollectionTypeFilters = ({ fb, selectedFilters }: ReturnType<typeof createFiltersBuilder>) => pipe(
187 () => getMatchingFilters(values(CollectionTypeFilter), selectedFilters),
188 filters => filters.map(collectionTypeToPropertyValue),
190 fb: buildCollectionTypeFilters({ fb, filters: mappedFilters }),
195 const COLLECTION_TYPES = values(CollectionType);
197 const NON_GENERAL_COLLECTION_TYPES = difference(COLLECTION_TYPES, [CollectionType.GENERAL]);
199 const COLLECTION_PROPERTIES_PREFIX = `${GroupContentsResourcePrefix.COLLECTION}.properties`;
201 const buildCollectionTypeFilters = ({ fb, filters }: { fb: FilterBuilder, filters: CollectionType[] }) => {
203 case filters.length === 0 || filters.length === COLLECTION_TYPES.length:
205 case includes(CollectionType.GENERAL, filters):
206 return fb.addNotIn('type', difference(NON_GENERAL_COLLECTION_TYPES, filters), COLLECTION_PROPERTIES_PREFIX);
208 return fb.addIn('type', filters, COLLECTION_PROPERTIES_PREFIX);
212 const serializeGroupTypeFilters = ({ fb, selectedFilters }: ReturnType<typeof createFiltersBuilder>) => pipe(
213 () => getMatchingFilters(values(GroupTypeFilter), selectedFilters),
216 fb: buildGroupTypeFilters({ fb, filters: mappedFilters, use_prefix: true }),
221 const GROUP_TYPES = values(GroupTypeFilter);
223 const buildGroupTypeFilters = ({ fb, filters, use_prefix }: { fb: FilterBuilder, filters: string[], use_prefix: boolean }) => {
225 case filters.length === 0 || filters.length === GROUP_TYPES.length:
227 case includes(GroupTypeFilter.PROJECT, filters):
228 return fb.addEqual('groups.group_class', 'project');
229 case includes(GroupTypeFilter.FILTER_GROUP, filters):
230 return fb.addEqual('groups.group_class', 'filter');
236 const serializeProcessTypeFilters = ({ fb, selectedFilters }: ReturnType<typeof createFiltersBuilder>) => pipe(
237 () => getMatchingFilters(values(ProcessTypeFilter), selectedFilters),
240 fb: buildProcessTypeFilters({ fb, filters: mappedFilters, use_prefix: true }),
245 const PROCESS_TYPES = values(ProcessTypeFilter);
246 const PROCESS_PREFIX = GroupContentsResourcePrefix.PROCESS;
248 const buildProcessTypeFilters = ({ fb, filters, use_prefix }: { fb: FilterBuilder, filters: string[], use_prefix: boolean }) => {
250 case filters.length === 0 || filters.length === PROCESS_TYPES.length:
252 case includes(ProcessTypeFilter.MAIN_PROCESS, filters):
253 return fb.addEqual('requesting_container_uuid', null, use_prefix ? PROCESS_PREFIX : '');
254 case includes(ProcessTypeFilter.CHILD_PROCESS, filters):
255 return fb.addDistinct('requesting_container_uuid', null, use_prefix ? PROCESS_PREFIX : '');
261 export const serializeResourceTypeFilters = pipe(
262 createFiltersBuilder,
263 serializeObjectTypeFilters,
264 serializeGroupTypeFilters,
265 serializeCollectionTypeFilters,
266 serializeProcessTypeFilters,
267 ({ fb }) => fb.getFilters(),
270 export const serializeOnlyProcessTypeFilters = pipe(
271 createFiltersBuilder,
272 ({ fb, selectedFilters }: ReturnType<typeof createFiltersBuilder>) => pipe(
273 () => getMatchingFilters(values(ProcessTypeFilter), selectedFilters),
276 fb: buildProcessTypeFilters({ fb, filters: mappedFilters, use_prefix: false }),
280 ({ fb }) => fb.getFilters(),
283 export const serializeSimpleObjectTypeFilters = (filters: Tree<DataTableFilterItem>) => {
284 return getSelectedNodes(filters)
286 .map(objectTypeToResourceKind);
289 export const buildProcessStatusFilters = (fb: FilterBuilder, activeStatusFilter: string, resourcePrefix?: string): FilterBuilder => {
290 switch (activeStatusFilter) {
291 case ProcessStatusFilter.ONHOLD: {
292 fb.addDistinct('state', ContainerRequestState.FINAL, resourcePrefix);
293 fb.addEqual('priority', '0', resourcePrefix);
294 fb.addIn('container.state', [ContainerState.QUEUED, ContainerState.LOCKED], resourcePrefix);
297 case ProcessStatusFilter.COMPLETED: {
298 fb.addEqual('container.state', ContainerState.COMPLETE, resourcePrefix);
299 fb.addEqual('container.exit_code', '0', resourcePrefix);
302 case ProcessStatusFilter.FAILED: {
303 fb.addEqual('container.state', ContainerState.COMPLETE, resourcePrefix);
304 fb.addDistinct('container.exit_code', '0', resourcePrefix);
307 case ProcessStatusFilter.QUEUED: {
308 fb.addEqual('container.state', ContainerState.QUEUED, resourcePrefix);
309 fb.addDistinct('priority', '0', resourcePrefix);
312 case ProcessStatusFilter.CANCELLED:
313 case ProcessStatusFilter.RUNNING: {
314 fb.addEqual('container.state', activeStatusFilter, resourcePrefix);