Verified Commit 6853f9f2 authored by Jakob Moser's avatar Jakob Moser
Browse files

Dynamically change favicon

parent 7652774d
Loading
Loading
Loading
Loading

js/favicon.mjs

0 → 100644
+7 −0
Original line number Diff line number Diff line
function setFavicon(href) {
    document.querySelector("link[rel~='icon']").href = href
}

export function setFaviconStatus(color) {
    setFavicon(`./lib/fscoli-next/img/favicon.${color}.png`)
}
+5 −0
Original line number Diff line number Diff line
export default {
    Up: {},
    UnexpectedUnprotectedUp: {},
    Down: {},
}
+36 −2
Original line number Diff line number Diff line
import { setFaviconStatus } from "../favicon.mjs"
import Interpretation from "./Interpretation.mjs"

const apiBase = "/api/v2"

export function interpretStatus(service) {
    const { status, expectUnauthorized } = service

    switch (status) {
        case null:
        case undefined:
            return null
        case 200:
        case 301:
        case 302:
            return expectUnauthorized
                ? Interpretation.UnexpectedUnprotectedUp
                : Interpretation.Up
        case 401:
            return expectUnauthorized ? Interpretation.Up : Interpretation.Down
        default:
            return Interpretation.Down
    }
}

export default {
    value: null,
    load() {
@@ -11,6 +34,17 @@ export default {
            }
        })

        m.request(`${apiBase}/status`).then(result => this.value = result)
    }
        m.request(`${apiBase}/status`).then(result => {
            this.value = result
            setFaviconStatus(this.healthy("fachschaft") ? "green" : "red")
        })
    },
    healthy(category) {
        const unhealthyServices = this.value.filter(
            it =>
                (category === undefined || it.category === category) &&
                interpretStatus(it) !== Interpretation.Up,
        )
        return unhealthyServices.length === 0
    },
}
+28 −25
Original line number Diff line number Diff line
import Interpretation from "../model/Interpretation.mjs"
import { interpretStatus } from "../model/services.mjs"

/**
 * "Interpret" a given HTTP status code, that is, return a list containing a human-readable label
 * (e.g. "Up") and a CSS color class (e.g. "green").
 * Return a list containing a human-readable label (e.g. "Up") and a CSS color class (e.g. "green")
 * indicating the status of this service.
 *
 * @param {int?} statusCode An HTTP status code
 * @param {boolean?} expectUnauthorized Whether 401 should be counted as a success
 * @returns A list of the form ["Label", "color"]
 */
function getStatusInterpretation(statusCode, expectUnauthorized) {
    const accessibleResult = expectUnauthorized ? ["Up (unprotected)", "orange"] : ["Up", "green"]
    const authorizationNeededResult = expectUnauthorized ? ["Up", "green"] : ["Down", "red"]

function getLabelAndClass(service) {
    const interpretation = interpretStatus(service)

    switch (statusCode) {
    switch (interpretation) {
        case null:
        case undefined:
            return [m("i.fa-solid.fa-circle-notch.fa-spin", {"aria-label": "Loading", title: "Loading"}), "black"]
        case 200:
        case 301:
        case 302:
            return accessibleResult
        case 401:
            return authorizationNeededResult
        default:
            return [
                m("i.fa-solid.fa-circle-notch.fa-spin", {
                    "aria-label": "Loading",
                    title: "Loading",
                }),
                "black",
            ]
        case Interpretation.Up:
            return ["Up", "green"]
        case Interpretation.UnexpectedUnprotectedUp:
            return ["Up (unprotected)", "orange"]
        case Interpretation.Down:
            return ["Down", "red"]
    }
}
@@ -52,18 +54,19 @@ export default {
        // Destructuring assignment: We know the method returns a list with two elements.
        // We want to do assign the first element to a const statusName, and the second to a const cssClass.
        // This can be done in a oneliner:
        const [statusName, cssClass] = getStatusInterpretation(service.status, service.expectUnauthorized)
        const [statusLabel, cssClass] = getLabelAndClass(service)

        // Create an HTML hyperlink element of the form
        // <a href="https://fachschaft.cl.uni-heidelberg.de" class="badge green" target="_blank"></a>
        // The class "badge" is used by some CSS code to style the link. target="_blank" ensures
        // the link will be opened in a new tab.
        return m(`a.badge.${cssClass}`, {
        return m(
            `a.badge.${cssClass}`,
            {
                href: getServiceUrl(service.host),
                target: "_blank",
        }, [
            m("span", service.name),
            m("span", statusName)
        ])
    }
            },
            [m("span", service.name), m("span", statusLabel)],
        )
    },
}
+2.19 KiB
Loading image diff...
Loading