Merge branch '20085-Sharing-Dialog-Form-Validation-Error' refs #20085
[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     REPOSITORIES: '/repositories',
29     SHARED_WITH_ME: '/shared-with-me',
30     RUN_PROCESS: '/run-process',
31     VIRTUAL_MACHINES_ADMIN: '/virtual-machines-admin',
32     VIRTUAL_MACHINES_USER: '/virtual-machines-user',
33     WORKFLOWS: '/workflows',
34     REGISTEREDWORKFLOW: `/workflows/:id(${RESOURCE_UUID_PATTERN})`,
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     USER_PROFILE: `/user/:id(${RESOURCE_UUID_PATTERN})`,
44     API_CLIENT_AUTHORIZATIONS: `/api_client_authorizations`,
45     GROUPS: '/groups',
46     GROUP_DETAILS: `/group/:id(${RESOURCE_UUID_PATTERN})`,
47     LINKS: '/links',
48     PUBLIC_FAVORITES: '/public-favorites',
49     COLLECTIONS_CONTENT_ADDRESS: `/collections/:id(${PORTABLE_DATA_HASH_PATTERN})`,
50     ALL_PROCESSES: '/all_processes',
51     NO_MATCH: '*',
52 };
53
54 export const getResourceUrl = (uuid: string) => {
55     const kind = extractUuidKind(uuid);
56     switch (kind) {
57         case ResourceKind.PROJECT:
58             return getProjectUrl(uuid);
59         case ResourceKind.USER:
60             return getProjectUrl(uuid);
61         case ResourceKind.COLLECTION:
62             return getCollectionUrl(uuid);
63         case ResourceKind.PROCESS:
64             return getProcessUrl(uuid);
65         case ResourceKind.WORKFLOW:
66             return getWorkflowUrl(uuid);
67         default:
68             return undefined;
69     }
70 };
71
72 /**
73  * @returns A relative or federated url for the given uuid, with a token for federated WB1 urls
74  */
75 export const getNavUrl = (uuid: string, config: FederationConfig, includeToken: boolean = true): string => {
76     const path = getResourceUrl(uuid) || "";
77     const cls = uuid.substring(0, 5);
78     if (cls === config.localCluster || extractUuidKind(uuid) === ResourceKind.USER || COLLECTION_PDH_REGEX.exec(uuid)) {
79         return path;
80     } else if (config.remoteHostsConfig[cls]) {
81         let u: URL;
82         if (config.remoteHostsConfig[cls].workbench2Url) {
83             /* NOTE: wb2 presently doesn't support passing api_token
84                to arbitrary page to set credentials, only through
85                api-token route.  So for navigation to work, user needs
86                to already be logged in.  In the future we want to just
87                request the records and display in the current
88                workbench instance making this redirect unnecessary. */
89             u = new URL(config.remoteHostsConfig[cls].workbench2Url);
90         } else {
91             u = new URL(config.remoteHostsConfig[cls].workbenchUrl);
92             if (includeToken) {
93                 u.search = "api_token=" + config.sessions.filter((s) => s.clusterId === cls)[0].token;
94             }
95         }
96         u.pathname = path;
97         return u.toString();
98     } else {
99         return "";
100     }
101 };
102
103
104 export const getProcessUrl = (uuid: string) => `/processes/${uuid}`;
105
106 export const getWorkflowUrl = (uuid: string) => `/workflows/${uuid}`;
107
108 export const getGroupUrl = (uuid: string) => `/group/${uuid}`;
109
110 export const getUserProfileUrl = (uuid: string) => `/user/${uuid}`;
111
112 export interface ResourceRouteParams {
113     id: string;
114 }
115
116 export const matchRootRoute = (route: string) =>
117     matchPath(route, { path: Routes.ROOT, exact: true });
118
119 export const matchFavoritesRoute = (route: string) =>
120     matchPath(route, { path: Routes.FAVORITES });
121
122 export const matchTrashRoute = (route: string) =>
123     matchPath(route, { path: Routes.TRASH });
124
125 export const matchAllProcessesRoute = (route: string) =>
126     matchPath(route, { path: Routes.ALL_PROCESSES });
127
128 export const matchRegisteredWorkflowRoute = (route: string) =>
129     matchPath<ResourceRouteParams>(route, { path: Routes.REGISTEREDWORKFLOW });
130
131 export const matchProjectRoute = (route: string) =>
132     matchPath<ResourceRouteParams>(route, { path: Routes.PROJECTS });
133
134 export const matchCollectionRoute = (route: string) =>
135     matchPath<ResourceRouteParams>(route, { path: Routes.COLLECTIONS });
136
137 export const matchProcessRoute = (route: string) =>
138     matchPath<ResourceRouteParams>(route, { path: Routes.PROCESSES });
139
140 export const matchSharedWithMeRoute = (route: string) =>
141     matchPath(route, { path: Routes.SHARED_WITH_ME });
142
143 export const matchRunProcessRoute = (route: string) =>
144     matchPath(route, { path: Routes.RUN_PROCESS });
145
146 export const matchWorkflowRoute = (route: string) =>
147     matchPath<ResourceRouteParams>(route, { path: Routes.WORKFLOWS });
148
149 export const matchSearchResultsRoute = (route: string) =>
150     matchPath<ResourceRouteParams>(route, { path: Routes.SEARCH_RESULTS });
151
152 export const matchUserVirtualMachineRoute = (route: string) =>
153     matchPath<ResourceRouteParams>(route, { path: Routes.VIRTUAL_MACHINES_USER });
154
155 export const matchAdminVirtualMachineRoute = (route: string) =>
156     matchPath<ResourceRouteParams>(route, { path: Routes.VIRTUAL_MACHINES_ADMIN });
157
158 export const matchRepositoriesRoute = (route: string) =>
159     matchPath<ResourceRouteParams>(route, { path: Routes.REPOSITORIES });
160
161 export const matchSshKeysUserRoute = (route: string) =>
162     matchPath(route, { path: Routes.SSH_KEYS_USER });
163
164 export const matchSshKeysAdminRoute = (route: string) =>
165     matchPath(route, { path: Routes.SSH_KEYS_ADMIN });
166
167 export const matchSiteManagerRoute = (route: string) =>
168     matchPath(route, { path: Routes.SITE_MANAGER });
169
170 export const matchMyAccountRoute = (route: string) =>
171     matchPath(route, { path: Routes.MY_ACCOUNT });
172
173 export const matchLinkAccountRoute = (route: string) =>
174     matchPath(route, { path: Routes.LINK_ACCOUNT });
175
176 export const matchKeepServicesRoute = (route: string) =>
177     matchPath(route, { path: Routes.KEEP_SERVICES });
178
179 export const matchTokenRoute = (route: string) =>
180     matchPath(route, { path: Routes.TOKEN });
181
182 export const matchFedTokenRoute = (route: string) =>
183     matchPath(route, { path: Routes.FED_LOGIN });
184
185 export const matchUsersRoute = (route: string) =>
186     matchPath(route, { path: Routes.USERS });
187
188 export const matchUserProfileRoute = (route: string) =>
189     matchPath<ResourceRouteParams>(route, { path: Routes.USER_PROFILE });
190
191 export const matchApiClientAuthorizationsRoute = (route: string) =>
192     matchPath(route, { path: Routes.API_CLIENT_AUTHORIZATIONS });
193
194 export const matchGroupsRoute = (route: string) =>
195     matchPath(route, { path: Routes.GROUPS });
196
197 export const matchGroupDetailsRoute = (route: string) =>
198     matchPath<ResourceRouteParams>(route, { path: Routes.GROUP_DETAILS });
199
200 export const matchLinksRoute = (route: string) =>
201     matchPath(route, { path: Routes.LINKS });
202
203 export const matchPublicFavoritesRoute = (route: string) =>
204     matchPath(route, { path: Routes.PUBLIC_FAVORITES });
205
206 export const matchCollectionsContentAddressRoute = (route: string) =>
207     matchPath(route, { path: Routes.COLLECTIONS_CONTENT_ADDRESS });