Skip to content

Commit

Permalink
Update activities UI (#5841)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
pa-lem authored Feb 25, 2025
1 parent e65a737 commit 8fb5afb
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 69 deletions.
6 changes: 3 additions & 3 deletions backend/infrahub/menu/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,9 +331,9 @@ def _extract_node_icon(model: MainSchemaTypes) -> str:
),
MenuItemDefinition(
namespace="Builtin",
name="ActivityLog",
label="Activity Log",
path="/activity-log",
name="Activities",
label="Activities",
path="/activities",
icon="mdi:timeline-text",
protected=True,
section=MenuSection.INTERNAL,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ const EVENT_DETAILS_QUERY = gql`
export async function getEventDetailsFromApi({
branchName,
atDate,
id,
...filters
}: EventDetailsFilters & { branchName?: string; atDate?: Date | null }) {
const { data } = await graphqlClient.query({
query: EVENT_DETAILS_QUERY,
variables: {
ids: [id],
...filters,
},
context: {
Expand Down
45 changes: 41 additions & 4 deletions frontend/app/src/entities/events/ui/event.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { EventNodeInterface, NodeMutatedEvent } from "@/shared/api/graphql/generated/graphql";
import { DateDisplay } from "@/shared/components/display/date-display";

import { ACCOUNT_OBJECT } from "@/config/constants";
import { QSP } from "@/config/qsp";
import { NodeLabel } from "@/entities/nodes/object/ui/node-label";
import { PropertyRow } from "@/entities/schema/ui/styled";
import { constructPath } from "@/shared/api/rest/fetch";
import { CopyToClipboard } from "@/shared/components/buttons/copy-to-clipboard";
import { Link } from "@/shared/components/ui/link";
import { Popover, PopoverContent, PopoverTrigger } from "@/shared/components/ui/popover";
import { TimelineBorder } from "@/shared/components/ui/timeline-border";
import {
Expand Down Expand Up @@ -52,17 +56,50 @@ export const EventDetails = ({
/>
<PropertyRow title="Event" value={event} />
<PropertyRow title="Occured at" value={<DateDisplay date={occurred_at} />} />
{account_id && <PropertyRow title="Account" value={<NodeLabel id={account_id} />} />}
{account_id && (
<PropertyRow
title="Account"
value={
<Link
to={constructPath(`/${ACCOUNT_OBJECT}/${account_id}`, [
{ name: QSP.BRANCH, value: props.branch },
])}
>
<NodeLabel id={account_id} />
</Link>
}
/>
)}
{primary_node?.id && (
<PropertyRow title="Primary Node" value={<NodeLabel id={primary_node?.id} />} />
<PropertyRow
title="Primary Node"
value={
<Link
to={constructPath(`/${primary_node.kind}/${primary_node.id}`, [
{ name: QSP.BRANCH, value: props.branch },
])}
>
<NodeLabel id={primary_node.id} />
</Link>
}
/>
)}
{!!related_nodes?.length && (
<PropertyRow
title="Related Nodes"
value={
<div className="flex items-center gap-1">
<div className="flex flex-col items-end gap-1">
{related_nodes.map((node) => {
return <NodeLabel key={node.id} id={node?.id} />;
return (
<Link
key={node.id}
to={constructPath(`/${node.kind}/${node.id}`, [
{ name: QSP.BRANCH, value: props.branch },
])}
>
<NodeLabel id={node?.id} />
</Link>
);
})}
</div>
}
Expand Down
11 changes: 7 additions & 4 deletions frontend/app/src/entities/events/ui/global-event-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { NodeEvents } from "./node-events";

const EventDetailsView = () => {
const { activityid } = useParams();

const { isLoading, data, error, refetch } = useEventDetails({ id: activityid });

return (
Expand All @@ -23,10 +24,12 @@ const EventDetailsView = () => {
<EventDetails {...data} />
</CardWithBorder>

<CardWithBorder className="p-0 border-0 flex-1">
<CardWithBorder.Title>Activities</CardWithBorder.Title>
<NodeEvents parentId={activityid} />
</CardWithBorder>
{data?.has_children && (
<CardWithBorder className="p-0 border-0 flex-1">
<CardWithBorder.Title>Sub activities</CardWithBorder.Title>
<NodeEvents parentId={activityid} />
</CardWithBorder>
)}
</div>
)}
</Content.CardContent>
Expand Down
29 changes: 20 additions & 9 deletions frontend/app/src/entities/events/ui/global-event.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Link } from "@/shared/components/ui/link";
import { Tooltip } from "@/shared/components/ui/tooltip";
import { classNames } from "@/shared/utils/common";
import { Icon } from "@iconify-icon/react";
import { format } from "date-fns";
Expand All @@ -12,29 +13,39 @@ export const Event = ({ __typename, ...props }: EventType) => {
return (
<div
className={classNames(
"grid grid-cols-2 p-2 rounded-md shadow-sm border transition-all",
"bg-gray-50",
props.has_children && "bg-custom-blue-500/10"
"grid grid-cols-3 relative gap-8 rounded-md shadow-sm transition-all border",
"bg-gray-50"
)}
>
<div className="flex flex-col gap-2 grow">
<div className="col-span-2 p-2.5">
{"attributes" in props && <NodeEvent {...props} />}

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

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

<div className="grid grid-cols-3 items-center text-right">
<div className="grid grid-cols-3 col-span-1 items-center text-right p-2.5 relative">
<div className="text-xs font-medium text-gray-500 flex items-center gap-1">
{props.has_children && (
<Tooltip enabled content="Contains sub activities">
<Icon
icon={"mdi:subtasks"}
className="absolute -left-8 rounded-full text-custom-blue-500 bg-custom-blue-500/10 p-1.5"
/>
</Tooltip>
)}

<Icon icon={"mdi:source-branch"} />
{props.branch}
</div>

<div className="flex text-xs font-medium text-gray-500">
<span className="mr-2">
{props.occurred_at && format(new Date(props.occurred_at), "yyyy-MM-dd HH:mm:ss (O)")}
</span>
<div className="flex text-xs font-medium text-gray-500 whitespace-nowrap">
{props.occurred_at && (
<Tooltip enabled content={props.occurred_at}>
<span>{format(new Date(props.occurred_at), "MMM dd - HH:mm:ss")}</span>
</Tooltip>
)}
</div>

<Link to={`/activities/${props.id}`} className="text-xs text-gray-500">
Expand Down
12 changes: 6 additions & 6 deletions frontend/app/src/entities/events/ui/global-events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ export const GlobalEvents = () => {
}

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

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

Expand Down
52 changes: 27 additions & 25 deletions frontend/app/src/entities/events/ui/global-node-event.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,34 +37,36 @@ export const NodeEvent = (props: NodeMutatedEvent) => {
const { schema } = useSchema(props.payload.data.node_kind);

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

<div className="font-semibold">
<NodeLabel id={account_id} />
</div>
<NodeLabel
id={account_id}
className="overflow-hidden text-ellipsis whitespace-nowrap font-semibold"
/>

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

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

<Link
to={constructPath(
`/objects/${props.payload.data.node_kind}/${props.payload.data.node_id}`,
[
{
name: QSP.BRANCH,
value: props.branch,
},
]
)}
>
<NodeLabel id={props.payload.data.node_id} />
</Link>
</div>
</div>
</>
<Link
to={constructPath(
`/objects/${props.payload.data.node_kind}/${props.payload.data.node_id}`,
[
{
name: QSP.BRANCH,
value: props.branch,
},
]
)}
className="overflow-hidden text-ellipsis"
>
<NodeLabel
id={props.primary_node.id}
kind={props.primary_node?.kind}
className="overflow-hidden text-ellipsis"
/>
</Link>
</div>
);
};
2 changes: 1 addition & 1 deletion frontend/app/src/entities/events/ui/node-event.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const NodeEvent = (props: NodeMutatedEvent) => {
`/objects/${props.payload.data.node_kind}/${props.payload.data.node_id}`
)}
>
<NodeLabel id={props.payload.data.node_id} />
<NodeLabel id={props.primary_node.id} kind={props.primary_node?.kind} />
</Link>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions frontend/app/src/entities/events/ui/standard-event.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const STANDARD_EVENTS_MAPPING: Record<string, (props: EventNodeInterface)
key={primary_node?.id}
to={constructPath(`/objects/CoreGroup/${primary_node?.id}`)}
>
<NodeLabel key={primary_node?.id} id={primary_node?.id} kind="CoreGroup" />
<NodeLabel key={primary_node?.id} id={primary_node?.id} kind={primary_node?.kind} />
</Link>
</span>
</div>
Expand Down Expand Up @@ -56,7 +56,7 @@ export const STANDARD_EVENTS_MAPPING: Record<string, (props: EventNodeInterface)
key={primary_node?.id}
to={constructPath(`/objects/CoreGroup/${primary_node?.id}`)}
>
<NodeLabel key={primary_node?.id} id={primary_node?.id} kind="CoreGroup" />
<NodeLabel key={primary_node?.id} id={primary_node?.id} kind={primary_node?.kind} />
</Link>
</span>
</div>
Expand Down
17 changes: 2 additions & 15 deletions frontend/app/src/entities/nodes/object/ui/node-label.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { NODE_OBJECT } from "@/config/constants";
import { TextDisplay } from "@/shared/components/display/text-display";
import { Skeleton } from "@/shared/components/skeleton";
import { classNames } from "@/shared/utils/common";
import { useNodeLabel } from "../api/get-display-label.query";
Expand All @@ -22,20 +21,8 @@ export const NodeLabel = ({ id, kind = NODE_OBJECT, className }: NodeLabelProps)
}

if (error || !data?.display_label) {
return (
<div className="italic">
<TextDisplay maxChars={20} preventShowMore>
{id}
</TextDisplay>
</div>
);
return <div className={classNames("italic", className)}>{id}</div>;
}

return (
<div className={classNames(className)}>
<TextDisplay maxChars={20} preventShowMore>
{data?.display_label}
</TextDisplay>
</div>
);
return <div className={className}>{data?.display_label}</div>;
};

0 comments on commit 8fb5afb

Please sign in to comment.