oncall-engine/dev/frontend_guidelines.md

125 lines
5 KiB
Markdown
Raw Normal View History

# OnCall Frontend Guidelines
The base guidelines we decided to follow are:
- <https://github.com/ryanmcdermott/clean-code-javascript>
- <https://github.com/grafana/grafana/tree/main/contribute/style-guides>
Anything that is either not covered by the materials above or we decided to do differently is stated in this document.
## Ways of working
### Code reviews
- PR can be merged when the following conditions are met:
- CI pipeline succeeded without bypassing checks
- There is at least 1 approval from the frontend team and no opened remarks from reviewers other than the approver
- All comments are replied, answered, addressed or discussed separately
- We make use of builtin GH PR reviews
- Minor comments that dont need to be addressed right away and are not a blocker for a merge
are marked with “Minor: “ prefix
- *Unless there is some important hotfix to make and no frontend mates are available*
## Technical conventions
### Type-safety
- Dont use implicit / explicit `any` or @ts-ignore
### Use auto generated types for new features
- For new features and endpoints that are covered by OpenApi schemas, we should use auto generated types and
typed http client
### Naming conventions on most used variables such as handlers, booleans etc
- Use descriptive naming (such as the use of is) that follows natural convention such as `isFormVerified`
or `isAuthenticated` instead of *verified*, *authenticated* etc
- Use descriptive naming for event handlers such as `onIconClick` or `onInputChange` rather than *handleChange*
- Include the **verb** part in the functions names
- For **3 or more** function arguments use object destructuring
<https://github.com/ryanmcdermott/clean-code-javascript?tab=readme-ov-file#function-arguments-2-or-fewer-ideally>
- For functions that return other functions getBlaBlaHandler (in case of handlers) or getBlaBlaFn
(if its not handler that is returned)
- Dont use higher-ordered functions without clear need
## State management
### Dont use returned values from MobX actions
- MobX actions should not return value that is later used within components. Instead MobX actions should update
observables and then components should consume observables to reflect data updates.
### Leverage small global stores over local state passed as props over multiple levels
- Create small specialized store in MobX even for small feature
instead of relying on local state that is passed down the React tree over multiple levels
e.g.:
alert_receive_channel_connected_channels.ts
alert_receive_channel_webhooks.ts
### Use global decorators / custom hooks / utilities consistently
- For example:
- `@WithGlobalNotification` to set successful / failing notification based on MobX actions result
- `@AutoLoadingState` to manage loading statuses of async actions
- `useIsLoading` to consume loading state
- `useDrawer` to manage drawers
- `useConfirmModal` to manage confirm modal
- Global helpers
## Code organization
### Store files in appropriate places
- Store files in appropriate places (components, containers, models etc)
- Helpers and configs should be stored in the same folder with the appropriate name
e.g. [container].helper.ts, [container].config.ts
- Project-wide utilities should be placed in the **utils** folder`
- Use named exports for all code you want to export from a file.
- Export only the code that is meant to be used outside the module.
### Dont opt-out from eslint / TS rules
- Avoid opting out from eslint or TS rules unless there is a strong reason / lack of possibility to follow the rule
## Styling
### Use Emotion.js with agreed code style
- Use emotion.js for styling
- Make use of `useStyles2` hook
- Use css `` syntax
- Place `getStyles` function at the end of the same file or in the separate file with `X.styles.ts` suffix
(if its reused by multiple components or its too large for placing in the same components file)
## React
### Keep components functional and small
- Use functional components for new features
- Leverage components composition, use many small components, render list items in dedicated component
and dereference values late
<https://mobx.js.org/react-optimizations.html>
- Keep components small and flat
- Use dedicated components over render functions in case a there's a risk that a single component grows too much
- Static values (especially non-primitive) that dont depend on local state, props or store should be extracted
out of component
- Dont create unnecessary local state that duplicates parts of global store
- Leverage custom hooks to extract repetitive logic
- Dont use useMemo / useCallback by default
## Architecture
### Use layered architecture
- Dont interact with backend directly from components
- Dont interact with 3rd party (faro, web storage etc) directly but rather through service
## Frontend-backend communication
### Use typed HTTP request and response payloads
- HTTP request payload and response payload should always be typed
- Use typed http client whenever we have auto-generated types available