Skip to main content
Glama
SecretList.svelte5.56 kB
<script lang="ts"> import { listSecrets, deleteSecret, type SecretInfo } from "./api"; interface Props { onAdd: () => void; onEdit: (id: string) => void; } let { onAdd, onEdit }: Props = $props(); let secrets = $state<SecretInfo[]>([]); let searchQuery = $state(""); let loading = $state(true); let error = $state(""); let filteredSecrets = $derived( secrets.filter( (s) => s.name.toLowerCase().includes(searchQuery.toLowerCase()) || (s.description || "").toLowerCase().includes(searchQuery.toLowerCase()) ) ); $effect(() => { loadSecrets(); }); export async function loadSecrets() { loading = true; error = ""; try { secrets = await listSecrets(); } catch (e) { error = String(e); } finally { loading = false; } } async function handleDelete(id: string, name: string) { if (!confirm(`Delete secret "${name}"?`)) return; try { await deleteSecret(id); await loadSecrets(); } catch (e) { error = String(e); } } function formatDate(timestamp: number): string { return new Date(timestamp * 1000).toLocaleDateString(); } </script> <div class="container"> <div class="header"> <h1>Secrets</h1> <button class="add-btn" onclick={onAdd}>+ Add Secret</button> </div> <div class="search-bar"> <input type="text" placeholder="Search secrets..." bind:value={searchQuery} /> </div> {#if error} <div class="error">{error}</div> {/if} {#if loading} <div class="loading">Loading...</div> {:else if filteredSecrets.length === 0} <div class="empty"> {#if searchQuery} No secrets match your search. {:else} No secrets yet. Click "Add Secret" to create one. {/if} </div> {:else} <div class="table-container"> <table> <thead> <tr> <th>Name</th> <th>Description</th> <th>Value</th> <th>Updated</th> <th>Actions</th> </tr> </thead> <tbody> {#each filteredSecrets as secret (secret.id)} <tr> <td class="name">{secret.name}</td> <td class="description">{secret.description || "-"}</td> <td class="value">••••••••</td> <td class="date">{formatDate(secret.updated_at)}</td> <td class="actions"> <button onclick={() => onEdit(secret.id)}>Edit</button> <button class="delete" onclick={() => handleDelete(secret.id, secret.name)} > Delete </button> </td> </tr> {/each} </tbody> </table> </div> {/if} </div> <style> .container { padding: 16px; max-width: 100%; overflow: hidden; } .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; } h1 { margin: 0; font-size: 1.5rem; } .add-btn { background: #4a90d9; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer; font-size: 0.875rem; } .add-btn:hover { background: #3a80c9; } .search-bar { margin-bottom: 16px; } .search-bar input { width: 100%; padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 1rem; box-sizing: border-box; } .error { background: #fee; color: #c00; padding: 8px 12px; border-radius: 4px; margin-bottom: 16px; } .loading, .empty { text-align: center; padding: 40px 20px; color: #666; } .table-container { overflow-x: auto; } table { width: 100%; border-collapse: collapse; font-size: 0.875rem; } th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid #eee; } th { background: #f5f5f5; font-weight: 600; white-space: nowrap; } .name { font-family: monospace; font-weight: 500; } .description { color: #666; max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .value { font-family: monospace; color: #999; } .date { white-space: nowrap; color: #666; } .actions { white-space: nowrap; } .actions button { padding: 4px 8px; margin-right: 4px; border: 1px solid #ccc; border-radius: 4px; background: #fff; cursor: pointer; font-size: 0.75rem; } .actions button:hover { background: #f0f0f0; } .actions button.delete { color: #c00; border-color: #c00; } .actions button.delete:hover { background: #fee; } @media (prefers-color-scheme: dark) { .search-bar input { background: #1a1a1a; border-color: #444; color: #f0f0f0; } th { background: #333; } th, td { border-color: #444; } .description, .date { color: #999; } .error { background: #4a1a1a; color: #faa; } .loading, .empty { color: #888; } .actions button { background: #2a2a2a; border-color: #555; color: #f0f0f0; } .actions button:hover { background: #3a3a3a; } .actions button.delete { color: #f88; border-color: #f88; } .actions button.delete:hover { background: #4a2a2a; } } </style>

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/AKarenin/Secret-mcp'

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