From d1d6a3301ab17954f78227a29cfe51e5b52f0510 Mon Sep 17 00:00:00 2001 From: Seongmin Lee Date: Mon, 15 Jun 2026 19:42:43 +0900 Subject: [PATCH] appview: update larger element on htmx handlers also see https://discord.com/channels/1361963801993285692/1361991850327674932/1516041992570929285 Signed-off-by: Seongmin Lee --- appview/accountmigration/accountmigration.go | 84 ++++++----- appview/pages/pages.go | 3 +- .../account/migrate/fragments/repoList.html | 93 ------------ .../account/migrate/fragments/step2.html | 133 ++++++++++++++++++ .../migrate/fragments/stepIndicator.html | 5 + .../templates/account/migrate/fromGitHub.html | 60 +++----- 6 files changed, 196 insertions(+), 182 deletions(-) delete mode 100644 appview/pages/templates/account/migrate/fragments/repoList.html create mode 100644 appview/pages/templates/account/migrate/fragments/step2.html create mode 100644 appview/pages/templates/account/migrate/fragments/stepIndicator.html diff --git a/appview/accountmigration/accountmigration.go b/appview/accountmigration/accountmigration.go index 561536e3..89c93959 100644 --- a/appview/accountmigration/accountmigration.go +++ b/appview/accountmigration/accountmigration.go @@ -71,26 +71,6 @@ func (s *AccountMigration) migratePage(w http.ResponseWriter, r *http.Request) { if err := s.pages.AccountMigrateFromGitHub(w, pages.AccountMigrateFromGitHubParams{ BaseParams: pages.BaseParamsFromContext(r.Context()), Knots: knots, - Repos: []pages.RepoImportParams{ - { - SourceKind: pages.RepoImportSourceGitHub, - CloneUrl: "https://github.com/boltlessengineer/rest.nvim", - Name: "rest.nvim", - Description: "A very fast, powerful, extensible and asynchronous Neovim HTTP client written in Lua.", - Website: "https://tangled.org", - Topics: []string{"lua", "neovim", "curl", "http-client", "nvim", "neovim-plugin", "rest-client"}, - Selected: true, - }, - { - SourceKind: pages.RepoImportSourceGitHub, - CloneUrl: "https://github.com/boltlessengineer/dot", - Name: "super-long-repo-name-fddasfsafdsfasdfaasdfasdfasfasdfasfdasdfasdfsadfsadfasdfaasdfasfasdfdsafd00000s", - Description: "dotfiles", - Website: "https://tangled.org", - Topics: []string{}, - Selected: true, - }, - }, }); err != nil { s.logger.Error("failed to render", "err", err) } @@ -117,11 +97,18 @@ type githubUserRepo struct { } func (s *AccountMigration) listGitHubRepos(w http.ResponseWriter, r *http.Request) { + var notice string + var params pages.AccountMigrateRepoListParams + defer func() { + s.pages.Notice(w, "listghrepos-error", notice) + s.pages.AccountMigrateRepoListFragment(w, params) + }() + user := s.oauth.GetMultiAccountUser(r) username := strings.TrimSpace(r.FormValue("username")) if username == "" { - s.pages.Notice(w, "migrate-error", "GitHub username is required.") + notice = "GitHub username is required." return } @@ -132,28 +119,28 @@ func (s *AccountMigration) listGitHubRepos(w http.ResponseWriter, r *http.Reques endpoint := fmt.Sprintf("https://api.github.com/users/%s/repos?%s", url.PathEscape(username), query.Encode()) req, err := http.NewRequestWithContext(r.Context(), http.MethodGet, endpoint, nil) if err != nil { - s.pages.Notice(w, "migrate-error", "Failed to build GitHub request.") + notice = "Failed to build GitHub request." return } req.Header.Set("Accept", "application/vnd.github+json") resp, err := http.DefaultClient.Do(req) if err != nil { - s.logger.Error("github list repos failed", "username", username, "err", err) - s.pages.Notice(w, "migrate-error", "Failed to reach GitHub. Try again.") + s.logger.Error("github list repos request failed", "username", username, "err", err) + notice = "Failed to reach GitHub. Try again." return } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - s.pages.Notice(w, "migrate-error", fmt.Sprintf("GitHub returned %d. Check the username.", resp.StatusCode)) + notice = fmt.Sprintf("GitHub returned %d. Check the username.", resp.StatusCode) return } var githubRepos []githubUserRepo if err := json.NewDecoder(resp.Body).Decode(&githubRepos); err != nil { s.logger.Error("decode github response failed", "err", err) - s.pages.Notice(w, "migrate-error", "Failed to parse GitHub response.") + notice = "Failed to parse GitHub response." return } @@ -197,39 +184,43 @@ func (s *AccountMigration) listGitHubRepos(w http.ResponseWriter, r *http.Reques return b.PushedAt.Compare(a.PushedAt) }) - if err := s.pages.AccountMigrateRepoListFragment(w, pages.AccountMigrateRepoListParams{ + params = pages.AccountMigrateRepoListParams{ Repos: importRepos, Knots: knots, - }); err != nil { - s.logger.Error("render repo-list fragment failed", "err", err) } + // render is deferred } func (s *AccountMigration) startMigration(w http.ResponseWriter, r *http.Request) { + var notice string + defer func() { + s.pages.Notice(w, "migration-error", notice) + }() + user := s.oauth.GetMultiAccountUser(r) if err := r.ParseForm(); err != nil { - s.pages.Notice(w, "migrate-error", "Invalid form submission.") + notice = "Invalid form submission." return } knots, err := s.enforcer.GetKnotsForUser(user.Did) if err != nil { s.logger.Error("knots lookup failed", "did", user.Did, "err", err) - s.pages.Notice(w, "migrate-error", "Failed to look up your knots.") + notice = "Failed to look up your knots." return } allowed := sets.Collect(slices.Values(knots)) sessionId := s.oauth.GetSessIdFromCookie(r) if sessionId == "" { - s.pages.Notice(w, "migrate-error", "Session expired. Log in again.") + notice = "Session expired. Log in again." return } count, err := strconv.Atoi(r.FormValue("count")) if err != nil || count <= 0 { - s.pages.Notice(w, "migrate-error", "Invalid form submission.") + notice = "Invalid form submission." return } @@ -251,24 +242,32 @@ func (s *AccountMigration) startMigration(w http.ResponseWriter, r *http.Request website := strings.TrimSpace(r.FormValue(fmt.Sprintf("website_%d", i))) topics := r.FormValue(fmt.Sprintf("topics_%d", i)) - if cloneUrl == "" || knot == "" || name == "" { - s.pages.Notice(w, "migrate-error", "Each selected row needs a name, clone URL, and knot.") + if cloneUrl == "" { + notice = fmt.Sprintf("Row %d: clone URL is missing.", i+1) + return + } + if knot == "" { + notice = fmt.Sprintf("Row %d: knot is missing.", i+1) + return + } + if name == "" { + notice = fmt.Sprintf("Row %d: name is missing.", i+1) return } if err := models.ValidateRepoName(name); err != nil { - s.pages.Notice(w, "migrate-error", fmt.Sprintf("Row %d: %s", i+1, err.Error())) + notice = fmt.Sprintf("Row %d: %s", i+1, err.Error()) return } if len([]rune(desc)) > 140 { - s.pages.Notice(w, "migrate-error", fmt.Sprintf("Row %d: description must be 140 characters or fewer.", i+1)) + notice = fmt.Sprintf("Row %d: description must be 140 characters or fewer.", i+1) return } if !allowed.Contains(knot) { - s.pages.Notice(w, "migrate-error", fmt.Sprintf("You are not a member of knot %q.", knot)) + notice = fmt.Sprintf("Row %d: You are not a member of knot %q.", i+1, knot) return } if seen.Contains(name) { - s.pages.Notice(w, "migrate-error", fmt.Sprintf("Duplicate repository name %q in selection.", name)) + notice = fmt.Sprintf("Row %d: Duplicate repository name %q in selection.", i+1, name) return } seen.Insert(name) @@ -300,7 +299,7 @@ func (s *AccountMigration) startMigration(w http.ResponseWriter, r *http.Request } if len(rows) == 0 { - s.pages.Notice(w, "migrate-error", "Pick at least one repo.") + notice = "Pick at least one repo." return } @@ -308,12 +307,11 @@ func (s *AccountMigration) startMigration(w http.ResponseWriter, r *http.Request if err := db.InsertGitRepoMigrations(r.Context(), s.db, rows); err != nil { s.logger.Error("insert migrations failed", "err", err) - s.pages.Notice(w, "migrate-error", "Failed to enqueue migrations.") + notice = "Failed to enqueue migrations." return } - w.Header().Set("HX-Redirect", "/settings/migration") - http.Redirect(w, r, "/settings/migration", http.StatusSeeOther) + s.pages.HxRedirect(w, "/settings/migration") } func (s *AccountMigration) progressRows(w http.ResponseWriter, r *http.Request) { diff --git a/appview/pages/pages.go b/appview/pages/pages.go index 8a0fd5ac..fba30fc0 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -2058,7 +2058,6 @@ func (p *Pages) AccountMigrate(w io.Writer, params AccountMigrateParams) error { type AccountMigrateFromGitHubParams struct { BaseParams Knots []string - Repos []RepoImportParams } type RepoImportSource string @@ -2092,7 +2091,7 @@ type AccountMigrateRepoListParams struct { } func (p *Pages) AccountMigrateRepoListFragment(w io.Writer, params AccountMigrateRepoListParams) error { - return p.executePlain("account/migrate/fragments/repoList", w, params) + return p.executePlain("account/migrate/fragments/step2", w, params) } type AccountMigrateProgressParams struct { diff --git a/appview/pages/templates/account/migrate/fragments/repoList.html b/appview/pages/templates/account/migrate/fragments/repoList.html deleted file mode 100644 index efe2a17c..00000000 --- a/appview/pages/templates/account/migrate/fragments/repoList.html +++ /dev/null @@ -1,93 +0,0 @@ -{{ define "account/migrate/fragments/repoList" }} -{{ if not .Repos }} -

No importable repositories found.

-{{ else }} -
- - -
- {{ range $i, $repo := .Repos }} -
- -
- - {{ if gt .Stars 0 }} -
- {{ i "star" "size-3 fill-current" }} - {{ scaleFmt .Stars }} -
- {{ end }} -
- -
- -
- {{ i "chevron-right" "size-4 group-open:hidden" }} - {{ i "chevron-down" "size-4 hidden group-open:block" }} -
-
-
-
- - - - - - - - - -
- Select a knot to migrate into -
- {{ range $.Knots }} - - {{ else }} -

No knots available.

- {{ end }} -
-
-
-
- {{ end }} -
- -
- -
-
-{{ end }} -{{ end }} diff --git a/appview/pages/templates/account/migrate/fragments/step2.html b/appview/pages/templates/account/migrate/fragments/step2.html new file mode 100644 index 00000000..cc406a0a --- /dev/null +++ b/appview/pages/templates/account/migrate/fragments/step2.html @@ -0,0 +1,133 @@ +{{ define "account/migrate/fragments/step2" }} +{{- $isPreview := eq .Repos nil -}} +
+
+ {{ template "account/migrate/fragments/stepIndicator" 2 }} +
+ + +
+
+

Choose & Configure Repositories

+
+ +
+
+ {{ if $isPreview }} +

No repositories yet, connect your account first.

+ {{ else if gt (len .Repos) 0 }} +
+ + +
+ {{ range $i, $repo := .Repos }} + {{ template "repo-row" (list $i $repo $) }} + {{ end }} +
+ +
+ + +
+
+ {{ else }} +

No importable repositories found.

+ {{ end }} +
+
+{{ end }} + +{{ define "repo-row" }} + {{- $i := index . 0 }} + {{- $repo := index . 1 }} + {{- $root := index . 2 }} +
+ +
+ + {{ if gt $repo.Stars 0 }} +
+ {{ i "star" "size-3 fill-current" }} + {{ scaleFmt $repo.Stars }} +
+ {{ end }} +
+ +
+ +
+ {{ i "chevron-right" "size-4 group-open:hidden" }} + {{ i "chevron-down" "size-4 hidden group-open:block" }} +
+
+
+
+ + + + + + + + + +
+ Select a knot to migrate into +
+ {{ range $root.Knots }} + + {{ else }} +

No knots available.

+ {{ end }} +
+
+
+
+{{ end }} diff --git a/appview/pages/templates/account/migrate/fragments/stepIndicator.html b/appview/pages/templates/account/migrate/fragments/stepIndicator.html new file mode 100644 index 00000000..5ace66a1 --- /dev/null +++ b/appview/pages/templates/account/migrate/fragments/stepIndicator.html @@ -0,0 +1,5 @@ +{{ define "account/migrate/fragments/stepIndicator" }} +
+ {{.}} +
+{{ end }} diff --git a/appview/pages/templates/account/migrate/fromGitHub.html b/appview/pages/templates/account/migrate/fromGitHub.html index 93815b17..a0a9894e 100644 --- a/appview/pages/templates/account/migrate/fromGitHub.html +++ b/appview/pages/templates/account/migrate/fromGitHub.html @@ -14,34 +14,36 @@

Migration covers your repos and commit history.
Issues and PRs aren't part of the import yet.

- {{ template "step-1" . }} - {{ template "step-2" . }} - - - {{ if not .Knots }}

You aren't a member of any knot yet. Join or register a knot first.

+ {{ else }} +
+ {{ template "step-1" . }} + {{ template "step-2" . }} +
{{ end }}
{{ end }} {{ define "step-1" }} -
+
- {{ template "numberCircle" 1 }} + {{ template "account/migrate/fragments/stepIndicator" 1 }}
-

Connect Your Account

+
+ +
{{ end }} {{ define "step-2" }} -
-
- {{ template "numberCircle" 2 }} -
- - -
-
-

Choose & Configure Repositories

-
- -
-
-
- - - {{ template "account/migrate/fragments/repoList" . }} -
-
-
-{{ end }} - -{{ define "numberCircle" }} -
- {{.}} -
+ {{ template "account/migrate/fragments/step2" }} {{ end }} -- 2.51.2