1
1
#Frontend
2
2
3
- This is a guide to help the Coder community and also Coder members contribute to
4
- our UI. It is ongoing work but we hope it provides some useful information to
5
- get started. If you have any questions or need help, please send us a message on
6
- our[ Discord server] ( https://discord.com/invite/coder ) . We'll be happy to help
3
+ Welcome to the guide for contributing to the Coder frontend. Whether you’re part
4
+ of the community or a Coder team member, this documentation will help you get
5
+ started.
6
+
7
+ If you have any questions, feel free to reach out on our
8
+ [ Discord server] ( https://discord.com/invite/coder ) , and we’ll be happy to assist
7
9
you.
8
10
9
11
##Running the UI
10
12
11
- You can run the UI and access the dashboard in two ways:
13
+ You can run the UI and access the Coder dashboard in two ways:
14
+
15
+ 1 . Build the UI pointing to an external Coder server:
16
+ ` CODER_HOST=https://mycoder.com pnpm dev ` inside of the` site ` folder. This
17
+ is helpful when you are building something in the UI and already have the
18
+ data on your deployed server.
19
+ 2 . Build the entire Coder server + UI locally:` ./scripts/develop.sh ` in the
20
+ root folder. This is useful for contributing to features that are not
21
+ deployed yet or that involve both the frontend and backend.
12
22
13
- - Build the UI pointing to an external Coder server:
14
- ` CODER_HOST=https://mycoder.com pnpm dev ` inside of the` site ` folder. This is
15
- helpful when you are building something in the UI and already have the data on
16
- your deployed server.
17
- - Build the entire Coder server + UI locally:` ./scripts/develop.sh ` in the root
18
- folder. It is useful when you have to contribute with features that are not
19
- deployed yet or when you have to work on both, frontend and backend.
23
+ In both cases, you can access the dashboard on` http://localhost:8080 ` . If using
24
+ ` ./scripts/develop.sh ` you can log in with the default credentials.
20
25
21
- In both cases, you can access the dashboard on ` http://localhost:8080 ` . If you
22
- are running the ` ./scripts/develop.sh ` you can log in using the default
23
- credentials: ` admin@coder.com ` and` SomeSecurePassword! ` .
26
+ > [ !TIP ]
27
+ >
28
+ > ** Default Credentials: ** ` admin@coder.com ` and` SomeSecurePassword! ` .
24
29
25
- ##Tech Stack
30
+ ##Tech Stack Overview
26
31
27
- All our dependencies are described in` site/package.json ` buthere are themost
28
- important ones :
32
+ All our dependencies are described in` site/package.json ` but thefollowing are
33
+ the most important :
29
34
30
- - [ React] ( https://reactjs.org/ ) as framework
35
+ - [ React] ( https://reactjs.org/ ) for the UI framework
31
36
- [ Typescript] ( https://www.typescriptlang.org/ ) to keep our sanity
32
37
- [ Vite] ( https://vitejs.dev/ ) to build the project
33
38
- [ Material V5] ( https://mui.com/material-ui/getting-started/ ) for UI components
@@ -39,63 +44,62 @@ important ones:
39
44
- [ Jest] ( https://jestjs.io/ ) for integration testing
40
45
- [ Storybook] ( https://storybook.js.org/ ) and
41
46
[ Chromatic] ( https://www.chromatic.com/ ) for visual testing
42
- - [ PNPM] ( https://pnpm.io/ ) as package manager
47
+ - [ PNPM] ( https://pnpm.io/ ) asthe package manager
43
48
44
49
##Structure
45
50
46
- All the code related to the UI is inside the` site ` folder and we defined a few
47
- conventions to help people to navigate through it.
51
+ All UI-related code is in the` site ` folder. Key directories include:
48
52
49
53
- ** e2e** - End-to-end (E2E) tests
50
54
- ** src** - Source code
51
55
- ** mocks** -[ Manual mocks] ( https://jestjs.io/docs/manual-mocks ) used by Jest
52
56
- ** @types ** - Custom types for dependencies that don't have defined types
53
57
(largely code that has no server-side equivalent)
54
- - ** api** - APIcode as function calls and types
58
+ - ** api** - API function calls and types
55
59
- ** queries** - react-query queries and mutations
56
- - ** components** - UI components
57
- - ** hooks** - Hooks that can be used across the application
58
- - ** pages** - Page components
59
- - ** testHelpers** - Helper functions to help with integration tests
60
+ - ** components** - Reusable UI components without Coder specific business
61
+ logic
62
+ - ** hooks** - Custom React hooks
63
+ - ** modules** - Coder-specific UI components
64
+ - ** pages** - Page-level components
65
+ - ** testHelpers** - Helper functions for integration testing
66
+ - ** theme** - theme configuration and color definitions
60
67
- ** util** - Helper functions that can be used across the application
61
- - ** static** - StaticUI assets like images, fonts, icons, etc
68
+ - ** static** - Static assets like images, fonts, icons, etc
62
69
63
70
##Routing
64
71
65
- We use[ react-router] ( https://reactrouter.com/en/main ) as our routing engine and
66
- adding a new route is very easy. If the new route needs to be authenticated, put
67
- it under the` <RequireAuth> ` route and if it needs to live inside of the
68
- dashboard, put it under the` <DashboardLayout> ` route.
72
+ We use[ react-router] ( https://reactrouter.com/en/main ) as our routing engine.
69
73
70
- The` RequireAuth ` component handles all the authentication logic for the routes
71
- and the` DashboardLayout ` wraps the route adding a navbar and passing down
72
- common dashboard data.
74
+ - Authenticated routes - Place routes requiring authentication inside the
75
+ ` <RequireAuth> ` route. The` RequireAuth ` component handles all the
76
+ authentication logic for the routes.
77
+ - Dashboard routes - routes that live in the dashboard should be placed under
78
+ the` <DashboardLayout> ` route. The` DashboardLayout ` adds a navbar and passes
79
+ down common dashboard data.
73
80
74
81
##Pages
75
82
76
- Pages are the top-level components of the app. The page component lives under
77
- the ` src/pages ` folder and each page should have its own folderso we can better
78
- group the views, tests,utility functions andso on. We use a structure where
79
- the page component is responsible for fetching all the data and passing it down
80
- to the view. We explain this decision a bit better in the next section .
83
+ Page components are the top-level components of the app and reside in the
84
+ ` src/pages ` folder. Each page should have its own folderto group relevant
85
+ views, tests, andutility functions. The page component fetches necessary data
86
+ and passes to the view. We explain this decision a bit better in the next
87
+ section which talks about where to fetch data .
81
88
82
- > ℹ️ Code that is only related to the page should live inside of the page folder
83
- > but if at some point it is used in other pages or components, you should
84
- > consider moving it to the` src ` level in the` utils ` ,` hooks ` or` components `
85
- > folder.
89
+ > ℹ️ If code within a page becomes reusable across other parts of the app,
90
+ > consider moving it to` src/utils ` ,` hooks ` ,` components ` , or` modules ` .
86
91
87
- ###States
92
+ ###Handling States
88
93
89
- A page usually has at least three states:** loading** ,** ready** /** success** ,
90
- and** error** , so always remember to handle these scenarios while you are coding
91
- a page. We also encourage you to add visual testing for these three states using
92
- a` *.stories.ts ` file.
94
+ A page typically has three states:** loading** ,** ready** /** success** , and
95
+ ** error** . Ensure you manage these states when developing pages. Use visual
96
+ tests for these states with` *.stories.ts ` files.
93
97
94
- ##Fetching data
98
+ ##Data Fetching
95
99
96
100
We use[ TanStack Query v4] ( https://tanstack.com/query/v4/docs/react/quick-start )
97
- to fetch data from the API.The queries and mutation should be placedinside of
98
- the api/queries folder when it is possible .
101
+ to fetch data from the API.Queries and mutation should be placedin the
102
+ api/queries folder.
99
103
100
104
###Where to fetch data
101
105
@@ -141,12 +145,14 @@ export const WithQuota: Story = {
141
145
142
146
###API
143
147
144
- We are using[ axios] ( https://github.com/axios/axios ) as our fetching library and
145
- writing the API functions in the` site/src/api/api.ts ` files. We also have
146
- auto-generated types from our Go server on` site/src/api/typesGenerated.ts ` .
147
- Usually, every endpoint has its own` Request ` and` Response ` types, but
148
- sometimes you need to pass extra parameters to make the call, like in the
149
- example below:
148
+ Our project uses[ axios] ( https://github.com/axios/axios ) as the HTTP client for
149
+ making API requests. The API functions are centralized in` site/src/api/api.ts ` .
150
+ Auto-generated TypeScript types derived from our Go server are located in
151
+ ` site/src/api/typesGenerated.ts ` .
152
+
153
+ Typically, each API endpoint corresponds to its own` Request ` and` Response `
154
+ types. However, some endpoints require additional parameters for successful
155
+ execution. Here's an illustrative example:"
150
156
151
157
``` ts
152
158
export const getAgentListeningPorts= async (
@@ -159,8 +165,8 @@ export const getAgentListeningPorts = async (
159
165
};
160
166
```
161
167
162
- Sometimes, a frontend operation can have multiple API calls, so it is okay to
163
- wrap it as a single function.
168
+ Sometimes, a frontend operation can have multiple API calls which can be wrapped
169
+ as a single function.
164
170
165
171
``` ts
166
172
export const updateWorkspaceVersion= async (
@@ -171,10 +177,13 @@ export const updateWorkspaceVersion = async (
171
177
};
172
178
```
173
179
174
- If you need more granular errors or control, you may should consider keep them
175
- separated and use XState for that.
180
+ ##Components and Modules
176
181
177
- ##Components
182
+ Components should be atomic, reusable and free of business logic. Modules are
183
+ similar to components except that they can be more complex and can contain
184
+ business logic specific to the product.
185
+
186
+ ###MUI
178
187
179
188
The codebase is currently using MUI v5. Please see the
180
189
[ official documentation] ( https://mui.com/material-ui/getting-started/ ) . In
@@ -184,8 +193,9 @@ out of the box.
184
193
185
194
###Structure
186
195
187
- Each component gets its own folder. Make sure you add a test and Storybook
188
- stories for the component as well. By keeping these tidy, the codebase will
196
+ Each component and module gets its own folder. Module folders may group multiple
197
+ files in a hierarchical structure. Storybook stories and component tests using
198
+ Storybook interactions are required. By keeping these tidy, the codebase will
189
199
remain easy to navigate, healthy and maintainable for all contributors.
190
200
191
201
###Accessibility
@@ -221,13 +231,32 @@ import { visuallyHidden } from "@mui/utils";
221
231
</Button >;
222
232
```
223
233
224
- ###Should I create a new component?
234
+ ###Should I create a new component or module?
235
+
236
+ Components could technically be used in any codebase and still feel at home. A
237
+ module would only make sense in the Coder codebase.
238
+
239
+ - Component
240
+ - Simple
241
+ - Atomic, used in multiple places
242
+ - Generic, would be useful as a component outside of the Coder product
243
+ - Good Examples:` Badge ` ,` Form ` ,` Timeline `
244
+ - Module
245
+ - Simple or Complex
246
+ - Used in multiple places
247
+ - Good Examples:` Provisioner ` ,` DashboardLayout ` ,` DeploymentBanner `
225
248
226
- As with most things in the world, it depends. If you are creating a new
227
- component to encapsulate some UI abstraction like` UsersTable ` it is ok but you
228
- should always try to use the base components that are provided by the library or
229
- from the codebase. It's recommended that you always do a quick search before
230
- creating a custom primitive component like dialogs, popovers, buttons, etc.
249
+ Our codebase has some legacy components that are being updated to follow these
250
+ new conventions, but all new components should follow these guidelines.
251
+
252
+ ##Styling
253
+
254
+ We use[ Emotion] ( https://emotion.sh/ ) to handle css styles.
255
+
256
+ ##Forms
257
+
258
+ We use[ Formik] ( https://formik.org/docs ) for forms along with
259
+ [ Yup] ( https://github.com/jquense/yup ) for schema definition and validation.
231
260
232
261
##Testing
233
262
@@ -293,10 +322,9 @@ that:
293
322
294
323
###Tests getting too slow
295
324
296
- A few times you can notice tests can take a very long time to get done.
297
- Sometimes it is because the test itself is complex and runs a lot of stuff, and
298
- sometimes it is because of how we are querying things. In the next section, we
299
- are going to talk more about them.
325
+ You may have observed that certain tests in our suite can be notably
326
+ time-consuming. Sometimes it is because the test itself is complex and sometimes
327
+ it is because of how the test is querying elements.
300
328
301
329
####Using` ByRole ` queries
302
330
@@ -326,12 +354,6 @@ const form = screen.getByTestId("form");
326
354
user .click (within (form ).getByRole (" button" ));
327
355
```
328
356
329
- ####` jest.spyOn ` with the API is not working
330
-
331
- For some unknown reason, we figured out the` jest.spyOn ` is not able to mock the
332
- API function when they are passed directly into the services XState machine
333
- configuration.
334
-
335
357
❌ Does not work
336
358
337
359
``` ts