Skip to content

Commit 8fb5afb

Browse files
authored
Update activities UI (#5841)
* sticky filters * add links to related nodes * update ui * fix query and update related node display * fix event node label * fix sticky filters * update ui * update title * update menu link
1 parent e65a737 commit 8fb5afb

File tree

10 files changed

+111
-69
lines changed

10 files changed

+111
-69
lines changed

backend/infrahub/menu/menu.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,9 @@ def _extract_node_icon(model: MainSchemaTypes) -> str:
331331
),
332332
MenuItemDefinition(
333333
namespace="Builtin",
334-
name="ActivityLog",
335-
label="Activity Log",
336-
path="/activity-log",
334+
name="Activities",
335+
label="Activities",
336+
path="/activities",
337337
icon="mdi:timeline-text",
338338
protected=True,
339339
section=MenuSection.INTERNAL,

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ const EVENT_DETAILS_QUERY = gql`
4848
export async function getEventDetailsFromApi({
4949
branchName,
5050
atDate,
51+
id,
5152
...filters
5253
}: EventDetailsFilters & { branchName?: string; atDate?: Date | null }) {
5354
const { data } = await graphqlClient.query({
5455
query: EVENT_DETAILS_QUERY,
5556
variables: {
57+
ids: [id],
5658
...filters,
5759
},
5860
context: {

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

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

4+
import { ACCOUNT_OBJECT } from "@/config/constants";
5+
import { QSP } from "@/config/qsp";
46
import { NodeLabel } from "@/entities/nodes/object/ui/node-label";
57
import { PropertyRow } from "@/entities/schema/ui/styled";
8+
import { constructPath } from "@/shared/api/rest/fetch";
69
import { CopyToClipboard } from "@/shared/components/buttons/copy-to-clipboard";
10+
import { Link } from "@/shared/components/ui/link";
711
import { Popover, PopoverContent, PopoverTrigger } from "@/shared/components/ui/popover";
812
import { TimelineBorder } from "@/shared/components/ui/timeline-border";
913
import {
@@ -52,17 +56,50 @@ export const EventDetails = ({
5256
/>
5357
<PropertyRow title="Event" value={event} />
5458
<PropertyRow title="Occured at" value={<DateDisplay date={occurred_at} />} />
55-
{account_id && <PropertyRow title="Account" value={<NodeLabel id={account_id} />} />}
59+
{account_id && (
60+
<PropertyRow
61+
title="Account"
62+
value={
63+
<Link
64+
to={constructPath(`/${ACCOUNT_OBJECT}/${account_id}`, [
65+
{ name: QSP.BRANCH, value: props.branch },
66+
])}
67+
>
68+
<NodeLabel id={account_id} />
69+
</Link>
70+
}
71+
/>
72+
)}
5673
{primary_node?.id && (
57-
<PropertyRow title="Primary Node" value={<NodeLabel id={primary_node?.id} />} />
74+
<PropertyRow
75+
title="Primary Node"
76+
value={
77+
<Link
78+
to={constructPath(`/${primary_node.kind}/${primary_node.id}`, [
79+
{ name: QSP.BRANCH, value: props.branch },
80+
])}
81+
>
82+
<NodeLabel id={primary_node.id} />
83+
</Link>
84+
}
85+
/>
5886
)}
5987
{!!related_nodes?.length && (
6088
<PropertyRow
6189
title="Related Nodes"
6290
value={
63-
<div className="flex items-center gap-1">
91+
<div className="flex flex-col items-end gap-1">
6492
{related_nodes.map((node) => {
65-
return <NodeLabel key={node.id} id={node?.id} />;
93+
return (
94+
<Link
95+
key={node.id}
96+
to={constructPath(`/${node.kind}/${node.id}`, [
97+
{ name: QSP.BRANCH, value: props.branch },
98+
])}
99+
>
100+
<NodeLabel id={node?.id} />
101+
</Link>
102+
);
66103
})}
67104
</div>
68105
}

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { NodeEvents } from "./node-events";
88

99
const EventDetailsView = () => {
1010
const { activityid } = useParams();
11+
1112
const { isLoading, data, error, refetch } = useEventDetails({ id: activityid });
1213

1314
return (
@@ -23,10 +24,12 @@ const EventDetailsView = () => {
2324
<EventDetails {...data} />
2425
</CardWithBorder>
2526

26-
<CardWithBorder className="p-0 border-0 flex-1">
27-
<CardWithBorder.Title>Activities</CardWithBorder.Title>
28-
<NodeEvents parentId={activityid} />
29-
</CardWithBorder>
27+
{data?.has_children && (
28+
<CardWithBorder className="p-0 border-0 flex-1">
29+
<CardWithBorder.Title>Sub activities</CardWithBorder.Title>
30+
<NodeEvents parentId={activityid} />
31+
</CardWithBorder>
32+
)}
3033
</div>
3134
)}
3235
</Content.CardContent>

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

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Link } from "@/shared/components/ui/link";
2+
import { Tooltip } from "@/shared/components/ui/tooltip";
23
import { classNames } from "@/shared/utils/common";
34
import { Icon } from "@iconify-icon/react";
45
import { format } from "date-fns";
@@ -12,29 +13,39 @@ export const Event = ({ __typename, ...props }: EventType) => {
1213
return (
1314
<div
1415
className={classNames(
15-
"grid grid-cols-2 p-2 rounded-md shadow-sm border transition-all",
16-
"bg-gray-50",
17-
props.has_children && "bg-custom-blue-500/10"
16+
"grid grid-cols-3 relative gap-8 rounded-md shadow-sm transition-all border",
17+
"bg-gray-50"
1818
)}
1919
>
20-
<div className="flex flex-col gap-2 grow">
20+
<div className="col-span-2 p-2.5">
2121
{"attributes" in props && <NodeEvent {...props} />}
2222

2323
{BRANCH_EVENTS.includes(__typename) && <BranchEvent {...props} />}
2424

2525
{STANDARD_EVENTS.includes(__typename) && <StandardEvent {...props} />}
2626
</div>
2727

28-
<div className="grid grid-cols-3 items-center text-right">
28+
<div className="grid grid-cols-3 col-span-1 items-center text-right p-2.5 relative">
2929
<div className="text-xs font-medium text-gray-500 flex items-center gap-1">
30+
{props.has_children && (
31+
<Tooltip enabled content="Contains sub activities">
32+
<Icon
33+
icon={"mdi:subtasks"}
34+
className="absolute -left-8 rounded-full text-custom-blue-500 bg-custom-blue-500/10 p-1.5"
35+
/>
36+
</Tooltip>
37+
)}
38+
3039
<Icon icon={"mdi:source-branch"} />
3140
{props.branch}
3241
</div>
3342

34-
<div className="flex text-xs font-medium text-gray-500">
35-
<span className="mr-2">
36-
{props.occurred_at && format(new Date(props.occurred_at), "yyyy-MM-dd HH:mm:ss (O)")}
37-
</span>
43+
<div className="flex text-xs font-medium text-gray-500 whitespace-nowrap">
44+
{props.occurred_at && (
45+
<Tooltip enabled content={props.occurred_at}>
46+
<span>{format(new Date(props.occurred_at), "MMM dd - HH:mm:ss")}</span>
47+
</Tooltip>
48+
)}
3849
</div>
3950

4051
<Link to={`/activities/${props.id}`} className="text-xs text-gray-500">

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ export const GlobalEvents = () => {
4141
}
4242

4343
return (
44-
<Content.Card>
44+
<Content.Card className="relative">
4545
<Content.CardTitle title="Activities" isReloadLoading={isLoading} reload={() => refetch()} />
46-
<div className="flex flex-col flex-grow gap-2 p-2">
47-
<div className="flex items-center gap-2">
48-
<GlobalEventsFilters />
49-
{filters.length > 0 && <FilterResetButton />}
50-
</div>
46+
<div className="flex items-center gap-2 sticky top-0 bg-white z-10 p-2">
47+
<GlobalEventsFilters />
48+
{filters.length > 0 && <FilterResetButton />}
49+
</div>
5150

51+
<div className="flex flex-col flex-grow gap-2 p-2 bg-white z-30">
5252
<div className="flex flex-col gap-2">
5353
{!isLoading && !flatData?.length && <NoDataFound message="No activity found." />}
5454

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

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,34 +37,36 @@ export const NodeEvent = (props: NodeMutatedEvent) => {
3737
const { schema } = useSchema(props.payload.data.node_kind);
3838

3939
return (
40-
<>
41-
<div className="flex items-center justify-between">
42-
<div className="flex items-center gap-2 text-sm">
43-
<Icon icon={schema?.icon ?? "mdi:cube-outline"} className="text-gray-400" />
40+
<div className="flex items-center gap-2 text-sm whitespace-nowrap">
41+
<Icon icon={schema?.icon ?? "mdi:cube-outline"} className="text-gray-400" />
4442

45-
<div className="font-semibold">
46-
<NodeLabel id={account_id} />
47-
</div>
43+
<NodeLabel
44+
id={account_id}
45+
className="overflow-hidden text-ellipsis whitespace-nowrap font-semibold"
46+
/>
4847

49-
<div className="text-gray-500">{NODE_EVENTS_MAPPING[event] ?? "-"}</div>
48+
<div className="text-gray-500">{NODE_EVENTS_MAPPING[event] ?? "-"}</div>
5049

51-
<div className="font-semibold">{schemaLabels[props.payload.data.node_kind] ?? "-"}</div>
50+
<div className="font-semibold">{schemaLabels[props.payload.data.node_kind] ?? "-"}</div>
5251

53-
<Link
54-
to={constructPath(
55-
`/objects/${props.payload.data.node_kind}/${props.payload.data.node_id}`,
56-
[
57-
{
58-
name: QSP.BRANCH,
59-
value: props.branch,
60-
},
61-
]
62-
)}
63-
>
64-
<NodeLabel id={props.payload.data.node_id} />
65-
</Link>
66-
</div>
67-
</div>
68-
</>
52+
<Link
53+
to={constructPath(
54+
`/objects/${props.payload.data.node_kind}/${props.payload.data.node_id}`,
55+
[
56+
{
57+
name: QSP.BRANCH,
58+
value: props.branch,
59+
},
60+
]
61+
)}
62+
className="overflow-hidden text-ellipsis"
63+
>
64+
<NodeLabel
65+
id={props.primary_node.id}
66+
kind={props.primary_node?.kind}
67+
className="overflow-hidden text-ellipsis"
68+
/>
69+
</Link>
70+
</div>
6971
);
7072
};

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export const NodeEvent = (props: NodeMutatedEvent) => {
5555
`/objects/${props.payload.data.node_kind}/${props.payload.data.node_id}`
5656
)}
5757
>
58-
<NodeLabel id={props.payload.data.node_id} />
58+
<NodeLabel id={props.primary_node.id} kind={props.primary_node?.kind} />
5959
</Link>
6060
</div>
6161
</div>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const STANDARD_EVENTS_MAPPING: Record<string, (props: EventNodeInterface)
2828
key={primary_node?.id}
2929
to={constructPath(`/objects/CoreGroup/${primary_node?.id}`)}
3030
>
31-
<NodeLabel key={primary_node?.id} id={primary_node?.id} kind="CoreGroup" />
31+
<NodeLabel key={primary_node?.id} id={primary_node?.id} kind={primary_node?.kind} />
3232
</Link>
3333
</span>
3434
</div>
@@ -56,7 +56,7 @@ export const STANDARD_EVENTS_MAPPING: Record<string, (props: EventNodeInterface)
5656
key={primary_node?.id}
5757
to={constructPath(`/objects/CoreGroup/${primary_node?.id}`)}
5858
>
59-
<NodeLabel key={primary_node?.id} id={primary_node?.id} kind="CoreGroup" />
59+
<NodeLabel key={primary_node?.id} id={primary_node?.id} kind={primary_node?.kind} />
6060
</Link>
6161
</span>
6262
</div>
Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { NODE_OBJECT } from "@/config/constants";
2-
import { TextDisplay } from "@/shared/components/display/text-display";
32
import { Skeleton } from "@/shared/components/skeleton";
43
import { classNames } from "@/shared/utils/common";
54
import { useNodeLabel } from "../api/get-display-label.query";
@@ -22,20 +21,8 @@ export const NodeLabel = ({ id, kind = NODE_OBJECT, className }: NodeLabelProps)
2221
}
2322

2423
if (error || !data?.display_label) {
25-
return (
26-
<div className="italic">
27-
<TextDisplay maxChars={20} preventShowMore>
28-
{id}
29-
</TextDisplay>
30-
</div>
31-
);
24+
return <div className={classNames("italic", className)}>{id}</div>;
3225
}
3326

34-
return (
35-
<div className={classNames(className)}>
36-
<TextDisplay maxChars={20} preventShowMore>
37-
{data?.display_label}
38-
</TextDisplay>
39-
</div>
40-
);
27+
return <div className={className}>{data?.display_label}</div>;
4128
};

0 commit comments

Comments
 (0)