mirror of
https://github.com/nocodb/nocodb.git
synced 2026-05-02 15:57:03 +00:00
refactor(gui): linting
Signed-off-by: Pranav C <61551451+pranavxc@users.noreply.github.com>
This commit is contained in:
@@ -1,30 +1,34 @@
|
||||
<template>
|
||||
|
||||
<div>
|
||||
|
||||
<h3 class="text-center mb-5 grey--text text--darken-2">Appearance</h3>
|
||||
<h3 class="text-center mb-5 grey--text text--darken-2">
|
||||
Appearance
|
||||
</h3>
|
||||
|
||||
<v-simple-table dense style="">
|
||||
<template v-slot:default>
|
||||
<template #default>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Dark Mode</td>
|
||||
<td>
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-icon @click="toggleDarkTheme" v-on="on" x-large
|
||||
:color="$vuetify.theme.dark ? 'primary':'primary'">
|
||||
mdi-bat
|
||||
</v-icon>
|
||||
</template>
|
||||
<h3 class="pa-3">
|
||||
{{ $vuetify.theme.dark ? 'It does come in Black' : 'Does it come in Black ?' }}
|
||||
<i></i>
|
||||
</h3>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</tr>
|
||||
<!--<tr>
|
||||
<tr>
|
||||
<td>Dark Mode</td>
|
||||
<td>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-icon
|
||||
x-large
|
||||
:color="$vuetify.theme.dark ? 'primary':'primary'"
|
||||
@click="toggleDarkTheme"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-bat
|
||||
</v-icon>
|
||||
</template>
|
||||
<h3 class="pa-3">
|
||||
{{ $vuetify.theme.dark ? 'It does come in Black' : 'Does it come in Black ?' }}
|
||||
<i />
|
||||
</h3>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</tr>
|
||||
<!--<tr>
|
||||
<td>Show metatables</td>
|
||||
<td>
|
||||
<v-tooltip bottom>
|
||||
@@ -38,122 +42,133 @@
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</tr>-->
|
||||
<tr>
|
||||
<td>Show Screensaver</td>
|
||||
<td>
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-checkbox v-model="showScreensaver" v-on="on" x-large
|
||||
color="primary">
|
||||
mdi-bat
|
||||
</v-checkbox>
|
||||
</template>
|
||||
Show/hide metatables
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Language</td>
|
||||
<td>
|
||||
<v-radio-group v-model="language" row>
|
||||
<v-radio
|
||||
v-for="{label,value} in languages"
|
||||
:key="value"
|
||||
:label="label"
|
||||
:value="value"
|
||||
></v-radio>
|
||||
</v-radio-group>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Themes</td>
|
||||
<td class="pa-1">
|
||||
<v-list rounded>
|
||||
<!-- <v-subheader>REPORTS</v-subheader>-->
|
||||
<v-list-item-group color="primary" v-model="item">
|
||||
<v-list-item
|
||||
class="mb-n1"
|
||||
v-for="(t,i) in themes"
|
||||
:key="i"
|
||||
:value="i"
|
||||
@click.native.prevent.stop="changeTheme(t,i)"
|
||||
>
|
||||
<v-list-item-content class="py-0">
|
||||
<div class="d-flex align-center" style="width:100%">
|
||||
<div style="width: 100px">{{ i }}</div>
|
||||
<div class="flex-grow-1">
|
||||
<v-container fluid class="pa-0">
|
||||
<v-row>
|
||||
<v-col class="mx-2" style="height: 20px" v-for="(col,key) in t"
|
||||
:style="{backgroundColor: col}"
|
||||
:key="key">
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
<tr>
|
||||
<td>Show Screensaver</td>
|
||||
<td>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-checkbox
|
||||
v-model="showScreensaver"
|
||||
x-large
|
||||
color="primary"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-bat
|
||||
</v-checkbox>
|
||||
</template>
|
||||
Show/hide metatables
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Language</td>
|
||||
<td>
|
||||
<v-radio-group v-model="language" row>
|
||||
<v-radio
|
||||
v-for="{label,value} in languages"
|
||||
:key="value"
|
||||
:label="label"
|
||||
:value="value"
|
||||
/>
|
||||
</v-radio-group>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Themes</td>
|
||||
<td class="pa-1">
|
||||
<v-list rounded>
|
||||
<!-- <v-subheader>REPORTS</v-subheader>-->
|
||||
<v-list-item-group v-model="item" color="primary">
|
||||
<v-list-item
|
||||
v-for="(t,i) in themes"
|
||||
:key="i"
|
||||
class="mb-n1"
|
||||
:value="i"
|
||||
@click.native.prevent.stop="changeTheme(t,i)"
|
||||
>
|
||||
<v-list-item-content class="py-0">
|
||||
<div class="d-flex align-center" style="width:100%">
|
||||
<div style="width: 100px">
|
||||
{{ i }}
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<v-container fluid class="pa-0">
|
||||
<v-row>
|
||||
<v-col
|
||||
v-for="(col,key) in t"
|
||||
:key="key"
|
||||
class="mx-2"
|
||||
style="height: 20px"
|
||||
:style="{backgroundColor: col}"
|
||||
/>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-list-item-content>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
class="mb-n2"
|
||||
value="Custom"
|
||||
@click.native.prevent.stop="changeTheme(customTheme,'Custom')"
|
||||
>
|
||||
<v-list-item-content class="py-0">
|
||||
<div class="d-flex align-center" style="width:100%">
|
||||
<div style="min-width: 100px">
|
||||
Custom
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<!-- <v-container fluid>-->
|
||||
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
class="mb-n2"
|
||||
value="Custom"
|
||||
@click.native.prevent.stop="changeTheme(customTheme,'Custom')">
|
||||
<v-list-item-content class="py-0">
|
||||
<div class="d-flex align-center" style="width:100%">
|
||||
<div style="min-width: 100px">Custom</div>
|
||||
<div class="flex-grow-1">
|
||||
<!-- <v-container fluid>-->
|
||||
|
||||
<x-btn
|
||||
small
|
||||
btn.class="ma-1 caption"
|
||||
v-for="(col,key) in customTheme"
|
||||
:color="col"
|
||||
:key="key"
|
||||
@click="customKey = key, colorPickerModel= true"
|
||||
tooltip="Click to change the color"
|
||||
> {{ key }}
|
||||
</x-btn>
|
||||
<x-btn
|
||||
v-for="(col,key) in customTheme"
|
||||
:key="key"
|
||||
small
|
||||
btn.class="ma-1 caption"
|
||||
:color="col"
|
||||
tooltip="Click to change the color"
|
||||
@click="customKey = key, colorPickerModel= true"
|
||||
>
|
||||
{{ key }}
|
||||
</x-btn>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</template>
|
||||
</v-simple-table>
|
||||
|
||||
|
||||
<v-dialog
|
||||
v-model="colorPickerModel"
|
||||
width="350"
|
||||
>
|
||||
<v-color-picker class="mx-auto my-2" @input="changeTheme(customTheme)" v-if="customTheme[customKey]"
|
||||
v-model="customTheme[customKey]"></v-color-picker>
|
||||
<v-color-picker
|
||||
v-if="customTheme[customKey]"
|
||||
v-model="customTheme[customKey]"
|
||||
class="mx-auto my-2"
|
||||
@input="changeTheme(customTheme)"
|
||||
/>
|
||||
</v-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
import XIcon from "../../global/xIcon";
|
||||
import themes from "../../../helpers/themes";
|
||||
import DlgLabelSubmitCancel from "@/components/utils/dlgLabelSubmitCancel";
|
||||
import themes from '../../../helpers/themes'
|
||||
|
||||
export default {
|
||||
components: {DlgLabelSubmitCancel, XIcon},
|
||||
components: { },
|
||||
|
||||
data() {
|
||||
data () {
|
||||
return {
|
||||
rightClickCount: 0,
|
||||
tab: null,
|
||||
languages: [
|
||||
{label: 'English', value: 'en'},
|
||||
{ label: 'English', value: 'en' }
|
||||
// {label: 'Japanese', value: 'ja'},
|
||||
// {label: 'Chinese', value: 'zh'}
|
||||
],
|
||||
@@ -168,88 +183,85 @@ export default {
|
||||
customKey: null,
|
||||
colorPickerModel: false,
|
||||
customTheme: {
|
||||
"primary": "#6f5dcc",
|
||||
"secondary": "#BFDBF7",
|
||||
"accent": "#ED254E",
|
||||
"info": "#00CED1",
|
||||
"success": "#4CAF50",
|
||||
"warning": "#FB8C00",
|
||||
error: '#ff0100',
|
||||
primary: '#6f5dcc',
|
||||
secondary: '#BFDBF7',
|
||||
accent: '#ED254E',
|
||||
info: '#00CED1',
|
||||
success: '#4CAF50',
|
||||
warning: '#FB8C00',
|
||||
error: '#ff0100'
|
||||
},
|
||||
themes: themes
|
||||
themes
|
||||
}
|
||||
},
|
||||
fetch ({ store, params }) {
|
||||
},
|
||||
computed: {
|
||||
language: {
|
||||
get() {
|
||||
return this.$store.state.windows.language;
|
||||
}, set(val) {
|
||||
this.$store.commit('windows/MutLanguage', val);
|
||||
get () {
|
||||
return this.$store.state.windows.language
|
||||
},
|
||||
set (val) {
|
||||
this.$store.commit('windows/MutLanguage', val)
|
||||
}
|
||||
},
|
||||
showMetatable: {
|
||||
get() {
|
||||
return this.$store.state.windows.metatables;
|
||||
get () {
|
||||
return this.$store.state.windows.metatables
|
||||
},
|
||||
set(show) {
|
||||
set (show) {
|
||||
this.$store.commit('windows/MutMetatables', show)
|
||||
}
|
||||
},
|
||||
showScreensaver: {
|
||||
get() {
|
||||
return this.$store.state.windows.screensaver;
|
||||
get () {
|
||||
return this.$store.state.windows.screensaver
|
||||
},
|
||||
set(show) {
|
||||
set (show) {
|
||||
this.$store.commit('windows/MutScreensaver', show)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
rightClick() {
|
||||
this.rightClickCount++;
|
||||
if (this.rightClickCount > 5) {
|
||||
// require('electron').remote.getCurrentWindow().toggleDevTools();
|
||||
this.rightClickCount = 0;
|
||||
}
|
||||
}
|
||||
, async changeTheme(t, theme = 'Custom') {
|
||||
this.item = theme;
|
||||
if (theme === 'Custom')
|
||||
await this.$store.dispatch('windows/ActSetTheme', {theme: {...t}, custom: true});
|
||||
await this.$store.dispatch('windows/ActSetTheme', {theme: {...t}, themeName: theme});
|
||||
|
||||
|
||||
},
|
||||
toggleDarkTheme() {
|
||||
this.$store.commit('windows/MutToggleDarkMode');
|
||||
}
|
||||
},
|
||||
fetch({store, params}) {
|
||||
},
|
||||
beforeCreated() {
|
||||
},
|
||||
created() {
|
||||
this.customTheme = {...this.customTheme, ...this.$store.state.windows.customTheme}
|
||||
this.item = this.$store.state.windows.themeName;
|
||||
created () {
|
||||
this.customTheme = { ...this.customTheme, ...this.$store.state.windows.customTheme }
|
||||
this.item = this.$store.state.windows.themeName
|
||||
this.$store.watch(
|
||||
state => state.windows.customTheme,
|
||||
theme => {
|
||||
this.customTheme = {...this.customTheme, ...theme};
|
||||
(theme) => {
|
||||
this.customTheme = { ...this.customTheme, ...theme }
|
||||
})
|
||||
|
||||
this.$store.watch(state => state.windows.themeName,
|
||||
theme => {
|
||||
(theme) => {
|
||||
this.$nextTick(() => {
|
||||
if (this.item !== theme) this.item = theme
|
||||
if (this.item !== theme) { this.item = theme }
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
rightClick () {
|
||||
this.rightClickCount++
|
||||
if (this.rightClickCount > 5) {
|
||||
// require('electron').remote.getCurrentWindow().toggleDevTools();
|
||||
this.rightClickCount = 0
|
||||
}
|
||||
},
|
||||
async changeTheme (t, theme = 'Custom') {
|
||||
this.item = theme
|
||||
if (theme === 'Custom') { await this.$store.dispatch('windows/ActSetTheme', { theme: { ...t }, custom: true }) }
|
||||
await this.$store.dispatch('windows/ActSetTheme', { theme: { ...t }, themeName: theme })
|
||||
},
|
||||
toggleDarkTheme () {
|
||||
this.$store.commit('windows/MutToggleDarkMode')
|
||||
}
|
||||
},
|
||||
beforeCreated () {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
|
||||
</style>
|
||||
<!--
|
||||
/**
|
||||
|
||||
@@ -1,87 +1,92 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-progress-linear
|
||||
v-if="progressbar"
|
||||
indeterminate
|
||||
color="green"
|
||||
v-if="progressbar"
|
||||
></v-progress-linear>
|
||||
<h3 class=" text-center mb-5 grey--text text--darken-2">Change environment</h3>
|
||||
/>
|
||||
<h3 class=" text-center mb-5 grey--text text--darken-2">
|
||||
Change environment
|
||||
</h3>
|
||||
<div>
|
||||
<div class="">
|
||||
<v-select
|
||||
v-model="selectedEnv"
|
||||
hide-details
|
||||
dense
|
||||
:items="envList"
|
||||
v-model="selectedEnv"
|
||||
label="Solo field"
|
||||
solo
|
||||
></v-select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 d-flex d-100">
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn small :disabled="progressbar" @click="dialogShow = false">Close</v-btn>
|
||||
<v-btn color="primary" small :disabled="progressbar" @click="changeEnv">Change</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn small :disabled="progressbar" @click="dialogShow = false">
|
||||
Close
|
||||
</v-btn>
|
||||
<v-btn color="primary" small :disabled="progressbar" @click="changeEnv">
|
||||
Change
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import {mapGetters} from 'vuex';
|
||||
import axios from "axios";
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: "env",
|
||||
name: 'Env',
|
||||
data: () => ({
|
||||
selectedEnv: 'dev',
|
||||
progressbar: false
|
||||
}),
|
||||
computed: {
|
||||
...mapGetters({
|
||||
envList: 'project/GtrEnvList',
|
||||
}),
|
||||
envList: 'project/GtrEnvList'
|
||||
})
|
||||
},
|
||||
mounted() {
|
||||
const unserializedList = this.$store.state.project.unserializedList;
|
||||
this.selectedEnv = (unserializedList[0]
|
||||
&& unserializedList[0].projectJson
|
||||
&& unserializedList[0].projectJson.workingEnv) || 'dev';
|
||||
mounted () {
|
||||
const unserializedList = this.$store.state.project.unserializedList
|
||||
this.selectedEnv = (unserializedList[0] &&
|
||||
unserializedList[0].projectJson &&
|
||||
unserializedList[0].projectJson.workingEnv) || 'dev'
|
||||
this.$store.watch((state) => {
|
||||
const unserializedList = state.project.unserializedList
|
||||
return (unserializedList[0]
|
||||
&& unserializedList[0].projectJson
|
||||
&& unserializedList[0].projectJson.workingEnv) || 'dev'
|
||||
}, (value) => this.selectedEnv = value)
|
||||
return (unserializedList[0] &&
|
||||
unserializedList[0].projectJson &&
|
||||
unserializedList[0].projectJson.workingEnv) || 'dev'
|
||||
}, (value) => { this.selectedEnv = value })
|
||||
},
|
||||
methods: {
|
||||
async changeEnv() {
|
||||
this.progressbar = true;
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'projectChangeEnv', {env: this.selectedEnv}]);
|
||||
await new Promise(resolve => {
|
||||
async changeEnv () {
|
||||
this.progressbar = true
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'projectChangeEnv', { env: this.selectedEnv }])
|
||||
await new Promise((resolve) => {
|
||||
const interv = setInterval(() => {
|
||||
axios.create({
|
||||
baseURL: `${this.$axios.defaults.baseURL}/dashboard`
|
||||
}).get('').then(() => {
|
||||
this.projectReloading = false;
|
||||
clearInterval(interv);
|
||||
resolve();
|
||||
}).catch(err => {
|
||||
this.projectReloading = false
|
||||
clearInterval(interv)
|
||||
resolve()
|
||||
}).catch(() => {
|
||||
})
|
||||
}, 1000);
|
||||
}, 1000)
|
||||
})
|
||||
this.progressbar = false;
|
||||
await this.$store.dispatch('users/ActSignOut');
|
||||
this.progressbar = false
|
||||
await this.$store.dispatch('users/ActSignOut')
|
||||
|
||||
await this.$store.dispatch('project/ActLoadProjectInfo');
|
||||
await this.$store.dispatch('project/ActLoadProjectInfo')
|
||||
if (this.$store.state.project.projectInfo.projectHasAdmin === false) {
|
||||
return this.$router.push('/start')
|
||||
}
|
||||
location.reload();
|
||||
},
|
||||
location.reload()
|
||||
}
|
||||
},
|
||||
props: {value: Boolean}
|
||||
props: { value: Boolean }
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,57 +1,70 @@
|
||||
<template>
|
||||
<v-card style="width: 100%">
|
||||
<v-toolbar height="40" class="elevation-0 toolbar-border-bottom">
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
|
||||
|
||||
<x-btn outlined tooltip="Reload log settings"
|
||||
color="primary"
|
||||
small
|
||||
:disabled="loading"
|
||||
@click="load"
|
||||
v-ge="['roles','reload']"
|
||||
@click.prevent>
|
||||
<v-icon small left>refresh</v-icon>
|
||||
<x-btn
|
||||
v-ge="['roles','reload']"
|
||||
outlined
|
||||
tooltip="Reload log settings"
|
||||
color="primary"
|
||||
small
|
||||
:disabled="loading"
|
||||
@click="load"
|
||||
@click.prevent
|
||||
>
|
||||
<v-icon small left>
|
||||
refresh
|
||||
</v-icon>
|
||||
Reload
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Toggle all checkbox"
|
||||
color="primary"
|
||||
small
|
||||
:disabled="loading"
|
||||
@click="toggleAll = !toggleAll; edited=true"
|
||||
v-ge="['roles','add new']"
|
||||
@click.prevent>
|
||||
<v-icon small left>{{ toggleAll ? 'mdi-toggle-switch-outline' : 'mdi-toggle-switch-off-outline' }}</v-icon>
|
||||
<x-btn
|
||||
v-ge="['roles','add new']"
|
||||
outlined
|
||||
tooltip="Toggle all checkbox"
|
||||
color="primary"
|
||||
small
|
||||
:disabled="loading"
|
||||
@click="toggleAll = !toggleAll; edited=true"
|
||||
@click.prevent
|
||||
>
|
||||
<v-icon small left>
|
||||
{{ toggleAll ? 'mdi-toggle-switch-outline' : 'mdi-toggle-switch-off-outline' }}
|
||||
</v-icon>
|
||||
Toggle All
|
||||
</x-btn>
|
||||
<x-btn outlined tooltip="Save Changes"
|
||||
color="primary"
|
||||
small
|
||||
@click="save"
|
||||
:disabled="!edited || loading"
|
||||
<x-btn
|
||||
v-ge="['rows','save']"
|
||||
outlined
|
||||
tooltip="Save Changes"
|
||||
color="primary"
|
||||
small
|
||||
:disabled="!edited || loading"
|
||||
|
||||
v-ge="['rows','save']"
|
||||
@click.prevent>
|
||||
<v-icon small left>save</v-icon>
|
||||
@click="save"
|
||||
@click.prevent
|
||||
>
|
||||
<v-icon small left>
|
||||
save
|
||||
</v-icon>
|
||||
Save
|
||||
</x-btn>
|
||||
|
||||
</v-toolbar>
|
||||
<div class="d-flex justify-center pa-2">
|
||||
<v-simple-table dense style="min-width: 500px;margin:0 auto">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Name</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th />
|
||||
<th>Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(v, key) in names">
|
||||
<td>
|
||||
<v-checkbox @change="edited = true" v-model="names[key]" class="mt-0 pt-0" dense hide-details></v-checkbox>
|
||||
</td>
|
||||
<td>{{ key }}</td>
|
||||
</tr>
|
||||
<tr v-for="(v, key) in names" :key="key">
|
||||
<td>
|
||||
<v-checkbox v-model="names[key]" class="mt-0 pt-0" dense hide-details @change="edited = true" />
|
||||
</td>
|
||||
<td>{{ key }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
</div>
|
||||
@@ -60,45 +73,46 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "logs",
|
||||
name: 'Logs',
|
||||
data: () => ({
|
||||
names: null,
|
||||
loading: false,
|
||||
edited: false
|
||||
}),
|
||||
async created() {
|
||||
computed: {
|
||||
toggleAll: {
|
||||
get () {
|
||||
return this.names && Object.values(this.names).some(v => v)
|
||||
},
|
||||
set (val) {
|
||||
this.names && Object.keys(this.names).forEach(k => this.$set(this.names, k, val))
|
||||
}
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
await this.load()
|
||||
},
|
||||
methods: {
|
||||
async load() {
|
||||
this.loading = true;
|
||||
async load () {
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcDebugGet'])
|
||||
this.names = JSON.parse(res.value);
|
||||
this.names = JSON.parse(res.value)
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
this.loading = false
|
||||
},
|
||||
async save() {
|
||||
this.loading = true;
|
||||
async save () {
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcDebugSet', this.names])
|
||||
this.$toast.success('Updated debug log settings successfully').goAway(3000);
|
||||
this.edited = false;
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [null, 'xcDebugSet', this.names])
|
||||
this.$toast.success('Updated debug log settings successfully').goAway(3000)
|
||||
this.edited = false
|
||||
} catch (e) {
|
||||
this.$toast.error('Some error occurred while updating debug log settings').goAway(3000);
|
||||
}
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
toggleAll: {
|
||||
get() {
|
||||
return this.names && Object.values(this.names).some(v => v)
|
||||
}, set(val) {
|
||||
this.names && Object.keys(this.names).forEach(k => this.$set(this.names, k, val));
|
||||
this.$toast.error('Some error occurred while updating debug log settings').goAway(3000)
|
||||
}
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,67 +1,70 @@
|
||||
<template>
|
||||
<div>
|
||||
<h3 class="text-center mb-5">Version And Update</h3>
|
||||
<h3 class="text-center mb-5">
|
||||
Version And Update
|
||||
</h3>
|
||||
|
||||
<v-simple-table dense>
|
||||
<template v-slot:default>
|
||||
<template #default>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Version
|
||||
</td>
|
||||
<td>
|
||||
<span @contextmenu="rightClick">{{ $store.state.windows.version }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- <tr>-->
|
||||
<!-- <td>-->
|
||||
<!-- Check for updates-->
|
||||
<!-- </td>-->
|
||||
<!-- <td>-->
|
||||
<!-- <v-switch-->
|
||||
<!-- flat-->
|
||||
<!-- v-model="checkForUpdate"-->
|
||||
<!-- color="grey "-->
|
||||
<!-- ></v-switch>-->
|
||||
<!-- </td>-->
|
||||
<!-- </tr>-->
|
||||
<tr @dblclick="enableAppRefresh = true">
|
||||
<td>
|
||||
Auto update
|
||||
</td>
|
||||
<td>
|
||||
<v-switch
|
||||
flat
|
||||
v-model="autoUpdate"
|
||||
color="grey "
|
||||
></v-switch>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="enableAppRefresh">
|
||||
<td>
|
||||
Application refresh
|
||||
</td>
|
||||
<td>
|
||||
<v-btn @click="applicationRefresh">Refresh</v-btn>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Version
|
||||
</td>
|
||||
<td>
|
||||
<span @contextmenu="rightClick">{{ $store.state.windows.version }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- <tr>-->
|
||||
<!-- <td>-->
|
||||
<!-- Check for updates-->
|
||||
<!-- </td>-->
|
||||
<!-- <td>-->
|
||||
<!-- <v-switch-->
|
||||
<!-- flat-->
|
||||
<!-- v-model="checkForUpdate"-->
|
||||
<!-- color="grey "-->
|
||||
<!-- ></v-switch>-->
|
||||
<!-- </td>-->
|
||||
<!-- </tr>-->
|
||||
<tr @dblclick="enableAppRefresh = true">
|
||||
<td>
|
||||
Auto update
|
||||
</td>
|
||||
<td>
|
||||
<v-switch
|
||||
v-model="autoUpdate"
|
||||
flat
|
||||
color="grey "
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="enableAppRefresh">
|
||||
<td>
|
||||
Application refresh
|
||||
</td>
|
||||
<td>
|
||||
<v-btn @click="applicationRefresh">
|
||||
Refresh
|
||||
</v-btn>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</template>
|
||||
</v-simple-table>
|
||||
|
||||
|
||||
<dlgLabelSubmitCancel
|
||||
v-if="dialogShow"
|
||||
:dialogShow="gaDialogShow"
|
||||
:actionsMtd="gaDialogFunction"
|
||||
:dialog-show="gaDialogShow"
|
||||
:actions-mtd="gaDialogFunction"
|
||||
heading="Click submit to disable Google Analytics."
|
||||
type="primary"
|
||||
/>
|
||||
|
||||
<dlgLabelSubmitCancel
|
||||
v-if="dialogShow"
|
||||
:dialogShow="logReportDialogShow"
|
||||
:actionsMtd="logReportDialogFunction"
|
||||
:dialog-show="logReportDialogShow"
|
||||
:actions-mtd="logReportDialogFunction"
|
||||
heading="Error reporting helps us to build a better product. Press cancel to help us build a better product ?"
|
||||
type="primary"
|
||||
/>
|
||||
@@ -69,129 +72,131 @@
|
||||
</template>
|
||||
<script>
|
||||
|
||||
import dlgLabelSubmitCancel from '../../utils/dlgLabelSubmitCancel';
|
||||
import XIcon from "../../global/xIcon";
|
||||
import themes from "../../../helpers/themes";
|
||||
import dlgLabelSubmitCancel from '../../utils/dlgLabelSubmitCancel'
|
||||
|
||||
export default {
|
||||
components: {XIcon, dlgLabelSubmitCancel},
|
||||
components: { dlgLabelSubmitCancel },
|
||||
|
||||
data() {
|
||||
data () {
|
||||
return {
|
||||
rightClickCount: 0,
|
||||
enableAppRefresh: false,
|
||||
gaDialogShow: false,
|
||||
logReportDialogShow: false,
|
||||
languages: [
|
||||
{label: 'English', value: 'en'},
|
||||
{ label: 'English', value: 'en' }
|
||||
// {label: 'Japanese', value: 'ja'},
|
||||
// {label: 'Chinese', value: 'zh'}
|
||||
],
|
||||
item: 'default',
|
||||
item: 'default'
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
checkForUpdate: {
|
||||
get() {
|
||||
get () {
|
||||
return this.$store.state.windows.checkForUpdate
|
||||
}, set(value) {
|
||||
},
|
||||
set (value) {
|
||||
this.$store.commit('windows/MutCheckForUpdate', value)
|
||||
}
|
||||
},
|
||||
autoUpdate: {
|
||||
get() {
|
||||
get () {
|
||||
return this.$store.state.windows.downloadAndUpdateRelease
|
||||
}, set(value) {
|
||||
},
|
||||
set (value) {
|
||||
this.$store.commit('windows/MutDownloadAndUpdateRelease', value)
|
||||
}
|
||||
},
|
||||
isGaEnabled: {
|
||||
get() {
|
||||
get () {
|
||||
return this.$store.state.windows.isGaEnabled
|
||||
}, set(value) {
|
||||
},
|
||||
set (value) {
|
||||
this.$store.commit('windows/MutToggleGaEnabled', value)
|
||||
}
|
||||
},
|
||||
isErrorReportingEnabled: {
|
||||
get() {
|
||||
get () {
|
||||
return this.$store.state.windows.isErrorReportingEnabled
|
||||
}, set(value) {
|
||||
},
|
||||
set (value) {
|
||||
this.$store.commit('windows/MutToggleErrorReportingEnabled', value)
|
||||
}
|
||||
},
|
||||
isTelemetryEnabled: {
|
||||
get() {
|
||||
get () {
|
||||
return this.$store.state.windows.isErrorReportingEnabled
|
||||
}, set(value) {
|
||||
},
|
||||
set (value) {
|
||||
this.$store.commit('windows/MutToggleTelemetryEnabled', value)
|
||||
}
|
||||
},
|
||||
dialogShow: {
|
||||
get() {
|
||||
return this.value;
|
||||
}, set(val) {
|
||||
this.$emit('input', val);
|
||||
get () {
|
||||
return this.value
|
||||
},
|
||||
set (val) {
|
||||
this.$emit('input', val)
|
||||
}
|
||||
},
|
||||
language: {
|
||||
get() {
|
||||
return this.$store.state.windows.language;
|
||||
}, set(val) {
|
||||
this.$store.commit('windows/MutSetLanguage', val);
|
||||
get () {
|
||||
return this.$store.state.windows.language
|
||||
},
|
||||
set (val) {
|
||||
this.$store.commit('windows/MutSetLanguage', val)
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
rightClick() {
|
||||
this.rightClickCount++;
|
||||
rightClick () {
|
||||
this.rightClickCount++
|
||||
if (this.rightClickCount > 5) {
|
||||
// require('electron').remote.getCurrentWindow().toggleDevTools();
|
||||
this.rightClickCount = 0;
|
||||
this.rightClickCount = 0
|
||||
}
|
||||
},
|
||||
async applicationRefresh() {
|
||||
localStorage.removeItem('vuex');
|
||||
location.reload();
|
||||
async applicationRefresh () {
|
||||
localStorage.removeItem('vuex')
|
||||
location.reload()
|
||||
},
|
||||
toggleGa(event) {
|
||||
toggleGa (event) {
|
||||
if (this.isGaEnabled) {
|
||||
this.gaDialogShow = true;
|
||||
} else
|
||||
this.isGaEnabled = true;
|
||||
this.gaDialogShow = true
|
||||
} else { this.isGaEnabled = true }
|
||||
},
|
||||
toggleLogReport(event) {
|
||||
toggleLogReport (event) {
|
||||
if (this.isErrorReportingEnabled) {
|
||||
this.logReportDialogShow = true;
|
||||
} else
|
||||
this.isErrorReportingEnabled = true;
|
||||
this.logReportDialogShow = true
|
||||
} else { this.isErrorReportingEnabled = true }
|
||||
},
|
||||
logReportDialogFunction(action) {
|
||||
logReportDialogFunction (action) {
|
||||
if (action !== 'hideDialog' && this.$store.state.users.user && this.$store.state.users.user.email) {
|
||||
this.isErrorReportingEnabled = false;
|
||||
this.isErrorReportingEnabled = false
|
||||
} else {
|
||||
this.$toast.error('Only a registered user can disable Error Reporting, Please Login then disable.').goAway(5000)
|
||||
}
|
||||
this.logReportDialogShow = false;
|
||||
this.logReportDialogShow = false
|
||||
},
|
||||
gaDialogFunction(action) {
|
||||
gaDialogFunction (action) {
|
||||
if (action !== 'hideDialog') {
|
||||
if (this.$store.state.users.user && this.$store.state.users.user.email) {
|
||||
this.isGaEnabled = false;
|
||||
this.isGaEnabled = false
|
||||
} else {
|
||||
this.$toast.error('Only a registered user can disable Google Analytics, Please Login then disable.').goAway(5000)
|
||||
}
|
||||
}
|
||||
this.gaDialogShow = false;
|
||||
},
|
||||
this.gaDialogShow = false
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
|
||||
</style>
|
||||
<!--
|
||||
/**
|
||||
|
||||
@@ -23,10 +23,12 @@
|
||||
color="primary"
|
||||
small
|
||||
outlined
|
||||
@click="exportMeta"
|
||||
:loading="loading === 'export-file'"
|
||||
@click="exportMeta"
|
||||
>
|
||||
<v-icon small>mdi-export</v-icon>
|
||||
<v-icon small>
|
||||
mdi-export
|
||||
</v-icon>
|
||||
<!-- Export to file -->
|
||||
{{ $t('management.meta.export_to_file') }}
|
||||
</v-btn>
|
||||
@@ -47,7 +49,9 @@
|
||||
outlined
|
||||
@click="importMeta"
|
||||
>
|
||||
<v-icon small>mdi-import</v-icon>
|
||||
<v-icon small>
|
||||
mdi-import
|
||||
</v-icon>
|
||||
|
||||
<!-- Import -->
|
||||
{{ $t('management.meta.import') }}
|
||||
@@ -69,7 +73,9 @@
|
||||
:loading="loading === 'export-zip'"
|
||||
@click="exportMetaZip()"
|
||||
>
|
||||
<v-icon small>mdi-export</v-icon>
|
||||
<v-icon small>
|
||||
mdi-export
|
||||
</v-icon>
|
||||
<!-- Export zip -->
|
||||
{{ $t('management.meta.export_to_zip') }}
|
||||
</v-btn>
|
||||
@@ -89,19 +95,21 @@
|
||||
outlined
|
||||
@click="$refs.importFile.click()"
|
||||
>
|
||||
<v-icon small>mdi-import</v-icon>
|
||||
<v-icon small>
|
||||
mdi-import
|
||||
</v-icon>
|
||||
|
||||
<!-- Import Zip -->
|
||||
{{ $t('management.meta.import_zip') }}
|
||||
</v-btn>
|
||||
|
||||
<input
|
||||
v-show="false"
|
||||
ref="importFile"
|
||||
type="file"
|
||||
accept=".zip"
|
||||
@change="importMetaZip"
|
||||
v-show="false"
|
||||
ref="importFile"
|
||||
/>
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -118,7 +126,9 @@
|
||||
outlined
|
||||
@click="resetMeta"
|
||||
>
|
||||
<v-icon small>mdi-delete-variant</v-icon>
|
||||
<v-icon small>
|
||||
mdi-delete-variant
|
||||
</v-icon>
|
||||
<!-- Reset -->
|
||||
{{ $t('management.meta.reset') }}
|
||||
</v-btn>
|
||||
@@ -128,169 +138,168 @@
|
||||
</v-simple-table>
|
||||
|
||||
<dlg-label-submit-cancel
|
||||
type="primary"
|
||||
v-if="dialogShow"
|
||||
:actionsMtd="confirmAction"
|
||||
:dialogShow="dialogShow"
|
||||
type="primary"
|
||||
:actions-mtd="confirmAction"
|
||||
:dialog-show="dialogShow"
|
||||
:heading="confirmMessage"
|
||||
>
|
||||
</dlg-label-submit-cancel>
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DlgLabelSubmitCancel from '@/components/utils/dlgLabelSubmitCancel';
|
||||
import DlgLabelSubmitCancel from '@/components/utils/dlgLabelSubmitCancel'
|
||||
|
||||
export default {
|
||||
name: 'xc-meta',
|
||||
name: 'XcMeta',
|
||||
components: {
|
||||
DlgLabelSubmitCancel,
|
||||
DlgLabelSubmitCancel
|
||||
},
|
||||
data: () => ({
|
||||
loading: null,
|
||||
dialogShow: false,
|
||||
confirmAction: null,
|
||||
confirmMessage: '',
|
||||
confirmMessage: ''
|
||||
}),
|
||||
methods: {
|
||||
async exportMeta() {
|
||||
this.dialogShow = true;
|
||||
this.confirmMessage = 'Do you want to export metadata from meta tables?';
|
||||
this.confirmAction = async act => {
|
||||
async exportMeta () {
|
||||
this.dialogShow = true
|
||||
this.confirmMessage = 'Do you want to export metadata from meta tables?'
|
||||
this.confirmAction = async (act) => {
|
||||
if (act === 'hideDialog') {
|
||||
this.dialogShow = false;
|
||||
this.dialogShow = false
|
||||
} else {
|
||||
this.loading = 'export-file';
|
||||
this.loading = 'export-file'
|
||||
try {
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [
|
||||
{
|
||||
// dbAlias: 'db',
|
||||
env: 'dev',
|
||||
env: 'dev'
|
||||
},
|
||||
'xcMetaTablesExportDbToLocalFs',
|
||||
]);
|
||||
this.$toast.success('Successfully exported metadata').goAway(3000);
|
||||
'xcMetaTablesExportDbToLocalFs'
|
||||
])
|
||||
this.$toast.success('Successfully exported metadata').goAway(3000)
|
||||
} catch (e) {
|
||||
this.$toast.error('Some internal error occurred').goAway(3000);
|
||||
this.$toast.error('Some internal error occurred').goAway(3000)
|
||||
}
|
||||
this.dialogShow = false;
|
||||
this.loading = null;
|
||||
this.dialogShow = false
|
||||
this.loading = null
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
async exportMetaZip() {
|
||||
this.dialogShow = true;
|
||||
this.confirmMessage = 'Do you want to export metadata from meta tables?';
|
||||
this.confirmAction = async act => {
|
||||
async exportMetaZip () {
|
||||
this.dialogShow = true
|
||||
this.confirmMessage = 'Do you want to export metadata from meta tables?'
|
||||
this.confirmAction = async (act) => {
|
||||
if (act === 'hideDialog') {
|
||||
this.dialogShow = false;
|
||||
this.dialogShow = false
|
||||
} else {
|
||||
this.loading = 'export-zip';
|
||||
let data;
|
||||
this.loading = 'export-zip'
|
||||
let data
|
||||
try {
|
||||
data = await this.$store.dispatch('sqlMgr/ActSqlOp', [
|
||||
{
|
||||
// dbAlias: 'db',
|
||||
env: 'dev',
|
||||
env: 'dev'
|
||||
},
|
||||
'xcMetaTablesExportDbToZip',
|
||||
null,
|
||||
null,
|
||||
{
|
||||
responseType: 'blob',
|
||||
},
|
||||
]);
|
||||
const url = window.URL.createObjectURL(new Blob([data], { type: 'application/zip' }));
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.setAttribute('download', 'meta.zip'); //or any other extension
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
this.$toast.success('Successfully exported metadata').goAway(3000);
|
||||
responseType: 'blob'
|
||||
}
|
||||
])
|
||||
const url = window.URL.createObjectURL(new Blob([data], { type: 'application/zip' }))
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.setAttribute('download', 'meta.zip') // or any other extension
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
this.$toast.success('Successfully exported metadata').goAway(3000)
|
||||
} catch (e) {
|
||||
this.$toast.error('Some internal error occurred').goAway(3000);
|
||||
this.$toast.error('Some internal error occurred').goAway(3000)
|
||||
}
|
||||
this.dialogShow = false;
|
||||
this.loading = null;
|
||||
this.dialogShow = false
|
||||
this.loading = null
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
async resetMeta() {
|
||||
this.dialogShow = true;
|
||||
this.confirmMessage = 'Do you want to clear metadata from meta tables?';
|
||||
this.confirmAction = async act => {
|
||||
async resetMeta () {
|
||||
this.dialogShow = true
|
||||
this.confirmMessage = 'Do you want to clear metadata from meta tables?'
|
||||
this.confirmAction = async (act) => {
|
||||
if (act === 'hideDialog') {
|
||||
this.dialogShow = false;
|
||||
this.dialogShow = false
|
||||
} else {
|
||||
this.loading = 'reset-metadata';
|
||||
this.loading = 'reset-metadata'
|
||||
try {
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [
|
||||
{
|
||||
// dbAlias: 'db',
|
||||
env: 'dev',
|
||||
env: 'dev'
|
||||
},
|
||||
'xcMetaTablesReset',
|
||||
]);
|
||||
this.$toast.success('Metadata cleared successfully').goAway(3000);
|
||||
'xcMetaTablesReset'
|
||||
])
|
||||
this.$toast.success('Metadata cleared successfully').goAway(3000)
|
||||
} catch (e) {
|
||||
this.$toast.error('Some internal error occurred').goAway(3000);
|
||||
this.$toast.error('Some internal error occurred').goAway(3000)
|
||||
}
|
||||
this.dialogShow = false;
|
||||
this.loading = null;
|
||||
this.dialogShow = false
|
||||
this.loading = null
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
async importMeta() {
|
||||
this.dialogShow = true;
|
||||
this.confirmMessage = 'Do you want to import metadata from meta directory?';
|
||||
this.confirmAction = async act => {
|
||||
async importMeta () {
|
||||
this.dialogShow = true
|
||||
this.confirmMessage = 'Do you want to import metadata from meta directory?'
|
||||
this.confirmAction = async (act) => {
|
||||
if (act === 'hideDialog') {
|
||||
this.dialogShow = false;
|
||||
this.dialogShow = false
|
||||
} else {
|
||||
this.loading = 'import-file';
|
||||
this.loading = 'import-file'
|
||||
try {
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [
|
||||
{
|
||||
env: 'dev',
|
||||
env: 'dev'
|
||||
},
|
||||
'xcMetaTablesImportLocalFsToDb',
|
||||
]);
|
||||
'xcMetaTablesImportLocalFsToDb'
|
||||
])
|
||||
|
||||
this.$toast.success('Metadata imported successfully').goAway(3000);
|
||||
this.$toast.success('Metadata imported successfully').goAway(3000)
|
||||
} catch (e) {
|
||||
this.$toast.error('Some internal error occurred').goAway(3000);
|
||||
this.$toast.error('Some internal error occurred').goAway(3000)
|
||||
}
|
||||
this.dialogShow = false;
|
||||
this.loading = null;
|
||||
this.dialogShow = false
|
||||
this.loading = null
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
async importMetaZip() {
|
||||
async importMetaZip () {
|
||||
if (this.$refs.importFile && this.$refs.importFile.files && this.$refs.importFile.files[0]) {
|
||||
const zipFile = this.$refs.importFile.files[0];
|
||||
this.loading = 'import-zip';
|
||||
const zipFile = this.$refs.importFile.files[0]
|
||||
this.loading = 'import-zip'
|
||||
try {
|
||||
this.$refs.importFile.value = '';
|
||||
this.$refs.importFile.value = ''
|
||||
await this.$store.dispatch('sqlMgr/ActUpload', [
|
||||
{
|
||||
// dbAlias: 'db',
|
||||
env: 'dev',
|
||||
env: 'dev'
|
||||
},
|
||||
'xcMetaTablesImportZipToLocalFsAndDb',
|
||||
{},
|
||||
zipFile,
|
||||
]);
|
||||
this.$toast.success('Successfully imported metadata').goAway(3000);
|
||||
zipFile
|
||||
])
|
||||
this.$toast.success('Successfully imported metadata').goAway(3000)
|
||||
} catch (e) {
|
||||
this.$toast.error('Some internal error occurred').goAway(3000);
|
||||
this.$toast.error('Some internal error occurred').goAway(3000)
|
||||
}
|
||||
this.dialogShow = false;
|
||||
this.loading = null;
|
||||
this.dialogShow = false
|
||||
this.loading = null
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user