Compare commits

..

15 Commits

Author SHA1 Message Date
Henrique Dias
4302ece49b chore(release): 2.50.0 2025-11-30 09:08:15 +01:00
Henrique Dias
e1ee14d827 chore(docs): update CLI documentation 2025-11-30 09:07:56 +01:00
Henrique Dias
84ca722261 ci: use docs on GitHub Pages 2025-11-30 08:49:24 +01:00
jake-dog
b9ac45d5da feat: configurable logout page URL for proxy/hook auth (#3884)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-11-30 08:44:34 +01:00
Henrique Dias
701522a060 fix: do not close editor if save failed
Closes #5591
2025-11-30 07:58:37 +01:00
transifex-integration[bot]
78e0395960 feat: update translations
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-11-30 07:32:51 +01:00
renovate[bot]
f0680cf0f5 chore(deps): update dependency prettier to v3.7.3 (#5592)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-30 07:31:40 +01:00
Krishan Bhasin
982405ec94 feat: render CSVs as table (#5569)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-11-29 10:45:11 +01:00
renovate[bot]
a78aaed214 chore(deps): update dependency prettier to v3.7.2 (#5589)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-29 10:25:22 +01:00
renovate[bot]
df11a7dd0e chore(deps): update all non-major dependencies (#5583)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-28 17:40:31 +01:00
renovate[bot]
79980bcf52 chore(deps): update all non-major dependencies to v14.1.0 (#5582)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-27 09:05:21 +01:00
renovate[bot]
3be134f23d chore(deps): update all non-major dependencies (#5578)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 13:56:59 +01:00
transifex-integration[bot]
279a5ccd1e feat: update frontend/src/i18n/hr.json
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-11-26 13:56:45 +01:00
renovate[bot]
87f73ac982 chore(deps): update dependency vue to v3.5.25 (#5577)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-24 09:39:33 +01:00
renovate[bot]
85cde140ba chore(deps): update dependency vue-tsc to v3.1.5 (#5575)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-23 08:10:22 +01:00
51 changed files with 767 additions and 308 deletions

View File

@@ -28,9 +28,11 @@ jobs:
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
name: Build and Release Docs
permissions:
contents: read
deployments: write
pull-requests: write
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
@@ -42,11 +44,9 @@ jobs:
uses: go-task/setup-task@v1
- name: Build site
run: task docs
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@v3
- name: Upload static files as artifact
uses: actions/upload-pages-artifact@v4
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy www/public --project-name=${{ secrets.CLOUDFLARE_PROJECT_NAME }}
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
path: www/public
- name: Deploy to GitHub Pages
uses: actions/deploy-pages@v4

View File

@@ -2,6 +2,21 @@
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
## [2.50.0](https://github.com/filebrowser/filebrowser/compare/v2.49.0...v2.50.0) (2025-11-30)
### Features
* configurable logout page URL for proxy/hook auth ([#3884](https://github.com/filebrowser/filebrowser/issues/3884)) ([b9ac45d](https://github.com/filebrowser/filebrowser/commit/b9ac45d5dac4b4eb2ba364629090fbf306cffd2b))
* render CSVs as table ([#5569](https://github.com/filebrowser/filebrowser/issues/5569)) ([982405e](https://github.com/filebrowser/filebrowser/commit/982405ec944f94baf43594b0ed2f06329ff4e9ed))
* update frontend/src/i18n/hr.json ([279a5cc](https://github.com/filebrowser/filebrowser/commit/279a5ccd1e8d7bde4568b63cb3c506af48b6c618))
* update translations ([78e0395](https://github.com/filebrowser/filebrowser/commit/78e039596070a3a9e643a693cc99960c69dcfe92))
### Bug Fixes
* do not close editor if save failed ([701522a](https://github.com/filebrowser/filebrowser/commit/701522a0600cfa542469540ed764630c0ba1a732)), closes [#5591](https://github.com/filebrowser/filebrowser/issues/5591)
## [2.49.0](https://github.com/filebrowser/filebrowser/compare/v2.48.2...v2.49.0) (2025-11-22)

View File

@@ -45,6 +45,7 @@ func addConfigFlags(flags *pflag.FlagSet) {
flags.String("auth.method", string(auth.MethodJSONAuth), "authentication type")
flags.String("auth.header", "", "HTTP header for auth.method=proxy")
flags.String("auth.command", "", "command for auth.method=hook")
flags.String("auth.logoutPage", "", "url of custom logout page")
flags.String("recaptcha.host", "https://www.google.com", "use another host for ReCAPTCHA. recaptcha.net might be useful in China")
flags.String("recaptcha.key", "", "ReCaptcha site key")
@@ -201,6 +202,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Fprintf(w, "Sign up:\t%t\n", set.Signup)
fmt.Fprintf(w, "Hide Login Button:\t%t\n", set.HideLoginButton)
fmt.Fprintf(w, "Create User Dir:\t%t\n", set.CreateUserDir)
fmt.Fprintf(w, "Logout Page:\t%s\n", set.LogoutPage)
fmt.Fprintf(w, "Minimum Password Length:\t%d\n", set.MinimumPasswordLength)
fmt.Fprintf(w, "Auth Method:\t%s\n", set.AuthMethod)
fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(set.Shell, " "))
@@ -328,6 +330,8 @@ func getSettings(flags *pflag.FlagSet, set *settings.Settings, ser *settings.Ser
set.DirMode, err = getAndParseFileMode(flags, flag.Name)
case "auth.method":
hasAuth = true
case "auth.logoutPage":
set.LogoutPage, err = flags.GetString(flag.Name)
case "branding.name":
set.Branding.Name, err = flags.GetString(flag.Name)
case "branding.theme":

View File

@@ -39,6 +39,7 @@
DisableUsedPercentage: false,
EnableExec: true,
EnableThumbs: true,
LogoutPage: "",
LoginPage: true,
Name: "",
NoAuth: false,

View File

@@ -71,5 +71,5 @@
"vite-plugin-compression2": "^2.3.1",
"vue-tsc": "^3.1.3"
},
"packageManager": "pnpm@10.23.0+sha512.21c4e5698002ade97e4efe8b8b4a89a8de3c85a37919f957e7a0f30f38fbc5bbdd05980ffe29179b2fb6e6e691242e098d945d1601772cad0fef5fb6411e2a4b"
"packageManager": "pnpm@10.24.0+sha512.01ff8ae71b4419903b65c60fb2dc9d34cf8bb6e06d03bde112ef38f7a34d6904c424ba66bea5cdcf12890230bf39f9580473140ed9c946fef328b6e5238a345a"
}

439
frontend/pnpm-lock.yaml generated
View File

@@ -10,13 +10,13 @@ importers:
dependencies:
'@chenfengyuan/vue-number-input':
specifier: ^2.0.1
version: 2.0.1(vue@3.5.24(typescript@5.9.3))
version: 2.0.1(vue@3.5.25(typescript@5.9.3))
'@vueuse/core':
specifier: ^14.0.0
version: 14.0.0(vue@3.5.24(typescript@5.9.3))
version: 14.1.0(vue@3.5.25(typescript@5.9.3))
'@vueuse/integrations':
specifier: ^14.0.0
version: 14.0.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.24(typescript@5.9.3))
version: 14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3))
ace-builds:
specifier: ^1.43.2
version: 1.43.4
@@ -52,13 +52,13 @@ importers:
version: 8.0.1
pinia:
specifier: ^3.0.4
version: 3.0.4(typescript@5.9.3)(vue@3.5.24(typescript@5.9.3))
version: 3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
pretty-bytes:
specifier: ^7.1.0
version: 7.1.0
qrcode.vue:
specifier: ^3.6.0
version: 3.6.0(vue@3.5.24(typescript@5.9.3))
version: 3.6.0(vue@3.5.25(typescript@5.9.3))
tus-js-client:
specifier: ^4.3.1
version: 4.3.1
@@ -76,13 +76,13 @@ importers:
version: 1.1.1(video.js@8.23.4)
vue:
specifier: ^3.5.17
version: 3.5.24(typescript@5.9.3)
version: 3.5.25(typescript@5.9.3)
vue-final-modal:
specifier: ^4.5.5
version: 4.5.5(@vueuse/core@14.0.0(vue@3.5.24(typescript@5.9.3)))(@vueuse/integrations@14.0.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.24(typescript@5.9.3)))(focus-trap@7.6.2)(vue@3.5.24(typescript@5.9.3))
version: 4.5.5(@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3)))(@vueuse/integrations@14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3)))(focus-trap@7.6.2)(vue@3.5.25(typescript@5.9.3))
vue-i18n:
specifier: ^11.1.10
version: 11.2.1(vue@3.5.24(typescript@5.9.3))
version: 11.2.2(vue@3.5.25(typescript@5.9.3))
vue-lazyload:
specifier: ^3.0.0
version: 3.0.0
@@ -91,14 +91,14 @@ importers:
version: 1.3.3
vue-router:
specifier: ^4.5.1
version: 4.6.3(vue@3.5.24(typescript@5.9.3))
version: 4.6.3(vue@3.5.25(typescript@5.9.3))
vue-toastification:
specifier: ^2.0.0-rc.5
version: 2.0.0-rc.5(vue@3.5.24(typescript@5.9.3))
version: 2.0.0-rc.5(vue@3.5.25(typescript@5.9.3))
devDependencies:
'@intlify/unplugin-vue-i18n':
specifier: ^11.0.1
version: 11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.2.1(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))
version: 11.0.1(@vue/compiler-dom@3.5.25)(eslint@9.39.1)(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))
'@tsconfig/node24':
specifier: ^24.0.2
version: 24.0.3
@@ -110,22 +110,22 @@ importers:
version: 24.10.1
'@typescript-eslint/eslint-plugin':
specifier: ^8.37.0
version: 8.47.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
version: 8.48.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
'@vitejs/plugin-legacy':
specifier: ^7.2.1
version: 7.2.1(terser@5.44.1)(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))
'@vitejs/plugin-vue':
specifier: ^6.0.1
version: 6.0.2(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.24(typescript@5.9.3))
version: 6.0.2(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.25(typescript@5.9.3))
'@vue/eslint-config-prettier':
specifier: ^10.2.0
version: 10.2.0(eslint@9.39.1)(prettier@3.6.2)
version: 10.2.0(eslint@9.39.1)(prettier@3.7.3)
'@vue/eslint-config-typescript':
specifier: ^14.6.0
version: 14.6.0(eslint-plugin-vue@10.6.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)))(eslint@9.39.1)(typescript@5.9.3)
version: 14.6.0(eslint-plugin-vue@10.6.2(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)))(eslint@9.39.1)(typescript@5.9.3)
'@vue/tsconfig':
specifier: ^0.8.1
version: 0.8.1(typescript@5.9.3)(vue@3.5.24(typescript@5.9.3))
version: 0.8.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
autoprefixer:
specifier: ^10.4.21
version: 10.4.22(postcss@8.5.6)
@@ -137,16 +137,16 @@ importers:
version: 10.1.8(eslint@9.39.1)
eslint-plugin-prettier:
specifier: ^5.5.1
version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.6.2)
version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.7.3)
eslint-plugin-vue:
specifier: ^10.5.1
version: 10.6.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1))
version: 10.6.2(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1))
postcss:
specifier: ^8.5.6
version: 8.5.6
prettier:
specifier: ^3.6.2
version: 3.6.2
version: 3.7.3
terser:
specifier: ^5.43.1
version: 5.44.1
@@ -161,7 +161,7 @@ importers:
version: 2.3.1(rollup@4.53.3)
vue-tsc:
specifier: ^3.1.3
version: 3.1.4(typescript@5.9.3)
version: 3.1.5(typescript@5.9.3)
packages:
@@ -887,20 +887,20 @@ packages:
vue-i18n:
optional: true
'@intlify/core-base@11.2.1':
resolution: {integrity: sha512-2V1A4yaN9ElAnQ6ih3HHEc+jZ+sHV6BlQHjCsnIVlOotL5NCUgJElIxgUFiJs6zV4puoAq3hHuQIfWNp+J+8yQ==}
'@intlify/core-base@11.2.2':
resolution: {integrity: sha512-0mCTBOLKIqFUP3BzwuFW23hYEl9g/wby6uY//AC5hTgQfTsM2srCYF2/hYGp+a5DZ/HIFIgKkLJMzXTt30r0JQ==}
engines: {node: '>= 16'}
'@intlify/message-compiler@11.2.1':
resolution: {integrity: sha512-J2454D3Agg3Kvgaj14gxTleJU8/H06Sisz7C2BwiHF0/i5Soyfb5ySpwn8GCL6yscDbOGj6xM+lUe6gO6BFQyg==}
'@intlify/message-compiler@11.2.2':
resolution: {integrity: sha512-XS2p8Ff5JxWsKhgfld4/MRQzZRQ85drMMPhb7Co6Be4ZOgqJX1DzcZt0IFgGTycgqL8rkYNwgnD443Q+TapOoA==}
engines: {node: '>= 16'}
'@intlify/shared@11.1.12':
resolution: {integrity: sha512-Om86EjuQtA69hdNj3GQec9ZC0L0vPSAnXzB3gP/gyJ7+mA7t06d9aOAiqMZ+xEOsumGP4eEBlfl8zF2LOTzf2A==}
engines: {node: '>= 16'}
'@intlify/shared@11.2.1':
resolution: {integrity: sha512-O67LZM4dbfr70WCsZLW+g+pIXdgQ66laLVd/FicW7iYgP/RuH0X1FDGSh+Hr9Gou/8TeldUE6KmTGdLwX2ufIA==}
'@intlify/shared@11.2.2':
resolution: {integrity: sha512-OtCmyFpSXxNu/oET/aN6HtPCbZ01btXVd0f3w00YsHOb13Kverk1jzA2k47pAekM55qbUw421fvPF1yxZ+gicw==}
engines: {node: '>= 16'}
'@intlify/unplugin-vue-i18n@11.0.1':
@@ -1127,11 +1127,11 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/eslint-plugin@8.47.0':
resolution: {integrity: sha512-fe0rz9WJQ5t2iaLfdbDc9T80GJy0AeO453q8C3YCilnGozvOyCG5t+EZtg7j7D88+c3FipfP/x+wzGnh1xp8ZA==}
'@typescript-eslint/eslint-plugin@8.48.0':
resolution: {integrity: sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@typescript-eslint/parser': ^8.47.0
'@typescript-eslint/parser': ^8.48.0
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
@@ -1154,8 +1154,8 @@ packages:
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/project-service@8.47.0':
resolution: {integrity: sha512-2X4BX8hUeB5JcA1TQJ7GjcgulXQ+5UkNb0DL8gHsHUHdFoiCTJoYLTpib3LtSDPZsRET5ygN4qqIWrHyYIKERA==}
'@typescript-eslint/project-service@8.48.0':
resolution: {integrity: sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
@@ -1168,8 +1168,8 @@ packages:
resolution: {integrity: sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/scope-manager@8.47.0':
resolution: {integrity: sha512-a0TTJk4HXMkfpFkL9/WaGTNuv7JWfFTQFJd6zS9dVAjKsojmv9HT55xzbEpnZoY+VUb+YXLMp+ihMLz/UlZfDg==}
'@typescript-eslint/scope-manager@8.48.0':
resolution: {integrity: sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/tsconfig-utils@8.37.0':
@@ -1184,8 +1184,8 @@ packages:
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/tsconfig-utils@8.47.0':
resolution: {integrity: sha512-ybUAvjy4ZCL11uryalkKxuT3w3sXJAuWhOoGS3T/Wu+iUu1tGJmk5ytSY8gbdACNARmcYEB0COksD2j6hfGK2g==}
'@typescript-eslint/tsconfig-utils@8.48.0':
resolution: {integrity: sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
@@ -1197,8 +1197,8 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/type-utils@8.47.0':
resolution: {integrity: sha512-QC9RiCmZ2HmIdCEvhd1aJELBlD93ErziOXXlHEZyuBo3tBiAZieya0HLIxp+DoDWlsQqDawyKuNEhORyku+P8A==}
'@typescript-eslint/type-utils@8.48.0':
resolution: {integrity: sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -1212,8 +1212,8 @@ packages:
resolution: {integrity: sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/types@8.47.0':
resolution: {integrity: sha512-nHAE6bMKsizhA2uuYZbEbmp5z2UpffNrPEqiKIeN7VsV6UY/roxanWfoRrf6x/k9+Obf+GQdkm0nPU+vnMXo9A==}
'@typescript-eslint/types@8.48.0':
resolution: {integrity: sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.37.0':
@@ -1228,8 +1228,8 @@ packages:
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/typescript-estree@8.47.0':
resolution: {integrity: sha512-k6ti9UepJf5NpzCjH31hQNLHQWupTRPhZ+KFF8WtTuTpy7uHPfeg2NM7cP27aCGajoEplxJDFVCEm9TGPYyiVg==}
'@typescript-eslint/typescript-estree@8.48.0':
resolution: {integrity: sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
@@ -1241,8 +1241,8 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/utils@8.47.0':
resolution: {integrity: sha512-g7XrNf25iL4TJOiPqatNuaChyqt49a/onq5YsJ9+hXeugK+41LVg7AxikMfM02PC6jbNtZLCJj6AUcQXJS/jGQ==}
'@typescript-eslint/utils@8.48.0':
resolution: {integrity: sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -1256,8 +1256,8 @@ packages:
resolution: {integrity: sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/visitor-keys@8.47.0':
resolution: {integrity: sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ==}
'@typescript-eslint/visitor-keys@8.48.0':
resolution: {integrity: sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@videojs/http-streaming@3.17.2':
@@ -1296,17 +1296,17 @@ packages:
'@volar/typescript@2.4.23':
resolution: {integrity: sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==}
'@vue/compiler-core@3.5.24':
resolution: {integrity: sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig==}
'@vue/compiler-core@3.5.25':
resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==}
'@vue/compiler-dom@3.5.24':
resolution: {integrity: sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw==}
'@vue/compiler-dom@3.5.25':
resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==}
'@vue/compiler-sfc@3.5.24':
resolution: {integrity: sha512-8EG5YPRgmTB+YxYBM3VXy8zHD9SWHUJLIGPhDovo3Z8VOgvP+O7UP5vl0J4BBPWYD9vxtBabzW1EuEZ+Cqs14g==}
'@vue/compiler-sfc@3.5.25':
resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==}
'@vue/compiler-ssr@3.5.24':
resolution: {integrity: sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg==}
'@vue/compiler-ssr@3.5.25':
resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==}
'@vue/devtools-api@6.6.4':
resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
@@ -1337,30 +1337,30 @@ packages:
typescript:
optional: true
'@vue/language-core@3.1.4':
resolution: {integrity: sha512-n/58wm8SkmoxMWkUNUH/PwoovWe4hmdyPJU2ouldr3EPi1MLoS7iDN46je8CsP95SnVBs2axInzRglPNKvqMcg==}
'@vue/language-core@3.1.5':
resolution: {integrity: sha512-FMcqyzWN+sYBeqRMWPGT2QY0mUasZMVIuHvmb5NT3eeqPrbHBYtCP8JWEUCDCgM+Zr62uuWY/qoeBrPrzfa78w==}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
'@vue/reactivity@3.5.24':
resolution: {integrity: sha512-BM8kBhtlkkbnyl4q+HiF5R5BL0ycDPfihowulm02q3WYp2vxgPcJuZO866qa/0u3idbMntKEtVNuAUp5bw4teg==}
'@vue/reactivity@3.5.25':
resolution: {integrity: sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==}
'@vue/runtime-core@3.5.24':
resolution: {integrity: sha512-RYP/byyKDgNIqfX/gNb2PB55dJmM97jc9wyF3jK7QUInYKypK2exmZMNwnjueWwGceEkP6NChd3D2ZVEp9undQ==}
'@vue/runtime-core@3.5.25':
resolution: {integrity: sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==}
'@vue/runtime-dom@3.5.24':
resolution: {integrity: sha512-Z8ANhr/i0XIluonHVjbUkjvn+CyrxbXRIxR7wn7+X7xlcb7dJsfITZbkVOeJZdP8VZwfrWRsWdShH6pngMxRjw==}
'@vue/runtime-dom@3.5.25':
resolution: {integrity: sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==}
'@vue/server-renderer@3.5.24':
resolution: {integrity: sha512-Yh2j2Y4G/0/4z/xJ1Bad4mxaAk++C2v4kaa8oSYTMJBJ00/ndPuxCnWeot0/7/qafQFLh5pr6xeV6SdMcE/G1w==}
'@vue/server-renderer@3.5.25':
resolution: {integrity: sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==}
peerDependencies:
vue: 3.5.24
vue: 3.5.25
'@vue/shared@3.5.24':
resolution: {integrity: sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A==}
'@vue/shared@3.5.25':
resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==}
'@vue/tsconfig@0.8.1':
resolution: {integrity: sha512-aK7feIWPXFSUhsCP9PFqPyFOcz4ENkb8hZ2pneL6m2UjCkccvaOhC/5KCKluuBufvp2KzkbdA2W2pk20vLzu3g==}
@@ -1373,13 +1373,13 @@ packages:
vue:
optional: true
'@vueuse/core@14.0.0':
resolution: {integrity: sha512-d6tKRWkZE8IQElX2aHBxXOMD478fHIYV+Dzm2y9Ag122ICBpNKtGICiXKOhWU3L1kKdttDD9dCMS4bGP3jhCTQ==}
'@vueuse/core@14.1.0':
resolution: {integrity: sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==}
peerDependencies:
vue: ^3.5.0
'@vueuse/integrations@14.0.0':
resolution: {integrity: sha512-5A0X7q9qyLtM3xyghq5nK/NEESf7cpcZlkQgXTMuW4JWiAMYxc1ImdhhGrk4negFBsq3ejvAlRmLdNrkcTzk1Q==}
'@vueuse/integrations@14.1.0':
resolution: {integrity: sha512-eNQPdisnO9SvdydTIXnTE7c29yOsJBD/xkwEyQLdhDC/LKbqrFpXHb3uS//7NcIrQO3fWVuvMGp8dbK6mNEMCA==}
peerDependencies:
async-validator: ^4
axios: ^1
@@ -1420,11 +1420,11 @@ packages:
universal-cookie:
optional: true
'@vueuse/metadata@14.0.0':
resolution: {integrity: sha512-6yoGqbJcMldVCevkFiHDBTB1V5Hq+G/haPlGIuaFZHpXC0HADB0EN1ryQAAceiW+ryS3niUwvdFbGiqHqBrfVA==}
'@vueuse/metadata@14.1.0':
resolution: {integrity: sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==}
'@vueuse/shared@14.0.0':
resolution: {integrity: sha512-mTCA0uczBgurRlwVaQHfG0Ja7UdGe4g9mwffiJmvLiTtp1G4AQyIjej6si/k8c8pUwTfVpNufck+23gXptPAkw==}
'@vueuse/shared@14.1.0':
resolution: {integrity: sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw==}
peerDependencies:
vue: ^3.5.0
@@ -1578,8 +1578,8 @@ packages:
engines: {node: '>=4'}
hasBin: true
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
custom-error-instance@2.1.1:
resolution: {integrity: sha512-p6JFxJc3M4OTD2li2qaHkDCw9SfMw82Ldr6OC9Je1aXiGfhx2W8p3GaoeaGrPJTUN9NirTM/KTxHWMUdR1rsUg==}
@@ -1668,8 +1668,8 @@ packages:
eslint-config-prettier:
optional: true
eslint-plugin-vue@10.6.0:
resolution: {integrity: sha512-TsoFluWxOpsJlE/l2jJygLQLWBPJ3Qdkesv7tBIunICbTcG0dS1/NBw/Ol4tJw5kHWlAVds4lUmC29/vlPUcEQ==}
eslint-plugin-vue@10.6.2:
resolution: {integrity: sha512-nA5yUs/B1KmKzvC42fyD0+l9Yd+LtEpVhWRbXuDj0e+ZURcTtyRbMDWUeJmTAh2wC6jC83raS63anNM2YT3NPw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@stylistic/eslint-plugin': ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0
@@ -2148,8 +2148,8 @@ packages:
resolution: {integrity: sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==}
hasBin: true
postcss-selector-parser@7.1.0:
resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==}
postcss-selector-parser@7.1.1:
resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==}
engines: {node: '>=4'}
postcss-value-parser@4.2.0:
@@ -2167,8 +2167,8 @@ packages:
resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
engines: {node: '>=6.0.0'}
prettier@3.6.2:
resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
prettier@3.7.3:
resolution: {integrity: sha512-QgODejq9K3OzoBbuyobZlUhznP5SKwPqp+6Q6xw6o8gnhr4O85L2U915iM2IDcfF2NPXVaM9zlo9tdwipnYwzg==}
engines: {node: '>=14'}
hasBin: true
@@ -2496,8 +2496,8 @@ packages:
focus-trap: '>=7.2.0'
vue: '>=3.2.0'
vue-i18n@11.2.1:
resolution: {integrity: sha512-cc3Wx4eJZac9WMS8mxhfYiCipm9PBQ2Dz15piWYm7DwNcCehaKRgpolEdiqrjjT27T3Wijz3xJ7NeIc8ofIWAA==}
vue-i18n@11.2.2:
resolution: {integrity: sha512-ULIKZyRluUPRCZmihVgUvpq8hJTtOqnbGZuv4Lz+byEKZq4mU0g92og414l6f/4ju+L5mORsiUuEPYrAuX2NJg==}
engines: {node: '>= 16'}
peerDependencies:
vue: ^3.0.0
@@ -2518,14 +2518,14 @@ packages:
peerDependencies:
vue: ^3.0.2
vue-tsc@3.1.4:
resolution: {integrity: sha512-GsRJxttj4WkmXW/zDwYPGMJAN3np/4jTzoDFQTpTsI5Vg/JKMWamBwamlmLihgSVHO66y9P7GX+uoliYxeI4Hw==}
vue-tsc@3.1.5:
resolution: {integrity: sha512-L/G9IUjOWhBU0yun89rv8fKqmKC+T0HfhrFjlIml71WpfBv9eb4E9Bev8FMbyueBIU9vxQqbd+oOsVcDa5amGw==}
hasBin: true
peerDependencies:
typescript: '>=5.0.0'
vue@3.5.24:
resolution: {integrity: sha512-uTHDOpVQTMjcGgrqFPSb8iO2m1DUvo+WbGqoXQz8Y1CeBYQ0FXf2z1gLRaBtHjlRz7zZUBHxjVB5VTLzYkvftg==}
vue@3.5.25:
resolution: {integrity: sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
@@ -3220,9 +3220,9 @@ snapshots:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
'@chenfengyuan/vue-number-input@2.0.1(vue@3.5.24(typescript@5.9.3))':
'@chenfengyuan/vue-number-input@2.0.1(vue@3.5.25(typescript@5.9.3))':
dependencies:
vue: 3.5.24(typescript@5.9.3)
vue: 3.5.25(typescript@5.9.3)
'@esbuild/aix-ppc64@0.25.12':
optional: true
@@ -3359,9 +3359,9 @@ snapshots:
'@humanwhocodes/retry@0.4.3': {}
'@intlify/bundle-utils@11.0.1(vue-i18n@11.2.1(vue@3.5.24(typescript@5.9.3)))':
'@intlify/bundle-utils@11.0.1(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))':
dependencies:
'@intlify/message-compiler': 11.2.1
'@intlify/message-compiler': 11.2.2
'@intlify/shared': 11.1.12
acorn: 8.15.0
esbuild: 0.25.12
@@ -3371,28 +3371,28 @@ snapshots:
source-map-js: 1.2.1
yaml-eslint-parser: 1.2.3
optionalDependencies:
vue-i18n: 11.2.1(vue@3.5.24(typescript@5.9.3))
vue-i18n: 11.2.2(vue@3.5.25(typescript@5.9.3))
'@intlify/core-base@11.2.1':
'@intlify/core-base@11.2.2':
dependencies:
'@intlify/message-compiler': 11.2.1
'@intlify/shared': 11.2.1
'@intlify/message-compiler': 11.2.2
'@intlify/shared': 11.2.2
'@intlify/message-compiler@11.2.1':
'@intlify/message-compiler@11.2.2':
dependencies:
'@intlify/shared': 11.2.1
'@intlify/shared': 11.2.2
source-map-js: 1.2.1
'@intlify/shared@11.1.12': {}
'@intlify/shared@11.2.1': {}
'@intlify/shared@11.2.2': {}
'@intlify/unplugin-vue-i18n@11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.2.1(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))':
'@intlify/unplugin-vue-i18n@11.0.1(@vue/compiler-dom@3.5.25)(eslint@9.39.1)(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1)
'@intlify/bundle-utils': 11.0.1(vue-i18n@11.2.1(vue@3.5.24(typescript@5.9.3)))
'@intlify/bundle-utils': 11.0.1(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))
'@intlify/shared': 11.1.12
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.12)(@vue/compiler-dom@3.5.24)(vue-i18n@11.2.1(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.12)(@vue/compiler-dom@3.5.25)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
'@typescript-eslint/scope-manager': 8.46.4
'@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
@@ -3401,9 +3401,9 @@ snapshots:
pathe: 2.0.3
picocolors: 1.1.1
unplugin: 2.3.10
vue: 3.5.24(typescript@5.9.3)
vue: 3.5.25(typescript@5.9.3)
optionalDependencies:
vue-i18n: 11.2.1(vue@3.5.24(typescript@5.9.3))
vue-i18n: 11.2.2(vue@3.5.25(typescript@5.9.3))
transitivePeerDependencies:
- '@vue/compiler-dom'
- eslint
@@ -3411,14 +3411,14 @@ snapshots:
- supports-color
- typescript
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.12)(@vue/compiler-dom@3.5.24)(vue-i18n@11.2.1(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))':
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.12)(@vue/compiler-dom@3.5.25)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@babel/parser': 7.28.5
optionalDependencies:
'@intlify/shared': 11.1.12
'@vue/compiler-dom': 3.5.24
vue: 3.5.24(typescript@5.9.3)
vue-i18n: 11.2.1(vue@3.5.24(typescript@5.9.3))
'@vue/compiler-dom': 3.5.25
vue: 3.5.25(typescript@5.9.3)
vue-i18n: 11.2.2(vue@3.5.25(typescript@5.9.3))
'@jridgewell/gen-mapping@0.3.13':
dependencies:
@@ -3576,14 +3576,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/eslint-plugin@8.47.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)':
'@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.37.0(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.47.0
'@typescript-eslint/type-utils': 8.47.0(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/utils': 8.47.0(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.47.0
'@typescript-eslint/scope-manager': 8.48.0
'@typescript-eslint/type-utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.48.0
eslint: 9.39.1
graphemer: 1.4.0
ignore: 7.0.5
@@ -3623,10 +3623,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/project-service@8.47.0(typescript@5.9.3)':
'@typescript-eslint/project-service@8.48.0(typescript@5.9.3)':
dependencies:
'@typescript-eslint/tsconfig-utils': 8.47.0(typescript@5.9.3)
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3)
'@typescript-eslint/types': 8.48.0
debug: 4.4.3
typescript: 5.9.3
transitivePeerDependencies:
@@ -3642,10 +3642,10 @@ snapshots:
'@typescript-eslint/types': 8.46.4
'@typescript-eslint/visitor-keys': 8.46.4
'@typescript-eslint/scope-manager@8.47.0':
'@typescript-eslint/scope-manager@8.48.0':
dependencies:
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/visitor-keys': 8.47.0
'@typescript-eslint/types': 8.48.0
'@typescript-eslint/visitor-keys': 8.48.0
'@typescript-eslint/tsconfig-utils@8.37.0(typescript@5.9.3)':
dependencies:
@@ -3655,7 +3655,7 @@ snapshots:
dependencies:
typescript: 5.9.3
'@typescript-eslint/tsconfig-utils@8.47.0(typescript@5.9.3)':
'@typescript-eslint/tsconfig-utils@8.48.0(typescript@5.9.3)':
dependencies:
typescript: 5.9.3
@@ -3671,11 +3671,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/type-utils@8.47.0(eslint@9.39.1)(typescript@5.9.3)':
'@typescript-eslint/type-utils@8.48.0(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.47.0(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/types': 8.48.0
'@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3)
debug: 4.4.3
eslint: 9.39.1
ts-api-utils: 2.1.0(typescript@5.9.3)
@@ -3687,7 +3687,7 @@ snapshots:
'@typescript-eslint/types@8.46.4': {}
'@typescript-eslint/types@8.47.0': {}
'@typescript-eslint/types@8.48.0': {}
'@typescript-eslint/typescript-estree@8.37.0(typescript@5.9.3)':
dependencies:
@@ -3721,17 +3721,16 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/typescript-estree@8.47.0(typescript@5.9.3)':
'@typescript-eslint/typescript-estree@8.48.0(typescript@5.9.3)':
dependencies:
'@typescript-eslint/project-service': 8.47.0(typescript@5.9.3)
'@typescript-eslint/tsconfig-utils': 8.47.0(typescript@5.9.3)
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/visitor-keys': 8.47.0
'@typescript-eslint/project-service': 8.48.0(typescript@5.9.3)
'@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3)
'@typescript-eslint/types': 8.48.0
'@typescript-eslint/visitor-keys': 8.48.0
debug: 4.4.3
fast-glob: 3.3.3
is-glob: 4.0.3
minimatch: 9.0.5
semver: 7.7.3
tinyglobby: 0.2.15
ts-api-utils: 2.1.0(typescript@5.9.3)
typescript: 5.9.3
transitivePeerDependencies:
@@ -3748,12 +3747,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.47.0(eslint@9.39.1)(typescript@5.9.3)':
'@typescript-eslint/utils@8.48.0(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1)
'@typescript-eslint/scope-manager': 8.47.0
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.48.0
'@typescript-eslint/types': 8.48.0
'@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3)
eslint: 9.39.1
typescript: 5.9.3
transitivePeerDependencies:
@@ -3769,9 +3768,9 @@ snapshots:
'@typescript-eslint/types': 8.46.4
eslint-visitor-keys: 4.2.1
'@typescript-eslint/visitor-keys@8.47.0':
'@typescript-eslint/visitor-keys@8.48.0':
dependencies:
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/types': 8.48.0
eslint-visitor-keys: 4.2.1
'@videojs/http-streaming@3.17.2(video.js@8.23.4)':
@@ -3815,11 +3814,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@vitejs/plugin-vue@6.0.2(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.24(typescript@5.9.3))':
'@vitejs/plugin-vue@6.0.2(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@rolldown/pluginutils': 1.0.0-beta.50
vite: 7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0)
vue: 3.5.24(typescript@5.9.3)
vue: 3.5.25(typescript@5.9.3)
'@volar/language-core@2.4.23':
dependencies:
@@ -3833,35 +3832,35 @@ snapshots:
path-browserify: 1.0.1
vscode-uri: 3.1.0
'@vue/compiler-core@3.5.24':
'@vue/compiler-core@3.5.25':
dependencies:
'@babel/parser': 7.28.5
'@vue/shared': 3.5.24
'@vue/shared': 3.5.25
entities: 4.5.0
estree-walker: 2.0.2
source-map-js: 1.2.1
'@vue/compiler-dom@3.5.24':
'@vue/compiler-dom@3.5.25':
dependencies:
'@vue/compiler-core': 3.5.24
'@vue/shared': 3.5.24
'@vue/compiler-core': 3.5.25
'@vue/shared': 3.5.25
'@vue/compiler-sfc@3.5.24':
'@vue/compiler-sfc@3.5.25':
dependencies:
'@babel/parser': 7.28.5
'@vue/compiler-core': 3.5.24
'@vue/compiler-dom': 3.5.24
'@vue/compiler-ssr': 3.5.24
'@vue/shared': 3.5.24
'@vue/compiler-core': 3.5.25
'@vue/compiler-dom': 3.5.25
'@vue/compiler-ssr': 3.5.25
'@vue/shared': 3.5.25
estree-walker: 2.0.2
magic-string: 0.30.21
postcss: 8.5.6
source-map-js: 1.2.1
'@vue/compiler-ssr@3.5.24':
'@vue/compiler-ssr@3.5.25':
dependencies:
'@vue/compiler-dom': 3.5.24
'@vue/shared': 3.5.24
'@vue/compiler-dom': 3.5.25
'@vue/shared': 3.5.25
'@vue/devtools-api@6.6.4': {}
@@ -3883,20 +3882,20 @@ snapshots:
dependencies:
rfdc: 1.4.1
'@vue/eslint-config-prettier@10.2.0(eslint@9.39.1)(prettier@3.6.2)':
'@vue/eslint-config-prettier@10.2.0(eslint@9.39.1)(prettier@3.7.3)':
dependencies:
eslint: 9.39.1
eslint-config-prettier: 10.1.8(eslint@9.39.1)
eslint-plugin-prettier: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.6.2)
prettier: 3.6.2
eslint-plugin-prettier: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.7.3)
prettier: 3.7.3
transitivePeerDependencies:
- '@types/eslint'
'@vue/eslint-config-typescript@14.6.0(eslint-plugin-vue@10.6.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)))(eslint@9.39.1)(typescript@5.9.3)':
'@vue/eslint-config-typescript@14.6.0(eslint-plugin-vue@10.6.2(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)))(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/utils': 8.37.0(eslint@9.39.1)(typescript@5.9.3)
eslint: 9.39.1
eslint-plugin-vue: 10.6.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1))
eslint-plugin-vue: 10.6.2(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1))
fast-glob: 3.3.3
typescript-eslint: 8.37.0(eslint@9.39.1)(typescript@5.9.3)
vue-eslint-parser: 10.2.0(eslint@9.39.1)
@@ -3905,11 +3904,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@vue/language-core@3.1.4(typescript@5.9.3)':
'@vue/language-core@3.1.5(typescript@5.9.3)':
dependencies:
'@volar/language-core': 2.4.23
'@vue/compiler-dom': 3.5.24
'@vue/shared': 3.5.24
'@vue/compiler-dom': 3.5.25
'@vue/shared': 3.5.25
alien-signals: 3.1.0
muggle-string: 0.4.1
path-browserify: 1.0.1
@@ -3917,56 +3916,56 @@ snapshots:
optionalDependencies:
typescript: 5.9.3
'@vue/reactivity@3.5.24':
'@vue/reactivity@3.5.25':
dependencies:
'@vue/shared': 3.5.24
'@vue/shared': 3.5.25
'@vue/runtime-core@3.5.24':
'@vue/runtime-core@3.5.25':
dependencies:
'@vue/reactivity': 3.5.24
'@vue/shared': 3.5.24
'@vue/reactivity': 3.5.25
'@vue/shared': 3.5.25
'@vue/runtime-dom@3.5.24':
'@vue/runtime-dom@3.5.25':
dependencies:
'@vue/reactivity': 3.5.24
'@vue/runtime-core': 3.5.24
'@vue/shared': 3.5.24
csstype: 3.1.3
'@vue/reactivity': 3.5.25
'@vue/runtime-core': 3.5.25
'@vue/shared': 3.5.25
csstype: 3.2.3
'@vue/server-renderer@3.5.24(vue@3.5.24(typescript@5.9.3))':
'@vue/server-renderer@3.5.25(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@vue/compiler-ssr': 3.5.24
'@vue/shared': 3.5.24
vue: 3.5.24(typescript@5.9.3)
'@vue/compiler-ssr': 3.5.25
'@vue/shared': 3.5.25
vue: 3.5.25(typescript@5.9.3)
'@vue/shared@3.5.24': {}
'@vue/shared@3.5.25': {}
'@vue/tsconfig@0.8.1(typescript@5.9.3)(vue@3.5.24(typescript@5.9.3))':
'@vue/tsconfig@0.8.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))':
optionalDependencies:
typescript: 5.9.3
vue: 3.5.24(typescript@5.9.3)
vue: 3.5.25(typescript@5.9.3)
'@vueuse/core@14.0.0(vue@3.5.24(typescript@5.9.3))':
'@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@types/web-bluetooth': 0.0.21
'@vueuse/metadata': 14.0.0
'@vueuse/shared': 14.0.0(vue@3.5.24(typescript@5.9.3))
vue: 3.5.24(typescript@5.9.3)
'@vueuse/metadata': 14.1.0
'@vueuse/shared': 14.1.0(vue@3.5.25(typescript@5.9.3))
vue: 3.5.25(typescript@5.9.3)
'@vueuse/integrations@14.0.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.24(typescript@5.9.3))':
'@vueuse/integrations@14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@vueuse/core': 14.0.0(vue@3.5.24(typescript@5.9.3))
'@vueuse/shared': 14.0.0(vue@3.5.24(typescript@5.9.3))
vue: 3.5.24(typescript@5.9.3)
'@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3))
'@vueuse/shared': 14.1.0(vue@3.5.25(typescript@5.9.3))
vue: 3.5.25(typescript@5.9.3)
optionalDependencies:
focus-trap: 7.6.2
jwt-decode: 4.0.0
'@vueuse/metadata@14.0.0': {}
'@vueuse/metadata@14.1.0': {}
'@vueuse/shared@14.0.0(vue@3.5.24(typescript@5.9.3))':
'@vueuse/shared@14.1.0(vue@3.5.25(typescript@5.9.3))':
dependencies:
vue: 3.5.24(typescript@5.9.3)
vue: 3.5.25(typescript@5.9.3)
'@xmldom/xmldom@0.7.13': {}
@@ -4118,7 +4117,7 @@ snapshots:
cssesc@3.0.0: {}
csstype@3.1.3: {}
csstype@3.2.3: {}
custom-error-instance@2.1.1: {}
@@ -4220,22 +4219,22 @@ snapshots:
dependencies:
eslint: 9.39.1
eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.6.2):
eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.7.3):
dependencies:
eslint: 9.39.1
prettier: 3.6.2
prettier: 3.7.3
prettier-linter-helpers: 1.0.0
synckit: 0.11.11
optionalDependencies:
eslint-config-prettier: 10.1.8(eslint@9.39.1)
eslint-plugin-vue@10.6.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)):
eslint-plugin-vue@10.6.2(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)):
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1)
eslint: 9.39.1
natural-compare: 1.4.0
nth-check: 2.1.1
postcss-selector-parser: 7.1.0
postcss-selector-parser: 7.1.1
semver: 7.7.3
vue-eslint-parser: 10.2.0(eslint@9.39.1)
xml-name-validator: 4.0.0
@@ -4668,10 +4667,10 @@ snapshots:
picomatch@4.0.3: {}
pinia@3.0.4(typescript@5.9.3)(vue@3.5.24(typescript@5.9.3)):
pinia@3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)):
dependencies:
'@vue/devtools-api': 7.7.8
vue: 3.5.24(typescript@5.9.3)
vue: 3.5.25(typescript@5.9.3)
optionalDependencies:
typescript: 5.9.3
@@ -4679,7 +4678,7 @@ snapshots:
dependencies:
'@babel/runtime': 7.28.4
postcss-selector-parser@7.1.0:
postcss-selector-parser@7.1.1:
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
@@ -4698,7 +4697,7 @@ snapshots:
dependencies:
fast-diff: 1.3.0
prettier@3.6.2: {}
prettier@3.7.3: {}
pretty-bytes@7.1.0: {}
@@ -4714,9 +4713,9 @@ snapshots:
punycode@2.3.1: {}
qrcode.vue@3.6.0(vue@3.5.24(typescript@5.9.3)):
qrcode.vue@3.6.0(vue@3.5.25(typescript@5.9.3)):
dependencies:
vue: 3.5.24(typescript@5.9.3)
vue: 3.5.25(typescript@5.9.3)
querystringify@2.2.0: {}
@@ -5014,19 +5013,19 @@ snapshots:
transitivePeerDependencies:
- supports-color
vue-final-modal@4.5.5(@vueuse/core@14.0.0(vue@3.5.24(typescript@5.9.3)))(@vueuse/integrations@14.0.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.24(typescript@5.9.3)))(focus-trap@7.6.2)(vue@3.5.24(typescript@5.9.3)):
vue-final-modal@4.5.5(@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3)))(@vueuse/integrations@14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3)))(focus-trap@7.6.2)(vue@3.5.25(typescript@5.9.3)):
dependencies:
'@vueuse/core': 14.0.0(vue@3.5.24(typescript@5.9.3))
'@vueuse/integrations': 14.0.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.24(typescript@5.9.3))
'@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3))
'@vueuse/integrations': 14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3))
focus-trap: 7.6.2
vue: 3.5.24(typescript@5.9.3)
vue: 3.5.25(typescript@5.9.3)
vue-i18n@11.2.1(vue@3.5.24(typescript@5.9.3)):
vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)):
dependencies:
'@intlify/core-base': 11.2.1
'@intlify/shared': 11.2.1
'@intlify/core-base': 11.2.2
'@intlify/shared': 11.2.2
'@vue/devtools-api': 6.6.4
vue: 3.5.24(typescript@5.9.3)
vue: 3.5.25(typescript@5.9.3)
vue-lazyload@3.0.0: {}
@@ -5034,28 +5033,28 @@ snapshots:
dependencies:
epubjs: 0.3.93
vue-router@4.6.3(vue@3.5.24(typescript@5.9.3)):
vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)):
dependencies:
'@vue/devtools-api': 6.6.4
vue: 3.5.24(typescript@5.9.3)
vue: 3.5.25(typescript@5.9.3)
vue-toastification@2.0.0-rc.5(vue@3.5.24(typescript@5.9.3)):
vue-toastification@2.0.0-rc.5(vue@3.5.25(typescript@5.9.3)):
dependencies:
vue: 3.5.24(typescript@5.9.3)
vue: 3.5.25(typescript@5.9.3)
vue-tsc@3.1.4(typescript@5.9.3):
vue-tsc@3.1.5(typescript@5.9.3):
dependencies:
'@volar/typescript': 2.4.23
'@vue/language-core': 3.1.4(typescript@5.9.3)
'@vue/language-core': 3.1.5(typescript@5.9.3)
typescript: 5.9.3
vue@3.5.24(typescript@5.9.3):
vue@3.5.25(typescript@5.9.3):
dependencies:
'@vue/compiler-dom': 3.5.24
'@vue/compiler-sfc': 3.5.24
'@vue/runtime-dom': 3.5.24
'@vue/server-renderer': 3.5.24(vue@3.5.24(typescript@5.9.3))
'@vue/shared': 3.5.24
'@vue/compiler-dom': 3.5.25
'@vue/compiler-sfc': 3.5.25
'@vue/runtime-dom': 3.5.25
'@vue/server-renderer': 3.5.25(vue@3.5.25(typescript@5.9.3))
'@vue/shared': 3.5.25
optionalDependencies:
typescript: 5.9.3

View File

@@ -129,6 +129,7 @@ import {
disableExternal,
disableUsedPercentage,
noAuth,
logoutPage,
loginPage,
} from "@/utils/constants";
import { files as api } from "@/api";
@@ -159,7 +160,7 @@ export default {
version: () => version,
disableExternal: () => disableExternal,
disableUsedPercentage: () => disableUsedPercentage,
canLogout: () => !noAuth && loginPage,
canLogout: () => !noAuth && (loginPage || logoutPage !== "/login"),
},
methods: {
...mapActions(useLayoutStore, ["closeHovers", "showHover"]),

View File

@@ -0,0 +1,202 @@
<template>
<div class="csv-viewer">
<div v-if="displayError" class="csv-error">
<i class="material-icons">error</i>
<p>{{ displayError }}</p>
</div>
<div v-else-if="data.headers.length === 0" class="csv-empty">
<i class="material-icons">description</i>
<p>{{ $t("files.lonely") }}</p>
</div>
<div
v-else
class="csv-table-container"
@wheel.stop
@touchmove.stop
>
<table class="csv-table">
<thead>
<tr>
<th v-for="(header, index) in data.headers" :key="index">
{{ header || `Column ${index + 1}` }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rowIndex) in data.rows" :key="rowIndex">
<td v-for="(cell, cellIndex) in row" :key="cellIndex">
{{ cell }}
</td>
</tr>
</tbody>
</table>
<div v-if="data.rows.length > 100" class="csv-info">
<i class="material-icons">info</i>
<span>Showing {{ data.rows.length }} rows</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { parseCSV, type CsvData } from "@/utils/csv";
import { computed } from "vue";
interface Props {
content: string;
error?: string;
}
const props = withDefaults(defineProps<Props>(), {
error: "",
});
const data = computed<CsvData>(() => {
try {
return parseCSV(props.content);
} catch (e) {
console.error("Failed to parse CSV:", e);
return { headers: [], rows: [] };
}
});
const displayError = computed(() => {
// External error takes priority (e.g., file too large)
if (props.error) {
return props.error;
}
// Check for parse errors
if (props.content && props.content.trim().length > 0 && data.value.headers.length === 0) {
return "Failed to parse CSV file";
}
return null;
});
</script>
<style scoped>
.csv-viewer {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: var(--surfacePrimary);
color: var(--textSecondary);
padding: 1rem;
padding-top: 4em;
box-sizing: border-box;
}
.csv-error,
.csv-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
gap: 1rem;
color: var(--textPrimary);
}
.csv-error i,
.csv-empty i {
font-size: 4rem;
opacity: 0.5;
}
.csv-error p,
.csv-empty p {
font-size: 1.1rem;
margin: 0;
}
.csv-table-container {
flex: 1;
overflow: auto;
background-color: var(--surfacePrimary);
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
/* Scrollbar styling for better visibility */
.csv-table-container::-webkit-scrollbar {
width: 12px;
height: 12px;
}
.csv-table-container::-webkit-scrollbar-track {
background: var(--background);
border-radius: 4px;
}
.csv-table-container::-webkit-scrollbar-thumb {
background: var(--borderSecondary);
border-radius: 4px;
}
.csv-table-container::-webkit-scrollbar-thumb:hover {
background: var(--textPrimary);
}
.csv-table {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
background-color: var(--surfacePrimary);
}
.csv-table thead {
position: sticky;
top: 0;
z-index: 10;
background-color: var(--surfaceSecondary);
}
.csv-table th {
padding: 0.875rem 1rem;
text-align: left;
font-weight: 600;
border-bottom: 2px solid var(--borderSecondary);
background-color: var(--surfaceSecondary);
white-space: nowrap;
color: var(--textSecondary);
font-size: 0.875rem;
}
.csv-table td {
padding: 0.75rem 1rem;
text-align: left;
border-bottom: 1px solid var(--borderPrimary);
white-space: nowrap;
max-width: 400px;
overflow: hidden;
text-overflow: ellipsis;
color: var(--textSecondary);
}
.csv-table tbody tr:nth-child(even) {
background-color: var(--background);
}
.csv-table tbody tr:hover {
background-color: var(--hover);
transition: background-color 0.15s ease;
}
.csv-info {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1rem;
margin-top: 0.5rem;
background-color: var(--surfaceSecondary);
border-radius: 4px;
border-left: 3px solid var(--blue);
color: var(--textSecondary);
font-size: 0.875rem;
}
.csv-info i {
font-size: 1.2rem;
color: var(--blue);
}
</style>

View File

@@ -43,7 +43,8 @@
"upload": "رفع",
"openFile": "فتح الملف",
"discardChanges": "إلغاء التغييرات",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "تحميل الملف",
@@ -75,7 +76,9 @@
"sortByLastModified": "الترتيب بآخر تعديل",
"sortByName": "الترتيب باﻹسم",
"sortBySize": "الترتيب بالحجم",
"noPreview": "لا يوجد عرض مسبق لهذا الملف."
"noPreview": "لا يوجد عرض مسبق لهذا الملف.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "حدد الملف أو المجلد",

View File

@@ -43,7 +43,8 @@
"upload": "Качи",
"openFile": "Отвори файл",
"discardChanges": "Изчисти",
"saveChanges": "Запиши промените"
"saveChanges": "Запиши промените",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Свали файл",
@@ -75,7 +76,9 @@
"sortByLastModified": "Подредба по последна промяна",
"sortByName": "Подредба по име",
"sortBySize": "Подредба по размер",
"noPreview": "За този файл не е наличен преглед."
"noPreview": "За този файл не е наличен преглед.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "избери файл или директория",

View File

@@ -43,7 +43,8 @@
"upload": "Pujar",
"openFile": "Obrir fitxer",
"discardChanges": "Descartar",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Descarregar fitxer",
@@ -75,7 +76,9 @@
"sortByLastModified": "Ordenar per última modificació",
"sortByName": "Ordenar per nom",
"sortBySize": "Ordenar per mida",
"noPreview": "La vista prèvia no està disponible per a aquest fitxer."
"noPreview": "La vista prèvia no està disponible per a aquest fitxer.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "seleccionar fitxer o carpeta",

View File

@@ -43,7 +43,8 @@
"upload": "Nahrát",
"openFile": "Otevřít soubor",
"discardChanges": "Zrušit změny",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Stáhnout soubor",
@@ -75,7 +76,9 @@
"sortByLastModified": "Seřadit podle poslední změny",
"sortByName": "Seřadit podle názvu",
"sortBySize": "Seřadit podle velikosti",
"noPreview": "Náhled pro tento soubor není k dispozici."
"noPreview": "Náhled pro tento soubor není k dispozici.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "vyberte soubor nebo adresář",

View File

@@ -43,7 +43,8 @@
"upload": "Upload",
"openFile": "Datei öffnen",
"discardChanges": "Verwerfen",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Download Datei",
@@ -75,7 +76,9 @@
"sortByLastModified": "Nach Änderungsdatum sortieren",
"sortByName": "Nach Namen sortieren",
"sortBySize": "Nach Größe sortieren",
"noPreview": "Für diese Datei ist keine Vorschau verfügbar."
"noPreview": "Für diese Datei ist keine Vorschau verfügbar.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "Wähle Datei oder Ordner",

View File

@@ -43,7 +43,8 @@
"upload": "Μεταφόρτωση",
"openFile": "Άνοιγμα αρχείου",
"discardChanges": "Discard",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Λήψη αρχείου",
@@ -75,7 +76,9 @@
"sortByLastModified": "Ταξινόμηση κατά πρόσφατη τροποποίηση",
"sortByName": "Ταξινόμηση κατά όνομα",
"sortBySize": "Ταξινόμηση κατά μέγεθος",
"noPreview": "Η προεπισκόπηση δεν είναι διαθέσιμη για αυτό το αρχείο."
"noPreview": "Η προεπισκόπηση δεν είναι διαθέσιμη για αυτό το αρχείο.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "επιλέξτε αρχείο ή φάκελο",

View File

@@ -43,7 +43,8 @@
"upload": "Upload",
"openFile": "Open file",
"discardChanges": "Discard",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Download File",
@@ -75,7 +76,9 @@
"sortByLastModified": "Sort by last modified",
"sortByName": "Sort by name",
"sortBySize": "Sort by size",
"noPreview": "Preview is not available for this file."
"noPreview": "Preview is not available for this file.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "select file or directory",

View File

@@ -43,7 +43,8 @@
"upload": "Subir",
"openFile": "Abrir archivo",
"discardChanges": "Discard",
"saveChanges": "Guardar cambios"
"saveChanges": "Guardar cambios",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Descargar fichero",
@@ -75,7 +76,9 @@
"sortByLastModified": "Ordenar por última modificación",
"sortByName": "Ordenar por nombre",
"sortBySize": "Ordenar por tamaño",
"noPreview": "La vista previa no está disponible para este archivo."
"noPreview": "La vista previa no está disponible para este archivo.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "seleccionar archivo o carpeta",

View File

@@ -43,7 +43,8 @@
"upload": "آپلود",
"openFile": "باز کردن فایل",
"discardChanges": "لغو کردن",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "دانلود فایل",
@@ -75,7 +76,9 @@
"sortByLastModified": "مرتب سازی آخرین ویرایش",
"sortByName": "مرتب سازی نام",
"sortBySize": "مرتب سازی اندازه",
"noPreview": "این فایل قابل نمایش نیست"
"noPreview": "این فایل قابل نمایش نیست",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "انتخاب فایل یا پوشه",

View File

@@ -43,7 +43,8 @@
"upload": "Importer",
"openFile": "Ouvrir le fichier",
"discardChanges": "Annuler",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Télécharger le fichier",
@@ -75,7 +76,9 @@
"sortByLastModified": "Trier par date de modification",
"sortByName": "Trier par nom",
"sortBySize": "Trier par taille",
"noPreview": "L'aperçu n'est pas disponible pour ce fichier."
"noPreview": "L'aperçu n'est pas disponible pour ce fichier.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "Sélectionner un fichier ou dossier",

View File

@@ -43,7 +43,8 @@
"upload": "העלאה",
"openFile": "פתח קובץ",
"discardChanges": "זריקת השינויים",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "הורד קובץ",
@@ -75,7 +76,9 @@
"sortByLastModified": "מיין לפי השינוי האחרון",
"sortByName": "מיין לפי שם",
"sortBySize": "מיין לפי גודל",
"noPreview": "לא זמינה תצוגה מקדימה לקובץ זה"
"noPreview": "לא זמינה תצוגה מקדימה לקובץ זה",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "בחר קובץ או תיקייה",

View File

@@ -43,7 +43,8 @@
"upload": "Prenesi",
"openFile": "Otvori datoteku",
"discardChanges": "Odbaci",
"saveChanges": "Spremi promjene"
"saveChanges": "Spremi promjene",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Preuzmi Datoteku",
@@ -75,7 +76,9 @@
"sortByLastModified": "Sortiraj po zadnjoj izmjeni",
"sortByName": "Sortiraj po nazivu",
"sortBySize": "Sortiraj po veličini",
"noPreview": "Pregled nije dostupan za ovu datoteku."
"noPreview": "Pregled nije dostupan za ovu datoteku.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "odaberi datoteku ili mapu",
@@ -102,7 +105,7 @@
"username": "Korisničko ime",
"usernameTaken": "Korisničko ime zauzeto",
"wrongCredentials": "Neispravno korisničko ime/lozinka",
"passwordTooShort": "Password must be at least {min} characters",
"passwordTooShort": "Lozinka mora sadržavati minimalno {min} znakova",
"logout_reasons": {
"inactivity": "Odjavljeni ste zbog neaktivnosti."
}
@@ -167,7 +170,7 @@
"allowNew": "Stvori nove datoteke i mape",
"allowPublish": "Objavi nove objave i stranice",
"allowSignup": "Dopusti registraciju korisnicima",
"hideLoginButton": "Hide the login button from public pages",
"hideLoginButton": "Sakrij tipku za prijavu s javnih stranica",
"avoidChanges": "(ostavite prazno kako biste izbjegli promjene)",
"branding": "Brendiranje",
"brandingDirectoryPath": "Put brendiranja",

View File

@@ -43,7 +43,8 @@
"upload": "Feltöltés",
"openFile": "Fájl megnyitása",
"discardChanges": "Discard",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Fájl letöltése",
@@ -75,7 +76,9 @@
"sortByLastModified": "Rendezés utolsó módosítás szerint",
"sortByName": "Rendezés név szerint",
"sortBySize": "Rendezés méret szerint",
"noPreview": "Ehhez a fájlhoz nincs előnézet."
"noPreview": "Ehhez a fájlhoz nincs előnézet.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "mappa vagy fájl kijelölése",

View File

@@ -43,7 +43,8 @@
"upload": "Hlaða upp",
"openFile": "Open file",
"discardChanges": "Discard",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Sækja skjal",
@@ -75,7 +76,9 @@
"sortByLastModified": "Flokka eftir Seinast breytt",
"sortByName": "Flokka eftir nafni",
"sortBySize": "Flokka eftir stærð",
"noPreview": "Preview is not available for this file."
"noPreview": "Preview is not available for this file.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "velja skjal eða möppu",

View File

@@ -43,7 +43,8 @@
"upload": "Carica",
"openFile": "Apri file",
"discardChanges": "Ignora",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Scarica file",
@@ -75,7 +76,9 @@
"sortByLastModified": "Ordina per ultima modifica",
"sortByName": "Ordina per nome",
"sortBySize": "Ordina per dimensione",
"noPreview": "L'anteprima non è disponibile per questo file."
"noPreview": "L'anteprima non è disponibile per questo file.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "seleziona un file o una cartella",

View File

@@ -43,7 +43,8 @@
"upload": "アップロード",
"openFile": "ファイルを開く",
"discardChanges": "Discard",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "ファイルのダウンロード",
@@ -75,7 +76,9 @@
"sortByLastModified": "更新日時で並べ替え",
"sortByName": "名前で並べ替え",
"sortBySize": "サイズで並べ替え",
"noPreview": "プレビューはこのファイルでは利用できません"
"noPreview": "プレビューはこのファイルでは利用できません",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "ファイルやフォルダーを選択",

View File

@@ -43,7 +43,8 @@
"upload": "업로드",
"openFile": "파일 열기",
"discardChanges": "변경 사항 취소",
"saveChanges": "변경사항 저장"
"saveChanges": "변경사항 저장",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "파일 다운로드",
@@ -75,7 +76,9 @@
"sortByLastModified": "수정시간순 정렬",
"sortByName": "이름순",
"sortBySize": "크기순",
"noPreview": "미리 보기가 지원되지 않는 파일 유형입니다."
"noPreview": "미리 보기가 지원되지 않는 파일 유형입니다.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "파일이나 디렉토리를 선택해주세요.",

View File

@@ -43,7 +43,8 @@
"upload": "Uploaden",
"openFile": "Open file",
"discardChanges": "Discard",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Bestand downloaden",
@@ -75,7 +76,9 @@
"sortByLastModified": "Sorteren op laatst bewerkt",
"sortByName": "Sorteren op naam",
"sortBySize": "Sorteren op grootte",
"noPreview": "Preview is not available for this file."
"noPreview": "Preview is not available for this file.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "selecteer bestand of map",

View File

@@ -43,7 +43,8 @@
"upload": "Last opp",
"openFile": "Open file",
"discardChanges": "Slett",
"saveChanges": "Lagre Endringane "
"saveChanges": "Lagre Endringane ",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Nedlast filen",
@@ -75,7 +76,9 @@
"sortByLastModified": "Sorter etter sist endret",
"sortByName": "Sorter etter navn",
"sortBySize": "Sorter etter størrelse",
"noPreview": "Forhåndsvisning er ikkje tilgjengeleg for denne filen."
"noPreview": "Forhåndsvisning er ikkje tilgjengeleg for denne filen.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "velg fil eller katalog",

View File

@@ -43,7 +43,8 @@
"upload": "Wyślij",
"openFile": "Otwórz plik",
"discardChanges": "Odrzuć",
"saveChanges": "Zapisz zmiany"
"saveChanges": "Zapisz zmiany",
"editAsText": "Edytuj jako tekst"
},
"download": {
"downloadFile": "Pobierz plik",
@@ -75,7 +76,9 @@
"sortByLastModified": "Sortuj wg ostatniej modyfikacji",
"sortByName": "Sortuj wg nazwy",
"sortBySize": "Sortuj wg rozmiaru",
"noPreview": "Podgląd tego pliku jest niedostępny."
"noPreview": "Podgląd tego pliku jest niedostępny.",
"csvTooLarge": "Plik CSV jest za duży do podglądu (>5 MB). Pobierz, aby wyświetlić.",
"csvLoadFailed": "Nie udało się załadować pliku CSV."
},
"help": {
"click": "zaznacz plik lub folder",

View File

@@ -43,7 +43,8 @@
"upload": "Enviar",
"openFile": "Abrir",
"discardChanges": "Discard",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Baixar arquivo",
@@ -75,7 +76,9 @@
"sortByLastModified": "Ordenar pela última modificação",
"sortByName": "Ordenar pelo nome",
"sortBySize": "Ordenar pelo tamanho",
"noPreview": "Pré-visualização não disponível para este arquivo."
"noPreview": "Pré-visualização não disponível para este arquivo.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "selecionar pasta ou arquivo",

View File

@@ -43,7 +43,8 @@
"upload": "Enviar",
"openFile": "Open file",
"discardChanges": "Discard",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Descarregar ficheiro",
@@ -75,7 +76,9 @@
"sortByLastModified": "Ordenar pela última alteração",
"sortByName": "Ordenar pelo nome",
"sortBySize": "Ordenar pelo tamanho",
"noPreview": "Preview is not available for this file."
"noPreview": "Preview is not available for this file.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "selecionar pasta ou ficheiro",

View File

@@ -43,7 +43,8 @@
"upload": "Încarcă",
"openFile": "Open file",
"discardChanges": "Discard",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Descarcă fișier",
@@ -75,7 +76,9 @@
"sortByLastModified": "Ordonează dup ultima modificare",
"sortByName": "Ordonează după nume",
"sortBySize": "Ordonează după dimensiune",
"noPreview": "Preview is not available for this file."
"noPreview": "Preview is not available for this file.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "alege fișier sau director",

View File

@@ -43,7 +43,8 @@
"upload": "Загрузить",
"openFile": "Открыть файл",
"discardChanges": "Отказаться",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Скачать файл",
@@ -75,7 +76,9 @@
"sortByLastModified": "Сортировка по дате изменения",
"sortByName": "Сортировка по имени",
"sortBySize": "Сортировка по размеру",
"noPreview": "Предварительный просмотр для этого файла недоступен."
"noPreview": "Предварительный просмотр для этого файла недоступен.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "выбрать файл или каталог",

View File

@@ -43,7 +43,8 @@
"upload": "Nahrať",
"openFile": "Otvoriť súbor",
"discardChanges": "Zahodiť",
"saveChanges": "Uložiť zmeny"
"saveChanges": "Uložiť zmeny",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Stiahnuť súbor",
@@ -75,7 +76,9 @@
"sortByLastModified": "Zoradiť podľa dátumu",
"sortByName": "Zoradiť podľa názvu",
"sortBySize": "Zoradiť podľa veľkosti",
"noPreview": "Pre tento súbor nie je dostupný náhľad."
"noPreview": "Pre tento súbor nie je dostupný náhľad.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "vyberie súbor alebo priečinok",

View File

@@ -43,7 +43,8 @@
"upload": "Ladda upp",
"openFile": "Öppna fil",
"discardChanges": "Förkasta",
"saveChanges": "Spara ändringar"
"saveChanges": "Spara ändringar",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Ladda ner fil",
@@ -75,7 +76,9 @@
"sortByLastModified": "Sortera på senast ändrad",
"sortByName": "Sortera på namn",
"sortBySize": "Sortera på storlek",
"noPreview": "Förhandsvisning är inte tillgänglig för denna fil."
"noPreview": "Förhandsvisning är inte tillgänglig för denna fil.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "välj fil eller mapp",

View File

@@ -43,7 +43,8 @@
"upload": "Yükle",
"openFile": "Dosyayı aç",
"discardChanges": "Discard",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Dosyayı indir",
@@ -75,7 +76,9 @@
"sortByLastModified": "Güncelleme tarihine göre sırala",
"sortByName": "İsme göre sırala",
"sortBySize": "Boyuta göre sırala",
"noPreview": "Bu dosya için önizleme aktif değil"
"noPreview": "Bu dosya için önizleme aktif değil",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "dosya veya klasör seçin",

View File

@@ -43,7 +43,8 @@
"upload": "Вивантажити",
"openFile": "Відкрити файл",
"discardChanges": "Скасувати",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Завантажити файл",
@@ -75,7 +76,9 @@
"sortByLastModified": "Сортувати за останнім зміненням",
"sortByName": "Сортувати за іменем",
"sortBySize": "Сортувати за розміром",
"noPreview": "Попередній перегляд для цього файлу недоступний."
"noPreview": "Попередній перегляд для цього файлу недоступний.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "вибрати файл чи каталог",

View File

@@ -43,7 +43,8 @@
"upload": "Tải lên",
"openFile": "Mở tệp",
"discardChanges": "Hủy bỏ thay đổi",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "Tải xuống tệp tin",
@@ -75,7 +76,9 @@
"sortByLastModified": "Sắp xếp theo ngày sửa đổi",
"sortByName": "Sắp xếp theo tên",
"sortBySize": "Sắp xếp theo kích thước",
"noPreview": "Không có bản xem trước cho tập tin này."
"noPreview": "Không có bản xem trước cho tập tin này.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "chọn tập tin hoặc thư mục",

View File

@@ -43,7 +43,8 @@
"upload": "上传",
"openFile": "打开文件",
"discardChanges": "放弃更改",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "下载文件",
@@ -75,7 +76,9 @@
"sortByLastModified": "按最后修改时间排序",
"sortByName": "按名称排序",
"sortBySize": "按大小排序",
"noPreview": "此文件无法预览。"
"noPreview": "此文件无法预览。",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "选择文件或文件夹",

View File

@@ -43,7 +43,8 @@
"upload": "上傳",
"openFile": "開啟檔案",
"discardChanges": "放棄變更",
"saveChanges": "Save changes"
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
},
"download": {
"downloadFile": "下載檔案",
@@ -75,7 +76,9 @@
"sortByLastModified": "按最後修改時間排序",
"sortByName": "按名稱排序",
"sortBySize": "按大小排序",
"noPreview": "此檔案無法預覽。"
"noPreview": "此檔案無法預覽。",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
},
"help": {
"click": "選擇檔案或目錄",

View File

@@ -2,7 +2,7 @@ import { useAuthStore } from "@/stores/auth";
import router from "@/router";
import type { JwtPayload } from "jwt-decode";
import { jwtDecode } from "jwt-decode";
import { baseURL, noAuth } from "./constants";
import { authMethod, baseURL, noAuth, logoutPage } from "./constants";
import { StatusError } from "@/api/utils";
import { setSafeTimeout } from "@/api/utils";
@@ -18,6 +18,12 @@ export function parseToken(token: string) {
authStore.jwt = token;
authStore.setUser(data.user);
// proxy auth with custom logout subject to unknown external timeout
if (logoutPage !== "/login" && authMethod === "proxy") {
console.warn("idle timeout disabled with proxy auth and custom logout");
return;
}
if (authStore.logoutTimer) {
clearTimeout(authStore.logoutTimer);
}
@@ -118,6 +124,8 @@ export function logout(reason?: string) {
localStorage.setItem("jwt", "");
if (noAuth) {
window.location.reload();
} else if (logoutPage !== "/login") {
document.location.href = `${logoutPage}`;
} else {
if (typeof reason === "string" && reason.trim() !== "") {
router.push({

View File

@@ -10,6 +10,7 @@ const version: string = window.FileBrowser.Version;
const logoURL = `${staticURL}/img/logo.svg`;
const noAuth: boolean = window.FileBrowser.NoAuth;
const authMethod = window.FileBrowser.AuthMethod;
const logoutPage: string = window.FileBrowser.LogoutPage;
const loginPage: boolean = window.FileBrowser.LoginPage;
const theme: UserTheme = window.FileBrowser.Theme;
const enableThumbs: boolean = window.FileBrowser.EnableThumbs;
@@ -32,6 +33,7 @@ export {
version,
noAuth,
authMethod,
logoutPage,
loginPage,
theme,
enableThumbs,

61
frontend/src/utils/csv.ts Normal file
View File

@@ -0,0 +1,61 @@
export interface CsvData {
headers: string[];
rows: string[][];
}
/**
* Parse CSV content into headers and rows
* Supports quoted fields and handles commas within quotes
*/
export function parseCSV(content: string): CsvData {
if (!content || content.trim().length === 0) {
return { headers: [], rows: [] };
}
const lines = content.split(/\r?\n/);
const result: string[][] = [];
for (const line of lines) {
if (line.trim().length === 0) continue;
const row: string[] = [];
let currentField = "";
let inQuotes = false;
for (let i = 0; i < line.length; i++) {
const char = line[i];
const nextChar = line[i + 1];
if (char === '"') {
if (inQuotes && nextChar === '"') {
// Escaped quote
currentField += '"';
i++; // Skip next quote
} else {
// Toggle quote state
inQuotes = !inQuotes;
}
} else if (char === "," && !inQuotes) {
// Field separator
row.push(currentField);
currentField = "";
} else {
currentField += char;
}
}
// Add the last field
row.push(currentField);
result.push(row);
}
if (result.length === 0) {
return { headers: [], rows: [] };
}
// First row is headers
const headers = result[0];
const rows = result.slice(1);
return { headers, rows };
}

View File

@@ -69,6 +69,12 @@ const currentView = computed(() => {
if (fileStore.req.isDir) {
return FileListing;
} else if (fileStore.req.extension.toLowerCase() === ".csv") {
// CSV files use Preview for table view, unless ?edit=true
if (route.query.edit === "true") {
return Editor;
}
return Preview;
} else if (
fileStore.req.type === "text" ||
fileStore.req.type === "textImmutable"

View File

@@ -186,7 +186,7 @@ const handlePageChange = (event: BeforeUnloadEvent) => {
}
};
const save = async () => {
const save = async (throwError?: boolean) => {
const button = "save";
buttons.loading("save");
@@ -197,6 +197,7 @@ const save = async () => {
} catch (e: any) {
buttons.done(button);
$showError(e);
if (throwError) throw e;
}
};
@@ -223,8 +224,10 @@ const close = () => {
finishClose();
},
saveAction: async () => {
await save();
finishClose();
try {
await save(true);
finishClose();
} catch {}
},
});
return;

View File

@@ -6,7 +6,7 @@
@mousemove="toggleNavigation"
@touchstart="toggleNavigation"
>
<header-bar v-if="isPdf || isEpub || showNav">
<header-bar v-if="isPdf || isEpub || isCsv || showNav">
<action icon="close" :label="$t('buttons.close')" @action="close()" />
<title>{{ name }}</title>
<action
@@ -24,6 +24,13 @@
:label="$t('buttons.rename')"
show="rename"
/>
<action
:disabled="layoutStore.loading"
v-if="isCsv && authStore.user?.perm.modify"
icon="edit_note"
:label="t('buttons.editAsText')"
@action="editAsText"
/>
<action
:disabled="layoutStore.loading"
v-if="authStore.user?.perm.delete"
@@ -87,6 +94,7 @@
<span>{{ size }}%</span>
</div>
</div>
<CsvViewer v-else-if="isCsv" :content="csvContent" :error="csvError" />
<ExtendedImage
v-else-if="fileStore.req?.type == 'image'"
:src="previewUrl"
@@ -176,11 +184,17 @@ import HeaderBar from "@/components/header/HeaderBar.vue";
import Action from "@/components/header/Action.vue";
import ExtendedImage from "@/components/files/ExtendedImage.vue";
import VideoPlayer from "@/components/files/VideoPlayer.vue";
import CsvViewer from "@/components/files/CsvViewer.vue";
import { VueReader } from "vue-reader";
import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import type { Rendition } from "epubjs";
import { getTheme } from "@/utils/theme";
import { useI18n } from "vue-i18n";
// CSV file size limit for preview (5MB)
// Prevents browser memory issues with large files
const CSV_MAX_SIZE = 5 * 1024 * 1024;
const location = useStorage("book-progress", 0, undefined, {
serializer: {
@@ -239,6 +253,8 @@ const hoverNav = ref<boolean>(false);
const autoPlay = ref<boolean>(false);
const previousRaw = ref<string>("");
const nextRaw = ref<string>("");
const csvContent = ref<string>("");
const csvError = ref<string>("");
const player = ref<HTMLVideoElement | HTMLAudioElement | null>(null);
@@ -248,6 +264,8 @@ const authStore = useAuthStore();
const fileStore = useFileStore();
const layoutStore = useLayoutStore();
const { t } = useI18n();
const route = useRoute();
const router = useRouter();
@@ -279,6 +297,7 @@ const isPdf = computed(() => fileStore.req?.extension.toLowerCase() == ".pdf");
const isEpub = computed(
() => fileStore.req?.extension.toLowerCase() == ".epub"
);
const isCsv = computed(() => fileStore.req?.extension.toLowerCase() == ".csv");
const isResizeEnabled = computed(() => resizePreview);
@@ -366,6 +385,18 @@ const updatePreview = async () => {
const dirs = route.fullPath.split("/");
name.value = decodeURIComponent(dirs[dirs.length - 1]);
// Load CSV content if it's a CSV file
if (isCsv.value && fileStore.req) {
csvContent.value = "";
csvError.value = "";
if (fileStore.req.size > CSV_MAX_SIZE) {
csvError.value = t("files.csvTooLarge");
} else {
csvContent.value = fileStore.req.content ?? "";
}
}
if (!listing.value) {
try {
const path = url.removeLastDir(route.path);
@@ -435,4 +466,8 @@ const close = () => {
};
const download = () => window.open(downloadUrl.value);
const editAsText = () => {
router.push({ path: route.path, query: { edit: "true" } });
};
</script>

View File

@@ -12,7 +12,9 @@ import (
"github.com/golang-jwt/jwt/v5"
"github.com/golang-jwt/jwt/v5/request"
fbAuth "github.com/filebrowser/filebrowser/v2/auth"
fbErrors "github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users"
)
@@ -61,6 +63,22 @@ func (e extractor) ExtractToken(r *http.Request) (string, error) {
return "", request.ErrNoTokenInRequest
}
func renewableErr(err error, d *data) bool {
if d.settings.AuthMethod != fbAuth.MethodProxyAuth || err == nil {
return false
}
if d.settings.LogoutPage == settings.DefaultLogoutPage {
return false
}
if !errors.Is(err, jwt.ErrTokenExpired) {
return false
}
return true
}
func withUser(fn handleFunc) handleFunc {
return func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
keyFunc := func(_ *jwt.Token) (interface{}, error) {
@@ -68,13 +86,9 @@ func withUser(fn handleFunc) handleFunc {
}
var tk authToken
token, err := request.ParseFromRequest(r, &extractor{}, keyFunc, request.WithClaims(&tk))
if err != nil || !token.Valid {
return http.StatusUnauthorized, nil
}
err = jwt.NewValidator(jwt.WithExpirationRequired()).Validate(tk)
if err != nil {
p := jwt.NewParser(jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}), jwt.WithExpirationRequired())
token, err := request.ParseFromRequest(r, &extractor{}, keyFunc, request.WithClaims(&tk), request.WithParser(p))
if (err != nil || !token.Valid) && !renewableErr(err, d) {
return http.StatusUnauthorized, nil
}

View File

@@ -38,6 +38,7 @@ func handleWithStaticData(w http.ResponseWriter, _ *http.Request, d *data, fSys
"Signup": d.settings.Signup,
"NoAuth": d.settings.AuthMethod == auth.MethodNoAuth,
"AuthMethod": d.settings.AuthMethod,
"LogoutPage": d.settings.LogoutPage,
"LoginPage": auther.LoginPage(),
"CSS": false,
"ReCaptcha": false,

View File

@@ -11,6 +11,7 @@ import (
)
const DefaultUsersHomeBasePath = "/users"
const DefaultLogoutPage = "/login"
const DefaultMinimumPasswordLength = 12
const DefaultFileMode = 0640
const DefaultDirMode = 0750
@@ -27,6 +28,7 @@ type Settings struct {
UserHomeBasePath string `json:"userHomeBasePath"`
Defaults UserDefaults `json:"defaults"`
AuthMethod AuthMethod `json:"authMethod"`
LogoutPage string `json:"logoutPage"`
Branding Branding `json:"branding"`
Tus Tus `json:"tus"`
Commands map[string][]string `json:"commands"`

View File

@@ -30,24 +30,34 @@ func (s *Storage) Get() (*Settings, error) {
if err != nil {
return nil, err
}
if set.UserHomeBasePath == "" {
set.UserHomeBasePath = DefaultUsersHomeBasePath
}
if set.LogoutPage == "" {
set.LogoutPage = DefaultLogoutPage
}
if set.MinimumPasswordLength == 0 {
set.MinimumPasswordLength = DefaultMinimumPasswordLength
}
if set.Tus == (Tus{}) {
set.Tus = Tus{
ChunkSize: DefaultTusChunkSize,
RetryCount: DefaultTusRetryCount,
}
}
if set.FileMode == 0 {
set.FileMode = DefaultFileMode
}
if set.DirMode == 0 {
set.DirMode = DefaultDirMode
}
return set, nil
}

View File

@@ -21,6 +21,7 @@ filebrowser config init [flags]
-a, --address string address to listen on (default "127.0.0.1")
--auth.command string command for auth.method=hook
--auth.header string HTTP header for auth.method=proxy
--auth.logoutPage string url of custom logout page
--auth.method string authentication type (default "json")
-b, --baseURL string base url
--branding.color string set the theme color

View File

@@ -18,6 +18,7 @@ filebrowser config set [flags]
-a, --address string address to listen on (default "127.0.0.1")
--auth.command string command for auth.method=hook
--auth.header string HTTP header for auth.method=proxy
--auth.logoutPage string url of custom logout page
--auth.method string authentication type (default "json")
-b, --baseURL string base url
--branding.color string set the theme color