From 8ca4b2d42f6af029d62c9a384fd7e2f532e9760e Mon Sep 17 00:00:00 2001 From: TheArchons Date: Sat, 4 Apr 2026 16:07:16 -0400 Subject: [PATCH 1/8] Introduce a Machine type and refactor Job to have a Machine field instead of just machine data. --- web-interface/src/routes/jobs.tsx | 250 +++++++++++++++-------------- web-interface/src/types/job.ts | 17 ++ web-interface/src/types/machine.ts | 15 ++ 3 files changed, 162 insertions(+), 120 deletions(-) create mode 100644 web-interface/src/types/job.ts create mode 100644 web-interface/src/types/machine.ts diff --git a/web-interface/src/routes/jobs.tsx b/web-interface/src/routes/jobs.tsx index a9e1651..265fa6f 100644 --- a/web-interface/src/routes/jobs.tsx +++ b/web-interface/src/routes/jobs.tsx @@ -3,14 +3,130 @@ import Card, { CardHeader, CardInfoField } from '#/components/Card.tsx' import { useState } from 'react' import { Button } from '#/components/Buttons.tsx' import Chart from '#/components/Chart.tsx' +import type {Job, UsageData} from "#/types/job.ts"; export const Route = createFileRoute('/jobs')({ component: JobsPage, + loader: loadJobs }) -export type UsageData = { - component: string // Component that we observe. E.g. GPU, CPU, etc. - observations: number[] +function loadJobs(): Job[] { + const jobs: Job[] = [ + { + id: 'job-1', + name: 'f3xkcd', + created: '2026-03-01 10:32 PM', + accessed: '2026-03-05 11:01 AM', + machine: { + id: "tenstorrent_1", + gpu: "TT-Blackhole", + cpu: "TT-Ascalon", + jobs: [], + diskUsage: "70GB/128GB (55%)", + cpuUsage: "95%", + ramUsage: "16.7GB/32GB (52%)", + network: { + down: "1.2 GB/s", + up: "340 MB/s" + }, + ip: "11.22.33.44" + }, + dockerImage: 'utmist/mpt-3.5-turbo', + usageHistory: [ + generateSampleUsageData(), + generateSampleUsageData(), + generateSampleUsageData(), + generateSampleUsageData(), + generateSampleUsageData(), + ], + }, + { + id: 'job-2', + name: 'f3xkcd', + created: '2026-03-01 10:32 PM', + accessed: '2026-03-05 11:01 AM', + machine: { + id: "tenstorrent_1", + gpu: "TT-Blackhole", + cpu: "TT-Ascalon", + jobs: [], + diskUsage: "70GB/128GB (55%)", + cpuUsage: "95%", + ramUsage: "16.7GB/32GB (52%)", + network: { + down: "1.2 GB/s", + up: "340 MB/s" + }, + ip: "11.22.33.44" + }, + dockerImage: 'utmist/mpt-3.5-turbo', + usageHistory: [ + generateSampleUsageData(), + generateSampleUsageData(), + generateSampleUsageData(), + generateSampleUsageData(), + generateSampleUsageData(), + ], + }, + { + id: 'job-3', + name: 'f3xkcd', + created: '2026-03-01 10:32 PM', + accessed: '2026-03-05 11:01 AM', + machine: { + id: "tenstorrent_1", + gpu: "TT-Blackhole", + cpu: "TT-Ascalon", + jobs: [], + diskUsage: "70GB/128GB (55%)", + cpuUsage: "95%", + ramUsage: "16.7GB/32GB (52%)", + network: { + down: "1.2 GB/s", + up: "340 MB/s" + }, + ip: "11.22.33.44" + }, + dockerImage: 'utmist/mpt-3.5-turbo', + usageHistory: [ + generateSampleUsageData(), + generateSampleUsageData(), + generateSampleUsageData(), + generateSampleUsageData(), + generateSampleUsageData(), + ], + }, + { + id: 'job-4', + name: 'f3xkcd', + created: '2026-03-01 10:32 PM', + accessed: '2026-03-05 11:01 AM', + machine: { + id: "tenstorrent_1", + gpu: "TT-Blackhole", + cpu: "TT-Ascalon", + jobs: [], + diskUsage: "70GB/128GB (55%)", + cpuUsage: "95%", + ramUsage: "16.7GB/32GB (52%)", + network: { + down: "1.2 GB/s", + up: "340 MB/s" + }, + ip: "11.22.33.44" + }, + dockerImage: 'utmist/mpt-3.5-turbo', + usageHistory: [ + generateSampleUsageData(), + generateSampleUsageData(), + generateSampleUsageData(), + generateSampleUsageData(), + generateSampleUsageData(), + ], + }, + ] + + return jobs } function generateSampleUsageData(): UsageData { @@ -28,114 +144,6 @@ function generateSampleUsageData(): UsageData { } } -export type Job = { - id: string - name: string - created: string - accessed: string - machine: string - gpu: string - cpu: string - dockerImage: string - ip: string - ram: string - diskUsage: string - cpuUtilization: string - networkIO: { down: string; up: string } - usageHistory: UsageData[] -} - -const sampleJobs: Job[] = [ - { - id: 'job-1', - name: 'f3xkcd', - created: '2026-03-01 10:32 PM', - accessed: '2026-03-05 11:01 AM', - machine: 'Tenstorrent_1', - gpu: 'TT-Blackhole', - cpu: 'TT-Ascalon', - dockerImage: 'utmist/mpt-3.5-turbo', - ip: '101.101.123.456', - ram: '32GB', - diskUsage: '70GB/128GB (55%)', - cpuUtilization: '95%', - networkIO: { down: '1.2 GB/s', up: '340 MB/s' }, - usageHistory: [ - generateSampleUsageData(), - generateSampleUsageData(), - generateSampleUsageData(), - generateSampleUsageData(), - generateSampleUsageData(), - ], - }, - { - id: 'job-2', - name: 'f3xkcd', - created: '2026-03-01 10:32 PM', - accessed: '2026-03-05 11:01 AM', - machine: 'Tenstorrent_1', - gpu: 'TT-Blackhole', - cpu: 'TT-Ascalon', - dockerImage: 'utmist/mpt-3.5-turbo', - ip: '101.101.123.456', - ram: '32GB', - diskUsage: '70GB/128GB (55%)', - cpuUtilization: '95%', - networkIO: { down: '1.2 GB/s', up: '340 MB/s' }, - usageHistory: [ - generateSampleUsageData(), - generateSampleUsageData(), - generateSampleUsageData(), - generateSampleUsageData(), - generateSampleUsageData(), - ], - }, - { - id: 'job-3', - name: 'f3xkcd', - created: '2026-03-01 10:32 PM', - accessed: '2026-03-05 11:01 AM', - machine: 'Tenstorrent_1', - gpu: 'TT-Blackhole', - cpu: 'TT-Ascalon', - dockerImage: 'utmist/mpt-3.5-turbo', - ip: '101.101.123.456', - ram: '32GB', - diskUsage: '70GB/128GB (55%)', - cpuUtilization: '95%', - networkIO: { down: '1.2 GB/s', up: '340 MB/s' }, - usageHistory: [ - generateSampleUsageData(), - generateSampleUsageData(), - generateSampleUsageData(), - generateSampleUsageData(), - generateSampleUsageData(), - ], - }, - { - id: 'job-4', - name: 'f3xkcd', - created: '2026-03-01 10:32 PM', - accessed: '2026-03-05 11:01 AM', - machine: 'Tenstorrent_1', - gpu: 'TT-Blackhole', - cpu: 'TT-Ascalon', - dockerImage: 'utmist/mpt-3.5-turbo', - ip: '101.101.123.456', - ram: '32GB', - diskUsage: '70GB/128GB (55%)', - cpuUtilization: '95%', - networkIO: { down: '1.2 GB/s', up: '340 MB/s' }, - usageHistory: [ - generateSampleUsageData(), - generateSampleUsageData(), - generateSampleUsageData(), - generateSampleUsageData(), - generateSampleUsageData(), - ], - }, -] - type JobCardProps = { job: Job onStart: (id: string) => void @@ -187,19 +195,19 @@ function JobCard({ {/* Info grid */}
- - + + - - + + - + - - + +
{/* Component Usage Chart */} @@ -235,10 +243,12 @@ function handleDelete(id: string) { } function JobsPage() { + const jobs = Route.useLoaderData(); + return (
- {sampleJobs.map((job) => ( + {jobs.map((job) => ( Date: Fri, 17 Apr 2026 10:09:08 -0400 Subject: [PATCH 2/8] Add a machine page --- web-interface/bun.lock | 3 + web-interface/package.json | 1 + web-interface/src/components/Buttons.tsx | 5 +- web-interface/src/components/Chart.tsx | 34 +- web-interface/src/routes/jobs.tsx | 156 +++---- web-interface/src/routes/machines.tsx | 494 ++++++++++++++++++++++- web-interface/src/types/job.ts | 10 +- web-interface/src/types/machine.ts | 8 +- 8 files changed, 608 insertions(+), 103 deletions(-) diff --git a/web-interface/bun.lock b/web-interface/bun.lock index b37b8a5..92b083d 100644 --- a/web-interface/bun.lock +++ b/web-interface/bun.lock @@ -9,6 +9,7 @@ "@tanstack/react-router": "latest", "@tanstack/react-router-devtools": "latest", "@tanstack/router-plugin": "^1.132.0", + "date-fns": "^4.1.0", "lucide-react": "^0.545.0", "react": "^19.2.0", "react-dom": "^19.2.0", @@ -511,6 +512,8 @@ "data-urls": ["data-urls@7.0.0", "", { "dependencies": { "whatwg-mimetype": "^5.0.0", "whatwg-url": "^16.0.0" } }, "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA=="], + "date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="], + "dayjs": ["dayjs@1.11.20", "", {}, "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ=="], "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], diff --git a/web-interface/package.json b/web-interface/package.json index b9e0451..a423092 100644 --- a/web-interface/package.json +++ b/web-interface/package.json @@ -20,6 +20,7 @@ "@tanstack/react-router": "latest", "@tanstack/react-router-devtools": "latest", "@tanstack/router-plugin": "^1.132.0", + "date-fns": "^4.1.0", "lucide-react": "^0.545.0", "react": "^19.2.0", "react-dom": "^19.2.0", diff --git a/web-interface/src/components/Buttons.tsx b/web-interface/src/components/Buttons.tsx index 1225fc8..76149a9 100644 --- a/web-interface/src/components/Buttons.tsx +++ b/web-interface/src/components/Buttons.tsx @@ -14,8 +14,7 @@ const fontSizeStyles = { base: 'text-base', lg: 'text-lg', xl: 'text-xl', -}; - +} type ButtonVariant = keyof typeof variantStyles type ButtonFontSize = keyof typeof fontSizeStyles @@ -34,7 +33,7 @@ export function Button({ return ( + + + {/* Info grid */} +
+
+ + + + +
+
+ + + +
+
+
+

Jobs

+ +
+ + + + + + + + + {machine.jobs.map((job) => ( + + + + + ))} + +
IDAccessed
+ + {job.id} + + + {format(job.accessed, 'yyyy-MM-dd')} +
+
+
+
+
+ + {/* Component Usage Chart */} + + + ) +} + function RouteComponent() { - return
Hello "/machines"!
+ function handleProvision(machineId: string) { + // TODO: Implement + console.log(`Provisioned ${machineId}`) + } + + const machines = Route.useLoaderData() + + return ( +
+
+ {machines.map((machine) => ( + + ))} +
+
+ ) } diff --git a/web-interface/src/types/job.ts b/web-interface/src/types/job.ts index 4b2aad1..2bf74a1 100644 --- a/web-interface/src/types/job.ts +++ b/web-interface/src/types/job.ts @@ -1,12 +1,12 @@ -import type {BaseMachine} from "#/types/machine.ts"; +import type { BaseMachine } from '#/types/machine.ts' export type BaseJob = { id: string name: string - created: string - accessed: string + created: Date + accessed: Date dockerImage: string - usageHistory: UsageData[] + usageHistory: UsageData[] // the usage of the resources of the machine allocated to this specific job } export type UsageData = { @@ -14,4 +14,4 @@ export type UsageData = { observations: number[] } -export type Job = BaseJob & { machine: BaseMachine } \ No newline at end of file +export type Job = BaseJob & { machine: BaseMachine } diff --git a/web-interface/src/types/machine.ts b/web-interface/src/types/machine.ts index 735fd35..d582304 100644 --- a/web-interface/src/types/machine.ts +++ b/web-interface/src/types/machine.ts @@ -1,15 +1,15 @@ -import type {BaseJob} from "#/types/job.ts"; +import type { BaseJob, UsageData } from '#/types/job.ts' export type BaseMachine = { id: string gpu: string cpu: string - jobs: string[] diskUsage: string ramUsage: string cpuUsage: string - network: { down: string, up: string } + network: { down: string; up: string } ip: string + usageHistory: UsageData[] // the usage of the total machine resources } -export type Machine = BaseMachine & { jobs: BaseJob[] } \ No newline at end of file +export type Machine = BaseMachine & { jobs: BaseJob[] } From a7283c79cf635b25502ffdf3478ddc0bbcc51b4e Mon Sep 17 00:00:00 2001 From: TheArchons Date: Fri, 17 Apr 2026 10:32:43 -0400 Subject: [PATCH 3/8] add links between jobs and machines --- web-interface/src/components/Card.tsx | 8 ++- web-interface/src/routes/jobs.tsx | 22 +++----- web-interface/src/routes/machines.tsx | 80 ++++++--------------------- web-interface/src/types/job.ts | 1 - 4 files changed, 32 insertions(+), 79 deletions(-) diff --git a/web-interface/src/components/Card.tsx b/web-interface/src/components/Card.tsx index 6715c1b..3bfe2a5 100644 --- a/web-interface/src/components/Card.tsx +++ b/web-interface/src/components/Card.tsx @@ -5,16 +5,18 @@ export function CardInfoField({ label, value, link, + hash }: { label: string value: string link?: string + hash?: string }) { return (
{label}
{link ? ( - + {value} ) : ( @@ -42,6 +44,6 @@ export function CardHeader({ ) } -export default function Card({ children }: { children: ReactNode }) { - return
{children}
+export default function Card({ children, id }: { children: ReactNode, id?: string }) { + return
{children}
} diff --git a/web-interface/src/routes/jobs.tsx b/web-interface/src/routes/jobs.tsx index cd1cde8..015d225 100644 --- a/web-interface/src/routes/jobs.tsx +++ b/web-interface/src/routes/jobs.tsx @@ -13,8 +13,7 @@ export const Route = createFileRoute('/jobs')({ function loadJobs(): Job[] { const jobs: Job[] = [ { - id: 'job-1', - name: 'f3xkcd', + id: 'f3xkcd', created: new Date('2026-03-01T22:32:00'), accessed: new Date('2026-03-05T11:01:00'), machine: { @@ -47,8 +46,7 @@ function loadJobs(): Job[] { ], }, { - id: 'job-2', - name: 'f3xkcd', + id: 'a1b2c3', created: new Date('2026-03-01T22:32:00'), accessed: new Date('2026-03-05T11:01:00'), machine: { @@ -81,12 +79,11 @@ function loadJobs(): Job[] { ], }, { - id: 'job-3', - name: 'f3xkcd', + id: 'x9y8z7', created: new Date('2026-03-01T22:32:00'), accessed: new Date('2026-03-05T11:01:00'), machine: { - id: 'tenstorrent_1', + id: 'tenstorrent_3', gpu: 'TT-Blackhole', cpu: 'TT-Ascalon', diskUsage: '70GB/128GB (55%)', @@ -115,12 +112,11 @@ function loadJobs(): Job[] { ], }, { - id: 'job-4', - name: 'f3xkcd', + id: 'm4n5p6', created: new Date('2026-03-01T22:32:00'), accessed: new Date('2026-03-05T11:01:00'), machine: { - id: 'tenstorrent_1', + id: 'tenstorrent_3', gpu: 'TT-Blackhole', cpu: 'TT-Ascalon', diskUsage: '70GB/128GB (55%)', @@ -184,8 +180,8 @@ function JobCard({ onDelete, }: JobCardProps) { return ( - - + + @@ -214,7 +210,7 @@ function JobCard({ label="Created" value={format(job.created, 'yyyy-MM-dd hh:mm a')} /> - + void }) { return ( - + diff --git a/web-interface/src/routes/machines.tsx b/web-interface/src/routes/machines.tsx index 423a547..fe47a00 100644 --- a/web-interface/src/routes/machines.tsx +++ b/web-interface/src/routes/machines.tsx @@ -17,6 +17,8 @@ function loadMachines(): Machine[] { const machines: Machine[] = [ { id: 'tenstorrent_1', + purpose: 'Inference', + isAvailable: true, gpu: 'TT-Blackhole', cpu: 'TT-Ascalon', jobs: [ @@ -143,6 +145,8 @@ function loadMachines(): Machine[] { }, { id: 'tenstorrent_2', + purpose: 'Inference', + isAvailable: true, gpu: 'TT-Blackhole', cpu: 'TT-Ascalon', jobs: [], @@ -164,6 +168,8 @@ function loadMachines(): Machine[] { }, { id: 'tenstorrent_3', + purpose: 'Inference', + isAvailable: true, gpu: 'TT-Blackhole', cpu: 'TT-Ascalon', jobs: [ @@ -212,6 +218,8 @@ function loadMachines(): Machine[] { }, { id: 'tenstorrent_4', + purpose: 'Training', + isAvailable: false, gpu: 'TT-Blackhole', cpu: 'TT-Ascalon', jobs: [ @@ -260,6 +268,8 @@ function loadMachines(): Machine[] { }, { id: 'tenstorrent_5', + purpose: 'Training', + isAvailable: true, gpu: 'TT-Blackhole', cpu: 'TT-Ascalon', jobs: [ @@ -308,6 +318,8 @@ function loadMachines(): Machine[] { }, { id: 'tenstorrent_6', + purpose: 'Inference', + isAvailable: false, gpu: 'TT-Blackhole', cpu: 'TT-Ascalon', jobs: [ @@ -368,7 +380,10 @@ function MachineCard({ }) { return ( - +