Skip to content

Commit

Permalink
Engagement listing filtering (#1493)
Browse files Browse the repository at this point in the history
* setup new engagement listing fields

* add back end filtering

* name cleanup

* update engagement listing tests

* naming update

* api lint

* finish front end

* allow for multiple fields

* api lint

* API Lint

* flake 8

* partial matching

* flake 8

* lint

* more lint
  • Loading branch information
djnunez-aot authored Apr 13, 2023
1 parent 31a7930 commit a5a94d9
Show file tree
Hide file tree
Showing 9 changed files with 410 additions and 24 deletions.
31 changes: 26 additions & 5 deletions met-api/src/met_api/models/engagement.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def get_engagements_paginated(

query = cls._filter_by_engagement_status(query, search_options)

query = cls._filter_by_project_type(query, search_options.get('project_type'))
query = cls._filter_by_project_metadata(query, search_options)

if assigned_engagements is not None:
query = cls._filter_by_assigned_engagements(query, assigned_engagements)
Expand Down Expand Up @@ -233,11 +233,32 @@ def _filter_by_search_text(query, search_options):
return query

@staticmethod
def _filter_by_project_type(query, project_type=None):
if project_type:
query = query.outerjoin(EngagementMetadataModel, EngagementMetadataModel.engagement_id == Engagement.id)\
.filter(EngagementMetadataModel.project_metadata['type'].astext == project_type)\
def _filter_by_project_metadata(query, search_options):
query = query.outerjoin(EngagementMetadataModel, EngagementMetadataModel.engagement_id == Engagement.id)

if project_type := search_options.get('project_type'):
query = query.filter(EngagementMetadataModel.project_metadata['type'].astext.ilike(f'%{project_type}%'))\
.params(val=project_type)

if project_name := search_options.get('project_name'):
query = query.filter(EngagementMetadataModel.project_metadata['project_name']
.astext.ilike(f'%{project_name}%'))\
.params(val=project_name)

if project_id := search_options.get('project_id'):
query = query.filter(EngagementMetadataModel.project_id == project_id)\
.params(val=project_id)

if application_number := search_options.get('application_number'):
query = query.filter(EngagementMetadataModel.project_metadata['application_number']
.astext.ilike(f'%{application_number}%'))\
.params(val=application_number)

if client_name := search_options.get('client_name'):
query = query.filter(EngagementMetadataModel.project_metadata['client_name']
.astext.ilike(f'%{client_name}%'))\
.params(val=client_name)

return query

@staticmethod
Expand Down
4 changes: 4 additions & 0 deletions met-api/src/met_api/resources/engagement.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ def get():
'published_from_date': args.get('published_from_date', None, type=str),
'published_to_date': args.get('published_to_date', None, type=str),
'project_type': args.get('project_type', None, type=str),
'project_id': args.get('project_id', None, type=str),
'project_name': args.get('project_name', None, type=str),
'application_number': args.get('application_number', None, type=str),
'client_name': args.get('client_name', None, type=str),
}

engagement_records = EngagementService()\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const initialEngagementFormData = {
end_date: '',
description: '',
content: '',

project_id: '',
project_metadata: {
project_name: '',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
import React, { useState } from 'react';
import { Grid, Stack, TextField, FormGroup, FormControlLabel, Checkbox } from '@mui/material';
import {
Grid,
Stack,
TextField,
FormGroup,
FormControlLabel,
Checkbox,
Select,
SelectChangeEvent,
MenuItem,
} from '@mui/material';
import { MetParagraph, MetLabel } from 'components/common';
import { EngagementDisplayStatus } from 'constants/engagementStatus';
import { PrimaryButton, SecondaryButton } from '../../../common';
import dayjs from 'dayjs';
import { formatToUTC } from 'components/common/dateHelper';
import { SearchOptions } from './SearchTypes';
import { AppConfig } from 'config';

interface filterParams {
setFilterParams: (newsearchOptions: SearchOptions) => void;
}

const AdvancedSearch: React.FC<filterParams> = ({ setFilterParams }) => {
const { engagementProjectTypes } = AppConfig.constants;

const intitialStatusList = {
[EngagementDisplayStatus[EngagementDisplayStatus.Draft]]: false,
[EngagementDisplayStatus[EngagementDisplayStatus.Scheduled]]: false,
Expand All @@ -22,8 +35,14 @@ const AdvancedSearch: React.FC<filterParams> = ({ setFilterParams }) => {
const [statusFilter, setStatusFilter] = useState(() => {
return intitialStatusList;
});

const initialFilterParams = {
status_list: [],
project_name: '',
project_id: '',
application_number: '',
client_name: '',
project_type: '',
created_from_date: '',
created_to_date: '',
published_from_date: '',
Expand All @@ -45,6 +64,14 @@ const AdvancedSearch: React.FC<filterParams> = ({ setFilterParams }) => {
);
};

const [projectFilter, setProjectFilter] = useState({
projectType: '',
projectId: '',
projectName: '',
clientName: '',
applicationNumber: '',
});

const [dateFilter, setDateFilter] = useState({
createdFromDate: '',
createdToDate: '',
Expand All @@ -53,13 +80,24 @@ const AdvancedSearch: React.FC<filterParams> = ({ setFilterParams }) => {
});
const { createdFromDate, createdToDate, publishedFromDate, publishedToDate } = dateFilter;

const { projectType, projectId, projectName, clientName, applicationNumber } = projectFilter;

const handleDateFilterChange = (e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
setDateFilter({
...dateFilter,
[e.target.name]: e.target.value,
});
};

const handleProjectDataChange = (
e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement> | SelectChangeEvent,
) => {
setProjectFilter({
...projectFilter,
[e.target.name]: e.target.value,
});
};

const handleSearch = () => {
/*
Database has the values in utc but the value we select from the calender is having only date without a time.
Expand All @@ -75,20 +113,38 @@ const AdvancedSearch: React.FC<filterParams> = ({ setFilterParams }) => {
const fPublishedToDate = publishedToDate
? formatToUTC(dayjs(publishedToDate).endOf('day').format('YYYY-MM-DD HH:mm:ss'))
: publishedToDate;
const fProjectType = projectType ? projectType : '';
const fprojectId = projectId ? projectId : '';
const fProjectName = projectName ? projectName : '';
const fClientName = clientName ? clientName : '';
const fAppNumber = applicationNumber ? applicationNumber : '';

setFilterParams({
status_list: selectedStatusList,
created_from_date: fCreatedFromDate,
created_to_date: fCreatedToDate,
published_from_date: fPublishedFromDate,
published_to_date: fPublishedToDate,
project_type: fProjectType,
project_id: fprojectId,
project_name: fProjectName,
client_name: fClientName,
application_number: fAppNumber,
});
};

const handleResetSearchFilters = () => {
setStatusFilter(intitialStatusList);
setSelectedStatusList([]);

setProjectFilter({
projectType: '',
projectId: '',
projectName: '',
clientName: '',
applicationNumber: '',
});

setDateFilter({
createdFromDate: '',
createdToDate: '',
Expand All @@ -101,8 +157,8 @@ const AdvancedSearch: React.FC<filterParams> = ({ setFilterParams }) => {

return (
<>
<Grid container direction="row" item mt={3} ml={2}>
<Grid item md={3} xs={12}>
<Grid container direction="row" item mt={3} ml={2} spacing={2}>
<Grid item md={1.5} xs={12} pr={1}>
<Grid item xs={12}>
<MetLabel>Status</MetLabel>
</Grid>
Expand Down Expand Up @@ -171,7 +227,7 @@ const AdvancedSearch: React.FC<filterParams> = ({ setFilterParams }) => {
}
label={
<MetParagraph>
Published - {EngagementDisplayStatus[EngagementDisplayStatus.Upcoming]}
{EngagementDisplayStatus[EngagementDisplayStatus.Upcoming]}
</MetParagraph>
}
/>
Expand Down Expand Up @@ -219,6 +275,124 @@ const AdvancedSearch: React.FC<filterParams> = ({ setFilterParams }) => {
</Grid>
</Grid>
<Grid item md={3} xs={12}>
<Grid item xs={12}>
<MetLabel>Project Name</MetLabel>
</Grid>
<Grid item xs={12}>
<Stack direction="row" alignItems="center" spacing={2}>
<TextField
id="project-name"
data-testid="project-name"
type="project_name"
InputLabelProps={{
shrink: false,
}}
sx={{ width: '80%' }}
name="projectName"
value={projectName}
onChange={handleProjectDataChange}
InputProps={{ inputProps: { max: projectName || null } }}
/>
</Stack>
</Grid>
<Grid item xs={12} mt={3}>
<MetLabel>Project #</MetLabel>
</Grid>
<Grid item xs={12}>
<Stack direction="row" alignItems="center" spacing={2}>
<TextField
id="project_id"
data-testid="project_id"
type="project_id"
InputLabelProps={{
shrink: false,
}}
sx={{ width: '80%' }}
name="projectId"
value={projectId}
onChange={handleProjectDataChange}
InputProps={{ inputProps: { max: projectId || null } }}
/>
</Stack>
</Grid>
<Grid item xs={12} mt={3}>
<MetLabel>Application #</MetLabel>
</Grid>
<Grid item xs={12}>
<Stack direction="row" alignItems="center" spacing={2}>
<TextField
id="application_number"
data-testid="application_number"
type="application_number"
InputLabelProps={{
shrink: false,
}}
sx={{ width: '80%' }}
name="applicationNumber"
value={applicationNumber}
onChange={handleProjectDataChange}
InputProps={{ inputProps: { max: applicationNumber || null } }}
/>
</Stack>
</Grid>
</Grid>
<Grid item md={3} xs={12}>
<Grid item xs={12}>
<MetLabel>Proponent</MetLabel>
</Grid>
<Grid item xs={12}>
<Stack direction="row" alignItems="center" spacing={2}>
<TextField
id="client_name"
data-testid="client_name"
type="clientName"
label=" "
InputLabelProps={{
shrink: false,
}}
sx={{ width: '80%' }}
name="clientName"
value={clientName}
onChange={handleProjectDataChange}
InputProps={{ inputProps: { min: clientName || null } }}
/>
</Stack>
</Grid>
<Grid item xs={12} mt={3}>
<MetLabel>Project Type</MetLabel>
</Grid>
<Grid item xs={12}>
<Select
id="project-type"
name="projectType"
variant="outlined"
label=" "
defaultValue=""
value={projectType}
sx={{ width: '80%' }}
size="small"
onChange={handleProjectDataChange}
>
<MenuItem value={''} sx={{ fontStyle: 'italic', height: '2em' }}>
none
</MenuItem>
{engagementProjectTypes.map((type: string) => {
return (
<MenuItem key={type} value={type}>
{type}
</MenuItem>
);
})}
</Select>
</Grid>
<Grid item xs={12} mt={2}>
<FormControlLabel
label={<MetParagraph>Has comments that need review</MetParagraph>}
control={<Checkbox disabled={true} />}
/>
</Grid>
</Grid>
<Grid item md={2} xs={12}>
<Grid item xs={12}>
<MetLabel>Date Created - From</MetLabel>
</Grid>
Expand Down Expand Up @@ -260,7 +434,7 @@ const AdvancedSearch: React.FC<filterParams> = ({ setFilterParams }) => {
</Stack>
</Grid>
</Grid>
<Grid item md={3} xs={12}>
<Grid item md={2} xs={12}>
<Grid item xs={12}>
<MetLabel>Date Created - To</MetLabel>
</Grid>
Expand Down Expand Up @@ -303,14 +477,6 @@ const AdvancedSearch: React.FC<filterParams> = ({ setFilterParams }) => {
</Stack>
</Grid>
</Grid>
<Grid item md={3} xs={12}>
<Grid item xs={12} mt={2}>
<FormControlLabel
label={<MetParagraph>Has comments that need review</MetParagraph>}
control={<Checkbox disabled={true} />}
/>
</Grid>
</Grid>
</Grid>
<Grid container direction="row" item justifyContent="flex-end">
<SecondaryButton data-testid="reset-filter-button" onClick={() => handleResetSearchFilters()}>
Expand Down
Loading

0 comments on commit a5a94d9

Please sign in to comment.