Repository navigation
FormulaConfigurationDetail
Type: Component Domain: Frontend — Configuration Route:
/configuration/formulas/$id(where$idis numeric ID ornew) Access: ADMIN role,configuration-enabledfeature flag Last updated: 2026-09-10 Status: Current
The FormulaConfigurationDetail page provides a unified interface for creating, viewing, and editing formula configuration sets. It operates in two modes:
-
Editable mode (future open-ended sets): Full form with area selector, date pickers, and
FormulaInputcomponents for each formula row - Read-only mode (closed/historical/deleted sets): Displays formula keys, sort order, expressions as code blocks, and declared variables
| Property | Value |
|---|---|
| Path | /configuration/formulas/:id |
| Params |
id — numeric ID or new
|
| Access Control | roles: [{ role: Role.ADMIN, clients: [] }] |
| Feature Flag | configuration-enabled |
| Redirect | Non-admin users → /unauthorized
|
None — this is a page component mounted by the router with :id param.
| Symbol | Type | Description |
|---|---|---|
FormulaConfigurationDetailPage |
FC |
Default export — the page component |
formatDate |
(dateString: string) => string |
Formats ISO date to yyyy-MM-dd
|
FormulaRow |
FC<FormulaRowProps> |
Internal formula row component (not exported) |
| State | Type | Purpose |
|---|---|---|
area |
'INTERIOR' | 'COASTAL' |
Selected area (disabled when not new) |
startDate |
string |
ISO date string (disabled when not new) |
endDate |
string |
ISO date string or empty for open-ended (disabled when not editable) |
formulas |
FormulaItemDto[] |
Array of formula items being edited/viewed |
| Computed | Type | Logic |
|---|---|---|
isNew |
boolean |
formulaSetId === 'new' |
isEditable |
boolean |
isNew OR (endDate === '' AND startDate > today at midnight) |
| Hook | Purpose |
|---|---|
useFormulaSetList |
Loads all sets for carry-forward logic (new sets) |
useCreateFormulaSet |
Mutation for creating new set |
useUpdateFormulaSet |
Mutation for updating existing set (PUT complete replace) |
useDeleteFormulaSet |
Mutation for soft-delete (future open-ended only) |
When isNew and area changes:
- Filters
listData.contentfor same area, not deleted - Takes most recent (first due to
startDate,DESCsort) - Copies all formulas with
validationErrorscleared - Sets
sortOrdersequentially (1-based) - Sets
startDateto today,endDateempty (open-ended)
| Handler | Action |
|---|---|
handleSave |
Builds DTO with current state, calls createMutation or updateMutation, navigates back to list on success |
handleDelete |
Confirms, calls deleteMutation, navigates back to list on success |
addFormulaRow |
Appends empty FormulaItemDto with next sortOrder
|
removeFormulaRow(index) |
Filters out formula at index |
updateFormulaRow(index, updates) |
Merges updates into formula at index |
handleFormulaChange(index, expression) |
Updates expression for formula at index |
handleKeyChange |
Updates formula key |
handleExpressionChange |
Updates expression and calls onFormulaChange
|
Internal component rendering each formula row.
| Prop | Type | Description |
|---|---|---|
index |
number |
Row index |
formula |
FormulaItemDto |
Formula data |
isEditable |
boolean |
Edit vs read-only mode |
onChange |
(updates) => void |
Partial formula updates |
onFormulaChange |
(expression) => void |
Expression change callback |
onRemove |
() => void |
Remove row callback |
availableNamespaces |
string[] |
Namespaces for autocomplete: ['da', 'sc', 'submission', 'hbs', 'fta']
|
Displays:
- Formula key (or
Formula Nif empty) - Sort order
- Expression in
<code>block - Declared variables as comma-separated list
Renders:
-
TextInputfor formula key (placeholder:da.mature.avoidableGradeY) -
FormulaInputcomponent with:-
initialFormula: current expression -
onChange:handleExpressionChange -
readOnly:false -
displayResult:true -
displayDependencyGraph:true -
fixedParams:{} -
dynamicParams: generated fromavailableNamespaces
-
- Validation errors from
formula.validationErrors(code + message)
generateDynamicParams(namespaces) creates example values for autocomplete:
| Namespace | Example Variables |
|---|---|
da |
da.mature.merchantableVolume: 1000, da.mature.totalVolume: 1200, da.mature.avoidableGradeY: 11.53, da.immature.merchantableVolume: 800
|
sc |
sc.PL: 0.45, sc.Sx: 0.3, sc.Hw: 0.15, sc.Fd: 0.1
|
submission |
submission.blockArea: 25.5, submission.wastePercentage: 0.05
|
hbs |
hbs.factor: 0 |
fta |
fta.adjustment: 0 |
| Module | Purpose |
|---|---|
@carbon/icons-react |
ChevronLeft, Save, Close, Upload, Delete
|
@carbon/react |
Button, Column, TextInput, Select, SelectItem
|
@tanstack/react-router |
useNavigate, useParams — typed navigate({ to: '/configuration/formulas' })
|
react |
useState, FC, useMemo, useEffect
|
@/components/core/PageTitle |
Page header |
@/components/Form/FormulaInput |
Formula editor per row |
@/hooks/useFormulaConfiguration |
All hooks: useFormulaSetList, useUpdateFormulaSet, useDeleteFormulaSet, useCreateFormulaSet
|
@/services/formulaConfiguration.types |
FormulaItemDto type |
| Consumer | Context |
|---|---|
| Router | File route src/routes/_authenticated/_admin/configuration/formulas/$id.tsx
|
FormulaConfigurationList |
Edit action navigates here |
-
Area immutable after creation —
Selectdisabled when!isNew -
Start date immutable after creation —
TextInputdisabled when!isNew -
End date editable only for future open-ended — disabled when
!isEditable -
Complete-replace PUT —
updateFormulaSetsends entire formula set; no partial updates -
Validation errors displayed per row — backend validation errors mapped to
validationErrorsarray - No optimistic updates — UI waits for mutation success before navigating
- Carry-forward only on area change — not re-triggered if user changes area back and forth
// File route: src/routes/_authenticated/_admin/configuration/formulas/$id.tsx
// ADMIN role + configuration-enabled flag are inherited from the _admin tier
// and the configuration.tsx section layout — the route declares neither.
export const Route = createFileRoute('/_authenticated/_admin/configuration/formulas/$id')({
component: FormulaConfigurationDetailPage,
staticData: { title: 'Formula Configuration Detail' },
});
// Typed navigation — the single Register on the router makes `to` literal-checked:
void navigate({ to: '/configuration/formulas' });| Scenario | Behavior |
|---|---|
| API returns 401/403 | Redirected to /unauthorized
|
| API returns 404 (update/delete) | Error caught, logged to console, user stays on page |
| API returns 422 (validation) |
updateMutation.isError/createMutation.isError true, validation errors summary shown |
| API returns 409 (conflict) | Error caught, "A future open-ended formula set already exists for this area" |
| User navigates away with unsaved changes | No warning — changes lost |
| Formula key empty on save | Sent as empty string; backend validation handles |
| Duplicate formula keys | Not prevented client-side; backend may reject |
- FormulaConfigurationList — List page with navigation to detail
- FormulaConfigurationService — API client and hooks
- FormulaInput — Monaco-powered formula editor component
- FormulaEditorPattern — Pattern page for FormulaInput integration
- ConfigurationPage — Parent configuration landing page
This wiki documents NR Waste Plus for users and developers. Verify security and deployment guidance against the current application configuration before applying it elsewhere.
- Report an issue or ask a question in the GitHub repository.
- Follow the Contributing Guidelines to propose an update.
- Read the Code of Conduct.
Collection indexes support human browsing and machine retrieval. Keep both current when adding or moving wiki pages.
NR Waste Plus Wiki | GitHub Repository