pinokiod 7.3.15 → 7.4.1
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/api/index.js +111 -15
- package/kernel/api/script/index.js +10 -0
- package/kernel/autolaunch.js +111 -0
- package/kernel/bin/ffmpeg.js +9 -791
- package/kernel/environment.js +89 -1
- package/kernel/git.js +9 -19
- package/kernel/index.js +142 -43
- package/kernel/launch_requirements.js +1115 -0
- package/kernel/procs.js +1 -1
- package/kernel/ready.js +231 -0
- package/kernel/script.js +16 -0
- package/kernel/shells.js +9 -1
- package/kernel/workspace_status.js +111 -45
- package/package.json +2 -3
- package/server/autolaunch.js +725 -0
- package/server/index.js +244 -411
- package/server/views/app.ejs +267 -160
- package/server/views/autolaunch.ejs +363 -75
- package/server/views/index.ejs +550 -26
- package/server/views/partials/app_autolaunch_dependency_events.ejs +99 -0
- package/server/views/partials/app_autolaunch_dependency_save.ejs +10 -0
- package/server/views/partials/app_autolaunch_dependency_styles.ejs +357 -0
- package/server/views/partials/app_autolaunch_modal_helpers.ejs +347 -0
- package/server/views/partials/autolaunch_dependency_helpers.ejs +204 -0
- package/server/views/partials/autolaunch_dependency_save.ejs +13 -0
- package/server/views/partials/autolaunch_dependency_styles.ejs +347 -0
- package/server/views/partials/home_action_modal.ejs +4 -1
- package/server/views/partials/launch_requirements_status_client.ejs +271 -0
- package/server/views/partials/launch_requirements_status_styles.ejs +171 -0
- package/server/views/partials/launch_settings_dependency_save_factory.ejs +45 -0
- package/server/views/partials/launch_settings_dependency_script_loader_factory.ejs +25 -0
- package/server/views/terminal.ejs +196 -2
- package/test/home-autolaunch-live-ui.test.js +455 -0
- package/test/launch-requirements-browser.test.js +579 -0
- package/test/launch-requirements-contract-coverage.test.js +627 -0
- package/test/launch-requirements-real-browser.js +625 -0
- package/test/launch-requirements-status-client.test.js +132 -0
- package/test/launch-requirements.test.js +1806 -0
- package/test/launch-settings-ui.test.js +370 -0
- package/test/procs.test.js +49 -0
- package/test/ready-state.test.js +49 -0
- package/test/server-autolaunch.test.js +1052 -0
- package/test/startup-git-index-benchmark.js +409 -0
- package/test/startup-git-index-browser.js +320 -0
- package/test/startup-git-index-performance.test.js +380 -0
- package/test/startup-git-index-refactor.test.js +450 -0
- package/test/startup-git-index-route.test.js +588 -0
- package/test/universal-launcher.smoke.spec.js +10 -9
- package/test/workspace-gitignore-benchmark.js +815 -0
- package/test/workspace-gitignore-path-scoped.test.js +256 -0
- package/script/verify-ffmpeg.js +0 -459
- package/spec/INSTRUCTION_SYNC.md +0 -432
package/server/views/app.ejs
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
<% if (agent === "electron") { %>
|
|
20
20
|
<link href="/electron.css" rel="stylesheet"/>
|
|
21
21
|
<% } %>
|
|
22
|
+
<% const appMobileBreakpointPx = 980 %>
|
|
22
23
|
<style>
|
|
23
24
|
:root {
|
|
24
25
|
--assist-surface-light: var(--pinokio-chrome-accent-bg-light);
|
|
@@ -603,6 +604,7 @@ body.dark .browserview-network-status {
|
|
|
603
604
|
color: rgba(248, 250, 252, 0.9);
|
|
604
605
|
background: var(--app-page-canvas-bg, #1b1c1d);
|
|
605
606
|
}
|
|
607
|
+
<%- include('./partials/launch_requirements_status_styles') %>
|
|
606
608
|
.browserview-network-status-inner {
|
|
607
609
|
display: flex;
|
|
608
610
|
flex-direction: column;
|
|
@@ -3685,6 +3687,11 @@ body.dark .disk-usage {
|
|
|
3685
3687
|
text-overflow: ellipsis;
|
|
3686
3688
|
color: var(--pinokio-sidebar-tab-muted);
|
|
3687
3689
|
}
|
|
3690
|
+
.app-autolaunch-label > span {
|
|
3691
|
+
min-width: 0;
|
|
3692
|
+
overflow: hidden;
|
|
3693
|
+
text-overflow: ellipsis;
|
|
3694
|
+
}
|
|
3688
3695
|
.app-autolaunch-label i {
|
|
3689
3696
|
width: 16px;
|
|
3690
3697
|
flex: 0 0 16px;
|
|
@@ -3702,6 +3709,7 @@ body.dark .disk-usage {
|
|
|
3702
3709
|
font-size: 11px;
|
|
3703
3710
|
font-weight: 700;
|
|
3704
3711
|
letter-spacing: 0.02em;
|
|
3712
|
+
white-space: nowrap;
|
|
3705
3713
|
}
|
|
3706
3714
|
.app-autolaunch-row[data-enabled="true"] .app-autolaunch-status {
|
|
3707
3715
|
color: rgba(22, 101, 52, 0.95);
|
|
@@ -3793,6 +3801,21 @@ body.dark .app-autolaunch-empty {
|
|
|
3793
3801
|
gap: 8px;
|
|
3794
3802
|
flex: 0 0 auto;
|
|
3795
3803
|
}
|
|
3804
|
+
.app-autolaunch-switch-group {
|
|
3805
|
+
display: inline-flex;
|
|
3806
|
+
align-items: center;
|
|
3807
|
+
gap: 7px;
|
|
3808
|
+
}
|
|
3809
|
+
.app-autolaunch-switch-caption {
|
|
3810
|
+
color: rgba(100, 116, 139, 0.95);
|
|
3811
|
+
font-size: 11px;
|
|
3812
|
+
font-weight: 700;
|
|
3813
|
+
line-height: 1;
|
|
3814
|
+
white-space: nowrap;
|
|
3815
|
+
}
|
|
3816
|
+
body.dark .app-autolaunch-switch-caption {
|
|
3817
|
+
color: rgba(148, 163, 184, 0.95);
|
|
3818
|
+
}
|
|
3796
3819
|
.app-autolaunch-close {
|
|
3797
3820
|
display: inline-flex;
|
|
3798
3821
|
align-items: center;
|
|
@@ -3914,10 +3937,42 @@ body.dark .app-autolaunch-section-label {
|
|
|
3914
3937
|
.app-autolaunch-script-option > div {
|
|
3915
3938
|
min-width: 0;
|
|
3916
3939
|
}
|
|
3940
|
+
.app-autolaunch-clear-script {
|
|
3941
|
+
min-height: 32px;
|
|
3942
|
+
border: 1px solid rgba(15, 23, 42, 0.08);
|
|
3943
|
+
border-radius: 6px;
|
|
3944
|
+
background: transparent;
|
|
3945
|
+
color: rgba(100, 116, 139, 0.95);
|
|
3946
|
+
display: inline-flex;
|
|
3947
|
+
align-items: center;
|
|
3948
|
+
justify-content: center;
|
|
3949
|
+
gap: 6px;
|
|
3950
|
+
padding: 0 9px;
|
|
3951
|
+
font: inherit;
|
|
3952
|
+
font-size: 12px;
|
|
3953
|
+
font-weight: 700;
|
|
3954
|
+
cursor: pointer;
|
|
3955
|
+
}
|
|
3956
|
+
.app-autolaunch-clear-script:hover {
|
|
3957
|
+
background: rgba(148, 163, 184, 0.16);
|
|
3958
|
+
color: rgba(15, 23, 42, 0.9);
|
|
3959
|
+
}
|
|
3960
|
+
.app-autolaunch-clear-script:disabled {
|
|
3961
|
+
cursor: not-allowed;
|
|
3962
|
+
opacity: 0.55;
|
|
3963
|
+
}
|
|
3917
3964
|
body.dark .app-autolaunch-script-option {
|
|
3918
3965
|
border-color: rgba(148, 163, 184, 0.16);
|
|
3919
3966
|
background: rgba(15, 23, 42, 0.72);
|
|
3920
3967
|
}
|
|
3968
|
+
body.dark .app-autolaunch-clear-script {
|
|
3969
|
+
border-color: rgba(148, 163, 184, 0.16);
|
|
3970
|
+
color: rgba(203, 213, 225, 0.9);
|
|
3971
|
+
}
|
|
3972
|
+
body.dark .app-autolaunch-clear-script:hover {
|
|
3973
|
+
background: rgba(148, 163, 184, 0.16);
|
|
3974
|
+
color: rgba(226, 232, 240, 0.92);
|
|
3975
|
+
}
|
|
3921
3976
|
body.dark .app-autolaunch-script-option:hover,
|
|
3922
3977
|
body.dark .app-autolaunch-script-option.selected {
|
|
3923
3978
|
border-color: rgba(96, 165, 250, 0.42);
|
|
@@ -3951,6 +4006,7 @@ body.dark .app-autolaunch-tag {
|
|
|
3951
4006
|
background: rgba(148, 163, 184, 0.18);
|
|
3952
4007
|
color: rgba(203, 213, 225, 0.9);
|
|
3953
4008
|
}
|
|
4009
|
+
<%- include('partials/app_autolaunch_dependency_styles') %>
|
|
3954
4010
|
.app-autolaunch-footer {
|
|
3955
4011
|
display: flex;
|
|
3956
4012
|
align-items: center;
|
|
@@ -6114,7 +6170,7 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
6114
6170
|
}
|
|
6115
6171
|
}
|
|
6116
6172
|
*/
|
|
6117
|
-
@media only screen and (max-width:
|
|
6173
|
+
@media only screen and (max-width: <%= appMobileBreakpointPx %>px) {
|
|
6118
6174
|
body {
|
|
6119
6175
|
display: flex !important;
|
|
6120
6176
|
flex-direction: row !important;
|
|
@@ -6355,7 +6411,7 @@ header.navheader h1 {
|
|
|
6355
6411
|
margin: 0 10px;
|
|
6356
6412
|
}
|
|
6357
6413
|
}
|
|
6358
|
-
@media only screen and (max-width:
|
|
6414
|
+
@media only screen and (max-width: <%= appMobileBreakpointPx %>px) {
|
|
6359
6415
|
:root {
|
|
6360
6416
|
--mobile-bottom-bar-height: calc(46px + env(safe-area-inset-bottom));
|
|
6361
6417
|
}
|
|
@@ -7884,13 +7940,16 @@ body.dark .pinokio-custom-terminal-header {
|
|
|
7884
7940
|
<div class="app-autolaunch-modal-head">
|
|
7885
7941
|
<div>
|
|
7886
7942
|
<div class="app-autolaunch-title">Autolaunch</div>
|
|
7887
|
-
<div class="app-autolaunch-note">
|
|
7943
|
+
<div class="app-autolaunch-note">Choose launch script, startup behavior, and requirements.</div>
|
|
7888
7944
|
</div>
|
|
7889
7945
|
<div class="app-autolaunch-modal-actions">
|
|
7890
|
-
<
|
|
7891
|
-
<span class="app-autolaunch-switch-
|
|
7892
|
-
<
|
|
7893
|
-
|
|
7946
|
+
<div class="app-autolaunch-switch-group">
|
|
7947
|
+
<span class="app-autolaunch-switch-caption">Start with Pinokio</span>
|
|
7948
|
+
<button type="button" class="app-autolaunch-switch" role="switch" aria-checked="<%= autolaunch_app.autolaunch_enabled ? 'true' : 'false' %>" data-app-autolaunch-switch aria-label="Start with Pinokio" title="Start with Pinokio is <%= autolaunch_app.autolaunch_enabled ? 'on' : 'off' %>">
|
|
7949
|
+
<span class="app-autolaunch-switch-label" data-app-autolaunch-switch-label><%= autolaunch_app.autolaunch_enabled ? 'ON' : 'OFF' %></span>
|
|
7950
|
+
<span class="app-autolaunch-switch-thumb" aria-hidden="true"></span>
|
|
7951
|
+
</button>
|
|
7952
|
+
</div>
|
|
7894
7953
|
<button type="button" class="app-autolaunch-close" data-app-autolaunch-close aria-label="Close">
|
|
7895
7954
|
<i class="fa-solid fa-xmark" aria-hidden="true"></i>
|
|
7896
7955
|
</button>
|
|
@@ -7902,6 +7961,12 @@ body.dark .pinokio-custom-terminal-header {
|
|
|
7902
7961
|
<div class="app-autolaunch-empty">Loading scripts...</div>
|
|
7903
7962
|
</div>
|
|
7904
7963
|
</div>
|
|
7964
|
+
<div class="app-autolaunch-modal-section">
|
|
7965
|
+
<div class="app-autolaunch-section-label">Requires</div>
|
|
7966
|
+
<div class="app-autolaunch-dependencies" data-app-autolaunch-dependencies>
|
|
7967
|
+
<div class="app-autolaunch-empty">Loading dependencies...</div>
|
|
7968
|
+
</div>
|
|
7969
|
+
</div>
|
|
7905
7970
|
<div class="app-autolaunch-footer">
|
|
7906
7971
|
<div class="app-autolaunch-feedback" data-app-autolaunch-feedback></div>
|
|
7907
7972
|
<a class="app-autolaunch-link" href="/autolaunch">Manage all</a>
|
|
@@ -7983,6 +8048,7 @@ body.dark .pinokio-custom-terminal-header {
|
|
|
7983
8048
|
<iframe class='selected' src="<%=editor_tab%>" allow="fullscreen *;" allowfullscreen></iframe>
|
|
7984
8049
|
<% } %>
|
|
7985
8050
|
<div id="browserview-network-status" class="browserview-network-status" hidden aria-live="polite"></div>
|
|
8051
|
+
<div id="launch-requirements-status" class="launch-requirements-status" data-launch-requirements-status hidden aria-live="polite"></div>
|
|
7986
8052
|
<%- include('./partials/browser_popout_surface') %>
|
|
7987
8053
|
</main>
|
|
7988
8054
|
<% if (type === 'run') { %>
|
|
@@ -8295,6 +8361,11 @@ body.dark .pinokio-custom-terminal-header {
|
|
|
8295
8361
|
let pendingSelectionRetry = null
|
|
8296
8362
|
let pendingHomeSelectionRetry = null
|
|
8297
8363
|
let initialWorkspaceDiskUsageRequested = false
|
|
8364
|
+
const openWithoutLaunching = <%- JSON.stringify(type === "run" && !autoselect) %>
|
|
8365
|
+
const appMobileBreakpoint = <%= appMobileBreakpointPx %>
|
|
8366
|
+
const appMobileBreakpointQuery = `(max-width: ${appMobileBreakpoint}px)`
|
|
8367
|
+
window.PinokioAppMobileBreakpoint = appMobileBreakpoint
|
|
8368
|
+
window.PinokioAppMobileBreakpointQuery = appMobileBreakpointQuery
|
|
8298
8369
|
const scheduleSelectionRetry = (delay = 100) => {
|
|
8299
8370
|
if (pendingSelectionRetry !== null) {
|
|
8300
8371
|
return
|
|
@@ -10004,7 +10075,9 @@ const rerenderMenuSection = (container, html) => {
|
|
|
10004
10075
|
return ""
|
|
10005
10076
|
}
|
|
10006
10077
|
})()
|
|
10007
|
-
|
|
10078
|
+
const triggeredByUser = Boolean(eventParam || explicitTarget)
|
|
10079
|
+
const automaticSelectionDisabled = openWithoutLaunching && !triggeredByUser
|
|
10080
|
+
let persistedSelectionRaw = automaticSelectionDisabled ? null : (selectionKey && storage ? storage.getItem(selectionKey) : null)
|
|
10008
10081
|
const devRouteActive = /\/dev(?:$|\/)/.test(currentPath || "")
|
|
10009
10082
|
let persistedSelectionPayload = null
|
|
10010
10083
|
if (persistedSelectionRaw) {
|
|
@@ -10029,9 +10102,8 @@ const rerenderMenuSection = (container, html) => {
|
|
|
10029
10102
|
persistedSelectionRaw = null
|
|
10030
10103
|
}
|
|
10031
10104
|
const originalHasPersistedSelection = Boolean(persistedSelectionPayload)
|
|
10032
|
-
const
|
|
10033
|
-
const
|
|
10034
|
-
const skipPersistedSelection = followCurrentDefault || (ignorePersistedSelection && Boolean(document.querySelector('[data-default]')))
|
|
10105
|
+
const followCurrentDefault = !automaticSelectionDisabled && forceDefaultSelection && !triggeredByUser
|
|
10106
|
+
const skipPersistedSelection = automaticSelectionDisabled || followCurrentDefault || (ignorePersistedSelection && Boolean(document.querySelector('[data-default]')))
|
|
10035
10107
|
let hasPersistedSelection = skipPersistedSelection ? false : originalHasPersistedSelection
|
|
10036
10108
|
if (skipPersistedSelection) {
|
|
10037
10109
|
persistedSelectionRaw = null
|
|
@@ -10053,7 +10125,7 @@ const rerenderMenuSection = (container, html) => {
|
|
|
10053
10125
|
target = eventParam.target?.closest(".frame-link") || null
|
|
10054
10126
|
}
|
|
10055
10127
|
|
|
10056
|
-
if (!target && global_selector) {
|
|
10128
|
+
if (!target && !automaticSelectionDisabled && global_selector) {
|
|
10057
10129
|
const candidate = document.querySelector(global_selector)
|
|
10058
10130
|
if (candidate) {
|
|
10059
10131
|
target = candidate
|
|
@@ -10065,11 +10137,11 @@ const rerenderMenuSection = (container, html) => {
|
|
|
10065
10137
|
}
|
|
10066
10138
|
}
|
|
10067
10139
|
|
|
10068
|
-
if (!target && !skipPersistedSelection) {
|
|
10140
|
+
if (!target && !automaticSelectionDisabled && !skipPersistedSelection) {
|
|
10069
10141
|
preselected = document.querySelector('#devtab.frame-link.selected') || document.querySelector('.frame-link.selected')
|
|
10070
10142
|
}
|
|
10071
10143
|
|
|
10072
|
-
if (!target && persistedSelectionPayload) {
|
|
10144
|
+
if (!target && !automaticSelectionDisabled && persistedSelectionPayload) {
|
|
10073
10145
|
target = restorePersistedFrameLink(persistedSelectionPayload)
|
|
10074
10146
|
if (!target && originalHasPersistedSelection) {
|
|
10075
10147
|
scheduleSelectionRetry()
|
|
@@ -10077,7 +10149,7 @@ const rerenderMenuSection = (container, html) => {
|
|
|
10077
10149
|
}
|
|
10078
10150
|
}
|
|
10079
10151
|
|
|
10080
|
-
if (!target && !skipPersistedSelection) {
|
|
10152
|
+
if (!target && !automaticSelectionDisabled && !skipPersistedSelection) {
|
|
10081
10153
|
const urlKey = selectionUrlStorageKey()
|
|
10082
10154
|
const storedUrl = urlKey && storage ? storage.getItem(urlKey) : null
|
|
10083
10155
|
if (storedUrl) {
|
|
@@ -10085,7 +10157,7 @@ const rerenderMenuSection = (container, html) => {
|
|
|
10085
10157
|
}
|
|
10086
10158
|
}
|
|
10087
10159
|
|
|
10088
|
-
if (!target && followCurrentDefault) {
|
|
10160
|
+
if (!target && !automaticSelectionDisabled && followCurrentDefault) {
|
|
10089
10161
|
const defaultSelection = getDefaultSelection()
|
|
10090
10162
|
if (defaultSelection) {
|
|
10091
10163
|
target = defaultSelection
|
|
@@ -10093,11 +10165,11 @@ const rerenderMenuSection = (container, html) => {
|
|
|
10093
10165
|
}
|
|
10094
10166
|
|
|
10095
10167
|
const devTab = document.querySelector('#devtab.frame-link')
|
|
10096
|
-
if (!target && preselected && preselected !== devTab) {
|
|
10168
|
+
if (!target && !automaticSelectionDisabled && preselected && preselected !== devTab) {
|
|
10097
10169
|
target = preselected
|
|
10098
10170
|
}
|
|
10099
10171
|
|
|
10100
|
-
if (!triggeredByUser && !resolvedByGlobalSelector && !target && devRouteActive && devTab) {
|
|
10172
|
+
if (!automaticSelectionDisabled && !triggeredByUser && !resolvedByGlobalSelector && !target && devRouteActive && devTab) {
|
|
10101
10173
|
const defaultCandidate = getDefaultSelection()
|
|
10102
10174
|
if (pluginLaunchActive && defaultCandidate) {
|
|
10103
10175
|
target = defaultCandidate
|
|
@@ -10106,7 +10178,7 @@ const rerenderMenuSection = (container, html) => {
|
|
|
10106
10178
|
}
|
|
10107
10179
|
}
|
|
10108
10180
|
|
|
10109
|
-
if (!target && preselected) {
|
|
10181
|
+
if (!target && !automaticSelectionDisabled && preselected) {
|
|
10110
10182
|
target = preselected
|
|
10111
10183
|
}
|
|
10112
10184
|
|
|
@@ -10141,7 +10213,7 @@ const rerenderMenuSection = (container, html) => {
|
|
|
10141
10213
|
}
|
|
10142
10214
|
<% } %>
|
|
10143
10215
|
|
|
10144
|
-
if (!target && preselected) {
|
|
10216
|
+
if (!target && !automaticSelectionDisabled && preselected) {
|
|
10145
10217
|
target = preselected
|
|
10146
10218
|
}
|
|
10147
10219
|
|
|
@@ -10278,7 +10350,6 @@ const rerenderMenuSection = (container, html) => {
|
|
|
10278
10350
|
eventParam.preventDefault()
|
|
10279
10351
|
eventParam.stopPropagation()
|
|
10280
10352
|
}
|
|
10281
|
-
|
|
10282
10353
|
// save target.href
|
|
10283
10354
|
<% if (type !== "run") { %>
|
|
10284
10355
|
let _url = new URL(target.href)
|
|
@@ -10372,7 +10443,7 @@ const rerenderMenuSection = (container, html) => {
|
|
|
10372
10443
|
writeFrameInjectDescriptors(targetFrame, targetInjectDescriptors)
|
|
10373
10444
|
publishBrowserviewInjectTargets([], { sync: true })
|
|
10374
10445
|
targetFrame.classList.remove("hidden")
|
|
10375
|
-
|
|
10446
|
+
let mode = target.getAttribute("data-mode")
|
|
10376
10447
|
if (mode === "refresh") {
|
|
10377
10448
|
if (targetFrame.src !== target.href) {
|
|
10378
10449
|
targetFrame.src = target.href
|
|
@@ -11031,14 +11102,12 @@ const rerenderMenuSection = (container, html) => {
|
|
|
11031
11102
|
}
|
|
11032
11103
|
|
|
11033
11104
|
|
|
11034
|
-
|
|
11035
|
-
|
|
11036
|
-
const mobileMenuQuery = window.matchMedia ? window.matchMedia("(max-width: 768px)") : null
|
|
11105
|
+
const mobileMenuQuery = window.matchMedia ? window.matchMedia(appMobileBreakpointQuery) : null
|
|
11037
11106
|
const isMobileMenuOpen = () => document.body.classList.contains("mobile-menu-open")
|
|
11038
11107
|
const appcanvas = document.querySelector(".appcanvas")
|
|
11039
11108
|
const closeWindowButton = document.querySelector("#close-window")
|
|
11040
11109
|
const mobileMenuBackdrop = document.querySelector("[data-mobile-menu-backdrop]")
|
|
11041
|
-
const isMobilePanelLayout = () => mobileMenuQuery ? mobileMenuQuery.matches : window.innerWidth <=
|
|
11110
|
+
const isMobilePanelLayout = () => mobileMenuQuery ? mobileMenuQuery.matches : window.innerWidth <= appMobileBreakpoint
|
|
11042
11111
|
const normalizeMobilePanelName = (value) => {
|
|
11043
11112
|
return value === "logs" || value === "ask-ai" || value === "feed" ? value : ""
|
|
11044
11113
|
}
|
|
@@ -11778,7 +11847,7 @@ const rerenderMenuSection = (container, html) => {
|
|
|
11778
11847
|
if (appcanvas && sidebarResizer && sidebarContainer) {
|
|
11779
11848
|
const SIDEBAR_MIN_WIDTH = 140
|
|
11780
11849
|
const SIDEBAR_MAX_WIDTH = 560
|
|
11781
|
-
const sidebarMobileQuery = window.matchMedia ? window.matchMedia(
|
|
11850
|
+
const sidebarMobileQuery = window.matchMedia ? window.matchMedia(appMobileBreakpointQuery) : null
|
|
11782
11851
|
const workspaceName = "<%= typeof name === 'string' ? name : '' %>"
|
|
11783
11852
|
const sidebarWidthStorageKey = workspaceName
|
|
11784
11853
|
? `pinokio-app-sidebar-width:${workspaceName}`
|
|
@@ -17796,7 +17865,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
17796
17865
|
enabled = false
|
|
17797
17866
|
}
|
|
17798
17867
|
|
|
17799
|
-
const communityModeQuery = window.matchMedia ? window.matchMedia("(max-width:
|
|
17868
|
+
const communityModeQuery = window.matchMedia ? window.matchMedia(window.PinokioAppMobileBreakpointQuery || "(max-width: <%= appMobileBreakpointPx %>px)") : null
|
|
17800
17869
|
let communityMode = false
|
|
17801
17870
|
|
|
17802
17871
|
const setCommunityMode = (next, opts) => {
|
|
@@ -18480,6 +18549,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
18480
18549
|
}
|
|
18481
18550
|
})()
|
|
18482
18551
|
|
|
18552
|
+
<%- include('partials/launch_requirements_status_client') %>
|
|
18553
|
+
|
|
18483
18554
|
;(function() {
|
|
18484
18555
|
const root = document.querySelector("[data-app-autolaunch]")
|
|
18485
18556
|
const initialState = <%- JSON.stringify((typeof autolaunch_app !== "undefined" && autolaunch_app) ? autolaunch_app : null).replace(/</g, "\\u003c") %>
|
|
@@ -18493,8 +18564,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
18493
18564
|
const switchLabel = root.querySelector("[data-app-autolaunch-switch-label]")
|
|
18494
18565
|
const closeButton = root.querySelector("[data-app-autolaunch-close]")
|
|
18495
18566
|
const scriptsEl = root.querySelector("[data-app-autolaunch-scripts]")
|
|
18567
|
+
const dependenciesEl = root.querySelector("[data-app-autolaunch-dependencies]")
|
|
18496
18568
|
const feedbackEl = root.querySelector("[data-app-autolaunch-feedback]")
|
|
18497
|
-
if (!appId || !button || !status || !modal || !switchButton || !switchLabel || !closeButton || !scriptsEl || !feedbackEl) return
|
|
18569
|
+
if (!appId || !button || !status || !modal || !switchButton || !switchLabel || !closeButton || !scriptsEl || !dependenciesEl || !feedbackEl) return
|
|
18498
18570
|
|
|
18499
18571
|
let state = Object.assign({}, initialState)
|
|
18500
18572
|
let candidateState = null
|
|
@@ -18502,6 +18574,13 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
18502
18574
|
let selectedScript = state.autolaunch || ""
|
|
18503
18575
|
let loadingCandidates = false
|
|
18504
18576
|
let saving = false
|
|
18577
|
+
let savingDependencies = false
|
|
18578
|
+
let savingDependencyScript = false
|
|
18579
|
+
let dependencyPickerOpen = false
|
|
18580
|
+
let dependencyScriptPickerOpen = ""
|
|
18581
|
+
let pendingDependencyId = ""
|
|
18582
|
+
let dependencyScriptCandidates = {}
|
|
18583
|
+
let dependencyScriptSelections = {}
|
|
18505
18584
|
|
|
18506
18585
|
const escapeHtml = (value) => {
|
|
18507
18586
|
if (value === null || value === undefined) return ""
|
|
@@ -18520,124 +18599,17 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
18520
18599
|
if (!candidateState) return []
|
|
18521
18600
|
return [].concat(candidateState.menu || [], candidateState.other || [])
|
|
18522
18601
|
}
|
|
18523
|
-
|
|
18524
|
-
|
|
18525
|
-
|
|
18526
|
-
|
|
18527
|
-
|
|
18528
|
-
|
|
18529
|
-
|
|
18530
|
-
|
|
18531
|
-
|
|
18532
|
-
|
|
18533
|
-
|
|
18534
|
-
const setBusy = (busy) => {
|
|
18535
|
-
saving = !!busy
|
|
18536
|
-
switchButton.disabled = saving || loadingCandidates
|
|
18537
|
-
button.toggleAttribute("aria-busy", saving)
|
|
18538
|
-
scriptsEl.querySelectorAll("input").forEach((input) => {
|
|
18539
|
-
input.disabled = saving
|
|
18540
|
-
})
|
|
18541
|
-
}
|
|
18542
|
-
const renderStatus = () => {
|
|
18543
|
-
const enabled = !!(state && state.autolaunch_enabled)
|
|
18544
|
-
status.textContent = enabled ? "ON" : "OFF"
|
|
18545
|
-
button.dataset.enabled = enabled ? "true" : "false"
|
|
18546
|
-
button.setAttribute("aria-label", `Auto launch ${enabled ? "On" : "Off"}`)
|
|
18547
|
-
switchButton.setAttribute("aria-checked", enabled ? "true" : "false")
|
|
18548
|
-
switchButton.title = `Auto launch is ${enabled ? "on" : "off"}`
|
|
18549
|
-
switchLabel.textContent = enabled ? "ON" : "OFF"
|
|
18550
|
-
root.classList.toggle("enabled", enabled)
|
|
18551
|
-
}
|
|
18552
|
-
const setOpen = (open) => {
|
|
18553
|
-
root.classList.toggle("open", !!open)
|
|
18554
|
-
button.setAttribute("aria-expanded", open ? "true" : "false")
|
|
18555
|
-
modal.classList.toggle("hidden", !open)
|
|
18556
|
-
if (open) {
|
|
18557
|
-
if (!candidateState && !loadingCandidates) {
|
|
18558
|
-
loadCandidates()
|
|
18559
|
-
}
|
|
18560
|
-
window.setTimeout(() => {
|
|
18561
|
-
if (!modal.classList.contains("hidden")) {
|
|
18562
|
-
switchButton.focus()
|
|
18563
|
-
}
|
|
18564
|
-
}, 0)
|
|
18565
|
-
} else {
|
|
18566
|
-
button.focus()
|
|
18567
|
-
}
|
|
18568
|
-
}
|
|
18569
|
-
const renderScripts = () => {
|
|
18570
|
-
if (loadingCandidates) {
|
|
18571
|
-
scriptsEl.innerHTML = '<div class="app-autolaunch-empty">Loading scripts...</div>'
|
|
18572
|
-
setBusy(false)
|
|
18573
|
-
return
|
|
18574
|
-
}
|
|
18575
|
-
if (candidateError) {
|
|
18576
|
-
scriptsEl.innerHTML = `<div class="app-autolaunch-empty">${escapeHtml(candidateError)}</div>`
|
|
18577
|
-
setBusy(false)
|
|
18578
|
-
return
|
|
18579
|
-
}
|
|
18580
|
-
if (!candidateState) {
|
|
18581
|
-
scriptsEl.innerHTML = '<div class="app-autolaunch-empty">Open to load scripts.</div>'
|
|
18582
|
-
setBusy(false)
|
|
18583
|
-
return
|
|
18584
|
-
}
|
|
18585
|
-
const candidates = allCandidates().slice()
|
|
18586
|
-
const current = candidateState.current || state.autolaunch || ""
|
|
18587
|
-
if (current && !candidates.some((candidate) => candidate && candidate.script === current)) {
|
|
18588
|
-
candidates.unshift({
|
|
18589
|
-
script: current,
|
|
18590
|
-
label: "Current",
|
|
18591
|
-
source: "current",
|
|
18592
|
-
current: true
|
|
18593
|
-
})
|
|
18594
|
-
}
|
|
18595
|
-
if (!selectedScript) {
|
|
18596
|
-
selectedScript = chooseInitialScript(candidateState)
|
|
18597
|
-
}
|
|
18598
|
-
if (candidates.length === 0) {
|
|
18599
|
-
scriptsEl.innerHTML = '<div class="app-autolaunch-empty">No local scripts were found for this app.</div>'
|
|
18600
|
-
setBusy(false)
|
|
18601
|
-
return
|
|
18602
|
-
}
|
|
18603
|
-
scriptsEl.innerHTML = candidates.map((candidate) => {
|
|
18604
|
-
const script = candidate && candidate.script ? candidate.script : ""
|
|
18605
|
-
if (!script) return ""
|
|
18606
|
-
const label = candidate.label || script
|
|
18607
|
-
const checked = script === selectedScript ? "checked" : ""
|
|
18608
|
-
const selected = script === selectedScript ? " selected" : ""
|
|
18609
|
-
const tags = [
|
|
18610
|
-
candidate.current ? '<span class="app-autolaunch-tag">Current</span>' : "",
|
|
18611
|
-
candidate.menu_default ? '<span class="app-autolaunch-tag">Default</span>' : "",
|
|
18612
|
-
candidate.has_params ? '<span class="app-autolaunch-tag">Params ignored</span>' : ""
|
|
18613
|
-
].filter(Boolean).join("")
|
|
18614
|
-
const pathLine = label === script
|
|
18615
|
-
? ""
|
|
18616
|
-
: `<div class="app-autolaunch-script-path" title="${escapeHtml(script)}">${escapeHtml(script)}</div>`
|
|
18617
|
-
return `
|
|
18618
|
-
<label class="app-autolaunch-script-option${selected}">
|
|
18619
|
-
<input type="radio" name="app-autolaunch-script" value="${escapeHtml(script)}" ${checked}>
|
|
18620
|
-
<div>
|
|
18621
|
-
<div class="app-autolaunch-script-title"><span>${escapeHtml(label)}</span>${tags}</div>
|
|
18622
|
-
${pathLine}
|
|
18623
|
-
</div>
|
|
18624
|
-
</label>
|
|
18625
|
-
`
|
|
18626
|
-
}).join("")
|
|
18627
|
-
setBusy(false)
|
|
18628
|
-
}
|
|
18629
|
-
const syncState = (updated) => {
|
|
18630
|
-
if (updated) {
|
|
18631
|
-
state = Object.assign({}, state, updated)
|
|
18632
|
-
if (candidateState) {
|
|
18633
|
-
candidateState.app = Object.assign({}, candidateState.app || {}, updated)
|
|
18634
|
-
candidateState.current = updated.autolaunch || ""
|
|
18635
|
-
}
|
|
18636
|
-
if (updated.autolaunch) {
|
|
18637
|
-
selectedScript = updated.autolaunch
|
|
18638
|
-
}
|
|
18639
|
-
}
|
|
18640
|
-
renderStatus()
|
|
18602
|
+
<%- include('partials/app_autolaunch_modal_helpers') %>
|
|
18603
|
+
const hasLaunchRequirementConfig = () => {
|
|
18604
|
+
return !!(
|
|
18605
|
+
state.autolaunch &&
|
|
18606
|
+
Array.isArray(state.autolaunch_depends) &&
|
|
18607
|
+
state.autolaunch_depends.length > 0
|
|
18608
|
+
)
|
|
18609
|
+
}
|
|
18610
|
+
const notifyLaunchRequirementsConfigured = () => {
|
|
18611
|
+
if (!hasLaunchRequirementConfig()) return
|
|
18612
|
+
window.dispatchEvent(new CustomEvent("pinokio:launch-requirements-configured"))
|
|
18641
18613
|
}
|
|
18642
18614
|
const loadCandidates = async () => {
|
|
18643
18615
|
loadingCandidates = true
|
|
@@ -18654,16 +18626,84 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
18654
18626
|
}
|
|
18655
18627
|
candidateState = data
|
|
18656
18628
|
syncState(data.app)
|
|
18657
|
-
selectedScript =
|
|
18629
|
+
selectedScript = configuredScript(data)
|
|
18658
18630
|
setFeedback("")
|
|
18659
18631
|
} catch (error) {
|
|
18660
18632
|
candidateError = error && error.message ? error.message : "Failed to load scripts."
|
|
18661
18633
|
} finally {
|
|
18662
18634
|
loadingCandidates = false
|
|
18663
18635
|
renderScripts()
|
|
18636
|
+
renderDependencies()
|
|
18664
18637
|
}
|
|
18665
18638
|
}
|
|
18666
|
-
|
|
18639
|
+
<%- include('partials/app_autolaunch_dependency_save') %>
|
|
18640
|
+
const updateDependencyCandidateState = (updatedApp) => {
|
|
18641
|
+
if (!updatedApp || !updatedApp.id || !candidateState || !Array.isArray(candidateState.dependency_apps)) return
|
|
18642
|
+
candidateState.dependency_apps = candidateState.dependency_apps.map((app) => app.id === updatedApp.id ? updatedApp : app)
|
|
18643
|
+
}
|
|
18644
|
+
<%- include('partials/launch_settings_dependency_script_loader_factory') %>
|
|
18645
|
+
const loadDependencyScriptCandidates = createLaunchSettingsDependencyScriptLoader({
|
|
18646
|
+
getCache: () => dependencyScriptCandidates,
|
|
18647
|
+
render: renderDependencies
|
|
18648
|
+
})
|
|
18649
|
+
const saveDependencyScript = async (dependencyId, script) => {
|
|
18650
|
+
const dependency = dependencyById(dependencyId)
|
|
18651
|
+
if (!dependency || !script || savingDependencyScript) return
|
|
18652
|
+
savingDependencyScript = true
|
|
18653
|
+
setBusy(true)
|
|
18654
|
+
setFeedback("Saving requirement script...")
|
|
18655
|
+
try {
|
|
18656
|
+
const response = await fetch("/autolaunch", {
|
|
18657
|
+
method: "POST",
|
|
18658
|
+
headers: {
|
|
18659
|
+
"Content-Type": "application/json",
|
|
18660
|
+
"Accept": "application/json"
|
|
18661
|
+
},
|
|
18662
|
+
body: JSON.stringify({
|
|
18663
|
+
app: dependencyId,
|
|
18664
|
+
script,
|
|
18665
|
+
enabled: !!dependency.autolaunch_enabled
|
|
18666
|
+
})
|
|
18667
|
+
})
|
|
18668
|
+
const data = await response.json()
|
|
18669
|
+
if (!response.ok || !data.ok) {
|
|
18670
|
+
throw new Error(data.error || "Failed to save launch script.")
|
|
18671
|
+
}
|
|
18672
|
+
updateDependencyCandidateState(data.app)
|
|
18673
|
+
if (pendingDependencyId === dependencyId) {
|
|
18674
|
+
const dependencies = Array.isArray(state.autolaunch_depends) ? state.autolaunch_depends.slice() : []
|
|
18675
|
+
if (!dependencies.includes(dependencyId)) {
|
|
18676
|
+
const savedDependency = await saveDependencies(dependencies.concat(dependencyId), "Requirement saved.")
|
|
18677
|
+
if (savedDependency) {
|
|
18678
|
+
notifyLaunchRequirementsConfigured()
|
|
18679
|
+
pendingDependencyId = ""
|
|
18680
|
+
delete dependencyScriptSelections[dependencyId]
|
|
18681
|
+
dependencyScriptPickerOpen = ""
|
|
18682
|
+
renderDependencies()
|
|
18683
|
+
}
|
|
18684
|
+
} else {
|
|
18685
|
+
pendingDependencyId = ""
|
|
18686
|
+
delete dependencyScriptSelections[dependencyId]
|
|
18687
|
+
dependencyScriptPickerOpen = ""
|
|
18688
|
+
renderDependencies()
|
|
18689
|
+
notifyLaunchRequirementsConfigured()
|
|
18690
|
+
setFeedback("Requirement saved.")
|
|
18691
|
+
}
|
|
18692
|
+
} else {
|
|
18693
|
+
dependencyScriptPickerOpen = ""
|
|
18694
|
+
delete dependencyScriptSelections[dependencyId]
|
|
18695
|
+
renderDependencies()
|
|
18696
|
+
setFeedback("Requirement script saved.")
|
|
18697
|
+
}
|
|
18698
|
+
} catch (error) {
|
|
18699
|
+
setFeedback(error && error.message ? error.message : "Failed to save launch script.", true)
|
|
18700
|
+
renderDependencies()
|
|
18701
|
+
} finally {
|
|
18702
|
+
savingDependencyScript = false
|
|
18703
|
+
setBusy(false)
|
|
18704
|
+
}
|
|
18705
|
+
}
|
|
18706
|
+
const saveScript = async (script, enabled = !!state.autolaunch_enabled) => {
|
|
18667
18707
|
if (saving) return
|
|
18668
18708
|
setBusy(true)
|
|
18669
18709
|
setFeedback(script ? "Saving..." : "Disabling...")
|
|
@@ -18674,17 +18714,52 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
18674
18714
|
"Content-Type": "application/json",
|
|
18675
18715
|
"Accept": "application/json"
|
|
18676
18716
|
},
|
|
18677
|
-
body: JSON.stringify({ app: appId, script: script || "" })
|
|
18717
|
+
body: JSON.stringify({ app: appId, script: script || "", enabled: !!enabled })
|
|
18718
|
+
})
|
|
18719
|
+
const data = await response.json()
|
|
18720
|
+
if (!response.ok || !data.ok) {
|
|
18721
|
+
throw new Error(data.error || "Failed to save Autolaunch settings.")
|
|
18722
|
+
}
|
|
18723
|
+
syncState(data.app)
|
|
18724
|
+
notifyLaunchRequirementsConfigured()
|
|
18725
|
+
setFeedback(data.app && data.app.autolaunch_enabled ? "Saved." : (script ? "Launch script saved." : "Disabled."))
|
|
18726
|
+
renderScripts()
|
|
18727
|
+
renderDependencies()
|
|
18728
|
+
} catch (error) {
|
|
18729
|
+
setFeedback(error && error.message ? error.message : "Failed to save Autolaunch settings.", true)
|
|
18730
|
+
renderStatus()
|
|
18731
|
+
} finally {
|
|
18732
|
+
setBusy(false)
|
|
18733
|
+
}
|
|
18734
|
+
}
|
|
18735
|
+
const clearScript = async () => {
|
|
18736
|
+
if (saving) return
|
|
18737
|
+
if (Array.isArray(state.autolaunch_depends) && state.autolaunch_depends.length > 0) {
|
|
18738
|
+
setFeedback("Remove requirements before clearing this app's launch script.", true)
|
|
18739
|
+
return
|
|
18740
|
+
}
|
|
18741
|
+
setBusy(true)
|
|
18742
|
+
setFeedback("Clearing launch script...")
|
|
18743
|
+
try {
|
|
18744
|
+
const response = await fetch("/autolaunch", {
|
|
18745
|
+
method: "POST",
|
|
18746
|
+
headers: {
|
|
18747
|
+
"Content-Type": "application/json",
|
|
18748
|
+
"Accept": "application/json"
|
|
18749
|
+
},
|
|
18750
|
+
body: JSON.stringify({ app: appId, clear_script: true })
|
|
18678
18751
|
})
|
|
18679
18752
|
const data = await response.json()
|
|
18680
18753
|
if (!response.ok || !data.ok) {
|
|
18681
|
-
throw new Error(data.error || "Failed to
|
|
18754
|
+
throw new Error(data.error || "Failed to clear launch script.")
|
|
18682
18755
|
}
|
|
18683
18756
|
syncState(data.app)
|
|
18684
|
-
|
|
18757
|
+
notifyLaunchRequirementsConfigured()
|
|
18758
|
+
setFeedback("Launch script cleared.")
|
|
18685
18759
|
renderScripts()
|
|
18760
|
+
renderDependencies()
|
|
18686
18761
|
} catch (error) {
|
|
18687
|
-
setFeedback(error && error.message ? error.message : "Failed to
|
|
18762
|
+
setFeedback(error && error.message ? error.message : "Failed to clear launch script.", true)
|
|
18688
18763
|
renderStatus()
|
|
18689
18764
|
} finally {
|
|
18690
18765
|
setBusy(false)
|
|
@@ -18693,23 +18768,25 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
18693
18768
|
const toggleAutolaunch = async () => {
|
|
18694
18769
|
if (saving || loadingCandidates) return
|
|
18695
18770
|
if (state.autolaunch_enabled) {
|
|
18696
|
-
|
|
18771
|
+
const script = selectedScript || state.autolaunch || ""
|
|
18772
|
+
await saveScript(script, false)
|
|
18697
18773
|
return
|
|
18698
18774
|
}
|
|
18699
18775
|
if (!candidateState) {
|
|
18700
18776
|
await loadCandidates()
|
|
18701
18777
|
}
|
|
18702
|
-
const script = selectedScript ||
|
|
18778
|
+
const script = selectedScript || ""
|
|
18703
18779
|
if (!script) {
|
|
18704
|
-
setFeedback("Choose a script first.", true)
|
|
18780
|
+
setFeedback("Choose a launch script first.", true)
|
|
18705
18781
|
return
|
|
18706
18782
|
}
|
|
18707
18783
|
selectedScript = script
|
|
18708
|
-
await saveScript(script)
|
|
18784
|
+
await saveScript(script, true)
|
|
18709
18785
|
}
|
|
18710
18786
|
|
|
18711
18787
|
renderStatus()
|
|
18712
18788
|
renderScripts()
|
|
18789
|
+
renderDependencies()
|
|
18713
18790
|
|
|
18714
18791
|
button.addEventListener("click", (event) => {
|
|
18715
18792
|
event.preventDefault()
|
|
@@ -18738,11 +18815,41 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
18738
18815
|
if (!input) return
|
|
18739
18816
|
selectedScript = input.value
|
|
18740
18817
|
renderScripts()
|
|
18741
|
-
if (
|
|
18742
|
-
saveScript(selectedScript)
|
|
18818
|
+
if (selectedScript !== state.autolaunch) {
|
|
18819
|
+
saveScript(selectedScript, !!state.autolaunch_enabled)
|
|
18743
18820
|
}
|
|
18744
18821
|
})
|
|
18745
|
-
|
|
18822
|
+
scriptsEl.addEventListener("click", (event) => {
|
|
18823
|
+
const clear = event.target && event.target.closest("[data-app-autolaunch-clear-script]")
|
|
18824
|
+
if (!clear) return
|
|
18825
|
+
event.preventDefault()
|
|
18826
|
+
clearScript()
|
|
18827
|
+
})
|
|
18828
|
+
<%- include('partials/app_autolaunch_dependency_events') %>
|
|
18829
|
+
window.addEventListener("pinokio:launch-requirements-choose-script", async (event) => {
|
|
18830
|
+
const dependency = event && event.detail ? event.detail.app : ""
|
|
18831
|
+
if (!dependency) return
|
|
18832
|
+
event.preventDefault()
|
|
18833
|
+
if (!candidateState && !loadingCandidates) {
|
|
18834
|
+
await loadCandidates()
|
|
18835
|
+
}
|
|
18836
|
+
setOpen(true)
|
|
18837
|
+
pendingDependencyId = ""
|
|
18838
|
+
dependencyScriptPickerOpen = dependency
|
|
18839
|
+
const dependencyApp = dependencyById(dependency)
|
|
18840
|
+
dependencyScriptSelections[dependency] = dependencyApp && dependencyApp.autolaunch ? dependencyApp.autolaunch : ""
|
|
18841
|
+
renderDependencies()
|
|
18842
|
+
loadDependencyScriptCandidates(dependency)
|
|
18843
|
+
})
|
|
18844
|
+
;(async () => {
|
|
18845
|
+
const params = new URLSearchParams(window.location.search || "")
|
|
18846
|
+
if (params.get("autolaunch") !== "1") return
|
|
18847
|
+
setOpen(true)
|
|
18848
|
+
if (!candidateState && !loadingCandidates) {
|
|
18849
|
+
await loadCandidates()
|
|
18850
|
+
}
|
|
18851
|
+
})()
|
|
18852
|
+
document.addEventListener("keydown", (event) => {
|
|
18746
18853
|
if (event.key === "Escape" && !modal.classList.contains("hidden")) {
|
|
18747
18854
|
setOpen(false)
|
|
18748
18855
|
}
|