Skip to content

Commit

Permalink
Merge branch 'main' into feat-2538-refactor-builder-actions
Browse files Browse the repository at this point in the history
  • Loading branch information
rajesh-jonnalagadda authored Dec 13, 2024
2 parents 3cd3878 + afc4a72 commit fcbcdfd
Show file tree
Hide file tree
Showing 44 changed files with 778 additions and 166 deletions.
22 changes: 22 additions & 0 deletions docs/deployment/monitoring.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: "Monitoring"
sidebarTitle: "Monitoring"
---

# Healthchecks

Keep's Backend healthcheck url:
```
{BACKEND_API_URL}/healthcheck
```

Keep's Frontend healthcheck url:
```
{FRONTEND_URL}/api/healthcheck
```

# Prometheus Metrics

(TBD)

> Please note that [/api/metrics](api-ref/metrics/get-metrics) are not designed for production instance's health monitoring, but for usage monitoring by a specific tenant.
1 change: 1 addition & 0 deletions docs/mint.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"group": "Deployment",
"pages": [
"deployment/configuration",
"deployment/monitoring",
{
"group": "Authentication",
"pages": [
Expand Down
2 changes: 1 addition & 1 deletion keep-ui/app/(keep)/alerts/alert-table-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const isDateWithinRange: FilterFn<AlertDto> = (row, columnId, value) => {
}

if (isValid(start) && isValid(end)) {
return isWithinInterval(startOfDay(date), { start, end });
return isWithinInterval(date, { start, end });
}

if (isValid(start)) {
Expand Down
8 changes: 6 additions & 2 deletions keep-ui/app/(keep)/error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ export default function ErrorComponent({

return (
<div className="error-container">
<Title>An error occurred while fetching data from the backend</Title>
<Title>
{error instanceof KeepApiError
? "An error occurred while fetching data from the backend"
: error.message || "An error occurred"}
</Title>
<div className="code-container">
<code>
{error instanceof KeepApiError && (
Expand All @@ -37,7 +41,7 @@ export default function ErrorComponent({
<br />
Message: {error.message}
<br />
Url: {error.url}
URL: {error.url}
</div>
)}
</code>
Expand Down
10 changes: 7 additions & 3 deletions keep-ui/app/(keep)/providers/provider-tile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,12 @@ export default function ProviderTile({ provider, onClick }: Props) {
"min-h-36 tile-basis text-left min-w-0 py-4 px-4 relative group flex justify-around items-center bg-white rounded-lg shadow hover:grayscale-0 gap-3" +
// Add fixed height only if provider card doesn't have much content
(!provider.installed && !provider.linked ? " h-32" : "") +
(!provider.linked ? "cursor-pointer hover:shadow-lg" : "") +
(provider.coming_soon ? " opacity-50 cursor-not-allowed" : "")
(!provider.linked
? " cursor-pointer hover:shadow-lg"
: " cursor-auto") +
(provider.coming_soon && !provider.linked
? " opacity-50 cursor-not-allowed"
: "")
}
onClick={provider.coming_soon ? undefined : onClick}
disabled={provider.coming_soon}
Expand Down Expand Up @@ -219,7 +223,7 @@ export default function ProviderTile({ provider, onClick }: Props) {
<div>
<Title className="capitalize" title={provider.details?.name}>
{provider.display_name}{" "}
{provider.coming_soon && (
{provider.coming_soon && !provider.linked && (
<span className="text-sm">(Coming Soon)</span>
)}
</Title>
Expand Down
16 changes: 9 additions & 7 deletions keep-ui/app/(keep)/providers/providers-tiles.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use client";
import { Icon, Title } from "@tremor/react";
import { Title } from "@tremor/react";
import { Providers, Provider } from "./providers";
import { useEffect, useState } from "react";
// TODO: replace with custom component, package is not updated for last 4 years
Expand All @@ -9,6 +9,7 @@ import ProviderTile from "./provider-tile";
import "react-sliding-side-panel/lib/index.css";
import { useSearchParams } from "next/navigation";
import { QuestionMarkCircleIcon } from "@heroicons/react/24/outline";
import { Tooltip } from "@/shared/ui";

const ProvidersTiles = ({
providers,
Expand Down Expand Up @@ -95,12 +96,13 @@ const ProvidersTiles = ({
<Title>{getSectionTitle()}</Title>
{linkedProvidersMode && (
<div className="relative">
<Icon
icon={QuestionMarkCircleIcon} // Use the appropriate icon for your use case
className="text-gray-400 hover:text-gray-600"
size="sm"
tooltip="Providers that send alerts to Keep and are not installed."
/>
<Tooltip
content={
<>Providers that send alerts to Keep and are not installed.</>
}
>
<QuestionMarkCircleIcon className="w-4 h-4" />
</Tooltip>
</div>
)}
</div>
Expand Down
1 change: 1 addition & 0 deletions keep-ui/app/(keep)/topology/model/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface TopologyService {
application_ids: string[];
// Added on client to optimize rendering
applications: TopologyApplicationMinimal[];
incidents?: number;
}

// We need to convert interface to type because only types are allowed in @xyflow/react
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,25 @@ import {
edgeLabelBgStyleNoHover,
edgeMarkerEndNoHover,
} from "@/app/(keep)/topology/ui/map/styles";
import { IncidentDto } from "@/entities/incidents/model";

export function getNodesAndEdgesFromTopologyData(
topologyData: TopologyService[],
applicationsMap: Map<string, TopologyApplication>
applicationsMap: Map<string, TopologyApplication>,
allIncidents: IncidentDto[]
) {
const nodeMap = new Map<string, TopologyNode>();
const edgeMap = new Map<string, Edge>();
const allServices = topologyData.map((data) => data.display_name);
// Create nodes from service definitions
for (const service of topologyData) {
const numIncidentsToService = allIncidents.filter((incident) =>
incident.services.includes(service.display_name)
);
const node: ServiceNodeType = {
id: service.service.toString(),
type: "service",
data: service,
data: { ...service, incidents: numIncidentsToService.length },
position: { x: 0, y: 0 }, // Dagre will handle the actual positioning
selectable: true,
};
Expand Down
49 changes: 32 additions & 17 deletions keep-ui/app/(keep)/topology/ui/map/service-node.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import React, { useEffect, useState } from "react";
import { Handle, NodeProps, NodeToolbar, Position } from "@xyflow/react";
import { useAlerts } from "@/utils/hooks/useAlerts";
import { useAlertPolling } from "@/utils/hooks/usePusher";
import { useRouter } from "next/navigation";
import { ServiceNodeType, TopologyService } from "../../model/models";
import { Badge } from "@tremor/react";
Expand Down Expand Up @@ -73,30 +71,43 @@ function ServiceDetailsTooltip({ data }: { data: TopologyService }) {
}

export function ServiceNode({ data, selected }: NodeProps<ServiceNodeType>) {
const { useAllAlerts } = useAlerts();
const { data: alerts, mutate } = useAllAlerts("feed");
const { data: pollAlerts } = useAlertPolling();
const router = useRouter();
const [showDetails, setShowDetails] = useState(false);
const [isTooltipReady, setIsTooltipReady] = useState(false);
const [tooltipDirection, setTooltipDirection] = useState<Position>(
Position.Bottom
);

useEffect(() => {
if (pollAlerts) {
mutate();
if (!showDetails) {
setTooltipDirection(Position.Bottom);
setIsTooltipReady(false);
return;
}
}, [pollAlerts, mutate]);

const relevantAlerts = alerts?.filter(
(alert) => alert.service === data.service
);
const node = document.querySelector(".tooltip-ref");
if (!node) return;

const rect = node.getBoundingClientRect();
const viewportHeight = window.innerHeight;

if (rect.bottom + 10 > viewportHeight) {
setTooltipDirection(Position.Top);
} else {
setTooltipDirection(Position.Bottom);
}
setIsTooltipReady(true);
}, [showDetails]);

const handleClick = () => {
router.push(
`/alerts/feed?cel=service%3D%3D${encodeURIComponent(`"${data.service}"`)}`
`/incidents?services={encodeURIComponent("${data.display_name}")}`
);
};

const alertCount = relevantAlerts?.length || 0;
const badgeColor = alertCount < THRESHOLD ? "bg-orange-500" : "bg-red-500";
const incidentsCount = data.incidents ?? 0;
const badgeColor =
incidentsCount < THRESHOLD ? "bg-orange-500" : "bg-red-500";

return (
<>
Expand All @@ -121,12 +132,12 @@ export function ServiceNode({ data, selected }: NodeProps<ServiceNodeType>) {
</div>
)}
<strong className="text-lg">{data.display_name || data.service}</strong>
{alertCount > 0 && (
{incidentsCount > 0 && (
<span
className={`absolute top-[-20px] right-[-20px] mt-2 mr-2 px-2 py-1 text-white text-xs font-bold rounded-full ${badgeColor} hover:cursor-pointer`}
onClick={handleClick}
>
{alertCount}
{incidentsCount}
</span>
)}
<div className="flex flex-wrap gap-1">
Expand All @@ -141,7 +152,11 @@ export function ServiceNode({ data, selected }: NodeProps<ServiceNodeType>) {
</div>
</div>

<NodeToolbar isVisible={showDetails} position={Position.Bottom}>
<NodeToolbar
isVisible={showDetails}
position={tooltipDirection}
className={clsx("tooltip-ref", !isTooltipReady && "invisible")}
>
<ServiceDetailsTooltip data={data} />
</NodeToolbar>

Expand Down
8 changes: 6 additions & 2 deletions keep-ui/app/(keep)/topology/ui/map/topology-map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import "@xyflow/react/dist/style.css";
import { areSetsEqual } from "@/utils/helpers";
import { getLayoutedElements } from "@/app/(keep)/topology/ui/map/getLayoutedElements";
import { getNodesAndEdgesFromTopologyData } from "@/app/(keep)/topology/ui/map/getNodesAndEdgesFromTopologyData";
import { useIncidents } from "@/utils/hooks/useIncidents";

const defaultFitViewOptions: FitViewOptions = {
padding: 0.1,
Expand Down Expand Up @@ -223,6 +224,8 @@ export function TopologyMap({

const previousNodesIds = useRef<Set<string>>(new Set());

const { data: allIncidents } = useIncidents();

useEffect(
function createAndSetLayoutedNodesAndEdges() {
if (!topologyData) {
Expand All @@ -231,7 +234,8 @@ export function TopologyMap({

const { nodeMap, edgeMap } = getNodesAndEdgesFromTopologyData(
topologyData,
applicationMap
applicationMap,
allIncidents?.items ?? []
);

const newNodes = Array.from(nodeMap.values());
Expand Down Expand Up @@ -262,7 +266,7 @@ export function TopologyMap({
setNodes(layoutedElements.nodes);
setEdges(layoutedElements.edges);
},
[topologyData, applicationMap]
[topologyData, applicationMap, allIncidents]
);

useEffect(
Expand Down
23 changes: 10 additions & 13 deletions keep-ui/app/(keep)/workflows/[workflow_id]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";
import { ArrowLeftIcon } from "@radix-ui/react-icons";
import Link from "next/link";
import { Link } from "@/components/ui";
import { ArrowRightIcon } from "@heroicons/react/16/solid";
import { Icon, Subtitle } from "@tremor/react";

export default function Layout({
children,
Expand All @@ -10,16 +11,12 @@ export default function Layout({
params: { workflow_id: string };
}) {
return (
<>
<div className="flex flex-col mb-4 h-full gap-6">
<Link
href="/workflows"
className="flex items-center text-gray-500 hover:text-gray-700"
>
<ArrowLeftIcon className="h-5 w-5 mr-1" /> Back to Workflows
</Link>
<div className="flex-1 overflow-auto h-full">{children}</div>
</div>
</>
<div className="flex flex-col mb-4 h-full gap-6">
<Subtitle className="text-sm">
<Link href="/workflows">All Workflows</Link>{" "}
<Icon icon={ArrowRightIcon} color="gray" size="xs" /> Workflow Details
</Subtitle>
<div className="flex-1 h-full">{children}</div>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { PiDiamondsFourFill } from "react-icons/pi";
import { FaHandPointer } from "react-icons/fa";
import { HiBellAlert } from "react-icons/hi2";
import { useRouter } from "next/navigation";
import { CursorArrowRaysIcon } from "@heroicons/react/24/outline";

interface Pagination {
limit: number;
Expand Down Expand Up @@ -116,7 +117,7 @@ export function getIcon(status: string) {
export function getTriggerIcon(triggered_by: string) {
switch (triggered_by) {
case "Manual":
return FaHandPointer;
return CursorArrowRaysIcon;
case "Scheduler":
return PiDiamondsFourFill;
case "Alert":
Expand Down
6 changes: 3 additions & 3 deletions keep-ui/app/(keep)/workflows/builder/CustomNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { MdNotStarted } from "react-icons/md";
import { GoSquareFill } from "react-icons/go";
import { PiDiamondsFourFill, PiSquareLogoFill } from "react-icons/pi";
import { BiSolidError } from "react-icons/bi";
import { FaHandPointer } from "react-icons/fa";
import { toast } from "react-toastify";
import { FlowNode, V2Step } from "@/app/(keep)/workflows/builder/types";
import { FlowNode } from "@/app/(keep)/workflows/builder/types";
import { CursorArrowRaysIcon } from "@heroicons/react/24/outline";

function IconUrlProvider(data: FlowNode["data"]) {
const { componentType, type } = data || {};
Expand Down Expand Up @@ -47,7 +47,7 @@ function CustomNode({ id, data }: FlowNode) {
const { type } = step;
switch (type) {
case "manual":
return <FaHandPointer size={32} />;
return <CursorArrowRaysIcon className="size-8" />;
case "interval":
return <PiDiamondsFourFill size={32} />;
}
Expand Down
4 changes: 2 additions & 2 deletions keep-ui/app/(keep)/workflows/builder/ToolBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { IoChevronUp, IoClose } from "react-icons/io5";
import Image from "next/image";
import { IoIosArrowDown } from "react-icons/io";
import useStore from "./builder-store";
import { FaHandPointer } from "react-icons/fa";
import { PiDiamondsFourFill } from "react-icons/pi";
import clsx from "clsx";
import { V2Step } from "@/app/(keep)/workflows/builder/types";
import { CursorArrowRaysIcon } from "@heroicons/react/24/outline";

const GroupedMenu = ({
name,
Expand Down Expand Up @@ -55,7 +55,7 @@ const GroupedMenu = ({
const { type } = step;
switch (type) {
case "manual":
return <FaHandPointer size={32} />;
return <CursorArrowRaysIcon className="size-8" />;
case "interval":
return <PiDiamondsFourFill size={32} />;
}
Expand Down
Loading

0 comments on commit fcbcdfd

Please sign in to comment.