clay-server 3.8.1 → 4.0.0-beta.10
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.
- package/lib/ask-user-mcp-server.js +5 -119
- package/lib/background-task-timing.js +105 -0
- package/lib/builtin-mates.js +6 -6
- package/lib/claude-hook-installer.js +15 -0
- package/lib/clay-history-mcp-server.js +62 -297
- package/lib/daemon.js +23 -1
- package/lib/debate-model-selection.js +119 -0
- package/lib/home-debate-tool-policy.js +164 -0
- package/lib/home-response-notifications.js +26 -0
- package/lib/knowledge-import.js +436 -0
- package/lib/knowledge-record-store.js +188 -0
- package/lib/knowledge-search.js +224 -0
- package/lib/mate-creation-mcp-server.js +55 -0
- package/lib/mate-knowledge-mcp-server.js +151 -0
- package/lib/mate-knowledge-migration.js +283 -0
- package/lib/mate-knowledge-service.js +488 -0
- package/lib/mate-knowledge-sync.js +482 -0
- package/lib/mate-ready-creation.js +95 -0
- package/lib/mates.js +2 -0
- package/lib/notes.js +2 -1
- package/lib/project-ask-user.js +64 -0
- package/lib/project-capsule-catalog.js +101 -0
- package/lib/project-connection.js +17 -0
- package/lib/project-debate-proposal.js +133 -17
- package/lib/project-debate.js +214 -110
- package/lib/project-delegated-follow-up.js +84 -0
- package/lib/project-delegated-session.js +53 -0
- package/lib/project-filesystem.js +7 -9
- package/lib/project-knowledge.js +23 -0
- package/lib/project-logs-comments.js +137 -0
- package/lib/project-logs-mcp-server.js +290 -0
- package/lib/project-logs-query.js +167 -0
- package/lib/project-logs-root.js +67 -0
- package/lib/project-logs-schema.js +259 -0
- package/lib/project-logs-service.js +357 -0
- package/lib/project-logs-snapshot.js +202 -0
- package/lib/project-logs-store.js +498 -0
- package/lib/project-logs-versioning.js +128 -0
- package/lib/project-logs.js +347 -0
- package/lib/project-mate-creation-proposal.js +120 -0
- package/lib/project-mate-interaction.js +14 -0
- package/lib/project-mate-knowledge.js +110 -0
- package/lib/project-memory.js +36 -7
- package/lib/project-models.js +157 -32
- package/lib/project-session-notes.js +2 -2
- package/lib/project-session-pair.js +8 -8
- package/lib/project-sessions.js +66 -51
- package/lib/project-vendor-login.js +414 -0
- package/lib/project-worker-proposal.js +25 -25
- package/lib/project-workspace-query.js +144 -0
- package/lib/project.js +433 -102
- package/lib/public/app.js +109 -48
- package/lib/public/css/avatar-imprints.css +0 -1
- package/lib/public/css/base.css +4 -0
- package/lib/public/css/capsule-ui.css +389 -0
- package/lib/public/css/command-palette.css +306 -6
- package/lib/public/css/home-capsule-library.css +243 -0
- package/lib/public/css/home-capsule-source.css +192 -0
- package/lib/public/css/home-debate-live.css +146 -0
- package/lib/public/css/home-debate-planning.css +125 -0
- package/lib/public/css/home-debates-archive.css +281 -0
- package/lib/public/css/home-hub.css +896 -405
- package/lib/public/css/home-mate-creation.css +34 -0
- package/lib/public/css/home-mate-model-picker.css +131 -0
- package/lib/public/css/home-mate-settings.css +344 -0
- package/lib/public/css/home-session-actions.css +265 -0
- package/lib/public/css/home-sidebar.css +667 -0
- package/lib/public/css/icon-strip.css +1 -2
- package/lib/public/css/input.css +79 -25
- package/lib/public/css/mates.css +7 -34
- package/lib/public/css/pane.css +1 -1
- package/lib/public/css/playbook.css +0 -80
- package/lib/public/css/project-logs.css +234 -0
- package/lib/public/css/scheduler.css +1 -1
- package/lib/public/css/sticky-notes.css +53 -117
- package/lib/public/css/tui-attention.css +0 -44
- package/lib/public/css/workspace-assignment.css +45 -0
- package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
- package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
- package/lib/public/index.html +96 -74
- package/lib/public/modules/app-connection.js +100 -5
- package/lib/public/modules/app-dm.js +43 -160
- package/lib/public/modules/app-home-hub.js +328 -585
- package/lib/public/modules/app-message-cards.js +242 -0
- package/lib/public/modules/app-message-router.js +84 -0
- package/lib/public/modules/app-messages.js +124 -38
- package/lib/public/modules/app-notifications.js +8 -119
- package/lib/public/modules/app-panels.js +43 -2
- package/lib/public/modules/app-projects.js +9 -1
- package/lib/public/modules/app-rendering.js +21 -602
- package/lib/public/modules/avatar-imprint.js +11 -8
- package/lib/public/modules/background-tasks-ui.js +139 -16
- package/lib/public/modules/chat-bubble-renderer.js +152 -0
- package/lib/public/modules/chat-render-runtime.js +198 -0
- package/lib/public/modules/command-palette.js +225 -436
- package/lib/public/modules/dm-render.js +82 -0
- package/lib/public/modules/home-capsule-creation-intent.js +31 -0
- package/lib/public/modules/home-capsule-library.js +146 -0
- package/lib/public/modules/home-capsule-source.js +383 -0
- package/lib/public/modules/home-chat-identity.js +35 -0
- package/lib/public/modules/home-chat-scroll.js +77 -0
- package/lib/public/modules/home-chat-stream-state.js +34 -0
- package/lib/public/modules/home-composer-focus.js +25 -0
- package/lib/public/modules/home-conversations-sheet.js +179 -0
- package/lib/public/modules/home-debate-activity.js +48 -0
- package/lib/public/modules/home-debate-controls.js +295 -0
- package/lib/public/modules/home-debate-launch.js +41 -0
- package/lib/public/modules/home-debate-live.js +284 -0
- package/lib/public/modules/home-debate-models.js +73 -0
- package/lib/public/modules/home-debate-planning.js +335 -0
- package/lib/public/modules/home-debates-archive.js +279 -0
- package/lib/public/modules/home-dock-resize.js +74 -0
- package/lib/public/modules/home-dock.js +446 -0
- package/lib/public/modules/home-mate-chat.js +496 -0
- package/lib/public/modules/home-mate-creation.js +109 -0
- package/lib/public/modules/home-mate-model-picker.js +281 -0
- package/lib/public/modules/home-mate-selection.js +38 -0
- package/lib/public/modules/home-mate-settings-menu.js +131 -0
- package/lib/public/modules/home-mate-settings.js +383 -0
- package/lib/public/modules/home-session-actions.js +373 -0
- package/lib/public/modules/home-session-model-confirmation.js +13 -0
- package/lib/public/modules/home-shell.js +9 -0
- package/lib/public/modules/home-sidebar-chat-list.js +63 -0
- package/lib/public/modules/home-sidebar.js +165 -0
- package/lib/public/modules/home-sub-surface.js +19 -0
- package/lib/public/modules/home-surface-boot.js +68 -0
- package/lib/public/modules/home-surface.js +141 -0
- package/lib/public/modules/home-tools.js +271 -0
- package/lib/public/modules/markdown.js +50 -2
- package/lib/public/modules/mate-management.js +86 -0
- package/lib/public/modules/mate-sidebar.js +0 -8
- package/lib/public/modules/mate-wizard.js +0 -7
- package/lib/public/modules/mention.js +17 -19
- package/lib/public/modules/pane-bridge.js +9 -0
- package/lib/public/modules/profile.js +4 -5
- package/lib/public/modules/project-logs-ambient.js +238 -0
- package/lib/public/modules/project-logs-render.js +359 -0
- package/lib/public/modules/project-logs.js +328 -0
- package/lib/public/modules/project-settings.js +34 -28
- package/lib/public/modules/project-switcher.js +11 -5
- package/lib/public/modules/project-workspace-assignment.js +23 -0
- package/lib/public/modules/scheduler.js +17 -3
- package/lib/public/modules/search-clay-chat.js +402 -0
- package/lib/public/modules/server-settings.js +14 -12
- package/lib/public/modules/session-actions.js +1 -1
- package/lib/public/modules/sidebar-mates.js +56 -552
- package/lib/public/modules/sidebar-mobile.js +12 -73
- package/lib/public/modules/sidebar-presence.js +37 -0
- package/lib/public/modules/sidebar-sessions.js +25 -1
- package/lib/public/modules/split-pair-ui.js +13 -13
- package/lib/public/modules/split-view.js +7 -0
- package/lib/public/modules/sticky-notes.js +106 -53
- package/lib/public/modules/tool-input-composition.js +48 -0
- package/lib/public/modules/tool-llm-status.js +167 -0
- package/lib/public/modules/tool-palette.js +76 -4
- package/lib/public/modules/tool-renderer-advanced.js +285 -0
- package/lib/public/modules/tool-renderer-chart.js +158 -0
- package/lib/public/modules/tool-renderer-semantics.js +35 -0
- package/lib/public/modules/tool-renderer.js +464 -0
- package/lib/public/modules/tool-runtime.js +309 -0
- package/lib/public/modules/tool-ui-evaluator.js +97 -0
- package/lib/public/modules/tool-ui-tree.js +21 -0
- package/lib/public/modules/tui-attention.js +10 -0
- package/lib/public/modules/user-settings.js +16 -23
- package/lib/public/modules/vendor-login.js +287 -0
- package/lib/public/modules/worker-proposal.js +2 -2
- package/lib/public/modules/workspace-assignment-card.js +149 -0
- package/lib/public/modules/workspace-assignment-routing.js +4 -0
- package/lib/public/style.css +14 -2
- package/lib/runtime-env.js +65 -0
- package/lib/sdk-bridge.js +120 -32
- package/lib/sdk-message-processor.js +34 -13
- package/lib/server-home-capsule-creation.js +36 -0
- package/lib/server-home-chat-events.js +287 -0
- package/lib/server-home-chat.js +518 -0
- package/lib/server-home-clay-entry.js +65 -0
- package/lib/server-home-clay-session-links.js +26 -0
- package/lib/server-home-debate-planning.js +214 -0
- package/lib/server-home-debates.js +137 -0
- package/lib/server-home-mate-creation.js +261 -0
- package/lib/server-home-models.js +241 -0
- package/lib/server-home-preferences.js +61 -0
- package/lib/server-mates.js +37 -0
- package/lib/server-tools.js +377 -0
- package/lib/server.js +166 -59
- package/lib/session-pair-mcp-server.js +6 -6
- package/lib/sessions.js +22 -4
- package/lib/tool-capsule-source.js +142 -0
- package/lib/tool-control-mcp-server.js +126 -0
- package/lib/tool-llm.js +48 -0
- package/lib/tool-storage.js +77 -0
- package/lib/tool-ui-spec-advanced.js +82 -0
- package/lib/tool-ui-spec.js +261 -0
- package/lib/tools-registry.js +286 -0
- package/lib/users-home-dock-preferences.js +77 -0
- package/lib/users-home-surface-preferences.js +99 -0
- package/lib/users-preferences.js +4 -7
- package/lib/users.js +12 -0
- package/lib/whats-new-content.js +3 -3
- package/lib/workspace-assignment-service.js +420 -0
- package/lib/workspace-query-mcp-server.js +154 -0
- package/lib/workspace-query-service.js +492 -0
- package/lib/ws-schema.js +107 -12
- package/lib/yoke/adapters/acp.js +2 -1
- package/lib/yoke/adapters/antigravity.js +2 -1
- package/lib/yoke/adapters/claude-worker.js +11 -4
- package/lib/yoke/adapters/claude.js +141 -46
- package/lib/yoke/adapters/codex.js +79 -11
- package/lib/yoke/adapters/kiro.js +2 -1
- package/lib/yoke/claude-user-input.js +38 -0
- package/lib/yoke/codex-app-server.js +20 -2
- package/lib/yoke/codex-background-tasks.js +8 -2
- package/lib/yoke/codex-user-input.js +64 -0
- package/lib/yoke/complete-once.js +164 -0
- package/lib/yoke/index.js +5 -1
- package/lib/yoke/interface.js +19 -0
- package/lib/yoke/mcp-bridge-server.js +2 -6
- package/lib/yoke/user-input.js +254 -0
- package/package.json +4 -3
- package/lib/public/css/home-chat.css +0 -380
- package/lib/public/modules/home-chat.js +0 -438
- package/lib/server-clay-home.js +0 -245
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// Compact provider/model status for LLM-enabled Capsule surfaces.
|
|
2
|
+
|
|
3
|
+
import { getWs } from './ws-ref.js';
|
|
4
|
+
|
|
5
|
+
var surfaces = [];
|
|
6
|
+
var requestCounter = 0;
|
|
7
|
+
var activeRequests = Object.create(null);
|
|
8
|
+
var states = Object.create(null);
|
|
9
|
+
var subscribers = [];
|
|
10
|
+
|
|
11
|
+
export var TOOL_LLM_ALIASES = Object.freeze(["fast", "standard", "deep"]);
|
|
12
|
+
|
|
13
|
+
function safeAlias(alias) {
|
|
14
|
+
return alias === "fast" || alias === "deep" ? alias : "standard";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isAlias(alias) {
|
|
18
|
+
return alias === "fast" || alias === "standard" || alias === "deep";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function initialToolLlmAlias(manifest) {
|
|
22
|
+
return manifest && isAlias(manifest.modelAlias) ? manifest.modelAlias : null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function toolLlmDisplayValue(modelState) {
|
|
26
|
+
var ready = modelState && modelState.status === "ready" && modelState.vendorName && modelState.modelName;
|
|
27
|
+
return ready ? modelState.vendorName + " · " + modelState.modelName : "No model configured";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function toolLlmShouldRetry(modelState) {
|
|
31
|
+
return !!modelState && modelState.status === "error";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function currentSurfaces() {
|
|
35
|
+
surfaces = surfaces.filter(function (surface) { return !!surface.root; });
|
|
36
|
+
return surfaces;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function notifyAlias(alias) {
|
|
40
|
+
var current = subscribers.slice();
|
|
41
|
+
for (var i = 0; i < current.length; i++) current[i](alias, getToolLlmConfiguration(alias));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function getToolLlmConfiguration(alias) {
|
|
45
|
+
alias = safeAlias(alias);
|
|
46
|
+
return Object.assign({ status: "loading", vendorName: "", modelName: "", error: "" }, states[alias] || {});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function subscribeToolLlmConfigurations(listener) {
|
|
50
|
+
subscribers.push(listener);
|
|
51
|
+
return function () {
|
|
52
|
+
var index = subscribers.indexOf(listener);
|
|
53
|
+
if (index !== -1) subscribers.splice(index, 1);
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function renderSurface(surface) {
|
|
58
|
+
if (!surface.alias) {
|
|
59
|
+
surface.value.textContent = "Selected when Capsule runs";
|
|
60
|
+
surface.value.title = "The concrete model is selected when this Capsule requests an LLM capability.";
|
|
61
|
+
surface.error.classList.add("hidden");
|
|
62
|
+
surface.retry.classList.add("hidden");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
var state = states[surface.alias] || { status: "loading", vendorName: "", modelName: "", error: "" };
|
|
66
|
+
var ready = state.status === "ready" && state.vendorName && state.modelName;
|
|
67
|
+
surface.value.textContent = toolLlmDisplayValue(state);
|
|
68
|
+
surface.value.title = ready ? "Capsule " + surface.alias + " model: " + state.vendorName + " · " + state.modelName : "No configured Capsule model";
|
|
69
|
+
surface.error.textContent = state.error || "";
|
|
70
|
+
surface.error.classList.toggle("hidden", !state.error);
|
|
71
|
+
surface.retry.classList.toggle("hidden", !toolLlmShouldRetry(state));
|
|
72
|
+
surface.retry.disabled = false;
|
|
73
|
+
surface.retry.textContent = "Retry";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function renderAlias(alias) {
|
|
77
|
+
var current = currentSurfaces();
|
|
78
|
+
for (var i = 0; i < current.length; i++) {
|
|
79
|
+
if (current[i].alias === alias) renderSurface(current[i]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function requestToolLlmConfiguration(alias) {
|
|
84
|
+
alias = safeAlias(alias);
|
|
85
|
+
var ws = getWs();
|
|
86
|
+
if (!ws || ws.readyState !== 1) {
|
|
87
|
+
activeRequests[alias] = null;
|
|
88
|
+
states[alias] = { status: "error", vendorName: "", modelName: "", error: "Connect to Clay to check the Capsule model." };
|
|
89
|
+
renderAlias(alias);
|
|
90
|
+
notifyAlias(alias);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
requestCounter++;
|
|
94
|
+
activeRequests[alias] = "tool-llm-config-" + requestCounter;
|
|
95
|
+
states[alias] = { status: "loading", vendorName: "", modelName: "", error: "" };
|
|
96
|
+
renderAlias(alias);
|
|
97
|
+
notifyAlias(alias);
|
|
98
|
+
ws.send(JSON.stringify({ type: "tool_llm_config_get", requestId: activeRequests[alias], alias: alias }));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function requestAllToolLlmConfigurations() {
|
|
102
|
+
for (var i = 0; i < TOOL_LLM_ALIASES.length; i++) requestToolLlmConfiguration(TOOL_LLM_ALIASES[i]);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function handleToolLlmConfigState(msg) {
|
|
106
|
+
if (!isAlias(msg.alias)) return;
|
|
107
|
+
var alias = msg.alias;
|
|
108
|
+
if (msg.requestId && msg.requestId !== activeRequests[alias]) return;
|
|
109
|
+
activeRequests[alias] = null;
|
|
110
|
+
states[alias] = {
|
|
111
|
+
status: msg.status === "ready" ? "ready" : "error",
|
|
112
|
+
vendorName: msg.vendorName || msg.vendor || "",
|
|
113
|
+
modelName: msg.modelName || msg.model || "",
|
|
114
|
+
error: msg.error || "",
|
|
115
|
+
};
|
|
116
|
+
renderAlias(alias);
|
|
117
|
+
notifyAlias(alias);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function createToolLlmStatus(alias) {
|
|
121
|
+
alias = isAlias(alias) ? alias : null;
|
|
122
|
+
var root = document.createElement("section");
|
|
123
|
+
root.className = "tool-llm-status";
|
|
124
|
+
root.setAttribute("aria-label", "Capsule model status");
|
|
125
|
+
var identity = document.createElement("div");
|
|
126
|
+
identity.className = "tool-llm-identity";
|
|
127
|
+
var label = document.createElement("span");
|
|
128
|
+
label.className = "tool-llm-label";
|
|
129
|
+
label.textContent = "Model";
|
|
130
|
+
var value = document.createElement("span");
|
|
131
|
+
value.className = "tool-llm-value";
|
|
132
|
+
value.setAttribute("aria-live", "polite");
|
|
133
|
+
identity.appendChild(label);
|
|
134
|
+
identity.appendChild(value);
|
|
135
|
+
var actions = document.createElement("div");
|
|
136
|
+
actions.className = "tool-llm-actions";
|
|
137
|
+
var retry = document.createElement("button");
|
|
138
|
+
retry.type = "button";
|
|
139
|
+
retry.className = "tool-llm-action hidden";
|
|
140
|
+
retry.addEventListener("click", function () {
|
|
141
|
+
if (surface.alias) requestToolLlmConfiguration(surface.alias);
|
|
142
|
+
});
|
|
143
|
+
var error = document.createElement("p");
|
|
144
|
+
error.className = "tool-llm-error hidden";
|
|
145
|
+
actions.appendChild(retry);
|
|
146
|
+
root.appendChild(identity);
|
|
147
|
+
root.appendChild(actions);
|
|
148
|
+
root.appendChild(error);
|
|
149
|
+
var surface = { root: root, alias: alias, value: value, retry: retry, error: error };
|
|
150
|
+
surfaces.push(surface);
|
|
151
|
+
renderSurface(surface);
|
|
152
|
+
if (alias) requestToolLlmConfiguration(alias);
|
|
153
|
+
return {
|
|
154
|
+
element: root,
|
|
155
|
+
setAlias: function (nextAlias) {
|
|
156
|
+
if (!isAlias(nextAlias)) return;
|
|
157
|
+
surface.alias = nextAlias;
|
|
158
|
+
renderSurface(surface);
|
|
159
|
+
requestToolLlmConfiguration(nextAlias);
|
|
160
|
+
},
|
|
161
|
+
dispose: function () {
|
|
162
|
+
surface.root = null;
|
|
163
|
+
var index = surfaces.indexOf(surface);
|
|
164
|
+
if (index !== -1) surfaces.splice(index, 1);
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
@@ -23,7 +23,7 @@ var SESSION_TOOLS = [
|
|
|
23
23
|
{ id: "file-browser-btn", icon: "folder-tree", label: "File browser" },
|
|
24
24
|
{ id: "terminal-sidebar-btn", icon: "square-terminal", label: "Terminal", countId: "terminal-sidebar-count" },
|
|
25
25
|
{ id: "sticky-notes-sidebar-btn", icon: "sticky-note", label: "Sticky Notes", countId: "sticky-notes-sidebar-count" },
|
|
26
|
-
{ id: "
|
|
26
|
+
{ id: "project-logs-btn", icon: "notebook-tabs", label: "Logs", countId: "project-logs-count" },
|
|
27
27
|
{ id: "loop-tool-btn", icon: "repeat", label: "Loop" },
|
|
28
28
|
{ id: "git-sidebar-btn", icon: "git-branch", label: "Git", countId: "git-sidebar-count" },
|
|
29
29
|
{ id: "mcp-btn", icon: "cable", label: "MCP Servers", countId: "mcp-sidebar-count" },
|
|
@@ -34,7 +34,6 @@ var MATE_TOOLS = [
|
|
|
34
34
|
{ id: "mate-memory-btn", icon: "brain", label: "Memory", countId: "mate-memory-count" },
|
|
35
35
|
{ id: "mate-knowledge-btn", icon: "book-open", label: "Knowledge", countId: "mate-knowledge-count" },
|
|
36
36
|
{ id: "mate-sticky-notes-btn", icon: "sticky-note", label: "Sticky Notes" },
|
|
37
|
-
{ id: "mate-scheduler-btn", icon: "calendar-clock", label: "Scheduled Tasks" },
|
|
38
37
|
{ id: "mate-debate-btn", icon: "mic", label: "Debate" },
|
|
39
38
|
{ id: "mate-mcp-btn", icon: "cable", label: "MCP Servers", countId: "mate-mcp-sidebar-count" },
|
|
40
39
|
{ id: "mate-skills-btn", icon: "puzzle", label: "Skills" },
|
|
@@ -53,10 +52,75 @@ var PALETTES = {
|
|
|
53
52
|
},
|
|
54
53
|
};
|
|
55
54
|
|
|
55
|
+
// Tools that were replaced in the session palette. A saved preference naming
|
|
56
|
+
// the old id would otherwise silently drop out (its element no longer exists)
|
|
57
|
+
// and the replacement would append to the end of the palette instead of
|
|
58
|
+
// inheriting the slot the user had chosen.
|
|
59
|
+
var LEGACY_SESSION_TOOL_IDS = {
|
|
60
|
+
"scheduler-btn": "project-logs-btn",
|
|
61
|
+
};
|
|
62
|
+
|
|
56
63
|
var _saveTimers = {};
|
|
57
64
|
var _draggingEl = null;
|
|
58
65
|
var _draggingPaletteName = null;
|
|
59
66
|
|
|
67
|
+
function indexOfId(list, id) {
|
|
68
|
+
for (var i = 0; i < list.length; i++) {
|
|
69
|
+
if (list[i] === id) return i;
|
|
70
|
+
}
|
|
71
|
+
return -1;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Rewrite a saved preference so a replaced tool keeps its slot.
|
|
75
|
+
//
|
|
76
|
+
// If the user already has an explicit preference for the replacement, that
|
|
77
|
+
// choice wins and the legacy id is simply dropped: their position, and whether
|
|
78
|
+
// they hid it, are never overridden. Otherwise the legacy id is replaced in
|
|
79
|
+
// place, at the exact index it occupied, in whichever list it appeared in.
|
|
80
|
+
//
|
|
81
|
+
// Exported for tests; returns new arrays and never mutates the input.
|
|
82
|
+
export function normalizeToolPreferences(name, prefs) {
|
|
83
|
+
var order = (prefs && prefs.order) || [];
|
|
84
|
+
var hidden = (prefs && prefs.hidden) || [];
|
|
85
|
+
var result = { order: order.slice(), hidden: hidden.slice(), migrated: false };
|
|
86
|
+
if (name !== "session") return result;
|
|
87
|
+
|
|
88
|
+
var legacyIds = Object.keys(LEGACY_SESSION_TOOL_IDS);
|
|
89
|
+
for (var i = 0; i < legacyIds.length; i++) {
|
|
90
|
+
var legacyId = legacyIds[i];
|
|
91
|
+
var replacementId = LEGACY_SESSION_TOOL_IDS[legacyId];
|
|
92
|
+
var inOrder = indexOfId(result.order, legacyId) !== -1;
|
|
93
|
+
var inHidden = indexOfId(result.hidden, legacyId) !== -1;
|
|
94
|
+
if (!inOrder && !inHidden) continue;
|
|
95
|
+
|
|
96
|
+
var explicit = indexOfId(result.order, replacementId) !== -1
|
|
97
|
+
|| indexOfId(result.hidden, replacementId) !== -1;
|
|
98
|
+
result.order = rewriteList(result.order, legacyId, replacementId, explicit);
|
|
99
|
+
result.hidden = rewriteList(result.hidden, legacyId, replacementId, explicit);
|
|
100
|
+
result.migrated = true;
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Drop the legacy id when the replacement is already chosen explicitly;
|
|
106
|
+
// otherwise swap it in place. Any duplicate of the replacement introduced by
|
|
107
|
+
// the swap is removed, keeping the first occurrence.
|
|
108
|
+
function rewriteList(list, legacyId, replacementId, dropLegacy) {
|
|
109
|
+
var out = [];
|
|
110
|
+
var seen = {};
|
|
111
|
+
for (var i = 0; i < list.length; i++) {
|
|
112
|
+
var id = list[i];
|
|
113
|
+
if (id === legacyId) {
|
|
114
|
+
if (dropLegacy) continue;
|
|
115
|
+
id = replacementId;
|
|
116
|
+
}
|
|
117
|
+
if (seen[id]) continue;
|
|
118
|
+
seen[id] = true;
|
|
119
|
+
out.push(id);
|
|
120
|
+
}
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
|
|
60
124
|
export function initToolPalettes() {
|
|
61
125
|
for (var name in PALETTES) {
|
|
62
126
|
buildPalette(name);
|
|
@@ -495,11 +559,13 @@ function applyPreferences(name, prefs) {
|
|
|
495
559
|
var hiddenGrid = hiddenSection ? hiddenSection.querySelector('.tool-palette-hidden-grid') : null;
|
|
496
560
|
if (!active || !hiddenGrid) return;
|
|
497
561
|
|
|
562
|
+
var normalized = normalizeToolPreferences(name, prefs);
|
|
563
|
+
|
|
498
564
|
var hiddenSet = {};
|
|
499
|
-
var hiddenList =
|
|
565
|
+
var hiddenList = normalized.hidden;
|
|
500
566
|
for (var i = 0; i < hiddenList.length; i++) hiddenSet[hiddenList[i]] = true;
|
|
501
567
|
|
|
502
|
-
var orderList =
|
|
568
|
+
var orderList = normalized.order;
|
|
503
569
|
// Any tools not in the stored order are appended in registry order so
|
|
504
570
|
// newly-added tools surface automatically for existing users.
|
|
505
571
|
var placed = {};
|
|
@@ -525,6 +591,12 @@ function applyPreferences(name, prefs) {
|
|
|
525
591
|
hiddenGrid.appendChild(hbtn);
|
|
526
592
|
}
|
|
527
593
|
}
|
|
594
|
+
|
|
595
|
+
// Write the rewritten preference back once, through the normal save path, so
|
|
596
|
+
// the migration survives reloads and reaches the user's other devices. The
|
|
597
|
+
// save reads the DOM this function just arranged, so it records exactly what
|
|
598
|
+
// is on screen.
|
|
599
|
+
if (normalized.migrated) queueSave(name);
|
|
528
600
|
}
|
|
529
601
|
|
|
530
602
|
function queueSave(name) {
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
// Host-owned advanced controls for the safe Capsule UI vocabulary.
|
|
2
|
+
|
|
3
|
+
import { collectionView, normalizeOptions, resolveProps, resolveValue, valueAtPath } from './tool-ui-evaluator.js';
|
|
4
|
+
import { renderChartNode } from './tool-renderer-chart.js';
|
|
5
|
+
|
|
6
|
+
var dialogOpeners = new WeakMap();
|
|
7
|
+
|
|
8
|
+
function nextGroupToken(context, prefix, authoredId) {
|
|
9
|
+
if (authoredId) return authoredId;
|
|
10
|
+
if (!Number.isInteger(context.autoControlIndex) || context.autoControlIndex < 1) context.autoControlIndex = 1;
|
|
11
|
+
return prefix + "-" + context.autoControlIndex++;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function emit(node, props, context, extra) {
|
|
15
|
+
var args = Object.assign({}, resolveValue(props.args || {}, context.state, context.item), extra || {});
|
|
16
|
+
if (node.id) args.controlId = node.id;
|
|
17
|
+
context.emit(node.action, args);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function appendRenderedChildren(target, children, context, renderNode) {
|
|
21
|
+
for (var i = 0; i < children.length; i++) {
|
|
22
|
+
var rendered = renderNode(children[i], context);
|
|
23
|
+
if (rendered) target.appendChild(rendered);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function renderForm(node, props, context, renderNode) {
|
|
28
|
+
var form = document.createElement("form");
|
|
29
|
+
form.className = "tool-form";
|
|
30
|
+
if (props.label) form.setAttribute("aria-label", String(props.label));
|
|
31
|
+
appendRenderedChildren(form, node.children || [], context, renderNode);
|
|
32
|
+
var error = document.createElement("div");
|
|
33
|
+
error.className = "tool-form-error hidden";
|
|
34
|
+
error.setAttribute("role", "alert");
|
|
35
|
+
form.appendChild(error);
|
|
36
|
+
form.addEventListener("submit", function (event) {
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
var invalid = form.querySelector(":invalid");
|
|
39
|
+
if (invalid) {
|
|
40
|
+
error.textContent = invalid.validationMessage || "Check the highlighted fields.";
|
|
41
|
+
error.classList.remove("hidden");
|
|
42
|
+
invalid.focus();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
error.classList.add("hidden");
|
|
46
|
+
emit(node, props, context, {});
|
|
47
|
+
});
|
|
48
|
+
var submit = document.createElement("button");
|
|
49
|
+
submit.type = "submit";
|
|
50
|
+
submit.className = "tool-button tool-button--variant-primary";
|
|
51
|
+
submit.dataset.toolControlId = node.id || "form-submit-" + context.autoControlIndex++;
|
|
52
|
+
submit.textContent = String(props.submitLabel || "Submit");
|
|
53
|
+
form.appendChild(submit);
|
|
54
|
+
return form;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function renderTabs(node, props, context, renderNode) {
|
|
58
|
+
var wrapper = document.createElement("div");
|
|
59
|
+
wrapper.className = "tool-tabs";
|
|
60
|
+
var list = document.createElement("div");
|
|
61
|
+
list.className = "tool-tab-list";
|
|
62
|
+
list.setAttribute("role", "tablist");
|
|
63
|
+
list.setAttribute("aria-label", String(props.label || "Sections"));
|
|
64
|
+
var panels = document.createElement("div");
|
|
65
|
+
var selected = valueAtPath(context.state, node.bind, context.item);
|
|
66
|
+
var groupToken = nextGroupToken(context, "tabs", node.id);
|
|
67
|
+
var children = node.children || [];
|
|
68
|
+
var dynamic = props.options ? normalizeOptions(props.options) : null;
|
|
69
|
+
var tabs = dynamic ? dynamic.map(function (option) { return { props: option, children: [] }; }) : children;
|
|
70
|
+
var buttons = [];
|
|
71
|
+
for (var i = 0; i < tabs.length; i++) {
|
|
72
|
+
var tab = tabs[i];
|
|
73
|
+
var tabProps = resolveProps(tab.props || {}, context.state, context.item);
|
|
74
|
+
var active = selected === tabProps.value || (selected === undefined && i === 0);
|
|
75
|
+
var button = document.createElement("button");
|
|
76
|
+
button.type = "button";
|
|
77
|
+
button.className = "tool-tab";
|
|
78
|
+
button.textContent = String(tabProps.label);
|
|
79
|
+
button.setAttribute("role", "tab");
|
|
80
|
+
button.setAttribute("aria-selected", active ? "true" : "false");
|
|
81
|
+
button.tabIndex = active ? 0 : -1;
|
|
82
|
+
button.disabled = tabProps.disabled === true;
|
|
83
|
+
var panelId = "tool-tab-panel-" + context.toolId + "-" + groupToken + "-" + i;
|
|
84
|
+
var tabId = "tool-tab-" + context.toolId + "-" + groupToken + "-" + i;
|
|
85
|
+
button.id = tabId;
|
|
86
|
+
button.setAttribute("aria-controls", panelId);
|
|
87
|
+
button.dataset.tabIndex = String(i);
|
|
88
|
+
button.addEventListener("click", function (event) {
|
|
89
|
+
var index = Number(event.currentTarget.dataset.tabIndex);
|
|
90
|
+
emit(node, props, context, { value: resolveProps(tabs[index].props || {}, context.state, context.item).value });
|
|
91
|
+
});
|
|
92
|
+
buttons.push(button);
|
|
93
|
+
list.appendChild(button);
|
|
94
|
+
if (active) {
|
|
95
|
+
var panel = document.createElement("div");
|
|
96
|
+
panel.id = panelId;
|
|
97
|
+
panel.className = "tool-tab-panel";
|
|
98
|
+
panel.setAttribute("role", "tabpanel");
|
|
99
|
+
panel.setAttribute("aria-labelledby", tabId);
|
|
100
|
+
appendRenderedChildren(panel, tab.children || [], context, renderNode);
|
|
101
|
+
panels.appendChild(panel);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
list.addEventListener("keydown", function (event) {
|
|
105
|
+
if (["ArrowLeft", "ArrowRight", "Home", "End"].indexOf(event.key) === -1) return;
|
|
106
|
+
event.preventDefault();
|
|
107
|
+
var enabled = buttons.filter(function (button) { return !button.disabled; });
|
|
108
|
+
if (!enabled.length) return;
|
|
109
|
+
var index = enabled.indexOf(document.activeElement);
|
|
110
|
+
var next = event.key === "Home" ? 0 : event.key === "End" ? enabled.length - 1 : (index + (event.key === "ArrowRight" ? 1 : -1) + enabled.length) % enabled.length;
|
|
111
|
+
enabled[next].focus();
|
|
112
|
+
});
|
|
113
|
+
wrapper.appendChild(list);
|
|
114
|
+
wrapper.appendChild(panels);
|
|
115
|
+
return wrapper;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function renderDialog(node, props, context, renderNode) {
|
|
119
|
+
var placeholder = document.createElement("span");
|
|
120
|
+
var dialogToken = nextGroupToken(context, "dialog", node.id);
|
|
121
|
+
if (props.open !== true) {
|
|
122
|
+
var openerId = dialogOpeners.get(context.container);
|
|
123
|
+
dialogOpeners.delete(context.container);
|
|
124
|
+
var returnTimer = openerId ? setTimeout(function () {
|
|
125
|
+
var controls = context.container.querySelectorAll("[data-tool-control-id]");
|
|
126
|
+
for (var i = 0; i < controls.length; i++) if (controls[i].dataset.toolControlId === openerId) controls[i].focus({ preventScroll: true });
|
|
127
|
+
}, 0) : null;
|
|
128
|
+
if (returnTimer) context.disposers.push(function () { clearTimeout(returnTimer); });
|
|
129
|
+
return placeholder;
|
|
130
|
+
}
|
|
131
|
+
if (context.activeControlId) dialogOpeners.set(context.container, context.activeControlId);
|
|
132
|
+
var overlay = document.createElement("div");
|
|
133
|
+
overlay.className = "tool-dialog-overlay";
|
|
134
|
+
var dialog = document.createElement("section");
|
|
135
|
+
dialog.className = "tool-dialog";
|
|
136
|
+
dialog.setAttribute("role", "dialog");
|
|
137
|
+
dialog.setAttribute("aria-modal", "true");
|
|
138
|
+
var title = document.createElement("h3");
|
|
139
|
+
var titleId = "tool-dialog-title-" + context.toolId + "-" + dialogToken;
|
|
140
|
+
title.id = titleId;
|
|
141
|
+
title.className = "tool-dialog-title";
|
|
142
|
+
title.textContent = String(props.label);
|
|
143
|
+
dialog.appendChild(title);
|
|
144
|
+
dialog.setAttribute("aria-labelledby", titleId);
|
|
145
|
+
if (props.description) {
|
|
146
|
+
var description = document.createElement("p");
|
|
147
|
+
var descriptionId = "tool-dialog-description-" + context.toolId + "-" + dialogToken;
|
|
148
|
+
description.id = descriptionId;
|
|
149
|
+
description.className = "tool-dialog-description";
|
|
150
|
+
description.textContent = String(props.description);
|
|
151
|
+
dialog.appendChild(description);
|
|
152
|
+
dialog.setAttribute("aria-describedby", descriptionId);
|
|
153
|
+
}
|
|
154
|
+
var close = document.createElement("button");
|
|
155
|
+
close.type = "button";
|
|
156
|
+
close.className = "tool-dialog-close";
|
|
157
|
+
close.textContent = "Close";
|
|
158
|
+
close.setAttribute("aria-label", "Close " + String(props.label));
|
|
159
|
+
close.addEventListener("click", function () { context.emit(props.closeAction, {}); });
|
|
160
|
+
dialog.appendChild(close);
|
|
161
|
+
appendRenderedChildren(dialog, node.children || [], context, renderNode);
|
|
162
|
+
overlay.appendChild(dialog);
|
|
163
|
+
overlay.addEventListener("mousedown", function (event) { if (event.target === overlay) context.emit(props.closeAction, {}); });
|
|
164
|
+
overlay.addEventListener("keydown", function (event) {
|
|
165
|
+
if (event.key === "Escape") { event.preventDefault(); context.emit(props.closeAction, {}); return; }
|
|
166
|
+
if (event.key !== "Tab") return;
|
|
167
|
+
var focusable = dialog.querySelectorAll("button:not(:disabled),input:not(:disabled),select:not(:disabled),textarea:not(:disabled),[tabindex]:not([tabindex='-1'])");
|
|
168
|
+
if (!focusable.length) return;
|
|
169
|
+
var first = focusable[0];
|
|
170
|
+
var last = focusable[focusable.length - 1];
|
|
171
|
+
if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); }
|
|
172
|
+
else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); }
|
|
173
|
+
});
|
|
174
|
+
var focusTimer = setTimeout(function () { if (context.container.contains(overlay)) close.focus(); }, 0);
|
|
175
|
+
context.disposers.push(function () { clearTimeout(focusTimer); });
|
|
176
|
+
return overlay;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function renderMenu(node, props, context) {
|
|
180
|
+
var wrapper = document.createElement("div");
|
|
181
|
+
wrapper.className = "tool-menu";
|
|
182
|
+
var trigger = document.createElement("button");
|
|
183
|
+
trigger.type = "button";
|
|
184
|
+
trigger.className = "tool-button tool-button--variant-ghost";
|
|
185
|
+
trigger.dataset.toolControlId = node.id || "menu-trigger-" + context.autoControlIndex++;
|
|
186
|
+
trigger.textContent = String(props.triggerLabel || props.label);
|
|
187
|
+
trigger.setAttribute("aria-haspopup", "menu");
|
|
188
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
189
|
+
var menu = document.createElement("div");
|
|
190
|
+
menu.className = "tool-menu-popup hidden";
|
|
191
|
+
menu.setAttribute("role", "menu");
|
|
192
|
+
menu.setAttribute("aria-label", String(props.label));
|
|
193
|
+
var dynamic = props.options ? normalizeOptions(props.options) : null;
|
|
194
|
+
var items = dynamic ? dynamic.map(function (option) { return { action: node.action, props: { label: option.label, disabled: option.disabled, args: { value: option.value } } }; }) : node.children || [];
|
|
195
|
+
for (var i = 0; i < items.length; i++) {
|
|
196
|
+
var item = document.createElement("button");
|
|
197
|
+
item.type = "button";
|
|
198
|
+
item.className = "tool-menu-item";
|
|
199
|
+
item.setAttribute("role", "menuitem");
|
|
200
|
+
var itemProps = resolveProps(items[i].props || {}, context.state, context.item);
|
|
201
|
+
item.textContent = String(itemProps.label);
|
|
202
|
+
item.disabled = itemProps.disabled === true;
|
|
203
|
+
item.dataset.menuIndex = String(i);
|
|
204
|
+
item.addEventListener("click", function (event) {
|
|
205
|
+
var selected = items[Number(event.currentTarget.dataset.menuIndex)];
|
|
206
|
+
closeMenu(true);
|
|
207
|
+
emit(selected, resolveProps(selected.props || {}, context.state, context.item), context, {});
|
|
208
|
+
});
|
|
209
|
+
menu.appendChild(item);
|
|
210
|
+
}
|
|
211
|
+
function closeMenu(focus) { menu.classList.add("hidden"); trigger.setAttribute("aria-expanded", "false"); if (focus) trigger.focus(); }
|
|
212
|
+
function openMenu() { menu.classList.remove("hidden"); trigger.setAttribute("aria-expanded", "true"); var first = menu.querySelector("[role='menuitem']:not(:disabled)"); if (first) first.focus(); }
|
|
213
|
+
trigger.addEventListener("click", function () { if (menu.classList.contains("hidden")) openMenu(); else closeMenu(false); });
|
|
214
|
+
trigger.addEventListener("keydown", function (event) { if (event.key === "ArrowDown") { event.preventDefault(); openMenu(); } });
|
|
215
|
+
menu.addEventListener("keydown", function (event) {
|
|
216
|
+
var controls = Array.prototype.slice.call(menu.querySelectorAll("[role='menuitem']:not(:disabled)"));
|
|
217
|
+
if (event.key === "Escape") { event.preventDefault(); closeMenu(true); return; }
|
|
218
|
+
if (["ArrowDown", "ArrowUp", "Home", "End"].indexOf(event.key) === -1) return;
|
|
219
|
+
event.preventDefault();
|
|
220
|
+
if (!controls.length) return;
|
|
221
|
+
var current = controls.indexOf(document.activeElement);
|
|
222
|
+
var next = event.key === "Home" ? 0 : event.key === "End" ? controls.length - 1 : (current + (event.key === "ArrowDown" ? 1 : -1) + controls.length) % controls.length;
|
|
223
|
+
controls[next].focus();
|
|
224
|
+
});
|
|
225
|
+
var outside = function (event) { if (!wrapper.contains(event.target)) closeMenu(false); };
|
|
226
|
+
document.addEventListener("mousedown", outside);
|
|
227
|
+
context.disposers.push(function () { document.removeEventListener("mousedown", outside); });
|
|
228
|
+
wrapper.appendChild(trigger);
|
|
229
|
+
wrapper.appendChild(menu);
|
|
230
|
+
return wrapper;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function renderPagination(node, props, context) {
|
|
234
|
+
var nav = document.createElement("nav");
|
|
235
|
+
nav.className = "tool-pagination";
|
|
236
|
+
nav.setAttribute("aria-label", String(props.label || "Pagination"));
|
|
237
|
+
var page = Math.max(1, Number(valueAtPath(context.state, node.bind, context.item)) || 1);
|
|
238
|
+
var total = Math.max(0, Number(props.total) || 0);
|
|
239
|
+
var pageSize = Math.max(1, Math.min(100, Number(props.pageSize) || 20));
|
|
240
|
+
var pages = Math.max(1, Math.ceil(total / pageSize));
|
|
241
|
+
function appendPageButton(target, label, current) {
|
|
242
|
+
var button = document.createElement("button");
|
|
243
|
+
button.type = "button";
|
|
244
|
+
button.className = "tool-button tool-button--variant-ghost";
|
|
245
|
+
button.textContent = label;
|
|
246
|
+
button.disabled = target < 1 || target > pages;
|
|
247
|
+
if (current) button.setAttribute("aria-current", "page");
|
|
248
|
+
button.addEventListener("click", function () { context.emit(props.pageAction, { value: target, pageSize: pageSize }); });
|
|
249
|
+
nav.appendChild(button);
|
|
250
|
+
}
|
|
251
|
+
appendPageButton(page - 1, "Previous", false);
|
|
252
|
+
var first = Math.max(1, Math.min(pages - 4, page - 2));
|
|
253
|
+
var last = Math.min(pages, first + 4);
|
|
254
|
+
for (var pi = first; pi <= last; pi++) appendPageButton(pi, String(pi), pi === page);
|
|
255
|
+
var status = document.createElement("span");
|
|
256
|
+
status.textContent = "Page " + Math.min(page, pages) + " of " + pages;
|
|
257
|
+
status.setAttribute("aria-live", "polite");
|
|
258
|
+
nav.appendChild(status);
|
|
259
|
+
appendPageButton(page + 1, "Next", false);
|
|
260
|
+
if (Array.isArray(props.pageSizes) && props.pageSizeAction) {
|
|
261
|
+
var size = document.createElement("select");
|
|
262
|
+
size.className = "tool-select tool-pagination-size";
|
|
263
|
+
size.setAttribute("aria-label", "Items per page");
|
|
264
|
+
props.pageSizes.slice(0, 10).forEach(function (value) {
|
|
265
|
+
var option = document.createElement("option");
|
|
266
|
+
option.value = String(value);
|
|
267
|
+
option.textContent = String(value) + " per page";
|
|
268
|
+
option.selected = value === pageSize;
|
|
269
|
+
size.appendChild(option);
|
|
270
|
+
});
|
|
271
|
+
size.addEventListener("change", function () { context.emit(props.pageSizeAction, { value: Number(size.value) }); });
|
|
272
|
+
nav.appendChild(size);
|
|
273
|
+
}
|
|
274
|
+
return nav;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export function renderAdvancedNode(node, props, context, renderNode) {
|
|
278
|
+
if (node.type === "form") return renderForm(node, props, context, renderNode);
|
|
279
|
+
if (node.type === "tabs") return renderTabs(node, props, context, renderNode);
|
|
280
|
+
if (node.type === "dialog") return renderDialog(node, props, context, renderNode);
|
|
281
|
+
if (node.type === "menu") return renderMenu(node, props, context);
|
|
282
|
+
if (node.type === "pagination") return renderPagination(node, props, context);
|
|
283
|
+
if (node.type === "chart") return renderChartNode(node, props, context);
|
|
284
|
+
return null;
|
|
285
|
+
}
|