pinokiod 5.1.10 → 5.1.11
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/fs/download_worker.js +158 -0
- package/kernel/api/fs/index.js +95 -91
- package/kernel/api/index.js +3 -0
- package/kernel/bin/index.js +5 -2
- package/kernel/environment.js +19 -2
- package/kernel/git.js +972 -1
- package/kernel/index.js +65 -30
- package/kernel/peer.js +1 -2
- package/kernel/plugin.js +0 -8
- package/kernel/procs.js +92 -36
- package/kernel/prototype.js +45 -22
- package/kernel/shells.js +30 -6
- package/kernel/sysinfo.js +33 -13
- package/kernel/util.js +61 -24
- package/kernel/workspace_status.js +131 -7
- package/package.json +1 -1
- package/pipe/index.js +1 -1
- package/server/index.js +1169 -350
- package/server/public/create-launcher.js +157 -2
- package/server/public/install.js +135 -41
- package/server/public/style.css +32 -1
- package/server/public/tab-link-popover.js +45 -14
- package/server/public/terminal-settings.js +51 -35
- package/server/public/urldropdown.css +89 -3
- package/server/socket.js +12 -7
- package/server/views/agents.ejs +4 -3
- package/server/views/app.ejs +798 -30
- package/server/views/bootstrap.ejs +2 -1
- package/server/views/checkpoints.ejs +1014 -0
- package/server/views/checkpoints_registry_beta.ejs +260 -0
- package/server/views/columns.ejs +4 -4
- package/server/views/connect.ejs +1 -0
- package/server/views/d.ejs +74 -4
- package/server/views/download.ejs +28 -28
- package/server/views/editor.ejs +4 -5
- package/server/views/env_editor.ejs +1 -1
- package/server/views/file_explorer.ejs +1 -1
- package/server/views/index.ejs +3 -1
- package/server/views/init/index.ejs +2 -1
- package/server/views/install.ejs +2 -1
- package/server/views/net.ejs +9 -7
- package/server/views/network.ejs +15 -14
- package/server/views/pro.ejs +5 -2
- package/server/views/prototype/index.ejs +2 -1
- package/server/views/registry_link.ejs +76 -0
- package/server/views/rows.ejs +4 -4
- package/server/views/screenshots.ejs +1 -0
- package/server/views/settings.ejs +1 -0
- package/server/views/shell.ejs +4 -6
- package/server/views/terminal.ejs +528 -38
- package/server/views/tools.ejs +1 -0
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/1764297248545 +0 -45
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/1764335557118 +0 -45
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/1764335834126 +0 -45
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/events +0 -12
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/latest +0 -45
|
@@ -364,6 +364,106 @@
|
|
|
364
364
|
return { syncTemplateFields, getTemplateValues, setTemplateValues };
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
+
function buildAttachmentSection() {
|
|
368
|
+
const wrapper = document.createElement('div');
|
|
369
|
+
wrapper.className = 'create-launcher-upload';
|
|
370
|
+
|
|
371
|
+
const label = document.createElement('div');
|
|
372
|
+
label.className = 'create-launcher-upload-label';
|
|
373
|
+
label.textContent = 'Attach files (optional)';
|
|
374
|
+
|
|
375
|
+
const dropzone = document.createElement('div');
|
|
376
|
+
dropzone.className = 'create-launcher-upload-dropzone';
|
|
377
|
+
dropzone.textContent = 'Drag and drop files here, or click to select';
|
|
378
|
+
|
|
379
|
+
const input = document.createElement('input');
|
|
380
|
+
input.type = 'file';
|
|
381
|
+
input.multiple = true;
|
|
382
|
+
input.style.display = 'none';
|
|
383
|
+
|
|
384
|
+
const list = document.createElement('ul');
|
|
385
|
+
list.className = 'create-launcher-upload-list';
|
|
386
|
+
|
|
387
|
+
let files = [];
|
|
388
|
+
|
|
389
|
+
function updateList() {
|
|
390
|
+
list.innerHTML = '';
|
|
391
|
+
if (!files.length) {
|
|
392
|
+
const empty = document.createElement('li');
|
|
393
|
+
empty.className = 'create-launcher-upload-empty';
|
|
394
|
+
empty.textContent = 'No files selected';
|
|
395
|
+
list.appendChild(empty);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
files.forEach((file, index) => {
|
|
399
|
+
const item = document.createElement('li');
|
|
400
|
+
item.className = 'create-launcher-upload-item';
|
|
401
|
+
const name = document.createElement('span');
|
|
402
|
+
name.className = 'create-launcher-upload-name';
|
|
403
|
+
name.textContent = file.name;
|
|
404
|
+
const size = document.createElement('span');
|
|
405
|
+
size.className = 'create-launcher-upload-size';
|
|
406
|
+
size.textContent = `${Math.max(1, Math.ceil(file.size / 1024))} KB`;
|
|
407
|
+
const remove = document.createElement('button');
|
|
408
|
+
remove.type = 'button';
|
|
409
|
+
remove.className = 'create-launcher-upload-remove';
|
|
410
|
+
remove.textContent = 'Remove';
|
|
411
|
+
remove.addEventListener('click', () => {
|
|
412
|
+
files = files.filter((_, i) => i !== index);
|
|
413
|
+
updateList();
|
|
414
|
+
});
|
|
415
|
+
item.appendChild(name);
|
|
416
|
+
item.appendChild(size);
|
|
417
|
+
item.appendChild(remove);
|
|
418
|
+
list.appendChild(item);
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function addFiles(fileList) {
|
|
423
|
+
const incoming = Array.from(fileList || []);
|
|
424
|
+
if (incoming.length) {
|
|
425
|
+
files = files.concat(incoming);
|
|
426
|
+
updateList();
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
dropzone.addEventListener('click', () => input.click());
|
|
431
|
+
dropzone.addEventListener('dragover', (event) => {
|
|
432
|
+
event.preventDefault();
|
|
433
|
+
dropzone.classList.add('dragover');
|
|
434
|
+
});
|
|
435
|
+
dropzone.addEventListener('dragleave', () => {
|
|
436
|
+
dropzone.classList.remove('dragover');
|
|
437
|
+
});
|
|
438
|
+
dropzone.addEventListener('drop', (event) => {
|
|
439
|
+
event.preventDefault();
|
|
440
|
+
dropzone.classList.remove('dragover');
|
|
441
|
+
addFiles(event.dataTransfer ? event.dataTransfer.files : []);
|
|
442
|
+
});
|
|
443
|
+
input.addEventListener('change', (event) => {
|
|
444
|
+
addFiles(event.target.files);
|
|
445
|
+
input.value = '';
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
updateList();
|
|
449
|
+
|
|
450
|
+
wrapper.appendChild(label);
|
|
451
|
+
wrapper.appendChild(dropzone);
|
|
452
|
+
wrapper.appendChild(list);
|
|
453
|
+
wrapper.appendChild(input);
|
|
454
|
+
|
|
455
|
+
return {
|
|
456
|
+
wrapper,
|
|
457
|
+
getFiles() {
|
|
458
|
+
return files.slice();
|
|
459
|
+
},
|
|
460
|
+
clear() {
|
|
461
|
+
files = [];
|
|
462
|
+
updateList();
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
367
467
|
function buildCreateLauncherUI({ mode = 'modal', tools }) {
|
|
368
468
|
const isPage = mode === 'page';
|
|
369
469
|
const overlay = isPage ? null : document.createElement('div');
|
|
@@ -453,6 +553,8 @@
|
|
|
453
553
|
folderInput.className = 'create-launcher-modal-input';
|
|
454
554
|
folderLabel.appendChild(folderInput);
|
|
455
555
|
|
|
556
|
+
const attachments = buildAttachmentSection();
|
|
557
|
+
|
|
456
558
|
const { wrapper: toolWrapper, toolEntries } = buildToolOptions(tools);
|
|
457
559
|
|
|
458
560
|
const error = document.createElement('div');
|
|
@@ -495,6 +597,7 @@
|
|
|
495
597
|
container.appendChild(promptLabel);
|
|
496
598
|
container.appendChild(templateWrapper);
|
|
497
599
|
container.appendChild(folderLabel);
|
|
600
|
+
container.appendChild(attachments.wrapper);
|
|
498
601
|
container.appendChild(toolWrapper);
|
|
499
602
|
container.appendChild(error);
|
|
500
603
|
container.appendChild(actions);
|
|
@@ -539,6 +642,7 @@
|
|
|
539
642
|
advancedLink,
|
|
540
643
|
bookmarkletLink,
|
|
541
644
|
linkRow,
|
|
645
|
+
attachments,
|
|
542
646
|
currentVariant: MODAL_VARIANTS.CREATE,
|
|
543
647
|
projectName: '',
|
|
544
648
|
resetFolderTracking() {
|
|
@@ -570,6 +674,9 @@
|
|
|
570
674
|
if (ui.folderLabel) {
|
|
571
675
|
ui.folderLabel.style.display = isAsk ? 'none' : '';
|
|
572
676
|
}
|
|
677
|
+
if (ui.attachments && ui.attachments.wrapper) {
|
|
678
|
+
ui.attachments.wrapper.style.display = isAsk ? 'none' : '';
|
|
679
|
+
}
|
|
573
680
|
if (ui.linkRow) {
|
|
574
681
|
ui.linkRow.style.display = isAsk ? 'none' : '';
|
|
575
682
|
}
|
|
@@ -624,6 +731,31 @@
|
|
|
624
731
|
return ui && ui.templateManager ? ui.templateManager.getTemplateValues() : new Map();
|
|
625
732
|
}
|
|
626
733
|
|
|
734
|
+
async function uploadAttachments(ui, files) {
|
|
735
|
+
if (!files || !files.length) {
|
|
736
|
+
return null;
|
|
737
|
+
}
|
|
738
|
+
const formData = new FormData();
|
|
739
|
+
files.forEach((file) => {
|
|
740
|
+
if (file) {
|
|
741
|
+
formData.append('files', file, file.name || 'file');
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
const response = await fetch('/create-upload', {
|
|
745
|
+
method: 'POST',
|
|
746
|
+
body: formData
|
|
747
|
+
});
|
|
748
|
+
if (!response.ok) {
|
|
749
|
+
const text = await response.text();
|
|
750
|
+
throw new Error(text || 'Failed to upload files.');
|
|
751
|
+
}
|
|
752
|
+
const data = await response.json();
|
|
753
|
+
if (data && data.error) {
|
|
754
|
+
throw new Error(data.error);
|
|
755
|
+
}
|
|
756
|
+
return data;
|
|
757
|
+
}
|
|
758
|
+
|
|
627
759
|
async function submitFromUi(ui) {
|
|
628
760
|
if (!ui) return;
|
|
629
761
|
ui.error.textContent = '';
|
|
@@ -639,6 +771,10 @@
|
|
|
639
771
|
: null
|
|
640
772
|
const selectedTool = selectedEntry && selectedEntry.input ? selectedEntry.input.value : ''
|
|
641
773
|
const selectedHref = selectedEntry && selectedEntry.input ? selectedEntry.input.dataset.agentHref : ''
|
|
774
|
+
const selectedFiles = ui.attachments && typeof ui.attachments.getFiles === 'function'
|
|
775
|
+
? ui.attachments.getFiles()
|
|
776
|
+
: [];
|
|
777
|
+
let uploadToken = '';
|
|
642
778
|
|
|
643
779
|
if (!selectedEntry || !selectedHref) {
|
|
644
780
|
ui.error.textContent = 'Please select an agent.';
|
|
@@ -682,6 +818,18 @@
|
|
|
682
818
|
finalPrompt = applyTemplateValues(rawPrompt, templateValues);
|
|
683
819
|
}
|
|
684
820
|
|
|
821
|
+
if (selectedFiles.length > 0) {
|
|
822
|
+
try {
|
|
823
|
+
const uploadResult = await uploadAttachments(ui, selectedFiles);
|
|
824
|
+
if (uploadResult && uploadResult.uploadToken) {
|
|
825
|
+
uploadToken = uploadResult.uploadToken;
|
|
826
|
+
}
|
|
827
|
+
} catch (uploadError) {
|
|
828
|
+
ui.error.textContent = uploadError.message || 'Failed to upload files.';
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
685
833
|
const prompt = finalPrompt.trim();
|
|
686
834
|
|
|
687
835
|
if (isAskVariant) {
|
|
@@ -701,6 +849,9 @@
|
|
|
701
849
|
if (selectedTool) {
|
|
702
850
|
params.set('tool', selectedTool);
|
|
703
851
|
}
|
|
852
|
+
if (uploadToken) {
|
|
853
|
+
params.set('uploadToken', uploadToken);
|
|
854
|
+
}
|
|
704
855
|
|
|
705
856
|
window.location.href = `/pro?${params.toString()}`;
|
|
706
857
|
}
|
|
@@ -719,7 +870,9 @@
|
|
|
719
870
|
|
|
720
871
|
document.body.appendChild(ui.overlay);
|
|
721
872
|
|
|
722
|
-
ui.confirmButton.addEventListener('click', () =>
|
|
873
|
+
ui.confirmButton.addEventListener('click', () => {
|
|
874
|
+
submitFromUi(ui);
|
|
875
|
+
});
|
|
723
876
|
if (ui.cancelButton) {
|
|
724
877
|
ui.cancelButton.addEventListener('click', hideModal);
|
|
725
878
|
}
|
|
@@ -791,7 +944,9 @@
|
|
|
791
944
|
root.innerHTML = '';
|
|
792
945
|
root.appendChild(ui.container);
|
|
793
946
|
|
|
794
|
-
ui.confirmButton.addEventListener('click', () =>
|
|
947
|
+
ui.confirmButton.addEventListener('click', () => {
|
|
948
|
+
submitFromUi(ui);
|
|
949
|
+
});
|
|
795
950
|
|
|
796
951
|
applyDefaultsToUi(ui, defaults);
|
|
797
952
|
ui.templateManager.syncTemplateFields(ui.promptTextarea.value, defaults.templateValues || {});
|
package/server/public/install.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const installname = async (url, name) => {
|
|
1
|
+
const installname = async (url, name, options) => {
|
|
2
2
|
if (url.startsWith("http")) {
|
|
3
3
|
let urlChunks = new URL(url).pathname.split("/")
|
|
4
4
|
let defaultName = urlChunks[urlChunks.length-1]
|
|
@@ -13,6 +13,7 @@ const installname = async (url, name) => {
|
|
|
13
13
|
// showCancelButton: true,
|
|
14
14
|
confirmButtonText: 'Download',
|
|
15
15
|
allowOutsideClick: false,
|
|
16
|
+
showLoaderOnConfirm: true,
|
|
16
17
|
didOpen: () => {
|
|
17
18
|
let input = Swal.getPopup().querySelector('#swal-input1')
|
|
18
19
|
if (name) {
|
|
@@ -21,16 +22,31 @@ const installname = async (url, name) => {
|
|
|
21
22
|
input.value = defaultName;
|
|
22
23
|
}
|
|
23
24
|
input.addEventListener("keypress", (e) => {
|
|
24
|
-
if (
|
|
25
|
+
if (e.key === "Enter") {
|
|
25
26
|
e.preventDefault()
|
|
26
27
|
e.stopPropagation()
|
|
27
28
|
Swal.clickConfirm()
|
|
28
29
|
}
|
|
29
30
|
})
|
|
30
31
|
},
|
|
31
|
-
preConfirm: () => {
|
|
32
|
-
const
|
|
33
|
-
|
|
32
|
+
preConfirm: async () => {
|
|
33
|
+
const folderName = (Swal.getPopup().querySelector("#swal-input1").value || "").trim()
|
|
34
|
+
const validationError = validateInstallFolderName(folderName)
|
|
35
|
+
if (validationError) {
|
|
36
|
+
Swal.showValidationMessage(validationError)
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const exists = await checkInstallDestinationExists(folderName, options)
|
|
41
|
+
if (exists) {
|
|
42
|
+
Swal.showValidationMessage("Folder already exists. Choose a different name.")
|
|
43
|
+
return false
|
|
44
|
+
}
|
|
45
|
+
} catch (error) {
|
|
46
|
+
Swal.showValidationMessage(error && error.message ? error.message : "Could not check destination folder")
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
return folderName
|
|
34
50
|
}
|
|
35
51
|
})
|
|
36
52
|
return result.value
|
|
@@ -64,53 +80,130 @@ const normalizeInstallPath = (rawPath) => {
|
|
|
64
80
|
return segments.join('/')
|
|
65
81
|
}
|
|
66
82
|
|
|
83
|
+
const validateInstallFolderName = (folderName) => {
|
|
84
|
+
if (!folderName) {
|
|
85
|
+
return "Name is required"
|
|
86
|
+
}
|
|
87
|
+
if (folderName === "." || folderName === "..") {
|
|
88
|
+
return "Invalid name"
|
|
89
|
+
}
|
|
90
|
+
if (/[\\/]/.test(folderName)) {
|
|
91
|
+
return "Name cannot include / or \\\\"
|
|
92
|
+
}
|
|
93
|
+
if (folderName.includes("\0")) {
|
|
94
|
+
return "Invalid name"
|
|
95
|
+
}
|
|
96
|
+
return null
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const checkInstallDestinationExists = async (folderName, options) => {
|
|
100
|
+
const normalizedPath = options && options.path ? normalizeInstallPath(options.path) : null
|
|
101
|
+
const relativePath = normalizedPath || DEFAULT_INSTALL_RELATIVE_PATH
|
|
102
|
+
const response = await fetch("/pinokio/install/exists", {
|
|
103
|
+
method: "POST",
|
|
104
|
+
headers: {
|
|
105
|
+
"Content-Type": "application/json"
|
|
106
|
+
},
|
|
107
|
+
body: JSON.stringify({
|
|
108
|
+
relativePath,
|
|
109
|
+
folderName
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
const payload = await response.json().catch(() => ({}))
|
|
113
|
+
if (!response.ok) {
|
|
114
|
+
const message = payload && payload.error ? payload.error : `Failed to check destination folder (${response.status})`
|
|
115
|
+
throw new Error(message)
|
|
116
|
+
}
|
|
117
|
+
return payload && payload.exists === true
|
|
118
|
+
}
|
|
119
|
+
|
|
67
120
|
const install = async (name, url, term, socket, options) => {
|
|
68
121
|
console.log("options", options)
|
|
69
122
|
const n = new N()
|
|
70
123
|
const normalizedPath = options && options.path ? normalizeInstallPath(options.path) : null
|
|
71
124
|
const targetPath = normalizedPath ? `~/${normalizedPath}` : `~/${DEFAULT_INSTALL_RELATIVE_PATH}`
|
|
72
125
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
126
|
+
try {
|
|
127
|
+
const exists = await checkInstallDestinationExists(name, options)
|
|
128
|
+
if (exists) {
|
|
129
|
+
n.Noty({
|
|
130
|
+
text: "Folder already exists. Choose a different name.",
|
|
131
|
+
timeout: 6000
|
|
132
|
+
})
|
|
133
|
+
return
|
|
80
134
|
}
|
|
135
|
+
} catch (error) {
|
|
136
|
+
n.Noty({
|
|
137
|
+
text: error && error.message ? error.message : "Could not verify destination folder",
|
|
138
|
+
timeout: 6000
|
|
139
|
+
})
|
|
140
|
+
return
|
|
141
|
+
}
|
|
81
142
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
143
|
+
try {
|
|
144
|
+
await new Promise((resolve, reject) => {
|
|
145
|
+
let settled = false
|
|
146
|
+
const settle = (fn, value) => {
|
|
147
|
+
if (settled) return
|
|
148
|
+
settled = true
|
|
149
|
+
fn(value)
|
|
150
|
+
}
|
|
151
|
+
socket.close()
|
|
85
152
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
cmd = `git clone ${url} ${name}`
|
|
91
|
-
}
|
|
92
|
-
socket.run({
|
|
93
|
-
method: "shell.run",
|
|
94
|
-
client: {
|
|
95
|
-
cols: term.cols,
|
|
96
|
-
rows: term.rows,
|
|
97
|
-
},
|
|
98
|
-
params: {
|
|
99
|
-
message: cmd,
|
|
100
|
-
path: targetPath
|
|
153
|
+
// normalize git url to the standard .git format
|
|
154
|
+
let branch
|
|
155
|
+
if (options && options.branch) {
|
|
156
|
+
branch = options.branch
|
|
101
157
|
}
|
|
102
|
-
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
158
|
+
|
|
159
|
+
if (!url.endsWith(".git")) {
|
|
160
|
+
url = url + ".git"
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
let cmd
|
|
164
|
+
if (branch) {
|
|
165
|
+
cmd = `git clone -b ${branch} ${url} ${name}`
|
|
166
|
+
} else {
|
|
167
|
+
cmd = `git clone ${url} ${name}`
|
|
111
168
|
}
|
|
169
|
+
socket.run({
|
|
170
|
+
method: "shell.run",
|
|
171
|
+
client: {
|
|
172
|
+
cols: term.cols,
|
|
173
|
+
rows: term.rows,
|
|
174
|
+
},
|
|
175
|
+
params: {
|
|
176
|
+
message: cmd,
|
|
177
|
+
path: targetPath,
|
|
178
|
+
on: [{
|
|
179
|
+
event: "/fatal:/i",
|
|
180
|
+
break: true
|
|
181
|
+
}]
|
|
182
|
+
}
|
|
183
|
+
}, (packet) => {
|
|
184
|
+
if (packet.type === 'stream') {
|
|
185
|
+
term.write(packet.data.raw)
|
|
186
|
+
} else if (packet.type === "result") {
|
|
187
|
+
if (packet.data && packet.data.error && packet.data.error.length > 0) {
|
|
188
|
+
n.Noty({
|
|
189
|
+
text: "Download failed. See terminal output for details.",
|
|
190
|
+
timeout: 6000
|
|
191
|
+
})
|
|
192
|
+
settle(reject, new Error("shell.run failed"))
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
settle(resolve)
|
|
196
|
+
} else if (packet.type === "error") {
|
|
197
|
+
n.Noty({
|
|
198
|
+
text: packet.data
|
|
199
|
+
})
|
|
200
|
+
settle(reject, new Error(typeof packet.data === "string" ? packet.data : "shell.run error"))
|
|
201
|
+
}
|
|
202
|
+
})
|
|
112
203
|
})
|
|
113
|
-
})
|
|
204
|
+
} catch (_) {
|
|
205
|
+
return
|
|
206
|
+
}
|
|
114
207
|
/*
|
|
115
208
|
options := {
|
|
116
209
|
html,
|
|
@@ -158,7 +251,8 @@ const createTerm = async (_theme) => {
|
|
|
158
251
|
})
|
|
159
252
|
let config = {
|
|
160
253
|
scrollback: 9999999,
|
|
161
|
-
fontSize:
|
|
254
|
+
fontSize: 14,
|
|
255
|
+
fontFamily: 'monospace',
|
|
162
256
|
theme,
|
|
163
257
|
}
|
|
164
258
|
let res = await fetch("/xterm_config").then((res) => {
|
package/server/public/style.css
CHANGED
|
@@ -2106,6 +2106,25 @@ body.dark .swal2-title {
|
|
|
2106
2106
|
background: rgba(0,0,0,0.8) !important;
|
|
2107
2107
|
*/
|
|
2108
2108
|
}
|
|
2109
|
+
.swal2-validation-message {
|
|
2110
|
+
margin: 12px 15px 0;
|
|
2111
|
+
padding: 10px 12px;
|
|
2112
|
+
border-radius: 6px;
|
|
2113
|
+
background: rgba(255, 66, 66, 0.12);
|
|
2114
|
+
border: 1px solid rgba(255, 66, 66, 0.18);
|
|
2115
|
+
border-left: 4px solid rgba(255, 66, 66, 0.55);
|
|
2116
|
+
color: rgba(0,0,0,0.85);
|
|
2117
|
+
text-align: left;
|
|
2118
|
+
font-size: 13px;
|
|
2119
|
+
line-height: 1.35;
|
|
2120
|
+
box-sizing: border-box;
|
|
2121
|
+
}
|
|
2122
|
+
body.dark .swal2-validation-message {
|
|
2123
|
+
background: rgba(255, 66, 66, 0.16);
|
|
2124
|
+
border-color: rgba(255, 66, 66, 0.25);
|
|
2125
|
+
border-left-color: rgba(255, 66, 66, 0.75);
|
|
2126
|
+
color: rgba(255,255,255,0.9);
|
|
2127
|
+
}
|
|
2109
2128
|
.swal2-modal button.swal2-cancel {
|
|
2110
2129
|
background: none !important;
|
|
2111
2130
|
}
|
|
@@ -2134,6 +2153,12 @@ body.dark .swal2-modal input {
|
|
|
2134
2153
|
color: var(--dark-btn-color);
|
|
2135
2154
|
border: 2px solid rgba(255,255,255,0.1);
|
|
2136
2155
|
}
|
|
2156
|
+
.swal2-modal input.swal2-inputerror {
|
|
2157
|
+
border-color: rgba(255, 66, 66, 0.6);
|
|
2158
|
+
}
|
|
2159
|
+
body.dark .swal2-modal input.swal2-inputerror {
|
|
2160
|
+
border-color: rgba(255, 66, 66, 0.55);
|
|
2161
|
+
}
|
|
2137
2162
|
.swal2-modal input {
|
|
2138
2163
|
/*
|
|
2139
2164
|
background: rgba(0,0,0,0.1) !important;
|
|
@@ -2765,7 +2790,7 @@ body.dark .mode-selector .btn2.selected {
|
|
|
2765
2790
|
}
|
|
2766
2791
|
.mode-selector .btn2 {
|
|
2767
2792
|
display: flex;
|
|
2768
|
-
align-items:
|
|
2793
|
+
align-items: stretch;
|
|
2769
2794
|
flex-direction: row;
|
|
2770
2795
|
justify-content: center;
|
|
2771
2796
|
padding: 5px 10px;
|
|
@@ -3508,6 +3533,12 @@ body.dark .logs-viewer-output {
|
|
|
3508
3533
|
#status-window {
|
|
3509
3534
|
display: none !important;
|
|
3510
3535
|
}
|
|
3536
|
+
.snapshot-btn-save {
|
|
3537
|
+
background: #7f5bf3 !important;
|
|
3538
|
+
}
|
|
3539
|
+
.snapshot-footer-actions .btn-primary {
|
|
3540
|
+
background: #7f5bf3 !important;
|
|
3541
|
+
}
|
|
3511
3542
|
|
|
3512
3543
|
@media (max-width: 800px) {
|
|
3513
3544
|
.logs-page {
|
|
@@ -1239,27 +1239,58 @@
|
|
|
1239
1239
|
popover.style.visibility = "hidden"
|
|
1240
1240
|
popover.style.maxHeight = ""
|
|
1241
1241
|
popover.style.overflowY = ""
|
|
1242
|
-
|
|
1243
1242
|
const popoverWidth = popover.offsetWidth
|
|
1244
1243
|
let popoverHeight = popover.offsetHeight
|
|
1245
1244
|
const viewportPadding = 12
|
|
1246
1245
|
const dropOffset = 8
|
|
1247
1246
|
|
|
1248
|
-
|
|
1249
|
-
const
|
|
1247
|
+
const appcanvas = document.querySelector(".appcanvas")
|
|
1248
|
+
const isVerticalLayout = !!(appcanvas && appcanvas.classList.contains("vertical"))
|
|
1250
1249
|
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
if (
|
|
1255
|
-
left =
|
|
1256
|
-
|
|
1250
|
+
let left
|
|
1251
|
+
let top
|
|
1252
|
+
|
|
1253
|
+
if (isVerticalLayout) {
|
|
1254
|
+
left = rect.right + dropOffset
|
|
1255
|
+
top = rect.top
|
|
1256
|
+
|
|
1257
|
+
if (left + popoverWidth > window.innerWidth - viewportPadding) {
|
|
1258
|
+
left = window.innerWidth - popoverWidth - viewportPadding
|
|
1259
|
+
}
|
|
1260
|
+
if (left < viewportPadding) {
|
|
1261
|
+
left = viewportPadding
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
const availableHeight = Math.max(0, window.innerHeight - viewportPadding * 2)
|
|
1265
|
+
if (availableHeight > 0 && popoverHeight > availableHeight) {
|
|
1266
|
+
popover.style.maxHeight = `${Math.round(availableHeight)}px`
|
|
1267
|
+
popover.style.overflowY = "auto"
|
|
1268
|
+
popoverHeight = Math.min(availableHeight, popover.offsetHeight)
|
|
1269
|
+
}
|
|
1257
1270
|
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1271
|
+
if (top + popoverHeight > window.innerHeight - viewportPadding) {
|
|
1272
|
+
top = window.innerHeight - popoverHeight - viewportPadding
|
|
1273
|
+
}
|
|
1274
|
+
if (top < viewportPadding) {
|
|
1275
|
+
top = viewportPadding
|
|
1276
|
+
}
|
|
1277
|
+
} else {
|
|
1278
|
+
left = rect.left
|
|
1279
|
+
top = Math.max(viewportPadding, rect.bottom + dropOffset)
|
|
1280
|
+
|
|
1281
|
+
if (left + popoverWidth > window.innerWidth - viewportPadding) {
|
|
1282
|
+
left = window.innerWidth - popoverWidth - viewportPadding
|
|
1283
|
+
}
|
|
1284
|
+
if (left < viewportPadding) {
|
|
1285
|
+
left = viewportPadding
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
const availableBelow = Math.max(0, window.innerHeight - viewportPadding - top)
|
|
1289
|
+
if (availableBelow > 0 && popoverHeight > availableBelow) {
|
|
1290
|
+
popover.style.maxHeight = `${Math.round(availableBelow)}px`
|
|
1291
|
+
popover.style.overflowY = "auto"
|
|
1292
|
+
popoverHeight = Math.min(availableBelow, popover.offsetHeight)
|
|
1293
|
+
}
|
|
1263
1294
|
}
|
|
1264
1295
|
|
|
1265
1296
|
popover.style.left = `${Math.round(left)}px`
|