Adding users controls on the frontend quit/shutdown/reboot
This commit is contained in:
parent
2ea8ef49e8
commit
9ed61f201e
@ -35,6 +35,18 @@
|
|||||||
<input type="checkbox" @change="switch_config('frontend', 'virtual_keyboard')" v-model="config.frontend.virtual_keyboard">
|
<input type="checkbox" @change="switch_config('frontend', 'virtual_keyboard')" v-model="config.frontend.virtual_keyboard">
|
||||||
<i class="form-icon"></i> Use virtual keyboard (for touch screen)
|
<i class="form-icon"></i> Use virtual keyboard (for touch screen)
|
||||||
</label>
|
</label>
|
||||||
|
<label class="form-switch">
|
||||||
|
<input type="checkbox" @change="switch_config('frontend', 'reboot_option')" v-model="config.frontend.reboot_option">
|
||||||
|
<i class="form-icon"></i> Allow the end-user to reboot the device from the interface.
|
||||||
|
</label>
|
||||||
|
<label class="form-switch">
|
||||||
|
<input type="checkbox" @change="switch_config('frontend', 'shutdown_option')" v-model="config.frontend.shutdown_option">
|
||||||
|
<i class="form-icon"></i> Allow the end-user to shutdown the device from the interface.
|
||||||
|
</label>
|
||||||
|
<label class="form-switch">
|
||||||
|
<input type="checkbox" @change="switch_config('frontend', 'quit_option')" v-model="config.frontend.quit_option">
|
||||||
|
<i class="form-icon"></i> Allow the end-user to quit the interface
|
||||||
|
</label>
|
||||||
<label class="form-switch">
|
<label class="form-switch">
|
||||||
<input type="checkbox" @change="switch_config('frontend', 'hide_mouse')" v-model="config.frontend.hide_mouse">
|
<input type="checkbox" @change="switch_config('frontend', 'hide_mouse')" v-model="config.frontend.hide_mouse">
|
||||||
<i class="form-icon"></i> Hide mouse (for touch screen)
|
<i class="form-icon"></i> Hide mouse (for touch screen)
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<transition name="fade" mode="out-in">
|
<div class="wrapper">
|
||||||
<router-view />
|
<Controls />
|
||||||
</transition>
|
<transition name="fade" mode="out-in">
|
||||||
|
<router-view />
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -26,5 +29,13 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.title = 'TinyCheck Frontend'
|
document.title = 'TinyCheck Frontend'
|
||||||
|
import Controls from "@/components/Controls.vue"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'app',
|
||||||
|
components: {
|
||||||
|
Controls
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -240,6 +240,11 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
width:100%;
|
||||||
|
height:100%;
|
||||||
|
}
|
||||||
|
|
||||||
.center {
|
.center {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -633,4 +638,45 @@ ul {
|
|||||||
100% {
|
100% {
|
||||||
opacity:1;
|
opacity:1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
position:fixed;
|
||||||
|
right:0;
|
||||||
|
top:0;
|
||||||
|
width: fit-content;
|
||||||
|
height: fit-content;
|
||||||
|
z-index: 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quit-icon {
|
||||||
|
background-image: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjMjUyNTI1IiB4bWxuczp4PSJodHRwOi8vbnMuYWRvYmUuY29tL0V4dGVuc2liaWxpdHkvMS4wLyIgeG1sbnM6aT0iaHR0cDovL25zLmFkb2JlLmNvbS9BZG9iZUlsbHVzdHJhdG9yLzEwLjAvIiB4bWxuczpncmFwaD0iaHR0cDovL25zLmFkb2JlLmNvbS9HcmFwaHMvMS4wLyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMCAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj48c3dpdGNoPjxmb3JlaWduT2JqZWN0IHJlcXVpcmVkRXh0ZW5zaW9ucz0iaHR0cDovL25zLmFkb2JlLmNvbS9BZG9iZUlsbHVzdHJhdG9yLzEwLjAvIiB4PSIwIiB5PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIj48L2ZvcmVpZ25PYmplY3Q+PGcgaTpleHRyYW5lb3VzPSJzZWxmIj48cGF0aCBkPSJNNTAsMi41QzIzLjgsMi41LDIuNSwyMy44LDIuNSw1MFMyMy44LDk3LjUsNTAsOTcuNVM5Ny41LDc2LjIsOTcuNSw1MFM3Ni4yLDIuNSw1MCwyLjV6IE03My40LDY2LjMgICAgYzAuNywwLjcsMC43LDEuNywwLDIuNGwtNC44LDQuOGMtMC43LDAuNy0xLjcsMC43LTIuNCwwTDUwLDU3LjJMMzMuNyw3My40Yy0wLjcsMC43LTEuNywwLjctMi40LDBsLTQuOC00LjggICAgYy0wLjctMC43LTAuNy0xLjcsMC0yLjRMNDIuOCw1MEwyNi42LDMzLjdjLTAuNy0wLjctMC43LTEuNywwLTIuNGw0LjgtNC44YzAuNy0wLjcsMS43LTAuNywyLjQsMEw1MCw0Mi44bDE2LjMtMTYuMyAgICBjMC43LTAuNywxLjctMC43LDIuNCwwbDQuOCw0LjhjMC43LDAuNywwLjcsMS43LDAsMi40TDU3LjIsNTBMNzMuNCw2Ni4zeiI+PC9wYXRoPjwvZz48L3N3aXRjaD48L3N2Zz4=");
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
display: block;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-top: 10px;
|
||||||
|
background-size: cover;
|
||||||
|
opacity: 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.off-icon {
|
||||||
|
background-image: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjMmIyYjJiIiB4bWxuczp4PSJodHRwOi8vbnMuYWRvYmUuY29tL0V4dGVuc2liaWxpdHkvMS4wLyIgeG1sbnM6aT0iaHR0cDovL25zLmFkb2JlLmNvbS9BZG9iZUlsbHVzdHJhdG9yLzEwLjAvIiB4bWxuczpncmFwaD0iaHR0cDovL25zLmFkb2JlLmNvbS9HcmFwaHMvMS4wLyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMCAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj48c3dpdGNoPjxmb3JlaWduT2JqZWN0IHJlcXVpcmVkRXh0ZW5zaW9ucz0iaHR0cDovL25zLmFkb2JlLmNvbS9BZG9iZUlsbHVzdHJhdG9yLzEwLjAvIiB4PSIwIiB5PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIj48L2ZvcmVpZ25PYmplY3Q+PGcgaTpleHRyYW5lb3VzPSJzZWxmIj48cGF0aCBkPSJNNTAsMi41TDUwLDIuNUMyMy44LDIuNSwyLjUsMjMuOCwyLjUsNTBsMCwwYzAsMjYuMiwyMS4zLDQ3LjUsNDcuNSw0Ny41bDAsMGMyNi4yLDAsNDcuNS0yMS4zLDQ3LjUtNDcuNWwwLDAgICAgQzk3LjUsMjMuOCw3Ni4yLDIuNSw1MCwyLjV6IE00NS43LDI0LjJjMC0yLjQsMS45LTQuMyw0LjMtNC4zczQuMywxLjksNC4zLDQuM3YyMS42YzAsMi40LTEuOSw0LjMtNC4zLDQuM3MtNC4zLTEuOS00LjMtNC4zVjI0LjIgICAgeiBNNTAsNzguNGMtMTUuMiwwLTI3LjYtMTIuNC0yNy42LTI3LjZjMC04LjcsNC0xNi43LDExLTIyYzEuOS0xLjQsNC42LTEsNiwwLjhjMS40LDEuOSwxLDQuNi0wLjgsNmMtNC44LDMuNi03LjYsOS4yLTcuNiwxNS4yICAgIGMwLDEwLjUsOC41LDE5LjEsMTkuMSwxOS4xYzEwLjUsMCwxOS4xLTguNSwxOS4xLTE5LjFjMC02LTIuOC0xMS41LTcuNi0xNS4yYy0xLjktMS40LTIuMy00LjEtMC44LTZjMS40LTEuOSw0LjEtMi4zLDYtMC44ICAgIGM3LDUuMywxMSwxMy4zLDExLDIyQzc3LjYsNjYsNjUuMiw3OC40LDUwLDc4LjR6Ij48L3BhdGg+PC9nPjwvc3dpdGNoPjwvc3ZnPg==");
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
display: block;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-top: 10px;
|
||||||
|
background-size: cover;
|
||||||
|
opacity: 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.off-icon:hover {
|
||||||
|
opacity: 0.3;
|
||||||
|
cursor:pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quit-icon:hover {
|
||||||
|
opacity: 0.3;
|
||||||
|
cursor:pointer;
|
||||||
}
|
}
|
52
app/frontend/src/components/Controls.vue
Normal file
52
app/frontend/src/components/Controls.vue
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<template>
|
||||||
|
<div class="controls">
|
||||||
|
<i class="off-icon" v-on:click="action('shutdown')" v-if="off_available && off_display"></i>
|
||||||
|
<i class="quit-icon" v-on:click="action('quit')" v-if="quit_available && quit_display"></i>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import axios from 'axios'
|
||||||
|
export default {
|
||||||
|
name: 'Controls',
|
||||||
|
data: function (){
|
||||||
|
return {
|
||||||
|
off_available : false,
|
||||||
|
off_display : false,
|
||||||
|
quit_available: false,
|
||||||
|
quit_display : false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
action: function(action) {
|
||||||
|
axios.get(`/api/misc/${action}`, { timeout: 30000 })
|
||||||
|
.then(response => {
|
||||||
|
if(response.data.status)
|
||||||
|
console.log(`Let's ${action}`)
|
||||||
|
})
|
||||||
|
.catch(error => { console.log(error) });
|
||||||
|
},
|
||||||
|
load_config: function() {
|
||||||
|
axios.get(`/api/misc/config`, { timeout: 60000 })
|
||||||
|
.then(response => {
|
||||||
|
this.quit_available = response.data.quit_option
|
||||||
|
this.off_available = response.data.shutdown_option
|
||||||
|
})
|
||||||
|
.catch(error => { console.log(error) });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route (){
|
||||||
|
if ( ["capture", "report"].includes(this.$router.currentRoute.name) || screen.height != window.innerHeight ){
|
||||||
|
this.off_display = false;
|
||||||
|
this.quit_display = false;
|
||||||
|
} else {
|
||||||
|
this.off_display = (this.off_available)? true : false;
|
||||||
|
this.quit_display = (this.quit_available)? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created: function() {
|
||||||
|
this.load_config()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
@ -27,12 +27,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<p>
|
<p>
|
||||||
<strong>Unfortunately, we got some issues.</strong>
|
<strong>Unfortunately, we got some issues <br />during the AP creation.</strong>
|
||||||
<br /><br />
|
<br /><br />
|
||||||
Please verify that you've two Wifi interfaces on your device<br />
|
Please verify that you've two WiFi interfaces on your device<br /> and try again by restarting it.<br /><br />
|
||||||
and restart it by clicking on the button below.<br />
|
|
||||||
</p>
|
</p>
|
||||||
<button class="btn" v-on:click="reboot()">Reboot the device</button>
|
<button v-if="reboot_option" class="btn" v-on:click="reboot()">Restart the device</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -53,14 +52,15 @@ export default {
|
|||||||
capture_token: false,
|
capture_token: false,
|
||||||
capture_start: false,
|
capture_start: false,
|
||||||
interval: false,
|
interval: false,
|
||||||
error: false
|
error: false,
|
||||||
|
reboot_option: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
generate_ap: function() {
|
generate_ap: function() {
|
||||||
clearInterval(this.interval)
|
clearInterval(this.interval)
|
||||||
this.ssid_name = false
|
this.ssid_name = false
|
||||||
axios.get(`/api/network/ap/start`, { timeout: 70000 })
|
axios.get(`/api/network/ap/start`, { timeout: 30000 })
|
||||||
.then(response => (this.show_ap(response.data)))
|
.then(response => (this.show_ap(response.data)))
|
||||||
},
|
},
|
||||||
show_ap: function(data) {
|
show_ap: function(data) {
|
||||||
@ -109,9 +109,19 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
load_config: function() {
|
||||||
|
axios.get(`/api/misc/config`, { timeout: 60000 })
|
||||||
|
.then(response => {
|
||||||
|
this.reboot_option = response.data.reboot_option
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error)
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created: function() {
|
created: function() {
|
||||||
|
this.load_config()
|
||||||
this.generate_ap();
|
this.generate_ap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,35 @@ def api_reboot():
|
|||||||
"""
|
"""
|
||||||
Reboot the device
|
Reboot the device
|
||||||
"""
|
"""
|
||||||
sp.Popen("reboot", shell=True)
|
if read_config(("frontend", "reboot_option")):
|
||||||
return jsonify({"mesage": "Let's reboot."})
|
sp.Popen("shutdown -r now", shell=True)
|
||||||
|
return jsonify({"mesage": "Let's reboot."})
|
||||||
|
else:
|
||||||
|
return jsonify({"message": "Option disabled", "status": False})
|
||||||
|
|
||||||
|
|
||||||
|
@misc_bp.route("/quit", methods=["GET"])
|
||||||
|
def api_quit():
|
||||||
|
"""
|
||||||
|
Quit the interface (Chromium browser)
|
||||||
|
"""
|
||||||
|
if read_config(("frontend", "quit_option")):
|
||||||
|
sp.Popen('pkill -INT -f "chromium-browser"', shell=True)
|
||||||
|
return jsonify({"message": "Let's quit", "status": True})
|
||||||
|
else:
|
||||||
|
return jsonify({"message": "Option disabled", "status": False})
|
||||||
|
|
||||||
|
|
||||||
|
@misc_bp.route("/shutdown", methods=["GET"])
|
||||||
|
def api_shutdown():
|
||||||
|
"""
|
||||||
|
Reboot the device
|
||||||
|
"""
|
||||||
|
if read_config(("frontend", "shutdown_option")):
|
||||||
|
sp.Popen("shutdown -h now", shell=True)
|
||||||
|
return jsonify({"message": "Let's shutdown", "status": True})
|
||||||
|
else:
|
||||||
|
return jsonify({"message": "Option disabled", "status": False})
|
||||||
|
|
||||||
|
|
||||||
@misc_bp.route("/config", methods=["GET"])
|
@misc_bp.route("/config", methods=["GET"])
|
||||||
@ -27,4 +54,7 @@ def get_config():
|
|||||||
"hide_mouse": read_config(("frontend", "hide_mouse")),
|
"hide_mouse": read_config(("frontend", "hide_mouse")),
|
||||||
"download_links": read_config(("frontend", "download_links")),
|
"download_links": read_config(("frontend", "download_links")),
|
||||||
"sparklines": read_config(("frontend", "sparklines")),
|
"sparklines": read_config(("frontend", "sparklines")),
|
||||||
|
"quit_option": read_config(("frontend", "quit_option")),
|
||||||
|
"shutdown_option": read_config(("frontend", "shutdown_option")),
|
||||||
|
"reboot_option": read_config(("frontend", "reboot_option"))
|
||||||
})
|
})
|
||||||
|
13
update.sh
13
update.sh
@ -45,5 +45,18 @@ elif [ $PWD = "/tmp/tinycheck" ]; then
|
|||||||
service tinycheck-frontend restart
|
service tinycheck-frontend restart
|
||||||
service tinycheck-watchers restart
|
service tinycheck-watchers restart
|
||||||
|
|
||||||
|
# Updating configuration with new key-val pairs.
|
||||||
|
if ! grep -q reboot_option /usr/share/tinycheck/config.yaml; then
|
||||||
|
sed -i 's/frontend:/frontend:\n reboot_option: true/g' /usr/share/tinycheck/config.yaml
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! grep -q shutdown_option /usr/share/tinycheck/config.yaml; then
|
||||||
|
sed -i 's/frontend:/frontend:\n shutdown_option: true/g' /usr/share/tinycheck/config.yaml
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! grep -q quit_option /usr/share/tinycheck/config.yaml; then
|
||||||
|
sed -i 's/frontend:/frontend:\n quit_option: true/g' /usr/share/tinycheck/config.yaml
|
||||||
|
fi
|
||||||
|
|
||||||
echo "[+] TinyCheck updated!"
|
echo "[+] TinyCheck updated!"
|
||||||
fi
|
fi
|
Loading…
Reference in New Issue
Block a user