Skip to content

Commit

Permalink
feat: added jobs overview
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeroen Nijhuis committed Dec 22, 2023
1 parent 54582e6 commit 6c2f217
Show file tree
Hide file tree
Showing 13 changed files with 231 additions and 69 deletions.
55 changes: 36 additions & 19 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@vueuse/core": "^10.7.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"date-fns": "^3.0.6",
"radix-vue": "^1.2.5",
"tailwind-merge": "^2.1.0",
"tailwindcss-animate": "^1.0.7",
Expand Down
17 changes: 15 additions & 2 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use tauri::api::shell;
use tauri::{CustomMenuItem, Manager, Menu, Submenu};
use k8s_openapi::api::batch::v1::Job;
use tauri::Manager;

use k8s_openapi::api::apps::v1::Deployment;
use k8s_openapi::api::core::v1::{Namespace, Pod, Service};
Expand Down Expand Up @@ -185,6 +185,18 @@ async fn list_services(
.map_err(|err| SerializableKubeError::from(err));
}

#[tauri::command]
async fn list_jobs(context: &str, namespace: &str) -> Result<Vec<Job>, SerializableKubeError> {
let client = client_with_context(context).await?;
let jobs_api: Api<Job> = Api::namespaced(client, namespace);

return jobs_api
.list(&ListParams::default())
.await
.map(|jobs| jobs.items)
.map_err(|err| SerializableKubeError::from(err));
}

struct TerminalSession {
writer: Arc<Mutex<Box<dyn Write + Send>>>,
}
Expand Down Expand Up @@ -298,6 +310,7 @@ fn main() {
get_pod,
list_deployments,
list_services,
list_jobs,
create_tty_session,
stop_tty_session,
write_to_pty
Expand Down
30 changes: 15 additions & 15 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,20 @@ import CommandPaletteProvider from "./providers/CommandPaletteProvider";

<template>
<AppLayout class="dark bg-zinc-900 text-sm rounded-lg">
<AuthCheck>
<template #default>
<KubeContextProvider>
<CommandPaletteProvider>
<Navigation />
<RouterViewport />
<Toaster />
<CommandPalette />
</CommandPaletteProvider>
</KubeContextProvider>
</template>
<template #loading>
<Loading label="K8s crew, prepare for take-off..." />
</template>
</AuthCheck>
<!-- <AuthCheck> -->
<!-- <template #default> -->
<KubeContextProvider>
<CommandPaletteProvider>
<Navigation />
<RouterViewport />
<Toaster />
<CommandPalette />
</CommandPaletteProvider>
</KubeContextProvider>
<!-- </template> -->
<!-- <template #loading> -->
<!-- <Loading label="K8s crew, prepare for take-off..." /> -->
<!-- </template> -->
<!-- </AuthCheck> -->
</AppLayout>
</template>
23 changes: 18 additions & 5 deletions src/command-palette/SwitchContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ export function SwitchContext(
contextCache["contexts"] = contexts;

contexts.map((context) => {
Kubernetes.getNamespaces(context).then((namespaces) => {
namespaceCache[context] = namespaces.map(
(namespace) => namespace.metadata?.name || ""
);
});
Kubernetes.getNamespaces(context)
.then((namespaces) => {
namespaceCache[context] = namespaces.map(
(namespace) => namespace.metadata?.name || ""
);
})
.catch((err) => {
namespaceCache[context] = [];
});
});
});

Expand All @@ -30,6 +34,15 @@ export function SwitchContext(
return {
name: context,
commands: async () => {
if (namespaceCache[context].length === 0) {
return [
{
name: "No namespaces found",
execute: () => {},
},
];
}

return namespaceCache[context].map((namespace) => {
return {
name: namespace,
Expand Down
21 changes: 6 additions & 15 deletions src/components/tables/deployments/columns.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { formatDateTimeDifference } from "@/lib/utils";
import { V1Deployment } from "@kubernetes/client-node";
import { ColumnDef } from "@tanstack/vue-table";

Expand All @@ -13,9 +14,6 @@ export const columns: ColumnDef<V1Deployment>[] = [
const total = row.status?.replicas || 0;
return `${ready}/${total}`;
},
meta: {
class: "text-right",
},
},
{
header: "Up-to-date",
Expand All @@ -24,24 +22,17 @@ export const columns: ColumnDef<V1Deployment>[] = [
const total = row.status?.replicas || 0;
return `${ready}/${total}`;
},
meta: {
class: "text-right",
},
},
{
header: "Available",
accessorKey: "status.availableReplicas",
meta: {
class: "text-right",
},
},
{
header: "Age",
accessorFn: (row) => {
const date = new Date(row.metadata?.creationTimestamp || "");
return `${Math.floor(
(Date.now() - date.getTime()) / 1000 / 60 / 60 / 24
)}d`;
},
accessorFn: (row) =>
formatDateTimeDifference(
row.metadata?.creationTimestamp || new Date(),
new Date()
),
},
];
32 changes: 32 additions & 0 deletions src/components/tables/jobs/columns.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { V1Job } from "@kubernetes/client-node";
import { ColumnDef } from "@tanstack/vue-table";
import { formatDateTimeDifference } from "@/lib/utils";

export const columns: ColumnDef<V1Job>[] = [
{
accessorKey: "metadata.name",
header: "Name",
},
{
header: "Completions",
accessorFn: (row) => {
return `${row.status?.succeeded ?? 0}/${row.spec?.completions}`;
},
},
{
header: "Duration",
accessorFn: (row) =>
formatDateTimeDifference(
row.status?.startTime || new Date(),
row.status?.completionTime || new Date()
),
},
{
header: "Age",
accessorFn: (row) =>
formatDateTimeDifference(
row.metadata?.creationTimestamp || new Date(),
new Date()
),
},
];
6 changes: 0 additions & 6 deletions src/components/tables/pods/columns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,13 @@ export const columns: ColumnDef<V1Pod>[] = [
`${row.status?.containerStatuses?.reduce((acc, curr) => {
return curr.ready ? acc + 1 : acc;
}, 0)} / ${row.status?.containerStatuses?.length}`,
meta: {
class: "text-right",
},
},
{
header: "Restarts",
accessorFn: (row) =>
`${row.status?.containerStatuses?.reduce((acc, curr) => {
return acc + curr.restartCount;
}, 0)}`,
meta: {
class: "text-right",
},
},
{
header: "Status",
Expand Down
12 changes: 6 additions & 6 deletions src/components/tables/services/columns.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { formatDateTimeDifference } from "@/lib/utils";
import { V1Deployment, V1Service } from "@kubernetes/client-node";
import { ColumnDef } from "@tanstack/vue-table";

Expand Down Expand Up @@ -30,11 +31,10 @@ export const columns: ColumnDef<V1Service>[] = [
},
{
header: "Age",
accessorFn: (row) => {
const date = new Date(row.metadata?.creationTimestamp || "");
return `${Math.floor(
(Date.now() - date.getTime()) / 1000 / 60 / 60 / 24
)}d`;
},
accessorFn: (row) =>
formatDateTimeDifference(
row.metadata?.creationTimestamp || new Date(),
new Date()
),
},
];
37 changes: 36 additions & 1 deletion src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import { camelize, getCurrentInstance, toHandlerKey } from "vue";
import { differenceInSeconds } from "date-fns";

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
Expand All @@ -13,3 +13,38 @@ export function injectStrict<T>(key: InjectionKey<T>, fallback?: T) {
}
return resolved;
}

export function formatDateTimeDifference(startDate: Date, endDate: Date) {
let remainingSeconds = differenceInSeconds(endDate, startDate);

const days = Math.floor(remainingSeconds / (3600 * 24));
remainingSeconds -= days * 3600 * 24;

const hours = Math.floor(remainingSeconds / 3600);
remainingSeconds -= hours * 3600;

const minutes = Math.floor(remainingSeconds / 60);
remainingSeconds -= minutes * 60;

const seconds = remainingSeconds;

// Construct the formatted string
let formattedDuration = "";
if (days > 0) {
formattedDuration += `${days}d`;
if (hours > 0) {
formattedDuration += `${hours}h`;
}
} else if (hours > 0) {
formattedDuration += `${hours}h`;
if (minutes > 0) {
formattedDuration += `${minutes}m`;
}
} else if (minutes > 0) {
formattedDuration += `${minutes}m`;
} else {
formattedDuration += `${seconds}s`;
}

return formattedDuration;
}
5 changes: 5 additions & 0 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ const routes: Array<RouteRecordRaw> = [
name: "Deployments",
component: () => import("./views/Deployments.vue"),
},
{
path: "/jobs",
name: "Jobs",
component: () => import("./views/Jobs.vue"),
},
{
path: "/services",
name: "Services",
Expand Down
Loading

0 comments on commit 6c2f217

Please sign in to comment.