Skip to content

Commit 1ba5169

Browse files
chore(site): remove search users and groups xservice (#10353)
1 parent d335261 commit 1ba5169

File tree

10 files changed

+97
-204
lines changed

10 files changed

+97
-204
lines changed

site/src/api/queries/templates.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
type TemplateVersion,
77
CreateTemplateRequest,
88
ProvisionerJob,
9+
UsersRequest,
910
TemplateRole,
1011
} from "api/typesGenerated";
1112
import {
@@ -156,6 +157,16 @@ export const updateActiveTemplateVersion = (
156157
};
157158
};
158159

160+
export const templaceACLAvailable = (
161+
templateId: string,
162+
options: UsersRequest,
163+
) => {
164+
return {
165+
queryKey: ["template", templateId, "aclAvailable", options],
166+
queryFn: () => API.getTemplateACLAvailable(templateId, options),
167+
};
168+
};
169+
159170
export const templateVersionExternalAuthKey = (versionId: string) => [
160171
"templateVersion",
161172
versionId,

site/src/pages/TemplateSettingsPage/TemplatePermissionsPage/TemplatePermissionsPageView.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { TableRowMenu } from "components/TableRowMenu/TableRowMenu";
2525
import {
2626
UserOrGroupAutocomplete,
2727
UserOrGroupAutocompleteValue,
28-
} from "components/UserOrGroupAutocomplete/UserOrGroupAutocomplete";
28+
} from "./UserOrGroupAutocomplete";
2929
import { type FC, useState } from "react";
3030
import { GroupAvatar } from "components/GroupAvatar/GroupAvatar";
3131
import { getGroupSubtitle } from "utils/groups";
@@ -46,7 +46,6 @@ type AddTemplateUserOrGroupProps = {
4646
const AddTemplateUserOrGroup: React.FC<AddTemplateUserOrGroupProps> = ({
4747
isLoading,
4848
onSubmit,
49-
organizationId,
5049
templateID,
5150
templateACL,
5251
}) => {
@@ -82,7 +81,6 @@ const AddTemplateUserOrGroup: React.FC<AddTemplateUserOrGroupProps> = ({
8281
<Stack direction="row" alignItems="center" spacing={1}>
8382
<UserOrGroupAutocomplete
8483
exclude={excludeFromAutocomplete}
85-
organizationId={organizationId}
8684
templateID={templateID}
8785
value={selectedOption}
8886
onChange={(newValue) => {
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,85 @@
11
import CircularProgress from "@mui/material/CircularProgress";
22
import TextField from "@mui/material/TextField";
33
import Autocomplete from "@mui/material/Autocomplete";
4-
import { useMachine } from "@xstate/react";
54
import Box from "@mui/material/Box";
65
import { type ChangeEvent, useState } from "react";
76
import { css } from "@emotion/react";
87
import type { Group, User } from "api/typesGenerated";
98
import { AvatarData } from "components/AvatarData/AvatarData";
109
import { getGroupSubtitle } from "utils/groups";
11-
import { searchUsersAndGroupsMachine } from "xServices/template/searchUsersAndGroupsXService";
1210
import { useDebouncedFunction } from "hooks/debounce";
11+
import { useQuery } from "react-query";
12+
import { templaceACLAvailable } from "api/queries/templates";
13+
import { prepareQuery } from "utils/filters";
1314

1415
export type UserOrGroupAutocompleteValue = User | Group | null;
1516

16-
const isGroup = (value: UserOrGroupAutocompleteValue): value is Group => {
17-
return value !== null && "members" in value;
18-
};
19-
2017
export type UserOrGroupAutocompleteProps = {
2118
value: UserOrGroupAutocompleteValue;
2219
onChange: (value: UserOrGroupAutocompleteValue) => void;
23-
organizationId: string;
24-
templateID?: string;
20+
templateID: string;
2521
exclude: UserOrGroupAutocompleteValue[];
2622
};
2723

28-
const autoCompleteStyles = css`
29-
width: 300px;
30-
31-
& .MuiFormControl-root {
32-
width: 100%;
33-
}
34-
35-
& .MuiInputBase-root {
36-
width: 100%;
37-
}
38-
`;
39-
4024
export const UserOrGroupAutocomplete: React.FC<
4125
UserOrGroupAutocompleteProps
42-
> = ({ value, onChange, organizationId, templateID, exclude }) => {
43-
const [isAutocompleteOpen, setIsAutocompleteOpen] = useState(false);
44-
const [searchState, sendSearch] = useMachine(searchUsersAndGroupsMachine, {
45-
context: {
46-
userResults: [],
47-
groupResults: [],
48-
organizationId,
49-
templateID,
50-
},
26+
> = ({ value, onChange, templateID, exclude }) => {
27+
const [autoComplete, setAutoComplete] = useState<{
28+
value: string;
29+
open: boolean;
30+
}>({
31+
value: "",
32+
open: false,
5133
});
52-
const { userResults, groupResults } = searchState.context;
53-
const options = [...groupResults, ...userResults].filter((result) => {
54-
const excludeIds = exclude.map((optionToExclude) => optionToExclude?.id);
55-
return !excludeIds.includes(result.id);
34+
const aclAvailableQuery = useQuery({
35+
...templaceACLAvailable(templateID, {
36+
q: prepareQuery(encodeURI(autoComplete.value)),
37+
limit: 25,
38+
}),
39+
enabled: autoComplete.open,
40+
keepPreviousData: true,
5641
});
42+
const options = aclAvailableQuery.data
43+
? [
44+
...aclAvailableQuery.data.groups,
45+
...aclAvailableQuery.data.users,
46+
].filter((result) => {
47+
const excludeIds = exclude.map(
48+
(optionToExclude) => optionToExclude?.id,
49+
);
50+
return !excludeIds.includes(result.id);
51+
})
52+
: [];
5753

5854
const { debounced: handleFilterChange } = useDebouncedFunction(
5955
(event: ChangeEvent<HTMLInputElement>) => {
60-
sendSearch("SEARCH", { query: event.target.value });
56+
setAutoComplete((state) => ({
57+
...state,
58+
value: event.target.value,
59+
}));
6160
},
6261
500,
6362
);
6463

6564
return (
6665
<Autocomplete
66+
noOptionsText="No users or groups found"
6767
value={value}
6868
id="user-or-group-autocomplete"
69-
open={isAutocompleteOpen}
69+
open={autoComplete.open}
7070
onOpen={() => {
71-
setIsAutocompleteOpen(true);
71+
setAutoComplete((state) => ({
72+
...state,
73+
open: true,
74+
}));
7275
}}
7376
onClose={() => {
74-
setIsAutocompleteOpen(false);
77+
setAutoComplete({
78+
value: isGroup(value) ? value.display_name : value?.email ?? "",
79+
open: false,
80+
});
7581
}}
7682
onChange={(_, newValue) => {
77-
if (newValue === null) {
78-
sendSearch("CLEAR_RESULTS");
79-
}
80-
8183
onChange(newValue);
8284
}}
8385
isOptionEqualToValue={(option, value) => option.id === value.id}
@@ -102,7 +104,7 @@ export const UserOrGroupAutocomplete: React.FC<
102104
);
103105
}}
104106
options={options}
105-
loading={searchState.matches("searching")}
107+
loading={aclAvailableQuery.isFetching}
106108
css={autoCompleteStyles}
107109
renderInput={(params) => (
108110
<>
@@ -116,7 +118,7 @@ export const UserOrGroupAutocomplete: React.FC<
116118
onChange: handleFilterChange,
117119
endAdornment: (
118120
<>
119-
{searchState.matches("searching") ? (
121+
{aclAvailableQuery.isFetching ? (
120122
<CircularProgress size={16} />
121123
) : null}
122124
{params.InputProps.endAdornment}
@@ -129,3 +131,19 @@ export const UserOrGroupAutocomplete: React.FC<
129131
/>
130132
);
131133
};
134+
135+
const isGroup = (value: UserOrGroupAutocompleteValue): value is Group => {
136+
return value !== null && "members" in value;
137+
};
138+
139+
const autoCompleteStyles = css`
140+
width: 300px;
141+
142+
& .MuiFormControl-root {
143+
width: 100%;
144+
}
145+
146+
& .MuiInputBase-root {
147+
width: 100%;
148+
}
149+
`;

site/src/pages/UsersPage/UsersFilter.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ import {
1111
} from "components/Filter/filter";
1212
import { BaseOption } from "components/Filter/options";
1313
import { UseFilterMenuOptions, useFilterMenu } from "components/Filter/menu";
14-
import { userFilterQuery } from "utils/filters";
1514
import { docs } from "utils/docs";
1615

16+
const userFilterQuery = {
17+
active: "status:active",
18+
all: "",
19+
};
20+
1721
type StatusOption = BaseOption & {
1822
color: string;
1923
};

site/src/pages/WorkspacesPage/filter/filter.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,16 @@ import {
1616
useFilter,
1717
} from "components/Filter/filter";
1818
import { UserFilterMenu, UserMenu } from "components/Filter/UserFilter";
19-
import { workspaceFilterQuery } from "utils/filters";
2019
import { docs } from "utils/docs";
2120

21+
export const workspaceFilterQuery = {
22+
me: "owner:me",
23+
all: "",
24+
running: "status:running",
25+
failed: "status:failed",
26+
dormant: "is-dormant:true",
27+
};
28+
2229
type FilterPreset = {
2330
query: string;
2431
name: string;

site/src/testHelpers/entities.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
type Health,
66
} from "api/api";
77
import { FieldError } from "api/errors";
8-
import { everyOneGroup } from "utils/groups";
98
import * as TypesGen from "api/typesGenerated";
109
import range from "lodash/range";
1110
import { Permissions } from "components/AuthProvider/permissions";
@@ -2145,6 +2144,17 @@ export const MockGroup: TypesGen.Group = {
21452144
source: "user",
21462145
};
21472146

2147+
const everyOneGroup = (organizationId: string): TypesGen.Group => ({
2148+
id: organizationId,
2149+
name: "Everyone",
2150+
display_name: "",
2151+
organization_id: organizationId,
2152+
members: [],
2153+
avatar_url: "",
2154+
quota_allowance: 0,
2155+
source: "user",
2156+
});
2157+
21482158
export const MockTemplateACL: TypesGen.TemplateACL = {
21492159
group: [
21502160
{ ...everyOneGroup(MockOrganization.id), role: "use" },

site/src/utils/filters.test.ts

Lines changed: 0 additions & 20 deletions
This file was deleted.

site/src/utils/filters.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,3 @@
1-
import * as TypesGen from "api/typesGenerated";
2-
3-
export const queryToFilter = (
4-
query?: string,
5-
): TypesGen.WorkspaceFilter | TypesGen.UsersRequest => {
6-
return {
7-
q: prepareQuery(query),
8-
};
9-
};
10-
111
export const prepareQuery = (query?: string) => {
122
return query?.trim().replace(/ +/g, " ");
133
};
14-
15-
export const workspaceFilterQuery = {
16-
me: "owner:me",
17-
all: "",
18-
running: "status:running",
19-
failed: "status:failed",
20-
dormant: "is-dormant:true",
21-
};
22-
23-
export const userFilterQuery = {
24-
active: "status:active",
25-
all: "",
26-
};

site/src/utils/groups.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,5 @@
11
import { Group } from "api/typesGenerated";
22

3-
export const everyOneGroup = (organizationId: string): Group => ({
4-
id: organizationId,
5-
name: "Everyone",
6-
display_name: "",
7-
organization_id: organizationId,
8-
members: [],
9-
avatar_url: "",
10-
quota_allowance: 0,
11-
source: "user",
12-
});
13-
143
/**
154
* Returns true if the provided group is the 'Everyone' group.
165
* The everyone group represents all the users in an organization

0 commit comments

Comments
 (0)