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:
parent
6c529a6908
commit
2d838b69fd
@ -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)
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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">
|
||||||
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
||||||
|
@ -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">
|
||||||
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user