Improve performance on user search results in add responders dropdown (#3325)

## Which issue(s) this PR fixes

Closes https://github.com/grafana/oncall/issues/3321

## Checklist

- [ ] Unit, integration, and e2e (if applicable) tests updated
- [ ] Documentation added (or `pr:no public docs` PR label added if not
required)
- [ ] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required)
This commit is contained in:
Joey Orlando 2023-11-13 08:43:33 -05:00 committed by GitHub
parent b2dda2fc35
commit 914a92cae8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 16 deletions

View file

@ -1,4 +1,6 @@
.add-responders-dropdown {
max-height: 500px;
overflow: hidden;
border: var(--border-medium);
position: absolute;
right: 16px;
@ -8,7 +10,7 @@
z-index: 10;
}
.team-direct-paging-info-alert {
.info-alert {
margin: 8px;
}

View file

@ -10,6 +10,7 @@ import GTable from 'components/GTable/GTable';
import Text from 'components/Text/Text';
import { Alert as AlertType } from 'models/alertgroup/alertgroup.types';
import { GrafanaTeam } from 'models/grafana_team/grafana_team.types';
import { PaginatedUsersResponse } from 'models/user/user';
import { UserCurrentlyOnCall } from 'models/user/user.types';
import { useStore } from 'state/useStore';
import { useDebouncedCallback, useOnClickOutside } from 'utils/hooks';
@ -51,12 +52,11 @@ const AddRespondersPopup = observer(
const [searchLoading, setSearchLoading] = useState<boolean>(true);
const [activeOption, setActiveOption] = useState<TabOptions>(isCreateMode ? TabOptions.Teams : TabOptions.Users);
const [teamSearchResults, setTeamSearchResults] = useState<GrafanaTeam[]>([]);
const [userSearchResults, setUserSearchResults] = useState<UserCurrentlyOnCall[]>([]);
const [onCallUserSearchResults, setOnCallUserSearchResults] = useState<UserCurrentlyOnCall[]>([]);
const [notOnCallUserSearchResults, setNotOnCallUserSearchResults] = useState<UserCurrentlyOnCall[]>([]);
const [searchTerm, setSearchTerm] = useState('');
const ref = useRef();
const usersCurrentlyOnCall = userSearchResults.filter(({ is_currently_oncall }) => is_currently_oncall);
const usersNotCurrentlyOnCall = userSearchResults.filter(({ is_currently_oncall }) => !is_currently_oncall);
useOnClickOutside(ref, () => {
setVisible(false);
@ -97,11 +97,18 @@ const AddRespondersPopup = observer(
);
const searchForUsers = useCallback(async () => {
/**
* specifying is_currently_oncall=all will tell the backend not to paginate the results
*/
const userResults = await userStore.search<UserCurrentlyOnCall[]>({ searchTerm, is_currently_oncall: 'all' });
setUserSearchResults(userResults);
const _search = async (is_currently_oncall: boolean) => {
const response = await userStore.search<PaginatedUsersResponse<UserCurrentlyOnCall>>({
searchTerm,
is_currently_oncall,
});
return response.results;
};
const [onCallUserSearchResults, notOnCallUserSearchResults] = await Promise.all([_search(true), _search(false)]);
setOnCallUserSearchResults(onCallUserSearchResults);
setNotOnCallUserSearchResults(notOnCallUserSearchResults);
}, [searchTerm]);
const searchForTeams = useCallback(async () => {
@ -153,9 +160,12 @@ const AddRespondersPopup = observer(
useEffect(() => {
if (existingPagedUsers.length > 0) {
const existingPagedUserIds = existingPagedUsers.map(({ pk }) => pk);
setUserSearchResults((userSearchResults) =>
userSearchResults.filter(({ pk }) => !existingPagedUserIds.includes(pk))
);
const _filterUsers = (users: UserCurrentlyOnCall[]) =>
users.filter(({ pk }) => !existingPagedUserIds.includes(pk));
setOnCallUserSearchResults(_filterUsers);
setNotOnCallUserSearchResults(_filterUsers);
}
}, [existingPagedUsers]);
@ -293,7 +303,7 @@ const AddRespondersPopup = observer(
) : (
<>
<Alert
className={cx('team-direct-paging-info-alert')}
className={cx('info-alert')}
severity="info"
title={
(
@ -330,8 +340,22 @@ const AddRespondersPopup = observer(
)}
{!searchLoading && activeOption === TabOptions.Users && (
<>
<UserResultsSection header="On-call now" users={usersCurrentlyOnCall} />
<UserResultsSection header="Not on-call" users={usersNotCurrentlyOnCall} />
<Alert
className={cx('info-alert')}
severity="info"
title={
(
<Text type="primary">
We display a maximum of 100 users per category. Use the search bar above to refine results. You
can search by username, email, or team name.
</Text>
) as any
}
/>
<UserResultsSection header="On-call now" users={onCallUserSearchResults} />
<div style={{ marginTop: '10px' }}>
<UserResultsSection header="Not on-call" users={notOnCallUserSearchResults} />
</div>
</>
)}
</div>

View file

@ -15,7 +15,7 @@ import { isUserActionAllowed, UserActions } from 'utils/authorization';
import { getTimezone, prepareForUpdate } from './user.helpers';
import { User } from './user.types';
type PaginatedUsersResponse<UT = User> = {
export type PaginatedUsersResponse<UT = User> = {
count: number;
page_size: number;
results: UT[];