UNPKG

openstack-uicore-foundation

Version:

ui reactjs components for openstack marketing site

63 lines (47 loc) 2.84 kB
# Component Patterns ## Upload Components (3 generations) | Version | Location | Rendering | Use Case | |---------|----------|-----------|----------| | V1 | `inputs/upload-input/` | Legacy, basic file list | Simple single-file uploads | | V2 | `inputs/upload-input-v2/` | Custom React UI | Multi-file with progress | | V3 | `inputs/upload-input-v3/` | MUI-based UI | Chunked uploads, async processing | **V1/V2 wrap `inputs/dropzone/index.js`** (DropzoneJS class); **V3 wraps `inputs/upload-input-v3/dropzone-v3.js`** (DropzoneV3 wrapper). The underlying Dropzone library is `dropzone@5.7.2`. ### Chunked Upload Architecture - `DropzoneJS` manages a chunk queue with `maxConcurrentChunks` (default: 6) - `setupChunkThrottle()` wraps Dropzone's `_uploadData` to enforce concurrency - Progress tracking uses `_completedBytes` floor to prevent oscillation during parallel chunk uploads - `options.uploadprogress` override in `getDjsConfig()` centralizes progress correction (guards against `NaN` bytesSent from queued chunks) - HTTP 202 responses trigger async polling via `_asyncProcessing` flag ### Upload Gotchas - **Progress oscillation:** Dropzone creates chunk entries with `progress:0` and `bytesSent:undefined` upfront. Raw progress average across chunks causes backsliding — always apply `_completedBytes` floor. - **Cancel cleanup:** `xhr.abort()` fires `onabort`, not `onload`/`onerror`. Cancelled files must be filtered from `chunkQueue` and `chunksInFlight` decremented in `removedfile` handler. - **NaN guard:** `Math.max(bytesSent || 0, ...)` — bytesSent can be `undefined` for queued chunks. ## MUI Components - Located in `src/components/mui/` - Follow pattern: component in `index.js`, styles in `.module.less` or `.module.scss` - Formik integration components in `mui/formik-inputs/` — prefix `mui-formik-*` - All MUI components use MUI v6 APIs ## Redux Pattern ```javascript // Action creator factory export const createAction = type => payload => ({ type, payload }); // Async thunk pattern export const myAction = (params) => async (dispatch, getState) => { dispatch(startLoading()); return getRequest( createAction(REQUEST_TYPE), createAction(RECEIVE_TYPE), buildAPIBaseUrl('/api/v1/endpoint'), authErrorHandler )(params)(dispatch, getState); }; ``` - Actions: constants + thunks in same file - Reducers: switch/case on action types - State shape: `loggedUserState` for auth, domain-specific reducers in consumers ## Testing Conventions - Test files: `__tests__/` directories adjacent to components - Framework: Jest + @testing-library/react - Mock pattern: `jest.mock('module')` at top of file - Component tests render with `@testing-library/react`, assert on DOM - Dropzone tests mock the Dropzone constructor to capture options and simulate events