aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/frontend/html/pages/projects.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenserver/frontend/html/pages/projects.js')
-rw-r--r--src/zenserver/frontend/html/pages/projects.js236
1 files changed, 108 insertions, 128 deletions
diff --git a/src/zenserver/frontend/html/pages/projects.js b/src/zenserver/frontend/html/pages/projects.js
index 2469bf70b..2e76a80f1 100644
--- a/src/zenserver/frontend/html/pages/projects.js
+++ b/src/zenserver/frontend/html/pages/projects.js
@@ -6,7 +6,7 @@ import { ZenPage } from "./page.js"
import { Fetcher } from "../util/fetcher.js"
import { Friendly } from "../util/friendly.js"
import { Modal } from "../util/modal.js"
-import { Table, Toolbar } from "../util/widgets.js"
+import { Table, Toolbar, Pager, add_copy_button } from "../util/widgets.js"
////////////////////////////////////////////////////////////////////////////////
export class Page extends ZenPage
@@ -39,8 +39,6 @@ export class Page extends ZenPage
// Projects list
var section = this._collapsible_section("Projects");
- section.tag().classify("dropall").text("drop-all").on_click(() => this.drop_all());
-
var columns = [
"name",
"project dir",
@@ -51,51 +49,21 @@ export class Page extends ZenPage
this._project_table = section.add_widget(Table, columns, Table.Flag_FitLeft|Table.Flag_PackRight|Table.Flag_Sortable|Table.Flag_AlignNumeric);
- var projects = await new Fetcher().resource("/prj/list").json();
- projects.sort((a, b) => (b.LastAccessTime || 0) - (a.LastAccessTime || 0));
-
- for (const project of projects)
- {
- var row = this._project_table.add_row(
- "",
- "",
- "",
- "",
- );
-
- var cell = row.get_cell(0);
- cell.tag().text(project.Id).on_click(() => this.view_project(project.Id));
-
- if (project.ProjectRootDir)
- {
- row.get_cell(1).tag("a").text(project.ProjectRootDir)
- .attr("href", "vscode://" + project.ProjectRootDir.replace(/\\/g, "/"));
- }
- if (project.EngineRootDir)
- {
- row.get_cell(2).tag("a").text(project.EngineRootDir)
- .attr("href", "vscode://" + project.EngineRootDir.replace(/\\/g, "/"));
- }
-
- cell = row.get_cell(-1);
- const action_tb = new Toolbar(cell, true).left();
- action_tb.add("view").on_click(() => this.view_project(project.Id));
- action_tb.add("drop").on_click(() => this.drop_project(project.Id));
-
- row.attr("zs_name", project.Id);
-
- // Fetch project details to get oplog count
- new Fetcher().resource("prj", project.Id).json().then((info) => {
- const oplogs = info["oplogs"] || [];
- row.get_cell(3).text(Friendly.sep(oplogs.length)).style("textAlign", "right");
- // Right-align the corresponding header cell
- const header = this._project_table._element.firstElementChild;
- if (header && header.children[4])
- {
- header.children[4].style.textAlign = "right";
- }
- }).catch(() => {});
- }
+ this._project_pager = new Pager(section, 25, () => this._render_projects_page(),
+ Pager.make_search_fn(() => this._projects_data, p => p.Id));
+ const drop_link = document.createElement("span");
+ drop_link.className = "dropall zen_action";
+ drop_link.style.position = "static";
+ drop_link.textContent = "drop-all";
+ drop_link.addEventListener("click", () => this.drop_all());
+ this._project_pager.prepend(drop_link);
+
+ const loading = Pager.loading(section);
+ this._projects_data = await new Fetcher().resource("/prj/list").json();
+ this._projects_data.sort((a, b) => a.Id.localeCompare(b.Id));
+ this._project_pager.set_total(this._projects_data.length);
+ this._render_projects_page();
+ loading.remove();
// Project detail area (inside projects section so it collapses together)
this._project_host = section;
@@ -110,39 +78,6 @@ export class Page extends ZenPage
}
}
- _collapsible_section(name)
- {
- const section = this.add_section(name);
- const container = section._parent.inner();
- const heading = container.firstElementChild;
-
- heading.style.cursor = "pointer";
- heading.style.userSelect = "none";
-
- const indicator = document.createElement("span");
- indicator.textContent = " \u25BC";
- indicator.style.fontSize = "0.7em";
- heading.appendChild(indicator);
-
- let collapsed = false;
- heading.addEventListener("click", (e) => {
- if (e.target !== heading && e.target !== indicator)
- {
- return;
- }
- collapsed = !collapsed;
- indicator.textContent = collapsed ? " \u25B6" : " \u25BC";
- let sibling = heading.nextElementSibling;
- while (sibling)
- {
- sibling.style.display = collapsed ? "none" : "";
- sibling = sibling.nextElementSibling;
- }
- });
-
- return section;
- }
-
_clear_param(name)
{
this._params.delete(name);
@@ -153,6 +88,7 @@ export class Page extends ZenPage
_render_stats(stats)
{
+ stats = this._merge_last_stats(stats);
const safe = (obj, path) => path.split(".").reduce((a, b) => a && a[b], obj);
const grid = this._stats_grid;
@@ -163,54 +99,48 @@ export class Page extends ZenPage
// Store Operations tile
{
- const store = safe(stats, "store");
- if (store)
- {
- const tile = grid.tag().classify("card").classify("stats-tile");
- tile.tag().classify("card-title").text("Store Operations");
- const columns = tile.tag().classify("tile-columns");
-
- const left = columns.tag().classify("tile-metrics");
- const proj = store.project || {};
- this._metric(left, Friendly.sep(proj.readcount || 0), "project reads", true);
- this._metric(left, Friendly.sep(proj.writecount || 0), "project writes");
- this._metric(left, Friendly.sep(proj.deletecount || 0), "project deletes");
-
- const right = columns.tag().classify("tile-metrics");
- const oplog = store.oplog || {};
- this._metric(right, Friendly.sep(oplog.readcount || 0), "oplog reads", true);
- this._metric(right, Friendly.sep(oplog.writecount || 0), "oplog writes");
- this._metric(right, Friendly.sep(oplog.deletecount || 0), "oplog deletes");
- }
+ const store = safe(stats, "store") || {};
+ const tile = grid.tag().classify("card").classify("stats-tile");
+ tile.tag().classify("card-title").text("Store Operations");
+ const columns = tile.tag().classify("tile-columns");
+
+ const left = columns.tag().classify("tile-metrics");
+ const proj = store.project || {};
+ this._metric(left, Friendly.sep(proj.readcount || 0), "project reads", true);
+ this._metric(left, Friendly.sep(proj.writecount || 0), "project writes");
+ this._metric(left, Friendly.sep(proj.deletecount || 0), "project deletes");
+
+ const right = columns.tag().classify("tile-metrics");
+ const oplog = store.oplog || {};
+ this._metric(right, Friendly.sep(oplog.readcount || 0), "oplog reads", true);
+ this._metric(right, Friendly.sep(oplog.writecount || 0), "oplog writes");
+ this._metric(right, Friendly.sep(oplog.deletecount || 0), "oplog deletes");
}
// Op & Chunk tile
{
- const store = safe(stats, "store");
- if (store)
- {
- const tile = grid.tag().classify("card").classify("stats-tile");
- tile.tag().classify("card-title").text("Ops & Chunks");
- const columns = tile.tag().classify("tile-columns");
-
- const left = columns.tag().classify("tile-metrics");
- const op = store.op || {};
- const opTotal = (op.hitcount || 0) + (op.misscount || 0);
- const opRatio = opTotal > 0 ? (((op.hitcount || 0) / opTotal) * 100).toFixed(1) + "%" : "-";
- this._metric(left, opRatio, "op hit ratio", true);
- this._metric(left, Friendly.sep(op.hitcount || 0), "op hits");
- this._metric(left, Friendly.sep(op.misscount || 0), "op misses");
- this._metric(left, Friendly.sep(op.writecount || 0), "op writes");
-
- const right = columns.tag().classify("tile-metrics");
- const chunk = store.chunk || {};
- const chunkTotal = (chunk.hitcount || 0) + (chunk.misscount || 0);
- const chunkRatio = chunkTotal > 0 ? (((chunk.hitcount || 0) / chunkTotal) * 100).toFixed(1) + "%" : "-";
- this._metric(right, chunkRatio, "chunk hit ratio", true);
- this._metric(right, Friendly.sep(chunk.hitcount || 0), "chunk hits");
- this._metric(right, Friendly.sep(chunk.misscount || 0), "chunk misses");
- this._metric(right, Friendly.sep(chunk.writecount || 0), "chunk writes");
- }
+ const store = safe(stats, "store") || {};
+ const tile = grid.tag().classify("card").classify("stats-tile");
+ tile.tag().classify("card-title").text("Ops & Chunks");
+ const columns = tile.tag().classify("tile-columns");
+
+ const left = columns.tag().classify("tile-metrics");
+ const op = store.op || {};
+ const opTotal = (op.hitcount || 0) + (op.misscount || 0);
+ const opRatio = opTotal > 0 ? (((op.hitcount || 0) / opTotal) * 100).toFixed(1) + "%" : "-";
+ this._metric(left, opRatio, "op hit ratio", true);
+ this._metric(left, Friendly.sep(op.hitcount || 0), "op hits");
+ this._metric(left, Friendly.sep(op.misscount || 0), "op misses");
+ this._metric(left, Friendly.sep(op.writecount || 0), "op writes");
+
+ const right = columns.tag().classify("tile-metrics");
+ const chunk = store.chunk || {};
+ const chunkTotal = (chunk.hitcount || 0) + (chunk.misscount || 0);
+ const chunkRatio = chunkTotal > 0 ? (((chunk.hitcount || 0) / chunkTotal) * 100).toFixed(1) + "%" : "-";
+ this._metric(right, chunkRatio, "chunk hit ratio", true);
+ this._metric(right, Friendly.sep(chunk.hitcount || 0), "chunk hits");
+ this._metric(right, Friendly.sep(chunk.misscount || 0), "chunk misses");
+ this._metric(right, Friendly.sep(chunk.writecount || 0), "chunk writes");
}
// Storage tile
@@ -231,6 +161,57 @@ export class Page extends ZenPage
}
}
+ _render_projects_page()
+ {
+ const { start, end } = this._project_pager.page_range();
+ this._project_table.clear(start);
+ for (let i = start; i < end; i++)
+ {
+ const project = this._projects_data[i];
+ const row = this._project_table.add_row(
+ "",
+ "",
+ "",
+ "",
+ );
+
+ const cell = row.get_cell(0);
+ cell.tag().text(project.Id).on_click(() => this.view_project(project.Id));
+ add_copy_button(cell.inner(), project.Id);
+
+ if (project.ProjectRootDir)
+ {
+ row.get_cell(1).tag("a").text(project.ProjectRootDir)
+ .attr("href", "vscode://" + project.ProjectRootDir.replace(/\\/g, "/"));
+ add_copy_button(row.get_cell(1).inner(), project.ProjectRootDir);
+ }
+ if (project.EngineRootDir)
+ {
+ row.get_cell(2).tag("a").text(project.EngineRootDir)
+ .attr("href", "vscode://" + project.EngineRootDir.replace(/\\/g, "/"));
+ add_copy_button(row.get_cell(2).inner(), project.EngineRootDir);
+ }
+
+ const action_cell = row.get_cell(-1);
+ const action_tb = new Toolbar(action_cell, true).left();
+ action_tb.add("view").on_click(() => this.view_project(project.Id));
+ action_tb.add("drop").on_click(() => this.drop_project(project.Id));
+
+ row.attr("zs_name", project.Id);
+
+ new Fetcher().resource("prj", project.Id).json().then((info) => {
+ const oplogs = info["oplogs"] || [];
+ row.get_cell(3).text(Friendly.sep(oplogs.length)).style("textAlign", "right");
+ }).catch(() => {});
+ }
+
+ const header = this._project_table._element.firstElementChild;
+ if (header && header.children[4])
+ {
+ header.children[4].style.textAlign = "right";
+ }
+ }
+
async view_project(project_id)
{
// Toggle off if already selected
@@ -351,10 +332,9 @@ export class Page extends ZenPage
async drop_all()
{
const drop = async () => {
- for (const row of this._project_table)
+ for (const project of this._projects_data || [])
{
- const project_id = row.attr("zs_name");
- await new Fetcher().resource("prj", project_id).delete();
+ await new Fetcher().resource("prj", project.Id).delete();
}
this.reload();
};