Compare commits

..
6 Commits
Author SHA1 Message Date
github-actions[bot]andGitHub 021dc2e8f9 chore(deps): update dependencies
Automated dependency update. All tests passed.
2026-10-09 03:20:39 +00:00
github-actions[bot]andGitHub fb31e31bec chore(deps): update dependencies
Automated dependency update. All tests passed.
2026-10-08 03:19:51 +00:00
github-actions[bot]andGitHub 0585326fea chore(deps): update dependency @lucide/vue to v1.52.0
Automated dependency update. All tests passed.
2026-10-07 03:19:22 +00:00
lukaszraczylo 5bca4c38f0 feat(alerts): raise one alert per open issue and pull request
Each open issue now has its own alert. An issue with recent activity is issue_fresh. An issue idle for issue_stale_after or longer is issue_stale. This replaces the single issues_stale line per repo.

A non-draft pull request younger than pr_warn_after now raises pr_fresh. Older pull requests keep pr_waiting.

All new alerts have warn severity, so a repo with open work is no longer green. The pr_open alert for auto actions is unchanged.
2026-10-06 14:14:26 +01:00
github-actions[bot]andGitHub eff9559aee chore(deps): update pnpm to v11.28.4
Automated dependency update. All tests passed.
2026-10-06 03:16:32 +00:00
lukaszraczylo 5c5416f6f0 fix(web): keep the action status fetch alive when a client disconnects
The status fetch used the request context. A client that dropped the
connection, such as a readiness probe with a one second timeout,
cancelled the fetch. The failure was then cached and every later
request showed no action status. The fetch now ignores the caller
cancellation and keeps its own timeout.
2026-10-05 15:53:52 +01:00
12 changed files with 180 additions and 175 deletions
+17 -15
View File
@@ -17,11 +17,11 @@ Release archives and the image checksums are signed with cosign.
The dashboard lists only what needs attention, grouped by project. The project with the newest problem comes first: The dashboard lists only what needs attention, grouped by project. The project with the newest problem comes first:
- Failing workflows, including scheduled and other background ones, with a link to the run. - Failing workflows, including scheduled and other background ones, with a link to the run.
- Pull requests that wait too long or fail their checks, with links and age. - Pull requests, one line each: new ones (`pr_fresh`), ones that wait too long (`pr_waiting`) and ones that fail their checks.
- Stale issues, as one line per project. - Open issues, one line each: new ones (`issue_fresh`) and ones without recent activity (`issue_stale`).
- Projects that failed to refresh, or loaded only in part. - Projects that failed to refresh, or loaded only in part.
A side panel lists every project with its latest release (or newest tag), a link to the release, and counts of workflows, open pull requests and issues. Healthy items do not appear anywhere else. A side panel lists every project with its latest release (or newest tag), a link to the release, and counts of workflows, open pull requests and issues. Every open non-draft pull request and every open issue raises a warning, so a project with open work is never green.
### Search and filters ### Search and filters
@@ -48,7 +48,9 @@ A side panel lists every project with its latest release (or newest tag), a link
| Non-draft PR open longer than `pr_warn_after` | warn | | Non-draft PR open longer than `pr_warn_after` | warn |
| PR checks failing | warn | | PR checks failing | warn |
| Workflow queued or running longer than `workflow_stuck_after` | warn | | Workflow queued or running longer than `workflow_stuck_after` | warn |
| Open issues without activity for `issue_stale_after` (one alert per repo) | warn | | Non-draft PR open less than `pr_warn_after` (`pr_fresh`) | warn |
| Open issue without activity for `issue_stale_after` (`issue_stale`, one alert per issue) | warn |
| Open issue with recent activity (`issue_fresh`, one alert per issue) | warn |
| A section failed to load, for example a missing App permission | warn | | A section failed to load, for example a missing App permission | warn |
| Data older than `data_stale_after` | warn | | Data older than `data_stale_after` | warn |
@@ -121,17 +123,17 @@ actions:
All metrics use the `ghtracker_` prefix. Gauges are computed at scrape time. All metrics use the `ghtracker_` prefix. Gauges are computed at scrape time.
| Metric | Labels | | Metric | Labels |
| -------------------------------------------------------------------------------------------------------------- | -------------------------- | | ----------------------------------------------------------------------------------------------------------------------------- | -------------------------- |
| `repo_up`, `repo_health` (0 ok, 1 warn, 2 crit) | repo | | `repo_up`, `repo_health` (0 ok, 1 warn, 2 crit) | repo |
| `repo_open_issues`, `repo_open_prs`, `repo_open_prs_failing_checks`, `repo_stale_issues` | repo | | `repo_open_issues`, `repo_open_prs`, `repo_open_prs_failing_checks`, `repo_stale_issues` | repo |
| `repo_oldest_pr_age_seconds`, `repo_last_refresh_timestamp_seconds` | repo | | `repo_oldest_pr_age_seconds`, `repo_last_refresh_timestamp_seconds` | repo |
| `pr_age_seconds`, `pr_checks_failing` | repo, number | | `pr_age_seconds`, `pr_checks_failing` | repo, number |
| `workflow_failing`, `workflow_running`, `workflow_last_run_timestamp_seconds` | repo, workflow, background | | `workflow_failing`, `workflow_running`, `workflow_last_run_timestamp_seconds` | repo, workflow, background |
| `release_info`, `release_published_timestamp_seconds` | repo, version, url | | `release_info`, `release_published_timestamp_seconds` | repo, version, url |
| `alerts` | severity | | `alerts` | severity |
| `refreshes_total`, `repo_refresh_errors_total`, `last_refresh_duration_seconds`, `github_rate_limit_remaining` | none | | `refreshes_total`, `repo_refresh_errors_total`, `last_refresh_duration_seconds`, `github_rate_limit_remaining` | none |
| `action_requests_total` (counter; result is `ok`, `rejected` or `error`, plus `auto_*` for auto actions; only with `actions`) | action, result | | `action_requests_total` (counter; result is `ok`, `rejected` or `error`, plus `auto_*` for auto actions; only with `actions`) | action, result |
Example alert rules: Example alert rules:
+29 -18
View File
@@ -67,7 +67,7 @@ func TestEvaluate(t *testing.T) {
}, map[string]model.Severity{KindWorkflowStuck: model.Warn}, model.Warn}, }, map[string]model.Severity{KindWorkflowStuck: model.Warn}, model.Warn},
"pr fresh": {func(r *model.Repo) { "pr fresh": {func(r *model.Repo) {
r.PRs = []model.PullRequest{{Number: 1, Fork: true, CreatedAt: t0.Add(-47 * time.Hour)}} r.PRs = []model.PullRequest{{Number: 1, Fork: true, CreatedAt: t0.Add(-47 * time.Hour)}}
}, map[string]model.Severity{}, model.OK}, }, map[string]model.Severity{KindPRFresh: model.Warn}, model.Warn},
"pr waiting warn": {func(r *model.Repo) { "pr waiting warn": {func(r *model.Repo) {
r.PRs = []model.PullRequest{{Number: 1, Fork: true, CreatedAt: t0.Add(-49 * time.Hour)}} r.PRs = []model.PullRequest{{Number: 1, Fork: true, CreatedAt: t0.Add(-49 * time.Hour)}}
}, map[string]model.Severity{KindPRWaiting: model.Warn}, model.Warn}, }, map[string]model.Severity{KindPRWaiting: model.Warn}, model.Warn},
@@ -79,11 +79,13 @@ func TestEvaluate(t *testing.T) {
}, map[string]model.Severity{}, model.OK}, }, map[string]model.Severity{}, model.OK},
"pr checks failing": {func(r *model.Repo) { "pr checks failing": {func(r *model.Repo) {
r.PRs = []model.PullRequest{{Number: 1, Fork: true, CreatedAt: t0, Checks: model.CheckSummary{State: model.ChecksFail, Failing: []string{"build"}}}} r.PRs = []model.PullRequest{{Number: 1, Fork: true, CreatedAt: t0, Checks: model.CheckSummary{State: model.ChecksFail, Failing: []string{"build"}}}}
}, map[string]model.Severity{KindPRChecks: model.Warn}, model.Warn}, }, map[string]model.Severity{KindPRFresh: model.Warn, KindPRChecks: model.Warn}, model.Warn},
"issues stale aggregated": {func(r *model.Repo) { "issue stale": {func(r *model.Repo) {
old := t0.Add(-40 * 24 * time.Hour) r.Issues = []model.Issue{{Number: 1, CreatedAt: t0.Add(-60 * 24 * time.Hour), UpdatedAt: t0.Add(-40 * 24 * time.Hour)}}
r.Issues = []model.Issue{{Number: 1, UpdatedAt: old}, {Number: 2, UpdatedAt: old}, {Number: 3, UpdatedAt: t0}} }, map[string]model.Severity{KindIssueStale: model.Warn}, model.Warn},
}, map[string]model.Severity{KindIssuesStale: model.Warn}, model.Warn}, "issue fresh": {func(r *model.Repo) {
r.Issues = []model.Issue{{Number: 1, CreatedAt: t0.Add(-time.Hour), UpdatedAt: t0}}
}, map[string]model.Severity{KindIssueFresh: model.Warn}, model.Warn},
"archived repo skips work alerts": {func(r *model.Repo) { "archived repo skips work alerts": {func(r *model.Repo) {
r.Archived = true r.Archived = true
r.PRs = []model.PullRequest{{Number: 1, Fork: true, CreatedAt: t0.Add(-30 * 24 * time.Hour)}} r.PRs = []model.PullRequest{{Number: 1, Fork: true, CreatedAt: t0.Add(-30 * 24 * time.Hour)}}
@@ -125,8 +127,10 @@ func TestEvaluateDisabledThresholds(t *testing.T) {
r := model.Repo{FullName: "o/r", RefreshedAt: t0, PRs: []model.PullRequest{{Number: 1, Fork: true, CreatedAt: t0.Add(-100 * 24 * time.Hour)}}, r := model.Repo{FullName: "o/r", RefreshedAt: t0, PRs: []model.PullRequest{{Number: 1, Fork: true, CreatedAt: t0.Add(-100 * 24 * time.Hour)}},
Issues: []model.Issue{{UpdatedAt: t0.Add(-100 * 24 * time.Hour)}}} Issues: []model.Issue{{UpdatedAt: t0.Add(-100 * 24 * time.Hour)}}}
off := config.Thresholds{PRWarnAfter: -1, PRCritAfter: -1, IssueStaleAfter: -1, WorkflowStuck: -1, DataStaleAfter: -1} off := config.Thresholds{PRWarnAfter: -1, PRCritAfter: -1, IssueStaleAfter: -1, WorkflowStuck: -1, DataStaleAfter: -1}
if a := withoutPROpen(Evaluate(&r, t0, off)); len(a) != 0 { for _, a := range withoutPROpen(Evaluate(&r, t0, off)) {
t.Fatalf("disabled checks produced %+v", a) if a.Kind != KindPRFresh && a.Kind != KindIssueFresh {
t.Fatalf("disabled checks produced %+v", a)
}
} }
} }
@@ -134,11 +138,11 @@ func TestAgeAdvancesWithoutRefresh(t *testing.T) {
r := model.Repo{FullName: "o/r", RefreshedAt: t0, PRs: []model.PullRequest{{Number: 1, Fork: true, CreatedAt: t0.Add(-40 * time.Hour)}}} r := model.Repo{FullName: "o/r", RefreshedAt: t0, PRs: []model.PullRequest{{Number: 1, Fork: true, CreatedAt: t0.Add(-40 * time.Hour)}}}
cfg := th() cfg := th()
cfg.DataStaleAfter = -1 cfg.DataStaleAfter = -1
if a := withoutPROpen(Evaluate(&r, t0, cfg)); len(a) != 0 { if a := withoutPROpen(Evaluate(&r, t0, cfg)); len(a) != 1 || a[0].Kind != KindPRFresh {
t.Fatalf("unexpected %+v", a) t.Fatalf("a PR below the warn threshold must be fresh: %+v", a)
} }
if a := withoutPROpen(Evaluate(&r, t0.Add(10*time.Hour), cfg)); len(a) != 1 || a[0].Severity != model.Warn { if a := withoutPROpen(Evaluate(&r, t0.Add(10*time.Hour), cfg)); len(a) != 1 || a[0].Kind != KindPRWaiting {
t.Fatalf("PR must cross the warn threshold as time passes: %+v", a) t.Fatalf("PR must turn from fresh to waiting as time passes: %+v", a)
} }
} }
@@ -490,9 +494,6 @@ func TestEvaluatePROpen(t *testing.T) {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
r := model.Repo{FullName: "o/r", Up: true, RefreshedAt: t0, Archived: tc.archived, PRs: []model.PullRequest{tc.pr}} r := model.Repo{FullName: "o/r", Up: true, RefreshedAt: t0, Archived: tc.archived, PRs: []model.PullRequest{tc.pr}}
alerts := Evaluate(&r, t0, th()) alerts := Evaluate(&r, t0, th())
if r.Health != model.OK {
t.Fatalf("health = %v, want ok", r.Health)
}
if !tc.want { if !tc.want {
if len(alerts) != 0 { if len(alerts) != 0 {
t.Fatalf("alerts = %+v, want none", alerts) t.Fatalf("alerts = %+v, want none", alerts)
@@ -501,21 +502,31 @@ func TestEvaluatePROpen(t *testing.T) {
} }
want := model.Alert{Severity: model.OK, Repo: "o/r", Kind: KindPROpen, Subject: "#7 fix", Detail: "open for 5h", want := model.Alert{Severity: model.OK, Repo: "o/r", Kind: KindPROpen, Subject: "#7 fix", Detail: "open for 5h",
URL: tc.pr.URL, Ref: "abc123", Author: "alice", Since: tc.pr.CreatedAt} URL: tc.pr.URL, Ref: "abc123", Author: "alice", Since: tc.pr.CreatedAt}
if len(alerts) != 1 || alerts[0] != want { if alerts = onlyPROpen(alerts); len(alerts) != 1 || alerts[0] != want {
t.Fatalf("alerts = %+v, want [%+v]", alerts, want) t.Fatalf("alerts = %+v, want [%+v]", alerts, want)
} }
}) })
} }
} }
func TestPROpenDoesNotChangeCounts(t *testing.T) { func onlyPROpen(in []model.Alert) []model.Alert {
var out []model.Alert
for _, a := range in {
if a.Kind == KindPROpen {
out = append(out, a)
}
}
return out
}
func TestPROpenHasNoSeverityOfItsOwn(t *testing.T) {
f := &fakeFetcher{fn: func(name string) (model.Repo, error) { f := &fakeFetcher{fn: func(name string) (model.Repo, error) {
return model.Repo{FullName: name, PRs: []model.PullRequest{{Number: 1, HeadSHA: "s", CreatedAt: t0}}}, nil return model.Repo{FullName: name, PRs: []model.PullRequest{{Number: 1, HeadSHA: "s", CreatedAt: t0}}}, nil
}} }}
c := newCollector(f, "o/a") c := newCollector(f, "o/a")
c.Refresh(context.Background()) c.Refresh(context.Background())
v := c.View() v := c.View()
if len(v.Alerts) != 1 || v.Alerts[0].Kind != KindPROpen || v.Crit != 0 || v.Warn != 0 || v.Repos[0].Health != model.OK { if len(onlyPROpen(v.Alerts)) != 1 || v.Alerts[0].Severity != model.Warn || v.Crit != 0 || v.Warn != 1 {
t.Fatalf("view = %+v", v) t.Fatalf("view = %+v", v)
} }
} }
+11 -16
View File
@@ -19,7 +19,9 @@ const (
KindWorkflowStuck = "workflow_stuck" KindWorkflowStuck = "workflow_stuck"
KindPRWaiting = "pr_waiting" KindPRWaiting = "pr_waiting"
KindPRChecks = "pr_checks_failing" KindPRChecks = "pr_checks_failing"
KindIssuesStale = "issues_stale" KindPRFresh = "pr_fresh"
KindIssueStale = "issue_stale"
KindIssueFresh = "issue_fresh"
// KindPROpen is informational plumbing for automatic actions; it has OK severity so it never moves health or counts. // KindPROpen is informational plumbing for automatic actions; it has OK severity so it never moves health or counts.
KindPROpen = "pr_open" KindPROpen = "pr_open"
) )
@@ -71,27 +73,20 @@ func Evaluate(r *model.Repo, now time.Time, th config.Thresholds) []model.Alert
add(model.Crit, KindPRWaiting, subject, "open "+Age(age), pr.URL, pr.CreatedAt) add(model.Crit, KindPRWaiting, subject, "open "+Age(age), pr.URL, pr.CreatedAt)
case th.PRWarnAfter > 0 && age >= th.PRWarnAfter: case th.PRWarnAfter > 0 && age >= th.PRWarnAfter:
add(model.Warn, KindPRWaiting, subject, "open "+Age(age), pr.URL, pr.CreatedAt) add(model.Warn, KindPRWaiting, subject, "open "+Age(age), pr.URL, pr.CreatedAt)
default:
add(model.Warn, KindPRFresh, subject, "new, open "+Age(age), pr.URL, pr.CreatedAt)
} }
if pr.Checks.State == model.ChecksFail { if pr.Checks.State == model.ChecksFail {
add(model.Warn, KindPRChecks, subject, summarizeChecks(pr.Checks), pr.URL, pr.UpdatedAt) add(model.Warn, KindPRChecks, subject, summarizeChecks(pr.Checks), pr.URL, pr.UpdatedAt)
} }
} }
if th.IssueStaleAfter > 0 { for _, is := range r.Issues {
var stale int subject := fmt.Sprintf("#%d %s", is.Number, is.Title)
var oldest time.Time if idle := now.Sub(is.UpdatedAt); th.IssueStaleAfter > 0 && idle >= th.IssueStaleAfter {
for _, is := range r.Issues { add(model.Warn, KindIssueStale, subject, "no activity for "+Age(idle), is.URL, is.UpdatedAt)
if now.Sub(is.UpdatedAt) >= th.IssueStaleAfter { } else {
stale++ add(model.Warn, KindIssueFresh, subject, "new, open "+Age(now.Sub(is.CreatedAt)), is.URL, is.CreatedAt)
if oldest.IsZero() || is.UpdatedAt.Before(oldest) {
oldest = is.UpdatedAt
}
}
}
if stale > 0 {
add(model.Warn, KindIssuesStale, fmt.Sprintf("%d stale issues", stale),
"no activity for "+Age(th.IssueStaleAfter)+" or more",
r.URL+"/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc", oldest)
} }
} }
return alerts return alerts
+2 -1
View File
@@ -158,7 +158,8 @@ func (a *Actions) statusRows(ctx context.Context, rt *actionRuntime) (map[alertR
if !rt.fetched.IsZero() && a.now().Sub(rt.fetched) < statusCacheTTL { if !rt.fetched.IsZero() && a.now().Sub(rt.fetched) < statusCacheTTL {
return rt.rows, rt.err return rt.rows, rt.err
} }
rows, err := a.fetchStatus(ctx, rt.cfg) // A client that disconnects mid-request must not fail the fetch that every later request reuses.
rows, err := a.fetchStatus(context.WithoutCancel(ctx), rt.cfg)
if err != nil { if err != nil {
a.log.Warn("action status unavailable", "action", rt.cfg.ID, "err", err) a.log.Warn("action status unavailable", "action", rt.cfg.ID, "err", err)
} }
+13
View File
@@ -2,6 +2,7 @@ package web
import ( import (
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"io" "io"
"log/slog" "log/slog"
@@ -407,3 +408,15 @@ func TestRedirectDoesNotForwardToken(t *testing.T) {
t.Fatal("bearer token forwarded across a redirect") t.Fatal("bearer token forwarded across a redirect")
} }
} }
func TestStatusFetchSurvivesCancelledRequest(t *testing.T) {
fh := newFakeHook(t)
fh.statBody = `[{"repo":"o/r","url":"` + alertURL + `","state":"running"}]`
h := newActionServer(t, nil, fh.srv.URL)
ctx, cancel := context.WithCancel(context.Background())
cancel()
rows, err := h.actions.statusRows(ctx, h.actions.list[0])
if err != nil || len(rows) != 1 {
t.Fatalf("rows=%d err=%v, want the fetch to complete despite the cancelled request", len(rows), err)
}
}
+3 -3
View File
@@ -138,10 +138,10 @@ func TestNewAutoRunnerNilWithoutAutoActions(t *testing.T) {
func TestStateCarriesPROpenRef(t *testing.T) { func TestStateCarriesPROpenRef(t *testing.T) {
st := buildState(autoView(autoPR(1, "abc", "x", nil)), true) st := buildState(autoView(autoPR(1, "abc", "x", nil)), true)
if len(st.Alerts) != 1 || st.Alerts[0].Kind != collector.KindPROpen || st.Alerts[0].Ref != "abc" || st.Alerts[0].Severity != "ok" { if len(st.Alerts) != 2 || st.Alerts[0].Kind != collector.KindPROpen || st.Alerts[0].Ref != "abc" || st.Alerts[0].Severity != "ok" || st.Alerts[1].Kind != collector.KindPRFresh {
t.Fatalf("alerts = %+v", st.Alerts) t.Fatalf("alerts = %+v", st.Alerts)
} }
if st.Counts.Crit != 0 || st.Counts.Warn != 0 || st.Repos[0].Health != "ok" { if st.Repos[0].Health != "warn" {
t.Fatalf("counts/health changed: %+v %s", st.Counts, st.Repos[0].Health) t.Fatalf("health = %s, want warn", st.Repos[0].Health)
} }
} }
+1 -1
View File
@@ -43,5 +43,5 @@
"vitest": "^5.0.1", "vitest": "^5.0.1",
"vue-tsc": "^3.3.11" "vue-tsc": "^3.3.11"
}, },
"packageManager": "[email protected].3" "packageManager": "[email protected].5"
} }
+97 -116
View File
@@ -25,7 +25,7 @@ importers:
version: 3.3.3(@fortawesome/[email protected])([email protected]([email protected])) version: 3.3.3(@fortawesome/[email protected])([email protected]([email protected]))
'@lucide/vue': '@lucide/vue':
specifier: ^1.49.0 specifier: ^1.49.0
version: 1.51.0([email protected]([email protected])) version: 1.52.0([email protected]([email protected]))
'@vueuse/core': '@vueuse/core':
specifier: ^15.0.0 specifier: ^15.0.0
version: 15.0.0([email protected]([email protected])) version: 15.0.0([email protected]([email protected]))
@@ -40,7 +40,7 @@ importers:
version: 4.0.3(@vue/[email protected])([email protected])([email protected]([email protected])) version: 4.0.3(@vue/[email protected])([email protected])([email protected]([email protected]))
reka-ui: reka-ui:
specifier: ^2.10.5 specifier: ^2.10.5
version: 2.10.5([email protected]([email protected])) version: 2.11.0([email protected]([email protected]))
tailwind-merge: tailwind-merge:
specifier: ^3.7.0 specifier: ^3.7.0
version: 3.7.0 version: 3.7.0
@@ -53,13 +53,13 @@ importers:
version: 10.0.1([email protected]([email protected])) version: 10.0.1([email protected]([email protected]))
'@tailwindcss/vite': '@tailwindcss/vite':
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3([email protected].2(@types/[email protected])([email protected])) version: 4.3.3([email protected].3(@types/[email protected])([email protected]))
'@types/node': '@types/node':
specifier: ^26.6.2 specifier: ^26.6.2
version: 26.6.4 version: 26.6.4
'@vitejs/plugin-vue': '@vitejs/plugin-vue':
specifier: ^6.0.9 specifier: ^6.0.9
version: 6.0.9([email protected].2(@types/[email protected])([email protected]))([email protected]([email protected])) version: 6.0.9([email protected].3(@types/[email protected])([email protected]))([email protected]([email protected]))
'@vue/test-utils': '@vue/test-utils':
specifier: ^2.5.1 specifier: ^2.5.1
version: 2.5.1(@vue/[email protected])(@vue/[email protected])([email protected]([email protected])) version: 2.5.1(@vue/[email protected])(@vue/[email protected])([email protected]([email protected]))
@@ -68,7 +68,7 @@ importers:
version: 10.12.0([email protected]) version: 10.12.0([email protected])
eslint-plugin-vue: eslint-plugin-vue:
specifier: ^10.11.1 specifier: ^10.11.1
version: 10.11.1(@typescript-eslint/[email protected].0([email protected]([email protected]))([email protected]))([email protected]([email protected]))([email protected]([email protected]([email protected]))) version: 10.11.1(@typescript-eslint/[email protected].1([email protected]([email protected]))([email protected]))([email protected]([email protected]))([email protected]([email protected]([email protected])))
globals: globals:
specifier: ^17.12.0 specifier: ^17.12.0
version: 17.13.0 version: 17.13.0
@@ -86,13 +86,13 @@ importers:
version: 6.0.3 version: 6.0.3
typescript-eslint: typescript-eslint:
specifier: ^8.70.1 specifier: ^8.70.1
version: 8.71.0([email protected]([email protected]))([email protected]) version: 8.71.1([email protected]([email protected]))([email protected])
vite: vite:
specifier: ^8.3.1 specifier: ^8.3.1
version: 8.3.2(@types/[email protected])([email protected]) version: 8.3.3(@types/[email protected])([email protected])
vitest: vitest:
specifier: ^5.0.1 specifier: ^5.0.1
version: 5.0.3(@types/[email protected])([email protected])([email protected].2(@types/[email protected])([email protected])) version: 5.0.3(@types/[email protected])([email protected])([email protected].3(@types/[email protected])([email protected]))
vue-tsc: vue-tsc:
specifier: ^3.3.11 specifier: ^3.3.11
version: 3.3.12([email protected]) version: 3.3.12([email protected])
@@ -170,8 +170,10 @@ packages:
'@floating-ui/[email protected]': '@floating-ui/[email protected]':
resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==}
'@floating-ui/vue@1.1.11': '@floating-ui/vue@2.0.1':
resolution: {integrity: sha512-HzHKCNVxnGS35r9fCHBc3+uCnjw9IWIlCPL683cGgM9Kgj2BiAl8x1mS7vtvP6F9S/e/q4O6MApwSHj8hNLGfw==} resolution: {integrity: sha512-043dyEKD9TDSfz080YH2vobubgg+NIo/9Fw4RAl7sEMpD8Am1DNrrSTl/GpMBjyGHoD/FbJY2QLawY+HSQsEIA==}
peerDependencies:
vue: '>=3.3.0'
'@fontsource-variable/[email protected]': '@fontsource-variable/[email protected]':
resolution: {integrity: sha512-F32xpS2NsGYoQi2ADSkKTgpJj7ozajsGgDJ8woTnqjmIB+dxDIqImjl4pXZVEExu8UFZ2ndhmX18EBS/hdz3Lw==} resolution: {integrity: sha512-F32xpS2NsGYoQi2ADSkKTgpJj7ozajsGgDJ8woTnqjmIB+dxDIqImjl4pXZVEExu8UFZ2ndhmX18EBS/hdz3Lw==}
@@ -248,8 +250,8 @@ packages:
'@keyv/[email protected]': '@keyv/[email protected]':
resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==}
'@lucide/[email protected]1.0': '@lucide/[email protected]2.0':
resolution: {integrity: sha512-zMkTAMP8OsPESz/GDedsZfr3VUF2IiHlj25mBZG6Pc8A8J8BdygkE8k1HhRFXEUNzytp5DqxiBQNm3RG/U2bVg==} resolution: {integrity: sha512-Gwr6c14jhY6BscoFU+B9OKsr7lg8RTAKOLgW0e61kkFwkt9Q7CZmB9AyJcvhoqapEJgRg2bFoeAcO+cqpgKzEQ==}
peerDependencies: peerDependencies:
vue: '>=3.0.1' vue: '>=3.0.1'
@@ -490,63 +492,63 @@ packages:
'@types/[email protected]': '@types/[email protected]':
resolution: {integrity: sha512-67MQl+fpWKVTT1NYdnmo3U4sc/xPo/zQBncVnI74qmQa0z/b+1g6iYqNmGCPbxO+zz2aklb08a0oHfegiVd0/w==} resolution: {integrity: sha512-67MQl+fpWKVTT1NYdnmo3U4sc/xPo/zQBncVnI74qmQa0z/b+1g6iYqNmGCPbxO+zz2aklb08a0oHfegiVd0/w==}
'@typescript-eslint/[email protected].0': '@typescript-eslint/[email protected].1':
resolution: {integrity: sha512-pqcS9c1HxZTHt7End4nXqd0s5lJrrFzrgCkKFJrsbUnaL6M3+6oBFZaslg6Gjsl3argl2DDRFROnXARaZ2e4Nw==} resolution: {integrity: sha512-nNlBf6HuotqMgZvSkWD5hNdemiBIxQ2NmrlgfcUIeZRs+BbakjscCQRq/Hb74EFVnFiSWWdL12JruqwBy3ERDw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
'@typescript-eslint/parser': ^8.71.0 '@typescript-eslint/parser': ^8.71.1
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/[email protected].0': '@typescript-eslint/[email protected].1':
resolution: {integrity: sha512-CG4nPk1f2zc8yw4pALqHsFYH2hdo+h1T9daSp21+Hnxi9LOE3GT9hAfTKJCBXVNM2GmYs1eMEP615wPoeOgk3A==} resolution: {integrity: sha512-oM/5sAqz/l1v/zYK1qTOPrn2+JIrBGC1V6uNYucRO5gh6eT9vWJ/RhPbGE59byvZEUQ4VP6XkLBaS5Jti5jpvw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/[email protected].0': '@typescript-eslint/[email protected].1':
resolution: {integrity: sha512-aABjw5rjBacYONVPaPiWOCjJu0vEF4a25iQuodlmQYL1trtLZ0X/y+2Vzl3BKI1odM4LnwLE1oUDXYp1wzx1TQ==} resolution: {integrity: sha512-Oijc9RUsohHjncg6iGi7gCtjnEjYt9FWv9u6ygK8uKcHK5eLjLAkqERQ9BaytbpceOFdk6kifPCS/zAZE+A99g==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/[email protected].0': '@typescript-eslint/[email protected].1':
resolution: {integrity: sha512-gWF0BhUcnjZxSpLE8ngS/59n2SB0J3YqRxvX1+2aoRJk9hNtHSLOV+TcarFiOr5ipXm3yc1QrI4c9YZc8zyCxw==} resolution: {integrity: sha512-1YUDZXdTnXLlob03SFHBipdyMBsDVm7zoSz0ytTJ39dk5J1TgsTK03VlR/dLXG/RLLUrPcYbD4rp23BmHxHP0w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/[email protected].0': '@typescript-eslint/[email protected].1':
resolution: {integrity: sha512-Z1UlWHADEK2Mlb9NpWfDeSjqoZ5EyrOv4R3eQpbkzqn/EwaIdOpXXupEA1+0ZIOSJSZZDBHG0BrQyN8zUG6Pwg==} resolution: {integrity: sha512-oTvkml5SxXhgg+WWKhod5qWQICDXtOB+/Hi9VdPKFAANJ2b7YOgMffgvzXuqog7R6A/JtrzRf128dsxummyWhg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/[email protected].0': '@typescript-eslint/[email protected].1':
resolution: {integrity: sha512-i8uO1qbdxeKgRnS5sCRt6On3/nfo2d2DwQe3Yvjx543zLy7r8ySqRuPPiIIXAhS03U0v5NfAFx+rUgxFzKKwNw==} resolution: {integrity: sha512-kH3t3jZCYv2PZSBEWPKTariLrCaoF1CLoPitYFBJOhAGEwWnSRAtGEifrfrpBa4K9JlwWNZotgA5w3/wLSk/FQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/[email protected].0': '@typescript-eslint/[email protected].1':
resolution: {integrity: sha512-cJ4OoxPGWvFnBTnSZyaU+qJzGTqPTGJY+gDchj6cRyLRdmIdt4rcsE4twj+zPfrNiWuVi38wijHzShL++Z9atQ==} resolution: {integrity: sha512-ybYnPTUwg3VQQOFEiBPLs8Jxl1ry2vXdn1kVKguomBbvxpetdu3MKTNDqFNUrlG8ylP9MpZosmXMFYlGQHk1oQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/[email protected].0': '@typescript-eslint/[email protected].1':
resolution: {integrity: sha512-PEEF4G5sLLWAS5BpPrUvms4ySZkiBQQZM4z+3ReI46axK5Vqr/vXBQatJQIZZOYdGyPUAKTtsrWzpqKuU+3DEw==} resolution: {integrity: sha512-pSKSEK1JJpHs6KiKVtABCE4iJK5d7FLFzDXQNBQ2oRY7LEd3UwOt3TZemTgu9syTIf56dJWlTn/pdmrO9oKUXQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/[email protected].0': '@typescript-eslint/[email protected].1':
resolution: {integrity: sha512-pKR/tEMVrXZG23UFKUn5BQf3zfmfk7KQceI2cGzywZ5nxM5Eu3hEJU1utjWzydtzBbcJAQhHN8iPCxobHpPcZQ==} resolution: {integrity: sha512-CBjT6gfAz3DW2j9Q4moFnqt208Aq+506sVGXfpRcyAeqn0EpayL0mjdWoCO2t3RC7GewNrFxdeehuEaPg6DMzQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/[email protected].0': '@typescript-eslint/[email protected].1':
resolution: {integrity: sha512-8eQ9R218XORK+KLosnf4bu/QsUXvUyVwTbArg7/0NMB1Pu87OJKvj4nhFblkYE8gQV73mW1dx1ptlPCkwRGa7A==} resolution: {integrity: sha512-0GxiUGqMU0qXJt58cBsiG3DP8lUmBaFo2vChtUX+CT7PnR3v/VGLLrzVP4K9r1lNiZXjHYefMBbPunplr09v6w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@vitejs/[email protected]': '@vitejs/[email protected]':
@@ -1242,8 +1244,8 @@ packages:
resolution: {integrity: sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==} resolution: {integrity: sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==}
engines: {node: '>=20'} engines: {node: '>=20'}
[email protected]0.5: [email protected]1.0:
resolution: {integrity: sha512-/8o0y9BThE0hcHKFg+3770tWcJh3qKdOEFxLOPb9HIajXeFoH/J530cZH62jUJunbqwBgpSBL9v7nB8LJ5pDXA==} resolution: {integrity: sha512-ilkpm4bIAol4jwzm4tpm3WVcffyGOpqksNZL1k1qO9QmIwAA+q8jroxjkUGLEn/GddfdExFfvofWfQiKZszUeQ==}
peerDependencies: peerDependencies:
vue: '>= 3.4.0' vue: '>= 3.4.0'
@@ -1307,8 +1309,8 @@ packages:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
[email protected].0: [email protected].1:
resolution: {integrity: sha512-fBdHYiqQ14RW6mOMXD14Svn82ZsCYAoQSzGRzyEjR59S5A2Krh/l7fGTOQ7iCr8gGy/mHVXtEF7s5fgjEdV0Pw==} resolution: {integrity: sha512-oiNVPC3/NbV1FpaHU07l8O6ynqG9v4PAiW2WvTrAmZdR0f2HI/gE668ElMLCK7Xbsu5k2fK5C4fXNiq05j7/nQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
@@ -1328,8 +1330,8 @@ packages:
[email protected]: [email protected]:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
[email protected].2: [email protected].3:
resolution: {integrity: sha512-SQr1x6W5vVSbROg7vsyXIaxK9b0G7zsT68acdWWRmnBUsgDieLCRG+Rep9WdZgcposvv/GSnr4GUUBqB3vXq6w==} resolution: {integrity: sha512-cTAldKPImjg6c+gk48U19POPn3GCBzZwpdsN8ZMEEcbpes+6/wvfqUd0C2y3qYY4wsj8PwgFwrZ/1jBPVttMSg==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@@ -1418,17 +1420,6 @@ packages:
[email protected]: [email protected]:
resolution: {integrity: sha512-LwcxzeliO9fkQcpJG0PoX8X5kmAhKmH9wkpDLxNabwzkQ9Zeib2YVHwFV4pcWmMLfXVfjr/dSV+DaJ3cIPgSNA==} resolution: {integrity: sha512-LwcxzeliO9fkQcpJG0PoX8X5kmAhKmH9wkpDLxNabwzkQ9Zeib2YVHwFV4pcWmMLfXVfjr/dSV+DaJ3cIPgSNA==}
[email protected]:
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
engines: {node: '>=12'}
hasBin: true
peerDependencies:
'@vue/composition-api': ^1.0.0-rc.1
vue: ^3.0.0-0 || ^2.6.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
[email protected]: [email protected]:
resolution: {integrity: sha512-Gk6gRDj0n/fkRa3C3l0bBheoBckUq/Rs0F/TvMWIS6nzzx67amAViMe9CkNgsP2tXyQONvGiHQESHwFtZ3aYDA==} resolution: {integrity: sha512-Gk6gRDj0n/fkRa3C3l0bBheoBckUq/Rs0F/TvMWIS6nzzx67amAViMe9CkNgsP2tXyQONvGiHQESHwFtZ3aYDA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1559,14 +1550,11 @@ snapshots:
'@floating-ui/[email protected]': {} '@floating-ui/[email protected]': {}
'@floating-ui/vue@1.1.11([email protected]([email protected]))': '@floating-ui/vue@2.0.1([email protected]([email protected]))':
dependencies: dependencies:
'@floating-ui/dom': 1.8.0 '@floating-ui/dom': 1.8.0
'@floating-ui/utils': 0.2.12 '@floating-ui/utils': 0.2.12
vue-demi: 0.14.10([email protected]([email protected])) vue: 3.5.43([email protected])
transitivePeerDependencies:
- '@vue/composition-api'
- vue
'@fontsource-variable/[email protected]': {} '@fontsource-variable/[email protected]': {}
@@ -1638,7 +1626,7 @@ snapshots:
'@keyv/[email protected]': {} '@keyv/[email protected]': {}
'@lucide/[email protected]1.0([email protected]([email protected]))': '@lucide/[email protected]2.0([email protected]([email protected]))':
dependencies: dependencies:
vue: 3.5.43([email protected]) vue: 3.5.43([email protected])
@@ -1758,12 +1746,12 @@ snapshots:
'@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3
'@tailwindcss/oxide-win32-x64-msvc': 4.3.3 '@tailwindcss/oxide-win32-x64-msvc': 4.3.3
'@tailwindcss/[email protected]([email protected].2(@types/[email protected])([email protected]))': '@tailwindcss/[email protected]([email protected].3(@types/[email protected])([email protected]))':
dependencies: dependencies:
'@tailwindcss/node': 4.3.3 '@tailwindcss/node': 4.3.3
'@tailwindcss/oxide': 4.3.3 '@tailwindcss/oxide': 4.3.3
tailwindcss: 4.3.3 tailwindcss: 4.3.3
vite: 8.3.2(@types/[email protected])([email protected]) vite: 8.3.3(@types/[email protected])([email protected])
'@tanstack/[email protected]': {} '@tanstack/[email protected]': {}
@@ -1797,14 +1785,14 @@ snapshots:
dependencies: dependencies:
'@types/node': 26.6.4 '@types/node': 26.6.4
'@typescript-eslint/[email protected].0(@typescript-eslint/[email protected].0([email protected]([email protected]))([email protected]))([email protected]([email protected]))([email protected])': '@typescript-eslint/[email protected].1(@typescript-eslint/[email protected].1([email protected]([email protected]))([email protected]))([email protected]([email protected]))([email protected])':
dependencies: dependencies:
'@eslint-community/regexpp': 4.12.2 '@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.71.0([email protected]([email protected]))([email protected]) '@typescript-eslint/parser': 8.71.1([email protected]([email protected]))([email protected])
'@typescript-eslint/scope-manager': 8.71.0 '@typescript-eslint/scope-manager': 8.71.1
'@typescript-eslint/type-utils': 8.71.0([email protected]([email protected]))([email protected]) '@typescript-eslint/type-utils': 8.71.1([email protected]([email protected]))([email protected])
'@typescript-eslint/utils': 8.71.0([email protected]([email protected]))([email protected]) '@typescript-eslint/utils': 8.71.1([email protected]([email protected]))([email protected])
'@typescript-eslint/visitor-keys': 8.71.0 '@typescript-eslint/visitor-keys': 8.71.1
eslint: 10.12.0([email protected]) eslint: 10.12.0([email protected])
ignore: 7.0.11 ignore: 7.0.11
natural-compare: 1.4.0 natural-compare: 1.4.0
@@ -1813,41 +1801,41 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/[email protected].0([email protected]([email protected]))([email protected])': '@typescript-eslint/[email protected].1([email protected]([email protected]))([email protected])':
dependencies: dependencies:
'@typescript-eslint/scope-manager': 8.71.0 '@typescript-eslint/scope-manager': 8.71.1
'@typescript-eslint/types': 8.71.0 '@typescript-eslint/types': 8.71.1
'@typescript-eslint/typescript-estree': 8.71.0([email protected]) '@typescript-eslint/typescript-estree': 8.71.1([email protected])
'@typescript-eslint/visitor-keys': 8.71.0 '@typescript-eslint/visitor-keys': 8.71.1
debug: 4.4.3 debug: 4.4.3
eslint: 10.12.0([email protected]) eslint: 10.12.0([email protected])
typescript: 6.0.3 typescript: 6.0.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/[email protected].0([email protected])': '@typescript-eslint/[email protected].1([email protected])':
dependencies: dependencies:
'@typescript-eslint/tsconfig-utils': 8.71.0([email protected]) '@typescript-eslint/tsconfig-utils': 8.71.1([email protected])
'@typescript-eslint/types': 8.71.0 '@typescript-eslint/types': 8.71.1
debug: 4.4.3 debug: 4.4.3
typescript: 6.0.3 typescript: 6.0.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/[email protected].0': '@typescript-eslint/[email protected].1':
dependencies: dependencies:
'@typescript-eslint/types': 8.71.0 '@typescript-eslint/types': 8.71.1
'@typescript-eslint/visitor-keys': 8.71.0 '@typescript-eslint/visitor-keys': 8.71.1
'@typescript-eslint/[email protected].0([email protected])': '@typescript-eslint/[email protected].1([email protected])':
dependencies: dependencies:
typescript: 6.0.3 typescript: 6.0.3
'@typescript-eslint/[email protected].0([email protected]([email protected]))([email protected])': '@typescript-eslint/[email protected].1([email protected]([email protected]))([email protected])':
dependencies: dependencies:
'@typescript-eslint/types': 8.71.0 '@typescript-eslint/types': 8.71.1
'@typescript-eslint/typescript-estree': 8.71.0([email protected]) '@typescript-eslint/typescript-estree': 8.71.1([email protected])
'@typescript-eslint/utils': 8.71.0([email protected]([email protected]))([email protected]) '@typescript-eslint/utils': 8.71.1([email protected]([email protected]))([email protected])
debug: 4.4.3 debug: 4.4.3
eslint: 10.12.0([email protected]) eslint: 10.12.0([email protected])
ts-api-utils: 2.5.0([email protected]) ts-api-utils: 2.5.0([email protected])
@@ -1855,14 +1843,14 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/[email protected].0': {} '@typescript-eslint/[email protected].1': {}
'@typescript-eslint/[email protected].0([email protected])': '@typescript-eslint/[email protected].1([email protected])':
dependencies: dependencies:
'@typescript-eslint/project-service': 8.71.0([email protected]) '@typescript-eslint/project-service': 8.71.1([email protected])
'@typescript-eslint/tsconfig-utils': 8.71.0([email protected]) '@typescript-eslint/tsconfig-utils': 8.71.1([email protected])
'@typescript-eslint/types': 8.71.0 '@typescript-eslint/types': 8.71.1
'@typescript-eslint/visitor-keys': 8.71.0 '@typescript-eslint/visitor-keys': 8.71.1
debug: 4.4.3 debug: 4.4.3
minimatch: 10.2.6 minimatch: 10.2.6
semver: 7.8.5 semver: 7.8.5
@@ -1872,36 +1860,36 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/[email protected].0([email protected]([email protected]))([email protected])': '@typescript-eslint/[email protected].1([email protected]([email protected]))([email protected])':
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.10.1([email protected]([email protected])) '@eslint-community/eslint-utils': 4.10.1([email protected]([email protected]))
'@typescript-eslint/scope-manager': 8.71.0 '@typescript-eslint/scope-manager': 8.71.1
'@typescript-eslint/types': 8.71.0 '@typescript-eslint/types': 8.71.1
'@typescript-eslint/typescript-estree': 8.71.0([email protected]) '@typescript-eslint/typescript-estree': 8.71.1([email protected])
eslint: 10.12.0([email protected]) eslint: 10.12.0([email protected])
typescript: 6.0.3 typescript: 6.0.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/[email protected].0': '@typescript-eslint/[email protected].1':
dependencies: dependencies:
'@typescript-eslint/types': 8.71.0 '@typescript-eslint/types': 8.71.1
eslint-visitor-keys: 5.0.1 eslint-visitor-keys: 5.0.1
'@vitejs/[email protected]([email protected].2(@types/[email protected])([email protected]))([email protected]([email protected]))': '@vitejs/[email protected]([email protected].3(@types/[email protected])([email protected]))([email protected]([email protected]))':
dependencies: dependencies:
'@rolldown/pluginutils': 1.0.1 '@rolldown/pluginutils': 1.0.1
vite: 8.3.2(@types/[email protected])([email protected]) vite: 8.3.3(@types/[email protected])([email protected])
vue: 3.5.43([email protected]) vue: 3.5.43([email protected])
'@vitest/[email protected]([email protected].2(@types/[email protected])([email protected]))': '@vitest/[email protected]([email protected].3(@types/[email protected])([email protected]))':
dependencies: dependencies:
'@jridgewell/trace-mapping': 0.3.31 '@jridgewell/trace-mapping': 0.3.31
'@vitest/spy': 5.0.3 '@vitest/spy': 5.0.3
estree-walker: 3.0.3 estree-walker: 3.0.3
magic-string: 1.4.2 magic-string: 1.4.2
optionalDependencies: optionalDependencies:
vite: 8.3.2(@types/[email protected])([email protected]) vite: 8.3.3(@types/[email protected])([email protected])
'@vitest/[email protected]': {} '@vitest/[email protected]': {}
@@ -2129,7 +2117,7 @@ snapshots:
[email protected]: {} [email protected]: {}
[email protected](@typescript-eslint/[email protected].0([email protected]([email protected]))([email protected]))([email protected]([email protected]))([email protected]([email protected]([email protected]))): [email protected](@typescript-eslint/[email protected].1([email protected]([email protected]))([email protected]))([email protected]([email protected]))([email protected]([email protected]([email protected]))):
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.10.1([email protected]([email protected])) '@eslint-community/eslint-utils': 4.10.1([email protected]([email protected]))
eslint: 10.12.0([email protected]) eslint: 10.12.0([email protected])
@@ -2140,7 +2128,7 @@ snapshots:
vue-eslint-parser: 10.4.1([email protected]([email protected])) vue-eslint-parser: 10.4.1([email protected]([email protected]))
xml-name-validator: 5.0.0 xml-name-validator: 5.0.0
optionalDependencies: optionalDependencies:
'@typescript-eslint/parser': 8.71.0([email protected]([email protected]))([email protected]) '@typescript-eslint/parser': 8.71.1([email protected]([email protected]))([email protected])
[email protected]: [email protected]:
dependencies: dependencies:
@@ -2529,10 +2517,9 @@ snapshots:
dependencies: dependencies:
hookified: 2.2.0 hookified: 2.2.0
[email protected]0.5([email protected]([email protected])): [email protected]1.0([email protected]([email protected])):
dependencies: dependencies:
'@floating-ui/dom': 1.8.0 '@floating-ui/vue': 2.0.1([email protected]([email protected]))
'@floating-ui/vue': 1.1.11([email protected]([email protected]))
'@internationalized/date': 3.12.4 '@internationalized/date': 3.12.4
'@internationalized/number': 3.6.8 '@internationalized/number': 3.6.8
'@tanstack/vue-virtual': 3.13.39([email protected]([email protected])) '@tanstack/vue-virtual': 3.13.39([email protected]([email protected]))
@@ -2542,8 +2529,6 @@ snapshots:
defu: 6.1.7 defu: 6.1.7
ohash: 2.0.12 ohash: 2.0.12
vue: 3.5.43([email protected]) vue: 3.5.43([email protected])
transitivePeerDependencies:
- '@vue/composition-api'
[email protected]: [email protected]:
dependencies: dependencies:
@@ -2603,12 +2588,12 @@ snapshots:
dependencies: dependencies:
prelude-ls: 1.2.1 prelude-ls: 1.2.1
[email protected].0([email protected]([email protected]))([email protected]): [email protected].1([email protected]([email protected]))([email protected]):
dependencies: dependencies:
'@typescript-eslint/eslint-plugin': 8.71.0(@typescript-eslint/[email protected].0([email protected]([email protected]))([email protected]))([email protected]([email protected]))([email protected]) '@typescript-eslint/eslint-plugin': 8.71.1(@typescript-eslint/[email protected].1([email protected]([email protected]))([email protected]))([email protected]([email protected]))([email protected])
'@typescript-eslint/parser': 8.71.0([email protected]([email protected]))([email protected]) '@typescript-eslint/parser': 8.71.1([email protected]([email protected]))([email protected])
'@typescript-eslint/typescript-estree': 8.71.0([email protected]) '@typescript-eslint/typescript-estree': 8.71.1([email protected])
'@typescript-eslint/utils': 8.71.0([email protected]([email protected]))([email protected]) '@typescript-eslint/utils': 8.71.1([email protected]([email protected]))([email protected])
eslint: 10.12.0([email protected]) eslint: 10.12.0([email protected])
typescript: 6.0.3 typescript: 6.0.3
transitivePeerDependencies: transitivePeerDependencies:
@@ -2624,7 +2609,7 @@ snapshots:
[email protected]: {} [email protected]: {}
[email protected].2(@types/[email protected])([email protected]): [email protected].3(@types/[email protected])([email protected]):
dependencies: dependencies:
lightningcss: 1.33.0 lightningcss: 1.33.0
picomatch: 4.0.7 picomatch: 4.0.7
@@ -2636,10 +2621,10 @@ snapshots:
fsevents: 2.3.3 fsevents: 2.3.3
jiti: 2.7.0 jiti: 2.7.0
[email protected](@types/[email protected])([email protected])([email protected].2(@types/[email protected])([email protected])): [email protected](@types/[email protected])([email protected])([email protected].3(@types/[email protected])([email protected])):
dependencies: dependencies:
'@types/chai': 5.2.3 '@types/chai': 5.2.3
'@vitest/mocker': 5.0.3([email protected].2(@types/[email protected])([email protected])) '@vitest/mocker': 5.0.3([email protected].3(@types/[email protected])([email protected]))
chai: 6.3.0 chai: 6.3.0
es-module-lexer: 2.3.2 es-module-lexer: 2.3.2
expect-type: 1.4.0 expect-type: 1.4.0
@@ -2650,7 +2635,7 @@ snapshots:
tinybench: 6.1.4 tinybench: 6.1.4
tinyexec: 1.3.0 tinyexec: 1.3.0
tinyglobby: 0.2.17 tinyglobby: 0.2.17
vite: 8.3.2(@types/[email protected])([email protected]) vite: 8.3.3(@types/[email protected])([email protected])
why-is-node-running: 3.2.1 why-is-node-running: 3.2.1
optionalDependencies: optionalDependencies:
'@types/node': 26.6.4 '@types/node': 26.6.4
@@ -2662,10 +2647,6 @@ snapshots:
[email protected]: {} [email protected]: {}
[email protected]([email protected]([email protected])):
dependencies:
vue: 3.5.43([email protected])
[email protected]([email protected]([email protected])): [email protected]([email protected]([email protected])):
dependencies: dependencies:
debug: 4.4.3 debug: 4.4.3
+1 -1
View File
@@ -156,7 +156,7 @@ describe('AttentionRow', () => {
it('omits the age for an unknown timestamp', () => { it('omits the age for an unknown timestamp', () => {
const w = mount(AttentionRow, { const w = mount(AttentionRow, {
props: { props: {
row: row({ since: '0001-01-01T00:00:00Z', kind: 'issues_stale' }), row: row({ since: '0001-01-01T00:00:00Z', kind: 'issue_stale' }),
nowMs, nowMs,
critSeconds: CRIT_SECONDS, critSeconds: CRIT_SECONDS,
}, },
+2 -2
View File
@@ -38,7 +38,7 @@ const fleet = () =>
}), }),
alert({ alert({
repo: 'b/two', repo: 'b/two',
kind: 'issues_stale', kind: 'issue_stale',
severity: 'warn', severity: 'warn',
subject: '4 stale issues', subject: '4 stale issues',
url: '3', url: '3',
@@ -62,7 +62,7 @@ describe('kindGroup', () => {
['workflow_stuck', 'workflow'], ['workflow_stuck', 'workflow'],
['pr_waiting', 'pr'], ['pr_waiting', 'pr'],
['pr_checks_failing', 'pr'], ['pr_checks_failing', 'pr'],
['issues_stale', 'issue'], ['issue_stale', 'issue'],
['refresh_failed', 'data'], ['refresh_failed', 'data'],
['data_stale', 'data'], ['data_stale', 'data'],
['partial_data', 'data'], ['partial_data', 'data'],
+1 -1
View File
@@ -24,7 +24,7 @@ export const emptyFilters = (): Filters => ({
export function kindGroup(kind: string): KindGroup { export function kindGroup(kind: string): KindGroup {
if (kind.startsWith('workflow_')) return 'workflow' if (kind.startsWith('workflow_')) return 'workflow'
if (kind.startsWith('pr_')) return 'pr' if (kind.startsWith('pr_')) return 'pr'
if (kind === 'issues_stale') return 'issue' if (kind.startsWith('issue_')) return 'issue'
return 'data' return 'data'
} }
+3 -1
View File
@@ -14,7 +14,9 @@ export const KIND_ICON: Record<string, IconDefinition> = {
workflow_stuck: faGears, workflow_stuck: faGears,
pr_waiting: faCodePullRequest, pr_waiting: faCodePullRequest,
pr_checks_failing: faCodePullRequest, pr_checks_failing: faCodePullRequest,
issues_stale: faCircleDot, pr_fresh: faCodePullRequest,
issue_stale: faCircleDot,
issue_fresh: faCircleDot,
refresh_failed: faPlugCircleXmark, refresh_failed: faPlugCircleXmark,
data_stale: faClockRotateLeft, data_stale: faClockRotateLeft,
partial_data: faTriangleExclamation, partial_data: faTriangleExclamation,