pinokiod 3.170.0 → 3.180.0
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/package.json +1 -1
- package/server/index.js +123 -3
- package/server/public/files-app/app.css +73 -1
- package/server/public/files-app/app.js +255 -2
- package/server/public/layout.js +1 -1
- package/server/public/style.css +5 -1
- package/server/routes/files.js +96 -0
- package/server/views/app.ejs +402 -22
- package/server/views/file_browser.ejs +9 -2
- package/server/views/index.ejs +2 -2
- package/server/views/layout.ejs +5 -5
- package/server/views/review.ejs +4 -3
package/server/routes/files.js
CHANGED
|
@@ -280,5 +280,101 @@ module.exports = function registerFileRoutes(app, { kernel, getTheme, exists })
|
|
|
280
280
|
});
|
|
281
281
|
}));
|
|
282
282
|
|
|
283
|
+
router.post('/api/files/delete', asyncHandler(async (req, res) => {
|
|
284
|
+
const { workspace, path: relativePath, root: rootParam } = req.body || {};
|
|
285
|
+
if (typeof relativePath !== 'string') {
|
|
286
|
+
throw createHttpError(400, 'Path must be provided');
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const resolved = await resolveWorkspacePath(workspace, relativePath, rootParam);
|
|
290
|
+
const { absolutePath, relativePosix, workspaceSlug } = resolved;
|
|
291
|
+
|
|
292
|
+
if (!relativePosix) {
|
|
293
|
+
throw createHttpError(400, 'Cannot delete workspace root');
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const stats = await fs.promises.stat(absolutePath).catch(() => null);
|
|
297
|
+
if (!stats) {
|
|
298
|
+
throw createHttpError(404, 'Path not found');
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
let removedType;
|
|
302
|
+
if (stats.isDirectory()) {
|
|
303
|
+
await fs.promises.rm(absolutePath, { recursive: true, force: true });
|
|
304
|
+
removedType = 'directory';
|
|
305
|
+
} else if (stats.isFile()) {
|
|
306
|
+
await fs.promises.unlink(absolutePath);
|
|
307
|
+
removedType = 'file';
|
|
308
|
+
} else {
|
|
309
|
+
throw createHttpError(400, 'Unsupported file type');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
res.json({
|
|
313
|
+
workspace: workspaceSlug,
|
|
314
|
+
path: relativePosix,
|
|
315
|
+
type: removedType,
|
|
316
|
+
success: true,
|
|
317
|
+
});
|
|
318
|
+
}));
|
|
319
|
+
|
|
320
|
+
router.post('/api/files/rename', asyncHandler(async (req, res) => {
|
|
321
|
+
const { workspace, path: relativePath, name: newName, root: rootParam } = req.body || {};
|
|
322
|
+
if (typeof relativePath !== 'string' || relativePath.length === 0) {
|
|
323
|
+
throw createHttpError(400, 'Path must be provided');
|
|
324
|
+
}
|
|
325
|
+
if (typeof newName !== 'string' || newName.trim().length === 0) {
|
|
326
|
+
throw createHttpError(400, 'New name must be provided');
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const sanitizedName = newName.trim();
|
|
330
|
+
if (sanitizedName.includes('/') || sanitizedName.includes('\\')) {
|
|
331
|
+
throw createHttpError(400, 'Name cannot contain path separators');
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const resolved = await resolveWorkspacePath(workspace, relativePath, rootParam);
|
|
335
|
+
const { absolutePath, relativePosix, workspaceSlug, workspaceRoot } = resolved;
|
|
336
|
+
|
|
337
|
+
if (!relativePosix) {
|
|
338
|
+
throw createHttpError(400, 'Cannot rename workspace root');
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const sourceStats = await fs.promises.stat(absolutePath).catch(() => null);
|
|
342
|
+
if (!sourceStats) {
|
|
343
|
+
throw createHttpError(404, 'Source path not found');
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const parentSegments = resolved.relativeSegments.slice(0, -1);
|
|
347
|
+
const sourceName = resolved.relativeSegments[resolved.relativeSegments.length - 1];
|
|
348
|
+
if (sourceName === sanitizedName) {
|
|
349
|
+
res.json({
|
|
350
|
+
workspace: workspaceSlug,
|
|
351
|
+
path: relativePosix,
|
|
352
|
+
target: relativePosix,
|
|
353
|
+
success: true,
|
|
354
|
+
unchanged: true,
|
|
355
|
+
});
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const targetAbsolute = path.resolve(workspaceRoot, ...parentSegments, sanitizedName);
|
|
360
|
+
const relativeTargetSegments = sanitizeSegments([...parentSegments, sanitizedName].join('/'));
|
|
361
|
+
const relativeTarget = relativeTargetSegments.join('/');
|
|
362
|
+
const collision = await fs.promises.stat(targetAbsolute).catch(() => null);
|
|
363
|
+
if (collision) {
|
|
364
|
+
throw createHttpError(409, 'A file or folder with that name already exists');
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
await fs.promises.rename(absolutePath, targetAbsolute);
|
|
368
|
+
|
|
369
|
+
const targetStats = await fs.promises.stat(targetAbsolute);
|
|
370
|
+
res.json({
|
|
371
|
+
workspace: workspaceSlug,
|
|
372
|
+
path: relativePosix,
|
|
373
|
+
target: relativeTarget,
|
|
374
|
+
type: targetStats.isDirectory() ? 'directory' : targetStats.isFile() ? 'file' : 'other',
|
|
375
|
+
success: true,
|
|
376
|
+
});
|
|
377
|
+
}));
|
|
378
|
+
|
|
283
379
|
app.use(router);
|
|
284
380
|
};
|
package/server/views/app.ejs
CHANGED
|
@@ -1759,6 +1759,10 @@ body.dark .swal2-html-container label {
|
|
|
1759
1759
|
--pinokio-custom-commit-close-color: rgba(71, 85, 105, 0.75);
|
|
1760
1760
|
--pinokio-custom-commit-close-hover-bg: rgba(148, 163, 184, 0.18);
|
|
1761
1761
|
--pinokio-custom-commit-close-hover-color: #0f172a;
|
|
1762
|
+
--pinokio-custom-commit-action-bg: rgba(59, 130, 246, 0.12);
|
|
1763
|
+
--pinokio-custom-commit-action-border: rgba(59, 130, 246, 0.35);
|
|
1764
|
+
--pinokio-custom-commit-action-color: #1d4ed8;
|
|
1765
|
+
--pinokio-custom-commit-action-hover: rgba(59, 130, 246, 0.18);
|
|
1762
1766
|
--pinokio-commit-item-bg: rgba(226, 232, 240, 0.6);
|
|
1763
1767
|
--pinokio-commit-item-hover-bg: rgba(59, 130, 246, 0.12);
|
|
1764
1768
|
--pinokio-commit-item-text: #0f172a;
|
|
@@ -1837,6 +1841,10 @@ body.dark {
|
|
|
1837
1841
|
--pinokio-custom-commit-close-color: rgba(226, 232, 240, 0.7);
|
|
1838
1842
|
--pinokio-custom-commit-close-hover-bg: rgba(148, 163, 184, 0.18);
|
|
1839
1843
|
--pinokio-custom-commit-close-hover-color: #f8fafc;
|
|
1844
|
+
--pinokio-custom-commit-action-bg: rgba(56, 189, 248, 0.12);
|
|
1845
|
+
--pinokio-custom-commit-action-border: rgba(56, 189, 248, 0.35);
|
|
1846
|
+
--pinokio-custom-commit-action-color: #7dd3fc;
|
|
1847
|
+
--pinokio-custom-commit-action-hover: rgba(56, 189, 248, 0.18);
|
|
1840
1848
|
--pinokio-commit-item-bg: rgba(15, 23, 42, 0.35);
|
|
1841
1849
|
--pinokio-commit-item-hover-bg: rgba(37, 99, 235, 0.16);
|
|
1842
1850
|
--pinokio-commit-item-text: #f8fafc;
|
|
@@ -2173,6 +2181,57 @@ body.dark {
|
|
|
2173
2181
|
flex-wrap: wrap;
|
|
2174
2182
|
}
|
|
2175
2183
|
|
|
2184
|
+
.pinokio-history-latest-banner {
|
|
2185
|
+
display: flex;
|
|
2186
|
+
justify-content: space-between;
|
|
2187
|
+
align-items: center;
|
|
2188
|
+
padding: 12px 20px;
|
|
2189
|
+
margin: 12px 20px 0;
|
|
2190
|
+
background: rgba(59, 130, 246, 0.08);
|
|
2191
|
+
border: 1px solid rgba(59, 130, 246, 0.18);
|
|
2192
|
+
border-radius: 10px;
|
|
2193
|
+
color: var(--pinokio-modal-title-color);
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
.pinokio-history-latest-text {
|
|
2197
|
+
font-size: 13px;
|
|
2198
|
+
font-weight: 600;
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
.pinokio-history-latest-btn {
|
|
2202
|
+
display: inline-flex;
|
|
2203
|
+
align-items: center;
|
|
2204
|
+
gap: 6px;
|
|
2205
|
+
background: rgba(59, 130, 246, 0.18);
|
|
2206
|
+
border: 1px solid rgba(59, 130, 246, 0.35);
|
|
2207
|
+
color: #1d4ed8;
|
|
2208
|
+
padding: 6px 14px;
|
|
2209
|
+
border-radius: 6px;
|
|
2210
|
+
font-weight: 600;
|
|
2211
|
+
font-size: 13px;
|
|
2212
|
+
cursor: pointer;
|
|
2213
|
+
transition: background 0.15s ease, border 0.15s ease, transform 0.15s ease;
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2216
|
+
.pinokio-history-latest-btn:hover {
|
|
2217
|
+
background: rgba(59, 130, 246, 0.24);
|
|
2218
|
+
transform: translateY(-1px);
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
.pinokio-history-latest-btn:focus-visible {
|
|
2222
|
+
outline: 2px solid rgba(59, 130, 246, 0.45);
|
|
2223
|
+
outline-offset: 3px;
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
.pinokio-history-latest-banner--disabled {
|
|
2227
|
+
opacity: 0.6;
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
.pinokio-history-latest-banner--disabled .pinokio-history-latest-btn {
|
|
2231
|
+
pointer-events: none;
|
|
2232
|
+
cursor: not-allowed;
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2176
2235
|
.pinokio-pill {
|
|
2177
2236
|
display: inline-flex;
|
|
2178
2237
|
align-items: center;
|
|
@@ -2553,6 +2612,104 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
2553
2612
|
flex: 1;
|
|
2554
2613
|
overflow: hidden;
|
|
2555
2614
|
padding: 24px;
|
|
2615
|
+
display: flex;
|
|
2616
|
+
flex-direction: column;
|
|
2617
|
+
gap: 16px;
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2620
|
+
.pinokio-git-commit-actions {
|
|
2621
|
+
display: flex;
|
|
2622
|
+
justify-content: flex-end;
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
.pinokio-git-commit-switch-btn {
|
|
2626
|
+
display: inline-flex;
|
|
2627
|
+
align-items: center;
|
|
2628
|
+
gap: 6px;
|
|
2629
|
+
background: var(--pinokio-custom-commit-action-bg);
|
|
2630
|
+
border: 1px solid var(--pinokio-custom-commit-action-border);
|
|
2631
|
+
color: var(--pinokio-custom-commit-action-color);
|
|
2632
|
+
padding: 6px 14px;
|
|
2633
|
+
border-radius: 6px;
|
|
2634
|
+
font-weight: 600;
|
|
2635
|
+
font-size: 13px;
|
|
2636
|
+
cursor: pointer;
|
|
2637
|
+
transition: background 0.15s ease, border 0.15s ease, transform 0.15s ease;
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
.pinokio-git-commit-switch-btn:hover {
|
|
2641
|
+
background: var(--pinokio-custom-commit-action-hover);
|
|
2642
|
+
transform: translateY(-1px);
|
|
2643
|
+
}
|
|
2644
|
+
|
|
2645
|
+
.pinokio-git-commit-switch-btn:focus-visible {
|
|
2646
|
+
outline: 2px solid var(--pinokio-custom-commit-action-color);
|
|
2647
|
+
outline-offset: 3px;
|
|
2648
|
+
}
|
|
2649
|
+
|
|
2650
|
+
.pinokio-custom-terminal-overlay {
|
|
2651
|
+
position: fixed;
|
|
2652
|
+
inset: 0;
|
|
2653
|
+
background: rgba(9, 11, 15, 0.7);
|
|
2654
|
+
display: flex;
|
|
2655
|
+
align-items: center;
|
|
2656
|
+
justify-content: center;
|
|
2657
|
+
z-index: 999999;
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
.pinokio-custom-terminal-modal {
|
|
2661
|
+
width: min(900px, 92vw);
|
|
2662
|
+
height: min(620px, 88vh);
|
|
2663
|
+
background: var(--pinokio-modal-surface-bg, #101522);
|
|
2664
|
+
color: var(--pinokio-modal-title-color);
|
|
2665
|
+
border-radius: 18px;
|
|
2666
|
+
box-shadow: 0 24px 60px rgba(15, 23, 42, 0.55);
|
|
2667
|
+
display: flex;
|
|
2668
|
+
flex-direction: column;
|
|
2669
|
+
overflow: hidden;
|
|
2670
|
+
border: 1px solid rgba(76, 137, 251, 0.2);
|
|
2671
|
+
}
|
|
2672
|
+
|
|
2673
|
+
.pinokio-custom-terminal-header {
|
|
2674
|
+
display: flex;
|
|
2675
|
+
justify-content: space-between;
|
|
2676
|
+
align-items: center;
|
|
2677
|
+
padding: 16px 20px;
|
|
2678
|
+
background: rgba(30, 41, 59, 0.8);
|
|
2679
|
+
border-bottom: 1px solid rgba(76, 137, 251, 0.25);
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
.pinokio-custom-terminal-header h3 {
|
|
2683
|
+
margin: 0;
|
|
2684
|
+
font-size: 15px;
|
|
2685
|
+
font-weight: 600;
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2688
|
+
.pinokio-custom-terminal-close {
|
|
2689
|
+
background: none;
|
|
2690
|
+
border: none;
|
|
2691
|
+
font-size: 26px;
|
|
2692
|
+
cursor: pointer;
|
|
2693
|
+
padding: 6px 10px;
|
|
2694
|
+
border-radius: 12px;
|
|
2695
|
+
color: rgba(226, 232, 240, 0.7);
|
|
2696
|
+
transition: background 0.2s ease, color 0.2s ease;
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
.pinokio-custom-terminal-close:hover {
|
|
2700
|
+
background: rgba(148, 163, 184, 0.18);
|
|
2701
|
+
color: #f8fafc;
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
.pinokio-custom-terminal-body {
|
|
2705
|
+
flex: 1;
|
|
2706
|
+
background: #0b1120;
|
|
2707
|
+
}
|
|
2708
|
+
|
|
2709
|
+
.pinokio-custom-terminal-body iframe {
|
|
2710
|
+
width: 100%;
|
|
2711
|
+
height: 100%;
|
|
2712
|
+
border: none;
|
|
2556
2713
|
}
|
|
2557
2714
|
|
|
2558
2715
|
.pinokio-git-commit-item {
|
|
@@ -2848,10 +3005,12 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
2848
3005
|
#fs-fork-btn .fs-status-label i {
|
|
2849
3006
|
font-size: 1rem;
|
|
2850
3007
|
}
|
|
2851
|
-
#fs-status .fs-status-btn .disk-usage
|
|
2852
|
-
#fs-status .fs-status-btn .badge {
|
|
3008
|
+
#fs-status .fs-status-btn .disk-usage {
|
|
2853
3009
|
display: none;
|
|
2854
3010
|
}
|
|
3011
|
+
#fs-status .git-changes .badge {
|
|
3012
|
+
display: inline-flex;
|
|
3013
|
+
}
|
|
2855
3014
|
}
|
|
2856
3015
|
/*
|
|
2857
3016
|
@media only screen and (max-width: 800px) {
|
|
@@ -2904,7 +3063,8 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
2904
3063
|
<button class='btn2' id='screenshot' data-tippy-content="take a screenshot"><i class="fa-solid fa-camera"></i></button>
|
|
2905
3064
|
<div class='sep'></div>
|
|
2906
3065
|
<div class='mode-selector'>
|
|
2907
|
-
<a class="btn2 <%=type === 'review' ? 'selected' : ''%>" href="<%=review_tab%>"><div><i class="fa-regular fa-message"></i></div><div class='caption'>
|
|
3066
|
+
<a class="btn2 <%=type === 'review' ? 'selected' : ''%>" href="<%=review_tab%>"><div><i class="fa-regular fa-message"></i></div><div class='caption'>Forum</div></a>
|
|
3067
|
+
<a class="btn2 <%=type === 'files' ? 'selected' : ''%>" href="<%=files_tab%>"><div><i class="fa-solid fa-file-lines"></i></div><div class='caption'>Files</div></a>
|
|
2908
3068
|
<a class="btn2 <%=type === 'browse' ? 'selected' : ''%>" href="<%=dev_tab%>"><div><i class="fa-solid fa-code"></i></div><div class='caption'>Dev</div></a>
|
|
2909
3069
|
<a class="btn2 <%=type === 'run' ? 'selected' : ''%>" href="<%=run_tab%>"><div><i class="fa-solid fa-circle-play"></i></div><div class='caption'>Run</div></a>
|
|
2910
3070
|
</div>
|
|
@@ -2931,6 +3091,7 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
2931
3091
|
</div>
|
|
2932
3092
|
</div>
|
|
2933
3093
|
<% } else { %>
|
|
3094
|
+
<% if (type !== 'files') { %>
|
|
2934
3095
|
<aside class='active'>
|
|
2935
3096
|
<!--
|
|
2936
3097
|
<div class='header-top header-item'>
|
|
@@ -2963,15 +3124,7 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
2963
3124
|
<div class='loader'><i class='fa-solid fa-angle-right'></i></div>
|
|
2964
3125
|
-->
|
|
2965
3126
|
</a>
|
|
2966
|
-
|
|
2967
|
-
<div class='tab'>
|
|
2968
|
-
<i class="fa-solid fa-file-lines"></i>
|
|
2969
|
-
<div class='display'>Files</div>
|
|
2970
|
-
<div class='tab-metric'>
|
|
2971
|
-
<span class='disk-usage tab-metric__value' data-path="/">--</span>
|
|
2972
|
-
</div>
|
|
2973
|
-
</div>
|
|
2974
|
-
</a>
|
|
3127
|
+
|
|
2975
3128
|
<div class="dynamic <%=type==='run' ? '' : 'selected'%>">
|
|
2976
3129
|
<div class='submenu'>
|
|
2977
3130
|
<% if (plugin_menu) { %>
|
|
@@ -3006,6 +3159,7 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
3006
3159
|
</div>
|
|
3007
3160
|
</div>
|
|
3008
3161
|
</aside>
|
|
3162
|
+
<% } %>
|
|
3009
3163
|
<% if (type === "run") { %>
|
|
3010
3164
|
<div class='appcanvas_filler'></div>
|
|
3011
3165
|
<% } %>
|
|
@@ -3024,6 +3178,62 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
3024
3178
|
</div>
|
|
3025
3179
|
</div>
|
|
3026
3180
|
-->
|
|
3181
|
+
<div class='fs-status-dropdown fs-open-explorer'>
|
|
3182
|
+
<button class='fs-status-btn' data-filepath="<%=path%>" type='button'>
|
|
3183
|
+
<span class='fs-status-label'>
|
|
3184
|
+
<i class="fa-solid fa-folder-open"></i>
|
|
3185
|
+
<span class='fs-status-title'>Open in File Explorer</span>
|
|
3186
|
+
</span>
|
|
3187
|
+
</button>
|
|
3188
|
+
</div>
|
|
3189
|
+
<div class='fs-status-dropdown git-changes'>
|
|
3190
|
+
<button id='fs-changes-btn' class='fs-status-btn revealer' data-group='#fs-changes-menu' type='button'>
|
|
3191
|
+
<span class='fs-status-label'><i class="fa-solid fa-code-compare"></i> Changes</span>
|
|
3192
|
+
<div class='badge'></div>
|
|
3193
|
+
</button>
|
|
3194
|
+
<div class='fs-dropdown-menu submenu hidden' id='fs-changes-menu'></div>
|
|
3195
|
+
</div>
|
|
3196
|
+
<div class='fs-status-dropdown git-fork'>
|
|
3197
|
+
<button id='fs-fork-btn' class='fs-status-btn revealer' data-group='#fs-fork-menu' type='button'>
|
|
3198
|
+
<span class='fs-status-label'>
|
|
3199
|
+
<i class="fa-solid fa-code-branch"></i>
|
|
3200
|
+
<span class='fs-status-title'>Fork</span>
|
|
3201
|
+
</span>
|
|
3202
|
+
</button>
|
|
3203
|
+
<div class='fs-dropdown-menu submenu hidden' id='fs-fork-menu'></div>
|
|
3204
|
+
</div>
|
|
3205
|
+
<div class='fs-status-dropdown git-publish'>
|
|
3206
|
+
<button id='fs-push-btn' class='fs-status-btn revealer' data-group='#fs-push-menu' type='button'>
|
|
3207
|
+
<span class='fs-status-label'>
|
|
3208
|
+
<i class="fa-brands fa-github"></i>
|
|
3209
|
+
<span class='fs-status-title'>Publish</span>
|
|
3210
|
+
</span>
|
|
3211
|
+
</button>
|
|
3212
|
+
<div class='fs-dropdown-menu submenu hidden' id='fs-push-menu'></div>
|
|
3213
|
+
</div>
|
|
3214
|
+
</div>
|
|
3215
|
+
<% } else if (type === 'files') { %>
|
|
3216
|
+
<div id='fs-status' data-workspace="<%=name%>" data-create-uri="<%=git_create_url%>" data-history-uri="<%=git_history_url%>" data-status-uri="<%=git_status_url%>" data-uri="<%=git_monitor_url%>" data-push-uri="<%=git_push_url%>" data-fork-uri="<%=git_fork_url%>">
|
|
3217
|
+
<!--
|
|
3218
|
+
<div class='fs-status-dropdown nested-menu git blue'>
|
|
3219
|
+
<button type='button' class='fs-status-btn frame-link reveal'>
|
|
3220
|
+
<span class='fs-status-label'>
|
|
3221
|
+
<i class="fa-brands fa-git-alt"></i>
|
|
3222
|
+
Git
|
|
3223
|
+
</span>
|
|
3224
|
+
</button>
|
|
3225
|
+
<div class='fs-dropdown-menu submenu hidden' id='git-repos'>
|
|
3226
|
+
</div>
|
|
3227
|
+
</div>
|
|
3228
|
+
-->
|
|
3229
|
+
<div class='fs-status-dropdown fs-open-explorer'>
|
|
3230
|
+
<button class='fs-status-btn' data-filepath="<%=path%>" type='button'>
|
|
3231
|
+
<span class='fs-status-label'>
|
|
3232
|
+
<i class="fa-solid fa-folder-open"></i>
|
|
3233
|
+
<span class='fs-status-title'>Open in File Explorer</span>
|
|
3234
|
+
</span>
|
|
3235
|
+
</button>
|
|
3236
|
+
</div>
|
|
3027
3237
|
<div class='fs-status-dropdown git-changes'>
|
|
3028
3238
|
<button id='fs-changes-btn' class='fs-status-btn revealer' data-group='#fs-changes-menu' type='button'>
|
|
3029
3239
|
<span class='fs-status-label'><i class="fa-solid fa-code-compare"></i> Changes</span>
|
|
@@ -3052,6 +3262,9 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
3052
3262
|
</div>
|
|
3053
3263
|
<% } %>
|
|
3054
3264
|
<main class='browserview'>
|
|
3265
|
+
<% if (type === 'files') { %>
|
|
3266
|
+
<iframe class='selected' src="<%=editor_tab%>"></iframe>
|
|
3267
|
+
<% } %>
|
|
3055
3268
|
</main>
|
|
3056
3269
|
</div>
|
|
3057
3270
|
</div>
|
|
@@ -6517,7 +6730,7 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
6517
6730
|
}
|
|
6518
6731
|
});
|
|
6519
6732
|
*/
|
|
6520
|
-
<% if (type === "browse") { %>
|
|
6733
|
+
<% if (type === "browse" || type === "files") { %>
|
|
6521
6734
|
const repoStatusCache = new Map()
|
|
6522
6735
|
let lastRepoList = []
|
|
6523
6736
|
let currentChanges = []
|
|
@@ -7143,10 +7356,43 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
7143
7356
|
const showIframeView = (src) => {
|
|
7144
7357
|
const iframeMarkup = `<iframe src="${src}" frameborder="0"></iframe>`
|
|
7145
7358
|
const diffBody = document.querySelector('.pinokio-modal-body--diff')
|
|
7359
|
+
let iframeContainer = null
|
|
7146
7360
|
if (diffBody) {
|
|
7147
7361
|
diffBody.classList.remove('pinokio-modal-body--diff')
|
|
7148
7362
|
diffBody.classList.add('pinokio-modal-body--iframe')
|
|
7149
7363
|
diffBody.innerHTML = iframeMarkup
|
|
7364
|
+
iframeContainer = diffBody
|
|
7365
|
+
} else {
|
|
7366
|
+
const activeSwal = Swal.isVisible()
|
|
7367
|
+
const fallbackHtml = `
|
|
7368
|
+
<div class="pinokio-modal-surface pinokio-modal-surface--iframe">
|
|
7369
|
+
<div class="pinokio-modal-body pinokio-modal-body--iframe"></div>
|
|
7370
|
+
</div>
|
|
7371
|
+
`
|
|
7372
|
+
const launchPromise = Swal.fire({
|
|
7373
|
+
html: fallbackHtml,
|
|
7374
|
+
customClass: {
|
|
7375
|
+
popup: 'pinokio-modern-modal',
|
|
7376
|
+
htmlContainer: 'pinokio-modern-html',
|
|
7377
|
+
closeButton: 'pinokio-modern-close'
|
|
7378
|
+
},
|
|
7379
|
+
backdrop: 'rgba(9,11,15,0.65)',
|
|
7380
|
+
width: 'min(720px, 90vw)',
|
|
7381
|
+
showConfirmButton: false,
|
|
7382
|
+
showCloseButton: true,
|
|
7383
|
+
buttonsStyling: false,
|
|
7384
|
+
focusConfirm: false,
|
|
7385
|
+
})
|
|
7386
|
+
if (!activeSwal) {
|
|
7387
|
+
launchPromise.then(() => {})
|
|
7388
|
+
}
|
|
7389
|
+
const container = Swal.getHtmlContainer()
|
|
7390
|
+
if (container) {
|
|
7391
|
+
iframeContainer = container.querySelector('.pinokio-modal-body--iframe')
|
|
7392
|
+
if (iframeContainer) {
|
|
7393
|
+
iframeContainer.innerHTML = iframeMarkup
|
|
7394
|
+
}
|
|
7395
|
+
}
|
|
7150
7396
|
}
|
|
7151
7397
|
const commitFooter = document.querySelector('.pinokio-modal-footer--commit')
|
|
7152
7398
|
if (commitFooter && commitFooter.parentNode) {
|
|
@@ -7616,7 +7862,7 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
7616
7862
|
}
|
|
7617
7863
|
|
|
7618
7864
|
const historyData = await response.json()
|
|
7619
|
-
displayGitHistory(historyData, { repoName: repoName || null, repoParam: repoParam || null })
|
|
7865
|
+
displayGitHistory(historyData, { repoName: repoName || null, repoParam: repoParam || null, repoData })
|
|
7620
7866
|
} catch (error) {
|
|
7621
7867
|
console.error('Failed to load git history:', error)
|
|
7622
7868
|
Swal.fire({
|
|
@@ -7629,6 +7875,7 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
7629
7875
|
|
|
7630
7876
|
const displayGitHistory = (historyData, options = {}) => {
|
|
7631
7877
|
const repoName = options && typeof options === 'object' ? options.repoName : null
|
|
7878
|
+
const repoData = options && typeof options === 'object' ? options.repoData : null
|
|
7632
7879
|
const commits = historyData.log || []
|
|
7633
7880
|
const remote = historyData.remote || ''
|
|
7634
7881
|
const currentRef = historyData.ref || 'HEAD'
|
|
@@ -7659,6 +7906,14 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
7659
7906
|
</div>
|
|
7660
7907
|
</div>
|
|
7661
7908
|
${metaBadges.length ? `<div class="pinokio-history-meta">${metaBadges.join('')}</div>` : ''}
|
|
7909
|
+
<div class="pinokio-history-latest-banner" data-history-latest-banner>
|
|
7910
|
+
<div class="pinokio-history-latest-text">
|
|
7911
|
+
Currently viewing ${escapeHtml(currentRef)}
|
|
7912
|
+
</div>
|
|
7913
|
+
<button type="button" class="pinokio-history-latest-btn" data-history-return-head>
|
|
7914
|
+
<i class="fa-solid fa-arrow-rotate-left"></i> Return to newest commit
|
|
7915
|
+
</button>
|
|
7916
|
+
</div>
|
|
7662
7917
|
<div class="pinokio-modal-body pinokio-modal-body--history">
|
|
7663
7918
|
${commits.length === 0 ?
|
|
7664
7919
|
'<div class="pinokio-history-empty">No commits found</div>' :
|
|
@@ -7689,8 +7944,53 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
7689
7944
|
if (commitInfo) {
|
|
7690
7945
|
await showCommitDiffModal(commitInfo)
|
|
7691
7946
|
}
|
|
7692
|
-
|
|
7947
|
+
})
|
|
7693
7948
|
})
|
|
7949
|
+
|
|
7950
|
+
const returnBtn = document.querySelector('[data-history-return-head]')
|
|
7951
|
+
const banner = document.querySelector('[data-history-latest-banner]')
|
|
7952
|
+
if (returnBtn && typeof showIframeView === 'function') {
|
|
7953
|
+
const repoParam = options && typeof options === 'object' ? options.repoParam : null
|
|
7954
|
+
let checkoutCwd = null
|
|
7955
|
+
if (historyData && typeof historyData.dir === 'string' && historyData.dir.length > 0) {
|
|
7956
|
+
checkoutCwd = historyData.dir
|
|
7957
|
+
} else if (repoParam) {
|
|
7958
|
+
checkoutCwd = repoParam
|
|
7959
|
+
}
|
|
7960
|
+
|
|
7961
|
+
const branchEntries = Array.isArray(historyData.branches) ? historyData.branches : []
|
|
7962
|
+
let checkoutTarget = null
|
|
7963
|
+
|
|
7964
|
+
if (repoData && typeof repoData.branch === 'string' && repoData.branch.length > 0 && repoData.branch !== currentRef) {
|
|
7965
|
+
checkoutTarget = repoData.branch
|
|
7966
|
+
}
|
|
7967
|
+
if (!checkoutTarget) {
|
|
7968
|
+
const nonCurrent = branchEntries.find((entry) => entry && typeof entry.branch === 'string' && entry.branch.length > 0 && entry.branch !== currentRef)
|
|
7969
|
+
if (nonCurrent) {
|
|
7970
|
+
checkoutTarget = nonCurrent.branch
|
|
7971
|
+
}
|
|
7972
|
+
}
|
|
7973
|
+
if (!checkoutTarget && branchEntries.length > 0) {
|
|
7974
|
+
checkoutTarget = branchEntries[0].branch
|
|
7975
|
+
}
|
|
7976
|
+
|
|
7977
|
+
if (checkoutCwd && checkoutTarget) {
|
|
7978
|
+
const checkoutUrl = `/run/scripts/git/checkout.json?cwd=${encodeURIComponent(checkoutCwd)}&commit=${encodeURIComponent(checkoutTarget)}&callback_target=parent&callback=$location.href`
|
|
7979
|
+
returnBtn.addEventListener('click', () => {
|
|
7980
|
+
openCheckoutTerminal(checkoutUrl)
|
|
7981
|
+
})
|
|
7982
|
+
} else {
|
|
7983
|
+
returnBtn.disabled = true
|
|
7984
|
+
if (banner) {
|
|
7985
|
+
banner.classList.add('pinokio-history-latest-banner--disabled')
|
|
7986
|
+
}
|
|
7987
|
+
}
|
|
7988
|
+
} else if (banner) {
|
|
7989
|
+
const parent = banner.parentNode
|
|
7990
|
+
if (parent) {
|
|
7991
|
+
parent.removeChild(banner)
|
|
7992
|
+
}
|
|
7993
|
+
}
|
|
7694
7994
|
}
|
|
7695
7995
|
})
|
|
7696
7996
|
}
|
|
@@ -7731,6 +8031,20 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
7731
8031
|
alert('No file changes detected.')
|
|
7732
8032
|
return
|
|
7733
8033
|
}
|
|
8034
|
+
|
|
8035
|
+
const commitOid = typeof diffData.oid === 'string' ? diffData.oid : (Array.isArray(changes) && typeof changes[0]?.ref === 'string' ? changes[0].ref : null)
|
|
8036
|
+
const commitCheckoutCwd = (() => {
|
|
8037
|
+
const url = typeof diffData.git_commit_url === 'string' ? new URL(diffData.git_commit_url, window.location.origin) : null
|
|
8038
|
+
if (!url) {
|
|
8039
|
+
return null
|
|
8040
|
+
}
|
|
8041
|
+
const cwdParam = url.searchParams.get('cwd')
|
|
8042
|
+
return cwdParam && cwdParam.length > 0 ? cwdParam : null
|
|
8043
|
+
})()
|
|
8044
|
+
|
|
8045
|
+
const checkoutUrl = commitOid && commitCheckoutCwd
|
|
8046
|
+
? `/run/scripts/git/checkout.json?cwd=${encodeURIComponent(commitCheckoutCwd)}&commit=${encodeURIComponent(commitOid)}&callback_target=parent&callback=$location.href`
|
|
8047
|
+
: null
|
|
7734
8048
|
|
|
7735
8049
|
// Create custom overlay modal
|
|
7736
8050
|
const overlay = document.createElement('div')
|
|
@@ -7755,6 +8069,13 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
7755
8069
|
<div class="pinokio-git-diff-empty-state">Select a file to view its changes</div>
|
|
7756
8070
|
</div>
|
|
7757
8071
|
</div>
|
|
8072
|
+
${checkoutUrl ? `
|
|
8073
|
+
<div class="pinokio-git-commit-actions">
|
|
8074
|
+
<button type="button" class="pinokio-git-commit-switch-btn">
|
|
8075
|
+
<i class="fa-solid fa-clock-rotate-left"></i> Switch to this version
|
|
8076
|
+
</button>
|
|
8077
|
+
</div>
|
|
8078
|
+
` : ''}
|
|
7758
8079
|
</div>
|
|
7759
8080
|
</div>
|
|
7760
8081
|
`
|
|
@@ -7763,14 +8084,23 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
7763
8084
|
|
|
7764
8085
|
// Add close handler
|
|
7765
8086
|
const closeBtn = overlay.querySelector('.pinokio-custom-commit-close')
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
8087
|
+
let escHandler = null
|
|
8088
|
+
const cleanupOverlay = () => {
|
|
8089
|
+
if (escHandler) {
|
|
8090
|
+
document.removeEventListener('keydown', escHandler)
|
|
8091
|
+
escHandler = null
|
|
8092
|
+
}
|
|
8093
|
+
if (overlay.parentNode) {
|
|
8094
|
+
overlay.parentNode.removeChild(overlay)
|
|
8095
|
+
}
|
|
8096
|
+
}
|
|
8097
|
+
|
|
8098
|
+
closeBtn.addEventListener('click', cleanupOverlay)
|
|
7769
8099
|
|
|
7770
8100
|
// Close on overlay click
|
|
7771
8101
|
overlay.addEventListener('click', (e) => {
|
|
7772
8102
|
if (e.target === overlay) {
|
|
7773
|
-
|
|
8103
|
+
cleanupOverlay()
|
|
7774
8104
|
}
|
|
7775
8105
|
})
|
|
7776
8106
|
|
|
@@ -7798,16 +8128,66 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
7798
8128
|
}
|
|
7799
8129
|
})
|
|
7800
8130
|
})
|
|
8131
|
+
|
|
8132
|
+
if (checkoutUrl) {
|
|
8133
|
+
const switchBtn = overlay.querySelector('.pinokio-git-commit-switch-btn')
|
|
8134
|
+
if (switchBtn) {
|
|
8135
|
+
switchBtn.addEventListener('click', () => {
|
|
8136
|
+
cleanupOverlay()
|
|
8137
|
+
showIframeView(checkoutUrl)
|
|
8138
|
+
})
|
|
8139
|
+
}
|
|
8140
|
+
}
|
|
7801
8141
|
|
|
7802
8142
|
// Handle escape key
|
|
7803
|
-
|
|
8143
|
+
escHandler = (e) => {
|
|
7804
8144
|
if (e.key === 'Escape') {
|
|
7805
|
-
|
|
7806
|
-
document.removeEventListener('keydown', escHandler)
|
|
8145
|
+
cleanupOverlay()
|
|
7807
8146
|
}
|
|
7808
8147
|
}
|
|
7809
8148
|
document.addEventListener('keydown', escHandler)
|
|
7810
8149
|
}
|
|
8150
|
+
|
|
8151
|
+
const openCheckoutTerminal = (src) => {
|
|
8152
|
+
const overlay = document.createElement('div')
|
|
8153
|
+
overlay.className = 'pinokio-custom-terminal-overlay'
|
|
8154
|
+
overlay.innerHTML = `
|
|
8155
|
+
<div class="pinokio-custom-terminal-modal">
|
|
8156
|
+
<div class="pinokio-custom-terminal-header">
|
|
8157
|
+
<h3>Git Checkout</h3>
|
|
8158
|
+
<button class="pinokio-custom-terminal-close">×</button>
|
|
8159
|
+
</div>
|
|
8160
|
+
<div class="pinokio-custom-terminal-body">
|
|
8161
|
+
<iframe src="${src}" frameborder="0"></iframe>
|
|
8162
|
+
</div>
|
|
8163
|
+
</div>
|
|
8164
|
+
`
|
|
8165
|
+
|
|
8166
|
+
const cleanup = () => {
|
|
8167
|
+
document.removeEventListener('keydown', escHandler)
|
|
8168
|
+
if (overlay.parentNode) {
|
|
8169
|
+
overlay.parentNode.removeChild(overlay)
|
|
8170
|
+
}
|
|
8171
|
+
}
|
|
8172
|
+
|
|
8173
|
+
const closeBtn = overlay.querySelector('.pinokio-custom-terminal-close')
|
|
8174
|
+
closeBtn.addEventListener('click', cleanup)
|
|
8175
|
+
|
|
8176
|
+
overlay.addEventListener('click', (event) => {
|
|
8177
|
+
if (event.target === overlay) {
|
|
8178
|
+
cleanup()
|
|
8179
|
+
}
|
|
8180
|
+
})
|
|
8181
|
+
|
|
8182
|
+
const escHandler = (event) => {
|
|
8183
|
+
if (event.key === 'Escape') {
|
|
8184
|
+
cleanup()
|
|
8185
|
+
}
|
|
8186
|
+
}
|
|
8187
|
+
|
|
8188
|
+
document.addEventListener('keydown', escHandler)
|
|
8189
|
+
document.body.appendChild(overlay)
|
|
8190
|
+
}
|
|
7811
8191
|
|
|
7812
8192
|
const createCommitItem = (commitData) => {
|
|
7813
8193
|
const commit = commitData.commit
|