|
|
|
@@ -56,45 +56,11 @@
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="sidebar-nav" role="navigation" aria-label="Main navigation">
|
|
|
|
|
<!-- Chat — primary action -->
|
|
|
|
|
<div class="nav-section" x-data="{ collapsed: false }" aria-label="Chat">
|
|
|
|
|
<div class="nav-section-title" @click="collapsed = !collapsed">
|
|
|
|
|
<span class="nav-label">Chat</span>
|
|
|
|
|
<span class="nav-section-chevron" :style="collapsed ? '' : 'transform:rotate(90deg)'">›</span>
|
|
|
|
|
</div>
|
|
|
|
|
<template x-if="!collapsed">
|
|
|
|
|
<div x-transition>
|
|
|
|
|
<a class="nav-item" :class="{ active: page === 'agents' }" @click="navigate('agents')" :aria-current="page === 'agents' ? 'page' : false">
|
|
|
|
|
<span class="nav-icon"><svg viewBox="0 0 24 24"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></span>
|
|
|
|
|
<span class="nav-label">Chat</span>
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Monitor -->
|
|
|
|
|
<div class="nav-section" x-data="{ collapsed: false }" aria-label="Monitor">
|
|
|
|
|
<div class="nav-section-title" @click="collapsed = !collapsed">
|
|
|
|
|
<span class="nav-label">Monitor</span>
|
|
|
|
|
<span class="nav-section-chevron" :style="collapsed ? '' : 'transform:rotate(90deg)'">›</span>
|
|
|
|
|
</div>
|
|
|
|
|
<template x-if="!collapsed">
|
|
|
|
|
<div x-transition>
|
|
|
|
|
<a class="nav-item" :class="{ active: page === 'overview' }" @click="navigate('overview')" :aria-current="page === 'overview' ? 'page' : false">
|
|
|
|
|
<!-- Overview — primary action as first screen -->
|
|
|
|
|
<a class="nav-item" :class="{ active: page === 'overview' }" @click="navigate('overview')" :aria-current="page === 'overview' ? 'page' : false" style="margin-bottom: 4px;">
|
|
|
|
|
<span class="nav-icon"><svg viewBox="0 0 24 24"><path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M9 22V12h6v10"/></svg></span>
|
|
|
|
|
<span class="nav-label">Overview</span>
|
|
|
|
|
</a>
|
|
|
|
|
<a class="nav-item" :class="{ active: page === 'analytics' }" @click="navigate('analytics')" :aria-current="page === 'analytics' ? 'page' : false">
|
|
|
|
|
<span class="nav-icon"><svg viewBox="0 0 24 24"><path d="M18 20V10M12 20V4M6 20v-6"/></svg></span>
|
|
|
|
|
<span class="nav-label">Analytics</span>
|
|
|
|
|
</a>
|
|
|
|
|
<a class="nav-item" :class="{ active: page === 'logs' }" @click="navigate('logs')" :aria-current="page === 'logs' ? 'page' : false">
|
|
|
|
|
<span class="nav-icon"><svg viewBox="0 0 24 24"><path d="m4 17 6-6-6-6"/><path d="M12 19h8"/></svg></span>
|
|
|
|
|
<span class="nav-label">Logs</span>
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Agents -->
|
|
|
|
|
<div class="nav-section" x-data="{ collapsed: false }" aria-label="Agents">
|
|
|
|
@@ -104,6 +70,10 @@
|
|
|
|
|
</div>
|
|
|
|
|
<template x-if="!collapsed">
|
|
|
|
|
<div x-transition>
|
|
|
|
|
<a class="nav-item" :class="{ active: page === 'agents' }" @click="navigate('agents')" :aria-current="page === 'agents' ? 'page' : false">
|
|
|
|
|
<span class="nav-icon"><svg viewBox="0 0 24 24"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></span>
|
|
|
|
|
<span class="nav-label">Chat</span>
|
|
|
|
|
</a>
|
|
|
|
|
<a class="nav-item" :class="{ active: page === 'sessions' }" @click="navigate('sessions')" :aria-current="page === 'sessions' ? 'page' : false">
|
|
|
|
|
<span class="nav-icon"><svg viewBox="0 0 24 24"><path d="m12 2-10 5 10 5 10-5z"/><path d="m2 17 10 5 10-5"/><path d="m2 12 10 5 10-5"/></svg></span>
|
|
|
|
|
<span class="nav-label">Sessions</span>
|
|
|
|
@@ -165,6 +135,26 @@
|
|
|
|
|
</template>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Monitor -->
|
|
|
|
|
<div class="nav-section" x-data="{ collapsed: false }" aria-label="Monitor">
|
|
|
|
|
<div class="nav-section-title" @click="collapsed = !collapsed">
|
|
|
|
|
<span class="nav-label">Monitor</span>
|
|
|
|
|
<span class="nav-section-chevron" :style="collapsed ? '' : 'transform:rotate(90deg)'">›</span>
|
|
|
|
|
</div>
|
|
|
|
|
<template x-if="!collapsed">
|
|
|
|
|
<div x-transition>
|
|
|
|
|
<a class="nav-item" :class="{ active: page === 'analytics' }" @click="navigate('analytics')" :aria-current="page === 'analytics' ? 'page' : false">
|
|
|
|
|
<span class="nav-icon"><svg viewBox="0 0 24 24"><path d="M18 20V10M12 20V4M6 20v-6"/></svg></span>
|
|
|
|
|
<span class="nav-label">Analytics</span>
|
|
|
|
|
</a>
|
|
|
|
|
<a class="nav-item" :class="{ active: page === 'logs' }" @click="navigate('logs')" :aria-current="page === 'logs' ? 'page' : false">
|
|
|
|
|
<span class="nav-icon"><svg viewBox="0 0 24 24"><path d="m4 17 6-6-6-6"/><path d="M12 19h8"/></svg></span>
|
|
|
|
|
<span class="nav-label">Logs</span>
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- System -->
|
|
|
|
|
<div class="nav-section" x-data="{ collapsed: false }" aria-label="System">
|
|
|
|
|
<div class="nav-section-title" @click="collapsed = !collapsed">
|
|
|
|
@@ -257,8 +247,10 @@
|
|
|
|
|
<template x-for="item in setupChecklist" :key="item.key">
|
|
|
|
|
<div class="setup-checklist-item">
|
|
|
|
|
<div class="setup-checklist-icon" :class="{ done: item.done }">
|
|
|
|
|
<span x-show="item.done">✓</span>
|
|
|
|
|
<span x-show="!item.done">○</span>
|
|
|
|
|
<span x-show="item.done">
|
|
|
|
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" style="display:block"><polyline points="20 6 9 17 4 12"/></svg>
|
|
|
|
|
</span>
|
|
|
|
|
<span x-show="!item.done" style="width:10px;height:10px;border-radius:50%;border:1.5px solid var(--border);display:block"></span>
|
|
|
|
|
</div>
|
|
|
|
|
<span style="flex:1" :style="item.done ? 'text-decoration:line-through;opacity:0.6' : ''" x-text="item.label"></span>
|
|
|
|
|
<a x-show="!item.done" :href="item.action" class="btn btn-ghost btn-sm" style="font-size:10px;padding:3px 8px">Go</a>
|
|
|
|
@@ -869,7 +861,7 @@
|
|
|
|
|
</div>
|
|
|
|
|
<span class="badge" :class="'badge-' + agent.state.toLowerCase()" x-text="agent.state" style="font-size:10px"></span>
|
|
|
|
|
<button class="agent-chip-config-btn" @click.stop="showDetail(agent)" title="Agent settings" style="display:flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:50%;border:1px solid var(--border);background:transparent;cursor:pointer;color:var(--text-dim);transition:all 0.15s;flex-shrink:0" @mouseenter="$el.style.borderColor='var(--accent)';$el.style.color='var(--accent)';$el.style.background='var(--surface2)'" @mouseleave="$el.style.borderColor='var(--border)';$el.style.color='var(--text-dim)';$el.style.background='transparent'">
|
|
|
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
|
|
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
@@ -904,7 +896,9 @@
|
|
|
|
|
<span x-show="detailAgent.identity && detailAgent.identity.emoji" x-text="detailAgent.identity && detailAgent.identity.emoji" style="margin-right:6px"></span>
|
|
|
|
|
<span x-text="detailAgent.name"></span>
|
|
|
|
|
</h3>
|
|
|
|
|
<button class="modal-close" @click="showDetailModal = false">×</button>
|
|
|
|
|
<button class="modal-close" @click="showDetailModal = false">
|
|
|
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="tabs" style="margin-bottom:16px">
|
|
|
|
|
<div class="tab" :class="{ active: detailTab === 'info' }" @click="detailTab = 'info'">Info</div>
|
|
|
|
@@ -1413,7 +1407,7 @@
|
|
|
|
|
<option value="conditional">Conditional</option>
|
|
|
|
|
<option value="loop">Loop</option>
|
|
|
|
|
</select>
|
|
|
|
|
<button class="btn btn-danger btn-sm" @click="newWf.steps.splice(i,1)">×</button>
|
|
|
|
|
<button class="btn btn-danger btn-sm" @click="newWf.steps.splice(i,1)"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button>
|
|
|
|
|
</div>
|
|
|
|
|
<input class="form-input mt-2" x-model="step.prompt" placeholder="Prompt template (use {{input}})">
|
|
|
|
|
</div>
|
|
|
|
@@ -1428,7 +1422,7 @@
|
|
|
|
|
<template x-if="runModal">
|
|
|
|
|
<div class="modal-overlay" @click.self="runModal = null" @keydown.escape.window="runModal = null">
|
|
|
|
|
<div class="modal">
|
|
|
|
|
<div class="modal-header"><h3 x-text="'Run: ' + runModal.name"></h3><button class="modal-close" @click="runModal = null">×</button></div>
|
|
|
|
|
<div class="modal-header"><h3 x-text="'Run: ' + runModal.name"></h3><button class="modal-close" @click="runModal = null"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button></div>
|
|
|
|
|
<div class="form-group"><label>Input</label><textarea class="form-textarea" x-model="runInput" placeholder="Enter workflow input..."></textarea></div>
|
|
|
|
|
<button class="btn btn-primary btn-block" @click="executeWorkflow()" :disabled="running">
|
|
|
|
|
<span x-show="!running">Execute</span><span x-show="running">Running...</span>
|
|
|
|
@@ -1444,7 +1438,7 @@
|
|
|
|
|
<template x-if="editModal">
|
|
|
|
|
<div class="modal-overlay" @click.self="editModal = null" @keydown.escape.window="editModal = null">
|
|
|
|
|
<div class="modal">
|
|
|
|
|
<div class="modal-header"><h3 x-text="'Edit: ' + editModal.name"></h3><button class="modal-close" @click="editModal = null">×</button></div>
|
|
|
|
|
<div class="modal-header"><h3 x-text="'Edit: ' + editModal.name"></h3><button class="modal-close" @click="editModal = null"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button></div>
|
|
|
|
|
<div class="form-group"><label>Name</label><input class="form-input" x-model="editWf.name" placeholder="Workflow name"></div>
|
|
|
|
|
<div class="form-group"><label>Description</label><input class="form-input" x-model="editWf.description" placeholder="What does this workflow do?"></div>
|
|
|
|
|
<div class="mb-4">
|
|
|
|
@@ -1462,7 +1456,7 @@
|
|
|
|
|
<option value="conditional">Conditional</option>
|
|
|
|
|
<option value="loop">Loop</option>
|
|
|
|
|
</select>
|
|
|
|
|
<button class="btn btn-danger btn-sm" @click="editWf.steps.splice(i,1)">×</button>
|
|
|
|
|
<button class="btn btn-danger btn-sm" @click="editWf.steps.splice(i,1)"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button>
|
|
|
|
|
</div>
|
|
|
|
|
<input class="form-input mt-2" x-model="step.prompt" placeholder="Prompt template (use {{input}})">
|
|
|
|
|
</div>
|
|
|
|
@@ -1550,7 +1544,7 @@
|
|
|
|
|
<div class="wf-editor-panel" x-show="showNodeEditor && selectedNode" x-transition>
|
|
|
|
|
<div class="wf-editor-header">
|
|
|
|
|
<span class="font-bold text-sm" x-text="selectedNode ? selectedNode.label : ''"></span>
|
|
|
|
|
<button class="btn btn-ghost btn-sm" @click="showNodeEditor = false">×</button>
|
|
|
|
|
<button class="btn btn-ghost btn-sm" @click="showNodeEditor = false"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button>
|
|
|
|
|
</div>
|
|
|
|
|
<template x-if="selectedNode">
|
|
|
|
|
<div>
|
|
|
|
@@ -1651,7 +1645,7 @@
|
|
|
|
|
<template x-if="showTomlPreview">
|
|
|
|
|
<div class="modal-overlay" @click.self="showTomlPreview = false" @keydown.escape.window="showTomlPreview = false">
|
|
|
|
|
<div class="modal" style="max-width:600px">
|
|
|
|
|
<div class="modal-header"><h3>Generated TOML</h3><button class="modal-close" @click="showTomlPreview = false">×</button></div>
|
|
|
|
|
<div class="modal-header"><h3>Generated TOML</h3><button class="modal-close" @click="showTomlPreview = false"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button></div>
|
|
|
|
|
<pre class="wf-toml-preview" x-text="tomlOutput"></pre>
|
|
|
|
|
<button class="btn btn-ghost btn-block mt-2" @click="navigator.clipboard.writeText(tomlOutput); OpenFangToast.success('Copied!')">Copy to Clipboard</button>
|
|
|
|
|
</div>
|
|
|
|
@@ -1662,7 +1656,7 @@
|
|
|
|
|
<template x-if="showSaveModal">
|
|
|
|
|
<div class="modal-overlay" @click.self="showSaveModal = false" @keydown.escape.window="showSaveModal = false">
|
|
|
|
|
<div class="modal">
|
|
|
|
|
<div class="modal-header"><h3>Save Workflow</h3><button class="modal-close" @click="showSaveModal = false">×</button></div>
|
|
|
|
|
<div class="modal-header"><h3>Save Workflow</h3><button class="modal-close" @click="showSaveModal = false"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button></div>
|
|
|
|
|
<div class="form-group"><label>Name</label><input class="form-input" x-model="workflowName" placeholder="my-workflow"></div>
|
|
|
|
|
<div class="form-group"><label>Description</label><input class="form-input" x-model="workflowDescription" placeholder="What does this workflow do?"></div>
|
|
|
|
|
<div class="text-xs text-dim mb-4" x-text="nodes.filter(function(n){return n.type!=='start'&&n.type!=='end'}).length + ' steps, ' + connections.length + ' connections'"></div>
|
|
|
|
@@ -1778,7 +1772,7 @@
|
|
|
|
|
<div class="modal">
|
|
|
|
|
<div class="modal-header">
|
|
|
|
|
<h3>Create Scheduled Job</h3>
|
|
|
|
|
<button class="modal-close" @click="showCreateForm = false">×</button>
|
|
|
|
|
<button class="modal-close" @click="showCreateForm = false"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
@@ -1988,28 +1982,28 @@
|
|
|
|
|
</h3>
|
|
|
|
|
<div class="text-xs text-dim mt-1" x-text="setupModal.quick_setup || setupModal.description"></div>
|
|
|
|
|
</div>
|
|
|
|
|
<button class="modal-close" @click="setupModal = null">×</button>
|
|
|
|
|
<button class="modal-close" @click="setupModal = null"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 3-step progress indicator (non-QR channels only) -->
|
|
|
|
|
<div class="channel-steps" x-show="!isQrChannel()">
|
|
|
|
|
<div class="channel-step-item">
|
|
|
|
|
<div class="channel-step-num" :class="{ active: setupStep === 1, done: setupStep > 1 }">
|
|
|
|
|
<span x-show="setupStep <= 1">1</span><span x-show="setupStep > 1">✓</span>
|
|
|
|
|
<span x-show="setupStep <= 1">1</span><span x-show="setupStep > 1"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" style="display:block"><polyline points="20 6 9 17 4 12"/></svg></span>
|
|
|
|
|
</div>
|
|
|
|
|
<span class="channel-step-label" :class="{ active: setupStep === 1, done: setupStep > 1 }">Configure</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="channel-step-line" :class="{ done: setupStep > 1 }"></div>
|
|
|
|
|
<div class="channel-step-item">
|
|
|
|
|
<div class="channel-step-num" :class="{ active: setupStep === 2, done: setupStep > 2 }">
|
|
|
|
|
<span x-show="setupStep <= 2">2</span><span x-show="setupStep > 2">✓</span>
|
|
|
|
|
<span x-show="setupStep <= 2">2</span><span x-show="setupStep > 2"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" style="display:block"><polyline points="20 6 9 17 4 12"/></svg></span>
|
|
|
|
|
</div>
|
|
|
|
|
<span class="channel-step-label" :class="{ active: setupStep === 2, done: setupStep > 2 }">Verify</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="channel-step-line" :class="{ done: setupStep > 2 }"></div>
|
|
|
|
|
<div class="channel-step-item">
|
|
|
|
|
<div class="channel-step-num" :class="{ active: setupStep === 3, done: setupStep >= 3 }">
|
|
|
|
|
<span x-show="setupStep < 3">3</span><span x-show="setupStep >= 3">✓</span>
|
|
|
|
|
<span x-show="setupStep < 3">3</span><span x-show="setupStep >= 3"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" style="display:block"><polyline points="20 6 9 17 4 12"/></svg></span>
|
|
|
|
|
</div>
|
|
|
|
|
<span class="channel-step-label" :class="{ active: setupStep === 3, done: setupStep >= 3 }">Ready</span>
|
|
|
|
|
</div>
|
|
|
|
@@ -2017,7 +2011,9 @@
|
|
|
|
|
|
|
|
|
|
<!-- Ready panel (step 3) for non-QR channels -->
|
|
|
|
|
<div x-show="!isQrChannel() && setupStep === 3 && testPassed" class="ready-panel">
|
|
|
|
|
<div class="ready-panel-icon">✓</div>
|
|
|
|
|
<div class="ready-panel-icon">
|
|
|
|
|
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="ready-panel-title" x-text="setupModal.display_name + ' is ready!'"></div>
|
|
|
|
|
<div class="ready-panel-desc">
|
|
|
|
|
Your channel is configured and verified. It will activate automatically.
|
|
|
|
@@ -2053,7 +2049,9 @@
|
|
|
|
|
|
|
|
|
|
<!-- QR: Connected! -->
|
|
|
|
|
<div x-show="!qr.loading && qr.connected" style="text-align:center;padding:2rem 0">
|
|
|
|
|
<div style="font-size:3rem;margin-bottom:0.5rem">✓</div>
|
|
|
|
|
<div style="margin-bottom:0.5rem;display:flex;justify-content:center">
|
|
|
|
|
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
|
|
|
|
</div>
|
|
|
|
|
<p class="text-sm" style="font-weight:600" x-text="qr.message || 'WhatsApp linked successfully!'"></p>
|
|
|
|
|
<p class="text-xs text-dim mt-1">Channel will activate automatically.</p>
|
|
|
|
|
</div>
|
|
|
|
@@ -2261,7 +2259,9 @@
|
|
|
|
|
<div class="search-input mb-4" style="position:relative">
|
|
|
|
|
<span style="color:var(--text-muted)"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg></span>
|
|
|
|
|
<input placeholder="Search ClawHub skills... (type to search)" x-model="clawhubSearch" @input="onSearchInput()" @keydown.enter="if(!$event.isComposing && $event.keyCode !== 229) searchClawHub()" @keydown.escape="clearSearch()" x-ref="clawhubSearchInput">
|
|
|
|
|
<button x-show="clawhubSearch" @click="clearSearch()" class="search-clear-btn" title="Clear search (Esc)">×</button>
|
|
|
|
|
<button x-show="clawhubSearch" @click="clearSearch()" class="search-clear-btn" title="Clear search (Esc)">
|
|
|
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Sort pills (always visible when not searching) -->
|
|
|
|
@@ -2458,7 +2458,9 @@ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path"]</pre>
|
|
|
|
|
<div>
|
|
|
|
|
<div class="modal-header">
|
|
|
|
|
<h3 x-text="skillDetail.name || skillDetail.slug"></h3>
|
|
|
|
|
<button class="modal-close" @click="closeDetail()">×</button>
|
|
|
|
|
<button class="modal-close" @click="closeDetail()">
|
|
|
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
<div class="flex gap-2 items-center flex-wrap">
|
|
|
|
@@ -2651,7 +2653,9 @@ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path"]</pre>
|
|
|
|
|
<div class="modal" style="max-width:600px">
|
|
|
|
|
<div class="modal-header">
|
|
|
|
|
<h3><span x-text="detailHand.icon"></span> <span x-text="detailHand.name"></span></h3>
|
|
|
|
|
<button class="modal-close" @click="detailHand = null">×</button>
|
|
|
|
|
<button class="modal-close" @click="detailHand = null">
|
|
|
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
<p x-text="detailHand.description"></p>
|
|
|
|
@@ -2705,7 +2709,9 @@ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path"]</pre>
|
|
|
|
|
<div class="wizard-title" x-text="'Set up ' + setupWizard.name"></div>
|
|
|
|
|
<div class="wizard-subtitle" x-text="setupWizard.description"></div>
|
|
|
|
|
</div>
|
|
|
|
|
<button class="wizard-close" @click="closeSetupWizard()">×</button>
|
|
|
|
|
<button class="wizard-close" @click="closeSetupWizard()">
|
|
|
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Step Indicators -->
|
|
|
|
@@ -2747,7 +2753,10 @@ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path"]</pre>
|
|
|
|
|
|
|
|
|
|
<!-- Satisfied: green message -->
|
|
|
|
|
<template x-if="req.satisfied">
|
|
|
|
|
<div class="dep-met-msg">✓ Detected on your system</div>
|
|
|
|
|
<div class="dep-met-msg" style="display:flex;align-items:center;gap:4px">
|
|
|
|
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
|
|
|
|
<span>Detected on your system</span>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- Not satisfied: show install instructions -->
|
|
|
|
@@ -2784,7 +2793,10 @@ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path"]</pre>
|
|
|
|
|
<div style="margin-bottom:10px">
|
|
|
|
|
<label class="text-xs text-dim" style="display:block;margin-bottom:4px" x-text="'Paste your ' + req.label + ':'"></label>
|
|
|
|
|
<input type="password" class="form-input" x-model="apiKeyInputs[req.key]" :placeholder="req.label" style="width:100%;font-family:var(--font-mono);font-size:12px">
|
|
|
|
|
<div class="text-xs" style="margin-top:4px;color:var(--green)" x-show="apiKeyInputs[req.key] && apiKeyInputs[req.key].trim() !== ''">✓ Token entered</div>
|
|
|
|
|
<div class="text-xs" style="margin-top:4px;color:var(--green);display:flex;align-items:center;gap:4px" x-show="apiKeyInputs[req.key] && apiKeyInputs[req.key].trim() !== ''">
|
|
|
|
|
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
|
|
|
|
<span>Token entered</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<details style="margin-bottom:8px">
|
|
|
|
|
<summary class="text-xs text-dim" style="cursor:pointer;user-select:none">Or set as environment variable</summary>
|
|
|
|
@@ -2838,13 +2850,17 @@ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path"]</pre>
|
|
|
|
|
</template>
|
|
|
|
|
<template x-if="installProgress.status === 'done' && !installProgress.error">
|
|
|
|
|
<div class="flex items-center gap-2">
|
|
|
|
|
<span style="color:var(--green);font-size:16px">✓</span>
|
|
|
|
|
<span style="color:var(--green);display:flex">
|
|
|
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
|
|
|
|
</span>
|
|
|
|
|
<span class="text-sm font-bold" style="color:var(--green)">Installation complete!</span>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
<template x-if="installProgress.error">
|
|
|
|
|
<div class="flex items-center gap-2">
|
|
|
|
|
<span style="color:var(--red);font-size:16px">✗</span>
|
|
|
|
|
<span style="color:var(--red);display:flex">
|
|
|
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
|
|
|
|
</span>
|
|
|
|
|
<span class="text-sm" style="color:var(--red)" x-text="installProgress.error"></span>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
@@ -3059,7 +3075,9 @@ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path"]</pre>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex items-center gap-2">
|
|
|
|
|
<button class="btn btn-ghost btn-sm" @click="refreshDashboard()">Refresh</button>
|
|
|
|
|
<button class="modal-close" @click="closeDashboard()">×</button>
|
|
|
|
|
<button class="modal-close" @click="closeDashboard()">
|
|
|
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
@@ -3610,12 +3628,12 @@ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path"]</pre>
|
|
|
|
|
<div class="card mt-4" style="border-left:3px solid var(--accent)">
|
|
|
|
|
<div class="font-bold" style="font-size:13px;margin-bottom:6px">Security Dependencies</div>
|
|
|
|
|
<div class="text-xs text-dim" style="line-height:1.8">
|
|
|
|
|
<code style="color:var(--accent-light)">sha2</code> SHA-256 ·
|
|
|
|
|
<code style="color:var(--accent-light)">hmac</code> HMAC-SHA256 ·
|
|
|
|
|
<code style="color:var(--accent-light)">subtle</code> constant-time ·
|
|
|
|
|
<code style="color:var(--accent-light)">ed25519-dalek</code> signing ·
|
|
|
|
|
<code style="color:var(--accent-light)">zeroize</code> secret wiping ·
|
|
|
|
|
<code style="color:var(--accent-light)">rand</code> randomness ·
|
|
|
|
|
<code style="color:var(--accent-light)">sha2</code> SHA-256 <svg width="3" height="3" viewBox="0 0 24 24" fill="currentColor" style="display:inline-block;vertical-align:middle;opacity:0.4"><circle cx="12" cy="12" r="10"/></svg>
|
|
|
|
|
<code style="color:var(--accent-light)">hmac</code> HMAC-SHA256 <svg width="3" height="3" viewBox="0 0 24 24" fill="currentColor" style="display:inline-block;vertical-align:middle;opacity:0.4"><circle cx="12" cy="12" r="10"/></svg>
|
|
|
|
|
<code style="color:var(--accent-light)">subtle</code> constant-time <svg width="3" height="3" viewBox="0 0 24 24" fill="currentColor" style="display:inline-block;vertical-align:middle;opacity:0.4"><circle cx="12" cy="12" r="10"/></svg>
|
|
|
|
|
<code style="color:var(--accent-light)">ed25519-dalek</code> signing <svg width="3" height="3" viewBox="0 0 24 24" fill="currentColor" style="display:inline-block;vertical-align:middle;opacity:0.4"><circle cx="12" cy="12" r="10"/></svg>
|
|
|
|
|
<code style="color:var(--accent-light)">zeroize</code> secret wiping <svg width="3" height="3" viewBox="0 0 24 24" fill="currentColor" style="display:inline-block;vertical-align:middle;opacity:0.4"><circle cx="12" cy="12" r="10"/></svg>
|
|
|
|
|
<code style="color:var(--accent-light)">rand</code> randomness <svg width="3" height="3" viewBox="0 0 24 24" fill="currentColor" style="display:inline-block;vertical-align:middle;opacity:0.4"><circle cx="12" cy="12" r="10"/></svg>
|
|
|
|
|
<code style="color:var(--accent-light)">governor</code> rate limiting
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
@@ -3642,7 +3660,7 @@ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path"]</pre>
|
|
|
|
|
<span class="badge" :class="netStatus && netStatus.enabled ? 'badge-success' : 'badge-muted'" x-text="netStatus && netStatus.enabled ? 'Enabled' : 'Disabled'" style="font-size:12px;padding:4px 10px"></span>
|
|
|
|
|
</div>
|
|
|
|
|
<div x-show="netStatus && netStatus.enabled" class="text-xs text-dim mb-2" style="margin-top:-8px">
|
|
|
|
|
Node: <span x-text="netStatus?.node_id?.substring(0,8) + '...'" class="font-bold"></span> •
|
|
|
|
|
Node: <span x-text="netStatus?.node_id?.substring(0,8) + '...'" class="font-bold"></span> <svg width="4" height="4" viewBox="0 0 24 24" fill="currentColor" style="display:inline-block;vertical-align:middle;opacity:0.5"><circle cx="12" cy="12" r="10"/></svg>
|
|
|
|
|
Listening on <span x-text="netStatus?.listen_address" class="font-bold"></span>
|
|
|
|
|
</div>
|
|
|
|
|
<div x-show="peersLoading" class="loading-state"><div class="spinner"></div><span>Loading peers...</span></div>
|
|
|
|
@@ -4259,7 +4277,7 @@ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path"]</pre>
|
|
|
|
|
<template x-if="showAdd">
|
|
|
|
|
<div class="modal-overlay" @click.self="showAdd = false" @keydown.escape.window="showAdd = false">
|
|
|
|
|
<div class="modal">
|
|
|
|
|
<div class="modal-header"><h3>Add Key</h3><button class="modal-close" @click="showAdd = false">×</button></div>
|
|
|
|
|
<div class="modal-header"><h3>Add Key</h3><button class="modal-close" @click="showAdd = false"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button></div>
|
|
|
|
|
<div class="form-group"><label>Key</label><input class="form-input" x-model="newKey" placeholder="my_key"></div>
|
|
|
|
|
<div class="form-group"><label>Value (JSON)</label><textarea class="form-textarea" x-model="newValue" placeholder='"hello"'></textarea></div>
|
|
|
|
|
<button class="btn btn-primary btn-block" @click="addKey()">Save</button>
|
|
|
|
@@ -4586,7 +4604,9 @@ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path"]</pre>
|
|
|
|
|
<div class="wizard-progress-step" :class="{ 'wiz-active': step === n, 'wiz-done': step > n }" @click="goToStep(n)">
|
|
|
|
|
<div class="wizard-progress-circle">
|
|
|
|
|
<span x-show="step <= n" x-text="n"></span>
|
|
|
|
|
<span x-show="step > n">✓</span>
|
|
|
|
|
<span x-show="step > n">
|
|
|
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" style="display:block"><polyline points="20 6 9 17 4 12"/></svg>
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<span class="wizard-progress-label" x-text="stepLabel(n)"></span>
|
|
|
|
|
</div>
|
|
|
|
@@ -4727,7 +4747,9 @@ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path"]</pre>
|
|
|
|
|
<template x-if="selectedProviderObj && providerIsConfigured(selectedProviderObj)">
|
|
|
|
|
<div class="card" style="border-left:3px solid var(--success);margin-top:16px">
|
|
|
|
|
<div class="flex items-center gap-2">
|
|
|
|
|
<span style="color:var(--success);font-size:18px">✓</span>
|
|
|
|
|
<div style="color:var(--success);display:flex;align-items:center;justify-content:center;width:24px;height:24px">
|
|
|
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<div class="font-bold" style="font-size:13px" x-text="selectedProviderObj.display_name + ' is configured and ready'"></div>
|
|
|
|
|
<div class="text-xs text-dim">You can test the connection or continue to the next step.</div>
|
|
|
|
@@ -4896,7 +4918,9 @@ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path"]</pre>
|
|
|
|
|
<!-- Step 6: Done -->
|
|
|
|
|
<div class="wizard-step" x-show="step === 6">
|
|
|
|
|
<div class="wizard-card" style="text-align:center;max-width:560px;margin:0 auto">
|
|
|
|
|
<div style="font-size:56px;margin-bottom:12px;color:var(--success)">✓</div>
|
|
|
|
|
<div style="margin-bottom:12px;color:var(--success);display:flex;justify-content:center">
|
|
|
|
|
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
|
|
|
|
</div>
|
|
|
|
|
<h3 style="font-size:20px;font-weight:700;margin-bottom:8px;color:var(--accent)">You're All Set!</h3>
|
|
|
|
|
<p style="font-size:13px;color:var(--text-dim);line-height:1.8;margin-bottom:24px">OpenFang is configured and ready to go. Here is a summary of what was set up:</p>
|
|
|
|
|
|
|
|
|
|