Skip to main content
Glama
FuncRunList.vue4.99 kB
<template> <FuncRunListLayout :funcRuns="funcRuns" :availableFuncKinds="availableFuncKinds" :selectedFuncKind="selectedFuncKind" :hasActiveFilters="hasActiveFilters" :isFetchingNextPage="isFetchingNextPage" :hasNextPage="hasNextPage" :isLoading="isLoading" emptyStateText="No function runs yet" emptyStateSecondaryText="Function history shows the output of executed functions, including logs, generated code, passed arguments, and results." @update:selectedFuncKind="(val) => (selectedFuncKind = val)" @resetFilters="resetFilters" @scroll="handleScroll" > <template #additional-filters> <div :class=" clsx( 'flex flex-row items-center gap-2xs border rounded', themeClasses('border-neutral-400', 'border-neutral-600'), ) " > <input v-model="componentNameFilter" type="text" placeholder="Find by component name" :class=" clsx( 'text-xs px-2xs py-2xs min-w-[250px] border-0', themeClasses( 'bg-white text-neutral-600 placeholder-neutral-500', 'bg-black text-neutral-400 placeholder-neutral-400', ), ) " /> </div> </template> </FuncRunListLayout> </template> <script lang="ts" setup> import { computed, ref, inject } from "vue"; import { useInfiniteQuery } from "@tanstack/vue-query"; import { themeClasses } from "@si/vue-lib/design-system"; import clsx from "clsx"; import FuncRunListLayout from "./layout_components/FuncRunListLayout.vue"; import { funcRunTypes, useApi, routes } from "./api_composables"; import { assertIsDefined, Context } from "./types"; import { FuncRun } from "./api_composables/func_run"; // Component props const props = defineProps<{ limit?: number; }>(); const ctx = inject<Context>("CONTEXT"); assertIsDefined(ctx); // Configure page size with default fallback const pageSize = computed(() => props.limit || 50); // Filter state const selectedFuncKind = ref<string>(""); const componentNameFilter = ref<string>(""); const api = useApi(); const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } = useInfiniteQuery({ queryKey: [ctx.changeSetId, "paginatedFuncRuns"], queryFn: async ({ pageParam = undefined, }): Promise<funcRunTypes.GetFuncRunsPaginatedResponse> => { const call = api.endpoint<funcRunTypes.GetFuncRunsPaginatedResponse>( routes.GetFuncRunsPaginated, ); const params = new URLSearchParams(); params.append("limit", pageSize.value.toString()); if (pageParam) { params.append("cursor", pageParam); } const req = await call.get(params); if (api.ok(req)) { return req.data; } return { funcRuns: [], nextCursor: null, }; }, initialPageParam: undefined, getNextPageParam: (lastPage: funcRunTypes.GetFuncRunsPaginatedResponse) => { return lastPage.nextCursor ?? undefined; }, }); // Flatten the pages of function runs for display const allFuncRuns = computed<FuncRun[]>(() => { if (!data.value) return []; return data.value.pages.flatMap((page) => page.funcRuns); }); // Get available func kinds from the data const availableFuncKinds = computed(() => { const kinds = new Set<string>(); allFuncRuns.value.forEach((funcRun) => { if (funcRun.functionKind) { kinds.add(funcRun.functionKind); } }); return Array.from(kinds).sort(); }); // Filter function runs based on selected func kind and component name const funcRuns = computed<FuncRun[]>(() => { let filtered = allFuncRuns.value; // Filter by function kind if selected if (selectedFuncKind.value) { filtered = filtered.filter( (funcRun) => funcRun.functionKind === selectedFuncKind.value, ); } // Filter by component name if provided if (componentNameFilter.value.trim()) { const searchTerm = componentNameFilter.value.toLowerCase().trim(); filtered = filtered.filter((funcRun) => { return funcRun.componentName?.toLowerCase().includes(searchTerm) || false; }); } return filtered; }); // Check if any filters are active const hasActiveFilters = computed(() => { return ( selectedFuncKind.value !== "" || componentNameFilter.value.trim() !== "" ); }); // Reset all filters const resetFilters = () => { selectedFuncKind.value = ""; componentNameFilter.value = ""; }; // Handle scroll to implement infinite loading const handleScroll = (event: Event) => { const target = event.target as HTMLElement; if (!target) return; const { scrollTop, scrollHeight, clientHeight } = target; const scrollBottom = scrollHeight - scrollTop - clientHeight; // Load more when user scrolls near the bottom (within 200px) if (scrollBottom < 200 && hasNextPage.value && !isFetchingNextPage.value) { fetchNextPage(); } }; </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