+5
-1
appview/pages/templates/repo/pipelines/workflow.html
+5
-1
appview/pages/templates/repo/pipelines/workflow.html
···
19
20
{{ define "sidebar" }}
21
{{ $active := .Workflow }}
22
{{ with .Pipeline }}
23
{{ $id := .Id }}
24
<div class="sticky top-2 grid grid-cols-1 rounded border border-gray-200 dark:border-gray-700 divide-y divide-gray-200 dark:divide-gray-700">
25
{{ range $name, $all := .Statuses }}
26
<a href="/{{ $.RepoInfo.FullName }}/pipelines/{{ $id }}/workflow/{{ $name }}" class="no-underline hover:no-underline hover:bg-gray-100/25 hover:dark:bg-gray-700/25">
27
<div
28
-
class="flex gap-2 items-center justify-between p-2 {{ if eq $name $active }}bg-gray-100/50 dark:bg-gray-700/50{{ end }}">
29
{{ $lastStatus := $all.Latest }}
30
{{ $kind := $lastStatus.Status.String }}
31
···
19
20
{{ define "sidebar" }}
21
{{ $active := .Workflow }}
22
+
23
+
{{ $activeTab := "bg-white dark:bg-gray-700 drop-shadow-sm" }}
24
+
{{ $inactiveTab := "bg-gray-100 dark:bg-gray-800" }}
25
+
26
{{ with .Pipeline }}
27
{{ $id := .Id }}
28
<div class="sticky top-2 grid grid-cols-1 rounded border border-gray-200 dark:border-gray-700 divide-y divide-gray-200 dark:divide-gray-700">
29
{{ range $name, $all := .Statuses }}
30
<a href="/{{ $.RepoInfo.FullName }}/pipelines/{{ $id }}/workflow/{{ $name }}" class="no-underline hover:no-underline hover:bg-gray-100/25 hover:dark:bg-gray-700/25">
31
<div
32
+
class="flex gap-2 items-center justify-between p-2 {{ if eq $name $active }} {{ $activeTab }} {{ else }} {{ $inactiveTab }} {{ end }}">
33
{{ $lastStatus := $all.Latest }}
34
{{ $kind := $lastStatus.Status.String }}
35
-168
appview/pages/templates/repo/settings.html
-168
appview/pages/templates/repo/settings.html
···
1
-
{{ define "title" }}settings · {{ .RepoInfo.FullName }}{{ end }}
2
-
3
-
{{ define "repoContent" }}
4
-
{{ template "collaboratorSettings" . }}
5
-
{{ template "branchSettings" . }}
6
-
{{ template "dangerZone" . }}
7
-
{{ template "spindleSelector" . }}
8
-
{{ template "spindleSecrets" . }}
9
-
{{ end }}
10
-
11
-
{{ define "collaboratorSettings" }}
12
-
<header class="font-bold text-sm mb-4 uppercase dark:text-white">
13
-
Collaborators
14
-
</header>
15
-
16
-
<div id="collaborator-list" class="flex flex-col gap-2 mb-2">
17
-
{{ range .Collaborators }}
18
-
<div id="collaborator" class="mb-2">
19
-
<a
20
-
href="/{{ didOrHandle .Did .Handle }}"
21
-
class="no-underline hover:underline text-black dark:text-white"
22
-
>
23
-
{{ didOrHandle .Did .Handle }}
24
-
</a>
25
-
<div>
26
-
<span class="text-sm text-gray-500 dark:text-gray-400">
27
-
{{ .Role }}
28
-
</span>
29
-
</div>
30
-
</div>
31
-
{{ end }}
32
-
</div>
33
-
34
-
{{ if .RepoInfo.Roles.CollaboratorInviteAllowed }}
35
-
<form
36
-
hx-put="/{{ $.RepoInfo.FullName }}/settings/collaborator"
37
-
class="group"
38
-
>
39
-
<label for="collaborator" class="dark:text-white">
40
-
add collaborator
41
-
</label>
42
-
<input
43
-
type="text"
44
-
id="collaborator"
45
-
name="collaborator"
46
-
required
47
-
class="dark:bg-gray-700 dark:text-white"
48
-
placeholder="enter did or handle">
49
-
<button class="btn my-2 flex gap-2 items-center dark:text-white dark:hover:bg-gray-700" type="text">
50
-
<span>add</span>
51
-
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
52
-
</button>
53
-
</form>
54
-
{{ end }}
55
-
{{ end }}
56
-
57
-
{{ define "dangerZone" }}
58
-
{{ if .RepoInfo.Roles.RepoDeleteAllowed }}
59
-
<form
60
-
hx-confirm="Are you sure you want to delete this repository?"
61
-
hx-delete="/{{ $.RepoInfo.FullName }}/settings/delete"
62
-
class="mt-6"
63
-
hx-indicator="#delete-repo-spinner">
64
-
<label for="branch">delete repository</label>
65
-
<button class="btn my-2 flex items-center" type="text">
66
-
<span>delete</span>
67
-
<span id="delete-repo-spinner" class="group">
68
-
{{ i "loader-circle" "ml-2 w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
69
-
</span>
70
-
</button>
71
-
<span>
72
-
Deleting a repository is irreversible and permanent.
73
-
</span>
74
-
</form>
75
-
{{ end }}
76
-
{{ end }}
77
-
78
-
{{ define "branchSettings" }}
79
-
<form hx-put="/{{ $.RepoInfo.FullName }}/settings/branches/default" class="mt-6 group">
80
-
<label for="branch">default branch</label>
81
-
<div class="flex gap-2 items-center">
82
-
<select id="branch" name="branch" required class="p-1 border border-gray-200 bg-white dark:bg-gray-800 dark:text-white dark:border-gray-700">
83
-
<option value="" disabled selected >
84
-
Choose a default branch
85
-
</option>
86
-
{{ range .Branches }}
87
-
<option value="{{ .Name }}" class="py-1" {{ if .IsDefault }}selected{{ end }} >
88
-
{{ .Name }}
89
-
</option>
90
-
{{ end }}
91
-
</select>
92
-
<button class="btn my-2 flex gap-2 items-center" type="submit">
93
-
<span>save</span>
94
-
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
95
-
</button>
96
-
</div>
97
-
</form>
98
-
{{ end }}
99
-
100
-
{{ define "spindleSelector" }}
101
-
{{ if .RepoInfo.Roles.IsOwner }}
102
-
<form hx-post="/{{ $.RepoInfo.FullName }}/settings/spindle" class="mt-6 group" >
103
-
<label for="spindle">spindle</label>
104
-
<div class="flex gap-2 items-center">
105
-
<select id="spindle" name="spindle" required class="p-1 border border-gray-200 bg-white dark:bg-gray-800 dark:text-white dark:border-gray-700">
106
-
<option value="" selected >
107
-
None
108
-
</option>
109
-
{{ range .Spindles }}
110
-
<option value="{{ . }}" class="py-1" {{ if eq . $.CurrentSpindle }}selected{{ end }}>
111
-
{{ . }}
112
-
</option>
113
-
{{ end }}
114
-
</select>
115
-
<button class="btn my-2 flex gap-2 items-center" type="submit">
116
-
<span>save</span>
117
-
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
118
-
</button>
119
-
</div>
120
-
</form>
121
-
{{ end }}
122
-
{{ end }}
123
-
124
-
{{ define "spindleSecrets" }}
125
-
{{ if $.CurrentSpindle }}
126
-
<header class="font-bold text-sm mb-4 uppercase dark:text-white">
127
-
Secrets
128
-
</header>
129
-
130
-
<div id="secret-list" class="flex flex-col gap-2 mb-2">
131
-
{{ range $idx, $secret := .Secrets }}
132
-
{{ with $secret }}
133
-
<div id="secret-{{$idx}}" class="mb-2">
134
-
{{ .Key }} created on {{ .CreatedAt }} by {{ .CreatedBy }}
135
-
</div>
136
-
{{ end }}
137
-
{{ end }}
138
-
</div>
139
-
<form
140
-
hx-put="/{{ $.RepoInfo.FullName }}/settings/secrets"
141
-
class="mt-6"
142
-
hx-indicator="#add-secret-spinner">
143
-
<label for="key">secret key</label>
144
-
<input
145
-
type="text"
146
-
id="key"
147
-
name="key"
148
-
required
149
-
class="dark:bg-gray-700 dark:text-white"
150
-
placeholder="SECRET_KEY" />
151
-
<label for="value">secret value</label>
152
-
<input
153
-
type="text"
154
-
id="value"
155
-
name="value"
156
-
required
157
-
class="dark:bg-gray-700 dark:text-white"
158
-
placeholder="SECRET VALUE" />
159
-
160
-
<button class="btn my-2 flex items-center" type="text">
161
-
<span>add</span>
162
-
<span id="add-secret-spinner" class="group">
163
-
{{ i "loader-circle" "ml-2 w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
164
-
</span>
165
-
</button>
166
-
</form>
167
-
{{ end }}
168
-
{{ end }}
···
+5
appview/strings/strings.go
+5
appview/strings/strings.go
···
99
w.WriteHeader(http.StatusInternalServerError)
100
return
101
}
102
+
if len(strings) < 1 {
103
+
l.Error("string not found")
104
+
s.Pages.Error404(w)
105
+
return
106
+
}
107
if len(strings) != 1 {
108
l.Error("incorrect number of records returned", "len(strings)", len(strings))
109
w.WriteHeader(http.StatusInternalServerError)
+13
-16
flake.nix
+13
-16
flake.nix
···
75
};
76
genjwks = self.callPackage ./nix/pkgs/genjwks.nix {};
77
lexgen = self.callPackage ./nix/pkgs/lexgen.nix {inherit indigo;};
78
-
appview = self.callPackage ./nix/pkgs/appview.nix {
79
inherit htmx-src htmx-ws-src lucide-src inter-fonts-src ibm-plex-mono-src;
80
};
81
spindle = self.callPackage ./nix/pkgs/spindle.nix {};
82
knot-unwrapped = self.callPackage ./nix/pkgs/knot-unwrapped.nix {};
83
knot = self.callPackage ./nix/pkgs/knot.nix {};
···
93
staticPackages = mkPackageSet pkgs.pkgsStatic;
94
crossPackages = mkPackageSet pkgs.pkgsCross.gnu64.pkgsStatic;
95
in {
96
-
appview = packages.appview;
97
-
lexgen = packages.lexgen;
98
-
knot = packages.knot;
99
-
knot-unwrapped = packages.knot-unwrapped;
100
-
spindle = packages.spindle;
101
-
genjwks = packages.genjwks;
102
-
sqlite-lib = packages.sqlite-lib;
103
104
pkgsStatic-appview = staticPackages.appview;
105
pkgsStatic-knot = staticPackages.knot;
···
132
pkgs.tailwindcss
133
pkgs.nixos-shell
134
pkgs.redis
135
packages'.lexgen
136
];
137
shellHook = ''
138
-
mkdir -p appview/pages/static/{fonts,icons}
139
-
cp -f ${htmx-src} appview/pages/static/htmx.min.js
140
-
cp -f ${htmx-ws-src} appview/pages/static/htmx-ext-ws.min.js
141
-
cp -rf ${lucide-src}/*.svg appview/pages/static/icons/
142
-
cp -f ${inter-fonts-src}/web/InterVariable*.woff2 appview/pages/static/fonts/
143
-
cp -f ${inter-fonts-src}/web/InterDisplay*.woff2 appview/pages/static/fonts/
144
-
cp -f ${ibm-plex-mono-src}/fonts/complete/woff2/IBMPlexMono-Regular.woff2 appview/pages/static/fonts/
145
export TANGLED_OAUTH_JWKS="$(${packages'.genjwks}/bin/genjwks)"
146
'';
147
env.CGO_ENABLED = 1;
···
149
});
150
apps = forAllSystems (system: let
151
pkgs = nixpkgsFor."${system}";
152
air-watcher = name: arg:
153
pkgs.writeShellScriptBin "run"
154
''
···
167
in {
168
watch-appview = {
169
type = "app";
170
-
program = ''${air-watcher "appview" ""}/bin/run'';
171
};
172
watch-knot = {
173
type = "app";
···
75
};
76
genjwks = self.callPackage ./nix/pkgs/genjwks.nix {};
77
lexgen = self.callPackage ./nix/pkgs/lexgen.nix {inherit indigo;};
78
+
appview-static-files = self.callPackage ./nix/pkgs/appview-static-files.nix {
79
inherit htmx-src htmx-ws-src lucide-src inter-fonts-src ibm-plex-mono-src;
80
};
81
+
appview = self.callPackage ./nix/pkgs/appview.nix {};
82
spindle = self.callPackage ./nix/pkgs/spindle.nix {};
83
knot-unwrapped = self.callPackage ./nix/pkgs/knot-unwrapped.nix {};
84
knot = self.callPackage ./nix/pkgs/knot.nix {};
···
94
staticPackages = mkPackageSet pkgs.pkgsStatic;
95
crossPackages = mkPackageSet pkgs.pkgsCross.gnu64.pkgsStatic;
96
in {
97
+
inherit (packages) appview appview-static-files lexgen genjwks spindle knot knot-unwrapped sqlite-lib;
98
99
pkgsStatic-appview = staticPackages.appview;
100
pkgsStatic-knot = staticPackages.knot;
···
127
pkgs.tailwindcss
128
pkgs.nixos-shell
129
pkgs.redis
130
+
pkgs.coreutils # for those of us who are on systems that use busybox (alpine)
131
packages'.lexgen
132
];
133
shellHook = ''
134
+
mkdir -p appview/pages/static
135
+
# no preserve is needed because watch-tailwind will want to be able to overwrite
136
+
cp -fr --no-preserve=ownership ${packages'.appview-static-files}/* appview/pages/static
137
export TANGLED_OAUTH_JWKS="$(${packages'.genjwks}/bin/genjwks)"
138
'';
139
env.CGO_ENABLED = 1;
···
141
});
142
apps = forAllSystems (system: let
143
pkgs = nixpkgsFor."${system}";
144
+
packages' = self.packages.${system};
145
air-watcher = name: arg:
146
pkgs.writeShellScriptBin "run"
147
''
···
160
in {
161
watch-appview = {
162
type = "app";
163
+
program = toString (pkgs.writeShellScript "watch-appview" ''
164
+
echo "copying static files to appview/pages/static..."
165
+
${pkgs.coreutils}/bin/cp -fr --no-preserve=ownership ${packages'.appview-static-files}/* appview/pages/static
166
+
${air-watcher "appview" ""}/bin/run
167
+
'');
168
};
169
watch-knot = {
170
type = "app";
+23
nix/pkgs/appview-static-files.nix
+23
nix/pkgs/appview-static-files.nix
···
···
1
+
{
2
+
runCommandLocal,
3
+
htmx-src,
4
+
htmx-ws-src,
5
+
lucide-src,
6
+
inter-fonts-src,
7
+
ibm-plex-mono-src,
8
+
sqlite-lib,
9
+
tailwindcss,
10
+
src,
11
+
}:
12
+
runCommandLocal "appview-static-files" {} ''
13
+
mkdir -p $out/{fonts,icons} && cd $out
14
+
cp -f ${htmx-src} htmx.min.js
15
+
cp -f ${htmx-ws-src} htmx-ext-ws.min.js
16
+
cp -rf ${lucide-src}/*.svg icons/
17
+
cp -f ${inter-fonts-src}/web/InterVariable*.woff2 fonts/
18
+
cp -f ${inter-fonts-src}/web/InterDisplay*.woff2 fonts/
19
+
cp -f ${ibm-plex-mono-src}/fonts/complete/woff2/IBMPlexMono-Regular.woff2 fonts/
20
+
# tailwindcss -c $src/tailwind.config.js -i $src/input.css -o tw.css won't work
21
+
# for whatever reason (produces broken css), so we are doing this instead
22
+
cd ${src} && ${tailwindcss}/bin/tailwindcss -i input.css -o $out/tw.css
23
+
''
+3
-14
nix/pkgs/appview.nix
+3
-14
nix/pkgs/appview.nix
···
1
{
2
buildGoApplication,
3
modules,
4
-
htmx-src,
5
-
htmx-ws-src,
6
-
lucide-src,
7
-
inter-fonts-src,
8
-
ibm-plex-mono-src,
9
-
tailwindcss,
10
sqlite-lib,
11
src,
12
}:
···
17
18
postUnpack = ''
19
pushd source
20
-
mkdir -p appview/pages/static/{fonts,icons}
21
-
cp -f ${htmx-src} appview/pages/static/htmx.min.js
22
-
cp -f ${htmx-ws-src} appview/pages/static/htmx-ext-ws.min.js
23
-
cp -rf ${lucide-src}/*.svg appview/pages/static/icons/
24
-
cp -f ${inter-fonts-src}/web/InterVariable*.woff2 appview/pages/static/fonts/
25
-
cp -f ${inter-fonts-src}/web/InterDisplay*.woff2 appview/pages/static/fonts/
26
-
cp -f ${ibm-plex-mono-src}/fonts/complete/woff2/IBMPlexMono-Regular.woff2 appview/pages/static/fonts/
27
-
${tailwindcss}/bin/tailwindcss -i input.css -o appview/pages/static/tw.css
28
popd
29
'';
30
+4
spindle/server.go
+4
spindle/server.go
···
242
return fmt.Errorf("no repo data found")
243
}
244
245
+
if src.Key() != tpl.TriggerMetadata.Repo.Knot {
246
+
return fmt.Errorf("repo knot does not match event source: %s != %s", src.Key(), tpl.TriggerMetadata.Repo.Knot)
247
+
}
248
+
249
// filter by repos
250
_, err = s.db.GetRepo(
251
tpl.TriggerMetadata.Repo.Knot,