1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import { unionize, ofType, UnionOf } from 'common/unionize';
6 import { extractUuidKind, Resource, ResourceWithProperties } from 'models/resource';
7 import { Dispatch } from 'redux';
8 import { RootState } from 'store/store';
9 import { ServiceRepository } from 'services/services';
10 import { getResourceService } from 'services/services';
11 import { addProperty, deleteProperty } from 'lib/resource-properties';
12 import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions';
13 import { getResource } from './resources';
14 import { TagProperty } from 'models/tag';
15 import { change, formValueSelector } from 'redux-form';
16 import { ResourcePropertiesFormData } from 'views-components/resource-properties-form/resource-properties-form';
18 export type ResourceWithDescription = Resource & { description?: string }
20 export const resourcesActions = unionize({
21 SET_RESOURCES: ofType<ResourceWithDescription[] >(),
22 DELETE_RESOURCES: ofType<string[]>()
25 export type ResourcesAction = UnionOf<typeof resourcesActions>;
27 export const updateResources = (resources: Resource[]) => resourcesActions.SET_RESOURCES(resources);
29 export const deleteResources = (resources: string[]) => resourcesActions.DELETE_RESOURCES(resources);
31 export const loadResource = (uuid: string, showErrors?: boolean) =>
32 async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
34 const kind = extractUuidKind(uuid);
35 const service = getResourceService(kind)(services);
37 const resource = await service.get(uuid, showErrors);
38 dispatch<any>(updateResources([resource]));
45 export const deleteResourceProperty = (uuid: string, key: string, value: string) =>
46 async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
47 const { resources } = getState();
49 const rsc = getResource(uuid)(resources) as ResourceWithProperties;
52 const kind = extractUuidKind(uuid);
53 const service = getResourceService(kind)(services);
54 if (!service) { return; }
56 const properties = Object.assign({}, rsc.properties);
59 let updatedRsc = await service.update(
61 properties: deleteProperty(properties, key, value),
63 updatedRsc = {...rsc, ...updatedRsc};
64 dispatch<any>(updateResources([updatedRsc]));
65 dispatch(snackbarActions.OPEN_SNACKBAR({ message: "Property has been successfully deleted.", hideDuration: 2000, kind: SnackbarKind.SUCCESS }));
67 dispatch(snackbarActions.OPEN_SNACKBAR({ message: e.errors[0], hideDuration: 2000, kind: SnackbarKind.ERROR }));
71 export const createResourceProperty = (data: TagProperty) =>
72 async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
73 const { uuid } = data;
74 const { resources } = getState();
76 const rsc = getResource(uuid)(resources) as ResourceWithProperties;
79 const kind = extractUuidKind(uuid);
80 const service = getResourceService(kind)(services);
81 if (!service) { return; }
84 const key = data.keyID || data.key;
85 const value = data.valueID || data.value;
86 const properties = Object.assign({}, rsc.properties);
87 let updatedRsc = await service.update(
89 properties: addProperty(properties, key, value),
92 updatedRsc = {...rsc, ...updatedRsc};
93 dispatch<any>(updateResources([updatedRsc]));
94 dispatch(snackbarActions.OPEN_SNACKBAR({ message: "Property has been successfully added.", hideDuration: 2000, kind: SnackbarKind.SUCCESS }));
96 const errorMsg = e.errors && e.errors.length > 0 ? e.errors[0] : "Error while adding property";
97 dispatch(snackbarActions.OPEN_SNACKBAR({ message: errorMsg, hideDuration: 2000, kind: SnackbarKind.ERROR }));
101 export const addPropertyToResourceForm = (data: ResourcePropertiesFormData, formName: string) =>
102 (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
103 const properties = { ...formValueSelector(formName)(getState(), 'properties') };
104 const vocabulary = getState().properties.vocabulary?.tags;
105 const dataTags = getTagsIfExist(data.key, data.value, vocabulary);
106 const key = data.keyID || dataTags.key || data.key;
107 const value = data.valueID || dataTags.value || data.value;
111 addProperty(properties, key, value)));
114 export const removePropertyFromResourceForm = (key: string, value: string, formName: string) =>
115 (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
116 const properties = { ...formValueSelector(formName)(getState(), 'properties') };
120 deleteProperty(properties, key, value)));
124 const getTagsIfExist = (dataKey: string, dataValue: string, vocabulary: any) => {
126 for (const key in vocabulary) {
127 if (vocabulary[key].labels.find(l=>l.label === dataKey)) {
129 const { values } = vocabulary[key];
130 for (const val in values) {
131 if (values[val].labels.find(l=>l.label === dataValue)) {
138 return { key: k, value: v };