1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import { dialogActions } from '~/store/dialog/dialog-actions';
6 import { RootState } from '~/store/store';
7 import { Dispatch } from 'redux';
8 import { ResourceKind, extractUuidKind, Resource } from '~/models/resource';
9 import { getResource } from '~/store/resources/resources';
10 import { GroupContentsResourcePrefix } from '~/services/groups-service/groups-service';
11 import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
12 import { ContainerRequestResource } from '~/models/container-request';
13 import { CollectionResource } from '~/models/collection';
14 import { ProjectResource } from '~/models/project';
16 export const ADVANCED_TAB_DIALOG = 'advancedTabDialog';
18 export interface AdvancedTabDialogData {
21 pythonExample: string;
23 cliGetExample: string;
24 cliUpdateHeader: string;
25 cliUpdateExample: string;
31 COLLECTION = 'collection',
32 STORAGE_CLASSES_CONFIRMED = 'storage_classes_confirmed'
36 CONTAINER_REQUEST = 'container_request',
37 OUTPUT_NAME = 'output_name'
42 DELETE_AT = 'delete_at'
45 export const openAdvancedTabDialog = (uuid: string) =>
46 (dispatch: Dispatch<any>, getState: () => RootState) => {
47 const { resources } = getState();
48 const kind = extractUuidKind(uuid);
49 const data = getResource<any>(uuid)(resources);
52 if (kind === ResourceKind.COLLECTION) {
53 const dataCollection: AdvancedTabDialogData = {
54 apiResponse: collectionApiResponse(data),
55 pythonHeader: pythonHeader(CollectionData.COLLECTION),
56 pythonExample: pythonExample(data.uuid, GroupContentsResourcePrefix.COLLECTION),
57 cliGetHeader: cliGetHeader(CollectionData.COLLECTION),
58 cliGetExample: cliGetExample(data.uuid, GroupContentsResourcePrefix.COLLECTION),
59 cliUpdateHeader: cliUpdateHeader(CollectionData.COLLECTION, CollectionData.STORAGE_CLASSES_CONFIRMED),
60 cliUpdateExample: cliUpdateExample(data.uuid, CollectionData.COLLECTION, data.storageClassesConfirmed, CollectionData.STORAGE_CLASSES_CONFIRMED),
61 curlHeader: curlHeader(CollectionData.COLLECTION, CollectionData.STORAGE_CLASSES_CONFIRMED),
62 curlExample: curlExample(data.uuid, GroupContentsResourcePrefix.COLLECTION, data.storageClassesConfirmed, CollectionData.COLLECTION, CollectionData.STORAGE_CLASSES_CONFIRMED)
64 dispatch(dialogActions.OPEN_DIALOG({ id: ADVANCED_TAB_DIALOG, data: dataCollection }));
65 } else if (kind === ResourceKind.PROCESS) {
66 const dataProcess: AdvancedTabDialogData = {
67 apiResponse: containerRequestApiResponse(data),
68 pythonHeader: pythonHeader(ProcessData.CONTAINER_REQUEST),
69 pythonExample: pythonExample(data.uuid, GroupContentsResourcePrefix.PROCESS),
70 cliGetHeader: cliGetHeader(ProcessData.CONTAINER_REQUEST),
71 cliGetExample: cliGetExample(data.uuid, GroupContentsResourcePrefix.PROCESS),
72 cliUpdateHeader: cliUpdateHeader(ProcessData.CONTAINER_REQUEST, ProcessData.OUTPUT_NAME),
73 cliUpdateExample: cliUpdateExample(data.uuid, ProcessData.CONTAINER_REQUEST, data.outputName, ProcessData.OUTPUT_NAME),
74 curlHeader: curlHeader(ProcessData.CONTAINER_REQUEST, ProcessData.OUTPUT_NAME),
75 curlExample: curlExample(data.uuid, GroupContentsResourcePrefix.PROCESS, data.outputName, ProcessData.CONTAINER_REQUEST, ProcessData.OUTPUT_NAME)
77 dispatch(dialogActions.OPEN_DIALOG({ id: ADVANCED_TAB_DIALOG, data: dataProcess }));
78 } else if (kind === ResourceKind.PROJECT) {
79 const dataProject: AdvancedTabDialogData = {
80 apiResponse: groupRequestApiResponse(data),
81 pythonHeader: pythonHeader(ProjectData.GROUP),
82 pythonExample: pythonExample(data.uuid, GroupContentsResourcePrefix.PROJECT),
83 cliGetHeader: cliGetHeader(ProjectData.GROUP),
84 cliGetExample: cliGetExample(data.uuid, GroupContentsResourcePrefix.PROJECT),
85 cliUpdateHeader: cliUpdateHeader(ProjectData.GROUP, ProjectData.DELETE_AT),
86 cliUpdateExample: cliUpdateExample(data.uuid, ProjectData.GROUP, data.deleteAt, ProjectData.DELETE_AT),
87 curlHeader: curlHeader(ProjectData.GROUP, ProjectData.DELETE_AT),
88 curlExample: curlExample(data.uuid, GroupContentsResourcePrefix.PROJECT, data.deleteAt, ProjectData.GROUP, ProjectData.DELETE_AT)
90 dispatch(dialogActions.OPEN_DIALOG({ id: ADVANCED_TAB_DIALOG, data: dataProject }));
93 dispatch(snackbarActions.OPEN_SNACKBAR({ message: "Could not open advanced tab for this resource.", hideDuration: 2000, kind: SnackbarKind.ERROR }));
97 const pythonHeader = (resourceKind: string) =>
98 `An example python command to get a ${resourceKind} using its uuid:`;
100 const pythonExample = (uuid: string, resourcePrefix: string) => {
101 const pythonExample = `import arvados
103 x = arvados.api().${resourcePrefix}().get(uuid='${uuid}').execute()`;
105 return pythonExample;
108 const cliGetHeader = (resourceKind: string) =>
109 `An example arv command to get a ${resourceKind} using its uuid:`;
111 const cliGetExample = (uuid: string, resourcePrefix: string) => {
112 const cliGetExample = `arv ${resourcePrefix} get \\
115 return cliGetExample;
118 const cliUpdateHeader = (resourceKind: string, resourceName: string) =>
119 `An example arv command to update the "${resourceName}" attribute for the current ${resourceKind}:`;
121 const cliUpdateExample = (uuid: string, resourceKind: string, resource: string | string[], resourceName: string) => {
122 const CLIUpdateCollectionExample = `arv ${resourceKind} update \\
124 --${resourceKind} '{"${resourceName}":${resource}}'`;
126 return CLIUpdateCollectionExample;
129 const curlHeader = (resourceKind: string, resource: string) =>
130 `An example curl command to update the "${resource}" attribute for the current ${resourceKind}:`;
132 const curlExample = (uuid: string, resourcePrefix: string, resource: string | string[], resourceKind: string, resourceName: string) => {
133 const curlExample = `curl -X PUT \\
134 -H "Authorization: OAuth2 $ARVADOS_API_TOKEN" \\
135 --data-urlencode ${resourceKind}@/dev/stdin \\
136 https://$ARVADOS_API_HOST/arvados/v1/${resourcePrefix}/${uuid} \\
139 "${resourceName}": ${resource}
146 const containerRequestApiResponse = (apiResponse: ContainerRequestResource) => {
147 const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, name, description, properties, state, requestingContainerUuid, containerUuid,
148 containerCountMax, mounts, runtimeConstraints, containerImage, environment, cwd, command, outputPath, priority, expiresAt, filters, updatedAt, containerCount,
149 useExisting, schedulingParameters, outputUuid, logUuid, outputName, outputTtl } = apiResponse;
152 "owner_uuid": "${ownerUuid}",
153 "created_at": "${createdAt}",
154 "modified_at": "${modifiedAt}",
155 "modified_by_client_uuid": "${modifiedByClientUuid}",
156 "modified_by_user_uuid": "${modifiedByUserUuid}",
158 "description": "${description}",
163 "requesting_container_uuid": "${requestingContainerUuid}",
164 "container_uuid": "${containerUuid}",
165 "container_count_max": "${containerCountMax}",
169 "runtime_constraints": { ${runtimeConstraints.API ? `\n "API": "${runtimeConstraints.API}",` : ''} ${runtimeConstraints.vcpus ? `\n "vcpus": "${runtimeConstraints.vcpus}",` : ''} ${runtimeConstraints.ram ? `\n "ram": "${runtimeConstraints.ram}"` : ''} ${runtimeConstraints.keepCacheRam ? `\n "keep_cache_ram": "${runtimeConstraints.keepCacheRam}"` : ''}
171 "container_image": "${containerImage}",
177 "${command.join(`", \n "`)}"
179 "output_path": "${outputPath}",
180 "priority": "${priority}",
181 "expires_at": "${expiresAt}",
182 "filters": "${filters}"
183 "updated_at": "${updatedAt || null}"
184 "container_count": "${containerCount}"
185 "use_existing": "${useExisting}",
186 "scheduling_parameters": { ${schedulingParameters.maxRunTime ? `\n "max_runtime": "${schedulingParameters.maxRunTime}",` : ''} ${schedulingParameters.partitions ? `\n "partitions": "${schedulingParameters.partitions}",` : ''} ${schedulingParameters.preemptible ? `\n "preemptible": "${schedulingParameters.preemptible}"` : ''}
188 "output_uuid": "${outputUuid}",
189 "log_uuid": "${logUuid}",
190 "output_name": "${outputName}",
191 "output_ttl": "${outputTtl}"
197 const collectionApiResponse = (apiResponse: CollectionResource) => {
198 const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, name, description, properties, portableDataHash, replicationDesired,
199 replicationConfirmedAt, replicationConfirmed, updatedAt, manifestText, deleteAt, fileNames, trashAt, isTrashed, storageClassesDesired,
200 storageClassesConfirmed, storageClassesConfirmedAt } = apiResponse;
203 "owner_uuid": "${ownerUuid}",
204 "created_at": "${createdAt}",
205 "modified_by_client_uuid": "${modifiedByClientUuid}",
206 "modified_by_user_uuid": "${modifiedByUserUuid}",
207 "modified_at": "${modifiedAt}",
208 "portable_data_hash": "${portableDataHash}",
209 "replication_desired": "${replicationDesired}",
210 "replication_confirmed_at": "${replicationConfirmedAt}",
211 "replication_confirmed": "${replicationConfirmed}",
212 "updated_at": "${updatedAt || null}"
213 "manifest_text": "${manifestText || null}",
215 "description": "${description}",
219 "delete_at": "${deleteAt}",
220 "file_names": "${fileNames || null}",
221 "trash_at": "${trashAt}",
222 "is_trashed": "${isTrashed}",
223 "storage_classes_desired": [
224 ${storageClassesDesired.length > 0 ? `"${storageClassesDesired.join(`", \n "`)}"` : ''}
226 "storage_classes_confirmed": [
227 ${storageClassesConfirmed.length > 0 ? `"${storageClassesConfirmed.join(`", \n "`)}"` : ''}
229 "storage_classes_confirmed_at": "${storageClassesConfirmedAt}"
235 const groupRequestApiResponse = (apiResponse: ProjectResource) => {
236 const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, name, description, updatedAt, groupClass, trashAt, isTrashed, deleteAt } = apiResponse;
239 "owner_uuid": "${ownerUuid}",
240 "created_at": "${createdAt}",
241 "modified_by_client_uuid": "${modifiedByClientUuid}",
242 "modified_by_user_uuid": "${modifiedByUserUuid}",
243 "modified_at": "${modifiedAt}",
245 "description": "${description}",
246 "updated_at": "${updatedAt || null}"
247 "group_class": "${groupClass}",
248 "trash_at": "${trashAt}",
249 "is_trashed": "${isTrashed}",
250 "delete_at": "${deleteAt}",