Client rescaffolded

This commit is contained in:
Fergal Moran
2020-09-04 19:57:33 +01:00
parent 1b47b257d9
commit dc0d682572
165 changed files with 1453 additions and 11665 deletions

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# bitchmin
Just some a website for managing & monitoring bits of my home

View File

@@ -1,5 +1,21 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 100

View File

@@ -1,29 +1,53 @@
module.exports = {
root: true,
env: {
node: true
node: true,
},
extends: [
'plugin:vue/essential',
'@vue/standard',
'@vue/typescript/recommended'
"plugin:vue/essential",
"eslint:recommended",
"@vue/typescript/recommended"
],
parserOptions: {
ecmaVersion: 2020
ecmaVersion: 2020,
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
quotes: [2, 'single', { avoidEscape: true }],
'@typescript-eslint/quotes': [2, 'single', { avoidEscape: true }],
},
overrides: [
{
files: [
'**/__tests__/*.{j,t}s?(x)',
'**/tests/unit/**/*.spec.{j,t}s?(x)'
'**/tests/unit/**/*.spec.{j,t}s?(x)',
],
env: {
mocha: true
}
}
]
}
mocha: true,
},
},
{
files: [
'**/__tests__/*.{j,t}s?(x)',
'**/tests/unit/**/*.spec.{j,t}s?(x)',
],
env: {
mocha: true,
},
},
],
extends: [
'plugin:@typescript-eslint/recommended',
'eslint:recommended',
'prettier/@typescript-eslint',
'plugin:vue/essential',
'@vue/typescript/recommended',
'@vue/airbnb',
],
};

View File

@@ -0,0 +1,4 @@
{
"tabWidth": 4,
"singleQuote": true
}

View File

@@ -1,6 +1,5 @@
FROM node:14-stretch as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install

View File

@@ -1,34 +1,3 @@
# bitchmin-client
## Project setup
```
yarn install
```
### Compiles and hot-reloads for development
```
yarn serve
```
### Compiles and minifies for production
```
yarn build
```
### Run your unit tests
```
yarn test:unit
```
### Run your end-to-end tests
```
yarn test:e2e
```
### Lints and fixes files
```
yarn lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
Vue web UI

View File

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

0
client/build.sh → bitchmin-client/build.sh Executable file → Normal file
View File

View File

@@ -10,13 +10,24 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"@types/jwt-decode": "^2.2.1",
"axios": "^0.20.0",
"axios-auth-refresh": "^3.0.0",
"core-js": "^3.6.5",
"dayjs": "^1.8.35",
"decko": "^1.2.0",
"ee-first": "^1.1.1",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.4",
"jwt-decode": "^2.2.0",
"prettier": "^2.1.1",
"register-service-worker": "^1.7.1",
"vue": "^2.6.11",
"vue-class-component": "^7.2.3",
"vue-property-decorator": "^8.4.2",
"vue-router": "^3.2.0",
"vue-toasted": "^1.1.28",
"vuetify": "^2.2.11",
"vuex": "^3.4.0"
},
"devDependencies": {
@@ -33,6 +44,7 @@
"@vue/cli-plugin-unit-mocha": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/eslint-config-airbnb": "^5.0.2",
"@vue/eslint-config-standard": "^5.1.2",
"@vue/eslint-config-typescript": "^5.0.2",
"@vue/test-utils": "^1.0.3",
@@ -44,8 +56,11 @@
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^6.2.2",
"node-sass": "^4.12.0",
"sass": "^1.19.0",
"sass-loader": "^8.0.2",
"typescript": "~3.9.3",
"vue-template-compiler": "^2.6.11"
"vue-cli-plugin-vuetify": "~2.0.7",
"vue-template-compiler": "^2.6.11",
"vuetify-loader": "^1.3.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 799 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.00251 14.9297L0 1.07422H6.14651L8.00251 4.27503L9.84583 1.07422H16L8.00251 14.9297Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 215 B

View File

@@ -1,17 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<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">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<meta http-equiv="X-UA-Compatible"
content="IE=edge">
<meta name="viewport"
content="width=device-width,initial-scale=1.0">
<link rel="icon"
href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css">
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
<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>
</body>
</html>

View File

@@ -1,32 +1,41 @@
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
<v-app id="bitchmin">
<TopBarNav v-if="isAuthenticated"/>
<SideBarNav v-if="isAuthenticated" />
<v-main>
<v-container fluid>
<router-view></router-view>
</v-container>
</v-main>
<Footer />
</v-app>
</template>
<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import TopBarNav from '@/components/TopBarNav.vue'; // @ is an alias to /src
import SideBarNav from '@/components/SideBarNav.vue'; // @ is an alias to /src
import Footer from '@/components/Footer.vue'; // @ is an alias to /src
@Component({
components: {
TopBarNav,
SideBarNav,
Footer,
},
})
export default class App extends Vue {
async mounted() {
this.$store.dispatch('loadInitialState');
}
get isAuthenticated() {
return this.$store.getters.isLoggedIn;
}
}
#nav {
padding: 30px;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
</script>
<style>
#keep .v-navigation-drawer__border {
display: none;
}
</style>

View File

@@ -9,7 +9,9 @@ import store from '@/store';
export class Api {
refreshing = false;
api: AxiosInstance;
tokenRefreshCallback = (failedRequest: any) => {
this.refreshing = true;
return this.api
@@ -19,14 +21,13 @@ export class Api {
store.dispatch;
localStorage.setItem(
'access_token',
tokenRefreshResponse.data.accessToken
tokenRefreshResponse.data.accessToken,
);
localStorage.setItem(
'refresh_token',
tokenRefreshResponse.data.refreshToken
tokenRefreshResponse.data.refreshToken,
);
failedRequest.response.config.headers['Authorization'] =
'Bearer ' + tokenRefreshResponse.data.accessToken;
failedRequest.response.config.headers.Authorization = `Bearer ${tokenRefreshResponse.data.accessToken}`;
store.dispatch('updateToken', {
accessToken: tokenRefreshResponse.data.accessToken,
refreshToken: tokenRefreshResponse.data.refreshToken,
@@ -48,21 +49,20 @@ export class Api {
this.put = this.put.bind(this);
this.patch = this.patch.bind(this);
}
_getAccessToken = () =>
this.refreshing
_getAccessToken = () => (this.refreshing
? localStorage.getItem('refresh_token')
: localStorage.getItem('access_token');
: localStorage.getItem('access_token'));
private __setupInterceptors(): void {
// Use interceptor to inject the token to requests
this.api.interceptors.request.use((request) => {
request.headers[
'Authorization'
] = `Bearer ${this._getAccessToken()}`;
request.headers.Authorization = `Bearer ${this._getAccessToken()}`;
return request;
});
createAuthRefreshInterceptor(this.api, this.tokenRefreshCallback);
}
/**
* Get Uri
*
@@ -96,7 +96,7 @@ export class Api {
*
*/
public request<T, R = AxiosResponse<T>>(
config: AxiosRequestConfig
config: AxiosRequestConfig,
): Promise<R> {
return this.api.request(config);
}
@@ -114,7 +114,7 @@ export class Api {
*/
public get<T, R = AxiosResponse<T>>(
url: string,
config?: AxiosRequestConfig
config?: AxiosRequestConfig,
): Promise<R> {
return this.api.get(url, config);
}
@@ -132,7 +132,7 @@ export class Api {
*/
public delete<T, R = AxiosResponse<T>>(
url: string,
config?: AxiosRequestConfig
config?: AxiosRequestConfig,
): Promise<R> {
return this.api.delete(url, config);
}
@@ -150,7 +150,7 @@ export class Api {
*/
public head<T, R = AxiosResponse<T>>(
url: string,
config?: AxiosRequestConfig
config?: AxiosRequestConfig,
): Promise<R> {
return this.api.head(url, config);
}
@@ -172,7 +172,7 @@ export class Api {
public post<T, B, R = AxiosResponse<T>>(
url: string,
data?: B,
config?: AxiosRequestConfig
config?: AxiosRequestConfig,
): Promise<R> {
return this.api.post(url, data, config);
}
@@ -193,7 +193,7 @@ export class Api {
public put<T, B, R = AxiosResponse<T>>(
url: string,
data?: B,
config?: AxiosRequestConfig
config?: AxiosRequestConfig,
): Promise<R> {
return this.api.put(url, data, config);
}
@@ -214,7 +214,7 @@ export class Api {
public patch<T, B, R = AxiosResponse<T>>(
url: string,
data?: B,
config?: AxiosRequestConfig
config?: AxiosRequestConfig,
): Promise<R> {
return this.api.patch(url, data, config);
}

View File

@@ -0,0 +1,23 @@
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import { AuthResult } from '@/models/';
import { UserLoginModel } from '@/models/userLoginModel';
import store from '@/store';
import { apiConfig } from './config';
import { Api } from './apiBase';
export class AuthApi extends Api {
constructor(config: AxiosRequestConfig) {
// NEVER FORGET THE SUPER
super(config);
}
public login(user: UserLoginModel): Promise<AxiosResponse<AuthResult>> {
return this.post('/auth/login/', user);
}
public register(user: UserLoginModel) {
return this.post('/auth/register/', user);
}
}
export const authApi = new AuthApi(apiConfig);

View File

@@ -0,0 +1,20 @@
import * as qs from 'qs';
export const API_BASE = process.env.VUE_APP_API_SERVER;
export const apiConfig = {
returnRejectedPromiseOnError: true,
withCredentials: true,
credentials: 'same-origin',
timeout: 30000,
baseURL: API_BASE,
headers: {
common: {
'Cache-Control': 'no-cache, no-store, must-revalidate',
Pragma: 'no-cache',
'Content-Type': 'application/json',
Accept: 'application/json',
},
},
paramsSerializer: (params: any) => qs.stringify(params, { indices: false }),
};

View File

@@ -0,0 +1,19 @@
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios';
import { Api } from '@/api/apiBase';
import { apiConfig } from '@/api/config';
import { ApiResult, DataApiResult } from '@/api/apiResult';
import { User } from '@/models';
export class DebugApi extends Api {
constructor(config: AxiosRequestConfig) {
// NEVER FORGET THE SUPER
super(config);
}
public async getDebug(): Promise<string> {
const result = await this.get<DataApiResult<string>>('/debug');
return result.data.payload || '';
}
}
export const debugApi = new DebugApi(apiConfig);

View File

@@ -0,0 +1,80 @@
import { Api } from '@/api/apiBase';
import { AxiosRequestConfig, AxiosResponse } from 'axios';
import { apiConfig } from '@/api/config';
import { ApiResult, DataApiResult } from '@/api/apiResult';
import { DnsRecord } from '@/models/dnsRecord';
export class DnsApi extends Api {
constructor(config: AxiosRequestConfig) {
// NEVER FORGET THE SUPER
super(config);
}
public async updateDnsRecord(
hostName: string,
ipAddress: string,
): Promise<DataApiResult<DnsRecord>> {
const result = await this.post<
ApiResult,
any,
AxiosResponse<DataApiResult<DnsRecord>>
>('/dns/', {
host: hostName,
ip: ipAddress,
});
return result.data;
}
public async deleteDnsRecord(
hostName: string,
): Promise<number> {
const result = await this.delete(`/dns/?host=${hostName}`);
return result.status;
}
public async refreshDnsRecord(
hostName: string,
ip: string,
): Promise<DataApiResult<DnsRecord>> {
const result = await this.post<
ApiResult,
any,
AxiosResponse<DataApiResult<DnsRecord>>
>('/dns/refresh', {
host: hostName,
ip,
});
return result.data;
}
public async verifyDnsRecord(
hostName: string,
ip: string,
): Promise<DataApiResult<string>> {
const result = await this.post<
ApiResult,
any,
AxiosResponse<DataApiResult<string>>
>('/dns/check/', {
host: hostName,
ip,
});
return result.data;
}
public async getDnsRecords(): Promise<DnsRecord[]> {
const result = await this.get<DnsRecord[]>('/dns/list');
return result.data;
}
public async getMyIP(): Promise<string> {
const result = await this.get<DataApiResult<string>>('/dns/myip');
return result.data.payload || 'Unknown IP';
}
public async getHeaders(): Promise<any> {
const result = await this.get<DataApiResult<any>>('/dns/headers');
return result.data.payload;
}
}
export const dnsApi = new DnsApi(apiConfig);

View File

@@ -4,4 +4,6 @@ import { dnsApi } from './dnsApi';
import { lightsApi } from './lightsApi';
import { debugApi } from './debugApi';
export { authApi, userApi, dnsApi, lightsApi, debugApi };
export {
authApi, userApi, dnsApi, lightsApi, debugApi,
};

View File

@@ -0,0 +1,51 @@
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios';
import { Api } from '@/api/apiBase';
import { apiConfig } from '@/api/config';
import { Light } from '@/models';
import { ApiResult, DataApiResult } from './apiResult';
export class LightsApi extends Api {
constructor(config: AxiosRequestConfig) {
// NEVER FORGET THE SUPER
super(config);
}
async getLights(): Promise<Light[]> {
const lights = await this.get<DataApiResult<Light[]>>(
'/lights/getlights',
);
return lights.data.payload || [];
}
async changeBrightness(
lightId: number,
brightness: number,
): Promise<boolean> {
const result = await this.post<
ApiResult,
any,
AxiosResponse<ApiResult>
>('/lights/setbrightness', {
lightId,
brightness,
});
return result.data.status === 'success';
}
async changeColour(
lightId: number,
colour: string,
): Promise<boolean> {
const result = await this.post<
ApiResult,
any,
AxiosResponse<ApiResult>
>('/lights/changecolour', {
lightId,
rgbColour: colour,
});
return result.data.status === 'success';
}
}
export const lightsApi = new LightsApi(apiConfig);

View File

@@ -0,0 +1,19 @@
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios';
import { Api } from '@/api/apiBase';
import { apiConfig } from '@/api/config';
import { ApiResult, DataApiResult } from '@/api/apiResult';
import { User } from '@/models';
export class UserApi extends Api {
constructor(config: AxiosRequestConfig) {
// NEVER FORGET THE SUPER
super(config);
}
public async getUser(): Promise<User> {
const result = await this.get<DataApiResult<User>>('/user');
return result.data.payload || { fullName: '' };
}
}
export const userApi = new UserApi(apiConfig);

View File

Before

Width:  |  Height:  |  Size: 539 B

After

Width:  |  Height:  |  Size: 539 B

View File

@@ -45,10 +45,13 @@
</template>
<script lang="ts">
import { Component, Prop, PropSync, Vue } from 'vue-property-decorator';
import {
Component, Prop, PropSync, Vue,
} from 'vue-property-decorator';
import { dnsApi } from '@/api';
import { DnsRecord } from '@/models/interfaces/dnsRecord';
import { DnsRecord } from '@/models/dnsRecord';
import dayjs from 'dayjs';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import relativeTime from 'dayjs/plugin/relativeTime';
import localizedFormat from 'dayjs/plugin/localizedFormat';
@@ -70,6 +73,7 @@ export default class DnsRecordsList extends Vue {
public records!: DnsRecord[];
private callInProgress = false;
errorMessage = '';
async refreshRecord(host: DnsRecord) {
@@ -99,13 +103,12 @@ export default class DnsRecordsList extends Vue {
const result = await dnsApi.deleteDnsRecord(record.host);
if (result === 200) {
Vue.toasted.success('Record deleted successfully');
this.records = this.records.filter((t) => {
return t.host !== record.host;
});
this.records = this.records.filter((t) => t.host !== record.host);
console.log('DnsRecordsList', 'delete', this.records);
}
this.callInProgress = false;
}
mounted() {
dayjs.extend(localizedFormat);
console.log('DnsRecordsList', 'mounded_after', this.records);

View File

@@ -0,0 +1,99 @@
<template>
<v-card class="mx-auto" outlined>
<template slot="progress">
<v-progress-linear color="deep-purple" height="10" indeterminate></v-progress-linear>
</template>
<v-card-title>Add New Host</v-card-title>
<v-card-text>
<v-row align="start" justify="start" class="mx-0">
<v-form ref="form" v-model="valid" :lazy-validation="lazy">
<v-text-field
v-model="hostName"
:rules="hostNameRules"
label="Host Name"
required
></v-text-field>
<v-text-field
v-model="ipAddress"
:rules="ipAddressRules"
label="IP Address"
required
></v-text-field>
<v-btn color="warning" :disabled="!valid" @click="processUpdate">Add record</v-btn>
</v-form>
</v-row>
</v-card-text>
</v-card>
</template>
<script lang="ts">
import { Component, PropSync, Vue } from 'vue-property-decorator';
import { dnsApi } from '@/api';
import { DnsRecord } from '@/models/dnsRecord';
import { DataApiResult } from '@/api/apiResult';
@Component({
name: 'DnsUpdateForm',
})
export default class DnsUpdateForm extends Vue {
msg = '';
error = '';
valid = true;
lazy = false;
hostName = '';
hostNameRules = [
(v: string) => !!v || 'Host name is required',
(v: string) => (v && v.length < 253) || 'Hostname cannot exceed 253 characters',
];
ipAddress = '';
ipAddressRules = [
(v: string) => !!v || 'IP address is required',
(v: string) => /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(
v,
) || 'Invalid IP Address',
(v: string) => (v && v.length < 16) || 'IP address cannot exceed 16 characters',
];
@PropSync('inrecords')
public records!: DnsRecord[];
validate() {
// this.$refs.form.validate();
}
processUpdate() {
dnsApi
.updateDnsRecord(this.hostName, this.ipAddress)
.then((r: DataApiResult<DnsRecord>) => {
if (r.status === 'success') {
this.error = '';
Vue.toasted.success('Update successful');
if (r.payload) {
this.records.unshift(r.payload);
this.$emit('update:inrecords', this.records);
}
this.ipAddress = '';
this.hostName = '';
} else {
this.error = 'Unable to add DNS record';
}
})
.catch((e: any) => {
console.log('DnsUpdateForm', 'error', e);
if (e.response && e.response.data.payload) {
this.error = e.response.data.payload;
} else {
this.error = e;
}
});
}
}
</script>

View File

@@ -1,13 +1,15 @@
<template>
<footer class="footer">
<div class="d-sm-flex justify-content-center justify-content-sm-between">
<span class="text-muted text-center text-sm-left d-block d-sm-inline-block">
<v-footer padless>
<v-col
class="text-center"
cols="12"
>
Brought to you with
<i class="mdi mdi-heart text-danger"></i> by
<a href="https://podnoms.com/" target="_blank">PodNoms</a>.
</span>
</div>
</footer>
</v-col>
</v-footer>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';

View File

@@ -1,64 +1,153 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
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>.
<v-container>
<v-row class="text-center">
<v-col cols="12">
<v-img
:src="require('../assets/logo.svg')"
class="my-3"
contain
height="200"
/>
</v-col>
<v-col class="mb-4">
<h1 class="display-2 font-weight-bold mb-3">
Welcome to Vuetify
</h1>
<p class="subheading font-weight-regular">
For help and collaboration with other Vuetify developers,
<br>please join our online
<a
href="https://community.vuetifyjs.com"
target="_blank"
>Discord Community</a>
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa" target="_blank" rel="noopener">pwa</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-unit-mocha" target="_blank" rel="noopener">unit-mocha</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-e2e-cypress" target="_blank" rel="noopener">e2e-cypress</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-typescript" target="_blank" rel="noopener">typescript</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><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></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><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></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</v-col>
<v-col
class="mb-5"
cols="12"
>
<h2 class="headline font-weight-bold mb-3">
What's next?
</h2>
<v-row justify="center">
<a
v-for="(next, i) in whatsNext"
:key="i"
:href="next.href"
class="subheading mx-3"
target="_blank"
>
{{ next.text }}
</a>
</v-row>
</v-col>
<v-col
class="mb-5"
cols="12"
>
<h2 class="headline font-weight-bold mb-3">
Important Links
</h2>
<v-row justify="center">
<a
v-for="(link, i) in importantLinks"
:key="i"
:href="link.href"
class="subheading mx-3"
target="_blank"
>
{{ link.text }}
</a>
</v-row>
</v-col>
<v-col
class="mb-5"
cols="12"
>
<h2 class="headline font-weight-bold mb-3">
Ecosystem
</h2>
<v-row justify="center">
<a
v-for="(eco, i) in ecosystem"
:key="i"
:href="eco.href"
class="subheading mx-3"
target="_blank"
>
{{ eco.text }}
</a>
</v-row>
</v-col>
</v-row>
</v-container>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
import Vue from 'vue';
@Component
export default class HelloWorld extends Vue {
@Prop() private msg!: string;
}
export default Vue.extend({
name: 'HelloWorld',
data: () => ({
ecosystem: [
{
text: 'vuetify-loader',
href: 'https://github.com/vuetifyjs/vuetify-loader',
},
{
text: 'github',
href: 'https://github.com/vuetifyjs/vuetify',
},
{
text: 'awesome-vuetify',
href: 'https://github.com/vuetifyjs/awesome-vuetify',
},
],
importantLinks: [
{
text: 'Documentation',
href: 'https://vuetifyjs.com',
},
{
text: 'Chat',
href: 'https://community.vuetifyjs.com',
},
{
text: 'Made with Vuetify',
href: 'https://madewithvuejs.com/vuetify',
},
{
text: 'Twitter',
href: 'https://twitter.com/vuetifyjs',
},
{
text: 'Articles',
href: 'https://medium.com/vuetify',
},
],
whatsNext: [
{
text: 'Explore components',
href: 'https://vuetifyjs.com/components/api-explorer',
},
{
text: 'Select a layout',
href: 'https://vuetifyjs.com/getting-started/pre-made-layouts',
},
{
text: 'Frequently Asked Questions',
href: 'https://vuetifyjs.com/getting-started/frequently-asked-questions',
},
],
}),
});
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

View File

@@ -30,6 +30,7 @@ import { Component, Vue } from 'vue-property-decorator';
@Component
export default class SideBarNav extends Vue {
drawer = null;
items = [
{ title: 'Debug', icon: 'mdi-bug', route: 'debug' },
{ title: 'DNS Config', icon: 'mdi-dns', route: 'bitchns' },

View File

@@ -0,0 +1,23 @@
<template>
<v-app-bar app clipped-left color="#90CAF9">
<v-app-bar-nav-icon @click="drawer = !drawer"></v-app-bar-nav-icon>
<span class="title ml-3 mr-5">
Bitch&nbsp;
<span class="font-weight-light">Mints</span>
</span>
<v-spacer></v-spacer>
<v-btn icon>
<v-icon @click="signout">mdi-exit-to-app</v-icon>
</v-btn>
</v-app-bar>
</template>
<script>
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class TopBarNav extends Vue {
signout() {
this.$store.dispatch('logout').then(() => this.$router.push('/login'));
}
}
</script>

View File

@@ -1,13 +1,22 @@
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import router from './router'
import store from './store'
import Vue from 'vue';
import App from './App.vue';
import './registerServiceWorker';
import router from './router';
import store from './store';
import vuetify from './plugins/vuetify';
import Toasted from 'vue-toasted';
Vue.config.productionTip = false
Vue.config.productionTip = false;
Vue.use(Toasted, {
theme: 'toasted-primary',
position: 'top-right',
duration: 2000,
});
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
vuetify,
render: (h) => h(App),
}).$mount('#app');

View File

@@ -4,3 +4,4 @@ export * from './userLoginModel';
export * from './user';
export * from './user';
export * from './light';
export * from './dnsRecord';

View File

@@ -0,0 +1,6 @@
import Vue from 'vue';
import Vuetify from 'vuetify/lib';
Vue.use(Vuetify);
export default new Vuetify({});

View File

@@ -1,32 +1,32 @@
/* eslint-disable no-console */
import { register } from 'register-service-worker'
import { register } from 'register-service-worker';
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready () {
ready() {
console.log(
'App is being served from cache by a service worker.\n' +
'For more details, visit https://goo.gl/AFskqB'
)
'App is being served from cache by a service worker.\n'
+ 'For more details, visit https://goo.gl/AFskqB',
);
},
registered () {
console.log('Service worker has been registered.')
registered() {
console.log('Service worker has been registered.');
},
cached () {
console.log('Content has been cached for offline use.')
cached() {
console.log('Content has been cached for offline use.');
},
updatefound () {
console.log('New content is downloading.')
updatefound() {
console.log('New content is downloading.');
},
updated () {
console.log('New content is available; please refresh.')
updated() {
console.log('New content is available; please refresh.');
},
offline () {
console.log('No internet connection found. App is running in offline mode.')
offline() {
console.log('No internet connection found. App is running in offline mode.');
},
error (error) {
console.error('Error during service worker registration:', error)
}
})
error(error) {
console.error('Error during service worker registration:', error);
},
});
}

View File

@@ -1,29 +1,97 @@
import Vue from 'vue'
import VueRouter, { RouteConfig } from 'vue-router'
import Home from '../views/Home.vue'
import Vue from 'vue';
import VueRouter, { RouteConfig } from 'vue-router';
import store from '@/store';
import Home from '../views/Home.vue';
import Login from '../views/Login.vue';
import Lights from '../views/Lights.vue';
import Debug from '../views/Debug.vue';
import BitchNS from '../views/BitchNS.vue';
import JwtDecoder from '../views/JwtDecoder.vue';
import MyIp from '../views/MyIp.vue';
Vue.use(VueRouter)
Vue.use(VueRouter);
const routes: Array<RouteConfig> = [
{
path: '/',
name: 'Home',
component: Home
component: Home,
meta: {
requiresAuth: true,
},
},
{
path: '/login',
name: 'Login',
component: Login,
meta: {
requiresAuth: false,
},
},
{
path: '/bitchns',
name: 'BitchNS',
component: BitchNS,
meta: {
requiresAuth: true,
},
},
{
path: '/jwt',
name: 'JwtDecoder',
component: JwtDecoder,
},
{
path: '/myip',
name: 'MyIP',
component: MyIp,
},
{
path: '/debug',
name: 'Debug',
component: Debug,
meta: {
requiresAuth: true,
},
},
{
path: '/lights',
name: 'Lights',
component: Lights,
meta: {
requiresAuth: true,
},
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'),
meta: {
requiresAuth: true,
},
},
];
const router = new VueRouter({
// abstract: true,
mode: 'history',
base: process.env.BASE_URL,
routes
})
routes,
});
export default router
router.beforeEach((to, from, next) => {
if (to.name === 'Home') {
console.log('index', 'Home Route Called', store.getters.isLoggedIn);
}
if (to.matched.some((record) => record.meta.requiresAuth)) {
if (store.getters.isLoggedIn) {
next();
return;
}
next('/login');
} else {
next();
}
});
export default router;

View File

@@ -1,4 +1,4 @@
import Vue, { VNode } from 'vue'
import Vue, { VNode } from 'vue';
declare global {
namespace JSX {

View File

@@ -1,4 +1,5 @@
declare module '*.vue' {
import Vue from 'vue'
export default Vue
import Vue from 'vue';
export default Vue;
}

View File

@@ -1,15 +1,122 @@
import Vue from 'vue'
import Vuex from 'vuex'
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)
import { authApi, userApi } from '@/api';
import { UserLoginModel } from '@/models';
Vue.use(Vuex);
const isObjectEmpty = (object: Record<string, any>) => {
let isEmpty = true;
for (const keys in object) {
isEmpty = false;
break;
}
return isEmpty;
};
export default new Vuex.Store({
state: {
status: '',
accessToken: localStorage.getItem('access_token') || '',
refreshToken: localStorage.getItem('refresh_token') || '',
user: {},
},
mutations: {
authRequest(state) {
state.status = 'loading';
},
loadUser(state) {
state.status = 'loading';
},
loadUserSuccess(state, { user }) {
state.status = 'success';
state.user = user;
},
authError(state) {
state.status = 'error';
},
authSuccess(state, { user, accessToken, refreshToken }) {
state.status = 'success';
state.accessToken = accessToken;
state.refreshToken = refreshToken;
state.user = user;
},
logout(state) {
state.status = '';
state.accessToken = '';
state.refreshToken = '';
state.user = {};
},
updateToken(state, { accessToken, refreshToken }) {
console.log('STORE', 'UpdatingTokens');
state.accessToken = accessToken;
state.refreshToken = refreshToken;
},
},
actions: {
},
modules: {
loadInitialState({ commit }) {
console.log('index', 'loadInitialState', 'Starting');
return new Promise((resolve, reject) => {
console.log('index', 'loadInitialState', 'Resolving');
// if we have a JWT but don't have a user, we should try to load the user
if (
this.state.accessToken
&& (!this.state.user || isObjectEmpty(this.state.user))
) {
console.log('index', 'loadInitialState', 'Starting');
commit('loadUser');
userApi.getUser().then((resp) => {
console.log('index', 'loadInitialState', 'Done', resp);
commit('loadUserSuccess', {
user: resp,
});
resolve(resp);
});
} else {
resolve({});
}
})
});
},
login({ commit }, user: UserLoginModel) {
return new Promise((resolve, reject) => {
console.log('store', 'login_start');
commit('refreshToken');
authApi
.login(user)
.then((resp) => {
localStorage.setItem(
'access_token',
resp.data.accessToken,
);
localStorage.setItem(
'refresh_token',
resp.data.refreshToken,
);
commit('authSuccess', {
user: resp.data.user,
accessToken: resp.data.accessToken,
refreshToken: resp.data.refreshToken,
});
resolve(resp);
})
.catch((err) => {
commit('authError');
localStorage.removeItem('token');
reject(err);
});
});
},
logout({ commit }) {
return new Promise((resolve, reject) => {
commit('logout');
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
resolve();
});
},
},
getters: {
isLoggedIn: (state) => !!state.accessToken,
authStatus: (state) => state.status,
},
});

View File

@@ -0,0 +1,22 @@
import jwtDecode from 'jwt-decode';
const isValidJwt = (jwt: string) => {
if (!jwt || jwt.split('.').length < 3) {
return false;
}
const data = JSON.parse(atob(jwt.split('.')[1]));
const exp = new Date(data.exp * 1000); // JS deals with dates in milliseconds since epoch
const now = new Date();
return now < exp;
};
const decodeJwtToken = (jwt: string) => {
if (jwt) {
console.log('JwtDecoder', 'tokenChanged', jwt);
const decoded = jwtDecode(jwt);
console.log('JwtDecoder', 'decoded', decoded);
return decoded;
}
};
export { isValidJwt, decodeJwtToken };

View File

@@ -0,0 +1,8 @@
const titleCase = (str: string) => str
.split(' ')
.map(
([firstChar, ...rest]) => firstChar.toUpperCase() + rest.join('').toLowerCase(),
)
.join(' ');
export { titleCase };

View File

@@ -26,7 +26,7 @@ import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src
import DnsRecordsList from '@/components/Dns/DnsRecordsList.vue';
import DnsUpdateForm from '@/components/Dns/DnsUpdateForm.vue';
import { DnsRecord } from '@/models/interfaces/dnsRecord';
import { DnsRecord } from '@/models';
import { dnsApi } from '@/api';
@Component({
@@ -38,6 +38,7 @@ import { dnsApi } from '@/api';
})
export default class BitchNS extends Vue {
dnsRecords: DnsRecord[] = [];
async mounted() {
this.dnsRecords = await dnsApi.getDnsRecords();
}

View File

@@ -1,18 +1,25 @@
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
</div>
<section>
<v-parallax src="/images/bitchmints.jpg" height="1100">
<v-layout column align-center justify-center class="white--text">
<h1 class="white--text mb-2 display-1 text-xs-center"
style="font-weight: 900; text-shadow: 3px 2px #000000">
BitchMints Admin
</h1>
</v-layout>
</v-parallax>
</section>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import HelloWorld from '@/components/HelloWorld.vue' // @ is an alias to /src
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src
@Component({
components: {
HelloWorld
}
HelloWorld,
},
})
export default class Home extends Vue {}
export default class Home extends Vue {
}
</script>

View File

@@ -74,8 +74,11 @@ import { decodeJwtToken, titleCase } from '@/utils';
})
export default class JwtDecoder extends Vue {
token = '';
error = '';
decoded: any = null;
tokenChanged() {
this.error = '';
this.decoded = null;

View File

@@ -48,17 +48,14 @@
/* eslint-disable no-var */
declare var require: (moduleId: string) => any;
/* eslint-disable @typescript-eslint/no-var-requires */
var colors = require('vue-color');
import { Component, Vue } from 'vue-property-decorator';
import { lightsApi } from '@/api';
import { Light } from '@/models/interfaces';
import { Light } from '@/models';
import { debounce } from 'decko';
@Component({
components: {
'compact-picker': colors.Compact,
},
})
export default class Lights extends Vue {
error = '';

View File

@@ -0,0 +1,80 @@
<template>
<v-row align="center" justify="center">
<v-col cols="12" sm="8" md="4">
<v-card class="elevation-12">
<v-toolbar color="primary" dark flat>
<v-toolbar-title>Login form</v-toolbar-title>
<v-spacer></v-spacer>
<v-tooltip bottom>
<template v-slot:activator="{ on }">
<v-btn :href="source" icon large target="_blank" v-on="on">
<v-icon>mdi-code-tags</v-icon>
</v-btn>
</template>
<span>Source</span>
</v-tooltip>
</v-toolbar>
<v-card-text>
<v-form>
<v-text-field
label="Login"
name="login"
prepend-icon="mdi-account"
placeholder="Email address"
v-model="email"
type="text"
></v-text-field>
<v-text-field
id="password"
label="Password"
name="password"
prepend-icon="mdi-lock"
placeholder="Password"
v-model="password"
type="password"
></v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn @click="authenticate" color="primary">Login</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import store from '@/store';
@Component({
components: {}
})
export default class Login extends Vue {
email = '';
password = '';
errorMsg = '';
authenticate() {
store
.dispatch('login', { email: this.email, password: this.password })
.then(() => {
console.log('Login', 'store_dispatch_login');
this.$router.push('/');
});
}
register() {
store
.dispatch('register', {
email: this.email,
password: this.password
})
.then(() => this.$router.push('/login'));
}
}
</script>

View File

@@ -0,0 +1,46 @@
<template>
<v-card class="mx-auto" outlined>
<template slot="progress">
<v-progress-linear color="deep-purple" height="10" indeterminate></v-progress-linear>
</template>
<v-card-title>Your Network details are</v-card-title>
<v-card-text>
<v-simple-table>
<template v-slot:default>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Value</th>
</tr>
</thead>
<tbody>
<tr v-for="(value, propertyName) in headers" :key="propertyName">
<th scope="row">{{ propertyName }}</th>
<td>{{ value }}</td>
</tr>
</tbody>
</template>
</v-simple-table>
</v-card-text>
</v-card>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { dnsApi } from '@/api';
@Component({
components: {},
})
export default class MyIp extends Vue {
ip: any = 'Unknown';
headers: any = {};
async mounted() {
this.ip = await dnsApi.getMyIP();
this.headers = await dnsApi.getHeaders();
console.log('MyIp', '', this.headers);
}
}
</script>

View File

@@ -1,12 +1,12 @@
module.exports = {
plugins: [
'cypress'
'cypress',
],
env: {
mocha: true,
'cypress/globals': true
'cypress/globals': true,
},
rules: {
strict: 'off'
}
}
strict: 'off',
},
};

View File

@@ -15,11 +15,12 @@ module.exports = (on, config) => {
// watchOptions: {}
// }))
return Object.assign({}, config, {
return {
...config,
fixturesFolder: 'tests/e2e/fixtures',
integrationFolder: 'tests/e2e/specs',
screenshotsFolder: 'tests/e2e/screenshots',
videosFolder: 'tests/e2e/videos',
supportFile: 'tests/e2e/support/index.js'
})
}
supportFile: 'tests/e2e/support/index.js',
};
};

View File

@@ -2,7 +2,7 @@
describe('My First Test', () => {
it('Visits the app root url', () => {
cy.visit('/')
cy.contains('h1', 'Welcome to Your Vue.js + TypeScript App')
})
})
cy.visit('/');
cy.contains('h1', 'Welcome to Your Vue.js + TypeScript App');
});
});

View File

@@ -14,7 +14,7 @@
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
import './commands';
// Alternatively you can use CommonJS syntax:
// require('./commands')

View File

@@ -1,13 +1,13 @@
import { expect } from 'chai'
import { shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'
import { expect } from 'chai';
import { shallowMount } from '@vue/test-utils';
import HelloWorld from '@/components/HelloWorld.vue';
describe('HelloWorld.vue', () => {
it('renders props.msg when passed', () => {
const msg = 'new message'
const msg = 'new message';
const wrapper = shallowMount(HelloWorld, {
propsData: { msg }
})
expect(wrapper.text()).to.include(msg)
})
})
propsData: { msg },
});
expect(wrapper.text()).to.include(msg);
});
});

View File

@@ -12,22 +12,11 @@
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env",
"mocha",
"chai"
],
"types": ["webpack-env", "mocha", "chai", "vuetify"],
"paths": {
"@/*": [
"src/*"
]
"@/*": ["src/*"]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
"lib": ["esnext", "dom", "dom.iterable", "scripthost"]
},
"include": [
"src/**/*.ts",
@@ -36,7 +25,5 @@
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,5 @@
module.exports = {
transpileDependencies: [
'vuetify',
],
};

View File

@@ -1091,6 +1091,11 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
"@types/jwt-decode@^2.2.1":
version "2.2.1"
resolved "https://registry.yarnpkg.com/@types/jwt-decode/-/jwt-decode-2.2.1.tgz#afdf5c527fcfccbd4009b5fd02d1e18241f2d2f2"
integrity sha512-aWw2YTtAdT7CskFyxEX2K21/zSDStuf/ikI3yBqmwpwJF0pS+/IX5DWv+1UFffZIbruP6cnT9/LAJV1gFwAT1A==
"@types/mime@*":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a"
@@ -1530,6 +1535,16 @@
optionalDependencies:
prettier "^1.18.2"
"@vue/eslint-config-airbnb@^5.0.2":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@vue/eslint-config-airbnb/-/eslint-config-airbnb-5.1.0.tgz#6a72e166af18ac821120ff36aae8b76b940f28aa"
integrity sha512-kme7oQRb3AY8UWd3X7d/uTkmrsbkhwcxhS7rvbxdvfJykLDy4GtO4MdQhmKWa7b8R/gjIMfBXaCN6XUZU9PC6Q==
dependencies:
eslint-config-airbnb-base "^14.0.0"
eslint-import-resolver-node "^0.3.4"
eslint-import-resolver-webpack "^0.12.2"
eslint-plugin-import "^2.21.2"
"@vue/eslint-config-standard@^5.1.2":
version "5.1.2"
resolved "https://registry.yarnpkg.com/@vue/eslint-config-standard/-/eslint-config-standard-5.1.2.tgz#c5d55af894a3ae23b65b1af4a425777ac0170b42"
@@ -2123,6 +2138,18 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428"
integrity sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==
axios-auth-refresh@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/axios-auth-refresh/-/axios-auth-refresh-3.0.0.tgz#dd8c8a8458250c554c9b00c6b2cf571397c8eec6"
integrity sha512-0XJnJY711f7opdT+b/au/xw1g4MYrjntXB8Oy5l48plbzOWLjUtJ+m8CtiNLgN3MAvGFJ/Q1NtQ7WKf2euKu6g==
axios@^0.20.0:
version "0.20.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd"
integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==
dependencies:
follow-redirects "^1.10.0"
babel-code-frame@^6.22.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
@@ -2718,6 +2745,21 @@ check-types@^8.0.3:
resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552"
integrity sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ==
"chokidar@>=2.0.0 <4.0.0", chokidar@^3.3.0, chokidar@^3.4.1:
version "3.4.2"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.2.tgz#38dc8e658dec3809741eb3ef7bb0a47fe424232d"
integrity sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==
dependencies:
anymatch "~3.1.1"
braces "~3.0.2"
glob-parent "~5.1.0"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
readdirp "~3.4.0"
optionalDependencies:
fsevents "~2.1.2"
chokidar@^2.0.0, chokidar@^2.1.8:
version "2.1.8"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
@@ -2737,21 +2779,6 @@ chokidar@^2.0.0, chokidar@^2.1.8:
optionalDependencies:
fsevents "^1.2.7"
chokidar@^3.3.0, chokidar@^3.4.1:
version "3.4.2"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.2.tgz#38dc8e658dec3809741eb3ef7bb0a47fe424232d"
integrity sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==
dependencies:
anymatch "~3.1.1"
braces "~3.0.2"
glob-parent "~5.1.0"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
readdirp "~3.4.0"
optionalDependencies:
fsevents "~2.1.2"
chownr@^1.1.1, chownr@^1.1.2:
version "1.1.4"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
@@ -3057,6 +3084,11 @@ config-chain@^1.1.12:
ini "^1.3.4"
proto-list "~1.2.1"
confusing-browser-globals@^1.0.9:
version "1.0.9"
resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz#72bc13b483c0276801681871d4898516f8f54fdd"
integrity sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==
connect-history-api-fallback@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc"
@@ -3534,6 +3566,11 @@ date-fns@^1.27.2:
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
dayjs@^1.8.35:
version "1.8.35"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.35.tgz#67118378f15d31623f3ee2992f5244b887606888"
integrity sha512-isAbIEenO4ilm6f8cpqvgjZCsuerDAz2Kb7ri201AiNn58aqXuaLJEnCtfIMdCvERZHNGRY5lDMTr/jdAnKSWQ==
de-indent@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
@@ -3565,6 +3602,11 @@ decamelize@^1.1.2, decamelize@^1.2.0:
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
decko@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decko/-/decko-1.2.0.tgz#fd43c735e967b8013306884a56fbe665996b6817"
integrity sha1-/UPHNelnuAEzBohKVvvmZZlraBc=
decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
@@ -4056,12 +4098,28 @@ escodegen@^1.11.1:
optionalDependencies:
source-map "~0.6.1"
eslint-config-airbnb-base@^14.0.0:
version "14.2.0"
resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz#fe89c24b3f9dc8008c9c0d0d88c28f95ed65e9c4"
integrity sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q==
dependencies:
confusing-browser-globals "^1.0.9"
object.assign "^4.1.0"
object.entries "^1.1.2"
eslint-config-prettier@^6.11.0:
version "6.11.0"
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz#f6d2238c1290d01c859a8b5c1f7d352a0b0da8b1"
integrity sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==
dependencies:
get-stdin "^6.0.0"
eslint-config-standard@^14.1.0:
version "14.1.1"
resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea"
integrity sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg==
eslint-import-resolver-node@^0.3.3:
eslint-import-resolver-node@^0.3.3, eslint-import-resolver-node@^0.3.4:
version "0.3.4"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==
@@ -4069,7 +4127,7 @@ eslint-import-resolver-node@^0.3.3:
debug "^2.6.9"
resolve "^1.13.1"
eslint-import-resolver-webpack@^0.12.1:
eslint-import-resolver-webpack@^0.12.1, eslint-import-resolver-webpack@^0.12.2:
version "0.12.2"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.12.2.tgz#769e86cd0c752a1536c19855ebd90aa14ce384ee"
integrity sha512-7Jnm4YAoNNkvqPaZkKdIHsKGmv8/uNnYC5QsXkiSodvX4XEEfH2AKOna98FK52fCDXm3q4HzuX+7pRMKkJ64EQ==
@@ -4119,7 +4177,7 @@ eslint-plugin-es@^3.0.0:
eslint-utils "^2.0.0"
regexpp "^3.0.0"
eslint-plugin-import@^2.20.2:
eslint-plugin-import@^2.20.2, eslint-plugin-import@^2.21.2:
version "2.22.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz#92f7736fe1fde3e2de77623c838dd992ff5ffb7e"
integrity sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==
@@ -4150,6 +4208,13 @@ eslint-plugin-node@^11.1.0:
resolve "^1.10.1"
semver "^6.1.0"
eslint-plugin-prettier@^3.1.4:
version "3.1.4"
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz#168ab43154e2ea57db992a2cd097c828171f75c2"
integrity sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg==
dependencies:
prettier-linter-helpers "^1.0.0"
eslint-plugin-promise@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a"
@@ -4514,6 +4579,11 @@ fast-deep-equal@^3.1.1:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-diff@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
fast-glob@^2.2.6:
version "2.2.7"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
@@ -4610,7 +4680,7 @@ file-entry-cache@^5.0.1:
dependencies:
flat-cache "^2.0.1"
file-loader@^4.2.0:
file-loader@^4.0.0, file-loader@^4.2.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-4.3.0.tgz#780f040f729b3d18019f20605f723e844b8a58af"
integrity sha512-aKrYPYjF1yG3oX0kWRrqrSMfgftm7oJW5M+m4owoldH5C51C0RkIwB++JbRvEW3IU6/ZG5n8UvEcdgwOt2UOWA==
@@ -4749,7 +4819,7 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
follow-redirects@^1.0.0:
follow-redirects@^1.0.0, follow-redirects@^1.10.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
@@ -4972,6 +5042,11 @@ get-stdin@^4.0.1:
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
get-stdin@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
@@ -5636,7 +5711,7 @@ internal-ip@^4.3.0:
default-gateway "^4.2.0"
ipaddr.js "^1.9.0"
interpret@^1.2.0:
interpret@^1.0.0, interpret@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
@@ -6239,6 +6314,11 @@ jsprim@^1.2.2:
json-schema "0.2.3"
verror "1.10.0"
jwt-decode@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-2.2.0.tgz#7d86bd56679f58ce6a84704a657dd392bba81a79"
integrity sha1-fYa9VmefWM5qhHBKZX3TkruoGnk=
killable@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
@@ -6408,7 +6488,7 @@ loader-utils@^0.2.16:
json5 "^0.5.0"
object-assign "^4.0.1"
loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0:
loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.0, loader-utils@^1.2.3, loader-utils@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
@@ -7245,6 +7325,14 @@ nth-check@^1.0.2, nth-check@~1.0.1:
dependencies:
boolbase "~1.0.0"
null-loader@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/null-loader/-/null-loader-3.0.0.tgz#3e2b6c663c5bda8c73a54357d8fa0708dc61b245"
integrity sha512-hf5sNLl8xdRho4UPBOOeoIwT3WhjYcMUQm0zj44EhD6UscMAz72o2udpoDFBgykucdEDGIcd6SXbc/G6zssbzw==
dependencies:
loader-utils "^1.2.3"
schema-utils "^1.0.0"
num2fraction@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
@@ -7319,6 +7407,15 @@ object.assign@4.1.0, object.assign@^4.1.0:
has-symbols "^1.0.0"
object-keys "^1.0.11"
object.entries@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.2.tgz#bc73f00acb6b6bb16c203434b10f9a7e797d3add"
integrity sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.17.5"
has "^1.0.3"
object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649"
@@ -8180,11 +8277,23 @@ prepend-http@^1.0.0:
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
prettier-linter-helpers@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
dependencies:
fast-diff "^1.1.2"
prettier@^1.18.2:
version "1.19.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
prettier@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.1.1.tgz#d9485dd5e499daa6cb547023b87a6cf51bee37d6"
integrity sha512-9bY+5ZWCfqj3ghYBLxApy2zf6m+NJo5GzmLTpr9FsApsfjriNnS2dahWReHMi7qNPhhHl9SYHJs2cHZLgexNIw==
pretty-bytes@^5.1.0:
version "5.4.1"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.4.1.tgz#cd89f79bbcef21e3d21eb0da68ffe93f803e884b"
@@ -8462,6 +8571,13 @@ readdirp@~3.4.0:
dependencies:
picomatch "^2.2.1"
rechoir@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=
dependencies:
resolve "^1.1.6"
redent@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
@@ -8704,7 +8820,7 @@ resolve-url@^0.2.1:
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
resolve@^1.10.0, resolve@^1.10.1, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2, resolve@^1.8.1:
resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2, resolve@^1.8.1:
version "1.17.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
@@ -8856,6 +8972,13 @@ sass-loader@^8.0.2:
schema-utils "^2.6.1"
semver "^6.3.0"
sass@^1.19.0:
version "1.26.10"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.26.10.tgz#851d126021cdc93decbf201d1eca2a20ee434760"
integrity sha512-bzN0uvmzfsTvjz0qwccN1sPm2HxxpNI/Xa+7PlUEMS+nQvbyuEK7Y0qFqxlPHhiNHb1Ze8WQJtU31olMObkAMw==
dependencies:
chokidar ">=2.0.0 <4.0.0"
sax@~1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
@@ -8930,7 +9053,7 @@ semver@^6.0.0, semver@^6.1.0, semver@^6.1.2, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.3.2:
semver@^7.1.2, semver@^7.3.2:
version "7.3.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
@@ -9063,6 +9186,15 @@ shell-quote@^1.6.1:
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2"
integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==
shelljs@^0.8.3:
version "0.8.4"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2"
integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==
dependencies:
glob "^7.0.0"
interpret "^1.0.0"
rechoir "^0.6.2"
sigmund@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
@@ -10237,6 +10369,15 @@ vue-class-component@^7.1.0, vue-class-component@^7.2.3:
resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-7.2.5.tgz#212b3548c4fdd3314774c4adbc1c3792a40b52d0"
integrity sha512-0CSftHY0bDTD+4FbYkuFf6+iKDjZ4h2in2YYJDRMk5daZIjrgT9LjFHvP7Rzqy9/s1pij3zDtTSLRUjsPWMwqg==
vue-cli-plugin-vuetify@~2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/vue-cli-plugin-vuetify/-/vue-cli-plugin-vuetify-2.0.7.tgz#fcb4f1655e7c9199ee40dcbf6465e2355fd074d5"
integrity sha512-4riK5bzyvkZ4CxpQk/Vl6z8n8tmJUhuxh+k8xc/MZRdCt9RxAm3G4SxcEweroqKGXg+CRRfhqysaEQVtd4D40Q==
dependencies:
null-loader "^3.0.0"
semver "^7.1.2"
shelljs "^0.8.3"
vue-eslint-parser@^7.0.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-7.1.0.tgz#9cdbcc823e656b087507a1911732b867ac101e83"
@@ -10310,11 +10451,29 @@ vue-template-es2015-compiler@^1.9.0:
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
vue-toasted@^1.1.28:
version "1.1.28"
resolved "https://registry.yarnpkg.com/vue-toasted/-/vue-toasted-1.1.28.tgz#dbabb83acc89f7a9e8765815e491d79f0dc65c26"
integrity sha512-UUzr5LX51UbbiROSGZ49GOgSzFxaMHK6L00JV8fir/CYNJCpIIvNZ5YmS4Qc8Y2+Z/4VVYRpeQL2UO0G800Raw==
vue@^2.6.11:
version "2.6.12"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.12.tgz#f5ebd4fa6bd2869403e29a896aed4904456c9123"
integrity sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg==
vuetify-loader@^1.3.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/vuetify-loader/-/vuetify-loader-1.6.0.tgz#05df0805b3ab2ff0de198109d34f9da3f69da667"
integrity sha512-1bx3YeZ712dT1+QMX+XSFlP0O5k5O5Ui9ysBBmUZ9bWkAEHWZJQI9soI+qG5qmeFxUC0L9QYMCIKP0hOL/pf3Q==
dependencies:
file-loader "^4.0.0"
loader-utils "^1.2.0"
vuetify@^2.2.11:
version "2.3.10"
resolved "https://registry.yarnpkg.com/vuetify/-/vuetify-2.3.10.tgz#c8cbc77ee1224b5a132f501a3762dee6d8c95a06"
integrity sha512-KzL/MhZ7ajubm9kwbdCoA/cRV50RX+a5Hcqiwt7Am1Fni2crDtl2no05UNwKroTfscrYYf07gq3WIFSurPsnCA==
vuex@^3.4.0:
version "3.5.1"
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.5.1.tgz#f1b8dcea649bc25254cf4f4358081dbf5da18b3d"

View File

@@ -1 +0,0 @@
node_modules

View File

@@ -1,13 +0,0 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

View File

@@ -1,30 +0,0 @@
{
"parser": "@typescript-eslint/parser",
"extends": [
"plugin:@typescript-eslint/recommended",
"eslint:recommended",
"prettier",
"prettier/@typescript-eslint"
],
"env": {
"es6": true,
"node": true
},
"rules": {
"no-debugger": "off",
"prettier/prettier": "error",
"max-len": [
"error",
{
"code": 80
}
],
"indent": [
"error",
2
]
},
"plugins": [
"prettier"
]
}

23
client/.gitignore vendored
View File

@@ -1,23 +0,0 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -1,6 +0,0 @@
server {
location / {
root /var/www/html;
try_files $uri $uri/ /index.html;
}
}

View File

@@ -1,23 +0,0 @@
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile off;
keepalive_timeout 60;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}

View File

@@ -1,4 +0,0 @@
{
"tabWidth": 4,
"singleQuote": true
}

View File

@@ -1,24 +0,0 @@
# client
## Project setup
```
yarn install
```
### Compiles and hot-reloads for development
```
yarn serve
```
### Compiles and minifies for production
```
yarn build
```
### Lints and fixes files
```
yarn lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

View File

View File

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

View File

@@ -1,83 +0,0 @@
{
"name": "bitchmin",
"version": "0.1.1",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@mdi/font": "^5.5.55",
"@types/jquery": "^3.5.1",
"@types/jwt-decode": "^2.2.1",
"@types/lodash": "^4.14.161",
"axios": "^0.20.0",
"axios-auth-refresh": "^3.0.0",
"bootstrap": "^4.5.2",
"compass-mixins": "^0.12.10",
"core-js": "^3.6.5",
"dayjs": "^1.8.35",
"decko": "^1.2.0",
"ee-first": "^1.1.1",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.4",
"fibers": "^5.0.0",
"fs": "^0.0.1-security",
"jquery": "^3.5.1",
"jwt-decode": "^2.2.0",
"lodash": "^4.17.20",
"popper.js": "^1.16.1",
"prettier": "^2.1.1",
"qs": "^6.9.4",
"vue": "^2.6.11",
"vue-class-component": "^7.2.3",
"vue-color": "^2.7.1",
"vue-property-decorator": "^8.4.2",
"vue-router": "^3.2.0",
"vue-toasted": "^1.1.28",
"vuetify": "^2.2.11",
"vuex": "^3.5.1"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^2.33.0",
"@typescript-eslint/parser": "^2.33.0",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-typescript": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/eslint-config-typescript": "^5.0.2",
"eslint": "^7.7.0",
"eslint-plugin-vue": "^6.2.2",
"node-sass": "^4.14.1",
"sass": "^1.19.0",
"sass-loader": "^10.0.1",
"style-resources-loader": "^1.3.2",
"typescript": "~3.9.3",
"vue-cli-plugin-style-resources-loader": "~0.1.4",
"vue-cli-plugin-vuetify": "~2.0.7",
"vue-template-compiler": "^2.6.11",
"vuetify-loader": "^1.3.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended",
"@vue/typescript/recommended"
],
"parserOptions": {
"ecmaVersion": 2020
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 153 187" style="enable-background:new 0 0 153 187;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.2;fill:#FFFFFF;}
</style>
<g>
<title>3</title>
<desc>Created with Sketch.</desc>
<g id="Mask-_x2B_-Mask-Mask" transform="translate(14.000000, 0.000000)">
<g id="Mask">
</g>
<g id="Mask_1_">
<path class="st0" d="M138,141.2c-3.6,0.5-7.3,0.8-11,0.8c-29.6,0-55.4-16.5-68.6-40.9c-6-11-9.4-23.7-9.4-37.1
c0-26.5,13.2-49.9,33.4-64H138v129.5"/>
</g>
<g id="Mask_2_">
<path class="st0" d="M138,141.2V187H-15c0.2-43.3,31.9-79.1,73.4-85.9c4.6-0.8,9.3-1.1,14.1-1.1c26.1,0,49.5,11.4,65.5,29.5"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 920 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Some files were not shown because too many files have changed in this diff Show More