Skip to content

Commit de66f0d

Browse files
docs: Add frontend guide (#5852)
1 parent 5c5ddc6 commit de66f0d

File tree

5 files changed

+148
-13
lines changed

5 files changed

+148
-13
lines changed

.vscode/settings.json

+8-1
Original file line numberDiff line numberDiff line change
@@ -198,5 +198,12 @@
198198
"go.testFlags": ["-short", "-coverpkg=./..."],
199199
// We often use a version of TypeScript that's ahead of the version shipped
200200
// with VS Code.
201-
"typescript.tsdk": "./site/node_modules/typescript/lib"
201+
"typescript.tsdk": "./site/node_modules/typescript/lib",
202+
"grammarly.selectors": [
203+
{
204+
"language": "markdown",
205+
"scheme": "file",
206+
"pattern": "docs/contributing/frontend.md"
207+
}
208+
]
202209
}

docs/CONTRIBUTING.md

+1-11
Original file line numberDiff line numberDiff line change
@@ -170,17 +170,7 @@ with a holistic perspective regarding the contribution.
170170

171171
### Frontend
172172

173-
#### Follow component conventions
174-
175-
Each component gets its own folder. Make sure you add a test and Storybook
176-
stories for the component as well. By keeping these tidy, the codebase will
177-
remain easy-to-navigate, healthy and maintainable for all contributors.
178-
179-
#### Keep accessibility in mind
180-
181-
We strive to keep our UI accessible. When using colors, avoid adding new
182-
elements with low color contrast. Always use labels on inputs, not just
183-
placeholders. These are important for screen-readers.
173+
Our frontend guide can be found [here](./contributing/frontend.md).
184174

185175
## Reviews
186176

docs/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# About Coder
22

3-
Coder is an open source platform for creating and managing developer workspaces
3+
Coder is an open-source platform for creating and managing developer workspaces
44
on your preferred clouds and servers.
55

66
<p align="center">

docs/contributing/frontend.md

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Frontend
2+
3+
This is a guide to help the Coder community and also Coder members contribute to our UI. It is ongoing work but we hope it provides some useful information to get started. If you have any questions or need help, please send us a message on our [Discord server](https://discord.com/invite/coder). We'll be happy to help you.
4+
5+
## Tech Stack
6+
7+
All our dependencies are described in `site/package.json` but here are the most important ones:
8+
9+
- [React](https://reactjs.org/) as framework
10+
- [Typescript](https://www.typescriptlang.org/) to keep our sanity
11+
- [Vite](https://vitejs.dev/) to build the project
12+
- [Material V4](https://v4.mui.com/) for UI components
13+
- [react-router](https://reactrouter.com/en/main) for routing
14+
- [TanStack Query v4](https://tanstack.com/query/v4/docs/react/overview) for fetching data
15+
- [XState](https://xstate.js.org/docs/) for handling complex state flows
16+
- [axios](https://github.com/axios/axios) as fetching lib
17+
- [Playwright](https://playwright.dev/) for E2E testing
18+
- [Jest](https://jestjs.io/) for integration testing
19+
- [Storybook](https://storybook.js.org/) and [Chromatic](https://www.chromatic.com/) for visual testing
20+
21+
## Structure
22+
23+
All the code related to the UI is inside the `site` folder and we defined a few conventions to help people to navigate through it.
24+
25+
- **e2e** - E2E tests
26+
- **src** - Source code
27+
- **mocks** - [Manual mocks](https://jestjs.io/docs/manual-mocks) used by Jest
28+
- **@types** - Custom types for dependencies that don't have defined types
29+
- **api** - API code as function calls and types
30+
- **components** - UI components
31+
- **hooks** - Hooks that can be used across the application
32+
- **i18n** - Translations
33+
- **pages** - Page components
34+
- **testHelpers** - Helper functions to help with integration tests
35+
- **util** - Helper functions that can be used across the application
36+
- **xServices** - XState machines used to fetch data and handle complex scenarios
37+
- **static** - UI static assets like images, fonts, icons, etc
38+
39+
## Routing
40+
41+
We use [react-router](https://reactrouter.com/en/main) as our routing engine and adding a new route is very easy. If the new route needs to be authenticated, put it under the `<RequireAuth>` route and if it needs to live inside of the dashboard, put it under the `<DashboardLayout>` route.
42+
43+
The `RequireAuth` component handles all the authentication logic for the routes and the `DashboardLayout` wraps the route adding a navbar and passing down common dashboard data.
44+
45+
## Pages
46+
47+
Pages are the top-level components of the app. The page component lives under the `src/pages` folder and each page should have its own folder so we can better group the views, tests, utility functions and so on. We use a structure where the page component is responsible for fetching all the data and passing it down to the view. We explain this decision a bit better in the next section.
48+
49+
> ℹ️ Code that is only related to the page should live inside of the page folder but if at some point it is used in other pages or components, you should consider moving it to the `src` level in the `utils`, `hooks` or `components` folder.
50+
51+
### States
52+
53+
A page usually has at least three states: **loading**, **ready** or **success**, and **error** so remember to always handle these scenarios while you are coding a page. We also encourage you to add visual testing for these three states using the `*.stories.ts` file.
54+
55+
## Fetching data
56+
57+
We use [TanStack Query v4](https://tanstack.com/query/v4/docs/react/overview)(previously known as react-query) to fetch data from the API. We also use [XState](https://xstate.js.org/docs/) to handle complex flows with multiple states and transitions.
58+
59+
> ℹ️ We recently changed how we are going to fetch data from the server so you will see a lot of fetches being made using XState machines but feel free to refactor it if you are already touching those files.
60+
61+
### Where to fetch data
62+
63+
Finding the right place to fetch data in React apps is the one million dollar question but we decided to make it only in the page components and pass the props down to the views. This makes it easier to find where data is being loaded and easy to test using Storybook. So you will see components like `UsersPage` and `UsersPageView`.
64+
65+
### API
66+
67+
We are using [axios](https://github.com/axios/axios) as our fetching library and writing the API functions in the `site/src/api/api.ts` files. We also have auto-generated types from our Go server on `site/src/api/typesGenerated.ts`. Usually, every endpoint has its own ` Request` and `Response` types but sometimes you need to pass extra parameters to make the call like the example below:
68+
69+
```ts
70+
export const getAgentListeningPorts = async (
71+
agentID: string,
72+
): Promise<TypesGen.ListeningPortsResponse> => {
73+
const response = await axios.get(
74+
`/api/v2/workspaceagents/${agentID}/listening-ports`,
75+
)
76+
return response.data
77+
}
78+
```
79+
80+
Sometimes, a FE operation can have multiple API calls so it is ok to wrap it as a single function.
81+
82+
```ts
83+
export const updateWorkspaceVersion = async (
84+
workspace: TypesGen.Workspace,
85+
): Promise<TypesGen.WorkspaceBuild> => {
86+
const template = await getTemplate(workspace.template_id)
87+
return startWorkspace(workspace.id, template.active_version_id)
88+
}
89+
```
90+
91+
If you need more granular errors or control, you may should consider keep them separated and use XState for that.
92+
93+
## Components
94+
95+
We are using [Material V4](https://v4.mui.com/) in our UI and we don't have any short-term plans to update or even replace it. It still provides good value for us and changing it would cost too much work which is not valuable right now but of course, it can change in the future.
96+
97+
### Structure
98+
99+
Each component gets its own folder. Make sure you add a test and Storybook stories for the component as well. By keeping these tidy, the codebase will remain easy to navigate, healthy and maintainable for all contributors.
100+
101+
### Accessibility
102+
103+
We strive to keep our UI accessible. When using colors, avoid adding new elements with low color contrast. Always use labels on inputs, not just placeholders. These are important for screen-readers.
104+
105+
### Should I create a new component?
106+
107+
As with most things in the world, it depends. If you are creating a new component to encapsulate some UI abstraction like `UsersTable` it is ok but you should always try to use the base components that are provided by the library or from the codebase so I recommend you to always do a quick search before creating a custom primitive component like dialogs, popovers, buttons, etc.
108+
109+
## Testing
110+
111+
We use three types of testing in our app: **E2E**, **Integration** and **Visual Testing**.
112+
113+
### E2E (end-to-end)
114+
115+
Are useful to test complete flows like "Create a user", "Import template", etc. For this one, we use [Playwright](https://playwright.dev/). If you only need to test if the page is being rendered correctly, you should probably consider using the **Visual Testing** approach.
116+
117+
> ℹ️ For scenarios where you need to be authenticated, you can use `test.use({ storageState: getStatePath("authState") })`.
118+
119+
### Integration
120+
121+
Test user interactions like "Click in a button shows a dialog", "Submit the form sends the correct data", etc. For this, we use [Jest](https://jestjs.io/) and [react-testing-library](https://testing-library.com/docs/react-testing-library/intro/). If the test involves routing checks like redirects or maybe checking the info on another page, you should probably consider using the **E2E** approach.
122+
123+
### Visual testing
124+
125+
Test components without user interaction like testing if a page view is rendered correctly depending on some parameters, if the button is showing a spinner if the `loading` props are passing, etc. This should always be your first option since it is way easier to maintain. For this, we use [Storybook](https://storybook.js.org/) and [Chromatic](https://www.chromatic.com/).
126+
127+
### What should I test?
128+
129+
Choosing what to test is not always easy since there are a lot of flows and a lot of things can happen but these are a few indicators that can help you with that:
130+
131+
- Things that can block the user
132+
- Reported bugs
133+
- Regression issues

docs/manifest.json

+5
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,11 @@
322322
"title": "Security",
323323
"description": "How to report vulnerabilities in Coder",
324324
"path": "./contributing/SECURITY.md"
325+
},
326+
{
327+
"title": "Frontend",
328+
"description": "Our guide for frontend development",
329+
"path": "./contributing/frontend.md"
325330
}
326331
]
327332
},

0 commit comments

Comments
 (0)