Merge branch '18284-vm-listing' into main. Closes #18284
[arvados-workbench2.git] / src / routes / routes.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { matchPath } from 'react-router';
6 import { ResourceKind, RESOURCE_UUID_PATTERN, extractUuidKind, COLLECTION_PDH_REGEX, PORTABLE_DATA_HASH_PATTERN } from 'models/resource';
7 import { getProjectUrl } from 'models/project';
8 import { getCollectionUrl } from 'models/collection';
9 import { Config } from 'common/config';
10 import { Session } from "models/session";
11
12 export interface FederationConfig {
13     localCluster: string;
14     remoteHostsConfig: { [key: string]: Config };
15     sessions: Session[];
16 }
17
18 export const Routes = {
19     ROOT: '/',
20     TOKEN: '/token',
21     FED_LOGIN: '/fedtoken',
22     ADD_SESSION: '/add-session',
23     PROJECTS: `/projects/:id(${RESOURCE_UUID_PATTERN})`,
24     COLLECTIONS: `/collections/:id(${RESOURCE_UUID_PATTERN})`,
25     PROCESSES: `/processes/:id(${RESOURCE_UUID_PATTERN})`,
26     FAVORITES: '/favorites',
27     TRASH: '/trash',
28     PROCESS_LOGS: `/process-logs/:id(${RESOURCE_UUID_PATTERN})`,
29     REPOSITORIES: '/repositories',
30     SHARED_WITH_ME: '/shared-with-me',
31     RUN_PROCESS: '/run-process',
32     VIRTUAL_MACHINES_ADMIN: '/virtual-machines-admin',
33     VIRTUAL_MACHINES_USER: '/virtual-machines-user',
34     WORKFLOWS: '/workflows',
35     SEARCH_RESULTS: '/search-results',
36     SSH_KEYS_ADMIN: `/ssh-keys-admin`,
37     SSH_KEYS_USER: `/ssh-keys-user`,
38     SITE_MANAGER: `/site-manager`,
39     MY_ACCOUNT: '/my-account',
40     LINK_ACCOUNT: '/link_account',
41     KEEP_SERVICES: `/keep-services`,
42     USERS: '/users',
43     API_CLIENT_AUTHORIZATIONS: `/api_client_authorizations`,
44     GROUPS: '/groups',
45     GROUP_DETAILS: `/group/:id(${RESOURCE_UUID_PATTERN})`,
46     LINKS: '/links',
47     PUBLIC_FAVORITES: '/public-favorites',
48     COLLECTIONS_CONTENT_ADDRESS: `/collections/:id(${PORTABLE_DATA_HASH_PATTERN})`,
49     ALL_PROCESSES: '/all_processes',
50     NO_MATCH: '*',
51 };
52
53 export const getResourceUrl = (uuid: string) => {
54     const kind = extractUuidKind(uuid);
55     switch (kind) {
56         case ResourceKind.PROJECT:
57             return getProjectUrl(uuid);
58         case ResourceKind.USER:
59             return getProjectUrl(uuid);
60         case ResourceKind.COLLECTION:
61             return getCollectionUrl(uuid);
62         case ResourceKind.PROCESS:
63             return getProcessUrl(uuid);
64         default:
65             return undefined;
66     }
67 };
68
69 export const getNavUrl = (uuid: string, config: FederationConfig) => {
70     const path = getResourceUrl(uuid) || "";
71     const cls = uuid.substring(0, 5);
72     if (cls === config.localCluster || extractUuidKind(uuid) === ResourceKind.USER || COLLECTION_PDH_REGEX.exec(uuid)) {
73         return path;
74     } else if (config.remoteHostsConfig[cls]) {
75         let u: URL;
76         if (config.remoteHostsConfig[cls].workbench2Url) {
77             /* NOTE: wb2 presently doesn't support passing api_token
78                to arbitrary page to set credentials, only through
79                api-token route.  So for navigation to work, user needs
80                to already be logged in.  In the future we want to just
81                request the records and display in the current
82                workbench instance making this redirect unnecessary. */
83             u = new URL(config.remoteHostsConfig[cls].workbench2Url);
84         } else {
85             u = new URL(config.remoteHostsConfig[cls].workbenchUrl);
86             u.search = "api_token=" + config.sessions.filter((s) => s.clusterId === cls)[0].token;
87         }
88         u.pathname = path;
89         return u.toString();
90     } else {
91         return "";
92     }
93 };
94
95
96 export const getProcessUrl = (uuid: string) => `/processes/${uuid}`;
97
98 export const getProcessLogUrl = (uuid: string) => `/process-logs/${uuid}`;
99
100 export const getGroupUrl = (uuid: string) => `/group/${uuid}`;
101
102 export interface ResourceRouteParams {
103     id: string;
104 }
105
106 export const matchRootRoute = (route: string) =>
107     matchPath(route, { path: Routes.ROOT, exact: true });
108
109 export const matchFavoritesRoute = (route: string) =>
110     matchPath(route, { path: Routes.FAVORITES });
111
112 export const matchTrashRoute = (route: string) =>
113     matchPath(route, { path: Routes.TRASH });
114
115 export const matchAllProcessesRoute = (route: string) =>
116     matchPath(route, { path: Routes.ALL_PROCESSES });
117
118 export const matchProjectRoute = (route: string) =>
119     matchPath<ResourceRouteParams>(route, { path: Routes.PROJECTS });
120
121 export const matchCollectionRoute = (route: string) =>
122     matchPath<ResourceRouteParams>(route, { path: Routes.COLLECTIONS });
123
124 export const matchProcessRoute = (route: string) =>
125     matchPath<ResourceRouteParams>(route, { path: Routes.PROCESSES });
126
127 export const matchProcessLogRoute = (route: string) =>
128     matchPath<ResourceRouteParams>(route, { path: Routes.PROCESS_LOGS });
129
130 export const matchSharedWithMeRoute = (route: string) =>
131     matchPath(route, { path: Routes.SHARED_WITH_ME });
132
133 export const matchRunProcessRoute = (route: string) =>
134     matchPath(route, { path: Routes.RUN_PROCESS });
135
136 export const matchWorkflowRoute = (route: string) =>
137     matchPath<ResourceRouteParams>(route, { path: Routes.WORKFLOWS });
138
139 export const matchSearchResultsRoute = (route: string) =>
140     matchPath<ResourceRouteParams>(route, { path: Routes.SEARCH_RESULTS });
141
142 export const matchUserVirtualMachineRoute = (route: string) =>
143     matchPath<ResourceRouteParams>(route, { path: Routes.VIRTUAL_MACHINES_USER });
144
145 export const matchAdminVirtualMachineRoute = (route: string) =>
146     matchPath<ResourceRouteParams>(route, { path: Routes.VIRTUAL_MACHINES_ADMIN });
147
148 export const matchRepositoriesRoute = (route: string) =>
149     matchPath<ResourceRouteParams>(route, { path: Routes.REPOSITORIES });
150
151 export const matchSshKeysUserRoute = (route: string) =>
152     matchPath(route, { path: Routes.SSH_KEYS_USER });
153
154 export const matchSshKeysAdminRoute = (route: string) =>
155     matchPath(route, { path: Routes.SSH_KEYS_ADMIN });
156
157 export const matchSiteManagerRoute = (route: string) =>
158     matchPath(route, { path: Routes.SITE_MANAGER });
159
160 export const matchMyAccountRoute = (route: string) =>
161     matchPath(route, { path: Routes.MY_ACCOUNT });
162
163 export const matchLinkAccountRoute = (route: string) =>
164     matchPath(route, { path: Routes.LINK_ACCOUNT });
165
166 export const matchKeepServicesRoute = (route: string) =>
167     matchPath(route, { path: Routes.KEEP_SERVICES });
168
169 export const matchTokenRoute = (route: string) =>
170     matchPath(route, { path: Routes.TOKEN });
171
172 export const matchFedTokenRoute = (route: string) =>
173     matchPath(route, { path: Routes.FED_LOGIN });
174
175 export const matchUsersRoute = (route: string) =>
176     matchPath(route, { path: Routes.USERS });
177
178 export const matchApiClientAuthorizationsRoute = (route: string) =>
179     matchPath(route, { path: Routes.API_CLIENT_AUTHORIZATIONS });
180
181 export const matchGroupsRoute = (route: string) =>
182     matchPath(route, { path: Routes.GROUPS });
183
184 export const matchGroupDetailsRoute = (route: string) =>
185     matchPath<ResourceRouteParams>(route, { path: Routes.GROUP_DETAILS });
186
187 export const matchLinksRoute = (route: string) =>
188     matchPath(route, { path: Routes.LINKS });
189
190 export const matchPublicFavoritesRoute = (route: string) =>
191     matchPath(route, { path: Routes.PUBLIC_FAVORITES });
192
193 export const matchCollectionsContentAddressRoute = (route: string) =>
194     matchPath(route, { path: Routes.COLLECTIONS_CONTENT_ADDRESS });