new media job support

This commit is contained in:
2023-09-01 12:22:25 +10:00
parent fcf5400f71
commit 41ae64a8c9
8 changed files with 362 additions and 638 deletions

View File

@@ -104,12 +104,25 @@ class MediaWorkerJob implements ShouldQueue
}
// Check if file already exists
if (Storage::disk($storage)->exists($data['name']) === true) {
if (array_key_exists('replace', $data) === false || isTrue($data['replace']) === false) {
$exists = Storage::disk($storage)->exists($data['name']);
if ($exists === true) {
if (array_key_exists('noreplace', $data) === true && isTrue($data['noreplace']) === true) {
$this->throwMediaJobFailure('file already exists on server');
}
}
if($exists === true) {
$pathInfo = pathinfo($data['name']);
$basename = $pathInfo['filename'];
$extension = $pathInfo['extension'];
$index = 0;
do {
$index++;
$data['name'] = $basename . '-' . $index . '.' . $extension;
} while (Storage::disk($storage)->exists($data['name']) === true);
}
if ($media === null) {
$newMedia = true;
$media = new Media([

View File

@@ -5,6 +5,7 @@ import {
defineComponent,
shallowReactive,
VNodeProps,
watch,
} from "vue";
export interface DialogInstance {
@@ -52,10 +53,10 @@ export function closeDialog(data?: unknown) {
}
const lastDialog = dialogRefs.pop();
if (data === undefined && lastDialog.comp) {
if (data === undefined && lastDialog.comp && lastDialog.comp.returnValue) {
data = lastDialog.comp.returnValue();
}
if (lastDialog) {
if (lastDialog && data !== undefined) {
lastDialog.resolve(data);
}
}
@@ -112,7 +113,9 @@ export function openDialog<C extends Component>(
});
window.setTimeout(() => {
const autofocusElement = document.querySelector("[autofocus]");
const autofocusElement = document.querySelector(
"[autofocus]",
) as HTMLInputElement;
if (autofocusElement) {
autofocusElement.focus();
}

View File

@@ -13,7 +13,17 @@
fill="currentColor" />
</svg>
<img
class="max-w-48 max-h-48 w-full h-full"
:class="[
'max-w-48',
'max-h-48',
'p-2',
'w-full',
'h-full',
{
'border-red-6': feedbackInvalid,
'border-2': feedbackInvalid,
},
]"
@load="handleImageLoaded"
@error="handleImageError"
:style="{ display: image == '' ? 'none' : 'block' }"
@@ -29,6 +39,11 @@
fill="currentColor" />
</svg>
<div class="text-center">
<p
v-if="feedbackInvalid"
class="px-2 -mt-2 pb-2 text-xs text-red-6">
{{ feedbackInvalid }}
</p>
<button
type="button"
class="font-medium px-6 py-1.5 rounded-md hover:shadow-md transition text-sm bg-sky-600 hover:bg-sky-500 text-white cursor-pointer"
@@ -55,7 +70,6 @@ import { toTitleCase } from "../helpers/string";
import { mediaGetThumbnail } from "../helpers/media";
import { openDialog } from "./SMDialog";
import SMDialogMedia from "./dialogs/SMDialogMedia.vue";
// import SMDialogUpload from "./dialogs/SMDialogUpload.vue";
import { Media } from "../helpers/api.types";
import SMLoading from "./SMLoading.vue";

View File

@@ -143,16 +143,10 @@
{ 'mb-6': showMediaName(item) },
]"
:style="{
backgroundImage:
item.status === 'OK'
? `url('${mediaGetThumbnail(
item,
)}')`
: 'initial',
backgroundColor:
item.status === 'OK'
? 'initial'
: 'rgba(220,220,220,1)',
backgroundImage: `url('${mediaGetThumbnail(
item,
)}')`,
backgroundColor: 'initial',
}">
<div
v-if="showMediaName(item)"
@@ -160,38 +154,11 @@
{{ item.title }}
</div>
<SMLoading
v-if="
item.status !== 'OK' &&
item.status.startsWith(
'Error',
) === false
"
v-if="false"
small
class="bg-white bg-op-90 w-full h-full"
>{{
item.status.split(":")
.length > 1
? item.status
.split(":")[1]
.trim()
: item.status
}}</SMLoading
>NONE</SMLoading
>
<div
v-if="
item.status.startsWith(
'Error',
) === true
">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-10 w-10"
viewBox="0 0 24 24">
<path
d="M13,13H11V7H13M13,17H11V15H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"
fill="rgba(220,38,38,1)" />
</svg>
</div>
</div>
</li>
</ul>
@@ -430,16 +397,9 @@
backgroundImage: `url('${mediaGetThumbnail(
item,
)}')`,
backgroundColor:
item.status === 'OK'
? 'initial'
: 'rgba(220,220,220,1)',
}">
<SMLoading
v-if="
item.status !== 'OK' &&
item.status.startsWith('Error') === false
"
v-if="false"
small
class="bg-white bg-op-90 w-full h-full" />
<div
@@ -996,11 +956,7 @@ const updateFiles = async () => {
let remaining = false;
mediaItems.value.forEach((item, index) => {
if (
isUUID(item.id) &&
item.status != "OK" &&
item.status.startsWith("Error") == false
) {
if (isUUID(item.id)) {
remaining = true;
api.get({
@@ -1056,9 +1012,9 @@ const updateFiles = async () => {
}
});
mediaItems.value = mediaItems.value.filter(
(item) => item.status.startsWith("Error") === false,
);
// mediaItems.value = mediaItems.value.filter(
// (item) => item.status.startsWith("Error") === false,
// );
if (remaining) {
updateFilesNonce.value = setTimeout(() => {
@@ -1106,7 +1062,6 @@ const handleLoad = async () => {
let params = {
page: page.value,
limit: perPage.value,
status: "!Error",
filter: "",
};
@@ -1202,8 +1157,8 @@ watch(mediaItems, () => {
const computedSelectDisabled = computed(() => {
if (selectedTab.value == "tab-browser") {
return (
selected.value.length == 0 ||
selected.value.findIndex((item) => item.status !== "OK") > -1
selected.value.length == 0 // ||
// selected.value.findIndex((item) => item.status !== "OK") > -1
);
} else if (selectedTab.value == "tab-url") {
return (

View File

@@ -0,0 +1,45 @@
<template>
<div
class="fixed top-0 left-0 w-full h-full bg-black bg-op-20 backdrop-blur"></div>
<div
class="fixed top-0 left-0 right-0 bottom-0 flex-justify-center flex-items-center flex">
<div
class="flex flex-col m-4 border-1 bg-white rounded-xl text-gray-5 px-4 md:px-12 py-4 md:py-8 max-w-200 w-full overflow-hidden">
<h2 class="mb-2">{{ props.title }}</h2>
<div
v-for="(row, index) in props.rows"
class="flex flex-col text-xs my-4"
:key="index">
<div class="w-full bg-gray-3 h-3 mb-2 rounded-2">
<div
class="bg-sky-600 h-3 rounded-2"
:style="{
width: `${props.progress[index]}%`,
}"></div>
</div>
<p class="m-0"></p>
{{ row }}
</div>
</div>
</div>
</template>
<script setup lang="ts">
const props = defineProps({
title: {
type: String,
default: "",
required: false,
},
rows: {
type: Array,
default: () => [],
required: false,
},
progress: {
type: Array,
default: () => [],
required: false,
},
});
</script>

View File

@@ -1,373 +0,0 @@
<template>
<div
class="fixed top-0 left-0 w-full h-full bg-black bg-op-20 backdrop-blur"></div>
<div
class="fixed top-0 left-0 right-0 bottom-0 flex-justify-center flex-items-center flex">
<div
class="flex flex-col m-4 border-1 bg-white rounded-xl text-gray-5 px-4 md:px-12 py-4 md:py-8 max-w-200 w-full overflow-hidden"
v-if="uploadFileCount > 0">
<h2 class="mb-2">Upload Media</h2>
<div class="flex flex-col text-xs pb-2 my-4">
<div class="w-full bg-gray-3 h-3 mb-2 rounded-2">
<div
class="bg-sky-600 h-3 rounded-2"
:style="{
width: `${progressUploadPercent}%`,
}"></div>
</div>
<p class="m-0">
{{ progressUploadStatus }}
</p>
</div>
<div class="flex flex-col text-xs my-2">
<div class="w-full bg-gray-3 h-3 mb-2 rounded-2">
<div
class="bg-sky-600 h-3 rounded-2"
:style="{
width: `${
(100 / uploadFileCount) * mediaItems.length
}%`,
}"></div>
</div>
<p class="m-0">
{{ progressFileStatus }}
</p>
</div>
</div>
<input
id="file"
ref="refUploadInput"
type="file"
style="display: none"
:accept="computedAccepts"
@change="handleChangeSelectFile" />
</div>
</template>
<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, Ref } from "vue";
import { closeDialog } from "../SMDialog";
import { api } from "../../helpers/api";
import { ApiInfo, Media, MediaResponse } from "../../helpers/api.types";
import { convertFileNameToTitle } from "../../helpers/utils";
import { isUUID } from "../../helpers/uuid";
import { useToastStore } from "../../store/ToastStore";
import { bytesReadable } from "../../helpers/types";
const props = defineProps({
mime: {
type: String,
default: "image/*",
required: false,
},
accepts: {
type: String,
default: "image/*",
required: false,
},
multiple: {
type: Boolean,
default: false,
required: false,
},
});
/**
* Reference to the File Upload Input element.
*/
const refUploadInput = ref<HTMLInputElement | null>(null);
/**
* Max upload size
*/
const max_upload_size = ref("");
/**
* List of current media items.
*/
const mediaItems: Ref<Media[]> = ref([]);
const processingItems: Ref<Media[]> = ref([]);
const uploadFileCount = ref(0);
const uploadFileNum = ref(0);
const uploadFileName = ref("");
const uploadFileProgress = ref(0);
const processFileName = ref("");
const processFileStatus = ref("");
const progressUploadPercent = computed(() => {
if (uploadFileCount.value <= uploadFileNum.value) {
return 100;
}
return (
(100 / uploadFileCount.value) * uploadFileNum.value +
(100 / uploadFileCount.value / 100) * uploadFileProgress.value
);
});
const progressUploadStatus = computed(() => {
if (uploadFileCount.value <= uploadFileNum.value) {
return `Uploaded ${uploadFileName.value}`;
}
return `Uploading ${uploadFileName.value} - ${uploadFileProgress.value}%`;
});
const progressFileStatus = computed(() => {
if (processFileName.value.length > 0) {
return (
processFileName.value +
" - " +
(processFileStatus.value.split(":").length > 1
? processFileStatus.value.split(":")[1].trim()
: processFileStatus.value)
);
}
return "Waiting for upload to complete";
});
/**
* Returns the file types accepted.
*/
const computedAccepts = computed(() => {
if (props.accepts.length > 0) {
return props.accepts;
}
if (props.mime.endsWith("/")) {
return `${props.mime}*`;
}
return props.mime;
});
const handleChangeSelectFile = async () => {
if (refUploadInput.value != null && refUploadInput.value.files != null) {
const fileList = Array.from(refUploadInput.value.files);
uploadFileCount.value = fileList.length;
for (
uploadFileNum.value = 0;
uploadFileNum.value < uploadFileCount.value;
uploadFileNum.value++
) {
const file = fileList[uploadFileNum.value];
const chunkSize = 50 * 1024 * 1024;
let chunk = 0;
let chunkCount = 1;
let resultMedia = null;
if (file.size > chunkSize) {
chunkCount = Math.ceil(file.size / chunkSize);
}
uploadFileName.value = file.name;
uploadFileProgress.value = 0;
while (chunk < chunkCount) {
let submitFormData = new FormData();
if (chunkCount == 1) {
submitFormData.append("file", file);
} else {
const offset = chunk * chunkSize;
const fileChunk = file.slice(offset, offset + chunkSize);
if (resultMedia !== null) {
submitFormData.append("id", resultMedia.id);
}
submitFormData.append("file", fileChunk);
submitFormData.append("chunk", (chunk + 1).toString());
submitFormData.append("chunk_count", chunkCount.toString());
}
submitFormData.append("name", file.name);
submitFormData.append(
"title",
convertFileNameToTitle(file.name),
);
submitFormData.append("description", "");
try {
let result = await api.post({
url: "/media",
body: submitFormData,
headers: {
"Content-Type": "multipart/form-data",
},
progress: (progressEvent) => {
uploadFileProgress.value = Math.floor(
((chunk * chunkSize + progressEvent.loaded) /
file.size) *
100,
);
},
});
if (result.data) {
resultMedia = (result.data as MediaResponse).medium;
}
} catch (error) {
let errorString = "A server error occurred";
if (error.status == 413) {
errorString = `The file is larger than ${max_upload_size.value}`;
}
useToastStore().addToast({
title: "Upload failed",
type: "danger",
content: errorString,
});
resultMedia = null;
break;
}
chunk++;
}
if (resultMedia != null) {
processingItems.value.push(resultMedia);
}
processFiles();
}
} else {
closeDialog(false);
}
};
const processFilesNonce = ref(null);
const processFiles = async () => {
if (processFilesNonce.value == null) {
let remaining = false;
for (let i = 0; i < processingItems.value.length; i++) {
let item = processingItems.value[i];
let breakLoop = true;
if (
isUUID(item.id) &&
item.status != "OK" &&
item.status.startsWith("Error") == false
) {
remaining = true;
api.get({
url: "/media/{id}",
params: {
id: item.id,
},
})
.then((updateResult) => {
if (updateResult.data) {
let removeItem = false;
const updateData =
updateResult.data as MediaResponse;
if (updateData.medium.status == "OK") {
mediaItems.value.push(updateData.medium);
removeItem = true;
} else if (
updateData.medium.status.startsWith("Error") ===
true
) {
removeItem = true;
useToastStore().addToast({
title: "Upload failed",
type: "danger",
content: updateData.medium.status,
});
} else {
processFileName.value = updateData.medium.name;
processFileStatus.value =
updateData.medium.status;
breakLoop = true;
}
if (removeItem) {
processingItems.value =
processingItems.value.filter(
(mediaItem) =>
mediaItem.id !==
updateData.medium.id,
);
}
} else {
throw "error";
}
})
.catch(() => {
/* error retreiving data */
processingItems.value = processingItems.value.filter(
(mediaItem) => mediaItem.id !== item.id,
);
});
}
if (!breakLoop) {
break;
}
}
if (remaining) {
processFilesNonce.value = setTimeout(() => {
processFilesNonce.value = null;
processFiles();
}, 500);
} else {
processFilesNonce.value = null;
}
}
if (processFilesNonce.value == null) {
if (mediaItems.value.length == 0) {
closeDialog(false);
}
if (props.multiple == false) {
closeDialog(mediaItems.value[0]);
}
closeDialog(mediaItems.value);
}
};
// Get max upload size
api.get({
url: "",
})
.then((result) => {
if (result.data) {
const data = result.data as ApiInfo;
max_upload_size.value = bytesReadable(data.max_upload_size);
}
})
.catch(() => {
/* empty */
});
const handleFocus = () => {
window.setTimeout(() => {
if (uploadFileCount.value == 0) {
closeDialog(false);
}
}, 20);
};
onMounted(() => {
window.addEventListener("focus", handleFocus);
if (refUploadInput.value != null) {
refUploadInput.value.click();
}
});
onUnmounted(() => {
window.removeEventListener("focus", handleFocus);
});
</script>

View File

@@ -19,7 +19,7 @@ interface ApiCallbackData {
type ApiProgressCallback = (progress: ApiProgressData) => void;
type ApiResultCallback = (data: ApiCallbackData) => void;
interface ApiOptions {
export interface ApiOptions {
url: string;
params?: object;
method?: string;

View File

@@ -5,7 +5,7 @@
:title="pageHeading"
:back-link="{ name: 'dashboard-media-list' }"
back-title="Back to Media" />
<SMLoading v-if="form.loading()">{{ progressText }}</SMLoading>
<SMLoading v-if="form.loading()" />
<div v-else class="max-w-4xl mx-auto px-4 mt-8">
<SMForm
:model-value="form"
@@ -77,9 +77,9 @@
</template>
<script setup lang="ts">
import { computed, reactive, ref, watch } from "vue";
import { computed, onMounted, reactive, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { api } from "../../helpers/api";
import { ApiOptions, api } from "../../helpers/api";
import { Form, FormControl } from "../../helpers/form";
import { bytesReadable } from "../../helpers/types";
import { And, Required } from "../../helpers/validate";
@@ -88,7 +88,7 @@ import {
MediaJobResponse,
MediaResponse,
} from "../../helpers/api.types";
import { openDialog } from "../../components/SMDialog";
import { closeDialog, openDialog } from "../../components/SMDialog";
import DialogConfirm from "../../components/dialogs/SMDialogConfirm.vue";
import SMForm from "../../components/SMForm.vue";
import SMInput from "../../components/SMInput.vue";
@@ -100,6 +100,7 @@ import SMSelectFile from "../../components/SMSelectFile.vue";
import { userHasPermission } from "../../helpers/utils";
import SMImageGallery from "../../components/SMImageGallery.vue";
import { toTitleCase } from "../../helpers/string";
import SMDialogProgress from "../../components/dialogs/SMDialogProgress.vue";
const route = useRoute();
const router = useRouter();
@@ -111,13 +112,12 @@ const pageHeading = route.params.id
? "Edit Multiple Media"
: "Edit Media"
: "Upload Media";
const progressText = ref("");
const galleryItems = ref([]);
const form = reactive(
Form({
file: FormControl("", And([Required()])),
title: FormControl(),
title: FormControl("", Required()),
description: FormControl(),
permission: FormControl(),
}),
@@ -193,204 +193,271 @@ const handleLoad = async () => {
}
};
const handleSubmit = async (enableFormCallBack) => {
let processing = false;
form.loading(true);
try {
if (editMultiple === false) {
let submitData = new FormData();
// add file if there is one
if (form.controls.file.value instanceof File) {
submitData.append("file", form.controls.file.value);
}
submitData.append("title", form.controls.title.value as string);
submitData.append(
"permission",
form.controls.permission.value as string,
);
submitData.append(
"description",
form.controls.description.value as string,
);
let result = null;
if (route.params.id) {
result = await api.put({
url: "/media/{id}",
params: {
id: route.params.id,
},
body: submitData,
headers: {
"Content-Type": "multipart/form-data",
},
progress: (progressEvent) =>
(progressText.value = `Uploading File: ${Math.floor(
(progressEvent.loaded / progressEvent.total) * 100,
)}%`),
});
} else {
result = await api.chunk({
url: "/media",
body: submitData,
headers: {
"Content-Type": "multipart/form-data",
},
chunk: "file",
progress: (progressEvent) =>
(progressText.value = `Uploading File: ${Math.floor(
(progressEvent.loaded / progressEvent.total) * 100,
)}%`),
});
}
const mediaJobId = result.data.media_job.id;
const mediaJobUpdate = async () => {
api.get({
url: "/media/job/{id}",
params: {
id: mediaJobId,
},
})
.then((result) => {
const data = result.data as MediaJobResponse;
// queued
// complete
// waiting
// processing - txt - prog
// invalid - err
// failed - err
if (data.media_job.status != "complete") {
if (data.media_job.status == "queued") {
progressText.value = "Queued for processing";
} else if (data.media_job.status == "processing") {
if (data.media_job.progress != -1) {
progressText.value = `${toTitleCase(
data.media_job.status_text,
)} ${data.media_job.progress}%`;
} else {
progressText.value = `${toTitleCase(
data.media_job.status_text,
)}`;
}
} else if (
data.media_job.status == "invalid" ||
data.media_job.status == "failed"
) {
useToastStore().addToast({
title: "Error Processing Media",
content: toTitleCase(
data.media_job.status_text,
),
type: "danger",
});
progressText.value = "";
form.loading(false);
return;
}
window.setTimeout(mediaJobUpdate, 500);
} else {
useToastStore().addToast({
title: route.params.id
? "Media Updated"
: "Media Created",
content: route.params.id
? "The media item has been updated."
: "The media item been created.",
type: "success",
});
progressText.value = "";
form.loading(false);
return;
}
})
.catch((e) => {
console.log("error", e);
});
};
processing = true;
mediaJobUpdate();
} else {
let successCount = 0;
let errorCount = 0;
(route.params.id as string).split(",").forEach(async (id) => {
try {
let data = {
title: form.controls.title.value,
content: form.controls.content.value,
};
await api.put({
url: "/media/{id}",
params: {
id: id,
},
body: data,
});
successCount++;
} catch (err) {
errorCount++;
}
});
if (errorCount === 0) {
useToastStore().addToast({
title: "Media Updated",
content: `The selected media have been updated.`,
type: "success",
});
} else if (successCount === 0) {
useToastStore().addToast({
title: "Error Updating Media",
content: "An unexpected server error occurred.",
type: "danger",
});
} else {
useToastStore().addToast({
title: "Some Media Updated",
content: `Only ${successCount} media items where updated. ${errorCount} could not because of an unexpected error.`,
type: "warning",
});
}
const dialogDataSetStatus = (dialogData, status, progress, add) => {
if (add) {
dialogData.rows.push(status);
dialogData.progress.push(progress);
} else {
const index = dialogData.rows.length - 1;
if (status.length > 0) {
dialogData.rows[index] = status;
}
// const urlParams = new URLSearchParams(window.location.search);
// const returnUrl = urlParams.get("return");
// if (returnUrl) {
// router.push(decodeURIComponent(returnUrl));
// } else {
// router.push({ name: "dashboard-media-list" });
// }
} catch (error) {
processing = false;
useToastStore().addToast({
title: "Server error",
content: "An error occurred saving the media.",
type: "danger",
});
enableFormCallBack();
} finally {
if (processing == false) {
progressText.value = "";
form.loading(false);
if (progress > -1) {
dialogData.progress[index] = progress;
}
}
};
const handleSubmit = async (enableFormCallBack) => {
if (editMultiple === false) {
let dialogData = ref({
title: "Upload Media",
rows: [],
progress: [],
});
openDialog(SMDialogProgress, dialogData.value);
let submitData = new FormData();
// add file if there is one
if (form.controls.file.value instanceof File) {
submitData.append("file", form.controls.file.value);
dialogDataSetStatus(
dialogData.value,
`Uploading File: ${form.controls.file.value.name}`,
0,
true,
);
}
submitData.append("title", form.controls.title.value as string);
submitData.append(
"permission",
form.controls.permission.value as string,
);
submitData.append(
"description",
form.controls.description.value as string,
);
let apiRequest: ApiOptions = {
url: "/media",
body: submitData,
headers: {
"Content-Type": "multipart/form-data",
},
progress: (progressEvent) => {
dialogDataSetStatus(
dialogData.value,
"",
Math.floor(
(progressEvent.loaded / progressEvent.total) * 100,
),
false,
);
},
};
if (submitData.has("file") == true) {
apiRequest.chunk = "file";
}
if (route.params.id) {
apiRequest.url = "/media/{id}";
apiRequest.method = "PUT";
apiRequest.params = {
id: route.params.id,
};
}
api.chunk(apiRequest)
.then((result) => {
if (submitData.has("file") == true) {
dialogDataSetStatus(
dialogData.value,
"Upload Complete",
100,
false,
);
}
dialogDataSetStatus(dialogData.value, "Processing", 0, true);
const mediaJobId = (result.data as MediaJobResponse).media_job
.id;
const mediaJobUpdate = async () => {
api.get({
url: "/media/job/{id}",
params: {
id: mediaJobId,
},
})
.then((result) => {
const data = result.data as MediaJobResponse;
const statusText = toTitleCase(
data.media_job.status_text,
);
if (data.media_job.status != "complete") {
if (data.media_job.status == "queued") {
dialogDataSetStatus(
dialogData.value,
"Queued for processing",
0,
false,
);
} else if (
data.media_job.status == "processing"
) {
dialogDataSetStatus(
dialogData.value,
statusText,
data.media_job.progress,
false,
);
} else if (
data.media_job.status == "invalid" ||
data.media_job.status == "failed"
) {
useToastStore().addToast({
title: "Error Processing Media",
content: statusText,
type: "danger",
});
form.controls.file.setValidationResult(
false,
statusText,
);
closeDialog();
enableFormCallBack();
return;
}
window.setTimeout(mediaJobUpdate, 500);
} else {
useToastStore().addToast({
title: route.params.id
? "Media Updated"
: "Media Created",
content: route.params.id
? "The media item has been updated."
: "The media item been created.",
type: "success",
});
closeDialog();
enableFormCallBack();
// return to dashboard
const urlParams = new URLSearchParams(
window.location.search,
);
const returnUrl = urlParams.get("return");
if (returnUrl) {
router.push(decodeURIComponent(returnUrl));
} else {
router.push({
name: "dashboard-media-list",
});
}
return;
}
})
.catch(() => {
useToastStore().addToast({
title: "Error Uploading Media",
content: "A server error occurred.",
type: "danger",
});
closeDialog();
enableFormCallBack();
});
};
mediaJobUpdate();
})
.catch((error) => {
if (error.status == 413) {
form.controls.file.setValidationResult(
false,
"The file size is too large",
);
useToastStore().addToast({
title: "Error Uploading Media",
content: "The file size is too large.",
type: "danger",
});
} else {
useToastStore().addToast({
title: "Error Uploading Media",
content: "A server error occurred.",
type: "danger",
});
}
closeDialog();
enableFormCallBack();
});
} else {
let successCount = 0;
let errorCount = 0;
(route.params.id as string).split(",").forEach(async (id) => {
try {
let data = {
title: form.controls.title.value,
content: form.controls.content.value,
};
await api.put({
url: "/media/{id}",
params: {
id: id,
},
body: data,
});
successCount++;
} catch (err) {
errorCount++;
}
});
if (errorCount === 0) {
useToastStore().addToast({
title: "Media Updated",
content: `The selected media have been updated.`,
type: "success",
});
} else if (successCount === 0) {
useToastStore().addToast({
title: "Error Updating Media",
content: "An unexpected server error occurred.",
type: "danger",
});
} else {
useToastStore().addToast({
title: "Some Media Updated",
content: `Only ${successCount} media items where updated. ${errorCount} could not because of an unexpected error.`,
type: "warning",
});
}
}
// const urlParams = new URLSearchParams(window.location.search);
// const returnUrl = urlParams.get("return");
// if (returnUrl) {
// router.push(decodeURIComponent(returnUrl));
// } else {
// router.push({ name: "dashboard-media-list" });
// }
};
const handleFailValidation = () => {
useToastStore().addToast({
title: "Save Error",