Skip to content

Commit 43697d2

Browse files
authored
Global activities updates and activity details page (#5806)
* add event filter * update main view * remove search * update filters query and components * handle boolean filter * handle dropdown and array * add all filters * handle overflow and fix filter list * enable filters in query * fix filter as array * fix brancehs choices * add event types * update query * fix query * fix group events * fix group event for node events * improve display label hook and update link to all activities * rename group event to standard event and handle schema events * get only top level events * update display label query to be disabled * start to have main + child events * add enabled props * rename * update text * update filter modal position * update query fn * update filter style * fix last import * udpate date in global view * fix count * update test * add details page * udpate details view * update test * ui * add main branch in activities list * fix link in global event to include branch * fix test * fix filter * update group event display for remain items * display temporary id for breadcrumb * add infinite query * fix node events * update breadcrumb * udpate use events filters * rename file * update ui * update accessibility * update ui * fix import * handle default case for standard events * update the way we deal with standard events * udpate ui for global events * lint * prepare for futur change * revert change * udpate details view * lint * lint * fix render on context change * add branch context
1 parent 020cc89 commit 43697d2

31 files changed

+573
-212
lines changed

frontend/app/src/app/router.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,19 @@ export const router = createBrowserRouter([
8989
index: true,
9090
lazy: () => import("@/pages/activities"),
9191
},
92+
{
93+
path: ":activityid",
94+
lazy: () => import("@/pages/activities/details"),
95+
handle: {
96+
breadcrumb: (match: UIMatch) => {
97+
return {
98+
type: "id",
99+
value: match.params.activityid,
100+
link: "/activities",
101+
};
102+
},
103+
},
104+
},
92105
],
93106
},
94107
{
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import graphqlClient from "@/shared/api/graphql/graphqlClientApollo";
2+
import { gql } from "@apollo/client";
3+
import { EventType } from "../ui/event";
4+
import { INFRAHUB_EVENT } from "../utils/constants";
5+
6+
export type EventDetailsFilters = {
7+
id: string;
8+
};
9+
10+
const EVENT_DETAILS_QUERY = gql`
11+
query GET_ACTIVITY_DETAILS($ids: [String!]) {
12+
InfrahubEvent(ids: $ids) {
13+
count
14+
edges {
15+
node {
16+
id
17+
event
18+
branch
19+
occurred_at
20+
level
21+
account_id
22+
primary_node {
23+
id
24+
kind
25+
}
26+
related_nodes {
27+
id
28+
kind
29+
}
30+
has_children
31+
__typename
32+
... on NodeMutatedEvent {
33+
attributes {
34+
action
35+
kind
36+
name
37+
value
38+
value_previous
39+
}
40+
payload
41+
}
42+
}
43+
}
44+
}
45+
}
46+
`;
47+
48+
export async function getEventDetailsFromApi({
49+
branchName,
50+
atDate,
51+
...filters
52+
}: EventDetailsFilters & { branchName?: string; atDate?: Date | null }) {
53+
const { data } = await graphqlClient.query({
54+
query: EVENT_DETAILS_QUERY,
55+
variables: {
56+
...filters,
57+
},
58+
context: {
59+
branch: branchName,
60+
date: atDate,
61+
},
62+
});
63+
64+
const activities: EventType[] = data?.[INFRAHUB_EVENT]?.edges?.map((edge) => {
65+
return edge.node;
66+
});
67+
68+
return activities[0];
69+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { getCurrentBranchName } from "@/entities/branches/domain/get-current-branch";
2+
import { store } from "@/shared/stores";
3+
import { datetimeAtom } from "@/shared/stores/time.atom";
4+
import { queryOptions, useQuery } from "@tanstack/react-query";
5+
import { getEventDetailsFromApi } from "./get-event-details-from-api";
6+
7+
export function getEventDetailsQueryOptions({ id }: { id: string }) {
8+
const currentBranchName = getCurrentBranchName();
9+
const timeMachineDate = store.get(datetimeAtom);
10+
11+
return queryOptions({
12+
queryKey: ["event-details", id],
13+
queryFn: () => {
14+
return getEventDetailsFromApi({
15+
id,
16+
branchName: currentBranchName,
17+
atDate: timeMachineDate,
18+
});
19+
},
20+
});
21+
}
22+
23+
export const useEventDetails = ({ id }: { id: string }) => {
24+
return useQuery(getEventDetailsQueryOptions({ id }));
25+
};

frontend/app/src/entities/events/api/get-events-from-api.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
import graphqlClient from "@/shared/api/graphql/graphqlClientApollo";
2+
import { ContextParams } from "@/shared/api/types";
23
import { gql } from "@apollo/client";
34
import { EventType } from "../ui/event";
45
import { INFRAHUB_EVENT } from "../utils/constants";
56

7+
export const OBJECTS_PER_PAGE = 40;
8+
69
export type GlobalEventsFilters = {
710
hasChildren?: boolean;
811
eventType?: Array<string>;
912
primaryNodeIds?: Array<string>;
1013
relatedNodeIds?: Array<string>;
1114
parentIds?: Array<string>;
1215
accountIds?: Array<string>;
16+
level?: number;
1317
since?: Date;
1418
until?: Date;
1519
offset?: number;
@@ -25,6 +29,7 @@ const EVENTS_QUERY = gql`
2529
$relatedNodeIds: [String!]
2630
$parentIds: [String!]
2731
$accountIds: [String!]
32+
$level: Int
2833
$since: DateTime
2934
$until: DateTime
3035
$offset: Int
@@ -38,6 +43,7 @@ const EVENTS_QUERY = gql`
3843
related_node__ids: $relatedNodeIds
3944
parent__ids: $parentIds
4045
account__ids: $accountIds
46+
level: $level
4147
since: $since
4248
until: $until
4349
offset: $offset
@@ -72,20 +78,34 @@ const EVENTS_QUERY = gql`
7278
}
7379
payload
7480
}
81+
... on BranchCreatedEvent {
82+
payload
83+
}
84+
... on StandardEvent {
85+
payload
86+
}
87+
... on BranchDeletedEvent {
88+
payload
89+
}
90+
... on BranchRebasedEvent {
91+
payload
92+
}
7593
}
7694
}
7795
}
7896
}
7997
`;
8098

8199
export async function getEventsFromApi({
100+
limit = OBJECTS_PER_PAGE,
82101
branchName,
83102
atDate,
84103
...filters
85-
}: GlobalEventsFilters & { branchName?: string; atDate?: Date | null }) {
104+
}: GlobalEventsFilters & ContextParams) {
86105
const { data } = await graphqlClient.query({
87106
query: EVENTS_QUERY,
88107
variables: {
108+
limit,
89109
...filters,
90110
},
91111
context: {
@@ -98,10 +118,5 @@ export async function getEventsFromApi({
98118
return edge.node;
99119
});
100120

101-
const count = data?.data?.[INFRAHUB_EVENT]?.count;
102-
103-
return {
104-
activities,
105-
count,
106-
};
121+
return activities;
107122
}
Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,40 @@
1-
import { getCurrentBranchName } from "@/entities/branches/domain/get-current-branch";
2-
import { store } from "@/shared/stores";
1+
import { useCurrentBranch } from "@/entities/branches/ui/branches-provider";
2+
import { ContextParams } from "@/shared/api/types";
33
import { datetimeAtom } from "@/shared/stores/time.atom";
4-
import { queryOptions, useQuery } from "@tanstack/react-query";
5-
import { GlobalEventsFilters, getEventsFromApi } from "./get-events-from-api";
4+
import { infiniteQueryOptions, useInfiniteQuery } from "@tanstack/react-query";
5+
import { useAtomValue } from "jotai";
6+
import { GlobalEventsFilters, OBJECTS_PER_PAGE, getEventsFromApi } from "./get-events-from-api";
67

7-
export function getEventsQueryOptions(filters: GlobalEventsFilters) {
8-
const currentBranchName = getCurrentBranchName();
9-
const timeMachineDate = store.get(datetimeAtom);
10-
11-
return queryOptions({
12-
queryKey: ["events", filters],
13-
queryFn: () => {
8+
export function getEventsQueryOptions({
9+
filters,
10+
branchName,
11+
atDate,
12+
}: { filters: GlobalEventsFilters } & ContextParams) {
13+
return infiniteQueryOptions({
14+
queryKey: [branchName, atDate, "events", filters],
15+
queryFn: ({ pageParam }) => {
1416
return getEventsFromApi({
1517
...filters,
16-
branchName: currentBranchName,
17-
atDate: timeMachineDate,
18+
offset: pageParam,
19+
branchName,
20+
atDate,
1821
});
1922
},
23+
initialPageParam: 0,
24+
getNextPageParam: (lastPage, _, lastPageParam) => {
25+
if (lastPage?.length < OBJECTS_PER_PAGE) {
26+
return undefined;
27+
}
28+
return lastPageParam + OBJECTS_PER_PAGE;
29+
},
2030
});
2131
}
2232

23-
export const useEvents = (filters: GlobalEventsFilters) => {
24-
return useQuery(getEventsQueryOptions(filters));
33+
export const useEvents = ({ filters }: { filters: GlobalEventsFilters }) => {
34+
const { currentBranch } = useCurrentBranch();
35+
const timeMachineDate = useAtomValue(datetimeAtom);
36+
37+
return useInfiniteQuery(
38+
getEventsQueryOptions({ filters, branchName: currentBranch.name, atDate: timeMachineDate })
39+
);
2540
};

frontend/app/src/entities/events/ui/branch-event.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,38 @@
1+
import { NodeLabel } from "@/entities/nodes/object/ui/node-label";
12
import { EventNodeInterface } from "@/shared/api/graphql/generated/graphql";
23
import { ReactNode } from "react";
34

4-
export const BRANCH_EVENTS_MAPPING: Record<string, (param: string) => ReactNode> = {
5-
"infrahub.branch.created": (branch) => (
5+
export const BRANCH_EVENTS_MAPPING: Record<string, (props: EventNodeInterface) => ReactNode> = {
6+
"infrahub.branch.created": (props) => (
67
<div>
7-
Branch <span className="text-black font-semibold">{branch}</span> created
8+
created the branch <span className="text-black font-semibold">{props.branch}</span>{" "}
89
</div>
910
),
10-
"infrahub.branch.rebased": (branch) => (
11+
"infrahub.branch.rebased": (props) => (
1112
<div>
12-
Branch <span className="text-black font-semibold">{branch}</span> rebased
13+
rebased the branch <span className="text-black font-semibold">{props.branch}</span>{" "}
1314
</div>
1415
),
15-
"infrahub.branch.deleted": (branch) => (
16+
"infrahub.branch.deleted": (props) => (
1617
<div>
17-
Branch <span className="text-black font-semibold">{branch}</span> deleted
18+
deleted the branch <span className="text-black font-semibold">{props.branch}</span>{" "}
1819
</div>
1920
),
2021
};
2122

2223
export const BranchEvent = (props: EventNodeInterface) => {
23-
const { event, branch } = props;
24+
const { event, account_id } = props;
2425

2526
return (
2627
<>
2728
<div className="flex items-center justify-between">
2829
<div className="flex items-center gap-2 text-sm">
2930
<div className="text-gray-500">
30-
{branch && BRANCH_EVENTS_MAPPING[event] && BRANCH_EVENTS_MAPPING[event](branch)}
31+
<div className="font-semibold">
32+
<NodeLabel id={account_id} />
33+
</div>
34+
35+
{BRANCH_EVENTS_MAPPING[event] && BRANCH_EVENTS_MAPPING[event](props)}
3136
</div>
3237
</div>
3338
</div>

frontend/app/src/entities/events/ui/event.tsx

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { EventNodeInterface, NodeMutatedEvent } from "@/shared/api/graphql/generated/graphql";
22
import { DateDisplay } from "@/shared/components/display/date-display";
33

4-
import { NodeLabel } from "@/entities/nodes/object/ui/display-label";
4+
import { NodeLabel } from "@/entities/nodes/object/ui/node-label";
55
import { PropertyRow } from "@/entities/schema/ui/styled";
66
import { CopyToClipboard } from "@/shared/components/buttons/copy-to-clipboard";
77
import { Popover, PopoverContent, PopoverTrigger } from "@/shared/components/ui/popover";
@@ -11,12 +11,12 @@ import {
1111
BRANCH_DELETED_EVENT,
1212
BRANCH_EVENTS,
1313
BRANCH_REBASEDED_EVENT,
14-
GROUP_EVENTS,
1514
NODE_MUTATED_EVENT,
15+
STANDARD_EVENTS,
1616
} from "../utils/constants";
1717
import { BranchEvent } from "./branch-event";
18-
import { GroupEvent } from "./group-event";
1918
import { EventAttributes, NodeEvent } from "./node-event";
19+
import { StandardEvent } from "./standard-event";
2020

2121
export type BranchEventType = EventNodeInterface & {
2222
__typename:
@@ -31,7 +31,15 @@ export type NodeEventType = NodeMutatedEvent & {
3131

3232
export type EventType = BranchEventType | NodeEventType;
3333

34-
export const EventDetails = ({ id, event, occurred_at, account_id, ...props }: EventType) => {
34+
export const EventDetails = ({
35+
id,
36+
event,
37+
occurred_at,
38+
account_id,
39+
primary_node,
40+
related_nodes,
41+
...props
42+
}: EventType) => {
3543
return (
3644
<div className="divide-y">
3745
<PropertyRow
@@ -45,6 +53,21 @@ export const EventDetails = ({ id, event, occurred_at, account_id, ...props }: E
4553
<PropertyRow title="Event" value={event} />
4654
<PropertyRow title="Occured at" value={<DateDisplay date={occurred_at} />} />
4755
{account_id && <PropertyRow title="Account" value={<NodeLabel id={account_id} />} />}
56+
{primary_node?.id && (
57+
<PropertyRow title="Primary Node" value={<NodeLabel id={primary_node?.id} />} />
58+
)}
59+
{!!related_nodes?.length && (
60+
<PropertyRow
61+
title="Related Nodes"
62+
value={
63+
<div className="flex items-center gap-1">
64+
{related_nodes.map((node) => {
65+
return <NodeLabel key={node.id} id={node?.id} />;
66+
})}
67+
</div>
68+
}
69+
/>
70+
)}
4871
{"attributes" in props && (
4972
<PropertyRow title="Changes" value={<EventAttributes attributes={props.attributes} />} />
5073
)}
@@ -65,7 +88,7 @@ export const Event = ({ __typename, ...props }: EventType) => {
6588

6689
{BRANCH_EVENTS.includes(__typename) && <BranchEvent {...props} />}
6790

68-
{GROUP_EVENTS.includes(__typename) && <GroupEvent {...props} />}
91+
{STANDARD_EVENTS.includes(__typename) && <StandardEvent {...props} />}
6992

7093
<div className="flex justify-between">
7194
<div className="text-xs font-medium text-gray-500 dark:text-neutral-400">

frontend/app/src/entities/events/ui/global-branch-event.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
1+
import { NodeLabel } from "@/entities/nodes/object/ui/node-label";
12
import { EventNodeInterface } from "@/shared/api/graphql/generated/graphql";
23
import { Icon } from "@iconify-icon/react";
34
import { BRANCH_EVENTS_MAPPING } from "./branch-event";
45

56
export const BranchEvent = (props: EventNodeInterface) => {
6-
const { event, branch } = props;
7+
const { event, account_id } = props;
78

89
return (
910
<div className="flex items-center justify-between">
1011
<div className="flex items-center gap-2 text-sm text-gray-500">
1112
<Icon icon="mdi:source-branch" className="text-gray-400" />
1213

13-
{branch && BRANCH_EVENTS_MAPPING[event] && BRANCH_EVENTS_MAPPING[event](branch)}
14+
<div className="text-black font-semibold">
15+
<NodeLabel id={account_id} />
16+
</div>
17+
18+
{BRANCH_EVENTS_MAPPING[event] && BRANCH_EVENTS_MAPPING[event](props)}
1419
</div>
1520
</div>
1621
);

0 commit comments

Comments
 (0)