3.8 KiB
3.8 KiB
Client Architecture
All rules described in the server-side architecture documentation apply to the client as well. As shown below, the directory structure additionally accommodates the front-end-specific concepts like components and containers.
Apps
The apps
folder contains the entry point for the UI code, such as for use in Kibana or testing.
Components
- Components should be stateless wherever possible with pages and containers holding state.
- Small (less than ~30 lines of JSX and less than ~120 lines total) components should simply get their own file.
- If a component gets too large to reason about, and/or needs multiple child components that are only used in this one place, place them all in a folder.
- All components, please use Styled-Components. This also applies to small tweaks to EUI, just use
styled(Component)
and theattrs
method for always used props. For example:
export const Toolbar = styled(EuiPanel).attrs(() => ({
paddingSize: 'none',
grow: false,
}))`
margin: -2px;
`;
However, components that tweak EUI should go into /public/components/eui/${componentName}
.
If using an EUI component that has not yet been typed, types should be placed into /types/eui.d.ts
Containers
- HOC's based on Apollo.
- One folder per data type e.g.
host
. Folder name should be singular. - One file per query type.
Pages
- Ideally one file per page, if more files are needed, move into folder containing the page and a layout file.
- Pages are class based components.
- Should hold most state, and any additional route logic.
- Are the only files where components are wrapped by containers. For example:
// Simple usage
const FancyLogPage = withSearchResults(class FancyLogPage extends React.Component<FancyLogPageProps> {
render() {
return (
<>
<Toolbar />
<LogView searchResults={/* ... */} />
<SearchBar />
<>
);
}
});
OR, for more complex scenarios:
// Advanced usage
const ConnectedToolbar = compose(
withTimeMutation,
withCurrentTime
)(Toolbar);
const ConnectedLogView = compose(
withLogEntries,
withSearchResults,
)(LogView);
const ConnectedSearchBar = compose(
withSearchMutation
)(SearchBar);
interface FancyLogPageProps {}
class FancyLogPage extends React.Component<FancyLogPageProps> {
render() {
return (
<>
<ConnectedToolbar />
<ConnectedLogView />
<ConnectedSearchBar />
<>
);
}
};
Transforms
- If you need to do some complex data transforms, it is better to put them here than in a utility or lib. Simpler transforms are probably easier to keep in a container.
- One file per transform
File structure
|-- infra-ui
|-- common
| |-- types.ts
|
|-- public
| |-- components //
| | |-- eui // staging area for eui customizations before pushing upstream
| | |-- layout // any layout components should be placed in here
| | |-- button.tsx
| | |-- mega_table // Where mega table is used directly with a data prop, not a composable table
| | |-- index.ts
| | |-- row.tsx
| | |-- table.tsx
| | |-- cell.tsx
| |
| |-- containers
| | |-- host
| | | |-- index.ts
| | | |-- with_all_hosts.ts
| | | |-- transforms
| | | |-- hosts_to_waffel.ts
| | |
| | |-- pod
| | |-- index.ts
| | |-- with_all_pods.ts
| |
| |-- pages
| | |-- home.tsx // the initial page of a plugin is always the `home` page
| | |-- hosts.tsx
| | |-- logging.tsx
| |
| |-- utils // utils folder for what utils folders are for ;)
| |
| |-- lib // covered in [Our code and arch](docs/arch.md)