Repository: goharbor/harbor-cli
Pull request #445: Adds harbor context command
Author: login: Darkhood148
Labels: name: enhancement
description: New feature or request
Created: 2025-04-25T07:29:26Z | Merged: 2025-05-20T13:14:44Z

## Related Issue:
https://github.com/goharbor/harbor-cli/issues/417

## Description:
Adds harbor context command to manage and switch context by reading/writing from `confg.yaml`


Diff:
diff --git a/cmd/harbor/root/cmd.go b/cmd/harbor/root/cmd.go
index b7c0de913..483b9ff3f 100644
--- a/cmd/harbor/root/cmd.go
+++ b/cmd/harbor/root/cmd.go
@@ -18,8 +18,9 @@ import (
 	"io"
 	"time"
 
+	"github.com/goharbor/harbor-cli/cmd/harbor/root/context"
+
 	"github.com/goharbor/harbor-cli/cmd/harbor/root/artifact"
-	"github.com/goharbor/harbor-cli/cmd/harbor/root/config"
 	"github.com/goharbor/harbor-cli/cmd/harbor/root/cve"
 	"github.com/goharbor/harbor-cli/cmd/harbor/root/instance"
 	"github.com/goharbor/harbor-cli/cmd/harbor/root/labels"
@@ -145,7 +146,7 @@ harbor help
 	root.AddCommand(cmd)
 
 	// System
-	cmd = config.Config()
+	cmd = context.Context()
 	cmd.GroupID = "system"
 	root.AddCommand(cmd)
 
diff --git a/cmd/harbor/root/config/cmd.go b/cmd/harbor/root/context/cmd.go
similarity index 57%
rename from cmd/harbor/root/config/cmd.go
rename to cmd/harbor/root/context/cmd.go
index d4b008e27..d0df7f31a 100644
--- a/cmd/harbor/root/config/cmd.go
+++ b/cmd/harbor/root/context/cmd.go
@@ -11,22 +11,25 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-package config
+package context
 
 import "github.com/spf13/cobra"
 
-func Config() *cobra.Command {
+func Context() *cobra.Command {
 	cmd := &cobra.Command{
-		Use:   "config",
-		Short: "Manage the config of the Harbor CLI",
-		Long: `The config command allows you to manage configurations of the Harbor CLI.
-				You can add, get, or delete specific config item, as well as list all config items of the Harbor Cli`,
+		Use:     "context",
+		Short:   "Manage locally available contexts",
+		Example: "harbor context list",
+		Long: `The context command allows you to manage configuration items of the Harbor CLI.
+				You can add, get, or delete specific configuration items, as well as list all configuration items of the Harbor CLI.`,
 	}
+
 	cmd.AddCommand(
-		ListConfigCommand(),
-		GetConfigItemCommand(),
-		UpdateConfigItemCommand(),
-		DeleteConfigItemCommand(),
+		ListContextCommand(),
+		GetContextItemCommand(),
+		UpdateContextItemCommand(),
+		DeleteContextItemCommand(),
+		SwitchContextCommand(),
 	)
 
 	return cmd
diff --git a/cmd/harbor/root/config/delete.go b/cmd/harbor/root/context/delete.go
similarity index 95%
rename from cmd/harbor/root/config/delete.go
rename to cmd/harbor/root/context/delete.go
index c3211da6c..a04a9b75a 100644
--- a/cmd/harbor/root/config/delete.go
+++ b/cmd/harbor/root/context/delete.go
@@ -11,7 +11,7 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-package config
+package context
 
 import (
 	"fmt"
@@ -25,9 +25,9 @@ import (
 
 var deleteCurrent bool
 
-// DeleteConfigItemCommand creates the 'harbor config delete' subcommand,
-// allowing you to do: harbor config delete <item>
-func DeleteConfigItemCommand() *cobra.Command {
+// DeleteContextItemCommand creates the 'harbor context delete' subcommand,
+// allowing you to do: harbor context delete <item>
+func DeleteContextItemCommand() *cobra.Command {
 	var credentialName string
 
 	cmd := &cobra.Command{
@@ -35,13 +35,13 @@ func DeleteConfigItemCommand() *cobra.Command {
 		Short: "Delete (clear) a specific config item",
 		Example: `
   # Clear the current credential's password
-  harbor config delete credentials.password
+  harbor context delete credentials.password
 
   # Clear a specific credential's password using --name
-  harbor config delete credentials.password --name admin@http://demo.goharbor.io
+  harbor context delete credentials.password --name admin@http://demo.goharbor.io
 
   # Clear the current credential
-  harbor config delete --current
+  harbor context delete --current
 `,
 		Long: `Clear the value of a specific CLI config item by setting it to its zero value.
 Case-insensitive field lookup, but uses the canonical (Go) field name internally.
diff --git a/cmd/harbor/root/config/get.go b/cmd/harbor/root/context/get.go
similarity index 98%
rename from cmd/harbor/root/config/get.go
rename to cmd/harbor/root/context/get.go
index c32935565..763e5da1b 100644
--- a/cmd/harbor/root/config/get.go
+++ b/cmd/harbor/root/context/get.go
@@ -11,7 +11,7 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-package config
+package context
 
 import (
 	"encoding/json"
@@ -26,7 +26,7 @@ import (
 )
 
 // GetConfigItemCommand creates the 'harbor config get' subcommand.
-func GetConfigItemCommand() *cobra.Command {
+func GetContextItemCommand() *cobra.Command {
 	var credentialName string
 
 	cmd := &cobra.Command{
@@ -34,7 +34,7 @@ func GetConfigItemCommand() *cobra.Command {
 		Short: "Get a specific config item",
 		Example: `
   # Get the current credential's username
-  harbor config get credentials.username
+  harbor context get credentials.username
 
   # Get a credential's username by specifying the credential name
   harbor config get credentials.username --name admin@http://demo.goharbor.io
diff --git a/cmd/harbor/root/config/list.go b/cmd/harbor/root/context/list.go
similarity index 63%
rename from cmd/harbor/root/config/list.go
rename to cmd/harbor/root/context/list.go
index 36b1b2d1b..24da31cec 100644
--- a/cmd/harbor/root/config/list.go
+++ b/cmd/harbor/root/context/list.go
@@ -11,29 +11,29 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-package config
+
+package context
 
 import (
 	"fmt"
 
+	"github.com/goharbor/harbor-cli/pkg/api"
 	"github.com/goharbor/harbor-cli/pkg/utils"
-	"github.com/sirupsen/logrus"
+	"github.com/goharbor/harbor-cli/pkg/views/context/list"
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
-	"gopkg.in/yaml.v3"
 )
 
-func ListConfigCommand() *cobra.Command {
+func ListContextCommand() *cobra.Command {
 	cmd := &cobra.Command{
 		Use:     "list",
-		Short:   "List config items",
-		Example: `  harbor config list`,
-		Long:    `Get information of all CLI config items`,
+		Short:   "List contexts",
+		Example: `  harbor context list`,
 		Args:    cobra.MaximumNArgs(0),
 		Run: func(cmd *cobra.Command, args []string) {
 			config, err := utils.GetCurrentHarborConfig()
 			if err != nil {
-				logrus.Errorf("Failed to get config: %v", err)
+				fmt.Println("failed to get config: ", utils.ParseHarborErrorMsg(err))
 				return
 			}
 
@@ -43,19 +43,19 @@ func ListConfigCommand() *cobra.Command {
 				// Use utils.PrintFormat if available
 				err = utils.PrintFormat(config, formatFlag)
 				if err != nil {
-					logrus.Errorf("Failed to print config: %v", err)
+					fmt.Println("Failed to print config: ", utils.ParseHarborErrorMsg(err))
+					return
 				}
 			} else {
-				// Default to YAML format
-				data, err := yaml.Marshal(config)
-				if err != nil {
-					logrus.Errorf("Failed to marshal config to YAML: %v", err)
-					return
+				var cxlist []api.ContextListView
+				for _, cred := range config.Credentials {
+					cx := api.ContextListView{Name: cred.Name, Username: cred.Username, Server: cred.ServerAddress}
+					cxlist = append(cxlist, cx)
 				}
-				fmt.Println(string(data))
+				currentCredential := config.CurrentCredentialName
+				list.ListContexts(cxlist, currentCredential)
 			}
 		},
 	}
-
 	return cmd
 }
diff --git a/cmd/harbor/root/context/switch.go b/cmd/harbor/root/context/switch.go
new file mode 100644
index 000000000..0e9c0f5b8
--- /dev/null
+++ b/cmd/harbor/root/context/switch.go
@@ -0,0 +1,72 @@
+// Copyright Project Harbor Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package context
+
+import (
+	"fmt"
+
+	"github.com/goharbor/harbor-cli/pkg/prompt"
+	"github.com/goharbor/harbor-cli/pkg/utils"
+	"github.com/spf13/cobra"
+)
+
+func SwitchContextCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:     "switch <none|context>",
+		Short:   "Switch to a new context",
+		Example: `harbor context switch harbor-cli@https-demo-goharbor-io`,
+		Args:    cobra.MaximumNArgs(1),
+		Run: func(cmd *cobra.Command, args []string) {
+			config, err := utils.GetCurrentHarborConfig()
+			if err != nil {
+				fmt.Println("failed to get config: ", utils.ParseHarborErrorMsg(err))
+				return
+			}
+
+			if len(args) == 1 {
+				newActiveCredential := args[0]
+				found := false
+
+				for _, cred := range config.Credentials {
+					if cred.Name == newActiveCredential {
+						found = true
+						break
+					}
+				}
+				if found {
+					config.CurrentCredentialName = newActiveCredential
+					if err := utils.UpdateConfigFile(config); err != nil {
+						fmt.Println("failed to update config: ", utils.ParseHarborErrorMsg(err))
+					}
+				} else {
+					fmt.Println("context doesn't exist")
+				}
+			} else {
+				res, err := prompt.GetActiveContextFromUser()
+				if err != nil {
+					fmt.Println("failed to get active context: ", utils.ParseHarborErrorMsg(err))
+					return
+				}
+				if res != "" {
+					config.CurrentCredentialName = res
+					if err := utils.UpdateConfigFile(config); err != nil {
+						fmt.Println("failed to update config: ", utils.ParseHarborErrorMsg(err))
+					}
+				}
+			}
+		},
+	}
+	return cmd
+}
diff --git a/cmd/harbor/root/config/update.go b/cmd/harbor/root/context/update.go
similarity index 98%
rename from cmd/harbor/root/config/update.go
rename to cmd/harbor/root/context/update.go
index bac1b4360..9619cdc21 100644
--- a/cmd/harbor/root/config/update.go
+++ b/cmd/harbor/root/context/update.go
@@ -11,7 +11,7 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-package config
+package context
 
 import (
 	"fmt"
@@ -26,7 +26,7 @@ import (
 
 // UpdateConfigItemCommand creates the 'harbor config update' subcommand,
 // allowing you to do: harbor config update <item> <value>.
-func UpdateConfigItemCommand() *cobra.Command {
+func UpdateContextItemCommand() *cobra.Command {
 	var credentialName string
 
 	cmd := &cobra.Command{
@@ -34,7 +34,7 @@ func UpdateConfigItemCommand() *cobra.Command {
 		Short: "Set/update a specific config item",
 		Example: `
   # Set/update the current credential's password
-  harbor config update credentials.password myNewSecret
+  harbor context update credentials.password myNewSecret
 
   # Set/update a credential's password by specifying the credential name
   harbor config update credentials.password myNewSecret --name admin@http://demo.goharbor.io
diff --git a/doc/cli-docs/harbor-config.md b/doc/cli-docs/harbor-config.md
deleted file mode 100644
index a1aafabf0..000000000
--- a/doc/cli-docs/harbor-config.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: harbor config
-weight: 30
----
-## harbor config
-
-### Description
-
-##### Manage the config of the Harbor CLI
-
-### Synopsis
-
-The config command allows you to manage configurations of the Harbor CLI.
-				You can add, get, or delete specific config item, as well as list all config items of the Harbor Cli
-
-### Options
-
-```sh
-  -h, --help   help for config
-```
-
-### Options inherited from parent commands
-
-```sh
-  -c, --config string          config file (default is $HOME/.config/harbor-cli/config.yaml)
-  -o, --output-format string   Output format. One of: json|yaml
-  -v, --verbose                verbose output
-```
-
-### SEE ALSO
-
-* [harbor](harbor.md)	 - Official Harbor CLI
-* [harbor config delete](harbor-config-delete.md)	 - Delete (clear) a specific config item
-* [harbor config get](harbor-config-get.md)	 - Get a specific config item
-* [harbor config list](harbor-config-list.md)	 - List config items
-* [harbor config update](harbor-config-update.md)	 - Set/update a specific config item
-
diff --git a/doc/cli-docs/harbor-config-delete.md b/doc/cli-docs/harbor-context-delete.md
similarity index 75%
rename from doc/cli-docs/harbor-config-delete.md
rename to doc/cli-docs/harbor-context-delete.md
index 72979b49f..57e1fafcb 100644
--- a/doc/cli-docs/harbor-config-delete.md
+++ b/doc/cli-docs/harbor-context-delete.md
@@ -1,8 +1,8 @@
 ---
-title: harbor config delete
+title: harbor context delete
 weight: 85
 ---
-## harbor config delete
+## harbor context delete
 
 ### Description
 
@@ -15,7 +15,7 @@ Case-insensitive field lookup, but uses the canonical (Go) field name internally
 If you specify --name, that credential (rather than the "current" one) will be used.
 
 ```sh
-harbor config delete <item> [flags]
+harbor context delete <item> [flags]
 ```
 
 ### Examples
@@ -23,13 +23,13 @@ harbor config delete <item> [flags]
 ```sh
 
   # Clear the current credential's password
-  harbor config delete credentials.password
+  harbor context delete credentials.password
 
   # Clear a specific credential's password using --name
-  harbor config delete credentials.password --name admin@http://demo.goharbor.io
+  harbor context delete credentials.password --name admin@http://demo.goharbor.io
 
   # Clear the current credential
-  harbor config delete --current
+  harbor context delete --current
 
 ```
 
@@ -51,5 +51,5 @@ harbor config delete <item> [flags]
 
 ### SEE ALSO
 
-* [harbor config](harbor-config.md)	 - Manage the config of the Harbor CLI
+* [harbor context](harbor-context.md)	 - Manage locally available contexts
 
diff --git a/doc/cli-docs/harbor-config-get.md b/doc/cli-docs/harbor-context-get.md
similarity index 81%
rename from doc/cli-docs/harbor-config-get.md
rename to doc/cli-docs/harbor-context-get.md
index dc0b6f81b..ce385dd69 100644
--- a/doc/cli-docs/harbor-config-get.md
+++ b/doc/cli-docs/harbor-context-get.md
@@ -1,8 +1,8 @@
 ---
-title: harbor config get
+title: harbor context get
 weight: 85
 ---
-## harbor config get
+## harbor context get
 
 ### Description
 
@@ -14,7 +14,7 @@ Get the value of a specific CLI config item.
 If you specify --name, that credential (rather than the "current" one) will be used.
 
 ```sh
-harbor config get <item> [flags]
+harbor context get <item> [flags]
 ```
 
 ### Examples
@@ -22,7 +22,7 @@ harbor config get <item> [flags]
 ```sh
 
   # Get the current credential's username
-  harbor config get credentials.username
+  harbor context get credentials.username
 
   # Get a credential's username by specifying the credential name
   harbor config get credentials.username --name admin@http://demo.goharbor.io
@@ -46,5 +46,5 @@ harbor config get <item> [flags]
 
 ### SEE ALSO
 
-* [harbor config](harbor-config.md)	 - Manage the config of the Harbor CLI
+* [harbor context](harbor-context.md)	 - Manage locally available contexts
 
diff --git a/doc/cli-docs/harbor-config-list.md b/doc/cli-docs/harbor-context-list.md
similarity index 61%
rename from doc/cli-docs/harbor-config-list.md
rename to doc/cli-docs/harbor-context-list.md
index cedb014d9..4103baca0 100644
--- a/doc/cli-docs/harbor-config-list.md
+++ b/doc/cli-docs/harbor-context-list.md
@@ -1,25 +1,21 @@
 ---
-title: harbor config list
+title: harbor context list
 weight: 25
 ---
-## harbor config list
+## harbor context list
 
 ### Description
 
-##### List config items
-
-### Synopsis
-
-Get information of all CLI config items
+##### List contexts
 
 ```sh
-harbor config list [flags]
+harbor context list [flags]
 ```
 
 ### Examples
 
 ```sh
-  harbor config list
+  harbor context list
 ```
 
 ### Options
@@ -38,5 +34,5 @@ harbor config list [flags]
 
 ### SEE ALSO
 
-* [harbor config](harbor-config.md)	 - Manage the config of the Harbor CLI
+* [harbor context](harbor-context.md)	 - Manage locally available contexts
 
diff --git a/doc/cli-docs/harbor-config-set.md b/doc/cli-docs/harbor-context-set.md
similarity index 100%
rename from doc/cli-docs/harbor-config-set.md
rename to doc/cli-docs/harbor-context-set.md
diff --git a/doc/cli-docs/harbor-context-switch.md b/doc/cli-docs/harbor-context-switch.md
new file mode 100644
index 000000000..14e06a00c
--- /dev/null
+++ b/doc/cli-docs/harbor-context-switch.md
@@ -0,0 +1,38 @@
+---
+title: harbor context switch
+weight: 50
+---
+## harbor context switch
+
+### Description
+
+##### Switch to a new context
+
+```sh
+harbor context switch <none|context> [flags]
+```
+
+### Examples
+
+```sh
+harbor context switch harbor-cli@https-demo-goharbor-io
+```
+
+### Options
+
+```sh
+  -h, --help   help for switch
+```
+
+### Options inherited from parent commands
+
+```sh
+  -c, --config string          config file (default is $HOME/.config/harbor-cli/config.yaml)
+  -o, --output-format string   Output format. One of: json|yaml
+  -v, --verbose                verbose output
+```
+
+### SEE ALSO
+
+* [harbor context](harbor-context.md)	 - Manage locally available contexts
+
diff --git a/doc/cli-docs/harbor-config-update.md b/doc/cli-docs/harbor-context-update.md
similarity index 81%
rename from doc/cli-docs/harbor-config-update.md
rename to doc/cli-docs/harbor-context-update.md
index e7cb944bb..8cdcafc6c 100644
--- a/doc/cli-docs/harbor-config-update.md
+++ b/doc/cli-docs/harbor-context-update.md
@@ -1,8 +1,8 @@
 ---
-title: harbor config update
+title: harbor context update
 weight: 10
 ---
-## harbor config update
+## harbor context update
 
 ### Description
 
@@ -15,7 +15,7 @@ Case-insensitive field lookup, but uses the canonical (Go) field name internally
 If you specify --name, that credential (rather than the "current" one) will be updated.
 
 ```sh
-harbor config update <item> <value> [flags]
+harbor context update <item> <value> [flags]
 ```
 
 ### Examples
@@ -23,7 +23,7 @@ harbor config update <item> <value> [flags]
 ```sh
 
   # Set/update the current credential's password
-  harbor config update credentials.password myNewSecret
+  harbor context update credentials.password myNewSecret
 
   # Set/update a credential's password by specifying the credential name
   harbor config update credentials.password myNewSecret --name admin@http://demo.goharbor.io
@@ -47,5 +47,5 @@ harbor config update <item> <value> [flags]
 
 ### SEE ALSO
 
-* [harbor config](harbor-config.md)	 - Manage the config of the Harbor CLI
+* [harbor context](harbor-context.md)	 - Manage locally available contexts
 
diff --git a/doc/cli-docs/harbor-context.md b/doc/cli-docs/harbor-context.md
new file mode 100644
index 000000000..1c782bafe
--- /dev/null
+++ b/doc/cli-docs/harbor-context.md
@@ -0,0 +1,44 @@
+---
+title: harbor context
+weight: 30
+---
+## harbor context
+
+### Description
+
+##### Manage locally available contexts
+
+### Synopsis
+
+The context command allows you to manage configuration items of the Harbor CLI.
+				You can add, get, or delete specific configuration items, as well as list all configuration items of the Harbor CLI.
+
+### Examples
+
+```sh
+harbor context list
+```
+
+### Options
+
+```sh
+  -h, --help   help for context
+```
+
+### Options inherited from parent commands
+
+```sh
+  -c, --config string          config file (default is $HOME/.config/harbor-cli/config.yaml)
+  -o, --output-format string   Output format. One of: json|yaml
+  -v, --verbose                verbose output
+```
+
+### SEE ALSO
+
+* [harbor](harbor.md)	 - Official Harbor CLI
+* [harbor context delete](harbor-context-delete.md)	 - Delete (clear) a specific config item
+* [harbor context get](harbor-context-get.md)	 - Get a specific config item
+* [harbor context list](harbor-context-list.md)	 - List contexts
+* [harbor context switch](harbor-context-switch.md)	 - Switch to a new context
+* [harbor context update](harbor-context-update.md)	 - Set/update a specific config item
+
diff --git a/doc/cli-docs/harbor.md b/doc/cli-docs/harbor.md
index e418003ef..8a998687f 100644
--- a/doc/cli-docs/harbor.md
+++ b/doc/cli-docs/harbor.md
@@ -36,7 +36,7 @@ harbor help
 ### SEE ALSO
 
 * [harbor artifact](harbor-artifact.md)	 - Manage artifacts
-* [harbor config](harbor-config.md)	 - Manage the config of the Harbor CLI
+* [harbor context](harbor-context.md)	 - Manage locally available contexts
 * [harbor cve-allowlist](harbor-cve-allowlist.md)	 - Manage system CVE allowlist
 * [harbor health](harbor-health.md)	 - Get the health status of Harbor components
 * [harbor info](harbor-info.md)	 - Display detailed Harbor system, statistics, and CLI environment information
diff --git a/doc/man-docs/man1/harbor-config-delete.1 b/doc/man-docs/man1/harbor-context-delete.1
similarity index 78%
rename from doc/man-docs/man1/harbor-config-delete.1
rename to doc/man-docs/man1/harbor-context-delete.1
index 029c924c3..f7ec959d4 100644
--- a/doc/man-docs/man1/harbor-config-delete.1
+++ b/doc/man-docs/man1/harbor-context-delete.1
@@ -2,11 +2,11 @@
 .TH "HARBOR" "1"  "Harbor Community" "Harbor User Manuals"
 
 .SH NAME
-harbor-config-delete - Delete (clear) a specific config item
+harbor-context-delete - Delete (clear) a specific config item
 
 
 .SH SYNOPSIS
-\fBharbor config delete  [flags]\fP
+\fBharbor context delete  [flags]\fP
 
 
 .SH DESCRIPTION
@@ -45,16 +45,16 @@ If you specify --name, that credential (rather than the "current" one) will be u
 .EX
 
   # Clear the current credential's password
-  harbor config delete credentials.password
+  harbor context delete credentials.password
 
   # Clear a specific credential's password using --name
-  harbor config delete credentials.password --name admin@http://demo.goharbor.io
+  harbor context delete credentials.password --name admin@http://demo.goharbor.io
 
   # Clear the current credential
-  harbor config delete --current
+  harbor context delete --current
 
 .EE
 
 
 .SH SEE ALSO
-\fBharbor-config(1)\fP
\ No newline at end of file
+\fBharbor-context(1)\fP
\ No newline at end of file
diff --git a/doc/man-docs/man1/harbor-config-get.1 b/doc/man-docs/man1/harbor-context-get.1
similarity index 85%
rename from doc/man-docs/man1/harbor-config-get.1
rename to doc/man-docs/man1/harbor-context-get.1
index ff0ced62f..d273db676 100644
--- a/doc/man-docs/man1/harbor-config-get.1
+++ b/doc/man-docs/man1/harbor-context-get.1
@@ -2,11 +2,11 @@
 .TH "HARBOR" "1"  "Harbor Community" "Harbor User Manuals"
 
 .SH NAME
-harbor-config-get - Get a specific config item
+harbor-context-get - Get a specific config item
 
 
 .SH SYNOPSIS
-\fBharbor config get  [flags]\fP
+\fBharbor context get  [flags]\fP
 
 
 .SH DESCRIPTION
@@ -40,7 +40,7 @@ If you specify --name, that credential (rather than the "current" one) will be u
 .EX
 
   # Get the current credential's username
-  harbor config get credentials.username
+  harbor context get credentials.username
 
   # Get a credential's username by specifying the credential name
   harbor config get credentials.username --name admin@http://demo.goharbor.io
@@ -49,4 +49,4 @@ If you specify --name, that credential (rather than the "current" one) will be u
 
 
 .SH SEE ALSO
-\fBharbor-config(1)\fP
\ No newline at end of file
+\fBharbor-context(1)\fP
\ No newline at end of file
diff --git a/doc/man-docs/man1/harbor-config-list.1 b/doc/man-docs/man1/harbor-context-list.1
similarity index 75%
rename from doc/man-docs/man1/harbor-config-list.1
rename to doc/man-docs/man1/harbor-context-list.1
index 51806a23a..926c0d4de 100644
--- a/doc/man-docs/man1/harbor-config-list.1
+++ b/doc/man-docs/man1/harbor-context-list.1
@@ -2,15 +2,15 @@
 .TH "HARBOR" "1"  "Harbor Community" "Harbor User Manuals"
 
 .SH NAME
-harbor-config-list - List config items
+harbor-context-list - List contexts
 
 
 .SH SYNOPSIS
-\fBharbor config list [flags]\fP
+\fBharbor context list [flags]\fP
 
 
 .SH DESCRIPTION
-Get information of all CLI config items
+List contexts
 
 
 .SH OPTIONS
@@ -33,9 +33,9 @@ Get information of all CLI config items
 
 .SH EXAMPLE
 .EX
-  harbor config list
+  harbor context list
 .EE
 
 
 .SH SEE ALSO
-\fBharbor-config(1)\fP
\ No newline at end of file
+\fBharbor-context(1)\fP
\ No newline at end of file
diff --git a/doc/man-docs/man1/harbor-config-set.1 b/doc/man-docs/man1/harbor-context-set.1
similarity index 100%
rename from doc/man-docs/man1/harbor-config-set.1
rename to doc/man-docs/man1/harbor-context-set.1
diff --git a/doc/man-docs/man1/harbor-config.1 b/doc/man-docs/man1/harbor-context-switch.1
similarity index 51%
rename from doc/man-docs/man1/harbor-config.1
rename to doc/man-docs/man1/harbor-context-switch.1
index 4a80b1133..5a3ca90ea 100644
--- a/doc/man-docs/man1/harbor-config.1
+++ b/doc/man-docs/man1/harbor-context-switch.1
@@ -2,21 +2,20 @@
 .TH "HARBOR" "1"  "Harbor Community" "Harbor User Manuals"
 
 .SH NAME
-harbor-config - Manage the config of the Harbor CLI
+harbor-context-switch - Switch to a new context
 
 
 .SH SYNOPSIS
-\fBharbor config [flags]\fP
+\fBharbor context switch  [flags]\fP
 
 
 .SH DESCRIPTION
-The config command allows you to manage configurations of the Harbor CLI.
-				You can add, get, or delete specific config item, as well as list all config items of the Harbor Cli
+Switch to a new context
 
 
 .SH OPTIONS
 \fB-h\fP, \fB--help\fP[=false]
-	help for config
+	help for switch
 
 
 .SH OPTIONS INHERITED FROM PARENT COMMANDS
@@ -32,5 +31,11 @@ The config command allows you to manage configurations of the Harbor CLI.
 	verbose output
 
 
+.SH EXAMPLE
+.EX
+harbor context switch harbor-cli@https-demo-goharbor-io
+.EE
+
+
 .SH SEE ALSO
-\fBharbor(1)\fP, \fBharbor-config-delete(1)\fP, \fBharbor-config-get(1)\fP, \fBharbor-config-list(1)\fP, \fBharbor-config-update(1)\fP
\ No newline at end of file
+\fBharbor-context(1)\fP
\ No newline at end of file
diff --git a/doc/man-docs/man1/harbor-config-update.1 b/doc/man-docs/man1/harbor-context-update.1
similarity index 85%
rename from doc/man-docs/man1/harbor-config-update.1
rename to doc/man-docs/man1/harbor-context-update.1
index 5cf7f138d..0ac041e5c 100644
--- a/doc/man-docs/man1/harbor-config-update.1
+++ b/doc/man-docs/man1/harbor-context-update.1
@@ -2,11 +2,11 @@
 .TH "HARBOR" "1"  "Harbor Community" "Harbor User Manuals"
 
 .SH NAME
-harbor-config-update - Set/update a specific config item
+harbor-context-update - Set/update a specific config item
 
 
 .SH SYNOPSIS
-\fBharbor config update   [flags]\fP
+\fBharbor context update   [flags]\fP
 
 
 .SH DESCRIPTION
@@ -41,7 +41,7 @@ If you specify --name, that credential (rather than the "current" one) will be u
 .EX
 
   # Set/update the current credential's password
-  harbor config update credentials.password myNewSecret
+  harbor context update credentials.password myNewSecret
 
   # Set/update a credential's password by specifying the credential name
   harbor config update credentials.password myNewSecret --name admin@http://demo.goharbor.io
@@ -50,4 +50,4 @@ If you specify --name, that credential (rather than the "current" one) will be u
 
 
 .SH SEE ALSO
-\fBharbor-config(1)\fP
\ No newline at end of file
+\fBharbor-context(1)\fP
\ No newline at end of file
diff --git a/doc/man-docs/man1/harbor-context.1 b/doc/man-docs/man1/harbor-context.1
new file mode 100644
index 000000000..4a670a3f6
--- /dev/null
+++ b/doc/man-docs/man1/harbor-context.1
@@ -0,0 +1,42 @@
+.nh
+.TH "HARBOR" "1"  "Harbor Community" "Harbor User Manuals"
+
+.SH NAME
+harbor-context - Manage locally available contexts
+
+
+.SH SYNOPSIS
+\fBharbor context [flags]\fP
+
+
+.SH DESCRIPTION
+The context command allows you to manage configuration items of the Harbor CLI.
+				You can add, get, or delete specific configuration items, as well as list all configuration items of the Harbor CLI.
+
+
+.SH OPTIONS
+\fB-h\fP, \fB--help\fP[=false]
+	help for context
+
+
+.SH OPTIONS INHERITED FROM PARENT COMMANDS
+\fB-c\fP, \fB--config\fP=""
+	config file (default is $HOME/.config/harbor-cli/config.yaml)
+
+.PP
+\fB-o\fP, \fB--output-format\fP=""
+	Output format. One of: json|yaml
+
+.PP
+\fB-v\fP, \fB--verbose\fP[=false]
+	verbose output
+
+
+.SH EXAMPLE
+.EX
+harbor context list
+.EE
+
+
+.SH SEE ALSO
+\fBharbor(1)\fP, \fBharbor-context-delete(1)\fP, \fBharbor-context-get(1)\fP, \fBharbor-context-list(1)\fP, \fBharbor-context-switch(1)\fP, \fBharbor-context-update(1)\fP
\ No newline at end of file
diff --git a/doc/man-docs/man1/harbor.1 b/doc/man-docs/man1/harbor.1
index ef3771ee0..33a130fef 100644
--- a/doc/man-docs/man1/harbor.1
+++ b/doc/man-docs/man1/harbor.1
@@ -43,4 +43,4 @@ harbor help
 
 
 .SH SEE ALSO
-\fBharbor-artifact(1)\fP, \fBharbor-config(1)\fP, \fBharbor-cve-allowlist(1)\fP, \fBharbor-health(1)\fP, \fBharbor-info(1)\fP, \fBharbor-instance(1)\fP, \fBharbor-label(1)\fP, \fBharbor-login(1)\fP, \fBharbor-project(1)\fP, \fBharbor-quota(1)\fP, \fBharbor-registry(1)\fP, \fBharbor-repo(1)\fP, \fBharbor-scanner(1)\fP, \fBharbor-schedule(1)\fP, \fBharbor-tag(1)\fP, \fBharbor-user(1)\fP, \fBharbor-version(1)\fP, \fBharbor-webhook(1)\fP
\ No newline at end of file
+\fBharbor-artifact(1)\fP, \fBharbor-context(1)\fP, \fBharbor-cve-allowlist(1)\fP, \fBharbor-health(1)\fP, \fBharbor-info(1)\fP, \fBharbor-instance(1)\fP, \fBharbor-label(1)\fP, \fBharbor-login(1)\fP, \fBharbor-project(1)\fP, \fBharbor-quota(1)\fP, \fBharbor-registry(1)\fP, \fBharbor-repo(1)\fP, \fBharbor-scanner(1)\fP, \fBharbor-schedule(1)\fP, \fBharbor-tag(1)\fP, \fBharbor-user(1)\fP, \fBharbor-version(1)\fP, \fBharbor-webhook(1)\fP
\ No newline at end of file
diff --git a/pkg/api/types.go b/pkg/api/types.go
index 78e128c8c..731b68698 100644
--- a/pkg/api/types.go
+++ b/pkg/api/types.go
@@ -34,6 +34,12 @@ type CreateRegView struct {
 	Insecure    bool
 }
 
+type ContextListView struct {
+	Name     string
+	Username string
+	Server   string
+}
+
 // Credential for Registry
 type RegistryCredential struct {
 	AccessKey    string `json:"access_key,omitempty"`
diff --git a/pkg/prompt/prompt.go b/pkg/prompt/prompt.go
index b9639b903..17eb238c3 100644
--- a/pkg/prompt/prompt.go
+++ b/pkg/prompt/prompt.go
@@ -17,6 +17,9 @@ import (
 	"errors"
 	"fmt"
 
+	"github.com/goharbor/harbor-cli/pkg/utils"
+	list "github.com/goharbor/harbor-cli/pkg/views/context/switch"
+
 	"github.com/goharbor/go-client/pkg/sdk/v2.0/models"
 	"github.com/goharbor/harbor-cli/pkg/api"
 	aview "github.com/goharbor/harbor-cli/pkg/views/artifact/select"
@@ -223,3 +226,22 @@ func GetQuotaIDFromUser() int64 {
 
 	return <-QuotaID
 }
+
+func GetActiveContextFromUser() (string, error) {
+	config, err := utils.GetCurrentHarborConfig()
+	if err != nil {
+		return "", err
+	}
+	var cxlist []api.ContextListView
+	for _, cred := range config.Credentials {
+		cx := api.ContextListView{Name: cred.Name, Username: cred.Username, Server: cred.ServerAddress}
+		cxlist = append(cxlist, cx)
+	}
+
+	res, err := list.ContextList(cxlist)
+	if err != nil {
+		return "", err
+	}
+
+	return res, nil
+}
diff --git a/pkg/views/base/tablelist/model.go b/pkg/views/base/tablelist/model.go
index 602eda80e..e07c2f46b 100644
--- a/pkg/views/base/tablelist/model.go
+++ b/pkg/views/base/tablelist/model.go
@@ -27,6 +27,7 @@ const (
 	WidthL   = 16
 	WidthXL  = 20
 	WidthXXL = 24
+	Width3XL = 30
 )
 
 type Model struct {
diff --git a/pkg/views/context/list/view.go b/pkg/views/context/list/view.go
new file mode 100644
index 000000000..2496489fe
--- /dev/null
+++ b/pkg/views/context/list/view.go
@@ -0,0 +1,70 @@
+// Copyright Project Harbor Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package list
+
+import (
+	"fmt"
+	"os"
+
+	"golang.org/x/term"
+
+	"github.com/charmbracelet/bubbles/table"
+	tea "github.com/charmbracelet/bubbletea"
+	"github.com/goharbor/harbor-cli/pkg/api"
+	"github.com/goharbor/harbor-cli/pkg/views/base/tablelist"
+)
+
+var columns = []table.Column{
+	{Title: "Name", Width: tablelist.Width3XL},
+	{Title: "Username", Width: tablelist.WidthL},
+	{Title: "Server Address", Width: tablelist.WidthXXL},
+}
+
+func ListContexts(contexts []api.ContextListView, currentCredential string) {
+	rows := selectActiveContext(contexts, currentCredential)
+
+	var opts []tea.ProgramOption
+	if !term.IsTerminal(int(os.Stdout.Fd())) {
+		opts = append(opts, tea.WithoutRenderer(), tea.WithInput(nil))
+	}
+
+	m := tablelist.NewModel(columns, rows, len(rows))
+
+	if _, err := tea.NewProgram(m, opts...).Run(); err != nil {
+		fmt.Println("Error running program:", err)
+		os.Exit(1)
+	}
+}
+
+func selectActiveContext(contexts []api.ContextListView, currentCredential string) []table.Row {
+	var rows []table.Row
+
+	for _, ctx := range contexts {
+		if ctx.Name == currentCredential {
+			rows = append([]table.Row{{
+				"* " + ctx.Name,
+				ctx.Username,
+				ctx.Server,
+			}}, rows...)
+		} else {
+			rows = append(rows, table.Row{
+				"  " + ctx.Name,
+				ctx.Username,
+				ctx.Server,
+			})
+		}
+	}
+	return rows
+}
diff --git a/pkg/views/context/switch/view.go b/pkg/views/context/switch/view.go
new file mode 100644
index 000000000..65a10dd06
--- /dev/null
+++ b/pkg/views/context/switch/view.go
@@ -0,0 +1,48 @@
+// Copyright Project Harbor Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package list
+
+import (
+	"errors"
+	"fmt"
+	"os"
+
+	"github.com/charmbracelet/bubbles/list"
+	tea "github.com/charmbracelet/bubbletea"
+	"github.com/goharbor/harbor-cli/pkg/api"
+	"github.com/goharbor/harbor-cli/pkg/views/base/selection"
+)
+
+func ContextList(contexts []api.ContextListView) (string, error) {
+	itemsList := make([]list.Item, len(contexts))
+
+	for i, ctx := range contexts {
+		itemsList[i] = selection.Item(ctx.Name)
+	}
+	m := selection.NewModel(itemsList, "Context")
+
+	p, err := tea.NewProgram(m, tea.WithAltScreen()).Run()
+
+	if err != nil {
+		fmt.Println("Error running program:", err)
+		os.Exit(1)
+	}
+
+	if p, ok := p.(selection.Model); ok {
+		return p.Choice, nil
+	} else {
+		return "", errors.New("invalid program")
+	}
+}
diff --git a/test/e2e/config_cmd_test.go b/test/e2e/config_cmd_test.go
index a067e7776..dfb066d6a 100644
--- a/test/e2e/config_cmd_test.go
+++ b/test/e2e/config_cmd_test.go
@@ -21,29 +21,29 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-func Test_ConfigCmd(t *testing.T) {
+func Test_ContextCmd(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
 	SetMockKeyring(t)
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config"})
+	rootCmd.SetArgs([]string{"context"})
 	err := rootCmd.Execute()
 	assert.Nil(t, err)
 }
 
-func Test_ConfigListCmd(t *testing.T) {
+func Test_ContextListCmd(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
 	SetMockKeyring(t)
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "list"})
+	rootCmd.SetArgs([]string{"context", "list"})
 	err := rootCmd.Execute()
 	assert.Nil(t, err)
 }
 
-func Test_ConfigGetCmd_Success(t *testing.T) {
+func Test_ContextGetCmd_Success(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
@@ -64,12 +64,12 @@ func Test_ConfigGetCmd_Success(t *testing.T) {
 		t.Fatal(err)
 	}
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "get", "credentials.serveraddress"})
+	rootCmd.SetArgs([]string{"context", "get", "credentials.serveraddress"})
 	err = rootCmd.Execute()
 	assert.NoError(t, err)
 }
 
-func Test_ConfigGetCmd_Failure(t *testing.T) {
+func Test_ContextGetCmd_Failure(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
@@ -90,12 +90,12 @@ func Test_ConfigGetCmd_Failure(t *testing.T) {
 		t.Fatal(err)
 	}
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "get", "serveraddress"})
+	rootCmd.SetArgs([]string{"context", "get", "serveraddress"})
 	err = rootCmd.Execute()
 	assert.Error(t, err, "Expected an error when getting a non-existent config item")
 }
 
-func Test_ConfigGetCmd_CredentialName_Success(t *testing.T) {
+func Test_ContextGetCmd_CredentialName_Success(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
@@ -116,12 +116,12 @@ func Test_ConfigGetCmd_CredentialName_Success(t *testing.T) {
 		t.Fatal(err)
 	}
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "get", "credentials.serveraddress", "--name", "harbor-cli@http://demo.goharbor.io"})
+	rootCmd.SetArgs([]string{"context", "get", "credentials.serveraddress", "--name", "harbor-cli@http://demo.goharbor.io"})
 	err = rootCmd.Execute()
 	assert.NoError(t, err)
 }
 
-func Test_ConfigGetCmd_CredentialName_Failure(t *testing.T) {
+func Test_ContextGetCmd_CredentialName_Failure(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
@@ -142,12 +142,12 @@ func Test_ConfigGetCmd_CredentialName_Failure(t *testing.T) {
 		t.Fatal(err)
 	}
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "get", "credentials.serveraddress", "--name", "harbor-cli@http://goharbor.io"})
+	rootCmd.SetArgs([]string{"context", "get", "credentials.serveraddress", "--name", "harbor-cli@http://goharbor.io"})
 	err = rootCmd.Execute()
 	assert.Error(t, err, "Expected an error when getting a non-existent credential name")
 }
 
-func Test_ConfigUpdateCmd_Success(t *testing.T) {
+func Test_ContextUpdateCmd_Success(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
@@ -168,12 +168,12 @@ func Test_ConfigUpdateCmd_Success(t *testing.T) {
 		t.Fatal(err)
 	}
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "update", "credentials.serveraddress", "http://demo.goharbor.io"})
+	rootCmd.SetArgs([]string{"context", "update", "credentials.serveraddress", "http://demo.goharbor.io"})
 	err = rootCmd.Execute()
 	assert.NoError(t, err)
 }
 
-func Test_ConfigUpdateCmd_CredentialName_Success(t *testing.T) {
+func Test_ContextUpdateCmd_CredentialName_Success(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
@@ -194,12 +194,12 @@ func Test_ConfigUpdateCmd_CredentialName_Success(t *testing.T) {
 		t.Fatal(err)
 	}
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "update", "credentials.serveraddress", "http://demo.goharbor.io", "--name", "harbor-cli@http://demo.goharbor.io"})
+	rootCmd.SetArgs([]string{"context", "update", "credentials.serveraddress", "http://demo.goharbor.io", "--name", "harbor-cli@http://demo.goharbor.io"})
 	err = rootCmd.Execute()
 	assert.NoError(t, err)
 }
 
-func Test_ConfigUpdateCmd_CredentialName_Failure(t *testing.T) {
+func Test_ContextUpdateCmd_CredentialName_Failure(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
@@ -220,12 +220,12 @@ func Test_ConfigUpdateCmd_CredentialName_Failure(t *testing.T) {
 		t.Fatal(err)
 	}
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "update", "credentials.serveraddress", "http://demo.goharbor.io", "--name", "harbor-cli@http://goharbor.io"})
+	rootCmd.SetArgs([]string{"context", "update", "credentials.serveraddress", "http://demo.goharbor.io", "--name", "harbor-cli@http://goharbor.io"})
 	err = rootCmd.Execute()
 	assert.Error(t, err, "Expected an error when setting a non-existent credential name")
 }
 
-func Test_ConfigUpdateCmd_Failure(t *testing.T) {
+func Test_ContextUpdateCmd_Failure(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
@@ -246,12 +246,12 @@ func Test_ConfigUpdateCmd_Failure(t *testing.T) {
 		t.Fatal(err)
 	}
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "update", "serveraddress", "http://demo.goharbor.io"})
+	rootCmd.SetArgs([]string{"context", "update", "serveraddress", "http://demo.goharbor.io"})
 	err = rootCmd.Execute()
 	assert.Error(t, err, "Expected an error when setting a non-existent config item")
 }
 
-func Test_ConfigDeleteCmd_Success(t *testing.T) {
+func Test_ContextDeleteCmd_Success(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
@@ -272,7 +272,7 @@ func Test_ConfigDeleteCmd_Success(t *testing.T) {
 		t.Fatal(err)
 	}
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "delete", "credentials.serveraddress"})
+	rootCmd.SetArgs([]string{"context", "delete", "credentials.serveraddress"})
 	err = rootCmd.Execute()
 	assert.NoError(t, err)
 	config, err := utils.GetCurrentHarborConfig()
@@ -282,7 +282,7 @@ func Test_ConfigDeleteCmd_Success(t *testing.T) {
 	assert.Empty(t, config.Credentials[0].ServerAddress)
 }
 
-func Test_ConfigDeleteCmd_Failure(t *testing.T) {
+func Test_ContextDeleteCmd_Failure(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
@@ -303,12 +303,12 @@ func Test_ConfigDeleteCmd_Failure(t *testing.T) {
 		t.Fatal(err)
 	}
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "delete", "serveraddress"})
+	rootCmd.SetArgs([]string{"context", "delete", "serveraddress"})
 	err = rootCmd.Execute()
 	assert.Error(t, err, "Expected an error when deleting a non-existent config item")
 }
 
-func Test_ConfigDeleteCmd_CredentialName_Success(t *testing.T) {
+func Test_ContextDeleteCmd_CredentialName_Success(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
@@ -329,7 +329,7 @@ func Test_ConfigDeleteCmd_CredentialName_Success(t *testing.T) {
 		t.Fatal(err)
 	}
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "delete", "credentials.serveraddress", "--name", "harbor-cli@http://demo.goharbor.io"})
+	rootCmd.SetArgs([]string{"context", "delete", "credentials.serveraddress", "--name", "harbor-cli@http://demo.goharbor.io"})
 	err = rootCmd.Execute()
 	assert.NoError(t, err)
 	config, err := utils.GetCurrentHarborConfig()
@@ -339,7 +339,7 @@ func Test_ConfigDeleteCmd_CredentialName_Success(t *testing.T) {
 	assert.Empty(t, config.Credentials[0].ServerAddress)
 }
 
-func Test_ConfigDeleteCmd_CredentialName_Failure(t *testing.T) {
+func Test_ContextDeleteCmd_CredentialName_Failure(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
@@ -360,12 +360,12 @@ func Test_ConfigDeleteCmd_CredentialName_Failure(t *testing.T) {
 		t.Fatal(err)
 	}
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "delete", "credentials.serveraddress", "--name", "harbor-cli@http://goharbor.io"})
+	rootCmd.SetArgs([]string{"context", "delete", "credentials.serveraddress", "--name", "harbor-cli@http://goharbor.io"})
 	err = rootCmd.Execute()
 	assert.Error(t, err, "Expected an error when deleting a non-existent credential name")
 }
 
-func Test_ConfigDeleteCmd_Current_Flag_Success(t *testing.T) {
+func Test_ContextDeleteCmd_Current_Flag_Success(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
@@ -392,7 +392,7 @@ func Test_ConfigDeleteCmd_Current_Flag_Success(t *testing.T) {
 		t.Fatal(err)
 	}
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "delete", "--current"})
+	rootCmd.SetArgs([]string{"context", "delete", "--current"})
 	err = rootCmd.Execute()
 	assert.NoError(t, err)
 	config, err := utils.GetCurrentHarborConfig()
@@ -404,13 +404,13 @@ func Test_ConfigDeleteCmd_Current_Flag_Success(t *testing.T) {
 	assert.NoError(t, err)
 }
 
-func Test_ConfigDeleteCmd_Current_Flag_With_Item_Failure(t *testing.T) {
+func Test_ContextDeleteCmd_Current_Flag_With_Item_Failure(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
 	SetMockKeyring(t)
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "delete", "credentials.serveraddress", "--current"})
+	rootCmd.SetArgs([]string{"context", "delete", "credentials.serveraddress", "--current"})
 	err := rootCmd.Execute()
 	assert.Error(t, err, "Expected an error when specifying both --current and an item")
 }


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR adds a new harbor context command to manage and switch contexts by reading/writing from a configuration file.  
- Introduces a new command (harbor context list) for listing contexts  
- Adds a new view for rendering the context list  
- Creates additional API types to support the context functionality

### Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

<details>
<summary>Show a summary per file</summary>

| File                                    | Description                                          |
|-----------------------------------------|------------------------------------------------------|
| pkg/views/context/list/view.go          | Adds a view to render the list of contexts using a table |
| pkg/api/types.go                        | Introduces the ContextListView type                  |
| cmd/harbor/root/context/list.go         | Implements the cobra command for listing contexts    |
| cmd/harbor/root/context/cmd.go          | Adds a context command to the overall CLI command hierarchy |
| cmd/harbor/root/cmd.go                    | Integrates the new context command into the root command collection |
</details>



<details>
<summary>Comments suppressed due to low confidence (1)</summary>

**cmd/harbor/root/context/list.go:38**
* [nitpick] Consider using named field initialization for ContextListView for improved clarity and maintainability (e.g., ContextListView{Name: cred.Name, Username: cred.Username, Server: cred.ServerAddress}).
```
cx := api.ContextListView{cred.Name, cred.Username, cred.ServerAddress}
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T13:25:17Z
user: login: bupd
body: @Darkhood148 Thanks for your contributions

I have added some suggestion for improvements

Also rebase & run `dagger call lint`. and fix the lint issues

Thanks
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-05-07T09:48:17Z
user: login: bupd
body: Thanks for your contributions

I have added suggestions please fix that.
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-05-09T20:55:29Z
user: login: bupd
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-05-13T12:15:56Z
user: login: bupd
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T12:16:25Z
user: login: Darkhood148
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T13:16:45Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

Adds a new `harbor context` command suite to manage and switch CLI contexts via the `config.yaml` file.

- Introduces a `ContextListView` type to render context listings.
- Implements `list`, `get`, `update`, `delete`, and `switch` subcommands under `harbor context`.
- Refactors command registrations and package names from `config` to `context`.

### Reviewed Changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 3 comments.

<details>
<summary>Show a summary per file</summary>

| File                                               | Description                                            |
| -------------------------------------------------- | ------------------------------------------------------ |
| pkg/api/types.go                                   | Adds `ContextListView` struct for context listings     |
| cmd/harbor/root/context/update.go                  | Renames update command and adjusts examples            |
| cmd/harbor/root/context/list.go                    | Implements `list` command using the new view           |
| cmd/harbor/root/context/get.go                     | Renames get command and updates examples               |
| cmd/harbor/root/context/delete.go                  | Renames delete command and handles credential removal  |
| cmd/harbor/root/context/switch.go                  | Adds `switch` command for changing active context      |
| cmd/harbor/root/context/cmd.go                     | Registers all `context` subcommands                    |
| cmd/harbor/root/cmd.go                             | Integrates `context` command into the root CLI         |
</details>



<details>
<summary>Comments suppressed due to low confidence (3)</summary>

**cmd/harbor/root/context/update.go:37**
* Update the example to use `harbor context update` instead of `harbor config update` for consistency.
```
  harbor config update credentials.password myNewSecret --name admin@http://demo.goharbor.io
```
**cmd/harbor/root/context/get.go:37**
* Update the example to use `harbor context get` instead of `harbor config get` to match the command name.
```
  harbor config get credentials.username --name admin@http://demo.goharbor.io
```
**cmd/harbor/root/context/list.go:1**
* Add unit tests for the new `harbor context list` command to ensure correct output formatting and error handling.
```
// Copyright Project Harbor Authors
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T15:37:16Z
user: login: Darkhood148
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T07:36:30Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This pull request adds a new harbor context command to manage and switch contexts by reading and writing from the config file.  
- Introduces new manual pages and CLI documentation for the harbor context switch command.  
- Implements update, get, list, delete, and switch subcommands under the new "context" command.  
- Updates the top-level command registration to include the new context command instead of the old config command.

### Reviewed Changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated no comments.

<details>
<summary>Show a summary per file</summary>

| File                                           | Description                                                |
| ---------------------------------------------- | ---------------------------------------------------------- |
| doc/man-docs/man1/harbor-context-switch.1      | Adds a new manual page for the harbor context switch command |
| doc/cli-docs/harbor-context-switch.md          | Adds CLI documentation for using the harbor context switch |
| cmd/harbor/root/context/update.go              | Renames and implements the update command for context items with one example still using the legacy reference |
| cmd/harbor/root/context/switch.go              | Implements the switch command for changing the active credentials |
| cmd/harbor/root/context/list.go                | Implements the list command for displaying available contexts |
| cmd/harbor/root/context/get.go                 | Renames and implements the get command for context items with one legacy example |
| cmd/harbor/root/context/delete.go              | Renames and implements the delete command for context items |
| cmd/harbor/root/context/cmd.go                 | Updates the context command group registration            |
| cmd/harbor/root/cmd.go                         | Removes the config command and registers the context command |
</details>



<details>
<summary>Comments suppressed due to low confidence (3)</summary>

**cmd/harbor/root/context/update.go:33**
* Consider updating the short description to refer to a 'context item' rather than a 'config item' for consistency with the new command group.
```
Short: "Set/update a specific config item",
```
**cmd/harbor/root/context/update.go:36**
* Update the second example to use 'harbor context update' instead of 'harbor config update' to avoid confusion.
```
harbor config update credentials.password myNewSecret --name admin@http://demo.goharbor.io
```
**cmd/harbor/root/context/get.go:36**
* Update the second example to use 'harbor context get' instead of 'harbor config get' to match the context command usage.
```
harbor config get credentials.username --name admin@http://demo.goharbor.io
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T08:36:30Z
user: login: bupd
body: LGTM, @Darkhood148 please resolve the conflicts
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-19T13:17:34Z
user: login: Vad1mo
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-20T13:14:36Z

Review comments:
diff_hunk: @@ -0,0 +1,45 @@
+// Copyright Project Harbor Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package context
+
+import (
+	"github.com/goharbor/harbor-cli/pkg/api"
+	"github.com/goharbor/harbor-cli/pkg/utils"
+	"github.com/goharbor/harbor-cli/pkg/views/context/list"
+	"github.com/sirupsen/logrus"
+	"github.com/spf13/cobra"
+)
+
+func ListContextCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:     "list",
+		Short:   "List contexts",
+		Example: `  harbor context list`,
+		Args:    cobra.MaximumNArgs(0),
+		Run: func(cmd *cobra.Command, args []string) {
+			config, err := utils.GetCurrentHarborConfig()
+			if err != nil {
+				logrus.Errorf("Error occurred: %v", err)
path: cmd/harbor/root/context/list.go
user: login: Copilot
body: The error from GetCurrentHarborConfig is only logged without stopping the execution, which may lead to a nil pointer dereference. Consider returning immediately or exiting after logging the error.
```suggestion
				logrus.Errorf("Error occurred: %v", err)
				return
```
created_at: 2025-04-29T13:25:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -15,10 +15,10 @@ package root
 
 import (
 	"fmt"
+	"github.com/goharbor/harbor-cli/cmd/harbor/root/context"
path: cmd/harbor/root/cmd.go
user: login: bupd
body: do gofmt -imports 

to fix the import order
created_at: 2025-05-07T09:44:02Z
author_association: MEMBER
diff_hunk: @@ -11,51 +11,36 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-package config
 
-import (
-	"fmt"
+package context
 
+import (
+	"github.com/goharbor/harbor-cli/pkg/api"
 	"github.com/goharbor/harbor-cli/pkg/utils"
+	"github.com/goharbor/harbor-cli/pkg/views/context/list"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
-	"github.com/spf13/viper"
-	"gopkg.in/yaml.v3"
 )
 
-func ListConfigCommand() *cobra.Command {
+func ListContextCommand() *cobra.Command {
 	cmd := &cobra.Command{
 		Use:     "list",
-		Short:   "List config items",
-		Example: `  harbor config list`,
-		Long:    `Get information of all CLI config items`,
+		Short:   "List contexts",
+		Example: `  harbor context list`,
 		Args:    cobra.MaximumNArgs(0),
 		Run: func(cmd *cobra.Command, args []string) {
 			config, err := utils.GetCurrentHarborConfig()
 			if err != nil {
-				logrus.Errorf("Failed to get config: %v", err)
+				logrus.Errorf("Error occurred: %v", err)
 				return
 			}
-
-			// Get the output format
-			formatFlag := viper.GetString("output-format")
path: cmd/harbor/root/context/list.go
user: login: bupd
body: we need this 

output context command in json. 

have a look at how other commands handles different output formats

https://github.com/goharbor/harbor-cli/blob/97c20c020984acffdf81b8a827176d5693c81599/cmd/harbor/root/project/list.go#L66
created_at: 2025-05-09T20:53:17Z
author_association: MEMBER
diff_hunk: @@ -21,29 +21,31 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-func Test_ConfigCmd(t *testing.T) {
+func Test_ContextCmd(t *testing.T) {
 	tempDir := t.TempDir()
 	data := Initialize(t, tempDir)
 	defer ConfigCleanup(t, data)
 	SetMockKeyring(t)
 	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config"})
+	rootCmd.SetArgs([]string{"context"})
 	err := rootCmd.Execute()
 	assert.Nil(t, err)
 }
 
-func Test_ConfigListCmd(t *testing.T) {
-	tempDir := t.TempDir()
-	data := Initialize(t, tempDir)
-	defer ConfigCleanup(t, data)
-	SetMockKeyring(t)
-	rootCmd := root.RootCmd()
-	rootCmd.SetArgs([]string{"config", "list"})
-	err := rootCmd.Execute()
-	assert.Nil(t, err)
-}
+// TODO: This test fails because it tries to open a TTY terminal which fails in GitHub workflows and dagger but works if you run it locally.
path: test/e2e/config_cmd_test.go
user: login: bupd
body: try to run tests with `-o json` it should not fail this way. 
We need tests
created_at: 2025-05-09T20:54:31Z
author_association: MEMBER
path: harbor-cli
user: login: bupd
body: please remove the bin file
created_at: 2025-05-13T12:14:27Z
author_association: MEMBER
path: harbor-cli
user: login: bupd
body: otherwise, lgtm. and do rebase onto main branch
created_at: 2025-05-13T12:16:25Z
author_association: MEMBER
path: harbor-cli
user: login: Darkhood148
body: Done.
created_at: 2025-05-13T13:16:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -25,23 +25,23 @@ import (
 
 var deleteCurrent bool
 
-// DeleteConfigItemCommand creates the 'harbor config delete' subcommand,
+// DeleteContextItemCommand creates the 'harbor config delete' subcommand,
 // allowing you to do: harbor config delete <item>
path: cmd/harbor/root/context/delete.go
user: login: Copilot
body: Update the comment to reflect `harbor context delete` instead of `harbor config delete`.
```suggestion
// DeleteContextItemCommand creates the 'harbor context delete' subcommand,
// allowing you to do: harbor context delete <item>
```
created_at: 2025-05-15T15:37:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,63 @@
+// Copyright Project Harbor Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package context
+
+import (
+	"github.com/goharbor/harbor-cli/pkg/utils"
+	"github.com/sirupsen/logrus"
+	"github.com/spf13/cobra"
+)
+
+func SwitchContextCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:     "switch <none|context>",
path: cmd/harbor/root/context/switch.go
user: login: Copilot
body: [nitpick] Consider simplifying the usage string to `switch [context]` to clearly indicate an optional context name.
```suggestion
		Use:     "switch [context]",
```
created_at: 2025-05-15T15:37:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -11,22 +11,25 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-package config
+package context
 
 import "github.com/spf13/cobra"
 
-func Config() *cobra.Command {
+func Context() *cobra.Command {
 	cmd := &cobra.Command{
-		Use:   "config",
-		Short: "Manage the config of the Harbor CLI",
-		Long: `The config command allows you to manage configurations of the Harbor CLI.
+		Use:     "context",
+		Short:   "Manage locally available contexts",
+		Example: "harbor context list",
+		Long: `The context command allows you to manage configs of the Harbor CLI.
 				You can add, get, or delete specific config item, as well as list all config items of the Harbor Cli`,
path: cmd/harbor/root/context/cmd.go
user: login: Copilot
body: [nitpick] Fix grammar and casing in the long description, e.g. pluralize "configs" to "configuration items" and standardize "CLI" casing.
```suggestion
		Long: `The context command allows you to manage configuration items of the Harbor CLI.
				You can add, get, or delete specific configuration items, as well as list all configuration items of the Harbor CLI.`,
```
created_at: 2025-05-15T15:37:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,63 @@
+// Copyright Project Harbor Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package context
+
+import (
+	"github.com/goharbor/harbor-cli/pkg/utils"
+	"github.com/sirupsen/logrus"
+	"github.com/spf13/cobra"
+)
+
+func SwitchContextCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:     "switch <none|context>",
path: cmd/harbor/root/context/switch.go
user: login: Darkhood148
body: Added none case
created_at: 2025-05-16T07:36:30Z
author_association: CONTRIBUTOR

PR comments:
user: login: Darkhood148
created_at: 2025-04-25T07:46:04Z
body: ![image](https://github.com/user-attachments/assets/e0909fb5-eb3f-4ac4-8acb-2a9b585aed4d)

author_association: CONTRIBUTOR
user: login: Darkhood148
created_at: 2025-04-29T14:29:33Z
body: @Vad1mo Should I continue working on this and add `harbor context switch` command?
author_association: CONTRIBUTOR
user: login: Darkhood148
created_at: 2025-05-07T07:27:46Z
body: Hi @bupd 
I have rename config to context as mentioned here: https://github.com/goharbor/harbor-cli/issues/438 . I have also improved the working of the `list` subcommand, giving it a neater ui. Can you review it please?

author_association: CONTRIBUTOR
user: login: bupd
created_at: 2025-05-07T09:43:29Z
body: @Darkhood148 rebase onto main branch
author_association: MEMBER
user: login: Darkhood148
created_at: 2025-05-08T17:07:23Z
body: @bupd Done the changes.
author_association: CONTRIBUTOR
user: login: Darkhood148
created_at: 2025-05-10T19:14:13Z
body: Done with the changes @bupd !
The test was failing due to `bubbletea` opening a TTY by default which fails in non-interactive environments like Dagger and Github Workflows. As mentioned in the documentation, this can be disabled by adding:
```go
if !term.IsTerminal(int(os.Stdout.Fd())) {
     opts = append(opts, tea.WithoutRenderer(), tea.WithInput(nil))
}
```
After adding this, the same test passes!
This could be useful while writing tests for other commands using bubbletea.
author_association: CONTRIBUTOR
user: login: Vad1mo
created_at: 2025-05-13T13:35:16Z
body: It would make sense if the `context list`sub-command would display what is the current context. 

Eg. with an Asterix

<img width="700" alt="Image" src="https://github.com/user-attachments/assets/7949eaf1-0c1d-4f92-927d-b192014d4a9c" />

author_association: MEMBER
user: login: Vad1mo
created_at: 2025-05-13T13:35:43Z
body: `context switch` should allow switching context, just like currently `harbor-cli login --name context`allows us to do so. 

Furthermore, we should only have one way to switch the context, so we should remove `harbor-cli login --name context`


author_association: MEMBER
user: login: Darkhood148
created_at: 2025-05-15T08:20:22Z
body: ![image](https://github.com/user-attachments/assets/f1e7200c-9ff1-4e40-8942-979f606a8792)

author_association: CONTRIBUTOR
user: login: Darkhood148
created_at: 2025-05-16T07:38:42Z
body: Using `context switch` without any arguments now opens this interactive selection window:
![image](https://github.com/user-attachments/assets/773db58d-6840-4ee2-9a5a-5e3a8da6e8ef)

author_association: CONTRIBUTOR
user: login: Darkhood148
created_at: 2025-05-16T08:24:28Z
body: @bupd @Vad1mo Done with the changes. Please review.
author_association: CONTRIBUTOR
user: login: Vad1mo
created_at: 2025-05-20T13:29:59Z
body: Rename `CurrentCredentialName:` into `CurrentContext`
author_association: MEMBER
user: login: Vad1mo
created_at: 2025-05-20T13:32:12Z
body: Mybe provide an output after context switch  e..g switched context from x to y.

```
❯ ./harbor-cli context switch vadim2@goharbor-io
""

```
author_association: MEMBER
user: login: Vad1mo
created_at: 2025-05-20T13:33:49Z
body: Display the current context in the UI

![image](https://github.com/user-attachments/assets/efc17b3d-4af0-41b7-87b2-c9855037fa9e)

author_association: MEMBER
user: login: Vad1mo
created_at: 2025-05-20T13:35:43Z
body: It would make more sense if the order of the list would not change and make the current context on the top:

![image](https://github.com/user-attachments/assets/108beaaa-5566-4e91-9281-d1938baabc1b)
![image](https://github.com/user-attachments/assets/113035d2-0f15-4ec9-8f47-b3e22eb5c304)


author_association: MEMBER