Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit456e04f

Browse files
committed
Add filter search on Users page
1 parent8293894 commit456e04f

File tree

14 files changed

+108
-58
lines changed

14 files changed

+108
-58
lines changed

‎site/src/api/api.test.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
importaxiosfrom"axios"
2-
import{getApiKey,getWorkspacesURL,login,logout}from"./api"
2+
import{getApiKey,getURLWithSearchParams,login,logout}from"./api"
33
import*asTypesGenfrom"./typesGenerated"
44

55
describe("api.ts",()=>{
@@ -114,16 +114,19 @@ describe("api.ts", () => {
114114
})
115115
})
116116

117-
describe("getWorkspacesURL",()=>{
118-
it.each<[TypesGen.WorkspaceFilter|undefined,string]>([
119-
[undefined,"/api/v2/workspaces"],
117+
describe("getURLWithSearchParams",()=>{
118+
it.each<[string,TypesGen.WorkspaceFilter|TypesGen.UsersRequest|undefined,string]>([
119+
["/api/v2/workspaces",undefined,"/api/v2/workspaces"],
120120

121-
[{q:""},"/api/v2/workspaces"],
122-
[{q:"owner:1"},"/api/v2/workspaces?q=owner%3A1"],
121+
["/api/v2/workspaces",{q:""},"/api/v2/workspaces"],
122+
["/api/v2/workspaces",{q:"owner:1"},"/api/v2/workspaces?q=owner%3A1"],
123123

124-
[{q:"owner:me"},"/api/v2/workspaces?q=owner%3Ame"],
125-
])(`getWorkspacesURL(%p) returns %p`,(filter,expected)=>{
126-
expect(getWorkspacesURL(filter)).toBe(expected)
124+
["/api/v2/workspaces",{q:"owner:me"},"/api/v2/workspaces?q=owner%3Ame"],
125+
126+
["/api/v2/users",{q:"status:active"},"/api/v2/users?q=status%3Aactive"],
127+
["/api/v2/users",{q:""},"/api/v2/users"],
128+
])(`getURLWithSearchParams(%p) returns %p`,(basePath,filter,expected)=>{
129+
expect(getURLWithSearchParams(basePath,filter)).toBe(expected)
127130
})
128131
})
129132
})

‎site/src/api/api.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ export const getApiKey = async (): Promise<TypesGen.GenerateAPIKeyResponse> => {
7272
returnresponse.data
7373
}
7474

75-
exportconstgetUsers=async():Promise<TypesGen.User[]>=>{
76-
constresponse=awaitaxios.get<TypesGen.User[]>("/api/v2/users?q=status:active,suspended")
75+
exportconstgetUsers=async(filter?:TypesGen.UsersRequest):Promise<TypesGen.User[]>=>{
76+
consturl=getURLWithSearchParams("/api/v2/users",filter)
77+
constresponse=awaitaxios.get<TypesGen.User[]>(url)
7778
returnresponse.data
7879
}
7980

@@ -144,8 +145,10 @@ export const getWorkspace = async (
144145
returnresponse.data
145146
}
146147

147-
exportconstgetWorkspacesURL=(filter?:TypesGen.WorkspaceFilter):string=>{
148-
constbasePath="/api/v2/workspaces"
148+
exportconstgetURLWithSearchParams=(
149+
basePath:string,
150+
filter?:TypesGen.WorkspaceFilter|TypesGen.UsersRequest,
151+
):string=>{
149152
constsearchParams=newURLSearchParams()
150153

151154
if(filter?.q&&filter.q!==""){
@@ -160,7 +163,7 @@ export const getWorkspacesURL = (filter?: TypesGen.WorkspaceFilter): string => {
160163
exportconstgetWorkspaces=async(
161164
filter?:TypesGen.WorkspaceFilter,
162165
):Promise<TypesGen.Workspace[]>=>{
163-
consturl=getWorkspacesURL(filter)
166+
consturl=getURLWithSearchParams("/api/v2/workspaces",filter)
164167
constresponse=awaitaxios.get<TypesGen.Workspace[]>(url)
165168
returnresponse.data
166169
}

‎site/src/components/SearchBarWithFilter/SearchBarWithFilter.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import{ComponentMeta,Story}from"@storybook/react"
2-
import{workspaceFilterQuery}from"../../util/workspace"
2+
import{workspaceFilterQuery}from"../../util/filters"
33
import{SearchBarWithFilter,SearchBarWithFilterProps}from"./SearchBarWithFilter"
44

55
exportdefault{

‎site/src/pages/UsersPage/UsersPage.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import { useActor, useSelector } from "@xstate/react"
22
importReact,{useContext,useEffect}from"react"
33
import{Helmet}from"react-helmet"
44
import{useNavigate}from"react-router"
5+
import{useSearchParams}from"react-router-dom"
56
import{ConfirmDialog}from"../../components/ConfirmDialog/ConfirmDialog"
67
import{ResetPasswordDialog}from"../../components/ResetPasswordDialog/ResetPasswordDialog"
8+
import{userFilterQuery}from"../../util/filters"
79
import{pageTitle}from"../../util/page"
810
import{selectPermissions}from"../../xServices/auth/authSelectors"
911
import{XServiceContext}from"../../xServices/StateContext"
@@ -31,6 +33,7 @@ export const UsersPage: React.FC = () => {
3133
newUserPassword,
3234
}=usersState.context
3335
constnavigate=useNavigate()
36+
const[searchParams,setSearchParams]=useSearchParams()
3437
constuserToBeSuspended=users?.find((u)=>u.id===userIdToSuspend)
3538
constuserToBeActivated=users?.find((u)=>u.id===userIdToActivate)
3639
constuserToResetPassword=users?.find((u)=>u.id===userIdToResetPassword)
@@ -46,8 +49,13 @@ export const UsersPage: React.FC = () => {
4649

4750
// Fetch users on component mount
4851
useEffect(()=>{
49-
usersSend("GET_USERS")
50-
},[usersSend])
52+
constfilter=searchParams.get("filter")
53+
constquery=filter!==null ?filter :userFilterQuery.active
54+
usersSend({
55+
type:"GET_USERS",
56+
query,
57+
})
58+
},[searchParams,usersSend])
5159

5260
// Fetch roles on component mount
5361
useEffect(()=>{
@@ -91,6 +99,11 @@ export const UsersPage: React.FC = () => {
9199
isLoading={isLoading}
92100
canEditUsers={canEditUsers}
93101
canCreateUser={canCreateUser}
102+
filter={usersState.context.filter}
103+
onFilter={(query)=>{
104+
searchParams.set("filter",query)
105+
setSearchParams(searchParams)
106+
}}
94107
/>
95108

96109
<ConfirmDialog

‎site/src/pages/UsersPage/UsersPageView.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,21 @@ import * as TypesGen from "../../api/typesGenerated"
55
import{ErrorSummary}from"../../components/ErrorSummary/ErrorSummary"
66
import{Margins}from"../../components/Margins/Margins"
77
import{PageHeader,PageHeaderTitle}from"../../components/PageHeader/PageHeader"
8+
import{SearchBarWithFilter}from"../../components/SearchBarWithFilter/SearchBarWithFilter"
89
import{UsersTable}from"../../components/UsersTable/UsersTable"
10+
import{userFilterQuery}from"../../util/filters"
911

1012
exportconstLanguage={
1113
pageTitle:"Users",
1214
createButton:"New user",
15+
activeUsersFilterName:"Active users",
16+
allUsersFilterName:"All users",
1317
}
1418

1519
exportinterfaceUsersPageViewProps{
1620
users?:TypesGen.User[]
1721
roles?:TypesGen.Role[]
22+
filter?:string
1823
error?:unknown
1924
isUpdatingUserRoles?:boolean
2025
canEditUsers?:boolean
@@ -25,6 +30,7 @@ export interface UsersPageViewProps {
2530
onActivateUser:(user:TypesGen.User)=>void
2631
onResetUserPassword:(user:TypesGen.User)=>void
2732
onUpdateUserRoles:(user:TypesGen.User,roles:TypesGen.Role["name"][])=>void
33+
onFilter:(query:string)=>void
2834
}
2935

3036
exportconstUsersPageView:FC<UsersPageViewProps>=({
@@ -40,7 +46,14 @@ export const UsersPageView: FC<UsersPageViewProps> = ({
4046
canEditUsers,
4147
canCreateUser,
4248
isLoading,
49+
filter,
50+
onFilter,
4351
})=>{
52+
constpresetFilters=[
53+
{query:userFilterQuery.active,name:Language.activeUsersFilterName},
54+
{query:userFilterQuery.all,name:Language.allUsersFilterName},
55+
]
56+
4457
return(
4558
<Margins>
4659
<PageHeader
@@ -55,6 +68,8 @@ export const UsersPageView: FC<UsersPageViewProps> = ({
5568
<PageHeaderTitle>Users</PageHeaderTitle>
5669
</PageHeader>
5770

71+
<SearchBarWithFilterfilter={filter}onFilter={onFilter}presetFilters={presetFilters}/>
72+
5873
{error ?(
5974
<ErrorSummaryerror={error}/>
6075
) :(

‎site/src/pages/WorkspacesPage/WorkspacesPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { useMachine } from "@xstate/react"
22
import{FC,useEffect}from"react"
33
import{Helmet}from"react-helmet"
44
import{useSearchParams}from"react-router-dom"
5+
import{workspaceFilterQuery}from"../../util/filters"
56
import{pageTitle}from"../../util/page"
6-
import{workspaceFilterQuery}from"../../util/workspace"
77
import{workspacesMachine}from"../../xServices/workspaces/workspacesXService"
88
import{WorkspacesPageView}from"./WorkspacesPageView"
99

‎site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ComponentMeta, Story } from "@storybook/react"
22
import{spawn}from"xstate"
33
import{ProvisionerJobStatus,WorkspaceTransition}from"../../api/typesGenerated"
44
import{MockWorkspace}from"../../testHelpers/entities"
5-
import{workspaceFilterQuery}from"../../util/workspace"
5+
import{workspaceFilterQuery}from"../../util/filters"
66
import{
77
workspaceItemMachine,
88
WorkspaceItemMachineRef,

‎site/src/pages/WorkspacesPage/WorkspacesPageView.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ import {
3535
HelpTooltipText,
3636
HelpTooltipTitle,
3737
}from"../../components/Tooltips/HelpTooltip/HelpTooltip"
38-
import{getDisplayStatus,workspaceFilterQuery}from"../../util/workspace"
38+
import{workspaceFilterQuery}from"../../util/filters"
39+
import{getDisplayStatus}from"../../util/workspace"
3940
import{WorkspaceItemMachineRef}from"../../xServices/workspaces/workspacesXService"
4041

4142
dayjs.extend(relativeTime)

‎site/src/util/filters.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import*asTypesGenfrom"../api/typesGenerated"
2+
import{queryToFilter}from"./filters"
3+
4+
describe("queryToFilter",()=>{
5+
it.each<[string|undefined,TypesGen.WorkspaceFilter|TypesGen.UsersRequest]>([
6+
[undefined,{}],
7+
["",{q:""}],
8+
["asdkfvjn",{q:"asdkfvjn"}],
9+
["owner:me",{q:"owner:me"}],
10+
["owner:me owner:me2",{q:"owner:me owner:me2"}],
11+
["me/dev",{q:"me/dev"}],
12+
["me/",{q:"me/"}],
13+
[" key:val owner:me ",{q:"key:val owner:me"}],
14+
])(`query=%p, filter=%p`,(query,filter)=>{
15+
expect(queryToFilter(query)).toEqual(filter)
16+
})
17+
})

‎site/src/util/filters.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import*asTypesGenfrom"../api/typesGenerated"
2+
3+
exportconstqueryToFilter=(query?:string):TypesGen.WorkspaceFilter|TypesGen.UsersRequest=>{
4+
constpreparedQuery=query?.trim().replace(/+/g," ")
5+
return{
6+
q:preparedQuery,
7+
}
8+
}
9+
10+
exportconstworkspaceFilterQuery={
11+
me:"owner:me",
12+
all:"",
13+
}
14+
15+
exportconstuserFilterQuery={
16+
active:"status:active",
17+
all:"",
18+
}

‎site/src/util/workspace.test.ts

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
importdayjsfrom"dayjs"
22
import*asTypesGenfrom"../api/typesGenerated"
33
import*asMocksfrom"../testHelpers/entities"
4-
import{
5-
defaultWorkspaceExtension,
6-
isWorkspaceDeleted,
7-
isWorkspaceOn,
8-
workspaceQueryToFilter,
9-
}from"./workspace"
4+
import{defaultWorkspaceExtension,isWorkspaceDeleted,isWorkspaceOn}from"./workspace"
105

116
describe("util > workspace",()=>{
127
describe("isWorkspaceOn",()=>{
@@ -106,18 +101,4 @@ describe("util > workspace", () => {
106101
expect(defaultWorkspaceExtension(dayjs(startTime))).toEqual(request)
107102
})
108103
})
109-
describe("workspaceQueryToFilter",()=>{
110-
it.each<[string|undefined,TypesGen.WorkspaceFilter]>([
111-
[undefined,{}],
112-
["",{q:""}],
113-
["asdkfvjn",{q:"asdkfvjn"}],
114-
["owner:me",{q:"owner:me"}],
115-
["owner:me owner:me2",{q:"owner:me owner:me2"}],
116-
["me/dev",{q:"me/dev"}],
117-
["me/",{q:"me/"}],
118-
[" key:val owner:me ",{q:"key:val owner:me"}],
119-
])(`query=%p, filter=%p`,(query,filter)=>{
120-
expect(workspaceQueryToFilter(query)).toEqual(filter)
121-
})
122-
})
123104
})

‎site/src/util/workspace.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -296,15 +296,3 @@ export const defaultWorkspaceExtension = (
296296
deadline:fourHoursFromNow.format(),
297297
}
298298
}
299-
300-
exportconstworkspaceQueryToFilter=(query?:string):TypesGen.WorkspaceFilter=>{
301-
constpreparedQuery=query?.trim().replace(/+/g," ")
302-
return{
303-
q:preparedQuery,
304-
}
305-
}
306-
307-
exportconstworkspaceFilterQuery={
308-
me:"owner:me",
309-
all:"",
310-
}

‎site/src/xServices/users/usersXService.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
}from"../../api/errors"
1111
import*asTypesGenfrom"../../api/typesGenerated"
1212
import{displayError,displaySuccess}from"../../components/GlobalSnackbar/utils"
13+
import{queryToFilter}from"../../util/filters"
1314
import{generateRandomString}from"../../util/random"
1415

1516
exportconstLanguage={
@@ -28,6 +29,7 @@ export const Language = {
2829
exportinterfaceUsersContext{
2930
// Get users
3031
users?:TypesGen.User[]
32+
filter?:string
3133
getUsersError?:Error|unknown
3234
createUserErrorMessage?:string
3335
createUserFormErrors?:FieldErrors
@@ -47,7 +49,7 @@ export interface UsersContext {
4749
}
4850

4951
exporttypeUsersEvent=
50-
|{type:"GET_USERS"}
52+
|{type:"GET_USERS";query:string}
5153
|{type:"CREATE";user:TypesGen.CreateUserRequest}
5254
|{type:"CANCEL_CREATE_USER"}
5355
// Suspend events
@@ -97,7 +99,10 @@ export const usersMachine = createMachine(
9799
states:{
98100
idle:{
99101
on:{
100-
GET_USERS:"gettingUsers",
102+
GET_USERS:{
103+
actions:"assignFilter",
104+
target:"gettingUsers",
105+
},
101106
CREATE:"creatingUser",
102107
CANCEL_CREATE_USER:{actions:["clearCreateUserError"]},
103108
SUSPEND_USER:{
@@ -242,7 +247,10 @@ export const usersMachine = createMachine(
242247
},
243248
error:{
244249
on:{
245-
GET_USERS:"gettingUsers",
250+
GET_USERS:{
251+
actions:"assignFilter",
252+
target:"gettingUsers",
253+
},
246254
},
247255
},
248256
},
@@ -252,7 +260,7 @@ export const usersMachine = createMachine(
252260
// Passing API.getUsers directly does not invoke the function properly
253261
// when it is mocked. This happen in the UsersPage tests inside of the
254262
// "shows a success message and refresh the page" test case.
255-
getUsers:()=>API.getUsers(),
263+
getUsers:(context)=>API.getUsers(queryToFilter(context.filter)),
256264
createUser:(_,event)=>API.createUser(event.user),
257265
suspendUser:(context)=>{
258266
if(!context.userIdToSuspend){
@@ -297,6 +305,9 @@ export const usersMachine = createMachine(
297305
assignUsers:assign({
298306
users:(_,event)=>event.data,
299307
}),
308+
assignFilter:assign({
309+
filter:(_,event)=>event.query,
310+
}),
300311
assignGetUsersError:assign({
301312
getUsersError:(_,event)=>event.data,
302313
}),

‎site/src/xServices/workspaces/workspacesXService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as API from "../../api/api"
33
import{getErrorMessage}from"../../api/errors"
44
import*asTypesGenfrom"../../api/typesGenerated"
55
import{displayError,displayMsg,displaySuccess}from"../../components/GlobalSnackbar/utils"
6-
import{workspaceQueryToFilter}from"../../util/workspace"
6+
import{queryToFilter}from"../../util/filters"
77

88
/**
99
* Workspace item machine
@@ -318,7 +318,7 @@ export const workspacesMachine = createMachine(
318318
}),
319319
},
320320
services:{
321-
getWorkspaces:(context)=>API.getWorkspaces(workspaceQueryToFilter(context.filter)),
321+
getWorkspaces:(context)=>API.getWorkspaces(queryToFilter(context.filter)),
322322
},
323323
},
324324
)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp