pinokiod 8.0.116 → 8.0.117

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.
@@ -5414,11 +5414,12 @@ class RegistryCore {
5414
5414
  where.push(clause.sql)
5415
5415
  values.push(...clause.values)
5416
5416
  }
5417
+ const folded = "pinokio_path_name(name)"
5417
5418
  const order = sizeSort === "asc"
5418
- ? "bytes ASC, name ASC"
5419
+ ? `bytes ASC, ${folded} ASC`
5419
5420
  : sizeSort === "desc"
5420
- ? "bytes DESC, name ASC"
5421
- : nameSort === "desc" ? "name DESC" : "name ASC"
5421
+ ? `bytes DESC, ${folded} ASC`
5422
+ : nameSort === "desc" ? `${folded} DESC` : `${folded} ASC`
5422
5423
  // Values bind in the order the placeholders appear: the CTE's substr, then
5423
5424
  // its WHERE, then the two separators in the outer select and filter.
5424
5425
  return this.database.prepare(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "8.0.116",
3
+ "version": "8.0.117",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -2098,13 +2098,14 @@ const sourceSort = (a, b) => {
2098
2098
  const rank = (source) => source && source.kind === "external" ? 1 : source ? 0 : 2
2099
2099
  return rank(first) - rank(second) || groupTitle(first).localeCompare(groupTitle(second))
2100
2100
  }
2101
- // The flat list is ordered by the name its Name column shows, matching the
2102
- // order the server paged in; the location is only the tie-break.
2103
- const flatName = (item) => basename(item.relative_path)
2101
+ // The name a row shows in its Name column. Every list orders by this, so the
2102
+ // order matches the column the user clicked; the path below it is context, not
2103
+ // the sort key.
2104
+ const rowName = (item) => basename(item.relative_path || item.path)
2104
2105
  const flatLocation = (item) => externalLocation(item) ||
2105
2106
  [groupTitle(sourceById(item.source_id)), item.relative_path].filter(Boolean).join(" / ")
2106
2107
  const renderFlatFiles = (items) => [...items]
2107
- .sort((a, b) => compareRows(a, b, flatName))
2108
+ .sort((a, b) => compareRows(a, b, rowName))
2108
2109
  .map((item) => {
2109
2110
  const expandable = Number(item.location_count) > 1
2110
2111
  return `<div class="vault-file-row">
@@ -2205,7 +2206,7 @@ const renderDuplicateGroups = (items) => {
2205
2206
  const action = source && source.shareable && allShareable
2206
2207
  ? `<button class="vault-button" type="button" data-deduplicate-scope="${attr(sourceId)}">${esc(COPY.deduplicate)} ${countLabel(allShareable)}</button>`
2207
2208
  : `<span class="vault-unavailable">${esc(COPY.sharing_unavailable)}</span>`
2208
- return `<div class="vault-group-row"><div class="vault-group-main"><div class="vault-group-title"><i class="fa-regular fa-folder"></i><span>${esc(groupTitle(source))}</span></div><div class="vault-group-meta">${countLabel(group.length, COPY.duplicate.toLowerCase(), COPY.duplicates.toLowerCase())} · ${bytes ? fmt(bytes) : COPY.unavailable}</div></div><div class="vault-group-action">${action}</div></div>${[...group].sort((a, b) => compareRows(a, b, (item) => item.relative_path)).map((item) => renderFileRow(item, 0, true)).join("")}`
2209
+ return `<div class="vault-group-row"><div class="vault-group-main"><div class="vault-group-title"><i class="fa-regular fa-folder"></i><span>${esc(groupTitle(source))}</span></div><div class="vault-group-meta">${countLabel(group.length, COPY.duplicate.toLowerCase(), COPY.duplicates.toLowerCase())} · ${bytes ? fmt(bytes) : COPY.unavailable}</div></div><div class="vault-group-action">${action}</div></div>${[...group].sort((a, b) => compareRows(a, b, rowName)).map((item) => renderFileRow(item, 0, true)).join("")}`
2209
2210
  }).join("")
2210
2211
  }
2211
2212
 
@@ -2226,8 +2227,10 @@ const emptyState = (view) => {
2226
2227
  return `<div class="vault-empty"><div class="vault-empty-inner"><i class="${content[2]}"></i><h3>${esc(content[0])}</h3><p>${esc(content[1])}</p>${view === "duplicates" ? `<button class="vault-button" type="button" data-view="all">${esc(COPY.view_all)}</button>` : ""}</div></div>`
2227
2228
  }
2228
2229
 
2229
- const renderReclaimable = (blobs) => {
2230
- if (!blobs.length) return emptyState("reclaimable")
2230
+ const renderReclaimable = (rows) => {
2231
+ if (!rows.length) return emptyState("reclaimable")
2232
+ const blobs = [...rows]
2233
+ .sort((left, right) => compareRows(left, right, (blob) => blob.hash))
2231
2234
  return blobs.map((blob) => `<div class="vault-file-row"><div class="vault-name-cell"><span class="vault-disclosure"></span><i class="fa-regular fa-file vault-name-icon"></i><span class="vault-name-copy"><span class="vault-file-name">${esc(`${blob.hash.slice(0, 12)}…`)}</span></span></div><span class="vault-size">${fmt(blob.size)}</span><span class="vault-space">${fmt(blob.size)}</span><span class="vault-row-action"><button class="vault-text-button" type="button" data-reclaim="${attr(blob.hash)}" data-reclaim-store="${attr(blob.store_id)}">${esc(COPY.reclaim)}</button></span></div>`).join("")
2232
2235
  }
2233
2236
 
@@ -2461,22 +2464,6 @@ const renderTable = (items) => {
2461
2464
  syncDuplicateGroupPageSelectionCheckbox()
2462
2465
  }
2463
2466
 
2464
- const orderedItems = (items) => {
2465
- if (state.view === "activity") return items
2466
- if (items.some((item) => item.kind === "duplicate_group")) return items
2467
- if (state.view === "reclaimable") {
2468
- return [...items].sort((a, b) => compareRows(a, b,
2469
- (blob) => blob.hash))
2470
- }
2471
- if (state.displayMode === "files" && supportsDisplayMode()) {
2472
- return [...items].sort((a, b) => compareRows(a, b, flatName))
2473
- }
2474
- return [...items].sort((a, b) => {
2475
- const sourceOrder = state.sourceId ? 0 : sourceSort([a.source_id], [b.source_id])
2476
- return sourceOrder || compareRows(a, b, (item) => item.relative_path || item.path)
2477
- })
2478
- }
2479
-
2480
2467
  const pagedItems = (items) => {
2481
2468
  const inventory = state.data.inventory
2482
2469
  state.page = Number(inventory.page) || 0
@@ -2493,7 +2480,7 @@ const pagedItems = (items) => {
2493
2480
  }
2494
2481
  }
2495
2482
  return {
2496
- items: orderedItems(items),
2483
+ items,
2497
2484
  start: Number(inventory.start) || 0,
2498
2485
  end: Number(inventory.end) || 0,
2499
2486
  total: Number(inventory.total) || 0,
@@ -394,7 +394,9 @@ describe("Save Space engine", () => {
394
394
  [`${root}\\app\\models\\big.bin`, 4000],
395
395
  [`${root}\\app\\models\\small.bin`, 10],
396
396
  [`${root}\\cache\\only\\deep\\x.bin`, 50],
397
- [`${root}\\loose.bin`, 700]
397
+ [`${root}\\loose.bin`, 700],
398
+ [`${root}\\Zebra\\z.bin`, 5],
399
+ [`${root}\\apple\\a.bin`, 5]
398
400
  ].forEach(([filePath, size], index) =>
399
401
  insert.run(filePath, `h${index}`, size, index + 1))
400
402
 
@@ -409,7 +411,24 @@ describe("Save Space engine", () => {
409
411
  limit: 50,
410
412
  offset: 0
411
413
  })
412
- assert.deepEqual(directories.map((row) => row.name), ["app", "cache"])
414
+ assert.deepEqual(directories.map((row) => row.name).slice(0, 2),
415
+ ["app", "cache"])
416
+ // Folder names fold case the same way file names do, so a capitalised
417
+ // folder does not jump ahead of every lowercase one.
418
+ const cased = core.treeDirectoryRows({
419
+ sourceId: "app:demo",
420
+ prefix: `${root}\\`,
421
+ separator: "\\",
422
+ statuses: [],
423
+ query: "",
424
+ nameOnly: false,
425
+ sizeSort: null,
426
+ nameSort: "asc",
427
+ limit: 50,
428
+ offset: 0
429
+ })
430
+ assert.deepEqual(cased.map((row) => row.name),
431
+ ["app", "apple", "cache", "Zebra"])
413
432
  assert.equal(directories[0].bytes, 4010)
414
433
  // The collapse reads these, so they have to carry the whole subpath.
415
434
  assert.equal(directories[1].lo, "cache\\only\\deep\\x.bin")
@@ -1015,6 +1015,43 @@ describe("Save Space interface", () => {
1015
1015
  dom.window.close()
1016
1016
  })
1017
1017
 
1018
+ test("Duplicates in Folders orders by name, not by the path below it", async () => {
1019
+ // Names and paths disagree on purpose: ordering by path gives decord,
1020
+ // numpy.libs, torch, triton -- which is what the screen used to show.
1021
+ const files = [
1022
+ ["zebra.dll", "app/decord/zebra.dll"],
1023
+ ["mango.dll", "app/numpy.libs/mango.dll"],
1024
+ ["apple.dll", "app/torch/lib/apple.dll"]
1025
+ ].map(([name, relative]) => item({
1026
+ path: `/pinokio/api/app/${relative}`,
1027
+ relative_path: relative,
1028
+ status: "duplicate",
1029
+ shareable: true,
1030
+ location_count: 2
1031
+ }))
1032
+ const base = fixture(files)
1033
+ base.inventory.source_counts.duplicates["app:app"] = files.length
1034
+ base.inventory.shareable_by_source["app:app"] = files.length
1035
+ const { dom } = await makePage(base)
1036
+ const document = dom.window.document
1037
+
1038
+ document.querySelector('[data-view="duplicates"]').click()
1039
+ await waitFor(() => document.querySelector(
1040
+ '[data-view="duplicates"].selected'))
1041
+ const names = () => [...document.querySelectorAll(
1042
+ "#vault-table-wrap .vault-file-name")].map((node) => node.textContent)
1043
+
1044
+ document.querySelector("[data-sort-name]").click()
1045
+ await waitFor(() => names()[0] === "apple.dll")
1046
+ assert.deepEqual(names(), ["apple.dll", "mango.dll", "zebra.dll"])
1047
+
1048
+ document.querySelector("[data-sort-name]").click()
1049
+ await waitFor(() => names()[0] === "zebra.dll")
1050
+ assert.deepEqual(names(), ["zebra.dll", "mango.dll", "apple.dll"])
1051
+ await settle()
1052
+ dom.window.close()
1053
+ })
1054
+
1018
1055
  test("name sorting is offered wherever the Name column holds a name", async () => {
1019
1056
  const duplicate = item({
1020
1057
  path: "/pinokio/api/app/models/duplicate.bin",