termcast 1.4.1 → 1.6.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.
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +30 -12
- package/dist/build.js.map +1 -1
- package/dist/cli.js +0 -40
- package/dist/cli.js.map +1 -1
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +7 -1
- package/dist/compile.js.map +1 -1
- package/dist/components/bar-graph.d.ts +23 -8
- package/dist/components/bar-graph.d.ts.map +1 -1
- package/dist/components/bar-graph.js +84 -40
- package/dist/components/bar-graph.js.map +1 -1
- package/dist/components/dotted-line-graph.d.ts +86 -0
- package/dist/components/dotted-line-graph.d.ts.map +1 -0
- package/dist/components/dotted-line-graph.js +260 -0
- package/dist/components/dotted-line-graph.js.map +1 -0
- package/dist/components/extension-preferences.d.ts.map +1 -1
- package/dist/components/extension-preferences.js +1 -10
- package/dist/components/extension-preferences.js.map +1 -1
- package/dist/components/graph.d.ts.map +1 -1
- package/dist/components/graph.js +7 -1
- package/dist/components/graph.js.map +1 -1
- package/dist/components/histogram.d.ts +42 -0
- package/dist/components/histogram.d.ts.map +1 -0
- package/dist/components/histogram.js +115 -0
- package/dist/components/histogram.js.map +1 -0
- package/dist/components/horizontal-bar-graph.d.ts +47 -0
- package/dist/components/horizontal-bar-graph.d.ts.map +1 -0
- package/dist/components/horizontal-bar-graph.js +137 -0
- package/dist/components/horizontal-bar-graph.js.map +1 -0
- package/dist/components/list.d.ts +9 -0
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +84 -21
- package/dist/components/list.js.map +1 -1
- package/dist/examples/bar-graph-weekly.js +2 -2
- package/dist/examples/bar-graph-weekly.js.map +1 -1
- package/dist/examples/charts-showcase-barchart.d.ts +2 -0
- package/dist/examples/charts-showcase-barchart.d.ts.map +1 -0
- package/dist/examples/charts-showcase-barchart.js +10 -0
- package/dist/examples/charts-showcase-barchart.js.map +1 -0
- package/dist/examples/charts-showcase-bargraph.d.ts +2 -0
- package/dist/examples/charts-showcase-bargraph.d.ts.map +1 -0
- package/dist/examples/charts-showcase-bargraph.js +60 -0
- package/dist/examples/charts-showcase-bargraph.js.map +1 -0
- package/dist/examples/charts-showcase-candle.d.ts +2 -0
- package/dist/examples/charts-showcase-candle.d.ts.map +1 -0
- package/dist/examples/charts-showcase-candle.js +30 -0
- package/dist/examples/charts-showcase-candle.js.map +1 -0
- package/dist/examples/charts-showcase-graph.d.ts +2 -0
- package/dist/examples/charts-showcase-graph.d.ts.map +1 -0
- package/dist/examples/charts-showcase-graph.js +33 -0
- package/dist/examples/charts-showcase-graph.js.map +1 -0
- package/dist/examples/charts-showcase-heatmap.d.ts +2 -0
- package/dist/examples/charts-showcase-heatmap.d.ts.map +1 -0
- package/dist/examples/charts-showcase-heatmap.js +36 -0
- package/dist/examples/charts-showcase-heatmap.js.map +1 -0
- package/dist/examples/charts-showcase-mixed.d.ts +2 -0
- package/dist/examples/charts-showcase-mixed.d.ts.map +1 -0
- package/dist/examples/charts-showcase-mixed.js +30 -0
- package/dist/examples/charts-showcase-mixed.js.map +1 -0
- package/dist/examples/charts-showcase-progress.d.ts +2 -0
- package/dist/examples/charts-showcase-progress.d.ts.map +1 -0
- package/dist/examples/charts-showcase-progress.js +10 -0
- package/dist/examples/charts-showcase-progress.js.map +1 -0
- package/dist/examples/graph-multi-series.js +1 -1
- package/dist/examples/graph-multi-series.js.map +1 -1
- package/dist/examples/horizontal-bar-graph-weekly.d.ts +2 -0
- package/dist/examples/horizontal-bar-graph-weekly.d.ts.map +1 -0
- package/dist/examples/horizontal-bar-graph-weekly.js +67 -0
- package/dist/examples/horizontal-bar-graph-weekly.js.map +1 -0
- package/dist/examples/list-detail-height-ratchet.d.ts +2 -0
- package/dist/examples/list-detail-height-ratchet.d.ts.map +1 -0
- package/dist/examples/list-detail-height-ratchet.js +26 -0
- package/dist/examples/list-detail-height-ratchet.js.map +1 -0
- package/dist/examples/simple-dotted-line-graph.d.ts +2 -0
- package/dist/examples/simple-dotted-line-graph.d.ts.map +1 -0
- package/dist/examples/simple-dotted-line-graph.js +39 -0
- package/dist/examples/simple-dotted-line-graph.js.map +1 -0
- package/dist/examples/simple-histogram.d.ts +2 -0
- package/dist/examples/simple-histogram.d.ts.map +1 -0
- package/dist/examples/simple-histogram.js +47 -0
- package/dist/examples/simple-histogram.js.map +1 -0
- package/dist/extensions/dev.d.ts.map +1 -1
- package/dist/extensions/dev.js +1 -0
- package/dist/extensions/dev.js.map +1 -1
- package/dist/globals.js +8 -0
- package/dist/globals.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/package-json.d.ts +2 -0
- package/dist/package-json.d.ts.map +1 -1
- package/dist/package-json.js +20 -17
- package/dist/package-json.js.map +1 -1
- package/dist/platform/node/sqlite.d.ts +6 -5
- package/dist/platform/node/sqlite.d.ts.map +1 -1
- package/dist/platform/node/sqlite.js +30 -14
- package/dist/platform/node/sqlite.js.map +1 -1
- package/dist/profiler.d.ts +2 -0
- package/dist/profiler.d.ts.map +1 -0
- package/dist/profiler.js +390 -0
- package/dist/profiler.js.map +1 -0
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +11 -9
- package/dist/theme.js.map +1 -1
- package/dist/utils/run-command.d.ts.map +1 -1
- package/dist/utils/run-command.js +8 -19
- package/dist/utils/run-command.js.map +1 -1
- package/dist/utils.d.ts +1 -19
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +1 -100
- package/dist/utils.js.map +1 -1
- package/package.json +18 -21
- package/src/build.tsx +38 -15
- package/src/cli.tsx +3 -40
- package/src/compile.tsx +9 -1
- package/src/compile.vitest.tsx +8 -8
- package/src/components/bar-graph.tsx +217 -111
- package/src/components/dotted-line-graph.tsx +407 -0
- package/src/components/extension-preferences.tsx +2 -12
- package/src/components/graph.tsx +5 -1
- package/src/components/histogram.tsx +228 -0
- package/src/components/horizontal-bar-graph.tsx +279 -0
- package/src/components/list.tsx +112 -26
- package/src/examples/action-shortcut.vitest.tsx +20 -20
- package/src/examples/actions-context.vitest.tsx +2 -2
- package/src/examples/bar-graph-weekly.tsx +2 -2
- package/src/examples/bar-graph-weekly.vitest.tsx +103 -102
- package/src/examples/charts-showcase-bargraph.tsx +103 -0
- package/src/examples/detail-metadata-showcase.vitest.tsx +12 -12
- package/src/examples/form-basic.vitest.tsx +11 -11
- package/src/examples/form-dropdown.vitest.tsx +11 -11
- package/src/examples/form-scroll.vitest.tsx +1 -1
- package/src/examples/form-tagpicker.vitest.tsx +11 -11
- package/src/examples/github.vitest.tsx +22 -31
- package/src/examples/graph-bar-chart.vitest.tsx +36 -36
- package/src/examples/graph-multi-series.tsx +1 -1
- package/src/examples/graph-polymarket.vitest.tsx +24 -24
- package/src/examples/graph-row.vitest.tsx +14 -14
- package/src/examples/graph-styles.vitest.tsx +77 -77
- package/src/examples/horizontal-bar-graph-weekly.tsx +138 -0
- package/src/examples/horizontal-bar-graph-weekly.vitest.tsx +164 -0
- package/src/examples/list-detail-height-ratchet.tsx +48 -0
- package/src/examples/list-detail-height-ratchet.vitest.tsx +161 -0
- package/src/examples/list-detail-metadata.vitest.tsx +51 -51
- package/src/examples/list-dropdown-default.vitest.tsx +27 -27
- package/src/examples/list-fetch-data.vitest.tsx +3 -3
- package/src/examples/list-loading-empty-view.vitest.tsx +1 -1
- package/src/examples/list-no-actions.vitest.tsx +3 -3
- package/src/examples/list-scrollbox.vitest.tsx +6 -6
- package/src/examples/list-spacing-mode.vitest.tsx +1 -1
- package/src/examples/list-with-detail.vitest.tsx +55 -55
- package/src/examples/list-with-dropdown.vitest.tsx +6 -6
- package/src/examples/list-with-sections.vitest.tsx +20 -20
- package/src/examples/list-with-toast.vitest.tsx +4 -4
- package/src/examples/simple-candle-chart.vitest.tsx +61 -59
- package/src/examples/simple-dotted-line-graph.tsx +53 -0
- package/src/examples/simple-dotted-line-graph.vitest.tsx +62 -0
- package/src/examples/simple-grid.vitest.tsx +4 -4
- package/src/examples/simple-heatmap.vitest.tsx +9 -9
- package/src/examples/simple-histogram.tsx +90 -0
- package/src/examples/simple-navigation.vitest.tsx +25 -25
- package/src/examples/simple-progress-bar.vitest.tsx +7 -7
- package/src/examples/swift-extension.vitest.tsx +5 -5
- package/src/examples/toast-action.vitest.tsx +4 -4
- package/src/extensions/dev.tsx +2 -1
- package/src/extensions/dev.vitest.tsx +17 -17
- package/src/globals.ts +9 -0
- package/src/index.tsx +21 -0
- package/src/package-json.tsx +24 -23
- package/src/platform/node/sqlite.ts +29 -13
- package/src/profiler.tsx +487 -0
- package/src/theme.tsx +11 -10
- package/src/utils/run-command.tsx +10 -19
- package/src/utils.tsx +0 -163
- package/src/examples/store.tsx +0 -4
- package/src/examples/store.vitest.tsx +0 -78
- package/src/extensions/home.tsx +0 -227
- package/src/extensions/store.tsx +0 -375
|
@@ -27,18 +27,18 @@ afterEach(() => {
|
|
|
27
27
|
test('ctrl+r shortcut should trigger Refresh action directly', async () => {
|
|
28
28
|
// Wait for list to render
|
|
29
29
|
await session.text({
|
|
30
|
-
waitFor: (text) => /
|
|
30
|
+
waitFor: (text) => /nt: 0/.test(text),
|
|
31
31
|
})
|
|
32
32
|
|
|
33
33
|
const initial = await session.text()
|
|
34
|
-
expect(initial).toContain('
|
|
34
|
+
expect(initial).toContain('nt: 0')
|
|
35
35
|
|
|
36
36
|
// Press ctrl+r directly to trigger Refresh action
|
|
37
37
|
await session.press(['ctrl', 'r'])
|
|
38
38
|
|
|
39
39
|
// Wait for the refresh to take effect
|
|
40
40
|
const afterCtrlR = await session.text({
|
|
41
|
-
waitFor: (text) => /
|
|
41
|
+
waitFor: (text) => /nt: 1/.test(text),
|
|
42
42
|
timeout: 5000,
|
|
43
43
|
})
|
|
44
44
|
expect(afterCtrlR).toMatchInlineSnapshot(`
|
|
@@ -49,7 +49,7 @@ test('ctrl+r shortcut should trigger Refresh action directly', async () => {
|
|
|
49
49
|
|
|
50
50
|
> Search...
|
|
51
51
|
|
|
52
|
-
›
|
|
52
|
+
›Refres...unt: 1Press ctrl+r to refresh...ter then select Refresh
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
|
|
@@ -57,11 +57,11 @@ test('ctrl+r shortcut should trigger Refresh action directly', async () => {
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
↵ refresh ↑↓ navigate ^k actions :vim
|
|
61
60
|
|
|
62
61
|
|
|
63
62
|
|
|
64
63
|
|
|
64
|
+
↵ refresh ↑↓ navigate ^k actions :vim
|
|
65
65
|
"
|
|
66
66
|
`)
|
|
67
67
|
}, 30000)
|
|
@@ -69,7 +69,7 @@ test('ctrl+r shortcut should trigger Refresh action directly', async () => {
|
|
|
69
69
|
test('action shortcut is displayed in action panel', async () => {
|
|
70
70
|
// Wait for list to render
|
|
71
71
|
await session.text({
|
|
72
|
-
waitFor: (text) => /
|
|
72
|
+
waitFor: (text) => /nt: 0/.test(text),
|
|
73
73
|
})
|
|
74
74
|
|
|
75
75
|
// Open action panel with ctrl+k
|
|
@@ -85,6 +85,7 @@ test('action shortcut is displayed in action panel', async () => {
|
|
|
85
85
|
expect(actionsPanel).toMatchInlineSnapshot(`
|
|
86
86
|
"
|
|
87
87
|
|
|
88
|
+
|
|
88
89
|
╭────────────────────────────────────────────────────────────────╮
|
|
89
90
|
│ │
|
|
90
91
|
│ Actions esc │
|
|
@@ -102,38 +103,37 @@ test('action shortcut is displayed in action panel', async () => {
|
|
|
102
103
|
│ │
|
|
103
104
|
│ │
|
|
104
105
|
│ │
|
|
105
|
-
│ ↵ select ↑↓ navigate │
|
|
106
|
-
│ │"
|
|
106
|
+
│ ↵ select ↑↓ navigate │"
|
|
107
107
|
`)
|
|
108
108
|
}, 30000)
|
|
109
109
|
|
|
110
110
|
test('action works via Enter (auto-execute first action)', async () => {
|
|
111
111
|
// Wait for list to render
|
|
112
112
|
await session.text({
|
|
113
|
-
waitFor: (text) => /
|
|
113
|
+
waitFor: (text) => /nt: 0/.test(text),
|
|
114
114
|
})
|
|
115
115
|
|
|
116
116
|
// Press Enter to auto-execute first action (Refresh)
|
|
117
117
|
await session.press('return')
|
|
118
118
|
|
|
119
119
|
const afterEnter = await session.text({
|
|
120
|
-
waitFor: (text) => /
|
|
120
|
+
waitFor: (text) => /nt: 1/.test(text),
|
|
121
121
|
timeout: 5000,
|
|
122
122
|
})
|
|
123
123
|
|
|
124
|
-
expect(afterEnter).toContain('
|
|
124
|
+
expect(afterEnter).toContain('nt: 1')
|
|
125
125
|
}, 30000)
|
|
126
126
|
|
|
127
127
|
test('ctrl+x shortcut should trigger Reset action directly', async () => {
|
|
128
128
|
// Wait for list to render and increment once via Enter
|
|
129
129
|
await session.text({
|
|
130
|
-
waitFor: (text) => /
|
|
130
|
+
waitFor: (text) => /nt: 0/.test(text),
|
|
131
131
|
})
|
|
132
132
|
|
|
133
133
|
// Increment via Enter first
|
|
134
134
|
await session.press('return')
|
|
135
135
|
await session.text({
|
|
136
|
-
waitFor: (text) => /
|
|
136
|
+
waitFor: (text) => /nt: 1/.test(text),
|
|
137
137
|
timeout: 5000,
|
|
138
138
|
})
|
|
139
139
|
|
|
@@ -142,27 +142,27 @@ test('ctrl+x shortcut should trigger Reset action directly', async () => {
|
|
|
142
142
|
|
|
143
143
|
// Wait for the reset to take effect
|
|
144
144
|
const afterCtrlX = await session.text({
|
|
145
|
-
waitFor: (text) => /
|
|
145
|
+
waitFor: (text) => /nt: 0/.test(text),
|
|
146
146
|
timeout: 5000,
|
|
147
147
|
})
|
|
148
|
-
expect(afterCtrlX).toContain('
|
|
148
|
+
expect(afterCtrlX).toContain('nt: 0')
|
|
149
149
|
}, 30000)
|
|
150
150
|
|
|
151
151
|
test('alt+d shortcut should trigger Double action directly', async () => {
|
|
152
152
|
// Wait for list to render
|
|
153
153
|
await session.text({
|
|
154
|
-
waitFor: (text) => /
|
|
154
|
+
waitFor: (text) => /nt: 0/.test(text),
|
|
155
155
|
})
|
|
156
156
|
|
|
157
157
|
// Increment twice via Enter to get count=2
|
|
158
158
|
await session.press('return')
|
|
159
159
|
await session.text({
|
|
160
|
-
waitFor: (text) => /
|
|
160
|
+
waitFor: (text) => /nt: 1/.test(text),
|
|
161
161
|
timeout: 5000,
|
|
162
162
|
})
|
|
163
163
|
await session.press('return')
|
|
164
164
|
await session.text({
|
|
165
|
-
waitFor: (text) => /
|
|
165
|
+
waitFor: (text) => /nt: 2/.test(text),
|
|
166
166
|
timeout: 5000,
|
|
167
167
|
})
|
|
168
168
|
|
|
@@ -171,8 +171,8 @@ test('alt+d shortcut should trigger Double action directly', async () => {
|
|
|
171
171
|
|
|
172
172
|
// Wait for the double to take effect
|
|
173
173
|
const afterAltD = await session.text({
|
|
174
|
-
waitFor: (text) => /
|
|
174
|
+
waitFor: (text) => /nt: 4/.test(text),
|
|
175
175
|
timeout: 5000,
|
|
176
176
|
})
|
|
177
|
-
expect(afterAltD).toContain('
|
|
177
|
+
expect(afterAltD).toContain('nt: 4')
|
|
178
178
|
}, 30000)
|
|
@@ -38,6 +38,7 @@ test('actions preserve React context through portal', async () => {
|
|
|
38
38
|
expect(actionsPanel).toMatchInlineSnapshot(`
|
|
39
39
|
"
|
|
40
40
|
|
|
41
|
+
|
|
41
42
|
╭────────────────────────────────────────────────────────────────╮
|
|
42
43
|
│ │
|
|
43
44
|
│ Actions esc │
|
|
@@ -55,8 +56,7 @@ test('actions preserve React context through portal', async () => {
|
|
|
55
56
|
│ │
|
|
56
57
|
│ │
|
|
57
58
|
│ │
|
|
58
|
-
│ ↵ select ↑↓ navigate │
|
|
59
|
-
│ │"
|
|
59
|
+
│ ↵ select ↑↓ navigate │"
|
|
60
60
|
`)
|
|
61
61
|
|
|
62
62
|
// Select "Show Counter" (first action, already selected)
|
|
@@ -151,7 +151,7 @@ function BarGraphWeeklyExample() {
|
|
|
151
151
|
<List.Item.Detail
|
|
152
152
|
metadata={
|
|
153
153
|
<List.Item.Detail.Metadata>
|
|
154
|
-
<BarGraph height={10} labels={manyColsLabels}>
|
|
154
|
+
<BarGraph height={10} labels={manyColsLabels} barWidth={1}>
|
|
155
155
|
{manyColsSeries.map((s, i) => {
|
|
156
156
|
return <BarGraph.Series key={i} data={s.data} title={s.title} />
|
|
157
157
|
})}
|
|
@@ -261,4 +261,4 @@ function BarGraphWeeklyExample() {
|
|
|
261
261
|
)
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
renderWithProviders(<BarGraphWeeklyExample />)
|
|
264
|
+
void renderWithProviders(<BarGraphWeeklyExample />)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// E2E tests for BarGraph vertical stacked bar chart.
|
|
2
|
-
// Bar segments
|
|
2
|
+
// Bar segments use █ (full block) chars for solid, gap-free columns.
|
|
3
3
|
|
|
4
4
|
import { test, expect, afterEach, beforeEach } from 'vitest'
|
|
5
5
|
import { launchTerminal, Session } from 'tuistory/src'
|
|
@@ -22,7 +22,7 @@ afterEach(() => {
|
|
|
22
22
|
test('bar graph renders bars, labels, and legend', async () => {
|
|
23
23
|
const text = await session.text({
|
|
24
24
|
waitFor: (text) => {
|
|
25
|
-
return text.includes('Mon') && text.includes('
|
|
25
|
+
return text.includes('Mon') && text.includes('Direct') && text.includes('0.0│')
|
|
26
26
|
},
|
|
27
27
|
timeout: 10000,
|
|
28
28
|
})
|
|
@@ -35,47 +35,47 @@ test('bar graph renders bars, labels, and legend', async () => {
|
|
|
35
35
|
|
|
36
36
|
> Search...
|
|
37
37
|
|
|
38
|
-
›Weekly
|
|
39
|
-
Revenue by
|
|
40
|
-
Server Load CPU / Memory / IO │
|
|
41
|
-
Many
|
|
42
|
-
Many Series (8) Legend overflow test │
|
|
43
|
-
Long
|
|
44
|
-
Week 1 vs Week 2 Two graphs in a Row │
|
|
45
|
-
│
|
|
46
|
-
│
|
|
47
|
-
│
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
38
|
+
›Weekly Traffi 3 channel...oss 6 days │ 110.0│ ██
|
|
39
|
+
Revenue by Regio EMEA / A...Americas │ │██ ██ ██ ██
|
|
40
|
+
Server Load CPU / Memory / IO │ 82.5│██ ██ ██ ██
|
|
41
|
+
Many C...ns (20)Overflow...h 20 bars │ │██ ██ ██ ██ ██
|
|
42
|
+
Many Series (8) Legend overflow test │ 55.0│██ ██ ██ ██ ██ ██
|
|
43
|
+
Long Label Labels wide...bar columns │ │██ ██ ██ ██ ██ ██
|
|
44
|
+
Week 1 vs Week 2 Two graphs in a Row │ 27.5│██ ██ ██ ██ ██ ██
|
|
45
|
+
│ │██ ██ ██ ██ ██ ██
|
|
46
|
+
│ 0.0│██ ██ ██ ██ ██ ██
|
|
47
|
+
│ Mon Tue Wed Thu FriSat
|
|
48
|
+
│ ■ Direct ■ Organic ■ Referral
|
|
49
|
+
│
|
|
50
|
+
│
|
|
51
|
+
│
|
|
52
|
+
│
|
|
53
|
+
│
|
|
54
|
+
│
|
|
55
|
+
│
|
|
56
|
+
│
|
|
57
|
+
│
|
|
58
|
+
│
|
|
59
|
+
↵ open detail ↑↓ navigate ^k act │
|
|
60
60
|
|
|
61
61
|
"
|
|
62
62
|
`)
|
|
63
63
|
|
|
64
64
|
expect(text).toContain('Mon')
|
|
65
|
-
expect(text).toContain('Sat')
|
|
66
65
|
expect(text).toContain('Direct')
|
|
66
|
+
expect(text).toContain('0.0│')
|
|
67
67
|
expect(text).toContain('█')
|
|
68
68
|
}, 30000)
|
|
69
69
|
|
|
70
70
|
test('many columns (20) clips with overflow hidden', async () => {
|
|
71
|
-
await session.text({ waitFor: (t) => t.includes('
|
|
71
|
+
await session.text({ waitFor: (t) => t.includes('(20)'), timeout: 10000 })
|
|
72
72
|
// Navigate: Weekly Traffic, Revenue, Server Load, Many Columns = 3 downs
|
|
73
73
|
session.sendKey('down')
|
|
74
74
|
session.sendKey('down')
|
|
75
75
|
session.sendKey('down')
|
|
76
76
|
|
|
77
77
|
await session.text({
|
|
78
|
-
waitFor: (t) => t.includes('›Many
|
|
78
|
+
waitFor: (t) => t.includes('›Many') && t.includes('(20)'),
|
|
79
79
|
timeout: 10000,
|
|
80
80
|
})
|
|
81
81
|
await session.waitIdle()
|
|
@@ -83,16 +83,16 @@ test('many columns (20) clips with overflow hidden', async () => {
|
|
|
83
83
|
|
|
84
84
|
// Bar graph rendering has non-deterministic ANSI highlights, so use toContain checks
|
|
85
85
|
// instead of inline snapshot for the bars area
|
|
86
|
-
expect(text).toContain('›Many
|
|
86
|
+
expect(text).toContain('›Many')
|
|
87
87
|
expect(text).toContain('BarGraph Showcase')
|
|
88
|
-
expect(text).toContain('
|
|
88
|
+
expect(text).toContain('█')
|
|
89
89
|
|
|
90
90
|
// Some labels visible, overflow clips the rest
|
|
91
|
-
expect(text).toContain('
|
|
91
|
+
expect(text).toContain('D')
|
|
92
92
|
expect(text).toContain('█')
|
|
93
93
|
}, 30000)
|
|
94
94
|
|
|
95
|
-
test('many series (8) legend clips on one
|
|
95
|
+
test('many series (8) bottom legend clips on one row', async () => {
|
|
96
96
|
await session.text({ waitFor: (t) => t.includes('Many Series'), timeout: 10000 })
|
|
97
97
|
// Navigate: Weekly, Revenue, Server, Many Columns, Many Series = 4 downs
|
|
98
98
|
session.sendKey('down')
|
|
@@ -113,39 +113,40 @@ test('many series (8) legend clips on one line', async () => {
|
|
|
113
113
|
|
|
114
114
|
> Search...
|
|
115
115
|
|
|
116
|
-
Weekly
|
|
117
|
-
Revenue by
|
|
118
|
-
Server Load CPU / Memory / IO │
|
|
119
|
-
Many
|
|
120
|
-
›Many Series (8) Legend overflow test │
|
|
121
|
-
Long
|
|
122
|
-
Week 1 vs Week 2 Two graphs in a Row │
|
|
123
|
-
│
|
|
124
|
-
│
|
|
125
|
-
│
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
116
|
+
Weekly Traffi 3 channel...oss 6 days │ 328.0│██ ██ ██ ██ ██
|
|
117
|
+
Revenue by Regio EMEA / A...Americas │ │██ ██ ██ ██ ██ ██
|
|
118
|
+
Server Load CPU / Memory / IO │ 246.0│██ ██ ██ ██ ██ ██
|
|
119
|
+
Many C...ns (20)Overflow...h 20 bars │ │██ ██ ██ ██ ██ ██
|
|
120
|
+
›Many Series (8) Legend overflow test │ 164.0│██ ██ ██ ██ ██ ██
|
|
121
|
+
Long Label Labels wide...bar columns │ │██ ██ ██ ██ ██ ██
|
|
122
|
+
Week 1 vs Week 2 Two graphs in a Row │ 82.0│██ ██ ██ ██ ██ ██
|
|
123
|
+
│ │██ ██ ██ ██ ██ ██
|
|
124
|
+
│ 0.0│██ ██ ██ ██ ██ ██
|
|
125
|
+
│ Mon Tue Wed Thu FriSat
|
|
126
|
+
│ ■ Series 1 ■ Series 2 ■ Series 3
|
|
127
|
+
│
|
|
128
|
+
│
|
|
129
|
+
│
|
|
130
|
+
│
|
|
131
|
+
│
|
|
132
|
+
│
|
|
133
|
+
│
|
|
134
|
+
│
|
|
135
|
+
│
|
|
136
|
+
│
|
|
137
|
+
↑↓ navigate ^k actions :vim │
|
|
138
138
|
|
|
139
139
|
"
|
|
140
140
|
`)
|
|
141
141
|
|
|
142
|
-
//
|
|
142
|
+
// Bottom legend is a single clipped row by default.
|
|
143
143
|
expect(text).toContain('Series 1')
|
|
144
|
+
expect(text).toContain('Series 3')
|
|
144
145
|
expect(text).toContain('█')
|
|
145
146
|
}, 30000)
|
|
146
147
|
|
|
147
148
|
test('long labels truncated by overflow hidden', async () => {
|
|
148
|
-
await session.text({ waitFor: (t) => t.includes('
|
|
149
|
+
await session.text({ waitFor: (t) => t.includes('Labels wide'), timeout: 10000 })
|
|
149
150
|
// Navigate: Weekly, Revenue, Server, Many Columns, Many Series, Long Labels = 5 downs
|
|
150
151
|
session.sendKey('down')
|
|
151
152
|
session.sendKey('down')
|
|
@@ -154,7 +155,7 @@ test('long labels truncated by overflow hidden', async () => {
|
|
|
154
155
|
session.sendKey('down')
|
|
155
156
|
|
|
156
157
|
const text = await session.text({
|
|
157
|
-
waitFor: (t) => t.includes('›Long
|
|
158
|
+
waitFor: (t) => t.includes('›Long Label') || t.includes('›Lon...bels'),
|
|
158
159
|
timeout: 10000,
|
|
159
160
|
})
|
|
160
161
|
|
|
@@ -166,33 +167,33 @@ test('long labels truncated by overflow hidden', async () => {
|
|
|
166
167
|
|
|
167
168
|
> Search...
|
|
168
169
|
|
|
169
|
-
Weekly
|
|
170
|
-
Revenue by
|
|
171
|
-
Server Load CPU / Memory / IO │
|
|
172
|
-
Many
|
|
173
|
-
Many Series (8) Legend overflow test │
|
|
174
|
-
›Long
|
|
175
|
-
Week 1 vs Week 2 Two graphs in a Row │
|
|
176
|
-
│
|
|
177
|
-
│
|
|
178
|
-
│
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
170
|
+
Weekly Traffi 3 channel...oss 6 days │ 75.0│ ██
|
|
171
|
+
Revenue by Regio EMEA / A...Americas │ │██ ██ ██
|
|
172
|
+
Server Load CPU / Memory / IO │ 56.3│██ ██ ██ ██
|
|
173
|
+
Many C...ns (20)Overflow...h 20 bars │ │██ ██ ██ ██
|
|
174
|
+
Many Series (8) Legend overflow test │ 37.5│██ ██ ██ ██ ██
|
|
175
|
+
›Long Label Labels wide...bar columns │ │██ ██ ██ ██ ██ ██
|
|
176
|
+
Week 1 vs Week 2 Two graphs in a Row │ 18.8│██ ██ ██ ██ ██ ██
|
|
177
|
+
│ │██ ██ ██ ██ ██ ██
|
|
178
|
+
│ 0.0│██ ██ ██ ██ ██ ██
|
|
179
|
+
│ Monday Thursday
|
|
180
|
+
│ ■ Views ■ Clicks
|
|
181
|
+
│
|
|
182
|
+
│
|
|
183
|
+
│
|
|
184
|
+
│
|
|
185
|
+
│
|
|
186
|
+
│
|
|
187
|
+
│
|
|
188
|
+
│
|
|
189
|
+
│
|
|
190
|
+
│
|
|
191
|
+
↑↓ navigate ^k actions :vim │
|
|
191
192
|
|
|
192
193
|
"
|
|
193
194
|
`)
|
|
194
195
|
|
|
195
|
-
expect(text).toContain('
|
|
196
|
+
expect(text).toContain('Labels wide')
|
|
196
197
|
expect(text).toContain('█')
|
|
197
198
|
}, 30000)
|
|
198
199
|
|
|
@@ -219,31 +220,31 @@ test('side-by-side bar graphs in a Row', async () => {
|
|
|
219
220
|
|
|
220
221
|
> Search...
|
|
221
222
|
|
|
222
|
-
Weekly
|
|
223
|
-
Revenue by
|
|
224
|
-
Server Load CPU / Memory / IO │
|
|
225
|
-
Many
|
|
226
|
-
Many Series (8) Legend overflow test │
|
|
227
|
-
Long
|
|
228
|
-
›Week 1 vs Week 2 Two graphs in a Row │
|
|
229
|
-
│
|
|
230
|
-
│
|
|
231
|
-
│
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
223
|
+
Weekly Traffi 3 channel...oss 6 days │ 110.0│ 130.0│
|
|
224
|
+
Revenue by Regio EMEA / A...Americas │ │██ ██ │██
|
|
225
|
+
Server Load CPU / Memory / IO │ 82.5│██ ██ 97.5│██ ██
|
|
226
|
+
Many C...ns (20)Overflow...h 20 bars │ │██ ██ ██ │██ ██ ██
|
|
227
|
+
Many Series (8) Legend overflow test │ 55.0│██ ██ ██ 65.0│██ ██ ██
|
|
228
|
+
Long Label Labels wide...bar columns │ │██ ██ ██ │██ ██ ██
|
|
229
|
+
›Week 1 vs Week 2 Two graphs in a Row │ 27.5│██ ██ ██ 32.5│██ ██ ██
|
|
230
|
+
│ │██ ██ ██ │██ ██ ██
|
|
231
|
+
│ 0.0│██ ██ ██ 0.0│██ ██ ██
|
|
232
|
+
│ Mon Tue Wed Mon Tue We
|
|
233
|
+
│ ■ Direct ■ Organ ■ Direct ■ Orga
|
|
234
|
+
│
|
|
235
|
+
│
|
|
236
|
+
│
|
|
237
|
+
│
|
|
238
|
+
│
|
|
239
|
+
│
|
|
240
|
+
│
|
|
241
|
+
│
|
|
242
|
+
│
|
|
243
|
+
│
|
|
244
|
+
↵ open detail ↑↓ navigate ^k act │
|
|
244
245
|
|
|
245
246
|
"
|
|
246
247
|
`)
|
|
247
248
|
|
|
248
|
-
expect(text).toContain('
|
|
249
|
+
expect(text).toContain('Direct')
|
|
249
250
|
}, 30000)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// Showcase: BarGraph vertical stacked bar chart inside a Detail view.
|
|
2
|
+
// Recreates a monthly model spend chart with stacked per-day usage.
|
|
3
|
+
|
|
4
|
+
import { BarGraph, Detail } from 'termcast'
|
|
5
|
+
import { renderWithProviders } from '../utils'
|
|
6
|
+
|
|
7
|
+
const labels = Array.from({ length: 30 }, (_, i) => {
|
|
8
|
+
const day = i + 1
|
|
9
|
+
if (day % 2 === 0) {
|
|
10
|
+
return ''
|
|
11
|
+
}
|
|
12
|
+
return String(day).padStart(2, '0')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const emptyMonth = Array.from({ length: 30 }, () => 0)
|
|
16
|
+
|
|
17
|
+
function withSpend(points: Record<number, number>): number[] {
|
|
18
|
+
return emptyMonth.map((_, i) => points[i + 1] || 0)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const modelSpend = [
|
|
22
|
+
{
|
|
23
|
+
title: 'deepseek-v4-flash (go)',
|
|
24
|
+
color: '#b5bb69',
|
|
25
|
+
data: withSpend({ 21: 0.6, 25: 1.05, 26: 1.3, 27: 1.9, 28: 0.55, 29: 0.8, 30: 1.1 }),
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
title: 'deepseek-v4-pro (go)',
|
|
29
|
+
color: '#8f59b5',
|
|
30
|
+
data: withSpend({ 25: 0.12 }),
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
title: 'kimi-k2.6 (go)',
|
|
34
|
+
color: '#64b86a',
|
|
35
|
+
data: withSpend({ 22: 3.25, 23: 1.65, 24: 2.2, 25: 2.05 }),
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
title: 'mimo-v2-omni (go)',
|
|
39
|
+
color: '#aaa25f',
|
|
40
|
+
data: withSpend({ 25: 0.12, 26: 0.15 }),
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
title: 'mimo-v2-pro (go)',
|
|
44
|
+
color: '#5ba895',
|
|
45
|
+
data: withSpend({ 16: 1.5, 17: 0.75, 21: 2.5 }),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
title: 'minimax-m2.7 (go)',
|
|
49
|
+
color: '#6c6cb8',
|
|
50
|
+
data: withSpend({ 20: 5 }),
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
title: 'qwen3.6-plus (go)',
|
|
54
|
+
color: '#b07a5c',
|
|
55
|
+
data: withSpend({ 17: 2.65, 18: 6.55, 19: 3.15 }),
|
|
56
|
+
},
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
function ChartsShowcaseBarGraph() {
|
|
60
|
+
return (
|
|
61
|
+
<Detail
|
|
62
|
+
navigationTitle="Model Spend"
|
|
63
|
+
markdown="# Model Spend\n\nApril 2026 usage by model and API key."
|
|
64
|
+
metadata={
|
|
65
|
+
<Detail.Metadata>
|
|
66
|
+
<box flexDirection="row" gap={2} paddingBottom={1}>
|
|
67
|
+
<box border borderColor="#2a2a2a" paddingLeft={2} paddingRight={2} height={3} justifyContent="center">
|
|
68
|
+
<text>‹ April 2026 ›</text>
|
|
69
|
+
</box>
|
|
70
|
+
<box border borderColor="#2d5fa8" paddingLeft={2} paddingRight={2} height={3} justifyContent="center">
|
|
71
|
+
<text>All Models⌄</text>
|
|
72
|
+
</box>
|
|
73
|
+
<box border borderColor="#2a2a2a" paddingLeft={2} paddingRight={2} height={3} justifyContent="center">
|
|
74
|
+
<text>All Keys⌄</text>
|
|
75
|
+
</box>
|
|
76
|
+
</box>
|
|
77
|
+
<box border borderColor="#2a2a2a" paddingTop={2} paddingLeft={2} paddingRight={2} paddingBottom={1}>
|
|
78
|
+
<BarGraph
|
|
79
|
+
height={24}
|
|
80
|
+
labels={labels}
|
|
81
|
+
barGap={1}
|
|
82
|
+
yFormat={(value) => `$${value.toFixed(0)}`}
|
|
83
|
+
showLegend
|
|
84
|
+
>
|
|
85
|
+
{modelSpend.map((series) => {
|
|
86
|
+
return (
|
|
87
|
+
<BarGraph.Series
|
|
88
|
+
key={series.title}
|
|
89
|
+
color={series.color}
|
|
90
|
+
data={series.data}
|
|
91
|
+
title={series.title}
|
|
92
|
+
/>
|
|
93
|
+
)
|
|
94
|
+
})}
|
|
95
|
+
</BarGraph>
|
|
96
|
+
</box>
|
|
97
|
+
</Detail.Metadata>
|
|
98
|
+
}
|
|
99
|
+
/>
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
void renderWithProviders(<ChartsShowcaseBarGraph />)
|