Fixed frontend

This commit is contained in:
Mutzi 2022-08-31 14:28:35 +02:00
parent df93c5e091
commit c290863e26
56 changed files with 1823 additions and 6370 deletions

15
frontend/.eslintrc.cjs Normal file
View File

@ -0,0 +1,15 @@
/* eslint-env node */
require("@rushstack/eslint-patch/modern-module-resolution");
module.exports = {
root: true,
extends: [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/eslint-config-typescript/recommended",
"@vue/eslint-config-prettier",
],
parserOptions: {
ecmaVersion: "latest",
},
};

27
frontend/.gitignore vendored
View File

@ -1,21 +1,26 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.vscode
*.suo
*.ntvs*
*.njsproj

View File

@ -1,7 +0,0 @@
{
"tabWidth": 4,
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"endOfLine": "lf"
}

46
frontend/README.md Normal file
View File

@ -0,0 +1,46 @@
# frontend
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
1. Disable the built-in TypeScript Extension
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Type-Check, Compile and Minify for Production
```sh
npm run build
```
### Lint with [ESLint](https://eslint.org/)
```sh
npm run lint
```

View File

@ -1,3 +0,0 @@
module.exports = {
presets: ['@vue/cli-plugin-babel/preset']
};

1
frontend/env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@ -1,29 +0,0 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir: __dirname,
sourceType: 'module'
},
plugins: ['@typescript-eslint/eslint-plugin', 'no-relative-import-paths'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended'
],
root: true,
env: {
node: true,
jest: true
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'no-relative-import-paths/no-relative-import-paths': [
'error',
{ allowSameFolder: true, rootDir: 'src' }
]
}
};

13
frontend/index.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@ -1,64 +1,41 @@
{
"name": "frontend",
"version": "0.1.0",
"version": "0.0.0",
"private": true,
"license": "suck my dick",
"scripts": {
"serve": "vue-cli-service build --watch --dest ../run/static",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
"dev": "vite build --outDir ../run/static --watch",
"build": "run-p type-check build-only",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
},
"dependencies": {
"axios": "^0.27.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"core-js": "^3.8.3",
"filesize": "^9.0.11",
"jwt-decode": "^3.1.2",
"naive-ui": "^2.32.1",
"stream-browserify": "^3.0.0",
"util": "^0.12.4",
"vue": "^3.2.13",
"vue-router": "^4.0.3"
"vue": "^3.2.37",
"vue-router": "^4.1.3"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.4.0",
"@typescript-eslint/parser": "^5.4.0",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-typescript": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"@vue/eslint-config-typescript": "^9.1.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.0.3",
"prettier": "^2.4.1",
"@rushstack/eslint-patch": "^1.1.4",
"@types/node": "^18.7.14",
"@vitejs/plugin-vue": "^3.0.1",
"@vue/eslint-config-prettier": "^7.0.0",
"@vue/eslint-config-typescript": "^11.0.0",
"@vue/tsconfig": "^0.1.3",
"eslint": "8.22.0",
"eslint-plugin-vue": "^9.3.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.7.1",
"sass": "^1.32.7",
"sass-loader": "^12.0.0",
"typescript": "~4.5.5",
"vfonts": "^0.0.3"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/typescript/recommended",
"plugin:prettier/recommended"
],
"parserOptions": {
"ecmaVersion": 2020
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"not ie 11"
]
"typescript": "~4.7.4",
"vite": "^3.0.4",
"vue-tsc": "^0.39.5"
}
}

View File

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<!--suppress HtmlUnknownTarget -->
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't
work properly without JavaScript enabled. Please enable it to
continue.</strong
>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@ -1,27 +1,27 @@
<script setup async lang="ts">
import { provide, ref } from 'vue';
import { useRouter } from 'vue-router';
import { TokenInjectType } from '@/api';
import { provide, ref } from "vue";
import { useRouter } from "vue-router";
import type { TokenInjectType } from "@/api";
const router = useRouter();
const jwt = ref<string | null>(localStorage.getItem('token'));
const jwt = ref<string | null>(localStorage.getItem("token"));
function setToken(token: string) {
jwt.value = token;
localStorage.setItem('token', token);
localStorage.setItem("token", token);
}
function logout() {
jwt.value = null;
localStorage.removeItem('token');
router.push({ name: 'login' });
localStorage.removeItem("token");
router.push({ name: "login" });
}
provide<TokenInjectType>('jwt', {
provide<TokenInjectType>("jwt", {
jwt,
setToken,
logout
logout,
});
</script>

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import App from './App';
import App from "./App.vue";
</script>
<template>

View File

@ -1,7 +1,7 @@
import { Requests, Responses, UserRole, get_token, post_token } from './base';
import { Requests, Responses, UserRole, get_token, post_token } from "./base";
export const get_users = (token: string): Promise<Responses.Admin.GetUsers> =>
get_token('/api/admin/users', token);
get_token("/api/admin/users", token);
export const set_role = (
user: number,
@ -9,10 +9,10 @@ export const set_role = (
token: string
): Promise<Responses.Admin.SetUserRole | Responses.ErrorResponse> =>
post_token<Requests.Admin.SetUserRole>(
'/api/admin/set_role',
"/api/admin/set_role",
{
user,
role
role,
},
token
);
@ -22,9 +22,9 @@ export const logout = (
token: string
): Promise<Responses.Admin.LogoutAllUser | Responses.ErrorResponse> =>
post_token<Requests.Admin.LogoutAll>(
'/api/admin/logout',
"/api/admin/logout",
{
user
user,
},
token
);
@ -34,9 +34,9 @@ export const delete_user = (
token: string
): Promise<Responses.Admin.DeleteUser | Responses.ErrorResponse> =>
post_token<Requests.Admin.DeleteUser>(
'/api/admin/delete',
"/api/admin/delete",
{
user
user,
},
token
);
@ -46,9 +46,9 @@ export const disable_tfa = (
token: string
): Promise<Responses.Admin.DisableTfa | Responses.ErrorResponse> =>
post_token<Requests.Admin.DisableTfa>(
'/api/admin/disable_2fa',
"/api/admin/disable_2fa",
{
user
user,
},
token
);

View File

@ -1,4 +1,4 @@
import { Responses, Requests, post, post_token } from './base';
import { Responses, Requests, post, post_token } from "./base";
export const auth_login = (
username: string,
@ -9,25 +9,25 @@ export const auth_login = (
| Responses.Auth.TfaRequiredResponse
| Responses.ErrorResponse
> =>
post<Requests.Auth.LoginRequest>('/api/auth/login', {
post<Requests.Auth.LoginRequest>("/api/auth/login", {
username: username,
password: password,
otp: otp
otp: otp,
});
export const auth_signup = (
username: string,
password: string
): Promise<Responses.Auth.SignupResponse | Responses.ErrorResponse> =>
post<Requests.Auth.SignUpRequest>('/api/auth/signup', {
post<Requests.Auth.SignUpRequest>("/api/auth/signup", {
username: username,
password: password
password: password,
});
export const refresh_token = (
token: string
): Promise<Responses.Auth.RefreshResponse | Responses.ErrorResponse> =>
post_token('/api/auth/refresh', {}, token);
post_token("/api/auth/refresh", {}, token);
export const change_password = (
oldPw: string,
@ -35,10 +35,10 @@ export const change_password = (
token: string
): Promise<Responses.Auth.ChangePasswordResponse | Responses.ErrorResponse> =>
post_token<Requests.Auth.ChangePasswordRequest>(
'/api/auth/change_password',
"/api/auth/change_password",
{
oldPassword: oldPw,
newPassword: newPw
newPassword: newPw,
},
token
);
@ -46,7 +46,7 @@ export const change_password = (
export const logout_all = (
token: string
): Promise<Responses.Auth.LogoutAllResponse | Responses.ErrorResponse> =>
post_token('/api/auth/logout_all', {}, token);
post_token("/api/auth/logout_all", {}, token);
export function tfa_setup(
mail: false,
@ -65,9 +65,9 @@ export function tfa_setup(
| Responses.ErrorResponse
> {
return post_token<Requests.Auth.TfaSetup>(
'/api/auth/2fa/setup',
"/api/auth/2fa/setup",
{
mail
mail,
},
token
);
@ -79,10 +79,10 @@ export const tfa_complete = (
token: string
): Promise<Responses.Auth.TfaCompletedResponse | Responses.ErrorResponse> =>
post_token<Requests.Auth.TfaComplete>(
'/api/auth/2fa/complete',
"/api/auth/2fa/complete",
{
mail,
code
code,
},
token
);
@ -90,4 +90,4 @@ export const tfa_complete = (
export const tfa_disable = (
token: string
): Promise<Responses.Auth.RemoveTfaResponse | Responses.ErrorResponse> =>
post_token('/api/auth/2fa/disable', {}, token);
post_token("/api/auth/2fa/disable", {}, token);

View File

@ -1,11 +1,11 @@
import axios from 'axios';
import { Requests, Responses, UserRole } from '../dto';
import axios from "axios";
import { Requests, Responses, UserRole } from "../dto";
export { Requests, Responses, UserRole };
export const post = <T extends Requests.BaseRequest>(url: string, data: T) =>
axios
.post(url, data, {
headers: { 'Content-type': 'application/json' }
headers: { "Content-type": "application/json" },
})
.then((res) => res.data)
.catch((err) => err.response.data);
@ -18,9 +18,9 @@ export const post_token = <T extends Requests.BaseRequest>(
axios
.post(url, data, {
headers: {
Authorization: 'Bearer ' + token,
'Content-type': 'application/json'
}
Authorization: "Bearer " + token,
"Content-type": "application/json",
},
})
.then((res) => res.data)
.catch((err) => err.response.data);
@ -34,10 +34,10 @@ export const post_token_form = (
axios
.post(url, data, {
headers: {
Authorization: 'Bearer ' + token,
'Content-type': 'multipart/form-data'
Authorization: "Bearer " + token,
"Content-type": "multipart/form-data",
},
onUploadProgress: onProgress
onUploadProgress: onProgress,
})
.then((res) => res.data)
.catch((err) => err.response.data);
@ -52,7 +52,7 @@ export const get = (url: string) =>
export const get_token = (url: string, token: string) =>
axios
.get(url, {
headers: { Authorization: 'Bearer ' + token }
headers: { Authorization: "Bearer " + token },
})
.then((res) => res.data)
.catch((err) => err.response.data);

View File

@ -4,13 +4,13 @@ import {
get_token,
post_token,
post_token_form,
isErrorResponse
} from './base';
isErrorResponse,
} from "./base";
export const get_root = (
token: string
): Promise<Responses.FS.GetRootResponse | Responses.ErrorResponse> =>
get_token('/api/fs/root', token);
get_token("/api/fs/root", token);
export const get_node = (
token: string,
@ -30,10 +30,10 @@ export const create_folder = (
name: string
): Promise<Responses.FS.CreateFolderResponse | Responses.ErrorResponse> =>
post_token<Requests.FS.CreateFolderRequest>(
'/api/fs/createFolder',
"/api/fs/createFolder",
{
parent: parent,
name: name
name: name,
},
token
);
@ -44,10 +44,10 @@ export const create_file = (
name: string
): Promise<Responses.FS.CreateFileResponse | Responses.ErrorResponse> =>
post_token<Requests.FS.CreateFileRequest>(
'/api/fs/createFile',
"/api/fs/createFile",
{
parent: parent,
name: name
name: name,
},
token
);
@ -68,20 +68,15 @@ export const upload_file = async (
if (isErrorResponse(node)) return node;
const form = new FormData();
form.set('file', file);
return post_token_form(
`/api/fs/upload/${node.id}`,
form,
token,
onProgress
);
form.set("file", file);
return post_token_form(`/api/fs/upload/${node.id}`, form, token, onProgress);
};
export function download_file(token: string, id: number) {
const form = document.createElement('form');
form.method = 'post';
form.target = '_blank';
form.action = '/api/fs/download';
const form = document.createElement("form");
form.method = "post";
form.target = "_blank";
form.action = "/api/fs/download";
form.innerHTML = `<input type="hidden" name="jwtToken" value="${token}"><input type="hidden" name="id" value="${id}">`;
document.body.appendChild(form);
form.submit();

View File

@ -1,6 +1,6 @@
export { Requests, Responses, UserRole, isErrorResponse } from './base';
export * as Auth from './auth';
export * as FS from './fs';
export * as User from './user';
export * as Admin from './admin';
export * from './util';
export { Requests, Responses, UserRole, isErrorResponse } from "./base";
export * as Auth from "./auth";
export * as FS from "./fs";
export * as User from "./user";
export * as Admin from "./admin";
export * from "./util";

View File

@ -1,11 +1,11 @@
import { Responses, get_token, post_token } from '@/api/base';
import { Responses, get_token, post_token } from "@/api/base";
export const get_user_info = (
token: string
): Promise<Responses.User.UserInfoResponse | Responses.ErrorResponse> =>
get_token('/api/user/info', token);
get_token("/api/user/info", token);
export const delete_user = (
token: string
): Promise<Responses.User.DeleteUserResponse | Responses.ErrorResponse> =>
post_token('/api/user/delete', {}, token);
post_token("/api/user/delete", {}, token);

View File

@ -1,7 +1,8 @@
import jwtDecode, { JwtPayload } from 'jwt-decode';
import { Ref, UnwrapRef } from 'vue';
import { isErrorResponse } from './base';
import { refresh_token } from './auth';
import type { JwtPayload } from "jwt-decode";
import type { Ref, UnwrapRef } from "vue";
import jwtDecode from "jwt-decode";
import { isErrorResponse } from "./base";
import { refresh_token } from "./auth";
export async function check_token(
token: TokenInjectType

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69" xmlns:v="https://vecta.io/nano"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>

After

Width:  |  Height:  |  Size: 308 B

View File

@ -1,21 +1,22 @@
<script setup lang="ts">
import { defineEmits, defineProps, inject } from 'vue';
import { check_token, FS, Responses, TokenInjectType } from '@/api';
import type { TokenInjectType } from "@/api";
import { defineEmits, defineProps, inject } from "vue";
import { check_token, FS, Responses } from "@/api";
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
const jwt = inject<TokenInjectType>("jwt") as TokenInjectType;
const props = defineProps<{
node: Responses.FS.GetNodeResponse;
}>();
const emit = defineEmits<{
(e: 'reloadNode'): void;
(e: "reloadNode"): void;
}>();
async function del() {
const token = await check_token(jwt);
if (!token) return;
await FS.delete_node(token, props.node.id);
emit('reloadNode');
emit("reloadNode");
}
async function download() {

View File

@ -1,26 +1,27 @@
<script setup lang="ts">
import { defineEmits, defineProps, inject, reactive, ref, watch } from 'vue';
import { FS, Responses, check_token, TokenInjectType } from '@/api';
import DirEntry from '@/components/FSView/DirEntry.vue';
import UploadFileDialog from '@/components/UploadDialog/UploadFileDialog.vue';
import { NModal } from 'naive-ui';
import type { TokenInjectType } from "@/api";
import { defineEmits, defineProps, inject, reactive, ref, watch } from "vue";
import { FS, Responses, check_token } from "@/api";
import DirEntry from "@/components/FSView/DirEntry.vue";
import UploadFileDialog from "@/components/UploadDialog/UploadFileDialog.vue";
import { NModal } from "naive-ui";
const props = defineProps<{
node: Responses.FS.GetNodeResponse;
}>();
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
const jwt = inject<TokenInjectType>("jwt") as TokenInjectType;
const emit = defineEmits<{
(e: 'reloadNode'): void;
(e: 'gotoRoot'): void;
(e: "reloadNode"): void;
(e: "gotoRoot"): void;
}>();
const fileInput = ref<HTMLInputElement>();
const uploadDialog = ref();
const uploadDialogShow = ref(false);
const new_folder_name = ref('');
const new_folder_name = ref("");
const files = ref<File[]>([]);
const nodes = ref<Responses.FS.GetNodeResponse[]>([]);
const hasParent = ref(false);
@ -29,7 +30,7 @@ const parentNode = reactive<Responses.FS.GetNodeResponse>({
statusCode: 200,
isFile: false,
parent: null,
name: '..'
name: "..",
});
watch(
@ -43,10 +44,7 @@ watch(
await Promise.all(
to.children?.map(async (child) => {
nodes.value.push(
(await FS.get_node(
token,
child
)) as Responses.FS.GetNodeResponse
(await FS.get_node(token, child)) as Responses.FS.GetNodeResponse
);
}) ?? []
);
@ -58,7 +56,7 @@ async function newFolder() {
const token = await check_token(jwt);
if (!token) return;
await FS.create_folder(token, props.node.id, new_folder_name.value);
emit('reloadNode');
emit("reloadNode");
}
async function uploadFiles() {
@ -69,18 +67,14 @@ async function uploadFiles() {
async function uploadFilesDialogOpen() {
await uploadDialog.value?.startUpload(props.node.id);
uploadDialogShow.value = false;
if (fileInput.value) fileInput.value.value = '';
emit('reloadNode');
if (fileInput.value) fileInput.value.value = "";
emit("reloadNode");
}
</script>
<template>
<div>
<input
type="text"
placeholder="Folder name"
v-model="new_folder_name"
/>
<input type="text" placeholder="Folder name" v-model="new_folder_name" />
<a href="#" @click="newFolder()">create folder</a>
</div>
<div>

View File

@ -1,12 +1,13 @@
<script setup lang="ts">
import { defineProps, inject } from 'vue';
import { check_token, FS, Responses, TokenInjectType } from '@/api';
import type { TokenInjectType } from "@/api";
import { defineProps, inject } from "vue";
import { check_token, FS, Responses } from "@/api";
const props = defineProps<{
node: Responses.FS.GetNodeResponse;
}>();
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
const jwt = inject<TokenInjectType>("jwt") as TokenInjectType;
async function del() {
const token = await check_token(jwt);

View File

@ -2,8 +2,7 @@
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this
project,<br />
For a guide and recipes on how to configure / customize this project,<br />
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener"
>vue-cli documentation</a
@ -55,9 +54,7 @@
<h3>Essential Links</h3>
<ul>
<li>
<a href="https://vuejs.org" target="_blank" rel="noopener"
>Core Docs</a
>
<a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a>
</li>
<li>
<a href="https://forum.vuejs.org" target="_blank" rel="noopener"
@ -70,33 +67,23 @@
>
</li>
<li>
<a
href="https://twitter.com/vuejs"
target="_blank"
rel="noopener"
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener"
>Twitter</a
>
</li>
<li>
<a href="https://news.vuejs.org" target="_blank" rel="noopener"
>News</a
>
<a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a>
</li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li>
<a
href="https://router.vuejs.org"
target="_blank"
rel="noopener"
<a href="https://router.vuejs.org" target="_blank" rel="noopener"
>vue-router</a
>
</li>
<li>
<a href="https://vuex.vuejs.org" target="_blank" rel="noopener"
>vuex</a
>
<a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a>
</li>
<li>
<a
@ -107,10 +94,7 @@
>
</li>
<li>
<a
href="https://vue-loader.vuejs.org"
target="_blank"
rel="noopener"
<a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener"
>vue-loader</a
>
</li>
@ -127,13 +111,13 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent } from "vue";
export default defineComponent({
name: 'HelloWorld',
name: "HelloWorld",
props: {
msg: String
}
msg: String,
},
});
</script>

View File

@ -1,8 +1,9 @@
<script setup lang="ts">
import { defineProps, defineExpose, ref } from 'vue';
import { isErrorResponse, FS } from '@/api';
import { NProgress } from 'naive-ui';
import filesize from 'filesize';
import type { Status } from "naive-ui/es/progress/src/interface";
import { defineProps, defineExpose, ref } from "vue";
import { isErrorResponse, FS } from "@/api";
import { NProgress } from "naive-ui";
import filesize from "filesize";
const props = defineProps<{
file: File;
@ -10,8 +11,8 @@ const props = defineProps<{
const progress = ref(0);
const percentage = ref(0);
const err = ref('');
const status = ref('info');
const err = ref("");
const status = ref<Status>("info");
async function startUpload(parent: number, token: string) {
const resp = await FS.upload_file(token, parent, props.file, (e) => {
@ -20,13 +21,13 @@ async function startUpload(parent: number, token: string) {
});
percentage.value = 100;
if (isErrorResponse(resp)) {
err.value = resp.message ?? 'Error';
status.value = 'error';
} else status.value = 'success';
err.value = resp.message ?? "Error";
status.value = "error";
} else status.value = "success";
}
defineExpose({
startUpload
startUpload,
});
</script>

View File

@ -1,14 +1,15 @@
<script setup lang="ts">
import { defineProps, defineExpose, ref, inject } from 'vue';
import { check_token, TokenInjectType } from '@/api';
import UploadEntry from '@/components/UploadDialog/UploadEntry.vue';
import { NCard } from 'naive-ui';
import type { TokenInjectType } from "@/api";
import { defineProps, defineExpose, ref, inject } from "vue";
import { check_token } from "@/api";
import UploadEntry from "@/components/UploadDialog/UploadEntry.vue";
import { NCard } from "naive-ui";
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
const jwt = inject<TokenInjectType>("jwt") as TokenInjectType;
const entries = ref<typeof UploadEntry[]>([]);
const done = ref(false);
let canCloseResolve = null;
let canCloseResolve: (value: unknown) => void = () => null;
const canClose = new Promise((r) => (canCloseResolve = r));
async function startUpload(parent: number) {
@ -22,7 +23,7 @@ async function startUpload(parent: number) {
}
defineExpose({
startUpload
startUpload,
});
defineProps<{
files: File[];
@ -32,15 +33,10 @@ defineProps<{
<template>
<n-card title="Upload Files">
<div>
<UploadEntry
v-for="f in files"
:key="f.name"
ref="entries"
:file="f"
/>
<UploadEntry v-for="f in files" :key="f.name" ref="entries" :file="f" />
</div>
<div>
<button v-if="done" @click="canCloseResolve()">Close</button>
<button v-if="done" @click="canCloseResolve(null)">Close</button>
</div>
</n-card>
</template>

View File

@ -1,8 +1,8 @@
export * as Requests from './requests';
export * as Responses from './responses';
export * as Requests from "./requests";
export * as Responses from "./responses";
export {
UserRole,
validateSync,
validateAsync,
validateAsyncInline
} from './utils';
validateAsyncInline,
} from "./utils";

View File

@ -1,6 +1,6 @@
import { BaseRequest } from './base';
import { IsEnum, IsNumber } from 'class-validator';
import { UserRole } from '@/dto';
import { BaseRequest } from "./base";
import { IsEnum, IsNumber } from "class-validator";
import { UserRole } from "@/dto";
export class AdminRequest extends BaseRequest {
@IsNumber()

View File

@ -1,11 +1,11 @@
import { BaseRequest } from './base';
import { BaseRequest } from "./base";
import {
IsBoolean,
IsEmail,
IsNotEmpty,
IsOptional,
IsString
} from 'class-validator';
IsString,
} from "class-validator";
export class SignUpRequest extends BaseRequest {
@IsEmail()

View File

@ -1,5 +1,5 @@
import { BaseRequest } from './base';
import { IsInt, IsNotEmpty, IsString, Min } from 'class-validator';
import { BaseRequest } from "./base";
import { IsInt, IsNotEmpty, IsString, Min } from "class-validator";
export class CreateFolderRequest extends BaseRequest {
@IsInt()

View File

@ -1,4 +1,4 @@
export * from './base';
export * as Auth from './auth';
export * as FS from './fs';
export * as Admin from './admin';
export * from "./base";
export * as Auth from "./auth";
export * as FS from "./fs";
export * as Admin from "./admin";

View File

@ -1,4 +1,4 @@
import { SuccessResponse } from './base';
import { SuccessResponse } from "./base";
import {
IsArray,
IsBoolean,
@ -6,9 +6,9 @@ import {
IsNotEmpty,
IsNumber,
IsString,
ValidateNested
} from 'class-validator';
import { UserRole, ValidateConstructor } from '../utils';
ValidateNested,
} from "class-validator";
import { UserRole, ValidateConstructor } from "../utils";
@ValidateConstructor
export class GetUsersEntry {

View File

@ -1,6 +1,6 @@
import { SuccessResponse } from './base';
import { IsBase32, IsJWT, IsNotEmpty } from 'class-validator';
import { ValidateConstructor } from '../utils';
import { SuccessResponse } from "./base";
import { IsBase32, IsJWT, IsNotEmpty } from "class-validator";
import { ValidateConstructor } from "../utils";
@ValidateConstructor
export class LoginResponse extends SuccessResponse {

View File

@ -1,4 +1,4 @@
import { IsNumber, Max, Min } from 'class-validator';
import { IsNumber, Max, Min } from "class-validator";
export class BaseResponse {
constructor(statusCode: number) {

View File

@ -1,13 +1,13 @@
import { SuccessResponse } from './base';
import { SuccessResponse } from "./base";
import {
IsBoolean,
IsInt,
IsNotEmpty,
IsOptional,
IsString,
Min
} from 'class-validator';
import { ValidateConstructor } from '../utils';
Min,
} from "class-validator";
import { ValidateConstructor } from "../utils";
@ValidateConstructor
export class GetRootResponse extends SuccessResponse {

View File

@ -1,5 +1,5 @@
export * from './base';
export * as Auth from './auth';
export * as FS from './fs';
export * as User from './user';
export * as Admin from './admin';
export * from "./base";
export * as Auth from "./auth";
export * as FS from "./fs";
export * as User from "./user";
export * as Admin from "./admin";

View File

@ -1,6 +1,6 @@
import { SuccessResponse } from './base';
import { ValidateConstructor } from '../utils';
import { IsBoolean, IsNotEmpty, IsString } from 'class-validator';
import { SuccessResponse } from "./base";
import { ValidateConstructor } from "../utils";
import { IsBoolean, IsNotEmpty, IsString } from "class-validator";
@ValidateConstructor
export class UserInfoResponse extends SuccessResponse {

View File

@ -1,24 +1,24 @@
import { validate, validateSync as _validateSync } from 'class-validator';
import { validate, validateSync as _validateSync } from "class-validator";
export enum UserRole {
ADMIN = 2,
USER = 1,
DISABLED = 0
DISABLED = 0,
}
export function validateSync<T extends object>(data: T): void {
const errors = _validateSync(data);
if (errors.length > 0) {
console.error('Validation failed, errors: ', errors);
throw new Error('Validation failed');
console.error("Validation failed, errors: ", errors);
throw new Error("Validation failed");
}
}
export async function validateAsync<T extends object>(data: T): Promise<void> {
const errors = await validate(data);
if (errors.length > 0) {
console.error('Validation failed, errors: ', errors);
throw new Error('Validation failed');
console.error("Validation failed, errors: ", errors);
throw new Error("Validation failed");
}
}

View File

@ -1,8 +1,8 @@
import { createApp } from 'vue';
import router from './router';
import AppAsyncWrapper from './AppAsyncWrapper.vue';
import { createApp } from "vue";
import AppAsyncWrapper from "./AppAsyncWrapper.vue";
import router from "./router";
const app = createApp(AppAsyncWrapper);
app.use(router);
app.config.unwrapInjectedRef = true;
app.mount('#app');
app.mount("#app");

View File

@ -1,63 +1,64 @@
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import LoginView from '@/views/LoginView.vue';
import SignupView from '@/views/SignupView.vue';
import HomeView from '@/views/HomeView.vue';
import AboutView from '@/views/AboutView.vue';
import FSView from '@/views/FSView.vue';
import SetTokenView from '@/views/SetTokenView.vue';
import ProfileView from '@/views/ProfileView.vue';
import TFAView from '@/views/TFAView.vue';
import AdminView from '@/views/AdminView.vue';
import type { RouteRecordRaw } from "vue-router";
import { createRouter, createWebHistory } from "vue-router";
import LoginView from "@/views/LoginView.vue";
import SignupView from "@/views/SignupView.vue";
import HomeView from "@/views/HomeView.vue";
import AboutView from "@/views/AboutView.vue";
import FSView from "@/views/FSView.vue";
import SetTokenView from "@/views/SetTokenView.vue";
import ProfileView from "@/views/ProfileView.vue";
import TFAView from "@/views/TFAView.vue";
import AdminView from "@/views/AdminView.vue";
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'home',
component: HomeView
path: "/",
name: "home",
component: HomeView,
},
{
path: '/profile',
name: 'profile',
component: ProfileView
path: "/profile",
name: "profile",
component: ProfileView,
},
{
path: '/profile/2fa-enable',
name: '2fa',
component: TFAView
path: "/profile/2fa-enable",
name: "2fa",
component: TFAView,
},
{
path: '/admin',
component: AdminView
path: "/admin",
component: AdminView,
},
{
path: '/about',
component: AboutView
path: "/about",
component: AboutView,
},
{
path: '/login',
name: 'login',
component: LoginView
path: "/login",
name: "login",
component: LoginView,
},
{
path: '/signup',
name: 'signup',
component: SignupView
path: "/signup",
name: "signup",
component: SignupView,
},
{
path: '/fs/:node_id',
name: 'fs',
component: FSView
path: "/fs/:node_id",
name: "fs",
component: FSView,
},
{
path: '/set_token',
component: SetTokenView
}
path: "/set_token",
component: SetTokenView,
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
history: createWebHistory(import.meta.env.BASE_URL),
routes,
});
export default router;

View File

@ -1,6 +0,0 @@
/* eslint-disable */
declare module '*.vue' {
import type { DefineComponent } from 'vue';
const component: DefineComponent<{}, {}, any>;
export default component;
}

View File

@ -1,16 +1,11 @@
<script setup lang="ts">
import { inject, onBeforeMount, ref } from 'vue';
import {
Responses,
check_token,
TokenInjectType,
Admin,
isErrorResponse
} from '@/api';
import { onBeforeRouteUpdate } from 'vue-router';
import router from '@/router';
import type { TokenInjectType } from "@/api";
import { inject, onBeforeMount, ref } from "vue";
import { Responses, check_token, Admin, isErrorResponse } from "@/api";
import { onBeforeRouteUpdate } from "vue-router";
import router from "@/router";
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
const jwt = inject<TokenInjectType>("jwt") as TokenInjectType;
const users = ref<Responses.Admin.GetUsersEntry[]>([]);
@ -25,7 +20,7 @@ async function updatePanel() {
if (!token) return;
const res = await Admin.get_users(token);
if (isErrorResponse(res)) return router.replace({ path: '/' });
if (isErrorResponse(res)) return router.replace({ path: "/" });
users.value = res.users;
}
@ -77,23 +72,23 @@ async function deleteUser(user: number) {
</tr>
<tr v-for="user in users" :key="user.id">
<td>{{ user.name }}</td>
<td>{{ user.gitlab ? 'Gitlab' : 'Password' }}</td>
<td>{{ user.gitlab ? "Gitlab" : "Password" }}</td>
<td>
<select @change="setRole(user.id, $event.target.value)">
<option value="0" :selected="user.role === 0 ? true : null">
<select @change="setRole(user.id, ($event.target as HTMLSelectElement).value)">
<option value="0" :selected="user.role === 0 ? true : undefined">
Disabled
</option>
<option value="1" :selected="user.role === 1 ? true : null">
<option value="1" :selected="user.role === 1 ? true : undefined">
User
</option>
<option value="2" :selected="user.role === 2 ? true : null">
<option value="2" :selected="user.role === 2 ? true : undefined">
Admin
</option>
</select>
</td>
<td v-if="user.gitlab"></td>
<td v-else>
{{ user.tfaEnabled ? 'Enabled' : 'Disabled' }}
{{ user.tfaEnabled ? "Enabled" : "Disabled" }}
</td>
<td>
<button v-if="user.tfaEnabled" @click="disableTfa(user.id)">

View File

@ -1,29 +1,24 @@
<script setup lang="ts">
import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router';
import { inject, onBeforeMount, ref } from 'vue';
import {
check_token,
FS,
Responses,
isErrorResponse,
TokenInjectType
} from '@/api';
import DirViewer from '@/components/FSView/DirViewer.vue';
import FileViewer from '@/components/FSView/FileViewer.vue';
import type { TokenInjectType } from "@/api";
import { onBeforeRouteUpdate, useRoute, useRouter } from "vue-router";
import { inject, onBeforeMount, ref } from "vue";
import { check_token, FS, Responses, isErrorResponse } from "@/api";
import DirViewer from "@/components/FSView/DirViewer.vue";
import FileViewer from "@/components/FSView/FileViewer.vue";
const router = useRouter();
const route = useRoute();
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
const jwt = inject<TokenInjectType>("jwt") as TokenInjectType;
const path = ref('');
const path = ref("");
const node = ref<Responses.FS.GetNodeResponse | null>(null);
async function fetch_node(node_id: number) {
const token = await check_token(jwt);
if (!token) return;
let [p, n] = [
const [p, n] = [
await FS.get_path(token, node_id),
await FS.get_node(token, node_id)
await FS.get_node(token, node_id),
];
if (isErrorResponse(p)) return gotoRoot();
if (isErrorResponse(n)) return gotoRoot();
@ -48,8 +43,8 @@ async function gotoRoot() {
if (isErrorResponse(rootRes)) return jwt.logout();
const root = rootRes.rootId;
await router.replace({
name: 'fs',
params: { node_id: root }
name: "fs",
params: { node_id: root },
});
}
</script>

View File

@ -1,12 +1,13 @@
<template><p></p></template>
<script setup lang="ts">
import { onBeforeRouteUpdate, useRouter } from 'vue-router';
import { inject, onBeforeMount } from 'vue';
import { FS, check_token, isErrorResponse, TokenInjectType } from '@/api';
import type { TokenInjectType } from "@/api";
import { onBeforeRouteUpdate, useRouter } from "vue-router";
import { inject, onBeforeMount } from "vue";
import { FS, check_token, isErrorResponse } from "@/api";
const router = useRouter();
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
const jwt = inject<TokenInjectType>("jwt") as TokenInjectType;
async function start_redirect() {
const token = await check_token(jwt);
@ -14,8 +15,8 @@ async function start_redirect() {
const root = await FS.get_root(token);
if (isErrorResponse(root)) return jwt.logout();
await router.replace({
name: 'fs',
params: { node_id: root.rootId }
name: "fs",
params: { node_id: root.rootId },
});
}

View File

@ -1,43 +1,44 @@
<script setup lang="ts">
import { ref, inject } from 'vue';
import { Auth, FS, isErrorResponse, TokenInjectType } from '@/api';
import { useRouter } from 'vue-router';
import type { TokenInjectType } from "@/api";
import { ref, inject } from "vue";
import { Auth, FS, isErrorResponse } from "@/api";
import { useRouter } from "vue-router";
const router = useRouter();
const username = ref('');
const password = ref('');
const otp = ref('');
const username = ref("");
const password = ref("");
const otp = ref("");
const error = ref('');
const error = ref("");
const requestOtp = ref(false);
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
const jwt = inject<TokenInjectType>("jwt") as TokenInjectType;
async function login() {
error.value = '';
if (username.value === '' || password.value === '') {
error.value = 'Email and/or Password missing';
error.value = "";
if (username.value === "" || password.value === "") {
error.value = "Email and/or Password missing";
return;
}
const res = await (requestOtp.value
? Auth.auth_login(username.value, password.value, otp.value)
: Auth.auth_login(username.value, password.value));
if (isErrorResponse(res)) error.value = 'Login failed: ' + res.message;
else if ('jwt' in res) {
if (isErrorResponse(res)) error.value = "Login failed: " + res.message;
else if ("jwt" in res) {
const root = await FS.get_root(res.jwt);
if (isErrorResponse(root)) {
error.value = 'Get root failed: ' + root.message;
error.value = "Get root failed: " + root.message;
return;
}
jwt.setToken(res.jwt);
await router.push({
name: 'fs',
params: { node_id: root.rootId }
name: "fs",
params: { node_id: root.rootId },
});
} else {
error.value = '';
error.value = "";
requestOtp.value = true;
}
}

View File

@ -1,22 +1,16 @@
<script setup lang="ts">
import { ref, inject, onBeforeMount } from 'vue';
import {
Auth,
User,
check_token,
isErrorResponse,
TokenInjectType,
Responses
} from '@/api';
import { onBeforeRouteUpdate } from 'vue-router';
import type { TokenInjectType } from "@/api";
import { ref, inject, onBeforeMount } from "vue";
import { Auth, User, check_token, isErrorResponse, Responses } from "@/api";
import { onBeforeRouteUpdate } from "vue-router";
const error = ref('');
const oldPw = ref('');
const newPw = ref('');
const newPw2 = ref('');
const error = ref("");
const oldPw = ref("");
const newPw = ref("");
const newPw2 = ref("");
const user = ref<Responses.User.UserInfoResponse | null>(null);
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
const jwt = inject<TokenInjectType>("jwt") as TokenInjectType;
onBeforeRouteUpdate(async () => {
await updateProfile();
@ -48,8 +42,8 @@ async function logoutAll() {
}
async function changePw() {
if (oldPw.value === '' || newPw.value === '' || newPw2.value === '') {
error.value = 'Password missing';
if (oldPw.value === "" || newPw.value === "" || newPw2.value === "") {
error.value = "Password missing";
return;
}
if (newPw.value !== newPw2.value) {
@ -60,7 +54,7 @@ async function changePw() {
if (!token) return;
const res = await Auth.change_password(oldPw.value, newPw.value, token);
if (isErrorResponse(res))
error.value = 'Password change failed: ' + res.message;
error.value = "Password change failed: " + res.message;
else jwt.logout();
}
@ -76,19 +70,11 @@ async function tfaDisable() {
<template v-if="user">
<div v-if="error !== ''" v-text="error"></div>
<div>User: {{ user.name }}</div>
<div>Signed in with {{ user.gitlab ? 'gitlab' : 'password' }}</div>
<div>Signed in with {{ user.gitlab ? "gitlab" : "password" }}</div>
<template v-if="!user.gitlab">
<div>
<input
type="password"
placeholder="Old password"
v-model="oldPw"
/>
<input
type="password"
placeholder="New password"
v-model="newPw"
/>
<input type="password" placeholder="Old password" v-model="oldPw" />
<input type="password" placeholder="New password" v-model="newPw" />
<input
type="password"
placeholder="Repeat new password"
@ -99,15 +85,11 @@ async function tfaDisable() {
<div>
<div>
2 Factor authentication:
{{ user.tfaEnabled ? 'Enabled' : 'Disabled' }}
{{ user.tfaEnabled ? "Enabled" : "Disabled" }}
</div>
<div>
<a href="#" v-if="user.tfaEnabled" @click="tfaDisable">
Disable
</a>
<router-link to="/profile/2fa-enable" v-else>
Enable
</router-link>
<a href="#" v-if="user.tfaEnabled" @click="tfaDisable"> Disable </a>
<router-link to="/profile/2fa-enable" v-else> Enable </router-link>
</div>
</div>
</template>

View File

@ -1,15 +1,15 @@
<script setup lang="ts">
import { inject } from 'vue';
import { TokenInjectType } from '@/api';
import { useRoute, useRouter } from 'vue-router';
import type { TokenInjectType } from "@/api";
import { inject } from "vue";
import { useRoute, useRouter } from "vue-router";
const router = useRouter();
const route = useRoute();
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
const jwt = inject<TokenInjectType>("jwt") as TokenInjectType;
if ('token' in route.query) jwt.setToken(route.query['token'] as string);
router.replace({ path: '/' });
if ("token" in route.query) jwt.setToken(route.query["token"] as string);
router.replace({ path: "/" });
</script>
<template>

View File

@ -1,15 +1,15 @@
<script setup lang="ts">
import { ref } from 'vue';
import { Auth, isErrorResponse } from '@/api';
import { ref } from "vue";
import { Auth, isErrorResponse } from "@/api";
const username = ref('');
const password = ref('');
const password2 = ref('');
const error = ref('');
const username = ref("");
const password = ref("");
const password2 = ref("");
const error = ref("");
async function signup() {
if (username.value === '' || password.value === '') {
error.value = 'Email and/or Password missing';
if (username.value === "" || password.value === "") {
error.value = "Email and/or Password missing";
return;
}
if (password.value !== password2.value) {
@ -18,8 +18,8 @@ async function signup() {
}
const res = await Auth.auth_signup(username.value, password.value);
error.value = isErrorResponse(res)
? 'Signup failed: ' + res.message
: 'Signup successful, please wait till an admin unlocks your account.';
? "Signup failed: " + res.message
: "Signup successful, please wait till an admin unlocks your account.";
}
</script>

View File

@ -1,31 +1,32 @@
<script setup lang="ts">
import { ref, inject } from 'vue';
import { Auth, check_token, isErrorResponse, TokenInjectType } from '@/api';
import type { TokenInjectType } from "@/api";
import { ref, inject } from "vue";
import { Auth, check_token, isErrorResponse } from "@/api";
enum state {
SELECT,
MAIL,
TOTP
TOTP,
}
const currentState = ref<state>(state.SELECT);
const error = ref('');
const qrImage = ref('');
const secret = ref('');
const code = ref('');
const error = ref("");
const qrImage = ref("");
const secret = ref("");
const code = ref("");
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
const jwt = inject<TokenInjectType>("jwt") as TokenInjectType;
async function selectMail() {
const token = await check_token(jwt);
if (!token) return;
error.value = 'Working...';
error.value = "Working...";
const res = await Auth.tfa_setup(true, token);
if (isErrorResponse(res))
error.value = 'Failed to select 2fa type: ' + res.message;
error.value = "Failed to select 2fa type: " + res.message;
else {
error.value = '';
error.value = "";
currentState.value = state.MAIL;
}
}
@ -33,14 +34,14 @@ async function selectMail() {
async function selectTotp() {
const token = await check_token(jwt);
if (!token) return;
error.value = 'Working...';
error.value = "Working...";
const res = await Auth.tfa_setup(false, token);
if (isErrorResponse(res))
error.value = 'Failed to select 2fa type: ' + res.message;
error.value = "Failed to select 2fa type: " + res.message;
else {
qrImage.value = res.qrCode;
secret.value = res.secret;
error.value = '';
error.value = "";
currentState.value = state.TOTP;
}
}
@ -48,14 +49,14 @@ async function selectTotp() {
async function submit() {
const token = await check_token(jwt);
if (!token) return;
error.value = 'Working...';
error.value = "Working...";
const res = await Auth.tfa_complete(
currentState.value === state.MAIL,
code.value,
token
);
if (isErrorResponse(res))
error.value = 'Failed to submit code: ' + res.message;
error.value = "Failed to submit code: " + res.message;
else jwt.logout();
}
</script>

View File

@ -0,0 +1,8 @@
{
"extends": "@vue/tsconfig/tsconfig.node.json",
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*"],
"compilerOptions": {
"composite": true,
"types": ["node"]
}
}

View File

@ -1,32 +1,19 @@
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"useDefineForClassFields": true,
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"strictPropertyInitialization": false,
"baseUrl": ".",
"types": ["webpack-env"],
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"strictPropertyInitialization": false,
"paths": {
"@/*": ["src/*"]
"@/*": ["./src/*"]
}
},
"lib": ["esnext", "dom", "dom.iterable", "scripthost"]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": ["node_modules"]
"references": [
{
"path": "./tsconfig.config.json"
}
]
}

14
frontend/vite.config.ts Normal file
View File

@ -0,0 +1,14 @@
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
});

View File

@ -1,12 +0,0 @@
const { defineConfig } = require('@vue/cli-service');
module.exports = defineConfig({
transpileDependencies: true,
configureWebpack: {
resolve: {
fallback: {
crypto: false,
stream: require.resolve('stream-browserify')
}
}
}
});

File diff suppressed because it is too large Load Diff