From 7eb985b616c12aed261fbef74a47c5a928c03e61 Mon Sep 17 00:00:00 2001
From: Ellie Huxtable <ellie@atuin.sh>
Date: Mon, 15 Jul 2024 19:12:01 +0100
Subject: feat(gui): add runbook list, ability to create and delete, sql
 storage (#2282)

* wip

* saving works :))

* functioning delete button

* persist selection properly
---
 ui/src/components/runbooks/List.tsx | 120 ++++++++++++++++++++++++++++++++++++
 1 file changed, 120 insertions(+)
 create mode 100644 ui/src/components/runbooks/List.tsx

(limited to 'ui/src/components/runbooks/List.tsx')

diff --git a/ui/src/components/runbooks/List.tsx b/ui/src/components/runbooks/List.tsx
new file mode 100644
index 00000000..be6e84f5
--- /dev/null
+++ b/ui/src/components/runbooks/List.tsx
@@ -0,0 +1,120 @@
+import { useEffect, useState } from "react";
+import {
+  Input,
+  Button,
+  ButtonGroup,
+  Card,
+  CardBody,
+  CardHeader,
+  Divider,
+  Tooltip,
+  Listbox,
+  ListboxItem,
+  Dropdown,
+  DropdownTrigger,
+  DropdownMenu,
+  DropdownItem,
+} from "@nextui-org/react";
+
+import { EllipsisVerticalIcon } from "lucide-react";
+
+import { DateTime } from "luxon";
+
+import { NotebookPenIcon } from "lucide-react";
+import Runbook from "@/state/runbooks/runbook";
+import { useStore } from "@/state/store";
+
+const NoteSidebar = () => {
+  const runbooks = useStore((state) => state.runbooks);
+  const refreshRunbooks = useStore((state) => state.refreshRunbooks);
+
+  const currentRunbook = useStore((state) => state.currentRunbook);
+  const setCurrentRunbook = useStore((state) => state.setCurrentRunbook);
+
+  useEffect(() => {
+    refreshRunbooks();
+  }, []);
+
+  return (
+    <div className="min-w-48 h-screen flex flex-col border-r-1">
+      <div className="overflow-y-auto flex-grow">
+        <Listbox
+          hideSelectedIcon
+          items={runbooks}
+          variant="flat"
+          aria-label="Runbook list"
+          selectionMode="single"
+          selectedKeys={[currentRunbook]}
+          itemClasses={{ base: "data-[selected=true]:bg-gray-200" }}
+          topContent={
+            <ButtonGroup>
+              <Tooltip showArrow content="New Runbook" closeDelay={50}>
+                <Button
+                  isIconOnly
+                  aria-label="New note"
+                  variant="light"
+                  size="sm"
+                  onPress={async () => {
+                    let runbook = await Runbook.create();
+                    setCurrentRunbook(runbook.id);
+                    refreshRunbooks();
+                  }}
+                >
+                  <NotebookPenIcon className="p-[0.15rem]" />
+                </Button>
+              </Tooltip>
+            </ButtonGroup>
+          }
+        >
+          {(runbook) => (
+            <ListboxItem
+              key={runbook.id}
+              onPress={() => {
+                setCurrentRunbook(runbook.id);
+              }}
+              textValue={runbook.name || "Untitled"}
+              endContent={
+                <Dropdown>
+                  <DropdownTrigger className="bg-transparent">
+                    <Button isIconOnly>
+                      <EllipsisVerticalIcon
+                        size="16px"
+                        className="bg-transparent"
+                      />
+                    </Button>
+                  </DropdownTrigger>
+                  <DropdownMenu aria-label="Dynamic Actions">
+                    <DropdownItem
+                      key={"delete"}
+                      color="danger"
+                      className="text-danger"
+                      onPress={async () => {
+                        await Runbook.delete(runbook.id);
+                        refreshRunbooks();
+                      }}
+                    >
+                      Delete
+                    </DropdownItem>
+                  </DropdownMenu>
+                </Dropdown>
+              }
+            >
+              <div className="flex flex-col">
+                <div className="text-md">{runbook.name || "Untitled"}</div>
+                <div className="text-xs text-gray-500">
+                  <em>
+                    {DateTime.fromJSDate(runbook.updated).toLocaleString(
+                      DateTime.DATETIME_SIMPLE,
+                    )}
+                  </em>
+                </div>
+              </div>
+            </ListboxItem>
+          )}
+        </Listbox>
+      </div>
+    </div>
+  );
+};
+
+export default NoteSidebar;
-- 
cgit v1.3.1

