web/satellite: reworked delete bucket modal to use common VModal component
Reworked delete bucket modal to use common VModal component to improve UX. Issue: https://github.com/storj/storj/issues/5104 Change-Id: I74acd07a0cb3f7e0231f88bf1255de9ac000ace5
This commit is contained in:
parent
8152920a51
commit
db864a8605
@ -18,6 +18,7 @@
|
||||
<ShareObjectModal v-if="isShareObjectModal" />
|
||||
<ObjectDetailsModal v-if="isObjectDetailsModal" />
|
||||
<NewFolderModal v-if="isNewFolderModal" />
|
||||
<DeleteBucketModal v-if="isDeleteBucketModal" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -39,10 +40,12 @@ import ShareBucketModal from '@/components/modals/ShareBucketModal.vue';
|
||||
import ObjectDetailsModal from '@/components/modals/ObjectDetailsModal.vue';
|
||||
import NewFolderModal from '@/components/modals/NewFolderModal.vue';
|
||||
import ShareObjectModal from '@/components/modals/ShareObjectModal.vue';
|
||||
import DeleteBucketModal from '@/components/modals/DeleteBucketModal.vue';
|
||||
|
||||
// @vue/component
|
||||
@Component({
|
||||
components: {
|
||||
DeleteBucketModal,
|
||||
CreateProjectPromptModal,
|
||||
CreateProjectModal,
|
||||
AddPaymentMethodModal,
|
||||
@ -153,6 +156,13 @@ export default class AllModals extends Vue {
|
||||
return this.$store.state.appStateModule.appState.isShareObjectModalShown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if delete bucket modal is shown.
|
||||
*/
|
||||
public get isDeleteBucketModal(): boolean {
|
||||
return this.$store.state.appStateModule.appState.isDeleteBucketModalShown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if object details modal is shown.
|
||||
*/
|
||||
|
224
web/satellite/src/components/modals/DeleteBucketModal.vue
Normal file
224
web/satellite/src/components/modals/DeleteBucketModal.vue
Normal file
@ -0,0 +1,224 @@
|
||||
// Copyright (C) 2022 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<VModal :on-close="closeModal">
|
||||
<template #content>
|
||||
<div class="modal">
|
||||
<h1 class="modal__title">Are you sure?</h1>
|
||||
<p class="modal__subtitle">
|
||||
Deleting bucket will delete all metadata related to this bucket.
|
||||
</p>
|
||||
<VInput
|
||||
class="modal__input"
|
||||
label="Bucket Name"
|
||||
placeholder="Enter bucket name"
|
||||
:is-loading="isLoading"
|
||||
@setData="onChangeName"
|
||||
/>
|
||||
<VButton
|
||||
label="Confirm Delete Bucket"
|
||||
width="100%"
|
||||
height="48px"
|
||||
:on-press="onDelete"
|
||||
:is-disabled="isLoading || !name"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</VModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import { APP_STATE_MUTATIONS } from '@/store/mutationConstants';
|
||||
import { OBJECTS_ACTIONS } from '@/store/modules/objects';
|
||||
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
|
||||
import { AnalyticsHttpApi } from '@/api/analytics';
|
||||
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||
import { AccessGrant, EdgeCredentials } from '@/types/accessGrants';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
import { MetaUtils } from '@/utils/meta';
|
||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||
|
||||
import VModal from '@/components/common/VModal.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import VInput from '@/components/common/VInput.vue';
|
||||
|
||||
// @vue/component
|
||||
@Component({
|
||||
components: {
|
||||
VInput,
|
||||
VButton,
|
||||
VModal,
|
||||
},
|
||||
})
|
||||
export default class DeleteBucketModal extends Vue {
|
||||
private worker: Worker;
|
||||
private name = '';
|
||||
private readonly FILE_BROWSER_AG_NAME: string = 'Web file browser API key';
|
||||
private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
|
||||
|
||||
public isLoading = false;
|
||||
|
||||
/**
|
||||
* Lifecycle hook after initial render.
|
||||
* Sets local worker.
|
||||
*/
|
||||
public mounted(): void {
|
||||
this.setWorker();
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds on delete button click logic.
|
||||
* Creates unrestricted access grant and deletes bucket.
|
||||
*/
|
||||
public async onDelete(): Promise<void> {
|
||||
if (this.isLoading) return;
|
||||
|
||||
this.isLoading = true;
|
||||
|
||||
try {
|
||||
if (!this.apiKey) {
|
||||
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.DELETE_BY_NAME_AND_PROJECT_ID, this.FILE_BROWSER_AG_NAME);
|
||||
const cleanAPIKey: AccessGrant = await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.CREATE, this.FILE_BROWSER_AG_NAME);
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.SET_API_KEY, cleanAPIKey.secret);
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const inOneDay = new Date(now.setDate(now.getDate() + 1));
|
||||
|
||||
await this.worker.postMessage({
|
||||
'type': 'SetPermission',
|
||||
'isDownload': false,
|
||||
'isUpload': false,
|
||||
'isList': true,
|
||||
'isDelete': true,
|
||||
'notAfter': inOneDay.toISOString(),
|
||||
'buckets': [],
|
||||
'apiKey': this.apiKey,
|
||||
});
|
||||
|
||||
const grantEvent: MessageEvent = await new Promise(resolve => this.worker.onmessage = resolve);
|
||||
if (grantEvent.data.error) {
|
||||
await this.$notify.error(grantEvent.data.error);
|
||||
return;
|
||||
}
|
||||
|
||||
const salt = await this.$store.dispatch(PROJECTS_ACTIONS.GET_SALT, this.$store.getters.selectedProject.id);
|
||||
const satelliteNodeURL: string = MetaUtils.getMetaContent('satellite-nodeurl');
|
||||
|
||||
this.worker.postMessage({
|
||||
'type': 'GenerateAccess',
|
||||
'apiKey': grantEvent.data.value,
|
||||
'passphrase': '',
|
||||
'salt': salt,
|
||||
'satelliteNodeURL': satelliteNodeURL,
|
||||
});
|
||||
|
||||
const accessGrantEvent: MessageEvent = await new Promise(resolve => this.worker.onmessage = resolve);
|
||||
if (accessGrantEvent.data.error) {
|
||||
await this.$notify.error(accessGrantEvent.data.error);
|
||||
return;
|
||||
}
|
||||
|
||||
const accessGrant = accessGrantEvent.data.value;
|
||||
|
||||
const gatewayCredentials: EdgeCredentials = await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.GET_GATEWAY_CREDENTIALS, { accessGrant });
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.SET_GATEWAY_CREDENTIALS, gatewayCredentials);
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.SET_S3_CLIENT);
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.DELETE_BUCKET, this.name);
|
||||
this.analytics.eventTriggered(AnalyticsEvent.BUCKET_DELETED);
|
||||
await this.fetchBuckets();
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message);
|
||||
return;
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
this.closeModal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches bucket using api.
|
||||
*/
|
||||
private async fetchBuckets(page = 1): Promise<void> {
|
||||
try {
|
||||
await this.$store.dispatch(BUCKET_ACTIONS.FETCH, page);
|
||||
} catch (error) {
|
||||
await this.$notify.error(`Unable to fetch buckets. ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets local worker with worker instantiated in store.
|
||||
*/
|
||||
public setWorker(): void {
|
||||
this.worker = this.$store.state.accessGrantsModule.accessGrantsWebWorker;
|
||||
this.worker.onerror = (error: ErrorEvent) => {
|
||||
this.$notify.error(error.message);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets name from input.
|
||||
*/
|
||||
public onChangeName(value: string): void {
|
||||
this.name = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes modal.
|
||||
*/
|
||||
public closeModal(): void {
|
||||
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_DELETE_BUCKET_MODAL_SHOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns apiKey from store.
|
||||
*/
|
||||
private get apiKey(): string {
|
||||
return this.$store.state.objectsModule.apiKey;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.modal {
|
||||
padding: 45px 70px;
|
||||
border-radius: 10px;
|
||||
font-family: 'font_regular', sans-serif;
|
||||
font-style: normal;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
max-width: 480px;
|
||||
|
||||
@media screen and (max-width: 700px) {
|
||||
padding: 45px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 22px;
|
||||
line-height: 27px;
|
||||
color: #000;
|
||||
margin: 0 0 18px;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-size: 18px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
letter-spacing: -0.1007px;
|
||||
color: rgb(37 37 37 / 70%);
|
||||
margin: 0 0 24px;
|
||||
}
|
||||
|
||||
&__input {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -59,13 +59,13 @@ import { APP_STATE_ACTIONS, PM_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
|
||||
import { LocalData } from '@/utils/localData';
|
||||
import { OBJECTS_ACTIONS } from '@/store/modules/objects';
|
||||
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
|
||||
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||
import { APP_STATE_MUTATIONS } from '@/store/mutationConstants';
|
||||
import { Project } from '@/types/projects';
|
||||
import { User } from '@/types/users';
|
||||
import { OBJECTS_ACTIONS } from '@/store/modules/objects';
|
||||
|
||||
import VLoader from '@/components/common/VLoader.vue';
|
||||
|
||||
@ -146,15 +146,8 @@ export default class ProjectSelection extends Vue {
|
||||
|
||||
if (this.isBucketsView) {
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.CLEAR);
|
||||
this.analytics.pageVisit(RouteConfig.Buckets.path);
|
||||
await this.$router.push(RouteConfig.Buckets.path).catch(() => {return; });
|
||||
|
||||
try {
|
||||
await this.$store.dispatch(BUCKET_ACTIONS.FETCH, this.FIRST_PAGE);
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -285,7 +278,7 @@ export default class ProjectSelection extends Vue {
|
||||
private get isBucketsView(): boolean {
|
||||
const currentRoute = this.$route.path;
|
||||
|
||||
return currentRoute.includes(RouteConfig.BucketsManagement.path);
|
||||
return currentRoute.includes(RouteConfig.Buckets.path);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -31,6 +31,7 @@ import { Component, Prop } from 'vue-property-decorator';
|
||||
import { RouteConfig } from '@/router';
|
||||
import { Bucket } from '@/types/buckets';
|
||||
import { LocalData } from '@/utils/localData';
|
||||
import { APP_STATE_MUTATIONS } from '@/store/mutationConstants';
|
||||
|
||||
import TableItem from '@/components/common/TableItem.vue';
|
||||
import Resizable from '@/components/common/Resizable.vue';
|
||||
@ -52,8 +53,6 @@ export default class BucketItem extends Resizable {
|
||||
@Prop({ default: null })
|
||||
public readonly itemData: Bucket;
|
||||
@Prop({ default: () => () => {} })
|
||||
public readonly showDeleteBucketPopup: () => void;
|
||||
@Prop({ default: () => () => {} })
|
||||
public readonly openDropdown;
|
||||
@Prop({ default: () => (_: string) => {} })
|
||||
public readonly onClick: (bucket: string) => void;
|
||||
@ -106,7 +105,7 @@ export default class BucketItem extends Resizable {
|
||||
* Holds on delete click logic.
|
||||
*/
|
||||
public onDeleteClick(): void {
|
||||
this.showDeleteBucketPopup();
|
||||
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_DELETE_BUCKET_MODAL_SHOWN);
|
||||
this.closeDropdown();
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,6 @@
|
||||
v-for="(bucket, key) in bucketsPage.buckets"
|
||||
:key="key"
|
||||
:item-data="bucket"
|
||||
:show-delete-bucket-popup="showDeleteBucketPopup"
|
||||
:dropdown-key="key"
|
||||
:open-dropdown="openDropdown"
|
||||
:is-dropdown-open="activeDropdown === key"
|
||||
@ -60,17 +59,6 @@
|
||||
</template>
|
||||
</v-table>
|
||||
<EncryptionBanner v-if="!isServerSideEncryptionBannerHidden" :hide="hideBanner" />
|
||||
<ObjectsPopup
|
||||
v-if="isDeletePopupVisible"
|
||||
:on-click="onDeleteBucketClick"
|
||||
title="Are you sure?"
|
||||
sub-title="Deleting this bucket will delete all metadata related to this bucket."
|
||||
button-label="Confirm Delete Bucket"
|
||||
:error-message="errorMessage"
|
||||
:is-loading="isRequestProcessing"
|
||||
@setName="setDeleteBucketName"
|
||||
@close="hideDeleteBucketPopup"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -80,20 +68,14 @@ import { Component, Vue, Watch } from 'vue-property-decorator';
|
||||
import { RouteConfig } from '@/router';
|
||||
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||
import { OBJECTS_ACTIONS } from '@/store/modules/objects';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
import { AccessGrant, EdgeCredentials } from '@/types/accessGrants';
|
||||
import { MetaUtils } from '@/utils/meta';
|
||||
import { Validator } from '@/utils/validation';
|
||||
import { LocalData } from '@/utils/localData';
|
||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||
import { BucketPage } from '@/types/buckets';
|
||||
import { APP_STATE_MUTATIONS } from '@/store/mutationConstants';
|
||||
import { AnalyticsHttpApi } from '@/api/analytics';
|
||||
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
|
||||
|
||||
import VLoader from '@/components/common/VLoader.vue';
|
||||
import BucketItem from '@/components/objects/BucketItem.vue';
|
||||
import ObjectsPopup from '@/components/objects/ObjectsPopup.vue';
|
||||
import VTable from '@/components/common/VTable.vue';
|
||||
import EncryptionBanner from '@/components/objects/EncryptionBanner.vue';
|
||||
|
||||
@ -106,7 +88,6 @@ import EmptyBucketIcon from '@/../static/images/objects/emptyBucket.svg';
|
||||
VTable,
|
||||
WhitePlusIcon,
|
||||
EmptyBucketIcon,
|
||||
ObjectsPopup,
|
||||
BucketItem,
|
||||
VLoader,
|
||||
EncryptionBanner,
|
||||
@ -114,14 +95,8 @@ import EmptyBucketIcon from '@/../static/images/objects/emptyBucket.svg';
|
||||
})
|
||||
export default class BucketsView extends Vue {
|
||||
private readonly FILE_BROWSER_AG_NAME: string = 'Web file browser API key';
|
||||
private worker: Worker;
|
||||
private grantWithPermissions = '';
|
||||
private deleteBucketName = '';
|
||||
|
||||
public isLoading = true;
|
||||
public isDeletePopupVisible = false;
|
||||
public isRequestProcessing = false;
|
||||
public errorMessage = '';
|
||||
public activeDropdown = -1;
|
||||
public isServerSideEncryptionBannerHidden = true;
|
||||
|
||||
@ -149,9 +124,6 @@ export default class BucketsView extends Vue {
|
||||
*/
|
||||
public async setBucketsView(): Promise<void> {
|
||||
try {
|
||||
await this.setWorker();
|
||||
await this.removeTemporaryAccessGrant();
|
||||
await this.setAccess();
|
||||
await this.fetchBuckets();
|
||||
|
||||
const wasDemoBucketCreated = LocalData.getDemoBucketCreatedStatus();
|
||||
@ -179,56 +151,6 @@ export default class BucketsView extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets access to S3 client.
|
||||
*/
|
||||
public async setAccess(): Promise<void> {
|
||||
const cleanAPIKey: AccessGrant = await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.CREATE, this.FILE_BROWSER_AG_NAME);
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.SET_API_KEY, cleanAPIKey.secret);
|
||||
|
||||
const now = new Date();
|
||||
const inThreeDays = new Date(now.setDate(now.getDate() + 3));
|
||||
|
||||
await this.worker.postMessage({
|
||||
'type': 'SetPermission',
|
||||
'isDownload': true,
|
||||
'isUpload': true,
|
||||
'isList': true,
|
||||
'isDelete': true,
|
||||
'notAfter': inThreeDays.toISOString(),
|
||||
'buckets': [],
|
||||
'apiKey': cleanAPIKey.secret,
|
||||
});
|
||||
|
||||
const grantEvent: MessageEvent = await new Promise(resolve => this.worker.onmessage = resolve);
|
||||
this.grantWithPermissions = grantEvent.data.value;
|
||||
if (grantEvent.data.error) {
|
||||
throw new Error(grantEvent.data.error);
|
||||
}
|
||||
|
||||
const salt = await this.$store.dispatch(PROJECTS_ACTIONS.GET_SALT, this.$store.getters.selectedProject.id);
|
||||
const satelliteNodeURL: string = MetaUtils.getMetaContent('satellite-nodeurl');
|
||||
|
||||
this.worker.postMessage({
|
||||
'type': 'GenerateAccess',
|
||||
'apiKey': this.grantWithPermissions,
|
||||
'passphrase': '',
|
||||
'salt': salt,
|
||||
'satelliteNodeURL': satelliteNodeURL,
|
||||
});
|
||||
|
||||
const accessGrantEvent: MessageEvent = await new Promise(resolve => this.worker.onmessage = resolve);
|
||||
if (accessGrantEvent.data.error) {
|
||||
throw new Error(accessGrantEvent.data.error);
|
||||
}
|
||||
|
||||
const accessGrant = accessGrantEvent.data.value;
|
||||
|
||||
const gatewayCredentials: EdgeCredentials = await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.GET_GATEWAY_CREDENTIALS, { accessGrant, isPublic: false });
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.SET_GATEWAY_CREDENTIALS, gatewayCredentials);
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.SET_S3_CLIENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches bucket using api.
|
||||
*/
|
||||
@ -240,70 +162,11 @@ export default class BucketsView extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets local worker with worker instantiated in store.
|
||||
*/
|
||||
public setWorker(): void {
|
||||
this.worker = this.$store.state.accessGrantsModule.accessGrantsWebWorker;
|
||||
this.worker.onerror = (error: ErrorEvent) => {
|
||||
this.$notify.error(error.message);
|
||||
};
|
||||
}
|
||||
|
||||
public onNewBucketButtonClick(): void {
|
||||
this.analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path);
|
||||
this.$router.push(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates first ever demo bucket for user.
|
||||
*/
|
||||
public async createDemoBucket(): Promise<void> {
|
||||
if (this.isRequestProcessing) return;
|
||||
|
||||
this.isRequestProcessing = true;
|
||||
|
||||
try {
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.CREATE_DEMO_BUCKET);
|
||||
await this.fetchBuckets();
|
||||
|
||||
LocalData.setDemoBucketCreatedStatus();
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message);
|
||||
} finally {
|
||||
this.isRequestProcessing = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds delete bucket click logic.
|
||||
*/
|
||||
public async onDeleteBucketClick(): Promise<void> {
|
||||
if (this.isRequestProcessing) return;
|
||||
|
||||
if (!this.isBucketNameValid(this.deleteBucketName)) return;
|
||||
|
||||
this.isRequestProcessing = true;
|
||||
|
||||
try {
|
||||
if (!this.edgeCredentials.accessKeyId) {
|
||||
await this.setAccess();
|
||||
}
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.DELETE_BUCKET, this.deleteBucketName);
|
||||
await this.fetchBuckets();
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message);
|
||||
return;
|
||||
} finally {
|
||||
this.isRequestProcessing = false;
|
||||
}
|
||||
|
||||
this.analytics.eventTriggered(AnalyticsEvent.BUCKET_DELETED);
|
||||
|
||||
this.deleteBucketName = '';
|
||||
this.hideDeleteBucketPopup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes temporary created access grant.
|
||||
*/
|
||||
@ -329,30 +192,6 @@ export default class BucketsView extends Vue {
|
||||
this.activeDropdown = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes delete bucket popup visible.
|
||||
*/
|
||||
public showDeleteBucketPopup(): void {
|
||||
this.deleteBucketName = '';
|
||||
this.isDeletePopupVisible = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides delete bucket popup.
|
||||
*/
|
||||
public hideDeleteBucketPopup(): void {
|
||||
this.errorMessage = '';
|
||||
this.isDeletePopupVisible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set delete bucket name form input.
|
||||
*/
|
||||
public setDeleteBucketName(name: string): void {
|
||||
this.errorMessage = '';
|
||||
this.deleteBucketName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides server-side encryption banner.
|
||||
*/
|
||||
@ -382,32 +221,6 @@ export default class BucketsView extends Vue {
|
||||
private get selectedProjectID(): string {
|
||||
return this.$store.getters.selectedProject.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns edge credentials from store.
|
||||
*/
|
||||
private get edgeCredentials(): EdgeCredentials {
|
||||
return this.$store.state.objectsModule.gatewayCredentials;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns validation status of a bucket name.
|
||||
*/
|
||||
private isBucketNameValid(name: string): boolean {
|
||||
switch (true) {
|
||||
case name.length < 3 || name.length > 63:
|
||||
this.errorMessage = 'Name must be not less than 3 and not more than 63 characters length';
|
||||
|
||||
return false;
|
||||
case !Validator.bucketName(name):
|
||||
this.errorMessage = 'Name must contain only lowercase latin characters, numbers, a hyphen or a period';
|
||||
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -1,164 +0,0 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="objects-popup" @click.self="onCloseClick">
|
||||
<div class="objects-popup__container">
|
||||
<h1 class="objects-popup__container__title">{{ title }}</h1>
|
||||
<p class="objects-popup__container__sub-title">{{ subTitle }}</p>
|
||||
<div class="objects-popup__container__info">
|
||||
<WarningIcon />
|
||||
<p class="objects-popup__container__info__msg">Only lowercase alphanumeric characters are allowed.</p>
|
||||
</div>
|
||||
<VInput
|
||||
class="objects-popup__container__input"
|
||||
label="Bucket Name"
|
||||
placeholder="Enter bucket name"
|
||||
:error="errorMessage"
|
||||
:is-loading="isLoading"
|
||||
@setData="onChangeName"
|
||||
/>
|
||||
<VButton
|
||||
:label="buttonLabel"
|
||||
width="100%"
|
||||
height="48px"
|
||||
:on-press="onClick"
|
||||
:is-disabled="isLoading"
|
||||
/>
|
||||
<div class="objects-popup__container__close-cross-container" @click="onCloseClick">
|
||||
<CloseCrossIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
|
||||
import VInput from '@/components/common/VInput.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
|
||||
import CloseCrossIcon from '@/../static/images/common/closeCross.svg';
|
||||
import WarningIcon from '@/../static/images/objects/warning.svg';
|
||||
|
||||
// @vue/component
|
||||
@Component({
|
||||
components: {
|
||||
VInput,
|
||||
VButton,
|
||||
CloseCrossIcon,
|
||||
WarningIcon,
|
||||
},
|
||||
})
|
||||
export default class ObjectsPopup extends Vue {
|
||||
@Prop({ default: () => () => {} })
|
||||
public readonly onClick: () => void;
|
||||
@Prop({ default: '' })
|
||||
public readonly title: string;
|
||||
@Prop({ default: '' })
|
||||
public readonly subTitle: string;
|
||||
@Prop({ default: '' })
|
||||
public readonly buttonLabel: string;
|
||||
@Prop({ default: '' })
|
||||
public readonly errorMessage: string;
|
||||
@Prop({ default: false })
|
||||
public readonly isLoading: boolean;
|
||||
|
||||
/**
|
||||
* Sets bucket name from input.
|
||||
*/
|
||||
public onChangeName(value: string): void {
|
||||
this.$emit('setName', value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes popup.
|
||||
*/
|
||||
public onCloseClick(): void {
|
||||
this.$emit('close');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.objects-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgb(27 37 51 / 75%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&__container {
|
||||
padding: 45px 70px;
|
||||
border-radius: 10px;
|
||||
font-family: 'font_regular', sans-serif;
|
||||
font-style: normal;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
max-width: 480px;
|
||||
position: relative;
|
||||
|
||||
&__title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 22px;
|
||||
line-height: 27px;
|
||||
color: #000;
|
||||
margin: 0 0 18px;
|
||||
}
|
||||
|
||||
&__sub-title {
|
||||
font-weight: normal;
|
||||
font-size: 18px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
letter-spacing: -0.1007px;
|
||||
color: rgb(37 37 37 / 70%);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&__info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 23px 14px;
|
||||
background: #f5f6fa;
|
||||
border: 1px solid #a9b5c1;
|
||||
margin: 20px 0;
|
||||
border-radius: 9px;
|
||||
|
||||
&__msg {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 19px;
|
||||
color: #1b2533;
|
||||
margin: 0 0 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&__input {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
&__close-cross-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
top: 30px;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover .close-cross-svg-path {
|
||||
fill: #2683ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -220,20 +220,6 @@ export default class UploadFile extends Vue {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.back {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
color: #000;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
margin: 0 0 30px 15px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.back:hover {
|
||||
color: #007bff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.file-browser {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
padding-bottom: 200px;
|
||||
|
@ -39,6 +39,7 @@ class ViewsState {
|
||||
public isAddTokenFundsModalShown = false,
|
||||
public isShareBucketModalShown = false,
|
||||
public isShareObjectModalShown = false,
|
||||
public isDeleteBucketModalShown = false,
|
||||
public isNewFolderModalShown = false,
|
||||
public isObjectDetailsModalShown = false,
|
||||
public isBillingNotificationShown = true,
|
||||
@ -157,6 +158,9 @@ export const appStateModule = {
|
||||
[APP_STATE_MUTATIONS.TOGGLE_SHARE_OBJECT_MODAL_SHOWN](state: State): void {
|
||||
state.appState.isShareObjectModalShown = !state.appState.isShareObjectModalShown;
|
||||
},
|
||||
[APP_STATE_MUTATIONS.TOGGLE_DELETE_BUCKET_MODAL_SHOWN](state: State): void {
|
||||
state.appState.isDeleteBucketModalShown = !state.appState.isDeleteBucketModalShown;
|
||||
},
|
||||
[APP_STATE_MUTATIONS.TOGGLE_OBJECT_DETAILS_MODAL_SHOWN](state: State): void {
|
||||
state.appState.isObjectDetailsModalShown = !state.appState.isObjectDetailsModalShown;
|
||||
},
|
||||
|
@ -17,7 +17,6 @@ export const OBJECTS_ACTIONS = {
|
||||
SET_FILE_COMPONENT_BUCKET_NAME: 'setFileComponentBucketName',
|
||||
FETCH_BUCKETS: 'fetchBuckets',
|
||||
CREATE_BUCKET: 'createBucket',
|
||||
CREATE_DEMO_BUCKET: 'createDemoBucket',
|
||||
DELETE_BUCKET: 'deleteBucket',
|
||||
CHECK_ONGOING_UPLOADS: 'checkOngoingUploads',
|
||||
};
|
||||
@ -145,11 +144,6 @@ export function makeObjectsModule(): StoreModule<ObjectsState, ObjectsContext> {
|
||||
Bucket: name,
|
||||
}).promise();
|
||||
},
|
||||
createDemoBucket: async function(ctx): Promise<void> {
|
||||
await ctx.state.s3Client.createBucket({
|
||||
Bucket: DEMO_BUCKET_NAME,
|
||||
}).promise();
|
||||
},
|
||||
deleteBucket: async function(ctx, name: string): Promise<void> {
|
||||
await ctx.state.s3Client.deleteBucket({
|
||||
Bucket: name,
|
||||
|
@ -39,6 +39,7 @@ export const APP_STATE_MUTATIONS = {
|
||||
TOGGLE_ADD_TOKEN_FUNDS_MODAL_SHOWN: 'TOGGLE_ADD_TOKEN_FUNDS_MODAL_SHOWN',
|
||||
TOGGLE_SHARE_BUCKET_MODAL_SHOWN: 'TOGGLE_SHARE_BUCKET_MODAL_SHOWN',
|
||||
TOGGLE_SHARE_OBJECT_MODAL_SHOWN: 'TOGGLE_SHARE_OBJECT_MODAL_SHOWN',
|
||||
TOGGLE_DELETE_BUCKET_MODAL_SHOWN: 'TOGGLE_DELETE_BUCKET_MODAL_SHOWN',
|
||||
TOGGLE_OBJECT_DETAILS_MODAL_SHOWN: 'TOGGLE_OBJECT_DETAILS_MODAL_SHOWN',
|
||||
TOGGLE_NEW_FOLDER_MODAL_SHOWN: 'TOGGLE_NEW_FOLDER_MODAL_SHOWN',
|
||||
SHOW_DELETE_PAYMENT_METHOD_POPUP: 'SHOW_DELETE_PAYMENT_METHOD_POPUP',
|
||||
|
Loading…
Reference in New Issue
Block a user