feat(webui): open a currated version of the user accounts section to non admin users
This commit is contained in:
parent
2bf1731343
commit
d40595cacb
8 changed files with 49 additions and 24 deletions
|
@ -2,9 +2,12 @@
|
||||||
<h1>User Accounts</h1>
|
<h1>User Accounts</h1>
|
||||||
<div class="flex-row" style="justify-content:space-between;">
|
<div class="flex-row" style="justify-content:space-between;">
|
||||||
<div style="min-width:240px;">
|
<div style="min-width:240px;">
|
||||||
<p>There are <span class="button">{{ len .Accounts }}</span> user accounts.</p>
|
<p>
|
||||||
<p>Use this page to inspect user accounts or create a new one.</p>
|
There are <strong>{{ len .Accounts }}</strong> user accounts.
|
||||||
|
Use this page to inspect user accounts.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
{{ if .Page.IsAdmin }}
|
||||||
<form action="/accounts" enctype="multipart/form-data" method="post">
|
<form action="/accounts" enctype="multipart/form-data" method="post">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>New User Account</legend>
|
<legend>New User Account</legend>
|
||||||
|
@ -39,6 +42,7 @@
|
||||||
<button class="primary" type="submit" value="submit">Create User Account</button>
|
<button class="primary" type="submit" value="submit">Create User Account</button>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
<article>
|
<article>
|
||||||
<table style="width:100%;">
|
<table style="width:100%;">
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
{{ if ne .Account.PasswordReset nil }}
|
{{ if ne .Account.PasswordReset nil }}
|
||||||
<h2>Password Reset</h2>
|
<h2>Password Reset</h2>
|
||||||
<article>
|
<article>
|
||||||
Direct the user to <a href="/account/{{ .Account.Id }}/reset/{{ .Account.PasswordReset }}">/account/{{ .Account.Id }}/reset/{{ .Account.PasswordReset }}</a> so that they can create their password.
|
Direct the user to <a href="/account/{{ .Account.Id }}/reset/{{ .Account.PasswordReset }}">/account/{{ .Account.Id }}/reset/{{ .Account.PasswordReset }}</a> so that they can create their password.
|
||||||
</article>
|
</article>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<h2>Status</h2>
|
<h2>Status</h2>
|
||||||
|
@ -24,6 +24,7 @@ Direct the user to <a href="/account/{{ .Account.Id }}/reset/{{ .Account.Passwor
|
||||||
{{ if .Account.IsAdmin }}
|
{{ if .Account.IsAdmin }}
|
||||||
<p>This accounts has <strong>admin</strong> privileges on TfStated.</p>
|
<p>This accounts has <strong>admin</strong> privileges on TfStated.</p>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
{{ if .Page.IsAdmin }}
|
||||||
<h2>Operations</h2>
|
<h2>Operations</h2>
|
||||||
<form action="/accounts/{{ .Account.Id }}" enctype="multipart/form-data" method="post">
|
<form action="/accounts/{{ .Account.Id }}" enctype="multipart/form-data" method="post">
|
||||||
<div class="flex-row">
|
<div class="flex-row">
|
||||||
|
@ -37,7 +38,8 @@ Direct the user to <a href="/account/{{ .Account.Id }}/reset/{{ .Account.Passwor
|
||||||
type="text"
|
type="text"
|
||||||
value="{{ .Username }}">
|
value="{{ .Username }}">
|
||||||
<label for="is-admin">Is Admin</label>
|
<label for="is-admin">Is Admin</label>
|
||||||
<input {{ if .Account.IsAdmin }} checked{{ end }}
|
<input {{ if .Account.IsAdmin }}checked{{ end }}
|
||||||
|
{{ if eq .Page.AccountId.String .Account.Id.String }}disabled{{ end }}
|
||||||
id="is-admin"
|
id="is-admin"
|
||||||
name="is-admin"
|
name="is-admin"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
@ -61,14 +63,23 @@ Direct the user to <a href="/account/{{ .Account.Id }}/reset/{{ .Account.Passwor
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Danger Zone</legend>
|
<legend>Danger Zone</legend>
|
||||||
<button type="submit" value="delete">Delete User Account</button>
|
<button {{ if eq .Page.AccountId.String .Account.Id.String }}disabled{{ end }}
|
||||||
|
type="submit"
|
||||||
|
value="delete">
|
||||||
|
Delete User Account
|
||||||
|
</button>
|
||||||
<!--<button type="submit" value="lock">Lock User Account</button>-->
|
<!--<button type="submit" value="lock">Lock User Account</button>-->
|
||||||
<button type="submit" value="reset-password">Reset Password</button>
|
<button {{ if or (ne .Account.PasswordReset nil) (eq .Page.AccountId.String .Account.Id.String) }}disabled{{ end }}
|
||||||
|
type="submit"
|
||||||
|
value="reset-password">
|
||||||
|
Reset Password
|
||||||
|
</button>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{{ if gt (len .Versions) 0 }}
|
{{ end }}
|
||||||
<h2>Activity</h2>
|
<h2>Activity</h2>
|
||||||
|
{{ if gt (len .Versions) 0 }}
|
||||||
<article>
|
<article>
|
||||||
<table style="width:100%;">
|
<table style="width:100%;">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -87,6 +98,8 @@ Direct the user to <a href="/account/{{ .Account.Id }}/reset/{{ .Account.Passwor
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</article>
|
</article>
|
||||||
|
{{ else }}
|
||||||
|
<p>This user account has not authored any change currently tracked by TfStated.</p>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<a href="/accounts">Go back to the user accounts list</a>
|
<a href="/accounts">Go back to the user accounts list</a>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
@ -28,12 +28,10 @@
|
||||||
<i class="material-symbols-outlined">settings</i>
|
<i class="material-symbols-outlined">settings</i>
|
||||||
<span>Settings</span>
|
<span>Settings</span>
|
||||||
</a>
|
</a>
|
||||||
{{ if .Page.IsAdmin }}
|
|
||||||
<a href="/accounts"{{ if eq .Page.Section "accounts" }} class="primary"{{ end}}>
|
<a href="/accounts"{{ if eq .Page.Section "accounts" }} class="primary"{{ end}}>
|
||||||
<i class="material-symbols-outlined">person</i>
|
<i class="material-symbols-outlined">person</i>
|
||||||
<span>User Accounts</span>
|
<span>User Accounts</span>
|
||||||
</a>
|
</a>
|
||||||
{{ end }}
|
|
||||||
<hr>
|
<hr>
|
||||||
<a href="/logout">
|
<a href="/logout">
|
||||||
<i class="material-symbols-outlined">logout</i>
|
<i class="material-symbols-outlined">logout</i>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<h1>States</h1>
|
<h1>States</h1>
|
||||||
<div class="flex-row" style="justify-content:space-between;">
|
<div class="flex-row" style="justify-content:space-between;">
|
||||||
<div style="min-width:240px;">
|
<div style="min-width:240px;">
|
||||||
<p>TfStated is currently managing <span class="button">{{ len .States }}</span> states.</p>
|
<p>TfStated is currently managing <strong>{{ len .States }}</strong> states.</p>
|
||||||
<p>Use this page to inspect the existing states.</p>
|
<p>Use this page to inspect the existing states.</p>
|
||||||
<p>You also have the option to upload a JSON state file in order to create a new state in TfStated. This is equivalent to using the <code>state push</code> command of OpenTofu/Terraform on a brand new state.</p>
|
<p>You also have the option to upload a JSON state file in order to create a new state in TfStated. This is equivalent to using the <code>state push</code> command of OpenTofu/Terraform on a brand new state.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,23 +2,22 @@
|
||||||
<h1>State</h1>
|
<h1>State</h1>
|
||||||
<p>
|
<p>
|
||||||
The state at path
|
The state at path
|
||||||
<span class="button">{{ .State.Path }}</span>
|
<strong>{{ .State.Path }}</strong>
|
||||||
has
|
has
|
||||||
<span class="button">{{ len .Versions }}</span>
|
<strong>{{ len .Versions }}</strong>
|
||||||
versions and is currently
|
versions and is currently
|
||||||
<span class="button">
|
<strong>
|
||||||
{{ if eq .State.Lock nil }}
|
{{ if eq .State.Lock nil }}
|
||||||
unlocked
|
unlocked.
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<span class="tooltip">
|
<span class="tooltip">
|
||||||
locked
|
locked.
|
||||||
<span class="tooltip-text">
|
<span class="tooltip-text">
|
||||||
{{ .State.Lock }}
|
{{ .State.Lock }}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</span>
|
</strong>
|
||||||
.
|
|
||||||
</p>
|
</p>
|
||||||
<p>Use this page to inspect the existing versions.</p>
|
<p>Use this page to inspect the existing versions.</p>
|
||||||
<article>
|
<article>
|
||||||
|
|
|
@ -5,9 +5,11 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.adyxax.org/adyxax/tfstated/pkg/model"
|
"git.adyxax.org/adyxax/tfstated/pkg/model"
|
||||||
|
"go.n16f.net/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Page struct {
|
type Page struct {
|
||||||
|
AccountId uuid.UUID
|
||||||
IsAdmin bool
|
IsAdmin bool
|
||||||
LightMode bool
|
LightMode bool
|
||||||
Section string
|
Section string
|
||||||
|
@ -16,6 +18,7 @@ type Page struct {
|
||||||
|
|
||||||
func makePage(r *http.Request, page *Page) *Page {
|
func makePage(r *http.Request, page *Page) *Page {
|
||||||
account := r.Context().Value(model.AccountContextKey{}).(*model.Account)
|
account := r.Context().Value(model.AccountContextKey{}).(*model.Account)
|
||||||
|
page.AccountId = account.Id
|
||||||
page.IsAdmin = account.IsAdmin
|
page.IsAdmin = account.IsAdmin
|
||||||
settings := r.Context().Value(model.SettingsContextKey{}).(*model.Settings)
|
settings := r.Context().Value(model.SettingsContextKey{}).(*model.Settings)
|
||||||
page.LightMode = settings.LightMode
|
page.LightMode = settings.LightMode
|
||||||
|
|
|
@ -13,8 +13,8 @@ func addRoutes(
|
||||||
requireSession := sessionsMiddleware(db)
|
requireSession := sessionsMiddleware(db)
|
||||||
requireLogin := loginMiddleware(db, requireSession)
|
requireLogin := loginMiddleware(db, requireSession)
|
||||||
requireAdmin := adminMiddleware(db, requireLogin)
|
requireAdmin := adminMiddleware(db, requireLogin)
|
||||||
mux.Handle("GET /accounts", requireAdmin(handleAccountsGET(db)))
|
mux.Handle("GET /accounts", requireLogin(handleAccountsGET(db)))
|
||||||
mux.Handle("GET /accounts/{id}", requireAdmin(handleAccountsIdGET(db)))
|
mux.Handle("GET /accounts/{id}", requireLogin(handleAccountsIdGET(db)))
|
||||||
mux.Handle("POST /accounts", requireAdmin(handleAccountsPOST(db)))
|
mux.Handle("POST /accounts", requireAdmin(handleAccountsPOST(db)))
|
||||||
mux.Handle("GET /healthz", handleHealthz())
|
mux.Handle("GET /healthz", handleHealthz())
|
||||||
mux.Handle("GET /login", requireSession(handleLoginGET()))
|
mux.Handle("GET /login", requireSession(handleLoginGET()))
|
||||||
|
|
|
@ -85,6 +85,11 @@ input:not([type=image i], [type=range i], [type=checkbox i], [type=radio i]) {
|
||||||
overflow: clip !important;
|
overflow: clip !important;
|
||||||
overflow-clip-margin: 0 !important;
|
overflow-clip-margin: 0 !important;
|
||||||
}
|
}
|
||||||
|
button:disabled, button:disabled:hover {
|
||||||
|
background-color: var(--bg-2);
|
||||||
|
border: 1px solid var(--fg-1);
|
||||||
|
color:var(--dim) !important;
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
font-family: var(--sans-font);
|
font-family: var(--sans-font);
|
||||||
|
@ -248,12 +253,11 @@ fieldset {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
button, .button {
|
button, .button {
|
||||||
background-color: var(--bg-2);
|
|
||||||
border: 1px solid var(--orange);
|
|
||||||
color: var(--orange);
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
background-color: var(--bg-2);
|
||||||
border: 1px solid var(--fg-1);
|
border: 1px solid var(--fg-1);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
color: var(--orange);
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
@ -329,6 +333,10 @@ footer p {
|
||||||
footer a {
|
footer a {
|
||||||
color: var(--green);
|
color: var(--green);
|
||||||
}
|
}
|
||||||
|
strong {
|
||||||
|
color: var(--orange);
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (640px <= width < 968px) { /*856*/
|
@media only screen and (640px <= width < 968px) { /*856*/
|
||||||
header {
|
header {
|
||||||
|
|
Loading…
Add table
Reference in a new issue