Refactor risks frontend to follow page arborescence conventions

- Split layout's monolithic query: each child route now owns its query
  via its own *PageLoader + *Page (overview/measures/documents/controls/
  obligations/scenarios).
- Rename tabs/RiskXTab.tsx -> <resource>/RiskXPage.tsx; drop UI-named
  tabs/ and dialogs/ folders.
- Move FormRiskDialog, PublishRiskListDialog and the extracted RiskRow
  into _components/ as named exports.
- Move risk form fragment ownership into FormRiskDialog: define
  FormRiskDialog_risk in the dialog and pass plain data to useRiskForm
  so spread sites colocate cleanly without disable comments.
- Align risk components with react-components.md naming: rename Relay
  fragments to ComponentName_typeName and replace 'type Props' aliases
  with 'interface ComponentNameProps'.
- Guard risk pages against null node and mutation errors: add
  __typename narrowing to every node(id) query, surface deleteRisk
  errors via toast, and resolve the confirm promise on error so the
  dialog no longer hangs.
- Replace deprecated useMutationWithToasts (FormRiskDialog) and
  useLazyLoadQuery (LinkScenarioDialog) with useMutation+useToast and
  useQueryLoader+usePreloadedQuery.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-05-28 15:02:09 +02:00
parent 361fc0f7bc
commit c78a713adf
21 changed files with 856 additions and 514 deletions

View File

@@ -12,51 +12,29 @@
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import { useFragment } from "react-relay";
import { graphql } from "relay-runtime";
import { z } from "zod";
import type {
useRiskFormFragment$data,
useRiskFormFragment$key,
} from "#/__generated__/core/useRiskFormFragment.graphql";
import type { FormRiskDialog_risk$data } from "#/__generated__/core/FormRiskDialog_risk.graphql";
import { useFormWithSchema } from "../useFormWithSchema";
const RiskFragment = graphql`
fragment useRiskFormFragment on Risk {
id
# eslint-disable-next-line relay/unused-fields
name
# eslint-disable-next-line relay/unused-fields
category
description
# eslint-disable-next-line relay/unused-fields
treatment
# eslint-disable-next-line relay/unused-fields
inherentLikelihood
# eslint-disable-next-line relay/unused-fields
inherentImpact
# eslint-disable-next-line relay/unused-fields
residualLikelihood
# eslint-disable-next-line relay/unused-fields
residualImpact
# eslint-disable-next-line relay/unused-fields
inherentRiskScore
# eslint-disable-next-line relay/unused-fields
residualRiskScore
# eslint-disable-next-line relay/unused-fields
note
owner {
id
}
}
`;
export type RiskNode = Pick<
FormRiskDialog_risk$data,
| "id"
| "name"
| "category"
| "description"
| "treatment"
| "inherentLikelihood"
| "inherentImpact"
| "residualLikelihood"
| "residualImpact"
| "inherentRiskScore"
| "residualRiskScore"
| "note"
| "owner"
>;
export type RiskNode = useRiskFormFragment$data;
export type RiskKey = useRiskFormFragment$key & { id: string };
// Export the schema so it can be used elsewhere
export const riskSchema = z.object({
category: z.string().min(1, "Category is required"),
name: z.string().min(1, "Name is required"),
@@ -70,8 +48,7 @@ export const riskSchema = z.object({
note: z.string().optional(),
});
export const useRiskForm = (riskKey?: RiskKey) => {
const risk = useFragment(RiskFragment, riskKey);
export const useRiskForm = (risk?: RiskNode) => {
return useFormWithSchema(riskSchema, {
defaultValues: risk
? {