From 69693cba286cecbc6faab245bfc56773719e9540 Mon Sep 17 00:00:00 2001 From: YanJin Date: Wed, 20 Oct 2021 16:19:58 +0200 Subject: [PATCH] ZKUI-19: Format the code by using prettier --- .prettierrc | 5 + src/js/IAMClient.js | 226 +++-- src/js/S3Client.js | 685 +++++++------- src/js/STSClient.js | 33 +- src/js/ZenkoClient.js | 116 +-- src/js/config.js | 51 +- src/js/managementClient.js | 28 +- src/js/mock/IAMClient.js | 56 +- src/js/mock/S3Client.js | 347 +++---- src/js/mock/STSClient.js | 22 +- src/js/mock/ZenkoClient.js | 38 +- src/js/mock/error.js | 34 +- src/js/mock/managementClient.js | 418 +++++---- src/js/utils.js | 17 +- src/react/App.js | 13 +- src/react/Navbar.js | 231 ++--- src/react/NoMatch.jsx | 12 +- src/react/Routes.jsx | 110 ++- src/react/ZenkoUI.js | 97 +- src/react/account/AccountContent.jsx | 18 +- src/react/account/AccountCreate.jsx | 203 ++-- src/react/account/AccountDetails.jsx | 37 +- src/react/account/AccountHead.jsx | 29 +- src/react/account/AccountList.jsx | 221 +++-- src/react/account/AccountRow.jsx | 87 +- src/react/account/Accounts.jsx | 77 +- .../account/__tests__/AccountCreate.test.jsx | 271 +++--- .../account/__tests__/AccountDetails.test.jsx | 81 +- .../account/__tests__/AccountHead.test.jsx | 30 +- .../account/__tests__/AccountList.test.jsx | 106 ++- src/react/account/__tests__/Accounts.test.jsx | 135 +-- src/react/account/details/Locations.jsx | 398 +++++--- src/react/account/details/Properties.jsx | 30 +- .../details/__tests__/Locations.test.jsx | 633 ++++++++----- .../details/properties/AccountInfo.jsx | 149 +-- .../details/properties/AccountKeys.jsx | 333 ++++--- .../details/properties/SecretKeyModal.jsx | 175 ++-- .../properties/__tests__/AccountInfo.test.jsx | 73 +- .../properties/__tests__/AccountKeys.test.jsx | 152 +-- .../__tests__/SecretKeyModal.test.jsx | 91 +- src/react/actions/__tests__/account.test.jsx | 380 ++++---- src/react/actions/__tests__/auth.test.js | 136 +-- .../actions/__tests__/configuration.test.js | 42 +- src/react/actions/__tests__/endpoint.test.js | 220 ++--- src/react/actions/__tests__/location.test.jsx | 242 ++--- .../actions/__tests__/replication.test.js | 120 +-- src/react/actions/__tests__/s3bucket.test.jsx | 324 ++++--- src/react/actions/__tests__/s3object.test.jsx | 879 ++++++++++-------- .../__tests__/utils/dispatchActionsList.js | 524 ++++++----- src/react/actions/__tests__/utils/testUtil.js | 484 +++++----- src/react/actions/__tests__/workflow.test.js | 130 +-- src/react/actions/__tests__/zenko.test.js | 313 ++++--- src/react/actions/account.js | 323 ++++--- src/react/actions/auth.js | 198 ++-- src/react/actions/configuration.js | 61 +- src/react/actions/endpoint.js | 88 +- src/react/actions/error.js | 99 +- src/react/actions/location.js | 105 ++- src/react/actions/network.js | 34 +- src/react/actions/oidc.js | 8 +- src/react/actions/replication.js | 117 ++- src/react/actions/s3bucket.js | 217 +++-- src/react/actions/s3object.js | 667 ++++++++----- src/react/actions/secrets.js | 16 +- src/react/actions/stats.js | 58 +- src/react/actions/sts.js | 73 +- src/react/actions/user.js | 336 +++---- src/react/actions/workflow.js | 83 +- src/react/actions/zenko.js | 207 +++-- src/react/backend/StorageMonitor.jsx | 335 ++++--- .../LocationDetails/LocationDetails.jsx | 158 ++-- .../LocationDetails/LocationDetailsAws.jsx | 236 ++--- .../LocationDetailsAwsCustom.jsx | 266 +++--- .../LocationDetails/LocationDetailsAzure.jsx | 224 ++--- .../LocationDetailsDOSpaces.jsx | 230 ++--- .../LocationDetails/LocationDetailsGcp.jsx | 233 ++--- .../LocationDetailsHyperdriveV2.jsx | 77 +- .../LocationDetails/LocationDetailsNFS.jsx | 376 ++++---- .../LocationDetailsSproxyd.jsx | 189 ++-- .../LocationDetails/LocationDetailsWasabi.jsx | 246 ++--- .../__tests__/LocationDetailsAws.test.jsx | 192 ++-- .../LocationDetailsAwsCustom.test.jsx | 208 +++-- .../__tests__/LocationDetailsAzure.test.jsx | 186 ++-- .../LocationDetailsDOSpaces.test.jsx | 186 ++-- .../__tests__/LocationDetailsGcp.test.jsx | 188 ++-- .../LocationDetailsHyperdriveV2.test.jsx | 218 +++-- .../__tests__/LocationDetailsNFS.test.jsx | 312 ++++--- .../__tests__/LocationDetailsSproxyd.test.jsx | 264 +++--- .../__tests__/LocationDetailsWasabi.test.jsx | 188 ++-- .../backend/location/LocationDetails/index.js | 1 - .../LocationDetails/storageOptions.js | 256 ++--- src/react/backend/location/LocationEditor.jsx | 371 ++++---- .../backend/location/LocationOptions.jsx | 57 +- .../__tests__/LocationEditor.test.jsx | 69 +- src/react/backend/location/constants.js | 139 +-- .../backend/location/locationFormCheck.js | 178 ++-- src/react/backend/location/utils.js | 202 ++-- src/react/databrowser/DataBrowser.jsx | 109 ++- .../databrowser/buckets/BucketCreate.jsx | 138 +-- .../databrowser/buckets/BucketDetails.jsx | 41 +- src/react/databrowser/buckets/BucketHead.jsx | 36 +- src/react/databrowser/buckets/BucketList.jsx | 251 +++-- src/react/databrowser/buckets/BucketRow.jsx | 87 +- src/react/databrowser/buckets/Buckets.jsx | 74 +- .../buckets/__tests__/BucketCreate.test.jsx | 150 +-- .../buckets/__tests__/BucketList.test.jsx | 143 +-- .../buckets/__tests__/Buckets.test.jsx | 93 +- .../databrowser/buckets/details/Overview.jsx | 258 ++--- .../details/__tests__/Overview.test.jsx | 230 ++--- .../databrowser/objects/FolderCreate.jsx | 111 ++- .../databrowser/objects/MetadataSearch.jsx | 189 ++-- .../databrowser/objects/ObjectDelete.jsx | 212 +++-- .../databrowser/objects/ObjectDetails.jsx | 108 ++- src/react/databrowser/objects/ObjectHead.jsx | 26 +- src/react/databrowser/objects/ObjectList.jsx | 158 +++- .../databrowser/objects/ObjectListTable.jsx | 451 +++++---- src/react/databrowser/objects/ObjectRow.jsx | 82 +- .../databrowser/objects/ObjectUpload.jsx | 286 +++--- src/react/databrowser/objects/Objects.jsx | 151 +-- .../objects/__tests__/FolderCreate.test.jsx | 126 +-- .../objects/__tests__/MetadataSearch.test.jsx | 182 ++-- .../objects/__tests__/ObjectDelete.test.jsx | 132 ++- .../objects/__tests__/ObjectDetails.test.jsx | 286 +++--- .../objects/__tests__/ObjectList.test.jsx | 348 ++++--- .../objects/__tests__/ObjectUpload.test.jsx | 296 +++--- .../objects/__tests__/utils/testUtil.js | 46 +- .../databrowser/objects/details/Metadata.jsx | 388 ++++---- .../objects/details/Properties.jsx | 84 +- .../databrowser/objects/details/Tags.jsx | 201 ++-- .../details/__tests__/Metadata.test.jsx | 439 +++++---- .../objects/details/__tests__/Tags.test.jsx | 257 ++--- src/react/endpoint/EndpointCreate.jsx | 215 +++-- src/react/endpoint/EndpointList.jsx | 269 +++--- src/react/endpoint/EndpointRow.jsx | 66 +- src/react/endpoint/Endpoints.jsx | 43 +- src/react/reducers/account.js | 19 +- src/react/reducers/auth.js | 75 +- src/react/reducers/bucket.js | 14 +- src/react/reducers/configuration.js | 19 +- src/react/reducers/index.js | 5 +- src/react/reducers/initialConstants.js | 343 +++---- src/react/reducers/instanceStatus.js | 19 +- src/react/reducers/instances.js | 19 +- src/react/reducers/networkActivity.js | 47 +- src/react/reducers/oidc.js | 19 +- src/react/reducers/s3.js | 334 ++++--- src/react/reducers/secrets.js | 35 +- src/react/reducers/stats.js | 36 +- src/react/reducers/uiAccounts.js | 43 +- src/react/reducers/uiBuckets.js | 27 +- src/react/reducers/uiConfig.js | 19 +- src/react/reducers/uiEndpoints.js | 28 +- src/react/reducers/uiErrors.js | 31 +- src/react/reducers/uiLocations.js | 22 +- src/react/reducers/uiObjects.js | 59 +- src/react/reducers/uiUser.js | 54 +- src/react/reducers/uiWorkflows.js | 43 +- src/react/reducers/user.js | 64 +- src/react/reducers/workflow.js | 57 +- src/react/reducers/zenko.js | 55 +- src/react/store.js | 4 +- src/react/ui-elements/Activity.jsx | 60 +- src/react/ui-elements/Breadcrumb.jsx | 239 +++-- src/react/ui-elements/Clipboard.jsx | 60 +- src/react/ui-elements/Container.jsx | 92 +- src/react/ui-elements/DeleteConfirmation.jsx | 46 +- src/react/ui-elements/EditableKeyValue.jsx | 231 ++--- src/react/ui-elements/ErrorHandlerModal.jsx | 38 +- src/react/ui-elements/FormContainer.jsx | 108 +-- src/react/ui-elements/FormLayout.jsx | 173 ++-- src/react/ui-elements/Head.jsx | 11 +- src/react/ui-elements/Hide.jsx | 58 +- src/react/ui-elements/Input.jsx | 57 +- src/react/ui-elements/InputList.jsx | 313 ++++--- src/react/ui-elements/ListLayout.jsx | 74 +- src/react/ui-elements/ListLayout2.jsx | 151 ++- src/react/ui-elements/ListLayout3.jsx | 64 +- src/react/ui-elements/ListLayout4.jsx | 14 +- src/react/ui-elements/Loader.jsx | 8 +- src/react/ui-elements/MiddleEllipsis.jsx | 213 +++-- src/react/ui-elements/Modal.jsx | 34 +- src/react/ui-elements/PrivateRoute.jsx | 28 +- src/react/ui-elements/ReauthDialog.jsx | 73 +- src/react/ui-elements/ScrollbarWrapper.jsx | 78 +- src/react/ui-elements/Table.jsx | 245 ++--- src/react/ui-elements/TableKeyValue.jsx | 59 +- src/react/ui-elements/TableKeyValue2.jsx | 91 +- src/react/ui-elements/Tabs.jsx | 12 +- src/react/ui-elements/TextBadge.jsx | 6 +- src/react/ui-elements/Utility.jsx | 6 +- src/react/ui-elements/Warning.jsx | 117 ++- .../ui-elements/__tests__/Activity.test.jsx | 50 +- .../ui-elements/__tests__/Clipboard.test.jsx | 32 +- .../__tests__/DeleteConfirmation.test.jsx | 96 +- .../__tests__/ErrorHandlerModal.test.jsx | 54 +- .../__tests__/MiddleEllipsis.test.jsx | 111 ++- .../__tests__/ReauthDialog.test.jsx | 159 ++-- src/react/utils/__tests__/hooks.test.jsx | 113 ++- src/react/utils/__tests__/index.test.jsx | 230 ++--- src/react/utils/actions.js | 14 +- src/react/utils/hooks.js | 58 +- src/react/utils/index.js | 83 +- src/react/utils/localStorage.js | 6 +- src/react/utils/s3.js | 113 +-- src/react/utils/storageOptions.js | 137 ++- src/react/utils/test.js | 199 ++-- src/react/workflow/WorkflowContent.jsx | 117 ++- src/react/workflow/WorkflowList.jsx | 200 ++-- src/react/workflow/WorkflowRow.jsx | 79 +- src/react/workflow/Workflows.jsx | 138 +-- src/react/workflow/details/Configuration.jsx | 126 ++- .../workflow/replication/Replication.jsx | 509 +++++----- src/react/workflow/replication/utils.jsx | 249 ++--- src/types/account.js | 27 +- src/types/actions.js | 425 +++++---- src/types/auth.js | 2 +- src/types/config.js | 58 +- src/types/entities.js | 14 +- src/types/iam.js | 24 +- src/types/location.js | 20 +- src/types/managementClient.js | 38 +- src/types/replication.js | 44 +- src/types/s3.js | 184 ++-- src/types/state.js | 167 ++-- src/types/stats.js | 153 ++- src/types/storageOptionsHelper.js | 8 +- src/types/sts.js | 24 +- src/types/ui.js | 4 +- src/types/user.js | 10 +- src/types/workflow.js | 14 +- src/types/zenko.js | 42 +- 231 files changed, 18595 insertions(+), 14684 deletions(-) create mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..52d65b1cb --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "all" +} diff --git a/src/js/IAMClient.js b/src/js/IAMClient.js index 8fc14380a..18bf49a16 100644 --- a/src/js/IAMClient.js +++ b/src/js/IAMClient.js @@ -6,115 +6,135 @@ import IAM from 'aws-sdk/clients/iam'; import type { IAMClient as IAMClientInterface } from '../types/iam'; import { getClients } from '../react/utils/actions'; -export function getAssumeRoleWithWebIdentityIAM(state: AppState, accountName: string): Promise { - const { oidc, auth, configuration } = state; - const { stsClient } = getClients(state); - const accounts = configuration.latest.users; - const account = accounts.find(a => a.userName === accountName); - - if (!account || !oidc || !oidc.user) - return Promise.reject(); - const assumeRoleParams = { - idToken: oidc.user.id_token, - RoleSessionName:'app1', - roleArn: `arn:aws:iam::${account.id}:role/roleForB`, +export function getAssumeRoleWithWebIdentityIAM( + state: AppState, + accountName: string, +): Promise { + const { oidc, auth, configuration } = state; + const { stsClient } = getClients(state); + const accounts = configuration.latest.users; + const account = accounts.find(a => a.userName === accountName); + + if (!account || !oidc || !oidc.user) return Promise.reject(); + const assumeRoleParams = { + idToken: oidc.user.id_token, + RoleSessionName: 'app1', + roleArn: `arn:aws:iam::${account.id}:role/roleForB`, + }; + return stsClient.assumeRoleWithWebIdentity(assumeRoleParams).then(creds => { + const params = { + accessKey: creds.Credentials.AccessKeyId, + secretKey: creds.Credentials.SecretAccessKey, + sessionToken: creds.Credentials.SessionToken, }; - return stsClient.assumeRoleWithWebIdentity(assumeRoleParams) - .then(creds => { - const params = { - accessKey: creds.Credentials.AccessKeyId, - secretKey: creds.Credentials.SecretAccessKey, - sessionToken: creds.Credentials.SessionToken, - }; - const iamClient = new IAMClient(auth.config.iamEndpoint); - iamClient.login(params); - return iamClient; - }); + const iamClient = new IAMClient(auth.config.iamEndpoint); + iamClient.login(params); + return iamClient; + }); } export default class IAMClient implements IAMClientInterface { - constructor(endpoint) { - this.endpoint = endpoint; - } - - login(creds: Credentials) { - this.client = new IAM({ - // endpoint: 'https://iam.amazonaws.com', - endpoint: this.endpoint, - accessKeyId: creds.accessKey, - secretAccessKey: creds.secretKey, - sessionToken: creds.sessionToken, - region: 'us-east-1', - }); - } - - logout() { - if (this.client) - this.client.config.update({ accessKeyId: '', secretAccessKey: '', sessionToken: '' }); - } - - createAccessKey(userName) { - return this.client.createAccessKey({ - UserName: userName, - }).promise(); - } - - createUser(userName) { - return this.client.createUser({ - UserName: userName, - }).promise(); - } - - deleteAccessKey(accessKey, userName) { - const params = { - AccessKeyId: accessKey, - UserName: userName, - }; - return this.client.deleteAccessKey(params).promise(); - } - - deleteUser(userName) { - return this.client.deleteUser({ - UserName: userName, - }).promise(); - } - - getUser(userName) { - return this.client.getUser({ - UserName: userName, - }).promise(); - } - - listOwnAccessKeys() { - return this.client.listAccessKeys().promise(); - } - - listAccessKeys(userName) { - return this.client.listAccessKeys({ - UserName: userName, - }).promise(); - } - - listAttachedUserPolicies(userName) { - return this.client.listAttachedUserPolicies({ - UserName: userName, - }).promise(); - } - - listGroupsForUser(userName) { - return this.client.listGroupsForUser({ - UserName: userName, - }).promise(); - } - - listUsers() { - return this.client.listUsers({ - MaxItems: 20, - }).promise(); - } + constructor(endpoint) { + this.endpoint = endpoint; + } + + login(creds: Credentials) { + this.client = new IAM({ + // endpoint: 'https://iam.amazonaws.com', + endpoint: this.endpoint, + accessKeyId: creds.accessKey, + secretAccessKey: creds.secretKey, + sessionToken: creds.sessionToken, + region: 'us-east-1', + }); + } + + logout() { + if (this.client) + this.client.config.update({ + accessKeyId: '', + secretAccessKey: '', + sessionToken: '', + }); + } + + createAccessKey(userName) { + return this.client + .createAccessKey({ + UserName: userName, + }) + .promise(); + } + + createUser(userName) { + return this.client + .createUser({ + UserName: userName, + }) + .promise(); + } + + deleteAccessKey(accessKey, userName) { + const params = { + AccessKeyId: accessKey, + UserName: userName, + }; + return this.client.deleteAccessKey(params).promise(); + } + + deleteUser(userName) { + return this.client + .deleteUser({ + UserName: userName, + }) + .promise(); + } + + getUser(userName) { + return this.client + .getUser({ + UserName: userName, + }) + .promise(); + } + + listOwnAccessKeys() { + return this.client.listAccessKeys().promise(); + } + + listAccessKeys(userName) { + return this.client + .listAccessKeys({ + UserName: userName, + }) + .promise(); + } + + listAttachedUserPolicies(userName) { + return this.client + .listAttachedUserPolicies({ + UserName: userName, + }) + .promise(); + } + + listGroupsForUser(userName) { + return this.client + .listGroupsForUser({ + UserName: userName, + }) + .promise(); + } + + listUsers() { + return this.client + .listUsers({ + MaxItems: 20, + }) + .promise(); + } } - // OFFLILE // export default class IAMClient { // constructor() { diff --git a/src/js/S3Client.js b/src/js/S3Client.js index e40a2a581..041138173 100644 --- a/src/js/S3Client.js +++ b/src/js/S3Client.js @@ -4,366 +4,403 @@ import { chunkArray } from './utils'; import { isVersioning } from '../react/utils'; const MULTIPART_UPLOAD = { - partSize: 1024 * 1024 * 6, - queueSize: 1, + partSize: 1024 * 1024 * 6, + queueSize: 1, }; const publicAclIndicator = 'http://acs.amazonaws.com/groups/global/AllUsers'; export default class S3Client { - client: S3; + client: S3; - constructor(endpoint) { - this.auth(endpoint, {}); - } + constructor(endpoint) { + this.auth(endpoint, {}); + } - auth(endpoint, creds) { - this.client = new S3({ - endpoint: endpoint, - accessKeyId: creds.accessKey, - secretAccessKey: creds.secretKey, - sessionToken: creds.sessionToken, - region: 'us-east-1', - s3ForcePathStyle: true, - signatureVersion: 'v4', - }); - } + auth(endpoint, creds) { + this.client = new S3({ + endpoint: endpoint, + accessKeyId: creds.accessKey, + secretAccessKey: creds.secretKey, + sessionToken: creds.sessionToken, + region: 'us-east-1', + s3ForcePathStyle: true, + signatureVersion: 'v4', + }); + } - listBuckets() { - return this.client.listBuckets().promise(); - } + listBuckets() { + return this.client.listBuckets().promise(); + } - listBucketsWithLocation() { - return this.client.listBuckets().promise() - .then(list => { - return Promise.all(list.Buckets.map((bucket, key) => { - return Promise.all([ - this.client.getBucketLocation({ Bucket: bucket.Name }).promise(), - this.client.getBucketVersioning({ Bucket: bucket.Name }).promise(), - ]) - .then(([loc, ver]) => { - list.Buckets[key].LocationConstraint = loc.LocationConstraint; - list.Buckets[key].VersionStatus = ver.Status; - }); - })).then(() => { - return list; - }); + listBucketsWithLocation() { + return this.client + .listBuckets() + .promise() + .then(list => { + return Promise.all( + list.Buckets.map((bucket, key) => { + return Promise.all([ + this.client.getBucketLocation({ Bucket: bucket.Name }).promise(), + this.client + .getBucketVersioning({ Bucket: bucket.Name }) + .promise(), + ]).then(([loc, ver]) => { + list.Buckets[key].LocationConstraint = loc.LocationConstraint; + list.Buckets[key].VersionStatus = ver.Status; }); - } + }), + ).then(() => { + return list; + }); + }); + } - createBucket(bucket) { - const params = { - Bucket: bucket.name, - CreateBucketConfiguration: { - LocationConstraint: bucket.locationConstraint, - }, - }; - return this.client.createBucket(params).promise(); - } + createBucket(bucket) { + const params = { + Bucket: bucket.name, + CreateBucketConfiguration: { + LocationConstraint: bucket.locationConstraint, + }, + }; + return this.client.createBucket(params).promise(); + } - deleteBucket(bucketName) { - const params = { - Bucket: bucketName, - }; - return this.client.deleteBucket(params).promise(); - } + deleteBucket(bucketName) { + const params = { + Bucket: bucketName, + }; + return this.client.deleteBucket(params).promise(); + } + + // objects + listObjects(params) { + const { Bucket, Prefix, ContinuationToken } = params; + return this.client + .listObjectsV2({ + Bucket, + Delimiter: '/', + Prefix, + MaxKeys: 100, + ContinuationToken, + }) + .promise(); + } - // objects - listObjects(params) { - const { Bucket, Prefix, ContinuationToken } = params; - return this.client.listObjectsV2({ - Bucket, - Delimiter: '/', - Prefix, - MaxKeys: 100, - ContinuationToken, - }).promise(); - } + listObjectVersions(params) { + const { Bucket, Prefix, KeyMarker, VersionIdMarker } = params; + return this.client + .listObjectVersions({ + Bucket, + Prefix, + Delimiter: '/', + MaxKeys: 100, + KeyMarker, + VersionIdMarker, + }) + .promise(); + } - listObjectVersions(params) { - const { Bucket, Prefix, KeyMarker, VersionIdMarker } = params; - return this.client.listObjectVersions({ - Bucket, - Prefix, - Delimiter: '/', - MaxKeys: 100, - KeyMarker, - VersionIdMarker, - }).promise(); - } + createFolder(bucketName, prefixWithSlash, folderName) { + const key = `${prefixWithSlash}${folderName}`; + const params = { + Bucket: bucketName, + Key: key, + }; + return this.client.putObject(params).promise(); + } - createFolder(bucketName, prefixWithSlash, folderName) { - const key = `${prefixWithSlash}${folderName}`; + uploadObject(bucketName, prefixWithSlash, files) { + return Promise.all( + files.map(file => { + const key = `${prefixWithSlash}${file.name}`; const params = { - Bucket: bucketName, - Key: key, + Bucket: bucketName, + Key: key, + Body: file, + ContentType: file.type, }; - return this.client.putObject(params).promise(); - } - - uploadObject(bucketName, prefixWithSlash, files) { - return Promise.all(files.map(file => { - const key = `${prefixWithSlash}${file.name}`; - const params = { - Bucket: bucketName, - Key: key, - Body: file, - ContentType: file.type, - }; - const options = { partSize: MULTIPART_UPLOAD.partSize, - queueSize: MULTIPART_UPLOAD.queueSize }; - return this.client.upload(params, options).promise(); - })); - } - - _deleteFolders(bucketName, folders){ - return new Promise((resolve, reject) => { - if (folders.length < 1) { - return resolve(); - } - return Promise.all(folders.map(folder => { - return this.listObjectVersions({ Bucket: bucketName, Prefix: folder.Key }) - .then((res) => { - const { Versions, DeleteMarkers, CommonPrefixes } = res; - const filteredVersions = Versions.filter(v => v.Key === folder.Key); - const filteredDM = DeleteMarkers.filter(v => v.Key === folder.Key); - // only delete "empty folders" - if (CommonPrefixes.length > 0 || filteredVersions.length + filteredDM.length < Versions.length + DeleteMarkers.length) { - return { - Errors: [Error('Cannot delete folder: The folder is not empty')], - }; - } - const versions = filteredVersions.map(v => { - return { - Key: v.Key, - VersionId: v.VersionId, - }; - }); - const deleteMarkers = filteredDM.map(v => { - return { - Key: v.Key, - VersionId: v.VersionId, - }; - }); - const objects = versions.concat(deleteMarkers); - return this.client.deleteObjects({ - Bucket: bucketName, - Delete: { - Objects: objects, - }, - }).promise(); - }); - })) - .then(results => { - const error = results.find(result => result.Errors.length > 0); - if (error) { - return reject(error.Errors[0]); - } - return resolve(); - }) - .catch(error => reject(error)); - }); - } + const options = { + partSize: MULTIPART_UPLOAD.partSize, + queueSize: MULTIPART_UPLOAD.queueSize, + }; + return this.client.upload(params, options).promise(); + }), + ); + } - deleteObjects(bucketName, objects, folders) { - return new Promise((resolve, reject) => { - if (objects.length < 1) { - return resolve(); - } - // NOTE: AWS S3 deleteObjects can not delete more than 1000 objects. - if (objects.length > 1000) { - const chunks = chunkArray(objects, 1000); - return Promise.all(chunks.map(chunk => { - const params = { - Bucket: bucketName, - Delete: { - Objects: chunk, - }, - }; - return this.client.deleteObjects(params).promise(); - })) - .then(() => resolve()) - .catch(error => reject(error)); + _deleteFolders(bucketName, folders) { + return new Promise((resolve, reject) => { + if (folders.length < 1) { + return resolve(); + } + return Promise.all( + folders.map(folder => { + return this.listObjectVersions({ + Bucket: bucketName, + Prefix: folder.Key, + }).then(res => { + const { Versions, DeleteMarkers, CommonPrefixes } = res; + const filteredVersions = Versions.filter(v => v.Key === folder.Key); + const filteredDM = DeleteMarkers.filter(v => v.Key === folder.Key); + // only delete "empty folders" + if ( + CommonPrefixes.length > 0 || + filteredVersions.length + filteredDM.length < + Versions.length + DeleteMarkers.length + ) { + return { + Errors: [ + Error('Cannot delete folder: The folder is not empty'), + ], + }; } - const params = { + const versions = filteredVersions.map(v => { + return { + Key: v.Key, + VersionId: v.VersionId, + }; + }); + const deleteMarkers = filteredDM.map(v => { + return { + Key: v.Key, + VersionId: v.VersionId, + }; + }); + const objects = versions.concat(deleteMarkers); + return this.client + .deleteObjects({ Bucket: bucketName, Delete: { - Objects: objects, + Objects: objects, }, + }) + .promise(); + }); + }), + ) + .then(results => { + const error = results.find(result => result.Errors.length > 0); + if (error) { + return reject(error.Errors[0]); + } + return resolve(); + }) + .catch(error => reject(error)); + }); + } + + deleteObjects(bucketName, objects, folders) { + return new Promise((resolve, reject) => { + if (objects.length < 1) { + return resolve(); + } + // NOTE: AWS S3 deleteObjects can not delete more than 1000 objects. + if (objects.length > 1000) { + const chunks = chunkArray(objects, 1000); + return Promise.all( + chunks.map(chunk => { + const params = { + Bucket: bucketName, + Delete: { + Objects: chunk, + }, }; - return this.client.deleteObjects(params, (error, data) => { - (error) ? reject(error) : resolve(data); - }); - }).then(() => this._deleteFolders(bucketName, folders)); - } + return this.client.deleteObjects(params).promise(); + }), + ) + .then(() => resolve()) + .catch(error => reject(error)); + } + const params = { + Bucket: bucketName, + Delete: { + Objects: objects, + }, + }; + return this.client.deleteObjects(params, (error, data) => { + error ? reject(error) : resolve(data); + }); + }).then(() => this._deleteFolders(bucketName, folders)); + } - getObjectSignedUrl(bucketName, objectName, versionId){ - const params = { - Bucket: bucketName, - Key: objectName, - VersionId: versionId, - }; - return this.client.getSignedUrl('getObject', params); - } + getObjectSignedUrl(bucketName, objectName, versionId) { + const params = { + Bucket: bucketName, + Key: objectName, + VersionId: versionId, + }; + return this.client.getSignedUrl('getObject', params); + } - // TODO: add VersionId - headObject(bucketName, objectName, versionId) { - const params = { - Bucket: bucketName, - Key: objectName, - VersionId: versionId, - // To avoid cached/outdated metadata. - IfNoneMatch: '', - }; - return this.client.headObject(params).promise(); - } + // TODO: add VersionId + headObject(bucketName, objectName, versionId) { + const params = { + Bucket: bucketName, + Key: objectName, + VersionId: versionId, + // To avoid cached/outdated metadata. + IfNoneMatch: '', + }; + return this.client.headObject(params).promise(); + } - putObjectMetadata(bucketName, objectKey, systemMetadata, userMetadata) { - const { CacheControl, ContentDisposition, ContentEncoding, - ContentType, WebsiteRedirectLocation } = systemMetadata; - const sourceName = `/${bucketName}/${objectKey}`; - const params = { - Bucket: bucketName, - Key: objectKey, - CopySource: sourceName, - CacheControl, - ContentDisposition, - ContentEncoding, - ContentType, - WebsiteRedirectLocation, - Metadata: userMetadata, - MetadataDirective: 'REPLACE', - }; - return this.client.copyObject(params).promise(); - } + putObjectMetadata(bucketName, objectKey, systemMetadata, userMetadata) { + const { + CacheControl, + ContentDisposition, + ContentEncoding, + ContentType, + WebsiteRedirectLocation, + } = systemMetadata; + const sourceName = `/${bucketName}/${objectKey}`; + const params = { + Bucket: bucketName, + Key: objectKey, + CopySource: sourceName, + CacheControl, + ContentDisposition, + ContentEncoding, + ContentType, + WebsiteRedirectLocation, + Metadata: userMetadata, + MetadataDirective: 'REPLACE', + }; + return this.client.copyObject(params).promise(); + } - getObjectTagging(bucketName, objectKey, versionId) { - const params = { - Bucket: bucketName, - Key: objectKey, - VersionId: versionId, - }; - return this.client.getObjectTagging(params).promise(); - } + getObjectTagging(bucketName, objectKey, versionId) { + const params = { + Bucket: bucketName, + Key: objectKey, + VersionId: versionId, + }; + return this.client.getObjectTagging(params).promise(); + } - putObjectTagging(bucketName, objectKey, tags, versionId) { - const params = { - Bucket: bucketName, - Key: objectKey, - Tagging: { - TagSet: tags, - }, - VersionId: versionId, - }; - return this.client.putObjectTagging(params).promise(); - } + putObjectTagging(bucketName, objectKey, tags, versionId) { + const params = { + Bucket: bucketName, + Key: objectKey, + Tagging: { + TagSet: tags, + }, + VersionId: versionId, + }; + return this.client.putObjectTagging(params).promise(); + } - toggleVersioning(bucketName, isVersioning) { - const params = { - Bucket: bucketName, - VersioningConfiguration: { - Status: isVersioning ? 'Enabled' : 'Suspended', - }, - }; - return this.client.putBucketVersioning(params).promise(); - } + toggleVersioning(bucketName, isVersioning) { + const params = { + Bucket: bucketName, + VersioningConfiguration: { + Status: isVersioning ? 'Enabled' : 'Suspended', + }, + }; + return this.client.putBucketVersioning(params).promise(); + } - _getBucketCors(params) { - return new Promise((resolve, reject) => { - this.client.getBucketCors(params, error => { - if (error) { - if (error.code === 'NoSuchCORSConfiguration') { - return resolve(false); - } - return reject(error); - } - return resolve(true); - }); - }); - } + _getBucketCors(params) { + return new Promise((resolve, reject) => { + this.client.getBucketCors(params, error => { + if (error) { + if (error.code === 'NoSuchCORSConfiguration') { + return resolve(false); + } + return reject(error); + } + return resolve(true); + }); + }); + } - _getBucketLocation(params) { - return new Promise((resolve, reject) => { - this.client.getBucketLocation(params, (error, data) => { - (error) ? reject(error) : resolve(data.LocationConstraint); - }); - }); - } + _getBucketLocation(params) { + return new Promise((resolve, reject) => { + this.client.getBucketLocation(params, (error, data) => { + error ? reject(error) : resolve(data.LocationConstraint); + }); + }); + } - _getBucketAcl(params) { - return new Promise((resolve, reject) => { - this.client.getBucketAcl(params, (error, data) => { - if (error) { - return reject(error); - } - return resolve(data); - }); - }); - } + _getBucketAcl(params) { + return new Promise((resolve, reject) => { + this.client.getBucketAcl(params, (error, data) => { + if (error) { + return reject(error); + } + return resolve(data); + }); + }); + } - _getBucketVersioning(params) { - return new Promise((resolve, reject) => { - this.client.getBucketVersioning(params, (error, data) => { - if (error) { - return reject(error); - } - if (data.Status) { - return resolve(data.Status); - } - return resolve('Disabled'); - }); - }); - } + _getBucketVersioning(params) { + return new Promise((resolve, reject) => { + this.client.getBucketVersioning(params, (error, data) => { + if (error) { + return reject(error); + } + if (data.Status) { + return resolve(data.Status); + } + return resolve('Disabled'); + }); + }); + } - _getBucketReplication(params) { - return new Promise((resolve, reject) => { - this.client.getBucketReplication(params, error => { - if (error) { - if (error.code === 'ReplicationConfigurationNotFoundError') { - return resolve(false); - } - return reject(error); - } - return resolve(true); - }); - }); - } + _getBucketReplication(params) { + return new Promise((resolve, reject) => { + this.client.getBucketReplication(params, error => { + if (error) { + if (error.code === 'ReplicationConfigurationNotFoundError') { + return resolve(false); + } + return reject(error); + } + return resolve(true); + }); + }); + } - getBucketInfo(bucketName) { - const params = { - Bucket: bucketName, - }; + getBucketInfo(bucketName) { + const params = { + Bucket: bucketName, + }; - const bucketInfo = { - name: bucketName, - policy: false, - owner: '', - aclGrantees: 0, - cors: false, - isVersioning: false, - versioning: 'Disabled', - public: false, - locationConstraint: '', - }; + const bucketInfo = { + name: bucketName, + policy: false, + owner: '', + aclGrantees: 0, + cors: false, + isVersioning: false, + versioning: 'Disabled', + public: false, + locationConstraint: '', + }; - return new Promise((resolve, reject) => { - return Promise.all([this._getBucketCors(params), this._getBucketLocation(params), - this._getBucketAcl(params), this._getBucketVersioning(params)]) - .then((values) => { - const [ cors, location, acl, versioning ] = values; - bucketInfo.cors = cors; - bucketInfo.locationConstraint = location; - bucketInfo.owner = acl.Owner.DisplayName; - bucketInfo.aclGrantees = acl.Grants.length; - bucketInfo.public = acl.Grants.find(grant => - grant.Grantee.URI === publicAclIndicator); - bucketInfo.versioning = versioning; - bucketInfo.isVersioning = isVersioning(versioning); - return resolve(bucketInfo); - }) - .catch(error => { - return reject(error); - }); + return new Promise((resolve, reject) => { + return Promise.all([ + this._getBucketCors(params), + this._getBucketLocation(params), + this._getBucketAcl(params), + this._getBucketVersioning(params), + ]) + .then(values => { + const [cors, location, acl, versioning] = values; + bucketInfo.cors = cors; + bucketInfo.locationConstraint = location; + bucketInfo.owner = acl.Owner.DisplayName; + bucketInfo.aclGrantees = acl.Grants.length; + bucketInfo.public = acl.Grants.find( + grant => grant.Grantee.URI === publicAclIndicator, + ); + bucketInfo.versioning = versioning; + bucketInfo.isVersioning = isVersioning(versioning); + return resolve(bucketInfo); + }) + .catch(error => { + return reject(error); }); - } + }); + } } diff --git a/src/js/STSClient.js b/src/js/STSClient.js index a48ee9c6d..62fcafd2f 100644 --- a/src/js/STSClient.js +++ b/src/js/STSClient.js @@ -1,24 +1,23 @@ import STS from 'aws-sdk/clients/sts'; export default class STSClient { - constructor(conf) { - this.client = new STS({ - endpoint: conf.endpoint, - region: 'us-east-1', - }); - } - - assumeRoleWithWebIdentity(params) { - const { idToken, roleArn } = params; - const p = { - DurationSeconds: 900, // 15 minutes - RoleArn: roleArn, - RoleSessionName: 'zenko-ui', - WebIdentityToken: idToken, - }; - return this.client.assumeRoleWithWebIdentity(p).promise(); - } + constructor(conf) { + this.client = new STS({ + endpoint: conf.endpoint, + region: 'us-east-1', + }); + } + assumeRoleWithWebIdentity(params) { + const { idToken, roleArn } = params; + const p = { + DurationSeconds: 900, // 15 minutes + RoleArn: roleArn, + RoleSessionName: 'zenko-ui', + WebIdentityToken: idToken, + }; + return this.client.assumeRoleWithWebIdentity(p).promise(); + } } // TODO: Testing only, remove it once STS.assumeRoleWithWebIdentity is implemented in Vault. diff --git a/src/js/ZenkoClient.js b/src/js/ZenkoClient.js index fd58a7ed9..4b87d7bfb 100644 --- a/src/js/ZenkoClient.js +++ b/src/js/ZenkoClient.js @@ -1,70 +1,82 @@ // @noflow import type { - Credentials, - SearchBucketResp, - SearchParams, - ZenkoClient as ZenkoClientInterface, + Credentials, + SearchBucketResp, + SearchParams, + ZenkoClient as ZenkoClientInterface, } from '../types/zenko'; import S3Client from './S3Client'; // TODO: prevent zenkoclient from including in the bundle the full AWS SDK. import ZenkoClientBase from 'zenkoclient'; - class ZenkoClient extends S3Client implements ZenkoClientInterface { - endpoint: string; - _xmlClient: ZenkoClientBase; + endpoint: string; + _xmlClient: ZenkoClientBase; - constructor(endpoint) { - super(endpoint); - this.endpoint = endpoint; - this._init(); - } + constructor(endpoint) { + super(endpoint); + this.endpoint = endpoint; + this._init(); + } - _init() { - const accessKey = ''; - const secretKey = ''; - const sessionToken = ''; - this._xmlClient = new ZenkoClientBase({ - accessKeyId: accessKey, - secretAccessKey: secretKey, - sessionToken, - apiVersion: '2018-07-11-xml', - endpoint: this.endpoint, - // sslEnabled: false, - s3ForcePathStyle: true, - signatureVersion: 'v4', - maxRetries: 0, - }); - } + _init() { + const accessKey = ''; + const secretKey = ''; + const sessionToken = ''; + this._xmlClient = new ZenkoClientBase({ + accessKeyId: accessKey, + secretAccessKey: secretKey, + sessionToken, + apiVersion: '2018-07-11-xml', + endpoint: this.endpoint, + // sslEnabled: false, + s3ForcePathStyle: true, + signatureVersion: 'v4', + maxRetries: 0, + }); + } - logout() { - this._xmlClient.config.update({ accessKeyId: '', secretAccessKey: '', sessionToken: '' }); - this.client.config.update({ accessKeyId: '', secretAccessKey: '', sessionToken: '' }); - } + logout() { + this._xmlClient.config.update({ + accessKeyId: '', + secretAccessKey: '', + sessionToken: '', + }); + this.client.config.update({ + accessKeyId: '', + secretAccessKey: '', + sessionToken: '', + }); + } - login(params: Credentials): void { - const { accessKey, secretKey, sessionToken } = params; - this._xmlClient.config.update({ - accessKeyId: accessKey, secretAccessKey: secretKey, sessionToken }); + login(params: Credentials): void { + const { accessKey, secretKey, sessionToken } = params; + this._xmlClient.config.update({ + accessKeyId: accessKey, + secretAccessKey: secretKey, + sessionToken, + }); - // TODO: use this.client.config.update instead of creating a new instance of S3. - this.auth(this.endpoint, params); - // updating credentials not working for AWS.S3.upload() call returning - // "Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1" - // but seems to work for all the other S3 calls. - // this.client.config.update({ - // accessKeyId: accessKey, secretAccessKey: secretKey, sessionToken }); - } + // TODO: use this.client.config.update instead of creating a new instance of S3. + this.auth(this.endpoint, params); + // updating credentials not working for AWS.S3.upload() call returning + // "Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1" + // but seems to work for all the other S3 calls. + // this.client.config.update({ + // accessKeyId: accessKey, secretAccessKey: secretKey, sessionToken }); + } - searchBucket(params: SearchParams): Promise { - const { Bucket, Query, Marker } = params; - return this._xmlClient.searchBucket({ - Bucket, - Query, - Marker, - }).promise(); - } + searchBucket(params: SearchParams): Promise { + const { Bucket, Query, Marker } = params; + return this._xmlClient + .searchBucket({ + Bucket, + Query, + Marker, + }) + .promise(); + } } export default ZenkoClient; diff --git a/src/js/config.js b/src/js/config.js index 91dc73057..d5423ea76 100644 --- a/src/js/config.js +++ b/src/js/config.js @@ -1,20 +1,35 @@ export function getAppConfig() { - return fetch('/config.json', { credentials: 'same-origin' }) - .then(response => { - return response.json(); - }) - .then(config => { - const { managementEndpoint, navbarConfigUrl, navbarEndpoint, stsEndpoint, zenkoEndpoint, iamEndpoint } = config; - if (!navbarEndpoint || !managementEndpoint || !stsEndpoint || !zenkoEndpoint || !iamEndpoint) { - throw new Error('incorrect or missing mandatory configuration information(s). (i.e. managementEndpoint, navbarEndpoint, stsEndpoint, iamEndpoint and zenkoEndpoint)'); - } - return { - managementEndpoint, - navbarConfigUrl, - navbarEndpoint, - stsEndpoint, - zenkoEndpoint, - iamEndpoint, - }; - }); + return fetch('/config.json', { credentials: 'same-origin' }) + .then(response => { + return response.json(); + }) + .then(config => { + const { + managementEndpoint, + navbarConfigUrl, + navbarEndpoint, + stsEndpoint, + zenkoEndpoint, + iamEndpoint, + } = config; + if ( + !navbarEndpoint || + !managementEndpoint || + !stsEndpoint || + !zenkoEndpoint || + !iamEndpoint + ) { + throw new Error( + 'incorrect or missing mandatory configuration information(s). (i.e. managementEndpoint, navbarEndpoint, stsEndpoint, iamEndpoint and zenkoEndpoint)', + ); + } + return { + managementEndpoint, + navbarConfigUrl, + navbarEndpoint, + stsEndpoint, + zenkoEndpoint, + iamEndpoint, + }; + }); } diff --git a/src/js/managementClient.js b/src/js/managementClient.js index bab50ecde..612bcfda1 100644 --- a/src/js/managementClient.js +++ b/src/js/managementClient.js @@ -1,18 +1,20 @@ import Swagger from 'swagger-client'; -function makeMgtClient(endpoint, token){ - return Swagger(endpoint + '/swagger.json', - { authorizations: { 'public-api': token } } - ) - .then(client => { - client.spec.schemes = [endpoint.split(':')[0]]; - const managementClient = client.apis['ui-facing']; - return managementClient; - }) - .catch(error => { - throw new Error( - `Unable to fetch OpenAPI descriptor: ${error.message || '(unknown reason)'}`); - }); +function makeMgtClient(endpoint, token) { + return Swagger(endpoint + '/swagger.json', { + authorizations: { 'public-api': token }, + }) + .then(client => { + client.spec.schemes = [endpoint.split(':')[0]]; + const managementClient = client.apis['ui-facing']; + return managementClient; + }) + .catch(error => { + throw new Error( + `Unable to fetch OpenAPI descriptor: ${error.message || + '(unknown reason)'}`, + ); + }); } export default makeMgtClient; diff --git a/src/js/mock/IAMClient.js b/src/js/mock/IAMClient.js index e7531ec2a..45f0c11cf 100644 --- a/src/js/mock/IAMClient.js +++ b/src/js/mock/IAMClient.js @@ -3,40 +3,40 @@ import type { IamAccessKey, ListAccessKeysResponse } from '../../types/user'; import type { AWSError } from '../../types/aws'; export const accountAccessKeys: Array = [ - { - AccessKeyId: 'LEAST_RECENT_KEY_BBB', - Status: 'Active', - CreateDate: '2020-04-19T16:15:29+00:00', - }, - { - AccessKeyId: 'MOST_RECENT_KEY_AAAA', - Status: 'Active', - CreateDate: '2021-04-19T16:15:26+00:00', - }, + { + AccessKeyId: 'LEAST_RECENT_KEY_BBB', + Status: 'Active', + CreateDate: '2020-04-19T16:15:29+00:00', + }, + { + AccessKeyId: 'MOST_RECENT_KEY_AAAA', + Status: 'Active', + CreateDate: '2021-04-19T16:15:26+00:00', + }, ]; export class MockIAMClient { - listOwnAccessKeys(): Promise { - return Promise.resolve({ - AccessKeyMetadata: accountAccessKeys, - }); - } - deleteAccessKey(): Promise { - return Promise.resolve(); - } + listOwnAccessKeys(): Promise { + return Promise.resolve({ + AccessKeyMetadata: accountAccessKeys, + }); + } + deleteAccessKey(): Promise { + return Promise.resolve(); + } } export class ErrorMockIAMClient { - _error: AWSError; + _error: AWSError; - constructor(error: AWSError) { - this._error = error; - } + constructor(error: AWSError) { + this._error = error; + } - listOwnAccessKeys(): Promise { - return Promise.reject(this._error); - } - deleteAccessKey(): Promise { - return Promise.reject(this._error); - } + listOwnAccessKeys(): Promise { + return Promise.reject(this._error); + } + deleteAccessKey(): Promise { + return Promise.reject(this._error); + } } diff --git a/src/js/mock/S3Client.js b/src/js/mock/S3Client.js index bfa96722f..117c34665 100644 --- a/src/js/mock/S3Client.js +++ b/src/js/mock/S3Client.js @@ -1,14 +1,14 @@ // @flow import type { - BucketInfo, - CreateBucketResponse, - GetObjectTaggingResponse, - GetSignedUrlResponse, - HeadObjectResponse, - ListObjectsResponse, - PutObjectTaggingResponse, - S3Client as S3ClientInterface, + BucketInfo, + CreateBucketResponse, + GetObjectTaggingResponse, + GetSignedUrlResponse, + HeadObjectResponse, + ListObjectsResponse, + PutObjectTaggingResponse, + S3Client as S3ClientInterface, } from '../../types/s3'; import type { AWSError } from '../../types/aws'; import { addTrailingSlash } from '../../react/utils'; @@ -21,220 +21,225 @@ export const prefix = 'toto/'; export const objectKey = 'toto/foo.jpg'; export const objectKey2 = 'test/tags.jpg'; export const commonPrefix = { - Prefix: prefix, + Prefix: prefix, }; export const nextContinuationToken = 'next'; export const s3Object = { - Key: addTrailingSlash(folderName), - LastModified: 'Wed Oct 07 2020 16:35:57', - Size: 0, - SignedUrl: '', + Key: addTrailingSlash(folderName), + LastModified: 'Wed Oct 07 2020 16:35:57', + Size: 0, + SignedUrl: '', }; export const objectMetadata = { - bucketName: bucketName, - contentLength: 4529171, - contentType: 'image/jpeg', - eTag: 'af4a08eac69ced858c99caee22978773', - lastModified: 'Fri Oct 16 2020 10:06:54', - metadata: [], - objectKey: 'bg.jpg', - objectName: 'bg.jpg', - prefixWithSlash: '', - versionId: '', - tags: [], + bucketName: bucketName, + contentLength: 4529171, + contentType: 'image/jpeg', + eTag: 'af4a08eac69ced858c99caee22978773', + lastModified: 'Fri Oct 16 2020 10:06:54', + metadata: [], + objectKey: 'bg.jpg', + objectName: 'bg.jpg', + prefixWithSlash: '', + versionId: '', + tags: [], }; -export const tags = [ - { Key: 'key1', Value: 'value1' }, -]; +export const tags = [{ Key: 'key1', Value: 'value1' }]; export const createBucketResponse: CreateBucketResponse = { - Location: '', + Location: '', }; export const file = { - path: '', - size: 0, + path: '', + size: 0, }; export const getSignedUrlResponse: GetSignedUrlResponse = ''; -export const listObjectsResponse = (prefixWithSlash: string): ListObjectsResponse => ({ - CommonPrefixes: [commonPrefix], - Contents: [s3Object], - ContinuationToken: '', - Delimiter: '', - EncodingType: '', - IsTruncated: false, - KeyCount: 0, - MaxKeys: 0, - Name: '', - NextContinuationToken: nextContinuationToken, - Prefix: prefixWithSlash, - StartAfter: '', +export const listObjectsResponse = ( + prefixWithSlash: string, +): ListObjectsResponse => ({ + CommonPrefixes: [commonPrefix], + Contents: [s3Object], + ContinuationToken: '', + Delimiter: '', + EncodingType: '', + IsTruncated: false, + KeyCount: 0, + MaxKeys: 0, + Name: '', + NextContinuationToken: nextContinuationToken, + Prefix: prefixWithSlash, + StartAfter: '', }); export const userMetadata = { - 'color': 'green', + color: 'green', }; export const systemMetadata = { - ContentType: 'application/octet-stream; charset=UTF-8', + ContentType: 'application/octet-stream; charset=UTF-8', }; export const info = { - LastModified: 'Wed Oct 14 2020 15:58:52', - ContentLength: 1400, - ContentType: 'image/jpeg', - ETag: '123456789', - VersionId: '1', - Metadata: userMetadata, + LastModified: 'Wed Oct 14 2020 15:58:52', + ContentLength: 1400, + ContentType: 'image/jpeg', + ETag: '123456789', + VersionId: '1', + Metadata: userMetadata, }; export const putObjectTaggingResponse: PutObjectTaggingResponse = { - VersionId: '1', + VersionId: '1', }; export const bucketInfoResponse: BucketInfo = { - name: bucketName, - policy: false, - owner: ownerName, - aclGrantees: 0, - cors: false, - versioning: 'Suspended', - isVersioning: false, - public: false, - locationConstraint: '', + name: bucketName, + policy: false, + owner: ownerName, + aclGrantees: 0, + cors: false, + versioning: 'Suspended', + isVersioning: false, + public: false, + locationConstraint: '', }; export class MockS3Client implements S3ClientInterface { - listBucketsWithLocation() { - return Promise.resolve({ - Buckets: [], - Owner: { - DisplayName: ownerName, - ID: 'id1', - }, - }); - } - - createBucket(): Promise { - return Promise.resolve(createBucketResponse); - } - - deleteBucket(): Promise { - return Promise.resolve(); - } - - createFolder(): Promise { - return Promise.resolve(); - } - - listObjects({ Prefix }: { Prefix: string }): Promise { - return Promise.resolve(listObjectsResponse(Prefix)); - } - - getObjectSignedUrl(): Promise { - return Promise.resolve(getSignedUrlResponse); - } - - uploadObject(): Promise { - return Promise.resolve(); - } - - deleteObjects(): Promise { - return Promise.resolve(); - } - - headObject(): Promise { - return Promise.resolve(info); - } - - getObjectTagging(bucketName: string, objectKey: string): Promise { - return Promise.resolve({ TagSet: bucketName === 'bucket' && objectKey === objectKey2 ? tags : [] }); - } - - putObjectMetadata(): Promise { - return Promise.resolve(); - } - - putObjectTagging(): Promise { - return Promise.resolve(putObjectTaggingResponse); - } - - getBucketInfo(): Promise { - return Promise.resolve(bucketInfoResponse); - } - - toggleVersioning(): Promise { - return Promise.resolve(); - } + listBucketsWithLocation() { + return Promise.resolve({ + Buckets: [], + Owner: { + DisplayName: ownerName, + ID: 'id1', + }, + }); + } + + createBucket(): Promise { + return Promise.resolve(createBucketResponse); + } + + deleteBucket(): Promise { + return Promise.resolve(); + } + + createFolder(): Promise { + return Promise.resolve(); + } + + listObjects({ Prefix }: { Prefix: string }): Promise { + return Promise.resolve(listObjectsResponse(Prefix)); + } + + getObjectSignedUrl(): Promise { + return Promise.resolve(getSignedUrlResponse); + } + + uploadObject(): Promise { + return Promise.resolve(); + } + + deleteObjects(): Promise { + return Promise.resolve(); + } + + headObject(): Promise { + return Promise.resolve(info); + } + + getObjectTagging( + bucketName: string, + objectKey: string, + ): Promise { + return Promise.resolve({ + TagSet: bucketName === 'bucket' && objectKey === objectKey2 ? tags : [], + }); + } + + putObjectMetadata(): Promise { + return Promise.resolve(); + } + + putObjectTagging(): Promise { + return Promise.resolve(putObjectTaggingResponse); + } + + getBucketInfo(): Promise { + return Promise.resolve(bucketInfoResponse); + } + + toggleVersioning(): Promise { + return Promise.resolve(); + } } export class ErrorMockS3Client implements S3ClientInterface { - _error: AWSError; + _error: AWSError; - constructor(error: AWSError) { - this._error = error; - } + constructor(error: AWSError) { + this._error = error; + } - createBucket(): Promise { - return Promise.reject(this._error); - } + createBucket(): Promise { + return Promise.reject(this._error); + } - listBucketsWithLocation(): Promise { - return Promise.reject(this._error); - } + listBucketsWithLocation(): Promise { + return Promise.reject(this._error); + } - deleteBucket(): Promise { - return Promise.reject(this._error); - } + deleteBucket(): Promise { + return Promise.reject(this._error); + } - createFolder(): Promise { - return Promise.reject(this._error); - } + createFolder(): Promise { + return Promise.reject(this._error); + } - listObjects(): Promise { - return Promise.reject(this._error); - } + listObjects(): Promise { + return Promise.reject(this._error); + } - getObjectSignedUrl(): Promise { - return Promise.reject(this._error); - } + getObjectSignedUrl(): Promise { + return Promise.reject(this._error); + } - uploadObject(): Promise { - return Promise.reject(this._error); - } + uploadObject(): Promise { + return Promise.reject(this._error); + } - deleteObjects(): Promise { - return Promise.reject(this._error); - } + deleteObjects(): Promise { + return Promise.reject(this._error); + } - headObject(): Promise { - return Promise.reject(this._error); - } + headObject(): Promise { + return Promise.reject(this._error); + } - getObjectTagging(): Promise { - return Promise.reject(this._error); - } + getObjectTagging(): Promise { + return Promise.reject(this._error); + } - putObjectMetadata(): Promise { - return Promise.reject(this._error); - } + putObjectMetadata(): Promise { + return Promise.reject(this._error); + } - putObjectTagging(): Promise { - return Promise.reject(this._error); - } + putObjectTagging(): Promise { + return Promise.reject(this._error); + } - bucketInfo(): Promise { - return Promise.reject(this._error); - } + bucketInfo(): Promise { + return Promise.reject(this._error); + } - getBucketInfo(): Promise { - return Promise.reject(this._error); - } + getBucketInfo(): Promise { + return Promise.reject(this._error); + } - toggleVersioning(): Promise { - return Promise.reject(this._error); - } + toggleVersioning(): Promise { + return Promise.reject(this._error); + } } diff --git a/src/js/mock/STSClient.js b/src/js/mock/STSClient.js index 0bc04a4fc..d1cabae58 100644 --- a/src/js/mock/STSClient.js +++ b/src/js/mock/STSClient.js @@ -1,17 +1,15 @@ // @flow -import type { - STSClient as STSClientInterface, -} from '../../types/sts'; +import type { STSClient as STSClientInterface } from '../../types/sts'; export class MockSTSClient implements STSClientInterface { - assumeRoleWithWebIdentity() { - return Promise.resolve({ - Credentials: { - AccessKeyId: 'accessKey1', - SecretAccessKey: 'verySecretKey1', - SessionToken: 'sessionKey1', - }, - }); - } + assumeRoleWithWebIdentity() { + return Promise.resolve({ + Credentials: { + AccessKeyId: 'accessKey1', + SecretAccessKey: 'verySecretKey1', + SessionToken: 'sessionKey1', + }, + }); + } } diff --git a/src/js/mock/ZenkoClient.js b/src/js/mock/ZenkoClient.js index ae27d9ab1..be9cc8d6a 100644 --- a/src/js/mock/ZenkoClient.js +++ b/src/js/mock/ZenkoClient.js @@ -1,30 +1,32 @@ // @noflow import { ErrorMockS3Client, MockS3Client } from './S3Client'; import type { - SearchBucketResp, - ZenkoClient as ZenkoClientInterface, + SearchBucketResp, + ZenkoClient as ZenkoClientInterface, } from '../../types/zenko'; import { AWSError } from '../../types/aws'; -export class MockZenkoClient extends MockS3Client implements ZenkoClientInterface { - _init(): void {} - logout(): void {} - login(): void {} +export class MockZenkoClient extends MockS3Client + implements ZenkoClientInterface { + _init(): void {} + logout(): void {} + login(): void {} - searchBucket(): Promise { - return Promise.resolve({ IsTruncated: false, Contents: [] }); - } + searchBucket(): Promise { + return Promise.resolve({ IsTruncated: false, Contents: [] }); + } } -export class ErrorMockZenkoClient extends ErrorMockS3Client implements ZenkoClientInterface { - _error: AWSError; +export class ErrorMockZenkoClient extends ErrorMockS3Client + implements ZenkoClientInterface { + _error: AWSError; - constructor(error: AWSError) { - super(error); - this._error = error; - } + constructor(error: AWSError) { + super(error); + this._error = error; + } - searchBucket(): Promise { - return Promise.reject(this._error); - } + searchBucket(): Promise { + return Promise.reject(this._error); + } } diff --git a/src/js/mock/error.js b/src/js/mock/error.js index 0486833e5..77e3513a2 100644 --- a/src/js/mock/error.js +++ b/src/js/mock/error.js @@ -2,25 +2,25 @@ import type { AWSError } from '../../types/aws'; export class ApiErrorObject extends Error { - code: number | string; - status: number | string; - message: string; - response: Object; + code: number | string; + status: number | string; + message: string; + response: Object; - constructor(message: string, status: string | number) { - super(message); - this.response = { - body: { - message, - }, - }; - this.status = status === undefined ? 500 : status; - } + constructor(message: string, status: string | number) { + super(message); + this.response = { + body: { + message, + }, + }; + this.status = status === undefined ? 500 : status; + } } export function awsErrorObject(message: string, code: string): AWSError { - return { - code, - message, - }; + return { + code, + message, + }; } diff --git a/src/js/mock/managementClient.js b/src/js/mock/managementClient.js index b3dd7ba8f..b047a16a4 100644 --- a/src/js/mock/managementClient.js +++ b/src/js/mock/managementClient.js @@ -2,265 +2,271 @@ import type { AccessKey, Account, SecretKey } from '../../types/account'; import type { - ApiAccountKeyResponse, - ApiAccountResponse, - ApiConfigurationResponse, - ManagementClient as ManagementClientInterface, + ApiAccountKeyResponse, + ApiAccountResponse, + ApiConfigurationResponse, + ManagementClient as ManagementClientInterface, } from '../../types/managementClient'; -import type { ConfigurationOverlay, Endpoint, Location, Replication } from '../../types/config'; +import type { + ConfigurationOverlay, + Endpoint, + Location, + Replication, +} from '../../types/config'; import type { APIWorkflows } from '../../types/workflow'; import { ApiErrorObject } from './error'; import type { InstanceStatus } from '../../types/stats'; import { toLocationType } from '../../types/config'; export const location: Location = { - name: 'location1', - locationType: toLocationType('location-file-v1'), - details: {}, - objectId: 'object-id', - isBuiltin: false, - isTransient: false, - sizeLimitGB: 10, + name: 'location1', + locationType: toLocationType('location-file-v1'), + details: {}, + objectId: 'object-id', + isBuiltin: false, + isTransient: false, + sizeLimitGB: 10, }; export const account: Account = { - arn: 'arn:aws:iam::538641674554:/bart/', - canonicalId: '41901f00de359c995578b3f7af6a9ab57ccca15f1a03ed97e29ba7fdf9a09c33', - createDate: Date.parse('04 Jan 2000 05:12:00 GMT'), - email: 'my@email.com', - id: '538641674554', - quotaMax: 12, - userName: 'bart', + arn: 'arn:aws:iam::538641674554:/bart/', + canonicalId: + '41901f00de359c995578b3f7af6a9ab57ccca15f1a03ed97e29ba7fdf9a09c33', + createDate: Date.parse('04 Jan 2000 05:12:00 GMT'), + email: 'my@email.com', + id: '538641674554', + quotaMax: 12, + userName: 'bart', }; export const latestOverlay: ConfigurationOverlay = { - version: 2, - users: [ account ], - locations: { 'location1': location }, - endpoints: [], + version: 2, + users: [account], + locations: { location1: location }, + endpoints: [], }; export const replicationWorkflow: Replication = { - streamId: '123e4567-e89b-12d3-a456-426614174001', - name: 'replication', - version: 1, - enabled: true, - source: { - prefix: 'myprefix', - bucketName: 'mybucket', - }, - destination: { - locations: [{ name: 'location-name' }], - preferredReadLocation: 'location-name', - }, + streamId: '123e4567-e89b-12d3-a456-426614174001', + name: 'replication', + version: 1, + enabled: true, + source: { + prefix: 'myprefix', + bucketName: 'mybucket', + }, + destination: { + locations: [{ name: 'location-name' }], + preferredReadLocation: 'location-name', + }, }; export const workflows: APIWorkflows = [ - { - 'replication': replicationWorkflow, - }, + { + replication: replicationWorkflow, + }, ]; export const accountAccessKey: AccessKey = 'ak1'; export const accountSecretKey: SecretKey = 'sk1'; export const accountName = 'bart'; export const key = { - accessKey: accountAccessKey, - createDate: '2021-04-28T11:19:34.000Z', - id: '538641674554', - secretKey: accountSecretKey, - userName: accountName, + accessKey: accountAccessKey, + createDate: '2021-04-28T11:19:34.000Z', + id: '538641674554', + secretKey: accountSecretKey, + userName: accountName, }; export const instanceStatus: InstanceStatus = { - metrics: {}, - state: { - runningConfigurationVersion: 0, - capabilities: { - secureChannel: true, - }, - latestConfigurationOverlay: latestOverlay, - lastSeen: new Date().toString(), - serverVersion: 'version', + metrics: {}, + state: { + runningConfigurationVersion: 0, + capabilities: { + secureChannel: true, }, + latestConfigurationOverlay: latestOverlay, + lastSeen: new Date().toString(), + serverVersion: 'version', + }, }; export const endpoint: Endpoint = { - hostname: 's3.example.com', - locationName: 'us-east-1', - isBuiltin: false, + hostname: 's3.example.com', + locationName: 'us-east-1', + isBuiltin: false, }; export class MockManagementClient implements ManagementClientInterface { - createConfigurationOverlayUser(): Promise { - return Promise.resolve({ - body: account, - }); - } - - deleteConfigurationOverlayUser(): Promise { - return Promise.resolve(); - } - - createConfigurationOverlayLocation(): Promise { - return Promise.resolve(location); - } - - updateConfigurationOverlayLocation(): Promise { - return Promise.resolve(location); - } - - deleteConfigurationOverlayLocation(): Promise { - return Promise.resolve(); - } - - getConfigurationOverlayView(): Promise { - return Promise.resolve({ - body: latestOverlay, - }); - } - - searchWorkflows(): Promise<{ body: APIWorkflows }> { - return Promise.resolve({ - body: workflows, - }); - } - - deleteBucketWorkflowReplication(): Promise { - return Promise.resolve(); - } - - updateBucketWorkflowReplication(): Promise<{ body: Replication }> { - return Promise.resolve({ - body: replicationWorkflow, - }); - } - - saveBucketWorkflowReplication(): Promise<{ body: Replication }> { - return Promise.resolve({ - body: replicationWorkflow, - }); - } - - generateKeyConfigurationOverlayUser(): Promise { - return Promise.resolve({ - body: key, - }); - } - - getLatestInstanceStatus(): Promise<{ body: InstanceStatus }> { - return Promise.resolve({ - body: instanceStatus, - }); - } - - createConfigurationOverlayEndpoint(): Promise<{ body: Endpoint }> { - return Promise.resolve({ - body: endpoint, - }); - } - - deleteConfigurationOverlayEndpoint(): Promise { - return Promise.resolve(); - } + createConfigurationOverlayUser(): Promise { + return Promise.resolve({ + body: account, + }); + } + + deleteConfigurationOverlayUser(): Promise { + return Promise.resolve(); + } + + createConfigurationOverlayLocation(): Promise { + return Promise.resolve(location); + } + + updateConfigurationOverlayLocation(): Promise { + return Promise.resolve(location); + } + + deleteConfigurationOverlayLocation(): Promise { + return Promise.resolve(); + } + + getConfigurationOverlayView(): Promise { + return Promise.resolve({ + body: latestOverlay, + }); + } + + searchWorkflows(): Promise<{ body: APIWorkflows }> { + return Promise.resolve({ + body: workflows, + }); + } + + deleteBucketWorkflowReplication(): Promise { + return Promise.resolve(); + } + + updateBucketWorkflowReplication(): Promise<{ body: Replication }> { + return Promise.resolve({ + body: replicationWorkflow, + }); + } + + saveBucketWorkflowReplication(): Promise<{ body: Replication }> { + return Promise.resolve({ + body: replicationWorkflow, + }); + } + + generateKeyConfigurationOverlayUser(): Promise { + return Promise.resolve({ + body: key, + }); + } + + getLatestInstanceStatus(): Promise<{ body: InstanceStatus }> { + return Promise.resolve({ + body: instanceStatus, + }); + } + + createConfigurationOverlayEndpoint(): Promise<{ body: Endpoint }> { + return Promise.resolve({ + body: endpoint, + }); + } + + deleteConfigurationOverlayEndpoint(): Promise { + return Promise.resolve(); + } } export class ErrorMockManagementClient implements ManagementClientInterface { - _error: ApiErrorObject; + _error: ApiErrorObject; - constructor(error: ApiErrorObject) { - this._error = error; - } + constructor(error: ApiErrorObject) { + this._error = error; + } - createConfigurationOverlayUser(): Promise { - return Promise.reject(this._error); - } + createConfigurationOverlayUser(): Promise { + return Promise.reject(this._error); + } - deleteConfigurationOverlayUser(): Promise { - return Promise.reject(this._error); - } + deleteConfigurationOverlayUser(): Promise { + return Promise.reject(this._error); + } - createConfigurationOverlayLocation(): Promise { - return Promise.reject(this._error); - } + createConfigurationOverlayLocation(): Promise { + return Promise.reject(this._error); + } - updateConfigurationOverlayLocation(): Promise { - return Promise.reject(this._error); - } + updateConfigurationOverlayLocation(): Promise { + return Promise.reject(this._error); + } - deleteConfigurationOverlayLocation(): Promise { - return Promise.reject(this._error); - } + deleteConfigurationOverlayLocation(): Promise { + return Promise.reject(this._error); + } - getConfigurationOverlayView(): Promise { - return Promise.reject(this._error); - } + getConfigurationOverlayView(): Promise { + return Promise.reject(this._error); + } - searchWorkflows(): Promise { - return Promise.reject(this._error); - } + searchWorkflows(): Promise { + return Promise.reject(this._error); + } - deleteBucketWorkflowReplication(): Promise { - return Promise.reject(this._error); - } + deleteBucketWorkflowReplication(): Promise { + return Promise.reject(this._error); + } - updateBucketWorkflowReplication(): Promise { - return Promise.reject(this._error); - } + updateBucketWorkflowReplication(): Promise { + return Promise.reject(this._error); + } - saveBucketWorkflowReplication(): Promise { - return Promise.reject(this._error); - } + saveBucketWorkflowReplication(): Promise { + return Promise.reject(this._error); + } - generateKeyConfigurationOverlayUser(): Promise { - return Promise.reject(this._error); - } + generateKeyConfigurationOverlayUser(): Promise { + return Promise.reject(this._error); + } - createConfigurationOverlayEndpoint(): Promise { - return Promise.reject(this._error); - } + createConfigurationOverlayEndpoint(): Promise { + return Promise.reject(this._error); + } - deleteConfigurationOverlayEndpoint(): Promise { - return Promise.reject(this._error); - } + deleteConfigurationOverlayEndpoint(): Promise { + return Promise.reject(this._error); + } } export class MockManagementClientWithConfigurationVersions extends MockManagementClient { - getStatusCallCounter: number - runningVersions: Array - getOverlayCounter: number - overlayVersions: Array - - constructor(runningVersions: Array, overlayVersions: Array) { - super(); - - this.getStatusCallCounter = 0; - this.runningVersions = runningVersions; - - this.getOverlayCounter = 0; - this.overlayVersions = overlayVersions; - } - - getLatestInstanceStatus(): Promise { - return super.getLatestInstanceStatus() - .then(({ body }) => ({ - body: { - ...body, - state: { - ...body.state, - runningConfigurationVersion: this.runningVersions[this.getStatusCallCounter++], - }, - }, - })); - } - - getConfigurationOverlayView(): Promise { - return super.getConfigurationOverlayView() - .then(({ body }) => ({ - body: { - ...body, - version: this.overlayVersions[this.getOverlayCounter++], - }, - })); - } + getStatusCallCounter: number; + runningVersions: Array; + getOverlayCounter: number; + overlayVersions: Array; + + constructor(runningVersions: Array, overlayVersions: Array) { + super(); + + this.getStatusCallCounter = 0; + this.runningVersions = runningVersions; + + this.getOverlayCounter = 0; + this.overlayVersions = overlayVersions; + } + + getLatestInstanceStatus(): Promise { + return super.getLatestInstanceStatus().then(({ body }) => ({ + body: { + ...body, + state: { + ...body.state, + runningConfigurationVersion: this.runningVersions[ + this.getStatusCallCounter++ + ], + }, + }, + })); + } + + getConfigurationOverlayView(): Promise { + return super.getConfigurationOverlayView().then(({ body }) => ({ + body: { + ...body, + version: this.overlayVersions[this.getOverlayCounter++], + }, + })); + } } diff --git a/src/js/utils.js b/src/js/utils.js index 1bb4f28f7..0eb52a343 100644 --- a/src/js/utils.js +++ b/src/js/utils.js @@ -1,11 +1,14 @@ // @flow -export function chunkArray(myArray: Array, chunk_size: number): Array { - const tempArray = []; +export function chunkArray( + myArray: Array, + chunk_size: number, +): Array { + const tempArray = []; - for (let index = 0; index < myArray.length; index += chunk_size) { - const myChunk = myArray.slice(index, index+chunk_size); - tempArray.push(myChunk); - } + for (let index = 0; index < myArray.length; index += chunk_size) { + const myChunk = myArray.slice(index, index + chunk_size); + tempArray.push(myChunk); + } - return tempArray; + return tempArray; } diff --git a/src/react/App.js b/src/react/App.js index 9ff8451c7..43bab7521 100644 --- a/src/react/App.js +++ b/src/react/App.js @@ -16,9 +16,10 @@ import ZenkoUI from './ZenkoUI'; // }); ReactDOM.render( - - - - - , - document.getElementById('app')); + + + + + , + document.getElementById('app'), +); diff --git a/src/react/Navbar.js b/src/react/Navbar.js index 4bf161122..7bd60b9be 100644 --- a/src/react/Navbar.js +++ b/src/react/Navbar.js @@ -7,136 +7,139 @@ import { ErrorBoundary } from 'react-error-boundary'; import type { OidcLogoutFunction } from '../types/auth'; function useWebComponent(src?: string, customElementName: string) { - const [hasFailed, setHasFailed] = useState(false); - useLayoutEffect(() => { - const body = document.body; - const element = [...(body?.querySelectorAll('script') || [])].find( - // eslint-disable-next-line flowtype-errors/show-errors - (scriptElement) => scriptElement.attributes.src?.value === src, - ); - if (!element && body && src) { - const scriptElement = document.createElement('script'); - scriptElement.src = src; - scriptElement.onload = () => { - customElements.whenDefined(customElementName).catch(() => { - setHasFailed(true); - }); - }; - scriptElement.onerror = () => { - setHasFailed(true); - }; - body.appendChild(scriptElement); - } - }, [src, customElementName]); - - if (hasFailed) { - throw new Error(`Failed to load component ${customElementName}`); + const [hasFailed, setHasFailed] = useState(false); + useLayoutEffect(() => { + const body = document.body; + const element = [...(body?.querySelectorAll('script') || [])].find( + // eslint-disable-next-line flowtype-errors/show-errors + scriptElement => scriptElement.attributes.src?.value === src, + ); + if (!element && body && src) { + const scriptElement = document.createElement('script'); + scriptElement.src = src; + scriptElement.onload = () => { + customElements.whenDefined(customElementName).catch(() => { + setHasFailed(true); + }); + }; + scriptElement.onerror = () => { + setHasFailed(true); + }; + body.appendChild(scriptElement); } + }, [src, customElementName]); + + if (hasFailed) { + throw new Error(`Failed to load component ${customElementName}`); + } } type NavbarWebComponent = HTMLElement & { logOut: OidcLogoutFunction }; function useLoginEffect(navbarRef: { current: NavbarWebComponent | null }) { - const dispatch = useDispatch(); - - useEffect(() => { - if (!navbarRef.current) { - return; - } - - const navbarElement = navbarRef.current; - - const onAuthenticated = (evt: Event) => { - // eslint-disable-next-line flowtype-errors/show-errors - if (evt.detail && evt.detail.profile) { - dispatch(addOIDCUser(evt.detail)); - dispatch(setOIDCLogout(navbarElement.logOut || null)); - } - }; - - navbarElement.addEventListener( - 'solutions-navbar--authenticated', - onAuthenticated, - ); - - return () => { - navbarElement.removeEventListener( - 'solutions-navbar--authenticated', - onAuthenticated, - ); - - }; - }, [navbarRef, dispatch]); + const dispatch = useDispatch(); + + useEffect(() => { + if (!navbarRef.current) { + return; + } + + const navbarElement = navbarRef.current; + + const onAuthenticated = (evt: Event) => { + // eslint-disable-next-line flowtype-errors/show-errors + if (evt.detail && evt.detail.profile) { + dispatch(addOIDCUser(evt.detail)); + dispatch(setOIDCLogout(navbarElement.logOut || null)); + } + }; + + navbarElement.addEventListener( + 'solutions-navbar--authenticated', + onAuthenticated, + ); + + return () => { + navbarElement.removeEventListener( + 'solutions-navbar--authenticated', + onAuthenticated, + ); + }; + }, [navbarRef, dispatch]); } function useThemeEffect(navbarRef: { current: NavbarWebComponent | null }) { - const dispatch = useDispatch(); - - useEffect(() => { - if (!navbarRef.current) { - return; - } - - const navbarElement = navbarRef.current; - - const onThemeChanged = (evt: Event) => { - // flow is not accepting CustomEvent type for listener arguments of {add,remove}EventListener https://github.com/facebook/flow/issues/7179 - // eslint-disable-next-line flowtype-errors/show-errors - if (evt.detail) { - dispatch(setTheme(evt.detail)); - } - }; - - navbarElement.addEventListener( - 'solutions-navbar--theme-changed', - onThemeChanged, - ); - - return () => { - navbarElement.removeEventListener( - 'solutions-navbar--theme-changed', - onThemeChanged, - ); - }; - }, [navbarRef, dispatch]); + const dispatch = useDispatch(); + + useEffect(() => { + if (!navbarRef.current) { + return; + } + + const navbarElement = navbarRef.current; + + const onThemeChanged = (evt: Event) => { + // flow is not accepting CustomEvent type for listener arguments of {add,remove}EventListener https://github.com/facebook/flow/issues/7179 + // eslint-disable-next-line flowtype-errors/show-errors + if (evt.detail) { + dispatch(setTheme(evt.detail)); + } + }; + + navbarElement.addEventListener( + 'solutions-navbar--theme-changed', + onThemeChanged, + ); + + return () => { + navbarElement.removeEventListener( + 'solutions-navbar--theme-changed', + onThemeChanged, + ); + }; + }, [navbarRef, dispatch]); } function ErrorFallback({ error }: { error: Error }) { - return ( -
-

Something went wrong:

-
{error.message}
-
- ); + return ( +
+

Something went wrong:

+
{error.message}
+
+ ); } export function Navbar() { - return ( - - - - ); + return ( + + + + ); } function InternalNavbar() { - const navbarEndpoint = useSelector((state: AppState) => state.auth.config.navbarEndpoint); - const navbarConfigUrl = useSelector((state: AppState) => state.auth.config.navbarConfigUrl); - useWebComponent(navbarEndpoint, 'solutions-navbar'); - - const navbarRef = useRef(null); - - useLoginEffect(navbarRef); - useThemeEffect(navbarRef); - - return ( - - ); + const navbarEndpoint = useSelector( + (state: AppState) => state.auth.config.navbarEndpoint, + ); + const navbarConfigUrl = useSelector( + (state: AppState) => state.auth.config.navbarConfigUrl, + ); + useWebComponent(navbarEndpoint, 'solutions-navbar'); + + const navbarRef = useRef(null); + + useLoginEffect(navbarRef); + useThemeEffect(navbarRef); + + return ( + + ); } diff --git a/src/react/NoMatch.jsx b/src/react/NoMatch.jsx index ba4530675..7954dadef 100644 --- a/src/react/NoMatch.jsx +++ b/src/react/NoMatch.jsx @@ -4,10 +4,16 @@ import { Warning } from './ui-elements/Warning'; import { useLocation } from 'react-router-dom'; function NoMatch() { - const { pathname } = useLocation(); - const title = `No match for "${pathname}"`; + const { pathname } = useLocation(); + const title = `No match for "${pathname}"`; - return ; + return ( + + ); } export default NoMatch; diff --git a/src/react/Routes.jsx b/src/react/Routes.jsx index fca5aafff..9d67075a2 100644 --- a/src/react/Routes.jsx +++ b/src/react/Routes.jsx @@ -2,7 +2,11 @@ import { NavbarContainer, RouteContainer } from './ui-elements/Container'; import React, { useEffect } from 'react'; import { Redirect, Route, Switch } from 'react-router-dom'; -import { loadClients, loadInstanceLatestStatus, loadInstanceStats } from './actions'; +import { + loadClients, + loadInstanceLatestStatus, + loadInstanceStats, +} from './actions'; import { useDispatch, useSelector } from 'react-redux'; import AccountCreate from './account/AccountCreate'; import Accounts from './account/Accounts'; @@ -17,63 +21,79 @@ import NoMatch from './NoMatch'; import Workflows from './workflow/Workflows'; function PrivateRoutes() { - const dispatch = useDispatch(); + const dispatch = useDispatch(); - const isClientsLoaded = useSelector((state: AppState) => state.auth.isClientsLoaded); - const user = useSelector((state: AppState) => state.oidc.user); + const isClientsLoaded = useSelector( + (state: AppState) => state.auth.isClientsLoaded, + ); + const user = useSelector((state: AppState) => state.oidc.user); - useEffect(() => { - const isAuthenticated = !!user && !user.expired; - if (isAuthenticated) { - // TODO: forbid loading clients when authorization server redirects the user back to ui.zenko.local with an authorization code. - // That will fix management API request being canceled during autentication. - dispatch(loadClients()); + useEffect(() => { + const isAuthenticated = !!user && !user.expired; + if (isAuthenticated) { + // TODO: forbid loading clients when authorization server redirects the user back to ui.zenko.local with an authorization code. + // That will fix management API request being canceled during autentication. + dispatch(loadClients()); - const refreshIntervalStatsUnit = setInterval( - () => dispatch(loadInstanceLatestStatus()), 10000); - const refreshIntervalStatsSeries = setInterval( - () => dispatch(loadInstanceStats()), 10000); - return () => { - clearInterval(refreshIntervalStatsUnit); - clearInterval(refreshIntervalStatsSeries); - }; - } - },[dispatch, user]); - - if (!isClientsLoaded) { - return Loading clients ; + const refreshIntervalStatsUnit = setInterval( + () => dispatch(loadInstanceLatestStatus()), + 10000, + ); + const refreshIntervalStatsSeries = setInterval( + () => dispatch(loadInstanceStats()), + 10000, + ); + return () => { + clearInterval(refreshIntervalStatsUnit); + clearInterval(refreshIntervalStatsSeries); + }; } - return ( - - }/> + }, [dispatch, user]); + + if (!isClientsLoaded) { + return Loading clients ; + } + return ( + + } /> - - + + - - + + - + - + - - + + - - - ); + + + ); } function Routes() { - return ( - - - - - - - ); + return ( + + + + + + + ); } export default Routes; diff --git a/src/react/ZenkoUI.js b/src/react/ZenkoUI.js index c16ab3a52..e9d0b06a9 100644 --- a/src/react/ZenkoUI.js +++ b/src/react/ZenkoUI.js @@ -1,5 +1,9 @@ // @flow -import { Container, MainContainer, ZenkoUIContainer } from './ui-elements/Container'; +import { + Container, + MainContainer, + ZenkoUIContainer, +} from './ui-elements/Container'; import React, { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import Activity from './ui-elements/Activity'; @@ -13,53 +17,64 @@ import ScrollbarWrapper from './ui-elements/ScrollbarWrapper'; import { ThemeProvider } from 'styled-components'; import { loadAppConfig } from './actions'; - function ZenkoUI() { - const isConfigLoaded = useSelector((state: AppState) => state.auth.isConfigLoaded); - const configFailure = useSelector((state: AppState) => state.auth.configFailure); - const configFailureErrorMessage = useSelector((state: AppState) => state.uiErrors.errorType === 'byComponent' ? - state.uiErrors.errorMsg : ''); - const theme = useSelector((state: AppState) => state.uiConfig.theme); - - const dispatch = useDispatch(); + const isConfigLoaded = useSelector( + (state: AppState) => state.auth.isConfigLoaded, + ); + const configFailure = useSelector( + (state: AppState) => state.auth.configFailure, + ); + const configFailureErrorMessage = useSelector((state: AppState) => + state.uiErrors.errorType === 'byComponent' ? state.uiErrors.errorMsg : '', + ); + const theme = useSelector((state: AppState) => state.uiConfig.theme); - useEffect(() => { - dispatch(loadAppConfig()); - },[dispatch]); + const dispatch = useDispatch(); - function content() { - if (configFailure) { - return - } - title="Error: Unable to load the appplication" - variant="danger"> - {configFailureErrorMessage} - - ; - } + useEffect(() => { + dispatch(loadAppConfig()); + }, [dispatch]); - if (isConfigLoaded) { - return ( - - - - - - ); - } + function content() { + if (configFailure) { + return ( + + } + title="Error: Unable to load the appplication" + variant="danger" + > + {configFailureErrorMessage} + + + ); + } - return Login in ; + if (isConfigLoaded) { + return ( + + + + + + ); } - return - { /* TODO: replace with core-ui scrollbar when colors are set correctly */ } - - - {content()} - - - ; + return Login in ; + } + + return ( + + + {' '} + {/* TODO: replace with core-ui scrollbar when colors are set correctly */} + + + {content()} + + + + ); } export default ZenkoUI; diff --git a/src/react/account/AccountContent.jsx b/src/react/account/AccountContent.jsx index 1423bc67b..7f409ef78 100644 --- a/src/react/account/AccountContent.jsx +++ b/src/react/account/AccountContent.jsx @@ -7,17 +7,17 @@ import AccountHead from './AccountHead'; import React from 'react'; type Props = { - account: ?Account, + account: ?Account, }; function AccountContent({ account }: Props) { - return ( - - - - - - - ); + return ( + + + + + + + ); } export default AccountContent; diff --git a/src/react/account/AccountCreate.jsx b/src/react/account/AccountCreate.jsx index 31eae59a2..d16b2d294 100644 --- a/src/react/account/AccountCreate.jsx +++ b/src/react/account/AccountCreate.jsx @@ -16,97 +16,140 @@ const regexpEmailAddress = /^\S+@\S+.\S+$/; const regexpName = /^[\w+=,.@ -]+$/; const schema = Joi.object({ - name: Joi.string().label('Name').required().min(2).max(64).regex(regexpName).message('Invalid Name'), - email: Joi.string().label('Root Account Email').required().max(256).regex(regexpEmailAddress).message('Invalid Root Account Email'), + name: Joi.string() + .label('Name') + .required() + .min(2) + .max(64) + .regex(regexpName) + .message('Invalid Name'), + email: Joi.string() + .label('Root Account Email') + .required() + .max(256) + .regex(regexpEmailAddress) + .message('Invalid Root Account Email'), }); function AccountCreate() { - const { register, handleSubmit, errors } = useForm({ - resolver: joiResolver(schema), - }); + const { register, handleSubmit, errors } = useForm({ + resolver: joiResolver(schema), + }); - const hasError = useSelector((state: AppState) => !!state.uiErrors.errorMsg && state.uiErrors.errorType === 'byComponent'); - const errorMessage = useSelector((state: AppState) => state.uiErrors.errorMsg); - const loading = useSelector((state: AppState) => state.networkActivity.counter > 0); + const hasError = useSelector( + (state: AppState) => + !!state.uiErrors.errorMsg && state.uiErrors.errorType === 'byComponent', + ); + const errorMessage = useSelector( + (state: AppState) => state.uiErrors.errorMsg, + ); + const loading = useSelector( + (state: AppState) => state.networkActivity.counter > 0, + ); - const dispatch = useDispatch(); + const dispatch = useDispatch(); - const onSubmit = ({ email, name }) => { - clearServerError(); - const payload = { userName: name, email }; - dispatch(createAccount(payload)); - }; + const onSubmit = ({ email, name }) => { + clearServerError(); + const payload = { userName: name, email }; + dispatch(createAccount(payload)); + }; - const handleCancel = (e) => { - if (e) { - e.preventDefault(); - } + const handleCancel = e => { + if (e) { + e.preventDefault(); + } - clearServerError(); - dispatch(goBack()); - }; + clearServerError(); + dispatch(goBack()); + }; - const clearServerError = () => { - if (hasError) { - dispatch(clearError()); - } - }; + const clearServerError = () => { + if (hasError) { + dispatch(clearError()); + } + }; - // clear server errors if clicked on outside of element. - const formRef = useRef(null); - useOutsideClick(formRef, clearServerError); + // clear server errors if clicked on outside of element. + const formRef = useRef(null); + useOutsideClick(formRef, clearServerError); - return - - Create New Account - - - Name - - - {errors.name?.message} - - - - Root Account Email - - - {errors.email?.message} - - - - { - hasError && } - title="Error" - variant="danger"> - {errorMessage} - - } - - -