clay-server 2.33.1 → 2.34.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1884,6 +1884,11 @@ body.mate-dm-active #layout.sidebar-collapsed .mate-collapsed-info {
1884
1884
  height: 16px;
1885
1885
  }
1886
1886
 
1887
+ .mate-sidebar-actions button.active {
1888
+ background: var(--bg-hover, rgba(255,255,255,0.1));
1889
+ color: var(--text-primary, #fff);
1890
+ }
1891
+
1887
1892
  .mate-session-list {
1888
1893
  flex: 1;
1889
1894
  overflow-y: auto;
@@ -1990,6 +1995,176 @@ body.mate-dm-active #layout.sidebar-collapsed .mate-collapsed-info {
1990
1995
  #mate-search-session-btn.active {
1991
1996
  color: var(--accent);
1992
1997
  }
1998
+
1999
+ /* Mate datastore inspector */
2000
+ #mate-sidebar-datastore {
2001
+ display: flex;
2002
+ flex-direction: column;
2003
+ flex: 1;
2004
+ min-height: 0;
2005
+ }
2006
+
2007
+ #mate-sidebar-datastore.hidden {
2008
+ display: none !important;
2009
+ }
2010
+
2011
+ .mate-db-status {
2012
+ padding: 8px 12px 0;
2013
+ font-size: 12px;
2014
+ color: var(--text-secondary, #8e8e8e);
2015
+ }
2016
+
2017
+ .mate-db-status[data-kind="error"] {
2018
+ color: var(--error, #ff6b6b);
2019
+ }
2020
+
2021
+ .mate-db-status[data-kind="warn"] {
2022
+ color: var(--warning, #f5a524);
2023
+ }
2024
+
2025
+ .mate-db-status[data-kind="ok"] {
2026
+ color: var(--success, #36b37e);
2027
+ }
2028
+
2029
+ .mate-db-layout {
2030
+ display: grid;
2031
+ grid-template-columns: 130px minmax(0, 1fr);
2032
+ gap: 10px;
2033
+ padding: 8px 8px 12px;
2034
+ min-height: 0;
2035
+ flex: 1;
2036
+ }
2037
+
2038
+ .mate-db-table-column,
2039
+ .mate-db-detail {
2040
+ min-height: 0;
2041
+ display: flex;
2042
+ flex-direction: column;
2043
+ }
2044
+
2045
+ .mate-db-table-list {
2046
+ overflow-y: auto;
2047
+ border: 1px solid var(--border-subtle, rgba(255,255,255,0.08));
2048
+ border-radius: 10px;
2049
+ background: var(--bg-alt, rgba(255,255,255,0.03));
2050
+ padding: 4px;
2051
+ flex: 1;
2052
+ }
2053
+
2054
+ .mate-db-table-item {
2055
+ width: 100%;
2056
+ display: flex;
2057
+ justify-content: space-between;
2058
+ gap: 6px;
2059
+ padding: 8px 10px;
2060
+ border: none;
2061
+ background: transparent;
2062
+ color: var(--text-secondary, #aaa);
2063
+ border-radius: 8px;
2064
+ text-align: left;
2065
+ cursor: pointer;
2066
+ }
2067
+
2068
+ .mate-db-table-item:hover,
2069
+ .mate-db-table-item.active {
2070
+ background: var(--sidebar-active, rgba(255,255,255,0.08));
2071
+ color: var(--text, #fff);
2072
+ }
2073
+
2074
+ .mate-db-table-item-name {
2075
+ overflow: hidden;
2076
+ text-overflow: ellipsis;
2077
+ white-space: nowrap;
2078
+ min-width: 0;
2079
+ }
2080
+
2081
+ .mate-db-table-item-type {
2082
+ font-size: 10px;
2083
+ text-transform: uppercase;
2084
+ letter-spacing: 0.05em;
2085
+ opacity: 0.7;
2086
+ flex-shrink: 0;
2087
+ }
2088
+
2089
+ .mate-db-empty {
2090
+ padding: 16px 10px;
2091
+ color: var(--text-secondary, #8e8e8e);
2092
+ font-size: 12px;
2093
+ }
2094
+
2095
+ .mate-db-section-title {
2096
+ font-size: 11px;
2097
+ font-weight: 700;
2098
+ text-transform: uppercase;
2099
+ letter-spacing: 0.08em;
2100
+ color: var(--text-muted, #9aa0a6);
2101
+ margin: 0 0 6px;
2102
+ }
2103
+
2104
+ .mate-db-detail {
2105
+ gap: 8px;
2106
+ min-width: 0;
2107
+ }
2108
+
2109
+ .mate-db-table-schema,
2110
+ .mate-db-result {
2111
+ margin: 0;
2112
+ padding: 10px;
2113
+ border-radius: 10px;
2114
+ border: 1px solid var(--border-subtle, rgba(255,255,255,0.08));
2115
+ background: var(--bg-alt, rgba(255,255,255,0.03));
2116
+ color: var(--text-secondary, #b8b8b8);
2117
+ font-size: 11px;
2118
+ line-height: 1.5;
2119
+ overflow: auto;
2120
+ white-space: pre-wrap;
2121
+ word-break: break-word;
2122
+ min-height: 0;
2123
+ }
2124
+
2125
+ .mate-db-table-schema {
2126
+ max-height: 120px;
2127
+ }
2128
+
2129
+ .mate-db-query,
2130
+ .mate-db-params {
2131
+ width: 100%;
2132
+ min-height: 72px;
2133
+ padding: 10px;
2134
+ border-radius: 10px;
2135
+ border: 1px solid var(--border-subtle, rgba(255,255,255,0.1));
2136
+ background: var(--bg-secondary, rgba(255,255,255,0.04));
2137
+ color: var(--text, #fff);
2138
+ font-family: var(--mono-font, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
2139
+ font-size: 11px;
2140
+ resize: vertical;
2141
+ }
2142
+
2143
+ .mate-db-params {
2144
+ min-height: 54px;
2145
+ }
2146
+
2147
+ .mate-db-actions {
2148
+ display: flex;
2149
+ gap: 8px;
2150
+ }
2151
+
2152
+ .mate-db-actions button {
2153
+ flex: 1;
2154
+ height: 30px;
2155
+ border: none;
2156
+ border-radius: 8px;
2157
+ background: var(--sidebar-active, rgba(255,255,255,0.08));
2158
+ color: var(--text, #fff);
2159
+ font-size: 12px;
2160
+ font-weight: 600;
2161
+ cursor: pointer;
2162
+ }
2163
+
2164
+ .mate-db-actions button:hover {
2165
+ background: var(--sidebar-hover, rgba(255,255,255,0.12));
2166
+ }
2167
+
1993
2168
  .mate-session-item.search-match {
1994
2169
  background: var(--accent-12, rgba(108, 92, 231, 0.12));
1995
2170
  }
@@ -1233,6 +1233,29 @@ pre.mermaid-error {
1233
1233
  .plan-card-body strong { font-weight: 600; }
1234
1234
  .plan-card-body blockquote { border-left: 3px solid var(--border); padding-left: 12px; color: var(--text-muted); margin: 8px 0; }
1235
1235
 
1236
+ .todo-widget.todo-widget-plan .todo-header {
1237
+ background: linear-gradient(180deg, rgba(var(--overlay-rgb), 0.04), rgba(var(--overlay-rgb), 0.015));
1238
+ }
1239
+
1240
+ .todo-widget.todo-widget-plan .todo-header-icon,
1241
+ .todo-widget.todo-widget-plan .todo-header-title {
1242
+ color: var(--accent);
1243
+ }
1244
+
1245
+ .todo-widget.todo-widget-plan .todo-header-count {
1246
+ color: var(--text-muted);
1247
+ font-weight: 500;
1248
+ }
1249
+
1250
+ .todo-widget.todo-widget-plan .todo-item.pending .todo-item-icon {
1251
+ opacity: 0.75;
1252
+ }
1253
+
1254
+ .todo-widget.todo-widget-plan .todo-item.in-progress .todo-item-text {
1255
+ color: var(--text);
1256
+ font-weight: 500;
1257
+ }
1258
+
1236
1259
  /* --- Plan permission (ExitPlanMode) --- */
1237
1260
  .plan-permission-header {
1238
1261
  background: var(--success-8) !important;
@@ -307,6 +307,82 @@
307
307
  .notif-banner-update-now:hover { opacity: 0.85; }
308
308
  .notif-banner-update-now:disabled { opacity: 0.6; cursor: default; }
309
309
 
310
+ .light-theme .notif-banner-clear-all {
311
+ background:
312
+ linear-gradient(180deg, rgba(255,255,255,0.88), rgba(255,255,255,0.72)),
313
+ rgba(255,255,255,0.62);
314
+ border-color: rgba(24, 32, 56, 0.10);
315
+ color: rgba(36, 45, 66, 0.72);
316
+ box-shadow:
317
+ inset 0 1px 0 rgba(255,255,255,0.85),
318
+ 0 8px 22px rgba(31, 41, 55, 0.08);
319
+ }
320
+
321
+ .light-theme .notif-banner-clear-all:hover {
322
+ color: rgba(22, 29, 45, 0.92);
323
+ background:
324
+ linear-gradient(180deg, rgba(255,255,255,0.94), rgba(255,255,255,0.78)),
325
+ rgba(255,255,255,0.7);
326
+ border-color: rgba(24, 32, 56, 0.14);
327
+ }
328
+
329
+ .light-theme .notif-banner {
330
+ background:
331
+ linear-gradient(180deg, rgba(255,255,255,0.92), rgba(255,255,255,0.74)),
332
+ rgba(255,255,255,0.60);
333
+ border-color: rgba(27, 35, 56, 0.08);
334
+ box-shadow:
335
+ inset 0 1px 0 rgba(255,255,255,0.88),
336
+ 0 10px 30px rgba(31, 41, 55, 0.10);
337
+ }
338
+
339
+ .light-theme .notif-banner:hover {
340
+ border-color: rgba(27, 35, 56, 0.12);
341
+ box-shadow:
342
+ inset 0 1px 0 rgba(255,255,255,0.92),
343
+ 0 12px 34px rgba(31, 41, 55, 0.12);
344
+ }
345
+
346
+ .light-theme .notif-banner-icon {
347
+ background: linear-gradient(180deg, rgba(255,255,255,0.92), rgba(244,247,252,0.82));
348
+ border-color: rgba(27, 35, 56, 0.08);
349
+ color: var(--text-secondary);
350
+ box-shadow: inset 0 1px 0 rgba(255,255,255,0.92);
351
+ }
352
+
353
+ .light-theme .notif-banner-project {
354
+ color: rgba(50, 62, 86, 0.74);
355
+ text-shadow: 0 1px 0 rgba(255,255,255,0.72);
356
+ }
357
+
358
+ .light-theme .notif-banner-title {
359
+ color: rgba(18, 24, 38, 0.95);
360
+ text-shadow: 0 1px 0 rgba(255,255,255,0.72);
361
+ }
362
+
363
+ .light-theme .notif-banner-text {
364
+ color: rgba(61, 73, 96, 0.76);
365
+ }
366
+
367
+ .light-theme .notif-banner-update .notif-banner-project,
368
+ .light-theme .notif-banner-auth .notif-banner-project {
369
+ color: rgba(50, 62, 86, 0.74);
370
+ }
371
+
372
+ .light-theme .notif-banner-auth .notif-banner-title,
373
+ .light-theme .notif-banner-update .notif-banner-title {
374
+ text-shadow: 0 1px 0 rgba(255,255,255,0.76);
375
+ }
376
+
377
+ .light-theme .notif-banner-close,
378
+ .light-theme .notif-banner-close:hover {
379
+ background: rgba(244, 246, 250, 0.98);
380
+ color: rgba(44, 52, 68, 0.88);
381
+ box-shadow:
382
+ 0 2px 6px rgba(31, 41, 55, 0.12),
383
+ inset 0 1px 0 rgba(255,255,255,0.88);
384
+ }
385
+
310
386
  /* ========================================================
311
387
  Mobile
312
388
  ======================================================== */
@@ -270,6 +270,7 @@
270
270
  <div class="mate-sidebar-sessions-header">
271
271
  <span>Conversations</span>
272
272
  <div class="mate-sidebar-actions">
273
+ <button id="mate-data-btn" type="button" title="Data inspector"><i data-lucide="database"></i></button>
273
274
  <button id="mate-search-session-btn" type="button" title="Search sessions"><i data-lucide="search"></i></button>
274
275
  <button id="mate-new-session-btn" type="button" title="New session"><i data-lucide="plus"></i></button>
275
276
  </div>
@@ -280,6 +281,33 @@
280
281
  </div>
281
282
  <div id="mate-session-list" class="mate-session-list"></div>
282
283
  </div>
284
+ <div id="mate-sidebar-datastore" class="hidden">
285
+ <div class="mate-sidebar-sessions-header">
286
+ <span>Data</span>
287
+ <div class="mate-sidebar-actions">
288
+ <button id="mate-db-refresh-btn" type="button" title="Refresh tables"><i data-lucide="refresh-cw"></i></button>
289
+ <button id="mate-db-back-btn" type="button" title="Back to conversations"><i data-lucide="x"></i></button>
290
+ </div>
291
+ </div>
292
+ <div class="mate-db-status" id="mate-db-status"></div>
293
+ <div class="mate-db-layout">
294
+ <div class="mate-db-table-column">
295
+ <div class="mate-db-section-title">Objects</div>
296
+ <div id="mate-db-table-list" class="mate-db-table-list"></div>
297
+ </div>
298
+ <div class="mate-db-detail">
299
+ <div class="mate-db-section-title" id="mate-db-table-name">No table selected</div>
300
+ <pre id="mate-db-table-schema" class="mate-db-table-schema"></pre>
301
+ <textarea id="mate-db-query" class="mate-db-query" spellcheck="false" placeholder="SELECT * FROM table LIMIT 50;"></textarea>
302
+ <textarea id="mate-db-params" class="mate-db-params" spellcheck="false" placeholder='[]'></textarea>
303
+ <div class="mate-db-actions">
304
+ <button id="mate-db-query-btn" type="button">Query</button>
305
+ <button id="mate-db-exec-btn" type="button">Exec</button>
306
+ </div>
307
+ <pre id="mate-db-result" class="mate-db-result"></pre>
308
+ </div>
309
+ </div>
310
+ </div>
283
311
  <div id="mate-sidebar-memory" class="hidden"></div>
284
312
  <div id="mate-sidebar-knowledge" class="hidden">
285
313
  <div class="mate-sidebar-sessions-header">
@@ -14,6 +14,7 @@ import { renderSessionList, updateSessionPresence, populateCliSessionList, handl
14
14
  import { updateDmBadge, renderSidebarPresence, setMentionActive, renderUserStrip } from './sidebar-mates.js';
15
15
  import { refreshMobileChatSheet } from './sidebar-mobile.js';
16
16
  import { renderMateSessionList, handleMateSearchResults, updateMateSidebarProfile } from './mate-sidebar.js';
17
+ import { handleMateDatastoreTablesResult, handleMateDatastoreDescribeResult, handleMateDatastoreQueryResult, handleMateDatastoreExecResult, handleMateDatastoreError, handleMateDatastoreChange } from './mate-datastore-ui.js';
17
18
  import { renderKnowledgeList, handleKnowledgeContent } from './mate-knowledge.js';
18
19
  import { renderMemoryList } from './mate-memory.js';
19
20
  import { handlePaletteSessionSwitch, setPaletteVersion } from './command-palette.js';
@@ -275,6 +276,30 @@ export function processMessage(msg) {
275
276
  updateProjectList(msg);
276
277
  break;
277
278
 
279
+ case "mate_db_tables_result":
280
+ handleMateDatastoreTablesResult(msg);
281
+ break;
282
+
283
+ case "mate_db_describe_result":
284
+ handleMateDatastoreDescribeResult(msg);
285
+ break;
286
+
287
+ case "mate_db_query_result":
288
+ handleMateDatastoreQueryResult(msg);
289
+ break;
290
+
291
+ case "mate_db_exec_result":
292
+ handleMateDatastoreExecResult(msg);
293
+ break;
294
+
295
+ case "mate_db_error":
296
+ handleMateDatastoreError(msg);
297
+ break;
298
+
299
+ case "mate_db_change":
300
+ handleMateDatastoreChange(msg);
301
+ break;
302
+
278
303
  case "update_available":
279
304
  // In multi-user mode, only show update UI to admins
280
305
  if (store.get('isMultiUserMode')) {
@@ -0,0 +1,270 @@
1
+ import { escapeHtml } from './utils.js';
2
+ import { refreshIcons } from './icons.js';
3
+ import { getWs } from './ws-ref.js';
4
+
5
+ var wsGetter = null;
6
+ var panelEl = null;
7
+ var tableListEl = null;
8
+ var tableNameEl = null;
9
+ var tableSchemaEl = null;
10
+ var queryInputEl = null;
11
+ var paramsInputEl = null;
12
+ var resultEl = null;
13
+ var statusEl = null;
14
+ var dataBtnEl = null;
15
+ var conversationsEl = null;
16
+ var memoryEl = null;
17
+ var knowledgeEl = null;
18
+ var currentTables = [];
19
+ var currentTable = null;
20
+ var panelOpen = false;
21
+
22
+ function sendWs(msg) {
23
+ var ws = wsGetter ? wsGetter() : getWs();
24
+ if (ws && ws.readyState === 1) ws.send(JSON.stringify(msg));
25
+ }
26
+
27
+ function setSectionVisibility(open) {
28
+ panelOpen = open;
29
+ if (panelEl) panelEl.classList.toggle("hidden", !open);
30
+ if (conversationsEl) conversationsEl.classList.toggle("hidden", open);
31
+ if (memoryEl) memoryEl.classList.toggle("hidden", true);
32
+ if (knowledgeEl) knowledgeEl.classList.toggle("hidden", true);
33
+ if (dataBtnEl) dataBtnEl.classList.toggle("active", open);
34
+ refreshIcons();
35
+ }
36
+
37
+ function requestTables() {
38
+ sendWs({ type: "mate_db_tables" });
39
+ }
40
+
41
+ function renderStatus(text, kind) {
42
+ if (!statusEl) return;
43
+ statusEl.textContent = text || "";
44
+ statusEl.dataset.kind = kind || "";
45
+ }
46
+
47
+ function renderResult(payload) {
48
+ if (!resultEl) return;
49
+ resultEl.textContent = JSON.stringify(payload, null, 2);
50
+ }
51
+
52
+ function renderTableList(objects) {
53
+ currentTables = objects || [];
54
+ if (!tableListEl) return;
55
+ tableListEl.innerHTML = "";
56
+
57
+ if (!currentTables.length) {
58
+ var empty = document.createElement("div");
59
+ empty.className = "mate-db-empty";
60
+ empty.textContent = "No tables or views found.";
61
+ tableListEl.appendChild(empty);
62
+ return;
63
+ }
64
+
65
+ for (var i = 0; i < currentTables.length; i++) {
66
+ (function (obj) {
67
+ var row = document.createElement("button");
68
+ row.type = "button";
69
+ row.className = "mate-db-table-item" + (currentTable === obj.name ? " active" : "");
70
+ var label = obj.type || "object";
71
+ row.innerHTML = '<span class="mate-db-table-item-name">' + escapeHtml(obj.name) + '</span>' +
72
+ '<span class="mate-db-table-item-type">' + escapeHtml(label) + '</span>';
73
+ row.addEventListener("click", function () {
74
+ selectTable(obj.name);
75
+ });
76
+ tableListEl.appendChild(row);
77
+ })(currentTables[i]);
78
+ }
79
+ }
80
+
81
+ function findFirstDescribableObject(objects) {
82
+ var list = objects || [];
83
+ for (var i = 0; i < list.length; i++) {
84
+ if (list[i] && (list[i].type === "table" || list[i].type === "view")) return list[i];
85
+ }
86
+ return null;
87
+ }
88
+
89
+ function findObjectByName(name) {
90
+ for (var i = 0; i < currentTables.length; i++) {
91
+ if (currentTables[i] && currentTables[i].name === name) return currentTables[i];
92
+ }
93
+ return null;
94
+ }
95
+
96
+ function selectTable(tableName) {
97
+ currentTable = tableName;
98
+ renderTableList(currentTables);
99
+ var obj = findObjectByName(tableName);
100
+ if (!obj) return;
101
+ if (obj.type !== "table" && obj.type !== "view") {
102
+ renderStatus("Selected " + (obj.type || "object") + " " + tableName + ".", "ok");
103
+ if (tableNameEl) tableNameEl.textContent = tableName;
104
+ if (tableSchemaEl) tableSchemaEl.textContent = obj.sql || "";
105
+ renderResult(obj);
106
+ return;
107
+ }
108
+ renderStatus("Loading " + tableName + "...", "info");
109
+ sendWs({ type: "mate_db_describe", table: tableName });
110
+ if (queryInputEl) queryInputEl.value = 'SELECT * FROM "' + tableName.replace(/"/g, '""') + '" LIMIT 50;';
111
+ }
112
+
113
+ function parseParams() {
114
+ if (!paramsInputEl) return [];
115
+ var text = paramsInputEl.value.trim();
116
+ if (!text) return [];
117
+ try {
118
+ var parsed = JSON.parse(text);
119
+ if (Array.isArray(parsed)) return parsed;
120
+ renderStatus("Parameters must be a JSON array.", "error");
121
+ } catch (e) {
122
+ renderStatus("Parameters must be valid JSON.", "error");
123
+ }
124
+ return null;
125
+ }
126
+
127
+ function sendQueryMessage(type) {
128
+ var sql = queryInputEl ? queryInputEl.value : "";
129
+ var params = parseParams();
130
+ if (params === null) return;
131
+ if (!sql || !sql.trim()) {
132
+ renderStatus("Enter SQL before running it.", "error");
133
+ return;
134
+ }
135
+ sendWs({ type: type, sql: sql, params: params });
136
+ }
137
+
138
+ export function initMateDatastoreUI(getWsFn) {
139
+ wsGetter = getWsFn;
140
+ panelEl = document.getElementById("mate-sidebar-datastore");
141
+ tableListEl = document.getElementById("mate-db-table-list");
142
+ tableNameEl = document.getElementById("mate-db-table-name");
143
+ tableSchemaEl = document.getElementById("mate-db-table-schema");
144
+ queryInputEl = document.getElementById("mate-db-query");
145
+ paramsInputEl = document.getElementById("mate-db-params");
146
+ resultEl = document.getElementById("mate-db-result");
147
+ statusEl = document.getElementById("mate-db-status");
148
+ dataBtnEl = document.getElementById("mate-data-btn");
149
+ conversationsEl = document.getElementById("mate-sidebar-conversations");
150
+ memoryEl = document.getElementById("mate-sidebar-memory");
151
+ knowledgeEl = document.getElementById("mate-sidebar-knowledge");
152
+
153
+ var refreshBtn = document.getElementById("mate-db-refresh-btn");
154
+ var queryBtn = document.getElementById("mate-db-query-btn");
155
+ var execBtn = document.getElementById("mate-db-exec-btn");
156
+ var backBtn = document.getElementById("mate-db-back-btn");
157
+
158
+ if (dataBtnEl) {
159
+ dataBtnEl.addEventListener("click", function () {
160
+ if (panelOpen) {
161
+ setSectionVisibility(false);
162
+ } else {
163
+ setSectionVisibility(true);
164
+ requestTables();
165
+ }
166
+ });
167
+ }
168
+
169
+ if (refreshBtn) {
170
+ refreshBtn.addEventListener("click", function () {
171
+ requestTables();
172
+ });
173
+ }
174
+
175
+ if (queryBtn) {
176
+ queryBtn.addEventListener("click", function () {
177
+ sendQueryMessage("mate_db_query");
178
+ });
179
+ }
180
+
181
+ if (execBtn) {
182
+ execBtn.addEventListener("click", function () {
183
+ sendQueryMessage("mate_db_exec");
184
+ });
185
+ }
186
+
187
+ if (backBtn) {
188
+ backBtn.addEventListener("click", function () {
189
+ setSectionVisibility(false);
190
+ });
191
+ }
192
+
193
+ setSectionVisibility(false);
194
+ }
195
+
196
+ export function showMateDatastorePanel() {
197
+ setSectionVisibility(true);
198
+ requestTables();
199
+ }
200
+
201
+ export function hideMateDatastorePanel() {
202
+ setSectionVisibility(false);
203
+ }
204
+
205
+ export function handleMateDatastoreTablesResult(msg) {
206
+ if (msg.ok === false) {
207
+ renderStatus(msg.message || "Failed to load datastore tables.", "error");
208
+ renderResult(msg);
209
+ return;
210
+ }
211
+ renderStatus(msg.warning || "Datastore tables loaded.", msg.warning ? "warn" : "ok");
212
+ renderTableList(msg.objects || []);
213
+ if (msg.objects && msg.objects.length > 0) {
214
+ var found = false;
215
+ for (var i = 0; i < msg.objects.length; i++) {
216
+ if (msg.objects[i].name === currentTable) {
217
+ found = true;
218
+ break;
219
+ }
220
+ }
221
+ if (!found) {
222
+ var firstObject = findFirstDescribableObject(msg.objects);
223
+ if (firstObject) selectTable(firstObject.name);
224
+ }
225
+ }
226
+ renderResult(msg.objects || []);
227
+ }
228
+
229
+ export function handleMateDatastoreDescribeResult(msg) {
230
+ if (msg.ok === false) {
231
+ renderStatus(msg.message || "Failed to describe table.", "error");
232
+ renderResult(msg);
233
+ return;
234
+ }
235
+ renderStatus(msg.warning || ("Described " + (msg.table || "table") + "."), msg.warning ? "warn" : "ok");
236
+ if (tableNameEl) tableNameEl.textContent = msg.table || "Table";
237
+ if (tableSchemaEl) tableSchemaEl.textContent = msg.createSql || "";
238
+ renderResult(msg);
239
+ }
240
+
241
+ export function handleMateDatastoreQueryResult(msg) {
242
+ if (msg.ok === false) {
243
+ renderStatus(msg.message || "Query failed.", "error");
244
+ renderResult(msg);
245
+ return;
246
+ }
247
+ renderStatus(msg.warning || ("Returned " + (msg.rowCount || 0) + " row(s)."), msg.warning ? "warn" : "ok");
248
+ renderResult(msg);
249
+ }
250
+
251
+ export function handleMateDatastoreExecResult(msg) {
252
+ if (msg.ok === false) {
253
+ renderStatus(msg.message || "Execution failed.", "error");
254
+ renderResult(msg);
255
+ return;
256
+ }
257
+ renderStatus(msg.warning || ("Applied " + (msg.changes || 0) + " change(s)."), msg.warning ? "warn" : "ok");
258
+ renderResult(msg);
259
+ requestTables();
260
+ }
261
+
262
+ export function handleMateDatastoreError(msg) {
263
+ renderStatus(msg.message || "Mate datastore error.", "error");
264
+ renderResult(msg);
265
+ }
266
+
267
+ export function handleMateDatastoreChange(msg) {
268
+ renderStatus("Datastore changed.", "info");
269
+ if (panelOpen) requestTables();
270
+ }
@@ -3,6 +3,7 @@ import { escapeHtml } from './utils.js';
3
3
  import { iconHtml, refreshIcons } from './icons.js';
4
4
  import { store } from './store.js';
5
5
  import { hideKnowledge } from './mate-knowledge.js';
6
+ import { hideMateDatastorePanel } from './mate-datastore-ui.js';
6
7
  import { isSchedulerOpen, closeScheduler } from './scheduler.js';
7
8
  import { hideNotes } from './sticky-notes.js';
8
9
  import { openSearch as openSessionSearch } from './session-search.js';
@@ -134,6 +135,7 @@ export function initMateSidebar(wsGetter) {
134
135
  }
135
136
 
136
137
  export function showMateSidebar(mateId, mateData) {
138
+ if (hideMateDatastorePanel) hideMateDatastorePanel();
137
139
  currentMateId = mateId;
138
140
  currentMate = mateData;
139
141
  cachedSessions = [];
@@ -366,6 +368,7 @@ export function getMateSessions() {
366
368
  }
367
369
 
368
370
  export function hideMateSidebar() {
371
+ if (hideMateDatastorePanel) hideMateDatastorePanel();
369
372
  currentMateId = null;
370
373
  currentMate = null;
371
374
  cachedSessions = [];