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 ` but here are the most
28
- important ones :
32
+ All our dependencies are described in ` site/package.json ` but the following 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/ ) as the 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** - API code 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** - Static UI 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 folder so we can better
78
- group the views, tests, utility functions and so 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 folder to group relevant
85
+ views, tests, and utility 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 placed inside of
98
- the api/queries folder when it is possible .
101
+ to fetch data from the API. Queries and mutation should be placed in 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
0 commit comments