@stoked-ui/github 0.1.0-alpha.11.2 → 0.1.0-alpha.13.1
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/GithubBranch/GithubBranch.d.ts +3 -2
- package/GithubBranch/GithubBranch.js +4 -2
- package/GithubCalendar/GithubCalendar.js +40 -4
- package/GithubEvents/EventTypes/PullRequest/FileChanges.d.ts +3 -1
- package/GithubEvents/EventTypes/PullRequest/FileChanges.js +161 -39
- package/GithubEvents/EventTypes/PullRequest/PullRequestView.d.ts +3 -1
- package/GithubEvents/EventTypes/PullRequest/PullRequestView.js +5 -4
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/modern/GithubBranch/GithubBranch.js +4 -2
- package/modern/GithubCalendar/GithubCalendar.js +40 -4
- package/modern/GithubEvents/EventTypes/PullRequest/FileChanges.js +161 -39
- package/modern/GithubEvents/EventTypes/PullRequest/PullRequestView.js +5 -4
- package/modern/index.js +1 -1
- package/node/GithubBranch/GithubBranch.js +4 -2
- package/node/GithubCalendar/GithubCalendar.js +40 -3
- package/node/GithubEvents/EventTypes/PullRequest/FileChanges.js +166 -43
- package/node/GithubEvents/EventTypes/PullRequest/PullRequestView.js +6 -3
- package/node/index.js +1 -1
- package/package.json +2 -2
- package/types/github.d.ts +9 -0
- package/stoked-ui-github-0.1.0-alpha.11.2.tgz +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { GithubBranchData } from '../types/github';
|
|
2
|
+
import { GithubBranchData, GithubFileHighlight } from '../types/github';
|
|
3
3
|
export interface GithubBranchProps {
|
|
4
4
|
owner: string;
|
|
5
5
|
repo: string;
|
|
@@ -8,5 +8,6 @@ export interface GithubBranchProps {
|
|
|
8
8
|
apiUrl?: string;
|
|
9
9
|
private?: boolean;
|
|
10
10
|
data?: GithubBranchData;
|
|
11
|
+
highlights?: GithubFileHighlight[];
|
|
11
12
|
}
|
|
12
|
-
export default function GithubBranch({ owner, repo, base, head, apiUrl, private: privateMode, data, }: GithubBranchProps): React.JSX.Element;
|
|
13
|
+
export default function GithubBranch({ owner, repo, base, head, apiUrl, private: privateMode, data, highlights, }: GithubBranchProps): React.JSX.Element;
|
|
@@ -52,7 +52,8 @@ export default function GithubBranch({
|
|
|
52
52
|
head,
|
|
53
53
|
apiUrl,
|
|
54
54
|
private: privateMode = false,
|
|
55
|
-
data
|
|
55
|
+
data,
|
|
56
|
+
highlights
|
|
56
57
|
}) {
|
|
57
58
|
const [branchData, setBranchData] = React.useState(data || null);
|
|
58
59
|
const [loading, setLoading] = React.useState(!data && !privateMode);
|
|
@@ -170,7 +171,8 @@ export default function GithubBranch({
|
|
|
170
171
|
title: "",
|
|
171
172
|
number: 0,
|
|
172
173
|
commits: branchData.commits,
|
|
173
|
-
files: branchData.files
|
|
174
|
+
files: branchData.files,
|
|
175
|
+
highlights: highlights
|
|
174
176
|
})]
|
|
175
177
|
}) : null]
|
|
176
178
|
});
|
|
@@ -3,9 +3,45 @@ import * as React from 'react';
|
|
|
3
3
|
import { Box } from "@mui/material";
|
|
4
4
|
import { ActivityCalendar } from "react-activity-calendar";
|
|
5
5
|
import { useTheme } from '@mui/material/styles';
|
|
6
|
-
import { useResize } from '@stoked-ui/common';
|
|
7
|
-
import { useResizeWindow } from '@stoked-ui/common';
|
|
8
6
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
+
function useWindowSize() {
|
|
8
|
+
const [size, setSize] = React.useState(() => {
|
|
9
|
+
if (typeof window === 'undefined') {
|
|
10
|
+
return [0, 0];
|
|
11
|
+
}
|
|
12
|
+
return [window.innerWidth, window.innerHeight];
|
|
13
|
+
});
|
|
14
|
+
React.useEffect(() => {
|
|
15
|
+
if (typeof window === 'undefined') {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
const handleResize = () => {
|
|
19
|
+
setSize([window.innerWidth, window.innerHeight]);
|
|
20
|
+
};
|
|
21
|
+
window.addEventListener('resize', handleResize);
|
|
22
|
+
handleResize();
|
|
23
|
+
return () => window.removeEventListener('resize', handleResize);
|
|
24
|
+
}, []);
|
|
25
|
+
return size;
|
|
26
|
+
}
|
|
27
|
+
function useElementSize(elementRef) {
|
|
28
|
+
const [size, setSize] = React.useState({
|
|
29
|
+
width: undefined,
|
|
30
|
+
height: undefined
|
|
31
|
+
});
|
|
32
|
+
React.useEffect(() => {
|
|
33
|
+
const handleResize = () => {
|
|
34
|
+
setSize({
|
|
35
|
+
width: elementRef.current ? elementRef.current.offsetWidth : undefined,
|
|
36
|
+
height: elementRef.current ? elementRef.current.offsetHeight : undefined
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
handleResize();
|
|
40
|
+
window.addEventListener('resize', handleResize);
|
|
41
|
+
return () => window.removeEventListener('resize', handleResize);
|
|
42
|
+
}, [elementRef]);
|
|
43
|
+
return size;
|
|
44
|
+
}
|
|
9
45
|
function formatActivityDate(date) {
|
|
10
46
|
const year = date.getFullYear();
|
|
11
47
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
@@ -70,8 +106,8 @@ export default function GithubCalendar({
|
|
|
70
106
|
const [labelsTimer, setLabelsTimer] = React.useState(null);
|
|
71
107
|
const theme = useTheme();
|
|
72
108
|
const elementRef = React.useRef(null);
|
|
73
|
-
const [windowWidth
|
|
74
|
-
const elemSize =
|
|
109
|
+
const [windowWidth] = useWindowSize();
|
|
110
|
+
const elemSize = useElementSize(elementRef);
|
|
75
111
|
React.useEffect(() => {
|
|
76
112
|
if (inputBlockSize) {
|
|
77
113
|
return;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { GithubFileHighlight } from '../../../types/github';
|
|
2
3
|
interface FileChange {
|
|
3
4
|
path: string;
|
|
4
5
|
type: 'added' | 'modified' | 'deleted';
|
|
@@ -12,6 +13,7 @@ interface FileChange {
|
|
|
12
13
|
}
|
|
13
14
|
interface FileChangesProps {
|
|
14
15
|
files: FileChange[];
|
|
16
|
+
highlights?: GithubFileHighlight[];
|
|
15
17
|
}
|
|
16
|
-
export default function FileChanges({ files }: FileChangesProps): React.JSX.Element;
|
|
18
|
+
export default function FileChanges({ files, highlights }: FileChangesProps): React.JSX.Element;
|
|
17
19
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
-
var _Chip, _Chip2, _Chip3, _FileIcon;
|
|
2
|
+
var _Chip, _Chip2, _Chip3, _FileIcon, _Chip4, _Typography;
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import Box from '@mui/material/Box';
|
|
5
5
|
import Typography from '@mui/material/Typography';
|
|
@@ -11,7 +11,7 @@ import FileIcon from '@mui/icons-material/InsertDriveFile';
|
|
|
11
11
|
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
|
12
12
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
13
13
|
import Chip from '@mui/material/Chip';
|
|
14
|
-
|
|
14
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
15
15
|
// const StyledTreeItem = styled(TreeItem)((props) => ({
|
|
16
16
|
// '& .MuiTreeItem-content': {
|
|
17
17
|
// padding: props.theme.spacing(1),
|
|
@@ -26,7 +26,7 @@ import Chip from '@mui/material/Chip';
|
|
|
26
26
|
// },
|
|
27
27
|
// },
|
|
28
28
|
// }));
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
const DiffView = styled(Box)(({
|
|
31
31
|
theme
|
|
32
32
|
}) => ({
|
|
@@ -66,8 +66,83 @@ const DiffLine = styled(Box, {
|
|
|
66
66
|
// children?: TreeNode[];
|
|
67
67
|
// }
|
|
68
68
|
|
|
69
|
+
function isGroupHighlight(highlight) {
|
|
70
|
+
return 'files' in highlight;
|
|
71
|
+
}
|
|
72
|
+
function normalizeHighlights(files, highlights = []) {
|
|
73
|
+
const fileMap = new Map(files.map(file => [file.path, file]));
|
|
74
|
+
const claimedPaths = new Set();
|
|
75
|
+
const groups = [];
|
|
76
|
+
highlights.forEach(highlight => {
|
|
77
|
+
const paths = isGroupHighlight(highlight) ? highlight.files : [highlight.file];
|
|
78
|
+
const matchedFiles = paths.map(path => fileMap.get(path)).filter(file => Boolean(file)).filter(file => {
|
|
79
|
+
if (claimedPaths.has(file.path)) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
claimedPaths.add(file.path);
|
|
83
|
+
return true;
|
|
84
|
+
});
|
|
85
|
+
if (matchedFiles.length > 0) {
|
|
86
|
+
groups.push({
|
|
87
|
+
files: matchedFiles,
|
|
88
|
+
comment: highlight.comment
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
highlightedGroups: groups,
|
|
94
|
+
remainingFiles: files.filter(file => !claimedPaths.has(file.path))
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function renderFileLabel(file) {
|
|
98
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
99
|
+
sx: {
|
|
100
|
+
display: 'flex',
|
|
101
|
+
alignItems: 'center',
|
|
102
|
+
gap: 1
|
|
103
|
+
},
|
|
104
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
105
|
+
variant: "body2",
|
|
106
|
+
children: file.path
|
|
107
|
+
}), /*#__PURE__*/_jsxs(Typography, {
|
|
108
|
+
variant: "caption",
|
|
109
|
+
color: "text.secondary",
|
|
110
|
+
children: ["+", file.additions, " -", file.deletions]
|
|
111
|
+
})]
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
function renderFileNode({
|
|
115
|
+
file,
|
|
116
|
+
index,
|
|
117
|
+
getFileIcon
|
|
118
|
+
}) {
|
|
119
|
+
const itemId = `file-${index}-${file.path.replace(/[^a-zA-Z0-9]/g, '-')}`;
|
|
120
|
+
return /*#__PURE__*/_jsx(TreeItem, {
|
|
121
|
+
itemId: itemId,
|
|
122
|
+
label: /*#__PURE__*/_jsxs(Box, {
|
|
123
|
+
sx: {
|
|
124
|
+
display: 'flex',
|
|
125
|
+
alignItems: 'center',
|
|
126
|
+
gap: 1
|
|
127
|
+
},
|
|
128
|
+
children: [getFileIcon(file.type), renderFileLabel(file)]
|
|
129
|
+
}),
|
|
130
|
+
children: /*#__PURE__*/_jsx(Box, {
|
|
131
|
+
sx: {
|
|
132
|
+
p: '16px'
|
|
133
|
+
},
|
|
134
|
+
children: /*#__PURE__*/_jsx(DiffView, {
|
|
135
|
+
children: file.diff.map((line, diffIndex) => /*#__PURE__*/_jsx(DiffLine, {
|
|
136
|
+
type: line.type,
|
|
137
|
+
children: line.content
|
|
138
|
+
}, `${itemId}-line-${diffIndex}`))
|
|
139
|
+
})
|
|
140
|
+
})
|
|
141
|
+
}, itemId);
|
|
142
|
+
}
|
|
69
143
|
export default function FileChanges({
|
|
70
|
-
files
|
|
144
|
+
files,
|
|
145
|
+
highlights
|
|
71
146
|
}) {
|
|
72
147
|
const [expanded, setExpanded] = React.useState([]);
|
|
73
148
|
const [selected, setSelected] = React.useState([]);
|
|
@@ -101,6 +176,10 @@ export default function FileChanges({
|
|
|
101
176
|
return _FileIcon || (_FileIcon = /*#__PURE__*/_jsx(FileIcon, {}));
|
|
102
177
|
}
|
|
103
178
|
};
|
|
179
|
+
const {
|
|
180
|
+
highlightedGroups,
|
|
181
|
+
remainingFiles
|
|
182
|
+
} = React.useMemo(() => normalizeHighlights(files, highlights), [files, highlights]);
|
|
104
183
|
|
|
105
184
|
// Transform files into tree nodes
|
|
106
185
|
// const items: TreeNode[] = files.map((file, index) => ({
|
|
@@ -134,8 +213,78 @@ export default function FileChanges({
|
|
|
134
213
|
// </Box>
|
|
135
214
|
// );
|
|
136
215
|
|
|
137
|
-
return /*#__PURE__*/
|
|
138
|
-
children: /*#__PURE__*/
|
|
216
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
217
|
+
children: [highlightedGroups.length > 0 ? /*#__PURE__*/_jsxs(Box, {
|
|
218
|
+
sx: {
|
|
219
|
+
mb: 3,
|
|
220
|
+
p: 2,
|
|
221
|
+
border: theme => `1px solid ${theme.palette.warning.main}`,
|
|
222
|
+
borderRadius: 2,
|
|
223
|
+
backgroundColor: 'action.hover'
|
|
224
|
+
},
|
|
225
|
+
children: [/*#__PURE__*/_jsxs(Box, {
|
|
226
|
+
sx: {
|
|
227
|
+
display: 'flex',
|
|
228
|
+
alignItems: 'center',
|
|
229
|
+
gap: 1,
|
|
230
|
+
mb: 1.5
|
|
231
|
+
},
|
|
232
|
+
children: [_Chip4 || (_Chip4 = /*#__PURE__*/_jsx(Chip, {
|
|
233
|
+
label: "Highlighted files",
|
|
234
|
+
size: "small",
|
|
235
|
+
color: "warning"
|
|
236
|
+
})), _Typography || (_Typography = /*#__PURE__*/_jsx(Typography, {
|
|
237
|
+
variant: "caption",
|
|
238
|
+
color: "text.secondary",
|
|
239
|
+
children: "Pulled out for focused review"
|
|
240
|
+
}))]
|
|
241
|
+
}), highlightedGroups.map((group, groupIndex) => /*#__PURE__*/_jsxs(Box, {
|
|
242
|
+
sx: {
|
|
243
|
+
mb: groupIndex === highlightedGroups.length - 1 ? 0 : 2,
|
|
244
|
+
p: 1.5,
|
|
245
|
+
borderRadius: 2,
|
|
246
|
+
border: '1px solid',
|
|
247
|
+
borderColor: 'divider',
|
|
248
|
+
backgroundColor: 'background.paper'
|
|
249
|
+
},
|
|
250
|
+
children: [group.comment ? /*#__PURE__*/_jsx(Typography, {
|
|
251
|
+
variant: "body2",
|
|
252
|
+
color: "text.secondary",
|
|
253
|
+
sx: {
|
|
254
|
+
mb: 1.5
|
|
255
|
+
},
|
|
256
|
+
children: group.comment
|
|
257
|
+
}) : null, /*#__PURE__*/_jsx(SimpleTreeView, {
|
|
258
|
+
slots: {
|
|
259
|
+
collapseIcon: ExpandMoreIcon,
|
|
260
|
+
expandIcon: ChevronRightIcon
|
|
261
|
+
},
|
|
262
|
+
defaultExpandedItems: group.files.map((file, index) => `highlight-${groupIndex}-${index}-${file.path.replace(/[^a-zA-Z0-9]/g, '-')}`),
|
|
263
|
+
children: group.files.map((file, index) => /*#__PURE__*/_jsx(TreeItem, {
|
|
264
|
+
itemId: `highlight-${groupIndex}-${index}-${file.path.replace(/[^a-zA-Z0-9]/g, '-')}`,
|
|
265
|
+
label: /*#__PURE__*/_jsxs(Box, {
|
|
266
|
+
sx: {
|
|
267
|
+
display: 'flex',
|
|
268
|
+
alignItems: 'center',
|
|
269
|
+
gap: 1
|
|
270
|
+
},
|
|
271
|
+
children: [getFileIcon(file.type), renderFileLabel(file)]
|
|
272
|
+
}),
|
|
273
|
+
children: /*#__PURE__*/_jsx(Box, {
|
|
274
|
+
sx: {
|
|
275
|
+
p: '16px'
|
|
276
|
+
},
|
|
277
|
+
children: /*#__PURE__*/_jsx(DiffView, {
|
|
278
|
+
children: file.diff.map((line, diffIndex) => /*#__PURE__*/_jsx(DiffLine, {
|
|
279
|
+
type: line.type,
|
|
280
|
+
children: line.content
|
|
281
|
+
}, `highlight-${groupIndex}-${index}-line-${diffIndex}`))
|
|
282
|
+
})
|
|
283
|
+
})
|
|
284
|
+
}, `highlight-${groupIndex}-${index}-${file.path}`))
|
|
285
|
+
})]
|
|
286
|
+
}, `highlight-group-${groupIndex}`))]
|
|
287
|
+
}) : null, /*#__PURE__*/_jsx(SimpleTreeView, {
|
|
139
288
|
slots: {
|
|
140
289
|
collapseIcon: ExpandMoreIcon,
|
|
141
290
|
expandIcon: ChevronRightIcon
|
|
@@ -145,38 +294,11 @@ export default function FileChanges({
|
|
|
145
294
|
onExpandedItemsChange: handleToggle,
|
|
146
295
|
onSelectedItemsChange: handleSelect,
|
|
147
296
|
multiSelect: true,
|
|
148
|
-
children:
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
display: 'flex',
|
|
155
|
-
alignItems: 'center',
|
|
156
|
-
gap: 1
|
|
157
|
-
},
|
|
158
|
-
children: [getFileIcon(file.type), /*#__PURE__*/_jsx(Typography, {
|
|
159
|
-
variant: "body2",
|
|
160
|
-
children: file.path
|
|
161
|
-
}), /*#__PURE__*/_jsxs(Typography, {
|
|
162
|
-
variant: "caption",
|
|
163
|
-
color: "text.secondary",
|
|
164
|
-
children: ["+", file.additions, " -", file.deletions]
|
|
165
|
-
})]
|
|
166
|
-
}),
|
|
167
|
-
children: /*#__PURE__*/_jsx(Box, {
|
|
168
|
-
sx: {
|
|
169
|
-
p: '16px'
|
|
170
|
-
},
|
|
171
|
-
children: /*#__PURE__*/_jsx(DiffView, {
|
|
172
|
-
children: file.diff.map((line, index) => /*#__PURE__*/_jsx(DiffLine, {
|
|
173
|
-
type: line.type,
|
|
174
|
-
children: line.content
|
|
175
|
-
}, `${itemId}-line-${index}`))
|
|
176
|
-
})
|
|
177
|
-
})
|
|
178
|
-
}, itemId);
|
|
179
|
-
})
|
|
180
|
-
})
|
|
297
|
+
children: remainingFiles.map((file, index) => renderFileNode({
|
|
298
|
+
file,
|
|
299
|
+
index,
|
|
300
|
+
getFileIcon
|
|
301
|
+
}))
|
|
302
|
+
})]
|
|
181
303
|
});
|
|
182
304
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { GithubFileHighlight } from '../../../types/github';
|
|
2
3
|
interface PullRequestViewProps {
|
|
3
4
|
title: string;
|
|
4
5
|
number: number;
|
|
@@ -24,6 +25,7 @@ interface PullRequestViewProps {
|
|
|
24
25
|
}>;
|
|
25
26
|
}>;
|
|
26
27
|
onCheckout?: (hash?: string) => void;
|
|
28
|
+
highlights?: GithubFileHighlight[];
|
|
27
29
|
}
|
|
28
|
-
export default function PullRequestView({ title, number, commits, files, onCheckout, }: PullRequestViewProps): React.JSX.Element;
|
|
30
|
+
export default function PullRequestView({ title, number, commits, files, onCheckout, highlights, }: PullRequestViewProps): React.JSX.Element;
|
|
29
31
|
export {};
|
|
@@ -9,9 +9,8 @@ import Typography from '@mui/material/Typography';
|
|
|
9
9
|
import { styled } from '@mui/material/styles';
|
|
10
10
|
import CommitsList from './CommitsList';
|
|
11
11
|
import FileChanges from './FileChanges';
|
|
12
|
-
|
|
13
|
-
// Custom styled components to match GitHub's UI
|
|
14
12
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
// Custom styled components to match GitHub's UI
|
|
15
14
|
const StyledTabs = styled(Tabs)(({
|
|
16
15
|
theme
|
|
17
16
|
}) => ({
|
|
@@ -63,7 +62,8 @@ export default function PullRequestView({
|
|
|
63
62
|
number,
|
|
64
63
|
commits,
|
|
65
64
|
files,
|
|
66
|
-
onCheckout
|
|
65
|
+
onCheckout,
|
|
66
|
+
highlights
|
|
67
67
|
}) {
|
|
68
68
|
const [tabValue, setTabValue] = React.useState(0);
|
|
69
69
|
const handleTabChange = (event, newValue) => {
|
|
@@ -125,7 +125,8 @@ export default function PullRequestView({
|
|
|
125
125
|
})
|
|
126
126
|
})
|
|
127
127
|
}), /*#__PURE__*/_jsx(FileChanges, {
|
|
128
|
-
files: files
|
|
128
|
+
files: files,
|
|
129
|
+
highlights: highlights
|
|
129
130
|
})]
|
|
130
131
|
})]
|
|
131
132
|
});
|
package/index.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ export { default as GithubCommit } from './GithubCommit';
|
|
|
4
4
|
export { default as GithubEvents } from './GithubEvents';
|
|
5
5
|
export { createGithubBranchHandler, createGithubCommitHandler, createGithubContributionsHandler, createGithubEventsHandler, getBranchCompareDetails, getCommitDetails, getGithubContributions, getGithubEvents, getPullRequestDetails, githubEventsQuery, } from './apiHandlers';
|
|
6
6
|
export type { EventsQuery } from './apiHandlers';
|
|
7
|
-
export type { GithubBranchData, GithubCommitData } from './types/github';
|
|
7
|
+
export type { GithubBranchData, GithubCommitData, GithubFileHighlight } from './types/github';
|
package/index.js
CHANGED
|
@@ -52,7 +52,8 @@ export default function GithubBranch({
|
|
|
52
52
|
head,
|
|
53
53
|
apiUrl,
|
|
54
54
|
private: privateMode = false,
|
|
55
|
-
data
|
|
55
|
+
data,
|
|
56
|
+
highlights
|
|
56
57
|
}) {
|
|
57
58
|
const [branchData, setBranchData] = React.useState(data || null);
|
|
58
59
|
const [loading, setLoading] = React.useState(!data && !privateMode);
|
|
@@ -170,7 +171,8 @@ export default function GithubBranch({
|
|
|
170
171
|
title: "",
|
|
171
172
|
number: 0,
|
|
172
173
|
commits: branchData.commits,
|
|
173
|
-
files: branchData.files
|
|
174
|
+
files: branchData.files,
|
|
175
|
+
highlights: highlights
|
|
174
176
|
})]
|
|
175
177
|
}) : null]
|
|
176
178
|
});
|
|
@@ -3,9 +3,45 @@ import * as React from 'react';
|
|
|
3
3
|
import { Box } from "@mui/material";
|
|
4
4
|
import { ActivityCalendar } from "react-activity-calendar";
|
|
5
5
|
import { useTheme } from '@mui/material/styles';
|
|
6
|
-
import { useResize } from '@stoked-ui/common';
|
|
7
|
-
import { useResizeWindow } from '@stoked-ui/common';
|
|
8
6
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
+
function useWindowSize() {
|
|
8
|
+
const [size, setSize] = React.useState(() => {
|
|
9
|
+
if (typeof window === 'undefined') {
|
|
10
|
+
return [0, 0];
|
|
11
|
+
}
|
|
12
|
+
return [window.innerWidth, window.innerHeight];
|
|
13
|
+
});
|
|
14
|
+
React.useEffect(() => {
|
|
15
|
+
if (typeof window === 'undefined') {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
const handleResize = () => {
|
|
19
|
+
setSize([window.innerWidth, window.innerHeight]);
|
|
20
|
+
};
|
|
21
|
+
window.addEventListener('resize', handleResize);
|
|
22
|
+
handleResize();
|
|
23
|
+
return () => window.removeEventListener('resize', handleResize);
|
|
24
|
+
}, []);
|
|
25
|
+
return size;
|
|
26
|
+
}
|
|
27
|
+
function useElementSize(elementRef) {
|
|
28
|
+
const [size, setSize] = React.useState({
|
|
29
|
+
width: undefined,
|
|
30
|
+
height: undefined
|
|
31
|
+
});
|
|
32
|
+
React.useEffect(() => {
|
|
33
|
+
const handleResize = () => {
|
|
34
|
+
setSize({
|
|
35
|
+
width: elementRef.current ? elementRef.current.offsetWidth : undefined,
|
|
36
|
+
height: elementRef.current ? elementRef.current.offsetHeight : undefined
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
handleResize();
|
|
40
|
+
window.addEventListener('resize', handleResize);
|
|
41
|
+
return () => window.removeEventListener('resize', handleResize);
|
|
42
|
+
}, [elementRef]);
|
|
43
|
+
return size;
|
|
44
|
+
}
|
|
9
45
|
function formatActivityDate(date) {
|
|
10
46
|
const year = date.getFullYear();
|
|
11
47
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
@@ -70,8 +106,8 @@ export default function GithubCalendar({
|
|
|
70
106
|
const [labelsTimer, setLabelsTimer] = React.useState(null);
|
|
71
107
|
const theme = useTheme();
|
|
72
108
|
const elementRef = React.useRef(null);
|
|
73
|
-
const [windowWidth
|
|
74
|
-
const elemSize =
|
|
109
|
+
const [windowWidth] = useWindowSize();
|
|
110
|
+
const elemSize = useElementSize(elementRef);
|
|
75
111
|
React.useEffect(() => {
|
|
76
112
|
if (inputBlockSize) {
|
|
77
113
|
return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
-
var _Chip, _Chip2, _Chip3, _FileIcon;
|
|
2
|
+
var _Chip, _Chip2, _Chip3, _FileIcon, _Chip4, _Typography;
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import Box from '@mui/material/Box';
|
|
5
5
|
import Typography from '@mui/material/Typography';
|
|
@@ -11,7 +11,7 @@ import FileIcon from '@mui/icons-material/InsertDriveFile';
|
|
|
11
11
|
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
|
12
12
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
13
13
|
import Chip from '@mui/material/Chip';
|
|
14
|
-
|
|
14
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
15
15
|
// const StyledTreeItem = styled(TreeItem)((props) => ({
|
|
16
16
|
// '& .MuiTreeItem-content': {
|
|
17
17
|
// padding: props.theme.spacing(1),
|
|
@@ -26,7 +26,7 @@ import Chip from '@mui/material/Chip';
|
|
|
26
26
|
// },
|
|
27
27
|
// },
|
|
28
28
|
// }));
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
const DiffView = styled(Box)(({
|
|
31
31
|
theme
|
|
32
32
|
}) => ({
|
|
@@ -66,8 +66,83 @@ const DiffLine = styled(Box, {
|
|
|
66
66
|
// children?: TreeNode[];
|
|
67
67
|
// }
|
|
68
68
|
|
|
69
|
+
function isGroupHighlight(highlight) {
|
|
70
|
+
return 'files' in highlight;
|
|
71
|
+
}
|
|
72
|
+
function normalizeHighlights(files, highlights = []) {
|
|
73
|
+
const fileMap = new Map(files.map(file => [file.path, file]));
|
|
74
|
+
const claimedPaths = new Set();
|
|
75
|
+
const groups = [];
|
|
76
|
+
highlights.forEach(highlight => {
|
|
77
|
+
const paths = isGroupHighlight(highlight) ? highlight.files : [highlight.file];
|
|
78
|
+
const matchedFiles = paths.map(path => fileMap.get(path)).filter(file => Boolean(file)).filter(file => {
|
|
79
|
+
if (claimedPaths.has(file.path)) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
claimedPaths.add(file.path);
|
|
83
|
+
return true;
|
|
84
|
+
});
|
|
85
|
+
if (matchedFiles.length > 0) {
|
|
86
|
+
groups.push({
|
|
87
|
+
files: matchedFiles,
|
|
88
|
+
comment: highlight.comment
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
highlightedGroups: groups,
|
|
94
|
+
remainingFiles: files.filter(file => !claimedPaths.has(file.path))
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function renderFileLabel(file) {
|
|
98
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
99
|
+
sx: {
|
|
100
|
+
display: 'flex',
|
|
101
|
+
alignItems: 'center',
|
|
102
|
+
gap: 1
|
|
103
|
+
},
|
|
104
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
105
|
+
variant: "body2",
|
|
106
|
+
children: file.path
|
|
107
|
+
}), /*#__PURE__*/_jsxs(Typography, {
|
|
108
|
+
variant: "caption",
|
|
109
|
+
color: "text.secondary",
|
|
110
|
+
children: ["+", file.additions, " -", file.deletions]
|
|
111
|
+
})]
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
function renderFileNode({
|
|
115
|
+
file,
|
|
116
|
+
index,
|
|
117
|
+
getFileIcon
|
|
118
|
+
}) {
|
|
119
|
+
const itemId = `file-${index}-${file.path.replace(/[^a-zA-Z0-9]/g, '-')}`;
|
|
120
|
+
return /*#__PURE__*/_jsx(TreeItem, {
|
|
121
|
+
itemId: itemId,
|
|
122
|
+
label: /*#__PURE__*/_jsxs(Box, {
|
|
123
|
+
sx: {
|
|
124
|
+
display: 'flex',
|
|
125
|
+
alignItems: 'center',
|
|
126
|
+
gap: 1
|
|
127
|
+
},
|
|
128
|
+
children: [getFileIcon(file.type), renderFileLabel(file)]
|
|
129
|
+
}),
|
|
130
|
+
children: /*#__PURE__*/_jsx(Box, {
|
|
131
|
+
sx: {
|
|
132
|
+
p: '16px'
|
|
133
|
+
},
|
|
134
|
+
children: /*#__PURE__*/_jsx(DiffView, {
|
|
135
|
+
children: file.diff.map((line, diffIndex) => /*#__PURE__*/_jsx(DiffLine, {
|
|
136
|
+
type: line.type,
|
|
137
|
+
children: line.content
|
|
138
|
+
}, `${itemId}-line-${diffIndex}`))
|
|
139
|
+
})
|
|
140
|
+
})
|
|
141
|
+
}, itemId);
|
|
142
|
+
}
|
|
69
143
|
export default function FileChanges({
|
|
70
|
-
files
|
|
144
|
+
files,
|
|
145
|
+
highlights
|
|
71
146
|
}) {
|
|
72
147
|
const [expanded, setExpanded] = React.useState([]);
|
|
73
148
|
const [selected, setSelected] = React.useState([]);
|
|
@@ -101,6 +176,10 @@ export default function FileChanges({
|
|
|
101
176
|
return _FileIcon || (_FileIcon = /*#__PURE__*/_jsx(FileIcon, {}));
|
|
102
177
|
}
|
|
103
178
|
};
|
|
179
|
+
const {
|
|
180
|
+
highlightedGroups,
|
|
181
|
+
remainingFiles
|
|
182
|
+
} = React.useMemo(() => normalizeHighlights(files, highlights), [files, highlights]);
|
|
104
183
|
|
|
105
184
|
// Transform files into tree nodes
|
|
106
185
|
// const items: TreeNode[] = files.map((file, index) => ({
|
|
@@ -134,8 +213,78 @@ export default function FileChanges({
|
|
|
134
213
|
// </Box>
|
|
135
214
|
// );
|
|
136
215
|
|
|
137
|
-
return /*#__PURE__*/
|
|
138
|
-
children: /*#__PURE__*/
|
|
216
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
217
|
+
children: [highlightedGroups.length > 0 ? /*#__PURE__*/_jsxs(Box, {
|
|
218
|
+
sx: {
|
|
219
|
+
mb: 3,
|
|
220
|
+
p: 2,
|
|
221
|
+
border: theme => `1px solid ${theme.palette.warning.main}`,
|
|
222
|
+
borderRadius: 2,
|
|
223
|
+
backgroundColor: 'action.hover'
|
|
224
|
+
},
|
|
225
|
+
children: [/*#__PURE__*/_jsxs(Box, {
|
|
226
|
+
sx: {
|
|
227
|
+
display: 'flex',
|
|
228
|
+
alignItems: 'center',
|
|
229
|
+
gap: 1,
|
|
230
|
+
mb: 1.5
|
|
231
|
+
},
|
|
232
|
+
children: [_Chip4 || (_Chip4 = /*#__PURE__*/_jsx(Chip, {
|
|
233
|
+
label: "Highlighted files",
|
|
234
|
+
size: "small",
|
|
235
|
+
color: "warning"
|
|
236
|
+
})), _Typography || (_Typography = /*#__PURE__*/_jsx(Typography, {
|
|
237
|
+
variant: "caption",
|
|
238
|
+
color: "text.secondary",
|
|
239
|
+
children: "Pulled out for focused review"
|
|
240
|
+
}))]
|
|
241
|
+
}), highlightedGroups.map((group, groupIndex) => /*#__PURE__*/_jsxs(Box, {
|
|
242
|
+
sx: {
|
|
243
|
+
mb: groupIndex === highlightedGroups.length - 1 ? 0 : 2,
|
|
244
|
+
p: 1.5,
|
|
245
|
+
borderRadius: 2,
|
|
246
|
+
border: '1px solid',
|
|
247
|
+
borderColor: 'divider',
|
|
248
|
+
backgroundColor: 'background.paper'
|
|
249
|
+
},
|
|
250
|
+
children: [group.comment ? /*#__PURE__*/_jsx(Typography, {
|
|
251
|
+
variant: "body2",
|
|
252
|
+
color: "text.secondary",
|
|
253
|
+
sx: {
|
|
254
|
+
mb: 1.5
|
|
255
|
+
},
|
|
256
|
+
children: group.comment
|
|
257
|
+
}) : null, /*#__PURE__*/_jsx(SimpleTreeView, {
|
|
258
|
+
slots: {
|
|
259
|
+
collapseIcon: ExpandMoreIcon,
|
|
260
|
+
expandIcon: ChevronRightIcon
|
|
261
|
+
},
|
|
262
|
+
defaultExpandedItems: group.files.map((file, index) => `highlight-${groupIndex}-${index}-${file.path.replace(/[^a-zA-Z0-9]/g, '-')}`),
|
|
263
|
+
children: group.files.map((file, index) => /*#__PURE__*/_jsx(TreeItem, {
|
|
264
|
+
itemId: `highlight-${groupIndex}-${index}-${file.path.replace(/[^a-zA-Z0-9]/g, '-')}`,
|
|
265
|
+
label: /*#__PURE__*/_jsxs(Box, {
|
|
266
|
+
sx: {
|
|
267
|
+
display: 'flex',
|
|
268
|
+
alignItems: 'center',
|
|
269
|
+
gap: 1
|
|
270
|
+
},
|
|
271
|
+
children: [getFileIcon(file.type), renderFileLabel(file)]
|
|
272
|
+
}),
|
|
273
|
+
children: /*#__PURE__*/_jsx(Box, {
|
|
274
|
+
sx: {
|
|
275
|
+
p: '16px'
|
|
276
|
+
},
|
|
277
|
+
children: /*#__PURE__*/_jsx(DiffView, {
|
|
278
|
+
children: file.diff.map((line, diffIndex) => /*#__PURE__*/_jsx(DiffLine, {
|
|
279
|
+
type: line.type,
|
|
280
|
+
children: line.content
|
|
281
|
+
}, `highlight-${groupIndex}-${index}-line-${diffIndex}`))
|
|
282
|
+
})
|
|
283
|
+
})
|
|
284
|
+
}, `highlight-${groupIndex}-${index}-${file.path}`))
|
|
285
|
+
})]
|
|
286
|
+
}, `highlight-group-${groupIndex}`))]
|
|
287
|
+
}) : null, /*#__PURE__*/_jsx(SimpleTreeView, {
|
|
139
288
|
slots: {
|
|
140
289
|
collapseIcon: ExpandMoreIcon,
|
|
141
290
|
expandIcon: ChevronRightIcon
|
|
@@ -145,38 +294,11 @@ export default function FileChanges({
|
|
|
145
294
|
onExpandedItemsChange: handleToggle,
|
|
146
295
|
onSelectedItemsChange: handleSelect,
|
|
147
296
|
multiSelect: true,
|
|
148
|
-
children:
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
display: 'flex',
|
|
155
|
-
alignItems: 'center',
|
|
156
|
-
gap: 1
|
|
157
|
-
},
|
|
158
|
-
children: [getFileIcon(file.type), /*#__PURE__*/_jsx(Typography, {
|
|
159
|
-
variant: "body2",
|
|
160
|
-
children: file.path
|
|
161
|
-
}), /*#__PURE__*/_jsxs(Typography, {
|
|
162
|
-
variant: "caption",
|
|
163
|
-
color: "text.secondary",
|
|
164
|
-
children: ["+", file.additions, " -", file.deletions]
|
|
165
|
-
})]
|
|
166
|
-
}),
|
|
167
|
-
children: /*#__PURE__*/_jsx(Box, {
|
|
168
|
-
sx: {
|
|
169
|
-
p: '16px'
|
|
170
|
-
},
|
|
171
|
-
children: /*#__PURE__*/_jsx(DiffView, {
|
|
172
|
-
children: file.diff.map((line, index) => /*#__PURE__*/_jsx(DiffLine, {
|
|
173
|
-
type: line.type,
|
|
174
|
-
children: line.content
|
|
175
|
-
}, `${itemId}-line-${index}`))
|
|
176
|
-
})
|
|
177
|
-
})
|
|
178
|
-
}, itemId);
|
|
179
|
-
})
|
|
180
|
-
})
|
|
297
|
+
children: remainingFiles.map((file, index) => renderFileNode({
|
|
298
|
+
file,
|
|
299
|
+
index,
|
|
300
|
+
getFileIcon
|
|
301
|
+
}))
|
|
302
|
+
})]
|
|
181
303
|
});
|
|
182
304
|
}
|
|
@@ -9,9 +9,8 @@ import Typography from '@mui/material/Typography';
|
|
|
9
9
|
import { styled } from '@mui/material/styles';
|
|
10
10
|
import CommitsList from './CommitsList';
|
|
11
11
|
import FileChanges from './FileChanges';
|
|
12
|
-
|
|
13
|
-
// Custom styled components to match GitHub's UI
|
|
14
12
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
// Custom styled components to match GitHub's UI
|
|
15
14
|
const StyledTabs = styled(Tabs)(({
|
|
16
15
|
theme
|
|
17
16
|
}) => ({
|
|
@@ -63,7 +62,8 @@ export default function PullRequestView({
|
|
|
63
62
|
number,
|
|
64
63
|
commits,
|
|
65
64
|
files,
|
|
66
|
-
onCheckout
|
|
65
|
+
onCheckout,
|
|
66
|
+
highlights
|
|
67
67
|
}) {
|
|
68
68
|
const [tabValue, setTabValue] = React.useState(0);
|
|
69
69
|
const handleTabChange = (event, newValue) => {
|
|
@@ -125,7 +125,8 @@ export default function PullRequestView({
|
|
|
125
125
|
})
|
|
126
126
|
})
|
|
127
127
|
}), /*#__PURE__*/_jsx(FileChanges, {
|
|
128
|
-
files: files
|
|
128
|
+
files: files,
|
|
129
|
+
highlights: highlights
|
|
129
130
|
})]
|
|
130
131
|
})]
|
|
131
132
|
});
|
package/modern/index.js
CHANGED
|
@@ -60,7 +60,8 @@ function GithubBranch({
|
|
|
60
60
|
head,
|
|
61
61
|
apiUrl,
|
|
62
62
|
private: privateMode = false,
|
|
63
|
-
data
|
|
63
|
+
data,
|
|
64
|
+
highlights
|
|
64
65
|
}) {
|
|
65
66
|
const [branchData, setBranchData] = React.useState(data || null);
|
|
66
67
|
const [loading, setLoading] = React.useState(!data && !privateMode);
|
|
@@ -178,7 +179,8 @@ function GithubBranch({
|
|
|
178
179
|
title: "",
|
|
179
180
|
number: 0,
|
|
180
181
|
commits: branchData.commits,
|
|
181
|
-
files: branchData.files
|
|
182
|
+
files: branchData.files,
|
|
183
|
+
highlights: highlights
|
|
182
184
|
})]
|
|
183
185
|
}) : null]
|
|
184
186
|
});
|
|
@@ -10,9 +10,46 @@ var React = _interopRequireWildcard(require("react"));
|
|
|
10
10
|
var _material = require("@mui/material");
|
|
11
11
|
var _reactActivityCalendar = require("react-activity-calendar");
|
|
12
12
|
var _styles = require("@mui/material/styles");
|
|
13
|
-
var _common = require("@stoked-ui/common");
|
|
14
13
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
15
14
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
15
|
+
function useWindowSize() {
|
|
16
|
+
const [size, setSize] = React.useState(() => {
|
|
17
|
+
if (typeof window === 'undefined') {
|
|
18
|
+
return [0, 0];
|
|
19
|
+
}
|
|
20
|
+
return [window.innerWidth, window.innerHeight];
|
|
21
|
+
});
|
|
22
|
+
React.useEffect(() => {
|
|
23
|
+
if (typeof window === 'undefined') {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
const handleResize = () => {
|
|
27
|
+
setSize([window.innerWidth, window.innerHeight]);
|
|
28
|
+
};
|
|
29
|
+
window.addEventListener('resize', handleResize);
|
|
30
|
+
handleResize();
|
|
31
|
+
return () => window.removeEventListener('resize', handleResize);
|
|
32
|
+
}, []);
|
|
33
|
+
return size;
|
|
34
|
+
}
|
|
35
|
+
function useElementSize(elementRef) {
|
|
36
|
+
const [size, setSize] = React.useState({
|
|
37
|
+
width: undefined,
|
|
38
|
+
height: undefined
|
|
39
|
+
});
|
|
40
|
+
React.useEffect(() => {
|
|
41
|
+
const handleResize = () => {
|
|
42
|
+
setSize({
|
|
43
|
+
width: elementRef.current ? elementRef.current.offsetWidth : undefined,
|
|
44
|
+
height: elementRef.current ? elementRef.current.offsetHeight : undefined
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
handleResize();
|
|
48
|
+
window.addEventListener('resize', handleResize);
|
|
49
|
+
return () => window.removeEventListener('resize', handleResize);
|
|
50
|
+
}, [elementRef]);
|
|
51
|
+
return size;
|
|
52
|
+
}
|
|
16
53
|
function formatActivityDate(date) {
|
|
17
54
|
const year = date.getFullYear();
|
|
18
55
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
@@ -77,8 +114,8 @@ function GithubCalendar({
|
|
|
77
114
|
const [labelsTimer, setLabelsTimer] = React.useState(null);
|
|
78
115
|
const theme = (0, _styles.useTheme)();
|
|
79
116
|
const elementRef = React.useRef(null);
|
|
80
|
-
const [windowWidth
|
|
81
|
-
const elemSize = (
|
|
117
|
+
const [windowWidth] = useWindowSize();
|
|
118
|
+
const elemSize = useElementSize(elementRef);
|
|
82
119
|
React.useEffect(() => {
|
|
83
120
|
if (inputBlockSize) {
|
|
84
121
|
return;
|
|
@@ -8,16 +8,17 @@ exports.default = FileChanges;
|
|
|
8
8
|
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
9
9
|
var React = _interopRequireWildcard(require("react"));
|
|
10
10
|
var _Box = _interopRequireDefault(require("@mui/material/Box"));
|
|
11
|
-
var
|
|
11
|
+
var _Typography2 = _interopRequireDefault(require("@mui/material/Typography"));
|
|
12
12
|
var _SimpleTreeView = require("@mui/x-tree-view/SimpleTreeView");
|
|
13
13
|
var _TreeItem = require("@mui/x-tree-view/TreeItem");
|
|
14
14
|
var _styles = require("@mui/material/styles");
|
|
15
15
|
var _InsertDriveFile = _interopRequireDefault(require("@mui/icons-material/InsertDriveFile"));
|
|
16
16
|
var _ChevronRight = _interopRequireDefault(require("@mui/icons-material/ChevronRight"));
|
|
17
17
|
var _ExpandMore = _interopRequireDefault(require("@mui/icons-material/ExpandMore"));
|
|
18
|
-
var
|
|
18
|
+
var _Chip5 = _interopRequireDefault(require("@mui/material/Chip"));
|
|
19
19
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
20
|
-
var _Chip, _Chip2, _Chip3, _FileIcon; // import FolderIcon from '@mui/icons-material/Folder';
|
|
20
|
+
var _Chip, _Chip2, _Chip3, _FileIcon, _Chip4, _Typography; // import FolderIcon from '@mui/icons-material/Folder';
|
|
21
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
21
22
|
// const StyledTreeItem = styled(TreeItem)((props) => ({
|
|
22
23
|
// '& .MuiTreeItem-content': {
|
|
23
24
|
// padding: props.theme.spacing(1),
|
|
@@ -32,7 +33,7 @@ var _Chip, _Chip2, _Chip3, _FileIcon; // import FolderIcon from '@mui/icons-mate
|
|
|
32
33
|
// },
|
|
33
34
|
// },
|
|
34
35
|
// }));
|
|
35
|
-
|
|
36
|
+
|
|
36
37
|
const DiffView = (0, _styles.styled)(_Box.default)(({
|
|
37
38
|
theme
|
|
38
39
|
}) => ({
|
|
@@ -72,8 +73,83 @@ const DiffLine = (0, _styles.styled)(_Box.default, {
|
|
|
72
73
|
// children?: TreeNode[];
|
|
73
74
|
// }
|
|
74
75
|
|
|
76
|
+
function isGroupHighlight(highlight) {
|
|
77
|
+
return 'files' in highlight;
|
|
78
|
+
}
|
|
79
|
+
function normalizeHighlights(files, highlights = []) {
|
|
80
|
+
const fileMap = new Map(files.map(file => [file.path, file]));
|
|
81
|
+
const claimedPaths = new Set();
|
|
82
|
+
const groups = [];
|
|
83
|
+
highlights.forEach(highlight => {
|
|
84
|
+
const paths = isGroupHighlight(highlight) ? highlight.files : [highlight.file];
|
|
85
|
+
const matchedFiles = paths.map(path => fileMap.get(path)).filter(file => Boolean(file)).filter(file => {
|
|
86
|
+
if (claimedPaths.has(file.path)) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
claimedPaths.add(file.path);
|
|
90
|
+
return true;
|
|
91
|
+
});
|
|
92
|
+
if (matchedFiles.length > 0) {
|
|
93
|
+
groups.push({
|
|
94
|
+
files: matchedFiles,
|
|
95
|
+
comment: highlight.comment
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
return {
|
|
100
|
+
highlightedGroups: groups,
|
|
101
|
+
remainingFiles: files.filter(file => !claimedPaths.has(file.path))
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function renderFileLabel(file) {
|
|
105
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
|
|
106
|
+
sx: {
|
|
107
|
+
display: 'flex',
|
|
108
|
+
alignItems: 'center',
|
|
109
|
+
gap: 1
|
|
110
|
+
},
|
|
111
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography2.default, {
|
|
112
|
+
variant: "body2",
|
|
113
|
+
children: file.path
|
|
114
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Typography2.default, {
|
|
115
|
+
variant: "caption",
|
|
116
|
+
color: "text.secondary",
|
|
117
|
+
children: ["+", file.additions, " -", file.deletions]
|
|
118
|
+
})]
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function renderFileNode({
|
|
122
|
+
file,
|
|
123
|
+
index,
|
|
124
|
+
getFileIcon
|
|
125
|
+
}) {
|
|
126
|
+
const itemId = `file-${index}-${file.path.replace(/[^a-zA-Z0-9]/g, '-')}`;
|
|
127
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_TreeItem.TreeItem, {
|
|
128
|
+
itemId: itemId,
|
|
129
|
+
label: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
|
|
130
|
+
sx: {
|
|
131
|
+
display: 'flex',
|
|
132
|
+
alignItems: 'center',
|
|
133
|
+
gap: 1
|
|
134
|
+
},
|
|
135
|
+
children: [getFileIcon(file.type), renderFileLabel(file)]
|
|
136
|
+
}),
|
|
137
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Box.default, {
|
|
138
|
+
sx: {
|
|
139
|
+
p: '16px'
|
|
140
|
+
},
|
|
141
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(DiffView, {
|
|
142
|
+
children: file.diff.map((line, diffIndex) => /*#__PURE__*/(0, _jsxRuntime.jsx)(DiffLine, {
|
|
143
|
+
type: line.type,
|
|
144
|
+
children: line.content
|
|
145
|
+
}, `${itemId}-line-${diffIndex}`))
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
}, itemId);
|
|
149
|
+
}
|
|
75
150
|
function FileChanges({
|
|
76
|
-
files
|
|
151
|
+
files,
|
|
152
|
+
highlights
|
|
77
153
|
}) {
|
|
78
154
|
const [expanded, setExpanded] = React.useState([]);
|
|
79
155
|
const [selected, setSelected] = React.useState([]);
|
|
@@ -86,19 +162,19 @@ function FileChanges({
|
|
|
86
162
|
const getFileIcon = type => {
|
|
87
163
|
switch (type) {
|
|
88
164
|
case 'added':
|
|
89
|
-
return _Chip || (_Chip = /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
165
|
+
return _Chip || (_Chip = /*#__PURE__*/(0, _jsxRuntime.jsx)(_Chip5.default, {
|
|
90
166
|
label: "A",
|
|
91
167
|
size: "small",
|
|
92
168
|
color: "success"
|
|
93
169
|
}));
|
|
94
170
|
case 'modified':
|
|
95
|
-
return _Chip2 || (_Chip2 = /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
171
|
+
return _Chip2 || (_Chip2 = /*#__PURE__*/(0, _jsxRuntime.jsx)(_Chip5.default, {
|
|
96
172
|
label: "M",
|
|
97
173
|
size: "small",
|
|
98
174
|
color: "warning"
|
|
99
175
|
}));
|
|
100
176
|
case 'deleted':
|
|
101
|
-
return _Chip3 || (_Chip3 = /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
177
|
+
return _Chip3 || (_Chip3 = /*#__PURE__*/(0, _jsxRuntime.jsx)(_Chip5.default, {
|
|
102
178
|
label: "D",
|
|
103
179
|
size: "small",
|
|
104
180
|
color: "error"
|
|
@@ -107,6 +183,10 @@ function FileChanges({
|
|
|
107
183
|
return _FileIcon || (_FileIcon = /*#__PURE__*/(0, _jsxRuntime.jsx)(_InsertDriveFile.default, {}));
|
|
108
184
|
}
|
|
109
185
|
};
|
|
186
|
+
const {
|
|
187
|
+
highlightedGroups,
|
|
188
|
+
remainingFiles
|
|
189
|
+
} = React.useMemo(() => normalizeHighlights(files, highlights), [files, highlights]);
|
|
110
190
|
|
|
111
191
|
// Transform files into tree nodes
|
|
112
192
|
// const items: TreeNode[] = files.map((file, index) => ({
|
|
@@ -140,8 +220,78 @@ function FileChanges({
|
|
|
140
220
|
// </Box>
|
|
141
221
|
// );
|
|
142
222
|
|
|
143
|
-
return /*#__PURE__*/(0, _jsxRuntime.
|
|
144
|
-
children: /*#__PURE__*/(0, _jsxRuntime.
|
|
223
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
|
|
224
|
+
children: [highlightedGroups.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
|
|
225
|
+
sx: {
|
|
226
|
+
mb: 3,
|
|
227
|
+
p: 2,
|
|
228
|
+
border: theme => `1px solid ${theme.palette.warning.main}`,
|
|
229
|
+
borderRadius: 2,
|
|
230
|
+
backgroundColor: 'action.hover'
|
|
231
|
+
},
|
|
232
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
|
|
233
|
+
sx: {
|
|
234
|
+
display: 'flex',
|
|
235
|
+
alignItems: 'center',
|
|
236
|
+
gap: 1,
|
|
237
|
+
mb: 1.5
|
|
238
|
+
},
|
|
239
|
+
children: [_Chip4 || (_Chip4 = /*#__PURE__*/(0, _jsxRuntime.jsx)(_Chip5.default, {
|
|
240
|
+
label: "Highlighted files",
|
|
241
|
+
size: "small",
|
|
242
|
+
color: "warning"
|
|
243
|
+
})), _Typography || (_Typography = /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography2.default, {
|
|
244
|
+
variant: "caption",
|
|
245
|
+
color: "text.secondary",
|
|
246
|
+
children: "Pulled out for focused review"
|
|
247
|
+
}))]
|
|
248
|
+
}), highlightedGroups.map((group, groupIndex) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
|
|
249
|
+
sx: {
|
|
250
|
+
mb: groupIndex === highlightedGroups.length - 1 ? 0 : 2,
|
|
251
|
+
p: 1.5,
|
|
252
|
+
borderRadius: 2,
|
|
253
|
+
border: '1px solid',
|
|
254
|
+
borderColor: 'divider',
|
|
255
|
+
backgroundColor: 'background.paper'
|
|
256
|
+
},
|
|
257
|
+
children: [group.comment ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography2.default, {
|
|
258
|
+
variant: "body2",
|
|
259
|
+
color: "text.secondary",
|
|
260
|
+
sx: {
|
|
261
|
+
mb: 1.5
|
|
262
|
+
},
|
|
263
|
+
children: group.comment
|
|
264
|
+
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_SimpleTreeView.SimpleTreeView, {
|
|
265
|
+
slots: {
|
|
266
|
+
collapseIcon: _ExpandMore.default,
|
|
267
|
+
expandIcon: _ChevronRight.default
|
|
268
|
+
},
|
|
269
|
+
defaultExpandedItems: group.files.map((file, index) => `highlight-${groupIndex}-${index}-${file.path.replace(/[^a-zA-Z0-9]/g, '-')}`),
|
|
270
|
+
children: group.files.map((file, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_TreeItem.TreeItem, {
|
|
271
|
+
itemId: `highlight-${groupIndex}-${index}-${file.path.replace(/[^a-zA-Z0-9]/g, '-')}`,
|
|
272
|
+
label: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
|
|
273
|
+
sx: {
|
|
274
|
+
display: 'flex',
|
|
275
|
+
alignItems: 'center',
|
|
276
|
+
gap: 1
|
|
277
|
+
},
|
|
278
|
+
children: [getFileIcon(file.type), renderFileLabel(file)]
|
|
279
|
+
}),
|
|
280
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Box.default, {
|
|
281
|
+
sx: {
|
|
282
|
+
p: '16px'
|
|
283
|
+
},
|
|
284
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(DiffView, {
|
|
285
|
+
children: file.diff.map((line, diffIndex) => /*#__PURE__*/(0, _jsxRuntime.jsx)(DiffLine, {
|
|
286
|
+
type: line.type,
|
|
287
|
+
children: line.content
|
|
288
|
+
}, `highlight-${groupIndex}-${index}-line-${diffIndex}`))
|
|
289
|
+
})
|
|
290
|
+
})
|
|
291
|
+
}, `highlight-${groupIndex}-${index}-${file.path}`))
|
|
292
|
+
})]
|
|
293
|
+
}, `highlight-group-${groupIndex}`))]
|
|
294
|
+
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_SimpleTreeView.SimpleTreeView, {
|
|
145
295
|
slots: {
|
|
146
296
|
collapseIcon: _ExpandMore.default,
|
|
147
297
|
expandIcon: _ChevronRight.default
|
|
@@ -151,38 +301,11 @@ function FileChanges({
|
|
|
151
301
|
onExpandedItemsChange: handleToggle,
|
|
152
302
|
onSelectedItemsChange: handleSelect,
|
|
153
303
|
multiSelect: true,
|
|
154
|
-
children:
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
display: 'flex',
|
|
161
|
-
alignItems: 'center',
|
|
162
|
-
gap: 1
|
|
163
|
-
},
|
|
164
|
-
children: [getFileIcon(file.type), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
|
|
165
|
-
variant: "body2",
|
|
166
|
-
children: file.path
|
|
167
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Typography.default, {
|
|
168
|
-
variant: "caption",
|
|
169
|
-
color: "text.secondary",
|
|
170
|
-
children: ["+", file.additions, " -", file.deletions]
|
|
171
|
-
})]
|
|
172
|
-
}),
|
|
173
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Box.default, {
|
|
174
|
-
sx: {
|
|
175
|
-
p: '16px'
|
|
176
|
-
},
|
|
177
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(DiffView, {
|
|
178
|
-
children: file.diff.map((line, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(DiffLine, {
|
|
179
|
-
type: line.type,
|
|
180
|
-
children: line.content
|
|
181
|
-
}, `${itemId}-line-${index}`))
|
|
182
|
-
})
|
|
183
|
-
})
|
|
184
|
-
}, itemId);
|
|
185
|
-
})
|
|
186
|
-
})
|
|
304
|
+
children: remainingFiles.map((file, index) => renderFileNode({
|
|
305
|
+
file,
|
|
306
|
+
index,
|
|
307
|
+
getFileIcon
|
|
308
|
+
}))
|
|
309
|
+
})]
|
|
187
310
|
});
|
|
188
311
|
}
|
|
@@ -16,8 +16,9 @@ var _styles = require("@mui/material/styles");
|
|
|
16
16
|
var _CommitsList = _interopRequireDefault(require("./CommitsList"));
|
|
17
17
|
var _FileChanges = _interopRequireDefault(require("./FileChanges"));
|
|
18
18
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
19
|
-
const _excluded = ["children", "value", "index"];
|
|
19
|
+
const _excluded = ["children", "value", "index"];
|
|
20
20
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
21
|
+
// Custom styled components to match GitHub's UI
|
|
21
22
|
const StyledTabs = (0, _styles.styled)(_Tabs.default)(({
|
|
22
23
|
theme
|
|
23
24
|
}) => ({
|
|
@@ -69,7 +70,8 @@ function PullRequestView({
|
|
|
69
70
|
number,
|
|
70
71
|
commits,
|
|
71
72
|
files,
|
|
72
|
-
onCheckout
|
|
73
|
+
onCheckout,
|
|
74
|
+
highlights
|
|
73
75
|
}) {
|
|
74
76
|
const [tabValue, setTabValue] = React.useState(0);
|
|
75
77
|
const handleTabChange = (event, newValue) => {
|
|
@@ -131,7 +133,8 @@ function PullRequestView({
|
|
|
131
133
|
})
|
|
132
134
|
})
|
|
133
135
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_FileChanges.default, {
|
|
134
|
-
files: files
|
|
136
|
+
files: files,
|
|
137
|
+
highlights: highlights
|
|
135
138
|
})]
|
|
136
139
|
})]
|
|
137
140
|
});
|
package/node/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stoked-ui/github",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.13.1",
|
|
4
4
|
"description": "Github components for Stoked UI",
|
|
5
5
|
"author": "Brian Stoker",
|
|
6
6
|
"main": "./node/index.js",
|
|
@@ -65,4 +65,4 @@
|
|
|
65
65
|
"private": false,
|
|
66
66
|
"module": "./index.js",
|
|
67
67
|
"types": "./index.d.ts"
|
|
68
|
-
}
|
|
68
|
+
}
|
package/types/github.d.ts
CHANGED
|
@@ -45,6 +45,15 @@ export interface GithubChangedFile {
|
|
|
45
45
|
deletions: number;
|
|
46
46
|
diff: GithubDiffLine[];
|
|
47
47
|
}
|
|
48
|
+
export interface GithubFileHighlightSingle {
|
|
49
|
+
file: string;
|
|
50
|
+
comment?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface GithubFileHighlightGroup {
|
|
53
|
+
files: string[];
|
|
54
|
+
comment?: string;
|
|
55
|
+
}
|
|
56
|
+
export type GithubFileHighlight = GithubFileHighlightSingle | GithubFileHighlightGroup;
|
|
48
57
|
export interface GithubContributor {
|
|
49
58
|
login: string;
|
|
50
59
|
name: string;
|
|
Binary file
|