Added jobRuns on the job page
Some checks failed
Push image to registry / build-image (push) Failing after 3m47s

This commit is contained in:
2025-03-15 17:44:30 +01:00
parent ad10dcaa0f
commit 070235e011
17 changed files with 330 additions and 18 deletions

View File

@ -0,0 +1,24 @@
<script setup lang="ts">
import Separator from "@/Components/ui/separator/Separator.vue";
import { JobRunArtifact } from "@/types/Jobs/job";
defineProps<{
jobRun: JobRunArtifact;
}>();
</script>
<template>
<ul>
<li v-for="artifact in jobRun.artifacts" :key="artifact.id">
<p>{{ artifact.name }}</p>
<p class="italic">{{ artifact.content }}</p>
</li>
</ul>
</template>
<style lang="scss" scoped>
ul {
list-style-type: circle;
padding-left: 1rem;
}
</style>

View File

@ -0,0 +1,28 @@
<script setup lang="ts">
import AccordionContent from "@/Components/ui/accordion/AccordionContent.vue";
import AccordionItem from "@/Components/ui/accordion/AccordionItem.vue";
import AccordionTrigger from "@/Components/ui/accordion/AccordionTrigger.vue";
import { JobRunArtifact } from "@/types/Jobs/job";
import JobRunArtifacts from "./JobRunArtifacts.vue";
defineProps<{
jobRun: JobRunArtifact;
}>();
</script>
<template>
<AccordionItem :value="''+jobRun.id" :class="[jobRun.success ? 'bg-green-100' : 'bg-red-200', 'first:rounded-t last:rounded-b', 'px-3']">
<AccordionTrigger>
{{ new Date(Date.parse(jobRun.created_at)).toLocaleTimeString(undefined, {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
})
}}
</AccordionTrigger>
<AccordionContent>
<JobRunArtifacts :jobRun="jobRun" />
</AccordionContent>
</AccordionItem>
</template>

View File

@ -0,0 +1,28 @@
<script setup lang="ts">
import { Job, JobRunArtifact } from "@/types/Jobs/job";
import JobRunItem from "./JobRunItem.vue";
import Accordion from "@/Components/ui/accordion/Accordion.vue";
import ScrollArea from "@/Components/ui/scroll-area/ScrollArea.vue";
defineProps<{
job: Job;
}>();
</script>
<template>
<h2>Ancien jobs</h2>
<ScrollArea class="min-h-[300px] max-h-[20vh] overflow-auto pr-2">
<Accordion type="multiple" collapsible>
<JobRunItem
:jobRun="jobRun"
v-for="jobRun in job.job_runs.sort((a, b) => {
return (
new Date(b.created_at).getTime() -
new Date(a.created_at).getTime()
);
})"
:key="jobRun.id"
/>
</Accordion>
</ScrollArea>
</template>

View File

@ -0,0 +1,19 @@
<script setup lang="ts">
import {
AccordionRoot,
type AccordionRootEmits,
type AccordionRootProps,
useForwardPropsEmits,
} from 'reka-ui'
const props = defineProps<AccordionRootProps>()
const emits = defineEmits<AccordionRootEmits>()
const forwarded = useForwardPropsEmits(props, emits)
</script>
<template>
<AccordionRoot v-bind="forwarded">
<slot />
</AccordionRoot>
</template>

View File

@ -0,0 +1,24 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { AccordionContent, type AccordionContentProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<AccordionContentProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
</script>
<template>
<AccordionContent
v-bind="delegatedProps"
class="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
>
<div :class="cn('pb-4 pt-0', props.class)">
<slot />
</div>
</AccordionContent>
</template>

View File

@ -0,0 +1,24 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { AccordionItem, type AccordionItemProps, useForwardProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<AccordionItemProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<AccordionItem
v-bind="forwardedProps"
:class="cn('border-b', props.class)"
>
<slot />
</AccordionItem>
</template>

View File

@ -0,0 +1,39 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { ChevronDown } from 'lucide-vue-next'
import {
AccordionHeader,
AccordionTrigger,
type AccordionTriggerProps,
} from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<AccordionTriggerProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
</script>
<template>
<AccordionHeader class="flex">
<AccordionTrigger
v-bind="delegatedProps"
:class="
cn(
'flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',
props.class,
)
"
>
<slot />
<slot name="icon">
<ChevronDown
class="h-4 w-4 shrink-0 transition-transform duration-200"
/>
</slot>
</AccordionTrigger>
</AccordionHeader>
</template>

View File

@ -0,0 +1,4 @@
export { default as Accordion } from './Accordion.vue'
export { default as AccordionContent } from './AccordionContent.vue'
export { default as AccordionItem } from './AccordionItem.vue'
export { default as AccordionTrigger } from './AccordionTrigger.vue'

View File

@ -0,0 +1,35 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { Separator, type SeparatorProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<
SeparatorProps & { class?: HTMLAttributes['class'], label?: string }
>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
</script>
<template>
<Separator
v-bind="delegatedProps"
:class="
cn(
'shrink-0 bg-border relative',
props.orientation === 'vertical' ? 'w-px h-full' : 'h-px w-full',
props.class,
)
"
>
<span
v-if="props.label"
:class="cn('text-xs text-muted-foreground bg-background absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 flex justify-center items-center',
props.orientation === 'vertical' ? 'w-[1px] px-1 py-2' : 'h-[1px] py-1 px-2',
)"
>{{ props.label }}</span>
</Separator>
</template>

View File

@ -0,0 +1 @@
export { default as Separator } from './Separator.vue'

View File

@ -1,6 +1,7 @@
<script setup lang="ts">
import JobForm from '../Components/Layout/Job/JobForm.vue'
import JobCard from '../Components/Layout/Job/JobCard.vue'
import JobRuns from '../Components/Layout/Job/JobRuns/JobRuns.vue';
import { Job } from "@/types/Jobs/job";
import { Head } from "@inertiajs/vue3";
@ -16,4 +17,6 @@ defineProps<{
<JobCard :job="job" />
<JobForm :job="job" :error="error" />
<JobRuns :job="job" />
</template>

View File

@ -1,8 +1,17 @@
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
import type { Updater } from '@tanstack/vue-table'
import type { Ref } from 'vue'
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
return twMerge(clsx(inputs))
}
export function valueUpdater<T extends Updater<any>>(updaterOrValue: T, ref: Ref) {
ref.value
= typeof updaterOrValue === 'function'
? updaterOrValue(ref.value)
: updaterOrValue
}
export async function httpApi<T>(route: string): Promise<T> {

View File

@ -5,8 +5,9 @@ export type Job = {
is_active: boolean;
job_infos: JobInfo[];
job_runs: JobRunArtifact[];
created_at: Date;
created_at: string;
}
export type JobInfo = {
@ -26,16 +27,23 @@ export type JobInfo = {
export type JobInfoType = {
id: number;
name: string;
created_at: Date;
created_at: string;
}
export type JobRunArtifact = {
jobId: number;
id: number;
job_id: number;
artifacts: JobArtifact[];
success: boolean;
created_at: string;
}
export type JobArtifact = {
id: number;
name: string;
content: string;
created_at: string;
}