mirror of
https://github.com/filebrowser/filebrowser.git
synced 2025-09-03 13:00:32 +00:00
Compare commits
8 Commits
25e47c3ce8
...
14ee054359
Author | SHA1 | Date | |
---|---|---|---|
![]() |
14ee054359 | ||
![]() |
7f559ffd07 | ||
![]() |
619f6837b0 | ||
![]() |
d778c192ae | ||
![]() |
a290c6d7db | ||
![]() |
c1b0207800 | ||
![]() |
c7a5c7efee | ||
![]() |
cbeec6d225 |
6
.github/workflows/main.yaml
vendored
6
.github/workflows/main.yaml
vendored
@ -29,7 +29,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.23.0
|
go-version: '1.24'
|
||||||
- run: make lint-backend
|
- run: make lint-backend
|
||||||
lint:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -57,7 +57,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.23.0
|
go-version: '1.24'
|
||||||
- run: make test-backend
|
- run: make test-backend
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -76,7 +76,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.23.0
|
go-version: '1.23'
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
with:
|
with:
|
||||||
package_json_file: "frontend/package.json"
|
package_json_file: "frontend/package.json"
|
||||||
|
26
CHANGELOG.md
26
CHANGELOG.md
@ -2,6 +2,32 @@
|
|||||||
|
|
||||||
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.
|
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.42.0](https://github.com/filebrowser/filebrowser/compare/v2.41.0...v2.42.0) (2025-07-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add Norwegian support ([#5332](https://github.com/filebrowser/filebrowser/issues/5332)) ([25e47c3](https://github.com/filebrowser/filebrowser/commit/25e47c3ce8b35b820b5370a4b8bfdf682bd5ae0b))
|
||||||
|
* select item on file list after navigating back ([#5329](https://github.com/filebrowser/filebrowser/issues/5329)) ([cbeec6d](https://github.com/filebrowser/filebrowser/commit/cbeec6d225691723c4750d7f84122ebb14d662bf))
|
||||||
|
* Translate frontend/src/i18n/en.json in no ([5eb3bf4](https://github.com/filebrowser/filebrowser/commit/5eb3bf40586c2ffc32f4834b5dd59f0eb719c1f7))
|
||||||
|
* Translate frontend/src/i18n/en.json in sk ([07dfdce](https://github.com/filebrowser/filebrowser/commit/07dfdce8e4c371f4ca7480f3cef0bd66ff5c9abb))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* norsk loading ([619f683](https://github.com/filebrowser/filebrowser/commit/619f6837b0d1ec6c654d30f4ecedd6696874721f))
|
||||||
|
|
||||||
|
|
||||||
|
### Reverts
|
||||||
|
|
||||||
|
* Revert "chore(release): 2.42.0" ([d778c19](https://github.com/filebrowser/filebrowser/commit/d778c192ae02c5e73781f7632e3b7276c5811e17))
|
||||||
|
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
* bump go version to 1.23.11 ([c7a5c7e](https://github.com/filebrowser/filebrowser/commit/c7a5c7efee2b2bede89ec90bafd1af61c39519ff))
|
||||||
|
* bump to go 1.24 ([c1b0207](https://github.com/filebrowser/filebrowser/commit/c1b0207800b4bb52c8dd459c1d69ce0f785473b6))
|
||||||
|
|
||||||
## [2.41.0](https://github.com/filebrowser/filebrowser/compare/v2.40.2...v2.41.0) (2025-07-22)
|
## [2.41.0](https://github.com/filebrowser/filebrowser/compare/v2.40.2...v2.41.0) (2025-07-22)
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ import FileList from "./FileList.vue";
|
|||||||
import { files as api } from "@/api";
|
import { files as api } from "@/api";
|
||||||
import buttons from "@/utils/buttons";
|
import buttons from "@/utils/buttons";
|
||||||
import * as upload from "@/utils/upload";
|
import * as upload from "@/utils/upload";
|
||||||
|
import { removePrefix } from "@/api/utils";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "copy",
|
name: "copy",
|
||||||
@ -76,7 +77,7 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
...mapState(useFileStore, ["req", "selected"]),
|
...mapState(useFileStore, ["req", "selected"]),
|
||||||
...mapState(useAuthStore, ["user"]),
|
...mapState(useAuthStore, ["user"]),
|
||||||
...mapWritableState(useFileStore, ["reload"]),
|
...mapWritableState(useFileStore, ["reload", "preselect"]),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(useLayoutStore, ["showHover", "closeHovers"]),
|
...mapActions(useLayoutStore, ["showHover", "closeHovers"]),
|
||||||
@ -100,6 +101,7 @@ export default {
|
|||||||
.copy(items, overwrite, rename)
|
.copy(items, overwrite, rename)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
buttons.success("copy");
|
buttons.success("copy");
|
||||||
|
this.preselect = removePrefix(items[0].to);
|
||||||
|
|
||||||
if (this.$route.path === this.dest) {
|
if (this.$route.path === this.dest) {
|
||||||
this.reload = true;
|
this.reload = true;
|
||||||
|
@ -48,16 +48,15 @@ export default {
|
|||||||
"selectedCount",
|
"selectedCount",
|
||||||
"req",
|
"req",
|
||||||
"selected",
|
"selected",
|
||||||
"currentPrompt",
|
|
||||||
]),
|
]),
|
||||||
...mapWritableState(useFileStore, ["reload"]),
|
...mapState(useLayoutStore, ["currentPrompt"]),
|
||||||
|
...mapWritableState(useFileStore, ["reload", "preselect"]),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(useLayoutStore, ["closeHovers"]),
|
...mapActions(useLayoutStore, ["closeHovers"]),
|
||||||
submit: async function () {
|
submit: async function () {
|
||||||
buttons.loading("delete");
|
buttons.loading("delete");
|
||||||
|
|
||||||
window.sessionStorage.setItem("modified", "true");
|
|
||||||
try {
|
try {
|
||||||
if (!this.isListing) {
|
if (!this.isListing) {
|
||||||
await api.remove(this.$route.path);
|
await api.remove(this.$route.path);
|
||||||
@ -81,6 +80,12 @@ export default {
|
|||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
buttons.success("delete");
|
buttons.success("delete");
|
||||||
|
|
||||||
|
const nearbyItem =
|
||||||
|
this.req.items[Math.max(0, Math.min(this.selected) - 1)];
|
||||||
|
|
||||||
|
this.preselect = nearbyItem?.path;
|
||||||
|
|
||||||
this.reload = true;
|
this.reload = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
buttons.done("delete");
|
buttons.done("delete");
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
id="focus-prompt"
|
id="focus-prompt"
|
||||||
@click="submit"
|
@click="currentPrompt.confirm"
|
||||||
class="button button--flat button--red"
|
class="button button--flat button--red"
|
||||||
:aria-label="$t('buttons.discardChanges')"
|
:aria-label="$t('buttons.discardChanges')"
|
||||||
:title="$t('buttons.discardChanges')"
|
:title="$t('buttons.discardChanges')"
|
||||||
@ -30,22 +30,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapActions } from "pinia";
|
import { mapState, mapActions } from "pinia";
|
||||||
import url from "@/utils/url";
|
|
||||||
import { useLayoutStore } from "@/stores/layout";
|
import { useLayoutStore } from "@/stores/layout";
|
||||||
import { useFileStore } from "@/stores/file";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "discardEditorChanges",
|
name: "discardEditorChanges",
|
||||||
|
computed: {
|
||||||
|
...mapState(useLayoutStore, ["currentPrompt"]),
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(useLayoutStore, ["closeHovers"]),
|
...mapActions(useLayoutStore, ["closeHovers"]),
|
||||||
...mapActions(useFileStore, ["updateRequest"]),
|
|
||||||
submit: async function () {
|
|
||||||
this.updateRequest(null);
|
|
||||||
|
|
||||||
const uri = url.removeLastDir(this.$route.path) + "/";
|
|
||||||
this.$router.push({ path: uri });
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapActions, mapState } from "pinia";
|
import { mapActions, mapState, mapWritableState } from "pinia";
|
||||||
import { useFileStore } from "@/stores/file";
|
import { useFileStore } from "@/stores/file";
|
||||||
import { useLayoutStore } from "@/stores/layout";
|
import { useLayoutStore } from "@/stores/layout";
|
||||||
import { useAuthStore } from "@/stores/auth";
|
import { useAuthStore } from "@/stores/auth";
|
||||||
@ -63,6 +63,7 @@ import FileList from "./FileList.vue";
|
|||||||
import { files as api } from "@/api";
|
import { files as api } from "@/api";
|
||||||
import buttons from "@/utils/buttons";
|
import buttons from "@/utils/buttons";
|
||||||
import * as upload from "@/utils/upload";
|
import * as upload from "@/utils/upload";
|
||||||
|
import { removePrefix } from "@/api/utils";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "move",
|
name: "move",
|
||||||
@ -77,6 +78,7 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
...mapState(useFileStore, ["req", "selected"]),
|
...mapState(useFileStore, ["req", "selected"]),
|
||||||
...mapState(useAuthStore, ["user"]),
|
...mapState(useAuthStore, ["user"]),
|
||||||
|
...mapWritableState(useFileStore, ["preselect"]),
|
||||||
excludedFolders() {
|
excludedFolders() {
|
||||||
return this.selected
|
return this.selected
|
||||||
.filter((idx) => this.req.items[idx].isDir)
|
.filter((idx) => this.req.items[idx].isDir)
|
||||||
@ -104,6 +106,7 @@ export default {
|
|||||||
.move(items, overwrite, rename)
|
.move(items, overwrite, rename)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
buttons.success("move");
|
buttons.success("move");
|
||||||
|
this.preselect = removePrefix(items[0].to);
|
||||||
this.$router.push({ path: this.dest });
|
this.$router.push({ path: this.dest });
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
|
@ -46,6 +46,7 @@ import { useFileStore } from "@/stores/file";
|
|||||||
import { useLayoutStore } from "@/stores/layout";
|
import { useLayoutStore } from "@/stores/layout";
|
||||||
import url from "@/utils/url";
|
import url from "@/utils/url";
|
||||||
import { files as api } from "@/api";
|
import { files as api } from "@/api";
|
||||||
|
import { removePrefix } from "@/api/utils";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "rename",
|
name: "rename",
|
||||||
@ -65,7 +66,7 @@ export default {
|
|||||||
"selectedCount",
|
"selectedCount",
|
||||||
"isListing",
|
"isListing",
|
||||||
]),
|
]),
|
||||||
...mapWritableState(useFileStore, ["reload"]),
|
...mapWritableState(useFileStore, ["reload", "preselect"]),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(useLayoutStore, ["closeHovers"]),
|
...mapActions(useLayoutStore, ["closeHovers"]),
|
||||||
@ -97,7 +98,6 @@ export default {
|
|||||||
newLink =
|
newLink =
|
||||||
url.removeLastDir(oldLink) + "/" + encodeURIComponent(this.name);
|
url.removeLastDir(oldLink) + "/" + encodeURIComponent(this.name);
|
||||||
|
|
||||||
window.sessionStorage.setItem("modified", "true");
|
|
||||||
try {
|
try {
|
||||||
await api.move([{ from: oldLink, to: newLink }]);
|
await api.move([{ from: oldLink, to: newLink }]);
|
||||||
if (!this.isListing) {
|
if (!this.isListing) {
|
||||||
@ -105,6 +105,8 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.preselect = removePrefix(newLink);
|
||||||
|
|
||||||
this.reload = true;
|
this.reload = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e);
|
this.$showError(e);
|
||||||
|
@ -30,6 +30,7 @@ export default {
|
|||||||
ja: "日本語",
|
ja: "日本語",
|
||||||
ko: "한국어",
|
ko: "한국어",
|
||||||
"nl-be": "Dutch (Belgium)",
|
"nl-be": "Dutch (Belgium)",
|
||||||
|
no: "Norsk",
|
||||||
pl: "Polski",
|
pl: "Polski",
|
||||||
"pt-br": "Português",
|
"pt-br": "Português",
|
||||||
pt: "Português (Brasil)",
|
pt: "Português (Brasil)",
|
||||||
|
@ -96,6 +96,9 @@ main {
|
|||||||
height: 3em;
|
height: 3em;
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
border-bottom: 1px solid var(--divider);
|
border-bottom: 1px solid var(--divider);
|
||||||
|
position: sticky;
|
||||||
|
z-index: 1000;
|
||||||
|
top: 4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.breadcrumbs span,
|
.breadcrumbs span,
|
||||||
|
@ -329,6 +329,7 @@ main .spinner .bounce2 {
|
|||||||
#editor-container {
|
#editor-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
padding-top: 4em;
|
padding-top: 4em;
|
||||||
@ -351,6 +352,8 @@ main .spinner .bounce2 {
|
|||||||
#editor-container .breadcrumbs {
|
#editor-container .breadcrumbs {
|
||||||
height: 2.3em;
|
height: 2.3em;
|
||||||
padding: 0 1em;
|
padding: 0 1em;
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** RTL - flip and position arrow of path ***/
|
/*** RTL - flip and position arrow of path ***/
|
||||||
|
@ -27,7 +27,7 @@ import("dayjs/locale/vi");
|
|||||||
import("dayjs/locale/zh-cn");
|
import("dayjs/locale/zh-cn");
|
||||||
import("dayjs/locale/zh-tw");
|
import("dayjs/locale/zh-tw");
|
||||||
import("dayjs/locale/cs");
|
import("dayjs/locale/cs");
|
||||||
import("dayjs/locale/no");
|
import("dayjs/locale/nb");
|
||||||
|
|
||||||
// All i18n resources specified in the plugin `include` option can be loaded
|
// All i18n resources specified in the plugin `include` option can be loaded
|
||||||
// at once using the import syntax
|
// at once using the import syntax
|
||||||
@ -102,7 +102,6 @@ export function detectLocale() {
|
|||||||
case /^tr\b/.test(locale):
|
case /^tr\b/.test(locale):
|
||||||
locale = "tr";
|
locale = "tr";
|
||||||
break;
|
break;
|
||||||
// ua wasnt a valid locale for ukraine
|
|
||||||
case /^uk\b/.test(locale):
|
case /^uk\b/.test(locale):
|
||||||
locale = "uk";
|
locale = "uk";
|
||||||
break;
|
break;
|
||||||
@ -116,6 +115,10 @@ export function detectLocale() {
|
|||||||
case /^nl-be\b/.test(locale):
|
case /^nl-be\b/.test(locale):
|
||||||
locale = "nl-be";
|
locale = "nl-be";
|
||||||
break;
|
break;
|
||||||
|
case /^nb\b/.test(locale):
|
||||||
|
case /^no\b/.test(locale):
|
||||||
|
locale = "no";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
locale = "en";
|
locale = "en";
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,13 @@
|
|||||||
"copy": "Kopírovať",
|
"copy": "Kopírovať",
|
||||||
"copyFile": "Kopírovať súbor",
|
"copyFile": "Kopírovať súbor",
|
||||||
"copyToClipboard": "Kopírovať do schránky",
|
"copyToClipboard": "Kopírovať do schránky",
|
||||||
"copyDownloadLinkToClipboard": "Copy download link to clipboard",
|
"copyDownloadLinkToClipboard": "Kopírovať odkaz na stiahnutie do schránky",
|
||||||
"create": "Vytvoriť",
|
"create": "Vytvoriť",
|
||||||
"delete": "Odstrániť",
|
"delete": "Odstrániť",
|
||||||
"download": "Stiahnuť",
|
"download": "Stiahnuť",
|
||||||
"file": "Súbor",
|
"file": "Súbor",
|
||||||
"folder": "Priečinok",
|
"folder": "Priečinok",
|
||||||
"fullScreen": "Toggle full screen",
|
"fullScreen": "Prepnúť na celú obrazovku",
|
||||||
"hideDotfiles": "Skryť súbory začínajúce bodkou",
|
"hideDotfiles": "Skryť súbory začínajúce bodkou",
|
||||||
"info": "Info",
|
"info": "Info",
|
||||||
"more": "Viac",
|
"more": "Viac",
|
||||||
@ -24,7 +24,7 @@
|
|||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"permalink": "Získať trvalý odkaz",
|
"permalink": "Získať trvalý odkaz",
|
||||||
"previous": "Predošlé",
|
"previous": "Predošlé",
|
||||||
"preview": "Preview",
|
"preview": "Náhľad",
|
||||||
"publish": "Zverejniť",
|
"publish": "Zverejniť",
|
||||||
"rename": "Premenovať",
|
"rename": "Premenovať",
|
||||||
"replace": "Nahradiť",
|
"replace": "Nahradiť",
|
||||||
@ -42,7 +42,7 @@
|
|||||||
"update": "Aktualizovať",
|
"update": "Aktualizovať",
|
||||||
"upload": "Nahrať",
|
"upload": "Nahrať",
|
||||||
"openFile": "Otvoriť súbor",
|
"openFile": "Otvoriť súbor",
|
||||||
"discardChanges": "Discard"
|
"discardChanges": "Zahodiť"
|
||||||
},
|
},
|
||||||
"download": {
|
"download": {
|
||||||
"downloadFile": "Stiahnuť súbor",
|
"downloadFile": "Stiahnuť súbor",
|
||||||
@ -50,7 +50,7 @@
|
|||||||
"downloadSelected": "Stiahnuť vybraté"
|
"downloadSelected": "Stiahnuť vybraté"
|
||||||
},
|
},
|
||||||
"upload": {
|
"upload": {
|
||||||
"abortUpload": "Are you sure you wish to abort?"
|
"abortUpload": "Naozaj chcete prerušiť?"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"forbidden": "You don't have permissions to access this.",
|
"forbidden": "You don't have permissions to access this.",
|
||||||
@ -110,7 +110,7 @@
|
|||||||
"deleteMessageMultiple": "Naozaj chcete odstrániť {count} súbor(ov)?",
|
"deleteMessageMultiple": "Naozaj chcete odstrániť {count} súbor(ov)?",
|
||||||
"deleteMessageSingle": "Naozaj chcete odstrániť tento súbor/priečinok?",
|
"deleteMessageSingle": "Naozaj chcete odstrániť tento súbor/priečinok?",
|
||||||
"deleteMessageShare": "Naozaj chcete odstrániť toto zdieľanie({path})?",
|
"deleteMessageShare": "Naozaj chcete odstrániť toto zdieľanie({path})?",
|
||||||
"deleteUser": "Are you sure you want to delete this user?",
|
"deleteUser": "Naozaj chcete odstrániť tohto používateľa?",
|
||||||
"deleteTitle": "Odstránenie súborov",
|
"deleteTitle": "Odstránenie súborov",
|
||||||
"displayName": "Zobrazený názov:",
|
"displayName": "Zobrazený názov:",
|
||||||
"download": "Stiahnuť súbory",
|
"download": "Stiahnuť súbory",
|
||||||
@ -137,11 +137,11 @@
|
|||||||
"show": "Zobraziť",
|
"show": "Zobraziť",
|
||||||
"size": "Veľkosť",
|
"size": "Veľkosť",
|
||||||
"upload": "Nahrať",
|
"upload": "Nahrať",
|
||||||
"uploadFiles": "Uploading {files} files...",
|
"uploadFiles": "Nahráva sa {files} súborov...",
|
||||||
"uploadMessage": "Zvoľte možnosť nahrávania.",
|
"uploadMessage": "Zvoľte možnosť nahrávania.",
|
||||||
"optionalPassword": "Voliteľné heslo",
|
"optionalPassword": "Voliteľné heslo",
|
||||||
"resolution": "Resolution",
|
"resolution": "Rozlíšenie",
|
||||||
"discardEditorChanges": "Are you sure you wish to discard the changes you've made?"
|
"discardEditorChanges": "Naozaj chcete zahodiť vykonané zmeny?"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"images": "Obrázky",
|
"images": "Obrázky",
|
||||||
@ -170,14 +170,14 @@
|
|||||||
"commandRunnerHelp": "Sem môžete nastaviť príkazy, ktoré sa vykonajú pri určitých udalostiach. Musíte písať jeden na riadok. Premenné prostredia {0} a {1} sú k dispozícii, s tým že {0} relatívne k {1}. Viac informácií o tejto funkcionalite a dostupných premenných prostredia nájdete na {2}.",
|
"commandRunnerHelp": "Sem môžete nastaviť príkazy, ktoré sa vykonajú pri určitých udalostiach. Musíte písať jeden na riadok. Premenné prostredia {0} a {1} sú k dispozícii, s tým že {0} relatívne k {1}. Viac informácií o tejto funkcionalite a dostupných premenných prostredia nájdete na {2}.",
|
||||||
"commandsUpdated": "Príkazy upravené!",
|
"commandsUpdated": "Príkazy upravené!",
|
||||||
"createUserDir": "Automaticky vytvoriť domovský priečinok pri pridaní používateľa",
|
"createUserDir": "Automaticky vytvoriť domovský priečinok pri pridaní používateľa",
|
||||||
"minimumPasswordLength": "Minimum password length",
|
"minimumPasswordLength": "Minimálna dĺžka hesla",
|
||||||
"tusUploads": "Chunked Uploads",
|
"tusUploads": "Nahrávanie po častiach",
|
||||||
"tusUploadsHelp": "File Browser supports chunked file uploads, allowing for the creation of efficient, reliable, resumable and chunked file uploads even on unreliable networks.",
|
"tusUploadsHelp": "Prehliadač súborov podporuje nahrávanie súborov po častiach, čo umožňuje vytváranie efektívnych, spoľahlivých, obnoviteľných a po častiach nahrávaných súborov aj v prípade nespoľahlivých sietí.",
|
||||||
"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.",
|
"tusUploadsChunkSize": "Označuje maximálnu veľkosť požiadavky (pre menšie nahratia sa použijú priame nahratia). Môžete zadať celé číslo označujúce veľkosť v bajtoch alebo reťazec ako 10 MB, 1 GB atď.",
|
||||||
"tusUploadsRetryCount": "Number of retries to perform if a chunk fails to upload.",
|
"tusUploadsRetryCount": "Počet opakovaných pokusov, ktoré sa majú vykonať, ak sa nepodarí nahrať časť súboru.",
|
||||||
"userHomeBasePath": "Base path for user home directories",
|
"userHomeBasePath": "Východisková cesta pre domáce adresáre používateľov",
|
||||||
"userScopeGenerationPlaceholder": "The scope will be auto generated",
|
"userScopeGenerationPlaceholder": "Rozsah bude automaticky generovaný",
|
||||||
"createUserHomeDirectory": "Create user home directory",
|
"createUserHomeDirectory": "Vytvoriť domovský adresár používateľa",
|
||||||
"customStylesheet": "Vlastný Stylesheet",
|
"customStylesheet": "Vlastný Stylesheet",
|
||||||
"defaultUserDescription": "Toto sú predvolané nastavenia nového používateľa.",
|
"defaultUserDescription": "Toto sú predvolané nastavenia nového používateľa.",
|
||||||
"disableExternalLinks": "Vypnúť externé odkazy (okrem dokumentácie)",
|
"disableExternalLinks": "Vypnúť externé odkazy (okrem dokumentácie)",
|
||||||
@ -217,14 +217,14 @@
|
|||||||
"rules": "Pravidlá",
|
"rules": "Pravidlá",
|
||||||
"rulesHelp": "Tu môžete definovať pravidlá pre konkrétneho používateľa. Blokované súbory používateľ nebude vidieť a ani nebude k nim mať prístup. Podporujeme regex a cesty relatívne k používateľovi.\n",
|
"rulesHelp": "Tu môžete definovať pravidlá pre konkrétneho používateľa. Blokované súbory používateľ nebude vidieť a ani nebude k nim mať prístup. Podporujeme regex a cesty relatívne k používateľovi.\n",
|
||||||
"scope": "Scope",
|
"scope": "Scope",
|
||||||
"setDateFormat": "Set exact date format",
|
"setDateFormat": "Nastaviť presný formát dátumu",
|
||||||
"settingsUpdated": "Nastavenia upravené!",
|
"settingsUpdated": "Nastavenia upravené!",
|
||||||
"shareDuration": "Trvanie zdieľania",
|
"shareDuration": "Trvanie zdieľania",
|
||||||
"shareManagement": "Správa zdieľania",
|
"shareManagement": "Správa zdieľania",
|
||||||
"shareDeleted": "Zdieľanie odstránené!",
|
"shareDeleted": "Zdieľanie odstránené!",
|
||||||
"singleClick": "Používať jeden klik na otváranie súborov a priečinkov",
|
"singleClick": "Používať jeden klik na otváranie súborov a priečinkov",
|
||||||
"themes": {
|
"themes": {
|
||||||
"default": "System default",
|
"default": "Predvolené nastavenie systému",
|
||||||
"dark": "Tmavá",
|
"dark": "Tmavá",
|
||||||
"light": "Svetlá",
|
"light": "Svetlá",
|
||||||
"title": "Téma"
|
"title": "Téma"
|
||||||
|
@ -9,6 +9,7 @@ export const useFileStore = defineStore("file", {
|
|||||||
selected: number[];
|
selected: number[];
|
||||||
multiple: boolean;
|
multiple: boolean;
|
||||||
isFiles: boolean;
|
isFiles: boolean;
|
||||||
|
preselect: string | null;
|
||||||
} => ({
|
} => ({
|
||||||
req: null,
|
req: null,
|
||||||
oldReq: null,
|
oldReq: null,
|
||||||
@ -16,6 +17,7 @@ export const useFileStore = defineStore("file", {
|
|||||||
selected: [],
|
selected: [],
|
||||||
multiple: false,
|
multiple: false,
|
||||||
isFiles: false,
|
isFiles: false,
|
||||||
|
preselect: null,
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
selectedCount: (state) => state.selected.length,
|
selectedCount: (state) => state.selected.length,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<header-bar
|
<header-bar
|
||||||
v-if="error || fileStore.req?.type === null"
|
v-if="error || fileStore.req?.type === undefined"
|
||||||
showMenu
|
showMenu
|
||||||
showLogo
|
showLogo
|
||||||
/>
|
/>
|
||||||
@ -9,7 +9,7 @@
|
|||||||
<breadcrumbs base="/files" />
|
<breadcrumbs base="/files" />
|
||||||
<errors v-if="error" :errorCode="error.status" />
|
<errors v-if="error" :errorCode="error.status" />
|
||||||
<component v-else-if="currentView" :is="currentView"></component>
|
<component v-else-if="currentView" :is="currentView"></component>
|
||||||
<div v-else-if="currentView !== null">
|
<div v-else>
|
||||||
<h2 class="message delayed">
|
<h2 class="message delayed">
|
||||||
<div class="spinner">
|
<div class="spinner">
|
||||||
<div class="bounce1"></div>
|
<div class="bounce1"></div>
|
||||||
@ -102,15 +102,7 @@ onUnmounted(() => {
|
|||||||
fetchDataController.abort();
|
fetchDataController.abort();
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(route, (to, from) => {
|
watch(route, () => {
|
||||||
if (from.path.endsWith("/")) {
|
|
||||||
window.sessionStorage.setItem(
|
|
||||||
"listFrozen",
|
|
||||||
(!to.path.endsWith("/")).toString()
|
|
||||||
);
|
|
||||||
} else if (to.path.endsWith("/")) {
|
|
||||||
fileStore.updateRequest(null);
|
|
||||||
}
|
|
||||||
fetchData();
|
fetchData();
|
||||||
});
|
});
|
||||||
watch(reload, (newValue) => {
|
watch(reload, (newValue) => {
|
||||||
@ -122,6 +114,32 @@ watch(uploadError, (newValue) => {
|
|||||||
|
|
||||||
// Define functions
|
// Define functions
|
||||||
|
|
||||||
|
const applyPreSelection = () => {
|
||||||
|
const preselect = fileStore.preselect;
|
||||||
|
fileStore.preselect = null;
|
||||||
|
|
||||||
|
if (!fileStore.req?.isDir || fileStore.oldReq === null) return;
|
||||||
|
|
||||||
|
let index = -1;
|
||||||
|
if (preselect) {
|
||||||
|
// Find item with the specified path
|
||||||
|
index = fileStore.req.items.findIndex((item) => item.path === preselect);
|
||||||
|
} else if (fileStore.oldReq.path.startsWith(fileStore.req.path)) {
|
||||||
|
// Get immediate child folder of the previous path
|
||||||
|
const name = fileStore.oldReq.path
|
||||||
|
.substring(fileStore.req.path.length)
|
||||||
|
.split("/")
|
||||||
|
.shift();
|
||||||
|
|
||||||
|
index = fileStore.req.items.findIndex(
|
||||||
|
(val) => val.path == fileStore.req!.path + name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index === -1) return;
|
||||||
|
fileStore.selected.push(index);
|
||||||
|
};
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
// Reset view information.
|
// Reset view information.
|
||||||
fileStore.reload = false;
|
fileStore.reload = false;
|
||||||
@ -130,12 +148,7 @@ const fetchData = async () => {
|
|||||||
layoutStore.closeHovers();
|
layoutStore.closeHovers();
|
||||||
|
|
||||||
// Set loading to true and reset the error.
|
// Set loading to true and reset the error.
|
||||||
if (
|
layoutStore.loading = true;
|
||||||
window.sessionStorage.getItem("listFrozen") !== "true" &&
|
|
||||||
window.sessionStorage.getItem("modified") !== "true"
|
|
||||||
) {
|
|
||||||
layoutStore.loading = true;
|
|
||||||
}
|
|
||||||
error.value = null;
|
error.value = null;
|
||||||
|
|
||||||
let url = route.path;
|
let url = route.path;
|
||||||
@ -149,6 +162,9 @@ const fetchData = async () => {
|
|||||||
fileStore.updateRequest(res);
|
fileStore.updateRequest(res);
|
||||||
document.title = `${res.name || t("sidebar.myFiles")} - ${t("files.files")} - ${name}`;
|
document.title = `${res.name || t("sidebar.myFiles")} - ${t("files.files")} - ${name}`;
|
||||||
layoutStore.loading = false;
|
layoutStore.loading = false;
|
||||||
|
|
||||||
|
// Selects the post-reload target item or the previously visited child folder
|
||||||
|
applyPreSelection();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof StatusError && err.is_canceled) {
|
if (err instanceof StatusError && err.is_canceled) {
|
||||||
return;
|
return;
|
||||||
|
@ -32,17 +32,25 @@
|
|||||||
/>
|
/>
|
||||||
</header-bar>
|
</header-bar>
|
||||||
|
|
||||||
<Breadcrumbs base="/files" noLink />
|
|
||||||
|
|
||||||
<!-- preview container -->
|
<!-- preview container -->
|
||||||
<div
|
<div class="loading delayed" v-if="layoutStore.loading">
|
||||||
v-show="isPreview && isMarkdownFile"
|
<div class="spinner">
|
||||||
id="preview-container"
|
<div class="bounce1"></div>
|
||||||
class="md_preview"
|
<div class="bounce2"></div>
|
||||||
v-html="previewContent"
|
<div class="bounce3"></div>
|
||||||
></div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<template v-else>
|
||||||
|
<Breadcrumbs base="/files" noLink />
|
||||||
|
|
||||||
<form v-show="!isPreview || !isMarkdownFile" id="editor"></form>
|
<div
|
||||||
|
v-show="isPreview && isMarkdownFile"
|
||||||
|
id="preview-container"
|
||||||
|
class="md_preview"
|
||||||
|
v-html="previewContent"
|
||||||
|
></div>
|
||||||
|
<form v-show="!isPreview || !isMarkdownFile" id="editor"></form>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -146,12 +154,19 @@ onBeforeUnmount(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onBeforeRouteUpdate((to, from, next) => {
|
onBeforeRouteUpdate((to, from, next) => {
|
||||||
if (!editor.value?.session.getUndoManager().isClean()) {
|
if (editor.value?.session.getUndoManager().isClean()) {
|
||||||
layoutStore.showHover("discardEditorChanges");
|
|
||||||
next(false);
|
|
||||||
} else {
|
|
||||||
next();
|
next();
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layoutStore.showHover({
|
||||||
|
prompt: "discardEditorChanges",
|
||||||
|
confirm: (event: Event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const keyEvent = (event: KeyboardEvent) => {
|
const keyEvent = (event: KeyboardEvent) => {
|
||||||
@ -216,13 +231,6 @@ const decreaseFontSize = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
if (!editor.value?.session.getUndoManager().isClean()) {
|
|
||||||
layoutStore.showHover("discardEditorChanges");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fileStore.updateRequest(null);
|
|
||||||
|
|
||||||
const uri = url.removeLastDir(route.path) + "/";
|
const uri = url.removeLastDir(route.path) + "/";
|
||||||
router.push({ path: uri });
|
router.push({ path: uri });
|
||||||
};
|
};
|
||||||
|
@ -303,6 +303,7 @@ import {
|
|||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
|
import { removePrefix } from "@/api/utils";
|
||||||
|
|
||||||
const showLimit = ref<number>(50);
|
const showLimit = ref<number>(50);
|
||||||
const columnWidth = ref<number>(280);
|
const columnWidth = ref<number>(280);
|
||||||
@ -420,25 +421,19 @@ const isMobile = computed(() => {
|
|||||||
|
|
||||||
watch(req, () => {
|
watch(req, () => {
|
||||||
// Reset the show value
|
// Reset the show value
|
||||||
if (
|
showLimit.value = 50;
|
||||||
window.sessionStorage.getItem("listFrozen") !== "true" &&
|
|
||||||
window.sessionStorage.getItem("modified") !== "true"
|
|
||||||
) {
|
|
||||||
showLimit.value = 50;
|
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
// Ensures that the listing is displayed
|
// Ensures that the listing is displayed
|
||||||
// How much every listing item affects the window height
|
// How much every listing item affects the window height
|
||||||
setItemWeight();
|
setItemWeight();
|
||||||
|
|
||||||
|
// Scroll to the item opened previously
|
||||||
|
if (!revealPreviousItem()) {
|
||||||
// Fill and fit the window with listing items
|
// Fill and fit the window with listing items
|
||||||
fillWindow(true);
|
fillWindow(true);
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
if (req.value?.isDir) {
|
|
||||||
window.sessionStorage.setItem("listFrozen", "false");
|
|
||||||
window.sessionStorage.setItem("modified", "false");
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -448,8 +443,11 @@ onMounted(() => {
|
|||||||
// How much every listing item affects the window height
|
// How much every listing item affects the window height
|
||||||
setItemWeight();
|
setItemWeight();
|
||||||
|
|
||||||
// Fill and fit the window with listing items
|
// Scroll to the item opened previously
|
||||||
fillWindow(true);
|
if (!revealPreviousItem()) {
|
||||||
|
// Fill and fit the window with listing items
|
||||||
|
fillWindow(true);
|
||||||
|
}
|
||||||
|
|
||||||
// Add the needed event listeners to the window and document.
|
// Add the needed event listeners to the window and document.
|
||||||
window.addEventListener("keydown", keyEvent);
|
window.addEventListener("keydown", keyEvent);
|
||||||
@ -589,10 +587,13 @@ const paste = (event: Event) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const preselect = removePrefix(route.path) + items[0].name;
|
||||||
|
|
||||||
let action = (overwrite: boolean, rename: boolean) => {
|
let action = (overwrite: boolean, rename: boolean) => {
|
||||||
api
|
api
|
||||||
.copy(items, overwrite, rename)
|
.copy(items, overwrite, rename)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
fileStore.preselect = preselect;
|
||||||
fileStore.reload = true;
|
fileStore.reload = true;
|
||||||
})
|
})
|
||||||
.catch($showError);
|
.catch($showError);
|
||||||
@ -604,6 +605,7 @@ const paste = (event: Event) => {
|
|||||||
.move(items, overwrite, rename)
|
.move(items, overwrite, rename)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
clipboardStore.resetClipboard();
|
clipboardStore.resetClipboard();
|
||||||
|
fileStore.preselect = preselect;
|
||||||
fileStore.reload = true;
|
fileStore.reload = true;
|
||||||
})
|
})
|
||||||
.catch($showError);
|
.catch($showError);
|
||||||
@ -731,6 +733,8 @@ const drop = async (event: DragEvent) => {
|
|||||||
|
|
||||||
const conflict = upload.checkConflict(files, items);
|
const conflict = upload.checkConflict(files, items);
|
||||||
|
|
||||||
|
const preselect = removePrefix(path) + (files[0].fullPath || files[0].name);
|
||||||
|
|
||||||
if (conflict) {
|
if (conflict) {
|
||||||
layoutStore.showHover({
|
layoutStore.showHover({
|
||||||
prompt: "replace",
|
prompt: "replace",
|
||||||
@ -738,11 +742,13 @@ const drop = async (event: DragEvent) => {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
layoutStore.closeHovers();
|
layoutStore.closeHovers();
|
||||||
upload.handleFiles(files, path, false);
|
upload.handleFiles(files, path, false);
|
||||||
|
fileStore.preselect = preselect;
|
||||||
},
|
},
|
||||||
confirm: (event: Event) => {
|
confirm: (event: Event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
layoutStore.closeHovers();
|
layoutStore.closeHovers();
|
||||||
upload.handleFiles(files, path, true);
|
upload.handleFiles(files, path, true);
|
||||||
|
fileStore.preselect = preselect;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -750,6 +756,7 @@ const drop = async (event: DragEvent) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
upload.handleFiles(files, path);
|
upload.handleFiles(files, path);
|
||||||
|
fileStore.preselect = preselect;
|
||||||
};
|
};
|
||||||
|
|
||||||
const uploadInput = (event: Event) => {
|
const uploadInput = (event: Event) => {
|
||||||
@ -953,4 +960,21 @@ const fillWindow = (fit = false) => {
|
|||||||
// Set the number of displayed items
|
// Set the number of displayed items
|
||||||
showLimit.value = showQuantity > totalItems ? totalItems : showQuantity;
|
showLimit.value = showQuantity > totalItems ? totalItems : showQuantity;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const revealPreviousItem = () => {
|
||||||
|
if (!fileStore.req || !fileStore.oldReq) return;
|
||||||
|
|
||||||
|
const index = fileStore.selected[0];
|
||||||
|
if (index === undefined) return;
|
||||||
|
|
||||||
|
showLimit.value =
|
||||||
|
index + Math.ceil((window.innerHeight * 2) / itemWeight.value);
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
const items = document.querySelectorAll("#listing .item");
|
||||||
|
items[index].scrollIntoView({ block: "center" });
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -301,10 +301,8 @@ watch(route, () => {
|
|||||||
// Specify hooks
|
// Specify hooks
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
window.addEventListener("keydown", key);
|
window.addEventListener("keydown", key);
|
||||||
if (fileStore.oldReq) {
|
listing.value = fileStore.oldReq?.items ?? null;
|
||||||
listing.value = fileStore.oldReq.items;
|
updatePreview();
|
||||||
updatePreview();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => window.removeEventListener("keydown", key));
|
onBeforeUnmount(() => window.removeEventListener("keydown", key));
|
||||||
@ -317,11 +315,16 @@ const deleteFile = () => {
|
|||||||
if (listing.value === null) {
|
if (listing.value === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
listing.value = listing.value.filter((item) => item.name !== name.value);
|
|
||||||
|
const index = listing.value.findIndex((item) => item.name == name.value);
|
||||||
|
listing.value.splice(index, 1);
|
||||||
|
|
||||||
if (hasNext.value) {
|
if (hasNext.value) {
|
||||||
next();
|
next();
|
||||||
} else if (!hasPrevious.value && !hasNext.value) {
|
} else if (!hasPrevious.value && !hasNext.value) {
|
||||||
|
const nearbyItem = listing.value[Math.max(0, index - 1)];
|
||||||
|
fileStore.preselect = nearbyItem?.path;
|
||||||
|
|
||||||
close();
|
close();
|
||||||
} else {
|
} else {
|
||||||
prev();
|
prev();
|
||||||
@ -427,8 +430,6 @@ const toggleNavigation = throttle(function () {
|
|||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
fileStore.updateRequest(null);
|
|
||||||
|
|
||||||
const uri = url.removeLastDir(route.path) + "/";
|
const uri = url.removeLastDir(route.path) + "/";
|
||||||
router.push({ path: uri });
|
router.push({ path: uri });
|
||||||
};
|
};
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
"exclude": [
|
"exclude": [
|
||||||
"src/components/Shell.vue",
|
"src/components/Shell.vue",
|
||||||
"src/components/prompts/Copy.vue",
|
"src/components/prompts/Copy.vue",
|
||||||
|
"src/components/prompts/Move.vue",
|
||||||
"src/components/prompts/Delete.vue",
|
"src/components/prompts/Delete.vue",
|
||||||
"src/components/prompts/FileList.vue",
|
"src/components/prompts/FileList.vue",
|
||||||
"src/components/prompts/Rename.vue",
|
"src/components/prompts/Rename.vue",
|
||||||
|
2
go.mod
2
go.mod
@ -1,6 +1,6 @@
|
|||||||
module github.com/filebrowser/filebrowser/v2
|
module github.com/filebrowser/filebrowser/v2
|
||||||
|
|
||||||
go 1.23.0
|
go 1.24
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/asdine/storm/v3 v3.2.1
|
github.com/asdine/storm/v3 v3.2.1
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
module github.com/filebrowser/filebrowser/v2/tools
|
module github.com/filebrowser/filebrowser/v2/tools
|
||||||
|
|
||||||
go 1.23.0
|
go 1.24
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golangci/golangci-lint/v2 v2.1.6
|
github.com/golangci/golangci-lint/v2 v2.1.6
|
||||||
|
Loading…
x
Reference in New Issue
Block a user