@scm-manager/ui-components 4.0.0-REACT19-20250913-143258 → 4.0.0-REACT19-20250915-121549
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-
|
|
3
|
+
"version": "4.0.0-REACT19-20250915-121549",
|
|
4
4
|
"description": "UI Components for SCM-Manager and its plugins",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"files": [
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"@scm-manager/jest-preset": "^2.15.0-alpha1",
|
|
38
38
|
"@scm-manager/prettier-config": "^2.12.0",
|
|
39
39
|
"@scm-manager/tsconfig": "^2.13.0",
|
|
40
|
-
"@scm-manager/ui-shortcuts": "4.0.0-REACT19-
|
|
41
|
-
"@scm-manager/ui-syntaxhighlighting": "4.0.0-REACT19-
|
|
42
|
-
"@scm-manager/ui-text": "4.0.0-REACT19-
|
|
43
|
-
"@scm-manager/ui-types": "4.0.0-REACT19-
|
|
40
|
+
"@scm-manager/ui-shortcuts": "4.0.0-REACT19-20250915-121549",
|
|
41
|
+
"@scm-manager/ui-syntaxhighlighting": "4.0.0-REACT19-20250915-121549",
|
|
42
|
+
"@scm-manager/ui-text": "4.0.0-REACT19-20250915-121549",
|
|
43
|
+
"@scm-manager/ui-types": "4.0.0-REACT19-20250915-121549",
|
|
44
44
|
"@storybook/addon-actions": "^9.0.8",
|
|
45
45
|
"@storybook/addon-docs": "^9.1.5",
|
|
46
46
|
"@storybook/addon-essentials": "^9.0.0-alpha.12",
|
|
@@ -67,15 +67,15 @@
|
|
|
67
67
|
"storybook-addon-themes": "^6.1.0"
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@scm-manager/ui-api": "4.0.0-REACT19-
|
|
71
|
-
"@scm-manager/ui-buttons": "4.0.0-REACT19-
|
|
72
|
-
"@scm-manager/ui-core": "4.0.0-REACT19-
|
|
73
|
-
"@scm-manager/ui-extensions": "4.0.0-REACT19-
|
|
74
|
-
"@scm-manager/ui-layout": "4.0.0-REACT19-
|
|
75
|
-
"@scm-manager/ui-overlays": "4.0.0-REACT19-
|
|
70
|
+
"@scm-manager/ui-api": "4.0.0-REACT19-20250915-121549",
|
|
71
|
+
"@scm-manager/ui-buttons": "4.0.0-REACT19-20250915-121549",
|
|
72
|
+
"@scm-manager/ui-core": "4.0.0-REACT19-20250915-121549",
|
|
73
|
+
"@scm-manager/ui-extensions": "4.0.0-REACT19-20250915-121549",
|
|
74
|
+
"@scm-manager/ui-layout": "4.0.0-REACT19-20250915-121549",
|
|
75
|
+
"@scm-manager/ui-overlays": "4.0.0-REACT19-20250915-121549",
|
|
76
76
|
"deepmerge": "^4.2.2",
|
|
77
77
|
"hast-util-sanitize": "^3.0.2",
|
|
78
|
-
"react-diff-view": "
|
|
78
|
+
"react-diff-view": "2.6.0",
|
|
79
79
|
"react-error-boundary": "^6.0.0",
|
|
80
80
|
"react-hook-form": "^7.33.1",
|
|
81
81
|
"react-select": "^2.1.2",
|
|
@@ -19,13 +19,13 @@ import { binder, extensionPoints } from "@scm-manager/ui-extensions";
|
|
|
19
19
|
import { NavLink } from "../navigation";
|
|
20
20
|
import { Route } from "react-router-dom";
|
|
21
21
|
import { useTranslation, WithTranslation, withTranslation } from "react-i18next";
|
|
22
|
-
import { Link, Links,
|
|
22
|
+
import { Link, Links, Repository } from "@scm-manager/ui-types";
|
|
23
23
|
import {
|
|
24
24
|
TitledGlobalSettingComponent,
|
|
25
25
|
TitledNamespaceSettingComponent,
|
|
26
26
|
TitledRepositorySettingComponent,
|
|
27
27
|
} from "./TitledSettings";
|
|
28
|
-
import { NAMESPACE_SUB_ROUTES,
|
|
28
|
+
import { NAMESPACE_SUB_ROUTES, REPOSITORY_SUB_ROUTES } from "@scm-manager/ui-core";
|
|
29
29
|
|
|
30
30
|
type GlobalRouteProps = {
|
|
31
31
|
url: string;
|
|
@@ -37,7 +37,7 @@ type RepositoryRouteProps = {
|
|
|
37
37
|
repository: Repository;
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
-
type RepositoryNavProps = WithTranslation & {
|
|
40
|
+
type RepositoryNavProps = WithTranslation & { absoluteRepoUrl: string };
|
|
41
41
|
|
|
42
42
|
type NamespaceNavProps = WithTranslation & { url: string };
|
|
43
43
|
|
|
@@ -119,8 +119,8 @@ class ConfigurationBinder {
|
|
|
119
119
|
};
|
|
120
120
|
|
|
121
121
|
// create NavigationLink with translated label
|
|
122
|
-
const RepoNavLink = withTranslation(this.i18nNamespace)(({ t,
|
|
123
|
-
return this.navLink(
|
|
122
|
+
const RepoNavLink = withTranslation(this.i18nNamespace)(({ t, absoluteRepoUrl }: RepositoryNavProps) => {
|
|
123
|
+
return this.navLink(absoluteRepoUrl + to, labelI18nKey, t);
|
|
124
124
|
});
|
|
125
125
|
|
|
126
126
|
// bind navigation link to extension point
|
|
@@ -144,7 +144,7 @@ class ConfigurationBinder {
|
|
|
144
144
|
to: string,
|
|
145
145
|
labelI18nKey: string,
|
|
146
146
|
linkName: string,
|
|
147
|
-
RepositoryComponent:
|
|
147
|
+
RepositoryComponent: ComponentType<object>,
|
|
148
148
|
sortKey?: string,
|
|
149
149
|
) {
|
|
150
150
|
// create predicate based on the link name of the current repository route
|
|
@@ -153,41 +153,37 @@ class ConfigurationBinder {
|
|
|
153
153
|
return props.repository && props.repository._links && props.repository._links[linkName];
|
|
154
154
|
};
|
|
155
155
|
|
|
156
|
+
const sanitizedTo = to.startsWith("/") ? to.substring(1) : to;
|
|
157
|
+
|
|
156
158
|
// create NavigationLink with translated label
|
|
157
|
-
const RepoNavLink = withTranslation(this.i18nNamespace)(({ t,
|
|
158
|
-
return this.navLink(
|
|
159
|
+
const RepoNavLink = withTranslation(this.i18nNamespace)(({ t, absoluteRepoUrl }: RepositoryNavProps) => {
|
|
160
|
+
return this.navLink(`${absoluteRepoUrl}/${REPOSITORY_SUB_ROUTES.SETTINGS}/${sanitizedTo}`, labelI18nKey, t, {
|
|
161
|
+
activeOnlyWhenExact: false,
|
|
162
|
+
});
|
|
159
163
|
});
|
|
160
164
|
|
|
161
165
|
// bind navigation link to extension point
|
|
162
166
|
binder.bind("repository.setting", RepoNavLink, repoPredicate, sortKey ?? linkName);
|
|
163
167
|
|
|
164
168
|
// route for global configuration, passes the current repository to component
|
|
165
|
-
const RepoRoute = ({
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
i18nNamespace={this.i18nNamespace}
|
|
173
|
-
label={labelI18nKey}
|
|
174
|
-
repository={repository}
|
|
175
|
-
>
|
|
176
|
-
<RepositoryComponent repository={repository} link={(link as Link).href} {...additionalProps} />
|
|
177
|
-
</TitledRepositorySettingComponent>,
|
|
178
|
-
);
|
|
179
|
-
}
|
|
169
|
+
const RepoRoute = ({ ...additionalProps }: RepositoryRouteProps) => {
|
|
170
|
+
return this.route(
|
|
171
|
+
"settings" + to,
|
|
172
|
+
<TitledRepositorySettingComponent i18nNamespace={this.i18nNamespace} label={labelI18nKey}>
|
|
173
|
+
<RepositoryComponent {...additionalProps} />
|
|
174
|
+
</TitledRepositorySettingComponent>,
|
|
175
|
+
);
|
|
180
176
|
};
|
|
181
177
|
|
|
182
178
|
// bind config route to extension point
|
|
183
|
-
binder.bind("repository.route", RepoRoute
|
|
179
|
+
binder.bind("repository.route", RepoRoute);
|
|
184
180
|
}
|
|
185
181
|
|
|
186
182
|
bindNamespaceSetting(
|
|
187
183
|
to: string,
|
|
188
184
|
labelI18nKey: string,
|
|
189
185
|
linkName: string,
|
|
190
|
-
ConfigurationComponent: ComponentType<
|
|
186
|
+
ConfigurationComponent: ComponentType<object>,
|
|
191
187
|
) {
|
|
192
188
|
const namespacePredicate = (props: extensionPoints.NamespaceSetting["props"]) =>
|
|
193
189
|
props.namespace && props.namespace._links && props.namespace._links[linkName];
|
|
@@ -200,20 +196,12 @@ class ConfigurationBinder {
|
|
|
200
196
|
binder.bind<extensionPoints.NamespaceSetting>("namespace.setting", NamespaceNavLink, namespacePredicate);
|
|
201
197
|
|
|
202
198
|
const NamespaceRoute = ({ ...additionalProps }: NamespaceNavProps) => {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
NAMESPACE_SUB_ROUTES.SETTINGS + to,
|
|
210
|
-
<TitledNamespaceSettingComponent i18nNamespace={this.i18nNamespace} label={labelI18nKey}>
|
|
211
|
-
<ConfigurationComponent namespace={namespace} link={(link as Link).href} {...additionalProps} />
|
|
212
|
-
</TitledNamespaceSettingComponent>,
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return null;
|
|
199
|
+
return this.route(
|
|
200
|
+
NAMESPACE_SUB_ROUTES.SETTINGS + to,
|
|
201
|
+
<TitledNamespaceSettingComponent i18nNamespace={this.i18nNamespace} label={labelI18nKey}>
|
|
202
|
+
<ConfigurationComponent {...additionalProps} />
|
|
203
|
+
</TitledNamespaceSettingComponent>,
|
|
204
|
+
);
|
|
217
205
|
};
|
|
218
206
|
|
|
219
207
|
binder.bind("namespace.route", NamespaceRoute);
|
|
@@ -16,8 +16,12 @@
|
|
|
16
16
|
|
|
17
17
|
import React, { FC, ReactNode } from "react";
|
|
18
18
|
import { useTranslation } from "react-i18next";
|
|
19
|
-
import {
|
|
20
|
-
|
|
19
|
+
import {
|
|
20
|
+
useDocumentTitle,
|
|
21
|
+
useDocumentTitleForRepository,
|
|
22
|
+
useNamespaceFromParams,
|
|
23
|
+
useRepositoryFromParams,
|
|
24
|
+
} from "@scm-manager/ui-core";
|
|
21
25
|
|
|
22
26
|
type GlobalProps = {
|
|
23
27
|
i18nNamespace: string;
|
|
@@ -35,16 +39,11 @@ export const TitledGlobalSettingComponent: FC<GlobalProps> = ({ children, i18nNa
|
|
|
35
39
|
type RepositoryProps = {
|
|
36
40
|
i18nNamespace: string;
|
|
37
41
|
label: string;
|
|
38
|
-
repository: Repository;
|
|
39
42
|
children?: ReactNode;
|
|
40
43
|
};
|
|
41
44
|
|
|
42
|
-
export const TitledRepositorySettingComponent: FC<RepositoryProps> = ({
|
|
43
|
-
|
|
44
|
-
i18nNamespace,
|
|
45
|
-
label,
|
|
46
|
-
repository,
|
|
47
|
-
}) => {
|
|
45
|
+
export const TitledRepositorySettingComponent: FC<RepositoryProps> = ({ children, i18nNamespace, label }) => {
|
|
46
|
+
const repository = useRepositoryFromParams();
|
|
48
47
|
const [t] = useTranslation(i18nNamespace);
|
|
49
48
|
const [commonTranslation] = useTranslation("commons");
|
|
50
49
|
useDocumentTitleForRepository(repository, t(label), commonTranslation("documentTitle.repositoryConfiguration"));
|
|
@@ -21,7 +21,7 @@ import { StyledHunk } from "./styledElements";
|
|
|
21
21
|
import LastHunkFooter from "./LastHunkFooter";
|
|
22
22
|
import { DiffExpandedCallback, DiffFileProps, ErrorHandler } from "./types";
|
|
23
23
|
import HunkFooter from "./HunkFooter";
|
|
24
|
-
// @ts-
|
|
24
|
+
// @ts-expect-error react-diff-view does not provide types with v2
|
|
25
25
|
import { Decoration, getChangeKey } from "react-diff-view";
|
|
26
26
|
import { collectHunkAnnotations, markConflicts } from "./helpers";
|
|
27
27
|
import HunkHeader from "./HunkHeader";
|
|
@@ -70,7 +70,7 @@ const DiffFileHunk: FC<Props> = ({
|
|
|
70
70
|
onClick(context);
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
|
-
[file, onClick]
|
|
73
|
+
[file, onClick],
|
|
74
74
|
);
|
|
75
75
|
|
|
76
76
|
const gutterEvents = useMemo(
|
|
@@ -78,7 +78,7 @@ const DiffFileHunk: FC<Props> = ({
|
|
|
78
78
|
onClick && {
|
|
79
79
|
onClick: (event: ChangeEvent) => handleClickEvent(event.change, hunk),
|
|
80
80
|
},
|
|
81
|
-
[handleClickEvent, hunk, onClick]
|
|
81
|
+
[handleClickEvent, hunk, onClick],
|
|
82
82
|
);
|
|
83
83
|
|
|
84
84
|
if (shouldMarkConflicts && hunk.changes) {
|
|
@@ -92,13 +92,13 @@ const DiffFileHunk: FC<Props> = ({
|
|
|
92
92
|
expandableHunk={expandableHunk}
|
|
93
93
|
diffExpanded={diffExpanded}
|
|
94
94
|
diffExpansionFailed={diffExpansionFailed}
|
|
95
|
-
|
|
95
|
+
/>,
|
|
96
96
|
);
|
|
97
97
|
} else if (i > 0) {
|
|
98
98
|
items.push(
|
|
99
99
|
<Decoration key={"decoration-" + hunk.content}>
|
|
100
100
|
<hr className="my-2" />
|
|
101
|
-
</Decoration
|
|
101
|
+
</Decoration>,
|
|
102
102
|
);
|
|
103
103
|
}
|
|
104
104
|
|
|
@@ -112,7 +112,11 @@ const DiffFileHunk: FC<Props> = ({
|
|
|
112
112
|
icon={hunkGutterHoverIcon}
|
|
113
113
|
actionable={!!gutterEvents}
|
|
114
114
|
highlightLineOnHover={highlightLineOnHover}
|
|
115
|
-
|
|
115
|
+
selectedChanges={[]}
|
|
116
|
+
generateAnchorID={() => undefined}
|
|
117
|
+
// @ts-expect-error react-diff-view does not provide types with v2
|
|
118
|
+
renderGutter={({ renderDefault, wrapInAnchor }) => wrapInAnchor(renderDefault())}
|
|
119
|
+
/>,
|
|
116
120
|
);
|
|
117
121
|
if (file._links?.lines) {
|
|
118
122
|
if (i === (file.hunks ?? []).length - 1) {
|
|
@@ -122,7 +126,7 @@ const DiffFileHunk: FC<Props> = ({
|
|
|
122
126
|
expandableHunk={expandableHunk}
|
|
123
127
|
diffExpanded={diffExpanded}
|
|
124
128
|
diffExpansionFailed={diffExpansionFailed}
|
|
125
|
-
|
|
129
|
+
/>,
|
|
126
130
|
);
|
|
127
131
|
} else {
|
|
128
132
|
items.push(
|
|
@@ -131,7 +135,7 @@ const DiffFileHunk: FC<Props> = ({
|
|
|
131
135
|
expandableHunk={expandableHunk}
|
|
132
136
|
diffExpanded={diffExpanded}
|
|
133
137
|
diffExpansionFailed={diffExpansionFailed}
|
|
134
|
-
|
|
138
|
+
/>,
|
|
135
139
|
);
|
|
136
140
|
}
|
|
137
141
|
}
|
|
@@ -77,7 +77,7 @@ const DiffFile: FC<Props> = ({
|
|
|
77
77
|
() =>
|
|
78
78
|
hasContent ||
|
|
79
79
|
(["add", "modify", "delete"].includes(file.type) && canDisplayBinaryFile(oldContentType, newContentType)),
|
|
80
|
-
[file, hasContent, newContentType, oldContentType]
|
|
80
|
+
[file, hasContent, newContentType, oldContentType],
|
|
81
81
|
);
|
|
82
82
|
const canRenderSideBySide = useMemo(() => hasContent && file.type === "modify", [file, hasContent]);
|
|
83
83
|
|
|
@@ -126,7 +126,7 @@ const DiffFile: FC<Props> = ({
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
},
|
|
129
|
-
[collapsed, file, canRenderContent, isCollapsedProp, onCollapseStateChange, stickyHeader]
|
|
129
|
+
[collapsed, file, canRenderContent, isCollapsedProp, onCollapseStateChange, stickyHeader],
|
|
130
130
|
);
|
|
131
131
|
|
|
132
132
|
const toggleSideBySide = useCallback((callback: () => void) => {
|
|
@@ -139,7 +139,7 @@ const DiffFile: FC<Props> = ({
|
|
|
139
139
|
setWhitespace(!whitespace);
|
|
140
140
|
callback();
|
|
141
141
|
},
|
|
142
|
-
[whitespace]
|
|
142
|
+
[whitespace],
|
|
143
143
|
);
|
|
144
144
|
|
|
145
145
|
const sideBySideToggle = useMemo(
|
|
@@ -161,7 +161,7 @@ const DiffFile: FC<Props> = ({
|
|
|
161
161
|
)}
|
|
162
162
|
</MenuContext.Consumer>
|
|
163
163
|
),
|
|
164
|
-
[canRenderSideBySide, sideBySide, t, toggleSideBySide]
|
|
164
|
+
[canRenderSideBySide, sideBySide, t, toggleSideBySide],
|
|
165
165
|
);
|
|
166
166
|
|
|
167
167
|
const whitespaceToggle = useMemo(
|
|
@@ -183,7 +183,7 @@ const DiffFile: FC<Props> = ({
|
|
|
183
183
|
)}
|
|
184
184
|
</MenuContext.Consumer>
|
|
185
185
|
),
|
|
186
|
-
[hasContent, t, toggleWhiteSpace, whitespace]
|
|
186
|
+
[hasContent, t, toggleWhiteSpace, whitespace],
|
|
187
187
|
);
|
|
188
188
|
|
|
189
189
|
const errorModal = useMemo(
|
|
@@ -196,7 +196,7 @@ const DiffFile: FC<Props> = ({
|
|
|
196
196
|
active={true}
|
|
197
197
|
/>
|
|
198
198
|
) : null,
|
|
199
|
-
[expansionError, t]
|
|
199
|
+
[expansionError, t],
|
|
200
200
|
);
|
|
201
201
|
|
|
202
202
|
const innerContent = useMemo(
|
|
@@ -253,7 +253,7 @@ const DiffFile: FC<Props> = ({
|
|
|
253
253
|
sideBySide,
|
|
254
254
|
whitespace,
|
|
255
255
|
viewType,
|
|
256
|
-
]
|
|
256
|
+
],
|
|
257
257
|
);
|
|
258
258
|
|
|
259
259
|
const body = useMemo(() => (!isCollapsed ? innerContent : null), [innerContent, isCollapsed]);
|
|
@@ -266,7 +266,7 @@ const DiffFile: FC<Props> = ({
|
|
|
266
266
|
modalBody={<MarginlessModalContent>{innerContent}</MarginlessModalContent>}
|
|
267
267
|
/>
|
|
268
268
|
) : null,
|
|
269
|
-
[canRenderContent, file, innerContent]
|
|
269
|
+
[canRenderContent, file, innerContent],
|
|
270
270
|
);
|
|
271
271
|
|
|
272
272
|
const collapseIcon = useMemo(
|
|
@@ -276,7 +276,7 @@ const DiffFile: FC<Props> = ({
|
|
|
276
276
|
) : (
|
|
277
277
|
<Icon alt={t("diff.hideContent")}>angle-down</Icon>
|
|
278
278
|
),
|
|
279
|
-
[isCollapsed, t]
|
|
279
|
+
[isCollapsed, t],
|
|
280
280
|
);
|
|
281
281
|
|
|
282
282
|
return (
|