@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 +6 -6
- package/src/ErrorBoundary.tsx +40 -39
- package/src/layout/Page.tsx +2 -5
- package/src/markdown/LazyMarkdownView.tsx +8 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scm-manager/ui-components",
|
|
3
|
-
"version": "4.0.0-REACT19-20251104-
|
|
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-
|
|
38
|
-
"@scm-manager/ui-types": "4.0.0-REACT19-20251104-
|
|
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-
|
|
70
|
-
"@scm-manager/ui-core": "4.0.0-REACT19-20251104-
|
|
71
|
-
"@scm-manager/ui-extensions": "4.0.0-REACT19-20251104-
|
|
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",
|
package/src/ErrorBoundary.tsx
CHANGED
|
@@ -15,26 +15,34 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import React, { FC, ReactNode, useEffect } from "react";
|
|
18
|
-
import {
|
|
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
|
|
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
|
|
37
|
-
fallback?: React.ComponentType<
|
|
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
|
|
102
|
+
return <FallbackComponent {...fallbackProps} />;
|
|
92
103
|
}
|
|
93
|
-
|
|
94
104
|
return <ErrorNotification error={error} />;
|
|
95
105
|
};
|
|
96
106
|
|
|
97
|
-
const ErrorBoundary: FC<
|
|
98
|
-
const rawError = useRouteError();
|
|
107
|
+
const ErrorBoundary: FC<ExportedProps> = ({ children, fallback }) => {
|
|
99
108
|
const location = useLocation();
|
|
100
109
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
|
120
|
+
return (
|
|
121
|
+
<ReactErrorBoundary resetKeys={[location.pathname]} FallbackComponent={ErrorBoundaryFallback}>
|
|
122
|
+
{children}
|
|
123
|
+
</ReactErrorBoundary>
|
|
124
|
+
);
|
|
124
125
|
};
|
|
125
126
|
|
|
126
127
|
export default ErrorBoundary;
|
package/src/layout/Page.tsx
CHANGED
|
@@ -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
|
-
<
|
|
122
|
-
|
|
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
|
-
<
|
|
239
|
-
|
|
240
|
-
|
|
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
|
}
|