feat(executions): add execution filters
This commit is contained in:
42
packages/web/src/components/DatePickerInput/index.jsx
Normal file
42
packages/web/src/components/DatePickerInput/index.jsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import * as React from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';
|
||||
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
||||
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
|
||||
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
|
||||
export default function DatePickerInput({
|
||||
onChange,
|
||||
defaultValue = '',
|
||||
label,
|
||||
disableFuture = false,
|
||||
minDate,
|
||||
maxDate,
|
||||
}) {
|
||||
const intl = useIntl();
|
||||
const formatMessage = useFormatMessage();
|
||||
|
||||
const props = {
|
||||
label,
|
||||
views: ['year', 'month', 'day'],
|
||||
onChange,
|
||||
disableFuture,
|
||||
disableHighlightToday: true,
|
||||
minDate,
|
||||
maxDate,
|
||||
};
|
||||
|
||||
if (defaultValue) {
|
||||
props.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
return (
|
||||
<LocalizationProvider
|
||||
dateAdapter={AdapterLuxon}
|
||||
adapterLocale={intl.locale}
|
||||
>
|
||||
<DatePicker {...props} />
|
||||
</LocalizationProvider>
|
||||
);
|
||||
}
|
||||
112
packages/web/src/components/ExecutionFilters/index.jsx
Normal file
112
packages/web/src/components/ExecutionFilters/index.jsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import FilterAltIcon from '@mui/icons-material/FilterAlt';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Collapse,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
} from '@mui/material';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { DateTime } from 'luxon';
|
||||
import { useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import Can from 'components/Can';
|
||||
import DatePickerInput from 'components/DatePickerInput';
|
||||
import useExecutionFilters from 'hooks/useExecutionFilters';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
|
||||
export default function ExecutionFilters({ onFilterChange }) {
|
||||
const theme = useTheme();
|
||||
const formatMessage = useFormatMessage();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
||||
|
||||
const {
|
||||
filters,
|
||||
filterByStartDateTime,
|
||||
filterByEndDateTime,
|
||||
filterByStatus,
|
||||
} = useExecutionFilters();
|
||||
|
||||
const [mobileFiltersOpen, setMobileFiltersOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{/* Mobile: Toggle Button for Filters */}
|
||||
{isMobile && (
|
||||
<Button
|
||||
variant="contained"
|
||||
startIcon={<FilterAltIcon />}
|
||||
onClick={() => setMobileFiltersOpen((prev) => !prev)}
|
||||
fullWidth
|
||||
sx={{ mb: 2 }}
|
||||
>
|
||||
{mobileFiltersOpen
|
||||
? formatMessage('executionFilters.hideFilters')
|
||||
: formatMessage('executionFilters.showFilters')}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* Filters Box (Always Visible on Large Screens) */}
|
||||
<Collapse in={!isMobile || mobileFiltersOpen}>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: { xs: 'column', md: 'row' },
|
||||
gap: 2,
|
||||
mb: 2,
|
||||
alignItems: { md: 'center' },
|
||||
}}
|
||||
>
|
||||
{/* Status Filter */}
|
||||
<FormControl fullWidth sx={{ maxWidth: { md: 300 } }}>
|
||||
<InputLabel shrink>
|
||||
{formatMessage('executionFilters.statusFilterLabel')}
|
||||
</InputLabel>
|
||||
|
||||
<Select
|
||||
label={formatMessage('executionFilters.statusFilterLabel')}
|
||||
value={filters.status}
|
||||
displayEmpty
|
||||
onChange={(e) => filterByStatus(e.target.value)}
|
||||
key={filters.status}
|
||||
>
|
||||
<MenuItem value={undefined}>
|
||||
{formatMessage('executionFilters.statusFilterAnyOption')}
|
||||
</MenuItem>
|
||||
<MenuItem value="success">
|
||||
{formatMessage('executionFilters.statusFilterSuccessfulOption')}
|
||||
</MenuItem>
|
||||
<MenuItem value="failure">
|
||||
{formatMessage('executionFilters.statusFilterFailedOption')}
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
{/* Date Filters */}
|
||||
<DatePickerInput
|
||||
label={formatMessage('executionFilters.startDateLabel')}
|
||||
key={`start-${filters.startDateTime}`}
|
||||
defaultValue={filters.startDateTime}
|
||||
disableFuture={true}
|
||||
onChange={filterByStartDateTime}
|
||||
maxDate={filters.endDateTime}
|
||||
/>
|
||||
|
||||
<DatePickerInput
|
||||
label={formatMessage('executionFilters.endDateLabel')}
|
||||
key={`end-${filters.endDateTime}`}
|
||||
defaultValue={filters.endDateTime}
|
||||
disableFuture={true}
|
||||
onChange={filterByEndDateTime}
|
||||
minDate={filters.startDateTime}
|
||||
/>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import englishMessages from 'locales/en.json';
|
||||
const IntlProvider = ({ children }) => {
|
||||
return (
|
||||
<BaseIntlProvider
|
||||
locale={navigator.language}
|
||||
locale={navigator.language.split('-')[0]}
|
||||
defaultLocale="en"
|
||||
messages={englishMessages}
|
||||
>
|
||||
|
||||
@@ -7,8 +7,9 @@ import FormControl from '@mui/material/FormControl';
|
||||
import SearchIcon from '@mui/icons-material/Search';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
|
||||
export default function SearchInput({ onChange, defaultValue = '', value }) {
|
||||
export default function SearchInput({ onChange, value }) {
|
||||
const formatMessage = useFormatMessage();
|
||||
|
||||
return (
|
||||
<FormControl variant="outlined" fullWidth>
|
||||
<InputLabel htmlFor="search-input">
|
||||
@@ -17,7 +18,6 @@ export default function SearchInput({ onChange, defaultValue = '', value }) {
|
||||
|
||||
<OutlinedInput
|
||||
value={value}
|
||||
defaultValue={defaultValue}
|
||||
id="search-input"
|
||||
type="text"
|
||||
size="medium"
|
||||
@@ -36,6 +36,5 @@ export default function SearchInput({ onChange, defaultValue = '', value }) {
|
||||
|
||||
SearchInput.propTypes = {
|
||||
onChange: PropTypes.func,
|
||||
defaultValue: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user