Project: Grafana (Observability and Analysis / Observability)
File: frontend.md

Generally we follow the Airbnb . - - - - - - - - - - - - - - - Try to keep files small and focused. Break large components up into sub-components. Use spaces for indentation. ```typescript // bad class dataLink { //... } // good class DataLink { //... } ``` ``` // bad interface buttonProps { //... } // bad interface button_props { //... } // bad interface IButtonProps { //... } // good interface ButtonProps { //... } // bad type requestInfo = ... // bad type request_info = ... // good type RequestInfo = ... ``` ``` // bad enum buttonVariant { //... } // good enum ButtonVariant { //... } ``` ```typescript // bad const CalculatePercentage = () => { ... } // bad const calculate_percentage = () => { ... } // good const calculatePercentage = () => { ... } ``` ```typescript class DateCalculator { // bad CalculateTimeRange () {...} } class DateCalculator { // bad calculatetimerange () {...} } class DateCalculator { // good calculateTimeRange () {...} } ``` ```typescript // bad const QueryTargets = []; // bad const query_targets = []; // good const queryTargets = []; ``` ```typescript interface ModalState { // bad IsActive: boolean; // bad is_active: boolean; // good isActive: boolean; } ``` ```typescript const getStyles = (theme: GrafanaTheme2) => ({ // bad ElementWrapper: css`...`, // bad // good elementWrapper: css({ padding: theme.spacing(1, 2), background: theme.colors.background.secondary, }), }); ``` Use hook useStyles2(getStyles) to memoize the styles generation and try to avoid passing props to the getStyles function and instead compose classes using emotion cx function. ```typescript // bad const constantValue = "This string won't change"; // bad const constant_value = "This string won't change"; // good const CONSTANT_VALUE = "This string won't change"; ``` SASS styles are deprecated. Please migrate to Emotion whenever you need to modify SASS styles. In general, you should let Typescript infer the types so that there's no need to explicitly define type for each variable. There are some exceptions to this: ```typescript // Typescript needs to know type of arrays or objects otherwise it would infer it as array of any // bad const stringArray = []; // good const stringArray: string[] = []; ``` Specify function return types explicitly in new code. This improves readability by being able to tell what a function returns just by looking at the signature. It also prevents errors when a function's return type is broader than expected by the author. Note: We don't have linting for this enabled because of lots of old code that needs to be fixed

```typescript // bad function transform(value?: string) { if (!value) { return undefined; } return applyTransform(value); } // good function transform(value?: string): TransformedValue | undefined { if (!value) { return undefined; } return applyTransform(value); } ``` Name files according to the primary export: When the primary export is a class or React component, use PascalCase. When the primary export is a function, use camelCase. For files exporting multiple utility functions, use the name that describes the responsibility of grouped utilities. For example, a file exporting math utilities should be named `math.ts`. Use `constants.ts` for files exporting constants. Use `actions.ts` for files exporting Redux actions. Use `reducers.ts` Redux reducers. Use `*.test.ts(x)` for test files. Use kebab case for directory names: lowercase, words delimited by hyphen ( `-` ). For example, `features/new-important-feature/utils.ts`. Organize your code in a directory that encloses feature code: Put Redux state and domain logic code in `state` directory (i.e. `features/my-feature/state/actions.ts`). Put React components in `components` directory (i.e. `features/my-feature/components/ButtonPeopleDreamOf.tsx`). Put test files next to the test subject. Put containers (pages) in feature root (i.e. `features/my-feature/DashboardPage.tsx`). Put API function calls that isn't a redux thunk in an `api.ts` file within the same directory. Subcomponents can live in the component folders. Small component do not need their own folder. Component SASS styles should live in the same folder as component code. For code that needs to be used by external plugin: Put components and types in `@grafana/ui`. Put data models and data utilities in `@grafana/data`. Put runtime services interfaces in `@grafana/runtime`. Use named exports for all code you want to export from a file. Use declaration exports (i.e. `export const foo = ...`). Avoid using default exports (for example, `export default foo`). Export only the code that is meant to be used outside the module. Use comments to document your code. Use comments (`/ ... */`) for props documentation. Use inline comments for comments inside functions, classes etc. Please try to follow the when adding comments. Linting is performed using . Use the following conventions when implementing React components: ```tsx // bad handleChange = () => { }; render() { return ( <MyComponent changed={this.handleChange} /> ); } // good onChange = () => { }; render() { return ( <MyComponent onChange={this.onChange} /> ); } ``` ```jsx // bad export class YourClass extends PureComponent { ... } // good export class YourClass extends PureComponent<{},{}> { ... } ``` ```typescript // bad constructor(props) {...} // good constructor(props: Props) {...} ``` ```typescript // bad static defaultProps = { ... } // good static defaultProps: Partial<Props> = { ... } ``` We prefer using function declarations over function expressions when creating a new react functional component. ```typescript // bad export const Component = (props: Props) => { ... } // bad export const Component: React.FC<Props> = (props) => { ... } // good export function Component(props: Props) { ... } ``` Some interesting readings on the topic: Don't mutate state in reducers or thunks. Use `createSlice`. See for more details. Use `reducerTester` to test reducers. See for more details. Use state selectors to access state instead of accessing state directly.