Skip to content

Commit 489b2fe

Browse files
committed
fix: Show suspended users in the UI
1 parent 8654dd1 commit 489b2fe

File tree

7 files changed

+61
-27
lines changed

7 files changed

+61
-27
lines changed

coderd/database/databasefake/databasefake.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -216,11 +216,13 @@ func (q *fakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams
216216
users = tmp
217217
}
218218

219-
if params.Status != "" {
219+
if len(params.Status) > 0 {
220220
usersFilteredByStatus := make([]database.User, 0, len(users))
221221
for i, user := range users {
222-
if params.Status == string(user.Status) {
223-
usersFilteredByStatus = append(usersFilteredByStatus, users[i])
222+
for _, status := range params.Status {
223+
if user.Status == status {
224+
usersFilteredByStatus = append(usersFilteredByStatus, users[i])
225+
}
224226
}
225227
}
226228
users = usersFilteredByStatus

coderd/database/queries.sql.go

+12-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/users.sql

+6-4
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,19 @@ WHERE
101101
WHEN @search :: text != '' THEN (
102102
email LIKE concat('%', @search, '%')
103103
OR username LIKE concat('%', @search, '%')
104-
)
104+
)
105105
ELSE true
106106
END
107107
-- Filter by status
108108
AND CASE
109109
-- @status needs to be a text because it can be empty, If it was
110110
-- user_status enum, it would not.
111-
WHEN @status :: text != '' THEN (
112-
status = @status :: user_status
111+
WHEN cardinality(@status :: user_status[]) > 0 THEN (
112+
status = ANY(@status :: user_status[])
113113
)
114-
ELSE true
114+
ELSE
115+
-- Only show active by default
116+
status = 'active'
115117
END
116118
-- End of filters
117119
ORDER BY

coderd/users.go

+17-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"errors"
88
"fmt"
99
"net/http"
10+
"strings"
1011
"time"
1112

1213
"github.com/go-chi/chi/v5"
@@ -105,10 +106,23 @@ func (api *API) postFirstUser(rw http.ResponseWriter, r *http.Request) {
105106

106107
func (api *API) users(rw http.ResponseWriter, r *http.Request) {
107108
var (
108-
searchName = r.URL.Query().Get("search")
109-
statusFilter = r.URL.Query().Get("status")
109+
searchName = r.URL.Query().Get("search")
110+
statusFilters = strings.Split(r.URL.Query().Get("status"), ",")
110111
)
111112

113+
statuses := make([]database.UserStatus, 0)
114+
for _, filter := range statusFilters {
115+
switch database.UserStatus(filter) {
116+
case database.UserStatusSuspended, database.UserStatusActive:
117+
statuses = append(statuses, database.UserStatus(filter))
118+
default:
119+
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
120+
Message: fmt.Sprintf("%q is not a valid user status", filter),
121+
})
122+
return
123+
}
124+
}
125+
112126
// Reading all users across the site
113127
if !api.Authorize(rw, r, rbac.ActionRead, rbac.ResourceUser) {
114128
return
@@ -124,7 +138,7 @@ func (api *API) users(rw http.ResponseWriter, r *http.Request) {
124138
OffsetOpt: int32(paginationParams.Offset),
125139
LimitOpt: int32(paginationParams.Limit),
126140
Search: searchName,
127-
Status: statusFilter,
141+
Status: statuses,
128142
})
129143
if errors.Is(err, sql.ErrNoRows) {
130144
httpapi.Write(rw, http.StatusOK, []codersdk.User{})

scripts/develop.sh

+6
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,11 @@ export CODER_DEV_ADMIN_PASSWORD=password
2424
trap 'kill 0' SIGINT
2525
CODERV2_HOST=http://127.0.0.1:3000 INSPECT_XSTATE=true yarn --cwd=./site dev &
2626
go run -tags embed cmd/coder/main.go server --dev --tunnel=true &
27+
28+
# Just a minor sleep to ensure the first user was created to make the member.
29+
sleep 2
30+
# || yes to always exit code 0. If this fails, whelp.
31+
go run cmd/coder/main.go users create --email=member@coder.com --username=member --password="${CODER_DEV_ADMIN_PASSWORD}" || yes
2732
wait
2833
)
34+

site/src/api/api.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export const getApiKey = async (): Promise<TypesGen.GenerateAPIKeyResponse> => {
6363
}
6464

6565
export const getUsers = async (): Promise<TypesGen.User[]> => {
66-
const response = await axios.get<TypesGen.User[]>("/api/v2/users?status=active")
66+
const response = await axios.get<TypesGen.User[]>("/api/v2/users?status=active,suspended")
6767
return response.data
6868
}
6969

site/src/components/UsersTable/UsersTable.tsx

+14-6
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ export const Language = {
1818
emptyMessage: "No users found",
1919
usernameLabel: "User",
2020
suspendMenuItem: "Suspend",
21+
activateMenuItem: "Activate",
2122
resetPasswordMenuItem: "Reset password",
2223
rolesLabel: "Roles",
24+
statusLabel: "Status",
2325
}
2426

2527
export interface UsersTableProps {
@@ -49,6 +51,7 @@ export const UsersTable: React.FC<UsersTableProps> = ({
4951
<TableRow>
5052
<TableCell>{Language.usernameLabel}</TableCell>
5153
<TableCell>{Language.rolesLabel}</TableCell>
54+
<TableCell>{Language.statusLabel}</TableCell>
5255
{/* 1% is a trick to make the table cell width fit the content */}
5356
{canEditUsers && <TableCell width="1%" />}
5457
</TableRow>
@@ -62,6 +65,9 @@ export const UsersTable: React.FC<UsersTableProps> = ({
6265
<TableCell>
6366
<AvatarData title={u.username} subtitle={u.email} />
6467
</TableCell>
68+
<TableCell>
69+
{u.status}
70+
</TableCell>
6571
<TableCell>
6672
{canEditUsers ? (
6773
<RoleSelect
@@ -78,16 +84,18 @@ export const UsersTable: React.FC<UsersTableProps> = ({
7884
<TableCell>
7985
<TableRowMenu
8086
data={u}
81-
menuItems={[
82-
{
87+
menuItems={
88+
// Return either suspend or activate depending on status
89+
(u.status == "active" ? [{
8390
label: Language.suspendMenuItem,
8491
onClick: onSuspendUser,
85-
},
86-
{
92+
}] : [{
93+
label: Language.activateMenuItem,
94+
onClick: onSuspendUser,
95+
}]).concat({
8796
label: Language.resetPasswordMenuItem,
8897
onClick: onResetUserPassword,
89-
},
90-
]}
98+
})}
9199
/>
92100
</TableCell>
93101
)}

0 commit comments

Comments
 (0)