Skip to content

Commit dc98af6

Browse files
committed
refactor: streams, logger, console
1 parent 5b10922 commit dc98af6

44 files changed

Lines changed: 622 additions & 548 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/web/src/features/stream/components/stream-console-input.tsx renamed to apps/web/src/features/console/components/console-input.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
import { ChevronDown, Send } from 'lucide-react';
1010
import type { KeyboardEvent } from 'react';
1111

12-
interface StreamConsoleInputProps {
12+
interface ConsoleInputProps {
1313
input: string;
1414
disabled: boolean;
1515
onChange: (value: string) => void;
@@ -18,14 +18,14 @@ interface StreamConsoleInputProps {
1818
onKeyDown: (e: KeyboardEvent<HTMLTextAreaElement>) => void;
1919
}
2020

21-
export function StreamConsoleInput({
21+
export function ConsoleInput({
2222
input,
2323
disabled,
2424
onChange,
2525
onSubmit,
2626
onExpand,
2727
onKeyDown,
28-
}: StreamConsoleInputProps) {
28+
}: ConsoleInputProps) {
2929
return (
3030
<div className="flex items-center gap-1.5">
3131
<Textarea

apps/web/src/features/stream/components/stream-output.tsx renamed to apps/web/src/features/console/components/console-output.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
import type { StreamEntry, StreamType } from '../types';
21
import { Card } from '@/features/shared/components/ui/card';
32
import { cn } from '@/lib/utils/cn';
43
import { useEffect, useRef } from 'react';
4+
import type { ConsoleEntry, ConsoleType } from '../types';
55

6-
interface StreamOutputProps {
7-
entries: StreamEntry[];
6+
interface ConsoleOutputProps {
7+
entries: ConsoleEntry[];
88
emptyMessage: string;
99
showTimestamp: boolean;
1010
autoScroll: boolean;
11-
getEntryColor: (type: StreamType) => string;
11+
getEntryColor: (type: ConsoleType) => string;
1212
}
1313

14-
export function StreamOutput({
14+
export function ConsoleOutput({
1515
entries,
1616
emptyMessage,
1717
showTimestamp,
1818
autoScroll,
1919
getEntryColor,
20-
}: StreamOutputProps) {
20+
}: ConsoleOutputProps) {
2121
const scrollContainerRef = useRef<HTMLDivElement>(null);
2222
const bottomRef = useRef<HTMLDivElement>(null);
2323

apps/web/src/features/stream/components/stream-console-toolbar.tsx renamed to apps/web/src/features/console/components/console-toolbar.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
} from 'lucide-react';
2121
import type { KeyboardEvent } from 'react';
2222

23-
interface StreamConsoleToolbarProps {
23+
interface ConsoleToolbarProps {
2424
input: string;
2525
disabled: boolean;
2626
entryCount: number;
@@ -37,7 +37,7 @@ interface StreamConsoleToolbarProps {
3737
onClear: () => void;
3838
}
3939

40-
export function StreamConsoleToolbar({
40+
export function ConsoleToolbar({
4141
input,
4242
disabled,
4343
entryCount,
@@ -52,7 +52,7 @@ export function StreamConsoleToolbar({
5252
onToggleAutoscroll,
5353
onCopy,
5454
onClear,
55-
}: StreamConsoleToolbarProps) {
55+
}: ConsoleToolbarProps) {
5656
return (
5757
<div className="flex flex-col gap-1.5">
5858
<div className="flex items-start gap-1.5">

apps/web/src/features/stream/components/stream-console.tsx renamed to apps/web/src/features/console/components/console.tsx

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,47 @@
11
import { m } from '@/paraglide/messages';
22
import { useState } from 'react';
33
import type { KeyboardEvent } from 'react';
4-
import { useStream } from '../stream-context';
4+
import { useConsole } from '../console-context';
55
import { sendToDeviceStr } from '@/features/jac-device/lib/connection';
66
import { useJacDevice } from '@/features/jac-device';
77
import { Card } from '@/features/shared/components/ui/card';
88
import { KeyValueDisplay } from '@/features/keyValue';
9-
import { getStreamEntryColor } from '../stream-utils';
10-
import { StreamConsoleInput } from './stream-console-input';
11-
import { StreamConsoleToolbar } from './stream-console-toolbar';
12-
import { StreamOutput } from './stream-output';
9+
import { ConsoleInput } from './console-input';
10+
import { ConsoleToolbar } from './console-toolbar';
11+
import { ConsoleOutput } from './console-output';
12+
import type { ConsoleType } from '../types';
1313

14-
interface StreamConsoleProps {
14+
interface ConsoleProps {
1515
displayKeyValue?: boolean;
1616
tooltipCollapsed?: boolean;
1717
}
1818

19-
export function StreamConsole({
19+
export function Console({
2020
displayKeyValue = true,
2121
tooltipCollapsed = false,
22-
}: StreamConsoleProps) {
23-
const { state, actions } = useStream();
24-
const { state: jacState } = useJacDevice();
25-
const { device } = jacState;
22+
}: ConsoleProps) {
23+
const { state, actions } = useConsole();
24+
const {
25+
state: { device },
26+
} = useJacDevice();
2627
const [input, setInput] = useState('');
2728
const [showTimestamp, setShowTimestamp] = useState(true);
2829
const [autoScroll, setAutoScroll] = useState(true);
2930
const [copied, setCopied] = useState(false);
3031
const [isToolbarCollapsed, setIsToolbarCollapsed] =
3132
useState(tooltipCollapsed);
3233

34+
function getStreamEntryColor(type: ConsoleType): string {
35+
switch (type) {
36+
case 'in':
37+
return 'text-foreground';
38+
case 'out':
39+
return 'text-foreground';
40+
case 'err':
41+
return 'text-red-400';
42+
}
43+
}
44+
3345
async function handleMessage(message: string) {
3446
if (!device) return;
3547
sendToDeviceStr(device, message + '\n', actions.addEntry);
@@ -50,7 +62,7 @@ export function StreamConsole({
5062
};
5163

5264
const handleCopyToClipboard = async () => {
53-
const content = state.consoleEntries
65+
const content = state.entries
5466
.map(entry => {
5567
const timestamp = showTimestamp
5668
? `[${entry.timestamp.toLocaleTimeString()}] `
@@ -72,7 +84,7 @@ export function StreamConsole({
7284
<div className="flex h-full flex-col gap-1.5 p-1.5">
7385
<Card className="p-1.5">
7486
{isToolbarCollapsed ? (
75-
<StreamConsoleInput
87+
<ConsoleInput
7688
input={input}
7789
disabled={!device}
7890
onChange={setInput}
@@ -81,10 +93,10 @@ export function StreamConsole({
8193
onKeyDown={handleKeyDown}
8294
/>
8395
) : (
84-
<StreamConsoleToolbar
96+
<ConsoleToolbar
8597
input={input}
8698
disabled={!device}
87-
entryCount={state.consoleEntries.length}
99+
entryCount={state.entries.length}
88100
showTimestamp={showTimestamp}
89101
autoScroll={autoScroll}
90102
copied={copied}
@@ -102,8 +114,8 @@ export function StreamConsole({
102114

103115
{displayKeyValue && <KeyValueDisplay />}
104116

105-
<StreamOutput
106-
entries={state.consoleEntries}
117+
<ConsoleOutput
118+
entries={state.entries}
107119
emptyMessage={m.terminal_console_empty()}
108120
showTimestamp={showTimestamp}
109121
autoScroll={autoScroll}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type { KeyValueMap } from '@/features/keyValue';
2+
import { createContext, useContext } from 'react';
3+
import type { AddToConsole, ConsoleEntry, ConsoleType } from './types';
4+
5+
export interface ConsoleState {
6+
entries: ConsoleEntry[];
7+
keyValueEntries: KeyValueMap;
8+
}
9+
10+
export interface ConsoleActions {
11+
addEntry: AddToConsole;
12+
clear(): void;
13+
clearType(type: ConsoleType): void;
14+
}
15+
16+
export interface ConsoleMeta {
17+
channel: string;
18+
}
19+
20+
export interface ConsoleContextValue {
21+
state: ConsoleState;
22+
actions: ConsoleActions;
23+
meta: ConsoleMeta;
24+
}
25+
26+
export const ConsoleContext = createContext<ConsoleContextValue | null>(null);
27+
28+
export function useConsole(): ConsoleContextValue {
29+
const context = useContext(ConsoleContext);
30+
if (!context) {
31+
throw new Error('Console.* components must be within Console.Provider');
32+
}
33+
return context;
34+
}
Lines changed: 20 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import type { StreamBusService } from '@/services/stream-bus-service';
2-
import { StreamTelemetryService } from '@/features/stream/services/stream-telemetry-service';
1+
import type { ConsoleBusService } from '@/services/console-bus-service';
32
import type { KeyValueMap } from '@/features/keyValue';
43
import {
54
useCallback,
@@ -8,30 +7,30 @@ import {
87
useState,
98
type ReactNode,
109
} from 'react';
11-
import { type AddToStream, type StreamEntry, type StreamType } from './types';
12-
import { isConsoleStream, isLogStream } from './stream-utils';
1310
import {
14-
streamLogKeys,
15-
StreamContext,
16-
type StreamContextValue,
17-
} from './stream-context';
11+
type AddToConsole,
12+
type ConsoleEntry,
13+
type ConsoleType,
14+
} from './types';
15+
import { ConsoleContext, type ConsoleContextValue } from './console-context';
16+
import { ConsoleTelemetryService } from './services/console-telemetry-service';
1817

19-
const defaultTelemetryService = new StreamTelemetryService();
18+
const defaultTelemetryService = new ConsoleTelemetryService();
2019

21-
export interface StreamProviderProps {
20+
export interface ConsoleProviderProps {
2221
channel: string;
23-
streamBusService: StreamBusService;
24-
telemetryService?: StreamTelemetryService;
22+
streamBusService: ConsoleBusService;
23+
telemetryService?: ConsoleTelemetryService;
2524
children: ReactNode;
2625
}
2726

28-
export function StreamProvider({
27+
export function ConsoleProvider({
2928
channel,
3029
streamBusService,
3130
telemetryService = defaultTelemetryService,
3231
children,
33-
}: StreamProviderProps) {
34-
const [entries, setEntries] = useState<StreamEntry[]>([]);
32+
}: ConsoleProviderProps) {
33+
const [entries, setEntries] = useState<ConsoleEntry[]>([]);
3534
const [keyValueEntries, setKeyValueEntries] = useState<KeyValueMap>({});
3635

3736
useEffect(() => {
@@ -53,7 +52,7 @@ export function StreamProvider({
5352
[channel, streamBusService]
5453
);
5554

56-
const addEntry = useCallback<AddToStream>(
55+
const addEntry = useCallback<AddToConsole>(
5756
(type, content) => {
5857
const charMapEntry = charMapCallback[content.trim()];
5958
if (charMapEntry) {
@@ -70,7 +69,7 @@ export function StreamProvider({
7069
}, [channel, streamBusService]);
7170

7271
const clearType = useCallback(
73-
(type: StreamType) => {
72+
(type: ConsoleType) => {
7473
const filtered = entries.filter(entry => entry.type !== type);
7574
streamBusService.clear(channel);
7675
for (const entry of filtered) {
@@ -80,22 +79,11 @@ export function StreamProvider({
8079
[entries, channel, streamBusService]
8180
);
8281

83-
const consoleEntries = useMemo(
84-
() => entries.filter(entry => isConsoleStream(entry.type)),
85-
[entries]
86-
);
87-
88-
const logEntries = useMemo(
89-
() => entries.filter(entry => isLogStream(entry.type)),
90-
[entries]
91-
);
92-
9382
// TODO: do I need to memoize this? Is React compiler smart enough to not re-render it incorrectly?
94-
const value = useMemo<StreamContextValue>(
83+
const value = useMemo<ConsoleContextValue>(
9584
() => ({
9685
state: {
97-
consoleEntries,
98-
logEntries,
86+
entries,
9987
keyValueEntries,
10088
},
10189
actions: {
@@ -105,21 +93,12 @@ export function StreamProvider({
10593
},
10694
meta: {
10795
channel,
108-
logKeys: streamLogKeys,
10996
},
11097
}),
111-
[
112-
consoleEntries,
113-
logEntries,
114-
keyValueEntries,
115-
addEntry,
116-
clear,
117-
clearType,
118-
channel,
119-
]
98+
[entries, keyValueEntries, addEntry, clear, clearType, channel]
12099
);
121100

122101
return (
123-
<StreamContext.Provider value={value}>{children}</StreamContext.Provider>
102+
<ConsoleContext.Provider value={value}>{children}</ConsoleContext.Provider>
124103
);
125104
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export { useConsole } from './console-context';
2+
export type { ConsoleContextValue } from './console-context';
3+
export { ConsoleProvider } from './console-provider';
4+
export type { ConsoleProviderProps } from './console-provider';
5+
export type { AddToConsole, ConsoleEntry, ConsoleType } from './types';
6+
7+
import { ConsoleProvider } from './console-provider';
8+
import { Console as ConsoleComponent } from './components/console';
9+
10+
export const Console = {
11+
Provider: ConsoleProvider,
12+
Console: ConsoleComponent,
13+
};

apps/web/src/features/stream/services/stream-telemetry-service.ts renamed to apps/web/src/features/console/services/console-telemetry-service.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import type { KeyValueMap } from '@/features/keyValue/lib/types';
22
import { parseKeyValue } from '@/features/keyValue/lib/parser/kvParser';
3-
import type { StreamEntry } from '@/features/stream/types';
3+
import type { ConsoleEntry } from '@/features/console/types';
44

5-
export class StreamTelemetryService {
6-
extractKeyValuePairs(entries: StreamEntry[]): KeyValueMap {
5+
export class ConsoleTelemetryService {
6+
extractKeyValuePairs(entries: ConsoleEntry[]): KeyValueMap {
77
return entries
8-
.filter(
9-
entry => entry.type === 'console-out' || entry.type === 'console-err'
10-
)
8+
.filter(entry => entry.type === 'out' || entry.type === 'err')
119
.reduce<KeyValueMap>((acc, entry) => {
1210
const parsed = parseKeyValue(entry.content);
1311
return { ...acc, ...parsed };
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export type ConsoleType = 'in' | 'out' | 'err';
2+
3+
export interface ConsoleEntry {
4+
timestamp: Date;
5+
type: ConsoleType;
6+
content: string;
7+
}
8+
9+
export type AddToConsole = (type: ConsoleType, content: string) => void;

apps/web/src/features/jac-device/components/controls/connection-selector.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import type {
1919
import { enqueueSnackbar } from 'notistack';
2020
import { ButtonGroup } from '@/features/shared/components/ui/button-group';
2121
import { useJacDevice } from '@/features/jac-device';
22-
import { useStream } from '@/features/stream';
22+
import { useConsole } from '@/features/console';
2323
import { useActiveProject } from '@/features/project/active-project';
2424
import { testConnection, uploadCode } from '@/features/jac-device/lib/device';
2525
import { useProjectEditor } from '@/features/project/editor';
@@ -36,7 +36,7 @@ export function ConnectionSelector() {
3636
>([]);
3737
const {
3838
actions: { addEntry },
39-
} = useStream();
39+
} = useConsole();
4040
const { state: jacState, actions: jacActions } = useJacDevice();
4141
const { connectionStatus, jacProject } = jacState;
4242
const { setDevice, setConnectionStatus } = jacActions;

0 commit comments

Comments
 (0)