updated vmail-ui

This commit is contained in:
Paul 2021-04-05 21:33:58 +02:00
parent 0e11b00087
commit dcfc49919c
20 changed files with 2616 additions and 2366 deletions

View File

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

4244
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -18,14 +18,14 @@
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "~4.4.0", "@vue/cli-plugin-babel": "~4.4.0",
"@vue/cli-plugin-eslint": "~4.4.0", "@vue/cli-plugin-eslint": "~4.4.0",
"@vue/cli-plugin-router": "^4.4.6", "@vue/cli-plugin-router": "^4.5.12",
"@vue/cli-service": "~4.4.0", "@vue/cli-service": "~4.4.0",
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",
"eslint": "^6.7.2", "eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2", "eslint-plugin-vue": "^6.2.2",
"sass": "^1.19.0", "sass": "^1.19.0",
"sass-loader": "^8.0.0", "sass-loader": "^8.0.0",
"vue-cli-plugin-vuetify": "^2.0.6", "vue-cli-plugin-vuetify": "^2.3.1",
"vue-template-compiler": "^2.6.11", "vue-template-compiler": "^2.6.11",
"vuetify-loader": "^1.3.0" "vuetify-loader": "^1.3.0"
}, },
@ -48,4 +48,4 @@
"last 2 versions", "last 2 versions",
"not dead" "not dead"
] ]
} }

View File

@ -8,15 +8,15 @@
</div> </div>
<div class="routers"> <div class="routers">
<v-icon small>mdi-account-settings</v-icon> <v-icon small>mdi-account-settings</v-icon>
<router-link to="/admin">Admin</router-link> <router-link to="/admin">Admins</router-link>
</div> </div>
<div class="routers"> <div class="routers">
<v-icon small>mdi-email-box</v-icon> <v-icon small>mdi-email-box</v-icon>
<router-link to="/mailbox">Mailbox</router-link> <router-link to="/mailbox">Mailboxes</router-link>
</div> </div>
<div class="routers"> <div class="routers">
<v-icon small>mdi-at</v-icon> <v-icon small>mdi-at</v-icon>
<router-link to="/alias">Alias</router-link> <router-link to="/alias">Aliases</router-link>
</div> </div>
<div class="routers"> <div class="routers">
<v-icon small>mdi-format-list-checkbox</v-icon> <v-icon small>mdi-format-list-checkbox</v-icon>

View File

@ -1 +1,26 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.5 100"><defs><style>.cls-1{fill:#1697f6;}.cls-2{fill:#7bc6ff;}.cls-3{fill:#1867c0;}.cls-4{fill:#aeddff;}</style></defs><title>Artboard 46</title><polyline class="cls-1" points="43.75 0 23.31 0 43.75 48.32"/><polygon class="cls-2" points="43.75 62.5 43.75 100 0 14.58 22.92 14.58 43.75 62.5"/><polyline class="cls-3" points="43.75 0 64.19 0 43.75 48.32"/><polygon class="cls-4" points="64.58 14.58 87.5 14.58 43.75 100 43.75 62.5 64.58 14.58"/></svg> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.5 100">
<defs>
<style>
.cls-1 {
fill: #1697f6;
}
.cls-2 {
fill: #7bc6ff;
}
.cls-3 {
fill: #1867c0;
}
.cls-4 {
fill: #aeddff;
}
</style>
</defs>
<title>Artboard 46</title>
<polyline class="cls-1" points="43.75 0 23.31 0 43.75 48.32" />
<polygon class="cls-2" points="43.75 62.5 43.75 100 0 14.58 22.92 14.58 43.75 62.5" />
<polyline class="cls-3" points="43.75 0 64.19 0 43.75 48.32" />
<polygon class="cls-4" points="64.58 14.58 87.5 14.58 43.75 100 43.75 62.5 64.58 14.58" />
</svg>

Before

Width:  |  Height:  |  Size: 539 B

After

Width:  |  Height:  |  Size: 779 B

View File

@ -1,21 +0,0 @@
import Axios from "axios";
import VmailApi from "@/classes/vmailapi.js"
export default class Admin {
constructor(url) {
this.vmailapi = new VmailApi(url);
this.apipath = "/api/admin";
}
GetList() {
return Axios.get(this.vmailapi.GetUrl() + this.apipath)
}
GetItem(name) {
return Axios.get(this.vmailapi.GetUrl() + this.apipath + "/" + name)
}
DeleteItem(name) {
return Axios.delete(this.vmailapi.GetUrl() + this.apipath + "/" + name)
}
}

View File

@ -1,21 +0,0 @@
import Axios from "axios";
import VmailApi from "@/classes/vmailapi.js"
export default class Alias {
constructor(url) {
this.vmailapi = new VmailApi(url);
this.apipath = "/api/alias";
}
GetList() {
return Axios.get(this.vmailapi.GetUrl() + this.apipath)
}
GetItem(name) {
return Axios.get(this.vmailapi.GetUrl() + this.apipath + "/" + name)
}
DeleteItem(name) {
return Axios.delete(this.vmailapi.GetUrl() + this.apipath + "/" + name)
}
}

View File

@ -1,14 +0,0 @@
import Axios from "axios";
import VmailApi from "@/classes/vmailapi.js"
export default class Log {
constructor(url) {
this.vmailapi = new VmailApi(url);
this.apipath = "/api/log";
this.readonly = true;
}
GetList() {
return Axios.get(this.vmailapi.GetUrl() + this.apipath)
}
}

View File

@ -1,21 +0,0 @@
import Axios from "axios";
import VmailApi from "@/classes/vmailapi.js"
export default class Mailbox {
constructor(url) {
this.vmailapi = new VmailApi(url);
this.apipath = "/api/mailbox";
}
GetList() {
return Axios.get(this.vmailapi.GetUrl() + this.apipath)
}
GetItem(name) {
return Axios.get(this.vmailapi.GetUrl() + this.apipath + "/" + name)
}
DeleteItem(name) {
return Axios.delete(this.vmailapi.GetUrl() + this.apipath + "/" + name)
}
}

View File

@ -3,6 +3,10 @@ export default class VmailApi {
this.url = url; this.url = url;
} }
Auth() {
return this;
}
GetUrl() { GetUrl() {
return this.url; return this.url;
} }

View File

@ -0,0 +1,34 @@
import Axios from "axios";
import VmailApi from "@/classes/vmailapi.js"
export default class VmailObject {
constructor(url, objecttype, readonly) {
this.vmailapi = new VmailApi(url);
this.apipath = `/api/${objecttype}`;
this.readonly = readonly;
}
GetModel() {
return Axios.get(this.vmailapi.GetUrl() + this.apipath + "/" + "model")
}
GetList() {
return Axios.get(this.vmailapi.GetUrl() + this.apipath)
}
GetItem(id) {
return Axios.get(this.vmailapi.GetUrl() + this.apipath + "/" + id)
}
CreateItem(data) {
return Axios.post(this.vmailapi.GetUrl() + this.apipath, data)
}
ModifyItem(id, data) {
return Axios.put(this.vmailapi.GetUrl() + this.apipath + "/" + id, data)
}
DeleteItem(id) {
return Axios.delete(this.vmailapi.GetUrl() + this.apipath + "/" + id)
}
}

View File

View File

@ -1,7 +1,10 @@
<template> <template>
<div class="List"> <div class="list">
<v-data-table :headers="headers" :items="itemlist" :items-per-page="20" class="elevation-1"> <v-data-table :headers="headers" :items="itemlist" :items-per-page="20" class="elevation-1">
<template v-slot:item.actions="{ item }"> <template v-slot:[`item.active`]="{ item }">
<v-simple-checkbox v-model="item.active" disabled></v-simple-checkbox>
</template>
<template v-slot:[`item.actions`]="{ item }">
<v-icon small class="mr-2" @click="editItem(item)"> <v-icon small class="mr-2" @click="editItem(item)">
mdi-pencil mdi-pencil
</v-icon> </v-icon>
@ -21,8 +24,10 @@
<v-row v-for="item in headers" :key="item"> <v-row v-for="item in headers" :key="item">
<template v-if="item.editable"> <template v-if="item.editable">
<v-col cols="16" sm="8" md="6"> <v-col cols="16" sm="8" md="6">
<v-checkbox v-if="typeof editedItem[item.value] == 'boolean'" v-model="editedItem[item.value]" v-bind:label="item.text"></v-checkbox> <v-checkbox v-if="typeof editedItem[item.value] == 'boolean'" v-model="editedItem[item.value]"
<v-text-field v-if="typeof editedItem[item.value] == 'string'" v-model="editedItem[item.value]" v-bind:label="item.text"></v-text-field> v-bind:label="item.text"></v-checkbox>
<v-text-field v-if="typeof editedItem[item.value] == 'string'" v-model="editedItem[item.value]"
v-bind:label="item.text"></v-text-field>
</v-col> </v-col>
</template> </template>
</v-row> </v-row>
@ -35,6 +40,15 @@
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-dialog> </v-dialog>
<v-snackbar v-model="snackbarshow" :timeout="snackbartimeout">
{{ snackbartext }}
<template v-slot:action="{ attrs }">
<v-btn color="blue" text v-bind="attrs" @click="snackbarshow=false">
Close
</v-btn>
</template>
</v-snackbar>
</div> </div>
</template> </template>
@ -43,6 +57,9 @@
name: 'List', name: 'List',
data() { data() {
return { return {
snackbarshow: false,
snackbartext: "",
snackbartimeout: 10000,
colsize: 3, colsize: 3,
editedItem: {} editedItem: {}
} }
@ -53,9 +70,11 @@
} }
}, },
methods: { methods: {
createItem(item) { /*createItem(name) {
return item; this.editedIndex = this.itemlist.indexOf(item);
}, this.editedItem = Object.assign({}, item);
this.dialog = true;
},*/
editItem(item) { editItem(item) {
this.editedIndex = this.itemlist.indexOf(item); this.editedIndex = this.itemlist.indexOf(item);
this.editedItem = Object.assign({}, item); this.editedItem = Object.assign({}, item);
@ -64,9 +83,10 @@
deleteItem(item) { deleteItem(item) {
const index = this.itemlist.indexOf(item); const index = this.itemlist.indexOf(item);
// Assuming that first elem of item is the primary key // Assuming that first elem of item is the primary key
confirm('Are you sure you want to delete this item?') && this.object.DeleteItem(item[Object.keys(item)[0]]).then(() => { confirm('Are you sure you want to delete this item?') && this.object.DeleteItem(item[Object.keys(item)[0]])
this.itemlist.splice(index, 1); .then(() => {
}); this.itemlist.splice(index, 1);
});
}, },
close() { close() {
this.dialog = false this.dialog = false
@ -77,18 +97,22 @@
}, },
save() { save() {
if (this.editedIndex > -1) { if (this.editedIndex > -1) {
Object.assign(this.desserts[this.editedIndex], this.editedItem) Object.assign(this.itemlist[this.editedIndex], this.editedItem)
} else { } else {
this.desserts.push(this.editedItem) this.itemlist.push(this.editedItem)
} }
this.close() this.object.ModifyItem(this.editedItem.id, this.editedItem).then((response) => {
this.snackbarshow = true;
this.snackbartext = response;
this.$parent.RefreshData();
});
this.close();
}, },
}, },
props: ["headers", "itemlist", "object"] props: ["headers", "itemlist", "object"]
} }
</script> </script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped> <style scoped>
h3 { h3 {
margin: 40px 0 0; margin: 40px 0 0;

View File

@ -1,23 +1,13 @@
<template> <template>
<div class="text-center"> <div class="text-center">
<v-menu offset-y <v-menu offset-y>
>
<template v-slot:activator="{ on, attrs }"> <template v-slot:activator="{ on, attrs }">
<v-btn <v-btn color="primary" dark v-bind="attrs" v-on="on">
color="primary"
dark
v-bind="attrs"
v-on="on"
>
Create Create
</v-btn> </v-btn>
</template> </template>
<v-list> <v-list>
<v-list-item <v-list-item v-for="(item, index) in items" :key="index" @click="opendialog(item.dest)" link>
v-for="(item, index) in items"
:key="index"
@click="test"
>
<v-list-item-title>{{ item.title }}</v-list-item-title> <v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item> </v-list-item>
</v-list> </v-list>
@ -26,15 +16,37 @@
</template> </template>
<script> <script>
import Vmailobject from '@/classes/vmailobject.js'
export default { export default {
name: 'Menu', name: 'Menu',
data: () => ({ data: () => ({
items: [ items: [{
{ title: 'Alias' }, title: 'Admin',
{ title: 'Mailbox' }, dest: 'admin',
{ title: 'Domain' }, cls: Vmailobject
},
{
title: 'Alias',
dest: 'alias',
cls: Vmailobject
},
{
title: 'Domain',
dest: 'domain',
cls: Vmailobject
},
{
title: 'Mailbox',
dest: 'mailbox',
cls: Vmailobject
},
] ]
}) }),
} methods: {
opendialog(item) {
console.log(item);
},
}
}
</script> </script>

View File

@ -4,8 +4,7 @@ import Mailbox from '../views/Mailbox.vue'
import Alias from '../views/Alias.vue' import Alias from '../views/Alias.vue'
import Log from '../views/Log.vue' import Log from '../views/Log.vue'
const routes = [ const routes = [{
{
path: '/', path: '/',
component: Home, component: Home,
}, },

View File

@ -1,47 +1,88 @@
<template> <template>
<div class="Admin"> <div class="admin">
<List :vmailapi="vmailapi" :headers="attrs" :itemlist="itemlist"/> <List :headers="attrs" :itemlist="itemlist" :object="admin" />
</div> </div>
</template> </template>
<script> <script>
import List from '@/components/list.vue' import Vmailobject from '@/classes/vmailobject.js'
import Admin from '@/classes/admin.js' import List from '@/components/list.vue'
export default { export default {
name: 'Admins', name: 'Admins',
data() { data() {
return { return {
attrs : [ attrs: [{
{text: "Username", value:"username", sortable: true, editable: true}, text: "Username",
{text: "Created", value:"created", sortable: true, editable: true}, value: "username",
{text: "Modified", value:"modified", sortable: true, editable: true}, sortable: true,
{text: "Active", value:"active", sortable: true, editable: true}, editable: true
{text: "Superadmin", value:"superadmin", sortable: true, editable: true}, },
{text: "Phone", value:"phone", sortable: true, editable: true}, {
{text: "Actions", value:"actions", sortable: false, editable: false}, text: "Created",
], value: "created",
itemlist: [], sortable: true,
item: {} editable: false
} },
}, {
components: { text: "Modified",
List value: "modified",
}, sortable: true,
props: ["vmailapi"], editable: false
mounted () { },
let admin = new Admin(this.vmailapi.GetUrl()) {
admin.GetList().then(response => { text: "Active",
this.itemlist = response.data; value: "active",
}) sortable: true,
}, editable: true
methods: { },
DeleteItem (name) { {
this.admin = new Admin(this.vmailapi.GetUrl()); text: "Super administrator",
this.admin.DeleteItem(name).then(response => { value: "superadmin",
return response; sortable: true,
}); editable: true
},
{
text: "Phone",
value: "phone",
sortable: true,
editable: true
},
{
text: "Actions",
value: "actions",
sortable: false,
editable: false
},
],
itemlist: [],
item: {}
}
},
components: {
List
},
props: ["vmailapi"],
mounted() {
this.admin = new Vmailobject(this.vmailapi.GetUrl(), this.$el.className)
this.RefreshData();
},
methods: {
RefreshData() {
this.admin.GetList().then(response => {
this.itemlist = response.data;
});
},
ModifyItem(id, item) {
this.admin.ModifyItem(id, item).then(response => {
return response;
});
},
DeleteItem(id) {
this.admin.DeleteItem(id).then(response => {
return response;
});
}
} }
} }
} </script>
</script>

View File

@ -1,47 +1,88 @@
<template> <template>
<div class="alias"> <div class="alias">
<List :vmailapi="vmailapi" :headers="attrs" :itemlist="itemlist" :object="alias"/> <List :headers="attrs" :itemlist="itemlist" :object="alias" />
</div> </div>
</template> </template>
<script> <script>
import List from '@/components/list.vue' import Vmailobject from '@/classes/vmailobject.js'
import Alias from '@/classes/alias.js' import List from '@/components/list.vue'
export default { export default {
name: 'Alias', name: 'Alias',
data() { data() {
return { return {
attrs : [ attrs: [{
{text: "Address", value:"address", sortable: true, editable: true}, text: "Address",
{text: "Destination", value:"goto", sortable: true, editable: true}, value: "address",
{text: "Domain", value:"domain", sortable: true, editable: true}, sortable: true,
{text: "Created", value:"created", sortable: true, editable: true}, editable: true
{text: "Modified", value:"modified", sortable: true, editable: true}, },
{text: "Active", value:"active", sortable: true, editable: true}, {
{text: "Actions", value:"actions", sortable: false, editable: false}, text: "Destination",
], value: "goto",
itemlist: [], sortable: true,
item: {} editable: true
} },
}, {
components: { text: "Domain",
List value: "domain",
}, sortable: true,
props: ["vmailapi"], editable: true
mounted () { },
this.alias = new Alias(this.vmailapi.GetUrl()) {
this.alias.GetList().then(response => { text: "Created",
this.itemlist = response.data; value: "created",
}) sortable: true,
}, editable: false
methods: { },
DeleteItem (name) { {
this.alias = new Alias(this.vmailapi.GetUrl()); text: "Modified",
this.alias.DeleteItem(name).then(response => { value: "modified",
return response; sortable: true,
}); editable: false
},
{
text: "Active",
value: "active",
sortable: true,
editable: false
},
{
text: "Actions",
value: "actions",
sortable: false,
editable: false
},
],
itemlist: [],
item: {}
}
},
components: {
List
},
props: ["vmailapi"],
mounted() {
this.alias = new Vmailobject(this.vmailapi.GetUrl(), this.$el.className)
this.RefreshData();
},
methods: {
RefreshData() {
this.alias.GetList().then(response => {
this.itemlist = response.data;
})
},
ModifyItem(id, item) {
this.alias.ModifyItem(id, item).then(response => {
return response;
});
},
DeleteItem(id) {
this.alias.DeleteItem(id).then(response => {
return response;
});
}
} }
} }
}
</script> </script>

View File

@ -6,14 +6,12 @@
</template> </template>
<script> <script>
export default { export default {
name: 'Home', name: 'Home',
data() { data() {
return { return {}
} },
}, components: {},
components: { props: ["vmailapi"]
}, }
props: ["vmailapi"] </script>
}
</script>

View File

@ -1,38 +1,56 @@
<template> <template>
<div class="log"> <div class="log">
<List :vmailapi="vmailapi" :headers="attrs" :itemlist="itemlist"/> <List :headers="attrs" :itemlist="itemlist" :object="log" />
</div> </div>
</template> </template>
<script> <script>
import List from '@/components/list.vue' import Vmailobject from '@/classes/vmailobject.js'
import Log from '@/classes/log.js' import List from '@/components/list.vue'
export default { export default {
name: 'Log', name: 'Log',
data() { data() {
return { return {
attrs : [ attrs: [{
{text: "ID", value:"id"}, text: "Date",
{text: "Timestamp", value:"timestamp"}, value: "timestamp"
{text: "Username", value:"username"}, },
{text: "Domain", value:"domain"}, {
{text: "Action", value:"action"}, text: "Username / IP",
{text: "Data", value:"data"}, value: "username"
], },
itemlist: [], {
item: {} text: "Domain",
value: "domain"
},
{
text: "Action",
value: "action"
},
{
text: "Modified Data",
value: "data"
},
],
itemlist: [],
item: {}
}
},
components: {
List
},
props: ["vmailapi"],
mounted() {
this.log = new Vmailobject(this.vmailapi.GetUrl(), this.$el.className)
this.RefreshData()
},
methods: {
RefreshData() {
this.log.GetList().then(response => {
this.itemlist = response.data;
})
}
} }
},
components: {
List
},
props: ["vmailapi"],
mounted () {
let log = new Log(this.vmailapi.GetUrl())
log.GetList().then(response => {
this.itemlist = response.data;
})
} }
}
</script> </script>

View File

@ -1,51 +1,112 @@
<template> <template>
<div class="mailbox"> <div class="mailbox">
<List :vmailapi="vmailapi" :headers="attrs" :itemlist="itemlist"/> <List :headers="attrs" :itemlist="itemlist" :object="mailbox" />
</div> </div>
</template> </template>
<script> <script>
import List from '@/components/list.vue' import Vmailobject from '@/classes/vmailobject.js'
import Mailbox from '@/classes/mailbox.js' import List from '@/components/list.vue'
export default { export default {
name: 'Mailbox', name: 'Mailbox',
data() { data() {
return { return {
attrs : [ attrs: [{
{text: "Username", value:"username", sortable: true, editable: true}, text: "Username",
{text: "Name", value:"name", sortable: true, editable: true}, value: "username",
{text: "Maildir", value:"maildir", sortable: true, editable: true}, sortable: true,
{text: "Quota", value:"quota", sortable: true, editable: true}, editable: true
{text: "Created", value:"created", sortable: true, editable: true}, },
{text: "Modified", value:"modified", sortable: true, editable: true}, {
{text: "Active", value:"active", sortable: true, editable: true}, text: "Name",
{text: "Domain", value:"domain", sortable: true, editable: true}, value: "name",
{text: "LocalPart", value:"localpart", sortable: true, editable: true}, sortable: true,
{text: "Phone", value:"phone", sortable: true, editable: true}, editable: true
{text: "Actions", value:"actions", sortable: false, editable: false}, },
], {
itemlist: [], text: "Mail directory",
item: {} value: "maildir",
} sortable: true,
}, editable: true
components: { },
List {
}, text: "Quota",
props: ["vmailapi"], value: "quota",
mounted () { sortable: true,
let mailbox = new Mailbox(this.vmailapi.GetUrl()) editable: true
mailbox.GetList().then(response => { },
this.itemlist = response.data; {
}) text: "Created",
}, value: "created",
methods: { sortable: true,
DeleteItem (name) { editable: false
this.mailbox = new Mailbox(this.vmailapi.GetUrl()); },
this.mailbox.DeleteItem(name).then(response => { {
return response; text: "Modified",
}); value: "modified",
sortable: true,
editable: false
},
{
text: "Active",
value: "active",
sortable: true,
editable: false
},
{
text: "Domain",
value: "domain",
sortable: true,
editable: true
},
{
text: "Email local part",
value: "localpart",
sortable: true,
editable: true
},
{
text: "Phone",
value: "phone",
sortable: true,
editable: true
},
{
text: "Actions",
value: "actions",
sortable: false,
editable: false
},
],
itemlist: [],
item: {}
}
},
components: {
List
},
props: ["vmailapi"],
mounted() {
this.mailbox = new Vmailobject(this.vmailapi.GetUrl(), this.$el.className)
this.RefreshData()
},
methods: {
RefreshData() {
this.mailbox.GetList().then(response => {
this.itemlist = response.data;
})
},
ModifyItem(id, item) {
this.mailbox.ModifyItem(id, item).then(response => {
return response;
});
},
DeleteItem(id) {
this.mailbox.DeleteItem(id).then(response => {
return response;
});
}
} }
} }
}
</script> </script>