From fb4bff75f3b15d427f3980bf4cb6d1a6c40decd2 Mon Sep 17 00:00:00 2001 From: Anirudh Oppiliappan Date: Mon, 25 Aug 2025 11:35:58 +0000 Subject: [PATCH] appview/{settings,pages}: rework settings ui Preserves the routes, but borrows a similar style to that of repo settings. Signed-off-by: Anirudh Oppiliappan --- appview/pages/funcmap.go | 8 ++++++++ appview/pages/pages.go | 32 +++++++++++++++++++++++++++----- appview/settings/settings.go | 53 ++++++++++++++++++++++++++++++++++++++++++++--------- appview/pages/templates/settings.html | 192 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ appview/pages/templates/user/settings/emails.html | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ appview/pages/templates/user/settings/keys.html | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ appview/pages/templates/user/settings/profile.html | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ appview/pages/templates/user/settings/fragments/emailListing.html | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ appview/pages/templates/user/settings/fragments/keyListing.html | 31 +++++++++++++++++++++++++++++++ appview/pages/templates/user/settings/fragments/sidebar.html | 16 ++++++++++++++++ 10 file(s) changed, 447 insertion(s)(+), 206 deletion(s)(-) diff --git a/appview/pages/funcmap.go b/appview/pages/funcmap.go --- a/appview/pages/funcmap.go +++ b/appview/pages/funcmap.go @@ -21,6 +21,7 @@ "github.com/go-enry/go-enry/v2" "tangled.sh/tangled.sh/core/appview/filetree" "tangled.sh/tangled.sh/core/appview/pages/markup" + "tangled.sh/tangled.sh/core/crypto" ) func (p *Pages) funcMap() template.FuncMap { @@ -281,6 +282,13 @@ "normalizeForHtmlId": func(s string) string { // TODO: extend this to handle other cases? return strings.ReplaceAll(s, ":", "_") + }, + "sshFingerprint": func(pubKey string) string { + fp, err := crypto.SSHFingerprint(pubKey) + if err != nil { + return "error" + } + return fp }, } } diff --git a/appview/pages/pages.go b/appview/pages/pages.go --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -306,14 +306,36 @@ return p.execute("timeline/timeline", w, params) } -type SettingsParams struct { +type UserProfileSettingsParams struct { LoggedInUser *oauth.User - PubKeys []db.PublicKey - Emails []db.Email + Tabs []map[string]any + Tab string } -func (p *Pages) Settings(w io.Writer, params SettingsParams) error { - return p.execute("settings", w, params) +func (p *Pages) UserProfileSettings(w io.Writer, params UserProfileSettingsParams) error { + return p.execute("user/settings/profile", w, params) +} + +type UserKeysSettingsParams struct { + LoggedInUser *oauth.User + PubKeys []db.PublicKey + Tabs []map[string]any + Tab string +} + +func (p *Pages) UserKeysSettings(w io.Writer, params UserKeysSettingsParams) error { + return p.execute("user/settings/keys", w, params) +} + +type UserEmailsSettingsParams struct { + LoggedInUser *oauth.User + Emails []db.Email + Tabs []map[string]any + Tab string +} + +func (p *Pages) UserEmailsSettings(w io.Writer, params UserEmailsSettingsParams) error { + return p.execute("user/settings/emails", w, params) } type KnotsParams struct { diff --git a/appview/settings/settings.go b/appview/settings/settings.go --- a/appview/settings/settings.go +++ b/appview/settings/settings.go @@ -33,19 +33,33 @@ Config *config.Config } +type tab = map[string]any + +var ( + settingsTabs []tab = []tab{ + {"Name": "profile", "Icon": "user"}, + {"Name": "keys", "Icon": "key"}, + {"Name": "emails", "Icon": "mail"}, + } +) + func (s *Settings) Router() http.Handler { r := chi.NewRouter() r.Use(middleware.AuthMiddleware(s.OAuth)) - r.Get("/", s.settings) + // settings pages + r.Get("/", s.profileSettings) + r.Get("/profile", s.profileSettings) r.Route("/keys", func(r chi.Router) { + r.Get("/", s.keysSettings) r.Put("/", s.keys) r.Delete("/", s.keys) }) r.Route("/emails", func(r chi.Router) { + r.Get("/", s.emailsSettings) r.Put("/", s.emails) r.Delete("/", s.emails) r.Get("/verify", s.emailsVerify) @@ -56,22 +70,43 @@ return r } -func (s *Settings) settings(w http.ResponseWriter, r *http.Request) { +func (s *Settings) profileSettings(w http.ResponseWriter, r *http.Request) { + user := s.OAuth.GetUser(r) + + s.Pages.UserProfileSettings(w, pages.UserProfileSettingsParams{ + LoggedInUser: user, + Tabs: settingsTabs, + Tab: "profile", + }) +} + +func (s *Settings) keysSettings(w http.ResponseWriter, r *http.Request) { user := s.OAuth.GetUser(r) pubKeys, err := db.GetPublicKeysForDid(s.Db, user.Did) if err != nil { log.Println(err) } + s.Pages.UserKeysSettings(w, pages.UserKeysSettingsParams{ + LoggedInUser: user, + PubKeys: pubKeys, + Tabs: settingsTabs, + Tab: "keys", + }) +} + +func (s *Settings) emailsSettings(w http.ResponseWriter, r *http.Request) { + user := s.OAuth.GetUser(r) emails, err := db.GetAllEmails(s.Db, user.Did) if err != nil { log.Println(err) } - s.Pages.Settings(w, pages.SettingsParams{ + s.Pages.UserEmailsSettings(w, pages.UserEmailsSettingsParams{ LoggedInUser: user, - PubKeys: pubKeys, Emails: emails, + Tabs: settingsTabs, + Tab: "emails", }) } @@ -201,7 +236,7 @@ return } - s.Pages.HxLocation(w, "/settings") + s.Pages.HxLocation(w, "/settings/emails") return } } @@ -244,7 +279,7 @@ return } - http.Redirect(w, r, "/settings", http.StatusSeeOther) + http.Redirect(w, r, "/settings/emails", http.StatusSeeOther) } func (s *Settings) emailsVerifyResend(w http.ResponseWriter, r *http.Request) { @@ -339,7 +374,7 @@ return } - s.Pages.HxLocation(w, "/settings") + s.Pages.HxLocation(w, "/settings/emails") } func (s *Settings) keys(w http.ResponseWriter, r *http.Request) { @@ -410,7 +445,7 @@ return } - s.Pages.HxLocation(w, "/settings") + s.Pages.HxLocation(w, "/settings/keys") return case http.MethodDelete: @@ -455,7 +490,7 @@ } log.Println("deleted successfully") - s.Pages.HxLocation(w, "/settings") + s.Pages.HxLocation(w, "/settings/keys") return } } diff --git a/appview/pages/templates/settings.html b/appview/pages/templates/settings.html deleted file mode 100644 --- a/appview/pages/templates/settings.html +++ /dev/null @@ -1,192 +0,0 @@ -{{ define "title" }}settings{{ end }} - -{{ define "content" }} -
-

Settings

-
-
- {{ block "profile" . }} {{ end }} - {{ block "keys" . }} {{ end }} - {{ block "emails" . }} {{ end }} -
-{{ end }} - -{{ define "profile" }} -

profile

-
-
- {{ if .LoggedInUser.Handle }} -
handle
-
@{{ .LoggedInUser.Handle }}
- {{ end }} -
did
-
{{ .LoggedInUser.Did }}
-
pds
-
{{ .LoggedInUser.Pds }}
-
-
-{{ end }} - -{{ define "keys" }} -

ssh keys

-
-

SSH public keys added here will be broadcasted to knots that you are a member of,
allowing you to push to repositories there.

-
- {{ range $index, $key := .PubKeys }} -
-
-
- {{ i "key" "w-3 h-3 dark:text-gray-300" }} -

{{ .Name }}

-
-

added {{ template "repo/fragments/time" .Created }}

-
- {{ .Key }} -
-
- -
- {{ end }} -
-
- - - - - - -
-
-
-{{ end }} - -{{ define "emails" }} -

email addresses

-
-

Commits authored using emails listed here will be associated with your Tangled profile.

-
- {{ range $index, $email := .Emails }} -
-
-
- {{ i "mail" "w-3 h-3 dark:text-gray-300" }} -

{{ .Address }}

-
- {{ if .Verified }} - verified - {{ else }} - unverified - {{ end }} - {{ if .Primary }} - primary - {{ end }} -
-
-

added {{ template "repo/fragments/time" .CreatedAt }}

-
-
- {{ if not .Verified }} - - {{ end }} - {{ if and (not .Primary) .Verified }} - - set as primary - - {{ end }} - {{ if not .Primary }} -
- - -
- {{ end }} -
-
- {{ end }} -
-
- - - - -
-
-
-
-{{ end }} diff --git a/appview/pages/templates/user/settings/emails.html b/appview/pages/templates/user/settings/emails.html new file mode 100644 --- /dev/null +++ b/appview/pages/templates/user/settings/emails.html @@ -0,0 +1,94 @@ +{{ define "title" }}{{ .Tab }} settings{{ end }} + +{{ define "content" }} +
+

Settings

+
+
+
+
+ {{ template "user/settings/fragments/sidebar" . }} +
+
+ {{ template "emailSettings" . }} +
+
+
+{{ end }} + +{{ define "emailSettings" }} +
+
+

Email Addresses

+

+ Commits authored using emails listed here will be associated with your Tangled profile. +

+
+
+ {{ template "addEmailButton" . }} +
+
+
+ {{ range .Emails }} + {{ template "user/settings/fragments/emailListing" (list $ .) }} + {{ else }} +
+ no emails added yet +
+ {{ end }} +
+{{ end }} + +{{ define "addEmailButton" }} + +
+ {{ template "addEmailModal" . }} +
+{{ end}} + +{{ define "addEmailModal" }} +
+

ADD EMAIL

+

Commits using this email will be associated with your profile.

+ +
+ + +
+
+
+
+{{ end }} \ No newline at end of file diff --git a/appview/pages/templates/user/settings/keys.html b/appview/pages/templates/user/settings/keys.html new file mode 100644 --- /dev/null +++ b/appview/pages/templates/user/settings/keys.html @@ -0,0 +1,101 @@ +{{ define "title" }}{{ .Tab }} settings{{ end }} + +{{ define "content" }} +
+

Settings

+
+
+
+
+ {{ template "user/settings/fragments/sidebar" . }} +
+
+ {{ template "sshKeysSettings" . }} +
+
+
+{{ end }} + +{{ define "sshKeysSettings" }} +
+
+

SSH Keys

+

+ SSH public keys added here will be broadcasted to knots that you are a member of, + allowing you to push to repositories there. +

+
+
+ {{ template "addKeyButton" . }} +
+
+
+ {{ range .PubKeys }} + {{ template "user/settings/fragments/keyListing" (list $ .) }} + {{ else }} +
+ no keys added yet +
+ {{ end }} +
+{{ end }} + +{{ define "addKeyButton" }} + +
+ {{ template "addKeyModal" . }} +
+{{ end}} + +{{ define "addKeyModal" }} +
+

ADD SSH KEY

+

SSH keys allow you to push to repositories in knots you're a member of.

+ + +
+ + +
+
+
+{{ end }} diff --git a/appview/pages/templates/user/settings/profile.html b/appview/pages/templates/user/settings/profile.html new file mode 100644 --- /dev/null +++ b/appview/pages/templates/user/settings/profile.html @@ -0,0 +1,64 @@ +{{ define "title" }}{{ .Tab }} settings{{ end }} + +{{ define "content" }} +
+

Settings

+
+
+
+
+ {{ template "user/settings/fragments/sidebar" . }} +
+
+ {{ template "profileInfo" . }} +
+
+
+{{ end }} + +{{ define "profileInfo" }} +
+
+

Profile

+

+ Your account information from your AT Protocol identity. +

+
+
+
+
+
+
+
+ {{ if .LoggedInUser.Handle }} + + @{{ .LoggedInUser.Handle }} + +
+ Handle +
+ {{ end }} +
+
+
+
+ + {{ .LoggedInUser.Did }} + +
+ Decentralized Identifier (DID) +
+
+
+
+
+ + {{ .LoggedInUser.Pds }} + +
+ Personal Data Server (PDS) +
+
+
+
+{{ end }} diff --git a/appview/pages/templates/user/settings/fragments/emailListing.html b/appview/pages/templates/user/settings/fragments/emailListing.html new file mode 100644 --- /dev/null +++ b/appview/pages/templates/user/settings/fragments/emailListing.html @@ -0,0 +1,62 @@ +{{ define "user/settings/fragments/emailListing" }} + {{ $root := index . 0 }} + {{ $email := index . 1 }} +
+
+
+ {{ i "mail" "w-4 h-4 text-gray-500 dark:text-gray-400" }} + + {{ $email.Address }} + +
+ {{ if $email.Verified }} + verified + {{ else }} + unverified + {{ end }} + {{ if $email.Primary }} + primary + {{ end }} +
+
+
+ added {{ template "repo/fragments/time" $email.CreatedAt }} +
+
+
+ {{ if not $email.Verified }} + + {{ end }} + {{ if and (not $email.Primary) $email.Verified }} + + {{ end }} + {{ if not $email.Primary }} + + {{ end }} +
+
+{{ end }} diff --git a/appview/pages/templates/user/settings/fragments/keyListing.html b/appview/pages/templates/user/settings/fragments/keyListing.html new file mode 100644 --- /dev/null +++ b/appview/pages/templates/user/settings/fragments/keyListing.html @@ -0,0 +1,31 @@ +{{ define "user/settings/fragments/keyListing" }} + {{ $root := index . 0 }} + {{ $key := index . 1 }} +
+
+
+ {{ i "key" "w-4" "h-4" }} + + {{ $key.Name }} + +
+ + {{ sshFingerprint $key.Key }} + +
+ added {{ template "repo/fragments/time" $key.Created }} +
+
+ +
+{{ end }} diff --git a/appview/pages/templates/user/settings/fragments/sidebar.html b/appview/pages/templates/user/settings/fragments/sidebar.html new file mode 100644 --- /dev/null +++ b/appview/pages/templates/user/settings/fragments/sidebar.html @@ -0,0 +1,16 @@ +{{ define "user/settings/fragments/sidebar" }} + {{ $active := .Tab }} + {{ $tabs := .Tabs }} +
+ {{ $activeTab := "bg-white dark:bg-gray-700 drop-shadow-sm" }} + {{ $inactiveTab := "bg-gray-100 dark:bg-gray-800" }} + {{ range $tabs }} + +
+ {{ i .Icon "size-4" }} + {{ .Name }} +
+
+ {{ end }} +
+{{ end }} \ No newline at end of file -- tangled.sh