web/satellite: add uploading large file notifications
Add default uploading large file notification when in buckets page. When dismissed, store in local storage. When user uploads a file that exceeds 1 GB, show warning notification. Issue https://github.com/storj/storj/issues/5148 Change-Id: I895a230c017e8439ab2c19ea494930b7e9900a47
This commit is contained in:
parent
27d9d9f6d4
commit
3f8eb58e4c
@ -0,0 +1,81 @@
|
||||
// Copyright (C) 2023 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="notification-wrap__content" :class="{ 'notification-wrap__warning-colors': warningNotification}">
|
||||
<component :is="notificationIcon" class="notification-wrap__content__icon" />
|
||||
<div class="notification-wrap__content__middle">
|
||||
<p class="text"><b>{{ wordingBold }}</b> {{ wording }}</p>
|
||||
<a target="_blank" href="https://docs.storj.io/dcs/getting-started/quickstart-objectbrowser#WeS6v">See documentation</a>
|
||||
</div>
|
||||
<CloseIcon class="notification-wrap__content__close" @click="onCloseClick" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import Vue, { VueConstructor } from 'vue';
|
||||
|
||||
import CloseIcon from '@/../static/images/notifications/closeSmall.svg';
|
||||
|
||||
const props = defineProps<{
|
||||
wordingBold: string;
|
||||
wording: string;
|
||||
notificationIcon: VueConstructor<Vue>;
|
||||
warningNotification: boolean;
|
||||
onCloseClick: () => void;
|
||||
}>();
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.notification-wrap {
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
border: 1px solid rgb(56 75 101 / 40%);
|
||||
padding: 16px;
|
||||
margin-bottom: 48px;
|
||||
font-family: 'font_regular', sans-serif;
|
||||
font-size: 14px;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 7px 20px rgba(0 0 0 / 15%);
|
||||
|
||||
&__icon {
|
||||
flex-shrink: 0;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
&__middle {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
gap: 16px;
|
||||
|
||||
& b {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
}
|
||||
|
||||
& a {
|
||||
color: black;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
&__close {
|
||||
flex-shrink: 0;
|
||||
margin-left: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&__warning-colors {
|
||||
background-color: #fec;
|
||||
border: 1px solid #ffd78a;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -35,6 +35,5 @@ onMounted(async (): Promise<void> => {
|
||||
<style scoped lang="scss">
|
||||
.objects-area {
|
||||
padding: 20px 45px;
|
||||
height: calc(100% - 40px);
|
||||
}
|
||||
</style>
|
||||
|
@ -262,6 +262,5 @@ watch(passphrase, async () => {
|
||||
<style scoped>
|
||||
.file-browser {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
padding-bottom: 200px;
|
||||
}
|
||||
</style>
|
||||
|
@ -30,6 +30,8 @@ class ViewsState {
|
||||
// for when the dashboard opens the pricing plan and the pricing plan navigates back repeatedly.
|
||||
public hasShownPricingPlan = false;
|
||||
public error: ErrorPageState = new ErrorPageState();
|
||||
public isLargeUploadNotificationShown = true;
|
||||
public isLargeUploadWarningNotificationShown = false;
|
||||
}
|
||||
|
||||
class ErrorPageState {
|
||||
@ -132,6 +134,14 @@ export const useAppStore = defineStore('app', () => {
|
||||
state.viewsState.hasShownPricingPlan = value;
|
||||
}
|
||||
|
||||
function setLargeUploadWarningNotification(value: boolean): void {
|
||||
state.viewsState.isLargeUploadWarningNotificationShown = value;
|
||||
}
|
||||
|
||||
function setLargeUploadNotification(value: boolean): void {
|
||||
state.viewsState.isLargeUploadNotificationShown = value;
|
||||
}
|
||||
|
||||
function closeDropdowns(): void {
|
||||
state.viewsState.activeDropdown = '';
|
||||
}
|
||||
@ -179,6 +189,8 @@ export const useAppStore = defineStore('app', () => {
|
||||
setPricingPlan,
|
||||
setManagePassphraseStep,
|
||||
setHasShownPricingPlan,
|
||||
setLargeUploadWarningNotification,
|
||||
setLargeUploadNotification,
|
||||
closeDropdowns,
|
||||
setErrorPage,
|
||||
removeErrorPage,
|
||||
|
@ -519,6 +519,12 @@ export const makeFilesModule = (): FilesModule => ({
|
||||
Body: file,
|
||||
};
|
||||
|
||||
// If file size exceeds 1 GB, show warning notification
|
||||
if (file.size > (1024 * 1024 * 1024)) {
|
||||
const appStore = useAppStore();
|
||||
appStore.setLargeUploadWarningNotification(true);
|
||||
}
|
||||
|
||||
const upload = state.s3.upload(
|
||||
{ ...params },
|
||||
{ partSize: 64 * 1024 * 1024 },
|
||||
|
@ -11,6 +11,7 @@ export class LocalData {
|
||||
private static bucketGuideHidden = 'bucketGuideHidden';
|
||||
private static serverSideEncryptionBannerHidden = 'serverSideEncryptionBannerHidden';
|
||||
private static serverSideEncryptionModalHidden = 'serverSideEncryptionModalHidden';
|
||||
private static largeUploadNotificationDismissed = 'largeUploadNotificationDismissed';
|
||||
private static sessionExpirationDate = 'sessionExpirationDate';
|
||||
private static projectLimitBannerHidden = 'projectLimitBannerHidden';
|
||||
|
||||
@ -84,6 +85,14 @@ export class LocalData {
|
||||
return value === 'true';
|
||||
}
|
||||
|
||||
public static getLargeUploadNotificationDismissed(): boolean {
|
||||
return Boolean(localStorage.getItem(LocalData.largeUploadNotificationDismissed));
|
||||
}
|
||||
|
||||
public static setLargeUploadNotificationDismissed(): void {
|
||||
localStorage.setItem(LocalData.largeUploadNotificationDismissed, 'true');
|
||||
}
|
||||
|
||||
public static getSessionExpirationDate(): Date | null {
|
||||
const data: string | null = localStorage.getItem(LocalData.sessionExpirationDate);
|
||||
if (data) {
|
||||
|
@ -62,6 +62,24 @@
|
||||
</v-banner>
|
||||
</div>
|
||||
<router-view class="dashboard__wrap__main-area__content-wrap__container__content" />
|
||||
<div class="banner-container__bottom dashboard__wrap__main-area__content-wrap__container__content">
|
||||
<UploadNotification
|
||||
v-if="isLargeUploadNotificationShown && !isLargeUploadWarningNotificationShown && isBucketsView"
|
||||
wording-bold="The web browser is best for uploads up to 1GB."
|
||||
wording="To upload larger files, check our recommendations"
|
||||
:notification-icon="CloudIcon"
|
||||
:warning-notification="false"
|
||||
:on-close-click="onNotificationCloseClick"
|
||||
/>
|
||||
<UploadNotification
|
||||
v-if="isLargeUploadWarningNotificationShown"
|
||||
wording-bold="Trying to upload a large file?"
|
||||
wording="Check the recommendations for your use case"
|
||||
:notification-icon="WarningIcon"
|
||||
:warning-notification="true"
|
||||
:on-close-click="onWarningNotificationCloseClick"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -122,6 +140,7 @@ import { useAccessGrantsStore } from '@/store/modules/accessGrantsStore';
|
||||
import { useBucketsStore } from '@/store/modules/bucketsStore';
|
||||
import { useProjectsStore } from '@/store/modules/projectsStore';
|
||||
|
||||
import UploadNotification from '@/components/notifications/UploadNotification.vue';
|
||||
import NavigationArea from '@/components/navigation/NavigationArea.vue';
|
||||
import InactivityModal from '@/components/modals/InactivityModal.vue';
|
||||
import BetaSatBar from '@/components/infoBars/BetaSatBar.vue';
|
||||
@ -134,7 +153,11 @@ import UpgradeNotification from '@/components/notifications/UpgradeNotification.
|
||||
import ProjectLimitBanner from '@/components/notifications/ProjectLimitBanner.vue';
|
||||
import BrandedLoader from '@/components/common/BrandedLoader.vue';
|
||||
|
||||
import CloudIcon from '@/../static/images/notifications/cloudAlert.svg';
|
||||
import WarningIcon from '@/../static/images/notifications/circleWarning.svg';
|
||||
|
||||
const bucketsStore = useBucketsStore();
|
||||
|
||||
const appStore = useAppStore();
|
||||
const agStore = useAccessGrantsStore();
|
||||
const billingStore = useBillingStore();
|
||||
@ -350,6 +373,20 @@ const showMFARecoveryCodeBar = computed((): boolean => {
|
||||
return user.isMFAEnabled && user.mfaRecoveryCodeCount < recoveryCodeWarningThreshold;
|
||||
});
|
||||
|
||||
/**
|
||||
* Indicates whether the large upload notification should be shown.
|
||||
*/
|
||||
const isLargeUploadNotificationShown = computed((): boolean => {
|
||||
return appStore.state.viewsState.isLargeUploadNotificationShown;
|
||||
});
|
||||
|
||||
/**
|
||||
* Indicates whether the large upload warning notification should be shown (file uploading exceeds 1GB).
|
||||
*/
|
||||
const isLargeUploadWarningNotificationShown = computed((): boolean => {
|
||||
return appStore.state.viewsState.isLargeUploadWarningNotificationShown;
|
||||
});
|
||||
|
||||
/**
|
||||
* Indicates if current route is create project page.
|
||||
*/
|
||||
@ -364,6 +401,28 @@ const isDashboardPage = computed((): boolean => {
|
||||
return router.currentRoute.name === RouteConfig.ProjectDashboard.name;
|
||||
});
|
||||
|
||||
/**
|
||||
* Indicates if current route is the bucketsView page.
|
||||
*/
|
||||
const isBucketsView = computed((): boolean => {
|
||||
return router.currentRoute.name === RouteConfig.BucketsManagement.name;
|
||||
});
|
||||
|
||||
/**
|
||||
* Closes upload notification and persists state in local storage.
|
||||
*/
|
||||
function onNotificationCloseClick(): void {
|
||||
appStore.setLargeUploadNotification(false);
|
||||
LocalData.setLargeUploadNotificationDismissed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes upload large files warning notification.
|
||||
*/
|
||||
function onWarningNotificationCloseClick(): void {
|
||||
appStore.setLargeUploadWarningNotification(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores project to vuex store and browser's local storage.
|
||||
* @param projectID - project id string
|
||||
@ -596,6 +655,10 @@ onMounted(async () => {
|
||||
if (action.name === 'clear') clearSessionTimers();
|
||||
});
|
||||
|
||||
if (LocalData.getLargeUploadNotificationDismissed()) {
|
||||
appStore.setLargeUploadNotification(false);
|
||||
}
|
||||
|
||||
try {
|
||||
await usersStore.getUser();
|
||||
await usersStore.getFrozenStatus();
|
||||
@ -690,6 +753,16 @@ onBeforeUnmount(() => {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.banner-container {
|
||||
|
||||
&__bottom {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.banner-container:empty {
|
||||
display: none;
|
||||
}
|
||||
@ -723,11 +796,15 @@ onBeforeUnmount(() => {
|
||||
&__container {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
&__content {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 48px 48px 0;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,3 @@
|
||||
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15 0.600006C22.9529 0.600006 29.4 7.04711 29.4 15C29.4 22.9529 22.9529 29.4 15 29.4C7.04711 29.4 0.600006 22.9529 0.600006 15C0.600006 7.04711 7.04711 0.600006 15 0.600006ZM15 3.24001C8.50514 3.24001 3.24001 8.50514 3.24001 15C3.24001 21.4949 8.50514 26.76 15 26.76C21.4949 26.76 26.76 21.4949 26.76 15C26.76 8.50514 21.4949 3.24001 15 3.24001ZM16.2 8.40074V15.9936C16.2 16.7226 15.609 17.3136 14.88 17.3136C14.1688 17.3136 13.5889 16.7511 13.5611 16.0467L13.56 15.9936V8.48858C13.56 7.75216 14.144 7.14842 14.88 7.12393C15.5852 7.10046 16.1758 7.65309 16.1993 8.35825C16.1998 8.37241 16.2 8.38657 16.2 8.40074ZM16.2 21.1207V21.2736C16.2 22.0026 15.609 22.5936 14.88 22.5936C14.1688 22.5936 13.5889 22.0311 13.5611 21.3267L13.56 21.2736V21.2086C13.56 20.4722 14.144 19.8684 14.88 19.8439C15.5852 19.8205 16.1758 20.3731 16.1993 21.0783C16.1998 21.0924 16.2 21.1066 16.2 21.1207Z" fill="#FF8A00"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1010 B |
5
web/satellite/static/images/notifications/cloudAlert.svg
Normal file
5
web/satellite/static/images/notifications/cloudAlert.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M34.4714 32C37.4486 32 39.8621 29.5865 39.8621 26.6094V25.4941C39.8621 22.5169 37.4486 20.1034 34.4714 20.1034L31.9243 20.1036C31.7154 13.9359 26.6496 9 20.431 9C15.6237 9 11.5053 11.9498 9.78712 16.138L8.93103 16.1379C4.55084 16.1379 1 19.6888 1 24.069C1 28.4492 4.55084 32 8.93103 32H34.4714Z" fill="#C8D3DE"/>
|
||||
<path d="M20.431 28.8275C25.0302 28.8275 28.7586 25.0991 28.7586 20.5C28.7586 15.9008 25.0302 12.1724 20.431 12.1724C15.8318 12.1724 12.1035 15.9008 12.1035 20.5C12.1035 25.0991 15.8318 28.8275 20.431 28.8275Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.431 21.6896C21.5261 21.6896 22.4138 22.5773 22.4138 23.6723C22.4138 24.7674 21.5261 25.6551 20.431 25.6551C19.336 25.6551 18.4483 24.7674 18.4483 23.6723C18.4483 22.5773 19.336 21.6896 20.431 21.6896ZM20.431 14.5516C21.3808 14.5516 22.1507 15.3215 22.1507 16.2713C22.1507 16.3526 22.1449 16.4339 22.1334 16.5145L21.6207 20.1034H19.2414L18.7287 16.5145C18.5944 15.5743 19.2477 14.7032 20.1878 14.5689C20.2684 14.5574 20.3497 14.5516 20.431 14.5516Z" fill="#FF458B"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
Loading…
Reference in New Issue
Block a user