mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-02 21:03:34 +03:00
# Description of Changes Redesign policies backend to treat sources a lot closer to how the frontend imagined them working (they're persistent now and have an API). Then connect the portal to the sources when mocks are off to allow for source creation in the UI. It's not particularly useful to do that right now because there's no policies UI, but I've tested manually that sources set up in the UI are usable by policies created via the API. I had to change the portal so that when mocks are off, it doesn't just hard crash when attempting to connect to all the backend APIs that don't exist yet. It'll still log the errors, but just continues on rendering the UI now. I also changed all the policies backend APIs to be gated behind a flag instead of behind the SaaS profile. This is because we haven't yet got the payment model sorted, but we're going to need this stuff running self-hosted to be able to test it locally.
69 lines
2.2 KiB
TypeScript
69 lines
2.2 KiB
TypeScript
import { Component, type ErrorInfo, type ReactNode } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Button, EmptyState } from "@shared/components";
|
|
|
|
/**
|
|
* Default fallback for {@link ErrorBoundary}. Split into a function component so
|
|
* it can read translations via the `useTranslation` hook, which the class-based
|
|
* boundary cannot call directly.
|
|
*/
|
|
function DefaultErrorFallback({ onRetry }: { onRetry: () => void }) {
|
|
const { t } = useTranslation();
|
|
return (
|
|
<EmptyState
|
|
title={t("errorBoundary.title")}
|
|
description={t("errorBoundary.description")}
|
|
actions={<Button onClick={onRetry}>{t("errorBoundary.retry")}</Button>}
|
|
/>
|
|
);
|
|
}
|
|
|
|
interface ErrorBoundaryProps {
|
|
children: ReactNode;
|
|
/** Custom fallback; receives a reset fn to retry the subtree. */
|
|
fallback?: (reset: () => void) => ReactNode;
|
|
}
|
|
|
|
interface ErrorBoundaryState {
|
|
error: Error | null;
|
|
}
|
|
|
|
/**
|
|
* Contains render/runtime crashes to its subtree so one failing view can never
|
|
* white-screen the whole portal. The app shell + navigation live OUTSIDE this
|
|
* boundary and stay interactive, so the user can always navigate away; the
|
|
* boundary is keyed by route in App, so moving to another view clears the error.
|
|
*
|
|
* This is what makes running against a real backend (mocks off) safe: a page
|
|
* that gets an unexpected/!missing response degrades to a contained error card
|
|
* instead of taking the app down.
|
|
*/
|
|
export class ErrorBoundary extends Component<
|
|
ErrorBoundaryProps,
|
|
ErrorBoundaryState
|
|
> {
|
|
state: ErrorBoundaryState = { error: null };
|
|
|
|
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
|
|
return { error };
|
|
}
|
|
|
|
componentDidCatch(error: Error, info: ErrorInfo): void {
|
|
// Log for debugging; the UI itself stays contained by the fallback.
|
|
console.error("Portal view crashed:", error, info.componentStack);
|
|
}
|
|
|
|
reset = (): void => this.setState({ error: null });
|
|
|
|
render(): ReactNode {
|
|
const { error } = this.state;
|
|
if (!error) return this.props.children;
|
|
if (this.props.fallback) return this.props.fallback(this.reset);
|
|
return (
|
|
<div style={{ padding: "2rem" }}>
|
|
<DefaultErrorFallback onRetry={this.reset} />
|
|
</div>
|
|
);
|
|
}
|
|
}
|