diff --git a/cvat-core/src/server-proxy.ts b/cvat-core/src/server-proxy.ts index 4cafdb8e..6deb7b73 100644 --- a/cvat-core/src/server-proxy.ts +++ b/cvat-core/src/server-proxy.ts @@ -205,1596 +205,1487 @@ class WorkerWrappedAxios { } } -class ServerProxy { - constructor() { - Axios.defaults.withCredentials = true; - Axios.defaults.xsrfHeaderName = 'X-CSRFTOKEN'; - Axios.defaults.xsrfCookieName = 'csrftoken'; - const workerAxios = new WorkerWrappedAxios(); - Axios.interceptors.request.use((reqConfig) => { - if ('params' in reqConfig && 'org' in reqConfig.params) { - return reqConfig; - } - - const organization = enableOrganization(); - // for users when organization is unset - // we are interested in getting all the users, - // not only those who are not in any organization - if (reqConfig.url.endsWith('/users') && !organization.org) { - return reqConfig; - } - - reqConfig.params = { ...organization, ...(reqConfig.params || {}) }; - return reqConfig; - }); - - let token = store.get('token'); - if (token) { - Axios.defaults.headers.common.Authorization = `Token ${token}`; - } +Axios.defaults.withCredentials = true; +Axios.defaults.xsrfHeaderName = 'X-CSRFTOKEN'; +Axios.defaults.xsrfCookieName = 'csrftoken'; +const workerAxios = new WorkerWrappedAxios(); +Axios.interceptors.request.use((reqConfig) => { + if ('params' in reqConfig && 'org' in reqConfig.params) { + return reqConfig; + } - async function about() { - const { backendAPI } = config; + const organization = enableOrganization(); + // for users when organization is unset + // we are interested in getting all the users, + // not only those who are not in any organization + if (reqConfig.url.endsWith('/users') && !organization.org) { + return reqConfig; + } - let response = null; - try { - response = await Axios.get(`${backendAPI}/server/about`, { - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } + reqConfig.params = { ...organization, ...(reqConfig.params || {}) }; + return reqConfig; +}); - return response.data; - } +let token = store.get('token'); +if (token) { + Axios.defaults.headers.common.Authorization = `Token ${token}`; +} - async function share(directoryArg) { - const { backendAPI } = config; +async function about() { + const { backendAPI } = config; - let response = null; - try { - response = await Axios.get(`${backendAPI}/server/share`, { - proxy: config.proxy, - params: { directory: directoryArg }, - }); - } catch (errorData) { - throw generateError(errorData); - } + let response = null; + try { + response = await Axios.get(`${backendAPI}/server/about`, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } - return response.data; - } + return response.data; +} - async function exception(exceptionObject) { - const { backendAPI } = config; +async function share(directoryArg) { + const { backendAPI } = config; - try { - await Axios.post(`${backendAPI}/server/exception`, JSON.stringify(exceptionObject), { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } - } + let response = null; + try { + response = await Axios.get(`${backendAPI}/server/share`, { + proxy: config.proxy, + params: { directory: directoryArg }, + }); + } catch (errorData) { + throw generateError(errorData); + } - async function formats() { - const { backendAPI } = config; + return response.data; +} - let response = null; - try { - response = await Axios.get(`${backendAPI}/server/annotation/formats`, { - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } +async function exception(exceptionObject) { + const { backendAPI } = config; - return response.data; - } + try { + await Axios.post(`${backendAPI}/server/exception`, JSON.stringify(exceptionObject), { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } +} - async function userAgreements() { - const { backendAPI } = config; - let response = null; - try { - response = await Axios.get(`${backendAPI}/user-agreements`, { - proxy: config.proxy, - validateStatus: (status) => status === 200 || status === 404, - }); +async function formats() { + const { backendAPI } = config; - if (response.status === 200) { - return response.data; - } + let response = null; + try { + response = await Axios.get(`${backendAPI}/server/annotation/formats`, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } - return []; - } catch (errorData) { - throw generateError(errorData); - } - } + return response.data; +} - async function register(username, firstName, lastName, email, password, confirmations) { - let response = null; - try { - const data = JSON.stringify({ - username, - first_name: firstName, - last_name: lastName, - email, - password1: password, - password2: password, - confirmations, - }); - response = await Axios.post(`${config.backendAPI}/auth/register`, data, { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } +async function userAgreements() { + const { backendAPI } = config; + let response = null; + try { + response = await Axios.get(`${backendAPI}/user-agreements`, { + proxy: config.proxy, + validateStatus: (status) => status === 200 || status === 404, + }); + if (response.status === 200) { return response.data; } - async function login(credential, password) { - const authenticationData = [ - `${encodeURIComponent(isEmail(credential) ? 'email' : 'username')}=${encodeURIComponent(credential)}`, - `${encodeURIComponent('password')}=${encodeURIComponent(password)}`, - ] - .join('&') - .replace(/%20/g, '+'); + return []; + } catch (errorData) { + throw generateError(errorData); + } +} - removeToken(); - let authenticationResponse = null; - try { - authenticationResponse = await Axios.post(`${config.backendAPI}/auth/login`, authenticationData, { - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } +async function register(username, firstName, lastName, email, password, confirmations) { + let response = null; + try { + const data = JSON.stringify({ + username, + first_name: firstName, + last_name: lastName, + email, + password1: password, + password2: password, + confirmations, + }); + response = await Axios.post(`${config.backendAPI}/auth/register`, data, { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } - if (authenticationResponse.headers['set-cookie']) { - // Browser itself setup cookie and header is none - // In NodeJS we need do it manually - const cookies = authenticationResponse.headers['set-cookie'].join(';'); - Axios.defaults.headers.common.Cookie = cookies; - } + return response.data; +} - token = authenticationResponse.data.key; - store.set('token', token); - Axios.defaults.headers.common.Authorization = `Token ${token}`; - } +async function login(credential, password) { + const authenticationData = [ + `${encodeURIComponent(isEmail(credential) ? 'email' : 'username')}=${encodeURIComponent(credential)}`, + `${encodeURIComponent('password')}=${encodeURIComponent(password)}`, + ] + .join('&') + .replace(/%20/g, '+'); + + removeToken(); + let authenticationResponse = null; + try { + authenticationResponse = await Axios.post(`${config.backendAPI}/auth/login`, authenticationData, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } - async function logout() { - try { - await Axios.post(`${config.backendAPI}/auth/logout`, { - proxy: config.proxy, - }); - removeToken(); - } catch (errorData) { - throw generateError(errorData); - } - } + if (authenticationResponse.headers['set-cookie']) { + // Browser itself setup cookie and header is none + // In NodeJS we need do it manually + const cookies = authenticationResponse.headers['set-cookie'].join(';'); + Axios.defaults.headers.common.Cookie = cookies; + } - async function changePassword(oldPassword, newPassword1, newPassword2) { - try { - const data = JSON.stringify({ - old_password: oldPassword, - new_password1: newPassword1, - new_password2: newPassword2, - }); - await Axios.post(`${config.backendAPI}/auth/password/change`, data, { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } - } + token = authenticationResponse.data.key; + store.set('token', token); + Axios.defaults.headers.common.Authorization = `Token ${token}`; +} - async function requestPasswordReset(email) { - try { - const data = JSON.stringify({ - email, - }); - await Axios.post(`${config.backendAPI}/auth/password/reset`, data, { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } - } +async function logout() { + try { + await Axios.post(`${config.backendAPI}/auth/logout`, { + proxy: config.proxy, + }); + removeToken(); + } catch (errorData) { + throw generateError(errorData); + } +} - async function resetPassword(newPassword1, newPassword2, uid, _token) { - try { - const data = JSON.stringify({ - new_password1: newPassword1, - new_password2: newPassword2, - uid, - token: _token, - }); - await Axios.post(`${config.backendAPI}/auth/password/reset/confirm`, data, { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } - } +async function changePassword(oldPassword, newPassword1, newPassword2) { + try { + const data = JSON.stringify({ + old_password: oldPassword, + new_password1: newPassword1, + new_password2: newPassword2, + }); + await Axios.post(`${config.backendAPI}/auth/password/change`, data, { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } +} - async function getSelf() { - const { backendAPI } = config; +async function requestPasswordReset(email) { + try { + const data = JSON.stringify({ + email, + }); + await Axios.post(`${config.backendAPI}/auth/password/reset`, data, { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } +} - let response = null; - try { - response = await Axios.get(`${backendAPI}/users/self`, { - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } +async function resetPassword(newPassword1, newPassword2, uid, _token) { + try { + const data = JSON.stringify({ + new_password1: newPassword1, + new_password2: newPassword2, + uid, + token: _token, + }); + await Axios.post(`${config.backendAPI}/auth/password/reset/confirm`, data, { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } +} - return response.data; - } +async function getSelf() { + const { backendAPI } = config; - async function authorized() { - try { - const response = await getSelf(); - if (!store.get('token')) { - store.set('token', response.key); - Axios.defaults.headers.common.Authorization = `Token ${response.key}`; - } - } catch (serverError) { - if (serverError.code === 401) { - // In CVAT app we use two types of authentication, - // So here we are forcing user have both credential types - // First request will fail if session is expired, then we check - // for precense of token - await logout(); - return false; - } + let response = null; + try { + response = await Axios.get(`${backendAPI}/users/self`, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } - throw serverError; - } + return response.data; +} - return true; +async function authorized() { + try { + const response = await getSelf(); + if (!store.get('token')) { + store.set('token', response.key); + Axios.defaults.headers.common.Authorization = `Token ${response.key}`; } - - async function serverRequest(url, data) { - try { - return ( - await Axios({ - url, - ...data, - }) - ).data; - } catch (errorData) { - throw generateError(errorData); - } + } catch (serverError) { + if (serverError.code === 401) { + // In CVAT app we use two types of authentication, + // So here we are forcing user have both credential types + // First request will fail if session is expired, then we check + // for precense of token + await logout(); + return false; } - async function searchProjectNames(search, limit) { - const { backendAPI, proxy } = config; + throw serverError; + } - let response = null; - try { - response = await Axios.get(`${backendAPI}/projects`, { - proxy, - params: { - names_only: true, - page: 1, - page_size: limit, - search, - }, - }); - } catch (errorData) { - throw generateError(errorData); - } + return true; +} - response.data.results.count = response.data.count; - return response.data.results; - } +async function serverRequest(url, data) { + try { + return ( + await Axios({ + url, + ...data, + }) + ).data; + } catch (errorData) { + throw generateError(errorData); + } +} - async function getProjects(filter = {}) { - const { backendAPI, proxy } = config; +async function searchProjectNames(search, limit) { + const { backendAPI, proxy } = config; + + let response = null; + try { + response = await Axios.get(`${backendAPI}/projects`, { + proxy, + params: { + names_only: true, + page: 1, + page_size: limit, + search, + }, + }); + } catch (errorData) { + throw generateError(errorData); + } - let response = null; - try { - if ('id' in filter) { - response = await Axios.get(`${backendAPI}/projects/${filter.id}`, { - proxy, - }); - const results = [response.data]; - results.count = 1; - return results; - } + response.data.results.count = response.data.count; + return response.data.results; +} - response = await Axios.get(`${backendAPI}/projects`, { - params: { - ...filter, - page_size: 12, - }, - proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } +async function getProjects(filter = {}) { + const { backendAPI, proxy } = config; - response.data.results.count = response.data.count; - return response.data.results; + let response = null; + try { + if ('id' in filter) { + response = await Axios.get(`${backendAPI}/projects/${filter.id}`, { + proxy, + }); + const results = [response.data]; + results.count = 1; + return results; } - async function saveProject(id, projectData) { - const { backendAPI } = config; + response = await Axios.get(`${backendAPI}/projects`, { + params: { + ...filter, + page_size: 12, + }, + proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } - try { - await Axios.patch(`${backendAPI}/projects/${id}`, JSON.stringify(projectData), { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } - } + response.data.results.count = response.data.count; + return response.data.results; +} - async function deleteProject(id) { - const { backendAPI } = config; +async function saveProject(id, projectData) { + const { backendAPI } = config; - try { - await Axios.delete(`${backendAPI}/projects/${id}`, { - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } - } + try { + await Axios.patch(`${backendAPI}/projects/${id}`, JSON.stringify(projectData), { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } +} - async function createProject(projectSpec) { - const { backendAPI } = config; +async function deleteProject(id) { + const { backendAPI } = config; - try { - const response = await Axios.post(`${backendAPI}/projects`, JSON.stringify(projectSpec), { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - return response.data; - } catch (errorData) { - throw generateError(errorData); - } - } + try { + await Axios.delete(`${backendAPI}/projects/${id}`, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } +} - async function getTasks(filter = {}) { - const { backendAPI } = config; +async function createProject(projectSpec) { + const { backendAPI } = config; - let response = null; - try { - if ('id' in filter) { - response = await Axios.get(`${backendAPI}/tasks/${filter.id}`, { - proxy: config.proxy, - }); - const results = [response.data]; - results.count = 1; - return results; - } + try { + const response = await Axios.post(`${backendAPI}/projects`, JSON.stringify(projectSpec), { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + return response.data; + } catch (errorData) { + throw generateError(errorData); + } +} - response = await Axios.get(`${backendAPI}/tasks`, { - params: { - ...filter, - page_size: 10, - }, - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } +async function getTasks(filter = {}) { + const { backendAPI } = config; - response.data.results.count = response.data.count; - return response.data.results; + let response = null; + try { + if ('id' in filter) { + response = await Axios.get(`${backendAPI}/tasks/${filter.id}`, { + proxy: config.proxy, + }); + const results = [response.data]; + results.count = 1; + return results; } - async function saveTask(id, taskData) { - const { backendAPI } = config; + response = await Axios.get(`${backendAPI}/tasks`, { + params: { + ...filter, + page_size: 10, + }, + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } - let response = null; - try { - response = await Axios.patch(`${backendAPI}/tasks/${id}`, JSON.stringify(taskData), { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } - - return response.data; - } - - async function deleteTask(id, organizationID = null) { - const { backendAPI } = config; + response.data.results.count = response.data.count; + return response.data.results; +} - try { - await Axios.delete(`${backendAPI}/tasks/${id}`, { - ...(organizationID ? { org: organizationID } : {}), - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } - } +async function saveTask(id, taskData) { + const { backendAPI } = config; - function exportDataset(instanceType) { - return async function ( - id: number, - format: string, - saveImages: boolean, - useDefaultSettings: boolean, - targetStorage: Storage, - name?: string, - ) { - const { backendAPI } = config; - const baseURL = `${backendAPI}/${instanceType}/${id}/${saveImages ? 'dataset' : 'annotations'}`; - const params: Params = { - ...enableOrganization(), - ...configureStorage(targetStorage, useDefaultSettings), - ...(name ? { filename: name.replace(/\//g, '_') } : {}), - format, - }; + let response = null; + try { + response = await Axios.patch(`${backendAPI}/tasks/${id}`, JSON.stringify(taskData), { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } - return new Promise((resolve, reject) => { - async function request() { - Axios.get(baseURL, { - proxy: config.proxy, - params, - }) - .then((response) => { - const isCloudStorage = targetStorage.location === StorageLocation.CLOUD_STORAGE; - const { status } = response; - if (status === 201) params.action = 'download'; - if (status === 202 || (isCloudStorage && status === 201)) { - setTimeout(request, 3000); - } else if (status === 201) { - resolve(`${baseURL}?${new URLSearchParams(params).toString()}`); - } else if (isCloudStorage && status === 200) { - resolve(); - } - }) - .catch((errorData) => { - reject(generateError(errorData)); - }); - } + return response.data; +} - setTimeout(request); - }); - }; - } +async function deleteTask(id, organizationID = null) { + const { backendAPI } = config; - async function importDataset( - id: number, - format: string, - useDefaultLocation: boolean, - sourceStorage: Storage, - file: File | string, - options: { - convMaskToPoly: boolean, - updateStatusCallback: (s: string, n: number) => void, + try { + await Axios.delete(`${backendAPI}/tasks/${id}`, { + ...(organizationID ? { org: organizationID } : {}), + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', }, - ): Promise { - const { backendAPI, origin } = config; - const params: Params & { conv_mask_to_poly: boolean } = { - ...enableOrganization(), - ...configureStorage(sourceStorage, useDefaultLocation), - format, - filename: typeof file === 'string' ? file : file.name, - conv_mask_to_poly: options.convMaskToPoly, - }; - - const url = `${backendAPI}/projects/${id}/dataset`; - - async function wait() { - return new Promise((resolve, reject) => { - async function requestStatus() { - try { - const response = await Axios.get(url, { - params: { ...params, action: 'import_status' }, - proxy: config.proxy, - }); - if (response.status === 202) { - if (response.data.message) { - options.updateStatusCallback(response.data.message, response.data.progress || 0); - } - setTimeout(requestStatus, 3000); - } else if (response.status === 201) { - resolve(); - } else { - reject(generateError(response)); - } - } catch (error) { - reject(generateError(error)); - } - } - setTimeout(requestStatus, 2000); - }); - } - const isCloudStorage = sourceStorage.location === StorageLocation.CLOUD_STORAGE; - - if (isCloudStorage) { - try { - await Axios.post(url, - new FormData(), { - params, - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } - } else { - const uploadConfig = { - chunkSize: config.uploadChunkSize * 1024 * 1024, - endpoint: `${origin}${backendAPI}/projects/${id}/dataset/`, - totalSentSize: 0, - totalSize: (file as File).size, - onUpdate: (percentage) => { - options.updateStatusCallback('The dataset is being uploaded to the server', percentage); - }, - }; + }); + } catch (errorData) { + throw generateError(errorData); + } +} - try { - await Axios.post(url, - new FormData(), { - params, - proxy: config.proxy, - headers: { 'Upload-Start': true }, - }); - await chunkUpload(file, uploadConfig); - await Axios.post(url, - new FormData(), { - params, - proxy: config.proxy, - headers: { 'Upload-Finish': true }, - }); - } catch (errorData) { - throw generateError(errorData); - } - } - try { - return await wait(); - } catch (errorData) { - throw generateError(errorData); - } - } +function exportDataset(instanceType) { + return async function ( + id: number, + format: string, + saveImages: boolean, + useDefaultSettings: boolean, + targetStorage: Storage, + name?: string, + ) { + const { backendAPI } = config; + const baseURL = `${backendAPI}/${instanceType}/${id}/${saveImages ? 'dataset' : 'annotations'}`; + const params: Params = { + ...enableOrganization(), + ...configureStorage(targetStorage, useDefaultSettings), + ...(name ? { filename: name.replace(/\//g, '_') } : {}), + format, + }; - async function backupTask(id: number, targetStorage: Storage, useDefaultSettings: boolean, fileName?: string) { - const { backendAPI } = config; - const params: Params = { - ...enableOrganization(), - ...configureStorage(targetStorage, useDefaultSettings), - ...(fileName ? { filename: fileName } : {}), - }; - const url = `${backendAPI}/tasks/${id}/backup`; - - return new Promise((resolve, reject) => { - async function request() { - try { - const response = await Axios.get(url, { - proxy: config.proxy, - params, - }); + return new Promise((resolve, reject) => { + async function request() { + Axios.get(baseURL, { + proxy: config.proxy, + params, + }) + .then((response) => { const isCloudStorage = targetStorage.location === StorageLocation.CLOUD_STORAGE; const { status } = response; if (status === 201) params.action = 'download'; if (status === 202 || (isCloudStorage && status === 201)) { setTimeout(request, 3000); } else if (status === 201) { - resolve(`${url}?${new URLSearchParams(params).toString()}`); + resolve(`${baseURL}?${new URLSearchParams(params).toString()}`); } else if (isCloudStorage && status === 200) { resolve(); } - } catch (errorData) { + }) + .catch((errorData) => { reject(generateError(errorData)); - } - } - - setTimeout(request); - }); - } - - async function restoreTask(storage: Storage, file: File | string) { - const { backendAPI } = config; - // keep current default params to 'freeze" them during this request - const params: Params = { - ...enableOrganization(), - ...configureStorage(storage), - }; - - const url = `${backendAPI}/tasks/backup`; - const taskData = new FormData(); - let response; - - async function wait() { - return new Promise((resolve, reject) => { - async function checkStatus() { - try { - taskData.set('rq_id', response.data.rq_id); - response = await Axios.post(url, taskData, { - proxy: config.proxy, - params, - }); - if (response.status === 202) { - setTimeout(checkStatus, 3000); - } else { - // to be able to get the task after it was created, pass frozen params - const importedTask = await getTasks({ id: response.data.id, ...params }); - resolve(importedTask[0]); - } - } catch (errorData) { - reject(generateError(errorData)); - } - } - setTimeout(checkStatus); - }); - } - const isCloudStorage = storage.location === StorageLocation.CLOUD_STORAGE; - - if (isCloudStorage) { - params.filename = file as string; - response = await Axios.post(url, - new FormData(), { - params, - proxy: config.proxy, - }); - } else { - const uploadConfig = { - chunkSize: config.uploadChunkSize * 1024 * 1024, - endpoint: `${origin}${backendAPI}/tasks/backup/`, - totalSentSize: 0, - totalSize: (file as File).size, - }; - await Axios.post(url, - new FormData(), { - params, - proxy: config.proxy, - headers: { 'Upload-Start': true }, - }); - const { filename } = await chunkUpload(file, uploadConfig); - response = await Axios.post(url, - new FormData(), { - params: { ...params, filename }, - proxy: config.proxy, - headers: { 'Upload-Finish': true }, }); } - return wait(); - } - async function backupProject( - id: number, - targetStorage: Storage, - useDefaultSettings: boolean, - fileName?: string, - ) { - const { backendAPI } = config; - // keep current default params to 'freeze" them during this request - const params: Params = { - ...enableOrganization(), - ...configureStorage(targetStorage, useDefaultSettings), - ...(fileName ? { filename: fileName } : {}), - }; + setTimeout(request); + }); + }; +} - const url = `${backendAPI}/projects/${id}/backup`; +async function importDataset( + id: number, + format: string, + useDefaultLocation: boolean, + sourceStorage: Storage, + file: File | string, + options: { + convMaskToPoly: boolean, + updateStatusCallback: (s: string, n: number) => void, + }, +): Promise { + const { backendAPI, origin } = config; + const params: Params & { conv_mask_to_poly: boolean } = { + ...enableOrganization(), + ...configureStorage(sourceStorage, useDefaultLocation), + format, + filename: typeof file === 'string' ? file : file.name, + conv_mask_to_poly: options.convMaskToPoly, + }; - return new Promise((resolve, reject) => { - async function request() { - try { - const response = await Axios.get(url, { - proxy: config.proxy, - params, - }); - const isCloudStorage = targetStorage.location === StorageLocation.CLOUD_STORAGE; - const { status } = response; - if (status === 201) params.action = 'download'; - if (status === 202 || (isCloudStorage && status === 201)) { - setTimeout(request, 3000); - } else if (status === 201) { - resolve(`${url}?${new URLSearchParams(params).toString()}`); - } else if (isCloudStorage && status === 200) { - resolve(); + const url = `${backendAPI}/projects/${id}/dataset`; + + async function wait() { + return new Promise((resolve, reject) => { + async function requestStatus() { + try { + const response = await Axios.get(url, { + params: { ...params, action: 'import_status' }, + proxy: config.proxy, + }); + if (response.status === 202) { + if (response.data.message) { + options.updateStatusCallback(response.data.message, response.data.progress || 0); } - } catch (errorData) { - reject(generateError(errorData)); + setTimeout(requestStatus, 3000); + } else if (response.status === 201) { + resolve(); + } else { + reject(generateError(response)); } + } catch (error) { + reject(generateError(error)); } + } + setTimeout(requestStatus, 2000); + }); + } + const isCloudStorage = sourceStorage.location === StorageLocation.CLOUD_STORAGE; - setTimeout(request); - }); + if (isCloudStorage) { + try { + await Axios.post(url, + new FormData(), { + params, + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } + } else { + const uploadConfig = { + chunkSize: config.uploadChunkSize * 1024 * 1024, + endpoint: `${origin}${backendAPI}/projects/${id}/dataset/`, + totalSentSize: 0, + totalSize: (file as File).size, + onUpdate: (percentage) => { + options.updateStatusCallback('The dataset is being uploaded to the server', percentage); + }, + }; + + try { + await Axios.post(url, + new FormData(), { + params, + proxy: config.proxy, + headers: { 'Upload-Start': true }, + }); + await chunkUpload(file, uploadConfig); + await Axios.post(url, + new FormData(), { + params, + proxy: config.proxy, + headers: { 'Upload-Finish': true }, + }); + } catch (errorData) { + throw generateError(errorData); } + } + try { + return await wait(); + } catch (errorData) { + throw generateError(errorData); + } +} - async function restoreProject(storage: Storage, file: File | string) { - const { backendAPI } = config; - // keep current default params to 'freeze" them during this request - const params: Params = { - ...enableOrganization(), - ...configureStorage(storage), - }; - - const url = `${backendAPI}/projects/backup`; - const projectData = new FormData(); - let response; - - async function wait() { - return new Promise((resolve, reject) => { - async function request() { - try { - projectData.set('rq_id', response.data.rq_id); - response = await Axios.post(`${backendAPI}/projects/backup`, projectData, { - proxy: config.proxy, - params, - }); - if (response.status === 202) { - setTimeout(request, 3000); - } else { - // to be able to get the task after it was created, pass frozen params - const restoredProject = await getProjects({ id: response.data.id, ...params }); - resolve(restoredProject[0]); - } - } catch (errorData) { - reject(generateError(errorData)); - } - } +async function backupTask(id: number, targetStorage: Storage, useDefaultSettings: boolean, fileName?: string) { + const { backendAPI } = config; + const params: Params = { + ...enableOrganization(), + ...configureStorage(targetStorage, useDefaultSettings), + ...(fileName ? { filename: fileName } : {}), + }; + const url = `${backendAPI}/tasks/${id}/backup`; - setTimeout(request); + return new Promise((resolve, reject) => { + async function request() { + try { + const response = await Axios.get(url, { + proxy: config.proxy, + params, }); + const isCloudStorage = targetStorage.location === StorageLocation.CLOUD_STORAGE; + const { status } = response; + if (status === 201) params.action = 'download'; + if (status === 202 || (isCloudStorage && status === 201)) { + setTimeout(request, 3000); + } else if (status === 201) { + resolve(`${url}?${new URLSearchParams(params).toString()}`); + } else if (isCloudStorage && status === 200) { + resolve(); + } + } catch (errorData) { + reject(generateError(errorData)); } + } - const isCloudStorage = storage.location === StorageLocation.CLOUD_STORAGE; + setTimeout(request); + }); +} - if (isCloudStorage) { - params.filename = file; - response = await Axios.post(url, - new FormData(), { - params, +async function restoreTask(storage: Storage, file: File | string) { + const { backendAPI } = config; + // keep current default params to 'freeze" them during this request + const params: Params = { + ...enableOrganization(), + ...configureStorage(storage), + }; + + const url = `${backendAPI}/tasks/backup`; + const taskData = new FormData(); + let response; + + async function wait() { + return new Promise((resolve, reject) => { + async function checkStatus() { + try { + taskData.set('rq_id', response.data.rq_id); + response = await Axios.post(url, taskData, { proxy: config.proxy, - }); - } else { - const uploadConfig = { - chunkSize: config.uploadChunkSize * 1024 * 1024, - endpoint: `${origin}${backendAPI}/projects/backup/`, - totalSentSize: 0, - totalSize: (file as File).size, - }; - await Axios.post(url, - new FormData(), { params, - proxy: config.proxy, - headers: { 'Upload-Start': true }, }); - const { filename } = await chunkUpload(file, uploadConfig); - response = await Axios.post(url, - new FormData(), { - params: { ...params, filename }, - proxy: config.proxy, - headers: { 'Upload-Finish': true }, - }); - } - return wait(); - } - - async function createTask(taskSpec, taskDataSpec, onUpdate) { - const { backendAPI, origin } = config; - // keep current default params to 'freeze" them during this request - const params = enableOrganization(); - - async function wait(id) { - return new Promise((resolve, reject) => { - async function checkStatus() { - try { - const response = await Axios.get(`${backendAPI}/tasks/${id}/status`, { params }); - if (['Queued', 'Started'].includes(response.data.state)) { - if (response.data.message !== '') { - onUpdate(response.data.message, response.data.progress || 0); - } - setTimeout(checkStatus, 1000); - } else if (response.data.state === 'Finished') { - resolve(); - } else if (response.data.state === 'Failed') { - // If request has been successful, but task hasn't been created - // Then passed data is wrong and we can pass code 400 - const message = ` - Could not create the task on the server. ${response.data.message}. - `; - reject(new ServerError(message, 400)); - } else { - // If server has another status, it is unexpected - // Therefore it is server error and we can pass code 500 - reject( - new ServerError( - `Unknown task state has been received: ${response.data.state}`, - 500, - ), - ); - } - } catch (errorData) { - reject(generateError(errorData)); - } + if (response.status === 202) { + setTimeout(checkStatus, 3000); + } else { + // to be able to get the task after it was created, pass frozen params + const importedTask = await getTasks({ id: response.data.id, ...params }); + resolve(importedTask[0]); } - - setTimeout(checkStatus, 1000); - }); - } - - const chunkSize = config.uploadChunkSize * 1024 * 1024; - const clientFiles = taskDataSpec.client_files; - const chunkFiles = []; - const bulkFiles = []; - let totalSize = 0; - let totalSentSize = 0; - for (const file of clientFiles) { - if (file.size > chunkSize) { - chunkFiles.push(file); - } else { - bulkFiles.push(file); + } catch (errorData) { + reject(generateError(errorData)); } - totalSize += file.size; } - delete taskDataSpec.client_files; + setTimeout(checkStatus); + }); + } + const isCloudStorage = storage.location === StorageLocation.CLOUD_STORAGE; + + if (isCloudStorage) { + params.filename = file as string; + response = await Axios.post(url, + new FormData(), { + params, + proxy: config.proxy, + }); + } else { + const uploadConfig = { + chunkSize: config.uploadChunkSize * 1024 * 1024, + endpoint: `${origin}${backendAPI}/tasks/backup/`, + totalSentSize: 0, + totalSize: (file as File).size, + }; + await Axios.post(url, + new FormData(), { + params, + proxy: config.proxy, + headers: { 'Upload-Start': true }, + }); + const { filename } = await chunkUpload(file, uploadConfig); + response = await Axios.post(url, + new FormData(), { + params: { ...params, filename }, + proxy: config.proxy, + headers: { 'Upload-Finish': true }, + }); + } + return wait(); +} - const taskData = new FormData(); - for (const [key, value] of Object.entries(taskDataSpec)) { - if (Array.isArray(value)) { - value.forEach((element, idx) => { - taskData.append(`${key}[${idx}]`, element); - }); - } else { - taskData.set(key, value); - } - } +async function backupProject( + id: number, + targetStorage: Storage, + useDefaultSettings: boolean, + fileName?: string, +) { + const { backendAPI } = config; + // keep current default params to 'freeze" them during this request + const params: Params = { + ...enableOrganization(), + ...configureStorage(targetStorage, useDefaultSettings), + ...(fileName ? { filename: fileName } : {}), + }; - let response = null; + const url = `${backendAPI}/projects/${id}/backup`; - onUpdate('The task is being created on the server..', null); + return new Promise((resolve, reject) => { + async function request() { try { - response = await Axios.post(`${backendAPI}/tasks`, JSON.stringify(taskSpec), { + const response = await Axios.get(url, { proxy: config.proxy, params, - headers: { - 'Content-Type': 'application/json', - }, }); + const isCloudStorage = targetStorage.location === StorageLocation.CLOUD_STORAGE; + const { status } = response; + if (status === 201) params.action = 'download'; + if (status === 202 || (isCloudStorage && status === 201)) { + setTimeout(request, 3000); + } else if (status === 201) { + resolve(`${url}?${new URLSearchParams(params).toString()}`); + } else if (isCloudStorage && status === 200) { + resolve(); + } } catch (errorData) { - throw generateError(errorData); + reject(generateError(errorData)); } + } - onUpdate('The data are being uploaded to the server..', null); + setTimeout(request); + }); +} - async function bulkUpload(taskId, files) { - const fileBulks = files.reduce((fileGroups, file) => { - const lastBulk = fileGroups[fileGroups.length - 1]; - if (chunkSize - lastBulk.size >= file.size) { - lastBulk.files.push(file); - lastBulk.size += file.size; - } else { - fileGroups.push({ files: [file], size: file.size }); - } - return fileGroups; - }, [{ files: [], size: 0 }]); - const totalBulks = fileBulks.length; - let currentChunkNumber = 0; - while (currentChunkNumber < totalBulks) { - for (const [idx, element] of fileBulks[currentChunkNumber].files.entries()) { - taskData.append(`client_files[${idx}]`, element); - } - const percentage = totalSentSize / totalSize; - onUpdate('The data are being uploaded to the server', percentage); - await Axios.post(`${backendAPI}/tasks/${taskId}/data`, taskData, { - ...params, +async function restoreProject(storage: Storage, file: File | string) { + const { backendAPI } = config; + // keep current default params to 'freeze" them during this request + const params: Params = { + ...enableOrganization(), + ...configureStorage(storage), + }; + + const url = `${backendAPI}/projects/backup`; + const projectData = new FormData(); + let response; + + async function wait() { + return new Promise((resolve, reject) => { + async function request() { + try { + projectData.set('rq_id', response.data.rq_id); + response = await Axios.post(`${backendAPI}/projects/backup`, projectData, { proxy: config.proxy, - headers: { 'Upload-Multiple': true }, + params, }); - for (let i = 0; i < fileBulks[currentChunkNumber].files.length; i++) { - taskData.delete(`client_files[${i}]`); + if (response.status === 202) { + setTimeout(request, 3000); + } else { + // to be able to get the task after it was created, pass frozen params + const restoredProject = await getProjects({ id: response.data.id, ...params }); + resolve(restoredProject[0]); } - totalSentSize += fileBulks[currentChunkNumber].size; - currentChunkNumber++; + } catch (errorData) { + reject(generateError(errorData)); } } - try { - await Axios.post(`${backendAPI}/tasks/${response.data.id}/data`, - taskData, { - ...params, - proxy: config.proxy, - headers: { 'Upload-Start': true }, - }); - const uploadConfig = { - endpoint: `${origin}${backendAPI}/tasks/${response.data.id}/data/`, - onUpdate: (percentage) => { - onUpdate('The data are being uploaded to the server', percentage); - }, - chunkSize, - totalSize, - totalSentSize, - }; - for (const file of chunkFiles) { - uploadConfig.totalSentSize += await chunkUpload(file, uploadConfig); - } - if (bulkFiles.length > 0) { - await bulkUpload(response.data.id, bulkFiles); - } - await Axios.post(`${backendAPI}/tasks/${response.data.id}/data`, - taskData, { - ...params, - proxy: config.proxy, - headers: { 'Upload-Finish': true }, - }); - } catch (errorData) { - try { - await deleteTask(response.data.id, params.org || null); - } catch (_) { - // ignore - } - throw generateError(errorData); - } + setTimeout(request); + }); + } - try { - await wait(response.data.id); - } catch (createException) { - await deleteTask(response.data.id, params.org || null); - throw createException; - } + const isCloudStorage = storage.location === StorageLocation.CLOUD_STORAGE; - // to be able to get the task after it was created, pass frozen params - const createdTask = await getTasks({ id: response.data.id, ...params }); - return createdTask[0]; - } + if (isCloudStorage) { + params.filename = file; + response = await Axios.post(url, + new FormData(), { + params, + proxy: config.proxy, + }); + } else { + const uploadConfig = { + chunkSize: config.uploadChunkSize * 1024 * 1024, + endpoint: `${origin}${backendAPI}/projects/backup/`, + totalSentSize: 0, + totalSize: (file as File).size, + }; + await Axios.post(url, + new FormData(), { + params, + proxy: config.proxy, + headers: { 'Upload-Start': true }, + }); + const { filename } = await chunkUpload(file, uploadConfig); + response = await Axios.post(url, + new FormData(), { + params: { ...params, filename }, + proxy: config.proxy, + headers: { 'Upload-Finish': true }, + }); + } + return wait(); +} - async function getJobs(filter = {}) { - const { backendAPI } = config; - const id = filter.id || null; +async function createTask(taskSpec, taskDataSpec, onUpdate) { + const { backendAPI, origin } = config; + // keep current default params to 'freeze" them during this request + const params = enableOrganization(); - let response = null; - try { - if (id !== null) { - response = await Axios.get(`${backendAPI}/jobs/${id}`, { - proxy: config.proxy, - }); - } else { - response = await Axios.get(`${backendAPI}/jobs`, { - proxy: config.proxy, - params: { - ...filter, - page_size: 12, - }, - }); + async function wait(id) { + return new Promise((resolve, reject) => { + async function checkStatus() { + try { + const response = await Axios.get(`${backendAPI}/tasks/${id}/status`, { params }); + if (['Queued', 'Started'].includes(response.data.state)) { + if (response.data.message !== '') { + onUpdate(response.data.message, response.data.progress || 0); + } + setTimeout(checkStatus, 1000); + } else if (response.data.state === 'Finished') { + resolve(); + } else if (response.data.state === 'Failed') { + // If request has been successful, but task hasn't been created + // Then passed data is wrong and we can pass code 400 + const message = ` + Could not create the task on the server. ${response.data.message}. + `; + reject(new ServerError(message, 400)); + } else { + // If server has another status, it is unexpected + // Therefore it is server error and we can pass code 500 + reject( + new ServerError( + `Unknown task state has been received: ${response.data.state}`, + 500, + ), + ); + } + } catch (errorData) { + reject(generateError(errorData)); } - } catch (errorData) { - throw generateError(errorData); } - return response.data; + setTimeout(checkStatus, 1000); + }); + } + + const chunkSize = config.uploadChunkSize * 1024 * 1024; + const clientFiles = taskDataSpec.client_files; + const chunkFiles = []; + const bulkFiles = []; + let totalSize = 0; + let totalSentSize = 0; + for (const file of clientFiles) { + if (file.size > chunkSize) { + chunkFiles.push(file); + } else { + bulkFiles.push(file); } + totalSize += file.size; + } + delete taskDataSpec.client_files; - async function getJobIssues(jobID) { - const { backendAPI } = config; + const taskData = new FormData(); + for (const [key, value] of Object.entries(taskDataSpec)) { + if (Array.isArray(value)) { + value.forEach((element, idx) => { + taskData.append(`${key}[${idx}]`, element); + }); + } else { + taskData.set(key, value); + } + } - let response = null; - try { - response = await Axios.get(`${backendAPI}/jobs/${jobID}/issues`, { - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } + let response = null; - return response.data; - } + onUpdate('The task is being created on the server..', null); + try { + response = await Axios.post(`${backendAPI}/tasks`, JSON.stringify(taskSpec), { + proxy: config.proxy, + params, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } - async function createComment(data) { - const { backendAPI } = config; + onUpdate('The data are being uploaded to the server..', null); - let response = null; - try { - response = await Axios.post(`${backendAPI}/comments`, JSON.stringify(data), { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); + async function bulkUpload(taskId, files) { + const fileBulks = files.reduce((fileGroups, file) => { + const lastBulk = fileGroups[fileGroups.length - 1]; + if (chunkSize - lastBulk.size >= file.size) { + lastBulk.files.push(file); + lastBulk.size += file.size; + } else { + fileGroups.push({ files: [file], size: file.size }); + } + return fileGroups; + }, [{ files: [], size: 0 }]); + const totalBulks = fileBulks.length; + let currentChunkNumber = 0; + while (currentChunkNumber < totalBulks) { + for (const [idx, element] of fileBulks[currentChunkNumber].files.entries()) { + taskData.append(`client_files[${idx}]`, element); + } + const percentage = totalSentSize / totalSize; + onUpdate('The data are being uploaded to the server', percentage); + await Axios.post(`${backendAPI}/tasks/${taskId}/data`, taskData, { + ...params, + proxy: config.proxy, + headers: { 'Upload-Multiple': true }, + }); + for (let i = 0; i < fileBulks[currentChunkNumber].files.length; i++) { + taskData.delete(`client_files[${i}]`); } + totalSentSize += fileBulks[currentChunkNumber].size; + currentChunkNumber++; + } + } - return response.data; + try { + await Axios.post(`${backendAPI}/tasks/${response.data.id}/data`, + taskData, { + ...params, + proxy: config.proxy, + headers: { 'Upload-Start': true }, + }); + const uploadConfig = { + endpoint: `${origin}${backendAPI}/tasks/${response.data.id}/data/`, + onUpdate: (percentage) => { + onUpdate('The data are being uploaded to the server', percentage); + }, + chunkSize, + totalSize, + totalSentSize, + }; + for (const file of chunkFiles) { + uploadConfig.totalSentSize += await chunkUpload(file, uploadConfig); + } + if (bulkFiles.length > 0) { + await bulkUpload(response.data.id, bulkFiles); + } + await Axios.post(`${backendAPI}/tasks/${response.data.id}/data`, + taskData, { + ...params, + proxy: config.proxy, + headers: { 'Upload-Finish': true }, + }); + } catch (errorData) { + try { + await deleteTask(response.data.id, params.org || null); + } catch (_) { + // ignore } + throw generateError(errorData); + } - async function createIssue(data) { - const { backendAPI } = config; + try { + await wait(response.data.id); + } catch (createException) { + await deleteTask(response.data.id, params.org || null); + throw createException; + } - let response = null; - try { - response = await Axios.post(`${backendAPI}/issues`, JSON.stringify(data), { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } + // to be able to get the task after it was created, pass frozen params + const createdTask = await getTasks({ id: response.data.id, ...params }); + return createdTask[0]; +} - return response.data; +async function getJobs(filter = {}) { + const { backendAPI } = config; + const id = filter.id || null; + + let response = null; + try { + if (id !== null) { + response = await Axios.get(`${backendAPI}/jobs/${id}`, { + proxy: config.proxy, + }); + } else { + response = await Axios.get(`${backendAPI}/jobs`, { + proxy: config.proxy, + params: { + ...filter, + page_size: 12, + }, + }); } + } catch (errorData) { + throw generateError(errorData); + } - async function updateIssue(issueID, data) { - const { backendAPI } = config; + return response.data; +} - let response = null; - try { - response = await Axios.patch(`${backendAPI}/issues/${issueID}`, JSON.stringify(data), { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } +async function getJobIssues(jobID) { + const { backendAPI } = config; - return response.data; - } + let response = null; + try { + response = await Axios.get(`${backendAPI}/jobs/${jobID}/issues`, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } - async function deleteIssue(issueID) { - const { backendAPI } = config; + return response.data; +} - try { - await Axios.delete(`${backendAPI}/issues/${issueID}`); - } catch (errorData) { - throw generateError(errorData); - } - } +async function createComment(data) { + const { backendAPI } = config; - async function saveJob(id, jobData) { - const { backendAPI } = config; + let response = null; + try { + response = await Axios.post(`${backendAPI}/comments`, JSON.stringify(data), { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } - let response = null; - try { - response = await Axios.patch(`${backendAPI}/jobs/${id}`, JSON.stringify(jobData), { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } + return response.data; +} - return response.data; - } +async function createIssue(data) { + const { backendAPI } = config; - async function getUsers(filter = { page_size: 'all' }) { - const { backendAPI } = config; + let response = null; + try { + response = await Axios.post(`${backendAPI}/issues`, JSON.stringify(data), { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } - let response = null; - try { - response = await Axios.get(`${backendAPI}/users`, { - proxy: config.proxy, - params: { - ...filter, - }, - }); - } catch (errorData) { - throw generateError(errorData); - } + return response.data; +} - return response.data.results; - } +async function updateIssue(issueID, data) { + const { backendAPI } = config; - async function getPreview(tid, jid) { - const { backendAPI } = config; + let response = null; + try { + response = await Axios.patch(`${backendAPI}/issues/${issueID}`, JSON.stringify(data), { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } - let response = null; - try { - const url = `${backendAPI}/${jid !== null ? 'jobs' : 'tasks'}/${jid || tid}/data`; - response = await Axios.get(url, { - params: { - type: 'preview', - }, - proxy: config.proxy, - responseType: 'blob', - }); - } catch (errorData) { - const code = errorData.response ? errorData.response.status : errorData.code; - throw new ServerError(`Could not get preview frame for the task ${tid} from the server`, code); - } + return response.data; +} - return response.data; - } +async function deleteIssue(issueID) { + const { backendAPI } = config; - async function getImageContext(jid, frame) { - const { backendAPI } = config; + try { + await Axios.delete(`${backendAPI}/issues/${issueID}`); + } catch (errorData) { + throw generateError(errorData); + } +} - let response = null; - try { - response = await Axios.get(`${backendAPI}/jobs/${jid}/data`, { - params: { - quality: 'original', - type: 'context_image', - number: frame, - }, - proxy: config.proxy, - responseType: 'blob', - }); - } catch (errorData) { - throw generateError(errorData); - } +async function saveJob(id, jobData) { + const { backendAPI } = config; - return response.data; - } + let response = null; + try { + response = await Axios.patch(`${backendAPI}/jobs/${id}`, JSON.stringify(jobData), { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } - async function getData(tid, jid, chunk) { - const { backendAPI } = config; + return response.data; +} - const url = jid === null ? `tasks/${tid}/data` : `jobs/${jid}/data`; +async function getUsers(filter = { page_size: 'all' }) { + const { backendAPI } = config; - let response = null; - try { - response = await workerAxios.get(`${backendAPI}/${url}`, { - params: { - ...enableOrganization(), - quality: 'compressed', - type: 'chunk', - number: chunk, - }, - proxy: config.proxy, - responseType: 'arraybuffer', - }); - } catch (errorData) { - throw generateError({ - message: '', - response: { - ...errorData.response, - data: String.fromCharCode.apply(null, new Uint8Array(errorData.response.data)), - }, - }); - } + let response = null; + try { + response = await Axios.get(`${backendAPI}/users`, { + proxy: config.proxy, + params: { + ...filter, + }, + }); + } catch (errorData) { + throw generateError(errorData); + } - return response; - } + return response.data.results; +} - async function getMeta(session, jid) { - const { backendAPI } = config; +async function getPreview(tid, jid) { + const { backendAPI } = config; - let response = null; - try { - response = await Axios.get(`${backendAPI}/${session}s/${jid}/data/meta`, { - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } + let response = null; + try { + const url = `${backendAPI}/${jid !== null ? 'jobs' : 'tasks'}/${jid || tid}/data`; + response = await Axios.get(url, { + params: { + type: 'preview', + }, + proxy: config.proxy, + responseType: 'blob', + }); + } catch (errorData) { + const code = errorData.response ? errorData.response.status : errorData.code; + throw new ServerError(`Could not get preview frame for the task ${tid} from the server`, code); + } - return response.data; - } + return response.data; +} - async function saveMeta(session, jid, meta) { - const { backendAPI } = config; +async function getImageContext(jid, frame) { + const { backendAPI } = config; - let response = null; - try { - response = await Axios.patch(`${backendAPI}/${session}s/${jid}/data/meta`, meta, { - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } + let response = null; + try { + response = await Axios.get(`${backendAPI}/jobs/${jid}/data`, { + params: { + quality: 'original', + type: 'context_image', + number: frame, + }, + proxy: config.proxy, + responseType: 'blob', + }); + } catch (errorData) { + throw generateError(errorData); + } - return response.data; - } + return response.data; +} - // Session is 'task' or 'job' - async function getAnnotations(session, id) { - const { backendAPI } = config; +async function getData(tid, jid, chunk) { + const { backendAPI } = config; - let response = null; - try { - response = await Axios.get(`${backendAPI}/${session}s/${id}/annotations`, { - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } + const url = jid === null ? `tasks/${tid}/data` : `jobs/${jid}/data`; - return response.data; - } + let response = null; + try { + response = await workerAxios.get(`${backendAPI}/${url}`, { + params: { + ...enableOrganization(), + quality: 'compressed', + type: 'chunk', + number: chunk, + }, + proxy: config.proxy, + responseType: 'arraybuffer', + }); + } catch (errorData) { + throw generateError({ + message: '', + response: { + ...errorData.response, + data: String.fromCharCode.apply(null, new Uint8Array(errorData.response.data)), + }, + }); + } - // Session is 'task' or 'job' - async function updateAnnotations(session, id, data, action) { - const { backendAPI } = config; - const url = `${backendAPI}/${session}s/${id}/annotations`; - const params = {}; - let requestFunc = null; + return response; +} - if (action.toUpperCase() === 'PUT') { - requestFunc = Axios.put.bind(Axios); - } else { - requestFunc = Axios.patch.bind(Axios); - params.action = action; - } +async function getMeta(session, jid) { + const { backendAPI } = config; - let response = null; - try { - response = await requestFunc(url, JSON.stringify(data), { - proxy: config.proxy, - params, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } + let response = null; + try { + response = await Axios.get(`${backendAPI}/${session}s/${jid}/data/meta`, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } - return response.data; - } + return response.data; +} - // Session is 'task' or 'job' - async function uploadAnnotations( - session, - id: number, - format: string, - useDefaultLocation: boolean, - sourceStorage: Storage, - file: File | string, - options: { convMaskToPoly: boolean }, - ): Promise { - const { backendAPI, origin } = config; - const params: Params & { conv_mask_to_poly: boolean } = { - ...enableOrganization(), - ...configureStorage(sourceStorage, useDefaultLocation), - format, - filename: typeof file === 'string' ? file : file.name, - conv_mask_to_poly: options.convMaskToPoly, - }; - - const url = `${backendAPI}/${session}s/${id}/annotations`; - - async function wait() { - return new Promise((resolve, reject) => { - async function requestStatus() { - try { - const response = await Axios.put( - url, - new FormData(), - { - params, - proxy: config.proxy, - }, - ); - if (response.status === 202) { - setTimeout(requestStatus, 3000); - } else { - resolve(); - } - } catch (errorData) { - reject(generateError(errorData)); - } - } - setTimeout(requestStatus); - }); - } - const isCloudStorage = sourceStorage.location === StorageLocation.CLOUD_STORAGE; +async function saveMeta(session, jid, meta) { + const { backendAPI } = config; - if (isCloudStorage) { - try { - await Axios.post(url, - new FormData(), { - params, - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } - } else { - const chunkSize = config.uploadChunkSize * 1024 * 1024; - const uploadConfig = { - chunkSize, - endpoint: `${origin}${backendAPI}/${session}s/${id}/annotations/`, - }; + let response = null; + try { + response = await Axios.patch(`${backendAPI}/${session}s/${jid}/data/meta`, meta, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } + + return response.data; +} + +// Session is 'task' or 'job' +async function getAnnotations(session, id) { + const { backendAPI } = config; + + let response = null; + try { + response = await Axios.get(`${backendAPI}/${session}s/${id}/annotations`, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } + + return response.data; +} + +// Session is 'task' or 'job' +async function updateAnnotations(session, id, data, action) { + const { backendAPI } = config; + const url = `${backendAPI}/${session}s/${id}/annotations`; + const params = {}; + let requestFunc = null; + + if (action.toUpperCase() === 'PUT') { + requestFunc = Axios.put.bind(Axios); + } else { + requestFunc = Axios.patch.bind(Axios); + params.action = action; + } + + let response = null; + try { + response = await requestFunc(url, JSON.stringify(data), { + proxy: config.proxy, + params, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } + + return response.data; +} + +// Session is 'task' or 'job' +async function uploadAnnotations( + session, + id: number, + format: string, + useDefaultLocation: boolean, + sourceStorage: Storage, + file: File | string, + options: { convMaskToPoly: boolean }, +): Promise { + const { backendAPI, origin } = config; + const params: Params & { conv_mask_to_poly: boolean } = { + ...enableOrganization(), + ...configureStorage(sourceStorage, useDefaultLocation), + format, + filename: typeof file === 'string' ? file : file.name, + conv_mask_to_poly: options.convMaskToPoly, + }; + + const url = `${backendAPI}/${session}s/${id}/annotations`; + async function wait() { + return new Promise((resolve, reject) => { + async function requestStatus() { try { - await Axios.post(url, - new FormData(), { - params, - proxy: config.proxy, - headers: { 'Upload-Start': true }, - }); - await chunkUpload(file, uploadConfig); - await Axios.post(url, - new FormData(), { + const response = await Axios.put( + url, + new FormData(), + { params, proxy: config.proxy, - headers: { 'Upload-Finish': true }, - }); + }, + ); + if (response.status === 202) { + setTimeout(requestStatus, 3000); + } else { + resolve(); + } } catch (errorData) { - throw generateError(errorData); + reject(generateError(errorData)); } } + setTimeout(requestStatus); + }); + } + const isCloudStorage = sourceStorage.location === StorageLocation.CLOUD_STORAGE; - try { - return await wait(); - } catch (errorData) { - throw generateError(errorData); - } - } - - // Session is 'task' or 'job' - async function dumpAnnotations(id, name, format) { - const { backendAPI } = config; - const baseURL = `${backendAPI}/tasks/${id}/annotations`; - const params = enableOrganization(); - params.format = encodeURIComponent(format); - if (name) { - const filename = name.replace(/\//g, '_'); - params.filename = encodeURIComponent(filename); - } - - return new Promise((resolve, reject) => { - async function request() { - Axios.get(baseURL, { - proxy: config.proxy, - params, - }) - .then((response) => { - if (response.status === 202) { - setTimeout(request, 3000); - } else { - params.action = 'download'; - resolve(`${baseURL}?${new URLSearchParams(params).toString()}`); - } - }) - .catch((errorData) => { - reject(generateError(errorData)); - }); - } - - setTimeout(request); - }); + if (isCloudStorage) { + try { + await Axios.post(url, + new FormData(), { + params, + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); } + } else { + const chunkSize = config.uploadChunkSize * 1024 * 1024; + const uploadConfig = { + chunkSize, + endpoint: `${origin}${backendAPI}/${session}s/${id}/annotations/`, + }; - async function saveLogs(logs) { - const { backendAPI } = config; - - try { - await Axios.post(`${backendAPI}/server/logs`, JSON.stringify(logs), { + try { + await Axios.post(url, + new FormData(), { + params, proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, + headers: { 'Upload-Start': true }, }); - } catch (errorData) { - throw generateError(errorData); - } + await chunkUpload(file, uploadConfig); + await Axios.post(url, + new FormData(), { + params, + proxy: config.proxy, + headers: { 'Upload-Finish': true }, + }); + } catch (errorData) { + throw generateError(errorData); } + } - async function getLambdaFunctions() { - const { backendAPI } = config; + try { + return await wait(); + } catch (errorData) { + throw generateError(errorData); + } +} - try { - const response = await Axios.get(`${backendAPI}/lambda/functions`, { - proxy: config.proxy, - }); - return response.data; - } catch (errorData) { - throw generateError(errorData); - } - } - - async function runLambdaRequest(body) { - const { backendAPI } = config; +// Session is 'task' or 'job' +async function dumpAnnotations(id, name, format) { + const { backendAPI } = config; + const baseURL = `${backendAPI}/tasks/${id}/annotations`; + const params = enableOrganization(); + params.format = encodeURIComponent(format); + if (name) { + const filename = name.replace(/\//g, '_'); + params.filename = encodeURIComponent(filename); + } - try { - const response = await Axios.post(`${backendAPI}/lambda/requests`, JSON.stringify(body), { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, + return new Promise((resolve, reject) => { + async function request() { + Axios.get(baseURL, { + proxy: config.proxy, + params, + }) + .then((response) => { + if (response.status === 202) { + setTimeout(request, 3000); + } else { + params.action = 'download'; + resolve(`${baseURL}?${new URLSearchParams(params).toString()}`); + } + }) + .catch((errorData) => { + reject(generateError(errorData)); }); - - return response.data; - } catch (errorData) { - throw generateError(errorData); - } } - async function callLambdaFunction(funId, body) { - const { backendAPI } = config; + setTimeout(request); + }); +} - try { - const response = await Axios.post(`${backendAPI}/lambda/functions/${funId}`, JSON.stringify(body), { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); +async function saveLogs(logs) { + const { backendAPI } = config; - return response.data; - } catch (errorData) { - throw generateError(errorData); - } - } + try { + await Axios.post(`${backendAPI}/server/logs`, JSON.stringify(logs), { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } +} - async function getLambdaRequests() { - const { backendAPI } = config; +async function getLambdaFunctions() { + const { backendAPI } = config; - try { - const response = await Axios.get(`${backendAPI}/lambda/requests`, { - proxy: config.proxy, - }); - - return response.data; - } catch (errorData) { - throw generateError(errorData); - } - } + try { + const response = await Axios.get(`${backendAPI}/lambda/functions`, { + proxy: config.proxy, + }); + return response.data; + } catch (errorData) { + throw generateError(errorData); + } +} - async function getRequestStatus(requestID) { - const { backendAPI } = config; +async function runLambdaRequest(body) { + const { backendAPI } = config; - try { - const response = await Axios.get(`${backendAPI}/lambda/requests/${requestID}`, { - proxy: config.proxy, - }); - return response.data; - } catch (errorData) { - throw generateError(errorData); - } - } + try { + const response = await Axios.post(`${backendAPI}/lambda/requests`, JSON.stringify(body), { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); - async function cancelLambdaRequest(requestId) { - const { backendAPI } = config; + return response.data; + } catch (errorData) { + throw generateError(errorData); + } +} - try { - await Axios.delete(`${backendAPI}/lambda/requests/${requestId}`, { - method: 'DELETE', - }); - } catch (errorData) { - throw generateError(errorData); - } - } +async function callLambdaFunction(funId, body) { + const { backendAPI } = config; - function predictorStatus(projectId) { - const { backendAPI } = config; + try { + const response = await Axios.post(`${backendAPI}/lambda/functions/${funId}`, JSON.stringify(body), { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); - return new Promise((resolve, reject) => { - async function request() { - try { - const response = await Axios.get(`${backendAPI}/predict/status`, { - params: { - project: projectId, - }, - }); - return response.data; - } catch (errorData) { - throw generateError(errorData); - } - } + return response.data; + } catch (errorData) { + throw generateError(errorData); + } +} - const timeoutCallback = async () => { - let data = null; - try { - data = await request(); - if (data.status === 'queued') { - setTimeout(timeoutCallback, 1000); - } else if (data.status === 'done') { - resolve(data); - } else { - throw new Error(`Unknown status was received "${data.status}"`); - } - } catch (error) { - reject(error); - } - }; +async function getLambdaRequests() { + const { backendAPI } = config; - setTimeout(timeoutCallback); - }); - } + try { + const response = await Axios.get(`${backendAPI}/lambda/requests`, { + proxy: config.proxy, + }); - function predictAnnotations(taskId, frame) { - return new Promise((resolve, reject) => { - const { backendAPI } = config; - - async function request() { - try { - const response = await Axios.get(`${backendAPI}/predict/frame`, { - params: { - task: taskId, - frame, - }, - }); - return response.data; - } catch (errorData) { - throw generateError(errorData); - } - } + return response.data; + } catch (errorData) { + throw generateError(errorData); + } +} - const timeoutCallback = async () => { - let data = null; - try { - data = await request(); - if (data.status === 'queued') { - setTimeout(timeoutCallback, 1000); - } else if (data.status === 'done') { - predictAnnotations.latestRequest.fetching = false; - resolve(data.annotation); - } else { - throw new Error(`Unknown status was received "${data.status}"`); - } - } catch (error) { - predictAnnotations.latestRequest.fetching = false; - reject(error); - } - }; +async function getRequestStatus(requestID) { + const { backendAPI } = config; - const closureId = Date.now(); - predictAnnotations.latestRequest.id = closureId; - const predicate = () => !predictAnnotations.latestRequest.fetching || - predictAnnotations.latestRequest.id !== closureId; - if (predictAnnotations.latestRequest.fetching) { - waitFor(5, predicate).then(() => { - if (predictAnnotations.latestRequest.id !== closureId) { - resolve(null); - } else { - predictAnnotations.latestRequest.fetching = true; - setTimeout(timeoutCallback); - } - }); - } else { - predictAnnotations.latestRequest.fetching = true; - setTimeout(timeoutCallback); - } - }); - } + try { + const response = await Axios.get(`${backendAPI}/lambda/requests/${requestID}`, { + proxy: config.proxy, + }); + return response.data; + } catch (errorData) { + throw generateError(errorData); + } +} - predictAnnotations.latestRequest = { - fetching: false, - id: null, - }; +async function cancelLambdaRequest(requestId) { + const { backendAPI } = config; - async function installedApps() { - const { backendAPI } = config; - try { - const response = await Axios.get(`${backendAPI}/server/plugins`, { - proxy: config.proxy, - }); - return response.data; - } catch (errorData) { - throw generateError(errorData); - } - } + try { + await Axios.delete(`${backendAPI}/lambda/requests/${requestId}`, { + method: 'DELETE', + }); + } catch (errorData) { + throw generateError(errorData); + } +} - async function createCloudStorage(storageDetail) { - const { backendAPI } = config; +function predictorStatus(projectId) { + const { backendAPI } = config; - const storageDetailData = prepareData(storageDetail); + return new Promise((resolve, reject) => { + async function request() { try { - const response = await Axios.post(`${backendAPI}/cloudstorages`, storageDetailData, { - proxy: config.proxy, + const response = await Axios.get(`${backendAPI}/predict/status`, { + params: { + project: projectId, + }, }); return response.data; } catch (errorData) { @@ -1802,597 +1693,651 @@ class ServerProxy { } } - async function updateCloudStorage(id, storageDetail) { - const { backendAPI } = config; - - const storageDetailData = prepareData(storageDetail); - try { - await Axios.patch(`${backendAPI}/cloudstorages/${id}`, storageDetailData, { - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } - } - - async function getCloudStorages(filter = {}) { - const { backendAPI } = config; - - let response = null; + const timeoutCallback = async () => { + let data = null; try { - response = await Axios.get(`${backendAPI}/cloudstorages`, { - proxy: config.proxy, - params: filter, - page_size: 12, - }); - } catch (errorData) { - throw generateError(errorData); + data = await request(); + if (data.status === 'queued') { + setTimeout(timeoutCallback, 1000); + } else if (data.status === 'done') { + resolve(data); + } else { + throw new Error(`Unknown status was received "${data.status}"`); + } + } catch (error) { + reject(error); } + }; - response.data.results.count = response.data.count; - return response.data.results; - } + setTimeout(timeoutCallback); + }); +} - async function getCloudStorageContent(id, manifestPath) { - const { backendAPI } = config; +function predictAnnotations(taskId, frame) { + return new Promise((resolve, reject) => { + const { backendAPI } = config; - let response = null; + async function request() { try { - const url = `${backendAPI}/cloudstorages/${id}/content${ - manifestPath ? `?manifest_path=${manifestPath}` : '' - }`; - response = await Axios.get(url, { - proxy: config.proxy, + const response = await Axios.get(`${backendAPI}/predict/frame`, { + params: { + task: taskId, + frame, + }, }); + return response.data; } catch (errorData) { throw generateError(errorData); } - - return response.data; } - async function getCloudStoragePreview(id) { - const { backendAPI } = config; - - let response = null; + const timeoutCallback = async () => { + let data = null; try { - const url = `${backendAPI}/cloudstorages/${id}/preview`; - response = await workerAxios.get(url, { - params: enableOrganization(), - proxy: config.proxy, - responseType: 'arraybuffer', - }); - } catch (errorData) { - throw generateError({ - message: '', - response: { - ...errorData.response, - data: String.fromCharCode.apply(null, new Uint8Array(errorData.response.data)), - }, - }); - } - - return new Blob([new Uint8Array(response)]); - } - - async function getCloudStorageStatus(id) { - const { backendAPI } = config; - - let response = null; - try { - const url = `${backendAPI}/cloudstorages/${id}/status`; - response = await Axios.get(url, { - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); + data = await request(); + if (data.status === 'queued') { + setTimeout(timeoutCallback, 1000); + } else if (data.status === 'done') { + predictAnnotations.latestRequest.fetching = false; + resolve(data.annotation); + } else { + throw new Error(`Unknown status was received "${data.status}"`); + } + } catch (error) { + predictAnnotations.latestRequest.fetching = false; + reject(error); } + }; - return response.data; + const closureId = Date.now(); + predictAnnotations.latestRequest.id = closureId; + const predicate = () => !predictAnnotations.latestRequest.fetching || + predictAnnotations.latestRequest.id !== closureId; + if (predictAnnotations.latestRequest.fetching) { + waitFor(5, predicate).then(() => { + if (predictAnnotations.latestRequest.id !== closureId) { + resolve(null); + } else { + predictAnnotations.latestRequest.fetching = true; + setTimeout(timeoutCallback); + } + }); + } else { + predictAnnotations.latestRequest.fetching = true; + setTimeout(timeoutCallback); } + }); +} - async function deleteCloudStorage(id) { - const { backendAPI } = config; +predictAnnotations.latestRequest = { + fetching: false, + id: null, +}; - try { - await Axios.delete(`${backendAPI}/cloudstorages/${id}`, { - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } - } +async function installedApps() { + const { backendAPI } = config; + try { + const response = await Axios.get(`${backendAPI}/server/plugins`, { + proxy: config.proxy, + }); + return response.data; + } catch (errorData) { + throw generateError(errorData); + } +} - async function getOrganizations() { - const { backendAPI } = config; +async function createCloudStorage(storageDetail) { + const { backendAPI } = config; - let response = null; - try { - response = await Axios.get(`${backendAPI}/organizations`, { - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } + const storageDetailData = prepareData(storageDetail); + try { + const response = await Axios.post(`${backendAPI}/cloudstorages`, storageDetailData, { + proxy: config.proxy, + }); + return response.data; + } catch (errorData) { + throw generateError(errorData); + } +} - return response.data; - } +async function updateCloudStorage(id, storageDetail) { + const { backendAPI } = config; - async function createOrganization(data) { - const { backendAPI } = config; + const storageDetailData = prepareData(storageDetail); + try { + await Axios.patch(`${backendAPI}/cloudstorages/${id}`, storageDetailData, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } +} - let response = null; - try { - response = await Axios.post(`${backendAPI}/organizations`, JSON.stringify(data), { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } +async function getCloudStorages(filter = {}) { + const { backendAPI } = config; - return response.data; - } + let response = null; + try { + response = await Axios.get(`${backendAPI}/cloudstorages`, { + proxy: config.proxy, + params: filter, + page_size: 12, + }); + } catch (errorData) { + throw generateError(errorData); + } - async function updateOrganization(id, data) { - const { backendAPI } = config; + response.data.results.count = response.data.count; + return response.data.results; +} - let response = null; - try { - response = await Axios.patch(`${backendAPI}/organizations/${id}`, JSON.stringify(data), { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } +async function getCloudStorageContent(id, manifestPath) { + const { backendAPI } = config; - return response.data; - } + let response = null; + try { + const url = `${backendAPI}/cloudstorages/${id}/content${ + manifestPath ? `?manifest_path=${manifestPath}` : '' + }`; + response = await Axios.get(url, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } - async function deleteOrganization(id) { - const { backendAPI } = config; + return response.data; +} - try { - await Axios.delete(`${backendAPI}/organizations/${id}`, { - proxy: config.proxy, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } - } +async function getCloudStoragePreview(id) { + const { backendAPI } = config; - async function getOrganizationMembers(orgSlug, page, pageSize, filters = {}) { - const { backendAPI } = config; + let response = null; + try { + const url = `${backendAPI}/cloudstorages/${id}/preview`; + response = await workerAxios.get(url, { + params: enableOrganization(), + proxy: config.proxy, + responseType: 'arraybuffer', + }); + } catch (errorData) { + throw generateError({ + message: '', + response: { + ...errorData.response, + data: String.fromCharCode.apply(null, new Uint8Array(errorData.response.data)), + }, + }); + } - let response = null; - try { - response = await Axios.get(`${backendAPI}/memberships`, { - proxy: config.proxy, - params: { - ...filters, - org: orgSlug, - page, - page_size: pageSize, - }, - }); - } catch (errorData) { - throw generateError(errorData); - } + return new Blob([new Uint8Array(response)]); +} - return response.data; - } +async function getCloudStorageStatus(id) { + const { backendAPI } = config; - async function inviteOrganizationMembers(orgId, data) { - const { backendAPI } = config; - try { - await Axios.post( - `${backendAPI}/invitations`, - { - ...data, - organization: orgId, - }, - { - proxy: config.proxy, - }, - ); - } catch (errorData) { - throw generateError(errorData); - } - } + let response = null; + try { + const url = `${backendAPI}/cloudstorages/${id}/status`; + response = await Axios.get(url, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } - async function updateOrganizationMembership(membershipId, data) { - const { backendAPI } = config; - let response = null; - try { - response = await Axios.patch( - `${backendAPI}/memberships/${membershipId}`, - { - ...data, - }, - { - proxy: config.proxy, - }, - ); - } catch (errorData) { - throw generateError(errorData); - } + return response.data; +} - return response.data; - } +async function deleteCloudStorage(id) { + const { backendAPI } = config; - async function deleteOrganizationMembership(membershipId) { - const { backendAPI } = config; + try { + await Axios.delete(`${backendAPI}/cloudstorages/${id}`, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } +} - try { - await Axios.delete(`${backendAPI}/memberships/${membershipId}`, { - proxy: config.proxy, - }); - } catch (errorData) { - throw generateError(errorData); - } - } +async function getOrganizations() { + const { backendAPI } = config; - async function getMembershipInvitation(id) { - const { backendAPI } = config; + let response = null; + try { + response = await Axios.get(`${backendAPI}/organizations`, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } - let response = null; - try { - response = await Axios.get(`${backendAPI}/invitations/${id}`, { - proxy: config.proxy, - }); - return response.data; - } catch (errorData) { - throw generateError(errorData); - } - } + return response.data; +} - async function getWebhookDelivery(webhookID: number, deliveryID: number): Promise { - const params = enableOrganization(); - const { backendAPI } = config; +async function createOrganization(data) { + const { backendAPI } = config; - try { - const response = await Axios.get(`${backendAPI}/webhooks/${webhookID}/deliveries/${deliveryID}`, { - proxy: config.proxy, - params, - headers: { - 'Content-Type': 'application/json', - }, - }); - return response.data; - } catch (errorData) { - throw generateError(errorData); - } - } + let response = null; + try { + response = await Axios.post(`${backendAPI}/organizations`, JSON.stringify(data), { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } - async function getWebhooks(filter, pageSize = 10): Promise { - const params = enableOrganization(); - const { backendAPI } = config; + return response.data; +} - try { - const response = await Axios.get(`${backendAPI}/webhooks`, { - proxy: config.proxy, - params: { - ...params, - ...filter, - page_size: pageSize, - }, - headers: { - 'Content-Type': 'application/json', - }, - }); +async function updateOrganization(id, data) { + const { backendAPI } = config; - response.data.results.count = response.data.count; - return response.data.results; - } catch (errorData) { - throw generateError(errorData); - } - } + let response = null; + try { + response = await Axios.patch(`${backendAPI}/organizations/${id}`, JSON.stringify(data), { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } - async function createWebhook(webhookData: any): Promise { - const params = enableOrganization(); - const { backendAPI } = config; + return response.data; +} - try { - const response = await Axios.post(`${backendAPI}/webhooks`, JSON.stringify(webhookData), { - proxy: config.proxy, - params, - headers: { - 'Content-Type': 'application/json', - }, - }); - return response.data; - } catch (errorData) { - throw generateError(errorData); - } - } +async function deleteOrganization(id) { + const { backendAPI } = config; - async function updateWebhook(webhookID: number, webhookData: any): Promise { - const params = enableOrganization(); - const { backendAPI } = config; + try { + await Axios.delete(`${backendAPI}/organizations/${id}`, { + proxy: config.proxy, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } +} - try { - const response = await Axios - .patch(`${backendAPI}/webhooks/${webhookID}`, JSON.stringify(webhookData), { - proxy: config.proxy, - params, - headers: { - 'Content-Type': 'application/json', - }, - }); - return response.data; - } catch (errorData) { - throw generateError(errorData); - } - } +async function getOrganizationMembers(orgSlug, page, pageSize, filters = {}) { + const { backendAPI } = config; + + let response = null; + try { + response = await Axios.get(`${backendAPI}/memberships`, { + proxy: config.proxy, + params: { + ...filters, + org: orgSlug, + page, + page_size: pageSize, + }, + }); + } catch (errorData) { + throw generateError(errorData); + } - async function deleteWebhook(webhookID: number): Promise { - const params = enableOrganization(); - const { backendAPI } = config; + return response.data; +} - try { - await Axios.delete(`${backendAPI}/webhooks/${webhookID}`, { - proxy: config.proxy, - params, - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (errorData) { - throw generateError(errorData); - } - } +async function inviteOrganizationMembers(orgId, data) { + const { backendAPI } = config; + try { + await Axios.post( + `${backendAPI}/invitations`, + { + ...data, + organization: orgId, + }, + { + proxy: config.proxy, + }, + ); + } catch (errorData) { + throw generateError(errorData); + } +} - async function pingWebhook(webhookID: number): Promise { - const params = enableOrganization(); - const { backendAPI } = config; - - async function waitPingDelivery(deliveryID: number): Promise { - return new Promise((resolve) => { - async function checkStatus(): Promise { - const delivery = await getWebhookDelivery(webhookID, deliveryID); - if (delivery.status_code) { - resolve(delivery); - } else { - setTimeout(checkStatus, 1000); - } - } - setTimeout(checkStatus, 1000); - }); - } +async function updateOrganizationMembership(membershipId, data) { + const { backendAPI } = config; + let response = null; + try { + response = await Axios.patch( + `${backendAPI}/memberships/${membershipId}`, + { + ...data, + }, + { + proxy: config.proxy, + }, + ); + } catch (errorData) { + throw generateError(errorData); + } - try { - const response = await Axios.post(`${backendAPI}/webhooks/${webhookID}/ping`, { - proxy: config.proxy, - params, - headers: { - 'Content-Type': 'application/json', - }, - }); + return response.data; +} - const deliveryID = response.data.id; - const delivery = await waitPingDelivery(deliveryID); - return delivery; - } catch (errorData) { - throw generateError(errorData); - } - } +async function deleteOrganizationMembership(membershipId) { + const { backendAPI } = config; - async function receiveWebhookEvents(type: WebhookSourceType): Promise { - const { backendAPI } = config; + try { + await Axios.delete(`${backendAPI}/memberships/${membershipId}`, { + proxy: config.proxy, + }); + } catch (errorData) { + throw generateError(errorData); + } +} - try { - const response = await Axios.get(`${backendAPI}/webhooks/events`, { - proxy: config.proxy, - params: { - type, - }, - headers: { - 'Content-Type': 'application/json', - }, - }); - return response.data.events; - } catch (errorData) { - throw generateError(errorData); - } - } +async function getMembershipInvitation(id) { + const { backendAPI } = config; - async function advancedAuthentication(): Promise { - const { backendAPI } = config; - try { - const response = await Axios.get(`${backendAPI}/server/advanced-auth`, { - proxy: config.proxy, - }); - return response.data; - } catch (errorData) { - throw generateError(errorData); - } - } + let response = null; + try { + response = await Axios.get(`${backendAPI}/invitations/${id}`, { + proxy: config.proxy, + }); + return response.data; + } catch (errorData) { + throw generateError(errorData); + } +} - Object.defineProperties( - this, - Object.freeze({ - server: { - value: Object.freeze({ - about, - share, - formats, - exception, - login, - logout, - advancedAuthentication, - changePassword, - requestPasswordReset, - resetPassword, - authorized, - register, - request: serverRequest, - userAgreements, - installedApps, - }), - writable: false, - }, +async function getWebhookDelivery(webhookID: number, deliveryID: number): Promise { + const params = enableOrganization(); + const { backendAPI } = config; - projects: { - value: Object.freeze({ - get: getProjects, - searchNames: searchProjectNames, - save: saveProject, - create: createProject, - delete: deleteProject, - exportDataset: exportDataset('projects'), - backup: backupProject, - restore: restoreProject, - importDataset, - }), - writable: false, - }, + try { + const response = await Axios.get(`${backendAPI}/webhooks/${webhookID}/deliveries/${deliveryID}`, { + proxy: config.proxy, + params, + headers: { + 'Content-Type': 'application/json', + }, + }); + return response.data; + } catch (errorData) { + throw generateError(errorData); + } +} - tasks: { - value: Object.freeze({ - get: getTasks, - save: saveTask, - create: createTask, - delete: deleteTask, - exportDataset: exportDataset('tasks'), - backup: backupTask, - restore: restoreTask, - }), - writable: false, - }, +async function getWebhooks(filter, pageSize = 10): Promise { + const params = enableOrganization(); + const { backendAPI } = config; + + try { + const response = await Axios.get(`${backendAPI}/webhooks`, { + proxy: config.proxy, + params: { + ...params, + ...filter, + page_size: pageSize, + }, + headers: { + 'Content-Type': 'application/json', + }, + }); - jobs: { - value: Object.freeze({ - get: getJobs, - save: saveJob, - exportDataset: exportDataset('jobs'), - }), - writable: false, - }, + response.data.results.count = response.data.count; + return response.data.results; + } catch (errorData) { + throw generateError(errorData); + } +} - users: { - value: Object.freeze({ - get: getUsers, - self: getSelf, - }), - writable: false, - }, +async function createWebhook(webhookData: any): Promise { + const params = enableOrganization(); + const { backendAPI } = config; - frames: { - value: Object.freeze({ - getData, - getMeta, - saveMeta, - getPreview, - getImageContext, - }), - writable: false, - }, + try { + const response = await Axios.post(`${backendAPI}/webhooks`, JSON.stringify(webhookData), { + proxy: config.proxy, + params, + headers: { + 'Content-Type': 'application/json', + }, + }); + return response.data; + } catch (errorData) { + throw generateError(errorData); + } +} - annotations: { - value: Object.freeze({ - updateAnnotations, - getAnnotations, - dumpAnnotations, - uploadAnnotations, - }), - writable: false, +async function updateWebhook(webhookID: number, webhookData: any): Promise { + const params = enableOrganization(); + const { backendAPI } = config; + + try { + const response = await Axios + .patch(`${backendAPI}/webhooks/${webhookID}`, JSON.stringify(webhookData), { + proxy: config.proxy, + params, + headers: { + 'Content-Type': 'application/json', }, + }); + return response.data; + } catch (errorData) { + throw generateError(errorData); + } +} - logs: { - value: Object.freeze({ - save: saveLogs, - }), - writable: false, - }, +async function deleteWebhook(webhookID: number): Promise { + const params = enableOrganization(); + const { backendAPI } = config; - lambda: { - value: Object.freeze({ - list: getLambdaFunctions, - status: getRequestStatus, - requests: getLambdaRequests, - run: runLambdaRequest, - call: callLambdaFunction, - cancel: cancelLambdaRequest, - }), - writable: false, - }, + try { + await Axios.delete(`${backendAPI}/webhooks/${webhookID}`, { + proxy: config.proxy, + params, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (errorData) { + throw generateError(errorData); + } +} - issues: { - value: Object.freeze({ - create: createIssue, - update: updateIssue, - get: getJobIssues, - delete: deleteIssue, - }), - writable: false, - }, +async function pingWebhook(webhookID: number): Promise { + const params = enableOrganization(); + const { backendAPI } = config; + + async function waitPingDelivery(deliveryID: number): Promise { + return new Promise((resolve) => { + async function checkStatus(): Promise { + const delivery = await getWebhookDelivery(webhookID, deliveryID); + if (delivery.status_code) { + resolve(delivery); + } else { + setTimeout(checkStatus, 1000); + } + } + setTimeout(checkStatus, 1000); + }); + } - comments: { - value: Object.freeze({ - create: createComment, - }), - writable: false, - }, + try { + const response = await Axios.post(`${backendAPI}/webhooks/${webhookID}/ping`, { + proxy: config.proxy, + params, + headers: { + 'Content-Type': 'application/json', + }, + }); - predictor: { - value: Object.freeze({ - status: predictorStatus, - predict: predictAnnotations, - }), - writable: false, - }, + const deliveryID = response.data.id; + const delivery = await waitPingDelivery(deliveryID); + return delivery; + } catch (errorData) { + throw generateError(errorData); + } +} - cloudStorages: { - value: Object.freeze({ - get: getCloudStorages, - getContent: getCloudStorageContent, - getPreview: getCloudStoragePreview, - getStatus: getCloudStorageStatus, - create: createCloudStorage, - delete: deleteCloudStorage, - update: updateCloudStorage, - }), - writable: false, - }, +async function receiveWebhookEvents(type: WebhookSourceType): Promise { + const { backendAPI } = config; - organizations: { - value: Object.freeze({ - get: getOrganizations, - create: createOrganization, - update: updateOrganization, - members: getOrganizationMembers, - invitation: getMembershipInvitation, - delete: deleteOrganization, - invite: inviteOrganizationMembers, - updateMembership: updateOrganizationMembership, - deleteMembership: deleteOrganizationMembership, - }), - writable: false, - }, + try { + const response = await Axios.get(`${backendAPI}/webhooks/events`, { + proxy: config.proxy, + params: { + type, + }, + headers: { + 'Content-Type': 'application/json', + }, + }); + return response.data.events; + } catch (errorData) { + throw generateError(errorData); + } +} - webhooks: { - value: Object.freeze({ - get: getWebhooks, - create: createWebhook, - update: updateWebhook, - delete: deleteWebhook, - ping: pingWebhook, - events: receiveWebhookEvents, - }), - writable: false, - }, - }), - ); +async function advancedAuthentication(): Promise { + const { backendAPI } = config; + try { + const response = await Axios.get(`${backendAPI}/server/advanced-auth`, { + proxy: config.proxy, + }); + return response.data; + } catch (errorData) { + throw generateError(errorData); } } -const serverProxy = new ServerProxy(); -export default serverProxy; +export default Object.freeze({ + server: Object.freeze({ + about, + share, + formats, + exception, + login, + logout, + advancedAuthentication, + changePassword, + requestPasswordReset, + resetPassword, + authorized, + register, + request: serverRequest, + userAgreements, + installedApps, + }), + + projects: Object.freeze({ + get: getProjects, + searchNames: searchProjectNames, + save: saveProject, + create: createProject, + delete: deleteProject, + exportDataset: exportDataset('projects'), + backup: backupProject, + restore: restoreProject, + importDataset, + }), + + tasks: Object.freeze({ + get: getTasks, + save: saveTask, + create: createTask, + delete: deleteTask, + exportDataset: exportDataset('tasks'), + backup: backupTask, + restore: restoreTask, + }), + + jobs: Object.freeze({ + get: getJobs, + save: saveJob, + exportDataset: exportDataset('jobs'), + }), + + users: Object.freeze({ + get: getUsers, + self: getSelf, + }), + + frames: Object.freeze({ + getData, + getMeta, + saveMeta, + getPreview, + getImageContext, + }), + + annotations: Object.freeze({ + updateAnnotations, + getAnnotations, + dumpAnnotations, + uploadAnnotations, + }), + + logs: Object.freeze({ + save: saveLogs, + }), + + lambda: Object.freeze({ + list: getLambdaFunctions, + status: getRequestStatus, + requests: getLambdaRequests, + run: runLambdaRequest, + call: callLambdaFunction, + cancel: cancelLambdaRequest, + }), + + issues: Object.freeze({ + create: createIssue, + update: updateIssue, + get: getJobIssues, + delete: deleteIssue, + }), + + comments: Object.freeze({ + create: createComment, + }), + + predictor: Object.freeze({ + status: predictorStatus, + predict: predictAnnotations, + }), + + cloudStorages: Object.freeze({ + get: getCloudStorages, + getContent: getCloudStorageContent, + getPreview: getCloudStoragePreview, + getStatus: getCloudStorageStatus, + create: createCloudStorage, + delete: deleteCloudStorage, + update: updateCloudStorage, + }), + + organizations: Object.freeze({ + get: getOrganizations, + create: createOrganization, + update: updateOrganization, + members: getOrganizationMembers, + invitation: getMembershipInvitation, + delete: deleteOrganization, + invite: inviteOrganizationMembers, + updateMembership: updateOrganizationMembership, + deleteMembership: deleteOrganizationMembership, + }), + + webhooks: Object.freeze({ + get: getWebhooks, + create: createWebhook, + update: updateWebhook, + delete: deleteWebhook, + ping: pingWebhook, + events: receiveWebhookEvents, + }), +});