<script type="module">import e from"./parts/function-detail.ok.js";import t from"./parts/function-logs.ok.js";import n from"./parts/function-runner.ok.js";import o from"./modals/function-modal.ok.js";import s from"./parts/functions-list.ok.js";export default{tag:"functions-index",unwrap:!0,dependencies:[s,e,n,t,o],context:e=>({get functions(){return e.$ok.stores.functions},get isGlobal(){return this.functions.isGlobalScope},get envName(){return this.functions.envName},get canManage(){return this.functions.canOpenModal},get isDetailView(){return"detail"===this.functions.currentView&&this.functions.hasSelected},get isOverviewView(){return!this.isDetailView},get selectedName(){return this.functions.selectedName},get totalFunctions(){return this.functions.functionsOverview.length},get enabledCount(){return this.functions.functionsOverview.filter(e=>!1!==e.value?.enabled).length},get disabledCount(){return this.functions.functionsOverview.filter(e=>!1===e.value?.enabled).length},get neverRunCount(){return this.functions.functionsOverview.filter(e=>!e.latestRun).length},get recentSuccessCount(){return this.functions.overviewRuns.filter(e=>"success"===e.value?.status).length},get recentErrorCount(){return this.functions.overviewRuns.filter(e=>["error","timeout","killed"].includes(e.value?.status)).length},fmt:e=>Number(e||0).toLocaleString(),relTime(e){if(!e)return"—";const t=Date.now()-e;return t<5e3?"just now":t<6e4?`${Math.round(t/1e3)}s ago`:t<36e5?`${Math.round(t/6e4)}m ago`:t<864e5?`${Math.round(t/36e5)}h ago`:new Date(e).toLocaleDateString()},latestLogLine(e){const t=e?.latestRun?.id||e?.latestRun?.runId;if(!t)return null;const n=this.functions.logsForRun(t);return n.length?n[n.length-1]?.msg:null},getRouteFunctionName(){try{const e=globalThis.location?.hash||"",t=e.includes("?")?e.split("?")[1]:"";return new URLSearchParams(t).get("name")}catch{return null}},goOverview(){const t=e.$ok.stores.functions;t.setView("overview"),t.select(null),e.$vars.$router?.push?.("/functions")},async openFunction(t){t&&(await e.$ok.stores.functions.select(t),e.$vars.$router?.push?.("/functions?name="+encodeURIComponent(t)))},async openCreateModal(){const t=e.$ok.stores.functions;t.canOpenModal&&(t.beginCreateDraft(),await e.$ok.shared.modal.open({owner:e,title:"Create Function",canDrag:!0,content:'<function-modal :modal="modal" mode="create" :on-done="onDone" />',context:n=>({modal:n,onDone:async n=>{await t.hydrateOverview(),n?.name&&await e.openFunction(n.name)}})}))},async openEditModal(){const t=e.$ok.stores.functions;t.hasSelected&&(t.beginEditDraft(),await e.$ok.shared.modal.open({owner:e,title:`Edit Function · ${t.selectedName}`,canDrag:!0,content:'<function-modal :modal="modal" mode="edit" :on-done="onDone" />',context:e=>({modal:e,onDone:async()=>{await t.select(t.selectedName),await t.loadOverviewRuns()}})}))}}),init(e){const t=async()=>{const t=this.getRouteFunctionName();t?await e.$ok.stores.functions.select(t):e.$ok.stores.functions.setView("overview")};e.$watch(()=>e.$ok.stores.okdb.selectedEnv,()=>e.$ok.stores.functions.onEnvChanged()),e.$watch(()=>globalThis.location?.hash,()=>t()),this.functions.onEnvChanged(),t()}};</script><template><component import="../../layouts/_default.ok.html"><template name="header"><div style="display:flex;align-items:center;justify-content:space-between;gap:16px;width:100%"><div><div style="font-size:22px;font-weight:700;color:var(--okdb-app-fg)">Functions</div><div style="margin-top:4px;font-size:12px;color:var(--okdb-app-fg-muted)"><if :="envName">{{ envName }}</if><if :="!envName">No environment selected</if></div><if :="isDetailView"><div style="margin-top:8px;font-size:13px;color:#a7c0d1">Viewing <strong>{{ selectedName }}</strong></div></if></div><div style="font-size:11px;color:var(--okdb-app-fg-muted);text-transform:uppercase;letter-spacing:.08em"><div>{{ envName || '—' }}</div></div></div></template><template name="sidebar"><functions-list @create="openCreateModal()" @overview="goOverview()" @open="openFunction($event.detail)"></functions-list></template><template name="default"><if :="isOverviewView"><div style="display:flex;flex-direction:column;gap:20px;max-width:980px"><div style="display:flex;align-items:center;gap:10px"><div style="font-weight:600;font-size:18px">Functions Overview</div><div style="margin-left:auto"><button @click="openCreateModal()" :disabled="!canManage" style="font-size:12px;padding:5px 12px;opacity:.85">+ New function</button></div></div><div class="fn-ov-stat-row"><div class="fn-ov-stat-card"><div class="fn-ov-stat-label">Functions</div><div class="fn-ov-stat-value" style="color:var(--okdb-accent)">{{ fmt(totalFunctions) }}</div></div><div class="fn-ov-stat-card"><div class="fn-ov-stat-label">Enabled</div><div class="fn-ov-stat-value" style="color:#4ade80">{{ fmt(enabledCount) }}</div></div><div class="fn-ov-stat-card"><div class="fn-ov-stat-label">Recent Success</div><div class="fn-ov-stat-value" style="color:var(--okdb-success)">{{ fmt(recentSuccessCount) }}</div></div><div class="fn-ov-stat-card"><div class="fn-ov-stat-label">Recent Failures</div><div class="fn-ov-stat-value" style="color:var(--okdb-danger)">{{ fmt(recentErrorCount) }}</div></div></div><if :="functions.functionsOverview.length === 0"><div class="fn-ov-empty"><div style="font-size:30px;margin-bottom:12px">ƒ</div><div style="font-weight:600;font-size:15px;margin-bottom:5px">No functions registered yet</div><div style="font-size:13px;opacity:.6;line-height:1.7">Create your first function from the sidebar and use the draft runner to validate it before saving.</div></div></if><if :="functions.functionsOverview.length > 0"><div class="fn-ov-card"><div class="fn-ov-card-head"><span style="font-weight:600;font-size:14px">Functions</span> <span style="font-size:12px;opacity:.45;margin-left:auto">{{ totalFunctions }} total · {{ neverRunCount }} never run</span></div><table class="fn-ov-table"><thead><tr><th>Name</th><th>Status</th><th style="text-align:right">Runs</th><th style="text-align:right">Latest</th><th></th></tr></thead><tbody><tr as="repeat" :of="functions.functionsOverview" let:item="fn" class="fn-ov-row" @click="openFunction(fn.key)"><td><div style="display:flex;flex-direction:column;gap:4px"><span style="font-family:monospace;font-size:13px;color:var(--okdb-app-fg)">{{ fn.key }}</span> <span style="font-size:11px;color:var(--okdb-app-fg-muted);max-width:360px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{{ fn.value?.metadata?.description || 'No description yet.' }}</span><if :="latestLogLine(fn)"><span style="font-size:11px;color:#8db1c8;max-width:360px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">log: {{ latestLogLine(fn) }}</span></if></div></td><td><span :style="fn.value?.enabled === false ? 'font-size:10px; color:var(--okdb-danger); text-transform:uppercase;' : 'font-size:10px; color:var(--okdb-success); text-transform:uppercase;'">{{ fn.value?.enabled === false ? 'disabled' : (fn.latestRun?.status || 'ready') }}</span></td><td style="text-align:right;color:var(--okdb-accent);font-weight:600">{{ fmt(functions.overviewRuns.filter(row => row.value?.functionName === fn.key).length) }}</td><td style="text-align:right;opacity:.55;font-size:12px">{{ relTime(fn.latestRun?.execution?.finishedAt ?? fn.latestRun?.request?.requestedAt) }}</td><td style="text-align:right;opacity:.3;font-size:11px;padding-right:16px">→</td></tr></tbody></table></div><div class="fn-ov-card"><div class="fn-ov-card-head"><span style="font-weight:600;font-size:14px">Recent Executions</span> <span style="font-size:12px;opacity:.4;margin-left:auto">last {{ functions.overviewRuns.length }}</span></div><table style="width:100%;border-collapse:collapse;font-size:12px"><tbody><tr as="repeat" :of="functions.overviewRuns" let:item="row" class="fn-ov-row fn-ov-row--sm" @click="openFunction(row.value?.functionName)"><td class="fn-ov-td" style="font-family:monospace;font-size:11px;color:var(--okdb-app-fg);padding-left:16px">{{ row.value?.functionName || row.key }}</td><td class="fn-ov-td"><span :style="row.value?.status === 'success' ? 'font-size:10px; color:var(--okdb-success);' : 'font-size:10px; color:var(--okdb-danger);'">{{ row.value?.status || '—' }}</span></td><td class="fn-ov-td" style="font-family:monospace;font-size:11px;opacity:.45;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{{ row.value?.id || row.key }}</td><td class="fn-ov-td" style="text-align:right;opacity:.35;white-space:nowrap;font-size:11px;padding-right:16px">{{ relTime(row.value?.execution?.finishedAt ?? row.value?.request?.requestedAt) }}</td></tr></tbody></table></div><function-logs title="Live function logs" empty="Run a function to see logs here."></function-logs></if></div></if><if :="isDetailView"><div style="display:grid;grid-template-columns:minmax(0,1.45fr) minmax(360px,.95fr);gap:16px;height:100%;min-height:0"><div style="display:grid;grid-template-rows:minmax(0,1fr) minmax(260px,.85fr);gap:16px;min-height:0"><div style="min-height:0;overflow:auto"><function-detail :on-edit="openEditModal"></function-detail></div><div style="min-height:0;overflow:auto"><function-logs :run-id="functions.selectedRun?.id || functions.selectedRun?.runId" :entries="functions.selectedLogEntries" title="Selected function live logs" empty="No logs captured for the selected run yet."></function-logs></div></div><div style="min-height:0;overflow:auto"><function-runner></function-runner></div></div></if></template></component></template><style>.fn-ov-stat-row{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}.fn-ov-card,.fn-ov-stat-card{border:1px solid var(--okdb-app-border);border-radius:12px;background:var(--okdb-app-bg-deep)}.fn-ov-stat-card{padding:14px}.fn-ov-stat-label{font-size:11px;text-transform:uppercase;color:var(--okdb-app-fg-muted);margin-bottom:6px}.fn-ov-stat-value{font-size:24px;font-weight:700;color:var(--okdb-app-fg)}.fn-ov-empty{border:1px dashed var(--okdb-app-border);border-radius:12px;padding:24px;text-align:center;color:var(--okdb-app-fg-muted);background:var(--okdb-app-bg-deep)}.fn-ov-card-head{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--okdb-app-border)}.fn-ov-table{width:100%;border-collapse:collapse;font-size:12px}.fn-ov-table thead th{text-align:left;padding:10px 16px;color:var(--okdb-app-fg-muted);font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;border-bottom:1px solid var(--okdb-app-border)}.fn-ov-row{cursor:pointer}.fn-ov-row:hover{background:var(--okdb-app-bg-deep)}.fn-ov-row td,.fn-ov-td{padding:12px 16px;border-bottom:1px solid var(--okdb-app-border)}.fn-ov-row--sm .fn-ov-td,.fn-ov-row--sm td{padding-top:10px;padding-bottom:10px}</style>