Skip to content

Commit

Permalink
feat: use actionable change request data in UI (#8613)
Browse files Browse the repository at this point in the history
This PR hooks up the actionable change request data to the counter in
the UI. It:
- creates a getter for the data. It only exposes data. We don't really
care about error or loading for this (it's not an important piece of
data), so we don't expose that just yet.
- Adds orval-generated schema
- Uses the hook in the UI.

It also stwitches the previous "notification badge" for MUI's built-in
badge. We already use that badge component for the event timeline, so I
thought it would make sense to do it here too. Overall, the effect is
pretty good, but there's a few kinks we might wanna work out. I'll make
a follow-up for that (worked out in this PR after all)
  • Loading branch information
thomasheartman authored Nov 1, 2024
1 parent 88e1ec5 commit dc18474
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 41 deletions.
76 changes: 35 additions & 41 deletions frontend/src/component/project/Project/Project.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,22 @@ import {
StyledTabContainer,
StyledTopRow,
} from './Project.styles';
import { Box, Paper, Tabs, Typography, styled } from '@mui/material';
import {
Badge as CounterBadge,
Box,
Paper,
Tabs,
Typography,
styled,
} from '@mui/material';
import useToast from 'hooks/useToast';
import useQueryParams from 'hooks/useQueryParams';
import { useEffect, useState } from 'react';
import {
type PropsWithChildren,
useEffect,
useState,
type ReactNode,
} from 'react';
import ProjectEnvironment from '../ProjectEnvironment/ProjectEnvironment';
import { ProjectFeaturesArchive } from './ProjectFeaturesArchive/ProjectFeaturesArchive';
import ProjectFlags from './ProjectFlags';
Expand Down Expand Up @@ -45,8 +57,8 @@ import { ProjectInsights } from './ProjectInsights/ProjectInsights';
import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview';
import { ProjectArchived } from './ArchiveProject/ProjectArchived';
import { usePlausibleTracker } from '../../../hooks/usePlausibleTracker';
import { ScreenReaderOnly } from 'component/common/ScreenReaderOnly/ScreenReaderOnly';
import { useUiFlag } from 'hooks/useUiFlag';
import { useActionableChangeRequests } from 'hooks/api/getters/useActionableChangeRequests/useActionableChangeRequests';

const StyledBadge = styled(Badge)(({ theme }) => ({
position: 'absolute',
Expand All @@ -64,46 +76,32 @@ interface ITab {
flag?: keyof UiFlags;
new?: boolean;
isEnterprise?: boolean;
label?: () => ReactNode;
}

const CircleContainer = styled('div')(({ theme }) => ({
position: 'absolute',
width: theme.spacing(2.5),
height: theme.spacing(2.5),
display: 'grid',
placeItems: 'center',
borderRadius: '50%',

background: theme.palette.background.alternative,
color: theme.palette.primary.contrastText,
fontSize: theme.typography.body2.fontSize,

// todo: revisit these values later
top: 10,
right: 0,
[theme.breakpoints.down('md')]: {
top: 2,
const StyledCounterBadge = styled(CounterBadge)(({ theme }) => ({
'.MuiBadge-badge': {
backgroundColor: theme.palette.background.alternative,
right: '2px',
},
flex: 'auto',
justifyContent: 'center',
minHeight: '1.5em',
alignItems: 'center',
}));

const ActionableChangeRequestsIndicator = () => {
// todo: useSWR for this instead (maybe conditional)
const count = 0;

if (count <= 0) {
return null;
}
const TabText = styled('span')(({ theme }) => ({
color: theme.palette.text.primary,
}));

const renderedCount = count > 9 ? '9+' : count;
const ChangeRequestsLabel = () => {
const projectId = useRequiredPathParam('projectId');
const { total } = useActionableChangeRequests(projectId);

return (
<CircleContainer>
<ScreenReaderOnly>You can move</ScreenReaderOnly>
{renderedCount}
<ScreenReaderOnly>
change requests into their next phase.
</ScreenReaderOnly>
</CircleContainer>
<StyledCounterBadge badgeContent={total ?? 0} color='primary'>
<TabText>Change requests</TabText>
</StyledCounterBadge>
);
};

Expand Down Expand Up @@ -160,6 +158,7 @@ export const Project = () => {
path: `${basePath}/change-requests`,
name: 'change-request',
isEnterprise: true,
label: simplifyProjectOverview ? ChangeRequestsLabel : undefined,
},
{
title: 'Applications',
Expand Down Expand Up @@ -300,7 +299,7 @@ export const Project = () => {
<StyledTab
data-loading-project
key={tab.title}
label={tab.title}
label={tab.label ? tab.label() : tab.title}
value={tab.path}
onClick={() => {
if (tab.title !== 'Flags') {
Expand Down Expand Up @@ -329,11 +328,6 @@ export const Project = () => {
</span>
}
/>
{simplifyProjectOverview &&
tab.name ===
'change-request' && (
<ActionableChangeRequestsIndicator />
)}
{(tab.isEnterprise &&
isPro() &&
enterpriseIcon) ||
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { formatApiPath } from 'utils/formatPath';
import handleErrorResponses from '../httpErrorResponseHandler';
import type { ActionableChangeRequestsSchema } from 'openapi/models/actionableChangeRequestsSchema';
import { useEnterpriseSWR } from '../useEnterpriseSWR/useEnterpriseSWR';

interface IUseActionableChangeRequestsOutput {
total?: number;
}

export const useActionableChangeRequests = (
projectId: string,
): IUseActionableChangeRequestsOutput => {
const { data } = useEnterpriseSWR<ActionableChangeRequestsSchema>(
{ total: 0 },
formatApiPath(
`api/admin/projects/${projectId}/change-requests/actionable`,
),
fetcher,
);

return {
total: data?.total,
};
};

const fetcher = (path: string) => {
return fetch(path)
.then(handleErrorResponses('Actionable change requests'))
.then((res) => res.json());
};
16 changes: 16 additions & 0 deletions frontend/src/openapi/models/actionableChangeRequestsSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/

/**
* Data related to actionable change requests in a project.
*/
export interface ActionableChangeRequestsSchema {
/**
* The number of actionable change requests in the project.
* @minimum 0
*/
total: number;
}

0 comments on commit dc18474

Please sign in to comment.