iam: Fix debouncing in user, team and service account pickers (#100830)
iam: fix debouncing in user, team and service account pickers
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { debounce, DebouncedFuncLeading, isNil } from 'lodash';
|
||||
import debounce from 'debounce-promise';
|
||||
import { isNil } from 'lodash';
|
||||
import { Component } from 'react';
|
||||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
@@ -17,42 +18,38 @@ export interface State {
|
||||
}
|
||||
|
||||
export class ServiceAccountPicker extends Component<Props, State> {
|
||||
debouncedSearch: DebouncedFuncLeading<typeof this.search>;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = { isLoading: false };
|
||||
this.search = this.search.bind(this);
|
||||
|
||||
this.debouncedSearch = debounce(this.search, 300, {
|
||||
leading: true,
|
||||
trailing: true,
|
||||
});
|
||||
}
|
||||
|
||||
search(query?: string) {
|
||||
this.setState({ isLoading: true });
|
||||
search = debounce(
|
||||
async (query?: string) => {
|
||||
this.setState({ isLoading: true });
|
||||
|
||||
if (isNil(query)) {
|
||||
query = '';
|
||||
}
|
||||
if (isNil(query)) {
|
||||
query = '';
|
||||
}
|
||||
|
||||
return getBackendSrv()
|
||||
.get(`/api/serviceaccounts/search?query=${query}&perpage=100`)
|
||||
.then((result: ServiceAccountsState) => {
|
||||
return result.serviceAccounts.map((sa) => ({
|
||||
id: sa.id,
|
||||
uid: sa.uid,
|
||||
value: sa,
|
||||
label: sa.login,
|
||||
imgUrl: sa.avatarUrl,
|
||||
login: sa.login,
|
||||
}));
|
||||
})
|
||||
.finally(() => {
|
||||
this.setState({ isLoading: false });
|
||||
});
|
||||
}
|
||||
return getBackendSrv()
|
||||
.get(`/api/serviceaccounts/search?query=${query}&perpage=100`)
|
||||
.then((result: ServiceAccountsState) => {
|
||||
return result.serviceAccounts.map((sa) => ({
|
||||
id: sa.id,
|
||||
uid: sa.uid,
|
||||
value: sa,
|
||||
label: sa.login,
|
||||
imgUrl: sa.avatarUrl,
|
||||
login: sa.login,
|
||||
}));
|
||||
})
|
||||
.finally(() => {
|
||||
this.setState({ isLoading: false });
|
||||
});
|
||||
},
|
||||
300,
|
||||
{ leading: true }
|
||||
);
|
||||
|
||||
render() {
|
||||
const { className, onSelected, inputId } = this.props;
|
||||
@@ -66,7 +63,7 @@ export class ServiceAccountPicker extends Component<Props, State> {
|
||||
inputId={inputId}
|
||||
isLoading={isLoading}
|
||||
defaultOptions={true}
|
||||
loadOptions={this.debouncedSearch}
|
||||
loadOptions={this.search}
|
||||
onChange={onSelected}
|
||||
placeholder="Start typing to search for service accounts"
|
||||
noOptionsMessage="No service accounts found"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { debounce, DebouncedFuncLeading, isNil } from 'lodash';
|
||||
import debounce from 'debounce-promise';
|
||||
import { isNil } from 'lodash';
|
||||
import { Component } from 'react';
|
||||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
@@ -18,17 +19,9 @@ export interface State {
|
||||
}
|
||||
|
||||
export class TeamPicker extends Component<Props, State> {
|
||||
debouncedSearch: DebouncedFuncLeading<typeof this.search>;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = { isLoading: false };
|
||||
this.search = this.search.bind(this);
|
||||
|
||||
this.debouncedSearch = debounce(this.search, 300, {
|
||||
leading: true,
|
||||
trailing: true,
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
@@ -50,28 +43,32 @@ export class TeamPicker extends Component<Props, State> {
|
||||
});
|
||||
}
|
||||
|
||||
search(query?: string) {
|
||||
this.setState({ isLoading: true });
|
||||
search = debounce(
|
||||
async (query?: string) => {
|
||||
this.setState({ isLoading: true });
|
||||
|
||||
if (isNil(query)) {
|
||||
query = '';
|
||||
}
|
||||
if (isNil(query)) {
|
||||
query = '';
|
||||
}
|
||||
|
||||
return getBackendSrv()
|
||||
.get(`/api/teams/search?perpage=100&page=1&query=${query}`)
|
||||
.then((result: { teams: Team[] }) => {
|
||||
const teams: Array<SelectableValue<Team>> = result.teams.map((team) => {
|
||||
return {
|
||||
value: team,
|
||||
label: team.name,
|
||||
imgUrl: team.avatarUrl,
|
||||
};
|
||||
return getBackendSrv()
|
||||
.get(`/api/teams/search?perpage=100&page=1&query=${query}`)
|
||||
.then((result: { teams: Team[] }) => {
|
||||
const teams: Array<SelectableValue<Team>> = result.teams.map((team) => {
|
||||
return {
|
||||
value: team,
|
||||
label: team.name,
|
||||
imgUrl: team.avatarUrl,
|
||||
};
|
||||
});
|
||||
|
||||
this.setState({ isLoading: false });
|
||||
return teams;
|
||||
});
|
||||
|
||||
this.setState({ isLoading: false });
|
||||
return teams;
|
||||
});
|
||||
}
|
||||
},
|
||||
300,
|
||||
{ leading: true }
|
||||
);
|
||||
|
||||
render() {
|
||||
const { onSelected, className } = this.props;
|
||||
@@ -81,7 +78,7 @@ export class TeamPicker extends Component<Props, State> {
|
||||
<AsyncSelect
|
||||
isLoading={isLoading}
|
||||
defaultOptions={true}
|
||||
loadOptions={this.debouncedSearch}
|
||||
loadOptions={this.search}
|
||||
value={value}
|
||||
onChange={onSelected}
|
||||
className={className}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { debounce, DebouncedFuncLeading, isNil } from 'lodash';
|
||||
import debounce from 'debounce-promise';
|
||||
import { isNil } from 'lodash';
|
||||
import { Component } from 'react';
|
||||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
@@ -17,42 +18,38 @@ export interface State {
|
||||
}
|
||||
|
||||
export class UserPicker extends Component<Props, State> {
|
||||
debouncedSearch: DebouncedFuncLeading<typeof this.search>;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = { isLoading: false };
|
||||
this.search = this.search.bind(this);
|
||||
|
||||
this.debouncedSearch = debounce(this.search, 300, {
|
||||
leading: true,
|
||||
trailing: true,
|
||||
});
|
||||
}
|
||||
|
||||
search(query?: string) {
|
||||
this.setState({ isLoading: true });
|
||||
search = debounce(
|
||||
async (query?: string) => {
|
||||
this.setState({ isLoading: true });
|
||||
|
||||
if (isNil(query)) {
|
||||
query = '';
|
||||
}
|
||||
if (isNil(query)) {
|
||||
query = '';
|
||||
}
|
||||
|
||||
return getBackendSrv()
|
||||
.get(`/api/org/users/lookup?query=${query}&limit=100`)
|
||||
.then((result: OrgUser[]) => {
|
||||
return result.map((user) => ({
|
||||
id: user.userId,
|
||||
uid: user.uid,
|
||||
value: user,
|
||||
label: user.login,
|
||||
imgUrl: user.avatarUrl,
|
||||
login: user.login,
|
||||
}));
|
||||
})
|
||||
.finally(() => {
|
||||
this.setState({ isLoading: false });
|
||||
});
|
||||
}
|
||||
return getBackendSrv()
|
||||
.get(`/api/org/users/lookup?query=${query}&limit=100`)
|
||||
.then((result: OrgUser[]) => {
|
||||
return result.map((user) => ({
|
||||
id: user.userId,
|
||||
uid: user.uid,
|
||||
value: user,
|
||||
label: user.login,
|
||||
imgUrl: user.avatarUrl,
|
||||
login: user.login,
|
||||
}));
|
||||
})
|
||||
.finally(() => {
|
||||
this.setState({ isLoading: false });
|
||||
});
|
||||
},
|
||||
300,
|
||||
{ leading: true }
|
||||
);
|
||||
|
||||
render() {
|
||||
const { className, onSelected, inputId } = this.props;
|
||||
@@ -66,7 +63,7 @@ export class UserPicker extends Component<Props, State> {
|
||||
inputId={inputId}
|
||||
isLoading={isLoading}
|
||||
defaultOptions={true}
|
||||
loadOptions={this.debouncedSearch}
|
||||
loadOptions={this.search}
|
||||
onChange={onSelected}
|
||||
placeholder="Start typing to search for user"
|
||||
noOptionsMessage="No users found"
|
||||
|
||||
Reference in New Issue
Block a user