[Status Page] WIP: Checkpoint
This commit is contained in:
		
							parent
							
								
									4b0a8087a2
								
							
						
					
					
						commit
						3e25f0e9d9
					
				
					 7 changed files with 159 additions and 18 deletions
				
			
		|  | @ -26,7 +26,7 @@ console.log("Importing this project modules"); | |||
| debug("Importing Monitor"); | ||||
| const Monitor = require("./model/monitor"); | ||||
| debug("Importing Settings"); | ||||
| const { getSettings, setSettings, setting, initJWTSecret } = require("./util-server"); | ||||
| const { getSettings, setSettings, setting, initJWTSecret, allowDevAllOrigin } = require("./util-server"); | ||||
| 
 | ||||
| debug("Importing Notification"); | ||||
| const { Notification } = require("./notification"); | ||||
|  | @ -127,7 +127,9 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString(); | |||
| 
 | ||||
|     console.log("Adding route") | ||||
| 
 | ||||
|     // ***************************
 | ||||
|     // Normal Router here
 | ||||
|     // ***************************
 | ||||
| 
 | ||||
|     // Robots.txt
 | ||||
|     app.get("/robots.txt", async (_request, response) => { | ||||
|  | @ -147,7 +149,28 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString(); | |||
| 
 | ||||
|     app.use("/", express.static("dist")); | ||||
| 
 | ||||
|     // Universal Route Handler, must be at the end
 | ||||
|     // ***************************
 | ||||
|     // Public API
 | ||||
|     // ***************************
 | ||||
| 
 | ||||
|     // Status Page Config
 | ||||
|     app.get("/api/status-page/config", async (_request, response) => { | ||||
|         allowDevAllOrigin(response); | ||||
|         let config = getSettings("statusPage"); | ||||
| 
 | ||||
|         if (! config.statusPageTheme) { | ||||
|             config.statusPageTheme = "light"; | ||||
|         } | ||||
| 
 | ||||
|         response.json(config); | ||||
|     }); | ||||
| 
 | ||||
|     // Status Page Polling Data
 | ||||
|     app.get("/api/status-page", async (_request, response) => { | ||||
|         allowDevAllOrigin(response); | ||||
|     }); | ||||
| 
 | ||||
|     // Universal Route Handler, must be at the end of all express route.
 | ||||
|     app.get("*", async (_request, response) => { | ||||
|         response.send(indexHTML); | ||||
|     }); | ||||
|  | @ -172,7 +195,7 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString(); | |||
|         }); | ||||
| 
 | ||||
|         // ***************************
 | ||||
|         // Public API
 | ||||
|         // Public Socket API
 | ||||
|         // ***************************
 | ||||
| 
 | ||||
|         socket.on("loginByToken", async (token, callback) => { | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ const { debug } = require("../src/util"); | |||
| const passwordHash = require("./password-hash"); | ||||
| const dayjs = require("dayjs"); | ||||
| const { Resolver } = require("dns"); | ||||
| const { allowAllOrigin } = require("./util-server"); | ||||
| 
 | ||||
| /** | ||||
|  * Init or reset JWT secret | ||||
|  | @ -271,3 +272,14 @@ exports.getTotalClientInRoom = (io, roomName) => { | |||
|         return 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| exports.allowDevAllOrigin = (res) => { | ||||
|     if (process.env.NODE_ENV === "development") { | ||||
|         exports.allowAllOrigin(res); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| exports.allowAllOrigin = (res) => { | ||||
|     res.header("Access-Control-Allow-Origin", "*"); | ||||
|     res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); | ||||
| } | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| import { library } from "@fortawesome/fontawesome-svg-core" | ||||
| import { faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons" | ||||
| import { faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp, faEye, faEyeSlash, faCheckCircle, faStream } from "@fortawesome/free-solid-svg-icons" | ||||
| //import { fa } from '@fortawesome/free-regular-svg-icons'
 | ||||
| import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome" | ||||
| 
 | ||||
| // Add Free Font Awesome Icons here
 | ||||
| // https://fontawesome.com/v5.15/icons?d=gallery&p=2&s=solid&m=free
 | ||||
| library.add(faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp, faEye, faEyeSlash); | ||||
| library.add(faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp, faEye, faEyeSlash, faCheckCircle, faStream); | ||||
| 
 | ||||
| export { FontAwesomeIcon } | ||||
|  |  | |||
|  | @ -18,6 +18,11 @@ | |||
|             </a> | ||||
| 
 | ||||
|             <ul class="nav nav-pills"> | ||||
|                 <li class="nav-item"> | ||||
|                     <router-link to="/status-page" class="nav-link status-page"> | ||||
|                         <font-awesome-icon icon="stream" /> {{ $t("Status Page") }} | ||||
|                     </router-link> | ||||
|                 </li> | ||||
|                 <li class="nav-item"> | ||||
|                     <router-link to="/dashboard" class="nav-link"> | ||||
|                         <font-awesome-icon icon="tachometer-alt" /> {{ $t("Dashboard") }} | ||||
|  | @ -128,6 +133,12 @@ export default { | |||
| <style lang="scss" scoped> | ||||
| @import "../assets/vars.scss"; | ||||
| 
 | ||||
| .nav-link { | ||||
|     &.status-page { | ||||
|         background-color: rgba(255, 255, 255, 0.1); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| .bottom-nav { | ||||
|     z-index: 1000; | ||||
|     position: fixed; | ||||
|  |  | |||
|  | @ -1,10 +1,11 @@ | |||
| import { io } from "socket.io-client"; | ||||
| import { useToast } from "vue-toastification"; | ||||
| import axios from "axios"; | ||||
| const toast = useToast() | ||||
| 
 | ||||
| let socket; | ||||
| 
 | ||||
| const noSocketIOPage = [ | ||||
| const noSocketIOPages = [ | ||||
|     "/status-page", | ||||
| ]; | ||||
| 
 | ||||
|  | @ -19,7 +20,6 @@ export default { | |||
|                 connected: false, | ||||
|                 connectCount: 0, | ||||
|                 initedSocketIO: false, | ||||
| 
 | ||||
|             }, | ||||
|             remember: (localStorage.remember !== "0"), | ||||
|             allowLoginDialog: false,        // Allowed to show login dialog, but "loggedIn" have to be true too. This exists because prevent the login dialog show 0.1s in first before the socket server auth-ed.
 | ||||
|  | @ -49,7 +49,7 @@ export default { | |||
|             } | ||||
| 
 | ||||
|             // No need to connect to the socket.io for status page
 | ||||
|             if (! bypass && noSocketIOPage.includes(location.pathname)) { | ||||
|             if (! bypass && noSocketIOPages.includes(location.pathname)) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|  | @ -359,7 +359,7 @@ export default { | |||
| 
 | ||||
|         // Reconnect the socket io, if status-page to dashboard
 | ||||
|         "$route.fullPath"(newValue, oldValue) { | ||||
|             if (noSocketIOPage.includes(newValue)) { | ||||
|             if (noSocketIOPages.includes(newValue)) { | ||||
|                 return; | ||||
|             } | ||||
|             this.initSocketIO(); | ||||
|  |  | |||
|  | @ -5,6 +5,8 @@ export default { | |||
|             system: (window.matchMedia("(prefers-color-scheme: dark)").matches) ? "dark" : "light", | ||||
|             userTheme: localStorage.theme, | ||||
|             userHeartbeatBar: localStorage.heartbeatBarTheme, | ||||
|             statusPageTheme: "dark", | ||||
|             path: "", | ||||
|         }; | ||||
|     }, | ||||
| 
 | ||||
|  | @ -25,14 +27,22 @@ export default { | |||
| 
 | ||||
|     computed: { | ||||
|         theme() { | ||||
|             if (this.userTheme === "auto") { | ||||
|                 return this.system; | ||||
|             if (this.path === "/status-page") { | ||||
|                 return this.statusPageTheme; | ||||
|             } else { | ||||
|                 if (this.userTheme === "auto") { | ||||
|                     return this.system; | ||||
|                 } | ||||
|                 return this.userTheme; | ||||
|             } | ||||
|             return this.userTheme; | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|     watch: { | ||||
|         "$route.fullPath"(path) { | ||||
|             this.path = path; | ||||
|         }, | ||||
| 
 | ||||
|         userTheme(to, from) { | ||||
|             localStorage.theme = to; | ||||
|         }, | ||||
|  |  | |||
|  | @ -1,17 +1,71 @@ | |||
| <template> | ||||
|     <button v-if="hasToken" @click="edit"> | ||||
|         <font-awesome-icon icon="edit" /> | ||||
|     </button> | ||||
|     <div class="container mt-3"> | ||||
|         <h1><img src="/icon.svg" alt /> Uptime Kuma</h1> | ||||
| 
 | ||||
|         <div v-if="hasToken" class="mt-3"> | ||||
|             <button class="btn btn-info me-2" @click="edit"> | ||||
|                 <font-awesome-icon icon="edit" /> | ||||
|                 Edit Status Page | ||||
|             </button> | ||||
| 
 | ||||
|             <router-link to="/dashboard" class="btn btn-info"> | ||||
|                 <font-awesome-icon icon="tachometer-alt" /> | ||||
|                 Go to Dashboard | ||||
|             </router-link> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="shadow-box list mt-4 p-4 overall-status"> | ||||
|             <font-awesome-icon icon="check-circle" class="ok" /> All Systems Operational | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="shadow-box list mt-4" :class="{ scrollbar: scrollbar }"> | ||||
|             <div v-if="Object.keys($root.monitorList).length === 0" class="text-center mt-3"> | ||||
|                 {{ $t("No Monitors, please") }} <router-link to="/add">{{ $t("add one") }}</router-link> | ||||
|             </div> | ||||
| 
 | ||||
|             <router-link v-for="(item, index) in sortedMonitorList" :key="index" :to="monitorURL(item.id)" class="item" :class="{ 'disabled': ! item.active }"> | ||||
|                 <div class="row"> | ||||
|                     <div class="col-6 col-md-8 small-padding" :class="{ 'monitorItem': $root.userHeartbeatBar == 'bottom' || $root.userHeartbeatBar == 'none' }"> | ||||
|                         <div class="info"> | ||||
|                             <Uptime :monitor="item" type="24" :pill="true" /> | ||||
|                             {{ item.name }} | ||||
|                         </div> | ||||
|                     </div> | ||||
|                     <div v-show="$root.userHeartbeatBar == 'normal'" :key="$root.userHeartbeatBar" class="col-6 col-md-4"> | ||||
|                         <HeartbeatBar size="small" :monitor-id="item.id" /> | ||||
|                     </div> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <div v-if="$root.userHeartbeatBar == 'bottom'" class="row"> | ||||
|                     <div class="col-12"> | ||||
|                         <HeartbeatBar size="small" :monitor-id="item.id" /> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </router-link> | ||||
|         </div> | ||||
| 
 | ||||
|         <footer class="mt-4"> | ||||
|             Powered by <a target="_blank" href="https://github.com/louislam/uptime-kuma">Uptime Kuma</a> | ||||
|         </footer> | ||||
|     </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { useToast } from "vue-toastification" | ||||
| const toast = useToast() | ||||
| import axios from "axios"; | ||||
| const toast = useToast(); | ||||
| const env = process.env.NODE_ENV || "production"; | ||||
| 
 | ||||
| // change the axios base url for development | ||||
| if (env === "development" || localStorage.dev === "dev") { | ||||
|     axios.defaults.baseURL = location.protocol + "//" + location.hostname + ":3001"; | ||||
| } | ||||
| 
 | ||||
| export default { | ||||
|     data() { | ||||
|         return { | ||||
|             hasToken: false, | ||||
|             config: {}, | ||||
|         } | ||||
|     }, | ||||
|     computed: { | ||||
|  | @ -20,17 +74,48 @@ export default { | |||
|     watch: { | ||||
| 
 | ||||
|     }, | ||||
|     created() { | ||||
|     async created() { | ||||
|         this.hasToken = ("token" in localStorage); | ||||
|         this.config = await axios.get("/api/status-page/config"); | ||||
| 
 | ||||
|         // Set Theme | ||||
|         this.$root.statusPageTheme = this.config.statusPageTheme; | ||||
|     }, | ||||
|     mounted() { | ||||
| 
 | ||||
|     }, | ||||
|     methods: { | ||||
|         edit() { | ||||
|             console.log("here"); | ||||
|             this.$root.initSocketIO(true); | ||||
|         } | ||||
|     }, | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| @import "../assets/vars.scss"; | ||||
| 
 | ||||
| .overall-status { | ||||
|     font-weight: bold; | ||||
|     font-size: 20px; | ||||
| 
 | ||||
|     .ok { | ||||
|         color: $primary; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| h1 { | ||||
|     font-size: 30px; | ||||
| 
 | ||||
|     img { | ||||
|         vertical-align: middle; | ||||
|         height: 60px; | ||||
|         width: 60px; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| footer { | ||||
|     text-align: center; | ||||
|     font-size: 14px; | ||||
| } | ||||
| </style> | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue