Merge branch 'master' into http-basicauth
This commit is contained in:
		
						commit
						34d8984e3a
					
				
					 10 changed files with 111 additions and 8 deletions
				
			
		
							
								
								
									
										2
									
								
								.github/ISSUE_TEMPLATE/ask-for-help.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/ISSUE_TEMPLATE/ask-for-help.yaml
									
									
									
									
										vendored
									
									
								
							|  | @ -1,6 +1,6 @@ | |||
| name: "❓ Ask for help" | ||||
| description: "Submit any question related to Uptime Kuma" | ||||
| title: "[Help] " | ||||
| #title: "[Help] " | ||||
| labels: [help] | ||||
| body: | ||||
|   - type: checkboxes | ||||
|  |  | |||
							
								
								
									
										2
									
								
								.github/ISSUE_TEMPLATE/bug_report.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/ISSUE_TEMPLATE/bug_report.yaml
									
									
									
									
										vendored
									
									
								
							|  | @ -1,6 +1,6 @@ | |||
| name: "🐛 Bug Report" | ||||
| description: "Submit a bug report to help us improve" | ||||
| title: "[Bug] " | ||||
| #title: "[Bug] " | ||||
| labels: [bug] | ||||
| body: | ||||
|   - type: checkboxes | ||||
|  |  | |||
							
								
								
									
										2
									
								
								.github/ISSUE_TEMPLATE/feature_request.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/ISSUE_TEMPLATE/feature_request.yaml
									
									
									
									
										vendored
									
									
								
							|  | @ -1,6 +1,6 @@ | |||
| name: 🚀 Feature Request | ||||
| description: "Submit a proposal for a new feature" | ||||
| title: "[Feature] " | ||||
| #title: "[Feature] " | ||||
| labels: [enhancement] | ||||
| body: | ||||
|   - type: checkboxes | ||||
|  |  | |||
|  | @ -160,6 +160,8 @@ class Monitor extends BeanModel { | |||
|                         }; | ||||
|                     } | ||||
| 
 | ||||
|                     debug(`[${this.name}] Prepare Options for axios`); | ||||
| 
 | ||||
|                     const options = { | ||||
|                         url: this.url, | ||||
|                         method: (this.method || "get").toLowerCase(), | ||||
|  | @ -180,6 +182,8 @@ class Monitor extends BeanModel { | |||
|                             return checkStatusCode(status, this.getAcceptedStatuscodes()); | ||||
|                         }, | ||||
|                     }; | ||||
| 
 | ||||
|                     debug(`[${this.name}] Axios Request`); | ||||
|                     let res = await axios.request(options); | ||||
|                     bean.msg = `${res.status} - ${res.statusText}`; | ||||
|                     bean.ping = dayjs().valueOf() - startTime; | ||||
|  | @ -187,12 +191,13 @@ class Monitor extends BeanModel { | |||
|                     // Check certificate if https is used
 | ||||
|                     let certInfoStartTime = dayjs().valueOf(); | ||||
|                     if (this.getUrl()?.protocol === "https:") { | ||||
|                         debug(`[${this.name}] Check cert`); | ||||
|                         try { | ||||
|                             let tlsInfoObject = checkCertificate(res); | ||||
|                             tlsInfo = await this.updateTlsInfo(tlsInfoObject); | ||||
| 
 | ||||
|                             if (!this.getIgnoreTls()) { | ||||
|                                 debug("call sendCertNotification"); | ||||
|                                 debug(`[${this.name}] call sendCertNotification`); | ||||
|                                 await this.sendCertNotification(tlsInfoObject); | ||||
|                             } | ||||
| 
 | ||||
|  | @ -371,15 +376,19 @@ class Monitor extends BeanModel { | |||
| 
 | ||||
|             let beatInterval = this.interval; | ||||
| 
 | ||||
|             debug(`[${this.name}] Check isImportant`); | ||||
|             let isImportant = Monitor.isImportantBeat(isFirstBeat, previousBeat?.status, bean.status); | ||||
| 
 | ||||
|             // Mark as important if status changed, ignore pending pings,
 | ||||
|             // Don't notify if disrupted changes to up
 | ||||
|             if (isImportant) { | ||||
|                 bean.important = true; | ||||
| 
 | ||||
|                 debug(`[${this.name}] sendNotification`); | ||||
|                 await Monitor.sendNotification(isFirstBeat, this, bean); | ||||
| 
 | ||||
|                 // Clear Status Page Cache
 | ||||
|                 debug(`[${this.name}] Check isImportant`); | ||||
|                 apicache.clear(); | ||||
| 
 | ||||
|             } else { | ||||
|  | @ -397,10 +406,14 @@ class Monitor extends BeanModel { | |||
|                 console.warn(`Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`); | ||||
|             } | ||||
| 
 | ||||
|             debug(`[${this.name}] Send to socket`); | ||||
|             io.to(this.user_id).emit("heartbeat", bean.toJSON()); | ||||
|             Monitor.sendStats(io, this.id, this.user_id); | ||||
| 
 | ||||
|             debug(`[${this.name}] Store`); | ||||
|             await R.store(bean); | ||||
| 
 | ||||
|             debug(`[${this.name}] prometheus.update`); | ||||
|             prometheus.update(bean, tlsInfo); | ||||
| 
 | ||||
|             previousBeat = bean; | ||||
|  | @ -414,7 +427,10 @@ class Monitor extends BeanModel { | |||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 debug(`[${this.name}] SetTimeout for next check.`); | ||||
|                 this.heartbeatInterval = setTimeout(safeBeat, beatInterval * 1000); | ||||
|             } else { | ||||
|                 console.log(`[${this.name}] isStop = true, no next check.`); | ||||
|             } | ||||
| 
 | ||||
|         }; | ||||
|  |  | |||
|  | @ -101,6 +101,10 @@ router.get("/api/status-page/config", async (_request, response) => { | |||
|         config.statusPagePublished = true; | ||||
|     } | ||||
| 
 | ||||
|     if (! config.statusPageTags) { | ||||
|         config.statusPageTags = false; | ||||
|     } | ||||
| 
 | ||||
|     if (! config.title) { | ||||
|         config.title = "Uptime Kuma"; | ||||
|     } | ||||
|  | @ -140,10 +144,25 @@ router.get("/api/status-page/monitor-list", cache("5 minutes"), async (_request, | |||
|     try { | ||||
|         await checkPublished(); | ||||
|         const publicGroupList = []; | ||||
|         let list = await R.find("group", " public = 1 ORDER BY weight "); | ||||
| 
 | ||||
|         const tagsVisible = (await getSettings("statusPage")).statusPageTags; | ||||
|         const list = await R.find("group", " public = 1 ORDER BY weight "); | ||||
|         for (let groupBean of list) { | ||||
|             publicGroupList.push(await groupBean.toPublicJSON()); | ||||
|             let monitorGroup = await groupBean.toPublicJSON(); | ||||
|             if (tagsVisible) { | ||||
|                 monitorGroup.monitorList = await Promise.all(monitorGroup.monitorList.map(async (monitor) => { | ||||
|                     // Includes tags as an array in response, allows for tags to be displayed on public status page
 | ||||
|                     const tags = await R.getAll( | ||||
|                             `SELECT monitor_tag.monitor_id, monitor_tag.value, tag.name, tag.color
 | ||||
|                             FROM monitor_tag | ||||
|                             JOIN tag | ||||
|                             ON monitor_tag.tag_id = tag.id | ||||
|                             WHERE monitor_tag.monitor_id = ?`, [monitor.id]
 | ||||
|                         ); | ||||
|                     return {...monitor, tags: tags} | ||||
|                 })); | ||||
|             } | ||||
| 
 | ||||
|             publicGroupList.push(monitorGroup); | ||||
|         } | ||||
| 
 | ||||
|         response.json(publicGroupList); | ||||
|  |  | |||
|  | @ -346,6 +346,10 @@ textarea.form-control { | |||
|         &.active { | ||||
|             background-color: #cdf8f4; | ||||
|         } | ||||
|         .tags { | ||||
|             // Removes margin to line up tags list with uptime percentage | ||||
|             margin-left: -0.25rem; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -41,6 +41,9 @@ | |||
|                                             <Uptime :monitor="monitor.element" type="24" :pill="true" /> | ||||
|                                             {{ monitor.element.name }} | ||||
|                                         </div> | ||||
|                                         <div class="tags"> | ||||
|                                             <Tag v-for="tag in monitor.element.tags" :key="tag" :item="tag" :size="'sm'" /> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                     <div :key="$root.userHeartbeatBar" class="col-3 col-md-4"> | ||||
|                                         <HeartbeatBar size="small" :monitor-id="monitor.element.id" /> | ||||
|  | @ -59,12 +62,14 @@ | |||
| import Draggable from "vuedraggable"; | ||||
| import HeartbeatBar from "./HeartbeatBar.vue"; | ||||
| import Uptime from "./Uptime.vue"; | ||||
| import Tag from "./Tag.vue"; | ||||
| 
 | ||||
| export default { | ||||
|     components: { | ||||
|         Draggable, | ||||
|         HeartbeatBar, | ||||
|         Uptime, | ||||
|         Tag, | ||||
|     }, | ||||
|     props: { | ||||
|         editMode: { | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| <template> | ||||
|     <span :class="className">{{ uptime }}</span> | ||||
|     <span :class="className" :title="24 + $t('-hour')">{{ uptime }}</span> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
|  |  | |||
|  | @ -279,4 +279,29 @@ export default { | |||
|     promosmsTypeSpeed: "SMS SPEED - La plus haute des priorités dans le système. Très rapide et fiable mais cher (environ le double du prix d'un SMS FULL).", | ||||
|     promosmsPhoneNumber: "Numéro de téléphone (Poiur les déstinataires Polonais, vous pouvez enlever les codes interna.)", | ||||
|     promosmsSMSSender: "SMS Expéditeur : Nom pré-enregistré ou l'un de base: InfoSMS, SMS Info, MaxSMS, INFO, SMS", | ||||
|     "Primary Base URL": "Primary Base URL", | ||||
|     emailCustomSubject: "Sujet personalisé", | ||||
|     clicksendsms: "ClickSend SMS", | ||||
|     checkPrice: "Vérification {0} tarifs:", | ||||
|     apiCredentials: "Crédentials de l'API", | ||||
|     octopushLegacyHint: "Vous utilisez l'ancienne version d'Octopush (2011-2020) ou la nouvelle version ?", | ||||
|     "Feishu WebHookUrl": "Feishu WebHookURL", | ||||
|     matrixHomeserverURL: "L'URL du serveur (avec http(s):// et le port de manière facultatif)", | ||||
|     "Internal Room Id": "ID de la salle interne", | ||||
|     matrixDesc1: "Vous pouvez trouvez l'ID de salle interne en regardant dans la section avancée des paramètres dans le client Matrix. C'est sensé ressembler à: !QMdRCpUIfLwsfjxye6:home.server.", | ||||
|     matrixDesc2: "Il est fortement recommandé de créer un nouvel utilisateur et de ne pas utiliser le jeton d'accès de votre propre utilisateur Matrix, car il vous donnera un accès complet à votre compte et à toutes les salles que vous avez rejointes. Au lieu de cela, créez un nouvel utilisateur et invitez-le uniquement dans la salle dans laquelle vous souhaitez recevoir la notification. Vous pouvez obtenir le jeton d'accès en exécutant {0}", | ||||
|     Method: "Méthode", | ||||
|     Body: "Le corps", | ||||
|     Headers: "En-têtes", | ||||
|     PushUrl: "Push URL", | ||||
|     HeadersInvalidFormat: "L'en-têtes de la requête n'est pas dans un format JSON valide: ", | ||||
|     BodyInvalidFormat: "Le corps de la requête n'est pas dans un format JSON valide: ", | ||||
|     "Monitor History": "Historique de la sonde", | ||||
|     clearDataOlderThan: "Garder l'historique des données de la sonde durant {0} jours.", | ||||
|     PasswordsDoNotMatch: "Les mots de passe ne correspondent pas.", | ||||
|     records: "Enregistrements", | ||||
|     "One record": "Un enregistrement", | ||||
|     steamApiKeyDescription: "Pour surveiller un serveur Steam, vous avez besoin  d'une clé Steam Web-API. Vous pouvez enregistrer votre clé ici: ", | ||||
|     "Current User": "Utilisateur actuel", | ||||
|     recent: "Récent", | ||||
| }; | ||||
|  |  | |||
|  | @ -77,6 +77,17 @@ | |||
|                     <font-awesome-icon icon="save" /> | ||||
|                     {{ $t("Switch to Dark Theme") }} | ||||
|                 </button> | ||||
| 
 | ||||
|                 <button class="btn btn-secondary me-2" @click="changeTagsVisibilty(!tagsVisible)"> | ||||
|                     <template v-if="tagsVisible"> | ||||
|                         <font-awesome-icon icon="eye-slash" /> | ||||
|                         {{ $t("Hide Tags") }} | ||||
|                     </template> | ||||
|                     <template v-else> | ||||
|                         <font-awesome-icon icon="eye" /> | ||||
|                         {{ $t("Show Tags") }} | ||||
|                     </template> | ||||
|                 </button> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|  | @ -292,6 +303,10 @@ export default { | |||
|             return this.config.statusPageTheme; | ||||
|         }, | ||||
| 
 | ||||
|         tagsVisible() { | ||||
|             return this.config.statusPageTags | ||||
|         }, | ||||
| 
 | ||||
|         logoClass() { | ||||
|             if (this.editMode) { | ||||
|                 return { | ||||
|  | @ -472,6 +487,25 @@ export default { | |||
|         changeTheme(name) { | ||||
|             this.config.statusPageTheme = name; | ||||
|         }, | ||||
|         changeTagsVisibilty(newState) { | ||||
|             this.config.statusPageTags = newState; | ||||
| 
 | ||||
|             // On load, the status page will not include tags if it's not enabled for security reasons | ||||
|             // Which means if we enable tags, it won't show in the UI until saved | ||||
|             // So we have this to enhance UX and load in the tags from the authenticated source instantly | ||||
|             this.$root.publicGroupList = this.$root.publicGroupList.map((group) => { | ||||
|                 return { | ||||
|                     ...group, | ||||
|                     monitorList: group.monitorList.map((monitor) => { | ||||
|                         // We only include the tags if visible so we can reuse the logic to hide the tags on disable | ||||
|                         return { | ||||
|                             ...monitor, | ||||
|                             tags: newState ? this.$root.monitorList[monitor.id].tags : [] | ||||
|                         } | ||||
|                     }) | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
| 
 | ||||
|         /** | ||||
|          * Crop Success | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue