aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzousar <[email protected]>2026-02-15 23:44:17 -0700
committerzousar <[email protected]>2026-02-15 23:44:17 -0700
commit81a6d5e29453db761d058b6418044c8cf04a167e (patch)
tree89a82f510e002a5c9dcf3852d87e08842dc92def
parentRestore handling for hard/soft name prefixes (diff)
downloadzen-81a6d5e29453db761d058b6418044c8cf04a167e.tar.xz
zen-81a6d5e29453db761d058b6418044c8cf04a167e.zip
Add support for listing files on oplog entries
-rw-r--r--src/zenserver/frontend/html/pages/entry.js119
1 files changed, 110 insertions, 9 deletions
diff --git a/src/zenserver/frontend/html/pages/entry.js b/src/zenserver/frontend/html/pages/entry.js
index 76afd3e1f..26ea78142 100644
--- a/src/zenserver/frontend/html/pages/entry.js
+++ b/src/zenserver/frontend/html/pages/entry.js
@@ -76,6 +76,21 @@ export class Page extends ZenPage
return null;
}
+ _is_null_io_hash_string(io_hash)
+ {
+ if (!io_hash)
+ return true;
+
+ for (let char of io_hash)
+ {
+ if (char != '0')
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
async _build_meta(section, entry)
{
var tree = {}
@@ -142,30 +157,34 @@ export class Page extends ZenPage
const name = entry.find("key").as_value();
var section = this.add_section(name);
+ var has_package_data = false;
// tree
{
var tree = entry.find("$tree");
if (tree == undefined)
tree = this._convert_legacy_to_tree(entry);
- if (tree == undefined)
- return this._display_unsupported(section, entry);
-
- delete tree["$id"];
-
- if (Object.keys(tree).length != 0)
+ if (tree != undefined)
{
- const sub_section = section.add_section("dependencies");
- this._build_deps(sub_section, tree);
+ delete tree["$id"];
+
+ if (Object.keys(tree).length != 0)
+ {
+ const sub_section = section.add_section("dependencies");
+ this._build_deps(sub_section, tree);
+ }
+ has_package_data = true;
}
}
// meta
+ if (has_package_data)
{
this._build_meta(section, entry);
}
// data
+ if (has_package_data)
{
const sub_section = section.add_section("data");
const table = sub_section.add_widget(
@@ -181,7 +200,7 @@ export class Page extends ZenPage
for (const item of pkg_data.as_array())
{
- var io_hash, size, raw_size, file_name;
+ var io_hash = undefined, size = undefined, raw_size = undefined, file_name = undefined;
for (const field of item.as_object())
{
if (field.is_named("data")) io_hash = field.as_value();
@@ -219,12 +238,94 @@ export class Page extends ZenPage
}
}
+ // files
+ var has_file_data = false;
+ {
+ const sub_section = section.add_section("files");
+ const table = sub_section.add_widget(
+ Table,
+ ["name", "actions"], Table.Flag_PackRight
+ );
+ table.id("filetable");
+ for (const field_name of ["files"])
+ {
+ var file_data = entry.find(field_name);
+ if (file_data == undefined)
+ continue;
+
+ has_file_data = true;
+
+ for (const item of file_data.as_array())
+ {
+ var io_hash = undefined, cid = undefined, server_path = undefined, client_path = undefined;
+ for (const field of item.as_object())
+ {
+ if (field.is_named("data")) io_hash = field.as_value();
+ else if (field.is_named("id")) cid = field.as_value();
+ else if (field.is_named("serverpath")) server_path = field.as_value();
+ else if (field.is_named("clientpath")) client_path = field.as_value();
+ }
+
+ if (io_hash instanceof Uint8Array)
+ {
+ var ret = "";
+ for (var x of io_hash)
+ ret += x.toString(16).padStart(2, "0");
+ io_hash = ret;
+ }
+
+ if (cid instanceof Uint8Array)
+ {
+ var ret = "";
+ for (var x of cid)
+ ret += x.toString(16).padStart(2, "0");
+ cid = ret;
+ }
+
+ const row = table.add_row(server_path);
+
+ var base_name = server_path.split("/").pop().split("\\").pop();
+ const project = this.get_param("project");
+ const oplog = this.get_param("oplog");
+ if (this._is_null_io_hash_string(io_hash))
+ {
+ const link = row.get_cell(0).link(
+ "/" + ["prj", project, "oplog", oplog, cid].join("/")
+ );
+ link.first_child().attr("download", `${cid}_${base_name}`);
+
+ const action_tb = new Toolbar(row.get_cell(-1), true);
+ action_tb.left().add("copy-id").on_click(async (v) => {
+ await navigator.clipboard.writeText(v);
+ }, cid);
+ }
+ else
+ {
+ const link = row.get_cell(0).link(
+ "/" + ["prj", project, "oplog", oplog, io_hash].join("/")
+ );
+ link.first_child().attr("download", `${io_hash}_${base_name}`);
+
+ const action_tb = new Toolbar(row.get_cell(-1), true);
+ action_tb.left().add("copy-hash").on_click(async (v) => {
+ await navigator.clipboard.writeText(v);
+ }, io_hash);
+ }
+
+ }
+ }
+ }
+
// props
+ if (has_package_data)
{
const object = entry.to_js_object();
var sub_section = section.add_section("props");
sub_section.add_widget(PropTable).add_object(object);
}
+
+ if (!has_package_data && !has_file_data)
+ return this._display_unsupported(section, entry);
}
_display_unsupported(section, entry)