Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT]: Runbooks queried by Github and Gitlab #1976

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b88145f
progress 1
Sep 21, 2024
85fd3f5
Merge branch 'main' into Runbooks-queried-by-github-and-gitlb
Mubashirshariq Sep 21, 2024
e1e5fcf
Merge branch 'main' into Runbooks-queried-by-github-and-gitlb
talboren Sep 24, 2024
d2e90fd
made some changes
Mubashirshariq Sep 29, 2024
e062dfd
Merge branch 'main' into Runbooks-queried-by-github-and-gitlb
rajesh-jonnalagadda Sep 30, 2024
2e9bc5d
fix: access token issue on frontend. but need to move the fetching lo…
rajesh-jonnalagadda Oct 1, 2024
8d1c443
chore:remvoed unwanted logs
rajesh-jonnalagadda Oct 1, 2024
17d9d85
Merge pull request #1 from rajeshj11/feat-1780-runbooks-intergation
Mubashirshariq Oct 1, 2024
546a0bd
refactor: moved the entire runbook fetching logic to backend and adde…
rajesh-jonnalagadda Oct 2, 2024
9c99c29
chore: clean up the code
rajesh-jonnalagadda Oct 2, 2024
a871262
chore: resolved the lint issues
rajesh-jonnalagadda Oct 2, 2024
8e87f9c
Merge pull request #2 from rajeshj11/feat-1780-runbooks-intergation
rajesh-jonnalagadda Oct 2, 2024
6775426
Merge branch 'main' into Runbooks-queried-by-github-and-gitlb
rajesh-jonnalagadda Oct 2, 2024
25cd6e8
fix: minor drop down issue
rajesh-jonnalagadda Oct 2, 2024
67772e0
Merge pull request #3 from rajeshj11/feat-1780-runbooks-intergation
rajesh-jonnalagadda Oct 2, 2024
a7e4cd3
refactor: modified the styles of the runbook page
rajesh-jonnalagadda Oct 2, 2024
c1ee5e1
Merge pull request #4 from rajeshj11/feat-1780-runbooks-intergation
rajesh-jonnalagadda Oct 2, 2024
bc61c4c
Merge branch 'main' into Runbooks-queried-by-github-and-gitlb
rajesh-jonnalagadda Oct 2, 2024
f3504c1
chore: fix the corrupted code
rajesh-jonnalagadda Oct 2, 2024
402cad8
Merge pull request #5 from rajeshj11/feat-1780-runbooks-intergation
rajesh-jonnalagadda Oct 2, 2024
27d38cf
Merge branch 'keephq:main' into Runbooks-queried-by-github-and-gitlb
Mubashirshariq Oct 6, 2024
6d6f865
Merge branch 'main' into Runbooks-queried-by-github-and-gitlb
rajesh-jonnalagadda Oct 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions keep-ui/app/providers/filter-context/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const PROVIDER_LABELS: Record<TProviderLabels, string> = {
ticketing: 'Ticketing',
data: 'Data',
queue: 'Queue',
runbook: 'Runbook',
}

export const PROVIDER_LABELS_KEYS = Object.keys(PROVIDER_LABELS);
4 changes: 3 additions & 1 deletion keep-ui/app/providers/provider-tile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
import "./provider-tile.css";
import moment from "moment";
import ImageWithFallback from "@/components/ImageWithFallback";
import { FaCode } from "react-icons/fa";
import { FaCode, FaMarkdown } from "react-icons/fa";

interface Props {
provider: Provider;
Expand Down Expand Up @@ -101,6 +101,8 @@ function getIconForTag(tag: TProviderLabels) {
return QueueListIcon;
case "topology":
return MapIcon;
case "runbook":
return FaMarkdown
default:
return ChatBubbleBottomCenterIcon;
}
Expand Down
2 changes: 1 addition & 1 deletion keep-ui/app/providers/providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ interface AlertDistritbuionData {
number: number;
}

export type TProviderLabels = 'alert' | 'topology' | 'messaging' | 'ticketing' | 'data' | 'queue';
export type TProviderLabels = 'alert' | 'topology' | 'messaging' | 'ticketing' | 'data' | 'queue' | 'runbook';

export interface Provider {
// key value pair of auth method name and auth method config
Expand Down
7 changes: 7 additions & 0 deletions keep-ui/app/runbooks/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import RunbookIncidentTable from './runbook-table';

export default function RunbookPage() {
return (
<RunbookIncidentTable />
);
}
299 changes: 299 additions & 0 deletions keep-ui/app/runbooks/runbook-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
"use client";

import React, { useEffect, useMemo, useState } from "react";
import Modal from "react-modal";
import {
Button,
Badge,
Select,
SelectItem,
TextInput,
Title,
Card,
} from "@tremor/react";
import { createColumnHelper, DisplayColumnDef } from "@tanstack/react-table";
import { GenericTable } from "@/components/table/GenericTable";
import { useRunBookTriggers } from "utils/hooks/useRunbook";
import { useForm, get } from "react-hook-form";
import Markdown from "react-markdown";
import remarkGfm from "remark-gfm";

const customStyles = {
content: {
top: "50%",
left: "50%",
right: "auto",
bottom: "auto",
marginRight: "-50%",
transform: "translate(-50%, -50%)",
width: "400px",
},
};

interface Incident {
id: number;
name: string;
}

interface Runbook {
id: number;
title: string;
incidents: Incident[];
}

const runbookData = [
{
id: 1,
title: "Database Recovery",
incidents: [
{ id: 101, name: "DB Outage on 2024-01-01" },
{ id: 102, name: "DB Backup Failure" },
],
},
{
id: 2,
title: "API Health Check",
incidents: [{ id: 201, name: "API Latency Issue" }],
},
{
id: 3,
title: "Server Restart Guide",
incidents: [
{ id: 301, name: "Unexpected Server Crash" },
{ id: 302, name: "Scheduled Maintenance" },
],
},
] as Runbook[];

const columnHelper = createColumnHelper<Runbook>();

const columns = [
columnHelper.display({
id: "title",
header: "Runbook Title",
cell: ({ row }) => {
return <div>{row.original.title}</div>;
},
}),
columnHelper.display({
id: "incidents",
header: "Incdients",
cell: ({ row }) => {
return (
<div>
{row.original.incidents?.map((incident: Incident) => (
<Badge key={incident.id} color="green" className="mr-2 mb-1">
{incident.name}
</Badge>
))}
</div>
);
},
}),
] as DisplayColumnDef<Runbook>[];

// function PreviewContent({type, data}:{type:string, data:string}){
// const [isModalOpen, setIsModalOpen] = useState(open);

// // const closeModal = () => {
// // setIsModalOpen(false);
// // };
// const decodeBase64 = (encodedContent:string) => {
// // Use atob to decode the Base64 string and then handle UTF-8 encoding
// return encodedContent ? decodeURIComponent(atob(encodedContent)) : '';
// };
// return <div className={`w-full h-full p-10`}>

// <Markdown remarkPlugins={[remarkGfm]}>
// {decodeBase64(data)}
// </Markdown>
// </div>
// }

// TO DO: Need to work on styling
function SettingsPage() {
const [isModalOpen, setIsModalOpen] = useState(false);
const { register, handleSubmit, reset, getValues, setValue, watch } =
useForm();
const [refresh, setRefresh] = useState(0);
const [openPreview, setOpenPreview] = useState(false);

const {
runBookInstalledProviders,
reposData,
handleSubmit: submitHandler,
provider,
fileData,
} = useRunBookTriggers(getValues(), refresh);

const selectedProviderId = watch(
"providerId",
provider?.details?.authentication?.provider_id ?? ""
);
const selectedRepo = watch(
"repoName",
provider?.details?.authentication?.repository ?? ""
);

useEffect(() => {
setValue(
"repoName",
reposData?.legnth ? provider?.details?.authentication.repository : ""
);
setOpenPreview(false);
}, [reposData]);

const openModal = () => {
reset(); // Reset form when opening modal
setIsModalOpen(true);
setOpenPreview(false);
};

const closeModal = (openPreview?: boolean) => {
setIsModalOpen(false);
if (openPreview) {
setOpenPreview(true);
} else {
setOpenPreview(false);
}
};

const onSubmit = (data: any) => {
submitHandler(data); // Call the submit handler with form data
// closeModal(); // Close modal after submit
};

const handleProviderChange = (value: string) => {
setValue("repoName", "");
setValue("providerId", value);
setRefresh((prev) => prev + 1);
};

return (
<div>
<Button onClick={openModal}>Settings</Button>
<Modal
isOpen={isModalOpen}
onRequestClose={() => closeModal()}
style={customStyles}
contentLabel="Settings Modal"
>
<h2>Runbook Settings</h2>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="space-y-4 w-full my-4 h-full overflow-hidden">
<div>
{/* <label>Choose Provider</label> */}
<Select
onValueChange={handleProviderChange} // Update the form value manually on change
placeholder="Select Provider"
required={true}
value={selectedProviderId}
>
<SelectItem key={"provider_select"} value="">
Select Provider
</SelectItem>
{runBookInstalledProviders?.map((provider) => {
return (
<SelectItem key={provider.id} value={provider.id}>
{provider?.details?.name}
</SelectItem>
);
})}
</Select>
</div>
<div>
<Select
onValueChange={(value: string) => {
setValue("repoName", value);
}}
placeholder="Select Repo"
value={selectedRepo}
>
<SelectItem key={"repo_select"} value="">
Select Repo
</SelectItem>
{reposData.map((repo: any) => (
<SelectItem key={repo.option_value} value={repo.option_value}>
{repo.display_name}
</SelectItem>
))}
</Select>
</div>
<div>
<TextInput
{...register("runBookTitle")}
placeholder="Enter Runbook Title"
required
/>
</div>
<div>
<TextInput
{...register("pathToMdFile")}
placeholder="Enter path to markdown files"
/>
</div>
</div>
{/* <div style={{ textAlign: "left" }}>
<Button
type="button"
onClick={()=>{closeModal(true)}}
style={{ marginRight: "10px" }}
>
Preview
</Button>

</div> */}
<div style={{ textAlign: "right" }}>
<Button
type="button"
onClick={() => closeModal()}
style={{ marginRight: "10px" }}
>
Cancel
</Button>
<Button type="submit" color="blue">
Query
</Button>
</div>
</form>
</Modal>
{/* {fileData?.content && openPreview &&<PreviewContent type="markdown" data={fileData?.content} />} */}
</div>
);
}

function RunbookIncidentTable() {
const [offset, setOffset] = useState(0);
const [limit, setLimit] = useState(10);

// Modal state management

const handlePaginationChange = (newLimit: number, newOffset: number) => {
setLimit(newLimit);
setOffset(newOffset);
};

return (
<div className="flex flex-col h-full gap-4">
<div className="flex justify-between items-center h-[10%]">
<Title>Runbook</Title>
<SettingsPage />
</div>
<Card className="flex-1 overflow-auto">
<GenericTable<Runbook>
data={runbookData}
columns={columns}
rowCount={runbookData.length}
offset={offset}
limit={limit}
onPaginationChange={handlePaginationChange}
onRowClick={(row) => {
console.log("Runbook clicked:", row);
}}
/>
</Card>
</div>
);
}

export default RunbookIncidentTable;
9 changes: 9 additions & 0 deletions keep-ui/components/navbar/NoiseReductionLinks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import classNames from "classnames";
import { AILink } from "./AILink";
import { TbTopologyRing } from "react-icons/tb";
import { FaVolumeMute } from "react-icons/fa";
import { FaMarkdown } from "react-icons/fa";
import { IoMdGitMerge } from "react-icons/io";
import { useTopology } from "@/app/topology/model/useTopology";

Expand Down Expand Up @@ -42,6 +43,14 @@ export const NoiseReductionLinks = ({ session }: NoiseReductionLinksProps) => {
</Disclosure.Button>

<Disclosure.Panel as="ul" className="space-y-2 p-2 pr-4">
<li >
<LinkWithIcon
href="/runbooks"
icon={FaMarkdown}
>
<Subtitle>Runbooks</Subtitle>
</LinkWithIcon>
</li>
<li>
<LinkWithIcon href="/deduplication" icon={IoMdGitMerge}>
<Subtitle>Deduplication</Subtitle>
Expand Down
1 change: 1 addition & 0 deletions keep-ui/utils/apiUrl.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

export function getApiURL(): string {
// https://github.com/vercel/next.js/issues/5354#issuecomment-520305040
// https://stackoverflow.com/questions/49411796/how-do-i-detect-whether-i-am-on-server-on-client-in-next-js
Expand Down
3 changes: 1 addition & 2 deletions keep-ui/utils/fetcher.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { KeepApiError } from '../app/error';

export const fetcher = async (
url: string,
accessToken: string | undefined,
requestInit: RequestInit = {}
requestInit: RequestInit = {},
) => {
const response = await fetch(url, {
headers: {
Expand Down
Loading
Loading