mirror of
https://github.com/KohakuBlueleaf/KohakuHub.git
synced 2026-04-30 09:28:35 -05:00
Re org kohakuboard ui routes
This commit is contained in:
@@ -2,11 +2,13 @@
|
|||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
import { initializeSliderSync } from "@/composables/useSliderSync";
|
import { initializeSliderSync } from "@/composables/useSliderSync";
|
||||||
import { useAnimationPreference } from "@/composables/useAnimationPreference";
|
import { useAnimationPreference } from "@/composables/useAnimationPreference";
|
||||||
|
import { getSystemInfo } from "@/utils/api";
|
||||||
|
|
||||||
const darkMode = ref(false);
|
const darkMode = ref(false);
|
||||||
const { animationsEnabled, toggleAnimations } = useAnimationPreference();
|
const { animationsEnabled, toggleAnimations } = useAnimationPreference();
|
||||||
|
const systemInfo = ref(null);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
const savedTheme = localStorage.getItem("theme");
|
const savedTheme = localStorage.getItem("theme");
|
||||||
darkMode.value =
|
darkMode.value =
|
||||||
savedTheme === "dark" ||
|
savedTheme === "dark" ||
|
||||||
@@ -15,6 +17,13 @@ onMounted(() => {
|
|||||||
|
|
||||||
// Initialize global slider synchronization
|
// Initialize global slider synchronization
|
||||||
initializeSliderSync();
|
initializeSliderSync();
|
||||||
|
|
||||||
|
// Fetch system info for mode detection
|
||||||
|
try {
|
||||||
|
systemInfo.value = await getSystemInfo();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to fetch system info:", error);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggleDarkMode() {
|
function toggleDarkMode() {
|
||||||
@@ -59,13 +68,13 @@ function updateTheme() {
|
|||||||
to="/"
|
to="/"
|
||||||
class="px-3 py-1.5 rounded-md text-sm font-medium transition-colors text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-blue-600 dark:hover:text-blue-400"
|
class="px-3 py-1.5 rounded-md text-sm font-medium transition-colors text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-blue-600 dark:hover:text-blue-400"
|
||||||
>
|
>
|
||||||
Dashboard
|
Projects
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
to="/experiments"
|
to="/experiments"
|
||||||
class="px-3 py-1.5 rounded-md text-sm font-medium transition-colors text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-blue-600 dark:hover:text-blue-400"
|
class="px-3 py-1.5 rounded-md text-sm font-medium transition-colors text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-blue-600 dark:hover:text-blue-400"
|
||||||
>
|
>
|
||||||
Experiments
|
Experiments (Legacy)
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,24 +1,25 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
import { fetchExperiments } from "@/utils/api";
|
import { fetchProjects } from "@/utils/api";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const experiments = ref([]);
|
const projects = ref([]);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
try {
|
try {
|
||||||
experiments.value = await fetchExperiments();
|
const result = await fetchProjects();
|
||||||
|
projects.value = result.projects;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to fetch experiments:", error);
|
console.error("Failed to fetch projects:", error);
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function viewExperiment(id) {
|
function viewProject(projectName) {
|
||||||
router.push(`/experiments/${id}`);
|
router.push(`/projects/${projectName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatDate(timestamp) {
|
function formatDate(timestamp) {
|
||||||
@@ -47,76 +48,37 @@ function formatSteps(steps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="loading" class="text-center py-12">
|
<div v-if="loading" class="text-center py-12">
|
||||||
<div class="text-gray-500 dark:text-gray-400">Loading experiments...</div>
|
<div class="text-gray-500 dark:text-gray-400">Loading projects...</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-else-if="experiments.length === 0"
|
v-else-if="projects.length === 0"
|
||||||
class="bg-white dark:bg-gray-900 rounded-lg shadow-md p-8 text-center border border-gray-200 dark:border-gray-800"
|
class="bg-white dark:bg-gray-900 rounded-lg shadow-md p-8 text-center border border-gray-200 dark:border-gray-800"
|
||||||
>
|
>
|
||||||
<div class="text-gray-500 dark:text-gray-400 mb-4">No boards found</div>
|
<div class="text-gray-500 dark:text-gray-400 mb-4">No projects found</div>
|
||||||
<p class="text-sm text-gray-400 dark:text-gray-500">
|
<p class="text-sm text-gray-400 dark:text-gray-500">
|
||||||
Start tracking your ML experiments with KohakuBoard client library.
|
Start tracking your ML experiments with KohakuBoard client library.
|
||||||
<br />
|
|
||||||
Boards are automatically discovered from:
|
|
||||||
<code class="bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded"
|
|
||||||
>./kohakuboard</code
|
|
||||||
>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
<div
|
<div
|
||||||
v-for="experiment in experiments"
|
v-for="project in projects"
|
||||||
:key="experiment.id"
|
:key="project.name"
|
||||||
@click="viewExperiment(experiment.id)"
|
@click="viewProject(project.name)"
|
||||||
class="bg-white dark:bg-gray-900 rounded-lg shadow-md p-4 cursor-pointer hover:shadow-lg transition-all border border-gray-200 dark:border-gray-800 hover:border-blue-400 dark:hover:border-blue-600"
|
class="bg-white dark:bg-gray-900 rounded-lg shadow-md p-6 cursor-pointer hover:shadow-lg transition-all border border-gray-200 dark:border-gray-800 hover:border-blue-400 dark:hover:border-blue-600"
|
||||||
>
|
>
|
||||||
<div class="flex items-start justify-between mb-3">
|
<h3 class="font-semibold text-xl text-gray-900 dark:text-gray-100 mb-2">
|
||||||
<h3 class="font-semibold text-lg text-gray-900 dark:text-gray-100">
|
{{ project.display_name }}
|
||||||
{{ experiment.name }}
|
</h3>
|
||||||
</h3>
|
<div class="text-gray-600 dark:text-gray-400 mb-4">
|
||||||
<span
|
{{ project.run_count }} {{ project.run_count === 1 ? "run" : "runs" }}
|
||||||
class="px-2 py-1 text-xs rounded font-medium"
|
|
||||||
:class="{
|
|
||||||
'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400':
|
|
||||||
experiment.status === 'completed',
|
|
||||||
'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400':
|
|
||||||
experiment.status === 'running',
|
|
||||||
'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400':
|
|
||||||
experiment.status === 'stopped',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ experiment.status }}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">
|
|
||||||
{{ experiment.description }}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="grid grid-cols-2 gap-2 text-sm">
|
|
||||||
<div>
|
|
||||||
<div class="text-gray-500 dark:text-gray-500">Board ID</div>
|
|
||||||
<div
|
|
||||||
class="font-mono text-xs text-gray-900 dark:text-gray-100 truncate"
|
|
||||||
:title="experiment.id"
|
|
||||||
>
|
|
||||||
{{ experiment.id }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="text-gray-500 dark:text-gray-500">Status</div>
|
|
||||||
<div class="font-medium text-gray-900 dark:text-gray-100">
|
|
||||||
{{ experiment.status }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="mt-3 pt-3 border-t border-gray-200 dark:border-gray-800 text-xs text-gray-500 dark:text-gray-500"
|
v-if="project.updated_at"
|
||||||
|
class="text-xs text-gray-500 dark:text-gray-500"
|
||||||
>
|
>
|
||||||
Created: {{ formatDate(experiment.created_at) }}
|
Updated: {{ formatDate(project.updated_at) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
1087
src/kohaku-board-ui/src/pages/projects/[project]/[id].vue
Normal file
1087
src/kohaku-board-ui/src/pages/projects/[project]/[id].vue
Normal file
File diff suppressed because it is too large
Load Diff
140
src/kohaku-board-ui/src/pages/projects/[project]/index.vue
Normal file
140
src/kohaku-board-ui/src/pages/projects/[project]/index.vue
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
import { fetchProjectRuns } from "@/utils/api";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const project = ref(route.params.project);
|
||||||
|
const runs = ref([]);
|
||||||
|
const loading = ref(true);
|
||||||
|
const projectOwner = ref(null);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
const result = await fetchProjectRuns(project.value);
|
||||||
|
runs.value = result.runs;
|
||||||
|
projectOwner.value = result.owner;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to fetch runs:", error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function viewRun(runId) {
|
||||||
|
// Use the main experiments viewer (the most important page!)
|
||||||
|
router.push(`/experiments/${runId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDate(timestamp) {
|
||||||
|
if (!timestamp) return "N/A";
|
||||||
|
return new Date(timestamp).toLocaleString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatSize(bytes) {
|
||||||
|
if (!bytes) return "N/A";
|
||||||
|
const mb = bytes / 1024 / 1024;
|
||||||
|
if (mb < 1) return `${(bytes / 1024).toFixed(1)} KB`;
|
||||||
|
if (mb < 1024) return `${mb.toFixed(1)} MB`;
|
||||||
|
return `${(mb / 1024).toFixed(2)} GB`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center justify-between mb-6">
|
||||||
|
<div>
|
||||||
|
<h1 class="text-3xl font-bold text-gray-900 dark:text-gray-100">
|
||||||
|
{{ project }}
|
||||||
|
</h1>
|
||||||
|
<p
|
||||||
|
v-if="projectOwner"
|
||||||
|
class="text-sm text-gray-500 dark:text-gray-400 mt-1"
|
||||||
|
>
|
||||||
|
Owner: {{ projectOwner }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<router-link
|
||||||
|
to="/projects"
|
||||||
|
class="px-4 py-2 bg-gray-600 hover:bg-gray-700 dark:bg-gray-500 dark:hover:bg-gray-600 text-white rounded-md font-medium transition-colors shadow-sm"
|
||||||
|
>
|
||||||
|
← Back to Projects
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="loading" class="text-center py-12">
|
||||||
|
<div class="text-gray-500 dark:text-gray-400">Loading runs...</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-else-if="runs.length === 0"
|
||||||
|
class="bg-white dark:bg-gray-900 rounded-lg shadow-md p-8 text-center border border-gray-200 dark:border-gray-800"
|
||||||
|
>
|
||||||
|
<div class="text-gray-500 dark:text-gray-400 mb-4">No runs found</div>
|
||||||
|
<p class="text-sm text-gray-400 dark:text-gray-500">
|
||||||
|
This project doesn't have any training runs yet.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="grid grid-cols-1 gap-4">
|
||||||
|
<div
|
||||||
|
v-for="run in runs"
|
||||||
|
:key="run.run_id"
|
||||||
|
@click="viewRun(run.run_id)"
|
||||||
|
class="bg-white dark:bg-gray-900 rounded-lg shadow-md p-4 cursor-pointer hover:shadow-lg transition-all border border-gray-200 dark:border-gray-800 hover:border-blue-400 dark:hover:border-blue-600"
|
||||||
|
>
|
||||||
|
<div class="flex items-start justify-between">
|
||||||
|
<div class="flex-1">
|
||||||
|
<h3 class="font-semibold text-lg text-gray-900 dark:text-gray-100">
|
||||||
|
{{ run.name }}
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-gray-500 dark:text-gray-400 font-mono mt-1">
|
||||||
|
{{ run.run_id }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div v-if="run.private !== undefined" class="ml-4">
|
||||||
|
<span
|
||||||
|
class="px-2 py-1 text-xs rounded font-medium"
|
||||||
|
:class="{
|
||||||
|
'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400':
|
||||||
|
run.private,
|
||||||
|
'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400':
|
||||||
|
!run.private,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ run.private ? "Private" : "Public" }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-4 text-sm">
|
||||||
|
<div>
|
||||||
|
<div class="text-gray-500 dark:text-gray-500">Created</div>
|
||||||
|
<div class="text-gray-900 dark:text-gray-100">
|
||||||
|
{{ formatDate(run.created_at) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="run.last_synced_at">
|
||||||
|
<div class="text-gray-500 dark:text-gray-500">Last Synced</div>
|
||||||
|
<div class="text-gray-900 dark:text-gray-100">
|
||||||
|
{{ formatDate(run.last_synced_at) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="run.total_size">
|
||||||
|
<div class="text-gray-500 dark:text-gray-500">Size</div>
|
||||||
|
<div class="text-gray-900 dark:text-gray-100">
|
||||||
|
{{ formatSize(run.total_size) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="run.config && Object.keys(run.config).length > 0">
|
||||||
|
<div class="text-gray-500 dark:text-gray-500">Config</div>
|
||||||
|
<div class="text-gray-900 dark:text-gray-100 text-xs">
|
||||||
|
{{ Object.keys(run.config).length }} params
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
75
src/kohaku-board-ui/src/pages/projects/index.vue
Normal file
75
src/kohaku-board-ui/src/pages/projects/index.vue
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import { fetchProjects } from "@/utils/api";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const projects = ref([]);
|
||||||
|
const loading = ref(true);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
const result = await fetchProjects();
|
||||||
|
projects.value = result.projects;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to fetch projects:", error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function viewProject(projectName) {
|
||||||
|
router.push(`/projects/${projectName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDate(timestamp) {
|
||||||
|
if (!timestamp) return "N/A";
|
||||||
|
return new Date(timestamp).toLocaleString();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center justify-between mb-6">
|
||||||
|
<h1 class="text-3xl font-bold text-gray-900 dark:text-gray-100">
|
||||||
|
Projects
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="loading" class="text-center py-12">
|
||||||
|
<div class="text-gray-500 dark:text-gray-400">Loading projects...</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-else-if="projects.length === 0"
|
||||||
|
class="bg-white dark:bg-gray-900 rounded-lg shadow-md p-8 text-center border border-gray-200 dark:border-gray-800"
|
||||||
|
>
|
||||||
|
<div class="text-gray-500 dark:text-gray-400 mb-4">No projects found</div>
|
||||||
|
<p class="text-sm text-gray-400 dark:text-gray-500">
|
||||||
|
Start tracking your ML experiments with KohakuBoard client library.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
<div
|
||||||
|
v-for="project in projects"
|
||||||
|
:key="project.name"
|
||||||
|
@click="viewProject(project.name)"
|
||||||
|
class="bg-white dark:bg-gray-900 rounded-lg shadow-md p-6 cursor-pointer hover:shadow-lg transition-all border border-gray-200 dark:border-gray-800 hover:border-blue-400 dark:hover:border-blue-600"
|
||||||
|
>
|
||||||
|
<h3 class="font-semibold text-xl text-gray-900 dark:text-gray-100 mb-2">
|
||||||
|
{{ project.display_name }}
|
||||||
|
</h3>
|
||||||
|
<div class="text-gray-600 dark:text-gray-400 mb-4">
|
||||||
|
{{ project.run_count }} {{ project.run_count === 1 ? "run" : "runs" }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="project.updated_at"
|
||||||
|
class="text-xs text-gray-500 dark:text-gray-500"
|
||||||
|
>
|
||||||
|
Updated: {{ formatDate(project.updated_at) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
15
src/kohaku-board-ui/src/typed-router.d.ts
vendored
15
src/kohaku-board-ui/src/typed-router.d.ts
vendored
@@ -22,6 +22,9 @@ declare module 'vue-router/auto-routes' {
|
|||||||
'/dashboard/[id]': RouteRecordInfo<'/dashboard/[id]', '/dashboard/:id', { id: ParamValue<true> }, { id: ParamValue<false> }>,
|
'/dashboard/[id]': RouteRecordInfo<'/dashboard/[id]', '/dashboard/:id', { id: ParamValue<true> }, { id: ParamValue<false> }>,
|
||||||
'/experiments/': RouteRecordInfo<'/experiments/', '/experiments', Record<never, never>, Record<never, never>>,
|
'/experiments/': RouteRecordInfo<'/experiments/', '/experiments', Record<never, never>, Record<never, never>>,
|
||||||
'/experiments/[id]': RouteRecordInfo<'/experiments/[id]', '/experiments/:id', { id: ParamValue<true> }, { id: ParamValue<false> }>,
|
'/experiments/[id]': RouteRecordInfo<'/experiments/[id]', '/experiments/:id', { id: ParamValue<true> }, { id: ParamValue<false> }>,
|
||||||
|
'/projects/': RouteRecordInfo<'/projects/', '/projects', Record<never, never>, Record<never, never>>,
|
||||||
|
'/projects/[project]/': RouteRecordInfo<'/projects/[project]/', '/projects/:project', { project: ParamValue<true> }, { project: ParamValue<false> }>,
|
||||||
|
'/projects/[project]/[id]': RouteRecordInfo<'/projects/[project]/[id]', '/projects/:project/:id', { project: ParamValue<true>, id: ParamValue<true> }, { project: ParamValue<false>, id: ParamValue<false> }>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,6 +54,18 @@ declare module 'vue-router/auto-routes' {
|
|||||||
routes: '/experiments/[id]'
|
routes: '/experiments/[id]'
|
||||||
views: never
|
views: never
|
||||||
}
|
}
|
||||||
|
'src/pages/projects/index.vue': {
|
||||||
|
routes: '/projects/'
|
||||||
|
views: never
|
||||||
|
}
|
||||||
|
'src/pages/projects/[project]/index.vue': {
|
||||||
|
routes: '/projects/[project]/'
|
||||||
|
views: never
|
||||||
|
}
|
||||||
|
'src/pages/projects/[project]/[id].vue': {
|
||||||
|
routes: '/projects/[project]/[id]'
|
||||||
|
views: never
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -74,7 +74,43 @@ export async function generateMockData(config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// BOARDS API - Real data from file system
|
// SYSTEM API - Mode detection
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get system information (mode, auth requirements, user info)
|
||||||
|
* @returns {Promise<Object>} System info
|
||||||
|
*/
|
||||||
|
export async function getSystemInfo() {
|
||||||
|
const response = await api.get("/system/info");
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// PROJECTS API - Project and run management
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all accessible projects
|
||||||
|
* @returns {Promise<Object>} Projects list
|
||||||
|
*/
|
||||||
|
export async function fetchProjects() {
|
||||||
|
const response = await api.get("/projects");
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch runs in a project
|
||||||
|
* @param {string} projectName - Project name
|
||||||
|
* @returns {Promise<Object>} Runs list with project info
|
||||||
|
*/
|
||||||
|
export async function fetchProjectRuns(projectName) {
|
||||||
|
const response = await api.get(`/projects/${projectName}/runs`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// BOARDS API - Real data from file system (LEGACY - kept for compatibility)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,6 +142,119 @@ export async function fetchBoardSummary(boardId) {
|
|||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// RUN DATA API - Project-based run access
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch run summary
|
||||||
|
* @param {string} project - Project name
|
||||||
|
* @param {string} runId - Run ID
|
||||||
|
* @returns {Promise<Object>} Run summary
|
||||||
|
*/
|
||||||
|
export async function fetchRunSummary(project, runId) {
|
||||||
|
const response = await api.get(`/projects/${project}/runs/${runId}/summary`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch available scalar metrics for a run
|
||||||
|
* @param {string} project - Project name
|
||||||
|
* @param {string} runId - Run ID
|
||||||
|
* @returns {Promise<Object>} Object with metrics array
|
||||||
|
*/
|
||||||
|
export async function fetchRunScalars(project, runId) {
|
||||||
|
const response = await api.get(`/projects/${project}/runs/${runId}/scalars`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch scalar data for a specific metric
|
||||||
|
* @param {string} project - Project name
|
||||||
|
* @param {string} runId - Run ID
|
||||||
|
* @param {string} metric - Metric name
|
||||||
|
* @param {Object} params - Query parameters (limit, etc.)
|
||||||
|
* @returns {Promise<Object>} Object with metric name and data array
|
||||||
|
*/
|
||||||
|
export async function fetchRunScalarData(project, runId, metric, params = {}) {
|
||||||
|
const response = await api.get(
|
||||||
|
`/projects/${project}/runs/${runId}/scalars/${metric}`,
|
||||||
|
{
|
||||||
|
params,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch available media log names
|
||||||
|
* @param {string} project - Project name
|
||||||
|
* @param {string} runId - Run ID
|
||||||
|
* @returns {Promise<Object>} Object with media array
|
||||||
|
*/
|
||||||
|
export async function fetchRunMedia(project, runId) {
|
||||||
|
const response = await api.get(`/projects/${project}/runs/${runId}/media`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch media data for a specific log name
|
||||||
|
* @param {string} project - Project name
|
||||||
|
* @param {string} runId - Run ID
|
||||||
|
* @param {string} name - Media log name
|
||||||
|
* @param {Object} params - Query parameters (limit, etc.)
|
||||||
|
* @returns {Promise<Object>} Object with name and data array
|
||||||
|
*/
|
||||||
|
export async function fetchRunMediaData(project, runId, name, params = {}) {
|
||||||
|
const response = await api.get(
|
||||||
|
`/projects/${project}/runs/${runId}/media/${name}`,
|
||||||
|
{
|
||||||
|
params,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get media file URL
|
||||||
|
* @param {string} project - Project name
|
||||||
|
* @param {string} runId - Run ID
|
||||||
|
* @param {string} filename - Media filename
|
||||||
|
* @returns {string} Media file URL
|
||||||
|
*/
|
||||||
|
export function getRunMediaFileUrl(project, runId, filename) {
|
||||||
|
return `/api/projects/${project}/runs/${runId}/media/files/${filename}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch available table log names
|
||||||
|
* @param {string} project - Project name
|
||||||
|
* @param {string} runId - Run ID
|
||||||
|
* @returns {Promise<Object>} Object with tables array
|
||||||
|
*/
|
||||||
|
export async function fetchRunTables(project, runId) {
|
||||||
|
const response = await api.get(`/projects/${project}/runs/${runId}/tables`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch table data for a specific log name
|
||||||
|
* @param {string} project - Project name
|
||||||
|
* @param {string} runId - Run ID
|
||||||
|
* @param {string} name - Table log name
|
||||||
|
* @param {Object} params - Query parameters (limit, etc.)
|
||||||
|
* @returns {Promise<Object>} Object with name and data array
|
||||||
|
*/
|
||||||
|
export async function fetchRunTableData(project, runId, name, params = {}) {
|
||||||
|
const response = await api.get(
|
||||||
|
`/projects/${project}/runs/${runId}/tables/${name}`,
|
||||||
|
{
|
||||||
|
params,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch available scalar metrics for a board
|
* Fetch available scalar metrics for a board
|
||||||
* @param {string} boardId - Board identifier
|
* @param {string} boardId - Board identifier
|
||||||
|
|||||||
Reference in New Issue
Block a user