diff --git a/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx b/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx
index d40b0189cd..bc9c3723bb 100644
--- a/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx
+++ b/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx
@@ -1,7 +1,9 @@
-import { useMemo, VFC } from 'react';
+import { ComponentProps, useEffect, useMemo, useState, VFC } from 'react';
import {
+ Autocomplete,
Box,
styled,
+ TextField,
Typography,
useMediaQuery,
useTheme,
@@ -17,6 +19,7 @@ import { FlagsProjectChart } from './FlagsProjectChart/FlagsProjectChart';
import { ProjectHealthChart } from './ProjectHealthChart/ProjectHealthChart';
import { TimeToProductionChart } from './TimeToProductionChart/TimeToProductionChart';
import { TimeToProduction } from './TimeToProduction/TimeToProduction';
+import { ProjectSelect, allOption } from './ProjectSelect/ProjectSelect';
const StyledGrid = styled(Box)(({ theme }) => ({
display: 'grid',
@@ -61,6 +64,7 @@ const useDashboardGrid = () => {
export const ExecutiveDashboard: VFC = () => {
const { executiveDashboardData, loading, error } = useExecutiveDashboard();
+ const [projects, setProjects] = useState([allOption.id]);
const flagPerUsers = useMemo(() => {
if (
@@ -75,6 +79,16 @@ export const ExecutiveDashboard: VFC = () => {
).toFixed(1);
}, [executiveDashboardData]);
+ const filteredProjectFlagTrends = useMemo(() => {
+ if (projects[0] === allOption.id) {
+ return executiveDashboardData.projectFlagTrends;
+ }
+
+ return executiveDashboardData.projectFlagTrends.filter((trend) =>
+ projects.includes(trend.project),
+ );
+ }, [executiveDashboardData, projects]);
+
const {
gridTemplateColumns,
chartSpan,
@@ -120,15 +134,16 @@ export const ExecutiveDashboard: VFC = () => {
isLoading={loading}
/>
+
+
+
{
span={largeChartSpan}
>
@@ -148,9 +161,7 @@ export const ExecutiveDashboard: VFC = () => {
diff --git a/frontend/src/component/executiveDashboard/ProjectSelect/ProjectSelect.tsx b/frontend/src/component/executiveDashboard/ProjectSelect/ProjectSelect.tsx
new file mode 100644
index 0000000000..88d58a4332
--- /dev/null
+++ b/frontend/src/component/executiveDashboard/ProjectSelect/ProjectSelect.tsx
@@ -0,0 +1,103 @@
+import { ComponentProps, Dispatch, SetStateAction, VFC } from 'react';
+import { Autocomplete, Box, styled, TextField } from '@mui/material';
+import { renderOption } from '../../playground/Playground/PlaygroundForm/renderOption';
+import useProjects from '../../../hooks/api/getters/useProjects/useProjects';
+
+const StyledBox = styled(Box)(({ theme }) => ({
+ width: '25%',
+ marginLeft: '75%',
+ marginBottom: theme.spacing(4),
+ marginTop: theme.spacing(4),
+ [theme.breakpoints.down('lg')]: {
+ width: '100%',
+ marginLeft: 0,
+ },
+}));
+
+interface IOption {
+ label: string;
+ id: string;
+}
+
+export const allOption = { label: 'ALL', id: '*' };
+
+interface IProjectSelectProps {
+ selectedProjects: string[];
+ onChange: Dispatch>;
+}
+
+export const ProjectSelect: VFC = ({
+ selectedProjects,
+ onChange,
+}) => {
+ const { projects: availableProjects } = useProjects();
+
+ const projectsOptions = [
+ allOption,
+ ...availableProjects.map(({ name: label, id }) => ({
+ label,
+ id,
+ })),
+ ];
+
+ const isAllProjects =
+ selectedProjects &&
+ (selectedProjects.length === 0 ||
+ (selectedProjects.length === 1 && selectedProjects[0] === '*'));
+
+ const onProjectsChange: ComponentProps['onChange'] = (
+ event,
+ value,
+ reason,
+ ) => {
+ const newProjects = value as IOption | IOption[];
+ if (reason === 'clear' || newProjects === null) {
+ return onChange([allOption.id]);
+ }
+ if (Array.isArray(newProjects)) {
+ if (newProjects.length === 0) {
+ return onChange([allOption.id]);
+ }
+ if (
+ newProjects.find(({ id }) => id === allOption.id) !== undefined
+ ) {
+ return onChange([allOption.id]);
+ }
+ return onChange(newProjects.map(({ id }) => id));
+ }
+ if (newProjects.id === allOption.id) {
+ return onChange([allOption.id]);
+ }
+
+ return onChange([newProjects.id]);
+ };
+
+ return (
+
+ (
+
+ )}
+ renderOption={renderOption}
+ getOptionLabel={({ label }) => label}
+ disableCloseOnSelect
+ size='small'
+ value={
+ isAllProjects
+ ? allOption
+ : projectsOptions.filter(({ id }) =>
+ selectedProjects.includes(id),
+ )
+ }
+ onChange={onProjectsChange}
+ data-testid={'DASHBOARD_PROJECT_SELECT'}
+ />
+
+ );
+};