feat(glance): add github components

This commit is contained in:
Nickolaj Jepsen 2025-12-15 00:08:41 +01:00
parent 4aa1f38ab9
commit 8fcf3c579d
4 changed files with 141 additions and 8 deletions

View file

@ -3,6 +3,7 @@
## Architecture Overview ## Architecture Overview
This is a **NixOS flake-based configuration** managing multiple hosts (desktop, laptop, homelab, work, WSL) with: This is a **NixOS flake-based configuration** managing multiple hosts (desktop, laptop, homelab, work, WSL) with:
- **flake-parts** for modular flake organization - **flake-parts** for modular flake organization
- **home-manager** integrated via `fireproof.home-manager` option (not standalone) - **home-manager** integrated via `fireproof.home-manager` option (not standalone)
- **agenix + agenix-rekey** for YubiKey-based secret management - **agenix + agenix-rekey** for YubiKey-based secret management
@ -79,6 +80,7 @@ just new-host <hostname> <user> # Bootstrap new host config
## Secret Management ## Secret Management
Secrets use **agenix-rekey** with YubiKey master identity: Secrets use **agenix-rekey** with YubiKey master identity:
- Global secrets: `secrets/*.age` - Global secrets: `secrets/*.age`
- Host-specific: `secrets/hosts/<hostname>/` (includes rekeyed secrets in `.rekey/`) - Host-specific: `secrets/hosts/<hostname>/` (includes rekeyed secrets in `.rekey/`)
- Reference secrets via `config.age.secrets.<name>.path` - Reference secrets via `config.age.secrets.<name>.path`

View file

@ -8,6 +8,8 @@
wsl.enable = true; wsl.enable = true;
}; };
wsl.usbip.autoAttach = ["1-9"];
system.stateVersion = "25.11"; system.stateVersion = "25.11";
}; };

View file

@ -385,12 +385,6 @@ in {
{ {
title = "Development"; title = "Development";
links = [ links = [
{
title = "GitHub";
url = "https://github.com";
icon = "si:github";
same-tab = true;
}
{ {
title = "Copilot"; title = "Copilot";
url = "https://github.com/copilot"; url = "https://github.com/copilot";
@ -414,7 +408,7 @@ in {
]; ];
} }
{ {
type = "split-column"; type = "group";
widgets = [ widgets = [
{ {
type = "hacker-news"; type = "hacker-news";
@ -435,6 +429,140 @@ in {
} }
]; ];
} }
{
size = "small";
widgets = [
{
type = "custom-api";
title = "Recent Repos";
title-url = "https://github.com";
cache = "10m";
url = "https://api.github.com/user/repos?sort=pushed&per_page=15&affiliation=owner,collaborator,organization_member";
headers = {
Authorization = "Bearer \${GITHUB_TOKEN}";
Accept = "application/vnd.github.v3+json";
};
template = ''
<ul class="list list-gap-10 collapsible-container" data-collapse-after="5">
{{ $items := .JSON.Array "" }}
{{ range $i, $repo := $items }}
{{ $repoPath := $repo.String "full_name" }}
<li{{ if ge $i 5 }} class="collapsible-item" style="animation-delay: {{ mul (sub $i 5) 20 }}ms;"{{ end }}>
<div style="display: flex; gap: 8px; align-items: flex-start;">
<a href="https://github.com/{{ $repo.String "owner.login" }}" style="flex-shrink: 0;">
<img src="{{ $repo.String "owner.avatar_url" }}&s=32" style="width: 20px; height: 20px; border-radius: 4px;" />
</a>
<div style="min-width: 0; flex: 1;">
<a href="{{ $repo.String "html_url" }}" class="color-highlight text-truncate block">{{ $repoPath }}</a>
<div style="font-size: 0.85em; margin-top: 2px;" class="color-subdue">
<span {{ $repo.String "pushed_at" | parseTime "rfc3339" | toRelativeTime }}></span>
</div>
</div>
</div>
</li>
{{ end }}
</ul>
'';
}
{
type = "custom-api";
title = "PRs Awaiting Review";
title-url = "https://github.com/pulls/review-requested";
cache = "10m";
url = "https://api.github.com/search/issues?q=is:pr+is:open+review-requested:@me&per_page=15";
headers = {
Authorization = "Bearer \${GITHUB_TOKEN}";
Accept = "application/vnd.github.v3+json";
};
template = ''
{{ $items := .JSON.Array "items" }}
{{ if eq (len $items) 0 }}
<p class="color-subdue" style="text-align: center;">No PRs awaiting review 🎉</p>
{{ else }}
<ul class="list list-gap-10 collapsible-container" data-collapse-after="5">
{{ range $i, $pr := $items }}
{{ $prDetails := newRequest ($pr.String "pull_request.url") | withHeader "Authorization" "Bearer ''${GITHUB_TOKEN}" | withHeader "Accept" "application/vnd.github.v3+json" | getResponse }}
{{ $headSha := $prDetails.JSON.String "head.sha" }}
{{ $repoPath := $pr.String "repository_url" | trimPrefix "https://api.github.com/repos/" }}
{{ $isDraft := $prDetails.JSON.Bool "draft" }}
{{ $mergeable := $prDetails.JSON.String "mergeable" }}
{{ $statusUrl := concat "https://api.github.com/repos/" $repoPath "/commits/" $headSha "/status" }}
{{ $status := newRequest $statusUrl | withHeader "Authorization" "Bearer ''${GITHUB_TOKEN}" | withHeader "Accept" "application/vnd.github.v3+json" | getResponse }}
{{ $state := $status.JSON.String "state" }}
{{ $statusCount := $status.JSON.Int "total_count" }}
<li{{ if ge $i 5 }} class="collapsible-item" style="animation-delay: {{ mul (sub $i 5) 20 }}ms;"{{ end }}>
<div style="display: flex; gap: 8px; align-items: flex-start;">
<a href="https://github.com/{{ $pr.String "user.login" }}" style="flex-shrink: 0;">
<img src="{{ $pr.String "user.avatar_url" }}&s=32" alt="{{ $pr.String "user.login" }}" style="width: 24px; height: 24px; border-radius: 50%;" />
</a>
<div style="min-width: 0; flex: 1;">
<a href="{{ $pr.String "html_url" }}" class="color-highlight" style="display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; line-height: 1.3;">{{ if $isDraft }}📝 {{ end }}{{ $pr.String "title" }}</a>
<div style="font-size: 0.85em; margin-top: 2px;" class="color-subdue">
<a href="https://github.com/{{ $pr.String "user.login" }}" class="color-primary" style="text-decoration: none;">{{ $pr.String "user.login" }}</a>
· <a href="https://github.com/{{ $repoPath }}" class="color-subdue">{{ $repoPath }}</a>
<a href="{{ $pr.String "html_url" }}" class="color-subdue">#{{ $pr.Int "number" }}</a>
· <span {{ $pr.String "created_at" | parseTime "rfc3339" | toRelativeTime }}></span>
{{ if gt $statusCount 0 }}· <a href="{{ $pr.String "html_url" }}/checks" style="text-decoration: none;">{{ if eq $state "success" }}{{ else if eq $state "failure" }}{{ else if eq $state "error" }}{{ else if eq $state "pending" }}🔄{{ else }}{{ end }}</a>{{ end }}
{{ if eq $mergeable "false" }}· conflicts{{ end }}
</div>
</div>
</div>
</li>
{{ end }}
</ul>
{{ end }}
'';
}
{
type = "custom-api";
title = "My Pull Requests";
title-url = "https://github.com/pulls";
cache = "10m";
url = "https://api.github.com/search/issues?q=is:pr+is:open+author:@me&per_page=15&sort=updated";
headers = {
Authorization = "Bearer \${GITHUB_TOKEN}";
Accept = "application/vnd.github.v3+json";
};
template = ''
{{ $items := .JSON.Array "items" }}
{{ if eq (len $items) 0 }}
<p class="color-subdue" style="text-align: center;">No open pull requests</p>
{{ else }}
<ul class="list list-gap-10 collapsible-container" data-collapse-after="5">
{{ range $i, $pr := $items }}
{{ $prDetails := newRequest ($pr.String "pull_request.url") | withHeader "Authorization" "Bearer ''${GITHUB_TOKEN}" | withHeader "Accept" "application/vnd.github.v3+json" | getResponse }}
{{ $headSha := $prDetails.JSON.String "head.sha" }}
{{ $repoPath := $pr.String "repository_url" | trimPrefix "https://api.github.com/repos/" }}
{{ $isDraft := $prDetails.JSON.Bool "draft" }}
{{ $mergeable := $prDetails.JSON.String "mergeable" }}
{{ $statusUrl := concat "https://api.github.com/repos/" $repoPath "/commits/" $headSha "/status" }}
{{ $status := newRequest $statusUrl | withHeader "Authorization" "Bearer ''${GITHUB_TOKEN}" | withHeader "Accept" "application/vnd.github.v3+json" | getResponse }}
{{ $state := $status.JSON.String "state" }}
{{ $statusCount := $status.JSON.Int "total_count" }}
{{ $reviewers := $prDetails.JSON.Array "requested_reviewers" }}
{{ $reviewCount := len $reviewers }}
<li{{ if ge $i 5 }} class="collapsible-item" style="animation-delay: {{ mul (sub $i 5) 20 }}ms;"{{ end }}>
<div style="display: flex; gap: 8px; align-items: flex-start;">
{{ if gt $statusCount 0 }}<a href="{{ $pr.String "html_url" }}/checks" style="flex-shrink: 0; font-size: 1.2em; line-height: 1; text-decoration: none;">{{ if eq $state "success" }}{{ else if eq $state "failure" }}{{ else if eq $state "error" }}{{ else if eq $state "pending" }}🔄{{ else }}{{ end }}</a>{{ end }}
<div style="min-width: 0; flex: 1;">
<a href="{{ $pr.String "html_url" }}" class="color-highlight" style="display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; line-height: 1.3;">{{ if $isDraft }}📝 {{ end }}{{ $pr.String "title" }}</a>
<div style="font-size: 0.85em; margin-top: 2px;" class="color-subdue">
<a href="https://github.com/{{ $repoPath }}" class="color-subdue">{{ $repoPath }}</a>
<a href="{{ $pr.String "html_url" }}" class="color-subdue">#{{ $pr.Int "number" }}</a>
· <span {{ $pr.String "updated_at" | parseTime "rfc3339" | toRelativeTime }}></span>
{{ if gt $reviewCount 0 }}· <a href="{{ $pr.String "html_url" }}" class="color-subdue">👀 {{ $reviewCount }}</a>{{ end }}
{{ if eq $mergeable "false" }}· conflicts{{ end }}
</div>
</div>
</div>
</li>
{{ end }}
</ul>
{{ end }}
'';
}
];
}
]; ];
} }
]; ];

View file

@ -11,6 +11,7 @@
defaultUser = config.fireproof.username; defaultUser = config.fireproof.username;
startMenuLaunchers = true; startMenuLaunchers = true;
interop.includePath = false; interop.includePath = false;
usbip.enable = true;
}; };
# WSL doesn't use a bootloader - disable systemd-boot # WSL doesn't use a bootloader - disable systemd-boot