Skip to content

Commit

Permalink
feat: health trend insight
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew committed Oct 2, 2024
1 parent 3ac2c17 commit c2dae53
Show file tree
Hide file tree
Showing 10 changed files with 213 additions and 11 deletions.
8 changes: 6 additions & 2 deletions frontend/src/component/personalDashboard/MyProjects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,12 @@ export const MyProjects: FC<{
</List>
</SpacedGridItem>
<SpacedGridItem item lg={4} md={1}>
{activeProjectStage === 'onboarded' ? (
<ProjectSetupComplete project={activeProject} />
{activeProjectStage === 'onboarded' &&
personalDashboardProjectDetails ? (
<ProjectSetupComplete
project={activeProject}
insights={personalDashboardProjectDetails.insights}
/>
) : null}
{activeProjectStage === 'onboarding-started' ||
activeProjectStage === 'loading' ? (
Expand Down
99 changes: 92 additions & 7 deletions frontend/src/component/personalDashboard/ProjectSetupComplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { styled, Typography } from '@mui/material';
import type { FC } from 'react';
import { Link } from 'react-router-dom';
import Lightbulb from '@mui/icons-material/LightbulbOutlined';
import type { PersonalDashboardProjectDetailsSchemaInsights } from '../../openapi';

const TitleContainer = styled('div')(({ theme }) => ({
display: 'flex',
Expand All @@ -18,18 +19,17 @@ const ActionBox = styled('article')(({ theme }) => ({
flexDirection: 'column',
}));

export const ProjectSetupComplete: FC<{ project: string }> = ({ project }) => {
const PercentageScore = styled('span')(({ theme }) => ({
color: theme.palette.primary.main,
}));

const ConnectedSdkProject: FC<{ project: string }> = ({ project }) => {
return (
<ActionBox>
<TitleContainer>
<Lightbulb color='primary' />
<h3>Project Insight</h3>
</TitleContainer>
<>
<Typography>
This project already has connected SDKs and existing feature
flags.
</Typography>

<Typography>
<Link to={`/projects/${project}?create=true`}>
Create a new feature flag
Expand All @@ -40,6 +40,91 @@ export const ProjectSetupComplete: FC<{ project: string }> = ({ project }) => {
</Link>{' '}
to work with existing flags
</Typography>
</>
);
};

type HeathTrend = 'consistent' | 'improved' | 'declined' | 'unknown';

const determineProjectHealthTrend = (
insights: PersonalDashboardProjectDetailsSchemaInsights,
) => {
let trend: HeathTrend = 'unknown';
if (
insights.avgHealthCurrentWindow !== null &&
insights.avgHealthPastWindow !== null
) {
if (insights.avgHealthCurrentWindow > insights.avgHealthPastWindow) {
trend = 'improved';
} else if (
insights.avgHealthCurrentWindow < insights.avgHealthPastWindow
) {
trend = 'declined';
} else if (
insights.avgHealthPastWindow === insights.avgHealthCurrentWindow
) {
trend = 'consistent';
}
}
return trend;
};

export const ProjectSetupComplete: FC<{
project: string;
insights: PersonalDashboardProjectDetailsSchemaInsights;
}> = ({ project, insights }) => {
const projectHealthTrend = determineProjectHealthTrend(insights);

return (
<ActionBox>
<TitleContainer>
<Lightbulb color='primary' />
<h3>Project Insight</h3>
</TitleContainer>

{projectHealthTrend === 'unknown' ? (
<ConnectedSdkProject project={project} />
) : null}
{projectHealthTrend === 'improved' ? (
<Typography>
On average, your project health went up from{' '}
<PercentageScore>
{insights.avgHealthPastWindow}%
</PercentageScore>{' '}
to{' '}
<PercentageScore>
{insights.avgHealthCurrentWindow}%
</PercentageScore>{' '}
during the last 4 weeks.
</Typography>
) : null}
{projectHealthTrend === 'declined' ? (
<Typography>
On average, your project health went down from{' '}
<PercentageScore>
{insights.avgHealthPastWindow}%
</PercentageScore>{' '}
to{' '}
<PercentageScore>
{insights.avgHealthCurrentWindow}%
</PercentageScore>{' '}
during the last 4 weeks.
</Typography>
) : null}
{projectHealthTrend === 'consistent' ? (
<Typography>
On average, your project health has remained at{' '}
<PercentageScore>
{insights.avgHealthCurrentWindow}%
</PercentageScore>{' '}
during the last 4 weeks.
</Typography>
) : null}
{projectHealthTrend !== 'unknown' ? (
<Link to={`/projects/${project}/insights`}>
View more insights
</Link>
) : null}
</ActionBox>
);
};
5 changes: 5 additions & 0 deletions frontend/src/openapi/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,7 @@ export * from './patchesSchema';
export * from './patsSchema';
export * from './permissionSchema';
export * from './personalDashboardProjectDetailsSchema';
export * from './personalDashboardProjectDetailsSchemaInsights';
export * from './personalDashboardProjectDetailsSchemaLatestEventsItem';
export * from './personalDashboardProjectDetailsSchemaOnboardingStatus';
export * from './personalDashboardProjectDetailsSchemaOnboardingStatusOneOf';
Expand Down Expand Up @@ -1144,6 +1145,10 @@ export * from './signalEndpointSignalsSchema';
export * from './signalEndpointTokenSchema';
export * from './signalEndpointTokensSchema';
export * from './signalEndpointsSchema';
export * from './signalQueryResponseSchema';
export * from './signalQuerySignalSchema';
export * from './signalQuerySignalSchemaPayload';
export * from './signalQuerySignalSchemaSource';
export * from './signalSchema';
export * from './signalSchemaPayload';
export * from './signalSchemaSource';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { PersonalDashboardProjectDetailsSchemaInsights } from './personalDashboardProjectDetailsSchemaInsights';
import type { PersonalDashboardProjectDetailsSchemaLatestEventsItem } from './personalDashboardProjectDetailsSchemaLatestEventsItem';
import type { PersonalDashboardProjectDetailsSchemaOnboardingStatus } from './personalDashboardProjectDetailsSchemaOnboardingStatus';
import type { PersonalDashboardProjectDetailsSchemaOwners } from './personalDashboardProjectDetailsSchemaOwners';
Expand All @@ -12,6 +13,8 @@ import type { PersonalDashboardProjectDetailsSchemaRolesItem } from './personalD
* Project details in personal dashboard
*/
export interface PersonalDashboardProjectDetailsSchema {
/** Insights for the project */
insights: PersonalDashboardProjectDetailsSchemaInsights;
/** The latest events for the project. */
latestEvents: PersonalDashboardProjectDetailsSchemaLatestEventsItem[];
/** The current onboarding status of the project. */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/

/**
* Insights for the project
*/
export type PersonalDashboardProjectDetailsSchemaInsights = {
/**
* The average health score in the current window of the last 4 weeks
* @nullable
*/
avgHealthCurrentWindow: number | null;
/**
* The average health score in the previous 4 weeks before the current window
* @nullable
*/
avgHealthPastWindow: number | null;
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@
*/

export type PersonalDashboardSchemaAdminsItem = {
/** @nullable */
email?: string;
/** The user ID. */
id: number;
/** @nullable */
imageUrl?: string;
/** The user's name. */
name?: string;
Expand Down
19 changes: 19 additions & 0 deletions frontend/src/openapi/models/signalQueryResponseSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { SignalQuerySignalSchema } from './signalQuerySignalSchema';

/**
* A list of signals that have been registered by the system
*/
export interface SignalQueryResponseSchema {
/** The list of signals */
signals: SignalQuerySignalSchema[];
/**
* The total count of signals
* @minimum 0
*/
total: number;
}
41 changes: 41 additions & 0 deletions frontend/src/openapi/models/signalQuerySignalSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { SignalQuerySignalSchemaPayload } from './signalQuerySignalSchemaPayload';
import type { SignalQuerySignalSchemaSource } from './signalQuerySignalSchemaSource';

/**
* An object describing a signal enriched with source data.
*/
export interface SignalQuerySignalSchema {
/** The date and time of when the signal was created. */
createdAt: string;
/**
* The signal's ID. Signal IDs are incrementing integers. In other words, a more recently created signal will always have a higher ID than an older one.
* @minimum 1
*/
id: number;
/** The payload of the signal. */
payload?: SignalQuerySignalSchemaPayload;
/** The signal source type. Should be used along with `sourceId` to uniquely identify the resource that created this signal. */
source: SignalQuerySignalSchemaSource;
/**
* A more detailed description of the source that registered this signal.
* @nullable
*/
sourceDescription?: string | null;
/** The ID of the source that created this signal. Should be used along with `source` to uniquely identify the resource that created this signal. */
sourceId: number;
/**
* The name of the source that registered this signal.
* @nullable
*/
sourceName?: string | null;
/**
* The name of the token used to register this signal.
* @nullable
*/
tokenName?: string | null;
}
10 changes: 10 additions & 0 deletions frontend/src/openapi/models/signalQuerySignalSchemaPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/

/**
* The payload of the signal.
*/
export type SignalQuerySignalSchemaPayload = { [key: string]: unknown };
16 changes: 16 additions & 0 deletions frontend/src/openapi/models/signalQuerySignalSchemaSource.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
*/

/**
* The signal source type. Should be used along with `sourceId` to uniquely identify the resource that created this signal.
*/
export type SignalQuerySignalSchemaSource =
(typeof SignalQuerySignalSchemaSource)[keyof typeof SignalQuerySignalSchemaSource];

// eslint-disable-next-line @typescript-eslint/no-redeclare
export const SignalQuerySignalSchemaSource = {
'signal-endpoint': 'signal-endpoint',
} as const;

0 comments on commit c2dae53

Please sign in to comment.