web/satellite: added notification when storage limit is exceeded in file browser
Added error notification when user tries to upload object after storage limit is exceeded. Slightly changed error handling on failed preview/map request. Issue: https://github.com/storj/storj/issues/5003 Change-Id: Iee91c1037b5c6de7b9718adcdfcea850fd3056ca
This commit is contained in:
parent
27f6fbdeda
commit
e1a85fccf4
@ -28,31 +28,40 @@
|
||||
"
|
||||
>
|
||||
<img
|
||||
v-if="previewIsImage"
|
||||
ref="previewImage"
|
||||
class="preview img-fluid"
|
||||
src="/static/static/images/common/loader.svg"
|
||||
aria-roledescription="image-preview"
|
||||
v-if="previewFailed"
|
||||
class="failed-preview"
|
||||
src="/static/static/images/common/errorNotice.svg"
|
||||
alt="failed preview"
|
||||
>
|
||||
<template v-else>
|
||||
<img
|
||||
v-if="previewIsImage"
|
||||
ref="previewImage"
|
||||
class="preview img-fluid"
|
||||
src="/static/static/images/common/loader.svg"
|
||||
aria-roledescription="image-preview"
|
||||
alt="preview"
|
||||
>
|
||||
|
||||
<video
|
||||
v-if="previewIsVideo"
|
||||
ref="previewVideo"
|
||||
class="preview"
|
||||
controls
|
||||
src=""
|
||||
aria-roledescription="video-preview"
|
||||
/>
|
||||
<video
|
||||
v-if="previewIsVideo"
|
||||
ref="previewVideo"
|
||||
class="preview"
|
||||
controls
|
||||
src=""
|
||||
aria-roledescription="video-preview"
|
||||
/>
|
||||
|
||||
<audio
|
||||
v-if="previewIsAudio"
|
||||
ref="previewAudio"
|
||||
class="preview"
|
||||
controls
|
||||
src=""
|
||||
aria-roledescription="audio-preview"
|
||||
/>
|
||||
<PlaceholderImage v-if="placeHolderDisplayable" />
|
||||
<audio
|
||||
v-if="previewIsAudio"
|
||||
ref="previewAudio"
|
||||
class="preview"
|
||||
controls
|
||||
src=""
|
||||
aria-roledescription="audio-preview"
|
||||
/>
|
||||
<PlaceholderImage v-if="placeHolderDisplayable" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-lg-4 pr-5">
|
||||
@ -176,8 +185,7 @@
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div class="mt-5">
|
||||
<div v-if="!mapFailed" class="mt-5">
|
||||
<div class="storage-nodes">
|
||||
Nodes storing this file
|
||||
</div>
|
||||
@ -210,6 +218,8 @@ import PlaceholderImage from '@/../static/images/browser/placeholder.svg'
|
||||
export default class FileModal extends Vue {
|
||||
public objectLink = '';
|
||||
public copyText = 'Copy Link';
|
||||
public previewFailed = false;
|
||||
public mapFailed = false;
|
||||
|
||||
public $refs!: {
|
||||
objectMap: HTMLImageElement;
|
||||
@ -328,23 +338,20 @@ export default class FileModal extends Vue {
|
||||
* Get the object map for the file being displayed.
|
||||
*/
|
||||
private async fetchObjectMap(): Promise<void> {
|
||||
try {
|
||||
if (!this.$store.state.files.fetchObjectMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
const objectMap: Blob | null = await this.$store.state.files.fetchObjectMap(
|
||||
this.filePath
|
||||
);
|
||||
|
||||
if (!objectMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$refs.objectMap.src = URL.createObjectURL(objectMap);
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message);
|
||||
if (!this.$store.state.files.fetchObjectMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
const objectMap: Blob | null = await this.$store.state.files.fetchObjectMap(
|
||||
this.filePath
|
||||
);
|
||||
|
||||
if (!objectMap) {
|
||||
this.mapFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.$refs.objectMap.src = URL.createObjectURL(objectMap);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -363,33 +370,30 @@ export default class FileModal extends Vue {
|
||||
* Set preview object.
|
||||
*/
|
||||
public async setPreview(): Promise<void> {
|
||||
try {
|
||||
if (!this.$store.state.files.fetchObjectPreview) {
|
||||
return;
|
||||
}
|
||||
if (!this.$store.state.files.fetchObjectPreview) {
|
||||
return;
|
||||
}
|
||||
|
||||
const object: Blob | null = await this.$store.state.files.fetchObjectPreview(
|
||||
this.filePath
|
||||
);
|
||||
const object: Blob | null = await this.$store.state.files.fetchObjectPreview(
|
||||
this.filePath
|
||||
);
|
||||
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
if (!object) {
|
||||
this.previewFailed = true
|
||||
return;
|
||||
}
|
||||
|
||||
const objectURL = URL.createObjectURL(object);
|
||||
const objectURL = URL.createObjectURL(object);
|
||||
|
||||
switch (true) {
|
||||
case this.previewIsImage:
|
||||
this.$refs.previewImage.src = objectURL;
|
||||
break;
|
||||
case this.previewIsVideo:
|
||||
this.$refs.previewVideo.src = objectURL;
|
||||
break;
|
||||
case this.previewIsAudio:
|
||||
this.$refs.previewAudio.src = objectURL;
|
||||
}
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message);
|
||||
switch (true) {
|
||||
case this.previewIsImage:
|
||||
this.$refs.previewImage.src = objectURL;
|
||||
break;
|
||||
case this.previewIsVideo:
|
||||
this.$refs.previewVideo.src = objectURL;
|
||||
break;
|
||||
case this.previewIsAudio:
|
||||
this.$refs.previewAudio.src = objectURL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,7 +408,7 @@ export default class FileModal extends Vue {
|
||||
* Copy the current opened file.
|
||||
*/
|
||||
public async copy(): Promise<void> {
|
||||
await navigator.clipboard.writeText(this.objectLink);
|
||||
await this.$copyText(this.objectLink);
|
||||
this.copyText = 'Copied!';
|
||||
setTimeout(() => {
|
||||
this.copyText = 'Copy Link';
|
||||
@ -529,4 +533,8 @@ export default class FileModal extends Vue {
|
||||
font-size: 14px;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.failed-preview {
|
||||
width: 50%;
|
||||
}
|
||||
</style>
|
||||
|
@ -75,14 +75,26 @@ export default class UploadFile extends Vue {
|
||||
* Generates a URL for an object map.
|
||||
*/
|
||||
public async fetchObjectMap(path: string): Promise<Blob | null> {
|
||||
return await this.getObjectViewOrMapBySignedRequest(path, true)
|
||||
try {
|
||||
return await this.getObjectViewOrMapBySignedRequest(path, true)
|
||||
} catch (error) {
|
||||
await this.$notify.error('Failed to fetch object map. Bandwidth limit may be exceeded');
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URL for an object map.
|
||||
*/
|
||||
public async fetchObjectPreview(path: string): Promise<Blob | null> {
|
||||
return await this.getObjectViewOrMapBySignedRequest(path, false)
|
||||
try {
|
||||
return await this.getObjectViewOrMapBySignedRequest(path, false)
|
||||
} catch (error) {
|
||||
await this.$notify.error('Failed to fetch object view. Bandwidth limit may be exceeded');
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,65 +135,64 @@ export default class UploadFile extends Vue {
|
||||
* Returns a URL for an object or a map.
|
||||
*/
|
||||
private async getObjectViewOrMapBySignedRequest(path: string, isMap: boolean): Promise<Blob | null> {
|
||||
path = `${this.bucket}/${path}`;
|
||||
path = encodeURIComponent(path.trim());
|
||||
|
||||
const url = new URL(`${this.linksharingURL}/s/${this.credentials.accessKeyId}/${path}`)
|
||||
|
||||
let request: HttpRequest = {
|
||||
method: 'GET',
|
||||
protocol: url.protocol,
|
||||
hostname: url.hostname,
|
||||
port: parseFloat(url.port),
|
||||
path: url.pathname,
|
||||
headers: {
|
||||
'host': url.host,
|
||||
}
|
||||
}
|
||||
|
||||
if (isMap) {
|
||||
request = Object.assign(request, {query: { 'map': '1' }});
|
||||
} else {
|
||||
request = Object.assign(request, {query: { 'view': '1' }});
|
||||
}
|
||||
|
||||
const signerCredentials: Credentials = {
|
||||
accessKeyId: this.credentials.accessKeyId,
|
||||
secretAccessKey: this.credentials.secretKey,
|
||||
};
|
||||
|
||||
const signer = new SignatureV4({
|
||||
applyChecksum: true,
|
||||
uriEscapePath: false,
|
||||
credentials: signerCredentials,
|
||||
region: "eu1",
|
||||
service: "linksharing",
|
||||
sha256: Sha256,
|
||||
});
|
||||
|
||||
let signedRequest: HttpRequest;
|
||||
try {
|
||||
path = `${this.bucket}/${path}`;
|
||||
path = encodeURIComponent(path.trim());
|
||||
|
||||
const url = new URL(`${this.linksharingURL}/s/${this.credentials.accessKeyId}/${path}`)
|
||||
|
||||
let request: HttpRequest = {
|
||||
method: 'GET',
|
||||
protocol: url.protocol,
|
||||
hostname: url.hostname,
|
||||
port: parseFloat(url.port),
|
||||
path: url.pathname,
|
||||
headers: {
|
||||
'host': url.host,
|
||||
}
|
||||
}
|
||||
|
||||
if (isMap) {
|
||||
request = Object.assign(request, {query: { 'map': '1' }});
|
||||
} else {
|
||||
request = Object.assign(request, {query: { 'view': '1' }});
|
||||
}
|
||||
|
||||
const signerCredentials: Credentials = {
|
||||
accessKeyId: this.credentials.accessKeyId,
|
||||
secretAccessKey: this.credentials.secretKey,
|
||||
};
|
||||
|
||||
const signer = new SignatureV4({
|
||||
applyChecksum: true,
|
||||
uriEscapePath: false,
|
||||
credentials: signerCredentials,
|
||||
region: "eu1",
|
||||
service: "linksharing",
|
||||
sha256: Sha256,
|
||||
});
|
||||
|
||||
const signedRequest: HttpRequest = await signer.sign(request);
|
||||
|
||||
let requestURL = `${this.linksharingURL}${signedRequest.path}`;
|
||||
if (isMap) {
|
||||
requestURL = `${requestURL}?map=1`;
|
||||
} else {
|
||||
requestURL = `${requestURL}?view=1`;
|
||||
}
|
||||
|
||||
const response = await fetch(requestURL, signedRequest);
|
||||
if (response.ok) {
|
||||
return await response.blob();
|
||||
}
|
||||
|
||||
await this.$notify.error(`${response.status}. Failed to fetch object view or map`);
|
||||
|
||||
return null;
|
||||
signedRequest = await signer.sign(request);
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
let requestURL = `${this.linksharingURL}${signedRequest.path}`;
|
||||
if (isMap) {
|
||||
requestURL = `${requestURL}?map=1`;
|
||||
} else {
|
||||
requestURL = `${requestURL}?view=1`;
|
||||
}
|
||||
|
||||
const response = await fetch(requestURL, signedRequest);
|
||||
if (response.ok) {
|
||||
return await response.blob();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -291,7 +291,7 @@ export const makeFilesModule = (): FilesModule => ({
|
||||
},
|
||||
actions: {
|
||||
async list({ commit, state }, path = state.path) {
|
||||
if (listCache.has(path) === true) {
|
||||
if (listCache.has(path)) {
|
||||
commit("updateFiles", {
|
||||
path,
|
||||
files: listCache.get(path),
|
||||
@ -323,10 +323,10 @@ export const makeFilesModule = (): FilesModule => ({
|
||||
Contents.sort((a, b) => {
|
||||
if (
|
||||
a === undefined ||
|
||||
a.LastModified === undefined ||
|
||||
b === undefined ||
|
||||
b.LastModified === undefined ||
|
||||
a.LastModified === b.LastModified
|
||||
a.LastModified === undefined ||
|
||||
b === undefined ||
|
||||
b.LastModified === undefined ||
|
||||
a.LastModified === b.LastModified
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
@ -334,44 +334,44 @@ export const makeFilesModule = (): FilesModule => ({
|
||||
return a.LastModified < b.LastModified ? -1 : 1;
|
||||
});
|
||||
|
||||
type DefinedCommonPrefix = CommonPrefix & {
|
||||
Prefix: string;
|
||||
};
|
||||
type DefinedCommonPrefix = CommonPrefix & {
|
||||
Prefix: string;
|
||||
};
|
||||
|
||||
const isPrefixDefined = (
|
||||
value: CommonPrefix
|
||||
): value is DefinedCommonPrefix => value.Prefix !== undefined;
|
||||
const isPrefixDefined = (
|
||||
value: CommonPrefix
|
||||
): value is DefinedCommonPrefix => value.Prefix !== undefined;
|
||||
|
||||
const prefixToFolder = ({
|
||||
Prefix,
|
||||
}: {
|
||||
Prefix: string;
|
||||
}): BrowserObject => ({
|
||||
Key: Prefix.slice(path.length, -1),
|
||||
LastModified: 0,
|
||||
Size: 0,
|
||||
type: "folder",
|
||||
});
|
||||
const prefixToFolder = ({
|
||||
Prefix,
|
||||
}: {
|
||||
Prefix: string;
|
||||
}): BrowserObject => ({
|
||||
Key: Prefix.slice(path.length, -1),
|
||||
LastModified: 0,
|
||||
Size: 0,
|
||||
type: "folder",
|
||||
});
|
||||
|
||||
const makeFileRelative = (file) => ({
|
||||
...file,
|
||||
Key: file.Key.slice(path.length),
|
||||
type: "file",
|
||||
});
|
||||
const makeFileRelative = (file) => ({
|
||||
...file,
|
||||
Key: file.Key.slice(path.length),
|
||||
type: "file",
|
||||
});
|
||||
|
||||
const isFileVisible = (file) =>
|
||||
file.Key.length > 0 && file.Key !== ".file_placeholder";
|
||||
const isFileVisible = (file) =>
|
||||
file.Key.length > 0 && file.Key !== ".file_placeholder";
|
||||
|
||||
const files = [
|
||||
...CommonPrefixes.filter(isPrefixDefined).map(prefixToFolder),
|
||||
...Contents.map(makeFileRelative).filter(isFileVisible),
|
||||
];
|
||||
const files = [
|
||||
...CommonPrefixes.filter(isPrefixDefined).map(prefixToFolder),
|
||||
...Contents.map(makeFileRelative).filter(isFileVisible),
|
||||
];
|
||||
|
||||
listCache.set(path, files);
|
||||
commit("updateFiles", {
|
||||
path,
|
||||
files,
|
||||
});
|
||||
listCache.set(path, files);
|
||||
commit("updateFiles", {
|
||||
path,
|
||||
files,
|
||||
});
|
||||
},
|
||||
|
||||
async back({ state, dispatch }) {
|
||||
@ -391,136 +391,139 @@ export const makeFilesModule = (): FilesModule => ({
|
||||
async upload({ commit, state, dispatch }, e: DragEvent) {
|
||||
assertIsInitialized(state);
|
||||
|
||||
type Item = DataTransferItem | FileSystemEntry;
|
||||
type Item = DataTransferItem | FileSystemEntry;
|
||||
|
||||
const items: Item[] = e.dataTransfer
|
||||
? [...e.dataTransfer.items]
|
||||
: e.target !== null
|
||||
? ((e.target as unknown) as { files: FileSystemEntry[] }).files
|
||||
: [];
|
||||
const items: Item[] = e.dataTransfer
|
||||
? [...e.dataTransfer.items]
|
||||
: e.target !== null
|
||||
? ((e.target as unknown) as { files: FileSystemEntry[] }).files
|
||||
: [];
|
||||
|
||||
async function* traverse(item: Item | Item[], path = "") {
|
||||
if ('isFile' in item && item.isFile === true) {
|
||||
const file = await new Promise(item.file.bind(item));
|
||||
yield { path, file };
|
||||
} else if (item instanceof File) {
|
||||
let relativePath = item.webkitRelativePath
|
||||
.split("/")
|
||||
.slice(0, -1)
|
||||
.join("/");
|
||||
async function* traverse(item: Item | Item[], path = "") {
|
||||
if ('isFile' in item && item.isFile === true) {
|
||||
const file = await new Promise(item.file.bind(item));
|
||||
yield { path, file };
|
||||
} else if (item instanceof File) {
|
||||
let relativePath = item.webkitRelativePath
|
||||
.split("/")
|
||||
.slice(0, -1)
|
||||
.join("/");
|
||||
|
||||
if (relativePath.length) {
|
||||
relativePath += "/";
|
||||
}
|
||||
if (relativePath.length) {
|
||||
relativePath += "/";
|
||||
}
|
||||
|
||||
yield { path: relativePath, file: item };
|
||||
} else if ('isFile' in item && item.isDirectory) {
|
||||
const dirReader = item.createReader();
|
||||
yield { path: relativePath, file: item };
|
||||
} else if ('isFile' in item && item.isDirectory) {
|
||||
const dirReader = item.createReader();
|
||||
|
||||
const entries = await new Promise(
|
||||
dirReader.readEntries.bind(dirReader)
|
||||
);
|
||||
const entries = await new Promise(
|
||||
dirReader.readEntries.bind(dirReader)
|
||||
);
|
||||
|
||||
for (const entry of entries) {
|
||||
yield* traverse(
|
||||
for (const entry of entries) {
|
||||
yield* traverse(
|
||||
(entry as FileSystemEntry) as Item,
|
||||
path + item.name + "/"
|
||||
);
|
||||
}
|
||||
} else if ("length" in item && typeof item.length === "number") {
|
||||
for (const i of item) {
|
||||
yield* traverse(i);
|
||||
}
|
||||
} else {
|
||||
throw new Error("Item is not directory or file");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
} else if ("length" in item && typeof item.length === "number") {
|
||||
for (const i of item) {
|
||||
yield* traverse(i);
|
||||
}
|
||||
} else {
|
||||
throw new Error("Item is not directory or file");
|
||||
}
|
||||
}
|
||||
|
||||
const isFileSystemEntry = (
|
||||
a: FileSystemEntry | null
|
||||
): a is FileSystemEntry => a !== null;
|
||||
const isFileSystemEntry = (
|
||||
a: FileSystemEntry | null
|
||||
): a is FileSystemEntry => a !== null;
|
||||
|
||||
const iterator = [...items]
|
||||
.map((item) =>
|
||||
"webkitGetAsEntry" in item ? item.webkitGetAsEntry() : item
|
||||
)
|
||||
.filter(isFileSystemEntry) as FileSystemEntry[];
|
||||
const iterator = [...items]
|
||||
.map((item) =>
|
||||
"webkitGetAsEntry" in item ? item.webkitGetAsEntry() : item
|
||||
)
|
||||
.filter(isFileSystemEntry) as FileSystemEntry[];
|
||||
|
||||
const fileNames = state.files.map((file) => file.Key);
|
||||
const fileNames = state.files.map((file) => file.Key);
|
||||
|
||||
function getUniqueFileName(fileName) {
|
||||
for (let count = 1; fileNames.includes(fileName); count++) {
|
||||
if (count > 1) {
|
||||
fileName = fileName.replace(/\((\d+)\)(.*)/, `(${count})$2`);
|
||||
} else {
|
||||
fileName = fileName.replace(/([^.]*)(.*)/, `$1 (${count})$2`);
|
||||
}
|
||||
}
|
||||
function getUniqueFileName(fileName) {
|
||||
for (let count = 1; fileNames.includes(fileName); count++) {
|
||||
if (count > 1) {
|
||||
fileName = fileName.replace(/\((\d+)\)(.*)/, `(${count})$2`);
|
||||
} else {
|
||||
fileName = fileName.replace(/([^.]*)(.*)/, `$1 (${count})$2`);
|
||||
}
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
for await (const { path, file } of traverse(iterator)) {
|
||||
const directories = path.split("/");
|
||||
const uniqueFirstDirectory = getUniqueFileName(directories[0]);
|
||||
directories[0] = uniqueFirstDirectory;
|
||||
for await (const { path, file } of traverse(iterator)) {
|
||||
const directories = path.split("/");
|
||||
directories[0] = getUniqueFileName(directories[0]);
|
||||
|
||||
const fileName = getUniqueFileName(directories.join("/") + file.name);
|
||||
const fileName = getUniqueFileName(directories.join("/") + file.name);
|
||||
|
||||
const params = {
|
||||
Bucket: state.bucket,
|
||||
Key: state.path + fileName,
|
||||
Body: file,
|
||||
};
|
||||
const params = {
|
||||
Bucket: state.bucket,
|
||||
Key: state.path + fileName,
|
||||
Body: file,
|
||||
};
|
||||
|
||||
const upload = state.s3.upload(
|
||||
{ ...params },
|
||||
{ partSize: 64 * 1024 * 1024 }
|
||||
);
|
||||
const upload = state.s3.upload(
|
||||
{ ...params },
|
||||
{ partSize: 64 * 1024 * 1024 }
|
||||
);
|
||||
|
||||
upload.on("httpUploadProgress", (progress) => {
|
||||
commit("setProgress", {
|
||||
Key: params.Key,
|
||||
progress: Math.round((progress.loaded / progress.total) * 100),
|
||||
});
|
||||
});
|
||||
upload.on("httpUploadProgress", (progress) => {
|
||||
commit("setProgress", {
|
||||
Key: params.Key,
|
||||
progress: Math.round((progress.loaded / progress.total) * 100),
|
||||
});
|
||||
});
|
||||
|
||||
commit("pushUpload", {
|
||||
...params,
|
||||
upload,
|
||||
progress: 0,
|
||||
});
|
||||
commit("pushUpload", {
|
||||
...params,
|
||||
upload,
|
||||
progress: 0,
|
||||
});
|
||||
|
||||
commit("addUploadToChain", async () => {
|
||||
if (
|
||||
state.uploading.findIndex((file) => file.Key === params.Key) === -1
|
||||
) {
|
||||
// upload cancelled or removed
|
||||
return -1;
|
||||
}
|
||||
commit("addUploadToChain", async () => {
|
||||
if (
|
||||
state.uploading.findIndex((file) => file.Key === params.Key) === -1
|
||||
) {
|
||||
// upload cancelled or removed
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
await upload.promise();
|
||||
} catch (e) {
|
||||
// An error is raised if the upload is aborted by the user
|
||||
console.log(e);
|
||||
}
|
||||
try {
|
||||
await upload.promise();
|
||||
} catch (error) {
|
||||
const limitExceededError = 'storage limit exceeded'
|
||||
if (error.message.includes(limitExceededError)) {
|
||||
dispatch('error', `Error: ${limitExceededError}`, {root:true})
|
||||
} else {
|
||||
dispatch('error', error.message, {root:true})
|
||||
}
|
||||
}
|
||||
|
||||
await dispatch("list");
|
||||
await dispatch("list");
|
||||
|
||||
const uploadedFiles = state.files.filter(
|
||||
(file) => file.type === "file"
|
||||
);
|
||||
const uploadedFiles = state.files.filter(
|
||||
(file) => file.type === "file"
|
||||
);
|
||||
|
||||
if (uploadedFiles.length === 1) {
|
||||
if (state.openModalOnFirstUpload === true) {
|
||||
commit("openModal", params.Key);
|
||||
}
|
||||
}
|
||||
if (uploadedFiles.length === 1) {
|
||||
if (state.openModalOnFirstUpload === true) {
|
||||
commit("openModal", params.Key);
|
||||
}
|
||||
}
|
||||
|
||||
commit("finishUpload", params.Key);
|
||||
});
|
||||
}
|
||||
commit("finishUpload", params.Key);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
async createFolder({ state, dispatch }, name) {
|
||||
|
Loading…
Reference in New Issue
Block a user