@hartvig/developer-control-center 0.8.6 → 0.8.8
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/.developer-control-center/metrics.json +1 -1
- package/.developer-control-center/status.json +1 -1
- package/.developer-control-center/timings.jsonl +25 -0
- package/.github/workflows/ci.yml +1 -7
- package/coverage/Developer Control Center/dcc.config.js.html +628 -0
- package/coverage/Developer Control Center/index.html +116 -0
- package/coverage/Developer Control Center/src/config/index.html +116 -0
- package/coverage/Developer Control Center/src/config/loader.ts.html +454 -0
- package/coverage/Developer Control Center/src/core/ci.ts.html +163 -0
- package/coverage/Developer Control Center/src/core/event-bus.ts.html +187 -0
- package/coverage/Developer Control Center/src/core/index.html +191 -0
- package/coverage/Developer Control Center/src/core/notifier.ts.html +187 -0
- package/coverage/Developer Control Center/src/core/persistence.ts.html +88 -0
- package/coverage/Developer Control Center/src/core/task-runner.ts.html +1498 -0
- package/coverage/Developer Control Center/src/core/workspaces.ts.html +304 -0
- package/coverage/Developer Control Center/src/plugins/index.html +116 -0
- package/coverage/Developer Control Center/src/plugins/manager.ts.html +259 -0
- package/coverage/Developer Control Center/src/status/index.html +116 -0
- package/coverage/Developer Control Center/src/status/store.ts.html +349 -0
- package/coverage/Developer Control Center/src/ui/command-list.tsx.html +574 -0
- package/coverage/Developer Control Center/src/ui/index.html +161 -0
- package/coverage/Developer Control Center/src/ui/metrics-panel.tsx.html +787 -0
- package/coverage/Developer Control Center/src/ui/panel.tsx.html +313 -0
- package/coverage/Developer Control Center/src/ui/status-panel.tsx.html +565 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +588 -0
- package/coverage/coverage-final.json +15 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +191 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dcc.config.js +2 -2
- package/dist/cli.js +1 -1
- package/dist/core/persistence.d.ts +2 -0
- package/dist/core/persistence.d.ts.map +1 -0
- package/dist/core/persistence.js +2 -0
- package/dist/core/persistence.js.map +1 -0
- package/dist/core/runtime.d.ts.map +1 -1
- package/dist/core/runtime.js +5 -3
- package/dist/core/runtime.js.map +1 -1
- package/dist/core/task-runner.d.ts +1 -0
- package/dist/core/task-runner.d.ts.map +1 -1
- package/dist/core/task-runner.js +81 -24
- package/dist/core/task-runner.js.map +1 -1
- package/dist/core/task-runner.test.d.ts +2 -0
- package/dist/core/task-runner.test.d.ts.map +1 -0
- package/dist/core/task-runner.test.js +326 -0
- package/dist/core/task-runner.test.js.map +1 -0
- package/dist/core/timer-plugin.d.ts.map +1 -1
- package/dist/core/timer-plugin.js +2 -1
- package/dist/core/timer-plugin.js.map +1 -1
- package/dist/plugins/manager.d.ts +2 -0
- package/dist/plugins/manager.d.ts.map +1 -1
- package/dist/plugins/manager.js +6 -2
- package/dist/plugins/manager.js.map +1 -1
- package/dist/plugins/manager.test.js +5 -2
- package/dist/plugins/manager.test.js.map +1 -1
- package/dist/ui/app.d.ts.map +1 -1
- package/dist/ui/app.js +124 -30
- package/dist/ui/app.js.map +1 -1
- package/dist/ui/app.test.d.ts +2 -0
- package/dist/ui/app.test.d.ts.map +1 -0
- package/dist/ui/app.test.js +157 -0
- package/dist/ui/app.test.js.map +1 -0
- package/dist/ui/command-list.test.d.ts +2 -0
- package/dist/ui/command-list.test.d.ts.map +1 -0
- package/dist/ui/command-list.test.js +104 -0
- package/dist/ui/command-list.test.js.map +1 -0
- package/dist/ui/metrics-panel.d.ts.map +1 -1
- package/dist/ui/metrics-panel.js +10 -9
- package/dist/ui/metrics-panel.js.map +1 -1
- package/dist/ui/metrics-panel.test.d.ts +2 -0
- package/dist/ui/metrics-panel.test.d.ts.map +1 -0
- package/dist/ui/metrics-panel.test.js +111 -0
- package/dist/ui/metrics-panel.test.js.map +1 -0
- package/dist/ui/panel.test.d.ts +2 -0
- package/dist/ui/panel.test.d.ts.map +1 -0
- package/dist/ui/panel.test.js +51 -0
- package/dist/ui/panel.test.js.map +1 -0
- package/dist/ui/status-panel.test.d.ts +2 -0
- package/dist/ui/status-panel.test.d.ts.map +1 -0
- package/dist/ui/status-panel.test.js +88 -0
- package/dist/ui/status-panel.test.js.map +1 -0
- package/package.json +4 -2
- package/src/cli.ts +1 -1
- package/src/core/persistence.ts +1 -0
- package/src/core/runtime.ts +7 -3
- package/src/core/task-runner.test.ts +395 -0
- package/src/core/task-runner.ts +80 -24
- package/src/core/timer-plugin.ts +2 -1
- package/src/plugins/manager.test.ts +5 -2
- package/src/plugins/manager.ts +6 -2
- package/src/ui/app.test.tsx +177 -0
- package/src/ui/app.tsx +167 -41
- package/src/ui/command-list.test.tsx +124 -0
- package/src/ui/metrics-panel.test.tsx +128 -0
- package/src/ui/metrics-panel.tsx +10 -10
- package/src/ui/panel.test.tsx +84 -0
- package/src/ui/status-panel.test.tsx +116 -0
- package/vitest.config.ts +1 -1
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import { render } from 'ink-testing-library';
|
|
5
|
+
import { Panel } from './panel.js';
|
|
6
|
+
|
|
7
|
+
describe('Panel', () => {
|
|
8
|
+
it('renders the title in the top border', () => {
|
|
9
|
+
const { lastFrame } = render(
|
|
10
|
+
<Panel title="Test" width={20} height={5}>
|
|
11
|
+
<React.Fragment />
|
|
12
|
+
</Panel>,
|
|
13
|
+
);
|
|
14
|
+
const frame = lastFrame();
|
|
15
|
+
expect(frame).toContain('╭─ Test');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('renders proper bottom border', () => {
|
|
19
|
+
const { lastFrame } = render(
|
|
20
|
+
<Panel title="Test" width={20} height={5}>
|
|
21
|
+
<React.Fragment />
|
|
22
|
+
</Panel>,
|
|
23
|
+
);
|
|
24
|
+
const frame = lastFrame();
|
|
25
|
+
expect(frame).toContain('╰');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('renders side borders for each content row', () => {
|
|
29
|
+
const { lastFrame } = render(
|
|
30
|
+
<Panel title="Test" width={20} height={5}>
|
|
31
|
+
<React.Fragment />
|
|
32
|
+
</Panel>,
|
|
33
|
+
);
|
|
34
|
+
const frame = lastFrame()!;
|
|
35
|
+
const lines = frame.split('\n');
|
|
36
|
+
expect(lines.length).toBe(5);
|
|
37
|
+
expect(lines[1].startsWith('│')).toBe(true);
|
|
38
|
+
expect(lines[1].endsWith('│')).toBe(true);
|
|
39
|
+
expect(lines[2].startsWith('│')).toBe(true);
|
|
40
|
+
expect(lines[2].endsWith('│')).toBe(true);
|
|
41
|
+
expect(lines[3].startsWith('│')).toBe(true);
|
|
42
|
+
expect(lines[3].endsWith('│')).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('renders children in the content area', () => {
|
|
46
|
+
const { lastFrame } = render(
|
|
47
|
+
<Panel title="Test" width={20} height={5}>
|
|
48
|
+
<Box><Text>hello</Text></Box>
|
|
49
|
+
</Panel>,
|
|
50
|
+
);
|
|
51
|
+
const frame = lastFrame();
|
|
52
|
+
expect(frame).toContain('hello');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('shows "↑N more" when hiddenAbove is set', () => {
|
|
56
|
+
const { lastFrame } = render(
|
|
57
|
+
<Panel title="Test" width={30} height={5} hiddenAbove={3}>
|
|
58
|
+
<React.Fragment />
|
|
59
|
+
</Panel>,
|
|
60
|
+
);
|
|
61
|
+
const frame = lastFrame();
|
|
62
|
+
expect(frame).toContain('↑3 more');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('shows "↓N more" when hiddenBelow is set', () => {
|
|
66
|
+
const { lastFrame } = render(
|
|
67
|
+
<Panel title="Test" width={30} height={5} hiddenBelow={2}>
|
|
68
|
+
<React.Fragment />
|
|
69
|
+
</Panel>,
|
|
70
|
+
);
|
|
71
|
+
const frame = lastFrame();
|
|
72
|
+
expect(frame).toContain('↓2 more');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('renders titleExtra next to the title', () => {
|
|
76
|
+
const { lastFrame } = render(
|
|
77
|
+
<Panel title="Main" width={30} height={5} titleExtra={<Text> [extra]</Text>}>
|
|
78
|
+
<React.Fragment />
|
|
79
|
+
</Panel>,
|
|
80
|
+
);
|
|
81
|
+
const frame = lastFrame();
|
|
82
|
+
expect(frame).toContain('[extra]');
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { render } from 'ink-testing-library';
|
|
4
|
+
import { StatusPanel } from './status-panel.js';
|
|
5
|
+
|
|
6
|
+
function makeTask(overrides: Record<string, any> = {}) {
|
|
7
|
+
return {
|
|
8
|
+
id: 'test',
|
|
9
|
+
label: 'Test Task',
|
|
10
|
+
status: 'running',
|
|
11
|
+
output: '',
|
|
12
|
+
startTime: Date.now(),
|
|
13
|
+
...overrides,
|
|
14
|
+
} as any;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe('StatusPanel', () => {
|
|
18
|
+
const baseProps = {
|
|
19
|
+
tasks: new Map(),
|
|
20
|
+
scrollOffsets: new Map(),
|
|
21
|
+
focusedPane: 'commands' as const,
|
|
22
|
+
width: 60,
|
|
23
|
+
menuRows: 10,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
it('shows no tasks yet when empty', () => {
|
|
27
|
+
const { lastFrame } = render(<StatusPanel {...baseProps} />);
|
|
28
|
+
expect(lastFrame()).toContain('No tasks yet');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('displays the task label and status', () => {
|
|
32
|
+
const tasks = new Map([['test', makeTask({ label: 'My Task', status: 'running' })]]);
|
|
33
|
+
const { lastFrame } = render(<StatusPanel {...baseProps} tasks={tasks} />);
|
|
34
|
+
const frame = lastFrame();
|
|
35
|
+
expect(frame).toContain('My Task');
|
|
36
|
+
expect(frame).toContain('RUNNING');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('shows success status with green icon', () => {
|
|
40
|
+
const tasks = new Map([['test', makeTask({ status: 'success' })]]);
|
|
41
|
+
const { lastFrame } = render(<StatusPanel {...baseProps} tasks={tasks} />);
|
|
42
|
+
expect(lastFrame()).toContain('PASS');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('shows failure status', () => {
|
|
46
|
+
const tasks = new Map([['test', makeTask({ status: 'failure', exitCode: 1 })]]);
|
|
47
|
+
const { lastFrame } = render(<StatusPanel {...baseProps} tasks={tasks} />);
|
|
48
|
+
expect(lastFrame()).toContain('FAIL');
|
|
49
|
+
expect(lastFrame()).toContain('exit 1');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('displays output lines', () => {
|
|
53
|
+
const tasks = new Map([['test', makeTask({ output: 'line1\nline2\nline3' })]]) as any;
|
|
54
|
+
const { lastFrame } = render(<StatusPanel {...baseProps} tasks={tasks} />);
|
|
55
|
+
const frame = lastFrame();
|
|
56
|
+
expect(frame).toContain('line1');
|
|
57
|
+
expect(frame).toContain('line2');
|
|
58
|
+
expect(frame).toContain('line3');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('shows confirm prompt when confirmingCommand is set', () => {
|
|
62
|
+
const { lastFrame } = render(
|
|
63
|
+
<StatusPanel
|
|
64
|
+
{...baseProps}
|
|
65
|
+
confirmingCommand={{ id: 'deploy', label: 'Deploy', command: 'npm run deploy' } as any}
|
|
66
|
+
/>,
|
|
67
|
+
);
|
|
68
|
+
const frame = lastFrame();
|
|
69
|
+
expect(frame).toContain('Run');
|
|
70
|
+
expect(frame).toContain('Deploy');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('shows input prompt when inputCommand is set', () => {
|
|
74
|
+
const { lastFrame } = render(
|
|
75
|
+
<StatusPanel
|
|
76
|
+
{...baseProps}
|
|
77
|
+
inputCommand={{ id: 'greet', label: 'Greet', command: 'echo', input: { message: 'Enter name:' } } as any}
|
|
78
|
+
/>,
|
|
79
|
+
);
|
|
80
|
+
const frame = lastFrame();
|
|
81
|
+
expect(frame).toContain('Enter name:');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('shows input value', () => {
|
|
85
|
+
const { lastFrame } = render(
|
|
86
|
+
<StatusPanel
|
|
87
|
+
{...baseProps}
|
|
88
|
+
inputCommand={{ id: 'greet', label: 'Greet', command: 'echo', input: {} } as any}
|
|
89
|
+
inputValue="hello"
|
|
90
|
+
/>,
|
|
91
|
+
);
|
|
92
|
+
expect(lastFrame()).toContain('hello');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('sanitizes ANSI escape codes from output', () => {
|
|
96
|
+
const tasks = new Map([['test', makeTask({ output: '\x1B[31mred\x1B[0m' })]]) as any;
|
|
97
|
+
const { lastFrame } = render(<StatusPanel {...baseProps} tasks={tasks} />);
|
|
98
|
+
expect(lastFrame()).not.toContain('\x1B[');
|
|
99
|
+
expect(lastFrame()).toContain('red');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('shows duration for completed tasks', () => {
|
|
103
|
+
const now = Date.now();
|
|
104
|
+
const tasks = new Map([
|
|
105
|
+
['test', makeTask({ startTime: now - 5000, endTime: now, status: 'success' })],
|
|
106
|
+
]) as any;
|
|
107
|
+
const { lastFrame } = render(<StatusPanel {...baseProps} tasks={tasks} />);
|
|
108
|
+
expect(lastFrame()).toContain('5.0s');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('shows watch mode indicator', () => {
|
|
112
|
+
const tasks = new Map([['test', makeTask({ watchMode: true, status: 'running' })]]);
|
|
113
|
+
const { lastFrame } = render(<StatusPanel {...baseProps} tasks={tasks} />);
|
|
114
|
+
expect(lastFrame()).toContain('WATCH');
|
|
115
|
+
});
|
|
116
|
+
});
|