Fetch statuspage.io info next to bookmarks

This commit is contained in:
dvdandroid 2024-08-04 20:05:15 +02:00
parent f5427310e8
commit 58ffe6e55f
4 changed files with 147 additions and 12 deletions

View file

@ -397,7 +397,8 @@ body {
border-radius: 50%;
}
.notice-icon-major {
.notice-icon-major,
.notice-icon-critical {
background: var(--color-negative);
}
@ -405,6 +406,10 @@ body {
border: 1px solid var(--color-negative);
}
.notice-icon-none {
border: 1px solid var(--color-positive);
}
kbd {
font: inherit;
padding: 0.1rem 0.8rem;
@ -1427,6 +1432,7 @@ kbd:active {
.inline-block { display: inline-block; }
.overflow-hidden { overflow: hidden; }
.relative { position: relative; }
.hidden { display: none; }
.flex { display: flex; }
.flex-wrap { flex-wrap: wrap; }
.flex-nowrap { flex-wrap: nowrap; }

View file

@ -31,6 +31,9 @@
</div>
{{ end }}
<a href="{{ .URL }}" class="bookmarks-link {{ if .HideArrow }}bookmarks-link-no-arrow {{ end }}color-highlight size-h4" {{ if not .SameTab }}target="_blank"{{ end }} rel="noreferrer">{{ .Title }}</a>
{{ if .StatusPage }}
<div class="notice-icon notice-icon-{{ .StatusPage.StatusPageInfo.StatusResponse.Indicator }} {{ if not .StatusPage.ShowIfOperational }} hidden {{ end }}" title="{{ .StatusPage.StatusPageInfo.StatusResponse.Description }}"></div>
{{ end}}
</li>
{{ end }}
</ul>

View file

@ -0,0 +1,66 @@
package feed
import (
"context"
"encoding/json"
"net/http"
"time"
)
type StatusPage struct {
URL string `yaml:"url"`
ShowIfOperational bool `yaml:"show-if-operational" default:"false"`
StatusPageInfo StatusPageInfo `yaml:"-"`
}
type StatusPageInfo struct {
StatusResponse StatusResponse `json:"status"`
Error error
}
type StatusResponse struct {
Indicator string `json:"indicator"`
Description string `json:"description"`
}
const summaryEndpointPath = "/api/v2/summary.json"
func getStatusPageTask(statusRequest *StatusPage) (StatusPageInfo, error) {
request, err := http.NewRequest(http.MethodGet, statusRequest.URL+summaryEndpointPath, nil)
if err != nil {
return StatusPageInfo{
Error: err,
}, nil
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()
request = request.WithContext(ctx)
var response *http.Response
response, err = defaultClient.Do(request)
var status StatusPageInfo
if err != nil {
status.Error = err
return status, nil
}
err = json.NewDecoder(response.Body).Decode(&status)
defer response.Body.Close()
return status, nil
}
func FetchStatusPages(requests []*StatusPage) ([]StatusPageInfo, error) {
job := newJob(getStatusPageTask, requests).withWorkers(20)
results, _, err := workerPoolDo(job)
if err != nil {
return nil, err
}
return results, nil
}

View file

@ -1,34 +1,41 @@
package widget
import (
"context"
"github.com/glanceapp/glance/internal/feed"
"html/template"
"time"
"github.com/glanceapp/glance/internal/assets"
)
type Bookmarks struct {
widgetBase `yaml:",inline"`
cachedHTML template.HTML `yaml:"-"`
Groups []struct {
Title string `yaml:"title"`
Color *HSLColorField `yaml:"color"`
Links []struct {
Title string `yaml:"title"`
URL string `yaml:"url"`
Icon string `yaml:"icon"`
IsSimpleIcon bool `yaml:"-"`
SameTab bool `yaml:"same-tab"`
HideArrow bool `yaml:"hide-arrow"`
Title string `yaml:"title"`
URL string `yaml:"url"`
Icon string `yaml:"icon"`
IsSimpleIcon bool `yaml:"-"`
SameTab bool `yaml:"same-tab"`
HideArrow bool `yaml:"hide-arrow"`
StatusPage *feed.StatusPage `yaml:"status-page"`
} `yaml:"links"`
} `yaml:"groups"`
Style string `yaml:"style"`
}
func (widget *Bookmarks) Initialize() error {
widget.withTitle("Bookmarks").withError(nil)
countStatusPages := 0
for g := range widget.Groups {
for l := range widget.Groups[g].Links {
if widget.Groups[g].Links[l].StatusPage != nil {
countStatusPages++
}
if widget.Groups[g].Links[l].Icon == "" {
continue
}
@ -38,11 +45,64 @@ func (widget *Bookmarks) Initialize() error {
}
}
widget.cachedHTML = widget.render(widget, assets.BookmarksTemplate)
w := widget.withTitle("Bookmarks")
if countStatusPages > 0 {
w.withCacheDuration(30 * time.Minute)
} else {
w.withError(nil)
}
return nil
}
func (widget *Bookmarks) Render() template.HTML {
return widget.cachedHTML
func (widget *Bookmarks) Update(ctx context.Context) {
countStatusPages := 0
for g := range widget.Groups {
for l := range widget.Groups[g].Links {
if widget.Groups[g].Links[l].StatusPage != nil {
if widget.Groups[g].Links[l].StatusPage.URL != "" {
countStatusPages++
}
}
}
}
if countStatusPages == 0 {
return
}
requests := make([]*feed.StatusPage, countStatusPages)
countStatusPages = 0
for g := range widget.Groups {
for l := range widget.Groups[g].Links {
if widget.Groups[g].Links[l].StatusPage != nil {
if widget.Groups[g].Links[l].StatusPage.URL != "" {
requests[countStatusPages] = widget.Groups[g].Links[l].StatusPage
countStatusPages++
}
}
}
}
statuses, err := feed.FetchStatusPages(requests)
if !widget.canContinueUpdateAfterHandlingErr(err) {
return
}
for g := range widget.Groups {
for l := range widget.Groups[g].Links {
if widget.Groups[g].Links[l].StatusPage != nil {
if widget.Groups[g].Links[l].StatusPage.URL != "" {
widget.Groups[g].Links[l].StatusPage.StatusPageInfo = statuses[0]
statuses = statuses[1:]
}
}
}
}
}
func (widget *Bookmarks) Render() template.HTML {
return widget.render(widget, assets.BookmarksTemplate)
}