1
0
mirror of https://github.com/donaldzou/WGDashboard.git synced 2024-11-21 14:51:45 +01:00

Finished job logs :)

This commit is contained in:
Donald Zou 2024-07-29 18:40:07 -04:00
parent b65828416f
commit 63e8553a09
16 changed files with 479 additions and 135 deletions

17
package-lock.json generated Normal file
View File

@ -0,0 +1,17 @@
{
"name": "Wireguard-Dashboard",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"dayjs": "^1.11.12"
}
},
"node_modules/dayjs": {
"version": "1.11.12",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz",
"integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg=="
}
}
}

5
package.json Normal file
View File

@ -0,0 +1,5 @@
{
"dependencies": {
"dayjs": "^1.11.12"
}
}

View File

@ -76,7 +76,7 @@ class CustomJsonEncoder(DefaultJSONProvider):
super().__init__(app)
def default(self, o):
if isinstance(o, WireguardConfiguration) or isinstance(o, Peer) or isinstance(o, PeerJob):
if isinstance(o, WireguardConfiguration) or isinstance(o, Peer) or isinstance(o, PeerJob) or isinstance(o, Log):
return o.toJson()
return super().default(self, o)
@ -99,6 +99,10 @@ class Log:
"Status": self.Status,
"Message": self.Message
}
def __dict__(self):
return self.toJson()
class Logger:
def __init__(self):
self.loggerdb = sqlite3.connect(os.path.join(CONFIGURATION_PATH, 'db', 'wgdashboard_log.db'),
@ -120,21 +124,26 @@ class Logger:
self.loggerdbCursor.execute(f"INSERT INTO JobLog (LogID, JobID, Status, Message) VALUES (?, ?, ?, ?)",
(str(uuid.uuid4()), JobID, Status, Message,))
self.loggerdb.commit()
self.getLogs()
except Exception as e:
print(e)
return False
return True
def getLogs(self, all: bool = False):
def getLogs(self, all: bool = False, configName = None) -> list[Log]:
logs: list[Log] = []
try:
table = self.loggerdb.execute(f"SELECT * FROM JobLog ORDER BY LogDate DESC {'LIMIT 5' if not all else ''}").fetchall()
allJobs = AllPeerJobs.getAllJobs(configName)
allJobsID = ", ".join([f"'{x.JobID}'" for x in allJobs])
table = self.loggerdb.execute(f"SELECT * FROM JobLog WHERE JobID IN ({allJobsID}) ORDER BY LogDate DESC").fetchall()
self.logs.clear()
for l in table:
self.logs.append(
logs.append(
Log(l["LogID"], l["JobID"], l["LogDate"], l["Status"], l["Message"]))
except Exception as e:
pass
return logs
return logs
@ -186,7 +195,18 @@ class PeerJobs:
self.Jobs.append(PeerJob(
job['JobID'], job['Configuration'], job['Peer'], job['Field'], job['Operator'], job['Value'],
job['CreationDate'], job['ExpireDate'], job['Action']))
# print(self.Jobs)
def getAllJobs(self, configuration: str = None):
if configuration is not None:
jobs = self.jobdbCursor.execute(
f"SELECT * FROM PeerJobs WHERE Configuration = ?", (configuration, )).fetchall()
j = []
for job in jobs:
j.append(PeerJob(
job['JobID'], job['Configuration'], job['Peer'], job['Field'], job['Operator'], job['Value'],
job['CreationDate'], job['ExpireDate'], job['Action']))
return j
return []
def __createPeerJobsDatabase(self):
existingTable = self.jobdbCursor.execute("SELECT name from sqlite_master where type='table'").fetchall()
@ -239,21 +259,6 @@ class PeerJobs:
except Exception as e:
return False, str(e)
# def finishJob(self, Job: PeerJob) -> tuple[bool, list] | tuple[bool, str]:
# try:
# if (len(str(Job.CreationDate))) == 0:
# return False, "Job does not exist"
# self.jobdbCursor.execute('''
# UPDATE PeerJobs SET ExpireDate = strftime('%Y-%m-%d %H:%M:%S','now') WHERE JobId = ?
# ''', (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)
def runJob(self):
needToDelete = []
for job in self.Jobs:
@ -1555,6 +1560,17 @@ def API_deletePeerScheduleJob():
return ResponseObject(s, data=p)
return ResponseObject(s, message=p)
@app.route('/api/getPeerScheduleJobLogs/<configName>', methods=['GET'])
def API_getPeerScheduleJobLogs(configName):
if configName not in WireguardConfigurations.keys():
return ResponseObject(False, "Configuration does not exist")
data = request.args.get("requestAll")
requestAll = False
if data is not None and data == "true":
requestAll = True
return ResponseObject(data=JobLogger.getLogs(requestAll, configName))
'''
Tools

View File

@ -14,7 +14,7 @@
"bootstrap": "^5.3.2",
"bootstrap-icons": "^1.11.2",
"cidr-tools": "^7.0.4",
"dayjs": "^1.11.10",
"dayjs": "^1.11.12",
"fuse.js": "^7.0.0",
"i": "^0.3.7",
"is-cidr": "^5.0.3",
@ -938,9 +938,9 @@
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/dayjs": {
"version": "1.11.10",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz",
"integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ=="
"version": "1.11.12",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz",
"integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg=="
},
"node_modules/decamelize": {
"version": "1.2.0",

View File

@ -15,7 +15,7 @@
"bootstrap": "^5.3.2",
"bootstrap-icons": "^1.11.2",
"cidr-tools": "^7.0.4",
"dayjs": "^1.11.10",
"dayjs": "^1.11.12",
"fuse.js": "^7.0.0",
"i": "^0.3.7",
"is-cidr": "^5.0.3",

View File

@ -61,9 +61,9 @@ export default {
</div>
</div>
<div class="card-body pt-1" style="font-size: 0.9rem">
<h5>
<h6>
{{Peer.name ? Peer.name : 'Untitled Peer'}}
</h5>
</h6>
<div class="mb-2">
<small class="text-muted">Public Key</small>
<p class="mb-0"><samp>{{Peer.id}}</samp></p>
@ -100,13 +100,14 @@ export default {
<style scoped>
.slide-fade-leave-active, .slide-fade-enter-active{
transition: all 0.2s cubic-bezier(1, 0.5, 0.8, 1);
transition: all 0.2s cubic-bezier(0.82, 0.58, 0.17, 0.9);
}
.slide-fade-enter-from,
.slide-fade-leave-to {
transform: translateY(20px);
opacity: 0;
filter: blur(3px);
}
.subMenuBtn.active{
@ -114,7 +115,7 @@ export default {
}
.peerCard{
transition: box-shadow 0.1s cubic-bezier(1, 0.5, 0.8, 1);
transition: box-shadow 0.1s cubic-bezier(0.82, 0.58, 0.17, 0.9);
}
.peerCard:hover{

View File

@ -1,9 +1,13 @@
<script>
import ScheduleDropdown from "@/components/configurationComponents/peerScheduleJobsComponents/scheduleDropdown.vue";
import SchedulePeerJob from "@/components/configurationComponents/peerScheduleJobsComponents/schedulePeerJob.vue";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
export default {
name: "peerJobs",
setup(){
const store = WireguardConfigurationsStore();
return {store}
},
props:{
selectedPeer: Object
},
@ -13,78 +17,24 @@ export default {
},
data(){
return {
dropdowns: {
Field: [
{
display: "Total Received",
value: "total_receive",
unit: "GB",
type: 'number'
},
{
display: "Total Sent",
value: "total_sent",
unit: "GB",
type: 'number'
},
{
display: "Total Data",
value: "total_data",
unit: "GB",
type: 'number'
},
{
display: "Date",
value: "date",
type: 'date'
}
],
Operator: [
{
display: "equal",
value: "eq"
},
{
display: "not equal",
value: "neq"
},
{
display: "larger than",
value: "lgt"
},
{
display: "less than",
value: "lst"
},
],
Action: [
{
display: "Restrict Peer",
value: "restrict"
},
{
display: "Delete Peer",
value: "delete"
}
]
},
}
},
methods:{
deleteJob(j){
this.selectedPeer.jobs = this.selectedPeer.jobs.filter(x => x.JobID !== j.JobID)
this.selectedPeer.jobs = this.selectedPeer.jobs.filter(x => x.JobID !== j.JobID);
},
addJob(){
this.selectedPeer.jobs.unshift(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,
Field: this.store.PeerScheduleJobs.dropdowns.Field[0].value,
Operator: this.store.PeerScheduleJobs.dropdowns.Operator[0].value,
Value: "",
CreationDate: "",
ExpireDate: "",
Action: this.dropdowns.Action[0].value
Action: this.store.PeerScheduleJobs.dropdowns.Action[0].value
}))
)
}
@ -96,7 +46,7 @@ export default {
<template>
<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="m-auto modal-dialog-centered dashboardModal mt-0">
<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">
<h4 class="mb-0 fw-normal">Schedule Jobs
@ -106,25 +56,26 @@ export default {
</div>
<div class="card-body px-4 pb-4 pt-2 position-relative">
<div class="d-flex align-items-center mb-3">
<button class="btn btn-sm btn-primary rounded-3" @click="this.addJob()">
<button class="btn bg-primary-subtle border-1 border-primary-subtle text-primary-emphasis rounded-3 shadow"
@click="this.addJob()">
<i class="bi bi-plus-lg me-2"></i> Job
</button>
</div>
<TransitionGroup name="schedulePeerJobTransition" tag="div" class="position-relative">
<SchedulePeerJob
@refresh="(j) => this.selectedPeer.jobs[index] = j"
@refresh="this.$emit('refresh')"
@delete="this.deleteJob(job)"
:dropdowns="this.dropdowns"
:dropdowns="this.store.PeerScheduleJobs.dropdowns"
:key="job.JobID"
:pjob="job" v-for="(job, index) in this.selectedPeer.jobs">
</SchedulePeerJob>
<div class="card" key="none" v-if="this.selectedPeer.jobs.length === 0">
<div class="card-body text-muted text-center">
<h1><i class="bi bi-emoji-frown-fill"></i></h1>
<h6 class="mb-0">This peer does not have any job yet.</h6>
<div class="card shadow-sm" key="none"
style="height: 153px"
v-if="this.selectedPeer.jobs.length === 0">
<div class="card-body text-muted text-center d-flex">
<h6 class="m-auto">This peer does not have any job yet.</h6>
</div>
</div>
</TransitionGroup>

View File

@ -0,0 +1,86 @@
<script>
import SchedulePeerJob from "@/components/configurationComponents/peerScheduleJobsComponents/schedulePeerJob.vue";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import {v4} from "uuid";
export default {
name: "peerJobsAllModal",
setup(){
const store = WireguardConfigurationsStore();
return {store}
},
components: {SchedulePeerJob},
props: {
configurationPeers: Array[Object]
},
methods:{
getuuid(){
return v4();
}
},
computed:{
getAllJobs(){
return this.configurationPeers.filter(x => x.jobs.length > 0)
}
}
}
</script>
<template>
<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="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">
<h4 class="mb-0 fw-normal">All Active Jobs
</h4>
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>
</div>
<div class="card-body px-4 pb-4 pt-2 ">
<div class="accordion" id="peerJobsLogsModalAccordion" v-if="this.getAllJobs.length > 0">
<div class="accordion-item" v-for="(p, index) in this.getAllJobs" :key="p.id">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
:data-bs-target="'#collapse_' + index">
<small>
<strong>
<span v-if="p.name">
{{p.name}} &#x2022;
</span>
<samp class="text-muted">{{p.id}}</samp>
</strong>
</small>
</button>
</h2>
<div :id="'collapse_' + index" class="accordion-collapse collapse"
data-bs-parent="#peerJobsLogsModalAccordion">
<div class="accordion-body">
<SchedulePeerJob
@delete="this.$emit('refresh')"
@refresh="this.$emit('refresh')"
:dropdowns="this.store.PeerScheduleJobs.dropdowns"
:viewOnly="true"
:key="job.JobID"
:pjob="job" v-for="job in p.jobs">
</SchedulePeerJob>
</div>
</div>
</div>
</div>
<div class="card shadow-sm"
style="height: 153px"
v-else>
<div class="card-body text-muted text-center d-flex">
<h6 class="m-auto">No active job at the moment.</h6>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@ -0,0 +1,162 @@
<script>
import dayjs from "dayjs";
import {fetchGet} from "@/utilities/fetch.js";
export default {
name: "peerJobsLogsModal",
props: {
configurationInfo: Object
},
data(){
return {
dataLoading: true,
data: [],
logFetchTime: undefined,
showLogID: false,
showJobID: true,
showSuccessJob: true,
showFailedJob: true,
showLogAmount: 10
}
},
async mounted(){
await this.fetchLog();
},
methods: {
async fetchLog(){
this.dataLoading = true;
await fetchGet(`/api/getPeerScheduleJobLogs/${this.configurationInfo.Name}`, {}, (res) => {
this.data = res.data;
this.logFetchTime = dayjs().format("YYYY-MM-DD HH:mm:ss")
this.dataLoading = false;
});
}
},
computed: {
getLogs(){
return this.data
.filter(x => {
return (this.showSuccessJob && x.Status === "1") || (this.showFailedJob && x.Status === "0")
})
},
showLogs(){
return this.getLogs.slice(0, this.showLogAmount);
}
}
}
</script>
<template>
<div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0 overflow-y-scroll">
<div class="container-fluid d-flex h-100 w-100">
<div class="m-auto mt-0 modal-dialog-centered dashboardModal" style="width: 100%">
<div class="card rounded-3 shadow w-100" >
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-0">
<h4 class="mb-0">Jobs Logs</h4>
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>
</div>
<div class="card-body px-4 pb-4 pt-2">
<div v-if="!this.dataLoading">
<p>Updated at: {{this.logFetchTime}}</p>
<div class="mb-2 d-flex gap-3">
<button @click="this.fetchLog()"
class="btn btn-sm rounded-3 shadow-sm
text-info-emphasis bg-info-subtle border-1 border-info-subtle me-1">
<i class="bi bi-arrow-clockwise me-2"></i>
Refresh
</button>
<div class="d-flex gap-3 align-items-center">
<span class="text-muted">Filter</span>
<div class="form-check">
<input class="form-check-input" type="checkbox" v-model="this.showSuccessJob"
id="jobLogsShowSuccessCheck">
<label class="form-check-label" for="jobLogsShowSuccessCheck">
<span class="badge text-success-emphasis bg-success-subtle">Success</span>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" v-model="this.showFailedJob"
id="jobLogsShowFailedCheck">
<label class="form-check-label" for="jobLogsShowFailedCheck">
<span class="badge text-danger-emphasis bg-danger-subtle">Failed</span>
</label>
</div>
</div>
<div class="d-flex gap-3 align-items-center ms-auto">
<span class="text-muted">Display</span>
<div class="form-check">
<input class="form-check-input" type="checkbox"
v-model="showJobID"
id="jobLogsShowJobIDCheck">
<label class="form-check-label" for="jobLogsShowJobIDCheck">
Job ID
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox"
v-model="showLogID"
id="jobLogsShowLogIDCheck">
<label class="form-check-label" for="jobLogsShowLogIDCheck">
Log ID
</label>
</div>
</div>
</div>
<table class="table">
<thead>
<tr>
<th scope="col">Date</th>
<th scope="col" v-if="showLogID">Log ID</th>
<th scope="col" v-if="showJobID">Job ID</th>
<th scope="col">Status</th>
<th scope="col">Message</th>
</tr>
</thead>
<tbody>
<tr v-for="log in this.showLogs" style="font-size: 0.875rem">
<th scope="row">{{log.LogDate}}</th>
<td v-if="showLogID"><samp class="text-muted">{{log.LogID}}</samp></td>
<td v-if="showJobID"><samp class="text-muted">{{log.JobID}}</samp></td>
<td>
<span class="badge" :class="[log.Status === '1' ? 'text-success-emphasis bg-success-subtle':'text-danger-emphasis bg-danger-subtle']">
{{log.Status === "1" ? 'Success': 'Failed'}}
</span>
</td>
<td>{{log.Message}}</td>
</tr>
</tbody>
</table>
<div class="d-flex gap-2">
<button v-if="this.getLogs.length > this.showLogAmount"
@click="this.showLogAmount += 20"
class="btn btn-sm rounded-3 shadow-sm
text-primary-emphasis bg-primary-subtle border-1 border-primary-subtle">
<i class="bi bi-chevron-down me-2"></i>
Show More
</button>
<button v-if="this.showLogAmount > 20"
@click="this.showLogAmount = 20"
class="btn btn-sm rounded-3 shadow-sm
text-primary-emphasis bg-primary-subtle border-1 border-primary-subtle">
<i class="bi bi-chevron-up me-2"></i>
Collapse
</button>
</div>
</div>
<div class="d-flex align-items-center flex-column" v-else>
<div class="spinner-border text-body" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@ -37,6 +37,8 @@ import PeerSettings from "@/components/configurationComponents/peerSettings.vue"
import PeerQRCode from "@/components/configurationComponents/peerQRCode.vue";
import PeerCreate from "@/components/configurationComponents/peerCreate.vue";
import PeerJobs from "@/components/configurationComponents/peerJobs.vue";
import PeerJobsAllModal from "@/components/configurationComponents/peerJobsAllModal.vue";
import PeerJobsLogsModal from "@/components/configurationComponents/peerJobsLogsModal.vue";
Chart.register(
ArcElement,
@ -66,7 +68,9 @@ Chart.register(
export default {
name: "peerList",
components: {PeerJobs, PeerCreate, PeerQRCode, PeerSettings, PeerSearch, Peer, Line, Bar},
components: {
PeerJobsLogsModal,
PeerJobsAllModal, PeerJobs, PeerCreate, PeerQRCode, PeerSettings, PeerSearch, Peer, Line, Bar},
setup(){
const dashboardConfigurationStore = DashboardConfigurationStore();
const wireguardConfigurationStore = WireguardConfigurationsStore();
@ -119,6 +123,12 @@ export default {
},
peerCreate: {
modalOpen: false
},
peerScheduleJobsAll: {
modalOpen: false
},
peerScheduleJobsLogs: {
modalOpen: false
}
}
},
@ -173,19 +183,6 @@ export default {
}, (res) => {
this.configurationInfo = res.data.configurationInfo;
this.configurationPeers = res.data.configurationPeers;
// let modals = [this.peerSetting, this.peerScheduleJobs, this.peerQRCode]
// modals.forEach(x => {
//
// if (x.modalOpen && this.configurationPeers.find(p => p.id === x.selectedPeer.id)){
// x.selectedPeer = this.configurationPeers.find(p => p.id === x.selectedPeer.id)
// console.log(this.configurationPeers.find(p => p.id === x.selectedPeer.id))
// }else{
// x.modalOpen = false
// }
// })
this.configurationPeers.forEach(x => {
x.restricted = false;
})
@ -534,12 +531,16 @@ export default {
<!-- <div class="d-flex align-items-center gap-3 mb-2">-->
<!-- <h3>Peers</h3>-->
<!-- </div>-->
<PeerSearch :configuration="this.configurationInfo"></PeerSearch>
<PeerSearch
@jobsAll="this.peerScheduleJobsAll.modalOpen = true"
@jobLogs="this.peerScheduleJobsLogs.modalOpen = true"
:configuration="this.configurationInfo"></PeerSearch>
<TransitionGroup name="list" tag="div" class="row gx-2 gy-2 z-0">
<div class="col-12 col-lg-6 col-xl-4"
:key="peer.id"
v-for="peer in this.searchPeers">
<Peer :Peer="peer"
@refresh="this.getPeers()"
@jobs="peerScheduleJobs.modalOpen = true; peerScheduleJobs.selectedPeer = this.configurationPeers.find(x => x.id === peer.id)"
@setting="peerSetting.modalOpen = true; peerSetting.selectedPeer = this.configurationPeers.find(x => x.id === peer.id)"
@ -548,7 +549,7 @@ export default {
</div>
</TransitionGroup>
</div>
<Transition name="fade">
<Transition name="zoom">
<PeerSettings v-if="this.peerSetting.modalOpen"
key="settings"
:selectedPeer="this.peerSetting.selectedPeer"
@ -556,13 +557,13 @@ export default {
@close="this.peerSetting.modalOpen = false">
</PeerSettings>
</Transition>
<Transition name="fade">
<Transition name="zoom">
<PeerQRCode :peerConfigData="this.peerQRCode.peerConfigData"
key="qrcode"
@close="this.peerQRCode.modalOpen = false"
v-if="peerQRCode.modalOpen"></PeerQRCode>
</Transition>
<Transition name="fade">
<Transition name="zoom">
<PeerJobs
@refresh="this.getPeers()"
v-if="this.peerScheduleJobs.modalOpen"
@ -570,13 +571,22 @@ export default {
@close="this.peerScheduleJobs.modalOpen = false">
</PeerJobs>
</Transition>
<!-- <Transition name="fade">-->
<!-- -->
<!-- </Transition>-->
<!-- <Transition name="fade">-->
<!-- -->
<!-- </Transition>-->
<Transition name="zoom">
<PeerJobsAllModal
v-if="this.peerScheduleJobsAll.modalOpen"
@refresh="this.getPeers()"
@close="this.peerScheduleJobsAll.modalOpen = false"
:configurationPeers="this.configurationPeers"
>
</PeerJobsAllModal>
</Transition>
<Transition name="zoom">
<PeerJobsLogsModal v-if="this.peerScheduleJobsLogs.modalOpen"
@close="this.peerScheduleJobsLogs.modalOpen = false"
:configurationInfo="this.configurationInfo"
>
</PeerJobsLogsModal>
</Transition>
</div>
</template>

View File

@ -6,7 +6,8 @@ export default {
peerConfigData: String
},
mounted() {
QRCode.toCanvas(document.querySelector("#qrcode"), this.peerConfigData , function (error) {
QRCode.toCanvas(document.querySelector("#qrcode"), this.peerConfigData , (error) => {
console.log(this.peerConfigData)
if (error) console.error(error)
})
}
@ -14,10 +15,10 @@ export default {
</script>
<template>
<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 m-auto">
<div class="modal-dialog-centered dashboardModal">
<div class="card m-auto rounded-3 shadow">
<div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0">
<div class="container d-flex h-100 w-100">
<div class="m-auto modal-dialog-centered dashboardModal justify-content-center">
<div class="card rounded-3 shadow">
<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>
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>

View File

@ -9,7 +9,8 @@ export default {
components: {ScheduleDropdown},
props: {
dropdowns: Array[Object],
pjob: Object
pjob: Object,
viewOnly: false
},
setup(props){
const job = ref({})

View File

@ -137,6 +137,28 @@ export default {
</a></li>
</ul>
</div>
<div class="dropdown">
<button class="btn dropdown-toggle text-secondary-emphasis bg-secondary-subtle rounded-3 border-1 border-secondary-subtle shadow-sm"
type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-three-dots me-2"></i>More
</button>
<ul class="dropdown-menu shadow mt-2 rounded-3">
<li>
<h6 class="dropdown-header">Peer Jobs</h6>
</li>
<li>
<a role="button" class="dropdown-item" @click="this.$emit('jobsAll')">
All Active Jobs
</a>
</li>
<li>
<a role="button" class="dropdown-item" @click="this.$emit('jobLogs')">
Logs
</a>
</li>
</ul>
</div>
</div>
</div>
</template>

View File

@ -53,7 +53,7 @@ export default {
</script>
<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="m-auto modal-dialog-centered dashboardModal">
<div class="card rounded-3 shadow flex-grow-1">

View File

@ -5,7 +5,64 @@ import isCidr from "is-cidr";
export const WireguardConfigurationsStore = defineStore('WireguardConfigurationsStore', {
state: () => ({
Configurations: undefined,
searchString: ""
searchString: "",
PeerScheduleJobs: {
dropdowns: {
Field: [
{
display: "Total Received",
value: "total_receive",
unit: "GB",
type: 'number'
},
{
display: "Total Sent",
value: "total_sent",
unit: "GB",
type: 'number'
},
{
display: "Total Data",
value: "total_data",
unit: "GB",
type: 'number'
},
{
display: "Date",
value: "date",
type: 'date'
}
],
Operator: [
{
display: "equal",
value: "eq"
},
{
display: "not equal",
value: "neq"
},
{
display: "larger than",
value: "lgt"
},
{
display: "less than",
value: "lst"
},
],
Action: [
{
display: "Restrict Peer",
value: "restrict"
},
{
display: "Delete Peer",
value: "delete"
}
]
}
}
}),
actions: {
async getConfigurations(){

View File

@ -1119,6 +1119,7 @@ pre.index-alert {
.peerSettingContainer {
background-color: #00000060;
z-index: 9999;
backdrop-filter: blur(1px);
}
.dashboardModal{
@ -1128,4 +1129,18 @@ pre.index-alert {
.dashboardModal > .card{
margin: 1.75rem;
}
}
.zoom-enter-active,
.zoom-leave-active {
transition: all 0.3s cubic-bezier(0.82, 0.58, 0.17, 0.9);
/*position: absolute;*/
/*padding-top: 50px*/
}
.zoom-enter-from,
.zoom-leave-to {
transform: scale(1.1);
filter: blur(3px);
opacity: 0;
}