pinokiod 7.5.19 → 7.5.21
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/kernel/bin/index.js +0 -5
- package/kernel/bin/setup.js +0 -1
- package/kernel/index.js +0 -3
- package/package.json +1 -1
- package/server/public/common.js +1 -1
- package/server/public/style.css +34 -0
- package/server/public/urldropdown.css +272 -0
- package/server/public/urldropdown.js +44 -12
- package/server/views/app.ejs +190 -146
- package/server/views/autolaunch.ejs +10 -1
- package/server/views/columns.ejs +13 -1
- package/server/views/d.ejs +54 -137
- package/server/views/index.ejs +14 -6
- package/server/views/partials/app_autolaunch_modal_helpers.ejs +4 -0
- package/server/views/partials/d_column_subtitle.ejs +10 -0
- package/server/views/partials/d_menu_column.ejs +18 -0
- package/server/views/partials/d_terminal_column.ejs +2 -11
- package/server/views/partials/d_terminal_options.ejs +1 -18
- package/server/views/partials/d_tool_tab.ejs +32 -0
- package/server/views/partials/main_sidebar.ejs +3 -0
- package/server/views/rows.ejs +13 -1
- package/system/plugin/antigravity-cli/common.js +10 -16
- package/test/antigravity-cli-plugin.test.js +26 -19
- package/test/home-autolaunch-live-ui.test.js +70 -0
- package/test/launch-requirements-browser.test.js +259 -3
- package/test/plugin-dev-iframe.test.js +67 -1
- package/test/plugin-sources.test.js +1 -1
- package/test/url-split-modal.test.js +107 -0
- package/system/plugin/crush/crush.png +0 -0
- package/system/plugin/crush/pinokio.js +0 -15
- package/system/plugin/qwen/pinokio.js +0 -34
- package/system/plugin/qwen/qwen.png +0 -0
- package/system/plugin/windsurf/pinokio.js +0 -23
- package/system/plugin/windsurf/windsurf.png +0 -0
package/server/views/d.ejs
CHANGED
|
@@ -872,144 +872,44 @@ body.dark .terminal-shell-options {
|
|
|
872
872
|
</div>
|
|
873
873
|
|
|
874
874
|
<%
|
|
875
|
-
|
|
876
|
-
const
|
|
877
|
-
const
|
|
878
|
-
|
|
875
|
+
const dynamicItems = Array.isArray(dynamic) ? dynamic : [];
|
|
876
|
+
const indexState = { value: 0 };
|
|
877
|
+
const getItemDescription = (item) => {
|
|
878
|
+
if (!item || typeof item !== "object") {
|
|
879
|
+
return "";
|
|
880
|
+
}
|
|
881
|
+
const candidates = [
|
|
882
|
+
item.description,
|
|
883
|
+
item.subtitle,
|
|
884
|
+
item.summary,
|
|
885
|
+
item.metadata && item.metadata.description,
|
|
886
|
+
item.meta && item.meta.description,
|
|
887
|
+
];
|
|
888
|
+
for (const candidate of candidates) {
|
|
889
|
+
if (typeof candidate === "string" && candidate.trim()) {
|
|
890
|
+
return candidate.trim();
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
return "";
|
|
894
|
+
};
|
|
895
|
+
const userTerminal = dynamicItems.find((item) => item && (item.title === "Terminals" || item.title === "Project Shell"));
|
|
896
|
+
const cliMenu = dynamicItems.find((item) => item && item.title === "Terminal Apps");
|
|
897
|
+
const ideMenu = dynamicItems.find((item) => item && item.title === "Desktop Apps");
|
|
879
898
|
const handled = new Set();
|
|
880
|
-
const primaryColumnCount = [userTerminal, cliMenu, ideMenu].filter((item) => item && item.menu && item.menu.length).length;
|
|
881
899
|
if (userTerminal) handled.add(userTerminal);
|
|
882
900
|
if (cliMenu) handled.add(cliMenu);
|
|
883
901
|
if (ideMenu) handled.add(ideMenu);
|
|
884
|
-
const remaining =
|
|
902
|
+
const remaining = dynamicItems.filter((item) => !handled.has(item));
|
|
885
903
|
%>
|
|
886
904
|
|
|
887
|
-
<div class='menu-grid
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
<%
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
<h3><i class='<%= cliMenu.icon %>'></i> <%= cliMenu.title %></h3>
|
|
896
|
-
</div>
|
|
897
|
-
<% if (cliMenu.subtitle || cliMenu.subtitle_link_href) { %>
|
|
898
|
-
<div class='column-subtitle'>
|
|
899
|
-
<% if (cliMenu.subtitle) { %>
|
|
900
|
-
<span><%= cliMenu.subtitle %></span><% if (cliMenu.subtitle_link_href && cliMenu.subtitle_link_label) { %> <% } %>
|
|
901
|
-
<% } %>
|
|
902
|
-
<% if (cliMenu.subtitle_link_href && cliMenu.subtitle_link_label) { %>
|
|
903
|
-
<a class='column-subtitle-link' href="<%= cliMenu.subtitle_link_href %>" target="_parent"><%= cliMenu.subtitle_link_label %></a>
|
|
904
|
-
<% } %>
|
|
905
|
-
</div>
|
|
906
|
-
<% } %>
|
|
907
|
-
<div class='tab-content'>
|
|
908
|
-
<% cliMenu.menu.forEach((i) => { %>
|
|
909
|
-
<div class='tab' role="button" tabindex="0" data-index="<%= index++ %>" data-target="@<%= i.href %>" data-href="<%= i.href %>">
|
|
910
|
-
<% if (i.image) { %>
|
|
911
|
-
<img src="<%= i.image %>">
|
|
912
|
-
<% } else if (i.icon) { %>
|
|
913
|
-
<i class="img <%= i.icon %>"></i>
|
|
914
|
-
<% } %>
|
|
915
|
-
<div class='tab-copy'>
|
|
916
|
-
<h2 class='tab-title'><%= i.title %></h2>
|
|
917
|
-
<% if (i.subtitle) { %>
|
|
918
|
-
<div class='tab-subtitle subtitle'><%= i.subtitle %></div>
|
|
919
|
-
<% } %>
|
|
920
|
-
</div>
|
|
921
|
-
<div class='tab-actions'>
|
|
922
|
-
<button class="tab-action-link" type="button" data-plugin-settings="true" data-href="<%= i.href %>" title="Manage plugin" data-tippy-content="Manage plugin" aria-label="Manage plugin">
|
|
923
|
-
<i class="fa-solid fa-gear"></i>
|
|
924
|
-
</button>
|
|
925
|
-
<div class='disclosure-indicator' aria-hidden="true">
|
|
926
|
-
<i class="fa-solid fa-chevron-right"></i>
|
|
927
|
-
</div>
|
|
928
|
-
</div>
|
|
929
|
-
</div>
|
|
930
|
-
<% }) %>
|
|
931
|
-
</div>
|
|
932
|
-
</div>
|
|
933
|
-
<% } %>
|
|
934
|
-
|
|
935
|
-
<% if (ideMenu && ideMenu.menu && ideMenu.menu.length) { %>
|
|
936
|
-
<div class='menu-container menu-column ide-column'>
|
|
937
|
-
<div class='tab-header'>
|
|
938
|
-
<h3><i class='<%= ideMenu.icon %>'></i> <%= ideMenu.title %></h3>
|
|
939
|
-
</div>
|
|
940
|
-
<% if (ideMenu.subtitle || ideMenu.subtitle_link_href) { %>
|
|
941
|
-
<div class='column-subtitle'>
|
|
942
|
-
<% if (ideMenu.subtitle) { %>
|
|
943
|
-
<span><%= ideMenu.subtitle %></span><% if (ideMenu.subtitle_link_href && ideMenu.subtitle_link_label) { %> <% } %>
|
|
944
|
-
<% } %>
|
|
945
|
-
<% if (ideMenu.subtitle_link_href && ideMenu.subtitle_link_label) { %>
|
|
946
|
-
<a class='column-subtitle-link' href="<%= ideMenu.subtitle_link_href %>" target="_parent"><%= ideMenu.subtitle_link_label %></a>
|
|
947
|
-
<% } %>
|
|
948
|
-
</div>
|
|
949
|
-
<% } %>
|
|
950
|
-
<div class='tab-content'>
|
|
951
|
-
<% ideMenu.menu.forEach((i) => { %>
|
|
952
|
-
<div class='tab' role="button" tabindex="0" data-index="<%= index++ %>" data-target="@<%= i.href %>" data-href="<%= i.href %>">
|
|
953
|
-
<% if (i.image) { %>
|
|
954
|
-
<img src="<%= i.image %>">
|
|
955
|
-
<% } else if (i.icon) { %>
|
|
956
|
-
<i class="img <%= i.icon %>"></i>
|
|
957
|
-
<% } %>
|
|
958
|
-
<div class='tab-copy'>
|
|
959
|
-
<h2 class='tab-title'><%= i.title %></h2>
|
|
960
|
-
<% if (i.subtitle) { %>
|
|
961
|
-
<div class='tab-subtitle subtitle'><%= i.subtitle %></div>
|
|
962
|
-
<% } %>
|
|
963
|
-
</div>
|
|
964
|
-
<div class='tab-actions'>
|
|
965
|
-
<button class="tab-action-link" type="button" data-plugin-settings="true" data-href="<%= i.href %>" title="Manage plugin" data-tippy-content="Manage plugin" aria-label="Manage plugin">
|
|
966
|
-
<i class="fa-solid fa-gear"></i>
|
|
967
|
-
</button>
|
|
968
|
-
<div class='disclosure-indicator' aria-hidden="true">
|
|
969
|
-
<i class="fa-solid fa-chevron-right"></i>
|
|
970
|
-
</div>
|
|
971
|
-
</div>
|
|
972
|
-
</div>
|
|
973
|
-
<% }) %>
|
|
974
|
-
</div>
|
|
975
|
-
</div>
|
|
976
|
-
<% } %>
|
|
977
|
-
</div>
|
|
978
|
-
|
|
979
|
-
<% remaining.forEach((item) => { %>
|
|
980
|
-
<% if (item.menu) { %>
|
|
981
|
-
<div class='menu-container'>
|
|
982
|
-
<div class='tab-header'>
|
|
983
|
-
<h3><i class='<%= item.icon %>'></i> <%= item.title %></h3>
|
|
984
|
-
</div>
|
|
985
|
-
<div class='tab-content'>
|
|
986
|
-
<% item.menu.forEach((i) => { %>
|
|
987
|
-
<div class='tab' role="button" tabindex="0" data-index="<%= index++ %>" data-target="@<%= i.href %>" data-href="<%= i.href %>">
|
|
988
|
-
<% if (i.image) { %>
|
|
989
|
-
<img src="<%= i.image %>">
|
|
990
|
-
<% } else if (i.icon) { %>
|
|
991
|
-
<i class="img <%= i.icon %>"></i>
|
|
992
|
-
<% } %>
|
|
993
|
-
<div class='tab-copy'>
|
|
994
|
-
<h2 class='tab-title'><%= i.title %></h2>
|
|
995
|
-
<% if (i.subtitle) { %>
|
|
996
|
-
<div class='tab-subtitle subtitle'><%= i.subtitle %></div>
|
|
997
|
-
<% } %>
|
|
998
|
-
</div>
|
|
999
|
-
<div class='tab-actions'>
|
|
1000
|
-
<button class="tab-action-link" type="button" data-plugin-settings="true" data-href="<%= i.href %>" title="Manage plugin" data-tippy-content="Manage plugin" aria-label="Manage plugin">
|
|
1001
|
-
<i class="fa-solid fa-gear"></i>
|
|
1002
|
-
</button>
|
|
1003
|
-
<div class='disclosure-indicator' aria-hidden="true">
|
|
1004
|
-
<i class="fa-solid fa-chevron-right"></i>
|
|
1005
|
-
</div>
|
|
1006
|
-
</div>
|
|
1007
|
-
</div>
|
|
1008
|
-
<% }) %>
|
|
1009
|
-
</div>
|
|
1010
|
-
</div>
|
|
1011
|
-
<% } else { %>
|
|
1012
|
-
<div class='tab' data-index="<%= index++ %>">
|
|
905
|
+
<div class='menu-grid'>
|
|
906
|
+
<%- include('./partials/d_menu_column', { section: cliMenu, indexState, getItemDescription, className: 'cli-column', showSettings: true }) %>
|
|
907
|
+
<%- include('./partials/d_menu_column', { section: ideMenu, indexState, getItemDescription, className: 'ide-column', showSettings: true }) %>
|
|
908
|
+
<% remaining.forEach((item) => { %>
|
|
909
|
+
<% if (item.menu) { %>
|
|
910
|
+
<%- include('./partials/d_menu_column', { section: item, indexState, getItemDescription, showSettings: true }) %>
|
|
911
|
+
<% } else { %>
|
|
912
|
+
<div class='tab' data-index="<%= indexState.value++ %>">
|
|
1013
913
|
<% if (item.image) { %>
|
|
1014
914
|
<img src="<%= item.image %>">
|
|
1015
915
|
<% } else if (item.icon) { %>
|
|
@@ -1017,8 +917,9 @@ body.dark .terminal-shell-options {
|
|
|
1017
917
|
<% } %>
|
|
1018
918
|
<div class='col'>
|
|
1019
919
|
<h2><%= item.title %></h2>
|
|
1020
|
-
<%
|
|
1021
|
-
|
|
920
|
+
<% const itemDescription = getItemDescription(item); %>
|
|
921
|
+
<% if (itemDescription) { %>
|
|
922
|
+
<div class='subtitle'><%= itemDescription %></div>
|
|
1022
923
|
<% } %>
|
|
1023
924
|
<div class='btns'>
|
|
1024
925
|
<% if (item.link) { %>
|
|
@@ -1028,8 +929,12 @@ body.dark .terminal-shell-options {
|
|
|
1028
929
|
</div>
|
|
1029
930
|
</div>
|
|
1030
931
|
</div>
|
|
932
|
+
<% } %>
|
|
933
|
+
<% }) %>
|
|
934
|
+
<% if (userTerminal && userTerminal.menu && userTerminal.menu.length) { %>
|
|
935
|
+
<%- include('./partials/d_terminal_column', { userTerminal, indexState, getItemDescription }) %>
|
|
1031
936
|
<% } %>
|
|
1032
|
-
|
|
937
|
+
</div>
|
|
1033
938
|
<% if (retry) { %>
|
|
1034
939
|
<div class='requirements'>
|
|
1035
940
|
<div class='content'>
|
|
@@ -1287,12 +1192,24 @@ const getPluginInstallRedirect = async (rawHref) => {
|
|
|
1287
1192
|
pluginInstallPreflightCache.set(pluginPath, redirectHref)
|
|
1288
1193
|
return redirectHref
|
|
1289
1194
|
}
|
|
1195
|
+
const navigateOutsideLauncher = (href) => {
|
|
1196
|
+
if (!href) {
|
|
1197
|
+
return
|
|
1198
|
+
}
|
|
1199
|
+
try {
|
|
1200
|
+
if (window.parent && window.parent !== window && window.parent !== window.top) {
|
|
1201
|
+
window.parent.location.href = href
|
|
1202
|
+
return
|
|
1203
|
+
}
|
|
1204
|
+
} catch (_) {}
|
|
1205
|
+
window.location.href = href
|
|
1206
|
+
}
|
|
1290
1207
|
const redirectToPluginInstallIfNeeded = async (rawHref) => {
|
|
1291
1208
|
const redirectHref = await getPluginInstallRedirect(rawHref)
|
|
1292
1209
|
if (!redirectHref) {
|
|
1293
1210
|
return false
|
|
1294
1211
|
}
|
|
1295
|
-
|
|
1212
|
+
navigateOutsideLauncher(redirectHref)
|
|
1296
1213
|
return true
|
|
1297
1214
|
}
|
|
1298
1215
|
const pluginSettingsHrefFromLaunchHref = (rawHref) => {
|
|
@@ -1462,7 +1379,7 @@ document.addEventListener("click", async (e) => {
|
|
|
1462
1379
|
e.stopPropagation()
|
|
1463
1380
|
const settingsHref = pluginSettingsHrefFromLaunchHref(settingsTarget.getAttribute('data-href') || '')
|
|
1464
1381
|
if (settingsHref) {
|
|
1465
|
-
|
|
1382
|
+
navigateOutsideLauncher(settingsHref)
|
|
1466
1383
|
}
|
|
1467
1384
|
return
|
|
1468
1385
|
}
|
package/server/views/index.ejs
CHANGED
|
@@ -2346,9 +2346,11 @@ const startHomeAutolaunchPolling = () => {
|
|
|
2346
2346
|
updateHomeActionStatus(line, "Running")
|
|
2347
2347
|
syncStopButtons(line, scripts)
|
|
2348
2348
|
const runningSection = getOrCreateRunningSection()
|
|
2349
|
-
if (runningSection) {
|
|
2349
|
+
if (runningSection && line.parentElement !== runningSection) {
|
|
2350
2350
|
runningSection.appendChild(line)
|
|
2351
|
+
return true
|
|
2351
2352
|
}
|
|
2353
|
+
return false
|
|
2352
2354
|
}
|
|
2353
2355
|
const getOrCreateNotRunningSection = () => {
|
|
2354
2356
|
let section = document.querySelector(".not-running-apps")
|
|
@@ -2374,9 +2376,11 @@ const startHomeAutolaunchPolling = () => {
|
|
|
2374
2376
|
syncStopButtons(line, [])
|
|
2375
2377
|
activeHomeAutolaunchApps.delete(line.getAttribute("data-autolaunch-app"))
|
|
2376
2378
|
const notRunningSection = getOrCreateNotRunningSection()
|
|
2377
|
-
if (notRunningSection) {
|
|
2379
|
+
if (notRunningSection && line.parentElement !== notRunningSection) {
|
|
2378
2380
|
notRunningSection.appendChild(line)
|
|
2381
|
+
return true
|
|
2379
2382
|
}
|
|
2383
|
+
return false
|
|
2380
2384
|
}
|
|
2381
2385
|
const autolaunchDependencyLabel = (autolaunch, dependencyId) => {
|
|
2382
2386
|
const apps = autolaunch && autolaunch.apps ? autolaunch.apps : {}
|
|
@@ -2472,18 +2476,19 @@ const startHomeAutolaunchPolling = () => {
|
|
|
2472
2476
|
}
|
|
2473
2477
|
const autolaunch = state.autolaunch || {}
|
|
2474
2478
|
const apps = autolaunch.apps || {}
|
|
2479
|
+
let shouldReorder = false
|
|
2475
2480
|
for (const line of lines) {
|
|
2476
2481
|
const app = line.getAttribute("data-autolaunch-app")
|
|
2477
2482
|
const autolaunchState = apps[app]
|
|
2478
2483
|
const runningScripts = scriptsByApp.get(app) || []
|
|
2479
2484
|
if (autolaunchState && !shouldDisplayAutolaunchStatus(app, autolaunchState, apps, runningApps)) {
|
|
2480
|
-
markAutolaunchIdle(line)
|
|
2485
|
+
shouldReorder = markAutolaunchIdle(line) || shouldReorder
|
|
2481
2486
|
} else if (isPreparingAutolaunchState(autolaunchState)) {
|
|
2482
2487
|
updateAutolaunchWaitingVisuals(line, autolaunchState, autolaunch, runningScripts)
|
|
2483
2488
|
} else if (runningApps.has(app)) {
|
|
2484
|
-
markAutolaunchRunning(line, runningScripts)
|
|
2489
|
+
shouldReorder = markAutolaunchRunning(line, runningScripts) || shouldReorder
|
|
2485
2490
|
} else if (state.launch_complete) {
|
|
2486
|
-
markAutolaunchIdle(line)
|
|
2491
|
+
shouldReorder = markAutolaunchIdle(line) || shouldReorder
|
|
2487
2492
|
} else {
|
|
2488
2493
|
updateAutolaunchWaitingVisuals(line, autolaunchState, autolaunch, runningScripts)
|
|
2489
2494
|
}
|
|
@@ -2491,9 +2496,12 @@ const startHomeAutolaunchPolling = () => {
|
|
|
2491
2496
|
if (getStartingLines().length === 0) {
|
|
2492
2497
|
if (hadStartingLines) {
|
|
2493
2498
|
hadStartingLines = false
|
|
2494
|
-
|
|
2499
|
+
shouldReorder = true
|
|
2495
2500
|
}
|
|
2496
2501
|
}
|
|
2502
|
+
if (shouldReorder) {
|
|
2503
|
+
reorderHomeSectionsByPreference()
|
|
2504
|
+
}
|
|
2497
2505
|
}
|
|
2498
2506
|
const requestHomeStatus = () => {
|
|
2499
2507
|
return new Promise((resolve, reject) => {
|
|
@@ -180,6 +180,10 @@
|
|
|
180
180
|
const setOpen = (open) => {
|
|
181
181
|
root.classList.toggle("open", !!open)
|
|
182
182
|
button.setAttribute("aria-expanded", open ? "true" : "false")
|
|
183
|
+
if (open && modal.parentElement !== document.body) {
|
|
184
|
+
// Avoid transformed sidebar ancestors trapping the fixed dialog.
|
|
185
|
+
document.body.appendChild(modal)
|
|
186
|
+
}
|
|
183
187
|
modal.classList.toggle("hidden", !open)
|
|
184
188
|
if (open) {
|
|
185
189
|
if (!candidateState && !loadingCandidates) {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<% if (section && (section.subtitle || section.subtitle_link_href)) { %>
|
|
2
|
+
<div class='column-subtitle'>
|
|
3
|
+
<% if (section.subtitle) { %>
|
|
4
|
+
<span><%= section.subtitle %></span><% if (section.subtitle_link_href && section.subtitle_link_label) { %> <% } %>
|
|
5
|
+
<% } %>
|
|
6
|
+
<% if (section.subtitle_link_href && section.subtitle_link_label) { %>
|
|
7
|
+
<a class='column-subtitle-link' href="<%= section.subtitle_link_href %>" target="_parent"><%= section.subtitle_link_label %></a>
|
|
8
|
+
<% } %>
|
|
9
|
+
</div>
|
|
10
|
+
<% } %>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<%
|
|
2
|
+
const rows = section && Array.isArray(section.menu) ? section.menu : [];
|
|
3
|
+
const sectionClass = typeof className === "string" ? className : "";
|
|
4
|
+
const enableSettings = typeof showSettings === "boolean" ? showSettings : true;
|
|
5
|
+
%>
|
|
6
|
+
<% if (section && rows.length) { %>
|
|
7
|
+
<div class='menu-container menu-column <%= sectionClass %>'>
|
|
8
|
+
<div class='tab-header'>
|
|
9
|
+
<h3><i class='<%= section.icon %>'></i> <%= section.title %></h3>
|
|
10
|
+
</div>
|
|
11
|
+
<%- include('./d_column_subtitle', { section }) %>
|
|
12
|
+
<div class='tab-content'>
|
|
13
|
+
<% rows.forEach((i) => { %>
|
|
14
|
+
<%- include('./d_tool_tab', { i, indexState, getItemDescription, showSettings: enableSettings }) %>
|
|
15
|
+
<% }) %>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
<% } %>
|
|
@@ -2,16 +2,7 @@
|
|
|
2
2
|
<div class='tab-header'>
|
|
3
3
|
<h3><i class='<%= userTerminal.icon %>'></i> <%= userTerminal.title === "Terminals" ? "Project Shell" : userTerminal.title %></h3>
|
|
4
4
|
</div>
|
|
5
|
-
|
|
6
|
-
<div class='column-subtitle'>
|
|
7
|
-
<% if (userTerminal.subtitle) { %>
|
|
8
|
-
<span><%= userTerminal.subtitle %></span><% if (userTerminal.subtitle_link_href && userTerminal.subtitle_link_label) { %> <% } %>
|
|
9
|
-
<% } %>
|
|
10
|
-
<% if (userTerminal.subtitle_link_href && userTerminal.subtitle_link_label) { %>
|
|
11
|
-
<a class='column-subtitle-link' href="<%= userTerminal.subtitle_link_href %>" target="_parent"><%= userTerminal.subtitle_link_label %></a>
|
|
12
|
-
<% } %>
|
|
13
|
-
</div>
|
|
14
|
-
<% } %>
|
|
5
|
+
<%- include('./d_column_subtitle', { section: userTerminal }) %>
|
|
15
6
|
<div class='tab-content'>
|
|
16
7
|
<% userTerminal.menu.forEach((i) => { %>
|
|
17
8
|
<div class='terminal-shell-group'>
|
|
@@ -29,7 +20,7 @@
|
|
|
29
20
|
</div>
|
|
30
21
|
</div>
|
|
31
22
|
<div class='terminal-shell-options'>
|
|
32
|
-
<%- include('./d_terminal_options', { options: i.menu || [] }) %>
|
|
23
|
+
<%- include('./d_terminal_options', { options: i.menu || [], indexState, getItemDescription }) %>
|
|
33
24
|
</div>
|
|
34
25
|
</div>
|
|
35
26
|
<% }) %>
|
|
@@ -1,20 +1,3 @@
|
|
|
1
1
|
<% options.forEach((i) => { %>
|
|
2
|
-
|
|
3
|
-
<% if (i.image) { %>
|
|
4
|
-
<img src="<%= i.image %>">
|
|
5
|
-
<% } else if (i.icon) { %>
|
|
6
|
-
<i class="img <%= i.icon %>"></i>
|
|
7
|
-
<% } %>
|
|
8
|
-
<div class='tab-copy'>
|
|
9
|
-
<h2 class='tab-title'><%= i.title %></h2>
|
|
10
|
-
<% if (i.subtitle) { %>
|
|
11
|
-
<div class='tab-subtitle subtitle'><%= i.subtitle %></div>
|
|
12
|
-
<% } %>
|
|
13
|
-
</div>
|
|
14
|
-
<div class='tab-actions'>
|
|
15
|
-
<div class='disclosure-indicator' aria-hidden="true">
|
|
16
|
-
<i class="fa-solid fa-chevron-right"></i>
|
|
17
|
-
</div>
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
2
|
+
<%- include('./d_tool_tab', { i, indexState, getItemDescription, showSettings: false, terminalOption: true, className: 'terminal-option-tab' }) %>
|
|
20
3
|
<% }) %>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<%
|
|
2
|
+
const href = i && typeof i.href === "string" ? i.href : "";
|
|
3
|
+
const target = href ? `@${href}` : "";
|
|
4
|
+
const tabIndex = typeof indexState !== "undefined" && indexState && typeof indexState.value === "number" ? indexState.value++ : 0;
|
|
5
|
+
const tabClass = ["tab", typeof className === "string" ? className : ""].filter(Boolean).join(" ");
|
|
6
|
+
const description = typeof getItemDescription === "function" ? getItemDescription(i) : (i && (i.description || i.subtitle || ""));
|
|
7
|
+
const enableSettings = typeof showSettings !== "undefined" && showSettings === true && href;
|
|
8
|
+
const isTerminalOption = typeof terminalOption !== "undefined" && terminalOption === true;
|
|
9
|
+
%>
|
|
10
|
+
<div class='<%= tabClass %>' role="button" tabindex="0" data-index="<%= tabIndex %>"<% if (isTerminalOption) { %> data-terminal-option-tab="true"<% } %> data-target="<%= target %>" data-href="<%= href %>">
|
|
11
|
+
<% if (i.image) { %>
|
|
12
|
+
<img src="<%= i.image %>">
|
|
13
|
+
<% } else if (i.icon) { %>
|
|
14
|
+
<i class="img <%= i.icon %>"></i>
|
|
15
|
+
<% } %>
|
|
16
|
+
<div class='tab-copy'>
|
|
17
|
+
<h2 class='tab-title'><%= i.title %></h2>
|
|
18
|
+
<% if (description) { %>
|
|
19
|
+
<div class='tab-subtitle subtitle'><%= description %></div>
|
|
20
|
+
<% } %>
|
|
21
|
+
</div>
|
|
22
|
+
<div class='tab-actions'>
|
|
23
|
+
<% if (enableSettings) { %>
|
|
24
|
+
<button class="tab-action-link" type="button" data-plugin-settings="true" data-href="<%= href %>" title="Manage plugin" data-tippy-content="Manage plugin" aria-label="Manage plugin">
|
|
25
|
+
<i class="fa-solid fa-gear"></i>
|
|
26
|
+
</button>
|
|
27
|
+
<% } %>
|
|
28
|
+
<div class='disclosure-indicator' aria-hidden="true">
|
|
29
|
+
<i class="fa-solid fa-chevron-right"></i>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
package/server/views/rows.ejs
CHANGED
|
@@ -321,8 +321,20 @@ body[data-agent='electron'] {
|
|
|
321
321
|
}
|
|
322
322
|
});
|
|
323
323
|
window.addEventListener('message', (event) => {
|
|
324
|
+
if (event.data && event.data.e === "layout-state-request") {
|
|
325
|
+
const closable = Array.from(document.querySelectorAll('iframe')).some((iframe) => {
|
|
326
|
+
return event.source === iframe.contentWindow;
|
|
327
|
+
});
|
|
328
|
+
if (event.source && typeof event.source.postMessage === "function") {
|
|
329
|
+
event.source.postMessage({
|
|
330
|
+
e: "layout-state",
|
|
331
|
+
closable
|
|
332
|
+
}, "*");
|
|
333
|
+
}
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
324
336
|
if (event.data && event.data.e === "close") {
|
|
325
|
-
// find the frame
|
|
337
|
+
// find the frame
|
|
326
338
|
// Find which iframe sent the message
|
|
327
339
|
const row0 = document.getElementById('row0');
|
|
328
340
|
const row1 = document.getElementById('row1');
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const fs = require("fs")
|
|
2
2
|
const path = require("path")
|
|
3
|
+
const installer = require("./install")
|
|
3
4
|
|
|
4
5
|
const MANAGED_DIR_PARTS = ["bin", "antigravity-cli"]
|
|
5
6
|
|
|
@@ -46,24 +47,17 @@ function workspaceFor(context, kernel) {
|
|
|
46
47
|
return args.cwd || kernel.path("home")
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
function installSteps(kernel) {
|
|
50
|
+
async function installSteps(kernel) {
|
|
51
|
+
await installer.install({
|
|
52
|
+
installDir: installDir(kernel),
|
|
53
|
+
managedDir: managedDir(kernel),
|
|
54
|
+
})
|
|
50
55
|
return [{
|
|
51
|
-
id: "
|
|
52
|
-
method: "
|
|
56
|
+
id: "installed",
|
|
57
|
+
method: "notify",
|
|
53
58
|
params: {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
_: [
|
|
57
|
-
process.execPath,
|
|
58
|
-
installerPath(),
|
|
59
|
-
"--install-dir",
|
|
60
|
-
installDir(kernel),
|
|
61
|
-
"--managed-dir",
|
|
62
|
-
managedDir(kernel),
|
|
63
|
-
]
|
|
64
|
-
},
|
|
65
|
-
path: kernel.path(),
|
|
66
|
-
buffer: 1024,
|
|
59
|
+
html: "Antigravity CLI installed in Pinokio.",
|
|
60
|
+
type: "success",
|
|
67
61
|
}
|
|
68
62
|
}]
|
|
69
63
|
}
|
|
@@ -7,6 +7,7 @@ const test = require("node:test")
|
|
|
7
7
|
const antigravityCli = require("../system/plugin/antigravity-cli/pinokio")
|
|
8
8
|
const antigravityCliAuto = require("../system/plugin/antigravity-cli-auto/pinokio")
|
|
9
9
|
const antigravityCommon = require("../system/plugin/antigravity-cli/common")
|
|
10
|
+
const antigravityInstaller = require("../system/plugin/antigravity-cli/install")
|
|
10
11
|
|
|
11
12
|
function createKernel(root, platform = "darwin") {
|
|
12
13
|
return {
|
|
@@ -25,28 +26,34 @@ test("Antigravity CLI plugins expose managed lifecycle actions", () => {
|
|
|
25
26
|
}
|
|
26
27
|
})
|
|
27
28
|
|
|
28
|
-
test("Antigravity CLI install and update
|
|
29
|
+
test("Antigravity CLI install and update call the bundled installer internally", async () => {
|
|
29
30
|
const root = path.join(os.tmpdir(), "pinokio-antigravity-test")
|
|
30
31
|
const kernel = createKernel(root)
|
|
32
|
+
const calls = []
|
|
33
|
+
const originalInstall = antigravityInstaller.install
|
|
34
|
+
antigravityInstaller.install = async (options) => {
|
|
35
|
+
calls.push(options)
|
|
36
|
+
}
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
assert.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
try {
|
|
39
|
+
const install = await antigravityCli.install(kernel, {})
|
|
40
|
+
const update = await antigravityCli.update(kernel, {})
|
|
41
|
+
|
|
42
|
+
assert.deepEqual(calls, [{
|
|
43
|
+
installDir: path.join(root, "bin"),
|
|
44
|
+
managedDir: path.join(root, "bin", "antigravity-cli"),
|
|
45
|
+
}, {
|
|
46
|
+
installDir: path.join(root, "bin"),
|
|
47
|
+
managedDir: path.join(root, "bin", "antigravity-cli"),
|
|
48
|
+
}])
|
|
49
|
+
|
|
50
|
+
for (const steps of [install, update]) {
|
|
51
|
+
assert.equal(steps.length, 1)
|
|
52
|
+
assert.equal(steps[0].method, "notify")
|
|
53
|
+
assert.equal(steps[0].params.type, "success")
|
|
54
|
+
}
|
|
55
|
+
} finally {
|
|
56
|
+
antigravityInstaller.install = originalInstall
|
|
50
57
|
}
|
|
51
58
|
})
|
|
52
59
|
|
|
@@ -82,6 +82,43 @@ function createHomeDomWithApps(appIds) {
|
|
|
82
82
|
})
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
function createHomeDomForIdleOrdering() {
|
|
86
|
+
const row = (appId, name, stopButton = false) => `
|
|
87
|
+
<div
|
|
88
|
+
class="line align-top home-app-line"
|
|
89
|
+
data-name="${name}"
|
|
90
|
+
data-autolaunch-app="${appId}"
|
|
91
|
+
data-autolaunch-starting="0"
|
|
92
|
+
data-autolaunch-script="start.js"
|
|
93
|
+
>
|
|
94
|
+
<h3><span class="title"><i class="fa-solid fa-circle"></i></span></h3>
|
|
95
|
+
<div class="menu-btns">
|
|
96
|
+
<button class="open-actions-modal" data-dialog-id="actions-${appId}" type="button">menu</button>
|
|
97
|
+
${stopButton ? `
|
|
98
|
+
<button class="btn shutdown" type="button" data-src="api/${appId}/start.js">
|
|
99
|
+
<i class="fa-solid fa-stop" aria-hidden="true"></i>
|
|
100
|
+
<span>Stop start.js</span>
|
|
101
|
+
</button>
|
|
102
|
+
` : ""}
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
<div id="actions-${appId}"><div class="home-actions-title-row"></div></div>
|
|
106
|
+
`
|
|
107
|
+
return new JSDOM(`
|
|
108
|
+
<!doctype html>
|
|
109
|
+
<body>
|
|
110
|
+
<div class="running-apps">${row("alpha", "Alpha", true)}</div>
|
|
111
|
+
<div class="not-running-apps">
|
|
112
|
+
${row("beta", "Beta")}
|
|
113
|
+
${row("gamma", "Gamma")}
|
|
114
|
+
</div>
|
|
115
|
+
</body>
|
|
116
|
+
`, {
|
|
117
|
+
runScripts: "outside-only",
|
|
118
|
+
url: "http://127.0.0.1:42000/home?sort=az"
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
85
122
|
function installHomeStatusMocks(window, responses) {
|
|
86
123
|
const timeouts = []
|
|
87
124
|
const intervals = []
|
|
@@ -225,6 +262,39 @@ test("home one-shot status refresh can update a stopped app row", async () => {
|
|
|
225
262
|
assert.equal(window.document.querySelector(".not-running-apps").contains(line), true)
|
|
226
263
|
})
|
|
227
264
|
|
|
265
|
+
test("home one-shot status refresh preserves idle app sort order after moving stopped row", async () => {
|
|
266
|
+
const script = await homeAutolaunchScript({ launchComplete: true })
|
|
267
|
+
const dom = createHomeDomForIdleOrdering()
|
|
268
|
+
const { window } = dom
|
|
269
|
+
const responses = [{
|
|
270
|
+
launch_complete: true,
|
|
271
|
+
running_apps: [],
|
|
272
|
+
running_scripts: [],
|
|
273
|
+
autolaunch: { apps: {} }
|
|
274
|
+
}]
|
|
275
|
+
installHomeStatusMocks(window, responses)
|
|
276
|
+
let reorderCalls = 0
|
|
277
|
+
window.reorderHomeSectionsByPreference = () => {
|
|
278
|
+
reorderCalls += 1
|
|
279
|
+
for (const selector of [".running-apps", ".not-running-apps"]) {
|
|
280
|
+
const section = window.document.querySelector(selector)
|
|
281
|
+
const lines = Array.from(section.querySelectorAll(":scope > .line"))
|
|
282
|
+
lines.sort((a, b) => (a.getAttribute("data-name") || "").localeCompare(b.getAttribute("data-name") || ""))
|
|
283
|
+
for (const line of lines) {
|
|
284
|
+
section.appendChild(line)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
window.eval(script)
|
|
290
|
+
await window.refreshHomeStatusOnce("alpha")
|
|
291
|
+
|
|
292
|
+
const idleNames = Array.from(window.document.querySelectorAll(".not-running-apps > .line"))
|
|
293
|
+
.map((line) => line.getAttribute("data-name"))
|
|
294
|
+
assert.deepEqual(idleNames, ["Alpha", "Beta", "Gamma"])
|
|
295
|
+
assert.equal(reorderCalls, 1)
|
|
296
|
+
})
|
|
297
|
+
|
|
228
298
|
test("home live status discovers a running target even when preparation status has already cleared", async () => {
|
|
229
299
|
const script = await homeAutolaunchScript()
|
|
230
300
|
const dom = createHomeDom({ running: false, stopButton: false })
|