feng-x commited on
Commit
2d4b091
·
verified ·
1 Parent(s): e88c8ff

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. web_demo/templates/admin.html +42 -6
web_demo/templates/admin.html CHANGED
@@ -264,6 +264,10 @@
264
  <h2>User Ratings</h2>
265
  <div class="chart-wrap"><canvas id="chartRatings"></canvas></div>
266
  </div>
 
 
 
 
267
  </div>
268
  </div>
269
 
@@ -628,13 +632,13 @@
628
  if (storageStats === null) return { label: "Storage used", value: "…", sub: "" };
629
  if (!storageStats.available) return { label: "Storage used", value: "n/a", sub: "persistence off" };
630
  const s = storageStats;
631
- const pct = s.used_fraction != null ? (s.used_fraction * 100).toFixed(0) + "%" : "";
632
- const p = s.prefixes || {};
633
- const part = (k) => (p[k] ? `${k} ${fmtBytes(p[k].bytes)}` : "");
634
- const sub = `${pct} of ${fmtBytes(s.quota_bytes)} · ` +
635
- [part("photos"), part("results"), part("feedback")].filter(Boolean).join(" · ");
636
  const subCls = (s.used_fraction != null && s.used_fraction > 0.8) ? "delta-down" : "";
637
- return { label: "Storage used", value: fmtBytes(s.total_bytes), sub, subCls };
638
  };
639
  const fmtDay = (iso) => {
640
  if (!iso) return "—";
@@ -791,6 +795,37 @@
791
  });
792
  };
793
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
794
  const loadStats = async () => {
795
  dashStatusLabel.textContent = "Loading...";
796
  const days = windowSelect.value;
@@ -820,6 +855,7 @@
820
  if (resp.status === 401) return;
821
  storageStats = await resp.json();
822
  if (lastStats) renderStatCards(lastStats); // re-render so the card fills in
 
823
  } catch (e) {
824
  console.error("Failed to load storage", e);
825
  }
 
264
  <h2>User Ratings</h2>
265
  <div class="chart-wrap"><canvas id="chartRatings"></canvas></div>
266
  </div>
267
+ <div class="chart-card">
268
+ <h2>Storage Breakdown</h2>
269
+ <div class="chart-wrap"><canvas id="chartStorage"></canvas></div>
270
+ </div>
271
  </div>
272
  </div>
273
 
 
632
  if (storageStats === null) return { label: "Storage used", value: "…", sub: "" };
633
  if (!storageStats.available) return { label: "Storage used", value: "n/a", sub: "persistence off" };
634
  const s = storageStats;
635
+ // Card is the at-a-glance headline only: % of quota + the quota it's
636
+ // measured against. The per-prefix breakdown lives in the Storage
637
+ // Breakdown doughnut below.
638
+ const pct = s.used_fraction != null ? (s.used_fraction * 100).toFixed(0) + "%" : fmtBytes(s.total_bytes);
639
+ const sub = `of ${fmtBytes(s.quota_bytes)}`;
640
  const subCls = (s.used_fraction != null && s.used_fraction > 0.8) ? "delta-down" : "";
641
+ return { label: "Storage used", value: pct, sub, subCls };
642
  };
643
  const fmtDay = (iso) => {
644
  if (!iso) return "—";
 
795
  });
796
  };
797
 
798
+ // Storage breakdown doughnut — fed by the separate /api/admin/storage
799
+ // fetch (not the stats payload), so it has its own render path. Shows the
800
+ // per-prefix split plus a Free slice for quota context.
801
+ const renderStorageChart = () => {
802
+ const canvas = document.getElementById("chartStorage");
803
+ if (!canvas || !storageStats || !storageStats.available) return;
804
+ const s = storageStats;
805
+ const p = s.prefixes || {};
806
+ const segs = [
807
+ { label: "Photos", bytes: (p.photos || {}).bytes || 0, color: "#7a8b3d" },
808
+ { label: "Results", bytes: (p.results || {}).bytes || 0, color: "#d99c4f" },
809
+ { label: "Feedback", bytes: (p.feedback || {}).bytes || 0, color: "#3d6b8b" },
810
+ ].filter((seg) => seg.bytes > 0);
811
+ const free = Math.max(0, (s.quota_bytes || 0) - (s.total_bytes || 0));
812
+ if (free > 0) segs.push({ label: "Free", bytes: free, color: "rgba(45,33,33,0.10)" });
813
+ upsertChart("storage", canvas, {
814
+ type: "doughnut",
815
+ data: {
816
+ labels: segs.map((seg) => seg.label),
817
+ datasets: [{ data: segs.map((seg) => seg.bytes), backgroundColor: segs.map((seg) => seg.color) }],
818
+ },
819
+ options: {
820
+ responsive: true, maintainAspectRatio: false,
821
+ plugins: {
822
+ legend: { position: "right", labels: { boxWidth: 12, font: { size: 11 } } },
823
+ tooltip: { callbacks: { label: (ctx) => `${ctx.label}: ${fmtBytes(ctx.parsed)}` } },
824
+ },
825
+ },
826
+ });
827
+ };
828
+
829
  const loadStats = async () => {
830
  dashStatusLabel.textContent = "Loading...";
831
  const days = windowSelect.value;
 
855
  if (resp.status === 401) return;
856
  storageStats = await resp.json();
857
  if (lastStats) renderStatCards(lastStats); // re-render so the card fills in
858
+ renderStorageChart();
859
  } catch (e) {
860
  console.error("Failed to load storage", e);
861
  }