pinokiod 8.0.107 → 8.0.110
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/vault/index.js +3 -38
- package/package.json +1 -1
- package/server/index.js +8 -0
- package/server/public/vault.js +13 -14
- package/server/views/app.ejs +9 -1
- package/test/vault-engine.test.js +23 -0
package/kernel/vault/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const fs = require("fs")
|
|
2
2
|
const path = require("path")
|
|
3
3
|
const crypto = require("crypto")
|
|
4
|
-
const { execFile } = require("child_process")
|
|
5
4
|
const { Worker } = require("worker_threads")
|
|
5
|
+
const Util = require("../util")
|
|
6
6
|
const Registry = require("./registry")
|
|
7
7
|
const Scanner = require("./scanner")
|
|
8
8
|
const Sweeper = require("./sweeper")
|
|
@@ -188,41 +188,11 @@ class FileActionChanges {
|
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
const revealInFileManager = (filePath, platform = process.platform) =>
|
|
192
|
-
new Promise((resolve, reject) => {
|
|
193
|
-
const command = platform === "darwin"
|
|
194
|
-
? "open"
|
|
195
|
-
: platform === "win32"
|
|
196
|
-
? "explorer.exe"
|
|
197
|
-
: "xdg-open"
|
|
198
|
-
const args = platform === "darwin"
|
|
199
|
-
? ["-R", filePath]
|
|
200
|
-
: platform === "win32"
|
|
201
|
-
? [`/select,${filePath}`]
|
|
202
|
-
: [path.dirname(filePath)]
|
|
203
|
-
execFile(command, args, {
|
|
204
|
-
timeout: 10000,
|
|
205
|
-
windowsHide: true
|
|
206
|
-
}, (error) => {
|
|
207
|
-
// Explorer reports a non-zero exit code even when it opens the folder,
|
|
208
|
-
// so an exit status alone is not a failure on Windows. A missing binary
|
|
209
|
-
// or a refused spawn still is.
|
|
210
|
-
if (error && platform === "win32" && Number.isInteger(error.code)) {
|
|
211
|
-
resolve()
|
|
212
|
-
return
|
|
213
|
-
}
|
|
214
|
-
error ? reject(error) : resolve()
|
|
215
|
-
})
|
|
216
|
-
})
|
|
217
|
-
|
|
218
191
|
class Vault {
|
|
219
192
|
constructor(kernel) {
|
|
220
193
|
this.kernel = kernel
|
|
221
194
|
this.fileManagerLauncher = (filePath) =>
|
|
222
|
-
|
|
223
|
-
filePath,
|
|
224
|
-
this.kernel.platform || process.platform
|
|
225
|
-
)
|
|
195
|
+
Util.openfs(filePath, { action: "view" }, this.kernel)
|
|
226
196
|
this.enabled = false
|
|
227
197
|
this.initialized = false
|
|
228
198
|
this.mode = null
|
|
@@ -3320,18 +3290,13 @@ class Vault {
|
|
|
3320
3290
|
}
|
|
3321
3291
|
|
|
3322
3292
|
publicDuplicateChildItems(rows) {
|
|
3323
|
-
const publicStatus = {
|
|
3324
|
-
reference: "tracked",
|
|
3325
|
-
duplicate: "duplicate",
|
|
3326
|
-
linked: "shared"
|
|
3327
|
-
}
|
|
3328
3293
|
return (rows || []).map((row) => Object.assign({
|
|
3329
3294
|
kind: "duplicate_path",
|
|
3330
3295
|
path: row.path,
|
|
3331
3296
|
hash: row.hash,
|
|
3332
3297
|
size: Number(row.size) || 0,
|
|
3333
3298
|
app: row.app || null,
|
|
3334
|
-
status:
|
|
3299
|
+
status: PUBLIC_FILE_STATUS[row.status],
|
|
3335
3300
|
registry_status: row.status,
|
|
3336
3301
|
shareable: row.status === "duplicate",
|
|
3337
3302
|
selectable: !!row.selectable
|
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -1833,6 +1833,13 @@ class Server {
|
|
|
1833
1833
|
const dev_initial_tab = type === "browse" && req.query && req.query.pinokio_dev_tab === "files"
|
|
1834
1834
|
? "files"
|
|
1835
1835
|
: "plugins"
|
|
1836
|
+
// Disk Saver hands one content group to another app: the page opens with
|
|
1837
|
+
// its Disk Saver tab selected and that group already expanded.
|
|
1838
|
+
const vault_initial_group = req.query &&
|
|
1839
|
+
typeof req.query.vault_group === "string" &&
|
|
1840
|
+
/^[a-f0-9]{64}$/i.test(req.query.vault_group)
|
|
1841
|
+
? req.query.vault_group.toLowerCase()
|
|
1842
|
+
: null
|
|
1836
1843
|
|
|
1837
1844
|
const registryEnabled = await this.isRegistryEnabled().catch(() => false)
|
|
1838
1845
|
let community_url = ""
|
|
@@ -1956,6 +1963,7 @@ class Server {
|
|
|
1956
1963
|
tabs: savedTabs,
|
|
1957
1964
|
editor_tab: editor_tab,
|
|
1958
1965
|
dev_initial_tab,
|
|
1966
|
+
vault_initial_group,
|
|
1959
1967
|
config,
|
|
1960
1968
|
protection_enabled: protectionPreference ? protectionPreference.protection_enabled !== false : false,
|
|
1961
1969
|
autolaunch_app: autolaunchAppState,
|
package/server/public/vault.js
CHANGED
|
@@ -238,7 +238,7 @@ const COPY = {
|
|
|
238
238
|
show_more_copies: "Show {count} more copies",
|
|
239
239
|
loading_locations: "Loading locations…",
|
|
240
240
|
open_in_disk_saver: "Open this file in Disk Saver",
|
|
241
|
-
open_location_confirm: "Open Disk Saver
|
|
241
|
+
open_location_confirm: "Open Disk Saver to review {location}?",
|
|
242
242
|
open_location_accept: "Open",
|
|
243
243
|
show_more_locations: "Show {count} more locations",
|
|
244
244
|
making_separate: "Making file separate",
|
|
@@ -658,23 +658,22 @@ const confirmLeave = (message, confirmLabel) => new Promise((resolve) => {
|
|
|
658
658
|
const openGlobalWorkspace = () => {
|
|
659
659
|
window.parent.location.assign("/vault")
|
|
660
660
|
}
|
|
661
|
-
// A copy
|
|
662
|
-
//
|
|
663
|
-
//
|
|
664
|
-
//
|
|
665
|
-
//
|
|
661
|
+
// A copy in another app opens that app's page with its Disk Saver tab selected
|
|
662
|
+
// and the group expanded, because an app's workspace only exists inside that
|
|
663
|
+
// page; opening the workspace URL directly strands the user with no navigation.
|
|
664
|
+
// Locations that are not apps have no such page and open the global workspace.
|
|
665
|
+
// The label and kind travel with the row: an app workspace cannot look up
|
|
666
|
+
// sources belonging to other apps.
|
|
666
667
|
const openContentGroup = async (group, kind, label) => {
|
|
667
|
-
// The label and kind travel with the row: an app workspace cannot look up
|
|
668
|
-
// sources belonging to other apps, so a lookup here would name every one of
|
|
669
|
-
// them "unknown" and send them all to the global page.
|
|
670
|
-
const app = kind === "app" && label ? label : null
|
|
671
|
-
const name = label || COPY.unknown_location
|
|
672
668
|
const accepted = await confirmLeave(
|
|
673
|
-
COPY.open_location_confirm.replace(
|
|
669
|
+
COPY.open_location_confirm.replace(
|
|
670
|
+
"{location}", label || COPY.unknown_location),
|
|
674
671
|
COPY.open_location_accept)
|
|
675
672
|
if (!accepted) return
|
|
676
|
-
const
|
|
677
|
-
|
|
673
|
+
const target = kind === "app" && label
|
|
674
|
+
? `/pinokio/browser/${encodeURIComponent(label)}?vault_group=${encodeURIComponent(group)}`
|
|
675
|
+
: `/vault?group=${encodeURIComponent(group)}`
|
|
676
|
+
window.parent.location.assign(target)
|
|
678
677
|
}
|
|
679
678
|
const applyAutomaticScanSnapshot = (snapshot) => {
|
|
680
679
|
if (!IS_APP_MODE || !AUTOMATIC_SUPPORTED) return
|
package/server/views/app.ejs
CHANGED
|
@@ -8694,7 +8694,7 @@ body.dark .pinokio-custom-terminal-header {
|
|
|
8694
8694
|
<% const vaultAutomaticSupported = typeof vault_automatic_supported === 'undefined' || vault_automatic_supported === true %>
|
|
8695
8695
|
<% const vaultAutomaticResultSignature = vaultAutomaticSupported && typeof vault_automatic_result_signature === 'string' ? vault_automatic_result_signature : '' %>
|
|
8696
8696
|
<% const vaultSidebarLabel = !vaultGlobalScanReady ? 'Disk Saver — Set up required' : vaultAutomaticSupported ? `Disk Saver — ${vaultAutomaticMode === 'automatic' ? 'Automatic' : 'Manual'} checking${vaultAutomaticResultSignature ? ' — Duplicate files found' : ''}` : 'Disk Saver' %>
|
|
8697
|
-
<a id='save-space-tab' data-mode="refresh" target="app-vault" href="/vault/app/<%=encodeURIComponent(name)%>" class="btn header-item frame-link<%=vaultAutomaticResultSignature ? ' app-vault-result-attention' : ''%>" data-index="vault" data-static="retain" data-tab-link-popover="false" aria-label="<%=vaultSidebarLabel%>">
|
|
8697
|
+
<a id='save-space-tab' data-mode="refresh" target="app-vault" href="/vault/app/<%=encodeURIComponent(name)%><%=typeof vault_initial_group === 'string' && vault_initial_group ? `?group=${vault_initial_group}` : ''%>" class="btn header-item frame-link<%=vaultAutomaticResultSignature ? ' app-vault-result-attention' : ''%>" data-index="vault" data-static="retain" data-tab-link-popover="false" aria-label="<%=vaultSidebarLabel%>">
|
|
8698
8698
|
<div class='tab'>
|
|
8699
8699
|
<i class="fa-solid fa-hard-drive menu-action-leading-icon"></i>
|
|
8700
8700
|
<div class='display'>Disk Saver</div>
|
|
@@ -9183,6 +9183,14 @@ body.dark .pinokio-custom-terminal-header {
|
|
|
9183
9183
|
window.history.replaceState(window.history.state, "", `${devTabUrl.pathname}${devTabUrl.search}${devTabUrl.hash}`)
|
|
9184
9184
|
} catch (_) {}
|
|
9185
9185
|
<% } %>
|
|
9186
|
+
<% if (typeof vault_initial_group === 'string' && vault_initial_group) { %>
|
|
9187
|
+
global_selector = "#save-space-tab.frame-link"
|
|
9188
|
+
try {
|
|
9189
|
+
const vaultTabUrl = new URL(window.location.href)
|
|
9190
|
+
vaultTabUrl.searchParams.delete("vault_group")
|
|
9191
|
+
window.history.replaceState(window.history.state, "", `${vaultTabUrl.pathname}${vaultTabUrl.search}${vaultTabUrl.hash}`)
|
|
9192
|
+
} catch (_) {}
|
|
9193
|
+
<% } %>
|
|
9186
9194
|
let pendingSelectionRetry = null
|
|
9187
9195
|
let pendingHomeSelectionRetry = null
|
|
9188
9196
|
let initialWorkspaceDiskUsageRequested = false
|
|
@@ -5,6 +5,7 @@ const fs = require("node:fs")
|
|
|
5
5
|
const os = require("node:os")
|
|
6
6
|
const path = require("node:path")
|
|
7
7
|
const Database = require("better-sqlite3")
|
|
8
|
+
const Util = require("../kernel/util")
|
|
8
9
|
const Vault = require("../kernel/vault")
|
|
9
10
|
const Registry = require("../kernel/vault/registry")
|
|
10
11
|
const {
|
|
@@ -105,6 +106,28 @@ describe("Save Space engine", () => {
|
|
|
105
106
|
}
|
|
106
107
|
})
|
|
107
108
|
|
|
109
|
+
test("file reveals reuse the shared file explorer launcher", async () => {
|
|
110
|
+
const kernel = { homedir: os.tmpdir(), platform: process.platform }
|
|
111
|
+
const vault = new Vault(kernel)
|
|
112
|
+
const originalOpenfs = Util.openfs
|
|
113
|
+
const calls = []
|
|
114
|
+
Util.openfs = (...args) => {
|
|
115
|
+
calls.push(args)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const filePath = path.join(os.tmpdir(), "model with spaces.bin")
|
|
120
|
+
await vault.fileManagerLauncher(filePath)
|
|
121
|
+
assert.deepEqual(calls, [[
|
|
122
|
+
filePath,
|
|
123
|
+
{ action: "view" },
|
|
124
|
+
kernel
|
|
125
|
+
]])
|
|
126
|
+
} finally {
|
|
127
|
+
Util.openfs = originalOpenfs
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
|
|
108
131
|
test("startup only reads the enable flag and defers Disk Saver storage", async () => {
|
|
109
132
|
const home = await makeHome()
|
|
110
133
|
const vault = new Vault({ homedir: home, platform: process.platform })
|