@profullstack/hqtui-demo 0.1.12 → 0.3.0

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.
@@ -1,5 +1,5 @@
1
1
  import type { Container, Theme } from "@profullstack/hqtui";
2
- import { focusPane, pane, scrollPane, type DemoState } from "../state.ts";
2
+ import { focusPane, pane, panelGap, scrollPane, type DemoState } from "../state.ts";
3
3
  import { bytes, num, percent } from "../format.ts";
4
4
 
5
5
  function rate(value: number): string {
@@ -9,6 +9,7 @@ function rate(value: number): string {
9
9
 
10
10
  /** Services, containers, kernel counters, filesystems and hardware sensors. */
11
11
  export function servicesScreen(ui: Container, state: DemoState, theme: Theme): void {
12
+ const gap = panelGap(state);
12
13
  const t = state.sample.telemetry;
13
14
  const failed = t.services.filter((s) => s.active === "failed");
14
15
 
@@ -49,7 +50,7 @@ export function servicesScreen(ui: Container, state: DemoState, theme: Theme): v
49
50
  });
50
51
  });
51
52
 
52
- row.column({ width: "0.85fr", gap: 1 }, (column) => {
53
+ row.column({ width: "0.85fr", gap }, (column) => {
53
54
  column.panel({ title: "Kernel", size: 11, borderColor: theme.accent }, (p) => {
54
55
  const k = t.kernel;
55
56
  p.keyValues([
@@ -1,11 +1,12 @@
1
1
  import type { Container, Theme } from "@profullstack/hqtui";
2
- import { focusPane, pane, scrollPane, type DemoState } from "../state.ts";
2
+ import { focusPane, pane, panelGap, scrollPane, type DemoState } from "../state.ts";
3
3
 
4
4
  /** Who is on this machine, who has been, and who failed to get in. */
5
5
  export function sessionsScreen(ui: Container, state: DemoState, theme: Theme): void {
6
+ const gap = panelGap(state);
6
7
  const t = state.sample.telemetry;
7
8
 
8
- ui.row({ size: 9, gap: 1 }, (row) => {
9
+ ui.row({ size: 9, gap }, (row) => {
9
10
  row.panel({ title: "Active Sessions", subtitle: String(t.sessions.length), borderColor: theme.success }, (p) => {
10
11
  if (t.sessions.length === 0) {
11
12
  p.label("No interactive sessions.");
@@ -74,7 +75,7 @@ export function sessionsScreen(ui: Container, state: DemoState, theme: Theme): v
74
75
  });
75
76
  });
76
77
 
77
- row.column({ width: "0.8fr", gap: 1 }, (column) => {
78
+ row.column({ width: "0.8fr", gap }, (column) => {
78
79
  column.panel({ title: "Failed Logins", borderColor: theme.danger }, (p) => {
79
80
  if (t.failedLogins.length === 0) {
80
81
  p.label("None recorded.");
@@ -1,12 +1,13 @@
1
1
  import type { Container, Theme } from "@profullstack/hqtui";
2
2
  import { gradient } from "@profullstack/hqtui";
3
- import type { DemoState } from "../state.ts";
3
+ import { panelGap, type DemoState } from "../state.ts";
4
4
  import { num } from "../format.ts";
5
5
 
6
6
  /** Every cell changes every frame — the worst case for a differential renderer. */
7
7
  export function stressScreen(ui: Container, state: DemoState, theme: Theme): void {
8
+ const gap = panelGap(state);
8
9
  const t = state.sample.time;
9
- ui.row({ size: 3, gap: 1 }, (r) => {
10
+ ui.row({ size: 3, gap }, (r) => {
10
11
  r.panel({ title: "Render" }, (p) => {
11
12
  p.text(`${num(state.renderMs, 2)} ms/frame`, { fg: theme.success });
12
13
  });
@@ -1,6 +1,6 @@
1
1
  import type { Container, Theme } from "@profullstack/hqtui";
2
2
  import { seriesColor } from "@profullstack/hqtui";
3
- import { focusPane, pane, scrollPane, type DemoState } from "../state.ts";
3
+ import { focusPane, pane, panelGap, scrollPane, type DemoState } from "../state.ts";
4
4
  import { num, percent } from "../format.ts";
5
5
 
6
6
  function rate(value: number): string {
@@ -19,11 +19,12 @@ const STATUS_COLORS = (theme: Theme): Record<string, number> => ({
19
19
 
20
20
  /** Every protocol in and out of this host: sockets, TCP counters, SSH, HTTP. */
21
21
  export function trafficScreen(ui: Container, state: DemoState, theme: Theme): void {
22
+ const gap = panelGap(state);
22
23
  const t = state.sample.telemetry;
23
24
  const net = t.net;
24
25
  const http = t.http;
25
26
 
26
- ui.row({ size: 13, gap: 1 }, (row) => {
27
+ ui.row({ size: 13, gap }, (row) => {
27
28
  row.panel({
28
29
  title: "Protocols",
29
30
  subtitle: `${t.inboundConnections} in / ${t.outboundConnections} out`,
@@ -86,7 +87,7 @@ export function trafficScreen(ui: Container, state: DemoState, theme: Theme): vo
86
87
  });
87
88
 
88
89
  ui.row({ size: "1fr", gap: 1 }, (row) => {
89
- row.column({ gap: 1 }, (column) => {
90
+ row.column({ gap }, (column) => {
90
91
  column.panel({
91
92
  title: "HTTP",
92
93
  subtitle: http ? `${num(http.requestsPerSecond, 1)} req/s` : "no access log",
@@ -135,7 +136,7 @@ export function trafficScreen(ui: Container, state: DemoState, theme: Theme): vo
135
136
  });
136
137
  });
137
138
 
138
- row.column({ width: "0.85fr", gap: 1 }, (column) => {
139
+ row.column({ width: "0.85fr", gap }, (column) => {
139
140
  column.panel({ title: "SSH Activity", subtitle: String(t.ssh.length), borderColor: theme.warning }, (p) => {
140
141
  if (t.ssh.length === 0) {
141
142
  p.label("No sshd events in the journal.");
package/src/state.ts CHANGED
@@ -26,6 +26,13 @@ export interface DemoState {
26
26
  /** Which pane the arrow keys drive, per screen. Clicking a pane sets it. */
27
27
  focused: Partial<Record<ScreenName, string>>;
28
28
  sort: "cpu" | "mem" | "pid" | "name";
29
+ /**
30
+ * Whether the [c] key has merged adjacent panel borders. Collapsing only
31
+ * happens where two bordered siblings actually touch, so the screens read
32
+ * this to lay out at a gap of zero; leaving them at one meant the key
33
+ * toggled a flag that could never reach a seam and nothing moved.
34
+ */
35
+ collapsed: boolean;
29
36
  filter: string;
30
37
  filtering: boolean;
31
38
  showHelp: boolean;
@@ -51,6 +58,11 @@ export interface DemoState {
51
58
  bytes: number;
52
59
  }
53
60
 
61
+ /** The seam between panels: zero while collapsed, so their borders can merge. */
62
+ export function panelGap(state: DemoState): number {
63
+ return state.collapsed ? 0 : 1;
64
+ }
65
+
54
66
  export interface Pane {
55
67
  selected: number;
56
68
  offset: number;
@@ -129,6 +141,7 @@ export function createState(
129
141
  panes: {},
130
142
  focused: {},
131
143
  sort: "cpu",
144
+ collapsed: false,
132
145
  filter: "",
133
146
  filtering: false,
134
147
  showHelp: false,