Merge branch '18559-user-profile' into main. Closes #18559
[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     SEARCH_RESULTS: '/search-results',
35     SSH_KEYS_ADMIN: `/ssh-keys-admin`,
36     SSH_KEYS_USER: `/ssh-keys-user`,
37     SITE_MANAGER: `/site-manager`,
38     MY_ACCOUNT: '/my-account',
39     LINK_ACCOUNT: '/link_account',
40     KEEP_SERVICES: `/keep-services`,
41     USERS: '/users',
42     USER_PROFILE: `/user/:id(${RESOURCE_UUID_PATTERN})`,
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 getGroupUrl = (uuid: string) => `/group/${uuid}`;
99
100 export const getUserProfileUrl = (uuid: string) => `/user/${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 matchSharedWithMeRoute = (route: string) =>
128     matchPath(route, { path: Routes.SHARED_WITH_ME });
129
130 export const matchRunProcessRoute = (route: string) =>
131     matchPath(route, { path: Routes.RUN_PROCESS });
132
133 export const matchWorkflowRoute = (route: string) =>
134     matchPath<ResourceRouteParams>(route, { path: Routes.WORKFLOWS });
135
136 export const matchSearchResultsRoute = (route: string) =>
137     matchPath<ResourceRouteParams>(route, { path: Routes.SEARCH_RESULTS });
138
139 export const matchUserVirtualMachineRoute = (route: string) =>
140     matchPath<ResourceRouteParams>(route, { path: Routes.VIRTUAL_MACHINES_USER });
141
142 export const matchAdminVirtualMachineRoute = (route: string) =>
143     matchPath<ResourceRouteParams>(route, { path: Routes.VIRTUAL_MACHINES_ADMIN });
144
145 export const matchRepositoriesRoute = (route: string) =>
146     matchPath<ResourceRouteParams>(route, { path: Routes.REPOSITORIES });
147
148 export const matchSshKeysUserRoute = (route: string) =>
149     matchPath(route, { path: Routes.SSH_KEYS_USER });
150
151 export const matchSshKeysAdminRoute = (route: string) =>
152     matchPath(route, { path: Routes.SSH_KEYS_ADMIN });
153
154 export const matchSiteManagerRoute = (route: string) =>
155     matchPath(route, { path: Routes.SITE_MANAGER });
156
157 export const matchMyAccountRoute = (route: string) =>
158     matchPath(route, { path: Routes.MY_ACCOUNT });
159
160 export const matchLinkAccountRoute = (route: string) =>
161     matchPath(route, { path: Routes.LINK_ACCOUNT });
162
163 export const matchKeepServicesRoute = (route: string) =>
164     matchPath(route, { path: Routes.KEEP_SERVICES });
165
166 export const matchTokenRoute = (route: string) =>
167     matchPath(route, { path: Routes.TOKEN });
168
169 export const matchFedTokenRoute = (route: string) =>
170     matchPath(route, { path: Routes.FED_LOGIN });
171
172 export const matchUsersRoute = (route: string) =>
173     matchPath(route, { path: Routes.USERS });
174
175 export const matchUserProfileRoute = (route: string) =>
176     matchPath<ResourceRouteParams>(route, { path: Routes.USER_PROFILE });
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 });