pinokiod 3.343.0 → 5.0.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/app/index.js +167 -0
- package/kernel/api/index.js +4 -0
- package/kernel/api/process/index.js +21 -0
- package/kernel/bin/browserless.js +15 -5
- package/kernel/bin/cli.js +13 -20
- package/kernel/bin/cuda.js +8 -2
- package/kernel/bin/index.js +24 -20
- package/kernel/bin/xcode-tools.js +29 -9
- package/kernel/environment.js +4 -1
- package/kernel/git.js +67 -1
- package/kernel/scripts/git/commit_files +31 -0
- package/kernel/scripts/git/reset_files +21 -0
- package/package.json +1 -1
- package/server/index.js +4 -61
- package/server/public/htmlmodal.js +12 -0
- package/server/views/app.ejs +502 -66
- package/server/views/index.ejs +4 -1
package/server/views/app.ejs
CHANGED
|
@@ -182,7 +182,9 @@ body.dark .appcanvas > aside {
|
|
|
182
182
|
background: var(--pinokio-sidebar-tabbar-bg);
|
|
183
183
|
border-bottom: 1px solid var(--pinokio-sidebar-tabbar-border);
|
|
184
184
|
*/
|
|
185
|
+
/*
|
|
185
186
|
padding: 0 12px;
|
|
187
|
+
*/
|
|
186
188
|
gap: 6px;
|
|
187
189
|
overflow: hidden;
|
|
188
190
|
--sidebar-tab-radius: 8px 8px 0 0;
|
|
@@ -1785,12 +1787,14 @@ body.dark {
|
|
|
1785
1787
|
height: 520px;
|
|
1786
1788
|
overflow: hidden;
|
|
1787
1789
|
display: flex;
|
|
1790
|
+
min-height: 0;
|
|
1788
1791
|
}
|
|
1789
1792
|
|
|
1790
1793
|
.pinokio-git-diff-main-container {
|
|
1791
1794
|
display: flex;
|
|
1792
1795
|
flex: 1;
|
|
1793
1796
|
height: 100%;
|
|
1797
|
+
min-height: 0;
|
|
1794
1798
|
backdrop-filter: blur(14px);
|
|
1795
1799
|
}
|
|
1796
1800
|
|
|
@@ -1802,16 +1806,16 @@ body.dark {
|
|
|
1802
1806
|
}
|
|
1803
1807
|
|
|
1804
1808
|
.pinokio-git-diff-file-item-row {
|
|
1805
|
-
display:
|
|
1806
|
-
|
|
1807
|
-
align-items:
|
|
1808
|
-
gap:
|
|
1809
|
+
display: grid;
|
|
1810
|
+
grid-template-columns: auto 1fr auto;
|
|
1811
|
+
align-items: center;
|
|
1812
|
+
gap: 8px;
|
|
1809
1813
|
width: 100%;
|
|
1810
1814
|
border: none;
|
|
1811
1815
|
background: transparent;
|
|
1812
1816
|
color: var(--pinokio-diff-sidebar-text);
|
|
1813
1817
|
font-size: 13px;
|
|
1814
|
-
padding: 10px
|
|
1818
|
+
padding: 10px 12px;
|
|
1815
1819
|
text-align: left;
|
|
1816
1820
|
cursor: pointer;
|
|
1817
1821
|
border-left: 3px solid transparent;
|
|
@@ -1819,6 +1823,35 @@ body.dark {
|
|
|
1819
1823
|
appearance: none;
|
|
1820
1824
|
}
|
|
1821
1825
|
|
|
1826
|
+
.pinokio-git-diff-file-checkbox {
|
|
1827
|
+
width: 18px;
|
|
1828
|
+
height: 18px;
|
|
1829
|
+
cursor: pointer;
|
|
1830
|
+
appearance: none;
|
|
1831
|
+
border: 1px solid #6b7280;
|
|
1832
|
+
border-radius: 4px;
|
|
1833
|
+
background: #f6f7fb;
|
|
1834
|
+
display: inline-grid;
|
|
1835
|
+
place-items: center;
|
|
1836
|
+
position: relative;
|
|
1837
|
+
margin-right: 2px;
|
|
1838
|
+
}
|
|
1839
|
+
.pinokio-git-diff-file-checkbox:checked {
|
|
1840
|
+
background: #2563eb;
|
|
1841
|
+
border-color: #1d4ed8;
|
|
1842
|
+
}
|
|
1843
|
+
.pinokio-git-diff-file-checkbox:checked::after {
|
|
1844
|
+
content: "✓";
|
|
1845
|
+
font-size: 13px;
|
|
1846
|
+
color: #fff;
|
|
1847
|
+
}
|
|
1848
|
+
.pinokio-git-diff-select-all {
|
|
1849
|
+
border-bottom: 1px solid var(--pinokio-diff-sidebar-border);
|
|
1850
|
+
position: sticky;
|
|
1851
|
+
top: 40px;
|
|
1852
|
+
background: #f8fafc;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1822
1855
|
.pinokio-git-diff-file-item-row .pinokio-git-diff-file {
|
|
1823
1856
|
font-weight: 600;
|
|
1824
1857
|
white-space: nowrap;
|
|
@@ -1839,13 +1872,16 @@ body.dark {
|
|
|
1839
1872
|
}
|
|
1840
1873
|
|
|
1841
1874
|
.pinokio-git-diff-file-item-row.pinokio-active-file-item {
|
|
1842
|
-
background:
|
|
1843
|
-
border-left-color:
|
|
1875
|
+
background: #eef2ff;
|
|
1876
|
+
border-left-color: #2563eb;
|
|
1844
1877
|
color: var(--pinokio-diff-sidebar-active-color);
|
|
1845
1878
|
}
|
|
1846
1879
|
|
|
1847
1880
|
.pinokio-git-diff-file-item-row.pinokio-active-file-item .pinokio-git-diff-status {
|
|
1848
|
-
color:
|
|
1881
|
+
color: #374151;
|
|
1882
|
+
}
|
|
1883
|
+
.pinokio-git-diff-file-item-row.pinokio-active-file-item .pinokio-git-diff-file-checkbox {
|
|
1884
|
+
border-color: #1d4ed8;
|
|
1849
1885
|
}
|
|
1850
1886
|
|
|
1851
1887
|
.pinokio-git-diff-file-item-row:focus-visible {
|
|
@@ -1859,11 +1895,99 @@ body.dark {
|
|
|
1859
1895
|
flex: 1;
|
|
1860
1896
|
background: var(--pinokio-diff-viewer-bg);
|
|
1861
1897
|
color: var(--pinokio-diff-viewer-text);
|
|
1862
|
-
|
|
1898
|
+
display: flex;
|
|
1899
|
+
flex-direction: column;
|
|
1900
|
+
overflow: hidden;
|
|
1863
1901
|
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
|
1864
1902
|
font-size: 13px;
|
|
1865
1903
|
line-height: 1.5;
|
|
1866
1904
|
}
|
|
1905
|
+
.pinokio-git-diff-viewer-header {
|
|
1906
|
+
display: flex;
|
|
1907
|
+
align-items: center;
|
|
1908
|
+
justify-content: space-between;
|
|
1909
|
+
gap: 12px;
|
|
1910
|
+
padding: 8px 12px;
|
|
1911
|
+
border-bottom: 1px solid var(--pinokio-diff-sidebar-border);
|
|
1912
|
+
background: var(--pinokio-diff-viewer-bg);
|
|
1913
|
+
position: sticky;
|
|
1914
|
+
top: 0;
|
|
1915
|
+
z-index: 1;
|
|
1916
|
+
}
|
|
1917
|
+
.pinokio-git-diff-viewer-title {
|
|
1918
|
+
font-weight: 600;
|
|
1919
|
+
overflow: hidden;
|
|
1920
|
+
text-overflow: ellipsis;
|
|
1921
|
+
white-space: nowrap;
|
|
1922
|
+
}
|
|
1923
|
+
.pinokio-git-diff-open-file {
|
|
1924
|
+
display: inline-flex;
|
|
1925
|
+
align-items: center;
|
|
1926
|
+
gap: 6px;
|
|
1927
|
+
padding: 8px 12px;
|
|
1928
|
+
border-radius: 8px;
|
|
1929
|
+
border: 1px solid #d1d5db;
|
|
1930
|
+
background: #f9fafb;
|
|
1931
|
+
color: inherit;
|
|
1932
|
+
text-decoration: none;
|
|
1933
|
+
font-weight: 600;
|
|
1934
|
+
font-size: 12px;
|
|
1935
|
+
font-family: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
|
|
1936
|
+
}
|
|
1937
|
+
.pinokio-git-diff-open-file:hover {
|
|
1938
|
+
background: #eef2ff;
|
|
1939
|
+
border-color: #cbd5e1;
|
|
1940
|
+
}
|
|
1941
|
+
.pinokio-git-diff-bulk-bar {
|
|
1942
|
+
display: flex;
|
|
1943
|
+
align-items: center;
|
|
1944
|
+
justify-content: space-between;
|
|
1945
|
+
gap: 12px;
|
|
1946
|
+
padding: 10px 12px;
|
|
1947
|
+
border-bottom: 1px solid #e5e7eb;
|
|
1948
|
+
background: #f8fafc;
|
|
1949
|
+
position: sticky;
|
|
1950
|
+
top: 0;
|
|
1951
|
+
z-index: 2;
|
|
1952
|
+
}
|
|
1953
|
+
.pinokio-git-diff-bulk-title {
|
|
1954
|
+
font-weight: 600;
|
|
1955
|
+
font-size: 13px;
|
|
1956
|
+
}
|
|
1957
|
+
.pinokio-git-diff-revert-btn {
|
|
1958
|
+
width: 100%;
|
|
1959
|
+
box-sizing: border-box;
|
|
1960
|
+
justify-content: center;
|
|
1961
|
+
display: inline-flex;
|
|
1962
|
+
align-items: center;
|
|
1963
|
+
gap: 6px;
|
|
1964
|
+
padding: 18px;
|
|
1965
|
+
border-radius: 5px;
|
|
1966
|
+
border: 1px solid #2563eb !important;
|
|
1967
|
+
background: #2563eb !important;
|
|
1968
|
+
color: #fff !important;
|
|
1969
|
+
cursor: pointer;
|
|
1970
|
+
font: inherit;
|
|
1971
|
+
}
|
|
1972
|
+
.pinokio-git-diff-revert-btn:hover {
|
|
1973
|
+
background: #1d4ed8;
|
|
1974
|
+
}
|
|
1975
|
+
.pinokio-git-diff-revert-btn:disabled {
|
|
1976
|
+
background: #e5e7eb !important;
|
|
1977
|
+
border-color: #cbd5e1 !important;
|
|
1978
|
+
color: #6b7280 !important;
|
|
1979
|
+
cursor: not-allowed;
|
|
1980
|
+
}
|
|
1981
|
+
.pinokio-git-diff-revert-btn, .pinokio-save-version-btn {
|
|
1982
|
+
font-family: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
|
|
1983
|
+
font-weight: 600;
|
|
1984
|
+
}
|
|
1985
|
+
.pinokio-git-diff-viewer-body {
|
|
1986
|
+
padding: 10px;
|
|
1987
|
+
overflow: auto;
|
|
1988
|
+
flex: 1 1 auto;
|
|
1989
|
+
min-height: 0;
|
|
1990
|
+
}
|
|
1867
1991
|
|
|
1868
1992
|
.pinokio-git-diff-empty-state {
|
|
1869
1993
|
display: grid;
|
|
@@ -2530,26 +2654,33 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
2530
2654
|
|
|
2531
2655
|
.pinokio-commit-message-input {
|
|
2532
2656
|
flex: 1;
|
|
2657
|
+
min-height: 44px;
|
|
2533
2658
|
}
|
|
2534
2659
|
|
|
2535
2660
|
.pinokio-save-version-btn {
|
|
2536
|
-
padding:
|
|
2537
|
-
|
|
2538
|
-
border:
|
|
2539
|
-
|
|
2540
|
-
|
|
2661
|
+
padding: 12px 18px;
|
|
2662
|
+
min-height: 44px;
|
|
2663
|
+
border-radius: 10px;
|
|
2664
|
+
border: 1px solid #2563eb !important;
|
|
2665
|
+
background: #2563eb !important;
|
|
2666
|
+
color: #fff !important;
|
|
2541
2667
|
font-weight: 600;
|
|
2542
2668
|
cursor: pointer;
|
|
2543
2669
|
}
|
|
2544
2670
|
|
|
2545
2671
|
.pinokio-save-version-btn:hover {
|
|
2546
|
-
|
|
2547
|
-
box-shadow: 0 14px 32px rgba(16, 185, 129, 0.35);
|
|
2672
|
+
background: #1d4ed8;
|
|
2548
2673
|
}
|
|
2549
2674
|
|
|
2550
2675
|
.pinokio-save-version-btn:active {
|
|
2551
2676
|
transform: translateY(0);
|
|
2552
2677
|
}
|
|
2678
|
+
.pinokio-save-version-btn:disabled {
|
|
2679
|
+
background: #e5e7eb;
|
|
2680
|
+
border-color: #cbd5e1;
|
|
2681
|
+
color: #6b7280;
|
|
2682
|
+
cursor: not-allowed;
|
|
2683
|
+
}
|
|
2553
2684
|
|
|
2554
2685
|
.pinokio-history-empty {
|
|
2555
2686
|
display: grid;
|
|
@@ -2847,6 +2978,7 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
2847
2978
|
}
|
|
2848
2979
|
|
|
2849
2980
|
.pinokio-diff-code-line-content {
|
|
2981
|
+
box-sizing: border-box;
|
|
2850
2982
|
display: block;
|
|
2851
2983
|
width: 100%;
|
|
2852
2984
|
padding: 6px 14px;
|
|
@@ -3040,6 +3172,10 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
3040
3172
|
}
|
|
3041
3173
|
}
|
|
3042
3174
|
*/
|
|
3175
|
+
.meta-icon {
|
|
3176
|
+
width: 30px;
|
|
3177
|
+
height: 30px;
|
|
3178
|
+
}
|
|
3043
3179
|
</style>
|
|
3044
3180
|
<link href="/app.css" rel="stylesheet"/>
|
|
3045
3181
|
<link href="/tab-link-popover.css" rel="stylesheet"/>
|
|
@@ -3115,6 +3251,9 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
3115
3251
|
<% if (type !== 'files') { %>
|
|
3116
3252
|
<aside class='active'>
|
|
3117
3253
|
<div class='menu-container'>
|
|
3254
|
+
<% if (config.icon) { %>
|
|
3255
|
+
<img class='meta-icon' src="<%=config.icon%>"/>
|
|
3256
|
+
<% } %>
|
|
3118
3257
|
<div class='m n system' data-type="n">
|
|
3119
3258
|
<%if (type==='browse') { %>
|
|
3120
3259
|
<a id='devtab' data-mode="refresh" target="<%=dev_link%>" href="<%=dev_link%>" class="btn frame-link selected" data-index="10">
|
|
@@ -3171,11 +3310,6 @@ body.dark .pinokio-fork-dropdown-remote, body.dark .pinokio-publish-dropdown-rem
|
|
|
3171
3310
|
<div class='container'>
|
|
3172
3311
|
<% if (type === "browse") { %>
|
|
3173
3312
|
<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%>">
|
|
3174
|
-
<div class="app-info" title="<%=config.title || name%>">
|
|
3175
|
-
<div class="app-info-card">
|
|
3176
|
-
<img src="<%= config.icon %>" onerror="this.onerror=null; this.src='/pinokio-black.png'" alt="Project icon">
|
|
3177
|
-
</div>
|
|
3178
|
-
</div>
|
|
3179
3313
|
<!--
|
|
3180
3314
|
<div class='fs-status-dropdown nested-menu git blue'>
|
|
3181
3315
|
<button type='button' class='fs-status-btn frame-link reveal'>
|
|
@@ -5780,6 +5914,28 @@ const rerenderMenuSection = (container, html) => {
|
|
|
5780
5914
|
})
|
|
5781
5915
|
}
|
|
5782
5916
|
|
|
5917
|
+
const isUntrackedStatus = (status) => {
|
|
5918
|
+
const s = (status || '').toLowerCase()
|
|
5919
|
+
return s.includes('new') || s.includes('add') || s.includes('untracked')
|
|
5920
|
+
}
|
|
5921
|
+
|
|
5922
|
+
const escapePathForShell = (value) => {
|
|
5923
|
+
if (typeof value !== 'string') return ''
|
|
5924
|
+
// Escape quotes and dollars/backticks to reduce shell injection risk
|
|
5925
|
+
const escaped = value.replace(/(["`$\\])/g, '\\$1')
|
|
5926
|
+
return `"${escaped}"`
|
|
5927
|
+
}
|
|
5928
|
+
|
|
5929
|
+
const buildPathArgs = (paths) => {
|
|
5930
|
+
if (!Array.isArray(paths) || paths.length === 0) {
|
|
5931
|
+
return ''
|
|
5932
|
+
}
|
|
5933
|
+
return paths
|
|
5934
|
+
.filter(Boolean)
|
|
5935
|
+
.map((p) => escapePathForShell(String(p)))
|
|
5936
|
+
.join(' ')
|
|
5937
|
+
}
|
|
5938
|
+
|
|
5783
5939
|
function getRepoListSnapshot() {
|
|
5784
5940
|
if (Array.isArray(lastRepoList) && lastRepoList.length > 0) {
|
|
5785
5941
|
return lastRepoList.slice()
|
|
@@ -6652,6 +6808,7 @@ const rerenderMenuSection = (container, html) => {
|
|
|
6652
6808
|
}
|
|
6653
6809
|
|
|
6654
6810
|
let messageListener = null
|
|
6811
|
+
let reopenDiffOnCallback = false
|
|
6655
6812
|
|
|
6656
6813
|
const showIframeView = (src) => {
|
|
6657
6814
|
const iframeMarkup = `<iframe src="${src}" frameborder="0"></iframe>`
|
|
@@ -6714,7 +6871,13 @@ const rerenderMenuSection = (container, html) => {
|
|
|
6714
6871
|
if (typeof check_git === 'function') {
|
|
6715
6872
|
check_git()
|
|
6716
6873
|
}
|
|
6717
|
-
|
|
6874
|
+
if (reopenDiffOnCallback && typeof showGitDiffModal === 'function') {
|
|
6875
|
+
reopenDiffOnCallback = false
|
|
6876
|
+
showGitDiffModal({ forceRefresh: true })
|
|
6877
|
+
} else {
|
|
6878
|
+
reopenDiffOnCallback = false
|
|
6879
|
+
}
|
|
6880
|
+
|
|
6718
6881
|
// Close the modal
|
|
6719
6882
|
Swal.close()
|
|
6720
6883
|
|
|
@@ -6951,17 +7114,13 @@ const rerenderMenuSection = (container, html) => {
|
|
|
6951
7114
|
else statusCounts.modified += 1
|
|
6952
7115
|
})
|
|
6953
7116
|
|
|
6954
|
-
|
|
6955
|
-
if (statusCounts.added) badgeFragments.push(`<span class="pinokio-pill"><i class="fa-solid fa-plus"></i>${statusCounts.added} added</span>`)
|
|
6956
|
-
if (statusCounts.modified) badgeFragments.push(`<span class="pinokio-pill"><i class="fa-solid fa-pen"></i>${statusCounts.modified} updated</span>`)
|
|
6957
|
-
if (statusCounts.deleted) badgeFragments.push(`<span class="pinokio-pill"><i class="fa-solid fa-trash"></i>${statusCounts.deleted} deleted</span>`)
|
|
6958
|
-
if (statusCounts.renamed) badgeFragments.push(`<span class="pinokio-pill"><i class="fa-solid fa-arrow-right-arrow-left"></i>${statusCounts.renamed} renamed</span>`)
|
|
6959
|
-
|
|
6960
|
-
const commitSection = showSaveButton ? `
|
|
7117
|
+
const commitSection = showSaveButton ? `
|
|
6961
7118
|
<div class="pinokio-modal-footer pinokio-modal-footer--commit">
|
|
6962
7119
|
<div class="pinokio-commit-message-container">
|
|
6963
7120
|
<input type="text" class="pinokio-modal-input pinokio-commit-message-input" placeholder="Enter commit message..." value="${generateCommitMessage(changes)}">
|
|
6964
|
-
<
|
|
7121
|
+
<div class="pinokio-commit-actions">
|
|
7122
|
+
<button type="button" class="pinokio-save-version-btn">Save selected</button>
|
|
7123
|
+
</div>
|
|
6965
7124
|
</div>
|
|
6966
7125
|
</div>
|
|
6967
7126
|
` : ''
|
|
@@ -6985,15 +7144,20 @@ const rerenderMenuSection = (container, html) => {
|
|
|
6985
7144
|
<i class="fa-solid fa-clock-rotate-left"></i> History
|
|
6986
7145
|
</button>
|
|
6987
7146
|
</div>
|
|
6988
|
-
${badgeFragments.length ? `<div class="pinokio-history-meta">${badgeFragments.join('')}</div>` : ''}
|
|
6989
7147
|
<div class="pinokio-modal-body pinokio-modal-body--diff" data-tab-panel="changes">
|
|
6990
7148
|
<div class="pinokio-git-diff-main-container">
|
|
6991
7149
|
<div class="pinokio-git-diff-file-list-panel">
|
|
7150
|
+
<div class="pinokio-git-diff-file-item-row pinokio-git-diff-select-all">
|
|
7151
|
+
<input type="checkbox" class="pinokio-git-diff-file-checkbox" data-select-all checked>
|
|
7152
|
+
<span class="pinokio-git-diff-file">Select all</span>
|
|
7153
|
+
<span></span>
|
|
7154
|
+
</div>
|
|
6992
7155
|
${changes.map((change, index) => `
|
|
6993
|
-
<
|
|
7156
|
+
<div class="pinokio-git-diff-file-item-row" role="button" tabindex="0" data-index="${index}" data-diffpath="${change.diffpath}" data-filepath="${change.file}" data-abspath="${change.path || ''}" data-status="${change.status || ''}">
|
|
7157
|
+
<input type="checkbox" class="pinokio-git-diff-file-checkbox" data-file-checkbox data-index="${index}" checked>
|
|
6994
7158
|
<span class="pinokio-git-diff-file">${change.file}</span>
|
|
6995
7159
|
<span class="pinokio-git-diff-status">${change.status}</span>
|
|
6996
|
-
</
|
|
7160
|
+
</div>
|
|
6997
7161
|
`).join('')}
|
|
6998
7162
|
</div>
|
|
6999
7163
|
<div class="pinokio-git-diff-viewer-panel">
|
|
@@ -7035,50 +7199,299 @@ const rerenderMenuSection = (container, html) => {
|
|
|
7035
7199
|
}
|
|
7036
7200
|
},
|
|
7037
7201
|
didOpen: () => {
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
const fileItems = container.querySelectorAll('.pinokio-git-diff-file-item-row')
|
|
7202
|
+
const container = Swal.getHtmlContainer()
|
|
7203
|
+
if (!container) return
|
|
7204
|
+
const fileItems = container.querySelectorAll('.pinokio-git-diff-file-item-row[data-index]')
|
|
7205
|
+
const fileCheckboxes = container.querySelectorAll('[data-file-checkbox]')
|
|
7206
|
+
const selectAllCheckbox = container.querySelector('[data-select-all]')
|
|
7041
7207
|
const diffViewer = container.querySelector('.pinokio-git-diff-viewer-panel')
|
|
7042
7208
|
const tabButtons = container.querySelectorAll('.pinokio-modal-tab')
|
|
7043
7209
|
const tabPanels = container.querySelectorAll('[data-tab-panel]')
|
|
7044
7210
|
const historyPanel = container.querySelector('[data-tab-panel="history"]')
|
|
7045
7211
|
const commitFooter = container.querySelector('.pinokio-modal-footer--commit')
|
|
7046
7212
|
let historyLoaded = false
|
|
7213
|
+
let repoCwd = ''
|
|
7214
|
+
try {
|
|
7215
|
+
const commitUrlObj = commitUrl ? new URL(commitUrl, window.location.origin) : null
|
|
7216
|
+
repoCwd = commitUrlObj ? (commitUrlObj.searchParams.get('cwd') || '') : ''
|
|
7217
|
+
} catch (error) {
|
|
7218
|
+
repoCwd = ''
|
|
7219
|
+
}
|
|
7220
|
+
if (diffViewer && repoCwd) {
|
|
7221
|
+
diffViewer.setAttribute('data-repo-cwd', repoCwd)
|
|
7222
|
+
}
|
|
7047
7223
|
|
|
7048
7224
|
const saveBtn = container.querySelector('.pinokio-save-version-btn')
|
|
7225
|
+
const commitMessageInput = container.querySelector('.pinokio-commit-message-input')
|
|
7226
|
+
const getCommitMessage = () => commitMessageInput ? commitMessageInput.value.trim() : ''
|
|
7227
|
+
|
|
7049
7228
|
if (saveBtn) {
|
|
7050
7229
|
saveBtn.addEventListener('click', () => {
|
|
7051
|
-
const
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
|
|
7056
|
-
|
|
7230
|
+
const commitMessage = getCommitMessage()
|
|
7231
|
+
if (!commitUrl) {
|
|
7232
|
+
Swal.showValidationMessage('No commit URL available')
|
|
7233
|
+
return
|
|
7234
|
+
}
|
|
7235
|
+
const selectedEntries = getSelectedEntries()
|
|
7236
|
+
if (!selectedEntries.length) {
|
|
7237
|
+
Swal.showValidationMessage('No files selected')
|
|
7238
|
+
return
|
|
7239
|
+
}
|
|
7240
|
+
const trackedPaths = []
|
|
7241
|
+
const untrackedPaths = []
|
|
7242
|
+
selectedEntries.forEach((entry) => {
|
|
7243
|
+
if (isUntrackedStatus(entry.status)) {
|
|
7244
|
+
untrackedPaths.push(entry.path)
|
|
7245
|
+
} else {
|
|
7246
|
+
trackedPaths.push(entry.path)
|
|
7057
7247
|
}
|
|
7058
|
-
|
|
7248
|
+
})
|
|
7249
|
+
const trackedArg = buildPathArgs(trackedPaths)
|
|
7250
|
+
const untrackedArg = buildPathArgs(untrackedPaths)
|
|
7251
|
+
if (!trackedArg && !untrackedArg) {
|
|
7252
|
+
Swal.showValidationMessage('No files selected')
|
|
7253
|
+
return
|
|
7254
|
+
}
|
|
7255
|
+
|
|
7256
|
+
const commitUrlObj = new URL(commitUrl, window.location.origin)
|
|
7257
|
+
const viewerCwd = commitUrlObj.searchParams.get('cwd') || repoCwd || ''
|
|
7258
|
+
if (!viewerCwd) {
|
|
7259
|
+
Swal.showValidationMessage('Repository path unavailable')
|
|
7260
|
+
return
|
|
7261
|
+
}
|
|
7262
|
+
|
|
7263
|
+
const parts = [`/run/scripts/git/commit_files.json?cwd=${encodeURIComponent(viewerCwd)}`]
|
|
7264
|
+
if (commitMessage) {
|
|
7265
|
+
parts.push(`message=${encodeURIComponent(commitMessage)}`)
|
|
7266
|
+
}
|
|
7267
|
+
if (trackedArg) {
|
|
7268
|
+
parts.push(`paths=${encodeURIComponent(trackedArg)}`)
|
|
7269
|
+
}
|
|
7270
|
+
if (untrackedArg) {
|
|
7271
|
+
parts.push(`untracked_paths=${encodeURIComponent(untrackedArg)}`)
|
|
7272
|
+
}
|
|
7273
|
+
parts.push('callback_target=parent')
|
|
7274
|
+
parts.push('callback=$location.href')
|
|
7275
|
+
const url = parts.join('&')
|
|
7276
|
+
showIframeView(url)
|
|
7277
|
+
})
|
|
7278
|
+
}
|
|
7279
|
+
|
|
7280
|
+
const fileItemsArray = Array.from(fileItems)
|
|
7281
|
+
const checkboxMap = new Map()
|
|
7282
|
+
fileCheckboxes.forEach((cb) => {
|
|
7283
|
+
const idx = Number(cb.getAttribute('data-index') || '-1')
|
|
7284
|
+
checkboxMap.set(idx, cb)
|
|
7285
|
+
})
|
|
7286
|
+
const selectedIndices = new Set(fileItemsArray.map((btn) => Number(btn.getAttribute('data-index') || '-1')))
|
|
7287
|
+
let lastSelectedIndex = null
|
|
7288
|
+
|
|
7289
|
+
const applySelectionClasses = () => {
|
|
7290
|
+
fileItemsArray.forEach((btn) => {
|
|
7291
|
+
const idx = Number(btn.getAttribute('data-index') || '-1')
|
|
7292
|
+
const isSelected = selectedIndices.has(idx)
|
|
7293
|
+
btn.classList.toggle('pinokio-active-file-item', isSelected)
|
|
7294
|
+
const cb = checkboxMap.get(idx)
|
|
7295
|
+
if (cb) {
|
|
7296
|
+
cb.checked = isSelected
|
|
7297
|
+
}
|
|
7298
|
+
})
|
|
7299
|
+
if (selectAllCheckbox) {
|
|
7300
|
+
const total = fileItemsArray.length
|
|
7301
|
+
const selectedCount = selectedIndices.size
|
|
7302
|
+
selectAllCheckbox.indeterminate = selectedCount > 0 && selectedCount < total
|
|
7303
|
+
selectAllCheckbox.checked = selectedCount === total
|
|
7304
|
+
}
|
|
7305
|
+
updateBulkBar()
|
|
7306
|
+
}
|
|
7307
|
+
|
|
7308
|
+
const getSelectedEntries = () => {
|
|
7309
|
+
const entries = []
|
|
7310
|
+
fileItemsArray.forEach((btn) => {
|
|
7311
|
+
const idx = Number(btn.getAttribute('data-index') || '-1')
|
|
7312
|
+
if (!selectedIndices.has(idx)) return
|
|
7313
|
+
const status = btn.getAttribute('data-status') || ''
|
|
7314
|
+
const filePath = btn.getAttribute('data-filepath') || ''
|
|
7315
|
+
const absPath = btn.getAttribute('data-abspath') || ''
|
|
7316
|
+
const pathValue = absPath || filePath
|
|
7317
|
+
if (!pathValue) return
|
|
7318
|
+
const entry = { status, filePath, path: pathValue }
|
|
7319
|
+
entries.push(entry)
|
|
7320
|
+
})
|
|
7321
|
+
return entries
|
|
7322
|
+
}
|
|
7323
|
+
|
|
7324
|
+
const fileListPanel = container.querySelector('.pinokio-git-diff-file-list-panel')
|
|
7325
|
+
const bulkResetButton = document.createElement('button')
|
|
7326
|
+
bulkResetButton.type = 'button'
|
|
7327
|
+
bulkResetButton.className = 'pinokio-git-diff-revert-btn pinokio-git-diff-bulk-btn'
|
|
7328
|
+
bulkResetButton.disabled = true
|
|
7329
|
+
bulkResetButton.innerHTML = `<i class="fa-solid fa-arrow-rotate-left"></i> Reset selected`
|
|
7330
|
+
const bulkResetContainer = document.createElement('div')
|
|
7331
|
+
bulkResetContainer.className = 'pinokio-git-diff-bulk-bar'
|
|
7332
|
+
bulkResetContainer.setAttribute('data-bulk-bar', 'true')
|
|
7333
|
+
bulkResetContainer.appendChild(bulkResetButton)
|
|
7334
|
+
if (fileListPanel) {
|
|
7335
|
+
fileListPanel.insertBefore(bulkResetContainer, fileListPanel.firstChild)
|
|
7336
|
+
}
|
|
7337
|
+
|
|
7338
|
+
function updateBulkBar() {
|
|
7339
|
+
const selectedEntries = getSelectedEntries()
|
|
7340
|
+
const selectionCount = selectedEntries.length
|
|
7341
|
+
const trackedPaths = []
|
|
7342
|
+
const untrackedPaths = []
|
|
7343
|
+
selectedEntries.forEach((entry) => {
|
|
7344
|
+
if (isUntrackedStatus(entry.status)) {
|
|
7345
|
+
untrackedPaths.push(entry.path)
|
|
7059
7346
|
} else {
|
|
7060
|
-
|
|
7347
|
+
trackedPaths.push(entry.path)
|
|
7061
7348
|
}
|
|
7062
7349
|
})
|
|
7350
|
+
const trackedArg = buildPathArgs(trackedPaths)
|
|
7351
|
+
const untrackedArg = buildPathArgs(untrackedPaths)
|
|
7352
|
+
const viewerCwd = (diffViewer && diffViewer.getAttribute('data-repo-cwd')) || repoCwd || ''
|
|
7353
|
+
const hasPaths = Boolean(trackedArg || untrackedArg)
|
|
7354
|
+
const hasTarget = Boolean(viewerCwd && hasPaths && selectionCount > 0)
|
|
7355
|
+
let bulkUrl = null
|
|
7356
|
+
if (hasTarget) {
|
|
7357
|
+
const urlParts = [`/run/scripts/git/reset_files.json?cwd=${encodeURIComponent(viewerCwd)}`]
|
|
7358
|
+
if (trackedArg) urlParts.push(`tracked_paths=${encodeURIComponent(trackedArg)}`)
|
|
7359
|
+
if (untrackedArg) urlParts.push(`untracked_paths=${encodeURIComponent(untrackedArg)}`)
|
|
7360
|
+
urlParts.push('callback_target=parent')
|
|
7361
|
+
urlParts.push('callback=$location.href')
|
|
7362
|
+
bulkUrl = urlParts.join('&')
|
|
7363
|
+
}
|
|
7364
|
+
bulkResetButton.textContent = `Reset selected (${selectionCount})`
|
|
7365
|
+
bulkResetButton.disabled = selectionCount === 0
|
|
7366
|
+
bulkResetButton.onclick = null
|
|
7367
|
+
bulkResetButton.onclick = () => {
|
|
7368
|
+
if (selectionCount === 0) return
|
|
7369
|
+
if (!viewerCwd || !hasPaths || !bulkUrl) {
|
|
7370
|
+
Swal.showValidationMessage('Cannot reset: missing repository context or paths')
|
|
7371
|
+
return
|
|
7372
|
+
}
|
|
7373
|
+
const confirmed = confirm(`Reset ${selectionCount} selected file${selectionCount === 1 ? '' : 's'}?`)
|
|
7374
|
+
if (!confirmed) return
|
|
7375
|
+
reopenDiffOnCallback = true
|
|
7376
|
+
showIframeView(bulkUrl)
|
|
7377
|
+
}
|
|
7063
7378
|
}
|
|
7064
7379
|
|
|
7065
|
-
|
|
7066
|
-
|
|
7067
|
-
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7380
|
+
const renderFileDiff = async (item) => {
|
|
7381
|
+
const diffpath = item.getAttribute('data-diffpath')
|
|
7382
|
+
const filePath = item.getAttribute('data-filepath') || ''
|
|
7383
|
+
const titleText = escapeHtml(filePath || 'Selected file')
|
|
7384
|
+
const openHref = (repoParam && filePath)
|
|
7385
|
+
? `/api/${encodeRepoPath(repoParam)}/${filePath.split('/').map(encodeURIComponent).join('/') }?fs=view`
|
|
7386
|
+
: null
|
|
7387
|
+
|
|
7388
|
+
const headerHtml = `
|
|
7389
|
+
<div class="pinokio-git-diff-viewer-header">
|
|
7390
|
+
<div class="pinokio-git-diff-viewer-title">${titleText}</div>
|
|
7391
|
+
${openHref ? `
|
|
7392
|
+
<button type="button" class="pinokio-git-diff-open-file" data-open-repo="${escapeHtml(repoParam || '')}" data-open-relpath="${escapeHtml(filePath || '')}">
|
|
7393
|
+
<i class="fa-solid fa-folder-open"></i>
|
|
7394
|
+
Open in explorer
|
|
7395
|
+
</button>
|
|
7396
|
+
` : ''}
|
|
7397
|
+
</div>
|
|
7398
|
+
`
|
|
7399
|
+
|
|
7400
|
+
diffViewer.innerHTML = `${headerHtml}<div class="pinokio-git-diff-viewer-body"><div class="pinokio-git-diff-empty-state">Loading…</div></div>`
|
|
7401
|
+
const diffBody = diffViewer.querySelector('.pinokio-git-diff-viewer-body')
|
|
7402
|
+
try {
|
|
7403
|
+
const diffRes = await fetch(diffpath)
|
|
7404
|
+
const diffJson = await diffRes.json()
|
|
7405
|
+
renderDiff(diffJson, diffBody)
|
|
7406
|
+
const openBtn = diffViewer.querySelector('.pinokio-git-diff-open-file')
|
|
7407
|
+
if (openBtn) {
|
|
7408
|
+
openBtn.addEventListener('click', async () => {
|
|
7409
|
+
const repoKey = openBtn.getAttribute('data-open-repo') || repoParam || ''
|
|
7410
|
+
const rel = openBtn.getAttribute('data-open-relpath') || ''
|
|
7411
|
+
if (!repoKey || !rel) return
|
|
7412
|
+
const encodedRepo = encodeRepoPath(repoKey)
|
|
7413
|
+
const encodedRel = rel.split('/').map(encodeURIComponent).join('/')
|
|
7414
|
+
const url = `/api/${encodedRepo}/${encodedRel}?fs=view`
|
|
7415
|
+
try {
|
|
7416
|
+
await fetch(url)
|
|
7417
|
+
} catch (error) {
|
|
7418
|
+
console.error('Failed to open in explorer', error)
|
|
7419
|
+
}
|
|
7420
|
+
})
|
|
7421
|
+
}
|
|
7422
|
+
} catch (error) {
|
|
7423
|
+
console.error('Error fetching diff:', error)
|
|
7424
|
+
if (diffBody) {
|
|
7425
|
+
diffBody.innerHTML = '<div class="pinokio-git-diff-empty-state">Error loading diff</div>'
|
|
7426
|
+
}
|
|
7427
|
+
}
|
|
7428
|
+
}
|
|
7429
|
+
|
|
7430
|
+
fileItemsArray.forEach(item => {
|
|
7431
|
+
item.addEventListener('click', async (event) => {
|
|
7432
|
+
const targetIsCheckbox = event.target && event.target.hasAttribute && event.target.hasAttribute('data-file-checkbox')
|
|
7433
|
+
const index = Number(item.getAttribute('data-index') || '-1')
|
|
7434
|
+
if (!targetIsCheckbox) {
|
|
7435
|
+
// Preview only
|
|
7436
|
+
lastSelectedIndex = index
|
|
7437
|
+
await renderFileDiff(item)
|
|
7438
|
+
return
|
|
7078
7439
|
}
|
|
7440
|
+
const cb = checkboxMap.get(index)
|
|
7441
|
+
const isChecked = cb ? cb.checked : selectedIndices.has(index)
|
|
7442
|
+
if (isChecked) {
|
|
7443
|
+
selectedIndices.add(index)
|
|
7444
|
+
} else {
|
|
7445
|
+
selectedIndices.delete(index)
|
|
7446
|
+
}
|
|
7447
|
+
lastSelectedIndex = index
|
|
7448
|
+
applySelectionClasses()
|
|
7449
|
+
await renderFileDiff(item)
|
|
7079
7450
|
})
|
|
7080
7451
|
})
|
|
7081
7452
|
|
|
7453
|
+
fileCheckboxes.forEach((cb) => {
|
|
7454
|
+
cb.addEventListener('click', (e) => {
|
|
7455
|
+
e.stopPropagation()
|
|
7456
|
+
})
|
|
7457
|
+
cb.addEventListener('change', async () => {
|
|
7458
|
+
const idx = Number(cb.getAttribute('data-index') || '-1')
|
|
7459
|
+
if (cb.checked) {
|
|
7460
|
+
selectedIndices.add(idx)
|
|
7461
|
+
} else {
|
|
7462
|
+
selectedIndices.delete(idx)
|
|
7463
|
+
}
|
|
7464
|
+
applySelectionClasses()
|
|
7465
|
+
const item = fileItemsArray.find((btn) => Number(btn.getAttribute('data-index') || '-1') === idx)
|
|
7466
|
+
if (item) {
|
|
7467
|
+
await renderFileDiff(item)
|
|
7468
|
+
}
|
|
7469
|
+
})
|
|
7470
|
+
})
|
|
7471
|
+
|
|
7472
|
+
if (selectAllCheckbox) {
|
|
7473
|
+
selectAllCheckbox.addEventListener('change', () => {
|
|
7474
|
+
if (selectAllCheckbox.checked) {
|
|
7475
|
+
fileItemsArray.forEach((btn) => {
|
|
7476
|
+
const idx = Number(btn.getAttribute('data-index') || '-1')
|
|
7477
|
+
selectedIndices.add(idx)
|
|
7478
|
+
})
|
|
7479
|
+
} else {
|
|
7480
|
+
selectedIndices.clear()
|
|
7481
|
+
}
|
|
7482
|
+
applySelectionClasses()
|
|
7483
|
+
const activeItem = fileItemsArray.find((btn) => btn.classList.contains('pinokio-active-file-item'))
|
|
7484
|
+
if (activeItem) {
|
|
7485
|
+
renderFileDiff(activeItem)
|
|
7486
|
+
}
|
|
7487
|
+
})
|
|
7488
|
+
selectAllCheckbox.addEventListener('click', (e) => {
|
|
7489
|
+
e.stopPropagation()
|
|
7490
|
+
})
|
|
7491
|
+
}
|
|
7492
|
+
|
|
7493
|
+
applySelectionClasses()
|
|
7494
|
+
|
|
7082
7495
|
const renderHistoryInline = (historyData) => {
|
|
7083
7496
|
if (!historyPanel) {
|
|
7084
7497
|
return
|
|
@@ -7506,15 +7919,15 @@ const rerenderMenuSection = (container, html) => {
|
|
|
7506
7919
|
<button class="pinokio-custom-commit-close">×</button>
|
|
7507
7920
|
</div>
|
|
7508
7921
|
<div class="pinokio-custom-commit-content">
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
<
|
|
7922
|
+
<div class="pinokio-git-diff-main-container">
|
|
7923
|
+
<div class="pinokio-git-diff-file-list-panel">
|
|
7924
|
+
${changes.map((change, index) => `
|
|
7925
|
+
<div class="pinokio-git-diff-file-item-row" role="button" tabindex="0" data-index="${index}" data-diffpath="${change.diffpath}" data-filepath="${change.file}" data-abspath="${change.path || ''}" data-status="${change.status || ''}">
|
|
7513
7926
|
<span class="pinokio-git-diff-file">${change.file}</span>
|
|
7514
7927
|
<span class="pinokio-git-diff-status">${change.status}</span>
|
|
7515
|
-
</
|
|
7928
|
+
</div>
|
|
7516
7929
|
`).join('')}
|
|
7517
|
-
|
|
7930
|
+
</div>
|
|
7518
7931
|
<div class="pinokio-git-diff-viewer-panel">
|
|
7519
7932
|
<div class="pinokio-git-diff-empty-state">Select a file to view its changes</div>
|
|
7520
7933
|
</div>
|
|
@@ -7557,6 +7970,9 @@ const rerenderMenuSection = (container, html) => {
|
|
|
7557
7970
|
// Add file click handlers
|
|
7558
7971
|
const fileItems = overlay.querySelectorAll('.pinokio-git-diff-file-item-row')
|
|
7559
7972
|
const diffViewer = overlay.querySelector('.pinokio-git-diff-viewer-panel')
|
|
7973
|
+
if (diffViewer && commitCheckoutCwd) {
|
|
7974
|
+
diffViewer.setAttribute('data-repo-cwd', commitCheckoutCwd)
|
|
7975
|
+
}
|
|
7560
7976
|
|
|
7561
7977
|
fileItems.forEach(item => {
|
|
7562
7978
|
item.addEventListener('click', async () => {
|
|
@@ -7566,15 +7982,35 @@ const rerenderMenuSection = (container, html) => {
|
|
|
7566
7982
|
item.classList.add('pinokio-active-file-item')
|
|
7567
7983
|
|
|
7568
7984
|
const diffpath = item.getAttribute('data-diffpath')
|
|
7569
|
-
|
|
7985
|
+
const filePath = item.getAttribute('data-filepath') || ''
|
|
7986
|
+
const titleText = escapeHtml(filePath || 'Selected file')
|
|
7987
|
+
const headerHtml = `
|
|
7988
|
+
<div class="pinokio-git-diff-viewer-header">
|
|
7989
|
+
<div class="pinokio-git-diff-viewer-title">${titleText}</div>
|
|
7990
|
+
</div>
|
|
7991
|
+
`
|
|
7992
|
+
|
|
7993
|
+
diffViewer.innerHTML = `${headerHtml}<div class="pinokio-git-diff-viewer-body"><div class="pinokio-git-diff-empty-state">Loading...</div></div>`
|
|
7994
|
+
const diffBody = diffViewer.querySelector('.pinokio-git-diff-viewer-body')
|
|
7570
7995
|
|
|
7571
7996
|
try {
|
|
7572
7997
|
const diffRes = await fetch(diffpath)
|
|
7573
7998
|
const diffData = await diffRes.json()
|
|
7574
|
-
renderDiff(diffData,
|
|
7999
|
+
renderDiff(diffData, diffBody)
|
|
8000
|
+
const resetBtn = diffViewer.querySelector('.pinokio-git-diff-revert-btn')
|
|
8001
|
+
if (resetBtn && revertUrl) {
|
|
8002
|
+
resetBtn.addEventListener('click', () => {
|
|
8003
|
+
const confirmed = confirm('Reset this file to the previous version?')
|
|
8004
|
+
if (confirmed) {
|
|
8005
|
+
showIframeView(revertUrl)
|
|
8006
|
+
}
|
|
8007
|
+
})
|
|
8008
|
+
}
|
|
7575
8009
|
} catch (error) {
|
|
7576
8010
|
console.error('Error fetching diff:', error)
|
|
7577
|
-
|
|
8011
|
+
if (diffBody) {
|
|
8012
|
+
diffBody.innerHTML = '<div class="pinokio-git-diff-empty-state">Error loading diff</div>'
|
|
8013
|
+
}
|
|
7578
8014
|
}
|
|
7579
8015
|
})
|
|
7580
8016
|
})
|