From 06e8713fa55065d38f02499d3e8d39fc86926cab Mon Sep 17 00:00:00 2001 From: Ramires Viana <59319979+ramiresviana@users.noreply.github.com> Date: Fri, 1 Aug 2025 13:44:38 -0300 Subject: [PATCH 001/202] fix: show file upload errors --- frontend/src/api/tus.ts | 14 ++++++++++++-- frontend/src/components/Sidebar.vue | 9 ++------- frontend/src/views/Files.vue | 5 ++++- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/frontend/src/api/tus.ts b/frontend/src/api/tus.ts index fbfef4da..8bffa6a5 100644 --- a/frontend/src/api/tus.ts +++ b/frontend/src/api/tus.ts @@ -55,12 +55,22 @@ export async function upload( return true; }, - onError: function (error) { + onError: function (error: Error | tus.DetailedError) { if (CURRENT_UPLOAD_LIST[filePath].interval) { clearInterval(CURRENT_UPLOAD_LIST[filePath].interval); } delete CURRENT_UPLOAD_LIST[filePath]; - reject(new Error(`Upload failed: ${error.message}`)); + + const message = + error instanceof tus.DetailedError + ? error.originalResponse === null + ? "000 No connection" + : error.originalResponse.getBody() + : "Upload failed"; + + console.error(error); + + reject(new Error(message)); }, onProgress: function (bytesUploaded) { const fileData = CURRENT_UPLOAD_LIST[filePath]; diff --git a/frontend/src/components/Sidebar.vue b/frontend/src/components/Sidebar.vue index 74fb45ad..5bbf8847 100644 --- a/frontend/src/components/Sidebar.vue +++ b/frontend/src/components/Sidebar.vue @@ -132,7 +132,6 @@ import { import { files as api } from "@/api"; import ProgressBar from "@/components/ProgressBar.vue"; import prettyBytes from "pretty-bytes"; -import { StatusError } from "@/api/utils.js"; const USAGE_DEFAULT = { used: "0 B", total: "0 B", usedPercentage: 0 }; @@ -181,13 +180,9 @@ export default { total: prettyBytes(usage.total, { binary: true }), usedPercentage: Math.round((usage.used / usage.total) * 100), }; - } catch (error) { - if (error instanceof StatusError && error.is_canceled) { - return; - } - this.$showError(error); + } finally { + return Object.assign(this.usage, usageStats); } - return Object.assign(this.usage, usageStats); }, toRoot() { this.$router.push({ path: "/files" }); diff --git a/frontend/src/views/Files.vue b/frontend/src/views/Files.vue index 805f4027..950cb86d 100644 --- a/frontend/src/views/Files.vue +++ b/frontend/src/views/Files.vue @@ -26,6 +26,7 @@ import { computed, defineAsyncComponent, + inject, onBeforeUnmount, onMounted, onUnmounted, @@ -50,6 +51,8 @@ import { name } from "../utils/constants"; const Editor = defineAsyncComponent(() => import("@/views/files/Editor.vue")); const Preview = defineAsyncComponent(() => import("@/views/files/Preview.vue")); +const $showError = inject("$showError")!; + const layoutStore = useLayoutStore(); const fileStore = useFileStore(); const uploadStore = useUploadStore(); @@ -109,7 +112,7 @@ watch(reload, (newValue) => { newValue && fetchData(); }); watch(uploadError, (newValue) => { - newValue && layoutStore.showError(); + newValue && $showError(newValue); }); // Define functions From 6d620c00a19c33e5cac10bfb2441846f30d0bade Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Mon, 4 Aug 2025 08:11:40 +0200 Subject: [PATCH 002/202] docs: reword configuration intro --- www/docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/docs/configuration.md b/www/docs/configuration.md index c8107b30..77f341a4 100644 --- a/www/docs/configuration.md +++ b/www/docs/configuration.md @@ -1,6 +1,6 @@ # Configuration -Most of the configuration can be understood through our Command Line Interface documentation. Although there are some specific topics that we want to cover on this section. +Most of the configuration can be understood through the command line interface documentation. To access it, you need to install File Browser and run `filebrowser --help`. In this page, we cover some specific, more complex, topics. ## Custom Branding From c14cf86f8304e01d804e01a7eef5ea093627ef37 Mon Sep 17 00:00:00 2001 From: Ramires Viana <59319979+ramiresviana@users.noreply.github.com> Date: Wed, 6 Aug 2025 11:47:48 -0300 Subject: [PATCH 003/202] refactor: upload progress calculation (#5350) --- frontend/src/api/search.ts | 2 +- frontend/src/api/tus.ts | 112 +----- .../src/components/prompts/UploadFiles.vue | 204 +++++++---- frontend/src/stores/upload.ts | 334 ++++++++---------- frontend/src/types/file.d.ts | 1 + frontend/src/types/upload.d.ts | 43 +-- frontend/src/utils/upload.ts | 11 +- frontend/src/views/Files.vue | 9 - frontend/src/views/Layout.vue | 14 +- frontend/tsconfig.tsc.json | 3 +- 10 files changed, 321 insertions(+), 412 deletions(-) diff --git a/frontend/src/api/search.ts b/frontend/src/api/search.ts index 871f0aed..6fa02d06 100644 --- a/frontend/src/api/search.ts +++ b/frontend/src/api/search.ts @@ -13,7 +13,7 @@ export default async function search(base: string, query: string) { let data = await res.json(); - data = data.map((item: UploadItem) => { + data = data.map((item: ResourceItem & { dir: boolean }) => { item.url = `/files${base}` + url.encodePath(item.path); if (item.dir) { diff --git a/frontend/src/api/tus.ts b/frontend/src/api/tus.ts index 8bffa6a5..d6601166 100644 --- a/frontend/src/api/tus.ts +++ b/frontend/src/api/tus.ts @@ -1,17 +1,11 @@ import * as tus from "tus-js-client"; import { baseURL, tusEndpoint, tusSettings, origin } from "@/utils/constants"; import { useAuthStore } from "@/stores/auth"; -import { useUploadStore } from "@/stores/upload"; import { removePrefix } from "@/api/utils"; const RETRY_BASE_DELAY = 1000; const RETRY_MAX_DELAY = 20000; -const SPEED_UPDATE_INTERVAL = 1000; -const ALPHA = 0.2; -const ONE_MINUS_ALPHA = 1 - ALPHA; -const RECENT_SPEEDS_LIMIT = 5; -const MB_DIVISOR = 1024 * 1024; -const CURRENT_UPLOAD_LIST: CurrentUploadList = {}; +const CURRENT_UPLOAD_LIST: { [key: string]: tus.Upload } = {}; export async function upload( filePath: string, @@ -56,11 +50,12 @@ export async function upload( return true; }, onError: function (error: Error | tus.DetailedError) { - if (CURRENT_UPLOAD_LIST[filePath].interval) { - clearInterval(CURRENT_UPLOAD_LIST[filePath].interval); - } delete CURRENT_UPLOAD_LIST[filePath]; + if (error.message === "Upload aborted") { + return reject(error); + } + const message = error instanceof tus.DetailedError ? error.originalResponse === null @@ -73,40 +68,16 @@ export async function upload( reject(new Error(message)); }, onProgress: function (bytesUploaded) { - const fileData = CURRENT_UPLOAD_LIST[filePath]; - fileData.currentBytesUploaded = bytesUploaded; - - if (!fileData.hasStarted) { - fileData.hasStarted = true; - fileData.lastProgressTimestamp = Date.now(); - - fileData.interval = window.setInterval(() => { - calcProgress(filePath); - }, SPEED_UPDATE_INTERVAL); - } if (typeof onupload === "function") { onupload({ loaded: bytesUploaded }); } }, onSuccess: function () { - if (CURRENT_UPLOAD_LIST[filePath].interval) { - clearInterval(CURRENT_UPLOAD_LIST[filePath].interval); - } delete CURRENT_UPLOAD_LIST[filePath]; resolve(); }, }); - CURRENT_UPLOAD_LIST[filePath] = { - upload: upload, - recentSpeeds: [], - initialBytesUploaded: 0, - currentBytesUploaded: 0, - currentAverageSpeed: 0, - lastProgressTimestamp: null, - sumOfRecentSpeeds: 0, - hasStarted: false, - interval: undefined, - }; + CURRENT_UPLOAD_LIST[filePath] = upload; upload.start(); }); } @@ -138,76 +109,11 @@ function isTusSupported() { return tus.isSupported === true; } -function computeETA(speed?: number) { - const state = useUploadStore(); - if (state.speedMbyte === 0) { - return Infinity; - } - const totalSize = state.sizes.reduce( - (acc: number, size: number) => acc + size, - 0 - ); - const uploadedSize = state.progress.reduce((a, b) => a + b, 0); - const remainingSize = totalSize - uploadedSize; - const speedBytesPerSecond = (speed ?? state.speedMbyte) * 1024 * 1024; - return remainingSize / speedBytesPerSecond; -} - -function computeGlobalSpeedAndETA() { - let totalSpeed = 0; - let totalCount = 0; - - for (const filePath in CURRENT_UPLOAD_LIST) { - totalSpeed += CURRENT_UPLOAD_LIST[filePath].currentAverageSpeed; - totalCount++; - } - - if (totalCount === 0) return { speed: 0, eta: Infinity }; - - const averageSpeed = totalSpeed / totalCount; - const averageETA = computeETA(averageSpeed); - - return { speed: averageSpeed, eta: averageETA }; -} - -function calcProgress(filePath: string) { - const uploadStore = useUploadStore(); - const fileData = CURRENT_UPLOAD_LIST[filePath]; - - const elapsedTime = - (Date.now() - (fileData.lastProgressTimestamp ?? 0)) / 1000; - const bytesSinceLastUpdate = - fileData.currentBytesUploaded - fileData.initialBytesUploaded; - const currentSpeed = bytesSinceLastUpdate / MB_DIVISOR / elapsedTime; - - if (fileData.recentSpeeds.length >= RECENT_SPEEDS_LIMIT) { - fileData.sumOfRecentSpeeds -= fileData.recentSpeeds.shift() ?? 0; - } - - fileData.recentSpeeds.push(currentSpeed); - fileData.sumOfRecentSpeeds += currentSpeed; - - const avgRecentSpeed = - fileData.sumOfRecentSpeeds / fileData.recentSpeeds.length; - fileData.currentAverageSpeed = - ALPHA * avgRecentSpeed + ONE_MINUS_ALPHA * fileData.currentAverageSpeed; - - const { speed, eta } = computeGlobalSpeedAndETA(); - uploadStore.setUploadSpeed(speed); - uploadStore.setETA(eta); - - fileData.initialBytesUploaded = fileData.currentBytesUploaded; - fileData.lastProgressTimestamp = Date.now(); -} - export function abortAllUploads() { for (const filePath in CURRENT_UPLOAD_LIST) { - if (CURRENT_UPLOAD_LIST[filePath].interval) { - clearInterval(CURRENT_UPLOAD_LIST[filePath].interval); - } - if (CURRENT_UPLOAD_LIST[filePath].upload) { - CURRENT_UPLOAD_LIST[filePath].upload.abort(true); - CURRENT_UPLOAD_LIST[filePath].upload.options!.onError!( + if (CURRENT_UPLOAD_LIST[filePath]) { + CURRENT_UPLOAD_LIST[filePath].abort(true); + CURRENT_UPLOAD_LIST[filePath].options!.onError!( new Error("Upload aborted") ); } diff --git a/frontend/src/components/prompts/UploadFiles.vue b/frontend/src/components/prompts/UploadFiles.vue index eb599aa8..883fffe3 100644 --- a/frontend/src/components/prompts/UploadFiles.vue +++ b/frontend/src/components/prompts/UploadFiles.vue @@ -1,20 +1,25 @@ - diff --git a/frontend/src/stores/upload.ts b/frontend/src/stores/upload.ts index 8429146e..53d96ea9 100644 --- a/frontend/src/stores/upload.ts +++ b/frontend/src/stores/upload.ts @@ -1,8 +1,9 @@ import { defineStore } from "pinia"; import { useFileStore } from "./file"; import { files as api } from "@/api"; -import { throttle } from "lodash-es"; import buttons from "@/utils/buttons"; +import { computed, inject, markRaw, ref } from "vue"; +import * as tus from "@/api/tus"; // TODO: make this into a user setting const UPLOADS_LIMIT = 5; @@ -13,208 +14,167 @@ const beforeUnload = (event: Event) => { // event.returnValue = ""; }; -// Utility function to format bytes into a readable string -function formatSize(bytes: number): string { - if (bytes === 0) return "0.00 Bytes"; +export const useUploadStore = defineStore("upload", () => { + const $showError = inject("$showError")!; - const k = 1024; - const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; - const i = Math.floor(Math.log(bytes) / Math.log(k)); + let progressInterval: number | null = null; - // Return the rounded size with two decimal places - return (bytes / k ** i).toFixed(2) + " " + sizes[i]; -} + // + // STATE + // -export const useUploadStore = defineStore("upload", { - // convert to a function - state: (): { - id: number; - sizes: number[]; - progress: number[]; - queue: UploadItem[]; - uploads: Uploads; - speedMbyte: number; - eta: number; - error: Error | null; - } => ({ - id: 0, - sizes: [], - progress: [], - queue: [], - uploads: {}, - speedMbyte: 0, - eta: 0, - error: null, - }), - getters: { - // user and jwt getter removed, no longer needed - getProgress: (state) => { - if (state.progress.length === 0) { - return 0; + const allUploads = ref([]); + const activeUploads = ref>(new Set()); + const lastUpload = ref(-1); + const totalBytes = ref(0); + const sentBytes = ref(0); + + // + // ACTIONS + // + + const upload = ( + path: string, + name: string, + file: File | null, + overwrite: boolean, + type: ResourceType + ) => { + if (!hasActiveUploads() && !hasPendingUploads()) { + window.addEventListener("beforeunload", beforeUnload); + buttons.loading("upload"); + } + + const upload: Upload = { + path, + name, + file, + overwrite, + type, + totalBytes: file?.size || 1, + sentBytes: 0, + // Stores rapidly changing sent bytes value without causing component re-renders + rawProgress: markRaw({ + sentBytes: 0, + }), + }; + + totalBytes.value += upload.totalBytes; + allUploads.value.push(upload); + + processUploads(); + }; + + const abort = () => { + // Resets the state by preventing the processing of the remaning uploads + lastUpload.value = Infinity; + tus.abortAllUploads(); + }; + + // + // GETTERS + // + + const pendingUploadCount = computed( + () => + allUploads.value.length - + (lastUpload.value + 1) + + activeUploads.value.size + ); + + // + // PRIVATE FUNCTIONS + // + + const hasActiveUploads = () => activeUploads.value.size > 0; + + const hasPendingUploads = () => + allUploads.value.length > lastUpload.value + 1; + + const isActiveUploadsOnLimit = () => activeUploads.value.size < UPLOADS_LIMIT; + + const processUploads = async () => { + if (!hasActiveUploads() && !hasPendingUploads()) { + const fileStore = useFileStore(); + window.removeEventListener("beforeunload", beforeUnload); + buttons.success("upload"); + reset(); + fileStore.reload = true; + } + + if (isActiveUploadsOnLimit() && hasPendingUploads()) { + if (!hasActiveUploads()) { + // Update the state in a fixed time interval + progressInterval = window.setInterval(syncState, 1000); } - const totalSize = state.sizes.reduce((a, b) => a + b, 0); - const sum = state.progress.reduce((a, b) => a + b, 0); - return Math.ceil((sum / totalSize) * 100); - }, - getProgressDecimal: (state) => { - if (state.progress.length === 0) { - return 0; + const upload = nextUpload(); + + if (upload.type === "dir") { + await api.post(upload.path).catch($showError); + } else { + const onUpload = (event: ProgressEvent) => { + upload.rawProgress.sentBytes = event.loaded; + }; + + await api + .post(upload.path, upload.file!, upload.overwrite, onUpload) + .catch((err) => err.message !== "Upload aborted" && $showError(err)); } - const totalSize = state.sizes.reduce((a, b) => a + b, 0); - const sum = state.progress.reduce((a, b) => a + b, 0); - return ((sum / totalSize) * 100).toFixed(2); - }, - getTotalProgressBytes: (state) => { - if (state.progress.length === 0 || state.sizes.length === 0) { - return "0 Bytes"; - } - const sum = state.progress.reduce((a, b) => a + b, 0); - return formatSize(sum); - }, - getTotalSize: (state) => { - if (state.sizes.length === 0) { - return "0 Bytes"; - } - const totalSize = state.sizes.reduce((a, b) => a + b, 0); - return formatSize(totalSize); - }, - filesInUploadCount: (state) => { - return Object.keys(state.uploads).length + state.queue.length; - }, - filesInUpload: (state) => { - const files = []; + finishUpload(upload); + } + }; - for (const index in state.uploads) { - const upload = state.uploads[index]; - const id = upload.id; - const type = upload.type; - const name = upload.file.name; - const size = state.sizes[id]; - const isDir = upload.file.isDir; - const progress = isDir - ? 100 - : Math.ceil((state.progress[id] / size) * 100); + const nextUpload = (): Upload => { + lastUpload.value++; - files.push({ - id, - name, - progress, - type, - isDir, - }); - } + const upload = allUploads.value[lastUpload.value]; + activeUploads.value.add(upload); - return files.sort((a, b) => a.progress - b.progress); - }, - uploadSpeed: (state) => { - return state.speedMbyte; - }, - getETA: (state) => state.eta, - }, - actions: { - // no context as first argument, use `this` instead - setProgress({ id, loaded }: { id: number; loaded: number }) { - this.progress[id] = loaded; - }, - setError(error: Error) { - this.error = error; - }, - reset() { - this.id = 0; - this.sizes = []; - this.progress = []; - this.queue = []; - this.uploads = {}; - this.speedMbyte = 0; - this.eta = 0; - this.error = null; - }, - addJob(item: UploadItem) { - this.queue.push(item); - this.sizes[this.id] = item.file.size; - this.id++; - }, - moveJob() { - const item = this.queue[0]; - this.queue.shift(); - this.uploads[item.id] = item; - }, - removeJob(id: number) { - delete this.uploads[id]; - }, - upload(item: UploadItem) { - const uploadsCount = Object.keys(this.uploads).length; + return upload; + }; - const isQueueEmpty = this.queue.length == 0; - const isUploadsEmpty = uploadsCount == 0; + const finishUpload = (upload: Upload) => { + sentBytes.value += upload.totalBytes - upload.sentBytes; + upload.sentBytes = upload.totalBytes; + upload.file = null; - if (isQueueEmpty && isUploadsEmpty) { - window.addEventListener("beforeunload", beforeUnload); - buttons.loading("upload"); - } + activeUploads.value.delete(upload); + processUploads(); + }; - this.addJob(item); - this.processUploads(); - }, - finishUpload(item: UploadItem) { - this.setProgress({ id: item.id, loaded: item.file.size }); - this.removeJob(item.id); - this.processUploads(); - }, - async processUploads() { - const uploadsCount = Object.keys(this.uploads).length; + const syncState = () => { + for (const upload of activeUploads.value) { + sentBytes.value += upload.rawProgress.sentBytes - upload.sentBytes; + upload.sentBytes = upload.rawProgress.sentBytes; + } + }; - const isBelowLimit = uploadsCount < UPLOADS_LIMIT; - const isQueueEmpty = this.queue.length == 0; - const isUploadsEmpty = uploadsCount == 0; + const reset = () => { + if (progressInterval !== null) { + clearInterval(progressInterval); + progressInterval = null; + } - const isFinished = isQueueEmpty && isUploadsEmpty; - const canProcess = isBelowLimit && !isQueueEmpty; + allUploads.value = []; + activeUploads.value = new Set(); + lastUpload.value = -1; + totalBytes.value = 0; + sentBytes.value = 0; + }; - if (isFinished) { - const fileStore = useFileStore(); - window.removeEventListener("beforeunload", beforeUnload); - buttons.success("upload"); - this.reset(); - fileStore.reload = true; - } + return { + // STATE + activeUploads, + totalBytes, + sentBytes, - if (canProcess) { - const item = this.queue[0]; - this.moveJob(); + // ACTIONS + upload, + abort, - if (item.file.isDir) { - await api.post(item.path).catch(this.setError); - } else { - const onUpload = throttle( - (event: ProgressEvent) => - this.setProgress({ - id: item.id, - loaded: event.loaded, - }), - 100, - { leading: true, trailing: false } - ); - - await api - .post(item.path, item.file.file as File, item.overwrite, onUpload) - .catch(this.setError); - } - - this.finishUpload(item); - } - }, - setUploadSpeed(value: number) { - this.speedMbyte = value; - }, - setETA(value: number) { - this.eta = value; - }, - // easily reset state using `$reset` - clearUpload() { - this.$reset(); - }, - }, + // GETTERS + pendingUploadCount, + }; }); diff --git a/frontend/src/types/file.d.ts b/frontend/src/types/file.d.ts index db2aa5fe..5664c16b 100644 --- a/frontend/src/types/file.d.ts +++ b/frontend/src/types/file.d.ts @@ -29,6 +29,7 @@ interface ResourceItem extends ResourceBase { } type ResourceType = + | "dir" | "video" | "audio" | "image" diff --git a/frontend/src/types/upload.d.ts b/frontend/src/types/upload.d.ts index 131f4b2c..4bad9e06 100644 --- a/frontend/src/types/upload.d.ts +++ b/frontend/src/types/upload.d.ts @@ -1,22 +1,15 @@ -interface Uploads { - [key: number]: Upload; -} - -interface Upload { - id: number; - file: UploadEntry; - type?: ResourceType; -} - -interface UploadItem { - id: number; - url?: string; +type Upload = { path: string; - file: UploadEntry; - dir?: boolean; - overwrite?: boolean; - type?: ResourceType; -} + name: string; + file: File | null; + type: ResourceType; + overwrite: boolean; + totalBytes: number; + sentBytes: number; + rawProgress: { + sentBytes: number; + }; +}; interface UploadEntry { name: string; @@ -27,17 +20,3 @@ interface UploadEntry { } type UploadList = UploadEntry[]; - -type CurrentUploadList = { - [key: string]: { - upload: import("tus-js-client").Upload; - recentSpeeds: number[]; - initialBytesUploaded: number; - currentBytesUploaded: number; - currentAverageSpeed: number; - lastProgressTimestamp: number | null; - sumOfRecentSpeeds: number; - hasStarted: boolean; - interval: number | undefined; - }; -}; diff --git a/frontend/src/utils/upload.ts b/frontend/src/utils/upload.ts index cdd974e8..e951cb43 100644 --- a/frontend/src/utils/upload.ts +++ b/frontend/src/utils/upload.ts @@ -132,7 +132,6 @@ export function handleFiles( layoutStore.closeHovers(); for (const file of files) { - const id = uploadStore.id; let path = base; if (file.fullPath !== undefined) { @@ -145,14 +144,8 @@ export function handleFiles( path += "/"; } - const item: UploadItem = { - id, - path, - file, - overwrite, - ...(!file.isDir && { type: detectType((file.file as File).type) }), - }; + const type = file.isDir ? "dir" : detectType((file.file as File).type); - uploadStore.upload(item); + uploadStore.upload(path, file.name, file.file ?? null, overwrite, type); } } diff --git a/frontend/src/views/Files.vue b/frontend/src/views/Files.vue index 950cb86d..5001659f 100644 --- a/frontend/src/views/Files.vue +++ b/frontend/src/views/Files.vue @@ -26,7 +26,6 @@ import { computed, defineAsyncComponent, - inject, onBeforeUnmount, onMounted, onUnmounted, @@ -37,7 +36,6 @@ import { files as api } from "@/api"; import { storeToRefs } from "pinia"; import { useFileStore } from "@/stores/file"; import { useLayoutStore } from "@/stores/layout"; -import { useUploadStore } from "@/stores/upload"; import HeaderBar from "@/components/header/HeaderBar.vue"; import Breadcrumbs from "@/components/Breadcrumbs.vue"; @@ -51,14 +49,10 @@ import { name } from "../utils/constants"; const Editor = defineAsyncComponent(() => import("@/views/files/Editor.vue")); const Preview = defineAsyncComponent(() => import("@/views/files/Preview.vue")); -const $showError = inject("$showError")!; - const layoutStore = useLayoutStore(); const fileStore = useFileStore(); -const uploadStore = useUploadStore(); const { reload } = storeToRefs(fileStore); -const { error: uploadError } = storeToRefs(uploadStore); const route = useRoute(); @@ -111,9 +105,6 @@ watch(route, () => { watch(reload, (newValue) => { newValue && fetchData(); }); -watch(uploadError, (newValue) => { - newValue && $showError(newValue); -}); // Define functions diff --git a/frontend/src/views/Layout.vue b/frontend/src/views/Layout.vue index 597a680e..5a91bee5 100644 --- a/frontend/src/views/Layout.vue +++ b/frontend/src/views/Layout.vue @@ -1,7 +1,11 @@ diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index 7de128ed..4070619d 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -42,7 +42,8 @@ "update": "Update", "upload": "Upload", "openFile": "Open file", - "discardChanges": "Discard" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Download File", diff --git a/frontend/src/stores/layout.ts b/frontend/src/stores/layout.ts index faf8bca7..372fca06 100644 --- a/frontend/src/stores/layout.ts +++ b/frontend/src/stores/layout.ts @@ -41,6 +41,7 @@ export const useLayoutStore = defineStore("layout", { prompt: value, confirm: null, action: undefined, + saveAction: undefined, props: null, close: null, }); @@ -51,6 +52,7 @@ export const useLayoutStore = defineStore("layout", { prompt: value.prompt, confirm: value?.confirm, action: value?.action, + saveAction: value?.saveAction, props: value?.props, close: value?.close, }); diff --git a/frontend/src/types/layout.d.ts b/frontend/src/types/layout.d.ts index b625cc07..a5c3f160 100644 --- a/frontend/src/types/layout.d.ts +++ b/frontend/src/types/layout.d.ts @@ -2,6 +2,7 @@ interface PopupProps { prompt: string; confirm?: any; action?: PopupAction; + saveAction?: () => void; props?: any; close?: (() => Promise) | null; } diff --git a/frontend/src/views/files/Editor.vue b/frontend/src/views/files/Editor.vue index 8db6252b..13013a9f 100644 --- a/frontend/src/views/files/Editor.vue +++ b/frontend/src/views/files/Editor.vue @@ -157,6 +157,10 @@ onBeforeRouteUpdate((to, from, next) => { event.preventDefault(); next(); }, + saveAction: async () => { + await save(); + next(); + }, }); }); From 82dc57ad43503c87428af9b1e9c814f4621e3cd0 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sat, 13 Sep 2025 08:44:52 +0200 Subject: [PATCH 020/202] chore(release): 2.43.0 --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc661cfd..6f487429 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,33 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.43.0](https://github.com/filebrowser/filebrowser/compare/v2.42.5...v2.43.0) (2025-09-13) + + +### Features + +* "save changes" button to discard changes dialog ([84e8632](https://github.com/filebrowser/filebrowser/commit/84e8632b98e315bfef2da77dd7d1049daec99241)) +* Translate frontend/src/i18n/en.json in es ([571ce6c](https://github.com/filebrowser/filebrowser/commit/571ce6cb0d7c8725d1cc1a3238ea506ddc72b060)) +* Translate frontend/src/i18n/en.json in fr ([6b1fa87](https://github.com/filebrowser/filebrowser/commit/6b1fa87ad38ebbb1a9c5d0e5fc88ba796c148bcf)) +* Updates for project File Browser ([#5427](https://github.com/filebrowser/filebrowser/issues/5427)) ([8950585](https://github.com/filebrowser/filebrowser/commit/89505851414bfcee6b9ff02087eb4cec51c330f6)) + + +### Bug Fixes + +* optimize markdown preview height ([783503a](https://github.com/filebrowser/filebrowser/commit/783503aece7fca9e26f7e849b0e7478aba976acb)) + + +### Build + +* **deps-dev:** bump vite from 6.1.6 to 6.3.6 in /frontend ([36c6cc2](https://github.com/filebrowser/filebrowser/commit/36c6cc203e10947439519a0413d5817921a1690d)) +* **deps:** bump github.com/go-viper/mapstructure/v2 in /tools ([280fa56](https://github.com/filebrowser/filebrowser/commit/280fa562a67824887ae6e2530a3b73739d6e1bb4)) +* **deps:** bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14 ([950028a](https://github.com/filebrowser/filebrowser/commit/950028abebe2898bac4ecfd8715c0967246310cb)) + + +### Refactorings + +* to use strings.Lines ([b482a9b](https://github.com/filebrowser/filebrowser/commit/b482a9bf0d292ec6542d2145a4408971e4c985f1)) + ### [2.42.5](https://github.com/filebrowser/filebrowser/compare/v2.42.4...v2.42.5) (2025-08-16) From 07692653ffe0ea5e517e6dc1fd3961172e931843 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sat, 13 Sep 2025 09:03:12 +0200 Subject: [PATCH 021/202] revert: build(deps): bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 788dcf19..cf005b55 100644 --- a/go.mod +++ b/go.mod @@ -65,7 +65,7 @@ require ( github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/cast v1.9.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/ulikunitz/xz v0.5.14 // indirect + github.com/ulikunitz/xz v0.5.12 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.uber.org/multierr v1.11.0 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect diff --git a/go.sum b/go.sum index a2988587..a9ccaa5b 100644 --- a/go.sum +++ b/go.sum @@ -232,8 +232,8 @@ github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSW github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc= github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.14 h1:uv/0Bq533iFdnMHZdRBTOlaNMdb1+ZxXIlHDZHIHcvg= -github.com/ulikunitz/xz v0.5.14/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= +github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= From 2f0c1f5fa288bad90ab70d5801a11f86a69b5cac Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sat, 13 Sep 2025 09:04:12 +0200 Subject: [PATCH 022/202] chore(release): 2.43.0 --- CHANGELOG.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f487429..f81c8cd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,38 @@ All notable changes to this project will be documented in this file. See [standa * optimize markdown preview height ([783503a](https://github.com/filebrowser/filebrowser/commit/783503aece7fca9e26f7e849b0e7478aba976acb)) +### Reverts + +* build(deps): bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14 ([0769265](https://github.com/filebrowser/filebrowser/commit/07692653ffe0ea5e517e6dc1fd3961172e931843)) + + +### Build + +* **deps-dev:** bump vite from 6.1.6 to 6.3.6 in /frontend ([36c6cc2](https://github.com/filebrowser/filebrowser/commit/36c6cc203e10947439519a0413d5817921a1690d)) +* **deps:** bump github.com/go-viper/mapstructure/v2 in /tools ([280fa56](https://github.com/filebrowser/filebrowser/commit/280fa562a67824887ae6e2530a3b73739d6e1bb4)) +* **deps:** bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14 ([950028a](https://github.com/filebrowser/filebrowser/commit/950028abebe2898bac4ecfd8715c0967246310cb)) + + +### Refactorings + +* to use strings.Lines ([b482a9b](https://github.com/filebrowser/filebrowser/commit/b482a9bf0d292ec6542d2145a4408971e4c985f1)) + +## [2.43.0](https://github.com/filebrowser/filebrowser/compare/v2.42.5...v2.43.0) (2025-09-13) + + +### Features + +* "save changes" button to discard changes dialog ([84e8632](https://github.com/filebrowser/filebrowser/commit/84e8632b98e315bfef2da77dd7d1049daec99241)) +* Translate frontend/src/i18n/en.json in es ([571ce6c](https://github.com/filebrowser/filebrowser/commit/571ce6cb0d7c8725d1cc1a3238ea506ddc72b060)) +* Translate frontend/src/i18n/en.json in fr ([6b1fa87](https://github.com/filebrowser/filebrowser/commit/6b1fa87ad38ebbb1a9c5d0e5fc88ba796c148bcf)) +* Updates for project File Browser ([#5427](https://github.com/filebrowser/filebrowser/issues/5427)) ([8950585](https://github.com/filebrowser/filebrowser/commit/89505851414bfcee6b9ff02087eb4cec51c330f6)) + + +### Bug Fixes + +* optimize markdown preview height ([783503a](https://github.com/filebrowser/filebrowser/commit/783503aece7fca9e26f7e849b0e7478aba976acb)) + + ### Build * **deps-dev:** bump vite from 6.1.6 to 6.3.6 in /frontend ([36c6cc2](https://github.com/filebrowser/filebrowser/commit/36c6cc203e10947439519a0413d5817921a1690d)) From 4ff247e134e4d61668ee656a258ed67f71414e18 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Thu, 18 Sep 2025 13:10:27 +0200 Subject: [PATCH 023/202] feat: Updates for project File Browser (#5446) Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- frontend/src/i18n/ar.json | 3 +- frontend/src/i18n/ca.json | 3 +- frontend/src/i18n/cs.json | 3 +- frontend/src/i18n/de.json | 3 +- frontend/src/i18n/el.json | 3 +- frontend/src/i18n/es.json | 3 +- frontend/src/i18n/fa.json | 3 +- frontend/src/i18n/he.json | 3 +- frontend/src/i18n/hu.json | 3 +- frontend/src/i18n/is.json | 3 +- frontend/src/i18n/it.json | 3 +- frontend/src/i18n/ja.json | 3 +- frontend/src/i18n/ko.json | 59 ++++++++++++++++++------------------ frontend/src/i18n/nl-be.json | 3 +- frontend/src/i18n/no.json | 3 +- frontend/src/i18n/pl.json | 3 +- frontend/src/i18n/pt-br.json | 3 +- frontend/src/i18n/pt.json | 3 +- frontend/src/i18n/ro.json | 3 +- frontend/src/i18n/ru.json | 3 +- frontend/src/i18n/sk.json | 3 +- frontend/src/i18n/sv-se.json | 3 +- frontend/src/i18n/tr.json | 3 +- frontend/src/i18n/uk.json | 3 +- frontend/src/i18n/vi.json | 3 +- frontend/src/i18n/zh-cn.json | 3 +- frontend/src/i18n/zh-tw.json | 3 +- 27 files changed, 82 insertions(+), 55 deletions(-) diff --git a/frontend/src/i18n/ar.json b/frontend/src/i18n/ar.json index 03edf825..7dcc555d 100644 --- a/frontend/src/i18n/ar.json +++ b/frontend/src/i18n/ar.json @@ -42,7 +42,8 @@ "update": "تحديث", "upload": "رفع", "openFile": "فتح الملف", - "discardChanges": "إلغاء التغييرات" + "discardChanges": "إلغاء التغييرات", + "saveChanges": "Save changes" }, "download": { "downloadFile": "تحميل الملف", diff --git a/frontend/src/i18n/ca.json b/frontend/src/i18n/ca.json index 77e32e47..6ba909df 100644 --- a/frontend/src/i18n/ca.json +++ b/frontend/src/i18n/ca.json @@ -42,7 +42,8 @@ "update": "Actualitzar", "upload": "Pujar", "openFile": "Obrir fitxer", - "discardChanges": "Descartar" + "discardChanges": "Descartar", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Descarregar fitxer", diff --git a/frontend/src/i18n/cs.json b/frontend/src/i18n/cs.json index 1c1077c8..58029d3a 100644 --- a/frontend/src/i18n/cs.json +++ b/frontend/src/i18n/cs.json @@ -42,7 +42,8 @@ "update": "Aktualizovat", "upload": "Nahrát", "openFile": "Otevřít soubor", - "discardChanges": "Zrušit změny" + "discardChanges": "Zrušit změny", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Stáhnout soubor", diff --git a/frontend/src/i18n/de.json b/frontend/src/i18n/de.json index 0a307f64..aaa647de 100644 --- a/frontend/src/i18n/de.json +++ b/frontend/src/i18n/de.json @@ -42,7 +42,8 @@ "update": "Update", "upload": "Upload", "openFile": "Datei öffnen", - "discardChanges": "Verwerfen" + "discardChanges": "Verwerfen", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Download Datei", diff --git a/frontend/src/i18n/el.json b/frontend/src/i18n/el.json index 9b021b80..13150356 100644 --- a/frontend/src/i18n/el.json +++ b/frontend/src/i18n/el.json @@ -42,7 +42,8 @@ "update": "Ενημέρωση", "upload": "Μεταφόρτωση", "openFile": "Άνοιγμα αρχείου", - "discardChanges": "Discard" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Λήψη αρχείου", diff --git a/frontend/src/i18n/es.json b/frontend/src/i18n/es.json index 646c7519..3ab1025d 100644 --- a/frontend/src/i18n/es.json +++ b/frontend/src/i18n/es.json @@ -42,7 +42,8 @@ "update": "Actualizar", "upload": "Subir", "openFile": "Abrir archivo", - "discardChanges": "Discard" + "discardChanges": "Discard", + "saveChanges": "Guardar cambios" }, "download": { "downloadFile": "Descargar fichero", diff --git a/frontend/src/i18n/fa.json b/frontend/src/i18n/fa.json index 478e8148..eb8ef99e 100644 --- a/frontend/src/i18n/fa.json +++ b/frontend/src/i18n/fa.json @@ -42,7 +42,8 @@ "update": "به روز سانی", "upload": "آپلود", "openFile": "باز کردن فایل", - "discardChanges": "لغو کردن" + "discardChanges": "لغو کردن", + "saveChanges": "Save changes" }, "download": { "downloadFile": "دانلود فایل", diff --git a/frontend/src/i18n/he.json b/frontend/src/i18n/he.json index 009f07b7..b7f13d88 100644 --- a/frontend/src/i18n/he.json +++ b/frontend/src/i18n/he.json @@ -42,7 +42,8 @@ "update": "עדכון", "upload": "העלאה", "openFile": "פתח קובץ", - "discardChanges": "זריקת השינויים" + "discardChanges": "זריקת השינויים", + "saveChanges": "Save changes" }, "download": { "downloadFile": "הורד קובץ", diff --git a/frontend/src/i18n/hu.json b/frontend/src/i18n/hu.json index 507f08da..2b426eb6 100644 --- a/frontend/src/i18n/hu.json +++ b/frontend/src/i18n/hu.json @@ -42,7 +42,8 @@ "update": "Frissítés", "upload": "Feltöltés", "openFile": "Fájl megnyitása", - "discardChanges": "Discard" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Fájl letöltése", diff --git a/frontend/src/i18n/is.json b/frontend/src/i18n/is.json index 54eeb727..c29ce698 100644 --- a/frontend/src/i18n/is.json +++ b/frontend/src/i18n/is.json @@ -42,7 +42,8 @@ "update": "Vista", "upload": "Hlaða upp", "openFile": "Open file", - "discardChanges": "Discard" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Sækja skjal", diff --git a/frontend/src/i18n/it.json b/frontend/src/i18n/it.json index 0205b955..000bd8ce 100644 --- a/frontend/src/i18n/it.json +++ b/frontend/src/i18n/it.json @@ -42,7 +42,8 @@ "update": "Aggiorna", "upload": "Carica", "openFile": "Apri file", - "discardChanges": "Ignora" + "discardChanges": "Ignora", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Scarica file", diff --git a/frontend/src/i18n/ja.json b/frontend/src/i18n/ja.json index cd380304..6ce903f7 100644 --- a/frontend/src/i18n/ja.json +++ b/frontend/src/i18n/ja.json @@ -42,7 +42,8 @@ "update": "更新", "upload": "アップロード", "openFile": "ファイルを開く", - "discardChanges": "Discard" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "ファイルのダウンロード", diff --git a/frontend/src/i18n/ko.json b/frontend/src/i18n/ko.json index 11fe3aac..54307897 100644 --- a/frontend/src/i18n/ko.json +++ b/frontend/src/i18n/ko.json @@ -3,17 +3,17 @@ "cancel": "취소", "clear": "지우기", "close": "닫기", - "continue": "Continue", + "continue": "계속", "copy": "복사", "copyFile": "파일 복사", "copyToClipboard": "클립보드 복사", - "copyDownloadLinkToClipboard": "Copy download link to clipboard", + "copyDownloadLinkToClipboard": "다운로드 링크 복사", "create": "생성", "delete": "삭제", "download": "다운로드", - "file": "File", - "folder": "Folder", - "fullScreen": "Toggle full screen", + "file": "파일", + "folder": "폴더", + "fullScreen": "전체 화면 전환", "hideDotfiles": "숨김파일(dotfile)을 표시 안함", "info": "정보", "more": "더보기", @@ -24,7 +24,7 @@ "ok": "확인", "permalink": "링크 얻기", "previous": "이전", - "preview": "Preview", + "preview": "미리보기", "publish": "게시", "rename": "이름 바꾸기", "replace": "대체", @@ -36,13 +36,14 @@ "selectMultiple": "다중 선택", "share": "공유", "shell": "쉘 전환", - "submit": "Submit", + "submit": "제출", "switchView": "보기 전환", "toggleSidebar": "사이드바 전환", "update": "업데이트", "upload": "업로드", - "openFile": "Open file", - "discardChanges": "Discard" + "openFile": "파일 열기", + "discardChanges": "변경 사항 취소", + "saveChanges": "변경사항 저장" }, "download": { "downloadFile": "파일 다운로드", @@ -50,13 +51,13 @@ "downloadSelected": "선택 항목 다운로드" }, "upload": { - "abortUpload": "Are you sure you wish to abort?" + "abortUpload": "업로드를 중단하시겠습니까?" }, "errors": { "forbidden": "접근 권한이 없습니다.", "internal": "오류가 발생하였습니다.", "notFound": "해당 경로를 찾을 수 없습니다.", - "connection": "The server can't be reached." + "connection": "서버에 연결할 수 없습니다." }, "files": { "body": "본문", @@ -74,7 +75,7 @@ "sortByLastModified": "수정시간순 정렬", "sortByName": "이름순", "sortBySize": "크기순", - "noPreview": "Preview is not available for this file." + "noPreview": "미리 보기가 지원되지 않는 파일 유형입니다." }, "help": { "click": "파일이나 디렉토리를 선택해주세요.", @@ -109,8 +110,8 @@ "currentlyNavigating": "현재 위치:", "deleteMessageMultiple": "{count} 개의 파일을 삭제하시겠습니까?", "deleteMessageSingle": "파일 혹은 디렉토리를 삭제하시겠습니까?", - "deleteMessageShare": "Are you sure you wish to delete this share({path})?", - "deleteUser": "Are you sure you want to delete this user?", + "deleteMessageShare": "이 공유({path})를 삭제하시겠습니까?", + "deleteUser": "이 계정을 삭제하시겠습니까?", "deleteTitle": "파일 삭제", "displayName": "게시 이름:", "download": "파일 다운로드", @@ -137,11 +138,11 @@ "show": "보기", "size": "크기", "upload": "업로드", - "uploadFiles": "Uploading {files} files...", + "uploadFiles": "{files}개의 파일 업로드 중...", "uploadMessage": "업로드 옵션을 선택하세요.", - "optionalPassword": "Optional password", - "resolution": "Resolution", - "discardEditorChanges": "Are you sure you wish to discard the changes you've made?" + "optionalPassword": "비밀번호 (선택)", + "resolution": "해상도", + "discardEditorChanges": "변경 사항을 취소하시겠습니까?" }, "search": { "images": "이미지", @@ -170,14 +171,14 @@ "commandRunnerHelp": "이벤트에 해당하는 명령을 설정하세요. 줄당 1개의 명령을 적으세요. 환경 변수{0} 와 {1}이 사용가능하며, {0} 은 {1}에 상대 경로 입니다. 자세한 사항은 {2} 를 참조하세요.", "commandsUpdated": "명령 수정됨!", "createUserDir": "Auto create user home dir while adding new user", - "minimumPasswordLength": "Minimum password length", - "tusUploads": "Chunked Uploads", - "tusUploadsHelp": "File Browser supports chunked file uploads, allowing for the creation of efficient, reliable, resumable and chunked file uploads even on unreliable networks.", - "tusUploadsChunkSize": "Indicates to maximum size of a request (direct uploads will be used for smaller uploads). You may input a plain integer denoting byte size input or a string like 10MB, 1GB etc.", - "tusUploadsRetryCount": "Number of retries to perform if a chunk fails to upload.", - "userHomeBasePath": "Base path for user home directories", - "userScopeGenerationPlaceholder": "The scope will be auto generated", - "createUserHomeDirectory": "Create user home directory", + "minimumPasswordLength": "최소 비밀번호 길이", + "tusUploads": "분할 업로드", + "tusUploadsHelp": "File Browser는 불안정한 네트워크에서도 효율적이고 신뢰성 있는 분할 업로드를 지원합니다.", + "tusUploadsChunkSize": "업로드 요청의 최대 크기 (예: 10MB, 1GB)", + "tusUploadsRetryCount": "업로드 실패 시 재시도 횟수", + "userHomeBasePath": "사용자 홈 폴더 기본 경로", + "userScopeGenerationPlaceholder": "범위는 자동으로 생성됩니다.", + "createUserHomeDirectory": "사용자 홈 폴더 생성", "customStylesheet": "커스텀 스타일시트", "defaultUserDescription": "아래 사항은 신규 사용자들에 대한 기본 설정입니다.", "disableExternalLinks": "외부 링크 감추기", @@ -217,14 +218,14 @@ "rules": "룰", "rulesHelp": "사용자별로 규칙을 허용/방지를 지정할 수 있습니다. 방지된 파일은 보이지 않고 사용자들은 접근할 수 없습니다. 사용자의 접근 허용 범위와 관련해 정규표현식(regex)과 경로를 지원합니다.\n", "scope": "범위", - "setDateFormat": "Set exact date format", + "setDateFormat": "날짜 형식 설정", "settingsUpdated": "설정 수정됨!", "shareDuration": "공유 기간", "shareManagement": "공유 내역 관리", - "shareDeleted": "Share deleted!", + "shareDeleted": "공유 삭제됨!", "singleClick": "한번 클릭으로 파일과 폴더를 열도록 합니다.", "themes": { - "default": "System default", + "default": "시스템 기본값", "dark": "다크테마", "light": "라이트테마", "title": "테마" diff --git a/frontend/src/i18n/nl-be.json b/frontend/src/i18n/nl-be.json index 9bf3b1fa..860f12ed 100644 --- a/frontend/src/i18n/nl-be.json +++ b/frontend/src/i18n/nl-be.json @@ -42,7 +42,8 @@ "update": "Updaten", "upload": "Uploaden", "openFile": "Open file", - "discardChanges": "Discard" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Bestand downloaden", diff --git a/frontend/src/i18n/no.json b/frontend/src/i18n/no.json index d077e96f..ae35e04e 100644 --- a/frontend/src/i18n/no.json +++ b/frontend/src/i18n/no.json @@ -42,7 +42,8 @@ "update": "Opptater", "upload": "Last opp", "openFile": "Open file", - "discardChanges": "Slett" + "discardChanges": "Slett", + "saveChanges": "Lagre Endringane " }, "download": { "downloadFile": "Nedlast filen", diff --git a/frontend/src/i18n/pl.json b/frontend/src/i18n/pl.json index 3d7835cc..5837faa7 100644 --- a/frontend/src/i18n/pl.json +++ b/frontend/src/i18n/pl.json @@ -42,7 +42,8 @@ "update": "Aktualizuj", "upload": "Wyślij", "openFile": "Otwórz plik", - "discardChanges": "Odrzuć" + "discardChanges": "Odrzuć", + "saveChanges": "Zapisz zmiany" }, "download": { "downloadFile": "Pobierz plik", diff --git a/frontend/src/i18n/pt-br.json b/frontend/src/i18n/pt-br.json index e0f04b66..ccce0f4d 100644 --- a/frontend/src/i18n/pt-br.json +++ b/frontend/src/i18n/pt-br.json @@ -42,7 +42,8 @@ "update": "Atualizar", "upload": "Enviar", "openFile": "Abrir", - "discardChanges": "Discard" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Baixar arquivo", diff --git a/frontend/src/i18n/pt.json b/frontend/src/i18n/pt.json index 6041ddd2..7babc212 100644 --- a/frontend/src/i18n/pt.json +++ b/frontend/src/i18n/pt.json @@ -42,7 +42,8 @@ "update": "Atualizar", "upload": "Enviar", "openFile": "Open file", - "discardChanges": "Discard" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Descarregar ficheiro", diff --git a/frontend/src/i18n/ro.json b/frontend/src/i18n/ro.json index 8063e655..b03d8c21 100644 --- a/frontend/src/i18n/ro.json +++ b/frontend/src/i18n/ro.json @@ -42,7 +42,8 @@ "update": "Actualizează", "upload": "Încarcă", "openFile": "Open file", - "discardChanges": "Discard" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Descarcă fișier", diff --git a/frontend/src/i18n/ru.json b/frontend/src/i18n/ru.json index 6d8d8059..3a9ff33a 100644 --- a/frontend/src/i18n/ru.json +++ b/frontend/src/i18n/ru.json @@ -42,7 +42,8 @@ "update": "Обновить", "upload": "Загрузить", "openFile": "Открыть файл", - "discardChanges": "Отказаться" + "discardChanges": "Отказаться", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Скачать файл", diff --git a/frontend/src/i18n/sk.json b/frontend/src/i18n/sk.json index a8e957de..d8b66b58 100644 --- a/frontend/src/i18n/sk.json +++ b/frontend/src/i18n/sk.json @@ -42,7 +42,8 @@ "update": "Aktualizovať", "upload": "Nahrať", "openFile": "Otvoriť súbor", - "discardChanges": "Zahodiť" + "discardChanges": "Zahodiť", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Stiahnuť súbor", diff --git a/frontend/src/i18n/sv-se.json b/frontend/src/i18n/sv-se.json index 015c106b..11315728 100644 --- a/frontend/src/i18n/sv-se.json +++ b/frontend/src/i18n/sv-se.json @@ -42,7 +42,8 @@ "update": "Uppdatera", "upload": "Ladda upp", "openFile": "Open file", - "discardChanges": "Discard" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Ladda ner fil", diff --git a/frontend/src/i18n/tr.json b/frontend/src/i18n/tr.json index 1c4572c0..6b87681c 100644 --- a/frontend/src/i18n/tr.json +++ b/frontend/src/i18n/tr.json @@ -42,7 +42,8 @@ "update": "Güncelle", "upload": "Yükle", "openFile": "Dosyayı aç", - "discardChanges": "Discard" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Dosyayı indir", diff --git a/frontend/src/i18n/uk.json b/frontend/src/i18n/uk.json index 08bb9cfd..7cddd910 100644 --- a/frontend/src/i18n/uk.json +++ b/frontend/src/i18n/uk.json @@ -42,7 +42,8 @@ "update": "Оновити", "upload": "Вивантажити", "openFile": "Відкрити файл", - "discardChanges": "Скасувати" + "discardChanges": "Скасувати", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Завантажити файл", diff --git a/frontend/src/i18n/vi.json b/frontend/src/i18n/vi.json index e47e73c1..a84ea286 100644 --- a/frontend/src/i18n/vi.json +++ b/frontend/src/i18n/vi.json @@ -42,7 +42,8 @@ "update": "Cập nhật", "upload": "Tải lên", "openFile": "Mở tệp", - "discardChanges": "Hủy bỏ thay đổi" + "discardChanges": "Hủy bỏ thay đổi", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Tải xuống tệp tin", diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json index fac470e8..c50e2d4e 100644 --- a/frontend/src/i18n/zh-cn.json +++ b/frontend/src/i18n/zh-cn.json @@ -42,7 +42,8 @@ "update": "更新", "upload": "上传", "openFile": "打开文件", - "discardChanges": "放弃更改" + "discardChanges": "放弃更改", + "saveChanges": "Save changes" }, "download": { "downloadFile": "下载文件", diff --git a/frontend/src/i18n/zh-tw.json b/frontend/src/i18n/zh-tw.json index 966cb14e..1522e28d 100644 --- a/frontend/src/i18n/zh-tw.json +++ b/frontend/src/i18n/zh-tw.json @@ -42,7 +42,8 @@ "update": "更新", "upload": "上傳", "openFile": "開啟檔案", - "discardChanges": "放棄變更" + "discardChanges": "放棄變更", + "saveChanges": "Save changes" }, "download": { "downloadFile": "下載檔案", From e6c674b3c616831942c4d4aacab0907d58003e23 Mon Sep 17 00:00:00 2001 From: MSomnium Studios <70982507+ArielLeyva@users.noreply.github.com> Date: Fri, 19 Sep 2025 09:09:26 -0400 Subject: [PATCH 024/202] fix: show login when session token expires --- frontend/src/css/login.css | 9 +++++++++ frontend/src/i18n/en.json | 5 ++++- frontend/src/stores/auth.ts | 5 +++++ frontend/src/utils/auth.ts | 24 ++++++++++++++++++++++-- frontend/src/views/Login.vue | 5 +++++ 5 files changed, 45 insertions(+), 3 deletions(-) diff --git a/frontend/src/css/login.css b/frontend/src/css/login.css index 14bfd1a5..62150ee6 100644 --- a/frontend/src/css/login.css +++ b/frontend/src/css/login.css @@ -45,6 +45,15 @@ animation: 0.2s opac forwards; } +#login .logout-message { + background: var(--icon-orange); + color: #fff; + padding: 0.5em; + text-align: center; + animation: 0.2s opac forwards; + text-transform: none; +} + @keyframes opac { 0% { opacity: 0; diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index 4070619d..9411d91e 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -101,7 +101,10 @@ "submit": "Login", "username": "Username", "usernameTaken": "Username already taken", - "wrongCredentials": "Wrong credentials" + "wrongCredentials": "Wrong credentials", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/frontend/src/stores/auth.ts b/frontend/src/stores/auth.ts index 459141ad..c33db87a 100644 --- a/frontend/src/stores/auth.ts +++ b/frontend/src/stores/auth.ts @@ -7,9 +7,11 @@ export const useAuthStore = defineStore("auth", { state: (): { user: IUser | null; jwt: string; + logoutTimer: number | null; } => ({ user: null, jwt: "", + logoutTimer: null, }), getters: { // user and jwt getter removed, no longer needed @@ -37,5 +39,8 @@ export const useAuthStore = defineStore("auth", { clearUser() { this.$reset(); }, + setLogoutTimer(logoutTimer: number | null) { + this.logoutTimer = logoutTimer; + }, }, }); diff --git a/frontend/src/utils/auth.ts b/frontend/src/utils/auth.ts index b868d90f..2b940cd4 100644 --- a/frontend/src/utils/auth.ts +++ b/frontend/src/utils/auth.ts @@ -16,6 +16,17 @@ export function parseToken(token: string) { const authStore = useAuthStore(); authStore.jwt = token; authStore.setUser(data.user); + + if (authStore.logoutTimer) { + clearTimeout(authStore.logoutTimer); + } + + const expiresAt = new Date(data.exp! * 1000); + authStore.setLogoutTimer( + window.setTimeout(() => { + logout("inactivity"); + }, expiresAt.getTime() - Date.now()) + ); } export async function validateLogin() { @@ -92,7 +103,7 @@ export async function signup(username: string, password: string) { } } -export function logout() { +export function logout(reason?: string) { document.cookie = "auth=; Max-Age=0; Path=/; SameSite=Strict;"; const authStore = useAuthStore(); @@ -102,6 +113,15 @@ export function logout() { if (noAuth) { window.location.reload(); } else { - router.push({ path: "/login" }); + if (typeof reason === "string" && reason.trim() !== "") { + router.push({ + path: "/login", + query: { "logout-reason": reason }, + }); + } else { + router.push({ + path: "/login", + }); + } } } diff --git a/frontend/src/views/Login.vue b/frontend/src/views/Login.vue index 5804789a..c0e78225 100644 --- a/frontend/src/views/Login.vue +++ b/frontend/src/views/Login.vue @@ -3,6 +3,9 @@
File Browser

{{ name }}

+

+ {{ t(`login.logout_reasons.${reason}`) }} +

{{ error }}
(createMode.value = !createMode.value); const $showError = inject("$showError")!; +const reason = route.query["logout-reason"] ?? null; + const submit = async (event: Event) => { event.preventDefault(); event.stopPropagation(); From 0eade717ce9d04bf48051922f11d983edbc7c2d0 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 21:32:15 +0200 Subject: [PATCH 025/202] feat: Updates for project File Browser (#5450) Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- frontend/src/i18n/ar.json | 5 ++++- frontend/src/i18n/ca.json | 5 ++++- frontend/src/i18n/cs.json | 5 ++++- frontend/src/i18n/de.json | 5 ++++- frontend/src/i18n/el.json | 5 ++++- frontend/src/i18n/es.json | 5 ++++- frontend/src/i18n/fa.json | 5 ++++- frontend/src/i18n/fr.json | 8 ++++++-- frontend/src/i18n/he.json | 5 ++++- frontend/src/i18n/hu.json | 5 ++++- frontend/src/i18n/is.json | 5 ++++- frontend/src/i18n/it.json | 5 ++++- frontend/src/i18n/ja.json | 5 ++++- frontend/src/i18n/ko.json | 5 ++++- frontend/src/i18n/nl-be.json | 5 ++++- frontend/src/i18n/no.json | 5 ++++- frontend/src/i18n/pl.json | 5 ++++- frontend/src/i18n/pt-br.json | 5 ++++- frontend/src/i18n/pt.json | 5 ++++- frontend/src/i18n/ro.json | 5 ++++- frontend/src/i18n/ru.json | 5 ++++- frontend/src/i18n/sk.json | 5 ++++- frontend/src/i18n/sv-se.json | 5 ++++- frontend/src/i18n/tr.json | 5 ++++- frontend/src/i18n/uk.json | 5 ++++- frontend/src/i18n/vi.json | 5 ++++- frontend/src/i18n/zh-cn.json | 5 ++++- frontend/src/i18n/zh-tw.json | 5 ++++- 28 files changed, 114 insertions(+), 29 deletions(-) diff --git a/frontend/src/i18n/ar.json b/frontend/src/i18n/ar.json index 7dcc555d..70feef51 100644 --- a/frontend/src/i18n/ar.json +++ b/frontend/src/i18n/ar.json @@ -101,7 +101,10 @@ "submit": "تسجيل دخول", "username": "إسم المستخدم", "usernameTaken": "إسم المستخدم غير متاح", - "wrongCredentials": "بيانات دخول خاطئة" + "wrongCredentials": "بيانات دخول خاطئة", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "دائم", "prompts": { diff --git a/frontend/src/i18n/ca.json b/frontend/src/i18n/ca.json index 6ba909df..4d698fa5 100644 --- a/frontend/src/i18n/ca.json +++ b/frontend/src/i18n/ca.json @@ -101,7 +101,10 @@ "submit": "Iniciar sessió", "username": "Usuari", "usernameTaken": "Nom d'usuari no disponible", - "wrongCredentials": "Usuari i/o contrasenya incorrectes" + "wrongCredentials": "Usuari i/o contrasenya incorrectes", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/frontend/src/i18n/cs.json b/frontend/src/i18n/cs.json index 58029d3a..c7e32842 100644 --- a/frontend/src/i18n/cs.json +++ b/frontend/src/i18n/cs.json @@ -101,7 +101,10 @@ "submit": "Přihlásit se", "username": "Uživatelské jméno", "usernameTaken": "Uživatelské jméno již existuje", - "wrongCredentials": "Nesprávné přihlašovací údaje" + "wrongCredentials": "Nesprávné přihlašovací údaje", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Trvalý", "prompts": { diff --git a/frontend/src/i18n/de.json b/frontend/src/i18n/de.json index aaa647de..d22a3be1 100644 --- a/frontend/src/i18n/de.json +++ b/frontend/src/i18n/de.json @@ -101,7 +101,10 @@ "submit": "Login", "username": "Benutzername", "usernameTaken": "Benutzername ist bereits vergeben", - "wrongCredentials": "Falsche Zugangsdaten" + "wrongCredentials": "Falsche Zugangsdaten", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/frontend/src/i18n/el.json b/frontend/src/i18n/el.json index 13150356..9fed72f1 100644 --- a/frontend/src/i18n/el.json +++ b/frontend/src/i18n/el.json @@ -101,7 +101,10 @@ "submit": "Είσοδος", "username": "Όνομα χρήστη", "usernameTaken": "Το όνομα χρήστη χρησιμοποιείται ήδη", - "wrongCredentials": "Λάθος όνομα ή/και κωδικός πρόσβασης" + "wrongCredentials": "Λάθος όνομα ή/και κωδικός πρόσβασης", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Μόνιμο", "prompts": { diff --git a/frontend/src/i18n/es.json b/frontend/src/i18n/es.json index 3ab1025d..e7f9e882 100644 --- a/frontend/src/i18n/es.json +++ b/frontend/src/i18n/es.json @@ -101,7 +101,10 @@ "submit": "Iniciar sesión", "username": "Usuario", "usernameTaken": "Nombre usuario no disponible", - "wrongCredentials": "Usuario y/o contraseña incorrectos" + "wrongCredentials": "Usuario y/o contraseña incorrectos", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanente", "prompts": { diff --git a/frontend/src/i18n/fa.json b/frontend/src/i18n/fa.json index eb8ef99e..70e10c12 100644 --- a/frontend/src/i18n/fa.json +++ b/frontend/src/i18n/fa.json @@ -101,7 +101,10 @@ "submit": "ورود", "username": "نام کاربری", "usernameTaken": "نام کاربری تکراری", - "wrongCredentials": "خطا در اعتبارسنجی" + "wrongCredentials": "خطا در اعتبارسنجی", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "دائمی", "prompts": { diff --git a/frontend/src/i18n/fr.json b/frontend/src/i18n/fr.json index c9110f66..16508807 100644 --- a/frontend/src/i18n/fr.json +++ b/frontend/src/i18n/fr.json @@ -42,7 +42,8 @@ "update": "Mettre à jour", "upload": "Importer", "openFile": "Ouvrir le fichier", - "discardChanges": "Annuler" + "discardChanges": "Annuler", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Télécharger le fichier", @@ -100,7 +101,10 @@ "submit": "Se connecter", "username": "Utilisateur·ice", "usernameTaken": "Le nom d'utilisateur·ice est déjà pris", - "wrongCredentials": "Identifiants incorrects !" + "wrongCredentials": "Identifiants incorrects !", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/frontend/src/i18n/he.json b/frontend/src/i18n/he.json index b7f13d88..a8e89a93 100644 --- a/frontend/src/i18n/he.json +++ b/frontend/src/i18n/he.json @@ -101,7 +101,10 @@ "submit": "התחברות", "username": "שם משתמש", "usernameTaken": "שם המשתמש כבר קיים", - "wrongCredentials": "פרטי התחברות שגויים" + "wrongCredentials": "פרטי התחברות שגויים", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "קבוע", "prompts": { diff --git a/frontend/src/i18n/hu.json b/frontend/src/i18n/hu.json index 2b426eb6..00fc419e 100644 --- a/frontend/src/i18n/hu.json +++ b/frontend/src/i18n/hu.json @@ -101,7 +101,10 @@ "submit": "Belépés", "username": "Felhasználói név", "usernameTaken": "A felhasználói név már foglalt", - "wrongCredentials": "Hibás hitelesítő adatok" + "wrongCredentials": "Hibás hitelesítő adatok", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Állandó", "prompts": { diff --git a/frontend/src/i18n/is.json b/frontend/src/i18n/is.json index c29ce698..c55455e5 100644 --- a/frontend/src/i18n/is.json +++ b/frontend/src/i18n/is.json @@ -101,7 +101,10 @@ "submit": "Innskráning", "username": "Notendanafn", "usernameTaken": "Þetta norendanafn er þegar í notkun", - "wrongCredentials": "Rangar notendaupplýsingar" + "wrongCredentials": "Rangar notendaupplýsingar", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Varanlegt", "prompts": { diff --git a/frontend/src/i18n/it.json b/frontend/src/i18n/it.json index 000bd8ce..995ba7cd 100644 --- a/frontend/src/i18n/it.json +++ b/frontend/src/i18n/it.json @@ -101,7 +101,10 @@ "submit": "Entra", "username": "Nome utente", "usernameTaken": "Username già usato", - "wrongCredentials": "Credenziali errate" + "wrongCredentials": "Credenziali errate", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanente", "prompts": { diff --git a/frontend/src/i18n/ja.json b/frontend/src/i18n/ja.json index 6ce903f7..99e4b017 100644 --- a/frontend/src/i18n/ja.json +++ b/frontend/src/i18n/ja.json @@ -101,7 +101,10 @@ "submit": "ログイン", "username": "ユーザー名", "usernameTaken": "ユーザー名はすでに取得されています", - "wrongCredentials": "ユーザー名またはパスワードが間違っています" + "wrongCredentials": "ユーザー名またはパスワードが間違っています", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "永久", "prompts": { diff --git a/frontend/src/i18n/ko.json b/frontend/src/i18n/ko.json index 54307897..ec64bd62 100644 --- a/frontend/src/i18n/ko.json +++ b/frontend/src/i18n/ko.json @@ -101,7 +101,10 @@ "submit": "로그인", "username": "사용자 이름", "usernameTaken": "사용자 이름이 존재합니다", - "wrongCredentials": "사용자 이름 또는 비밀번호를 확인하십시오" + "wrongCredentials": "사용자 이름 또는 비밀번호를 확인하십시오", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "영구", "prompts": { diff --git a/frontend/src/i18n/nl-be.json b/frontend/src/i18n/nl-be.json index 860f12ed..c104ef81 100644 --- a/frontend/src/i18n/nl-be.json +++ b/frontend/src/i18n/nl-be.json @@ -101,7 +101,10 @@ "submit": "Log in", "username": "Gebruikersnaam", "usernameTaken": "Gebruikersnaam reeds in gebruik", - "wrongCredentials": "Verkeerde inloggegevens" + "wrongCredentials": "Verkeerde inloggegevens", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/frontend/src/i18n/no.json b/frontend/src/i18n/no.json index ae35e04e..b3ff472f 100644 --- a/frontend/src/i18n/no.json +++ b/frontend/src/i18n/no.json @@ -101,7 +101,10 @@ "submit": "Logg inn", "username": "Brukernavn", "usernameTaken": "Brukernavn er allerede i bruk", - "wrongCredentials": "Feil legitimasjon" + "wrongCredentials": "Feil legitimasjon", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/frontend/src/i18n/pl.json b/frontend/src/i18n/pl.json index 5837faa7..54dd9aed 100644 --- a/frontend/src/i18n/pl.json +++ b/frontend/src/i18n/pl.json @@ -101,7 +101,10 @@ "submit": "Zaloguj", "username": "Nazwa użytkownika", "usernameTaken": "Ta nazwa użytkownika jest zajęta", - "wrongCredentials": "Błędne dane logowania" + "wrongCredentials": "Błędne dane logowania", + "logout_reasons": { + "inactivity": "Wylogowano z powodu braku aktywności." + } }, "permanent": "Permanentny", "prompts": { diff --git a/frontend/src/i18n/pt-br.json b/frontend/src/i18n/pt-br.json index ccce0f4d..8e314c77 100644 --- a/frontend/src/i18n/pt-br.json +++ b/frontend/src/i18n/pt-br.json @@ -101,7 +101,10 @@ "submit": "Login", "username": "Nome do usuário", "usernameTaken": "Nome de usuário já existe", - "wrongCredentials": "Ops! Dados incorretos." + "wrongCredentials": "Ops! Dados incorretos.", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanente", "prompts": { diff --git a/frontend/src/i18n/pt.json b/frontend/src/i18n/pt.json index 7babc212..4c719cc9 100644 --- a/frontend/src/i18n/pt.json +++ b/frontend/src/i18n/pt.json @@ -101,7 +101,10 @@ "submit": "Entrar na conta", "username": "Nome de utilizador", "usernameTaken": "O nome de utilizador já está registado", - "wrongCredentials": "Dados errados" + "wrongCredentials": "Dados errados", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanente", "prompts": { diff --git a/frontend/src/i18n/ro.json b/frontend/src/i18n/ro.json index b03d8c21..232b0e4d 100644 --- a/frontend/src/i18n/ro.json +++ b/frontend/src/i18n/ro.json @@ -101,7 +101,10 @@ "submit": "Autentificare", "username": "Utilizator", "usernameTaken": "Utilizatorul există", - "wrongCredentials": "Informații greșite" + "wrongCredentials": "Informații greșite", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/frontend/src/i18n/ru.json b/frontend/src/i18n/ru.json index 3a9ff33a..931cf68d 100644 --- a/frontend/src/i18n/ru.json +++ b/frontend/src/i18n/ru.json @@ -101,7 +101,10 @@ "submit": "Войти", "username": "Имя пользователя", "usernameTaken": "Данное имя пользователя уже занято", - "wrongCredentials": "Неверные данные" + "wrongCredentials": "Неверные данные", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Постоянный", "prompts": { diff --git a/frontend/src/i18n/sk.json b/frontend/src/i18n/sk.json index d8b66b58..2f01ef8c 100644 --- a/frontend/src/i18n/sk.json +++ b/frontend/src/i18n/sk.json @@ -101,7 +101,10 @@ "submit": "Prihlásiť", "username": "Používateľské meno", "usernameTaken": "Meno je už obsadené", - "wrongCredentials": "Nesprávne prihlasovacie údaje" + "wrongCredentials": "Nesprávne prihlasovacie údaje", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Trvalé", "prompts": { diff --git a/frontend/src/i18n/sv-se.json b/frontend/src/i18n/sv-se.json index 11315728..319b7eb2 100644 --- a/frontend/src/i18n/sv-se.json +++ b/frontend/src/i18n/sv-se.json @@ -101,7 +101,10 @@ "submit": "Logga in", "username": "Användarnamn", "usernameTaken": "Användarnamn upptaget", - "wrongCredentials": "Fel inloggning" + "wrongCredentials": "Fel inloggning", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Permanent", "prompts": { diff --git a/frontend/src/i18n/tr.json b/frontend/src/i18n/tr.json index 6b87681c..aa0d3558 100644 --- a/frontend/src/i18n/tr.json +++ b/frontend/src/i18n/tr.json @@ -101,7 +101,10 @@ "submit": "Giriş", "username": "Kullanıcı adı", "usernameTaken": "Kullanıcı adı mevcut", - "wrongCredentials": "Yanlış hesap bilgileri" + "wrongCredentials": "Yanlış hesap bilgileri", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Kalıcı", "prompts": { diff --git a/frontend/src/i18n/uk.json b/frontend/src/i18n/uk.json index 7cddd910..d3f01c9f 100644 --- a/frontend/src/i18n/uk.json +++ b/frontend/src/i18n/uk.json @@ -101,7 +101,10 @@ "submit": "Увійти", "username": "Ім'я користувача", "usernameTaken": "Ім'я користувача вже використовується", - "wrongCredentials": "Неправильне ім'я користувача або пароль" + "wrongCredentials": "Неправильне ім'я користувача або пароль", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Постійний", "prompts": { diff --git a/frontend/src/i18n/vi.json b/frontend/src/i18n/vi.json index a84ea286..380f98ff 100644 --- a/frontend/src/i18n/vi.json +++ b/frontend/src/i18n/vi.json @@ -101,7 +101,10 @@ "submit": "Đăng nhập", "username": "Tên người dùng", "usernameTaken": "Tên người dùng đã tồn tại", - "wrongCredentials": "Thông tin đăng nhập không đúng" + "wrongCredentials": "Thông tin đăng nhập không đúng", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "Vĩnh viễn", "prompts": { diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json index c50e2d4e..c18c7e98 100644 --- a/frontend/src/i18n/zh-cn.json +++ b/frontend/src/i18n/zh-cn.json @@ -101,7 +101,10 @@ "submit": "登录", "username": "用户名", "usernameTaken": "用户名已经被使用", - "wrongCredentials": "用户名或密码错误" + "wrongCredentials": "用户名或密码错误", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "永久", "prompts": { diff --git a/frontend/src/i18n/zh-tw.json b/frontend/src/i18n/zh-tw.json index 1522e28d..adcfde91 100644 --- a/frontend/src/i18n/zh-tw.json +++ b/frontend/src/i18n/zh-tw.json @@ -101,7 +101,10 @@ "submit": "登入", "username": "帳號", "usernameTaken": "用戶名已存在", - "wrongCredentials": "帳號或密碼錯誤" + "wrongCredentials": "帳號或密碼錯誤", + "logout_reasons": { + "inactivity": "You have been logged out due to inactivity." + } }, "permanent": "永久", "prompts": { From dec7a027378fbc6948d203199c44a640a141bcad Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 14:26:24 +0000 Subject: [PATCH 026/202] feat: Translate frontend/src/i18n/en.json in no 100% translated source file: 'frontend/src/i18n/en.json' on 'no'. --- frontend/src/i18n/no.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/i18n/no.json b/frontend/src/i18n/no.json index b3ff472f..a3803ae9 100644 --- a/frontend/src/i18n/no.json +++ b/frontend/src/i18n/no.json @@ -103,7 +103,7 @@ "usernameTaken": "Brukernavn er allerede i bruk", "wrongCredentials": "Feil legitimasjon", "logout_reasons": { - "inactivity": "You have been logged out due to inactivity." + "inactivity": "Du har blitt logget ut på grunn av inaktivitet" } }, "permanent": "Permanent", From b9787c78f3889171f94db19e7655dce68c64b6fb Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 25 Sep 2025 16:47:00 +0200 Subject: [PATCH 027/202] feat: allow setting ace editor theme (#3826) Co-authored-by: Henrique Dias --- cmd/config.go | 1 + cmd/root.go | 7 +++-- cmd/users.go | 3 ++ .../components/settings/AceEditorTheme.vue | 24 ++++++++++++++ frontend/src/i18n/en.json | 1 + frontend/src/types/settings.d.ts | 1 + frontend/src/types/user.d.ts | 1 + frontend/src/utils/theme.ts | 16 ++++++++++ frontend/src/views/files/Editor.vue | 15 +++++---- frontend/src/views/settings/Profile.vue | 14 ++++++++- http/auth.go | 2 ++ settings/defaults.go | 20 ++++++------ tools/package.json | 3 +- users/users.go | 31 ++++++++++--------- 14 files changed, 104 insertions(+), 35 deletions(-) create mode 100644 frontend/src/components/settings/AceEditorTheme.vue diff --git a/cmd/config.go b/cmd/config.go index 5ce54ad9..ebb9c69f 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -221,6 +221,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut fmt.Fprintf(w, "\tFile Creation Mode:\t%O\n", set.FileMode) fmt.Fprintf(w, "\tDirectory Creation Mode:\t%O\n", set.DirMode) fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " ")) + fmt.Fprintf(w, "\tAce editor syntax highlighting theme:\t%s\n", set.Defaults.AceEditorTheme) fmt.Fprintf(w, "\tSorting:\n") fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By) fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc) diff --git a/cmd/root.go b/cmd/root.go index 286f6343..a9704cf4 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -424,9 +424,10 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) error { MinimumPasswordLength: settings.DefaultMinimumPasswordLength, UserHomeBasePath: settings.DefaultUsersHomeBasePath, Defaults: settings.UserDefaults{ - Scope: ".", - Locale: "en", - SingleClick: false, + Scope: ".", + Locale: "en", + SingleClick: false, + AceEditorTheme: getStringParam(flags, "defaults.aceEditorTheme"), Perm: users.Permissions{ Admin: false, Execute: true, diff --git a/cmd/users.go b/cmd/users.go index dd3d1f52..5b458a5a 100644 --- a/cmd/users.go +++ b/cmd/users.go @@ -79,6 +79,7 @@ func addUserFlags(flags *pflag.FlagSet) { flags.Bool("singleClick", false, "use single clicks only") flags.Bool("dateFormat", false, "use date format (true for absolute time, false for relative)") flags.Bool("hideDotfiles", false, "hide dotfiles") + flags.String("aceEditorTheme", "", "ace editor's syntax highlighting theme for users") } func getViewMode(flags *pflag.FlagSet) (users.ViewMode, error) { @@ -110,6 +111,8 @@ func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all defaults.ViewMode, err = getViewMode(flags) case "singleClick": defaults.SingleClick, err = getBool(flags, flag.Name) + case "aceEditorTheme": + defaults.AceEditorTheme, err = getString(flags, flag.Name) case "perm.admin": defaults.Perm.Admin, err = getBool(flags, flag.Name) case "perm.execute": diff --git a/frontend/src/components/settings/AceEditorTheme.vue b/frontend/src/components/settings/AceEditorTheme.vue new file mode 100644 index 00000000..09efe48b --- /dev/null +++ b/frontend/src/components/settings/AceEditorTheme.vue @@ -0,0 +1,24 @@ + + + diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index 9411d91e..b6325511 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrator", "allowCommands": "Execute commands", diff --git a/frontend/src/types/settings.d.ts b/frontend/src/types/settings.d.ts index 90ca6ae7..ba56c612 100644 --- a/frontend/src/types/settings.d.ts +++ b/frontend/src/types/settings.d.ts @@ -21,6 +21,7 @@ interface SettingsDefaults { commands: any[]; hideDotfiles: boolean; dateFormat: boolean; + aceEditorTheme: string; } interface SettingsBranding { diff --git a/frontend/src/types/user.d.ts b/frontend/src/types/user.d.ts index b81806fc..40c453c5 100644 --- a/frontend/src/types/user.d.ts +++ b/frontend/src/types/user.d.ts @@ -13,6 +13,7 @@ interface IUser { dateFormat: boolean; viewMode: ViewModeType; sorting?: Sorting; + aceEditorTheme: string; } type ViewModeType = "list" | "mosaic" | "mosaic gallery"; diff --git a/frontend/src/utils/theme.ts b/frontend/src/utils/theme.ts index 8058356a..0244b044 100644 --- a/frontend/src/utils/theme.ts +++ b/frontend/src/utils/theme.ts @@ -1,4 +1,6 @@ import { theme } from "./constants"; +import "ace-builds"; +import { themesByName } from "ace-builds/src-noconflict/ext-themelist"; export const getTheme = (): UserTheme => { return (document.documentElement.className as UserTheme) || theme; @@ -32,3 +34,17 @@ export const getMediaPreference = (): UserTheme => { return "light"; } }; + +export const getEditorTheme = (themeName: string) => { + if (!themeName.startsWith("ace/theme/")) { + themeName = `ace/theme/${themeName}`; + } + const themeKey = themeName.replace("ace/theme/", ""); + if (themesByName[themeKey] !== undefined) { + return themeName; + } else if (getTheme() === "dark") { + return "ace/theme/twilight"; + } else { + return "ace/theme/chrome"; + } +}; diff --git a/frontend/src/views/files/Editor.vue b/frontend/src/views/files/Editor.vue index 13013a9f..f3d9aa94 100644 --- a/frontend/src/views/files/Editor.vue +++ b/frontend/src/views/files/Editor.vue @@ -69,7 +69,7 @@ import HeaderBar from "@/components/header/HeaderBar.vue"; import { useAuthStore } from "@/stores/auth"; import { useFileStore } from "@/stores/file"; import { useLayoutStore } from "@/stores/layout"; -import { getTheme } from "@/utils/theme"; +import { getEditorTheme } from "@/utils/theme"; import { marked } from "marked"; import { inject, onBeforeUnmount, onMounted, ref, watchEffect } from "vue"; import { useI18n } from "vue-i18n"; @@ -122,7 +122,7 @@ onMounted(() => { value: fileContent, showPrintMargin: false, readOnly: fileStore.req?.type === "textImmutable", - theme: "ace/theme/chrome", + theme: getEditorTheme(authStore.user?.aceEditorTheme ?? ""), mode: modelist.getModeForPath(fileStore.req!.name).mode, wrap: true, enableBasicAutocompletion: true, @@ -130,10 +130,6 @@ onMounted(() => { enableSnippets: true, }); - if (getTheme() === "dark") { - editor.value!.setTheme("ace/theme/twilight"); - } - editor.value.setFontSize(fontSize.value); editor.value.focus(); }); @@ -219,6 +215,13 @@ const decreaseFontSize = () => { }; const close = () => { + if (!editor.value?.session.getUndoManager().isClean()) { + layoutStore.showHover("discardEditorChanges"); + return; + } + + fileStore.updateRequest(null); + const uri = url.removeLastDir(route.path) + "/"; router.push({ path: uri }); }; diff --git a/frontend/src/views/settings/Profile.vue b/frontend/src/views/settings/Profile.vue index c677092f..1b079473 100644 --- a/frontend/src/views/settings/Profile.vue +++ b/frontend/src/views/settings/Profile.vue @@ -24,6 +24,13 @@ class="input input--block" v-model:locale="locale" > + +

{{ t("settings.aceEditorTheme") }}

+
@@ -81,6 +88,7 @@ import { useAuthStore } from "@/stores/auth"; import { useLayoutStore } from "@/stores/layout"; import { users as api } from "@/api"; +import AceEditorTheme from "@/components/settings/AceEditorTheme.vue"; import Languages from "@/components/settings/Languages.vue"; import { computed, inject, onMounted, ref } from "vue"; import { useI18n } from "vue-i18n"; @@ -98,6 +106,7 @@ const hideDotfiles = ref(false); const singleClick = ref(false); const dateFormat = ref(false); const locale = ref(""); +const aceEditorTheme = ref(""); const passwordClass = computed(() => { const baseClass = "input input--block"; @@ -113,13 +122,14 @@ const passwordClass = computed(() => { return `${baseClass} input--red`; }); -onMounted(() => { +onMounted(async () => { layoutStore.loading = true; if (authStore.user === null) return false; locale.value = authStore.user.locale; hideDotfiles.value = authStore.user.hideDotfiles; singleClick.value = authStore.user.singleClick; dateFormat.value = authStore.user.dateFormat; + aceEditorTheme.value = authStore.user.aceEditorTheme; layoutStore.loading = false; return true; }); @@ -163,6 +173,7 @@ const updateSettings = async (event: Event) => { hideDotfiles: hideDotfiles.value, singleClick: singleClick.value, dateFormat: dateFormat.value, + aceEditorTheme: aceEditorTheme.value, }; await api.update(data, [ @@ -170,6 +181,7 @@ const updateSettings = async (event: Event) => { "hideDotfiles", "singleClick", "dateFormat", + "aceEditorTheme", ]); authStore.updateUser(data); $showSuccess(t("settings.settingsUpdated")); diff --git a/http/auth.go b/http/auth.go index 0ecaed14..62d6779e 100644 --- a/http/auth.go +++ b/http/auth.go @@ -31,6 +31,7 @@ type userInfo struct { HideDotfiles bool `json:"hideDotfiles"` DateFormat bool `json:"dateFormat"` Username string `json:"username"` + AceEditorTheme string `json:"aceEditorTheme"` } type authToken struct { @@ -200,6 +201,7 @@ func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.Use HideDotfiles: user.HideDotfiles, DateFormat: user.DateFormat, Username: user.Username, + AceEditorTheme: user.AceEditorTheme, }, RegisteredClaims: jwt.RegisteredClaims{ IssuedAt: jwt.NewNumericDate(time.Now()), diff --git a/settings/defaults.go b/settings/defaults.go index d60e36dc..5b6c3f2a 100644 --- a/settings/defaults.go +++ b/settings/defaults.go @@ -8,15 +8,16 @@ import ( // UserDefaults is a type that holds the default values // for some fields on User. type UserDefaults struct { - Scope string `json:"scope"` - Locale string `json:"locale"` - ViewMode users.ViewMode `json:"viewMode"` - SingleClick bool `json:"singleClick"` - Sorting files.Sorting `json:"sorting"` - Perm users.Permissions `json:"perm"` - Commands []string `json:"commands"` - HideDotfiles bool `json:"hideDotfiles"` - DateFormat bool `json:"dateFormat"` + Scope string `json:"scope"` + Locale string `json:"locale"` + ViewMode users.ViewMode `json:"viewMode"` + SingleClick bool `json:"singleClick"` + Sorting files.Sorting `json:"sorting"` + Perm users.Permissions `json:"perm"` + Commands []string `json:"commands"` + HideDotfiles bool `json:"hideDotfiles"` + DateFormat bool `json:"dateFormat"` + AceEditorTheme string `json:"aceEditorTheme"` } // Apply applies the default options to a user. @@ -30,4 +31,5 @@ func (d *UserDefaults) Apply(u *users.User) { u.Commands = d.Commands u.HideDotfiles = d.HideDotfiles u.DateFormat = d.DateFormat + u.AceEditorTheme = d.AceEditorTheme } diff --git a/tools/package.json b/tools/package.json index 9a2bd1c6..9433b94e 100644 --- a/tools/package.json +++ b/tools/package.json @@ -3,5 +3,6 @@ "@commitlint/cli": "^15.0.0", "@commitlint/config-conventional": "^15.0.0", "standard-version": "^9.3.2" - } + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/users/users.go b/users/users.go index e0310f21..020faf11 100644 --- a/users/users.go +++ b/users/users.go @@ -20,21 +20,22 @@ const ( // User describes a user. type User struct { - ID uint `storm:"id,increment" json:"id"` - Username string `storm:"unique" json:"username"` - Password string `json:"password"` - Scope string `json:"scope"` - Locale string `json:"locale"` - LockPassword bool `json:"lockPassword"` - ViewMode ViewMode `json:"viewMode"` - SingleClick bool `json:"singleClick"` - Perm Permissions `json:"perm"` - Commands []string `json:"commands"` - Sorting files.Sorting `json:"sorting"` - Fs afero.Fs `json:"-" yaml:"-"` - Rules []rules.Rule `json:"rules"` - HideDotfiles bool `json:"hideDotfiles"` - DateFormat bool `json:"dateFormat"` + ID uint `storm:"id,increment" json:"id"` + Username string `storm:"unique" json:"username"` + Password string `json:"password"` + Scope string `json:"scope"` + Locale string `json:"locale"` + LockPassword bool `json:"lockPassword"` + ViewMode ViewMode `json:"viewMode"` + SingleClick bool `json:"singleClick"` + Perm Permissions `json:"perm"` + Commands []string `json:"commands"` + Sorting files.Sorting `json:"sorting"` + Fs afero.Fs `json:"-" yaml:"-"` + Rules []rules.Rule `json:"rules"` + HideDotfiles bool `json:"hideDotfiles"` + DateFormat bool `json:"dateFormat"` + AceEditorTheme string `json:"aceEditorTheme"` } // GetRules implements rules.Provider. From 692ca5eaf01e4dcf346ba03f82c5dbd50cce246b Mon Sep 17 00:00:00 2001 From: MSomnium Studios <70982507+ArielLeyva@users.noreply.github.com> Date: Thu, 25 Sep 2025 10:54:28 -0400 Subject: [PATCH 028/202] fix(upload): throttle upload speed calculation to 100ms to avoid Infinity MB/s (#5456) Co-authored-by: Henrique Dias --- .../src/components/prompts/UploadFiles.vue | 29 ++++++++++++-- http/auth.go | 40 +++++++++---------- 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/frontend/src/components/prompts/UploadFiles.vue b/frontend/src/components/prompts/UploadFiles.vue index 883fffe3..4d96d5bb 100644 --- a/frontend/src/components/prompts/UploadFiles.vue +++ b/frontend/src/components/prompts/UploadFiles.vue @@ -14,7 +14,7 @@ }}
-
{{ speedMbytes }}/s
+
{{ speedText }}/s
{{ formattedETA }} remaining
{{ sentPercent }}% Completed
@@ -88,6 +88,7 @@ const uploadStore = useUploadStore(); const { sentBytes, totalBytes } = storeToRefs(uploadStore); const byteToMbyte = partial({ exponent: 2 }); +const byteToKbyte = partial({ exponent: 1 }); const sentPercent = computed(() => ((uploadStore.sentBytes / uploadStore.totalBytes) * 100).toFixed(2) @@ -95,11 +96,33 @@ const sentPercent = computed(() => const sentMbytes = computed(() => byteToMbyte(uploadStore.sentBytes)); const totalMbytes = computed(() => byteToMbyte(uploadStore.totalBytes)); -const speedMbytes = computed(() => byteToMbyte(speed.value)); +const speedText = computed(() => { + const bytes = speed.value; + + if (bytes < 1024 * 1024) { + const kb = parseFloat(byteToKbyte(bytes)); + return `${kb.toFixed(2)} KB`; + } else { + const mb = parseFloat(byteToMbyte(bytes)); + return `${mb.toFixed(2)} MB`; + } +}); let lastSpeedUpdate: number = 0; let recentSpeeds: number[] = []; +let lastThrottleTime = 0; + +const throttledCalculateSpeed = (sentBytes: number, oldSentBytes: number) => { + const now = Date.now(); + if (now - lastThrottleTime < 100) { + return; + } + + lastThrottleTime = now; + calculateSpeed(sentBytes, oldSentBytes); +}; + const calculateSpeed = (sentBytes: number, oldSentBytes: number) => { // Reset the state when the uploads batch is complete if (sentBytes === 0) { @@ -149,7 +172,7 @@ const calculateEta = () => { eta.value = remainingSize / speedBytesPerSecond; }; -watch(sentBytes, calculateSpeed); +watch(sentBytes, throttledCalculateSpeed); watch(totalBytes, (totalBytes, oldTotalBytes) => { if (oldTotalBytes !== 0) { diff --git a/http/auth.go b/http/auth.go index 62d6779e..18d10025 100644 --- a/http/auth.go +++ b/http/auth.go @@ -21,16 +21,16 @@ const ( ) type userInfo struct { - ID uint `json:"id"` - Locale string `json:"locale"` - ViewMode users.ViewMode `json:"viewMode"` - SingleClick bool `json:"singleClick"` - Perm users.Permissions `json:"perm"` - Commands []string `json:"commands"` - LockPassword bool `json:"lockPassword"` - HideDotfiles bool `json:"hideDotfiles"` - DateFormat bool `json:"dateFormat"` - Username string `json:"username"` + ID uint `json:"id"` + Locale string `json:"locale"` + ViewMode users.ViewMode `json:"viewMode"` + SingleClick bool `json:"singleClick"` + Perm users.Permissions `json:"perm"` + Commands []string `json:"commands"` + LockPassword bool `json:"lockPassword"` + HideDotfiles bool `json:"hideDotfiles"` + DateFormat bool `json:"dateFormat"` + Username string `json:"username"` AceEditorTheme string `json:"aceEditorTheme"` } @@ -191,16 +191,16 @@ func renewHandler(tokenExpireTime time.Duration) handleFunc { func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User, tokenExpirationTime time.Duration) (int, error) { claims := &authToken{ User: userInfo{ - ID: user.ID, - Locale: user.Locale, - ViewMode: user.ViewMode, - SingleClick: user.SingleClick, - Perm: user.Perm, - LockPassword: user.LockPassword, - Commands: user.Commands, - HideDotfiles: user.HideDotfiles, - DateFormat: user.DateFormat, - Username: user.Username, + ID: user.ID, + Locale: user.Locale, + ViewMode: user.ViewMode, + SingleClick: user.SingleClick, + Perm: user.Perm, + LockPassword: user.LockPassword, + Commands: user.Commands, + HideDotfiles: user.HideDotfiles, + DateFormat: user.DateFormat, + Username: user.Username, AceEditorTheme: user.AceEditorTheme, }, RegisteredClaims: jwt.RegisteredClaims{ From d29ad356d1067c87b2821debab91286549f512a0 Mon Sep 17 00:00:00 2001 From: MSomnium Studios <70982507+ArielLeyva@users.noreply.github.com> Date: Thu, 25 Sep 2025 10:57:30 -0400 Subject: [PATCH 029/202] feat: Improved path display in the new file and directory modal (#5451) --- .../src/components/prompts/CreateFilePath.vue | 87 +++++++++++++++++++ frontend/src/components/prompts/NewDir.vue | 2 + frontend/src/components/prompts/NewFile.vue | 2 + 3 files changed, 91 insertions(+) create mode 100644 frontend/src/components/prompts/CreateFilePath.vue diff --git a/frontend/src/components/prompts/CreateFilePath.vue b/frontend/src/components/prompts/CreateFilePath.vue new file mode 100644 index 00000000..9636b6cc --- /dev/null +++ b/frontend/src/components/prompts/CreateFilePath.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/frontend/src/components/prompts/NewDir.vue b/frontend/src/components/prompts/NewDir.vue index 1eb6d481..85d47bb8 100644 --- a/frontend/src/components/prompts/NewDir.vue +++ b/frontend/src/components/prompts/NewDir.vue @@ -14,6 +14,7 @@ v-model.trim="name" tabindex="1" /> +
@@ -48,6 +49,7 @@ import { files as api } from "@/api"; import url from "@/utils/url"; import { useRoute, useRouter } from "vue-router"; import { useI18n } from "vue-i18n"; +import CreateFilePath from "@/components/prompts/CreateFilePath.vue"; const $showError = inject("$showError")!; diff --git a/frontend/src/components/prompts/NewFile.vue b/frontend/src/components/prompts/NewFile.vue index b7c05d44..d3fb34ed 100644 --- a/frontend/src/components/prompts/NewFile.vue +++ b/frontend/src/components/prompts/NewFile.vue @@ -13,6 +13,7 @@ @keyup.enter="submit" v-model.trim="name" /> +
@@ -42,6 +43,7 @@ import { useI18n } from "vue-i18n"; import { useRoute, useRouter } from "vue-router"; import { useFileStore } from "@/stores/file"; import { useLayoutStore } from "@/stores/layout"; +import CreateFilePath from "@/components/prompts/CreateFilePath.vue"; import { files as api } from "@/api"; import url from "@/utils/url"; From c4725428e07da72b855009e2c13c6ed91d32e0b7 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Thu, 25 Sep 2025 17:09:16 +0200 Subject: [PATCH 030/202] fix: computation of file path --- frontend/src/components/prompts/CreateFilePath.vue | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/prompts/CreateFilePath.vue b/frontend/src/components/prompts/CreateFilePath.vue index 9636b6cc..ec470f3a 100644 --- a/frontend/src/components/prompts/CreateFilePath.vue +++ b/frontend/src/components/prompts/CreateFilePath.vue @@ -41,12 +41,11 @@ const container = ref(null); const path = computed(() => { let basePath = fileStore.isFiles ? route.path : url.removeLastDir(route.path); + if (!basePath.endsWith("/")) { + basePath += "/"; + } basePath += props.name; - - return basePath - .replace(/^\/[^\/]+/, "") - .split("/") - .filter(Boolean); + return basePath.split("/").filter(Boolean).splice(1); }); watch(path, () => { From 949ddffef20e38169902c5fd74dca4815dcecf11 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Thu, 25 Sep 2025 17:13:30 +0200 Subject: [PATCH 031/202] fix: some formatting issues with i18n files --- frontend/src/i18n/ar.json | 4 ++-- frontend/src/i18n/ca.json | 4 ++-- frontend/src/i18n/cs.json | 4 ++-- frontend/src/i18n/de.json | 4 ++-- frontend/src/i18n/el.json | 4 ++-- frontend/src/i18n/en.json | 4 ++-- frontend/src/i18n/es.json | 4 ++-- frontend/src/i18n/fa.json | 4 ++-- frontend/src/i18n/fr.json | 4 ++-- frontend/src/i18n/he.json | 4 ++-- frontend/src/i18n/hu.json | 4 ++-- frontend/src/i18n/is.json | 4 ++-- frontend/src/i18n/it.json | 4 ++-- frontend/src/i18n/ja.json | 4 ++-- frontend/src/i18n/ko.json | 4 ++-- frontend/src/i18n/nl-be.json | 4 ++-- frontend/src/i18n/no.json | 4 ++-- frontend/src/i18n/pl.json | 4 ++-- frontend/src/i18n/pt-br.json | 4 ++-- frontend/src/i18n/pt.json | 4 ++-- frontend/src/i18n/ro.json | 4 ++-- frontend/src/i18n/ru.json | 4 ++-- frontend/src/i18n/sk.json | 4 ++-- frontend/src/i18n/sv-se.json | 4 ++-- frontend/src/i18n/tr.json | 4 ++-- frontend/src/i18n/uk.json | 4 ++-- frontend/src/i18n/vi.json | 4 ++-- frontend/src/i18n/zh-cn.json | 4 ++-- frontend/src/i18n/zh-tw.json | 4 ++-- 29 files changed, 58 insertions(+), 58 deletions(-) diff --git a/frontend/src/i18n/ar.json b/frontend/src/i18n/ar.json index 70feef51..9b06d2d3 100644 --- a/frontend/src/i18n/ar.json +++ b/frontend/src/i18n/ar.json @@ -42,8 +42,8 @@ "update": "تحديث", "upload": "رفع", "openFile": "فتح الملف", - "discardChanges": "إلغاء التغييرات", - "saveChanges": "Save changes" + "discardChanges": "إلغاء التغييرات", + "saveChanges": "Save changes" }, "download": { "downloadFile": "تحميل الملف", diff --git a/frontend/src/i18n/ca.json b/frontend/src/i18n/ca.json index 4d698fa5..353eeb22 100644 --- a/frontend/src/i18n/ca.json +++ b/frontend/src/i18n/ca.json @@ -42,8 +42,8 @@ "update": "Actualitzar", "upload": "Pujar", "openFile": "Obrir fitxer", - "discardChanges": "Descartar", - "saveChanges": "Save changes" + "discardChanges": "Descartar", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Descarregar fitxer", diff --git a/frontend/src/i18n/cs.json b/frontend/src/i18n/cs.json index c7e32842..635a1d96 100644 --- a/frontend/src/i18n/cs.json +++ b/frontend/src/i18n/cs.json @@ -42,8 +42,8 @@ "update": "Aktualizovat", "upload": "Nahrát", "openFile": "Otevřít soubor", - "discardChanges": "Zrušit změny", - "saveChanges": "Save changes" + "discardChanges": "Zrušit změny", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Stáhnout soubor", diff --git a/frontend/src/i18n/de.json b/frontend/src/i18n/de.json index d22a3be1..40971820 100644 --- a/frontend/src/i18n/de.json +++ b/frontend/src/i18n/de.json @@ -42,8 +42,8 @@ "update": "Update", "upload": "Upload", "openFile": "Datei öffnen", - "discardChanges": "Verwerfen", - "saveChanges": "Save changes" + "discardChanges": "Verwerfen", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Download Datei", diff --git a/frontend/src/i18n/el.json b/frontend/src/i18n/el.json index 9fed72f1..ba75606f 100644 --- a/frontend/src/i18n/el.json +++ b/frontend/src/i18n/el.json @@ -42,8 +42,8 @@ "update": "Ενημέρωση", "upload": "Μεταφόρτωση", "openFile": "Άνοιγμα αρχείου", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Λήψη αρχείου", diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index b6325511..15a297df 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -42,8 +42,8 @@ "update": "Update", "upload": "Upload", "openFile": "Open file", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Download File", diff --git a/frontend/src/i18n/es.json b/frontend/src/i18n/es.json index e7f9e882..a3565f4f 100644 --- a/frontend/src/i18n/es.json +++ b/frontend/src/i18n/es.json @@ -42,8 +42,8 @@ "update": "Actualizar", "upload": "Subir", "openFile": "Abrir archivo", - "discardChanges": "Discard", - "saveChanges": "Guardar cambios" + "discardChanges": "Discard", + "saveChanges": "Guardar cambios" }, "download": { "downloadFile": "Descargar fichero", diff --git a/frontend/src/i18n/fa.json b/frontend/src/i18n/fa.json index 70e10c12..e4a2532e 100644 --- a/frontend/src/i18n/fa.json +++ b/frontend/src/i18n/fa.json @@ -42,8 +42,8 @@ "update": "به روز سانی", "upload": "آپلود", "openFile": "باز کردن فایل", - "discardChanges": "لغو کردن", - "saveChanges": "Save changes" + "discardChanges": "لغو کردن", + "saveChanges": "Save changes" }, "download": { "downloadFile": "دانلود فایل", diff --git a/frontend/src/i18n/fr.json b/frontend/src/i18n/fr.json index 16508807..fcbd239b 100644 --- a/frontend/src/i18n/fr.json +++ b/frontend/src/i18n/fr.json @@ -42,8 +42,8 @@ "update": "Mettre à jour", "upload": "Importer", "openFile": "Ouvrir le fichier", - "discardChanges": "Annuler", - "saveChanges": "Save changes" + "discardChanges": "Annuler", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Télécharger le fichier", diff --git a/frontend/src/i18n/he.json b/frontend/src/i18n/he.json index a8e89a93..9bb3145a 100644 --- a/frontend/src/i18n/he.json +++ b/frontend/src/i18n/he.json @@ -42,8 +42,8 @@ "update": "עדכון", "upload": "העלאה", "openFile": "פתח קובץ", - "discardChanges": "זריקת השינויים", - "saveChanges": "Save changes" + "discardChanges": "זריקת השינויים", + "saveChanges": "Save changes" }, "download": { "downloadFile": "הורד קובץ", diff --git a/frontend/src/i18n/hu.json b/frontend/src/i18n/hu.json index 00fc419e..0971d9cc 100644 --- a/frontend/src/i18n/hu.json +++ b/frontend/src/i18n/hu.json @@ -42,8 +42,8 @@ "update": "Frissítés", "upload": "Feltöltés", "openFile": "Fájl megnyitása", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Fájl letöltése", diff --git a/frontend/src/i18n/is.json b/frontend/src/i18n/is.json index c55455e5..65a5eb00 100644 --- a/frontend/src/i18n/is.json +++ b/frontend/src/i18n/is.json @@ -42,8 +42,8 @@ "update": "Vista", "upload": "Hlaða upp", "openFile": "Open file", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Sækja skjal", diff --git a/frontend/src/i18n/it.json b/frontend/src/i18n/it.json index 995ba7cd..b1135aac 100644 --- a/frontend/src/i18n/it.json +++ b/frontend/src/i18n/it.json @@ -42,8 +42,8 @@ "update": "Aggiorna", "upload": "Carica", "openFile": "Apri file", - "discardChanges": "Ignora", - "saveChanges": "Save changes" + "discardChanges": "Ignora", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Scarica file", diff --git a/frontend/src/i18n/ja.json b/frontend/src/i18n/ja.json index 99e4b017..574bf59a 100644 --- a/frontend/src/i18n/ja.json +++ b/frontend/src/i18n/ja.json @@ -42,8 +42,8 @@ "update": "更新", "upload": "アップロード", "openFile": "ファイルを開く", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "ファイルのダウンロード", diff --git a/frontend/src/i18n/ko.json b/frontend/src/i18n/ko.json index ec64bd62..ea5a1e67 100644 --- a/frontend/src/i18n/ko.json +++ b/frontend/src/i18n/ko.json @@ -42,8 +42,8 @@ "update": "업데이트", "upload": "업로드", "openFile": "파일 열기", - "discardChanges": "변경 사항 취소", - "saveChanges": "변경사항 저장" + "discardChanges": "변경 사항 취소", + "saveChanges": "변경사항 저장" }, "download": { "downloadFile": "파일 다운로드", diff --git a/frontend/src/i18n/nl-be.json b/frontend/src/i18n/nl-be.json index c104ef81..af659e5c 100644 --- a/frontend/src/i18n/nl-be.json +++ b/frontend/src/i18n/nl-be.json @@ -42,8 +42,8 @@ "update": "Updaten", "upload": "Uploaden", "openFile": "Open file", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Bestand downloaden", diff --git a/frontend/src/i18n/no.json b/frontend/src/i18n/no.json index a3803ae9..08c6992c 100644 --- a/frontend/src/i18n/no.json +++ b/frontend/src/i18n/no.json @@ -42,8 +42,8 @@ "update": "Opptater", "upload": "Last opp", "openFile": "Open file", - "discardChanges": "Slett", - "saveChanges": "Lagre Endringane " + "discardChanges": "Slett", + "saveChanges": "Lagre Endringane " }, "download": { "downloadFile": "Nedlast filen", diff --git a/frontend/src/i18n/pl.json b/frontend/src/i18n/pl.json index 54dd9aed..06f1c8fd 100644 --- a/frontend/src/i18n/pl.json +++ b/frontend/src/i18n/pl.json @@ -42,8 +42,8 @@ "update": "Aktualizuj", "upload": "Wyślij", "openFile": "Otwórz plik", - "discardChanges": "Odrzuć", - "saveChanges": "Zapisz zmiany" + "discardChanges": "Odrzuć", + "saveChanges": "Zapisz zmiany" }, "download": { "downloadFile": "Pobierz plik", diff --git a/frontend/src/i18n/pt-br.json b/frontend/src/i18n/pt-br.json index 8e314c77..a4938c49 100644 --- a/frontend/src/i18n/pt-br.json +++ b/frontend/src/i18n/pt-br.json @@ -42,8 +42,8 @@ "update": "Atualizar", "upload": "Enviar", "openFile": "Abrir", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Baixar arquivo", diff --git a/frontend/src/i18n/pt.json b/frontend/src/i18n/pt.json index 4c719cc9..2555eafb 100644 --- a/frontend/src/i18n/pt.json +++ b/frontend/src/i18n/pt.json @@ -42,8 +42,8 @@ "update": "Atualizar", "upload": "Enviar", "openFile": "Open file", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Descarregar ficheiro", diff --git a/frontend/src/i18n/ro.json b/frontend/src/i18n/ro.json index 232b0e4d..5f4a630e 100644 --- a/frontend/src/i18n/ro.json +++ b/frontend/src/i18n/ro.json @@ -42,8 +42,8 @@ "update": "Actualizează", "upload": "Încarcă", "openFile": "Open file", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Descarcă fișier", diff --git a/frontend/src/i18n/ru.json b/frontend/src/i18n/ru.json index 931cf68d..d9407647 100644 --- a/frontend/src/i18n/ru.json +++ b/frontend/src/i18n/ru.json @@ -42,8 +42,8 @@ "update": "Обновить", "upload": "Загрузить", "openFile": "Открыть файл", - "discardChanges": "Отказаться", - "saveChanges": "Save changes" + "discardChanges": "Отказаться", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Скачать файл", diff --git a/frontend/src/i18n/sk.json b/frontend/src/i18n/sk.json index 2f01ef8c..06c73a98 100644 --- a/frontend/src/i18n/sk.json +++ b/frontend/src/i18n/sk.json @@ -42,8 +42,8 @@ "update": "Aktualizovať", "upload": "Nahrať", "openFile": "Otvoriť súbor", - "discardChanges": "Zahodiť", - "saveChanges": "Save changes" + "discardChanges": "Zahodiť", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Stiahnuť súbor", diff --git a/frontend/src/i18n/sv-se.json b/frontend/src/i18n/sv-se.json index 319b7eb2..47c041c0 100644 --- a/frontend/src/i18n/sv-se.json +++ b/frontend/src/i18n/sv-se.json @@ -42,8 +42,8 @@ "update": "Uppdatera", "upload": "Ladda upp", "openFile": "Open file", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Ladda ner fil", diff --git a/frontend/src/i18n/tr.json b/frontend/src/i18n/tr.json index aa0d3558..ed635501 100644 --- a/frontend/src/i18n/tr.json +++ b/frontend/src/i18n/tr.json @@ -42,8 +42,8 @@ "update": "Güncelle", "upload": "Yükle", "openFile": "Dosyayı aç", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Dosyayı indir", diff --git a/frontend/src/i18n/uk.json b/frontend/src/i18n/uk.json index d3f01c9f..a81010f6 100644 --- a/frontend/src/i18n/uk.json +++ b/frontend/src/i18n/uk.json @@ -42,8 +42,8 @@ "update": "Оновити", "upload": "Вивантажити", "openFile": "Відкрити файл", - "discardChanges": "Скасувати", - "saveChanges": "Save changes" + "discardChanges": "Скасувати", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Завантажити файл", diff --git a/frontend/src/i18n/vi.json b/frontend/src/i18n/vi.json index 380f98ff..07864ce8 100644 --- a/frontend/src/i18n/vi.json +++ b/frontend/src/i18n/vi.json @@ -42,8 +42,8 @@ "update": "Cập nhật", "upload": "Tải lên", "openFile": "Mở tệp", - "discardChanges": "Hủy bỏ thay đổi", - "saveChanges": "Save changes" + "discardChanges": "Hủy bỏ thay đổi", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Tải xuống tệp tin", diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json index c18c7e98..6a8b9065 100644 --- a/frontend/src/i18n/zh-cn.json +++ b/frontend/src/i18n/zh-cn.json @@ -42,8 +42,8 @@ "update": "更新", "upload": "上传", "openFile": "打开文件", - "discardChanges": "放弃更改", - "saveChanges": "Save changes" + "discardChanges": "放弃更改", + "saveChanges": "Save changes" }, "download": { "downloadFile": "下载文件", diff --git a/frontend/src/i18n/zh-tw.json b/frontend/src/i18n/zh-tw.json index adcfde91..4ceb886c 100644 --- a/frontend/src/i18n/zh-tw.json +++ b/frontend/src/i18n/zh-tw.json @@ -42,8 +42,8 @@ "update": "更新", "upload": "上傳", "openFile": "開啟檔案", - "discardChanges": "放棄變更", - "saveChanges": "Save changes" + "discardChanges": "放棄變更", + "saveChanges": "Save changes" }, "download": { "downloadFile": "下載檔案", From 1165f00bd4dcb0dcfbc084f54f51902ba4b4a714 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 17:19:21 +0200 Subject: [PATCH 032/202] feat: Updates for project File Browser (#5457) Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- frontend/src/i18n/ar.json | 1 + frontend/src/i18n/ca.json | 1 + frontend/src/i18n/cs.json | 1 + frontend/src/i18n/de.json | 1 + frontend/src/i18n/el.json | 1 + frontend/src/i18n/es.json | 1 + frontend/src/i18n/fa.json | 1 + frontend/src/i18n/fr.json | 1 + frontend/src/i18n/he.json | 1 + frontend/src/i18n/hu.json | 1 + frontend/src/i18n/is.json | 1 + frontend/src/i18n/it.json | 1 + frontend/src/i18n/ja.json | 1 + frontend/src/i18n/ko.json | 1 + frontend/src/i18n/nl-be.json | 1 + frontend/src/i18n/no.json | 1 + frontend/src/i18n/pl.json | 1 + frontend/src/i18n/pt-br.json | 1 + frontend/src/i18n/pt.json | 1 + frontend/src/i18n/ro.json | 1 + frontend/src/i18n/ru.json | 1 + frontend/src/i18n/sk.json | 1 + frontend/src/i18n/sv-se.json | 1 + frontend/src/i18n/tr.json | 1 + frontend/src/i18n/uk.json | 1 + frontend/src/i18n/vi.json | 1 + frontend/src/i18n/zh-cn.json | 1 + frontend/src/i18n/zh-tw.json | 1 + 28 files changed, 28 insertions(+) diff --git a/frontend/src/i18n/ar.json b/frontend/src/i18n/ar.json index 9b06d2d3..26e95765 100644 --- a/frontend/src/i18n/ar.json +++ b/frontend/src/i18n/ar.json @@ -158,6 +158,7 @@ "video": "فيديوهات" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "إدارة", "administrator": "مدير", "allowCommands": "تنفيذ اﻷوامر", diff --git a/frontend/src/i18n/ca.json b/frontend/src/i18n/ca.json index 353eeb22..e17c7c80 100644 --- a/frontend/src/i18n/ca.json +++ b/frontend/src/i18n/ca.json @@ -158,6 +158,7 @@ "video": "Vídeo" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrador", "allowCommands": "Executar comandes", diff --git a/frontend/src/i18n/cs.json b/frontend/src/i18n/cs.json index 635a1d96..914b843f 100644 --- a/frontend/src/i18n/cs.json +++ b/frontend/src/i18n/cs.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrátor", "allowCommands": "Povolit příkazy", diff --git a/frontend/src/i18n/de.json b/frontend/src/i18n/de.json index 40971820..48c91eb8 100644 --- a/frontend/src/i18n/de.json +++ b/frontend/src/i18n/de.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrator", "allowCommands": "Befehle ausführen", diff --git a/frontend/src/i18n/el.json b/frontend/src/i18n/el.json index ba75606f..97206a1f 100644 --- a/frontend/src/i18n/el.json +++ b/frontend/src/i18n/el.json @@ -158,6 +158,7 @@ "video": "Βίντεο" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Διαχειριστής", "administrator": "Διαχειριστής", "allowCommands": "Εκτέλεση εντολών", diff --git a/frontend/src/i18n/es.json b/frontend/src/i18n/es.json index a3565f4f..2981ece1 100644 --- a/frontend/src/i18n/es.json +++ b/frontend/src/i18n/es.json @@ -158,6 +158,7 @@ "video": "Vídeo" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrador", "allowCommands": "Ejecutar comandos", diff --git a/frontend/src/i18n/fa.json b/frontend/src/i18n/fa.json index e4a2532e..1d885fcc 100644 --- a/frontend/src/i18n/fa.json +++ b/frontend/src/i18n/fa.json @@ -158,6 +158,7 @@ "video": "ویدئو " }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrator", "allowCommands": "اجرای دستورات", diff --git a/frontend/src/i18n/fr.json b/frontend/src/i18n/fr.json index fcbd239b..bf07499a 100644 --- a/frontend/src/i18n/fr.json +++ b/frontend/src/i18n/fr.json @@ -158,6 +158,7 @@ "video": "Vidéo" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrateur·ice", "allowCommands": "Exécuter des commandes", diff --git a/frontend/src/i18n/he.json b/frontend/src/i18n/he.json index 9bb3145a..6576ebd0 100644 --- a/frontend/src/i18n/he.json +++ b/frontend/src/i18n/he.json @@ -158,6 +158,7 @@ "video": "וידאו" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "מנהל", "administrator": "מנהל ראשי", "allowCommands": "הפעלת פקודות", diff --git a/frontend/src/i18n/hu.json b/frontend/src/i18n/hu.json index 0971d9cc..dd58ed1d 100644 --- a/frontend/src/i18n/hu.json +++ b/frontend/src/i18n/hu.json @@ -158,6 +158,7 @@ "video": "Videó" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Adminisztrátor", "allowCommands": "Parancsok futtatása", diff --git a/frontend/src/i18n/is.json b/frontend/src/i18n/is.json index 65a5eb00..431f21ef 100644 --- a/frontend/src/i18n/is.json +++ b/frontend/src/i18n/is.json @@ -158,6 +158,7 @@ "video": "Myndbönd" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Stjórnandi", "administrator": "Stjórnandi", "allowCommands": "Senda skipanir", diff --git a/frontend/src/i18n/it.json b/frontend/src/i18n/it.json index b1135aac..929d90ed 100644 --- a/frontend/src/i18n/it.json +++ b/frontend/src/i18n/it.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Amministratore", "allowCommands": "Esegui comandi", diff --git a/frontend/src/i18n/ja.json b/frontend/src/i18n/ja.json index 574bf59a..0e6b9c04 100644 --- a/frontend/src/i18n/ja.json +++ b/frontend/src/i18n/ja.json @@ -158,6 +158,7 @@ "video": "動画" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "管理者", "administrator": "管理者", "allowCommands": "コマンドの実行", diff --git a/frontend/src/i18n/ko.json b/frontend/src/i18n/ko.json index ea5a1e67..64a6c7d5 100644 --- a/frontend/src/i18n/ko.json +++ b/frontend/src/i18n/ko.json @@ -158,6 +158,7 @@ "video": "비디오" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "관리자", "administrator": "관리자", "allowCommands": "명령 실행", diff --git a/frontend/src/i18n/nl-be.json b/frontend/src/i18n/nl-be.json index af659e5c..78a7c281 100644 --- a/frontend/src/i18n/nl-be.json +++ b/frontend/src/i18n/nl-be.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrator", "allowCommands": "Commando's uitvoeren", diff --git a/frontend/src/i18n/no.json b/frontend/src/i18n/no.json index 08c6992c..3eea3638 100644 --- a/frontend/src/i18n/no.json +++ b/frontend/src/i18n/no.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrator", "allowCommands": "Utfør kommandoer", diff --git a/frontend/src/i18n/pl.json b/frontend/src/i18n/pl.json index 06f1c8fd..b9db7455 100644 --- a/frontend/src/i18n/pl.json +++ b/frontend/src/i18n/pl.json @@ -158,6 +158,7 @@ "video": "Wideo" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrator", "allowCommands": "Wykonaj polecenie", diff --git a/frontend/src/i18n/pt-br.json b/frontend/src/i18n/pt-br.json index a4938c49..d29f98d6 100644 --- a/frontend/src/i18n/pt-br.json +++ b/frontend/src/i18n/pt-br.json @@ -158,6 +158,7 @@ "video": "Vídeos" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrador", "allowCommands": "Executar comandos", diff --git a/frontend/src/i18n/pt.json b/frontend/src/i18n/pt.json index 2555eafb..e54a4f0d 100644 --- a/frontend/src/i18n/pt.json +++ b/frontend/src/i18n/pt.json @@ -158,6 +158,7 @@ "video": "Vídeos" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrador", "allowCommands": "Executar comandos", diff --git a/frontend/src/i18n/ro.json b/frontend/src/i18n/ro.json index 5f4a630e..73719a4e 100644 --- a/frontend/src/i18n/ro.json +++ b/frontend/src/i18n/ro.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrator", "allowCommands": "Execută comenzi", diff --git a/frontend/src/i18n/ru.json b/frontend/src/i18n/ru.json index d9407647..0678ce14 100644 --- a/frontend/src/i18n/ru.json +++ b/frontend/src/i18n/ru.json @@ -158,6 +158,7 @@ "video": "Видео" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Админ", "administrator": "Администратор", "allowCommands": "Запуск команд", diff --git a/frontend/src/i18n/sk.json b/frontend/src/i18n/sk.json index 06c73a98..68112fba 100644 --- a/frontend/src/i18n/sk.json +++ b/frontend/src/i18n/sk.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrátor", "allowCommands": "Vykonávať príkazy", diff --git a/frontend/src/i18n/sv-se.json b/frontend/src/i18n/sv-se.json index 47c041c0..9f66a141 100644 --- a/frontend/src/i18n/sv-se.json +++ b/frontend/src/i18n/sv-se.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administratör", "allowCommands": "Exekvera kommandon", diff --git a/frontend/src/i18n/tr.json b/frontend/src/i18n/tr.json index ed635501..7493821e 100644 --- a/frontend/src/i18n/tr.json +++ b/frontend/src/i18n/tr.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Yönetim", "administrator": "Yönetici", "allowCommands": "Komutları çalıştır", diff --git a/frontend/src/i18n/uk.json b/frontend/src/i18n/uk.json index a81010f6..40a96893 100644 --- a/frontend/src/i18n/uk.json +++ b/frontend/src/i18n/uk.json @@ -158,6 +158,7 @@ "video": "Відео" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Адмін", "administrator": "Адміністратор", "allowCommands": "Запуск команд", diff --git a/frontend/src/i18n/vi.json b/frontend/src/i18n/vi.json index 07864ce8..fab93759 100644 --- a/frontend/src/i18n/vi.json +++ b/frontend/src/i18n/vi.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Quản trị viên", "administrator": "Người quản trị", "allowCommands": "Thực thi lệnh", diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json index 6a8b9065..15cf8e3c 100644 --- a/frontend/src/i18n/zh-cn.json +++ b/frontend/src/i18n/zh-cn.json @@ -158,6 +158,7 @@ "video": "视频" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "管理员", "administrator": "管理员", "allowCommands": "执行命令(Shell 命令)", diff --git a/frontend/src/i18n/zh-tw.json b/frontend/src/i18n/zh-tw.json index 4ceb886c..d59f1efd 100644 --- a/frontend/src/i18n/zh-tw.json +++ b/frontend/src/i18n/zh-tw.json @@ -158,6 +158,7 @@ "video": "影片" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "管理員", "administrator": "管理員", "allowCommands": "執行命令", From 878cdfbc52bdb4c4385f24904a87927f852cb907 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Thu, 25 Sep 2025 17:20:12 +0200 Subject: [PATCH 033/202] chore(release): 2.44.0 --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f81c8cd4..9bf8bd77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,26 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.44.0](https://github.com/filebrowser/filebrowser/compare/v2.43.0...v2.44.0) (2025-09-25) + + +### Features + +* allow setting ace editor theme ([#3826](https://github.com/filebrowser/filebrowser/issues/3826)) ([b9787c7](https://github.com/filebrowser/filebrowser/commit/b9787c78f3889171f94db19e7655dce68c64b6fb)) +* Improved path display in the new file and directory modal ([#5451](https://github.com/filebrowser/filebrowser/issues/5451)) ([d29ad35](https://github.com/filebrowser/filebrowser/commit/d29ad356d1067c87b2821debab91286549f512a0)) +* Translate frontend/src/i18n/en.json in no ([dec7a02](https://github.com/filebrowser/filebrowser/commit/dec7a027378fbc6948d203199c44a640a141bcad)) +* Updates for project File Browser ([#5446](https://github.com/filebrowser/filebrowser/issues/5446)) ([4ff247e](https://github.com/filebrowser/filebrowser/commit/4ff247e134e4d61668ee656a258ed67f71414e18)) +* Updates for project File Browser ([#5450](https://github.com/filebrowser/filebrowser/issues/5450)) ([0eade71](https://github.com/filebrowser/filebrowser/commit/0eade717ce9d04bf48051922f11d983edbc7c2d0)) +* Updates for project File Browser ([#5457](https://github.com/filebrowser/filebrowser/issues/5457)) ([1165f00](https://github.com/filebrowser/filebrowser/commit/1165f00bd4dcb0dcfbc084f54f51902ba4b4a714)) + + +### Bug Fixes + +* computation of file path ([c472542](https://github.com/filebrowser/filebrowser/commit/c4725428e07da72b855009e2c13c6ed91d32e0b7)) +* show login when session token expires ([e6c674b](https://github.com/filebrowser/filebrowser/commit/e6c674b3c616831942c4d4aacab0907d58003e23)) +* some formatting issues with i18n files ([949ddff](https://github.com/filebrowser/filebrowser/commit/949ddffef20e38169902c5fd74dca4815dcecf11)) +* **upload:** throttle upload speed calculation to 100ms to avoid Infinity MB/s ([#5456](https://github.com/filebrowser/filebrowser/issues/5456)) ([692ca5e](https://github.com/filebrowser/filebrowser/commit/692ca5eaf01e4dcf346ba03f82c5dbd50cce246b)) + ## [2.43.0](https://github.com/filebrowser/filebrowser/compare/v2.42.5...v2.43.0) (2025-09-13) From d0039afbb76a9364c1e6ac9715ccc3c239dc8cb6 Mon Sep 17 00:00:00 2001 From: Ryan <43447928+Rmiller5466@users.noreply.github.com> Date: Fri, 3 Oct 2025 04:42:24 -0400 Subject: [PATCH 034/202] fix: wrong url on settings branding link --- frontend/src/views/settings/Global.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/views/settings/Global.vue b/frontend/src/views/settings/Global.vue index e397c6f7..0a42a293 100644 --- a/frontend/src/views/settings/Global.vue +++ b/frontend/src/views/settings/Global.vue @@ -65,7 +65,7 @@ {{ t("settings.documentation") }} From a397e7305d1572baf67823413f97a29eea38f0cc Mon Sep 17 00:00:00 2001 From: Ryan <43447928+Rmiller5466@users.noreply.github.com> Date: Fri, 17 Oct 2025 10:45:36 -0400 Subject: [PATCH 035/202] fix: editor discard prompt doesn't save nor discard Co-authored-by: Ryan Miller --- .../components/prompts/DiscardEditorChanges.vue | 10 ++-------- frontend/src/views/files/Editor.vue | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/prompts/DiscardEditorChanges.vue b/frontend/src/components/prompts/DiscardEditorChanges.vue index bd6bc49a..7a99c5fc 100644 --- a/frontend/src/components/prompts/DiscardEditorChanges.vue +++ b/frontend/src/components/prompts/DiscardEditorChanges.vue @@ -17,7 +17,7 @@