Skip to content

Commit a8ffe72

Browse files
committed
V1.2.0
1 parent 17cf979 commit a8ffe72

File tree

10 files changed

+504
-90
lines changed

10 files changed

+504
-90
lines changed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
![npm](https://img.shields.io/npm/dy/remix-development-tools?style=plastic)
77
![GitHub top language](https://img.shields.io/github/languages/top/Code-Forge-Net/Remix-Dev-Tools?style=plastic)
88

9-
Remix Development Tools is an open-source package designed to enhance your development workflow when working with Remix, a full-stack JavaScript framework for building web applications. This package provides a user-friendly interface consisting of two tabs, **Active Page** and **Routes**, along with a side tab called **Timeline**. With Remix Development Tools, you can efficiently monitor and manage various aspects of your Remix projects, including page information, URL parameters, server responses, loader data, routes, and more.
9+
Remix Development Tools is an open-source package designed to enhance your development workflow when working with Remix, a full-stack JavaScript framework for building web applications. This package provides a user-friendly interface consisting of three tabs, **Active Page**, **Terminal** and **Routes**, along with a side tab called **Timeline**. With Remix Development Tools, you can efficiently monitor and manage various aspects of your Remix projects, including page information, URL parameters, server responses, loader data, routes, and more.
1010

1111
## Features
1212

@@ -34,6 +34,15 @@ The **Routes** tab enables you to manage and explore the routes within your Remi
3434

3535
The **Timeline** side tab provides a timeline view of events occurring during the development process. This tab helps you track the sequence of actions and events, providing valuable insights into the execution flow of your application.
3636

37+
### Terminal tab
38+
39+
The terminal tab allows you to run terminal commands from the Remix Dev Tools. This is useful for running commands like `npm run typecheck` or `npm run lint:fix` without having to switch to the terminal in VS code. The tab requires you to connect to Remix Forge VS Code extension to work properly.
40+
41+
You can press `Arrow Up` and `Arrow Down` to cycle through the history of commands you have run in the terminal.
42+
You can press `Arrow Left` and `Arrow Right` to cycle through all available commands in your projects package.json file.
43+
You can press `Ctrl + C` to cancel the current command.
44+
You can press `Ctrl + L` to clear the terminal.
45+
3746
## Getting Started
3847

3948
To install and utilize Remix Development Tools, follow these steps:

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "remix-development-tools",
33
"description": "Remix development tools.",
44
"author": "Alem Tuzlak",
5-
"version": "1.1.3",
5+
"version": "1.2.0",
66
"license": "MIT",
77
"keywords": [
88
"remix",

src/RemixDevTools/context/rdtReducer.ts

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { TimelineEvent } from "./timeline";
22
import type { Tabs } from "../tabs";
3+
import { Terminal } from "./terminal";
34

45
export type RouteWildcards = Record<string, Record<string, string> | undefined>;
56

67
export type RemixDevToolsState = {
78
timeline: TimelineEvent[];
89
showRouteBoundaries?: boolean;
10+
terminals: Terminal[];
911
settings: {
1012
routeWildcards: RouteWildcards;
1113
activeTab: Tabs;
@@ -18,6 +20,7 @@ export type RemixDevToolsState = {
1820
export const initialState: RemixDevToolsState = {
1921
timeline: [],
2022
showRouteBoundaries: false,
23+
terminals: [{ id: 0, locked: false, output: [], history: [] }],
2124
settings: {
2225
routeWildcards: {},
2326
activeTab: "timeline",
@@ -35,11 +38,52 @@ type SetTimelineEvent = {
3538
payload: TimelineEvent;
3639
};
3740

41+
type ToggleTerminalLock = {
42+
type: "TOGGLE_TERMINAL_LOCK";
43+
payload: {
44+
terminalId: Terminal["id"];
45+
locked?: boolean;
46+
};
47+
};
48+
49+
type AddOrRemoveTerminal = {
50+
type: "ADD_OR_REMOVE_TERMINAL";
51+
payload?: Terminal["id"];
52+
};
53+
54+
type AddTerminalOutput = {
55+
type: "ADD_TERMINAL_OUTPUT";
56+
payload: {
57+
terminalId: Terminal["id"];
58+
output: Terminal["output"][number];
59+
};
60+
};
61+
62+
type AddTerminalHistory = {
63+
type: "ADD_TERMINAL_HISTORY";
64+
payload: {
65+
terminalId: Terminal["id"];
66+
history: Terminal["history"][number];
67+
};
68+
};
69+
70+
type ClearTerminalOutput = {
71+
type: "CLEAR_TERMINAL_OUTPUT";
72+
payload: Terminal["id"];
73+
};
74+
3875
type SetActiveTab = {
3976
type: "SET_ACTIVE_TAB";
4077
payload: Tabs;
4178
};
4279

80+
type SetProcessId = {
81+
type: "SET_PROCESS_ID";
82+
payload: {
83+
terminalId: Terminal["id"];
84+
processId?: number;
85+
};
86+
};
4387
type SetDevToolsHeight = {
4488
type: "SET_HEIGHT";
4589
payload: number;
@@ -68,7 +112,13 @@ type SetShouldConnectToForgeAction = {
68112
/** Aggregate of all action types */
69113
export type RemixDevToolsActions =
70114
| SetTimelineEvent
115+
| ToggleTerminalLock
116+
| AddOrRemoveTerminal
117+
| AddTerminalOutput
118+
| ClearTerminalOutput
119+
| AddTerminalHistory
71120
| SetActiveTab
121+
| SetProcessId
72122
| PurgeTimeline
73123
| SetRouteWildcards
74124
| SetDevToolsHeight
@@ -120,7 +170,97 @@ export const rdtReducer = (
120170
height: payload,
121171
},
122172
};
173+
case "SET_PROCESS_ID":
174+
return {
175+
...state,
176+
terminals: state.terminals.map((terminal) => {
177+
if (terminal.id === payload.terminalId) {
178+
return {
179+
...terminal,
180+
processId: payload.processId,
181+
};
182+
}
183+
return terminal;
184+
}),
185+
};
186+
case "TOGGLE_TERMINAL_LOCK":
187+
return {
188+
...state,
189+
terminals: state.terminals.map((terminal) => {
190+
if (terminal.id === payload.terminalId) {
191+
return {
192+
...terminal,
193+
locked: payload.locked ?? !terminal.locked,
194+
};
195+
}
196+
return terminal;
197+
}),
198+
};
199+
case "ADD_OR_REMOVE_TERMINAL": {
200+
const terminalExists = state.terminals.some(
201+
(terminal) => terminal.id === payload
202+
);
203+
if (terminalExists) {
204+
return {
205+
...state,
206+
terminals: state.terminals
207+
.filter((terminal) => terminal.id !== payload)
208+
.map((terminal, i) => ({ ...terminal, id: i })),
209+
};
210+
}
211+
return {
212+
...state,
213+
terminals: [
214+
...state.terminals,
215+
{
216+
id: state.terminals.length,
217+
locked: false,
218+
history: [],
219+
output: [],
220+
},
221+
],
222+
};
223+
}
224+
case "ADD_TERMINAL_OUTPUT":
225+
return {
226+
...state,
227+
terminals: state.terminals.map((terminal) => {
228+
if (terminal.id === payload.terminalId) {
229+
return {
230+
...terminal,
231+
output: [...terminal.output, payload.output],
232+
};
233+
}
234+
return terminal;
235+
}),
236+
};
237+
case "CLEAR_TERMINAL_OUTPUT":
238+
return {
239+
...state,
240+
terminals: state.terminals.map((terminal) => {
241+
if (terminal.id === payload) {
242+
return {
243+
...terminal,
244+
output: [],
245+
};
246+
}
247+
return terminal;
248+
}),
249+
};
123250

251+
case "ADD_TERMINAL_HISTORY":
252+
return {
253+
...state,
254+
terminals: state.terminals.map((terminal) => {
255+
if (terminal.id === payload.terminalId) {
256+
return {
257+
...terminal,
258+
history: [...terminal.history, payload.history],
259+
};
260+
}
261+
return terminal;
262+
}),
263+
};
124264
case "SET_SHOULD_CONNECT_TO_FORGE":
125265
return {
126266
...state,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export interface TerminalOutput {
2+
type: "output" | "command" | "error";
3+
value: string;
4+
}
5+
6+
export interface Terminal {
7+
id: number;
8+
locked: boolean;
9+
history: string[];
10+
output: TerminalOutput[];
11+
processId?: number;
12+
}

src/RemixDevTools/context/useRDTContext.ts

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ import { RDTContext, REMIX_DEV_TOOLS } from "./RDTContext";
33
import { TimelineEvent } from "./timeline";
44
import { Tabs } from "../tabs";
55
import { RouteWildcards } from "./rdtReducer";
6+
import { Terminal } from "./terminal";
67

78
const useRDTContext = () => {
89
const context = useContext(RDTContext);
910
if (context === undefined) {
1011
throw new Error("useRDTContext must be used within a RDTContextProvider");
1112
}
1213
const { state, dispatch } = context;
13-
const { timeline, settings, showRouteBoundaries } = state;
14+
const { timeline, settings, showRouteBoundaries, terminals } = state;
1415
const { activeTab, shouldConnectWithForge, routeWildcards, port, height } =
1516
settings;
1617

@@ -45,6 +46,40 @@ const useRDTContext = () => {
4546
},
4647
[dispatch]
4748
);
49+
const addOrRemoveTerminal = useCallback(
50+
(terminalId?: Terminal["id"]) => {
51+
dispatch({ type: "ADD_OR_REMOVE_TERMINAL", payload: terminalId });
52+
},
53+
[dispatch]
54+
);
55+
56+
const toggleTerminalLock = useCallback(
57+
(terminalId: Terminal["id"], locked?: boolean) => {
58+
dispatch({
59+
type: "TOGGLE_TERMINAL_LOCK",
60+
payload: { terminalId, locked },
61+
});
62+
},
63+
[dispatch]
64+
);
65+
66+
const addTerminalOutput = useCallback(
67+
(terminalId: Terminal["id"], output: Terminal["output"][number]) => {
68+
dispatch({
69+
type: "ADD_TERMINAL_OUTPUT",
70+
payload: { terminalId, output },
71+
});
72+
},
73+
[dispatch]
74+
);
75+
76+
const clearTerminalOutput = useCallback(
77+
(terminalId: Terminal["id"]) => {
78+
dispatch({ type: "CLEAR_TERMINAL_OUTPUT", payload: terminalId });
79+
},
80+
[dispatch]
81+
);
82+
4883
const setShouldConnectWithForge = useCallback(
4984
(shouldConnectWithForge: boolean) => {
5085
dispatch({
@@ -55,6 +90,15 @@ const useRDTContext = () => {
5590
[dispatch]
5691
);
5792

93+
const addTerminalHistory = useCallback(
94+
(terminalId: Terminal["id"], history: Terminal["history"][number]) => {
95+
dispatch({
96+
type: "ADD_TERMINAL_HISTORY",
97+
payload: { terminalId, history },
98+
});
99+
},
100+
[dispatch]
101+
);
58102
const setHeight = useCallback(
59103
(height: number) => {
60104
dispatch({
@@ -64,6 +108,15 @@ const useRDTContext = () => {
64108
},
65109
[dispatch]
66110
);
111+
const setProcessId = useCallback(
112+
(terminalId: Terminal["id"], processId?: number) => {
113+
dispatch({
114+
type: "SET_PROCESS_ID",
115+
payload: { terminalId, processId },
116+
});
117+
},
118+
[dispatch]
119+
);
67120

68121
return {
69122
setTimelineEvent,
@@ -79,6 +132,13 @@ const useRDTContext = () => {
79132
showRouteBoundaries,
80133
setHeight,
81134
setRouteWildcards,
135+
terminals,
136+
addOrRemoveTerminal,
137+
toggleTerminalLock,
138+
addTerminalOutput,
139+
clearTerminalOutput,
140+
addTerminalHistory,
141+
setProcessId,
82142
};
83143
};
84144

0 commit comments

Comments
 (0)