fix(plugins): JSON-serialize CallFunctionJSON return values + backward compat Lua args

Root cause: CallFunctionJSON used .String() on Lua return values, which
for tables produces 'table: 0x...' — not valid JSON. Frontend does
JSON.parse() on the result and silently caught the parse error.

Fix:
- runtime.go: convert Lua return value to JSON via luaValueToGo +
  json.Marshal so tables become proper JSON arrays/objects
- main.lua: add backward compat in get_events() and update_event()
  to accept both positional args (start, end) and table params
- CalendarPluginPage.svelte: show errors in UI instead of silent catch;
  restructure template to always show iframe + error overlay
This commit is contained in:
2026-06-08 11:31:18 +08:00
parent fddbd3a98a
commit f769daa617
9 changed files with 61 additions and 25 deletions
+27 -11
View File
@@ -107,6 +107,7 @@
})
} catch (e) {
console.error('[CalendarPluginPage] loadCalendarData:', e)
error = String(e)
}
}
@@ -206,21 +207,24 @@
<div class="plugin-page">
{#if loading}
<p class="loading">Загрузка…</p>
{:else if error}
<p class="error">{error}</p>
{:else if htmlPanel}
<iframe
bind:this={iframeEl}
class="plugin-frame"
srcdoc={htmlPanel}
sandbox="allow-scripts allow-same-origin"
title="{pluginName} panel"
></iframe>
{:else}
{:else if !htmlPanel}
<div class="empty-state">
<p>Плагин «{pluginName}» активен, но HTML-панель не настроена.</p>
<p class="hint">Для отображения контента добавьте поле <code>panel</code> в <code>plugin.json</code>.</p>
</div>
{:else}
<div class="plugin-frame-container">
{#if error}
<div class="plugin-error-bar">{error}</div>
{/if}
<iframe
bind:this={iframeEl}
class="plugin-frame"
srcdoc={htmlPanel}
sandbox="allow-scripts allow-same-origin"
title="{pluginName} panel"
></iframe>
</div>
{/if}
</div>
@@ -232,5 +236,17 @@
.error { color: #f87171; }
.empty-state { text-align: center; padding: 3rem 1rem; color: var(--text-dim, #888); }
.empty-state code { background: var(--surface-alt, #252538); padding: 0.15rem 0.4rem; border-radius: 3px; font-size: 0.85rem; }
.plugin-frame-container { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.plugin-error-bar {
padding: 0.5rem 1rem;
background: rgba(248, 113, 113, 0.12);
border: 1px solid #f87171;
border-bottom: none;
border-radius: 8px 8px 0 0;
color: #f87171;
font-size: 0.85rem;
flex-shrink: 0;
}
.plugin-frame { flex: 1; border: 1px solid var(--border, #2a2a3e); border-radius: 8px; background: #fff; width: 100%; min-height: 400px; display: block; }
.plugin-frame-container .plugin-frame { border-radius: 0 0 8px 8px; border-top: none; }
</style>