Skip to content

Commit 2666810

Browse files
DAcodedBEATArun Philip
authored andcommitted
feat: show version on dashboard
Display release version in dashboard footer and includes template optimizations for better reuse. Signed-off-by: Arun Philip <arun@corkinc.com>
1 parent ccbf006 commit 2666810

8 files changed

Lines changed: 301 additions & 270 deletions

File tree

.github/workflows/release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,6 @@ jobs:
6060
echo "Version: $VERSION"
6161
[ -n "$VERSION" ] || { echo "ERROR: --version produced empty output"; exit 1; }
6262
if [ "${GITHUB_EVENT_NAME}" != "pull_request" ]; then
63-
EXPECTED="${GITHUB_REF_NAME}"
63+
EXPECTED="${GITHUB_REF_NAME#v}"
6464
[ "$VERSION" = "$EXPECTED" ] || { echo "ERROR: expected $EXPECTED got $VERSION"; exit 1; }
6565
fi

server/ui-base.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>{{block "title" .}}Tailscale OIDC Identity Provider{{end}}</title>
5+
<link href="/style.css" rel="stylesheet" type="text/css"/>
6+
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
7+
</head>
8+
9+
<body>
10+
{{template "header"}}
11+
12+
{{block "content" .}}{{end}}
13+
14+
{{template "footer" .}}
15+
</body>
16+
</html>

server/ui-edit.html

Lines changed: 124 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -1,198 +1,161 @@
1-
<!DOCTYPE html>
2-
<html>
3-
<head>
4-
<title>
5-
{{if .IsNew}}Add New Client{{else}}Edit Client{{end}} - Tailscale OIDC Identity Provider
6-
</title>
7-
<link rel="stylesheet" type="text/css" href="/style.css" />
8-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
9-
</head>
10-
11-
<body>
12-
{{template "header"}}
13-
14-
<main>
15-
<div class="form-container">
1+
{{define "content"}}
2+
<main>
3+
<div class="form-container">
164
<div class="form-header">
17-
<h2>
18-
{{if .IsNew}}Add New OIDC Client{{else}}Edit OIDC Client{{end}}
19-
</h2>
20-
<a href="/" class="btn btn-secondary">← Back to Clients</a>
5+
<h2>
6+
{{if .IsNew}}Add New OIDC Client{{else}}Edit OIDC Client{{end}}
7+
</h2>
8+
<a href="/" class="btn btn-secondary">← Back to Clients</a>
219
</div>
2210

2311
{{if .Success}}
2412
<div class="alert alert-success">
25-
{{.Success}}
13+
{{.Success}}
2614
</div>
2715
{{end}}
2816

2917
{{if .Error}}
3018
<div class="alert alert-error">
31-
{{.Error}}
19+
{{.Error}}
3220
</div>
3321
{{end}}
3422

3523
{{if and .Secret .IsNew}}
3624
<div class="client-info">
37-
<h3>Client Created Successfully!</h3>
38-
<p class="warning">⚠️ Save both the Client ID and Secret now! The secret will not be shown again.</p>
39-
40-
<div class="form-group">
41-
<label>Client ID</label>
42-
<div class="secret-field">
43-
<input type="text" value="{{.ID}}" readonly class="secret-input" id="client-id">
44-
<button type="button" onclick="copyClientId(event)" class="btn btn-secondary btn-small">Copy</button>
25+
<h3>Client Created Successfully!</h3>
26+
<p class="warning">⚠️ Save both the Client ID and Secret now! The secret will not be shown again.</p>
27+
28+
<div class="form-group">
29+
<label>Client ID</label>
30+
<div class="secret-field">
31+
<input type="text" value="{{.ID}}" readonly class="secret-input" aria-label="Client ID">
32+
<button type="button" onclick="copyValue(this.previousElementSibling, this)" class="btn btn-secondary btn-small">Copy</button>
33+
</div>
4534
</div>
46-
</div>
47-
48-
<div class="form-group">
49-
<label>Client Secret</label>
50-
<div class="secret-field">
51-
<input type="text" value="{{.Secret}}" readonly class="secret-input" id="client-secret">
52-
<button type="button" onclick="copySecret(event)" class="btn btn-secondary btn-small">Copy</button>
35+
36+
<div class="form-group">
37+
<label>Client Secret</label>
38+
<div class="secret-field">
39+
<input type="text" value="{{.Secret}}" readonly class="secret-input" aria-label="Client Secret">
40+
<button type="button" onclick="copyValue(this.previousElementSibling, this)" class="btn btn-secondary btn-small">Copy</button>
41+
</div>
5342
</div>
54-
</div>
5543
</div>
5644
{{end}}
5745

5846
{{if and .Secret .IsEdit}}
5947
<div class="secret-display">
60-
<h3>New Client Secret</h3>
61-
<p class="warning">⚠️ Save this secret now! It will not be shown again.</p>
62-
<div class="secret-field">
63-
<input type="text" value="{{.Secret}}" readonly class="secret-input" id="client-secret">
64-
<button type="button" onclick="copySecret(event)" class="btn btn-secondary btn-small">Copy</button>
65-
</div>
48+
<h3>New Client Secret</h3>
49+
<p class="warning">⚠️ Save this secret now! It will not be shown again.</p>
50+
<div class="secret-field">
51+
<input type="text" value="{{.Secret}}" readonly class="secret-input" aria-label="Client Secret">
52+
<button type="button" onclick="copyValue(this.previousElementSibling, this)" class="btn btn-secondary btn-small">Copy</button>
53+
</div>
6654
</div>
6755
{{end}}
6856

6957
<form method="POST" class="client-form">
70-
<div class="form-group">
71-
<label for="name">Client Name</label>
72-
<input
73-
type="text"
74-
id="name"
75-
name="name"
76-
value="{{.Name}}"
77-
placeholder="e.g., My Application"
78-
class="form-input"
79-
>
80-
<div class="form-help">
81-
A descriptive name for this OIDC client (optional).
82-
</div>
83-
</div>
84-
85-
<div class="form-group">
86-
<label for="redirect_uris">Redirect URIs <span class="required">*</span></label>
87-
<textarea
88-
id="redirect_uris"
89-
name="redirect_uris"
90-
placeholder="https://example.com/auth/callback&#10;https://example.com/oauth/callback"
91-
class="form-input"
92-
rows="4"
93-
required
94-
>{{joinRedirectURIs .RedirectURIs}}</textarea>
95-
<div class="form-help">
96-
Enter one redirect URI per line. Users will be redirected to one of these URLs after authentication.
58+
<div class="form-group">
59+
<label for="name">Client Name</label>
60+
<input
61+
type="text"
62+
id="name"
63+
name="name"
64+
value="{{.Name}}"
65+
placeholder="e.g., My Application"
66+
class="form-input"
67+
>
68+
<div class="form-help">
69+
A descriptive name for this OIDC client (optional).
70+
</div>
9771
</div>
98-
</div>
99-
100-
{{if .IsEdit}}
101-
<div class="form-group">
102-
<label>Client ID</label>
103-
<input
104-
type="text"
105-
value="{{.ID}}"
106-
readonly
107-
class="form-input form-input-readonly"
108-
>
109-
<div class="form-help">
110-
The client ID cannot be changed.
72+
73+
<div class="form-group">
74+
<label for="redirect_uris">Redirect URIs <span class="required">*</span></label>
75+
<textarea
76+
id="redirect_uris"
77+
name="redirect_uris"
78+
placeholder="https://example.com/auth/callback&#10;https://example.com/oauth/callback"
79+
class="form-input"
80+
rows="4"
81+
required
82+
>{{joinRedirectURIs .RedirectURIs}}</textarea>
83+
<div class="form-help">
84+
Enter one redirect URI per line. Users will be redirected to one of these URLs after authentication.
85+
</div>
11186
</div>
112-
</div>
113-
{{end}}
114-
115-
<div class="form-actions">
116-
<button type="submit" class="btn btn-primary">
117-
{{if .IsNew}}Create Client{{else}}Update Client{{end}}
118-
</button>
119-
87+
12088
{{if .IsEdit}}
121-
<button type="submit" name="action" value="regenerate_secret" class="btn btn-warning"
122-
onclick="return confirm('Are you sure you want to regenerate the client secret? The old secret will stop working immediately.')">
123-
Regenerate Secret
124-
</button>
125-
126-
<button type="submit" name="action" value="delete" class="btn btn-danger"
127-
onclick="return confirm('Are you sure you want to delete this client? This cannot be undone.')">
128-
Delete Client
129-
</button>
89+
<div class="form-group">
90+
<label>Client ID</label>
91+
<input
92+
type="text"
93+
value="{{.ID}}"
94+
readonly
95+
class="form-input form-input-readonly"
96+
>
97+
<div class="form-help">
98+
The client ID cannot be changed.
99+
</div>
100+
</div>
130101
{{end}}
131-
</div>
102+
103+
<div class="form-actions">
104+
<button type="submit" class="btn btn-primary">
105+
{{if .IsNew}}Create Client{{else}}Update Client{{end}}
106+
</button>
107+
108+
{{if .IsEdit}}
109+
<button type="submit" name="action" value="regenerate_secret" class="btn btn-warning"
110+
onclick="return confirm('Are you sure you want to regenerate the client secret? The old secret will stop working immediately.')">
111+
Regenerate Secret
112+
</button>
113+
114+
<button type="submit" name="action" value="delete" class="btn btn-danger"
115+
onclick="return confirm('Are you sure you want to delete this client? This cannot be undone.')">
116+
Delete Client
117+
</button>
118+
{{end}}
119+
</div>
132120
</form>
133121

134122
{{if .IsEdit}}
135123
<div class="client-info">
136-
<h3>Client Information</h3>
137-
<dl>
138-
<dt>Client ID</dt>
139-
<dd><code>{{.ID}}</code></dd>
140-
<dt>Secret Status</dt>
141-
<dd>
142-
{{if .HasSecret}}
143-
<span class="status-active">Secret configured</span>
144-
{{else}}
145-
<span class="status-inactive">No secret</span>
146-
{{end}}
147-
</dd>
148-
</dl>
124+
<h3>Client Information</h3>
125+
<dl>
126+
<dt>Client ID</dt>
127+
<dd><code>{{.ID}}</code></dd>
128+
<dt>Secret Status</dt>
129+
<dd>
130+
{{if .HasSecret}}
131+
<span class="status-active">Secret configured</span>
132+
{{else}}
133+
<span class="status-inactive">No secret</span>
134+
{{end}}
135+
</dd>
136+
</dl>
149137
</div>
150138
{{end}}
151-
</div>
152-
</main>
153-
154-
<script>
155-
function copySecret(event) {
156-
const secretInput = document.getElementById('client-secret');
157-
secretInput.select();
158-
secretInput.setSelectionRange(0, 99999); // For mobile devices
159-
160-
navigator.clipboard.writeText(secretInput.value).then(function() {
161-
const button = event.target;
162-
const originalText = button.textContent;
163-
button.textContent = 'Copied!';
164-
button.classList.add('btn-success');
165-
166-
setTimeout(function() {
167-
button.textContent = originalText;
168-
button.classList.remove('btn-success');
169-
}, 2000);
170-
}).catch(function(err) {
171-
console.error('Failed to copy: ', err);
172-
alert('Failed to copy to clipboard. Please copy manually.');
173-
});
174-
}
175-
176-
function copyClientId(event) {
177-
const clientIdInput = document.getElementById('client-id');
178-
clientIdInput.select();
179-
clientIdInput.setSelectionRange(0, 99999); // For mobile devices
180-
181-
navigator.clipboard.writeText(clientIdInput.value).then(function() {
182-
const button = event.target;
183-
const originalText = button.textContent;
184-
button.textContent = 'Copied!';
185-
button.classList.add('btn-success');
186-
187-
setTimeout(function() {
188-
button.textContent = originalText;
189-
button.classList.remove('btn-success');
190-
}, 2000);
191-
}).catch(function(err) {
192-
console.error('Failed to copy: ', err);
193-
alert('Failed to copy to clipboard. Please copy manually.');
139+
</div>
140+
</main>
141+
142+
<script>
143+
function copyValue(input, button) {
144+
input.select();
145+
input.setSelectionRange(0, 99999); // For mobile devices
146+
147+
navigator.clipboard.writeText(input.value).then(function () {
148+
const originalText = button.textContent;
149+
button.textContent = 'Copied!';
150+
button.classList.add('btn-success');
151+
152+
setTimeout(function () {
153+
button.textContent = originalText;
154+
button.classList.remove('btn-success');
155+
}, 2000);
156+
}).catch(function () {
157+
alert('Failed to copy to clipboard. Please copy manually.');
194158
});
195-
}
196-
</script>
197-
</body>
198-
</html>
159+
}
160+
</script>
161+
{{end}}

server/ui-footer.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<footer class="app-footer">
2+
<div class="footer-content">
3+
<span class="version-info">tsidp {{GetAppVersion}}</span>
4+
</div>
5+
</footer>

0 commit comments

Comments
 (0)