17074: Add remaining requestCount implementations
[arvados.git] / services / workbench2 / src / store / favorite-panel / favorite-panel-middleware-service.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { DataExplorerMiddlewareService, dataExplorerToListParams, listResultsToDataExplorerItemsMeta } from "store/data-explorer/data-explorer-middleware-service";
6 import { FavoritePanelColumnNames } from "views/favorite-panel/favorite-panel";
7 import { RootState } from "../store";
8 import { getUserUuid } from "common/getuser";
9 import { DataColumns } from "components/data-table/data-table";
10 import { ServiceRepository } from "services/services";
11 import { FilterBuilder } from "services/api/filter-builder";
12 import { updateFavorites } from "../favorites/favorites-actions";
13 import { favoritePanelActions } from "./favorite-panel-action";
14 import { Dispatch, MiddlewareAPI } from "redux";
15 import { resourcesActions } from "store/resources/resources-actions";
16 import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions';
17 import { progressIndicatorActions } from 'store/progress-indicator/progress-indicator-actions';
18 import { DataExplorer, getDataExplorer } from "store/data-explorer/data-explorer-reducer";
19 import { loadMissingProcessesInformation } from "store/project-panel/project-panel-run-middleware-service";
20 import { getDataExplorerColumnFilters } from 'store/data-explorer/data-explorer-middleware-service';
21 import { serializeSimpleObjectTypeFilters } from '../resource-type-filters/resource-type-filters';
22 import { ResourceKind } from "models/resource";
23 import { LinkClass, LinkResource } from "models/link";
24 import { GroupContentsResource } from "services/groups-service/groups-service";
25 import { ListArguments, ListResults } from "services/common-service/common-service";
26 import { couldNotFetchItemsAvailable } from "store/data-explorer/data-explorer-action";
27
28 export class FavoritePanelMiddlewareService extends DataExplorerMiddlewareService {
29     constructor(private services: ServiceRepository, id: string) {
30         super(id);
31     }
32
33     getTypeFilters(dataExplorer: DataExplorer) {
34         const columns = dataExplorer.columns as DataColumns<string, GroupContentsResource>;
35         return serializeSimpleObjectTypeFilters(getDataExplorerColumnFilters(columns, FavoritePanelColumnNames.TYPE));
36     }
37
38     getLinkFilters(dataExplorer: DataExplorer, uuid: string): string {
39         return new FilterBuilder()
40             .addEqual("link_class", LinkClass.STAR)
41             .addEqual('tail_uuid', uuid)
42             .addEqual('tail_kind', ResourceKind.USER)
43             .addIsA("head_uuid", this.getTypeFilters(dataExplorer))
44             .getFilters();
45     }
46
47     getResourceFilters(dataExplorer: DataExplorer, uuids: string[]): string {
48         return new FilterBuilder()
49             .addIn("uuid", uuids)
50             .addILike("name", dataExplorer.searchValue)
51             .addIsA("uuid", this.getTypeFilters(dataExplorer))
52             .getFilters();
53     }
54
55     getLinkParams(dataExplorer: DataExplorer, uuid: string): ListArguments {
56         return {
57             ...dataExplorerToListParams(dataExplorer),
58             filters: this.getLinkFilters(dataExplorer, uuid),
59             count: "none",
60         };
61     }
62
63     getCountParams(dataExplorer: DataExplorer, uuid: string): ListArguments {
64         return {
65             filters: this.getLinkFilters(dataExplorer, uuid),
66             limit: 0,
67             count: "exact",
68         };
69     }
70
71     async requestItems(api: MiddlewareAPI<Dispatch, RootState>, criteriaChanged?: boolean, background?: boolean) {
72         const dataExplorer = getDataExplorer(api.getState().dataExplorer, this.getId());
73         const uuid = getUserUuid(api.getState());
74         if (!dataExplorer) {
75             api.dispatch(favoritesPanelDataExplorerIsNotSet());
76         } else if (!uuid || !uuid.length) {
77             userNotAvailable();
78         } else {
79             try {
80                 if (!background) { api.dispatch(progressIndicatorActions.START_WORKING(this.getId())); }
81
82                 // Get items
83                 const responseLinks = await this.services.linkService.list(this.getLinkParams(dataExplorer, uuid));
84                 const uuids = responseLinks.items.map(it => it.headUuid);
85
86                 const groupItems = await this.services.groupsService.list({
87                     filters: this.getResourceFilters(dataExplorer, uuids),
88                 });
89                 const collectionItems = await this.services.collectionService.list({
90                     filters: this.getResourceFilters(dataExplorer, uuids),
91                 });
92                 const processItems = await this.services.containerRequestService.list({
93                     filters: this.getResourceFilters(dataExplorer, uuids),
94                 });
95
96                 const orderedItems = [
97                     ...groupItems.items,
98                     ...collectionItems.items,
99                     ...processItems.items
100                 ];
101
102                 api.dispatch(resourcesActions.SET_RESOURCES(orderedItems));
103                 await api.dispatch<any>(loadMissingProcessesInformation(processItems.items));
104                 api.dispatch(favoritePanelActions.SET_ITEMS({
105                     ...listResultsToDataExplorerItemsMeta(responseLinks),
106                     items: orderedItems.map((resource: any) => resource.uuid),
107                 }));
108                 api.dispatch<any>(updateFavorites(uuids));
109             } catch (e) {
110                 api.dispatch(favoritePanelActions.SET_ITEMS({
111                     items: [],
112                     itemsAvailable: 0,
113                     page: 0,
114                     rowsPerPage: dataExplorer.rowsPerPage
115                 }));
116                 api.dispatch(couldNotFetchFavoritesContents());
117             } finally {
118                 api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId()));
119             }
120         }
121     }
122
123     async requestCount(api: MiddlewareAPI<Dispatch, RootState>, criteriaChanged?: boolean, background?: boolean) {
124         const state = api.getState();
125         const dataExplorer = getDataExplorer(state.dataExplorer, this.getId());
126         const uuid = getUserUuid(api.getState());
127
128         if (criteriaChanged && uuid && uuid.length) {
129             // Get itemsAvailable
130             return this.services.linkService.list(this.getCountParams(dataExplorer, uuid))
131                 .then((results: ListResults<LinkResource>) => {
132                     if (results.itemsAvailable !== undefined) {
133                         api.dispatch<any>(favoritePanelActions.SET_ITEMS_AVAILABLE(results.itemsAvailable));
134                     } else {
135                         couldNotFetchItemsAvailable();
136                     }
137                 });
138         }
139     }
140 }
141
142 const favoritesPanelDataExplorerIsNotSet = () =>
143     snackbarActions.OPEN_SNACKBAR({
144         message: 'Favorites panel is not ready.',
145         kind: SnackbarKind.ERROR
146     });
147
148 const couldNotFetchFavoritesContents = () =>
149     snackbarActions.OPEN_SNACKBAR({
150         message: 'Could not fetch favorites contents.',
151         kind: SnackbarKind.ERROR
152     });
153
154 const userNotAvailable = () =>
155     snackbarActions.OPEN_SNACKBAR({
156         message: 'User favorites not available.',
157         kind: SnackbarKind.ERROR
158     });