forked from MapComplete/MapComplete
		
	Add simple status page
This commit is contained in:
		
							parent
							
								
									bdea29eea1
								
							
						
					
					
						commit
						811bcecea4
					
				
					 6 changed files with 354 additions and 3 deletions
				
			
		| 
						 | 
					@ -21,9 +21,9 @@
 | 
				
			||||||
      "oauth_secret": "NBWGhWDrD3QDB35xtVuxv4aExnmIt4FA_WgeLtwxasg",
 | 
					      "oauth_secret": "NBWGhWDrD3QDB35xtVuxv4aExnmIt4FA_WgeLtwxasg",
 | 
				
			||||||
      "url": "https://www.openstreetmap.org"
 | 
					      "url": "https://www.openstreetmap.org"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "mvt_layer_server": "https://proxy.mapcomplete.org/public.{type}_{layer}/{z}/{x}/{y}.pbf",
 | 
					    "mvt_layer_server": "https://cache.mapcomplete.org/public.{type}_{layer}/{z}/{x}/{y}.pbf",
 | 
				
			||||||
    "#summary_server": "Should be the endpoint; appending status.json should work",
 | 
					    "#summary_server": "Should be the endpoint; appending status.json should work",
 | 
				
			||||||
    "summary_server": "https://proxy0.mapcomplete.org/",
 | 
					    "summary_server": "https://cache.mapcomplete.org/",
 | 
				
			||||||
    "geoip_server": "https://ipinfo.mapcomplete.org/",
 | 
					    "geoip_server": "https://ipinfo.mapcomplete.org/",
 | 
				
			||||||
    "error_server": "https://report.mapcomplete.org/report",
 | 
					    "error_server": "https://report.mapcomplete.org/report",
 | 
				
			||||||
    "disabled:oauth_credentials": {
 | 
					    "disabled:oauth_credentials": {
 | 
				
			||||||
| 
						 | 
					@ -93,7 +93,7 @@
 | 
				
			||||||
    "generate:charging-stations": "cd ./assets/layers/charging_station && vite-node csvToJson.ts && cd -",
 | 
					    "generate:charging-stations": "cd ./assets/layers/charging_station && vite-node csvToJson.ts && cd -",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "clean:tests": "find . -type f -name \"*.doctest.ts\" | xargs -r rm",
 | 
					    "clean:tests": "find . -type f -name \"*.doctest.ts\" | xargs -r rm",
 | 
				
			||||||
    "clean": "rm -rf .cache/ && (find *.html | grep -v \"^\\(404\\|index\\|land\\|privacy\\|test\\|studio\\|theme\\|style_test\\|statistics\\|leaderboard\\).html\" | xargs -r rm) && (ls | grep \"^index_[a-zA-Z_-]\\+\\.ts$\" | xargs -r rm)",
 | 
					    "clean": "rm -rf .cache/ && (find *.html | grep -v \"^\\(404\\|index\\|land\\|privacy\\|test\\|studio\\|theme\\|style_test\\|statistics\\|status\\|leaderboard\\).html\" | xargs -r rm) && (ls | grep \"^index_[a-zA-Z_-]\\+\\.ts$\" | xargs -r rm)",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "generate:dependency-graph": "node_modules/.bin/depcruise --exclude \"^node_modules\" --output-type dot Logic/State/MapState.ts > dependencies.dot && dot dependencies.dot -T svg -o dependencies.svg && rm dependencies.dot",
 | 
					    "generate:dependency-graph": "node_modules/.bin/depcruise --exclude \"^node_modules\" --output-type dot Logic/State/MapState.ts > dependencies.dot && dot dependencies.dot -T svg -o dependencies.svg && rm dependencies.dot",
 | 
				
			||||||
    "scrapeWebsites": "vite-node scripts/importscripts/compareWebsiteData.ts -- ~/Downloads/ShopsWithWebsiteNodes.csv ~/data/scraped_websites/",
 | 
					    "scrapeWebsites": "vite-node scripts/importscripts/compareWebsiteData.ts -- ~/Downloads/ShopsWithWebsiteNodes.csv ~/data/scraped_websites/",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										7
									
								
								src/UI/Status/MCService.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/UI/Status/MCService.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					import { Store } from "../../Logic/UIEventSource"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface MCService {
 | 
				
			||||||
 | 
					    name: string
 | 
				
			||||||
 | 
					    status: Store<"online" | "degraded" | "offline">,
 | 
				
			||||||
 | 
					    message?: Store<undefined | string>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								src/UI/Status/ServiceIndicator.svelte
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/UI/Status/ServiceIndicator.svelte
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					import StatusIcon from "./StatusIcon.svelte"
 | 
				
			||||||
 | 
					import type { MCService } from "./MCService.js"
 | 
				
			||||||
 | 
					import AccordionSingle from "../Flowbite/AccordionSingle.svelte"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export let service: MCService
 | 
				
			||||||
 | 
					let status = service.status
 | 
				
			||||||
 | 
					let msg = service.message
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<AccordionSingle>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<h3 slot="header" class="flex items-center m-0"> <StatusIcon status={$status}/> {service.name}</h3>
 | 
				
			||||||
 | 
					<div class="mx-4">
 | 
				
			||||||
 | 
					  {#if $msg}
 | 
				
			||||||
 | 
					  {$msg}
 | 
				
			||||||
 | 
					    {:else}
 | 
				
			||||||
 | 
					    No extra information available
 | 
				
			||||||
 | 
					    {/if}
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					</AccordionSingle>
 | 
				
			||||||
							
								
								
									
										285
									
								
								src/UI/Status/StatusGUI.svelte
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								src/UI/Status/StatusGUI.svelte
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,285 @@
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  import { Store, UIEventSource } from "../../Logic/UIEventSource"
 | 
				
			||||||
 | 
					  import StatusIcon from "./StatusIcon.svelte"
 | 
				
			||||||
 | 
					  import type { MCService } from "./MCService"
 | 
				
			||||||
 | 
					  import ServiceIndicator from "./ServiceIndicator.svelte"
 | 
				
			||||||
 | 
					  import { OsmConnection } from "../../Logic/Osm/OsmConnection"
 | 
				
			||||||
 | 
					  import Constants from "../../Models/Constants"
 | 
				
			||||||
 | 
					  import { Utils } from "../../Utils"
 | 
				
			||||||
 | 
					  import Loading from "../Base/Loading.svelte"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let services: MCService[] = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let states = [undefined, "online", "degraded", "offline"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function simpleMessage(s: Store<{ success: any } | { error: any }>): Store<string> {
 | 
				
			||||||
 | 
					    return s.mapD(s => {
 | 
				
			||||||
 | 
					      if (s["success"]) {
 | 
				
			||||||
 | 
					        return JSON.stringify(s["success"])
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return s["error"]
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    const connection = new OsmConnection()
 | 
				
			||||||
 | 
					    const osmApi = connection.apiIsOnline
 | 
				
			||||||
 | 
					    services.push({
 | 
				
			||||||
 | 
					      name: connection.Backend(),
 | 
				
			||||||
 | 
					      status: osmApi.mapD(serviceState => {
 | 
				
			||||||
 | 
					        switch (serviceState) {
 | 
				
			||||||
 | 
					          case "offline":
 | 
				
			||||||
 | 
					            return "offline"
 | 
				
			||||||
 | 
					          case "online":
 | 
				
			||||||
 | 
					            return "online"
 | 
				
			||||||
 | 
					          case "readonly":
 | 
				
			||||||
 | 
					            return "degraded"
 | 
				
			||||||
 | 
					          case "unknown":
 | 
				
			||||||
 | 
					            return undefined
 | 
				
			||||||
 | 
					          case "unreachable":
 | 
				
			||||||
 | 
					            return "offline"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
 | 
					      message: osmApi
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    const s = "https://studio.mapcomplete.org"
 | 
				
			||||||
 | 
					    const status = UIEventSource.FromPromiseWithErr(
 | 
				
			||||||
 | 
					      Utils.downloadJson(s + "/overview")
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    services.push({
 | 
				
			||||||
 | 
					      name: s,
 | 
				
			||||||
 | 
					      status: status.mapD(s => {
 | 
				
			||||||
 | 
					        if (s["error"]) {
 | 
				
			||||||
 | 
					          return "offline"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const files: string[] = s["success"]["allFiles"]
 | 
				
			||||||
 | 
					        if (files.length < 10) {
 | 
				
			||||||
 | 
					          return "offline"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (files.length < 100) {
 | 
				
			||||||
 | 
					          return "degraded"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return "online"
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
 | 
					      message: status.mapD(s => {
 | 
				
			||||||
 | 
					        if(s["error"]){
 | 
				
			||||||
 | 
					          return s["error"]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const files: string[] = s["success"]["allFiles"]
 | 
				
			||||||
 | 
					        return "Contains "+(files.length ?? "no")+" files"
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    services.push(
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: Constants.GeoIpServer,
 | 
				
			||||||
 | 
					        status: UIEventSource.FromPromiseWithErr(
 | 
				
			||||||
 | 
					          Utils.downloadJson(Constants.GeoIpServer + "/status")
 | 
				
			||||||
 | 
					        ).mapD(result => {
 | 
				
			||||||
 | 
					          if (result["success"].online) {
 | 
				
			||||||
 | 
					            return "online"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (result["error"]) {
 | 
				
			||||||
 | 
					            return "offline"
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            return "degraded"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					        message: simpleMessage(UIEventSource.FromPromiseWithErr(
 | 
				
			||||||
 | 
					          Utils.downloadJson(Constants.GeoIpServer + "/ip")
 | 
				
			||||||
 | 
					        ))
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    const s = Constants.ErrorReportServer
 | 
				
			||||||
 | 
					    const status = UIEventSource.FromPromiseWithErr(
 | 
				
			||||||
 | 
					      Utils.downloadJson(s.replace(/\/report$/, "/status"))
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    services.push({
 | 
				
			||||||
 | 
					      name: s,
 | 
				
			||||||
 | 
					      status: status.mapD(s => {
 | 
				
			||||||
 | 
					        if (s["error"]) {
 | 
				
			||||||
 | 
					          return "offline"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const data = s["success"]
 | 
				
			||||||
 | 
					        if (data["errors_today"] === 0) {
 | 
				
			||||||
 | 
					          return "online"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return "degraded"
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
 | 
					      message: simpleMessage(status)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    const s = Constants.linkedDataProxy.replace(/\/[^/]*$/, "")
 | 
				
			||||||
 | 
					    const status = UIEventSource.FromPromiseWithErr(
 | 
				
			||||||
 | 
					      Utils.downloadJson(s + "/status")
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    services.push({
 | 
				
			||||||
 | 
					      name: s,
 | 
				
			||||||
 | 
					      status: status.mapD(s => {
 | 
				
			||||||
 | 
					        if (s["error"]) {
 | 
				
			||||||
 | 
					          return "offline"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const data = s["success"]
 | 
				
			||||||
 | 
					        if (data.cached_entries < 10 || data.uptime < 60 * 60) {
 | 
				
			||||||
 | 
					          return "degraded"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return "online"
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
 | 
					      message: simpleMessage(status)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    const s = Constants.SummaryServer
 | 
				
			||||||
 | 
					    const status = UIEventSource.FromPromiseWithErr(
 | 
				
			||||||
 | 
					      Utils.downloadJson(s + "/summary/status.json")
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    services.push({
 | 
				
			||||||
 | 
					      name: s,
 | 
				
			||||||
 | 
					      status: status.mapD(s => {
 | 
				
			||||||
 | 
					        if (s["error"]) {
 | 
				
			||||||
 | 
					          return "offline"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        console.log(s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const attributes = s["success"]["meta"]
 | 
				
			||||||
 | 
					        const lastUpdate = new Date(attributes["current_timestamp"])
 | 
				
			||||||
 | 
					        console.log("Last update:", lastUpdate, attributes["current_timestamp"], attributes)
 | 
				
			||||||
 | 
					        const timediffSec = (new Date().getTime() - lastUpdate.getTime()) / 1000
 | 
				
			||||||
 | 
					        const timediffDays = timediffSec / (60 * 60 * 26)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (timediffDays > 7) {
 | 
				
			||||||
 | 
					          return "degraded"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return "online"
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
 | 
					      message: status.mapD(s => {
 | 
				
			||||||
 | 
					        if (s["error"]) {
 | 
				
			||||||
 | 
					          return s["error"]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const attributes = s["success"]["meta"]
 | 
				
			||||||
 | 
					        const lastUpdate = new Date(attributes["current_timestamp"])
 | 
				
			||||||
 | 
					        const timediffSec = (new Date().getTime() - lastUpdate.getTime()) / 1000
 | 
				
			||||||
 | 
					        const timediffDays = timediffSec / (60 * 60 * 26)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const json = JSON.stringify(s["success"], null, "  ")
 | 
				
			||||||
 | 
					        return "Database is " + Math.floor(timediffDays) + " days out of sync\n\n" + json
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    const s = Constants.countryCoderEndpoint
 | 
				
			||||||
 | 
					    const status = UIEventSource.FromPromiseWithErr(
 | 
				
			||||||
 | 
					      Utils.downloadJson(s + "/0.0.0.json")
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    services.push({
 | 
				
			||||||
 | 
					      name: s,
 | 
				
			||||||
 | 
					      status: status.mapD(s => {
 | 
				
			||||||
 | 
					        if (s["error"]) {
 | 
				
			||||||
 | 
					          return "offline"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const arr = s["success"]
 | 
				
			||||||
 | 
					        if (Array.isArray(arr)) {
 | 
				
			||||||
 | 
					          return "online"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return "degraded"
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
 | 
					      message: status.map(s => JSON.stringify(s))
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    for (const defaultOverpassUrl of Constants.defaultOverpassUrls) {
 | 
				
			||||||
 | 
					      const statusUrl = defaultOverpassUrl.replace(/\/interpreter$/, "/status")
 | 
				
			||||||
 | 
					      const status = UIEventSource.FromPromiseWithErr(
 | 
				
			||||||
 | 
					        Utils.download(statusUrl)
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      services.push({
 | 
				
			||||||
 | 
					        name: "Overpass-server: " + defaultOverpassUrl,
 | 
				
			||||||
 | 
					        status: status.mapD(result => {
 | 
				
			||||||
 | 
					          if (result["error"]) {
 | 
				
			||||||
 | 
					            return "offline"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          // "Connected as: 3587935836
 | 
				
			||||||
 | 
					          // Current time: 2024-07-14T00:35:58Z
 | 
				
			||||||
 | 
					          // Announced endpoint: gall.openstreetmap.de
 | 
				
			||||||
 | 
					          // Rate limit: 6
 | 
				
			||||||
 | 
					          // 6 slots available now.
 | 
				
			||||||
 | 
					          // Currently running queries (pid, space limit, time limit, start time):\n"
 | 
				
			||||||
 | 
					          const msgs = result["success"].split("\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          return "online"
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					        message: simpleMessage(status)
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    services.push({
 | 
				
			||||||
 | 
					      name: "Mangrove reviews",
 | 
				
			||||||
 | 
					      status: UIEventSource.FromPromiseWithErr(
 | 
				
			||||||
 | 
					        Utils.download("https://api.mangrove.reviews")
 | 
				
			||||||
 | 
					      ).mapD(r => {
 | 
				
			||||||
 | 
					        if (r["success"]) {
 | 
				
			||||||
 | 
					          return "online"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return "offline"
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let all = new UIEventSource<"online" | "degraded" | "offline">("online")
 | 
				
			||||||
 | 
					  let someLoading = new UIEventSource(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function setAll() {
 | 
				
			||||||
 | 
					    const data = Utils.NoNull(services.map(s => s.status.data))
 | 
				
			||||||
 | 
					    someLoading.setData(data.length !== services.length)
 | 
				
			||||||
 | 
					    if (data.some(d => d === "offline")) {
 | 
				
			||||||
 | 
					      all.setData("offline")
 | 
				
			||||||
 | 
					    } else if (data.some(d => d === "degraded")) {
 | 
				
			||||||
 | 
					      all.setData("degraded")
 | 
				
			||||||
 | 
					    } else if (data.some(d => d === "online")) {
 | 
				
			||||||
 | 
					      all.setData("online")
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      all.setData(undefined)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (const service of services) {
 | 
				
			||||||
 | 
					    service.status.addCallbackD(() => {
 | 
				
			||||||
 | 
					      setAll()
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<h1>MapComplete status indicators</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{#if $someLoading}
 | 
				
			||||||
 | 
					  <Loading />
 | 
				
			||||||
 | 
					{/if}
 | 
				
			||||||
 | 
					<StatusIcon status={$all} cls="w-16 h-16" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{#each services as service}
 | 
				
			||||||
 | 
					  <ServiceIndicator {service} />
 | 
				
			||||||
 | 
					{/each}
 | 
				
			||||||
							
								
								
									
										26
									
								
								src/UI/Status/StatusIcon.svelte
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/UI/Status/StatusIcon.svelte
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					  import Loading from "../Base/Loading.svelte"
 | 
				
			||||||
 | 
					  import CheckCircle from "@babeard/svelte-heroicons/mini/CheckCircle"
 | 
				
			||||||
 | 
					  import XCircle from "@rgossiaux/svelte-heroicons/solid/XCircle"
 | 
				
			||||||
 | 
					  import { twJoin } from "tailwind-merge"
 | 
				
			||||||
 | 
					  import { XIcon } from "@rgossiaux/svelte-heroicons/outline"
 | 
				
			||||||
 | 
					  import Exclamation from "@rgossiaux/svelte-heroicons/solid/Exclamation"
 | 
				
			||||||
 | 
					  import Check from "@babeard/svelte-heroicons/mini/Check"
 | 
				
			||||||
 | 
					  import { XCircleIcon } from "@rgossiaux/svelte-heroicons/solid"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  export let status: "online" | "degraded" | "offline"
 | 
				
			||||||
 | 
					  export let cls: string = "w-6 h-6 mx-1"
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{#if status === "online"}
 | 
				
			||||||
 | 
					  <CheckCircle class={twJoin(cls,"rounded-full")} style="color: #22cc22" />
 | 
				
			||||||
 | 
					{:else if status === "degraded"}
 | 
				
			||||||
 | 
					  <Exclamation class={twJoin(cls,"rounded-full")} style="color: #eecc22"  />
 | 
				
			||||||
 | 
					{:else if status === "offline"}
 | 
				
			||||||
 | 
					  <XCircleIcon class={twJoin(cls,"rounded-full")} style="color: #bb2222"  />
 | 
				
			||||||
 | 
					{:else if status === undefined}
 | 
				
			||||||
 | 
					  <Loading />
 | 
				
			||||||
 | 
					{:else}
 | 
				
			||||||
 | 
					  ? {status}
 | 
				
			||||||
 | 
					{/if}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/UI/StatusGui.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/UI/StatusGui.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					import StatusGUI from "./Status/StatusGUI.svelte"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class StatusGui {
 | 
				
			||||||
 | 
					    public setup() {
 | 
				
			||||||
 | 
					        new StatusGUI({
 | 
				
			||||||
 | 
					            target: document.getElementById("main"),
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					new StatusGui().setup()
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue