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 }} - -{{ 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 -}} +No repositories yet, connect your account first.
+ {{ else if gt (len .Repos) 0 }} + + {{ else }} +No importable repositories found.
+ {{ end }} +Migration covers your repos and commit history.
Issues and PRs aren't part of the import yet.
You aren't a member of any knot yet. Join or register a knot first.
+ {{ else }} +