1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-31 01:16:01 +02:00

feat: display basic list of project events (#8291)

This commit is contained in:
Mateusz Kwasniewski 2024-09-27 14:02:30 +02:00 committed by GitHub
parent c502e99b85
commit 147984f9d5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 286 additions and 140 deletions

View File

@ -0,0 +1,22 @@
import type { FC } from 'react';
import type { PersonalDashboardProjectDetailsSchema } from '../../openapi';
import { Markdown } from '../common/Markdown/Markdown';
export const LatestProjectEvents: FC<{
latestEvents: PersonalDashboardProjectDetailsSchema['latestEvents'];
}> = ({ latestEvents }) => {
return (
<ul>
{latestEvents.map((event) => {
return (
<li key={event.summary}>
<Markdown>
{event.summary ||
'No preview available for this event'}
</Markdown>
</li>
);
})}
</ul>
);
};

View File

@ -29,6 +29,8 @@ import type {
import { FlagExposure } from 'component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FlagExposure';
import { RoleAndOwnerInfo } from './RoleAndOwnerInfo';
import { ContentGridNoProjects } from './ContentGridNoProjects';
import { LatestProjectEvents } from './LatestProjectEvents';
import { usePersonalDashboardProjectDetails } from 'hooks/api/getters/usePersonalDashboard/usePersonalDashboardProjectDetails';
const ScreenExplanation = styled(Typography)(({ theme }) => ({
marginTop: theme.spacing(1),
@ -122,11 +124,11 @@ const SpacedGridItem = styled(Grid)(({ theme }) => ({
}));
const useProjects = (projects: PersonalDashboardSchemaProjectsItem[]) => {
const [activeProject, setActiveProject] = useState(projects[0]?.name);
const [activeProject, setActiveProject] = useState(projects[0]?.id);
useEffect(() => {
if (!activeProject && projects.length > 0) {
setActiveProject(projects[0].name);
setActiveProject(projects[0].id);
}
}, [JSON.stringify(projects)]);
@ -185,14 +187,13 @@ export const PersonalDashboard = () => {
personalDashboard?.projects || [],
);
// TODO: since we use this one only for the onboarding status, we can add th eonboarding status to the personal dashboard project details API
const { project: activeProjectOverview, loading } =
useProjectOverview(activeProject);
const { personalDashboardProjectDetails, loading: loadingDetails } =
usePersonalDashboardProjectDetails(activeProject);
const onboardingCompleted = Boolean(
!loading &&
activeProject &&
activeProjectOverview?.onboardingStatus.status === 'onboarded',
);
const stage = activeProjectOverview?.onboardingStatus.status ?? 'loading';
const [welcomeDialog, setWelcomeDialog] = useLocalStorageState<
'seen' | 'not_seen'
@ -250,10 +251,10 @@ export const PersonalDashboard = () => {
<ListItemButton
sx={projectStyle}
selected={
project.name === activeProject
project.id === activeProject
}
onClick={() =>
setActiveProject(project.name)
setActiveProject(project.id)
}
>
<ProjectBox>
@ -272,7 +273,7 @@ export const PersonalDashboard = () => {
/>
</IconButton>
</ProjectBox>
{project.name === activeProject ? (
{project.id === activeProject ? (
<ActiveProjectDetails
project={project}
/>
@ -284,14 +285,23 @@ export const PersonalDashboard = () => {
</List>
</SpacedGridItem>
<SpacedGridItem item lg={4} md={1}>
{onboardingCompleted ? (
{stage === 'onboarded' ? (
<ProjectSetupComplete project={activeProject} />
) : activeProject ? (
<CreateFlag project={activeProject} />
) : null}
</SpacedGridItem>
<SpacedGridItem item lg={4} md={1}>
{activeProject ? (
{stage === 'onboarded' &&
personalDashboardProjectDetails ? (
<LatestProjectEvents
latestEvents={
personalDashboardProjectDetails.latestEvents
}
/>
) : null}
{stage === 'onboarding-started' ||
stage === 'first-flag-created' ? (
<ConnectSDK project={activeProject} />
) : null}
</SpacedGridItem>

View File

@ -0,0 +1,33 @@
import useSWR from 'swr';
import { formatApiPath } from 'utils/formatPath';
import handleErrorResponses from '../httpErrorResponseHandler';
import type { PersonalDashboardProjectDetailsSchema } from 'openapi';
export interface IPersonalDashboardProjectDetailsOutput {
personalDashboardProjectDetails?: PersonalDashboardProjectDetailsSchema;
refetch: () => void;
loading: boolean;
error?: Error;
}
export const usePersonalDashboardProjectDetails = (
project: string,
): IPersonalDashboardProjectDetailsOutput => {
const { data, error, mutate } = useSWR(
formatApiPath(`api/admin/personal-dashboard/${project}`),
fetcher,
);
return {
personalDashboardProjectDetails: data,
loading: !error && !data,
refetch: () => mutate(),
error,
};
};
const fetcher = (path: string) => {
return fetch(path)
.then(handleErrorResponses('Personal Dashboard Project Details'))
.then((res) => res.json());
};

View File

@ -0,0 +1,14 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
export type GetPersonalDashboardProjectDetails401 = {
/** The ID of the error instance */
id?: string;
/** A description of what went wrong. */
message?: string;
/** The name of the error kind */
name?: string;
};

View File

@ -0,0 +1,14 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
export type GetPersonalDashboardProjectDetails403 = {
/** The ID of the error instance */
id?: string;
/** A description of what went wrong. */
message?: string;
/** The name of the error kind */
name?: string;
};

View File

@ -0,0 +1,14 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
export type GetPersonalDashboardProjectDetails404 = {
/** The ID of the error instance */
id?: string;
/** A description of what went wrong. */
message?: string;
/** The name of the error kind */
name?: string;
};

View File

@ -693,6 +693,9 @@ export * from './getPats404';
export * from './getPersonalDashboard401';
export * from './getPersonalDashboard403';
export * from './getPersonalDashboard404';
export * from './getPersonalDashboardProjectDetails401';
export * from './getPersonalDashboardProjectDetails403';
export * from './getPersonalDashboardProjectDetails404';
export * from './getPlayground400';
export * from './getPlayground401';
export * from './getProfile401';
@ -900,19 +903,21 @@ export * from './patchSchemaOp';
export * from './patchesSchema';
export * from './patsSchema';
export * from './permissionSchema';
export * from './personalDashboardProjectDetailsSchema';
export * from './personalDashboardProjectDetailsSchemaLatestEventsItem';
export * from './personalDashboardProjectDetailsSchemaOwners';
export * from './personalDashboardProjectDetailsSchemaOwnersOneOfItem';
export * from './personalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOf';
export * from './personalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfOwnerType';
export * from './personalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfThree';
export * from './personalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfThreeOwnerType';
export * from './personalDashboardProjectDetailsSchemaOwnersOneOfSixItem';
export * from './personalDashboardProjectDetailsSchemaOwnersOneOfSixItemOwnerType';
export * from './personalDashboardProjectDetailsSchemaRolesItem';
export * from './personalDashboardProjectDetailsSchemaRolesItemType';
export * from './personalDashboardSchema';
export * from './personalDashboardSchemaFlagsItem';
export * from './personalDashboardSchemaProjectsItem';
export * from './personalDashboardSchemaProjectsItemOwners';
export * from './personalDashboardSchemaProjectsItemOwnersOneOfItem';
export * from './personalDashboardSchemaProjectsItemOwnersOneOfItemAnyOf';
export * from './personalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfOwnerType';
export * from './personalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfThree';
export * from './personalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfThreeOwnerType';
export * from './personalDashboardSchemaProjectsItemOwnersOneOfSixItem';
export * from './personalDashboardSchemaProjectsItemOwnersOneOfSixItemOwnerType';
export * from './personalDashboardSchemaProjectsItemRolesItem';
export * from './personalDashboardSchemaProjectsItemRolesItemType';
export * from './playgroundConstraintSchema';
export * from './playgroundConstraintSchemaOperator';
export * from './playgroundFeatureSchema';

View File

@ -0,0 +1,23 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { PersonalDashboardProjectDetailsSchemaLatestEventsItem } from './personalDashboardProjectDetailsSchemaLatestEventsItem';
import type { PersonalDashboardProjectDetailsSchemaOwners } from './personalDashboardProjectDetailsSchemaOwners';
import type { PersonalDashboardProjectDetailsSchemaRolesItem } from './personalDashboardProjectDetailsSchemaRolesItem';
/**
* Project details in personal dashboard
*/
export interface PersonalDashboardProjectDetailsSchema {
/** The latest events for the project. */
latestEvents: PersonalDashboardProjectDetailsSchemaLatestEventsItem[];
/** The users and/or groups that have the "owner" role in this project. If no such users or groups exist, the list will contain the "system" owner instead. */
owners: PersonalDashboardProjectDetailsSchemaOwners;
/**
* The list of roles that the user has in this project.
* @minItems 1
*/
roles: PersonalDashboardProjectDetailsSchemaRolesItem[];
}

View File

@ -0,0 +1,18 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
/**
* An event summary
*/
export type PersonalDashboardProjectDetailsSchemaLatestEventsItem = {
/** Which user created this event */
createdBy: string;
/**
* **[Experimental]** A markdown-formatted summary of the event.
* @nullable
*/
summary: string | null;
};

View File

@ -0,0 +1,14 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { PersonalDashboardProjectDetailsSchemaOwnersOneOfItem } from './personalDashboardProjectDetailsSchemaOwnersOneOfItem';
import type { PersonalDashboardProjectDetailsSchemaOwnersOneOfSixItem } from './personalDashboardProjectDetailsSchemaOwnersOneOfSixItem';
/**
* The users and/or groups that have the "owner" role in this project. If no such users or groups exist, the list will contain the "system" owner instead.
*/
export type PersonalDashboardProjectDetailsSchemaOwners =
| PersonalDashboardProjectDetailsSchemaOwnersOneOfItem[]
| PersonalDashboardProjectDetailsSchemaOwnersOneOfSixItem[];

View File

@ -0,0 +1,11 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOf } from './personalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOf';
import type { PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfThree } from './personalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfThree';
export type PersonalDashboardProjectDetailsSchemaOwnersOneOfItem =
| PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOf
| PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfThree;

View File

@ -0,0 +1,15 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfOwnerType } from './personalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfOwnerType';
export type PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOf = {
/** @nullable */
email?: string | null;
/** @nullable */
imageUrl?: string | null;
name: string;
ownerType: PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfOwnerType;
};

View File

@ -0,0 +1,14 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
export type PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfOwnerType =
(typeof PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfOwnerType)[keyof typeof PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfOwnerType];
// eslint-disable-next-line @typescript-eslint/no-redeclare
export const PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfOwnerType =
{
user: 'user',
} as const;

View File

@ -0,0 +1,11 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfThreeOwnerType } from './personalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfThreeOwnerType';
export type PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfThree = {
name: string;
ownerType: PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfThreeOwnerType;
};

View File

@ -0,0 +1,14 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
export type PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfThreeOwnerType =
(typeof PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfThreeOwnerType)[keyof typeof PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfThreeOwnerType];
// eslint-disable-next-line @typescript-eslint/no-redeclare
export const PersonalDashboardProjectDetailsSchemaOwnersOneOfItemAnyOfThreeOwnerType =
{
group: 'group',
} as const;

View File

@ -0,0 +1,10 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { PersonalDashboardProjectDetailsSchemaOwnersOneOfSixItemOwnerType } from './personalDashboardProjectDetailsSchemaOwnersOneOfSixItemOwnerType';
export type PersonalDashboardProjectDetailsSchemaOwnersOneOfSixItem = {
ownerType: PersonalDashboardProjectDetailsSchemaOwnersOneOfSixItemOwnerType;
};

View File

@ -0,0 +1,14 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
export type PersonalDashboardProjectDetailsSchemaOwnersOneOfSixItemOwnerType =
(typeof PersonalDashboardProjectDetailsSchemaOwnersOneOfSixItemOwnerType)[keyof typeof PersonalDashboardProjectDetailsSchemaOwnersOneOfSixItemOwnerType];
// eslint-disable-next-line @typescript-eslint/no-redeclare
export const PersonalDashboardProjectDetailsSchemaOwnersOneOfSixItemOwnerType =
{
system: 'system',
} as const;

View File

@ -3,16 +3,16 @@
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { PersonalDashboardSchemaProjectsItemRolesItemType } from './personalDashboardSchemaProjectsItemRolesItemType';
import type { PersonalDashboardProjectDetailsSchemaRolesItemType } from './personalDashboardProjectDetailsSchemaRolesItemType';
/**
* An Unleash role.
*/
export type PersonalDashboardSchemaProjectsItemRolesItem = {
export type PersonalDashboardProjectDetailsSchemaRolesItem = {
/** The id of the role */
id: number;
/** The name of the role */
name: string;
/** The type of the role */
type: PersonalDashboardSchemaProjectsItemRolesItemType;
type: PersonalDashboardProjectDetailsSchemaRolesItemType;
};

View File

@ -7,11 +7,11 @@
/**
* The type of the role
*/
export type PersonalDashboardSchemaProjectsItemRolesItemType =
(typeof PersonalDashboardSchemaProjectsItemRolesItemType)[keyof typeof PersonalDashboardSchemaProjectsItemRolesItemType];
export type PersonalDashboardProjectDetailsSchemaRolesItemType =
(typeof PersonalDashboardProjectDetailsSchemaRolesItemType)[keyof typeof PersonalDashboardProjectDetailsSchemaRolesItemType];
// eslint-disable-next-line @typescript-eslint/no-redeclare
export const PersonalDashboardSchemaProjectsItemRolesItemType = {
export const PersonalDashboardProjectDetailsSchemaRolesItemType = {
custom: 'custom',
project: 'project',
root: 'root',

View File

@ -3,8 +3,6 @@
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { PersonalDashboardSchemaProjectsItemOwners } from './personalDashboardSchemaProjectsItemOwners';
import type { PersonalDashboardSchemaProjectsItemRolesItem } from './personalDashboardSchemaProjectsItemRolesItem';
export type PersonalDashboardSchemaProjectsItem = {
/** The number of features this project has */
@ -17,11 +15,4 @@ export type PersonalDashboardSchemaProjectsItem = {
memberCount: number;
/** The name of the project */
name: string;
/** The users and/or groups that have the "owner" role in this project. If no such users or groups exist, the list will contain the "system" owner instead. */
owners?: PersonalDashboardSchemaProjectsItemOwners;
/**
* The list of roles that the user has in this project.
* @minItems 1
*/
roles?: PersonalDashboardSchemaProjectsItemRolesItem[];
};

View File

@ -1,14 +0,0 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { PersonalDashboardSchemaProjectsItemOwnersOneOfItem } from './personalDashboardSchemaProjectsItemOwnersOneOfItem';
import type { PersonalDashboardSchemaProjectsItemOwnersOneOfSixItem } from './personalDashboardSchemaProjectsItemOwnersOneOfSixItem';
/**
* The users and/or groups that have the "owner" role in this project. If no such users or groups exist, the list will contain the "system" owner instead.
*/
export type PersonalDashboardSchemaProjectsItemOwners =
| PersonalDashboardSchemaProjectsItemOwnersOneOfItem[]
| PersonalDashboardSchemaProjectsItemOwnersOneOfSixItem[];

View File

@ -1,11 +0,0 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOf } from './personalDashboardSchemaProjectsItemOwnersOneOfItemAnyOf';
import type { PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfThree } from './personalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfThree';
export type PersonalDashboardSchemaProjectsItemOwnersOneOfItem =
| PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOf
| PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfThree;

View File

@ -1,15 +0,0 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfOwnerType } from './personalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfOwnerType';
export type PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOf = {
/** @nullable */
email?: string | null;
/** @nullable */
imageUrl?: string | null;
name: string;
ownerType: PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfOwnerType;
};

View File

@ -1,14 +0,0 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
export type PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfOwnerType =
(typeof PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfOwnerType)[keyof typeof PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfOwnerType];
// eslint-disable-next-line @typescript-eslint/no-redeclare
export const PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfOwnerType =
{
user: 'user',
} as const;

View File

@ -1,11 +0,0 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfThreeOwnerType } from './personalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfThreeOwnerType';
export type PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfThree = {
name: string;
ownerType: PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfThreeOwnerType;
};

View File

@ -1,14 +0,0 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
export type PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfThreeOwnerType =
(typeof PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfThreeOwnerType)[keyof typeof PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfThreeOwnerType];
// eslint-disable-next-line @typescript-eslint/no-redeclare
export const PersonalDashboardSchemaProjectsItemOwnersOneOfItemAnyOfThreeOwnerType =
{
group: 'group',
} as const;

View File

@ -1,10 +0,0 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { PersonalDashboardSchemaProjectsItemOwnersOneOfSixItemOwnerType } from './personalDashboardSchemaProjectsItemOwnersOneOfSixItemOwnerType';
export type PersonalDashboardSchemaProjectsItemOwnersOneOfSixItem = {
ownerType: PersonalDashboardSchemaProjectsItemOwnersOneOfSixItemOwnerType;
};

View File

@ -1,13 +0,0 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
export type PersonalDashboardSchemaProjectsItemOwnersOneOfSixItemOwnerType =
(typeof PersonalDashboardSchemaProjectsItemOwnersOneOfSixItemOwnerType)[keyof typeof PersonalDashboardSchemaProjectsItemOwnersOneOfSixItemOwnerType];
// eslint-disable-next-line @typescript-eslint/no-redeclare
export const PersonalDashboardSchemaProjectsItemOwnersOneOfSixItemOwnerType = {
system: 'system',
} as const;

View File

@ -48,6 +48,7 @@ export class PersonalDashboardService {
const projects = await this.projectReadModel.getProjectsForAdminUi({
ids: userProjectIds,
archived: false,
});
const normalizedProjects = projects.map((project) => ({

View File

@ -6,7 +6,7 @@ export const personalDashboardProjectDetailsSchema = {
type: 'object',
description: 'Project details in personal dashboard',
additionalProperties: false,
required: ['owners', 'roles'],
required: ['owners', 'roles', 'latestEvents'],
properties: {
latestEvents: {
type: 'array',