Merge remote-tracking branch 'kloon15/vue3' into vue3
This commit is contained in:
commit
bf99823977
@ -3,26 +3,20 @@
|
|||||||
"env": {
|
"env": {
|
||||||
"node": true
|
"node": true
|
||||||
},
|
},
|
||||||
"parser": "vue-eslint-parser",
|
|
||||||
"extends": [
|
"extends": [
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:@typescript-eslint/eslint-recommended",
|
|
||||||
"plugin:@typescript-eslint/recommended",
|
|
||||||
"plugin:vue/vue3-essential",
|
"plugin:vue/vue3-essential",
|
||||||
|
"eslint:recommended",
|
||||||
|
"@vue/eslint-config-typescript",
|
||||||
"@vue/eslint-config-prettier"
|
"@vue/eslint-config-prettier"
|
||||||
|
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"vue/multi-word-component-names": "off",
|
"vue/multi-word-component-names": "off",
|
||||||
"vue/no-reserved-component-names": "warn",
|
"vue/no-reserved-component-names": "warn",
|
||||||
"vue/no-mutating-props": "warn",
|
"vue/no-mutating-props": "warn",
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
"no-undef": "error"
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
|
||||||
"no-undef": "off"
|
|
||||||
},
|
},
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": "latest",
|
"ecmaVersion": "latest",
|
||||||
"sourceType": "module",
|
"sourceType": "module"
|
||||||
"parser": "@typescript-eslint/parser"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1434
frontend/package-lock.json
generated
1434
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -14,17 +14,17 @@
|
|||||||
"format": "prettier --write ."
|
"format": "prettier --write ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@vue/eslint-config-typescript": "^11.0.3",
|
||||||
"@vueuse/core": "^10.4.1",
|
"@vueuse/core": "^10.4.1",
|
||||||
"ace-builds": "^1.24.1",
|
"ace-builds": "^1.24.2",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"core-js": "^3.32.1",
|
"core-js": "^3.32.2",
|
||||||
"dayjs": "^1.11.9",
|
"dayjs": "^1.11.9",
|
||||||
"filesize": "^10.0.12",
|
"filesize": "^10.0.12",
|
||||||
"js-base64": "^3.7.5",
|
"js-base64": "^3.7.5",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^3.1.2",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"material-icons": "^1.13.10",
|
"material-icons": "^1.13.11",
|
||||||
"moment": "^2.29.4",
|
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"pinia": "^2.1.6",
|
"pinia": "^2.1.6",
|
||||||
"pretty-bytes": "^6.1.1",
|
"pretty-bytes": "^6.1.1",
|
||||||
@ -32,26 +32,32 @@
|
|||||||
"tus-js-client": "^3.1.1",
|
"tus-js-client": "^3.1.1",
|
||||||
"utif": "^3.1.0",
|
"utif": "^3.1.0",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-i18n": "^9.2.2",
|
"vue-i18n": "^9.3.0",
|
||||||
"vue-lazyload": "^3.0.0",
|
"vue-lazyload": "^3.0.0",
|
||||||
"vue-router": "^4.2.4",
|
"vue-router": "^4.2.4",
|
||||||
"vue-toastification": "^2.0.0-rc.5"
|
"vue-toastification": "^2.0.0-rc.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
<<<<<<< HEAD
|
||||||
"@intlify/unplugin-vue-i18n": "^0.12.3",
|
"@intlify/unplugin-vue-i18n": "^0.12.3",
|
||||||
"@types/lodash-es": "^4.17.9",
|
"@types/lodash-es": "^4.17.9",
|
||||||
|
=======
|
||||||
|
"@intlify/unplugin-vue-i18n": "^1.0.1",
|
||||||
|
"@types/lodash-es": "^4.17.9",
|
||||||
|
"@types/node": "^20.6.0",
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
"@typescript-eslint/eslint-plugin": "^6.6.0",
|
"@typescript-eslint/eslint-plugin": "^6.6.0",
|
||||||
"@vitejs/plugin-legacy": "^4.1.1",
|
"@vitejs/plugin-legacy": "^4.1.1",
|
||||||
"@vitejs/plugin-vue": "^4.3.3",
|
"@vitejs/plugin-vue": "^4.3.4",
|
||||||
"@vue/eslint-config-prettier": "^8.0.0",
|
"@vue/eslint-config-prettier": "^8.0.0",
|
||||||
"autoprefixer": "^10.4.15",
|
"autoprefixer": "^10.4.15",
|
||||||
"eslint": "^8.48.0",
|
"eslint": "^8.49.0",
|
||||||
"eslint-plugin-prettier": "^5.0.0",
|
"eslint-plugin-prettier": "^5.0.0",
|
||||||
"eslint-plugin-vue": "^9.17.0",
|
"eslint-plugin-vue": "^9.17.0",
|
||||||
"jsdom": "^22.1.0",
|
"jsdom": "^22.1.0",
|
||||||
"postcss": "^8.4.28",
|
"postcss": "^8.4.29",
|
||||||
"prettier": "^3.0.2",
|
"prettier": "^3.0.3",
|
||||||
"terser": "^5.19.2",
|
"terser": "^5.19.4",
|
||||||
"vite": "^4.4.9",
|
"vite": "^4.4.9",
|
||||||
"vite-plugin-compression2": "^0.10.4",
|
"vite-plugin-compression2": "^0.10.4",
|
||||||
"vite-plugin-rewrite-all": "^1.0.1"
|
"vite-plugin-rewrite-all": "^1.0.1"
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
:root {
|
:root {
|
||||||
--background: #141D24;
|
--background: #141d24;
|
||||||
--surfacePrimary: #20292F;
|
--surfacePrimary: #20292f;
|
||||||
--surfaceSecondary: #3A4147;
|
--surfaceSecondary: #3a4147;
|
||||||
--divider: rgba(255, 255, 255, 0.12);
|
--divider: rgba(255, 255, 255, 0.12);
|
||||||
--icon: #ffffff;
|
--icon: #ffffff;
|
||||||
--textPrimary: rgba(255, 255, 255, 0.87);
|
--textPrimary: rgba(255, 255, 255, 0.87);
|
||||||
@ -16,7 +16,8 @@ body {
|
|||||||
#loading {
|
#loading {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
}
|
}
|
||||||
#loading .spinner div, main .spinner div {
|
#loading .spinner div,
|
||||||
|
main .spinner div {
|
||||||
background: var(--icon);
|
background: var(--icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +57,7 @@ header {
|
|||||||
color: var(--textPrimary) !important;
|
color: var(--textPrimary) !important;
|
||||||
}
|
}
|
||||||
.action:hover {
|
.action:hover {
|
||||||
background-color: rgba(255, 255, 255, .1);
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
}
|
}
|
||||||
.action i {
|
.action i {
|
||||||
color: var(--icon) !important;
|
color: var(--icon) !important;
|
||||||
@ -77,7 +78,7 @@ nav > div {
|
|||||||
color: var(--textPrimary) !important;
|
color: var(--textPrimary) !important;
|
||||||
}
|
}
|
||||||
.breadcrumbs a:hover {
|
.breadcrumbs a:hover {
|
||||||
background-color: rgba(255, 255, 255, .1);
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#listing .item {
|
#listing .item {
|
||||||
@ -141,11 +142,11 @@ nav > div {
|
|||||||
border-color: rgba(255, 255, 255, 0.15);
|
border-color: rgba(255, 255, 255, 0.15);
|
||||||
}
|
}
|
||||||
.input--red {
|
.input--red {
|
||||||
background: #73302D;
|
background: #73302d;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input--green {
|
.input--green {
|
||||||
background: #147A41;
|
background: #147a41;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard #nav .wrapper,
|
.dashboard #nav .wrapper,
|
||||||
@ -166,7 +167,7 @@ table th {
|
|||||||
.file-list li:before {
|
.file-list li:before {
|
||||||
color: var(--textSecondary);
|
color: var(--textSecondary);
|
||||||
}
|
}
|
||||||
.file-list li[aria-selected=true]:before {
|
.file-list li[aria-selected="true"]:before {
|
||||||
color: var(--icon);
|
color: var(--icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,15 @@ import { createURL, fetchURL, removePrefix } from "./utils";
|
|||||||
import { baseURL } from "@/utils/constants";
|
import { baseURL } from "@/utils/constants";
|
||||||
import { useAuthStore } from "@/stores/auth";
|
import { useAuthStore } from "@/stores/auth";
|
||||||
import { upload as postTus, useTus } from "./tus";
|
import { upload as postTus, useTus } from "./tus";
|
||||||
|
import type {
|
||||||
|
ApiContent,
|
||||||
|
ApiMethod,
|
||||||
|
ApiOpts,
|
||||||
|
ChecksumAlgs,
|
||||||
|
IFile,
|
||||||
|
} from "@/types";
|
||||||
|
|
||||||
export async function fetch(url: ApiUrl) {
|
export async function fetch(url: string) {
|
||||||
url = removePrefix(url);
|
url = removePrefix(url);
|
||||||
|
|
||||||
const res = await fetchURL(`/api/resources${url}`, {});
|
const res = await fetchURL(`/api/resources${url}`, {});
|
||||||
@ -29,7 +36,7 @@ export async function fetch(url: ApiUrl) {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resourceAction(url: ApiUrl, method: ApiMethod, content?: any) {
|
async function resourceAction(url: string, method: ApiMethod, content?: any) {
|
||||||
url = removePrefix(url);
|
url = removePrefix(url);
|
||||||
|
|
||||||
const opts: ApiOpts = {
|
const opts: ApiOpts = {
|
||||||
@ -45,11 +52,11 @@ async function resourceAction(url: ApiUrl, method: ApiMethod, content?: any) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function remove(url: ApiUrl) {
|
export async function remove(url: string) {
|
||||||
return resourceAction(url, "DELETE");
|
return resourceAction(url, "DELETE");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function put(url: ApiUrl, content = "") {
|
export async function put(url: string, content = "") {
|
||||||
return resourceAction(url, "PUT", content);
|
return resourceAction(url, "PUT", content);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +90,7 @@ export function download(format: any, ...files: string[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function post(
|
export async function post(
|
||||||
url: ApiUrl,
|
url: string,
|
||||||
content: ApiContent = "",
|
content: ApiContent = "",
|
||||||
overwrite = false,
|
overwrite = false,
|
||||||
onupload: any = () => {}
|
onupload: any = () => {}
|
||||||
@ -103,7 +110,7 @@ export async function post(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function postResources(
|
async function postResources(
|
||||||
url: ApiUrl,
|
url: string,
|
||||||
content: ApiContent = "",
|
content: ApiContent = "",
|
||||||
overwrite = false,
|
overwrite = false,
|
||||||
onupload: any
|
onupload: any
|
||||||
@ -178,7 +185,7 @@ export function copy(items: any[], overwrite = false, rename = false) {
|
|||||||
return moveCopy(items, true, overwrite, rename);
|
return moveCopy(items, true, overwrite, rename);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checksum(url: ApiUrl, algo: algo) {
|
export async function checksum(url: string, algo: ChecksumAlgs) {
|
||||||
const data = await resourceAction(`${url}?checksum=${algo}`, "GET");
|
const data = await resourceAction(`${url}?checksum=${algo}`, "GET");
|
||||||
return (await data.json()).checksums[algo];
|
return (await data.json()).checksums[algo];
|
||||||
}
|
}
|
||||||
@ -213,7 +220,7 @@ export function getSubtitlesURL(file: IFile) {
|
|||||||
return subtitles;
|
return subtitles;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function usage(url: ApiUrl) {
|
export async function usage(url: string) {
|
||||||
url = removePrefix(url);
|
url = removePrefix(url);
|
||||||
|
|
||||||
const res = await fetchURL(`/api/usage${url}`, {});
|
const res = await fetchURL(`/api/usage${url}`, {});
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
|
import type { IShare } from "@/types";
|
||||||
import { fetchURL, removePrefix, createURL } from "./utils";
|
import { fetchURL, removePrefix, createURL } from "./utils";
|
||||||
import { baseURL } from "@/utils/constants";
|
import { baseURL } from "@/utils/constants";
|
||||||
|
|
||||||
export async function fetch(url: ApiUrl, password: string = "") {
|
export async function fetch(url: string, password: string = "") {
|
||||||
url = removePrefix(url);
|
url = removePrefix(url);
|
||||||
|
|
||||||
const res = await fetchURL(
|
const res = await fetchURL(
|
||||||
@ -66,7 +67,7 @@ export function download(
|
|||||||
window.open(url);
|
window.open(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDownloadURL(share: IFile, inline = false) {
|
export function getDownloadURL(share: IShare, inline = false) {
|
||||||
const params = {
|
const params = {
|
||||||
...(inline && { inline: "true" }),
|
...(inline && { inline: "true" }),
|
||||||
...(share.token && { token: share.token }),
|
...(share.token && { token: share.token }),
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { fetchURL, removePrefix } from "./utils";
|
import { fetchURL, removePrefix } from "./utils";
|
||||||
import url from "../utils/url";
|
import url from "../utils/url";
|
||||||
|
import type { Item } from "@/types";
|
||||||
|
|
||||||
export default async function search(base: apiUrl, query: string) {
|
export default async function search(base: string, query: string) {
|
||||||
base = removePrefix(base);
|
base = removePrefix(base);
|
||||||
query = encodeURIComponent(query);
|
query = encodeURIComponent(query);
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ export default async function search(base: apiUrl, query: string) {
|
|||||||
|
|
||||||
let data = await res.json();
|
let data = await res.json();
|
||||||
|
|
||||||
data = data.map((item: item) => {
|
data = data.map((item: Item) => {
|
||||||
item.url = `/files${base}` + url.encodePath(item.path);
|
item.url = `/files${base}` + url.encodePath(item.path);
|
||||||
|
|
||||||
if (item.dir) {
|
if (item.dir) {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import type { ISettings } from "@/types";
|
||||||
import { fetchURL, fetchJSON } from "./utils";
|
import { fetchURL, fetchJSON } from "./utils";
|
||||||
|
|
||||||
export function get() {
|
export function get() {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import type { ApiUrl, IShare } from "@/types";
|
||||||
import { fetchURL, fetchJSON, removePrefix, createURL } from "./utils";
|
import { fetchURL, fetchJSON, removePrefix, createURL } from "./utils";
|
||||||
|
|
||||||
export async function list() {
|
export async function list() {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { baseURL, tusEndpoint, tusSettings } from "@/utils/constants";
|
|||||||
import { useAuthStore } from "@/stores/auth";
|
import { useAuthStore } from "@/stores/auth";
|
||||||
import { removePrefix } from "@/api/utils";
|
import { removePrefix } from "@/api/utils";
|
||||||
import { fetchURL } from "./utils";
|
import { fetchURL } from "./utils";
|
||||||
|
import type { ApiContent, TusSettings } from "@/types";
|
||||||
|
|
||||||
const RETRY_BASE_DELAY = 1000;
|
const RETRY_BASE_DELAY = 1000;
|
||||||
const RETRY_MAX_DELAY = 20000;
|
const RETRY_MAX_DELAY = 20000;
|
||||||
@ -57,7 +58,7 @@ export async function upload(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createUpload(resourcePath: resourcePath) {
|
async function createUpload(resourcePath: string) {
|
||||||
const headResp = await fetchURL(resourcePath, {
|
const headResp = await fetchURL(resourcePath, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
});
|
});
|
||||||
@ -68,7 +69,7 @@ async function createUpload(resourcePath: resourcePath) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeRetryDelays(tusSettings: tusSettings): number[] | undefined {
|
function computeRetryDelays(tusSettings: TusSettings): number[] | undefined {
|
||||||
if (!tusSettings.retryCount || tusSettings.retryCount < 1) {
|
if (!tusSettings.retryCount || tusSettings.retryCount < 1) {
|
||||||
// Disable retries altogether
|
// Disable retries altogether
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import type { User } from "@/types/user";
|
||||||
import { fetchURL, fetchJSON } from "./utils";
|
import { fetchURL, fetchJSON } from "./utils";
|
||||||
|
|
||||||
export async function getAll() {
|
export async function getAll() {
|
||||||
@ -8,7 +9,7 @@ export async function get(id: number) {
|
|||||||
return fetchJSON(`/api/users/${id}`, {});
|
return fetchJSON(`/api/users/${id}`, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function create(user: user) {
|
export async function create(user: User) {
|
||||||
const res = await fetchURL(`/api/users`, {
|
const res = await fetchURL(`/api/users`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@ -23,7 +24,7 @@ export async function create(user: user) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function update(user: user, which = ["all"]) {
|
export async function update(user: User, which = ["all"]) {
|
||||||
await fetchURL(`/api/users/${user.id}`, {
|
await fetchURL(`/api/users/${user.id}`, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
|||||||
@ -1,9 +1,20 @@
|
|||||||
import { useAuthStore } from "@/stores/auth";
|
import { useAuthStore } from "@/stores/auth";
|
||||||
|
import type { ApiOpts, SearchParams } from "@/types";
|
||||||
import { renew, logout } from "@/utils/auth";
|
import { renew, logout } from "@/utils/auth";
|
||||||
import { baseURL } from "@/utils/constants";
|
import { baseURL } from "@/utils/constants";
|
||||||
import { encodePath } from "@/utils/url";
|
import { encodePath } from "@/utils/url";
|
||||||
|
|
||||||
export async function fetchURL(url: ApiUrl, opts: ApiOpts, auth = true) {
|
export class StatusError extends Error {
|
||||||
|
constructor(
|
||||||
|
message: any,
|
||||||
|
public status?: number
|
||||||
|
) {
|
||||||
|
super(message);
|
||||||
|
this.name = "StatusError";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchURL(url: string, opts: ApiOpts, auth = true) {
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
@ -20,11 +31,7 @@ export async function fetchURL(url: ApiUrl, opts: ApiOpts, auth = true) {
|
|||||||
...rest,
|
...rest,
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
const error = new Error("000 No connection");
|
throw new StatusError("000 No connection", 0);
|
||||||
// @ts-ignore don't know yet how to solve
|
|
||||||
error.status = 0;
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auth && res.headers.get("X-Renew-Token") === "true") {
|
if (auth && res.headers.get("X-Renew-Token") === "true") {
|
||||||
@ -32,9 +39,7 @@ export async function fetchURL(url: ApiUrl, opts: ApiOpts, auth = true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (res.status < 200 || res.status > 299) {
|
if (res.status < 200 || res.status > 299) {
|
||||||
const error = new Error(await res.text());
|
const error = new StatusError(await res.text(), res.status);
|
||||||
// @ts-ignore don't know yet how to solve
|
|
||||||
error.status = res.status;
|
|
||||||
|
|
||||||
if (auth && res.status == 401) {
|
if (auth && res.status == 401) {
|
||||||
logout();
|
logout();
|
||||||
@ -46,7 +51,7 @@ export async function fetchURL(url: ApiUrl, opts: ApiOpts, auth = true) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchJSON(url: ApiUrl, opts?: any) {
|
export async function fetchJSON(url: string, opts?: any) {
|
||||||
const res = await fetchURL(url, opts);
|
const res = await fetchURL(url, opts);
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
@ -56,7 +61,7 @@ export async function fetchJSON(url: ApiUrl, opts?: any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removePrefix(url: ApiUrl) {
|
export function removePrefix(url: string) {
|
||||||
url = url.split("/").splice(2).join("/");
|
url = url.split("/").splice(2).join("/");
|
||||||
|
|
||||||
if (url === "") url = "/";
|
if (url === "") url = "/";
|
||||||
@ -64,7 +69,7 @@ export function removePrefix(url: ApiUrl) {
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createURL(endpoint: ApiUrl, params = {}, auth = true) {
|
export function createURL(endpoint: string, params = {}, auth = true) {
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
let prefix = baseURL;
|
let prefix = baseURL;
|
||||||
@ -73,7 +78,7 @@ export function createURL(endpoint: ApiUrl, params = {}, auth = true) {
|
|||||||
}
|
}
|
||||||
const url = new URL(prefix + encodePath(endpoint), origin);
|
const url = new URL(prefix + encodePath(endpoint), origin);
|
||||||
|
|
||||||
const searchParams: searchParams = {
|
const searchParams: SearchParams = {
|
||||||
...(auth && { auth: authStore.jwt }),
|
...(auth && { auth: authStore.jwt }),
|
||||||
...params,
|
...params,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -74,6 +74,10 @@ import Commands from "./Commands.vue";
|
|||||||
import { enableExec } from "@/utils/constants";
|
import { enableExec } from "@/utils/constants";
|
||||||
import { computed, onMounted, ref, watch } from "vue";
|
import { computed, onMounted, ref, watch } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
import { IUser } from "@/types";
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
@ -82,9 +86,15 @@ const originalUserScope = ref<string | null>(null);
|
|||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
user: IUser;
|
user: IUser;
|
||||||
|
<<<<<<< HEAD
|
||||||
createUserDir: boolean;
|
createUserDir: boolean;
|
||||||
isNew: boolean;
|
isNew: boolean;
|
||||||
isDefault: boolean;
|
isDefault: boolean;
|
||||||
|
=======
|
||||||
|
isNew: boolean;
|
||||||
|
isDefault: boolean;
|
||||||
|
createUserDir?: boolean;
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
@ -24,29 +24,9 @@ import("dayjs/locale/uk");
|
|||||||
import("dayjs/locale/zh-cn");
|
import("dayjs/locale/zh-cn");
|
||||||
import("dayjs/locale/zh-tw");
|
import("dayjs/locale/zh-tw");
|
||||||
|
|
||||||
import he from "./he.json";
|
// All i18n resources specified in the plugin `include` option can be loaded
|
||||||
import hu from "./hu.json";
|
// at once using the import syntax
|
||||||
import ar from "./ar.json";
|
import messages from "@intlify/unplugin-vue-i18n/messages";
|
||||||
import de from "./de.json";
|
|
||||||
import en from "./en.json";
|
|
||||||
import es from "./es.json";
|
|
||||||
import fr from "./fr.json";
|
|
||||||
import is from "./is.json";
|
|
||||||
import it from "./it.json";
|
|
||||||
import ja from "./ja.json";
|
|
||||||
import ko from "./ko.json";
|
|
||||||
import nlBE from "./nl-be.json";
|
|
||||||
import pl from "./pl.json";
|
|
||||||
import pt from "./pt.json";
|
|
||||||
import ptBR from "./pt-br.json";
|
|
||||||
import ro from "./ro.json";
|
|
||||||
import ru from "./ru.json";
|
|
||||||
import sk from "./sk.json";
|
|
||||||
import tr from "./tr.json";
|
|
||||||
import uk from "./uk.json";
|
|
||||||
import svSE from "./sv-se.json";
|
|
||||||
import zhCN from "./zh-cn.json";
|
|
||||||
import zhTW from "./zh-tw.json";
|
|
||||||
|
|
||||||
export function detectLocale() {
|
export function detectLocale() {
|
||||||
// locale is an RFC 5646 language tag
|
// locale is an RFC 5646 language tag
|
||||||
@ -132,7 +112,8 @@ export function detectLocale() {
|
|||||||
return locale;
|
return locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeEmpty = (obj) =>
|
// TODO: was this really necessary?
|
||||||
|
function removeEmpty(obj: Record<string, any>): void {
|
||||||
Object.keys(obj)
|
Object.keys(obj)
|
||||||
.filter((k) => obj[k] !== null && obj[k] !== undefined && obj[k] !== "") // Remove undef. and null and empty.string.
|
.filter((k) => obj[k] !== null && obj[k] !== undefined && obj[k] !== "") // Remove undef. and null and empty.string.
|
||||||
.reduce(
|
.reduce(
|
||||||
@ -142,37 +123,14 @@ const removeEmpty = (obj) =>
|
|||||||
: Object.assign(newObj, { [k]: obj[k] }), // Copy value.
|
: Object.assign(newObj, { [k]: obj[k] }), // Copy value.
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export const rtlLanguages = ["he", "ar"];
|
export const rtlLanguages = ["he", "ar"];
|
||||||
|
|
||||||
export const i18n = createI18n({
|
export const i18n = createI18n({
|
||||||
locale: detectLocale(),
|
locale: detectLocale(),
|
||||||
fallbackLocale: "en",
|
fallbackLocale: "en",
|
||||||
messages: {
|
messages,
|
||||||
he: removeEmpty(he),
|
|
||||||
hu: removeEmpty(hu),
|
|
||||||
ar: removeEmpty(ar),
|
|
||||||
de: removeEmpty(de),
|
|
||||||
en: en,
|
|
||||||
es: removeEmpty(es),
|
|
||||||
fr: removeEmpty(fr),
|
|
||||||
is: removeEmpty(is),
|
|
||||||
it: removeEmpty(it),
|
|
||||||
ja: removeEmpty(ja),
|
|
||||||
ko: removeEmpty(ko),
|
|
||||||
"nl-be": removeEmpty(nlBE),
|
|
||||||
pl: removeEmpty(pl),
|
|
||||||
"pt-br": removeEmpty(ptBR),
|
|
||||||
pt: removeEmpty(pt),
|
|
||||||
ru: removeEmpty(ru),
|
|
||||||
ro: removeEmpty(ro),
|
|
||||||
sk: removeEmpty(sk),
|
|
||||||
sv: removeEmpty(svSE),
|
|
||||||
tr: removeEmpty(tr),
|
|
||||||
uk: removeEmpty(uk),
|
|
||||||
"zh-cn": removeEmpty(zhCN),
|
|
||||||
"zh-tw": removeEmpty(zhTW),
|
|
||||||
},
|
|
||||||
// expose i18n.global for outside components
|
// expose i18n.global for outside components
|
||||||
legacy: true,
|
legacy: true,
|
||||||
});
|
});
|
||||||
@ -1,4 +1,3 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import { disableExternal } from "@/utils/constants";
|
import { disableExternal } from "@/utils/constants";
|
||||||
import { createApp } from "vue";
|
import { createApp } from "vue";
|
||||||
import VueLazyload from "vue-lazyload";
|
import VueLazyload from "vue-lazyload";
|
||||||
@ -64,7 +63,7 @@ const toastConfig = {
|
|||||||
icon: true,
|
icon: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
app.provide("$showSuccess", (message) => {
|
app.provide("$showSuccess", (message: string) => {
|
||||||
const $toast = useToast();
|
const $toast = useToast();
|
||||||
$toast.success(
|
$toast.success(
|
||||||
{
|
{
|
||||||
@ -73,22 +72,27 @@ app.provide("$showSuccess", (message) => {
|
|||||||
message: message,
|
message: message,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// their type defs are messed up
|
||||||
|
//@ts-ignore
|
||||||
{ ...toastConfig, rtl: rtlLanguages.includes(i18n.global.locale) }
|
{ ...toastConfig, rtl: rtlLanguages.includes(i18n.global.locale) }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.provide("$showError", (error, displayReport = true) => {
|
app.provide("$showError", (error: Error | string, displayReport = true) => {
|
||||||
const $toast = useToast();
|
const $toast = useToast();
|
||||||
$toast.error(
|
$toast.error(
|
||||||
{
|
{
|
||||||
component: CustomToast,
|
component: CustomToast,
|
||||||
props: {
|
props: {
|
||||||
message: error.message || error,
|
message: (error as Error).message || error,
|
||||||
isReport: !disableExternal && displayReport,
|
isReport: !disableExternal && displayReport,
|
||||||
// TODO: i couldnt use $t inside the component
|
// TODO: i couldnt use $t inside the component
|
||||||
|
//@ts-ignore
|
||||||
reportText: i18n.global.t("buttons.reportIssue"),
|
reportText: i18n.global.t("buttons.reportIssue"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// their type defs are messed up
|
||||||
|
//@ts-ignore
|
||||||
{
|
{
|
||||||
...toastConfig,
|
...toastConfig,
|
||||||
timeout: 0,
|
timeout: 0,
|
||||||
|
|||||||
@ -176,12 +176,10 @@ const router = createRouter({
|
|||||||
routes,
|
routes,
|
||||||
});
|
});
|
||||||
|
|
||||||
router.beforeResolve(async (to: RouteLocation, from, next) => {
|
router.beforeResolve(async (to, from, next) => {
|
||||||
let title;
|
let title;
|
||||||
try {
|
try {
|
||||||
// this should not fail after we finished the migration
|
title = i18n.global.t(titles[to.name as keyof typeof titles]);
|
||||||
// @ts-ignore
|
|
||||||
title = i18n.global.t(titles[to.name]);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// @ts-nocheck
|
import type { IUser } from "@/types";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import i18n, { detectLocale } from "@/i18n";
|
import i18n, { detectLocale } from "@/i18n";
|
||||||
@ -19,33 +19,29 @@ export const useAuthStore = defineStore("auth", {
|
|||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
// no context as first argument, use `this` instead
|
// no context as first argument, use `this` instead
|
||||||
setUser(value: user) {
|
setUser(user: IUser | null) {
|
||||||
if (value === null) {
|
if (user === null) {
|
||||||
this.user = null;
|
this.user = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const locale = value.locale || detectLocale();
|
const locale = user.locale || detectLocale();
|
||||||
dayjs.locale(locale);
|
dayjs.locale(locale);
|
||||||
// @ts-ignore Don't know how to fix this yet
|
// according to doc u only need .value if legacy: false but they lied
|
||||||
|
// https://vue-i18n.intlify.dev/guide/essentials/scope.html#local-scope-1
|
||||||
|
//@ts-ignore
|
||||||
i18n.global.locale.value = locale;
|
i18n.global.locale.value = locale;
|
||||||
this.user = value;
|
this.user = user;
|
||||||
},
|
},
|
||||||
updateUser(value: user) {
|
updateUser(user: Partial<IUser>) {
|
||||||
if (typeof value !== "object") return;
|
if (user.locale) {
|
||||||
|
dayjs.locale(user.locale);
|
||||||
let field: userKey;
|
// see above
|
||||||
for (field in value) {
|
//@ts-ignore
|
||||||
if (field === "locale") {
|
i18n.global.locale.value = user.locale;
|
||||||
const locale = value[field];
|
|
||||||
dayjs.locale(locale);
|
|
||||||
// @ts-ignore Don't know how to fix this yet
|
|
||||||
i18n.global.locale.value = locale;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-ignore to fix
|
|
||||||
this.user[field] = cloneDeep(value[field]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.user = { ...this.user, ...cloneDeep(user) } as IUser;
|
||||||
},
|
},
|
||||||
// easily reset state using `$reset`
|
// easily reset state using `$reset`
|
||||||
clearUser() {
|
clearUser() {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import type { IFile } from "@/types";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
export const useFileStore = defineStore("file", {
|
export const useFileStore = defineStore("file", {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import type { LayoutValue } from "@/types";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
// import { useAuthPreferencesStore } from "./auth-preferences";
|
// import { useAuthPreferencesStore } from "./auth-preferences";
|
||||||
// import { useAuthEmailStore } from "./auth-email";
|
// import { useAuthEmailStore } from "./auth-email";
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { useFileStore } from "./file";
|
import { useFileStore } from "./file";
|
||||||
import { files as api } from "@/api";
|
import { files as api } from "@/api";
|
||||||
import throttle from "lodash/throttle";
|
import throttle from "lodash/throttle";
|
||||||
import buttons from "@/utils/buttons";
|
import buttons from "@/utils/buttons";
|
||||||
|
import type { Item, Uploads } from "@/types";
|
||||||
|
|
||||||
|
// TODO: make this into a user setting
|
||||||
const UPLOADS_LIMIT = 5;
|
const UPLOADS_LIMIT = 5;
|
||||||
|
|
||||||
const beforeUnload = (event: Event) => {
|
const beforeUnload = (event: Event) => {
|
||||||
@ -20,8 +21,8 @@ export const useUploadStore = defineStore("upload", {
|
|||||||
sizes: any[];
|
sizes: any[];
|
||||||
progress: any[];
|
progress: any[];
|
||||||
queue: any[];
|
queue: any[];
|
||||||
uploads: uploads;
|
uploads: Uploads;
|
||||||
error: any;
|
error: Error | null;
|
||||||
} => ({
|
} => ({
|
||||||
id: 0,
|
id: 0,
|
||||||
sizes: [],
|
sizes: [],
|
||||||
@ -39,7 +40,6 @@ export const useUploadStore = defineStore("upload", {
|
|||||||
|
|
||||||
const totalSize = state.sizes.reduce((a, b) => a + b, 0);
|
const totalSize = state.sizes.reduce((a, b) => a + b, 0);
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
const sum: number = state.progress.reduce((acc, val) => acc + val);
|
const sum: number = state.progress.reduce((acc, val) => acc + val);
|
||||||
return Math.ceil((sum / totalSize) * 100);
|
return Math.ceil((sum / totalSize) * 100);
|
||||||
},
|
},
|
||||||
@ -80,7 +80,7 @@ export const useUploadStore = defineStore("upload", {
|
|||||||
const { id, loaded } = obj;
|
const { id, loaded } = obj;
|
||||||
this.progress[id] = loaded;
|
this.progress[id] = loaded;
|
||||||
},
|
},
|
||||||
setError(error) {
|
setError(error: Error) {
|
||||||
this.error = error;
|
this.error = error;
|
||||||
},
|
},
|
||||||
reset() {
|
reset() {
|
||||||
@ -88,7 +88,7 @@ export const useUploadStore = defineStore("upload", {
|
|||||||
this.sizes = [];
|
this.sizes = [];
|
||||||
this.progress = [];
|
this.progress = [];
|
||||||
},
|
},
|
||||||
addJob(item: item) {
|
addJob(item: Item) {
|
||||||
this.queue.push(item);
|
this.queue.push(item);
|
||||||
this.sizes[this.id] = item.file.size;
|
this.sizes[this.id] = item.file.size;
|
||||||
this.id++;
|
this.id++;
|
||||||
@ -103,7 +103,7 @@ export const useUploadStore = defineStore("upload", {
|
|||||||
// Vue.delete(this.uploads, id);
|
// Vue.delete(this.uploads, id);
|
||||||
delete this.uploads[id];
|
delete this.uploads[id];
|
||||||
},
|
},
|
||||||
upload(item: item) {
|
upload(item: Item) {
|
||||||
const uploadsCount = Object.keys(this.uploads).length;
|
const uploadsCount = Object.keys(this.uploads).length;
|
||||||
|
|
||||||
const isQueueEmpty = this.queue.length == 0;
|
const isQueueEmpty = this.queue.length == 0;
|
||||||
@ -117,7 +117,7 @@ export const useUploadStore = defineStore("upload", {
|
|||||||
this.addJob(item);
|
this.addJob(item);
|
||||||
this.processUploads();
|
this.processUploads();
|
||||||
},
|
},
|
||||||
finishUpload(item: item) {
|
finishUpload(item: Item) {
|
||||||
this.setProgress({ id: item.id, loaded: item.file.size > 0 });
|
this.setProgress({ id: item.id, loaded: item.file.size > 0 });
|
||||||
this.removeJob(item.id);
|
this.removeJob(item.id);
|
||||||
this.processUploads();
|
this.processUploads();
|
||||||
|
|||||||
27
frontend/src/types/api.d.ts
vendored
27
frontend/src/types/api.d.ts
vendored
@ -1,40 +1,45 @@
|
|||||||
type ApiUrl = string; // Can also be set as a path eg: "path1" | "path2"
|
export type ApiUrl = string; // Can also be set as a path eg: "path1" | "path2"
|
||||||
|
|
||||||
type resourcePath = string;
|
export type ApiMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
||||||
|
|
||||||
type ApiMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
export type ApiContent =
|
||||||
|
|
||||||
type ApiContent =
|
|
||||||
| Blob
|
| Blob
|
||||||
| File
|
| File
|
||||||
| Pick<ReadableStreamDefaultReader<any>, "read">
|
| Pick<ReadableStreamDefaultReader<any>, "read">
|
||||||
| "";
|
| "";
|
||||||
|
|
||||||
interface ApiOpts {
|
export interface ApiOpts {
|
||||||
method?: ApiMethod;
|
method?: ApiMethod;
|
||||||
headers?: object;
|
headers?: object;
|
||||||
body?: any;
|
body?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface tusSettings {
|
export interface TusSettings {
|
||||||
retryCount: number;
|
retryCount: number;
|
||||||
chunkSize: number;
|
chunkSize: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type algo = any;
|
export type ChecksumAlgs = "md5" | "sha1" | "sha256" | "sha512";
|
||||||
|
|
||||||
type inline = any;
|
type inline = any;
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
interface IShare {
|
interface IShare {
|
||||||
expire: any;
|
expire: any;
|
||||||
|
=======
|
||||||
|
export interface IShare {
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
hash: string;
|
hash: string;
|
||||||
path: string;
|
path: string;
|
||||||
userID: number;
|
expire?: any;
|
||||||
token: string;
|
userID?: number;
|
||||||
|
token?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface settings {
|
interface settings {
|
||||||
any;
|
any;
|
||||||
}
|
}
|
||||||
|
|
||||||
type searchParams = any;
|
export interface SearchParams {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|||||||
24
frontend/src/types/file.d.ts
vendored
24
frontend/src/types/file.d.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
interface IFile {
|
export interface IFile {
|
||||||
index?: number;
|
index?: number;
|
||||||
name: string;
|
name: string;
|
||||||
modified: string;
|
modified: string;
|
||||||
@ -7,14 +7,14 @@ interface IFile {
|
|||||||
isDir: boolean;
|
isDir: boolean;
|
||||||
size: number;
|
size: number;
|
||||||
fullPath: string;
|
fullPath: string;
|
||||||
type: uploadType;
|
type: FileType;
|
||||||
items: IFile[];
|
items: IFile[];
|
||||||
token?: string;
|
token?: string;
|
||||||
hash: string;
|
hash: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type uploadType =
|
export type FileType =
|
||||||
| "video"
|
| "video"
|
||||||
| "audio"
|
| "audio"
|
||||||
| "image"
|
| "image"
|
||||||
@ -37,12 +37,22 @@ type req = {
|
|||||||
hash: string;
|
hash: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface uploads {
|
export interface Uploads {
|
||||||
[key: string]: upload;
|
[key: string]: Upload;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface upload {
|
export interface Upload {
|
||||||
id: number;
|
id: number;
|
||||||
file: file;
|
file: IFile;
|
||||||
type: string;
|
type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Item {
|
||||||
|
id: number;
|
||||||
|
url?: string;
|
||||||
|
path: string;
|
||||||
|
file: IFile;
|
||||||
|
dir?: boolean;
|
||||||
|
overwrite?: boolean;
|
||||||
|
type?: FileType;
|
||||||
|
}
|
||||||
|
|||||||
6
frontend/src/types/index.d.ts
vendored
Normal file
6
frontend/src/types/index.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export * from "./api";
|
||||||
|
export * from "./file";
|
||||||
|
export * from "./layout";
|
||||||
|
export * from "./settings";
|
||||||
|
export * from "./toast";
|
||||||
|
export * from "./user";
|
||||||
2
frontend/src/types/layout.d.ts
vendored
2
frontend/src/types/layout.d.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
interface LayoutValue {
|
export interface LayoutValue {
|
||||||
prompt: string;
|
prompt: string;
|
||||||
confirm: any;
|
confirm: any;
|
||||||
action?: boolean;
|
action?: boolean;
|
||||||
|
|||||||
23
frontend/src/types/settings.d.ts
vendored
23
frontend/src/types/settings.d.ts
vendored
@ -1,8 +1,10 @@
|
|||||||
interface ISettings {
|
import type { Permissions } from "./user";
|
||||||
|
|
||||||
|
export interface ISettings {
|
||||||
signup: boolean;
|
signup: boolean;
|
||||||
createUserDir: boolean;
|
createUserDir: boolean;
|
||||||
userHomeBasePath: string;
|
userHomeBasePath: string;
|
||||||
defaults: Defaults;
|
defaults: SettingsDefaults;
|
||||||
rules: any[];
|
rules: any[];
|
||||||
branding: SettingsBranding;
|
branding: SettingsBranding;
|
||||||
tus: SettingsTus;
|
tus: SettingsTus;
|
||||||
@ -16,7 +18,7 @@ interface SettingsDefaults {
|
|||||||
viewMode: string;
|
viewMode: string;
|
||||||
singleClick: boolean;
|
singleClick: boolean;
|
||||||
sorting: SettingsSorting;
|
sorting: SettingsSorting;
|
||||||
perm: SettingsPerm;
|
perm: Permissions;
|
||||||
commands: any[];
|
commands: any[];
|
||||||
hideDotfiles: boolean;
|
hideDotfiles: boolean;
|
||||||
dateFormat: boolean;
|
dateFormat: boolean;
|
||||||
@ -27,17 +29,6 @@ interface SettingsSorting {
|
|||||||
asc: boolean;
|
asc: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SettingsPerm {
|
|
||||||
admin: boolean;
|
|
||||||
execute: boolean;
|
|
||||||
create: boolean;
|
|
||||||
rename: boolean;
|
|
||||||
modify: boolean;
|
|
||||||
delete: boolean;
|
|
||||||
share: boolean;
|
|
||||||
download: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SettingsBranding {
|
interface SettingsBranding {
|
||||||
name: string;
|
name: string;
|
||||||
disableExternal: boolean;
|
disableExternal: boolean;
|
||||||
@ -52,7 +43,7 @@ interface SettingsTus {
|
|||||||
retryCount: number;
|
retryCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SettingsCommand {
|
export interface SettingsCommand {
|
||||||
after_copy?: string[];
|
after_copy?: string[];
|
||||||
after_delete?: string[];
|
after_delete?: string[];
|
||||||
after_rename?: string[];
|
after_rename?: string[];
|
||||||
@ -65,7 +56,7 @@ interface SettingsCommand {
|
|||||||
before_upload?: string[];
|
before_upload?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SettingsUnit {
|
export interface SettingsUnit {
|
||||||
KB: number;
|
KB: number;
|
||||||
MB: number;
|
MB: number;
|
||||||
GB: number;
|
GB: number;
|
||||||
|
|||||||
6
frontend/src/types/toast.d.ts
vendored
6
frontend/src/types/toast.d.ts
vendored
@ -1 +1,5 @@
|
|||||||
type TToast = (message: string) => void;
|
export type IToastSuccess = (message: string) => void;
|
||||||
|
export type IToastError = (
|
||||||
|
error: Error | string,
|
||||||
|
displayReport?: boolean
|
||||||
|
) => void;
|
||||||
|
|||||||
46
frontend/src/types/user.d.ts
vendored
46
frontend/src/types/user.d.ts
vendored
@ -1,11 +1,16 @@
|
|||||||
|
<<<<<<< HEAD
|
||||||
type UserKey = keyof IUser;
|
type UserKey = keyof IUser;
|
||||||
|
|
||||||
interface IUser {
|
interface IUser {
|
||||||
|
=======
|
||||||
|
export interface IUser {
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
id: number;
|
id: number;
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
scope: string;
|
scope: string;
|
||||||
locale: string;
|
locale: string;
|
||||||
|
<<<<<<< HEAD
|
||||||
lockPassword: boolean;
|
lockPassword: boolean;
|
||||||
viewMode: string;
|
viewMode: string;
|
||||||
singleClick: boolean;
|
singleClick: boolean;
|
||||||
@ -32,3 +37,44 @@ interface UserSorting {
|
|||||||
by: string;
|
by: string;
|
||||||
asc: boolean;
|
asc: boolean;
|
||||||
}
|
}
|
||||||
|
=======
|
||||||
|
perm: Permissions;
|
||||||
|
commands: string[];
|
||||||
|
rules: IRule[];
|
||||||
|
lockPassword: boolean;
|
||||||
|
hideDotfiles: boolean;
|
||||||
|
singleClick: boolean;
|
||||||
|
dateFormat: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Permissions {
|
||||||
|
admin: boolean;
|
||||||
|
copy: boolean;
|
||||||
|
create: boolean;
|
||||||
|
delete: boolean;
|
||||||
|
download: boolean;
|
||||||
|
execute: boolean;
|
||||||
|
modify: boolean;
|
||||||
|
move: boolean;
|
||||||
|
rename: boolean;
|
||||||
|
share: boolean;
|
||||||
|
shell: boolean;
|
||||||
|
upload: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserSorting {
|
||||||
|
by: string;
|
||||||
|
asc: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRule {
|
||||||
|
allow: boolean;
|
||||||
|
path: string;
|
||||||
|
regex: boolean;
|
||||||
|
regexp: IRegexp;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IRegexp {
|
||||||
|
raw: string;
|
||||||
|
}
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
|
|||||||
@ -2,10 +2,12 @@ import { useAuthStore } from "@/stores/auth";
|
|||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import jwt_decode from "jwt-decode";
|
import jwt_decode from "jwt-decode";
|
||||||
import { baseURL } from "./constants";
|
import { baseURL } from "./constants";
|
||||||
|
import { StatusError } from "@/api/utils";
|
||||||
|
import type { User } from "@/types";
|
||||||
|
|
||||||
export function parseToken(token: string) {
|
export function parseToken(token: string) {
|
||||||
// falsy or malformed jwt will throw InvalidTokenError
|
// falsy or malformed jwt will throw InvalidTokenError
|
||||||
const data = jwt_decode<{ [key: string]: any; user: user }>(token);
|
const data = jwt_decode<{ [key: string]: any; user: User }>(token);
|
||||||
|
|
||||||
document.cookie = `auth=${token}; Path=/; SameSite=Strict;`;
|
document.cookie = `auth=${token}; Path=/; SameSite=Strict;`;
|
||||||
|
|
||||||
@ -80,8 +82,7 @@ export async function signup(username: string, password: string) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
// @ts-ignore still need to fix these errors
|
throw new StatusError(res.statusText, res.status);
|
||||||
throw new Error(res.status);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { useUploadStore } from "@/stores/upload";
|
import { useUploadStore } from "@/stores/upload";
|
||||||
|
import type { IFile, Item, FileType } from "@/types";
|
||||||
import url from "@/utils/url";
|
import url from "@/utils/url";
|
||||||
|
|
||||||
export function checkConflict(files: file[], items: item[]) {
|
export function checkConflict(files: IFile[], items: Item[]) {
|
||||||
if (typeof items === "undefined" || items === null) {
|
if (typeof items === "undefined" || items === null) {
|
||||||
items = [];
|
items = [];
|
||||||
}
|
}
|
||||||
@ -34,7 +35,7 @@ export function checkConflict(files: file[], items: item[]) {
|
|||||||
return conflict;
|
return conflict;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function scanFiles(dt: { [key: string]: any; item: item }) {
|
export function scanFiles(dt: { [key: string]: any; item: Item }) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let reading = 0;
|
let reading = 0;
|
||||||
const contents: any[] = [];
|
const contents: any[] = [];
|
||||||
@ -56,7 +57,7 @@ export function scanFiles(dt: { [key: string]: any; item: item }) {
|
|||||||
function readEntry(entry: any, directory = "") {
|
function readEntry(entry: any, directory = "") {
|
||||||
if (entry.isFile) {
|
if (entry.isFile) {
|
||||||
reading++;
|
reading++;
|
||||||
entry.file((file: file) => {
|
entry.file((file: IFile) => {
|
||||||
reading--;
|
reading--;
|
||||||
|
|
||||||
file.fullPath = `${directory}${file.name}`;
|
file.fullPath = `${directory}${file.name}`;
|
||||||
@ -101,7 +102,7 @@ export function scanFiles(dt: { [key: string]: any; item: item }) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function detectType(mimetype: string): uploadType {
|
function detectType(mimetype: string): FileType {
|
||||||
if (mimetype.startsWith("video")) return "video";
|
if (mimetype.startsWith("video")) return "video";
|
||||||
if (mimetype.startsWith("audio")) return "audio";
|
if (mimetype.startsWith("audio")) return "audio";
|
||||||
if (mimetype.startsWith("image")) return "image";
|
if (mimetype.startsWith("image")) return "image";
|
||||||
@ -110,7 +111,7 @@ function detectType(mimetype: string): uploadType {
|
|||||||
return "blob";
|
return "blob";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleFiles(files: file[], base: string, overwrite = false) {
|
export function handleFiles(files: IFile[], base: string, overwrite = false) {
|
||||||
const uploadStore = useUploadStore();
|
const uploadStore = useUploadStore();
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
@ -128,7 +129,7 @@ export function handleFiles(files: file[], base: string, overwrite = false) {
|
|||||||
path += "/";
|
path += "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
const item = {
|
const item: Item = {
|
||||||
id,
|
id,
|
||||||
path,
|
path,
|
||||||
file,
|
file,
|
||||||
|
|||||||
@ -1,67 +0,0 @@
|
|||||||
import Vue from "vue";
|
|
||||||
import Noty from "noty";
|
|
||||||
import VueLazyload from "vue-lazyload";
|
|
||||||
// @ts-ignore
|
|
||||||
import i18n from "@/i18n";
|
|
||||||
import { disableExternal } from "@/utils/constants";
|
|
||||||
|
|
||||||
Vue.use(VueLazyload);
|
|
||||||
|
|
||||||
Vue.config.productionTip = true;
|
|
||||||
|
|
||||||
const notyDefault = {
|
|
||||||
type: "info",
|
|
||||||
layout: "bottomRight",
|
|
||||||
timeout: 1000,
|
|
||||||
progressBar: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
Vue.prototype.$noty = (opts) => {
|
|
||||||
new Noty(Object.assign({}, notyDefault, opts)).show();
|
|
||||||
};
|
|
||||||
|
|
||||||
Vue.prototype.$showSuccess = (message) => {
|
|
||||||
new Noty(
|
|
||||||
Object.assign({}, notyDefault, {
|
|
||||||
text: message,
|
|
||||||
type: "success",
|
|
||||||
})
|
|
||||||
).show();
|
|
||||||
};
|
|
||||||
|
|
||||||
Vue.prototype.$showError = (error, displayReport = true) => {
|
|
||||||
let btns = [
|
|
||||||
Noty.button(i18n.t("buttons.close"), "", function () {
|
|
||||||
n.close();
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (!disableExternal && displayReport) {
|
|
||||||
btns.unshift(
|
|
||||||
Noty.button(i18n.t("buttons.reportIssue"), "", function () {
|
|
||||||
window.open(
|
|
||||||
"https://github.com/filebrowser/filebrowser/issues/new/choose"
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let n = new Noty(
|
|
||||||
Object.assign({}, notyDefault, {
|
|
||||||
text: error.message || error,
|
|
||||||
type: "error",
|
|
||||||
timeout: null,
|
|
||||||
buttons: btns,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
n.show();
|
|
||||||
};
|
|
||||||
|
|
||||||
Vue.directive("focus", {
|
|
||||||
inserted: function (el) {
|
|
||||||
el.focus();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Vue;
|
|
||||||
@ -34,6 +34,7 @@ import {
|
|||||||
watch,
|
watch,
|
||||||
} from "vue";
|
} from "vue";
|
||||||
import { files as api } from "@/api";
|
import { files as api } from "@/api";
|
||||||
|
import { storeToRefs } from "pinia";
|
||||||
import { useFileStore } from "@/stores/file";
|
import { useFileStore } from "@/stores/file";
|
||||||
import { useLayoutStore } from "@/stores/layout";
|
import { useLayoutStore } from "@/stores/layout";
|
||||||
import { useUploadStore } from "@/stores/upload";
|
import { useUploadStore } from "@/stores/upload";
|
||||||
@ -51,6 +52,9 @@ const layoutStore = useLayoutStore();
|
|||||||
const fileStore = useFileStore();
|
const fileStore = useFileStore();
|
||||||
const uploadStore = useUploadStore();
|
const uploadStore = useUploadStore();
|
||||||
|
|
||||||
|
const { reload } = storeToRefs(fileStore);
|
||||||
|
const { error: uploadError } = storeToRefs(uploadStore);
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const { t } = useI18n({});
|
const { t } = useI18n({});
|
||||||
@ -98,14 +102,11 @@ onUnmounted(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
watch(route, () => fetchData());
|
watch(route, () => fetchData());
|
||||||
// @ts-ignore
|
watch(reload, (newValue) => {
|
||||||
watch(fileStore.reload, (val) => {
|
newValue && fetchData();
|
||||||
if (val) {
|
|
||||||
fetchData();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
watch(uploadStore.error, (newValue, oldValue) => {
|
watch(uploadError, (newValue) => {
|
||||||
newValue && newValue !== oldValue && layoutStore.showError();
|
newValue && layoutStore.showError();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Define functions
|
// Define functions
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- <div v-if="true" class="layoutStore.progress">
|
<div v-if="uploadStore.getProgress" class="progress">
|
||||||
<div v-bind:style="{ width: this.layoutStore.progress + '%' }"></div>
|
<div v-bind:style="{ width: uploadStore.getProgress + '%' }"></div>
|
||||||
</div> -->
|
</div>
|
||||||
<sidebar></sidebar>
|
<sidebar></sidebar>
|
||||||
<main>
|
<main>
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
@ -21,6 +21,7 @@
|
|||||||
import { useAuthStore } from "@/stores/auth";
|
import { useAuthStore } from "@/stores/auth";
|
||||||
import { useLayoutStore } from "@/stores/layout";
|
import { useLayoutStore } from "@/stores/layout";
|
||||||
import { useFileStore } from "@/stores/file";
|
import { useFileStore } from "@/stores/file";
|
||||||
|
import { useUploadStore } from "@/stores/upload";
|
||||||
import Sidebar from "@/components/Sidebar.vue";
|
import Sidebar from "@/components/Sidebar.vue";
|
||||||
import Prompts from "@/components/prompts/Prompts.vue";
|
import Prompts from "@/components/prompts/Prompts.vue";
|
||||||
import Shell from "@/components/Shell.vue";
|
import Shell from "@/components/Shell.vue";
|
||||||
@ -32,6 +33,7 @@ import { useRoute } from "vue-router";
|
|||||||
const layoutStore = useLayoutStore();
|
const layoutStore = useLayoutStore();
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const fileStore = useFileStore();
|
const fileStore = useFileStore();
|
||||||
|
const uploadStore = useUploadStore();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
watch(route, () => {
|
watch(route, () => {
|
||||||
|
|||||||
@ -71,10 +71,7 @@ const submit = async (event: Event) => {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
let redirect = route.query.redirect;
|
const redirect = (route.query.redirect || "/files/") as string;
|
||||||
if (redirect === "" || redirect === undefined || redirect === null) {
|
|
||||||
redirect = "/files/";
|
|
||||||
}
|
|
||||||
|
|
||||||
let captcha = "";
|
let captcha = "";
|
||||||
if (recaptcha) {
|
if (recaptcha) {
|
||||||
@ -99,7 +96,6 @@ const submit = async (event: Event) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await auth.login(username.value, password.value, captcha);
|
await auth.login(username.value, password.value, captcha);
|
||||||
// @ts-ignore
|
|
||||||
router.push({ path: redirect });
|
router.push({ path: redirect });
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
|||||||
@ -194,9 +194,10 @@ import Item from "@/components/files/ListingItem.vue";
|
|||||||
import Clipboard from "clipboard";
|
import Clipboard from "clipboard";
|
||||||
import { useFileStore } from "@/stores/file";
|
import { useFileStore } from "@/stores/file";
|
||||||
import { useLayoutStore } from "@/stores/layout";
|
import { useLayoutStore } from "@/stores/layout";
|
||||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue";
|
import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import type { IToastSuccess } from "@/types";
|
||||||
|
|
||||||
const error = ref<null | any>(null);
|
const error = ref<null | any>(null);
|
||||||
const showLimit = ref<number>(100);
|
const showLimit = ref<number>(100);
|
||||||
@ -206,6 +207,8 @@ const hash = ref<any>(null);
|
|||||||
const token = ref<any>(null);
|
const token = ref<any>(null);
|
||||||
const clip = ref<any>(null);
|
const clip = ref<any>(null);
|
||||||
|
|
||||||
|
const $showSuccess = inject<IToastSuccess>("$showError")!;
|
||||||
|
|
||||||
const { t } = useI18n({});
|
const { t } = useI18n({});
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@ -256,7 +259,7 @@ const fetchData = async () => {
|
|||||||
fileStore.reload = false;
|
fileStore.reload = false;
|
||||||
fileStore.selected = [];
|
fileStore.selected = [];
|
||||||
fileStore.multiple = false;
|
fileStore.multiple = false;
|
||||||
// fileStore.closeHovers();
|
layoutStore.closeHovers();
|
||||||
|
|
||||||
// Set loading to true and reset the error.
|
// Set loading to true and reset the error.
|
||||||
layoutStore.loading = true;
|
layoutStore.loading = true;
|
||||||
@ -324,7 +327,6 @@ const download = () => {
|
|||||||
files.push(req.value.items[i].path);
|
files.push(req.value.items[i].path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
api.download(format, hash.value, token.value, ...files);
|
api.download(format, hash.value, token.value, ...files);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -332,8 +334,7 @@ const download = () => {
|
|||||||
|
|
||||||
const linkSelected = () => {
|
const linkSelected = () => {
|
||||||
return isSingleFile() && req.value
|
return isSingleFile() && req.value
|
||||||
? // @ts-ignore
|
? api.getDownloadURL({
|
||||||
api.getDownloadURL({
|
|
||||||
hash: hash.value,
|
hash: hash.value,
|
||||||
path: req.value.items[fileStore.selected[0]].path,
|
path: req.value.items[fileStore.selected[0]].path,
|
||||||
})
|
})
|
||||||
@ -348,7 +349,7 @@ onMounted(async () => {
|
|||||||
window.addEventListener("keydown", keyEvent);
|
window.addEventListener("keydown", keyEvent);
|
||||||
clip.value = new Clipboard(".copy-clipboard");
|
clip.value = new Clipboard(".copy-clipboard");
|
||||||
clip.value.on("success", () => {
|
clip.value.on("success", () => {
|
||||||
// $showSuccess(this.t("success.linkCopied"));
|
$showSuccess(t("success.linkCopied"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -158,6 +158,7 @@
|
|||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p class="small">{{ t("settings.defaultUserDescription") }}</p>
|
<p class="small">{{ t("settings.defaultUserDescription") }}</p>
|
||||||
|
|
||||||
|
<!-- TODO: idk how to fix this ts error -->
|
||||||
<user-form
|
<user-form
|
||||||
:isNew="false"
|
:isNew="false"
|
||||||
:isDefault="true"
|
:isDefault="true"
|
||||||
@ -239,6 +240,13 @@ import Themes from "@/components/settings/Themes.vue";
|
|||||||
import Errors from "@/views/Errors.vue";
|
import Errors from "@/views/Errors.vue";
|
||||||
import { computed, inject, onBeforeUnmount, onMounted, ref } from "vue";
|
import { computed, inject, onBeforeUnmount, onMounted, ref } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import type {
|
||||||
|
ISettings,
|
||||||
|
IToastError,
|
||||||
|
IToastSuccess,
|
||||||
|
SettingsCommand,
|
||||||
|
SettingsUnit,
|
||||||
|
} from "@/types";
|
||||||
|
|
||||||
const error = ref<any>(null);
|
const error = ref<any>(null);
|
||||||
const originalSettings = ref<ISettings | null>(null);
|
const originalSettings = ref<ISettings | null>(null);
|
||||||
@ -246,12 +254,12 @@ const settings = ref<ISettings | null>(null);
|
|||||||
const debounceTimeout = ref<number | null>(null);
|
const debounceTimeout = ref<number | null>(null);
|
||||||
|
|
||||||
const commandObject = ref<{
|
const commandObject = ref<{
|
||||||
[key in keyof SettingsCommand]: string;
|
[key in keyof SettingsCommand]: string[] | string;
|
||||||
}>({});
|
}>({});
|
||||||
const shellValue = ref<string>("");
|
const shellValue = ref<string>("");
|
||||||
|
|
||||||
const $showError = inject<TToast>("$showError") as TToast;
|
const $showError = inject<IToastError>("$showError")!;
|
||||||
const $showSuccess = inject<TToast>("$showSuccess") as TToast;
|
const $showSuccess = inject<IToastSuccess>("$showSuccess")!;
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
@ -304,6 +312,7 @@ const save = async () => {
|
|||||||
commands: {},
|
commands: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
for (const name of Object.keys(settings.value.commands)) {
|
for (const name of Object.keys(settings.value.commands)) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -317,6 +326,22 @@ const save = async () => {
|
|||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
newSettings.commands[name] = newValue;
|
newSettings.commands[name] = newValue;
|
||||||
|
=======
|
||||||
|
const keys = Object.keys(settings.value.commands) as Array<
|
||||||
|
keyof SettingsCommand
|
||||||
|
>;
|
||||||
|
for (const key of keys) {
|
||||||
|
// not sure if we can safely assert non-null
|
||||||
|
const newValue = commandObject.value[key];
|
||||||
|
if (!newValue) continue;
|
||||||
|
|
||||||
|
if (Array.isArray(newValue)) {
|
||||||
|
newSettings.commands[key] = newValue;
|
||||||
|
} else if (key in commandObject.value) {
|
||||||
|
newSettings.commands[key] = newValue
|
||||||
|
.split("\n")
|
||||||
|
.filter((cmd: string) => cmd !== "");
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newSettings.shell = shellValue.value.split("\n");
|
newSettings.shell = shellValue.value.split("\n");
|
||||||
@ -371,16 +396,20 @@ onMounted(async () => {
|
|||||||
const original: ISettings = await api.get();
|
const original: ISettings = await api.get();
|
||||||
let newSettings: ISettings = { ...original, commands: {} };
|
let newSettings: ISettings = { ...original, commands: {} };
|
||||||
|
|
||||||
for (const key in original.commands) {
|
const keys = Object.keys(original.commands) as Array<keyof SettingsCommand>;
|
||||||
// @ts-ignore
|
for (const key in keys) {
|
||||||
|
//@ts-ignore
|
||||||
newSettings.commands[key] = original.commands[key];
|
newSettings.commands[key] = original.commands[key];
|
||||||
// @ts-ignore
|
//@ts-ignore
|
||||||
commandObject.value[key] = original.commands[key].join("\n");
|
commandObject.value[key] = original.commands[key].join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
originalSettings.value = original;
|
originalSettings.value = original;
|
||||||
settings.value = newSettings;
|
settings.value = newSettings;
|
||||||
|
<<<<<<< HEAD
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
=======
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
shellValue.value = newSettings.shell.join("\n");
|
shellValue.value = newSettings.shell.join("\n");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error.value = e;
|
error.value = e;
|
||||||
|
|||||||
@ -83,13 +83,22 @@ import Languages from "@/components/settings/Languages.vue";
|
|||||||
// import i18n, { rtlLanguages } from "@/i18n";
|
// import i18n, { rtlLanguages } from "@/i18n";
|
||||||
import { inject, onMounted, ref } from "vue";
|
import { inject, onMounted, ref } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
import type { IToastError, IToastSuccess } from "@/types";
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
|
|
||||||
const layoutStore = useLayoutStore();
|
const layoutStore = useLayoutStore();
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
const $showError = inject("$showError") as TToast;
|
const $showError = inject("$showError") as TToast;
|
||||||
const $showSuccess = inject("$showSuccess") as TToast;
|
const $showSuccess = inject("$showSuccess") as TToast;
|
||||||
|
=======
|
||||||
|
const $showError = inject<IToastError>("$showError")!;
|
||||||
|
const $showSuccess = inject<IToastSuccess>("$showSuccess")!;
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
|
|
||||||
const password = ref<string>("");
|
const password = ref<string>("");
|
||||||
const passwordConf = ref<string>("");
|
const passwordConf = ref<string>("");
|
||||||
|
|||||||
@ -71,9 +71,16 @@ import Clipboard from "clipboard";
|
|||||||
import Errors from "@/views/Errors.vue";
|
import Errors from "@/views/Errors.vue";
|
||||||
import { inject, onBeforeUnmount, ref, onMounted } from "vue";
|
import { inject, onBeforeUnmount, ref, onMounted } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
const $showError = inject("$showError") as TToast;
|
const $showError = inject("$showError") as TToast;
|
||||||
const $showSuccess = inject("$showSuccess") as TToast;
|
const $showSuccess = inject("$showSuccess") as TToast;
|
||||||
|
=======
|
||||||
|
import type { IShare, IToastError, IToastSuccess } from "@/types";
|
||||||
|
|
||||||
|
const $showError = inject<IToastError>("$showError")!;
|
||||||
|
const $showSuccess = inject<IToastSuccess>("$showSuccess")!;
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const layoutStore = useLayoutStore();
|
const layoutStore = useLayoutStore();
|
||||||
|
|||||||
@ -75,19 +75,31 @@ import { useLayoutStore } from "@/stores/layout";
|
|||||||
import { users as api, settings } from "@/api";
|
import { users as api, settings } from "@/api";
|
||||||
import UserForm from "@/components/settings/UserForm.vue";
|
import UserForm from "@/components/settings/UserForm.vue";
|
||||||
import Errors from "@/views/Errors.vue";
|
import Errors from "@/views/Errors.vue";
|
||||||
|
<<<<<<< HEAD
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { cloneDeep } from "lodash-es";
|
import { cloneDeep } from "lodash-es";
|
||||||
import { computed, inject, onMounted, ref, watch } from "vue";
|
import { computed, inject, onMounted, ref, watch } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
=======
|
||||||
|
import { computed, inject, onMounted, ref, watch } from "vue";
|
||||||
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import type { IToastError, IToastSuccess, IUser } from "@/types";
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
|
|
||||||
const error = ref<any | null>(null);
|
const error = ref<any | null>(null);
|
||||||
const originalUser = ref<IUser | null>(null);
|
const originalUser = ref<IUser | null>(null);
|
||||||
const user = ref<IUser | null>(null);
|
const user = ref<IUser | null>(null);
|
||||||
const createUserDir = ref<boolean>(false);
|
const createUserDir = ref<boolean>(false);
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
const $showError = inject("$showError") as TToast;
|
const $showError = inject("$showError") as TToast;
|
||||||
const $showSuccess = inject("$showSuccess") as TToast;
|
const $showSuccess = inject("$showSuccess") as TToast;
|
||||||
|
=======
|
||||||
|
const $showError = inject<IToastError>("$showError")!;
|
||||||
|
const $showSuccess = inject<IToastSuccess>("$showSuccess")!;
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const layoutStore = useLayoutStore();
|
const layoutStore = useLayoutStore();
|
||||||
@ -121,6 +133,8 @@ const fetchData = async () => {
|
|||||||
rules: [],
|
rules: [],
|
||||||
lockPassword: false,
|
lockPassword: false,
|
||||||
id: 0,
|
id: 0,
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const id = Array.isArray(route.params.id)
|
const id = Array.isArray(route.params.id)
|
||||||
@ -137,6 +151,48 @@ const fetchData = async () => {
|
|||||||
|
|
||||||
const deletePrompt = () => layoutStore.showHover("deleteUser");
|
const deletePrompt = () => layoutStore.showHover("deleteUser");
|
||||||
|
|
||||||
|
const deleteUser = async (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (user.value === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await api.remove(user.value.id);
|
||||||
|
router.push({ path: "/settings/users" });
|
||||||
|
$showSuccess(t("settings.userDeleted"));
|
||||||
|
} catch (e: any) {
|
||||||
|
e.message === "403" ? $showError(t("errors.forbidden")) : $showError(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const save = async (event: Event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (originalUser.value === null || user.value === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (isNew.value) {
|
||||||
|
const newUser: IUser = {
|
||||||
|
...originalUser.value,
|
||||||
|
...user.value,
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const id = Array.isArray(route.params.id)
|
||||||
|
? route.params.id.join("")
|
||||||
|
: route.params.id;
|
||||||
|
user.value = { ...(await api.get(parseInt(id))) };
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
error.value = e;
|
||||||
|
} finally {
|
||||||
|
layoutStore.loading = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
const deletePrompt = () => layoutStore.showHover("deleteUser");
|
||||||
|
|
||||||
const deleteUser = async (e: Event) => {
|
const deleteUser = async (e: Event) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (user.value === null) {
|
if (user.value === null) {
|
||||||
@ -170,6 +226,16 @@ const save = async (event: Event) => {
|
|||||||
|
|
||||||
if (user.value.id === authStore.user?.id) {
|
if (user.value.id === authStore.user?.id) {
|
||||||
authStore.setUser({ ...cloneDeep(user) });
|
authStore.setUser({ ...cloneDeep(user) });
|
||||||
|
=======
|
||||||
|
const loc = (await api.create(newUser)) as string;
|
||||||
|
router.push({ path: loc });
|
||||||
|
$showSuccess(t("settings.userCreated"));
|
||||||
|
} else {
|
||||||
|
await api.update(user);
|
||||||
|
|
||||||
|
if (user.value.id === authStore.user?.id) {
|
||||||
|
authStore.updateUser(user.value);
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
}
|
}
|
||||||
|
|
||||||
$showSuccess(t("settings.userUpdated"));
|
$showSuccess(t("settings.userUpdated"));
|
||||||
|
|||||||
@ -47,6 +47,10 @@ import { users as api } from "@/api";
|
|||||||
import Errors from "@/views/Errors.vue";
|
import Errors from "@/views/Errors.vue";
|
||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
import type { IUser } from "@/types";
|
||||||
|
>>>>>>> kloon15/vue3
|
||||||
|
|
||||||
const error = ref<any>(null);
|
const error = ref<any>(null);
|
||||||
const users = ref<IUser[]>([]);
|
const users = ref<IUser[]>([]);
|
||||||
|
|||||||
@ -5,26 +5,19 @@
|
|||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "Node",
|
"moduleResolution": "Node10",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"jsx": "preserve",
|
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"outDir": "../dist/frontend",
|
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"lib": ["ESNext", "DOM"],
|
"lib": ["ESNext", "DOM"],
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"types": ["vite/client"],
|
"types": ["vite/client", "@intlify/unplugin-vue-i18n/messages"],
|
||||||
"typeRoots": ["./node_modules/@types", "./some-custom-lib"],
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src/**/*.ts", "src/**/*.vue", "src/i18n/index.ts.bak"],
|
||||||
"./**/*.ts",
|
|
||||||
"src/**/*.d.ts",
|
|
||||||
"src/**/*.vue",
|
|
||||||
],
|
|
||||||
"exclude": ["node_modules", "dist"]
|
"exclude": ["node_modules", "dist"]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,9 @@ import pluginRewriteAll from "vite-plugin-rewrite-all";
|
|||||||
|
|
||||||
const plugins = [
|
const plugins = [
|
||||||
vue(),
|
vue(),
|
||||||
VueI18nPlugin({}),
|
VueI18nPlugin({
|
||||||
|
include: [path.resolve(__dirname, "./src/i18n/**.json")],
|
||||||
|
}),
|
||||||
legacy({
|
legacy({
|
||||||
// defaults already drop IE support
|
// defaults already drop IE support
|
||||||
targets: ["defaults"],
|
targets: ["defaults"],
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user