feat(backend): hide repository from ui

Ayman Bagabas created

Change summary

server/backend/repo.go          |  7 ++++++
server/backend/sqlite/repo.go   | 14 +++++++++++++
server/backend/sqlite/sql.go    |  1 
server/backend/sqlite/sqlite.go | 30 ++++++++++++++++++++++++++-
server/cmd/hidden.go            | 37 +++++++++++++++++++++++++++++++++++
server/cmd/repo.go              |  1 
ui/pages/selection/selection.go |  3 ++
7 files changed, 91 insertions(+), 2 deletions(-)

Detailed changes

server/backend/repo.go 🔗

@@ -10,6 +10,7 @@ type RepositoryOptions struct {
 	Description string
 	ProjectName string
 	Mirror      bool
+	Hidden      bool
 }
 
 // RepositoryStore is an interface for managing repositories.
@@ -46,6 +47,10 @@ type RepositoryMetadata interface {
 	SetPrivate(repo string, private bool) error
 	// IsMirror returns whether the repository is a mirror.
 	IsMirror(repo string) bool
+	// IsHidden returns whether the repository is hidden.
+	IsHidden(repo string) bool
+	// SetHidden sets whether the repository is hidden.
+	SetHidden(repo string, hidden bool) error
 }
 
 // RepositoryAccess is an interface for managing repository access.
@@ -71,6 +76,8 @@ type Repository interface {
 	IsPrivate() bool
 	// IsMirror returns whether the repository is a mirror.
 	IsMirror() bool
+	// IsHidden returns whether the repository is hidden.
+	IsHidden() bool
 	// Open returns the underlying git.Repository.
 	Open() (*git.Repository, error)
 }

server/backend/sqlite/repo.go 🔗

@@ -86,3 +86,17 @@ func (r *Repo) ProjectName() string {
 
 	return name
 }
+
+// IsHidden returns whether the repository is hidden.
+//
+// It implements backend.Repository.
+func (r *Repo) IsHidden() bool {
+	var hidden bool
+	if err := wrapTx(r.db, context.Background(), func(tx *sqlx.Tx) error {
+		return tx.Get(&hidden, "SELECT hidden FROM repo WHERE name = ?", r.name)
+	}); err != nil {
+		return false
+	}
+
+	return hidden
+}

server/backend/sqlite/sql.go 🔗

@@ -37,6 +37,7 @@ var (
 		description TEXT NOT NULL,
 		private BOOLEAN NOT NULL,
 		mirror BOOLEAN NOT NULL,
+		hidden BOOLEAN NOT NULL,
 		created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
 		updated_at DATETIME NOT NULL
 	);`

server/backend/sqlite/sqlite.go 🔗

@@ -133,9 +133,9 @@ func (d *SqliteBackend) CreateRepository(name string, opts backend.RepositoryOpt
 	}
 
 	if err := wrapTx(d.db, context.Background(), func(tx *sqlx.Tx) error {
-		_, err := tx.Exec(`INSERT INTO repo (name, project_name, description, private, mirror, updated_at)
+		_, err := tx.Exec(`INSERT INTO repo (name, project_name, description, private, mirror, hidden, updated_at)
 			VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP);`,
-			name, opts.ProjectName, opts.Description, opts.Private, opts.Mirror)
+			name, opts.ProjectName, opts.Description, opts.Private, opts.Mirror, opts.Hidden)
 		return err
 	}); err != nil {
 		logger.Debug("failed to create repository in database", "err", err)
@@ -324,6 +324,32 @@ func (d *SqliteBackend) IsPrivate(repo string) bool {
 	return private
 }
 
+// IsHidden returns true if the repository is hidden.
+//
+// It implements backend.Backend.
+func (d *SqliteBackend) IsHidden(repo string) bool {
+	repo = utils.SanitizeRepo(repo)
+	var hidden bool
+	if err := wrapTx(d.db, context.Background(), func(tx *sqlx.Tx) error {
+		return tx.Get(&hidden, "SELECT hidden FROM repo WHERE name = ?", repo)
+	}); err != nil {
+		return false
+	}
+
+	return hidden
+}
+
+// SetHidden sets the hidden flag of a repository.
+//
+// It implements backend.Backend.
+func (d *SqliteBackend) SetHidden(repo string, hidden bool) error {
+	repo = utils.SanitizeRepo(repo)
+	return wrapDbErr(wrapTx(d.db, context.Background(), func(tx *sqlx.Tx) error {
+		_, err := tx.Exec("UPDATE repo SET hidden = ?, updated_at = CURRENT_TIMESTAMP WHERE name = ?;", hidden, repo)
+		return err
+	}))
+}
+
 // ProjectName returns the project name of a repository.
 //
 // It implements backend.Backend.

server/cmd/hidden.go 🔗

@@ -0,0 +1,37 @@
+package cmd
+
+import "github.com/spf13/cobra"
+
+func hiddenCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "hidden REPOSITORY [TRUE|FALSE]",
+		Short: "Hide or unhide a repository",
+		Args:  cobra.MinimumNArgs(1),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			cfg, _ := fromContext(cmd)
+			repo := args[0]
+			switch len(args) {
+			case 1:
+				if err := checkIfReadable(cmd, args); err != nil {
+					return err
+				}
+
+				hidden := cfg.Backend.IsHidden(repo)
+				cmd.Println(hidden)
+			case 2:
+				if err := checkIfCollab(cmd, args); err != nil {
+					return err
+				}
+
+				hidden := args[1] == "true"
+				if err := cfg.Backend.SetHidden(repo, hidden); err != nil {
+					return err
+				}
+			}
+
+			return nil
+		},
+	}
+
+	return cmd
+}

server/cmd/repo.go 🔗

@@ -16,6 +16,7 @@ func repoCommand() *cobra.Command {
 		createCommand(),
 		deleteCommand(),
 		descriptionCommand(),
+		hiddenCommand(),
 		importCommand(),
 		listCommand(),
 		privateCommand(),

ui/pages/selection/selection.go 🔗

@@ -198,6 +198,9 @@ func (s *Selection) Init() tea.Cmd {
 	}
 	sortedItems := make(Items, 0)
 	for _, r := range repos {
+		if r.IsHidden() {
+			continue
+		}
 		al := cfg.Backend.AccessLevelByPublicKey(r.Name(), pk)
 		if al >= backend.ReadOnlyAccess {
 			item, err := NewItem(r, cfg)