mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 01:18:23 +00:00
[Feature] :: Allow users to be filtered via status (#4908)
* add: user filter via status * fix: typo in options name * refactor: add All options to status filters
This commit is contained in:
parent
c5d03f904c
commit
e50fa984ee
4 changed files with 43 additions and 11 deletions
|
|
@ -1,15 +1,28 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Select from '@/_ui/Select';
|
||||||
|
|
||||||
|
const userStatusOptions = [
|
||||||
|
{ name: 'All', value: '' },
|
||||||
|
{ name: 'Active', value: 'active' },
|
||||||
|
{ name: 'Invited', value: 'invited' },
|
||||||
|
{ name: 'Archived', value: 'archived' },
|
||||||
|
];
|
||||||
|
|
||||||
const UsersFilter = ({ filterList, darkMode, clearIconPressed }) => {
|
const UsersFilter = ({ filterList, darkMode, clearIconPressed }) => {
|
||||||
const [options, setOptions] = React.useState({ email: '', firstName: '', lastName: '' });
|
const [options, setOptions] = React.useState({ email: '', firstName: '', lastName: '', status: '' });
|
||||||
|
|
||||||
const valuesChanged = (event) => {
|
const valuesChanged = (event, key) => {
|
||||||
const newOptions = { ...options, [event.target.name]: event.target.value };
|
let newOptions = {};
|
||||||
|
if (!key) {
|
||||||
|
newOptions = { ...options, [event.target.name]: event.target.value };
|
||||||
|
} else {
|
||||||
|
newOptions = { ...options, [key]: event };
|
||||||
|
}
|
||||||
setOptions(newOptions);
|
setOptions(newOptions);
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearTextAndResult = () => {
|
const clearTextAndResult = () => {
|
||||||
setOptions({ email: '', firstName: '', lastName: '' });
|
setOptions({ email: '', firstName: '', lastName: '', status: '' });
|
||||||
clearIconPressed();
|
clearIconPressed();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -32,7 +45,7 @@ const UsersFilter = ({ filterList, darkMode, clearIconPressed }) => {
|
||||||
data-cy="email-filter-input-field"
|
data-cy="email-filter-input-field"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-3">
|
<div className="col-2">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
|
|
@ -44,7 +57,7 @@ const UsersFilter = ({ filterList, darkMode, clearIconPressed }) => {
|
||||||
data-cy="first-name-filter-input-field"
|
data-cy="first-name-filter-input-field"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-3">
|
<div className="col-2">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
|
|
@ -56,7 +69,17 @@ const UsersFilter = ({ filterList, darkMode, clearIconPressed }) => {
|
||||||
data-cy="last-name-filter-input-field"
|
data-cy="last-name-filter-input-field"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-3 d-flex gap-3">
|
<div className="col-2">
|
||||||
|
<Select
|
||||||
|
options={userStatusOptions}
|
||||||
|
value={options.status}
|
||||||
|
onChange={(value) => valuesChanged(value, 'status')}
|
||||||
|
width={'100%'}
|
||||||
|
height="36px"
|
||||||
|
useMenuPortal={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="col-2 d-flex gap-3">
|
||||||
<button type="submit" className="btn btn-primary" onClick={() => filterList(options)} data-cy="filter-button">
|
<button type="submit" className="btn btn-primary" onClick={() => filterList(options)} data-cy="filter-button">
|
||||||
Filter
|
Filter
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ export const organizationService = {
|
||||||
|
|
||||||
function getUsers(page, options) {
|
function getUsers(page, options) {
|
||||||
const requestOptions = { method: 'GET', headers: authHeader() };
|
const requestOptions = { method: 'GET', headers: authHeader() };
|
||||||
const { firstName, lastName, email } = options;
|
const { firstName, lastName, email, status } = options;
|
||||||
const query = queryString.stringify({ page, firstName, lastName, email });
|
const query = queryString.stringify({ page, firstName, lastName, email, status });
|
||||||
|
|
||||||
return fetch(`${config.apiUrl}/organizations/users?${query}`, requestOptions).then(handleResponse);
|
return fetch(`${config.apiUrl}/organizations/users?${query}`, requestOptions).then(handleResponse);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,12 @@ export class OrganizationsController {
|
||||||
@CheckPolicies((ability: AppAbility) => ability.can('viewAllUsers', UserEntity))
|
@CheckPolicies((ability: AppAbility) => ability.can('viewAllUsers', UserEntity))
|
||||||
@Get('users')
|
@Get('users')
|
||||||
async getUsers(@User() user, @Query() query) {
|
async getUsers(@User() user, @Query() query) {
|
||||||
const { page, email, firstName, lastName } = query;
|
const { page, email, firstName, lastName, status } = query;
|
||||||
const filterOptions = {
|
const filterOptions = {
|
||||||
...(email && { email }),
|
...(email && { email }),
|
||||||
...(firstName && { firstName }),
|
...(firstName && { firstName }),
|
||||||
...(lastName && { lastName }),
|
...(lastName && { lastName }),
|
||||||
|
...(status && { status }),
|
||||||
};
|
};
|
||||||
const usersCount = await this.organizationsService.usersCount(user, filterOptions);
|
const usersCount = await this.organizationsService.usersCount(user, filterOptions);
|
||||||
let users = [];
|
let users = [];
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ type FetchUserResponse = {
|
||||||
accountSetupToken?: string;
|
accountSetupToken?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type UserFilterOptions = { email?: string; firstName?: string; lastName?: string };
|
type UserFilterOptions = { email?: string; firstName?: string; lastName?: string; status?: string };
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class OrganizationsService {
|
export class OrganizationsService {
|
||||||
|
|
@ -150,6 +150,10 @@ export class OrganizationsService {
|
||||||
qb.orWhere('lower(user.lastName) like :lastName', {
|
qb.orWhere('lower(user.lastName) like :lastName', {
|
||||||
lastName: `%${options?.lastName.toLowerCase()}%`,
|
lastName: `%${options?.lastName.toLowerCase()}%`,
|
||||||
});
|
});
|
||||||
|
if (options?.status)
|
||||||
|
qb.orWhere('organization_user.status = :status', {
|
||||||
|
status: `${options?.status}`,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const getAndConditions = () => {
|
const getAndConditions = () => {
|
||||||
|
|
@ -166,6 +170,10 @@ export class OrganizationsService {
|
||||||
qb.andWhere('lower(user.lastName) like :lastName', {
|
qb.andWhere('lower(user.lastName) like :lastName', {
|
||||||
lastName: `%${options?.lastName.toLowerCase()}%`,
|
lastName: `%${options?.lastName.toLowerCase()}%`,
|
||||||
});
|
});
|
||||||
|
if (options?.status)
|
||||||
|
qb.andWhere('organization_user.status = :status', {
|
||||||
|
status: `${options?.status}`,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const query = createQueryBuilder(OrganizationUser, 'organization_user')
|
const query = createQueryBuilder(OrganizationUser, 'organization_user')
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue