1
0
mirror of https://github.com/donaldzou/WGDashboard.git synced 2024-11-06 16:00:28 +01:00

Peer schedule style is almost done

But I don't feel it quite right..
This commit is contained in:
Donald Zou 2024-06-25 23:02:13 +08:00
parent 6c529a6908
commit 2d838b69fd
9 changed files with 298 additions and 183 deletions

View File

@ -126,6 +126,7 @@ class PeerJobs:
self.__getJobs() self.__getJobs()
def __getJobs(self): def __getJobs(self):
self.Jobs.clear()
jobs = self.jobdbCursor.execute("SELECT * FROM PeerJobs WHERE ExpireDate IS NULL").fetchall() jobs = self.jobdbCursor.execute("SELECT * FROM PeerJobs WHERE ExpireDate IS NULL").fetchall()
for job in jobs: for job in jobs:
self.Jobs.append(PeerJob( self.Jobs.append(PeerJob(
@ -158,6 +159,22 @@ class PeerJobs:
def searchJob(self, Configuration: str, Peer: str): def searchJob(self, Configuration: str, Peer: str):
return list(filter(lambda x: x.Configuration == Configuration and x.Peer == Peer, self.Jobs)) return list(filter(lambda x: x.Configuration == Configuration and x.Peer == Peer, self.Jobs))
def saveJob(self, Job: PeerJob) -> tuple[bool, list] | tuple[bool, str]:
try:
if (len(str(Job.CreationDate))) == 0:
self.jobdbCursor.execute('''
INSERT INTO PeerJobs VALUES (?, ?, ?, ?, ?, ?, strftime('%Y-%m-%d %H:%M:%S','now'), NULL, ?)
''', (Job.JobID, Job.Configuration, Job.Peer, Job.Field, Job.Operator, Job.Value, Job.Action,))
else:
self.jobdbCursor.execute('''
UPDATE PeerJobs SET Field = ?, Operator = ?, Value = ?, Action = ? WHERE JobID = ?
''', (Job.Field, Job.Operator, Job.Value, Job.Action, Job.JobID))
self.jobdb.commit()
self.__getJobs()
return True, list(filter(lambda x: x.Configuration == Job.Configuration and x.Peer == Job.Peer and x.JobID == Job.JobID, self.Jobs))
except Exception as e:
return False, str(e)
class WireguardConfiguration: class WireguardConfiguration:
class InvalidConfigurationFileException(Exception): class InvalidConfigurationFileException(Exception):
@ -233,7 +250,6 @@ class WireguardConfiguration:
self.__parser.write(configFile) self.__parser.write(configFile)
self.Peers: list[Peer] = [] self.Peers: list[Peer] = []
# Create tables in database # Create tables in database
self.__createDatabase() self.__createDatabase()
self.getPeersList() self.getPeersList()
@ -638,6 +654,7 @@ class Peer:
self.getJobs() self.getJobs()
def toJson(self): def toJson(self):
self.getJobs()
return self.__dict__ return self.__dict__
def __repr__(self): def __repr__(self):
@ -1368,6 +1385,32 @@ def API_getDashboardTheme():
return ResponseObject(data=DashboardConfig.GetConfig("Server", "dashboard_theme")[1]) return ResponseObject(data=DashboardConfig.GetConfig("Server", "dashboard_theme")[1])
@app.route('/api/savePeerScheduleJob/', methods=["POST"])
def API_savePeerScheduleJob():
data = request.json
if "Job" not in data.keys() not in WireguardConfigurations.keys():
return ResponseObject(False, "Please specify job")
job: dict = data['Job']
if "Peer" not in job.keys() or "Configuration" not in job.keys():
return ResponseObject(False, "Please specify peer and configuration")
configuration = WireguardConfigurations.get(job['Configuration'])
f, fp = configuration.searchPeer(job['Peer'])
if not f:
return ResponseObject(False, "Peer does not exist in this configuration")
s, p = AllPeerJobs.saveJob(PeerJob(
job['JobID'], job['Configuration'], job['Peer'], job['Field'], job['Operator'], job['Value'],
job['CreationDate'], job['ExpireDate'], job['Action']))
if s:
return ResponseObject(s, data=p)
return ResponseObject(s, message=p)
'''
Tools
'''
@app.route('/api/ping/getAllPeersIpAddress') @app.route('/api/ping/getAllPeersIpAddress')
def API_ping_getAllPeersIpAddress(): def API_ping_getAllPeersIpAddress():
ips = {} ips = {}
@ -1546,19 +1589,6 @@ def gunicornConfig():
return app_ip, app_port return app_ip, app_port
# def runGunicorn():
# sqldb = sqlite3.connect(os.path.join(CONFIGURATION_PATH, 'db', 'wgdashboard.db'), check_same_thread=False)
# sqldb.row_factory = sqlite3.Row
# cursor = sqldb.cursor()
# _, app_ip = DashboardConfig.GetConfig("Server", "app_ip")
# _, app_port = DashboardConfig.GetConfig("Server", "app_port")
# WireguardConfigurations = _getConfigurationList()
# bgThread = threading.Thread(target=backGroundThread)
# bgThread.daemon = True
# bgThread.start()
# return app
sqldb = sqlite3.connect(os.path.join(CONFIGURATION_PATH, 'db', 'wgdashboard.db'), check_same_thread=False) sqldb = sqlite3.connect(os.path.join(CONFIGURATION_PATH, 'db', 'wgdashboard.db'), check_same_thread=False)
sqldb.row_factory = sqlite3.Row sqldb.row_factory = sqlite3.Row
cursor = sqldb.cursor() cursor = sqldb.cursor()
@ -1572,4 +1602,3 @@ bgThread.start()
if __name__ == "__main__": if __name__ == "__main__":
app.run(host=app_ip, debug=True, port=app_port) app.run(host=app_ip, debug=True, port=app_port)

View File

@ -3,6 +3,7 @@ import ScheduleDropdown from "@/components/configurationComponents/peerScheduleJ
import SchedulePeerJob from "@/components/configurationComponents/peerScheduleJobsComponents/schedulePeerJob.vue"; import SchedulePeerJob from "@/components/configurationComponents/peerScheduleJobsComponents/schedulePeerJob.vue";
export default { export default {
name: "peerJobs", name: "peerJobs",
props:{ props:{
selectedPeer: Object selectedPeer: Object
}, },
@ -67,33 +68,65 @@ export default {
} }
] ]
}, },
}
},
methods:{
deleteJob(j, index){
if (j.CreationDate){
}else{
this.selectedPeer.jobs = this.selectedPeer.jobs.filter(x => x.JobID !== j.JobID)
}
},
addJob(){
this.selectedPeer.jobs.push(JSON.parse(JSON.stringify({
JobID: crypto.randomUUID(),
Configuration: this.selectedPeer.configuration.Name,
Peer: this.selectedPeer.id,
Field: this.dropdowns.Field[0].value,
Operator: this.dropdowns.Operator[0].value,
Value: "",
CreationDate: "",
ExpireDate: "",
Action: this.dropdowns.Action[0].value
}))
)
} }
} }
} }
</script> </script>
<template> <template>
<div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0"> <div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0 overflow-y-scroll">
<div class="container d-flex h-100 w-100"> <div class="container d-flex h-100 w-100">
<div class="card m-auto rounded-3 shadow" style="width: 700px"> <div class="m-auto modal-dialog-centered dashboardModal">
<div class="card rounded-3 shadow" style="width: 700px">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-2"> <div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-2">
<h4 class="mb-0 fw-normal">Schedule Jobs <h4 class="mb-0 fw-normal">Schedule Jobs
<strong></strong> <strong></strong>
</h4> </h4>
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button> <button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>
</div> </div>
<div class="card-body px-4 pb-4 pt-0"> <div class="card-body px-4 pb-4 pt-2">
<!-- <div class="d-flex gap-2 mb-3">--> <div class="d-flex align-items-center mb-3">
<!-- <small>{{selectedPeer.name ? selectedPeer.name : "Untitled Peer"}}</small>--> <input class="form-control form-control-sm w-auto rounded-3" placeholder="Search Job...">
<!-- <small class="ms-auto"><samp>{{this.selectedPeer.id}}</samp></small>--> <button class="btn btn-sm btn-primary rounded-3 ms-auto" @click="this.addJob()">
<!-- </div>--> <i class="bi bi-plus-lg me-2"></i> Job
</button>
</div>
<TransitionGroup name="fade">
<SchedulePeerJob <SchedulePeerJob
@refresh="this.$emit('refresh')"
@delete="this.deleteJob(job)"
:dropdowns="this.dropdowns" :dropdowns="this.dropdowns"
:pjob="job" v-for="job in this.selectedPeer.jobs"> :key="job.JobID"
:pjob="job" v-for="(job) in this.selectedPeer.jobs">
</SchedulePeerJob> </SchedulePeerJob>
</TransitionGroup>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -551,6 +551,7 @@ export default {
</Transition> </Transition>
<Transition name="fade"> <Transition name="fade">
<PeerJobs <PeerJobs
@refresh="this.getPeers()"
v-if="this.peerScheduleJobs.modalOpen" v-if="this.peerScheduleJobs.modalOpen"
:selectedPeer="this.peerScheduleJobs.selectedPeer" :selectedPeer="this.peerScheduleJobs.selectedPeer"
@close="this.peerScheduleJobs.modalOpen = false"> @close="this.peerScheduleJobs.modalOpen = false">

View File

@ -14,8 +14,9 @@ export default {
</script> </script>
<template> <template>
<div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0"> <div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0 overflow-y-scroll">
<div class="container d-flex h-100 w-100"> <div class="container d-flex h-100 w-100 m-auto">
<div class="modal-dialog-centered dashboardModal">
<div class="card m-auto rounded-3 shadow"> <div class="card m-auto rounded-3 shadow">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-0"> <div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-0">
<h4 class="mb-0">QR Code</h4> <h4 class="mb-0">QR Code</h4>
@ -27,11 +28,8 @@ export default {
</div> </div>
</div> </div>
</div> </div>
</div>
</template> </template>
<style scoped> <style scoped>
.peerSettingContainer {
background-color: #00000060;
z-index: 1000;
}
</style> </style>

View File

@ -8,8 +8,10 @@ export default {
data: String, data: String,
edit: false edit: false
}, },
mounted() { setup(props) {
console.log(this.options) if (props.data === undefined){
this.$emit('update', this.options[0].value)
}
}, },
computed:{ computed:{
currentSelection(){ currentSelection(){
@ -21,7 +23,8 @@ export default {
<template> <template>
<div class="dropdown scheduleDropdown"> <div class="dropdown scheduleDropdown">
<button class="btn btn-sm btn-outline-primary rounded-3" :class="{disabled: !edit}" type="button" data-bs-toggle="dropdown" aria-expanded="false"> <button class="btn btn-sm btn-outline-primary rounded-3"
:class="{'disabled': !edit}" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<samp>{{this.currentSelection.display}}</samp> <samp>{{this.currentSelection.display}}</samp>
</button> </button>
<ul class="dropdown-menu rounded-3 shadow" style="font-size: 0.875rem; width: 200px"> <ul class="dropdown-menu rounded-3 shadow" style="font-size: 0.875rem; width: 200px">
@ -40,4 +43,7 @@ export default {
opacity: 1; opacity: 1;
background-color: rgba(13, 110, 253, 0.09); background-color: rgba(13, 110, 253, 0.09);
} }
.btn{
//padding: 0.1rem 0.4rem;
}
</style> </style>

View File

@ -1,5 +1,8 @@
<script> <script>
import ScheduleDropdown from "@/components/configurationComponents/peerScheduleJobsComponents/scheduleDropdown.vue"; import ScheduleDropdown from "@/components/configurationComponents/peerScheduleJobsComponents/scheduleDropdown.vue";
import {ref} from "vue";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {fetchPost} from "@/utilities/fetch.js";
export default { export default {
name: "schedulePeerJob", name: "schedulePeerJob",
@ -8,22 +11,45 @@ export default {
dropdowns: Array[Object], dropdowns: Array[Object],
pjob: Object pjob: Object
}, },
setup(props){
const job = ref({})
const edit = ref(false)
const newJob = ref(false)
job.value = JSON.parse(JSON.stringify(props.pjob))
if (!job.value.CreationDate){
edit.value = true
newJob.value = true
}
const store = DashboardConfigurationStore()
return {job, edit, newJob, store}
},
data(){ data(){
return { return {
job: Object,
inputType: undefined, inputType: undefined,
edit: false
} }
}, },
beforeMount() { watch:{
this.job = JSON.parse(JSON.stringify(this.pjob)) pjob: {
deep: true,
handler(newValue){
this.job = JSON.parse(JSON.stringify(newValue))
}
}
}, },
methods: { methods: {
save(){ save(){
if (this.job.Field && this.job.Operator && this.job.Action && this.job.Value){ if (this.job.Field && this.job.Operator && this.job.Action && this.job.Value){
if (this.job.Field === 'date'){ fetchPost(`/api/savePeerScheduleJob/`, {
this.job.Value = new Date(this.job.Value).getTime(); Job: this.job
}, (res) => {
if (res.status){
this.edit = false;
this.store.newMessage("Server", "Job Saved!", "success")
this.$emit("refresh")
}else{
this.store.newMessage("Server", res.message, "danger")
} }
})
}else{ }else{
this.alert(); this.alert();
} }
@ -40,23 +66,28 @@ export default {
}, 2000) }, 2000)
}, },
reset(){ reset(){
if(this.job.CreationDate){
this.job = JSON.parse(JSON.stringify(this.pjob)); this.job = JSON.parse(JSON.stringify(this.pjob));
this.edit = false; this.edit = false;
}else{
this.$emit('delete')
}
} }
}, },
} }
</script> </script>
<template> <template>
<div class="card shadow-sm rounded-3"> <div class="card shadow-sm rounded-3 mb-2" :class="{'border-warning-subtle': this.newJob}">
<div class="card-header bg-transparent text-muted border-0"> <div class="card-header bg-transparent text-muted border-0">
<small class="d-flex"> <small class="d-flex" v-if="!this.newJob">
<strong class="me-auto">Job ID</strong> <strong class="me-auto">Job ID</strong>
<samp>{{this.job.JobID}}</samp> <samp>{{this.job.JobID}}</samp>
</small> </small>
<small v-else><span class="badge text-bg-warning">Unsaved Job</span></small>
</div> </div>
<div class="card-body pt-1" style="font-family: var(--bs-font-monospace)"> <div class="card-body pt-1" style="font-family: var(--bs-font-monospace)">
<div class="d-flex gap-3 align-items-center mb-2"> <div class="d-flex gap-2 align-items-center mb-2">
<samp> <samp>
if if
</samp> </samp>
@ -87,18 +118,17 @@ export default {
v-model="this.job.Value" v-model="this.job.Value"
style="width: auto"> style="width: auto">
<samp> <samp>
{{this.dropdowns.Field.find(x => x.value === this.job.Field).unit}} { {{this.dropdowns.Field.find(x => x.value === this.job.Field)?.unit}} {
</samp> </samp>
</div> </div>
<div class="px-5 d-flex gap-3 align-items-center"> <div class="px-5 d-flex gap-2 align-items-center">
<samp>execute</samp> <samp>then</samp>
<ScheduleDropdown <ScheduleDropdown
:edit="edit" :edit="edit"
:options="this.dropdowns.Action" :options="this.dropdowns.Action"
:data="this.job.Action" :data="this.job.Action"
@update="(value) => this.job.Action = value" @update="(value) => this.job.Action = value"
></ScheduleDropdown> ></ScheduleDropdown>
<samp>;</samp>
</div> </div>
<div class="d-flex gap-3"> <div class="d-flex gap-3">
<samp>}</samp> <samp>}</samp>
@ -123,5 +153,11 @@ export default {
</template> </template>
<style scoped> <style scoped>
*{
font-size: 0.875rem;
}
input{
padding: 0.1rem 0.4rem;
}
</style> </style>

View File

@ -55,7 +55,8 @@ export default {
<template> <template>
<div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0"> <div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0">
<div class="container d-flex h-100 w-100"> <div class="container d-flex h-100 w-100">
<div class="card m-auto rounded-3 shadow" style="width: 700px"> <div class="m-auto modal-dialog-centered dashboardModal">
<div class="card rounded-3 shadow flex-grow-1">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4"> <div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4">
<h4 class="mb-0">Peer Settings</h4> <h4 class="mb-0">Peer Settings</h4>
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button> <button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>
@ -180,6 +181,8 @@ export default {
</div> </div>
</div> </div>
</div>
</template> </template>
<style scoped> <style scoped>

View File

@ -14,8 +14,8 @@ export default {
</script> </script>
<template> <template>
<div class="col-md-3 col-lg-2 d-md-block p-3"> <div class="col-md-3 col-lg-2 d-md-block p-3" style="height: calc(-50px + 100vh);">
<nav id="sidebarMenu" class=" bg-body-tertiary sidebar border h-100 rounded-3 shadow" > <nav id="sidebarMenu" class=" bg-body-tertiary sidebar border h-100 rounded-3 shadow overflow-y-scroll" >
<div class="sidebar-sticky pt-3"> <div class="sidebar-sticky pt-3">
<ul class="nav flex-column"> <ul class="nav flex-column">
<li class="nav-item"> <li class="nav-item">

View File

@ -1120,3 +1120,12 @@ pre.index-alert {
background-color: #00000060; background-color: #00000060;
z-index: 9999; z-index: 9999;
} }
.dashboardModal{
min-height: calc(100% - 1.75rem * 2);
width: 700px
}
.dashboardModal > .card{
margin: 1.75rem;
}