Skip to main content
Glama
FuncRunDetailsLayout.vue5.45 kB
<template> <section :class=" clsx( 'flex flex-col h-full', themeClasses( 'bg-shade-0 text-shade-100', 'bg-neutral-900 text-shade-0', ), ) " > <header :class=" clsx( 'flex flex-row items-center gap-xs px-sm py-xs border-t border-b border-neutral-600', themeClasses('bg-neutral-200', 'bg-neutral-800'), ) " > <NewButton tooltip="Close (Esc)" tooltipPlacement="top" icon="x" tone="empty" :class=" clsx( 'active:bg-white active:text-black', themeClasses('hover:bg-neutral-200', 'hover:bg-neutral-600'), ) " @click="navigateBack" /> <!-- Function info --> <div class="flex-1 flex flex-row items-center gap-xs"> <span class="sm"> {{ displayName }} </span> <!-- add a bit more "gap" to the first (dt) element, so the pairs have more space between them --> <!-- negative bottom margin to pull it down so all items are visually aligned --> <dl :class=" clsx( 'text-sm flex flex-row items-center gap-2xs [&>dt]:ml-2xs mb-[-0.25em]', themeClasses('text-neutral-600', 'text-neutral-400'), ) " > <slot name="headerList"> </slot> </dl> <FuncRunStatusBadge v-if="funcRun && status" :status="status" /> </div> <!-- Action buttons --> <div class="flex gap-xs"> <slot name="actions"></slot> </div> </header> <!-- Error banner for hinting --> <StatusBox v-if="errorHint" kind="error" class="mx-xs mt-sm mb-xs" :text="errorHint" /> <div v-if="noLogs" class="grid grid-cols-[1fr_1fr] grid-rows-[1fr_1fr_1fr] gap-xs p-xs min-h-0" > <slot name="grid" /> </div> <div v-else class="flex flex-row flex-1 min-h-0 p-xs gap-xs"> <GridItemWithLiveHeader class="basis-1/2" title="Logs" :live="!!isLive && funcRun?.state === 'Running'" disableCollapse > <template v-if="logText"> <pre v-if="logsTooLarge"> {{ logText }} </pre> <CodeViewer v-else ref="logsContainer" :code="logText" language="log" allowCopy /> </template> <div v-else class="text-neutral-400 italic text-xs p-xs"> No logs available </div> </GridItemWithLiveHeader> <div class="grid basis-1/2 gap-xs h-full overflow-hidden min-h-0" :style="gridStyles" > <slot name="grid" /> </div> </div> </section> </template> <script lang="ts" setup> import { computed, ref, watch } from "vue"; import { themeClasses, NewButton } from "@si/vue-lib/design-system"; import { useRoute, useRouter } from "vue-router"; import clsx from "clsx"; import CodeViewer from "@/components/CodeViewer.vue"; import FuncRunStatusBadge from "../FuncRunStatusBadge.vue"; import StatusBox from "./StatusBox.vue"; import GridItemWithLiveHeader from "./GridItemWithLiveHeader.vue"; import { FuncRun } from "../api_composables/func_run"; import { prevPage } from "../logic_composables/navigation_stack"; const props = defineProps<{ displayName: string; funcRun?: FuncRun; noLogs?: boolean; status: string; logText: string; logsTooLarge: boolean; isLive?: boolean; errorHint?: string; errorMessageRaw?: string; collapsingStyles?: string; }>(); const gridStyles = computed( () => props.collapsingStyles ?? "grid-template-rows: 1fr 1fr 1fr;", ); const router = useRouter(); const route = useRoute(); // Navigate back to explore_grid view const navigateBack = () => { const lastPage = prevPage(); // if we aren't coming from new-hotness, go to where we came from // usually component details if (lastPage && lastPage.name !== "new-hotness") { router.push({ name: lastPage.name, params: lastPage.params, }); } else { router.push({ name: "new-hotness", params: { workspacePk: route.params.workspacePk, changeSetId: route.params.changeSetId, }, query: { retainSessionState: 1 }, }); } }; const logText = computed(() => { if (props.errorHint && props.errorMessageRaw) return `${props.logText}\n${props.errorHint}\nRaw error message: ${props.errorMessageRaw}`; if (props.errorHint && !props.errorMessageRaw) return `${props.logText}\n${props.errorHint}`; if (!props.errorHint && props.errorMessageRaw) return `${props.logText}\nRaw error message: ${props.errorMessageRaw}`; return props.logText; }); const logsContainer = ref<InstanceType<typeof CodeViewer> | null>(null); // Watch for log updates to scroll to bottom when they're loaded watch( () => props.logText, (newText, oldText) => { if (newText && (!oldText || newText.length > oldText.length)) { // If logs were added, scroll to bottom after a short delay to allow rendering setTimeout(() => { if (logsContainer.value?.$el) { const codeElement = logsContainer.value.$el.querySelector(".overflow-auto"); if (codeElement) { codeElement.scrollTop = codeElement.scrollHeight; } } }, 100); } }, ); </script>

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server