@scm-manager/ui-components 4.0.0-REACT19-20251104-141645 → 4.0.0-REACT19-20251104-162002

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scm-manager/ui-components",
3
- "version": "4.0.0-REACT19-20251104-141645",
3
+ "version": "4.0.0-REACT19-20251104-162002",
4
4
  "description": "UI Components for SCM-Manager and its plugins",
5
5
  "main": "src/index.ts",
6
6
  "files": [
@@ -34,8 +34,8 @@
34
34
  "@scm-manager/eslint-config": "^2.18.2",
35
35
  "@scm-manager/prettier-config": "^2.12.0",
36
36
  "@scm-manager/tsconfig": "^2.13.0",
37
- "@scm-manager/ui-syntaxhighlighting": "4.0.0-REACT19-20251104-141645",
38
- "@scm-manager/ui-types": "4.0.0-REACT19-20251104-141645",
37
+ "@scm-manager/ui-syntaxhighlighting": "4.0.0-REACT19-20251104-162002",
38
+ "@scm-manager/ui-types": "4.0.0-REACT19-20251104-162002",
39
39
  "@storybook/addon-actions": "^9.0.8",
40
40
  "@storybook/addon-docs": "^9.1.5",
41
41
  "@storybook/addon-essentials": "^9.0.0-alpha.12",
@@ -66,9 +66,9 @@
66
66
  "vitest": "^3.2.4"
67
67
  },
68
68
  "dependencies": {
69
- "@scm-manager/ui-api": "4.0.0-REACT19-20251104-141645",
70
- "@scm-manager/ui-core": "4.0.0-REACT19-20251104-141645",
71
- "@scm-manager/ui-extensions": "4.0.0-REACT19-20251104-141645",
69
+ "@scm-manager/ui-api": "4.0.0-REACT19-20251104-162002",
70
+ "@scm-manager/ui-core": "4.0.0-REACT19-20251104-162002",
71
+ "@scm-manager/ui-extensions": "4.0.0-REACT19-20251104-162002",
72
72
  "deepmerge": "^4.2.2",
73
73
  "hast-util-sanitize": "^3.0.2",
74
74
  "react-diff-view": "2.6.0",
@@ -15,26 +15,34 @@
15
15
  */
16
16
 
17
17
  import React, { FC, ReactNode, useEffect } from "react";
18
- import { isRouteErrorResponse, useLocation, useRouteError } from "react-router-dom";
18
+ import { useLocation } from "react-router-dom";
19
19
  import { useTranslation } from "react-i18next";
20
20
  import classNames from "classnames";
21
21
  import styled from "styled-components";
22
22
  import { MissingLinkError, urls, useIndexLink } from "@scm-manager/ui-api";
23
- import { ErrorBoundary as ReactErrorBoundary } from "react-error-boundary";
23
+ import { ErrorBoundary as ReactErrorBoundary, FallbackProps } from "react-error-boundary";
24
24
  import { useDocumentTitle } from "@scm-manager/ui-core";
25
25
  import ErrorNotification from "./ErrorNotification";
26
26
  import ErrorPage from "./ErrorPage";
27
27
  import { Subtitle, Title } from "./layout";
28
28
  import Icon from "./Icon";
29
29
 
30
- type ErrorDisplayProps = {
30
+ type ErrorState = {
31
31
  error: Error;
32
- errorInfo?: { componentStack?: string }; // Optional gemacht
33
- fallback?: React.ComponentType<{ error: Error }>;
34
32
  };
35
33
 
36
- type GlobalErrorBoundaryProps = {
37
- fallback?: React.ComponentType<{ error: Error }>;
34
+ type ExportedProps = {
35
+ fallback?: React.ComponentType<ErrorState>;
36
+ children?: ReactNode;
37
+ };
38
+
39
+ type ErrorDisplayProps = {
40
+ error: Error;
41
+ // react-error-boundary does not pass errorInfo to the fallback component by default
42
+ // for performance reasons, but it can be logged via the `onError` prop.
43
+ // We keep it in the signature for compatibility with the custom fallback prop.
44
+ errorInfo?: { componentStack: string };
45
+ fallback?: React.ComponentType<ErrorState>;
38
46
  };
39
47
 
40
48
  const RedirectIconContainer = styled.div`
@@ -44,7 +52,6 @@ const RedirectIconContainer = styled.div`
44
52
  const RedirectPage: FC = () => {
45
53
  const [t] = useTranslation("commons");
46
54
  useDocumentTitle(t("errorNotification.prefix"));
47
-
48
55
  return (
49
56
  <section className="section">
50
57
  <div className="container">
@@ -65,7 +72,7 @@ const RedirectPage: FC = () => {
65
72
  );
66
73
  };
67
74
 
68
- const ErrorDisplay: FC<ErrorDisplayProps> = ({ error, fallback: FallbackComponent }) => {
75
+ const ErrorDisplay: FC<ErrorDisplayProps> = ({ error, errorInfo, fallback: FallbackComponent }) => {
69
76
  const loginLink = useIndexLink("login");
70
77
  const [t] = useTranslation("commons");
71
78
  const location = useLocation();
@@ -80,47 +87,41 @@ const ErrorDisplay: FC<ErrorDisplayProps> = ({ error, fallback: FallbackComponen
80
87
  if (isMissingLink) {
81
88
  if (loginLink) {
82
89
  return <RedirectPage />;
83
- } else {
84
- return (
85
- <ErrorPage error={error} title={t("errorNotification.prefix")} subtitle={t("errorNotification.forbidden")} />
86
- );
87
90
  }
91
+ return (
92
+ <ErrorPage error={error} title={t("errorNotification.prefix")} subtitle={t("errorNotification.forbidden")} />
93
+ );
88
94
  }
89
95
 
96
+ const fallbackProps = {
97
+ error,
98
+ errorInfo,
99
+ };
100
+
90
101
  if (FallbackComponent) {
91
- return <FallbackComponent error={error} />;
102
+ return <FallbackComponent {...fallbackProps} />;
92
103
  }
93
-
94
104
  return <ErrorNotification error={error} />;
95
105
  };
96
106
 
97
- const ErrorBoundary: FC<GlobalErrorBoundaryProps & { children?: ReactNode }> = ({ fallback, children }) => {
98
- const rawError = useRouteError();
107
+ const ErrorBoundary: FC<ExportedProps> = ({ children, fallback }) => {
99
108
  const location = useLocation();
100
109
 
101
- if (!rawError) {
102
- const ErrorBoundaryFallback = ({ error }: { error: Error }) => (
103
- <ErrorDisplay error={error} errorInfo={{ componentStack: "" }} fallback={fallback} />
104
- );
105
-
106
- return (
107
- <ReactErrorBoundary resetKeys={[location.pathname]} FallbackComponent={ErrorBoundaryFallback}>
108
- {children}
109
- </ReactErrorBoundary>
110
- );
111
- }
112
-
113
- let error: Error;
114
-
115
- if (isRouteErrorResponse(rawError)) {
116
- error = new Error(`${rawError.status} ${rawError.statusText}`);
117
- } else if (rawError instanceof Error) {
118
- error = rawError;
119
- } else {
120
- error = new Error(rawError ? String(rawError) : "Unknown Error");
121
- }
110
+ const ErrorBoundaryFallback = ({ error }: FallbackProps) => (
111
+ <ErrorDisplay
112
+ error={error}
113
+ // For compatibility with potential custom fallbacks that expect errorInfo.
114
+ // The actual component stack is available in the `onError` callback below.
115
+ errorInfo={{ componentStack: "" }}
116
+ fallback={fallback}
117
+ />
118
+ );
122
119
 
123
- return <ErrorDisplay error={error} errorInfo={{ componentStack: "Loader/Action Error" }} fallback={fallback} />;
120
+ return (
121
+ <ReactErrorBoundary resetKeys={[location.pathname]} FallbackComponent={ErrorBoundaryFallback}>
122
+ {children}
123
+ </ReactErrorBoundary>
124
+ );
124
125
  };
125
126
 
126
127
  export default ErrorBoundary;
@@ -19,7 +19,6 @@ import classNames from "classnames";
19
19
  import styled from "styled-components";
20
20
  import Loading from "./../Loading";
21
21
  import { ErrorNotification, Subtitle, Title } from "@scm-manager/ui-core";
22
- import ErrorBoundary from "../ErrorBoundary";
23
22
  import PageActions from "./PageActions";
24
23
 
25
24
  type Props = {
@@ -118,10 +117,8 @@ const Page: FC<Props> = ({ title, afterTitle, subtitle, loading, error, showCont
118
117
  <section className="section">
119
118
  <div className="container">
120
119
  {renderPageHeader()}
121
- <ErrorBoundary>
122
- <ErrorNotification error={error} />
123
- {renderContent()}
124
- </ErrorBoundary>
120
+ <ErrorNotification error={error} />
121
+ {renderContent()}
125
122
  </div>
126
123
  </section>
127
124
  );
@@ -23,7 +23,6 @@ import remark2rehype from "remark-rehype";
23
23
  import rehype2react from "rehype-react";
24
24
  import gfm from "remark-gfm";
25
25
  import { BinderContext } from "@scm-manager/ui-extensions";
26
- import ErrorBoundary from "../ErrorBoundary";
27
26
  import { create as createMarkdownHeadingRenderer } from "./MarkdownHeadingRenderer";
28
27
  import { create as createMarkdownLinkRenderer } from "./MarkdownLinkRenderer";
29
28
  import { create as createMarkdownImageRenderer } from "./MarkdownImageRenderer";
@@ -74,7 +73,7 @@ const xmlMarkupSample = `\`\`\`xml
74
73
  </your>
75
74
  \`\`\``;
76
75
 
77
- const MarkdownErrorNotification: FC = () => {
76
+ export const MarkdownErrorNotification: FC = () => {
78
77
  const [t] = useTranslation("commons");
79
78
  return (
80
79
  <Notification type="danger">
@@ -182,14 +181,14 @@ class LazyMarkdownView extends React.Component<Props, State> {
182
181
  if (!remarkRendererList.link) {
183
182
  // @ts-ignore
184
183
  const extensionPoints = this.context.getExtensions(
185
- "markdown-renderer.link.protocol"
184
+ "markdown-renderer.link.protocol",
186
185
  ) as ProtocolLinkRendererExtension[];
187
186
  protocolLinkRendererExtensions = extensionPoints.reduce<ProtocolLinkRendererExtensionMap>(
188
187
  (prev, { protocol, renderer }) => {
189
188
  prev[protocol] = renderer;
190
189
  return prev;
191
190
  },
192
- {}
191
+ {},
193
192
  );
194
193
  remarkRendererList.link = createMarkdownLinkRenderer(basePath, protocolLinkRendererExtensions);
195
194
  }
@@ -199,7 +198,7 @@ class LazyMarkdownView extends React.Component<Props, State> {
199
198
  }
200
199
 
201
200
  const remarkPlugins = [...mdastPlugins, createChangesetShortlinkParser(t), createValuelessTextAdapter()].map(
202
- createMdastPlugin
201
+ createMdastPlugin,
203
202
  );
204
203
 
205
204
  let processor = unified()
@@ -224,7 +223,7 @@ class LazyMarkdownView extends React.Component<Props, State> {
224
223
  protocols: {
225
224
  href: Object.keys(protocolLinkRendererExtensions),
226
225
  },
227
- })
226
+ }),
228
227
  )
229
228
  .use(rehype2react, {
230
229
  createElement: React.createElement,
@@ -235,14 +234,9 @@ class LazyMarkdownView extends React.Component<Props, State> {
235
234
  const renderedMarkdown: any = processor.processSync(content).result;
236
235
 
237
236
  return (
238
- <ErrorBoundary fallback={MarkdownErrorNotification}>
239
- <HorizontalScrollDiv
240
- ref={(el) => this.setState({ contentRef: el })}
241
- className={classNames("content", className)}
242
- >
243
- {renderedMarkdown}
244
- </HorizontalScrollDiv>
245
- </ErrorBoundary>
237
+ <HorizontalScrollDiv ref={(el) => this.setState({ contentRef: el })} className={classNames("content", className)}>
238
+ {renderedMarkdown}
239
+ </HorizontalScrollDiv>
246
240
  );
247
241
  }
248
242
  }