Hello from MCP server

List Files | Just Commands | Repo | Logs

← back |
<template>
  <div v-if="sessionStore.debugMode" class="debug-toolbar">
    <div class="debug-toolbar-row">
      <span class="debug-label">Debug:</span>
      <select v-model="selectedFunction" class="debug-select">
        <option value="">-- Select Function --</option>
        <optgroup v-for="group in functionGroups" :key="group.label" :label="group.label">
          <option v-for="fn in group.functions" :key="fn.value" :value="fn.value">
            {{ fn.label }}
          </option>
        </optgroup>
      </select>
      <button type="button" class="debug-btn" @click="showDebugInfo = !showDebugInfo">
        {{ showDebugInfo ? 'Hide' : 'Show' }} State
      </button>
    </div>
    <div v-if="showDebugInfo" class="debug-info">
      <div class="debug-row">
        <div class="debug-col">
          <slot name="info-sections">
            <div class="debug-section">
              <strong>No info sections provided</strong>
            </div>
          </slot>
        </div>
        <div class="debug-col">
          <div class="debug-section">
            <strong>Lifecycle States:</strong>
          </div>
          <div v-for="(lc, idx) in lifecycleStates" :key="'lc-'+idx" class="debug-log-entry">
            <span class="debug-time">{{ lc.time }}</span>
            <span class="debug-lifecycle">{{ lc.state }}</span>
          </div>
          <div v-if="lifecycleStates.length === 0" class="debug-empty">No lifecycle events yet</div>
        </div>
        <div class="debug-col">
          <div class="debug-section">
            <strong>Function Executions:</strong>
          </div>
          <div v-for="(fn, idx) in functionExecutions" :key="'fn-'+idx" class="debug-log-entry">
            <span class="debug-time">{{ fn.time }}</span>
            <span class="debug-fn">{{ fn.name }}({{ fn.args || '' }})</span>
          </div>
          <div v-if="functionExecutions.length === 0" class="debug-empty">No function calls yet</div>
        </div>
      </div>

      <!-- Reactive Variables JSON -->
      <div class="debug-json-section">
        <div class="debug-json-header">
          <strong>Reactive Variables:</strong>
          <button type="button" class="debug-btn-small" @click="jsonExpanded = !jsonExpanded; jsonKey++">
            {{ jsonExpanded ? 'Collapse' : 'Expand' }}
          </button>
        </div>
        <pre class="debug-json"><code><JsonViewer :key="jsonKey" :data="reactiveData" :start-collapsed="!jsonExpanded" :expand-all="jsonExpanded" /></code></pre>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
import JsonViewer from "@/components/JsonViewer.vue";
import { useSessionStore } from "@/stores/session";

const sessionStore = useSessionStore();

export interface FunctionOption {
  label: string;
  value: string;
}

export interface FunctionGroup {
  label: string;
  functions: FunctionOption[];
}

interface FunctionExecution {
  name: string;
  time: string;
  args?: string;
}

interface LifecycleState {
  state: string;
  time: string;
}

defineProps<{
  functionGroups?: FunctionGroup[];
  reactiveData?: Record<string, any>;
}>();

const selectedFunction = ref('');
const showDebugInfo = ref(false);
const jsonExpanded = ref(false);
const jsonKey = ref(0);

const functionExecutions = ref<FunctionExecution[]>([]);
const lifecycleStates = ref<LifecycleState[]>([]);

function logExecution(name: string, args?: any[]) {
  const time = new Date().toLocaleTimeString('en-US', {
    hour12: false,
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    fractionalSecondDigits: 3
  });
  const argsStr = args
    ? args.map(a => typeof a === 'object' ? JSON.stringify(a).slice(0, 50) : String(a)).join(', ')
    : undefined;
  functionExecutions.value.unshift({ name, time, args: argsStr });
  if (functionExecutions.value.length > 20) functionExecutions.value.pop();
}

function logLifecycle(state: string) {
  const time = new Date().toLocaleTimeString('en-US', {
    hour12: false,
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    fractionalSecondDigits: 3
  });
  lifecycleStates.value.unshift({ state, time });
  if (lifecycleStates.value.length > 10) lifecycleStates.value.pop();
}

defineExpose({
  logExecution,
  logLifecycle,
  selectedFunction,
  showDebugInfo,
});
</script>

<style scoped>
.debug-toolbar {
  padding: 12px 16px;
  margin: 0;
  background: #f5f5f5;
  border-bottom: 1px solid #ddd;
  font-family: system-ui, sans-serif;
  font-size: 13px;
}

.debug-toolbar-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.debug-label {
  font-weight: 600;
  color: #000;
}

.debug-select {
  flex: 1;
  min-width: 200px;
  max-width: 400px;
  padding: 6px 10px;
  font-size: 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  background: #fff;
  color: #333;
  cursor: pointer;
}

.debug-btn {
  padding: 6px 14px;
  font-size: 12px;
  cursor: pointer;
  background: #000;
  color: #fff;
  border: 1px solid #000;
  border-radius: 4px;
}

.debug-btn:hover {
  background: #333;
}

.debug-info {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid #ddd;
}

.debug-row {
  display: flex;
  gap: 24px;
  flex-wrap: wrap;
}

.debug-col {
  flex: 1;
  min-width: 200px;
  max-width: 400px;
}

.debug-section {
  padding: 4px 0;
  font-size: 12px;
  color: #333;
}

.debug-section strong {
  color: #666;
}

.debug-job-chip {
  display: inline-block;
  margin-left: 6px;
  padding: 2px 6px;
  background: #e8e8e8;
  color: #000;
  border-radius: 3px;
  font-family: monospace;
  font-size: 11px;
}

.debug-log-entry {
  display: flex;
  gap: 8px;
  padding: 2px 0;
  font-size: 11px;
  font-family: monospace;
}

.debug-time {
  color: #999;
  flex-shrink: 0;
}

.debug-lifecycle {
  color: #9333ea;
  font-weight: 500;
}

.debug-fn {
  color: #000;
  word-break: break-all;
}

.debug-empty {
  font-size: 11px;
  color: #999;
  font-style: italic;
  padding: 4px 0;
}

.debug-json-section {
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid #ddd;
}

.debug-json-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
}

.debug-json-header strong {
  color: #666;
  font-size: 12px;
}

.debug-btn-small {
  padding: 3px 8px;
  font-size: 11px;
  cursor: pointer;
  background: #000;
  color: #fff;
  border: 1px solid #000;
  border-radius: 3px;
}

.debug-btn-small:hover {
  background: #333;
}

.debug-json {
  margin: 0;
  padding: 12px;
  background: #fff;
  border: 1px solid #ddd;
  border-radius: 4px;
  overflow-x: auto;
  max-height: 400px;
  overflow-y: auto;
}

.debug-json code {
  font-family: monospace;
  font-size: 11px;
  color: #333;
  white-space: pre;
}
</style>