Skip to content

Commit

Permalink
feat: add stateful set (#39)
Browse files Browse the repository at this point in the history
Co-authored-by: David Hu <[email protected]>
  • Loading branch information
davidhu2000 and David Hu authored Jan 21, 2023
1 parent c2964f4 commit ef1e40a
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 22 deletions.
7 changes: 5 additions & 2 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

mod resources;

use crate::resources::{cron_jobs, deployments, jobs, namespaces, pods, replica_sets};
use crate::resources::{
cron_jobs, deployments, jobs, namespaces, pods, replica_sets, stateful_sets,
};

fn main() {
tauri::Builder::default()
Expand All @@ -18,7 +20,8 @@ fn main() {
pods::get_pod_logs,
pods::get_pods,
namespaces::get_namespaces,
replica_sets::get_replica_sets
replica_sets::get_replica_sets,
stateful_sets::get_stateful_sets
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
Expand Down
1 change: 1 addition & 0 deletions src-tauri/src/resources/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ pub mod jobs;
pub mod namespaces;
pub mod pods;
pub mod replica_sets;
pub mod stateful_sets;
11 changes: 11 additions & 0 deletions src-tauri/src/resources/stateful_sets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use k8s_openapi::api::apps::v1::StatefulSet;
use kube::{api::ListParams, core::ObjectList, Api};

use super::internal::get_api;

#[tauri::command]
pub async fn get_stateful_sets(namespace: Option<String>) -> ObjectList<StatefulSet> {
let api: Api<StatefulSet> = get_api(namespace).await;
let lp = ListParams::default();
return api.list(&lp).await.unwrap();
}
32 changes: 25 additions & 7 deletions src/components/action-group.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,48 @@
import type { PencilIcon } from "@heroicons/react/20/solid";
import { ArrowPathIcon, ArrowsUpDownIcon, PencilIcon } from "@heroicons/react/20/solid";
import type { PropsWithChildren } from "react";

export function ActionGroup({ children }: PropsWithChildren) {
return <span className="isolate inline-flex rounded-md shadow-sm">{children}</span>;
}

export type Actions = "logs" | "edit" | "scale" | "restart";

interface ActionButtonProps {
Icon: typeof PencilIcon;
label: string;
label: Actions;
position: "left" | "right" | "middle";
onClick: () => void;
}

export function ActionButton({ Icon, label, position, onClick }: ActionButtonProps) {
const getIcon = (label: Actions) => {
switch (label) {
case "logs":
return ArrowPathIcon;
case "edit":
return PencilIcon;
case "scale":
return ArrowsUpDownIcon;
case "restart":
return ArrowPathIcon;
}
};

export function ActionButton({ label, position, onClick }: ActionButtonProps) {
const roundedClass =
position === "left" ? "rounded-l-md" : position === "right" ? "rounded-r-md" : "";

const Icon = getIcon(label);

return (
<button
type="button"
onClick={onClick}
className={`relative ${position === "left" ? "" : "-ml-px"
} inline-flex items-center ${roundedClass} border border-gray-300 p-2 hover:bg-gray-50`}
className={`relative ${
position === "left" ? "" : "-ml-px"
} inline-flex items-center ${roundedClass} border border-gray-300 p-2 hover:bg-gray-50`}
>
<Icon className="mr-2 h-5 w-5 text-gray-400" aria-hidden="true" />
{label}
{label[0].toUpperCase()}
{label.slice(1)}
</button>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface ModalProps {
handleClose: () => void;
deployment: V1Deployment;
}
export function ScaleDeploymentModal({ isOpen, handleClose, deployment }: ModalProps): JSX.Element {
export function ScaleModal({ isOpen, handleClose, deployment }: ModalProps): JSX.Element {
const [replicas, setReplicas] = useState<number>(deployment.spec?.replicas || 0);

const scaleMutation = useMutation({
Expand Down
13 changes: 5 additions & 8 deletions src/deployments/deployments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { invoke } from "@tauri-apps/api";
import { lazy, Suspense, useState } from "react";

import { ActionButton, ActionGroup } from "../components/action-group";
import { ScaleModal } from "../components/scale-modal";
import { Table, TableHeader, TableBody, TableCell } from "../components/table";
import { useCurrentNamespace } from "../namespaces/namespaces";
import { ScaleDeploymentModal } from "./scale-deployment-modal";

const ResourceEditDrawer = lazy(() =>
import("../components/resource-edit-drawer").then((module) => ({
Expand Down Expand Up @@ -68,20 +68,17 @@ export function Deployments() {
<TableCell>
<ActionGroup>
<ActionButton
Icon={ArrowPathIcon}
label="Restart"
label="restart"
position="left"
onClick={() => restartMutation.mutate(item)}
/>
<ActionButton
Icon={ArrowsUpDownIcon}
label="Scale"
label="scale"
position="middle"
onClick={() => handleOpen(item, "scale")}
/>
<ActionButton
Icon={PencilIcon}
label="Edit"
label="edit"
position="right"
onClick={() => handleOpen(item, "edit")}
/>
Expand All @@ -102,7 +99,7 @@ export function Deployments() {

<Suspense fallback={<div>Loading Scale Form</div>}>
{selected && (
<ScaleDeploymentModal
<ScaleModal
isOpen={action === "scale"}
handleClose={handleClose}
deployment={selected}
Expand Down
6 changes: 2 additions & 4 deletions src/pods/pods.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,12 @@ export function Pods() {
<TableCell>
<ActionGroup>
<ActionButton
Icon={BarsArrowDownIcon}
label="Logs"
label="logs"
position="left"
onClick={() => handleOpen(pod, "logs")}
/>
<ActionButton
Icon={PencilIcon}
label="Edit"
label="edit"
position="right"
onClick={() => handleOpen(pod, "edit")}
/>
Expand Down
2 changes: 2 additions & 0 deletions src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Jobs } from "./jobs/jobs";
import { Layout } from "./layout";
import { Pods } from "./pods/pods";
import { ReplicaSets } from "./replica-sets/replica-sets";
import { StatefulSets } from "./stateful-sets/stateful-sets";
import { TestPlayground } from "./test-playground/test-playground";

const rootRoute = createRouteConfig({
Expand All @@ -27,6 +28,7 @@ export const routes = [
{ name: "Jobs", path: "/jobs", component: Jobs },
{ name: "Pods", path: "/pods", component: Pods },
{ name: "Replica Sets", path: "/replica-sets", component: ReplicaSets },
{ name: "Stateful Sets", path: "/stateful-sets", component: StatefulSets },
{ name: "Testing", path: "/test-playground", component: TestPlayground },
] as const;

Expand Down
100 changes: 100 additions & 0 deletions src/stateful-sets/stateful-sets.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import type { V1StatefulSet } from "@kubernetes/client-node";
import { useQuery } from "@tanstack/react-query";
import { invoke } from "@tauri-apps/api";
import { lazy, Suspense, useState } from "react";

import { ActionButton, ActionGroup } from "../components/action-group";
import { Table, TableHeader, TableBody, TableCell } from "../components/table";
import { useCurrentNamespace } from "../namespaces/namespaces";
import { ScaleModal } from "../components/scale-modal";

const ResourceEditDrawer = lazy(() =>
import("../components/resource-edit-drawer").then((module) => ({
default: module.ResourceEditDrawer,
}))
);

type Actions = "edit" | "logs" | "scale";

export function StatefulSets() {
const { namespace } = useCurrentNamespace();

const result = useQuery(
["deployments", namespace],
() => {
return invoke<{ items: V1StatefulSet[] }>(`get_stateful_sets`, { namespace });
},
{ refetchInterval: 1000 }
);

const data = result.data?.items ?? [];

const [action, setAction] = useState<Actions | null>(null);
const [selected, setSelected] = useState<V1StatefulSet | null>(null);

const handleOpen = (deployment: V1StatefulSet, action: Actions) => {
setSelected(deployment);
setAction(action);
};

const handleClose = () => {
setSelected(null);
setAction(null);
};

return (
<div>
<Table>
<TableHeader headers={["Name", "Image", "Pods", "Actions"]} />
<TableBody>
{data.map((item) => (
<tr key={item.metadata?.uid}>
<TableCell>{item.metadata?.name}</TableCell>
<TableCell>{item.spec?.template.spec?.containers[0].image}</TableCell>
<TableCell>
{item.status?.availableReplicas} / {item.status?.replicas}
</TableCell>
<TableCell>
<ActionGroup>
<ActionButton
label="logs"
position="left"
onClick={() => handleOpen(item, "logs")}
/>
<ActionButton
label="edit"
position="middle"
onClick={() => handleOpen(item, "edit")}
/>
<ActionButton
label="scale"
position="right"
onClick={() => handleOpen(item, "scale")}
/>
</ActionGroup>
</TableCell>
</tr>
))}
</TableBody>
</Table>

<Suspense fallback={<div>Loading Editor</div>}>
<ResourceEditDrawer
isOpen={action === "edit"}
handleClose={handleClose}
selectedResource={selected}
/>
</Suspense>

<Suspense fallback={<div>Loading Scale Form</div>}>
{selected && (
<ScaleModal
isOpen={action === "scale"}
handleClose={handleClose}
deployment={selected}
/>
)}
</Suspense>
</div>
);
}

0 comments on commit ef1e40a

Please sign in to comment.