mirror of
https://github.com/coder/coder.git
synced 2026-10-29 17:44:33 +08:00
feat: add display_name field to groups (#8740)
* feat: add display_name field to groups This is a non-unique human friendly group name for display purposes. This means a display name can be used instead of using an environment var to remap groups with OIDC names to Coder names. Now groups can retain the OIDC name for mapping, and use a display name for display purposes.
This commit is contained in:
@@ -151,6 +151,7 @@ var auditableResourcesTypes = map[any]map[string]Action{
|
||||
&database.AuditableGroup{}: {
|
||||
"id": ActionTrack,
|
||||
"name": ActionTrack,
|
||||
"display_name": ActionTrack,
|
||||
"organization_id": ActionIgnore, // Never changes.
|
||||
"avatar_url": ActionTrack,
|
||||
"quota_allowance": ActionTrack,
|
||||
|
||||
@@ -12,7 +12,11 @@ import (
|
||||
)
|
||||
|
||||
func (r *RootCmd) groupCreate() *clibase.Cmd {
|
||||
var avatarURL string
|
||||
var (
|
||||
avatarURL string
|
||||
displayName string
|
||||
)
|
||||
|
||||
client := new(codersdk.Client)
|
||||
cmd := &clibase.Cmd{
|
||||
Use: "create <name>",
|
||||
@@ -30,8 +34,9 @@ func (r *RootCmd) groupCreate() *clibase.Cmd {
|
||||
}
|
||||
|
||||
group, err := client.CreateGroup(ctx, org.ID, codersdk.CreateGroupRequest{
|
||||
Name: inv.Args[0],
|
||||
AvatarURL: avatarURL,
|
||||
Name: inv.Args[0],
|
||||
DisplayName: displayName,
|
||||
AvatarURL: avatarURL,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create group: %w", err)
|
||||
@@ -50,6 +55,12 @@ func (r *RootCmd) groupCreate() *clibase.Cmd {
|
||||
Env: "CODER_AVATAR_URL",
|
||||
Value: clibase.StringOf(&avatarURL),
|
||||
},
|
||||
{
|
||||
Flag: "display-name",
|
||||
Description: `Optional human friendly name for the group.`,
|
||||
Env: "CODER_DISPLAY_NAME",
|
||||
Value: clibase.StringOf(&displayName),
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
|
||||
@@ -15,10 +15,11 @@ import (
|
||||
|
||||
func (r *RootCmd) groupEdit() *clibase.Cmd {
|
||||
var (
|
||||
avatarURL string
|
||||
name string
|
||||
addUsers []string
|
||||
rmUsers []string
|
||||
avatarURL string
|
||||
name string
|
||||
displayName string
|
||||
addUsers []string
|
||||
rmUsers []string
|
||||
)
|
||||
client := new(codersdk.Client)
|
||||
cmd := &clibase.Cmd{
|
||||
@@ -52,6 +53,10 @@ func (r *RootCmd) groupEdit() *clibase.Cmd {
|
||||
req.AvatarURL = &avatarURL
|
||||
}
|
||||
|
||||
if inv.ParsedFlags().Lookup("display-name").Changed {
|
||||
req.DisplayName = &displayName
|
||||
}
|
||||
|
||||
userRes, err := client.Users(ctx, codersdk.UsersRequest{})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get users: %w", err)
|
||||
@@ -90,6 +95,12 @@ func (r *RootCmd) groupEdit() *clibase.Cmd {
|
||||
Description: "Update the group avatar.",
|
||||
Value: clibase.StringOf(&avatarURL),
|
||||
},
|
||||
{
|
||||
Flag: "display-name",
|
||||
Description: `Optional human friendly name for the group.`,
|
||||
Env: "CODER_DISPLAY_NAME",
|
||||
Value: clibase.StringOf(&displayName),
|
||||
},
|
||||
{
|
||||
Flag: "add-users",
|
||||
FlagShorthand: "a",
|
||||
|
||||
@@ -67,6 +67,7 @@ type groupTableRow struct {
|
||||
|
||||
// For table output:
|
||||
Name string `json:"-" table:"name,default_sort"`
|
||||
DisplayName string `json:"-" table:"display_name"`
|
||||
OrganizationID uuid.UUID `json:"-" table:"organization_id"`
|
||||
Members []string `json:"-" table:"members"`
|
||||
AvatarURL string `json:"-" table:"avatar_url"`
|
||||
@@ -81,6 +82,7 @@ func groupsToRows(groups ...codersdk.Group) []groupTableRow {
|
||||
}
|
||||
rows = append(rows, groupTableRow{
|
||||
Name: group.Name,
|
||||
DisplayName: group.DisplayName,
|
||||
OrganizationID: group.OrganizationID,
|
||||
AvatarURL: group.AvatarURL,
|
||||
Members: members,
|
||||
|
||||
@@ -6,5 +6,8 @@ Create a user group
|
||||
-u, --avatar-url string, $CODER_AVATAR_URL
|
||||
Set an avatar for a group.
|
||||
|
||||
--display-name string, $CODER_DISPLAY_NAME
|
||||
Optional human friendly name for the group.
|
||||
|
||||
---
|
||||
Run `coder --help` for a list of global options.
|
||||
|
||||
@@ -9,6 +9,9 @@ Edit a user group
|
||||
-u, --avatar-url string
|
||||
Update the group avatar.
|
||||
|
||||
--display-name string, $CODER_DISPLAY_NAME
|
||||
Optional human friendly name for the group.
|
||||
|
||||
-n, --name string
|
||||
Update the group name.
|
||||
|
||||
|
||||
+3
-3
@@ -3,9 +3,9 @@ Usage: coder groups list [flags]
|
||||
List user groups
|
||||
|
||||
[1mOptions[0m
|
||||
-c, --column string-array (default: name,organization id,members,avatar url)
|
||||
Columns to display in table output. Available columns: name,
|
||||
organization id, members, avatar url.
|
||||
-c, --column string-array (default: name,display name,organization id,members,avatar url)
|
||||
Columns to display in table output. Available columns: name, display
|
||||
name, organization id, members, avatar url.
|
||||
|
||||
-o, --output string (default: table)
|
||||
Output format. Available formats: table, json.
|
||||
|
||||
@@ -56,6 +56,7 @@ func (api *API) postGroupByOrganization(rw http.ResponseWriter, r *http.Request)
|
||||
group, err := api.Database.InsertGroup(ctx, database.InsertGroupParams{
|
||||
ID: uuid.New(),
|
||||
Name: req.Name,
|
||||
DisplayName: req.DisplayName,
|
||||
OrganizationID: org.ID,
|
||||
AvatarURL: req.AvatarURL,
|
||||
QuotaAllowance: int32(req.QuotaAllowance),
|
||||
@@ -177,6 +178,7 @@ func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) {
|
||||
ID: group.ID,
|
||||
AvatarURL: group.AvatarURL,
|
||||
Name: group.Name,
|
||||
DisplayName: group.DisplayName,
|
||||
QuotaAllowance: group.QuotaAllowance,
|
||||
}
|
||||
|
||||
@@ -190,6 +192,9 @@ func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) {
|
||||
if req.QuotaAllowance != nil {
|
||||
updateGroupParams.QuotaAllowance = int32(*req.QuotaAllowance)
|
||||
}
|
||||
if req.DisplayName != nil {
|
||||
updateGroupParams.DisplayName = *req.DisplayName
|
||||
}
|
||||
|
||||
group, err = tx.UpdateGroupByID(ctx, updateGroupParams)
|
||||
if err != nil {
|
||||
@@ -395,9 +400,11 @@ func convertGroup(g database.Group, users []database.User) codersdk.Group {
|
||||
for _, user := range users {
|
||||
orgs[user.ID] = []uuid.UUID{g.OrganizationID}
|
||||
}
|
||||
|
||||
return codersdk.Group{
|
||||
ID: g.ID,
|
||||
Name: g.Name,
|
||||
DisplayName: g.DisplayName,
|
||||
OrganizationID: g.OrganizationID,
|
||||
AvatarURL: g.AvatarURL,
|
||||
QuotaAllowance: int(g.QuotaAllowance),
|
||||
|
||||
@@ -37,6 +37,7 @@ func TestCreateGroup(t *testing.T) {
|
||||
require.Equal(t, "hi", group.Name)
|
||||
require.Equal(t, "https://example.com", group.AvatarURL)
|
||||
require.Empty(t, group.Members)
|
||||
require.Empty(t, group.DisplayName)
|
||||
require.NotEqual(t, uuid.Nil.String(), group.ID.String())
|
||||
})
|
||||
|
||||
@@ -124,11 +125,45 @@ func TestPatchGroup(t *testing.T) {
|
||||
codersdk.FeatureTemplateRBAC: 1,
|
||||
},
|
||||
}})
|
||||
const displayName = "foobar"
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
group, err := client.CreateGroup(ctx, user.OrganizationID, codersdk.CreateGroupRequest{
|
||||
Name: "hi",
|
||||
AvatarURL: "https://example.com",
|
||||
QuotaAllowance: 10,
|
||||
DisplayName: "",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 10, group.QuotaAllowance)
|
||||
|
||||
group, err = client.PatchGroup(ctx, group.ID, codersdk.PatchGroupRequest{
|
||||
Name: "bye",
|
||||
AvatarURL: ptr.Ref("https://google.com"),
|
||||
QuotaAllowance: ptr.Ref(20),
|
||||
DisplayName: ptr.Ref(displayName),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, displayName, group.DisplayName)
|
||||
require.Equal(t, "bye", group.Name)
|
||||
require.Equal(t, "https://google.com", group.AvatarURL)
|
||||
require.Equal(t, 20, group.QuotaAllowance)
|
||||
})
|
||||
|
||||
t.Run("DisplayNameUnchanged", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client, user := coderdenttest.New(t, &coderdenttest.Options{LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{
|
||||
codersdk.FeatureTemplateRBAC: 1,
|
||||
},
|
||||
}})
|
||||
const displayName = "foobar"
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
group, err := client.CreateGroup(ctx, user.OrganizationID, codersdk.CreateGroupRequest{
|
||||
Name: "hi",
|
||||
AvatarURL: "https://example.com",
|
||||
QuotaAllowance: 10,
|
||||
DisplayName: displayName,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 10, group.QuotaAllowance)
|
||||
@@ -139,6 +174,7 @@ func TestPatchGroup(t *testing.T) {
|
||||
QuotaAllowance: ptr.Ref(20),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, displayName, group.DisplayName)
|
||||
require.Equal(t, "bye", group.Name)
|
||||
require.Equal(t, "https://google.com", group.AvatarURL)
|
||||
require.Equal(t, 20, group.QuotaAllowance)
|
||||
|
||||
Reference in New Issue
Block a user