Skip to main content
Glama
ActionsList.vue6.12 kB
<template> <TreeNode :enableGroupToggle="populated > 0" styleAsGutter> <template #label> <div :class=" clsx( 'flex flex-row gap-2xs justify-between place-items-center bg-neutral-100 dark:bg-neutral-700 text-sm', changeSet ? 'py-2xs px-xs' : 'py-xs', ) " > <template v-if="changeSet"> <div class="flex flex-col flex-grow min-w-0"> <Timestamp :date="changeSet.appliedAt" :timeClasses=" themeClasses('text-neutral-500', 'text-neutral-400') " class="text-sm" dateClasses="font-bold" showTimeIfToday size="long" /> <div :class=" clsx( 'text-xs truncate', themeClasses('text-neutral-500', 'text-neutral-400'), ) " > <span class="font-bold">Change Set:</span> {{ changeSet.name }} </div> </div> <div class="flex-none font-bold">{{ populated }} Action(s)</div> <!-- TODO(Wendy) - maybe a PillCounter makes more sense here? --> <!-- <PillCounter v-tooltip="{ content: 'Actions', placement: 'left' }" :count="displayActions.length" class="flex-none font-bold cursor-pointer" size="lg" /> --> </template> <template v-else> <div class="grow-0 mx-[.66em]"> <Icon class="attributes-panel-item__type-icon" name="bullet-list" size="sm" /> </div> <div class="grow">{{ populated }} Action(s)</div> <div class="grow-0 flex flex-row mr-xs"> <div v-for="(cnt, actionKind) in actionsByKind" :key="actionKind" class="flex flex-row mx-2xs p-2xs rounded dark:bg-neutral-900 bg-neutral-200" > <div class="mx-2xs">{{ cnt }}</div> <StatusIndicatorIcon :status="actionKind.toString()" size="sm" type="action" /> </div> </div> </template> </div> </template> <template v-if="proposedActions"> <div v-for="action in proposedActions" :key="action.id" :class=" clsx( 'border-b', themeClasses('border-neutral-100', 'border-neutral-700'), ) " > <ActionCard :action="action" :noInteraction="props.noInteraction" :selected="isSelected(action)" :slim="props.slim" @click="props.clickAction && props.clickAction(action, $event)" @history="openHistory" @remove="actionsStore.CANCEL([action.id])" /> </div> </template> <template v-if="historyActions"> <div v-for="action in historyActions" :key="action.id" :class=" clsx( 'border-b', themeClasses('border-neutral-100', 'border-neutral-700'), ) " > <ActionHistoryCard :action="action" :noInteraction="props.noInteraction" :selected="isSelected(action)" :slim="props.slim" @history="openHistory" @remove="actionsStore.CANCEL([action.id])" /> </div> </template> </TreeNode> </template> <script lang="ts" setup> import clsx from "clsx"; import { Icon, Timestamp, TreeNode, themeClasses, } from "@si/vue-lib/design-system"; import { PropType, computed } from "vue"; import { useActionsStore, ActionView, ActionHistoryView, FuncRunId, ActionProposedView, } from "@/store/actions.store"; import { DefaultMap } from "@/utils/defaultmap"; import { ChangeSet } from "@/api/sdf/dal/change_set"; import StatusIndicatorIcon from "@/components/StatusIndicatorIcon.vue"; import ActionCard from "./ActionCard.vue"; import ActionHistoryCard from "./ActionHistoryCard.vue"; export interface ActionProposedViewWithHydratedChildren extends ActionProposedView { dependentOnActions: ActionProposedView[]; myDependentActions: ActionProposedView[]; holdStatusInfluencedByActions: ActionProposedView[]; } export type ActionsListKind = "proposed" | "history"; const actionsStore = useActionsStore(); type clickFn = ( action: ActionProposedViewWithHydratedChildren, e: MouseEvent, ) => void; const props = defineProps({ proposedActions: { type: Array<ActionProposedViewWithHydratedChildren>, required: false, }, historyActions: { type: Array<ActionHistoryView>, required: false }, noInteraction: { type: Boolean }, selectedActionIds: { type: Array<string> }, selectedFuncRunIds: { type: Array<string> }, slim: { type: Boolean }, clickAction: { type: Function as PropType<clickFn>, default: undefined, }, changeSet: { type: Object as PropType<ChangeSet> }, }); const populated = computed( () => (props.proposedActions?.length ?? 0) || (props.historyActions?.length ?? 0), ); const selectedIds = computed<string[]>(() => { if (props.proposedActions) { return props.selectedActionIds || []; } return props.selectedFuncRunIds || []; }); const isSelected = (action: ActionView) => { let id: string | undefined; if (props.historyActions) { id = action.funcRunId; } else { id = action.id; } if (id) return selectedIds.value.includes(id); return false; }; const actionsByKind = computed(() => { const actions = props.proposedActions ?? props.historyActions; if (!actions) return {}; const counts = new DefaultMap<string, number>(() => 0); for (const action of actions) { counts.set(action.kind, counts.get(action.kind) + 1); } return Object.fromEntries(counts); }); const emit = defineEmits<{ (e: "history", id: FuncRunId, tabSlug: string): void; }>(); function openHistory(id: FuncRunId, slug: string) { emit("history", id, slug); } </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