Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4a32061

Browse files
rodrimaiajohnstcn
andauthored
feat(workspaces): change sorting order of the workspace list (coder#7594)
* feat(workspaces): implement sorting order on workspace list * split slice into its own function and test it * use require instead of assert * Update coderd/workspaces_internal_test.go Co-authored-by: Cian Johnston <[email protected]> * refactor tests into table tests * fix test --------- Co-authored-by: Cian Johnston <[email protected]>
1 parent 5d711fc commit 4a32061

File tree

2 files changed

+117
-5
lines changed

2 files changed

+117
-5
lines changed

coderd/workspaces.go

+23-5
Original file line numberDiff line numberDiff line change
@@ -1147,16 +1147,34 @@ func convertWorkspaces(workspaces []database.Workspace, data workspaceData) ([]c
11471147
&owner,
11481148
))
11491149
}
1150-
sort.Slice(apiWorkspaces, func(i, j int) bool {
1151-
iw := apiWorkspaces[i]
1152-
jw := apiWorkspaces[j]
1150+
1151+
sortWorkspaces(apiWorkspaces)
1152+
1153+
return apiWorkspaces, nil
1154+
}
1155+
1156+
func sortWorkspaces(workspaces []codersdk.Workspace) {
1157+
sort.Slice(workspaces, func(i, j int) bool {
1158+
iw := workspaces[i]
1159+
jw := workspaces[j]
1160+
1161+
if iw.LatestBuild.Status == codersdk.WorkspaceStatusRunning && jw.LatestBuild.Status != codersdk.WorkspaceStatusRunning {
1162+
return true
1163+
}
1164+
1165+
if jw.LatestBuild.Status == codersdk.WorkspaceStatusRunning && iw.LatestBuild.Status != codersdk.WorkspaceStatusRunning {
1166+
return false
1167+
}
1168+
1169+
if iw.OwnerID != jw.OwnerID {
1170+
return iw.OwnerName < jw.OwnerName
1171+
}
1172+
11531173
if jw.LastUsedAt.IsZero() && iw.LastUsedAt.IsZero() {
11541174
return iw.Name < jw.Name
11551175
}
11561176
return iw.LastUsedAt.After(jw.LastUsedAt)
11571177
})
1158-
1159-
return apiWorkspaces, nil
11601178
}
11611179

11621180
func convertWorkspace(

coderd/workspaces_internal_test.go

+94
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"testing"
55
"time"
66

7+
"github.com/google/uuid"
78
"github.com/stretchr/testify/require"
89

910
"github.com/coder/coder/coderd/database"
@@ -80,3 +81,96 @@ func Test_calculateDeletingAt(t *testing.T) {
8081
})
8182
}
8283
}
84+
85+
func TestSortWorkspaces(t *testing.T) {
86+
// the correct sorting order is:
87+
// 1. first show workspaces that are currently running,
88+
// 2. then sort by user_name,
89+
// 3. then sort by last_used_at (descending),
90+
t.Parallel()
91+
92+
workspaceFactory := func(t *testing.T, name string, ownerID uuid.UUID, ownerName string, status codersdk.WorkspaceStatus, lastUsedAt time.Time) codersdk.Workspace {
93+
t.Helper()
94+
return codersdk.Workspace{
95+
ID: uuid.New(),
96+
OwnerID: ownerID,
97+
OwnerName: ownerName,
98+
LatestBuild: codersdk.WorkspaceBuild{
99+
Status: status,
100+
},
101+
Name: name,
102+
LastUsedAt: lastUsedAt,
103+
}
104+
}
105+
106+
userAuuid := uuid.New()
107+
108+
workspaceRunningUserA := workspaceFactory(t, "running-userA", userAuuid, "userA", codersdk.WorkspaceStatusRunning, time.Now())
109+
workspaceRunningUserB := workspaceFactory(t, "running-userB", uuid.New(), "userB", codersdk.WorkspaceStatusRunning, time.Now())
110+
workspacePendingUserC := workspaceFactory(t, "pending-userC", uuid.New(), "userC", codersdk.WorkspaceStatusPending, time.Now())
111+
workspaceRunningUserA2 := workspaceFactory(t, "running-userA2", userAuuid, "userA", codersdk.WorkspaceStatusRunning, time.Now().Add(time.Minute))
112+
workspaceRunningUserZ := workspaceFactory(t, "running-userZ", uuid.New(), "userZ", codersdk.WorkspaceStatusRunning, time.Now())
113+
workspaceRunningUserA3 := workspaceFactory(t, "running-userA3", userAuuid, "userA", codersdk.WorkspaceStatusRunning, time.Now().Add(time.Hour))
114+
115+
testCases := []struct {
116+
name string
117+
input []codersdk.Workspace
118+
expectedOrder []string
119+
}{
120+
{
121+
name: "Running workspaces should be first",
122+
input: []codersdk.Workspace{
123+
workspaceRunningUserB,
124+
workspacePendingUserC,
125+
workspaceRunningUserA,
126+
},
127+
expectedOrder: []string{
128+
"running-userA",
129+
"running-userB",
130+
"pending-userC",
131+
},
132+
},
133+
{
134+
name: "then sort by owner name",
135+
input: []codersdk.Workspace{
136+
workspaceRunningUserZ,
137+
workspaceRunningUserA,
138+
workspaceRunningUserB,
139+
},
140+
expectedOrder: []string{
141+
"running-userA",
142+
"running-userB",
143+
"running-userZ",
144+
},
145+
},
146+
{
147+
name: "then sort by last used at (recent first)",
148+
input: []codersdk.Workspace{
149+
workspaceRunningUserA,
150+
workspaceRunningUserA2,
151+
workspaceRunningUserA3,
152+
},
153+
expectedOrder: []string{
154+
"running-userA3",
155+
"running-userA2",
156+
"running-userA",
157+
},
158+
},
159+
}
160+
161+
for _, tc := range testCases {
162+
tc := tc
163+
t.Run(tc.name, func(t *testing.T) {
164+
t.Parallel()
165+
workspaces := tc.input
166+
sortWorkspaces(workspaces)
167+
168+
var resultNames []string
169+
for _, workspace := range workspaces {
170+
resultNames = append(resultNames, workspace.Name)
171+
}
172+
173+
require.Equal(t, tc.expectedOrder, resultNames, tc.name)
174+
})
175+
}
176+
}

0 commit comments

Comments
 (0)