From 2a18ed97b7aac02e26ecedd3fa73bfc9e1a2d02f Mon Sep 17 00:00:00 2001 From: Maya Date: Thu, 10 Jun 2021 14:01:30 +0300 Subject: [PATCH 01/97] Update server-proxy --- cvat-core/src/server-proxy.js | 82 +++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/cvat-core/src/server-proxy.js b/cvat-core/src/server-proxy.js index f3627d4ec2f8..a6e4dc45383d 100644 --- a/cvat-core/src/server-proxy.js +++ b/cvat-core/src/server-proxy.js @@ -1120,6 +1120,77 @@ } } + async function createCloudStorage(storageDetail) { + const { backendAPI } = config; + + try { + const response = await Axios.post(`${backendAPI}/cloudstorages`, JSON.stringify(storageDetail), { + proxy: config.proxy, + }); + return response.data; + } catch (errorData) { + throw generateError(errorData); + } + } + + async function saveCloudStorage(id, cloudStorageData) { + const { backendAPI } = config; + + try { + await Axios.patch(`${backendAPI}/cloudstorages/${id}`, JSON.stringify(cloudStorageData), { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } + } + + async function getCloudStorage(id) { + const { backendAPI } = config; + + let response = null; + try { + response = await Axios.get(`${backendAPI}/cloudstorages/${id}`, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } + + return response.data; + } + + async function getCloudStorageContent(id, manifestPath) { + const { backendAPI } = config; + + let response = null; + try { + const url = manifestPath + ? `${backendAPI}/cloudstorages/${id}/content?manifest=${manifestPath}` + : `${backendAPI}/cloudstorages/${id}/content`; + response = await Axios.get(url, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } + + return response.data; + } + + async function deleteCloudStorage(id) { + const { backendAPI } = config; + + try { + await Axios.delete(`${backendAPI}/cloudstorages/${id}`); + } catch (errorData) { + throw generateError(errorData); + } + } + Object.defineProperties( this, Object.freeze({ @@ -1246,6 +1317,17 @@ }), writable: false, }, + + cloudstorage: { + value: Object.freeze({ + get: getCloudStorage, + getContent: getCloudStorageContent, + create: createCloudStorage, + delete: deleteCloudStorage, + save: saveCloudStorage, + }), + writable: false, + }, }), ); } From c64410e675771a094393d903f34df3a0ec681108 Mon Sep 17 00:00:00 2001 From: Maya Date: Thu, 10 Jun 2021 14:02:10 +0300 Subject: [PATCH 02/97] Add cloud storage implementation && update enums --- cvat-core/src/cloud-storage.js | 407 +++++++++++++++++++++++++++++++++ cvat-core/src/enums.js | 34 ++- 2 files changed, 440 insertions(+), 1 deletion(-) create mode 100644 cvat-core/src/cloud-storage.js diff --git a/cvat-core/src/cloud-storage.js b/cvat-core/src/cloud-storage.js new file mode 100644 index 000000000000..630282257594 --- /dev/null +++ b/cvat-core/src/cloud-storage.js @@ -0,0 +1,407 @@ +// Copyright (C) 2021 Intel Corporation +// +// SPDX-License-Identifier: MIT + +(() => { + const PluginRegistry = require('./plugins'); + const serverProxy = require('./server-proxy'); + const { ArgumentError } = require('./exceptions'); + const { CredentialsType, ProviderType } = require('./enums'); + + /** + * Class representing a cloud storage + * @memberof module:API.cvat.classes + */ + class CloudStorage { + // TODO: add storage availability status (avaliable/unavaliable) + constructor(initialData) { + const data = { + id: undefined, + displayName: undefined, + description: undefined, + credentialsType: undefined, + provider: undefined, + resourceName: undefined, + accountName: undefined, + accesskey: undefined, + secretKey: undefined, + token: undefined, + specificAttibutes: undefined, + owner: undefined, + created_date: undefined, + updated_date: undefined, + manifestPath: undefined, + }; + + for (const property in data) { + if (Object.prototype.hasOwnProperty.call(data, property) && property in initialData) { + data[property] = initialData[property]; + } + } + + Object.defineProperties( + this, + Object.freeze({ + /** + * @name id + * @type {integer} + * @memberof module:API.cvat.classes.CloudStorage + * @readonly + * @instance + */ + id: { + get: () => data.id, + }, + /** + * Storage name + * @name displayName + * @type {string} + * @memberof module:API.cvat.classes.CloudStorage + * @instance + * @throws {module:API.cvat.exceptions.ArgumentError} + */ + displayName: { + get: () => data.displayName, + set: (value) => { + if (!value.trim().length) { + throw new ArgumentError('Value must not be empty'); + } + data.displayName = value; + }, + }, + /** + * Storage description + * @name description + * @type {string} + * @memberof module:API.cvat.classes.CloudStorage + * @instance + */ + description: { + get: () => data.description, + set: (value) => { + data.description = value; + }, + }, + /** + * Account name (for Azure) + * @name accountName + * @type {string} + * @memberof module:API.cvat.classes.CloudStorage + * @instance + * @throws {module:API.cvat.exceptions.ArgumentError} + */ + accountName: { + get: () => data.accountName, + set: (value) => { + if (typeof value === 'string') { + if (value.trim().length) { + data.accountName = value; + } else { + throw new ArgumentError('Value must not be empty'); + } + } + }, + }, + /** + * AWS access key id + * @name accessKey + * @type {string} + * @memberof module:API.cvat.classes.CloudStorage + * @instance + * @throws {module:API.cvat.exceptions.ArgumentError} + */ + accessKey: { + get: () => data.accessKey, + set: (value) => { + if (typeof value === 'string') { + if (value.trim().length) { + data.accesskey = value; + } else { + throw new ArgumentError('Value must not be empty'); + } + } + }, + }, + /** + * AWS secret key + * @name secretKey + * @type {string} + * @memberof module:API.cvat.classes.CloudStorage + * @instance + * @throws {module:API.cvat.exceptions.ArgumentError} + */ + secretKey: { + get: () => data.secretKey, + set: (value) => { + if (typeof value === 'string') { + if (value.trim().length) { + data.secretKey = value; + } else { + throw new ArgumentError('Value must not be empty'); + } + } + }, + }, + /** + * Session token + * @name token + * @type {string} + * @memberof module:API.cvat.classes.CloudStorage + * @instance + * @throws {module:API.cvat.exceptions.ArgumentError} + */ + token: { + get: () => data.token, + set: (value) => { + if (typeof value === 'string') { + if (value.trim().length) { + data.token = value; + } else { + throw new ArgumentError('Value must not be empty'); + } + } + }, + }, + /** + * Unique resource name + * @name resourceName + * @type {string} + * @memberof module:API.cvat.classes.CloudStorage + * @instance + * @throws {module:API.cvat.exceptions.ArgumentError} + */ + resourceName: { + get: () => data.resourceName, + set: (value) => { + if (!value.trim().length) { + throw new ArgumentError('Value must not be empty'); + } + data.resourceName = value; + }, + }, + /** + * @name manifestPath + * @type {string} + * @memberof module:API.cvat.classes.CloudStorage + * @instance + */ + manifestPath: { + get: () => data.manifestPath, + set: (value) => { + if (typeof value !== undefined) { + data.manifestPath = value; + } + }, + }, + /** + * @name provider + * @type {module:API.cvat.enums.ProviderType} + * @memberof module:API.cvat.classes.CloudStorage + * @instance + * @throws {module:API.cvat.exceptions.ArgumentError} + */ + provider: { + get: () => data.provider, + set: (value) => { + if (value !== undefined && !!ProviderType[value]) { + data.provider = value; + } else { + throw new ArgumentError('Value must be one from ProviderType values'); + } + }, + }, + /** + * @name credentialsType + * @type {module:API.cvat.enums.CredentialsType} + * @memberof module:API.cvat.classes.CloudStorage + * @instance + * @throws {module:API.cvat.exceptions.ArgumentError} + */ + credentialsType: { + get: () => data.credentialsType, + set: (value) => { + if (value !== undefined && !!CredentialsType[value]) { + data.credentialsType = value; + } else { + throw new ArgumentError('Value must be one from CredentialsType values'); + } + }, + }, + /** + * @name specificAttibutes + * @type {string} + * @memberof module:API.cvat.classes.CloudStorage + * @instance + * @throws {module:API.cvat.exceptions.ArgumentError} + */ + specificAttibutes: { + get: () => data.specificAttibutes, + set: (attributesValue) => { + if (typeof attributesValue === 'string') { + for (const keyValuePair of attributesValue.split('&')) { + const [key, value] = keyValuePair.split('='); + if (key && value) { + throw new ArgumentError('Value mast match the key1=value1&key2=value2'); + } + } + data.specificAttibutes = attributesValue; + } else { + throw new ArgumentError('Value mast be string'); + } + }, + }, + /** + * Instance of a user who has created the cloud storage + * @name owner + * @type {module:API.cvat.classes.User} + * @memberof module:API.cvat.classes.CloudStorage + * @readonly + * @instance + */ + owner: { + get: () => data.owner, + }, + /** + * @name createdDate + * @type {string} + * @memberof module:API.cvat.classes.CloudStorage + * @readonly + * @instance + */ + createdDate: { + get: () => data.created_date, + }, + /** + * @name updatedDate + * @type {string} + * @memberof module:API.cvat.classes.CloudStorage + * @readonly + * @instance + */ + updatedDate: { + get: () => data.updated_date, + }, + // _internalData: { + // get: () => data, + // }, + }), + ); + } + + /** + * Method updates data of a created cloud storage or creates new cloud storage + * @method save + * @returns {module:API.cvat.classes.CloudStorage} + * @memberof module:API.cvat.classes.CloudStorage + * @readonly + * @instance + * @async + * @throws {module:API.cvat.exceptions.ServerError} + * @throws {module:API.cvat.exceptions.PluginError} + */ + async save() { + const result = await PluginRegistry.apiWrapper.call(this, CloudStorage.prototype.save); + return result; + } + + /** + * Method deletes a cloud storage from a server + * @method delete + * @memberof module:API.cvat.classes.CloudStorage + * @readonly + * @instance + * @async + * @throws {module:API.cvat.exceptions.ServerError} + * @throws {module:API.cvat.exceptions.PluginError} + */ + async delete() { + const result = await PluginRegistry.apiWrapper.call(this, CloudStorage.prototype.delete); + return result; + } + + /** + * Method returns cloud storage content + * @method getContent + * @memberof module:API.cvat.classes.CloudStorage + * @readonly + * @instance + * @async + * @throws {module:API.cvat.exceptions.ServerError} + * @throws {module:API.cvat.exceptions.PluginError} + */ + async getContent() { + const result = await PluginRegistry.apiWrapper.call(this, CloudStorage.prototype.getContent); + return result; + } + } + + CloudStorage.prototype.save.implementation = async function () { + // update + if (typeof this.id !== 'undefined') { + const cloudStorageData = { + displayName: this.displayName, + description: this.description ? this.description : null, + credentialsType: this.credentialsType ? this.credentialsType : null, + provided: this.provider ? this.provider : null, + resourceName: this.resourceName ? this.resourceName : null, + secretKey: this.secretKey ? this.secretKey : null, + token: this.token ? this.token : null, + accessKey: this.accessKey ? this.accessKey : null, + accountName: this.accountName ? this.accountName : null, + specificAttibutes: this.specificAttibutes ? this.specificAttibutes : null, + }; + + await serverProxy.cloudStorage.save(this.id, cloudStorageData); + return this; + } + + // create + const cloudStorageData = { + displayName: this.displayName, + credentialsType: this.credentialsType, + provider: this.provider, + resourceName: this.resourceName, + }; + + if (this.description) { + cloudStorageData.description = this.description; + } + + if (this.accountName) { + cloudStorageData.accountName = this.accountName; + } + + if (this.accessKey) { + cloudStorageData.accessKey = this.accessKey; + } + + if (this.secretKey) { + cloudStorageData.secretKey = this.secretKey; + } + + if (this.token) { + cloudStorageData.token = this.token; + } + + if (this.specificAttibutes) { + cloudStorageData.specificAttibutes = this.specificAttibutes; + } + + const cloudStorage = await serverProxy.cloudStorages.create(cloudStorageData); + return new CloudStorage(cloudStorage); + }; + + CloudStorage.prototype.delete.implementation = async function () { + const result = await serverProxy.cloudStorages.delete(this.id); + return result; + }; + + CloudStorage.prototype.getContent.implementation = async function () { + const result = await serverProxy.cloudStorage.getContent(this.id, this.manifestPath); + return result; + }; + + module.exports = { + CloudStorage, + }; +})(); diff --git a/cvat-core/src/enums.js b/cvat-core/src/enums.js index 4ce6d80c08c6..e5fbffe02ad4 100644 --- a/cvat-core/src/enums.js +++ b/cvat-core/src/enums.js @@ -1,4 +1,4 @@ -// Copyright (C) 2019-2020 Intel Corporation +// Copyright (C) 2019-2021 Intel Corporation // // SPDX-License-Identifier: MIT @@ -333,6 +333,36 @@ '#733380', ]; + /** + * Provider types + * @enum {string} + * @name ProviderType + * @memberof module:API.cvat.enums + * @property {string} AWS_S3 'AWS_S3_BUCKET' + * @property {string} AZURE 'AZURE_BLOB_CONTAINER' + * @readonly + */ + const ProviderType = Object.freeze({ + AWS_S3: 'AWS_S3_BUCKET', + AZURE: 'AZURE_BLOB_CONTAINER', + }); + + /** + * Types of cloud storage credentials + * @enum {string} + * @name CredentialsType + * @memberof module:API.cvat.enums + * @property {string} TEMP_KEY_SECRET_KEY_TOKEN_SET 'TEMP_KEY_SECRET_KEY_TOKEN_SET' + * @property {string} ACCOUNT_NAME_TOKEN_PAIR 'ACCOUNT_NAME_TOKEN_PAIR' + * @property {string} ANONYMOUS_ACCESS 'ANONYMOUS_ACCESS' + * @readonly + */ + const CredentialsType = Object.freeze({ + TEMP_KEY_SECRET_KEY_TOKEN_SET: 'TEMP_KEY_SECRET_KEY_TOKEN_SET', + ACCOUNT_NAME_TOKEN_PAIR: 'ACCOUNT_NAME_TOKEN_PAIR', + ANONYMOUS_ACCESS: 'ANONYMOUS_ACCESS', + }); + module.exports = { ShareFileType, TaskStatus, @@ -348,5 +378,7 @@ colors, Source, DimensionType, + ProviderType, + CredentialsType, }; })(); From 3e5264d0f88f7f426d7145e416086ac61d76ace9 Mon Sep 17 00:00:00 2001 From: Maya Date: Thu, 10 Jun 2021 14:54:56 +0300 Subject: [PATCH 03/97] Add api && fix server-proxy --- cvat-core/src/api-implementation.js | 33 ++++++++++++++++++++++++- cvat-core/src/api.js | 38 +++++++++++++++++++++++++++++ cvat-core/src/server-proxy.js | 6 ++--- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/cvat-core/src/api-implementation.js b/cvat-core/src/api-implementation.js index 5e9ff610ca52..2b39203ba3aa 100644 --- a/cvat-core/src/api-implementation.js +++ b/cvat-core/src/api-implementation.js @@ -16,13 +16,16 @@ camelToSnake, } = require('./common'); - const { TaskStatus, TaskMode, DimensionType } = require('./enums'); + const { + TaskStatus, TaskMode, DimensionType, ProviderType, + } = require('./enums'); const User = require('./user'); const { AnnotationFormats } = require('./annotation-formats'); const { ArgumentError } = require('./exceptions'); const { Task } = require('./session'); const { Project } = require('./project'); + const { CloudStorage } = require('./cloud-storage'); function implementAPI(cvat) { cvat.plugins.list.implementation = PluginRegistry.list; @@ -250,6 +253,34 @@ cvat.projects.searchNames.implementation = async (search, limit) => serverProxy.projects.searchNames(search, limit); + cvat.cloudStorages.get.implementation = async (filter) => { + checkFilter(filter, { + page: isInteger, + displayName: isString, + resourceName: isString, + id: isInteger, + owner: isString, + search: isString, + provider: isEnum.bind(ProviderType), + }); + + checkExclusiveFields(filter, ['id', 'search'], ['page']); + + const searchParams = new URLSearchParams(); + for (const field of ['displayName', 'resourceName', 'owner', 'search', 'provider', 'id', 'page']) { + if (Object.prototype.hasOwnProperty.call(filter, field)) { + searchParams.set(field, filter[field]); + } + } + + const cloudStoragesData = await serverProxy.cloudStoarges.getCloudStorages(searchParams.toString()); + const cloudStorages = cloudStoragesData.map((cloudStorage) => new CloudStorage(cloudStorage)); + + cloudStorages.count = cloudStoragesData.count; + + return cloudStorages; + }; + return cvat; } diff --git a/cvat-core/src/api.js b/cvat-core/src/api.js index a5d36b6ce833..fc9f62564e6b 100644 --- a/cvat-core/src/api.js +++ b/cvat-core/src/api.js @@ -20,6 +20,7 @@ function build() { const { Project } = require('./project'); const { Attribute, Label } = require('./labels'); const MLModel = require('./ml-model'); + const { CloudStorage } = require('./cloud-storage'); const enums = require('./enums'); @@ -746,6 +747,41 @@ function build() { PluginError, ServerError, }, + /** + * Namespace is used for getting cloud storages + * @namespace cloudStorages + * @memberof module:API.cvat + */ + cloudStorages: { + /** + * @typedef {Object} CloudStorageFilter + * @property {string} displayName Check if displayName contains this value + * @property {string} resourceName Check if resourceName contains this value + * @property {module:API.cvat.enums.ProviderType} provider Check if provider contains this value + * @property {integer} id Check if id equals this value + * @property {integer} page Get specific page + * (default REST API returns 20 clouds storages per request. + * In order to get more, it is need to specify next page) + * @property {string} owner Check if owner user contains this value + * @property {string} search Combined search of contains among all fields + * @global + */ + + /** + * Method returns list of cloud storages corresponding to a filter + * @method get + * @async + * @memberof module:API.cvat.cloudStorages + * @param {CloudStorageFilter} [filter={}] cloud storage filter + * @returns {module:API.cvat.classes.CloudStorage[]} + * @throws {module:API.cvat.exceptions.PluginError} + * @throws {module:API.cvat.exceptions.ServerError} + */ + async get(filter = {}) { + const result = await PluginRegistry.apiWrapper(cvat.cloudStorages.get, filter); + return result; + }, + }, /** * Namespace is used for access to classes * @namespace classes @@ -765,6 +801,7 @@ function build() { Comment, Issue, Review, + CloudStorage, }, }; @@ -777,6 +814,7 @@ function build() { cvat.lambda = Object.freeze(cvat.lambda); cvat.client = Object.freeze(cvat.client); cvat.enums = Object.freeze(cvat.enums); + cvat.cloudStorages = Object.freeze(cvat.cloudStorages); const implementAPI = require('./api-implementation'); diff --git a/cvat-core/src/server-proxy.js b/cvat-core/src/server-proxy.js index a6e4dc45383d..35eaa4213397 100644 --- a/cvat-core/src/server-proxy.js +++ b/cvat-core/src/server-proxy.js @@ -1148,12 +1148,12 @@ } } - async function getCloudStorage(id) { + async function getCloudStorages(filter = '') { const { backendAPI } = config; let response = null; try { - response = await Axios.get(`${backendAPI}/cloudstorages/${id}`, { + response = await Axios.get(`${backendAPI}/cloudstorages?page_size=20&${filter}`, { proxy: config.proxy, }); } catch (errorData) { @@ -1320,7 +1320,7 @@ cloudstorage: { value: Object.freeze({ - get: getCloudStorage, + getCloudStorages, getContent: getCloudStorageContent, create: createCloudStorage, delete: deleteCloudStorage, From 3aebaa9ed8b698eab16e1e41f4060cb17226b7e2 Mon Sep 17 00:00:00 2001 From: Maya Date: Tue, 15 Jun 2021 12:12:03 +0300 Subject: [PATCH 04/97] Add fixes --- cvat-core/src/api-implementation.js | 18 +++- cvat-core/src/api.js | 8 +- cvat-core/src/cloud-storage.js | 162 +++++++++++++++------------- cvat-core/src/enums.js | 18 ++-- cvat-core/src/server-proxy.js | 10 +- 5 files changed, 121 insertions(+), 95 deletions(-) diff --git a/cvat-core/src/api-implementation.js b/cvat-core/src/api-implementation.js index 2b39203ba3aa..2fc22c71c115 100644 --- a/cvat-core/src/api-implementation.js +++ b/cvat-core/src/api-implementation.js @@ -17,7 +17,7 @@ } = require('./common'); const { - TaskStatus, TaskMode, DimensionType, ProviderType, + TaskStatus, TaskMode, DimensionType, CloudStorageProviderType, } = require('./enums'); const User = require('./user'); @@ -261,19 +261,27 @@ id: isInteger, owner: isString, search: isString, - provider: isEnum.bind(ProviderType), + provider: isEnum.bind(CloudStorageProviderType), }); checkExclusiveFields(filter, ['id', 'search'], ['page']); const searchParams = new URLSearchParams(); - for (const field of ['displayName', 'resourceName', 'owner', 'search', 'provider', 'id', 'page']) { + for (const field of ['displayName', 'owner', 'search', 'id', 'page']) { if (Object.prototype.hasOwnProperty.call(filter, field)) { - searchParams.set(field, filter[field]); + searchParams.set(camelToSnake(field), filter[field]); } } - const cloudStoragesData = await serverProxy.cloudStoarges.getCloudStorages(searchParams.toString()); + if (Object.prototype.hasOwnProperty.call(filter, 'resourceName')) { + searchParams.set('resource', filter.resourceName); + } + + if (Object.prototype.hasOwnProperty.call(filter, 'provider')) { + searchParams.set('provider_type', filter.provider); + } + + const cloudStoragesData = await serverProxy.cloudStoarges.get(searchParams.toString()); const cloudStorages = cloudStoragesData.map((cloudStorage) => new CloudStorage(cloudStorage)); cloudStorages.count = cloudStoragesData.count; diff --git a/cvat-core/src/api.js b/cvat-core/src/api.js index fc9f62564e6b..88bff3c28549 100644 --- a/cvat-core/src/api.js +++ b/cvat-core/src/api.js @@ -757,18 +757,18 @@ function build() { * @typedef {Object} CloudStorageFilter * @property {string} displayName Check if displayName contains this value * @property {string} resourceName Check if resourceName contains this value - * @property {module:API.cvat.enums.ProviderType} provider Check if provider contains this value + * @property {module:API.cvat.enums.ProviderType} provider Check if provider equal this value * @property {integer} id Check if id equals this value * @property {integer} page Get specific page * (default REST API returns 20 clouds storages per request. * In order to get more, it is need to specify next page) - * @property {string} owner Check if owner user contains this value - * @property {string} search Combined search of contains among all fields + * @property {string} owner Check if an owner name contains this value + * @property {string} search Combined search of contains among all the fields * @global */ /** - * Method returns list of cloud storages corresponding to a filter + * Method returns a list of cloud storages corresponding to a filter * @method get * @async * @memberof module:API.cvat.cloudStorages diff --git a/cvat-core/src/cloud-storage.js b/cvat-core/src/cloud-storage.js index 630282257594..b7064ea246b8 100644 --- a/cvat-core/src/cloud-storage.js +++ b/cvat-core/src/cloud-storage.js @@ -6,7 +6,7 @@ const PluginRegistry = require('./plugins'); const serverProxy = require('./server-proxy'); const { ArgumentError } = require('./exceptions'); - const { CredentialsType, ProviderType } = require('./enums'); + const { CloudStorageCredentialsType, CloudStorageProviderType } = require('./enums'); /** * Class representing a cloud storage @@ -17,20 +17,20 @@ constructor(initialData) { const data = { id: undefined, - displayName: undefined, + display_name: undefined, description: undefined, - credentialsType: undefined, - provider: undefined, - resourceName: undefined, - accountName: undefined, - accesskey: undefined, - secretKey: undefined, - token: undefined, - specificAttibutes: undefined, + credentials_type: undefined, + provider_type: undefined, + resource: undefined, + account_name: undefined, + key: undefined, + secret_key: undefined, + session_token: undefined, + specific_attibutes: undefined, owner: undefined, created_date: undefined, updated_date: undefined, - manifestPath: undefined, + manifest_path: undefined, }; for (const property in data) { @@ -61,12 +61,14 @@ * @throws {module:API.cvat.exceptions.ArgumentError} */ displayName: { - get: () => data.displayName, + get: () => data.display_name, set: (value) => { - if (!value.trim().length) { - throw new ArgumentError('Value must not be empty'); + if (typeof value !== 'string') { + throw new ArgumentError(`Value must be string. ${typeof value} was found`); + } else if (!value.trim().length) { + throw new ArgumentError('Value must not be empty string'); } - data.displayName = value; + data.display_name = value; }, }, /** @@ -75,15 +77,19 @@ * @type {string} * @memberof module:API.cvat.classes.CloudStorage * @instance + * @throws {module:API.cvat.exceptions.ArgumentError} */ description: { get: () => data.description, set: (value) => { + if (typeof value !== 'string') { + throw new ArgumentError('Value must be string'); + } data.description = value; }, }, /** - * Account name (for Azure) + * Azure account name * @name accountName * @type {string} * @memberof module:API.cvat.classes.CloudStorage @@ -91,14 +97,16 @@ * @throws {module:API.cvat.exceptions.ArgumentError} */ accountName: { - get: () => data.accountName, + get: () => data.account_name, set: (value) => { if (typeof value === 'string') { if (value.trim().length) { - data.accountName = value; + data.account_name = value; } else { throw new ArgumentError('Value must not be empty'); } + } else { + throw new ArgumentError(`Value must be a string. ${typeof value} was found`); } }, }, @@ -111,14 +119,16 @@ * @throws {module:API.cvat.exceptions.ArgumentError} */ accessKey: { - get: () => data.accessKey, + get: () => data.key, set: (value) => { if (typeof value === 'string') { if (value.trim().length) { - data.accesskey = value; + data.key = value; } else { throw new ArgumentError('Value must not be empty'); } + } else { + throw new ArgumentError(`Value must be a string. ${typeof value} was found`); } }, }, @@ -131,14 +141,16 @@ * @throws {module:API.cvat.exceptions.ArgumentError} */ secretKey: { - get: () => data.secretKey, + get: () => data.secret_key, set: (value) => { if (typeof value === 'string') { if (value.trim().length) { - data.secretKey = value; + data.secret_key = value; } else { throw new ArgumentError('Value must not be empty'); } + } else { + throw new ArgumentError(`Value must be a string. ${typeof value} was found`); } }, }, @@ -151,14 +163,16 @@ * @throws {module:API.cvat.exceptions.ArgumentError} */ token: { - get: () => data.token, + get: () => data.session_token, set: (value) => { if (typeof value === 'string') { if (value.trim().length) { - data.token = value; + data.session_token = value; } else { throw new ArgumentError('Value must not be empty'); } + } else { + throw new ArgumentError(`Value must be a string. ${typeof value} was found`); } }, }, @@ -171,12 +185,14 @@ * @throws {module:API.cvat.exceptions.ArgumentError} */ resourceName: { - get: () => data.resourceName, + get: () => data.resource, set: (value) => { - if (!value.trim().length) { + if (typeof value !== 'string') { + throw new ArgumentError(`Value must be string. ${typeof value} was found`); + } else if (!value.trim().length) { throw new ArgumentError('Value must not be empty'); } - data.resourceName = value; + data.resource = value; }, }, /** @@ -184,12 +200,15 @@ * @type {string} * @memberof module:API.cvat.classes.CloudStorage * @instance + * @throws {module:API.cvat.exceptions.ArgumentError} */ manifestPath: { - get: () => data.manifestPath, + get: () => data.manifest_path, set: (value) => { - if (typeof value !== undefined) { - data.manifestPath = value; + if (typeof value !== 'string') { + data.manifest_path = value; + } else { + throw new ArgumentError('Value must be a string'); } }, }, @@ -201,29 +220,29 @@ * @throws {module:API.cvat.exceptions.ArgumentError} */ provider: { - get: () => data.provider, - set: (value) => { - if (value !== undefined && !!ProviderType[value]) { - data.provider = value; + get: () => data.provider_type, + set: (key) => { + if (key !== undefined && !!CloudStorageProviderType[key]) { + data.provider_type = CloudStorageProviderType[key]; } else { - throw new ArgumentError('Value must be one from ProviderType values'); + throw new ArgumentError('Value must be one CloudStorageProviderType keys'); } }, }, /** * @name credentialsType - * @type {module:API.cvat.enums.CredentialsType} + * @type {module:API.cvat.enums.CloudStorageCredentialsType} * @memberof module:API.cvat.classes.CloudStorage * @instance * @throws {module:API.cvat.exceptions.ArgumentError} */ credentialsType: { - get: () => data.credentialsType, - set: (value) => { - if (value !== undefined && !!CredentialsType[value]) { - data.credentialsType = value; + get: () => data.credentials_type, + set: (key) => { + if (key !== undefined && !!CloudStorageCredentialsType[key]) { + data.credentials_type = CloudStorageCredentialsType[key]; } else { - throw new ArgumentError('Value must be one from CredentialsType values'); + throw new ArgumentError('Value must be one CloudStorageCredentialsType keys'); } }, }, @@ -235,18 +254,20 @@ * @throws {module:API.cvat.exceptions.ArgumentError} */ specificAttibutes: { - get: () => data.specificAttibutes, + get: () => data.specific_attibutes, set: (attributesValue) => { if (typeof attributesValue === 'string') { - for (const keyValuePair of attributesValue.split('&')) { - const [key, value] = keyValuePair.split('='); - if (key && value) { - throw new ArgumentError('Value mast match the key1=value1&key2=value2'); - } + const attrValues = new URLSearchParams( + Array.from(new URLSearchParams(attributesValue).entries()).filter( + ([key, value]) => !!key && !!value, + ), + ).toString(); + if (!attrValues) { + throw new ArgumentError('Value must match the key1=value1&key2=value2'); } - data.specificAttibutes = attributesValue; + data.specific_attibutes = attributesValue; } else { - throw new ArgumentError('Value mast be string'); + throw new ArgumentError('Value must be a string'); } }, }, @@ -281,9 +302,6 @@ updatedDate: { get: () => data.updated_date, }, - // _internalData: { - // get: () => data, - // }, }), ); } @@ -339,28 +357,28 @@ // update if (typeof this.id !== 'undefined') { const cloudStorageData = { - displayName: this.displayName, + display_name: this.displayName, description: this.description ? this.description : null, - credentialsType: this.credentialsType ? this.credentialsType : null, - provided: this.provider ? this.provider : null, - resourceName: this.resourceName ? this.resourceName : null, - secretKey: this.secretKey ? this.secretKey : null, - token: this.token ? this.token : null, - accessKey: this.accessKey ? this.accessKey : null, - accountName: this.accountName ? this.accountName : null, - specificAttibutes: this.specificAttibutes ? this.specificAttibutes : null, + credentials_type: this.credentialsType ? this.credentialsType : null, + provided_type: this.provider ? this.provider : null, + resource: this.resourceName ? this.resourceName : null, + secret_key: this.secretKey ? this.secretKey : null, + session_token: this.token ? this.token : null, + key: this.accessKey ? this.accessKey : null, + account_name: this.accountName ? this.accountName : null, + specific_attibutes: this.specificAttibutes ? this.specificAttibutes : null, }; - await serverProxy.cloudStorage.save(this.id, cloudStorageData); + await serverProxy.cloudStorages.update(this.id, cloudStorageData); return this; } // create const cloudStorageData = { - displayName: this.displayName, - credentialsType: this.credentialsType, - provider: this.provider, - resourceName: this.resourceName, + display_name: this.displayName, + credentials_type: this.credentialsType, + provider_type: this.provider, + resource: this.resourceName, }; if (this.description) { @@ -368,23 +386,23 @@ } if (this.accountName) { - cloudStorageData.accountName = this.accountName; + cloudStorageData.account_name = this.accountName; } if (this.accessKey) { - cloudStorageData.accessKey = this.accessKey; + cloudStorageData.key = this.accessKey; } if (this.secretKey) { - cloudStorageData.secretKey = this.secretKey; + cloudStorageData.secret_key = this.secretKey; } if (this.token) { - cloudStorageData.token = this.token; + cloudStorageData.session_token = this.token; } if (this.specificAttibutes) { - cloudStorageData.specificAttibutes = this.specificAttibutes; + cloudStorageData.specific_attibutes = this.specificAttibutes; } const cloudStorage = await serverProxy.cloudStorages.create(cloudStorageData); @@ -397,7 +415,7 @@ }; CloudStorage.prototype.getContent.implementation = async function () { - const result = await serverProxy.cloudStorage.getContent(this.id, this.manifestPath); + const result = await serverProxy.cloudStorages.getContent(this.id, this.manifestPath); return result; }; diff --git a/cvat-core/src/enums.js b/cvat-core/src/enums.js index e5fbffe02ad4..405b0629a6c7 100644 --- a/cvat-core/src/enums.js +++ b/cvat-core/src/enums.js @@ -334,30 +334,30 @@ ]; /** - * Provider types + * Types of cloud storage providers * @enum {string} - * @name ProviderType + * @name CloudStorageProviderType * @memberof module:API.cvat.enums * @property {string} AWS_S3 'AWS_S3_BUCKET' * @property {string} AZURE 'AZURE_BLOB_CONTAINER' * @readonly */ - const ProviderType = Object.freeze({ - AWS_S3: 'AWS_S3_BUCKET', - AZURE: 'AZURE_BLOB_CONTAINER', + const CloudStorageProviderType = Object.freeze({ + AWS_S3_BUCKET: 'AWS_S3_BUCKET', + AZURE_BLOB_CONTAINER: 'AZURE_BLOB_CONTAINER', }); /** * Types of cloud storage credentials * @enum {string} - * @name CredentialsType + * @name CloudStorageCredentialsType * @memberof module:API.cvat.enums * @property {string} TEMP_KEY_SECRET_KEY_TOKEN_SET 'TEMP_KEY_SECRET_KEY_TOKEN_SET' * @property {string} ACCOUNT_NAME_TOKEN_PAIR 'ACCOUNT_NAME_TOKEN_PAIR' * @property {string} ANONYMOUS_ACCESS 'ANONYMOUS_ACCESS' * @readonly */ - const CredentialsType = Object.freeze({ + const CloudStorageCredentialsType = Object.freeze({ TEMP_KEY_SECRET_KEY_TOKEN_SET: 'TEMP_KEY_SECRET_KEY_TOKEN_SET', ACCOUNT_NAME_TOKEN_PAIR: 'ACCOUNT_NAME_TOKEN_PAIR', ANONYMOUS_ACCESS: 'ANONYMOUS_ACCESS', @@ -378,7 +378,7 @@ colors, Source, DimensionType, - ProviderType, - CredentialsType, + CloudStorageProviderType, + CloudStorageCredentialsType, }; })(); diff --git a/cvat-core/src/server-proxy.js b/cvat-core/src/server-proxy.js index 35eaa4213397..fa77a7199cbf 100644 --- a/cvat-core/src/server-proxy.js +++ b/cvat-core/src/server-proxy.js @@ -1133,7 +1133,7 @@ } } - async function saveCloudStorage(id, cloudStorageData) { + async function updateCloudStorage(id, cloudStorageData) { const { backendAPI } = config; try { @@ -1169,7 +1169,7 @@ let response = null; try { const url = manifestPath - ? `${backendAPI}/cloudstorages/${id}/content?manifest=${manifestPath}` + ? `${backendAPI}/cloudstorages/${id}/content?manifest_path=${manifestPath}` : `${backendAPI}/cloudstorages/${id}/content`; response = await Axios.get(url, { proxy: config.proxy, @@ -1318,13 +1318,13 @@ writable: false, }, - cloudstorage: { + cloudStorages: { value: Object.freeze({ - getCloudStorages, + get: getCloudStorages, getContent: getCloudStorageContent, create: createCloudStorage, delete: deleteCloudStorage, - save: saveCloudStorage, + update: updateCloudStorage, }), writable: false, }, From e86dd6f3d2867e87c560d7220a012ba5243434e2 Mon Sep 17 00:00:00 2001 From: Maya Date: Tue, 15 Jun 2021 13:07:28 +0300 Subject: [PATCH 05/97] small update --- cvat-core/src/server-proxy.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cvat-core/src/server-proxy.js b/cvat-core/src/server-proxy.js index fa77a7199cbf..da0001f0c19b 100644 --- a/cvat-core/src/server-proxy.js +++ b/cvat-core/src/server-proxy.js @@ -1168,9 +1168,9 @@ let response = null; try { - const url = manifestPath - ? `${backendAPI}/cloudstorages/${id}/content?manifest_path=${manifestPath}` - : `${backendAPI}/cloudstorages/${id}/content`; + const url = `${backendAPI}/cloudstorages/${id}/content${ + manifestPath ? `?manifest_path=${manifestPath}` : '' + }`; response = await Axios.get(url, { proxy: config.proxy, }); From 113a4faadbef1f632f3d0d43bf50fea34297d644 Mon Sep 17 00:00:00 2001 From: Maya Date: Tue, 15 Jun 2021 16:33:50 +0300 Subject: [PATCH 06/97] Init --- cvat-ui/src/actions/cloud-storage-actions.ts | 198 +++++++++++++ cvat-ui/src/base.scss | 2 + .../create-cloud-storage-content.tsx | 263 ++++++++++++++++++ .../create-cloud-storage-page.tsx | 29 ++ .../create-cloud-storage-page/styles.scss | 51 ++++ cvat-ui/src/components/enums.tsx | 25 ++ .../components/file-manager/file-manager.tsx | 46 ++- .../src/components/file-manager/styles.scss | 16 ++ cvat-ui/src/components/header/header.tsx | 12 + cvat-ui/src/reducers/cloud-storage-reducer.ts | 191 +++++++++++++ cvat-ui/src/reducers/interfaces.ts | 48 ++++ cvat-ui/src/reducers/notifications-reducer.ts | 78 ++++++ 12 files changed, 957 insertions(+), 2 deletions(-) create mode 100644 cvat-ui/src/actions/cloud-storage-actions.ts create mode 100644 cvat-ui/src/components/create-cloud-storage-page/create-cloud-storage-content.tsx create mode 100644 cvat-ui/src/components/create-cloud-storage-page/create-cloud-storage-page.tsx create mode 100644 cvat-ui/src/components/create-cloud-storage-page/styles.scss create mode 100644 cvat-ui/src/components/enums.tsx create mode 100644 cvat-ui/src/reducers/cloud-storage-reducer.ts diff --git a/cvat-ui/src/actions/cloud-storage-actions.ts b/cvat-ui/src/actions/cloud-storage-actions.ts new file mode 100644 index 000000000000..14a983a62554 --- /dev/null +++ b/cvat-ui/src/actions/cloud-storage-actions.ts @@ -0,0 +1,198 @@ +// Copyright (C) 2021 Intel Corporation +// +// SPDX-License-Identifier: MIT + +import { AnyAction, Dispatch, ActionCreator } from 'redux'; +import { ThunkAction } from 'utils/redux'; +import getCore from 'cvat-core-wrapper'; +import { CloudStoragesQuery } from 'reducers/interfaces'; // CloudStorage + +const cvat = getCore(); + +export enum CloudStorageActionsTypes { + // GET_FILE = 'GET_FILE', + // GET_FILE_SUCCESS = 'GET_FILES_SUCCESS', + // GET_FILE_FAILED = 'GET_FILE_FAILED', + GET_CLOUD_STORAGES = 'GET_CLOUD_STORAGES', + GET_CLOUD_STORAGE_SUCCESS = 'GET_CLOUD_STORAGES_SUCCESS', + GET_CLOUD_STORAGE_FAILED = 'GET_CLOUD_STORAGES_FAILED', + CREATE_CLOUD_STORAGE = 'CREATE_CLOUD_STORAGE', + CREATE_CLOUD_STORAGE_SUCCESS = 'CREATE_CLOUD_STORAGE_SUCCESS', + CREATE_CLOUD_STORAGE_FAILED = 'CREATE_CLOUD_STORAGE_FAILED', + DELETE_CLOUD_STORAGE = 'DELETE_CLOUD_STORAGE', + DELETE_CLOUD_STORAGE_SUCCESS = 'DELETE_CLOUD_STORAGE_SUCCESS', + DELETE_CLOUD_STORAGE_FAILED = 'DELETE_CLOUD_STORAGE_FAILED', + UPDATE_CLOUD_STORAGE = 'UPDATE_CLOUD_STORAGE', + UPDATE_CLOUD_STORAGE_SUCCESS = 'UPDATE_CLOUD_STORAGE_SUCCESS', + UPDATE_CLOUD_STORAGE_FAILED = 'UPDATE_CLOUD_STORAGE_FAILED', + LOAD_CLOUD_STORAGE_CONTENT = 'LOAD_CLOUD_STORAGE_CONTENT', + LOAD_CLOUD_STORAGE_CONTENT_FAILED = 'LOAD_CLOUD_STORAGE_CONTENT_FAILED', + LOAD_CLOUD_STORAGE_CONTENT_SUCCESS = 'LOAD_CLOUD_STORAGE_CONTENT_SUCCESS', +} + +// TODO +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function getCloudStorages(): AnyAction { + const action = { + type: CloudStorageActionsTypes.GET_CLOUD_STORAGES, + payload: {}, + }; + + return action; +} + +// TODO +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function getCloudStoragesSuccess( + array: any[], + previews: string[], + count: number, + query: CloudStoragesQuery, +): AnyAction { + const action = { + type: CloudStorageActionsTypes.GET_CLOUD_STORAGE_SUCCESS, + payload: { + previews, + array, + count, + query, + }, + }; + + return action; +} + +// TODO +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function getCloudStoragesFailed(error: any, query: CloudStoragesQuery): AnyAction { + const action = { + type: CloudStorageActionsTypes.GET_CLOUD_STORAGE_FAILED, + payload: { + error, + query, + }, + }; + + return action; +} + +// export function CloudStoragesAsync(query: CloudStoragesQuery): ThunkAction { +// return async (dispatch: ActionCreator): Promise => { +// dispatch(getCloudStorages()); + +// // We need remove all keys with null values from query +// const filteredQuery = { ...query }; +// for (const key in filteredQuery) { +// if (filteredQuery[key] === null) { +// delete filteredQuery[key]; +// } +// } + +// let result = null; +// try { +// result = await cvat.cloudStorages.get(filteredQuery); +// } catch (error) { +// dispatch(getCloudStoragesFailed(error, query)); +// return; +// } + +// const array = Array.from(result); +// const promises = array.map((cloudStorage: CloudStorage): +// string => (cloudStorage as any).frames.preview().catch(() => '')); + +// dispatch(getCloudStoragesSuccess(array, await Promise.all(promises), result.count, query)); +// }; +// } + +function deleteCloudStorage(cloudStorageID: number): AnyAction { + const action = { + type: CloudStorageActionsTypes.DELETE_CLOUD_STORAGE, + payload: { + cloudStorageID, + }, + }; + + return action; +} + +function deleteCloudStorageSuccess(cloudStorageID: number): AnyAction { + const action = { + type: CloudStorageActionsTypes.DELETE_CLOUD_STORAGE_SUCCESS, + payload: { + cloudStorageID, + }, + }; + + return action; +} + +function deleteCloudStorageFailed(cloudStorageID: number, error: any): AnyAction { + const action = { + type: CloudStorageActionsTypes.DELETE_CLOUD_STORAGE_FAILED, + payload: { + cloudStorageID, + error, + }, + }; + + return action; +} + +export function deleteCloudStorageAsync(cloudStorageInstance: any): ThunkAction { + return async (dispatch: ActionCreator): Promise => { + try { + dispatch(deleteCloudStorage(cloudStorageInstance.id)); + await cloudStorageInstance.delete(); + } catch (error) { + dispatch(deleteCloudStorageFailed(cloudStorageInstance.id, error)); + return; + } + + dispatch(deleteCloudStorageSuccess(cloudStorageInstance.id)); + }; +} + +function createCloudStorage(): AnyAction { + const action = { + type: CloudStorageActionsTypes.CREATE_CLOUD_STORAGE, + payload: {}, + }; + + return action; +} + +function createCloudStorageSuccess(cloudStorageId: number): AnyAction { + const action = { + type: CloudStorageActionsTypes.CREATE_CLOUD_STORAGE_SUCCESS, + payload: { + cloudStorageId, + }, + }; + + return action; +} + +function createCloudStorageFailed(error: any): AnyAction { + const action = { + type: CloudStorageActionsTypes.CREATE_CLOUD_STORAGE_FAILED, + payload: { + error, + }, + }; + + return action; +} + +export function createCloudStorageAsync(data: any): ThunkAction { + return async (dispatch: ActionCreator): Promise => { + const cloudStorageInstance = new cvat.classes.CloudStorage(data); + + dispatch(createCloudStorage()); + try { + const savedCloudStorage = await cloudStorageInstance.save(); + dispatch(createCloudStorageSuccess(savedCloudStorage.id)); + } catch (error) { + dispatch(createCloudStorageFailed(error)); + } + }; +} diff --git a/cvat-ui/src/base.scss b/cvat-ui/src/base.scss index 4097dbe04692..370be9d02b25 100644 --- a/cvat-ui/src/base.scss +++ b/cvat-ui/src/base.scss @@ -35,6 +35,8 @@ $objects-bar-icons-color: #242424; // #6e6e6e $active-label-background-color: #d8ecff; $object-item-border-color: rgba(0, 0, 0, 0.7); $slider-color: #1890ff; +$cansel-button-color1: #b8b8b8; +$cansel-button-color2: #c7c7c7; $box-shadow-base: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05); diff --git a/cvat-ui/src/components/create-cloud-storage-page/create-cloud-storage-content.tsx b/cvat-ui/src/components/create-cloud-storage-page/create-cloud-storage-content.tsx new file mode 100644 index 000000000000..38f72da43d4c --- /dev/null +++ b/cvat-ui/src/components/create-cloud-storage-page/create-cloud-storage-content.tsx @@ -0,0 +1,263 @@ +// Copyright (C) 2020-2021 Intel Corporation +// +// SPDX-License-Identifier: MIT + +import React from 'react'; +import { RouteComponentProps } from 'react-router'; // useHistory +import { withRouter } from 'react-router-dom'; +import { Row, Col } from 'antd/lib/grid'; +import Button from 'antd/lib/button'; +import Form, { FormInstance } from 'antd/lib/form'; +import Select from 'antd/lib/select'; +import Input from 'antd/lib/input'; +import TextArea from 'antd/lib/input/TextArea'; +import { ProviderType, CredentialsType } from '../enums'; + +export interface CreateCloudStorageData { + providerType: ProviderType | null; + credentialsType: CredentialsType | null; + resource: string | null; + displayName: string | null; +} + +interface Props { + onCreate: (data: CreateCloudStorageData) => void; + status: string; + cloudStorageId: number | null; +} + +interface State { + providerType: ProviderType | null | string; + displayName: string; + resource: string; + credentialsType: null | CredentialsType | string; +} + +const defaultState = { + providerType: null, + credentialsType: null, + resource: '', + displayName: '', +}; + +class CreateCloudStorageContent extends React.PureComponent { + formRef = React.createRef(); + + public constructor(props: Props & RouteComponentProps) { + super(props); + this.state = { ...defaultState }; + } + + onSumbit = async (): Promise => { + let cloudStorageData: Record = {}; + if (this.formRef.current) { + const formValues = await this.formRef.current.validateFields(); + cloudStorageData = { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ...cloudStorageData, + ...formValues, + }; + } + }; + + onReset = (): void => { + this.formRef.current?.resetFields(); + }; + + private selectProviderType = (newProviderType: ProviderType | null | string): void => { + const curentState = this.state; + this.setState({ + ...curentState, + providerType: newProviderType, + credentialsType: null, + }); + }; + + private selectCredentialsType = (newCredentialsType: CredentialsType | null | string): void => { + const currentState = this.state; + this.setState({ + ...currentState, + credentialsType: newCredentialsType, + }); + }; + + private renderCredentialsBlok(): JSX.Element { + const { credentialsType, providerType } = this.state; + let credentials; + switch (providerType && credentialsType) { + case ProviderType.AWS_S3_BUCKET && CredentialsType.TEMP_KEY_SECRET_KEY_TOKEN_SET: { + credentials = ( + <> + + + + + + + + + + + ); + break; + } + case ProviderType.AZURE_BLOB_CONTAINER && CredentialsType.ACCOUNT_NAME_TOKEN_PAIR: { + credentials = ( + <> + + + + + + + + ); + break; + } + default: { + credentials = <>; + break; + } + } + + return credentials; + } + + private renderAWSS3Configuration(): JSX.Element { + return ( + <> + + + + + + + {this.renderCredentialsBlok()} + + ); + } + + private renderAzureBlobStorageConfiguration(): JSX.Element { + return ( + <> + + + + + + + {/* TODO: need to change selected value on credentials + type to "default" when provider type value changes */} + {this.renderCredentialsBlok()} + + ); + } + + public render(): JSX.Element { + const { providerType } = this.state; + + return ( + + +
+ + + + +