enhance contract document rendering with detailed cargo information

- Updated ContractDocumentViewModelBuilder to include cargoTypeName, containerType, and cargoSummary in the schedule.
- Modified contract dynamic template tests to validate the new cargo fields.
- Enhanced contract renderer service tests to reflect changes in cargo data structure.
- Updated contract view model interface to include new cargo-related fields.
- Improved dynamic template rendering to display cargo type and container type.
- Refactored exchange settings controller and service to streamline error handling and feed status management.
- Introduced article HTML conversion functions to support Quill editor integration for structured article editing.
- Added tests for article HTML conversion to ensure correct round-trip processing of clauses and bullets.
This commit is contained in:
Marshal
2026-08-04 13:03:39 +00:00
parent 45216c5624
commit d0040a6851
14 changed files with 472 additions and 224 deletions

View File

@@ -222,10 +222,10 @@ const RuleEngineResourcePage = () => {
// instead of mutating: the rate keeps its current value until an approver
// applies the change. DRAFT rates still edit directly.
const isRates = config?.slug === "rates";
const [rateError, setRateError] = useState<string | null>(null);
// No error modal here: the workflow falls back to a toast when no handler is
// passed, which keeps failures visible without a dialog to dismiss.
const rateChangeWorkflow = useRateChangeWorkflow(
Boolean(isRates && canView),
setRateError,
);
const canApproveRates = Boolean(isRates && canApproveRuleEngineChange(user, "rates"));
/** rateId → its pending change, for the row badge. */
@@ -265,8 +265,10 @@ const RuleEngineResourcePage = () => {
useCargoTypeParentOptions(editingId, config?.slug === "cargo-types");
const { data: cargoLeafOptions, isLoading: cargoLeafOptionsLoading } =
useCargoLeafOptions(usesCargoTypeField);
// No "None" on rates: a rate's container scope is either a real type or the
// field is hidden entirely, so offering None only invites an unscoped rate.
const { data: containerTypeOptions, isLoading: containerTypeOptionsLoading } =
useContainerTypeOptions(config?.slug === "rates", usesContainerTypeField);
useContainerTypeOptions(false, usesContainerTypeField);
const { data: liveRateOptions, isLoading: liveRateOptionsLoading } =
useLiveRateOptions(usesLiveRateField);
const { data: wagonTypeOptions, isLoading: wagonTypeOptionsLoading } =
@@ -695,22 +697,6 @@ const RuleEngineResourcePage = () => {
/>
) : null}
<Modal
opened={rateError != null}
onClose={() => setRateError(null)}
title="Cannot save rate change"
centered
>
<Text size="sm" c="red">
{rateError}
</Text>
<Group justify="flex-end" mt="md">
<Button variant="light" onClick={() => setRateError(null)}>
Close
</Button>
</Group>
</Modal>
<Modal
opened={priorityError != null}
onClose={() => setPriorityError(null)}