Skip to content

Commit

Permalink
Merge pull request #4628 from cloud-gov/chore-component-improvement
Browse files Browse the repository at this point in the history
chore: improve component separation of concerns, hooks, purity
  • Loading branch information
drewbo authored Oct 25, 2024
2 parents f76fda3 + 0f8fbbf commit d331db0
Show file tree
Hide file tree
Showing 82 changed files with 1,429 additions and 1,632 deletions.
4 changes: 2 additions & 2 deletions .cloudgov/manifest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ applications:
command: yarn start
disk_quota: 5G
instances: ((instances))
memory: ((memory))
memory: 512MB
- type: worker
command: yarn start-workers
disk_quota: 5G
Expand Down Expand Up @@ -63,7 +63,7 @@ applications:
command: yarn start-bull-board:cg
disk_quota: 2G
instances: 1
memory: ((memory))
memory: 512MB
routes:
- route: queues.((domain))
services:
Expand Down
5 changes: 2 additions & 3 deletions .cloudgov/vars/pages-dev.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
product: pages
name: pages-dev
domain: pages-dev.cloud.gov
memory: 256MB
instances: 2
env: dev
env_postfix: -dev
log_level: verbose
feature_auth_uaa: 'true'
feature_bull_site_build_queue: 'true'
feature_auth_uaa: "true"
feature_bull_site_build_queue: "true"
uaa_host: https://uaa.fr-stage.cloud.gov
uaa_login_host: https://login.fr-stage.cloud.gov
new_relic_app_name: web-pages-dev
Expand Down
5 changes: 2 additions & 3 deletions .cloudgov/vars/pages-production.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
product: pages
name: pages-production
domain: pages.cloud.gov
memory: 512MB
instances: 4
env: production
env_postfix: -production
log_level: info
feature_auth_uaa: 'true'
feature_bull_site_build_queue: 'true'
feature_auth_uaa: "true"
feature_bull_site_build_queue: "true"
uaa_host: https://uaa.fr.cloud.gov
uaa_login_host: https://login.fr.cloud.gov
new_relic_app_name: web-pages-production
Expand Down
5 changes: 2 additions & 3 deletions .cloudgov/vars/pages-staging.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
product: pages
name: pages-staging
domain: pages-staging.cloud.gov
memory: 256MB
instances: 2
env: staging
env_postfix: -staging
log_level: verbose
feature_auth_uaa: 'true'
feature_bull_site_build_queue: 'true'
feature_auth_uaa: "true"
feature_bull_site_build_queue: "true"
uaa_host: https://uaa.fr-stage.cloud.gov
uaa_login_host: https://login.fr-stage.cloud.gov
new_relic_app_name: web-pages-staging
Expand Down
41 changes: 22 additions & 19 deletions docs/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -460,39 +460,41 @@ The following conventions used to build and maintain the frontend UI.

The frontend UI should be structured to improve consistency and developer experience by establishing and maintaining the following standards. The frontend consists of a single page application architecture using Nunjucks templates to rendered by the server and React to render pages in the browser.

### Transitional Design Notes
- Currently much of the application state is managed via a [Redux](https://redux.js.org/) store.
- We are intending to transition our router to [Tanstack Router](https://tanstack.com/router/latest) and use [Tanstack Query](https://tanstack.com/query/latest) to update how our data is fetched and stored in the application.
- This latter change will likely partially supplant the Redux store as more state is maintained as [cached API requests](https://tkdodo.eu/blog/react-query-as-a-state-manager)

#### Server rendered views (Nunjucks)
- Templates in the [`./views`](../views) directory.

#### Browser rendered pages (React)
- Page template components are in the [`./frontend/pages`](../frontend/pages) directory.
- Each page is named `index.jsx` and located in the file structure at a path matching the intended route. For example, to find the component which renders `pages.cloud.gov/sites/new`, look in `frontend/pages/sites/new`. Dynamic routes are matched using `$id`, e.g the component which renders `pages.cloud.gov/sites/2/build/3/logs` is in the folder `frontend/pages/sites/$siteId/builds/$buildId/logs`.
- This pattern is inteded to support a future move to file-based routing, potentially [Tanstack Router](https://tanstack.com/router/latest)
- Only page template components should be used to render the routes in the [`./frontend/routes.js`](../frontend/routes.js) file.
- Pages are composed of two types of components: Pure components and dynamic components. The majority of components used should be written as pure components.
- Most HTTP requests should be called from the page component with the response data being passed down to pure components. Dynamic components should be used sparingly and scoped to a specific purpose to encapsulate complexity and state to the specific dynamic component.
- Most UI state should be defined at the page level using React hooks.
- Global app state should only be connected to page template components.

#### Components (React)

##### Pure Components
- Pure components are in two places:
- Components can be found in two places:
- Components which are used across pages are in the [`./frontend/shared`](../frontend/shared) directory.
- Components which are specific to a page are in the `./pages/<page>/components/` directory.
- Components which are specific to a page are co-located in the `./pages/**/<page>/` directory.
- Shared components are primarily used to display information or be a general action that can be reused throughout the UI. ie:
- A title component that displays the provided string property.
- A button component that will call a function on click.
- Page-specific components aren't shared throughout the UI but have similar functions as enumerated below.
- All of the component properties are passed directly to the component.
- Property types should be booleans, numbers, strings, arrays, objects, or functions.
- No HTTP requests should be called from within a pure component.
- No state management actions should happen within a pure component unless it is specific to that component with no external side effects. ie:
- A menu component with a button that opens an element to display a list of links. The state of the menu being open or closed can be encapsulated within that component and its state does not effect any other components and actions.

##### Dynamic Components
- Dynamic components are in the `./pages/<page>/components/` directory for a give page.
- These are primarily used to encapsulate complex requests, actions, and state management within a specific UI component. ie.
- A build logs component that polls the API to retrieve and append new logs.
- The component properties passed to a dynamic component should only be used to define its initial state and/or HTTP requests.
- React hooks should manage the state and custom hook's should be created to help manage the state within the dynamic component.

- We've mostly abandoned the distinction between pure and dynamic components. In general, it's preferred for non-page template components to be pure (the render is fuly controlled via props) but some components will receive additional inputs via `useSelector` (reading from the global redux state), a localized `useState` hook, or a custom hook. For completeness, for pure components:
- All of the component properties are passed directly to the component.
- Property types should be booleans, numbers, strings, arrays, objects, or functions.
- No HTTP requests should be called from within a pure component.
- No state management actions should happen within a pure component unless it is specific to that component with no external side effects. ie:
- A menu component with a button that opens an element to display a list of links. The state of the menu being open or closed can be encapsulated within that component and its state does not effect any other components and actions.
- And for dynamic components:
- These are primarily used to encapsulate complex requests, actions, and state management within a specific UI component. ie.
- A build logs component that polls the API to retrieve and append new logs.
- The component properties passed to a dynamic component should only be used to define its initial state and/or HTTP requests.
- React hooks should manage the state and custom hook's should be created to help manage the state within the dynamic component.

#### State management

Expand All @@ -506,6 +508,7 @@ The frontend UI should be structured to improve consistency and developer experi
- The `useBuildLogs` hook would define the state and effects associated with the build logs dynamic component.
- The `useSiteBuilds` hook would define the state and effects for a site's build history


## Event Driven Queueing

### Queues
Expand Down
21 changes: 21 additions & 0 deletions frontend/hooks/useOrganizationRoles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* eslint-disable import/prefer-default-export */
import { useEffect, useState } from 'react';
import api from '../util/federalistApi';

const initState = {
orgRoles: null,
isLoading: true,
};

export const useOrganizationRoles = () => {
const [state, setState] = useState(initState);

useEffect(() => {
api.fetchOrganizationRoles().then(data => setState({
isLoading: false,
orgRoles: data,
}));
}, []);

return state;
};
Loading

0 comments on commit d331db0

Please sign in to comment.