mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: show organization name for groups on user profile (#14448)
This commit is contained in:
committed by
GitHub
parent
4b5c45d6df
commit
49afab12d5
Generated
+6
@@ -10343,10 +10343,16 @@ const docTemplate = `{
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"organization_display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"organization_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"organization_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"quota_allowance": {
|
||||
"type": "integer"
|
||||
},
|
||||
|
||||
Generated
+6
@@ -9287,10 +9287,16 @@
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"organization_display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"organization_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"organization_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"quota_allowance": {
|
||||
"type": "integer"
|
||||
},
|
||||
|
||||
@@ -208,17 +208,19 @@ func Users(users []database.User, organizationIDs map[uuid.UUID][]uuid.UUID) []c
|
||||
})
|
||||
}
|
||||
|
||||
func Group(group database.Group, members []database.GroupMember, totalMemberCount int) codersdk.Group {
|
||||
func Group(row database.GetGroupsRow, members []database.GroupMember, totalMemberCount int) codersdk.Group {
|
||||
return codersdk.Group{
|
||||
ID: group.ID,
|
||||
Name: group.Name,
|
||||
DisplayName: group.DisplayName,
|
||||
OrganizationID: group.OrganizationID,
|
||||
AvatarURL: group.AvatarURL,
|
||||
Members: ReducedUsersFromGroupMembers(members),
|
||||
TotalMemberCount: totalMemberCount,
|
||||
QuotaAllowance: int(group.QuotaAllowance),
|
||||
Source: codersdk.GroupSource(group.Source),
|
||||
ID: row.Group.ID,
|
||||
Name: row.Group.Name,
|
||||
DisplayName: row.Group.DisplayName,
|
||||
OrganizationID: row.Group.OrganizationID,
|
||||
AvatarURL: row.Group.AvatarURL,
|
||||
Members: ReducedUsersFromGroupMembers(members),
|
||||
TotalMemberCount: totalMemberCount,
|
||||
QuotaAllowance: int(row.Group.QuotaAllowance),
|
||||
Source: codersdk.GroupSource(row.Group.Source),
|
||||
OrganizationName: row.OrganizationName,
|
||||
OrganizationDisplayName: row.OrganizationDisplayName,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1503,7 +1503,7 @@ func (q *querier) GetGroupMembersCountByGroupID(ctx context.Context, groupID uui
|
||||
return memberCount, nil
|
||||
}
|
||||
|
||||
func (q *querier) GetGroups(ctx context.Context, arg database.GetGroupsParams) ([]database.Group, error) {
|
||||
func (q *querier) GetGroups(ctx context.Context, arg database.GetGroupsParams) ([]database.GetGroupsRow, error) {
|
||||
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err == nil {
|
||||
// Optimize this query for system users as it is used in telemetry.
|
||||
// Calling authz on all groups in a deployment for telemetry jobs is
|
||||
|
||||
@@ -607,7 +607,10 @@ func (s *MethodTestSuite) TestOrganization() {
|
||||
check.Args(database.GetGroupsParams{
|
||||
OrganizationID: o.ID,
|
||||
}).Asserts(rbac.ResourceSystem, policy.ActionRead, a, policy.ActionRead, b, policy.ActionRead).
|
||||
Returns([]database.Group{a, b}).
|
||||
Returns([]database.GetGroupsRow{
|
||||
{Group: a, OrganizationName: o.Name, OrganizationDisplayName: o.DisplayName},
|
||||
{Group: b, OrganizationName: o.Name, OrganizationDisplayName: o.DisplayName},
|
||||
}).
|
||||
// Fail the system check shortcut
|
||||
FailSystemObjectChecks()
|
||||
}))
|
||||
|
||||
@@ -2609,7 +2609,7 @@ func (q *FakeQuerier) GetGroupMembersCountByGroupID(ctx context.Context, groupID
|
||||
return int64(len(users)), nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) GetGroups(_ context.Context, arg database.GetGroupsParams) ([]database.Group, error) {
|
||||
func (q *FakeQuerier) GetGroups(_ context.Context, arg database.GetGroupsParams) ([]database.GetGroupsRow, error) {
|
||||
err := validateDatabaseType(arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -2634,7 +2634,8 @@ func (q *FakeQuerier) GetGroups(_ context.Context, arg database.GetGroupsParams)
|
||||
}
|
||||
}
|
||||
|
||||
filtered := make([]database.Group, 0)
|
||||
orgDetailsCache := make(map[uuid.UUID]struct{ name, displayName string })
|
||||
filtered := make([]database.GetGroupsRow, 0)
|
||||
for _, group := range q.groups {
|
||||
if arg.OrganizationID != uuid.Nil && group.OrganizationID != arg.OrganizationID {
|
||||
continue
|
||||
@@ -2645,7 +2646,24 @@ func (q *FakeQuerier) GetGroups(_ context.Context, arg database.GetGroupsParams)
|
||||
continue
|
||||
}
|
||||
|
||||
filtered = append(filtered, group)
|
||||
orgDetails, ok := orgDetailsCache[group.ID]
|
||||
if !ok {
|
||||
for _, org := range q.organizations {
|
||||
if group.OrganizationID == org.ID {
|
||||
orgDetails = struct{ name, displayName string }{
|
||||
name: org.Name, displayName: org.DisplayName,
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
orgDetailsCache[group.ID] = orgDetails
|
||||
}
|
||||
|
||||
filtered = append(filtered, database.GetGroupsRow{
|
||||
Group: group,
|
||||
OrganizationName: orgDetails.name,
|
||||
OrganizationDisplayName: orgDetails.displayName,
|
||||
})
|
||||
}
|
||||
|
||||
return filtered, nil
|
||||
|
||||
@@ -669,7 +669,7 @@ func (m metricsStore) GetGroupMembersCountByGroupID(ctx context.Context, groupID
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m metricsStore) GetGroups(ctx context.Context, arg database.GetGroupsParams) ([]database.Group, error) {
|
||||
func (m metricsStore) GetGroups(ctx context.Context, arg database.GetGroupsParams) ([]database.GetGroupsRow, error) {
|
||||
start := time.Now()
|
||||
r0, r1 := m.s.GetGroups(ctx, arg)
|
||||
m.queryLatencies.WithLabelValues("GetGroups").Observe(time.Since(start).Seconds())
|
||||
|
||||
@@ -1330,10 +1330,10 @@ func (mr *MockStoreMockRecorder) GetGroupMembersCountByGroupID(arg0, arg1 any) *
|
||||
}
|
||||
|
||||
// GetGroups mocks base method.
|
||||
func (m *MockStore) GetGroups(arg0 context.Context, arg1 database.GetGroupsParams) ([]database.Group, error) {
|
||||
func (m *MockStore) GetGroups(arg0 context.Context, arg1 database.GetGroupsParams) ([]database.GetGroupsRow, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetGroups", arg0, arg1)
|
||||
ret0, _ := ret[0].([]database.Group)
|
||||
ret0, _ := ret[0].([]database.GetGroupsRow)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
@@ -183,6 +183,10 @@ func (g Group) RBACObject() rbac.Object {
|
||||
})
|
||||
}
|
||||
|
||||
func (g GetGroupsRow) RBACObject() rbac.Object {
|
||||
return g.Group.RBACObject()
|
||||
}
|
||||
|
||||
func (gm GroupMember) RBACObject() rbac.Object {
|
||||
return rbac.ResourceGroupMember.WithID(gm.UserID).InOrg(gm.OrganizationID).WithOwner(gm.UserID.String())
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ type sqlcQuerier interface {
|
||||
// count even if the caller does not have read access to ResourceGroupMember.
|
||||
// They only need ResourceGroup read access.
|
||||
GetGroupMembersCountByGroupID(ctx context.Context, groupID uuid.UUID) (int64, error)
|
||||
GetGroups(ctx context.Context, arg GetGroupsParams) ([]Group, error)
|
||||
GetGroups(ctx context.Context, arg GetGroupsParams) ([]GetGroupsRow, error)
|
||||
GetHealthSettings(ctx context.Context) (string, error)
|
||||
GetHungProvisionerJobs(ctx context.Context, updatedAt time.Time) ([]ProvisionerJob, error)
|
||||
GetJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg GetJFrogXrayScanByWorkspaceAndAgentIDParams) (JfrogXrayScan, error)
|
||||
|
||||
@@ -1562,32 +1562,36 @@ func (q *sqlQuerier) GetGroupByOrgAndName(ctx context.Context, arg GetGroupByOrg
|
||||
|
||||
const getGroups = `-- name: GetGroups :many
|
||||
SELECT
|
||||
id, name, organization_id, avatar_url, quota_allowance, display_name, source
|
||||
groups.id, groups.name, groups.organization_id, groups.avatar_url, groups.quota_allowance, groups.display_name, groups.source,
|
||||
organizations.name AS organization_name,
|
||||
organizations.display_name AS organization_display_name
|
||||
FROM
|
||||
groups
|
||||
groups
|
||||
INNER JOIN
|
||||
organizations ON groups.organization_id = organizations.id
|
||||
WHERE
|
||||
true
|
||||
AND CASE
|
||||
WHEN $1:: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
|
||||
groups.organization_id = $1
|
||||
ELSE true
|
||||
END
|
||||
AND CASE
|
||||
-- Filter to only include groups a user is a member of
|
||||
WHEN $2::uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
|
||||
EXISTS (
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
-- this view handles the 'everyone' group in orgs.
|
||||
group_members_expanded
|
||||
WHERE
|
||||
group_members_expanded.group_id = groups.id
|
||||
AND
|
||||
group_members_expanded.user_id = $2
|
||||
)
|
||||
ELSE true
|
||||
END
|
||||
true
|
||||
AND CASE
|
||||
WHEN $1:: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
|
||||
groups.organization_id = $1
|
||||
ELSE true
|
||||
END
|
||||
AND CASE
|
||||
-- Filter to only include groups a user is a member of
|
||||
WHEN $2::uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
|
||||
EXISTS (
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
-- this view handles the 'everyone' group in orgs.
|
||||
group_members_expanded
|
||||
WHERE
|
||||
group_members_expanded.group_id = groups.id
|
||||
AND
|
||||
group_members_expanded.user_id = $2
|
||||
)
|
||||
ELSE true
|
||||
END
|
||||
`
|
||||
|
||||
type GetGroupsParams struct {
|
||||
@@ -1595,23 +1599,31 @@ type GetGroupsParams struct {
|
||||
HasMemberID uuid.UUID `db:"has_member_id" json:"has_member_id"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) GetGroups(ctx context.Context, arg GetGroupsParams) ([]Group, error) {
|
||||
type GetGroupsRow struct {
|
||||
Group Group `db:"group" json:"group"`
|
||||
OrganizationName string `db:"organization_name" json:"organization_name"`
|
||||
OrganizationDisplayName string `db:"organization_display_name" json:"organization_display_name"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) GetGroups(ctx context.Context, arg GetGroupsParams) ([]GetGroupsRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getGroups, arg.OrganizationID, arg.HasMemberID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Group
|
||||
var items []GetGroupsRow
|
||||
for rows.Next() {
|
||||
var i Group
|
||||
var i GetGroupsRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.Name,
|
||||
&i.OrganizationID,
|
||||
&i.AvatarURL,
|
||||
&i.QuotaAllowance,
|
||||
&i.DisplayName,
|
||||
&i.Source,
|
||||
&i.Group.ID,
|
||||
&i.Group.Name,
|
||||
&i.Group.OrganizationID,
|
||||
&i.Group.AvatarURL,
|
||||
&i.Group.QuotaAllowance,
|
||||
&i.Group.DisplayName,
|
||||
&i.Group.Source,
|
||||
&i.OrganizationName,
|
||||
&i.OrganizationDisplayName,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1703,15 +1715,15 @@ INSERT INTO groups (
|
||||
id,
|
||||
name,
|
||||
organization_id,
|
||||
source
|
||||
source
|
||||
)
|
||||
SELECT
|
||||
gen_random_uuid(),
|
||||
group_name,
|
||||
$1,
|
||||
$2
|
||||
gen_random_uuid(),
|
||||
group_name,
|
||||
$1,
|
||||
$2
|
||||
FROM
|
||||
UNNEST($3 :: text[]) AS group_name
|
||||
UNNEST($3 :: text[]) AS group_name
|
||||
ON CONFLICT DO NOTHING
|
||||
RETURNING id, name, organization_id, avatar_url, quota_allowance, display_name, source
|
||||
`
|
||||
|
||||
@@ -22,32 +22,36 @@ LIMIT
|
||||
|
||||
-- name: GetGroups :many
|
||||
SELECT
|
||||
*
|
||||
sqlc.embed(groups),
|
||||
organizations.name AS organization_name,
|
||||
organizations.display_name AS organization_display_name
|
||||
FROM
|
||||
groups
|
||||
groups
|
||||
INNER JOIN
|
||||
organizations ON groups.organization_id = organizations.id
|
||||
WHERE
|
||||
true
|
||||
AND CASE
|
||||
WHEN @organization_id:: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
|
||||
groups.organization_id = @organization_id
|
||||
ELSE true
|
||||
END
|
||||
AND CASE
|
||||
-- Filter to only include groups a user is a member of
|
||||
WHEN @has_member_id::uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
|
||||
EXISTS (
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
-- this view handles the 'everyone' group in orgs.
|
||||
group_members_expanded
|
||||
WHERE
|
||||
group_members_expanded.group_id = groups.id
|
||||
AND
|
||||
group_members_expanded.user_id = @has_member_id
|
||||
)
|
||||
ELSE true
|
||||
END
|
||||
true
|
||||
AND CASE
|
||||
WHEN @organization_id:: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
|
||||
groups.organization_id = @organization_id
|
||||
ELSE true
|
||||
END
|
||||
AND CASE
|
||||
-- Filter to only include groups a user is a member of
|
||||
WHEN @has_member_id::uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
|
||||
EXISTS (
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
-- this view handles the 'everyone' group in orgs.
|
||||
group_members_expanded
|
||||
WHERE
|
||||
group_members_expanded.group_id = groups.id
|
||||
AND
|
||||
group_members_expanded.user_id = @has_member_id
|
||||
)
|
||||
ELSE true
|
||||
END
|
||||
;
|
||||
|
||||
-- name: InsertGroup :one
|
||||
@@ -70,15 +74,15 @@ INSERT INTO groups (
|
||||
id,
|
||||
name,
|
||||
organization_id,
|
||||
source
|
||||
source
|
||||
)
|
||||
SELECT
|
||||
gen_random_uuid(),
|
||||
group_name,
|
||||
@organization_id,
|
||||
@source
|
||||
gen_random_uuid(),
|
||||
group_name,
|
||||
@organization_id,
|
||||
@source
|
||||
FROM
|
||||
UNNEST(@group_names :: text[]) AS group_name
|
||||
UNNEST(@group_names :: text[]) AS group_name
|
||||
-- If the name conflicts, do nothing.
|
||||
ON CONFLICT DO NOTHING
|
||||
RETURNING *;
|
||||
@@ -113,5 +117,3 @@ DELETE FROM
|
||||
groups
|
||||
WHERE
|
||||
id = $1;
|
||||
|
||||
|
||||
|
||||
@@ -491,7 +491,7 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo
|
||||
}
|
||||
ownerGroupNames := []string{}
|
||||
for _, group := range ownerGroups {
|
||||
ownerGroupNames = append(ownerGroupNames, group.Name)
|
||||
ownerGroupNames = append(ownerGroupNames, group.Group.Name)
|
||||
}
|
||||
err = s.Pubsub.Publish(codersdk.WorkspaceNotifyChannel(workspace.ID), []byte{})
|
||||
if err != nil {
|
||||
|
||||
@@ -373,7 +373,7 @@ func (r *remoteReporter) createSnapshot() (*Snapshot, error) {
|
||||
}
|
||||
snapshot.Groups = make([]Group, 0, len(groups))
|
||||
for _, group := range groups {
|
||||
snapshot.Groups = append(snapshot.Groups, ConvertGroup(group))
|
||||
snapshot.Groups = append(snapshot.Groups, ConvertGroup(group.Group))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
+6
-4
@@ -34,10 +34,12 @@ type Group struct {
|
||||
// How many members are in this group. Shows the total count,
|
||||
// even if the user is not authorized to read group member details.
|
||||
// May be greater than `len(Group.Members)`.
|
||||
TotalMemberCount int `json:"total_member_count"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
QuotaAllowance int `json:"quota_allowance"`
|
||||
Source GroupSource `json:"source"`
|
||||
TotalMemberCount int `json:"total_member_count"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
QuotaAllowance int `json:"quota_allowance"`
|
||||
Source GroupSource `json:"source"`
|
||||
OrganizationName string `json:"organization_name"`
|
||||
OrganizationDisplayName string `json:"organization_display_name"`
|
||||
}
|
||||
|
||||
func (g Group) IsEveryone() bool {
|
||||
|
||||
Generated
+93
-71
@@ -219,7 +219,9 @@ curl -X GET http://coder-server:8080/api/v2/groups?organization=string&has_membe
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"organization_display_name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"organization_name": "string",
|
||||
"quota_allowance": 0,
|
||||
"source": "user",
|
||||
"total_member_count": 0
|
||||
@@ -237,29 +239,31 @@ curl -X GET http://coder-server:8080/api/v2/groups?organization=string&has_membe
|
||||
|
||||
Status Code **200**
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ---------------------- | ------------------------------------------------------ | -------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `[array item]` | array | false | | |
|
||||
| `» avatar_url` | string | false | | |
|
||||
| `» display_name` | string | false | | |
|
||||
| `» id` | string(uuid) | false | | |
|
||||
| `» members` | array | false | | |
|
||||
| `»» avatar_url` | string(uri) | false | | |
|
||||
| `»» created_at` | string(date-time) | true | | |
|
||||
| `»» email` | string(email) | true | | |
|
||||
| `»» id` | string(uuid) | true | | |
|
||||
| `»» last_seen_at` | string(date-time) | false | | |
|
||||
| `»» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | false | | |
|
||||
| `»» name` | string | false | | |
|
||||
| `»» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | |
|
||||
| `»» theme_preference` | string | false | | |
|
||||
| `»» updated_at` | string(date-time) | false | | |
|
||||
| `»» username` | string | true | | |
|
||||
| `» name` | string | false | | |
|
||||
| `» organization_id` | string(uuid) | false | | |
|
||||
| `» quota_allowance` | integer | false | | |
|
||||
| `» source` | [codersdk.GroupSource](schemas.md#codersdkgroupsource) | false | | |
|
||||
| `» total_member_count` | integer | false | | How many members are in this group. Shows the total count, even if the user is not authorized to read group member details. May be greater than `len(Group.Members)`. |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ----------------------------- | ------------------------------------------------------ | -------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `[array item]` | array | false | | |
|
||||
| `» avatar_url` | string | false | | |
|
||||
| `» display_name` | string | false | | |
|
||||
| `» id` | string(uuid) | false | | |
|
||||
| `» members` | array | false | | |
|
||||
| `»» avatar_url` | string(uri) | false | | |
|
||||
| `»» created_at` | string(date-time) | true | | |
|
||||
| `»» email` | string(email) | true | | |
|
||||
| `»» id` | string(uuid) | true | | |
|
||||
| `»» last_seen_at` | string(date-time) | false | | |
|
||||
| `»» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | false | | |
|
||||
| `»» name` | string | false | | |
|
||||
| `»» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | |
|
||||
| `»» theme_preference` | string | false | | |
|
||||
| `»» updated_at` | string(date-time) | false | | |
|
||||
| `»» username` | string | true | | |
|
||||
| `» name` | string | false | | |
|
||||
| `» organization_display_name` | string | false | | |
|
||||
| `» organization_id` | string(uuid) | false | | |
|
||||
| `» organization_name` | string | false | | |
|
||||
| `» quota_allowance` | integer | false | | |
|
||||
| `» source` | [codersdk.GroupSource](schemas.md#codersdkgroupsource) | false | | |
|
||||
| `» total_member_count` | integer | false | | How many members are in this group. Shows the total count, even if the user is not authorized to read group member details. May be greater than `len(Group.Members)`. |
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
@@ -322,7 +326,9 @@ curl -X GET http://coder-server:8080/api/v2/groups/{group} \
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"organization_display_name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"organization_name": "string",
|
||||
"quota_allowance": 0,
|
||||
"source": "user",
|
||||
"total_member_count": 0
|
||||
@@ -381,7 +387,9 @@ curl -X DELETE http://coder-server:8080/api/v2/groups/{group} \
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"organization_display_name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"organization_name": "string",
|
||||
"quota_allowance": 0,
|
||||
"source": "user",
|
||||
"total_member_count": 0
|
||||
@@ -455,7 +463,9 @@ curl -X PATCH http://coder-server:8080/api/v2/groups/{group} \
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"organization_display_name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"organization_name": "string",
|
||||
"quota_allowance": 0,
|
||||
"source": "user",
|
||||
"total_member_count": 0
|
||||
@@ -1214,7 +1224,9 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/groups
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"organization_display_name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"organization_name": "string",
|
||||
"quota_allowance": 0,
|
||||
"source": "user",
|
||||
"total_member_count": 0
|
||||
@@ -1232,29 +1244,31 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/groups
|
||||
|
||||
Status Code **200**
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ---------------------- | ------------------------------------------------------ | -------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `[array item]` | array | false | | |
|
||||
| `» avatar_url` | string | false | | |
|
||||
| `» display_name` | string | false | | |
|
||||
| `» id` | string(uuid) | false | | |
|
||||
| `» members` | array | false | | |
|
||||
| `»» avatar_url` | string(uri) | false | | |
|
||||
| `»» created_at` | string(date-time) | true | | |
|
||||
| `»» email` | string(email) | true | | |
|
||||
| `»» id` | string(uuid) | true | | |
|
||||
| `»» last_seen_at` | string(date-time) | false | | |
|
||||
| `»» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | false | | |
|
||||
| `»» name` | string | false | | |
|
||||
| `»» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | |
|
||||
| `»» theme_preference` | string | false | | |
|
||||
| `»» updated_at` | string(date-time) | false | | |
|
||||
| `»» username` | string | true | | |
|
||||
| `» name` | string | false | | |
|
||||
| `» organization_id` | string(uuid) | false | | |
|
||||
| `» quota_allowance` | integer | false | | |
|
||||
| `» source` | [codersdk.GroupSource](schemas.md#codersdkgroupsource) | false | | |
|
||||
| `» total_member_count` | integer | false | | How many members are in this group. Shows the total count, even if the user is not authorized to read group member details. May be greater than `len(Group.Members)`. |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ----------------------------- | ------------------------------------------------------ | -------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `[array item]` | array | false | | |
|
||||
| `» avatar_url` | string | false | | |
|
||||
| `» display_name` | string | false | | |
|
||||
| `» id` | string(uuid) | false | | |
|
||||
| `» members` | array | false | | |
|
||||
| `»» avatar_url` | string(uri) | false | | |
|
||||
| `»» created_at` | string(date-time) | true | | |
|
||||
| `»» email` | string(email) | true | | |
|
||||
| `»» id` | string(uuid) | true | | |
|
||||
| `»» last_seen_at` | string(date-time) | false | | |
|
||||
| `»» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | false | | |
|
||||
| `»» name` | string | false | | |
|
||||
| `»» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | |
|
||||
| `»» theme_preference` | string | false | | |
|
||||
| `»» updated_at` | string(date-time) | false | | |
|
||||
| `»» username` | string | true | | |
|
||||
| `» name` | string | false | | |
|
||||
| `» organization_display_name` | string | false | | |
|
||||
| `» organization_id` | string(uuid) | false | | |
|
||||
| `» organization_name` | string | false | | |
|
||||
| `» quota_allowance` | integer | false | | |
|
||||
| `» source` | [codersdk.GroupSource](schemas.md#codersdkgroupsource) | false | | |
|
||||
| `» total_member_count` | integer | false | | How many members are in this group. Shows the total count, even if the user is not authorized to read group member details. May be greater than `len(Group.Members)`. |
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
@@ -1330,7 +1344,9 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/groups
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"organization_display_name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"organization_name": "string",
|
||||
"quota_allowance": 0,
|
||||
"source": "user",
|
||||
"total_member_count": 0
|
||||
@@ -1390,7 +1406,9 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/groups/
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"organization_display_name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"organization_name": "string",
|
||||
"quota_allowance": 0,
|
||||
"source": "user",
|
||||
"total_member_count": 0
|
||||
@@ -2136,7 +2154,9 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/acl/available \
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"organization_display_name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"organization_name": "string",
|
||||
"quota_allowance": 0,
|
||||
"source": "user",
|
||||
"total_member_count": 0
|
||||
@@ -2171,31 +2191,33 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/acl/available \
|
||||
|
||||
Status Code **200**
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ----------------------- | ------------------------------------------------------ | -------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `[array item]` | array | false | | |
|
||||
| `» groups` | array | false | | |
|
||||
| `»» avatar_url` | string | false | | |
|
||||
| `»» display_name` | string | false | | |
|
||||
| `»» id` | string(uuid) | false | | |
|
||||
| `»» members` | array | false | | |
|
||||
| `»»» avatar_url` | string(uri) | false | | |
|
||||
| `»»» created_at` | string(date-time) | true | | |
|
||||
| `»»» email` | string(email) | true | | |
|
||||
| `»»» id` | string(uuid) | true | | |
|
||||
| `»»» last_seen_at` | string(date-time) | false | | |
|
||||
| `»»» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | false | | |
|
||||
| `»»» name` | string | false | | |
|
||||
| `»»» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | |
|
||||
| `»»» theme_preference` | string | false | | |
|
||||
| `»»» updated_at` | string(date-time) | false | | |
|
||||
| `»»» username` | string | true | | |
|
||||
| `»» name` | string | false | | |
|
||||
| `»» organization_id` | string(uuid) | false | | |
|
||||
| `»» quota_allowance` | integer | false | | |
|
||||
| `»» source` | [codersdk.GroupSource](schemas.md#codersdkgroupsource) | false | | |
|
||||
| `»» total_member_count` | integer | false | | How many members are in this group. Shows the total count, even if the user is not authorized to read group member details. May be greater than `len(Group.Members)`. |
|
||||
| `» users` | array | false | | |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ------------------------------ | ------------------------------------------------------ | -------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `[array item]` | array | false | | |
|
||||
| `» groups` | array | false | | |
|
||||
| `»» avatar_url` | string | false | | |
|
||||
| `»» display_name` | string | false | | |
|
||||
| `»» id` | string(uuid) | false | | |
|
||||
| `»» members` | array | false | | |
|
||||
| `»»» avatar_url` | string(uri) | false | | |
|
||||
| `»»» created_at` | string(date-time) | true | | |
|
||||
| `»»» email` | string(email) | true | | |
|
||||
| `»»» id` | string(uuid) | true | | |
|
||||
| `»»» last_seen_at` | string(date-time) | false | | |
|
||||
| `»»» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | false | | |
|
||||
| `»»» name` | string | false | | |
|
||||
| `»»» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | |
|
||||
| `»»» theme_preference` | string | false | | |
|
||||
| `»»» updated_at` | string(date-time) | false | | |
|
||||
| `»»» username` | string | true | | |
|
||||
| `»» name` | string | false | | |
|
||||
| `»» organization_display_name` | string | false | | |
|
||||
| `»» organization_id` | string(uuid) | false | | |
|
||||
| `»» organization_name` | string | false | | |
|
||||
| `»» quota_allowance` | integer | false | | |
|
||||
| `»» source` | [codersdk.GroupSource](schemas.md#codersdkgroupsource) | false | | |
|
||||
| `»» total_member_count` | integer | false | | How many members are in this group. Shows the total count, even if the user is not authorized to read group member details. May be greater than `len(Group.Members)`. |
|
||||
| `» users` | array | false | | |
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
|
||||
Generated
+17
-11
@@ -244,7 +244,9 @@
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"organization_display_name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"organization_name": "string",
|
||||
"quota_allowance": 0,
|
||||
"source": "user",
|
||||
"total_member_count": 0
|
||||
@@ -2847,7 +2849,9 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"organization_display_name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"organization_name": "string",
|
||||
"quota_allowance": 0,
|
||||
"source": "user",
|
||||
"total_member_count": 0
|
||||
@@ -2856,17 +2860,19 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| -------------------- | ----------------------------------------------------- | -------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `avatar_url` | string | false | | |
|
||||
| `display_name` | string | false | | |
|
||||
| `id` | string | false | | |
|
||||
| `members` | array of [codersdk.ReducedUser](#codersdkreduceduser) | false | | |
|
||||
| `name` | string | false | | |
|
||||
| `organization_id` | string | false | | |
|
||||
| `quota_allowance` | integer | false | | |
|
||||
| `source` | [codersdk.GroupSource](#codersdkgroupsource) | false | | |
|
||||
| `total_member_count` | integer | false | | How many members are in this group. Shows the total count, even if the user is not authorized to read group member details. May be greater than `len(Group.Members)`. |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| --------------------------- | ----------------------------------------------------- | -------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `avatar_url` | string | false | | |
|
||||
| `display_name` | string | false | | |
|
||||
| `id` | string | false | | |
|
||||
| `members` | array of [codersdk.ReducedUser](#codersdkreduceduser) | false | | |
|
||||
| `name` | string | false | | |
|
||||
| `organization_display_name` | string | false | | |
|
||||
| `organization_id` | string | false | | |
|
||||
| `organization_name` | string | false | | |
|
||||
| `quota_allowance` | integer | false | | |
|
||||
| `source` | [codersdk.GroupSource](#codersdkgroupsource) | false | | |
|
||||
| `total_member_count` | integer | false | | How many members are in this group. Shows the total count, even if the user is not authorized to read group member details. May be greater than `len(Group.Members)`. |
|
||||
|
||||
## codersdk.GroupSource
|
||||
|
||||
|
||||
@@ -78,7 +78,11 @@ func (api *API) postGroupByOrganization(rw http.ResponseWriter, r *http.Request)
|
||||
var emptyMembers []database.GroupMember
|
||||
aReq.New = group.Auditable(emptyMembers)
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusCreated, db2sdk.Group(group, nil, 0))
|
||||
httpapi.Write(ctx, rw, http.StatusCreated, db2sdk.Group(database.GetGroupsRow{
|
||||
Group: group,
|
||||
OrganizationName: org.Name,
|
||||
OrganizationDisplayName: org.DisplayName,
|
||||
}, nil, 0))
|
||||
}
|
||||
|
||||
// @Summary Update group by name
|
||||
@@ -275,6 +279,11 @@ func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
org, err := api.Database.GetOrganizationByID(ctx, group.OrganizationID)
|
||||
if err != nil {
|
||||
httpapi.InternalServerError(rw, err)
|
||||
}
|
||||
|
||||
patchedMembers, err := api.Database.GetGroupMembersByGroupID(ctx, group.ID)
|
||||
if err != nil {
|
||||
httpapi.InternalServerError(rw, err)
|
||||
@@ -289,7 +298,11 @@ func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, db2sdk.Group(group, patchedMembers, int(memberCount)))
|
||||
httpapi.Write(ctx, rw, http.StatusOK, db2sdk.Group(database.GetGroupsRow{
|
||||
Group: group,
|
||||
OrganizationName: org.Name,
|
||||
OrganizationDisplayName: org.DisplayName,
|
||||
}, patchedMembers, int(memberCount)))
|
||||
}
|
||||
|
||||
// @Summary Delete group by name
|
||||
@@ -368,6 +381,11 @@ func (api *API) group(rw http.ResponseWriter, r *http.Request) {
|
||||
group = httpmw.GroupParam(r)
|
||||
)
|
||||
|
||||
org, err := api.Database.GetOrganizationByID(ctx, group.OrganizationID)
|
||||
if err != nil {
|
||||
httpapi.InternalServerError(rw, err)
|
||||
}
|
||||
|
||||
users, err := api.Database.GetGroupMembersByGroupID(ctx, group.ID)
|
||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
httpapi.InternalServerError(rw, err)
|
||||
@@ -380,7 +398,11 @@ func (api *API) group(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, db2sdk.Group(group, users, int(memberCount)))
|
||||
httpapi.Write(ctx, rw, http.StatusOK, db2sdk.Group(database.GetGroupsRow{
|
||||
Group: group,
|
||||
OrganizationName: org.Name,
|
||||
OrganizationDisplayName: org.DisplayName,
|
||||
}, users, int(memberCount)))
|
||||
}
|
||||
|
||||
// @Summary Get groups by organization
|
||||
@@ -456,12 +478,12 @@ func (api *API) groups(rw http.ResponseWriter, r *http.Request) {
|
||||
|
||||
resp := make([]codersdk.Group, 0, len(groups))
|
||||
for _, group := range groups {
|
||||
members, err := api.Database.GetGroupMembersByGroupID(ctx, group.ID)
|
||||
members, err := api.Database.GetGroupMembersByGroupID(ctx, group.Group.ID)
|
||||
if err != nil {
|
||||
httpapi.InternalServerError(rw, err)
|
||||
return
|
||||
}
|
||||
memberCount, err := api.Database.GetGroupMembersCountByGroupID(ctx, group.ID)
|
||||
memberCount, err := api.Database.GetGroupMembersCountByGroupID(ctx, group.Group.ID)
|
||||
if err != nil {
|
||||
httpapi.InternalServerError(rw, err)
|
||||
return
|
||||
|
||||
@@ -61,12 +61,12 @@ func (api *API) templateAvailablePermissions(rw http.ResponseWriter, r *http.Req
|
||||
sdkGroups := make([]codersdk.Group, 0, len(groups))
|
||||
for _, group := range groups {
|
||||
// nolint:gocritic
|
||||
members, err := api.Database.GetGroupMembersByGroupID(dbauthz.AsSystemRestricted(ctx), group.ID)
|
||||
members, err := api.Database.GetGroupMembersByGroupID(dbauthz.AsSystemRestricted(ctx), group.Group.ID)
|
||||
if err != nil {
|
||||
httpapi.InternalServerError(rw, err)
|
||||
return
|
||||
}
|
||||
memberCount, err := api.Database.GetGroupMembersCountByGroupID(ctx, group.ID)
|
||||
memberCount, err := api.Database.GetGroupMembersCountByGroupID(ctx, group.Group.ID)
|
||||
if err != nil {
|
||||
httpapi.InternalServerError(rw, err)
|
||||
return
|
||||
@@ -147,8 +147,12 @@ func (api *API) templateACL(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
groups = append(groups, codersdk.TemplateGroup{
|
||||
Group: db2sdk.Group(group.Group, members, int(memberCount)),
|
||||
Role: convertToTemplateRole(group.Actions),
|
||||
Group: db2sdk.Group(database.GetGroupsRow{
|
||||
Group: group.Group,
|
||||
OrganizationName: template.OrganizationName,
|
||||
OrganizationDisplayName: template.OrganizationDisplayName,
|
||||
}, members, int(memberCount)),
|
||||
Role: convertToTemplateRole(group.Actions),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+8
-2
@@ -1603,14 +1603,20 @@ class ApiMethods {
|
||||
return response.data;
|
||||
};
|
||||
|
||||
getGroups = async (): Promise<TypesGen.Group[]> => {
|
||||
const response = await this.axios.get("/api/v2/groups");
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param organization Can be the organization's ID or name
|
||||
*/
|
||||
getGroups = async (organization: string): Promise<TypesGen.Group[]> => {
|
||||
getGroupsByOrganization = async (
|
||||
organization: string,
|
||||
): Promise<TypesGen.Group[]> => {
|
||||
const response = await this.axios.get(
|
||||
`/api/v2/organizations/${organization}/groups`,
|
||||
);
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
|
||||
@@ -8,16 +8,25 @@ import type { QueryClient, UseQueryOptions } from "react-query";
|
||||
|
||||
type GroupSortOrder = "asc" | "desc";
|
||||
|
||||
const getGroupsQueryKey = (organization: string) => [
|
||||
const groupsQueryKey = ["groups"];
|
||||
|
||||
export const groups = () => {
|
||||
return {
|
||||
queryKey: groupsQueryKey,
|
||||
queryFn: () => API.getGroups(),
|
||||
} satisfies UseQueryOptions<Group[]>;
|
||||
};
|
||||
|
||||
const getGroupsByOrganizationQueryKey = (organization: string) => [
|
||||
"organization",
|
||||
organization,
|
||||
"groups",
|
||||
];
|
||||
|
||||
export const groups = (organization: string) => {
|
||||
export const groupsByOrganization = (organization: string) => {
|
||||
return {
|
||||
queryKey: getGroupsQueryKey(organization),
|
||||
queryFn: () => API.getGroups(organization),
|
||||
queryKey: getGroupsByOrganizationQueryKey(organization),
|
||||
queryFn: () => API.getGroupsByOrganization(organization),
|
||||
} satisfies UseQueryOptions<Group[]>;
|
||||
};
|
||||
|
||||
@@ -37,9 +46,9 @@ export const group = (organization: string, groupName: string) => {
|
||||
|
||||
export type GroupsByUserId = Readonly<Map<string, readonly Group[]>>;
|
||||
|
||||
export function groupsByUserId(organization: string) {
|
||||
export function groupsByUserId() {
|
||||
return {
|
||||
...groups(organization),
|
||||
...groups(),
|
||||
select: (allGroups) => {
|
||||
// Sorting here means that nothing has to be sorted for the individual
|
||||
// user arrays later
|
||||
@@ -63,14 +72,13 @@ export function groupsByUserId(organization: string) {
|
||||
} satisfies UseQueryOptions<Group[], unknown, GroupsByUserId>;
|
||||
}
|
||||
|
||||
export function groupsForUser(organization: string, userId: string) {
|
||||
export function groupsForUser(userId: string) {
|
||||
return {
|
||||
...groups(organization),
|
||||
...groups(),
|
||||
select: (allGroups) => {
|
||||
const groupsForUser = allGroups.filter((group) => {
|
||||
const groupMemberIds = group.members.map((member) => member.id);
|
||||
return groupMemberIds.includes(userId);
|
||||
});
|
||||
const groupsForUser = allGroups.filter((group) =>
|
||||
group.members.some((member) => member.id === userId),
|
||||
);
|
||||
|
||||
return sortGroupsByName(groupsForUser, "asc");
|
||||
},
|
||||
@@ -106,7 +114,10 @@ export const createGroup = (queryClient: QueryClient, organization: string) => {
|
||||
mutationFn: (request: CreateGroupRequest) =>
|
||||
API.createGroup(organization, request),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(getGroupsQueryKey(organization));
|
||||
await queryClient.invalidateQueries(groupsQueryKey);
|
||||
await queryClient.invalidateQueries(
|
||||
getGroupsByOrganizationQueryKey(organization),
|
||||
);
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -155,12 +166,15 @@ export const invalidateGroup = (
|
||||
groupId: string,
|
||||
) =>
|
||||
Promise.all([
|
||||
queryClient.invalidateQueries(getGroupsQueryKey(organization)),
|
||||
queryClient.invalidateQueries(groupsQueryKey),
|
||||
queryClient.invalidateQueries(
|
||||
getGroupsByOrganizationQueryKey(organization),
|
||||
),
|
||||
queryClient.invalidateQueries(getGroupQueryKey(organization, groupId)),
|
||||
]);
|
||||
|
||||
export function sortGroupsByName(
|
||||
groups: readonly Group[],
|
||||
export function sortGroupsByName<T extends Group>(
|
||||
groups: readonly T[],
|
||||
order: GroupSortOrder,
|
||||
) {
|
||||
return [...groups].sort((g1, g2) => {
|
||||
|
||||
Generated
+2
@@ -623,6 +623,8 @@ export interface Group {
|
||||
readonly avatar_url: string;
|
||||
readonly quota_allowance: number;
|
||||
readonly source: GroupSource;
|
||||
readonly organization_name: string;
|
||||
readonly organization_display_name: string;
|
||||
}
|
||||
|
||||
// From codersdk/groups.go
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getErrorMessage } from "api/errors";
|
||||
import { groups } from "api/queries/groups";
|
||||
import { groupsByOrganization } from "api/queries/groups";
|
||||
import { displayError } from "components/GlobalSnackbar/utils";
|
||||
import { useAuthenticated } from "contexts/auth/RequireAuth";
|
||||
import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility";
|
||||
@@ -12,7 +12,7 @@ import GroupsPageView from "./GroupsPageView";
|
||||
export const GroupsPage: FC = () => {
|
||||
const { permissions } = useAuthenticated();
|
||||
const { template_rbac: isTemplateRBACEnabled } = useFeatureVisibility();
|
||||
const groupsQuery = useQuery(groups("default"));
|
||||
const groupsQuery = useQuery(groupsByOrganization("default"));
|
||||
|
||||
useEffect(() => {
|
||||
if (groupsQuery.error) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import GroupAdd from "@mui/icons-material/GroupAddOutlined";
|
||||
import Button from "@mui/material/Button";
|
||||
import { getErrorMessage } from "api/errors";
|
||||
import { groups } from "api/queries/groups";
|
||||
import { groupsByOrganization } from "api/queries/groups";
|
||||
import { organizationPermissions } from "api/queries/organizations";
|
||||
import type { Organization } from "api/typesGenerated";
|
||||
import { EmptyState } from "components/EmptyState/EmptyState";
|
||||
@@ -21,11 +21,9 @@ import GroupsPageView from "./GroupsPageView";
|
||||
export const GroupsPage: FC = () => {
|
||||
const feats = useFeatureVisibility();
|
||||
const { organization: organizationName } = useParams() as {
|
||||
organization?: string;
|
||||
organization: string;
|
||||
};
|
||||
const groupsQuery = useQuery(
|
||||
organizationName ? groups(organizationName) : { enabled: false },
|
||||
);
|
||||
const groupsQuery = useQuery(groupsByOrganization(organizationName));
|
||||
const { organizations } = useOrganizationSettings();
|
||||
const organization = organizations?.find((o) => o.name === organizationName);
|
||||
const permissionsQuery = useQuery(organizationPermissions(organization?.id));
|
||||
|
||||
@@ -17,8 +17,7 @@ export const AccountPage: FC = () => {
|
||||
|
||||
const hasGroupsFeature = entitlements.features.user_role_management.enabled;
|
||||
const groupsQuery = useQuery({
|
||||
// TODO: This should probably list all groups, not just default org groups
|
||||
...groupsForUser("default", me.id),
|
||||
...groupsForUser(me.id),
|
||||
enabled: hasGroupsFeature,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import type { Group } from "api/typesGenerated";
|
||||
import {
|
||||
MockGroup as MockGroup1,
|
||||
MockUser,
|
||||
@@ -7,7 +6,7 @@ import {
|
||||
} from "testHelpers/entities";
|
||||
import { AccountUserGroups } from "./AccountUserGroups";
|
||||
|
||||
const MockGroup2: Group = {
|
||||
const MockGroup2 = {
|
||||
...MockGroup1,
|
||||
avatar_url: "",
|
||||
display_name: "Goofy Goobers",
|
||||
|
||||
@@ -55,12 +55,7 @@ export const AccountUserGroups: FC<AccountGroupsProps> = ({
|
||||
imgUrl={group.avatar_url}
|
||||
altText={group.display_name || group.name}
|
||||
header={group.display_name || group.name}
|
||||
subtitle={
|
||||
<>
|
||||
{group.total_member_count} member
|
||||
{group.total_member_count !== 1 && "s"}
|
||||
</>
|
||||
}
|
||||
subtitle={group.organization_display_name}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
|
||||
@@ -43,7 +43,7 @@ const UsersPage: FC = () => {
|
||||
const { entitlements, experiments } = useDashboard();
|
||||
const [searchParams] = searchParamsResult;
|
||||
|
||||
const groupsByUserIdQuery = useQuery(groupsByUserId("default"));
|
||||
const groupsByUserIdQuery = useQuery(groupsByUserId());
|
||||
const authMethodsQuery = useQuery(authMethods());
|
||||
|
||||
const { permissions, user: me } = useAuthenticated();
|
||||
|
||||
@@ -2512,27 +2512,33 @@ export const MockGroup: TypesGen.Group = {
|
||||
display_name: "Front-End",
|
||||
avatar_url: "https://example.com",
|
||||
organization_id: MockOrganization.id,
|
||||
organization_name: MockOrganization.name,
|
||||
organization_display_name: MockOrganization.display_name,
|
||||
members: [MockUser, MockUser2],
|
||||
quota_allowance: 5,
|
||||
source: "user",
|
||||
total_member_count: 2,
|
||||
};
|
||||
|
||||
const everyOneGroup = (organizationId: string): TypesGen.Group => ({
|
||||
id: organizationId,
|
||||
const MockEveryoneGroup: TypesGen.Group = {
|
||||
// The "Everyone" group must have the same ID as a the organization it belongs
|
||||
// to.
|
||||
id: MockOrganization.id,
|
||||
name: "Everyone",
|
||||
display_name: "",
|
||||
organization_id: organizationId,
|
||||
organization_id: MockOrganization.id,
|
||||
organization_name: MockOrganization.name,
|
||||
organization_display_name: MockOrganization.display_name,
|
||||
members: [],
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
total_member_count: 0,
|
||||
});
|
||||
};
|
||||
|
||||
export const MockTemplateACL: TypesGen.TemplateACL = {
|
||||
group: [
|
||||
{ ...everyOneGroup(MockOrganization.id), role: "use" },
|
||||
{ ...MockEveryoneGroup, role: "use" },
|
||||
{ ...MockGroup, role: "admin" },
|
||||
],
|
||||
users: [{ ...MockUser, role: "use" }],
|
||||
|
||||
Reference in New Issue
Block a user