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',
32 export enum GroupTypeFilter {
33 PROJECT = 'Project (normal)',
34 FILTER_GROUP = 'Filter group',
37 export enum CollectionTypeFilter {
38 GENERAL_COLLECTION = 'General',
39 OUTPUT_COLLECTION = 'Output',
40 LOG_COLLECTION = 'Log',
41 INTERMEDIATE_COLLECTION = 'Intermediate',
44 export enum ProcessTypeFilter {
45 MAIN_PROCESS = 'Main',
46 CHILD_PROCESS = 'Child',
49 const initFilter = (name: string, parent = '', isSelected?: boolean) =>
50 setNode<DataTableFilterItem>({
56 selected: isSelected !== undefined ? isSelected : true,
58 status: TreeNodeStatus.LOADED,
61 export const getSimpleObjectTypeFilters = pipe(
62 (): DataTableFilters => createTree<DataTableFilterItem>(),
63 initFilter(ObjectTypeFilter.PROJECT),
64 initFilter(ObjectTypeFilter.PROCESS),
65 initFilter(ObjectTypeFilter.COLLECTION),
68 // Using pipe() with more than 7 arguments makes the return type be 'any',
69 // causing compile issues.
70 export const getInitialResourceTypeFilters = pipe(
71 (): DataTableFilters => createTree<DataTableFilterItem>(),
73 initFilter(ObjectTypeFilter.PROJECT),
74 initFilter(GroupTypeFilter.PROJECT, ObjectTypeFilter.PROJECT),
75 initFilter(GroupTypeFilter.FILTER_GROUP, ObjectTypeFilter.PROJECT),
78 initFilter(ObjectTypeFilter.PROCESS),
79 initFilter(ProcessTypeFilter.MAIN_PROCESS, ObjectTypeFilter.PROCESS),
80 initFilter(ProcessTypeFilter.CHILD_PROCESS, ObjectTypeFilter.PROCESS)
83 initFilter(ObjectTypeFilter.COLLECTION),
84 initFilter(CollectionTypeFilter.GENERAL_COLLECTION, ObjectTypeFilter.COLLECTION),
85 initFilter(CollectionTypeFilter.OUTPUT_COLLECTION, ObjectTypeFilter.COLLECTION),
86 initFilter(CollectionTypeFilter.INTERMEDIATE_COLLECTION, ObjectTypeFilter.COLLECTION),
87 initFilter(CollectionTypeFilter.LOG_COLLECTION, ObjectTypeFilter.COLLECTION),
91 export const getInitialProcessTypeFilters = pipe(
92 (): DataTableFilters => createTree<DataTableFilterItem>(),
93 initFilter(ProcessTypeFilter.MAIN_PROCESS),
94 initFilter(ProcessTypeFilter.CHILD_PROCESS, '', false)
97 export const getInitialProcessStatusFilters = pipe(
98 (): DataTableFilters => createTree<DataTableFilterItem>(),
100 initFilter(ProcessStatusFilter.ALL, '', true),
101 initFilter(ProcessStatusFilter.ONHOLD, '', false),
102 initFilter(ProcessStatusFilter.QUEUED, '', false),
103 initFilter(ProcessStatusFilter.RUNNING, '', false),
104 initFilter(ProcessStatusFilter.COMPLETED, '', false),
105 initFilter(ProcessStatusFilter.CANCELLED, '', false),
106 initFilter(ProcessStatusFilter.FAILED, '', false),
110 export const getTrashPanelTypeFilters = pipe(
111 (): DataTableFilters => createTree<DataTableFilterItem>(),
112 initFilter(ObjectTypeFilter.PROJECT),
113 initFilter(ObjectTypeFilter.COLLECTION),
114 initFilter(CollectionTypeFilter.GENERAL_COLLECTION, ObjectTypeFilter.COLLECTION),
115 initFilter(CollectionTypeFilter.OUTPUT_COLLECTION, ObjectTypeFilter.COLLECTION),
116 initFilter(CollectionTypeFilter.INTERMEDIATE_COLLECTION, ObjectTypeFilter.COLLECTION),
117 initFilter(CollectionTypeFilter.LOG_COLLECTION, ObjectTypeFilter.COLLECTION),
120 const createFiltersBuilder = (filters: DataTableFilters) =>
121 ({ fb: new FilterBuilder(), selectedFilters: getSelectedNodes(filters) });
123 const getMatchingFilters = (values: string[], filters: TreeNode<DataTableFilterItem>[]) =>
126 .filter(includes(__, values));
128 const objectTypeToResourceKind = (type: ObjectTypeFilter) => {
130 case ObjectTypeFilter.PROJECT:
131 return ResourceKind.PROJECT;
132 case ObjectTypeFilter.PROCESS:
133 return ResourceKind.PROCESS;
134 case ObjectTypeFilter.COLLECTION:
135 return ResourceKind.COLLECTION;
139 const serializeObjectTypeFilters = ({ fb, selectedFilters }: ReturnType<typeof createFiltersBuilder>) => {
140 const groupFilters = getMatchingFilters(values(GroupTypeFilter), selectedFilters);
141 const collectionFilters = getMatchingFilters(values(CollectionTypeFilter), selectedFilters);
142 const processFilters = getMatchingFilters(values(ProcessTypeFilter), selectedFilters);
143 const typeFilters = pipe(
144 () => new Set(getMatchingFilters(values(ObjectTypeFilter), selectedFilters)),
145 set => groupFilters.length > 0
146 ? set.add(ObjectTypeFilter.PROJECT)
148 set => collectionFilters.length > 0
149 ? set.add(ObjectTypeFilter.COLLECTION)
151 set => processFilters.length > 0
152 ? set.add(ObjectTypeFilter.PROCESS)
154 set => Array.from(set)
158 fb: typeFilters.length > 0
159 ? fb.addIsA('uuid', typeFilters.map(objectTypeToResourceKind))
165 const collectionTypeToPropertyValue = (type: CollectionTypeFilter) => {
167 case CollectionTypeFilter.GENERAL_COLLECTION:
168 return CollectionType.GENERAL;
169 case CollectionTypeFilter.OUTPUT_COLLECTION:
170 return CollectionType.OUTPUT;
171 case CollectionTypeFilter.LOG_COLLECTION:
172 return CollectionType.LOG;
173 case CollectionTypeFilter.INTERMEDIATE_COLLECTION:
174 return CollectionType.INTERMEDIATE;
176 return CollectionType.GENERAL;
180 const serializeCollectionTypeFilters = ({ fb, selectedFilters }: ReturnType<typeof createFiltersBuilder>) => pipe(
181 () => getMatchingFilters(values(CollectionTypeFilter), selectedFilters),
182 filters => filters.map(collectionTypeToPropertyValue),
184 fb: buildCollectionTypeFilters({ fb, filters: mappedFilters }),
189 const COLLECTION_TYPES = values(CollectionType);
191 const NON_GENERAL_COLLECTION_TYPES = difference(COLLECTION_TYPES, [CollectionType.GENERAL]);
193 const COLLECTION_PROPERTIES_PREFIX = `${GroupContentsResourcePrefix.COLLECTION}.properties`;
195 const buildCollectionTypeFilters = ({ fb, filters }: { fb: FilterBuilder, filters: CollectionType[] }) => {
197 case filters.length === 0 || filters.length === COLLECTION_TYPES.length:
199 case includes(CollectionType.GENERAL, filters):
200 return fb.addNotIn('type', difference(NON_GENERAL_COLLECTION_TYPES, filters), COLLECTION_PROPERTIES_PREFIX);
202 return fb.addIn('type', filters, COLLECTION_PROPERTIES_PREFIX);
206 const serializeGroupTypeFilters = ({ fb, selectedFilters }: ReturnType<typeof createFiltersBuilder>) => pipe(
207 () => getMatchingFilters(values(GroupTypeFilter), selectedFilters),
210 fb: buildGroupTypeFilters({ fb, filters: mappedFilters, use_prefix: true }),
215 const GROUP_TYPES = values(GroupTypeFilter);
217 const buildGroupTypeFilters = ({ fb, filters, use_prefix }: { fb: FilterBuilder, filters: string[], use_prefix: boolean }) => {
219 case filters.length === 0 || filters.length === GROUP_TYPES.length:
221 case includes(GroupTypeFilter.PROJECT, filters):
222 return fb.addEqual('groups.group_class', 'project');
223 case includes(GroupTypeFilter.FILTER_GROUP, filters):
224 return fb.addEqual('groups.group_class', 'filter');
230 const serializeProcessTypeFilters = ({ fb, selectedFilters }: ReturnType<typeof createFiltersBuilder>) => pipe(
231 () => getMatchingFilters(values(ProcessTypeFilter), selectedFilters),
234 fb: buildProcessTypeFilters({ fb, filters: mappedFilters, use_prefix: true }),
239 const PROCESS_TYPES = values(ProcessTypeFilter);
240 const PROCESS_PREFIX = GroupContentsResourcePrefix.PROCESS;
242 const buildProcessTypeFilters = ({ fb, filters, use_prefix }: { fb: FilterBuilder, filters: string[], use_prefix: boolean }) => {
244 case filters.length === 0 || filters.length === PROCESS_TYPES.length:
246 case includes(ProcessTypeFilter.MAIN_PROCESS, filters):
247 return fb.addEqual('requesting_container_uuid', null, use_prefix ? PROCESS_PREFIX : '');
248 case includes(ProcessTypeFilter.CHILD_PROCESS, filters):
249 return fb.addDistinct('requesting_container_uuid', null, use_prefix ? PROCESS_PREFIX : '');
255 export const serializeResourceTypeFilters = pipe(
256 createFiltersBuilder,
257 serializeObjectTypeFilters,
258 serializeGroupTypeFilters,
259 serializeCollectionTypeFilters,
260 serializeProcessTypeFilters,
261 ({ fb }) => fb.getFilters(),
264 export const serializeOnlyProcessTypeFilters = pipe(
265 createFiltersBuilder,
266 ({ fb, selectedFilters }: ReturnType<typeof createFiltersBuilder>) => pipe(
267 () => getMatchingFilters(values(ProcessTypeFilter), selectedFilters),
270 fb: buildProcessTypeFilters({ fb, filters: mappedFilters, use_prefix: false }),
274 ({ fb }) => fb.getFilters(),
277 export const serializeSimpleObjectTypeFilters = (filters: Tree<DataTableFilterItem>) => {
278 return getSelectedNodes(filters)
280 .map(objectTypeToResourceKind);
283 export const buildProcessStatusFilters = (fb: FilterBuilder, activeStatusFilter: string, resourcePrefix?: string): FilterBuilder => {
284 switch (activeStatusFilter) {
285 case ProcessStatusFilter.ONHOLD: {
286 fb.addDistinct('state', ContainerRequestState.FINAL, resourcePrefix);
287 fb.addEqual('priority', '0', resourcePrefix);
288 fb.addIn('container.state', [ContainerState.QUEUED, ContainerState.LOCKED], resourcePrefix);
291 case ProcessStatusFilter.COMPLETED: {
292 fb.addEqual('container.state', ContainerState.COMPLETE, resourcePrefix);
293 fb.addEqual('container.exit_code', '0', resourcePrefix);
296 case ProcessStatusFilter.FAILED: {
297 fb.addEqual('container.state', ContainerState.COMPLETE, resourcePrefix);
298 fb.addDistinct('container.exit_code', '0', resourcePrefix);
301 case ProcessStatusFilter.QUEUED: {
302 fb.addEqual('container.state', ContainerState.QUEUED, resourcePrefix);
303 fb.addDistinct('priority', '0', resourcePrefix);
306 case ProcessStatusFilter.CANCELLED:
307 case ProcessStatusFilter.RUNNING: {
308 fb.addEqual('container.state', activeStatusFilter, resourcePrefix);