@stoked-ui/github 0.0.0-a.0

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.
Files changed (95) hide show
  1. package/CHANGELOG.md +15014 -0
  2. package/GithubCalendar/GithubCalendar.d.ts +7 -0
  3. package/GithubCalendar/GithubCalendar.js +330 -0
  4. package/GithubCalendar/index.d.ts +2 -0
  5. package/GithubCalendar/index.js +2 -0
  6. package/GithubCalendar/package.json +6 -0
  7. package/GithubEvents/EventTypes/CreateEvent.d.ts +7 -0
  8. package/GithubEvents/EventTypes/CreateEvent.js +72 -0
  9. package/GithubEvents/EventTypes/DeleteEvent.d.ts +7 -0
  10. package/GithubEvents/EventTypes/DeleteEvent.js +65 -0
  11. package/GithubEvents/EventTypes/ForkEvent.d.ts +7 -0
  12. package/GithubEvents/EventTypes/ForkEvent.js +77 -0
  13. package/GithubEvents/EventTypes/IssueCommentEvent.d.ts +7 -0
  14. package/GithubEvents/EventTypes/IssueCommentEvent.js +210 -0
  15. package/GithubEvents/EventTypes/IssuesEvent.d.ts +7 -0
  16. package/GithubEvents/EventTypes/IssuesEvent.js +97 -0
  17. package/GithubEvents/EventTypes/ProjectsV2ColumnEvent.d.ts +7 -0
  18. package/GithubEvents/EventTypes/ProjectsV2ColumnEvent.js +69 -0
  19. package/GithubEvents/EventTypes/ProjectsV2Event.d.ts +7 -0
  20. package/GithubEvents/EventTypes/ProjectsV2Event.js +74 -0
  21. package/GithubEvents/EventTypes/ProjectsV2FieldEvent.d.ts +7 -0
  22. package/GithubEvents/EventTypes/ProjectsV2FieldEvent.js +77 -0
  23. package/GithubEvents/EventTypes/ProjectsV2ItemEvent.d.ts +7 -0
  24. package/GithubEvents/EventTypes/ProjectsV2ItemEvent.js +79 -0
  25. package/GithubEvents/EventTypes/PullRequest/CommitsList.d.ts +17 -0
  26. package/GithubEvents/EventTypes/PullRequest/CommitsList.js +99 -0
  27. package/GithubEvents/EventTypes/PullRequest/FileChanges.d.ts +17 -0
  28. package/GithubEvents/EventTypes/PullRequest/FileChanges.js +182 -0
  29. package/GithubEvents/EventTypes/PullRequest/PullRequestEvent.d.ts +8 -0
  30. package/GithubEvents/EventTypes/PullRequest/PullRequestEvent.js +374 -0
  31. package/GithubEvents/EventTypes/PullRequest/PullRequestView.d.ts +29 -0
  32. package/GithubEvents/EventTypes/PullRequest/PullRequestView.js +132 -0
  33. package/GithubEvents/EventTypes/PushEvent.d.ts +7 -0
  34. package/GithubEvents/EventTypes/PushEvent.js +106 -0
  35. package/GithubEvents/GithubEvents.d.ts +49 -0
  36. package/GithubEvents/GithubEvents.js +1454 -0
  37. package/GithubEvents/index.d.ts +2 -0
  38. package/GithubEvents/index.js +2 -0
  39. package/GithubEvents/package.json +6 -0
  40. package/LICENSE +21 -0
  41. package/README.md +29 -0
  42. package/apiHandlers/getPullRequestDetails.d.ts +7 -0
  43. package/apiHandlers/getPullRequestDetails.js +120 -0
  44. package/apiHandlers/index.d.ts +1 -0
  45. package/apiHandlers/index.js +1 -0
  46. package/apiHandlers/package.json +6 -0
  47. package/index.d.ts +3 -0
  48. package/index.js +10 -0
  49. package/modern/GithubCalendar/GithubCalendar.js +330 -0
  50. package/modern/GithubCalendar/index.js +2 -0
  51. package/modern/GithubEvents/EventTypes/CreateEvent.js +72 -0
  52. package/modern/GithubEvents/EventTypes/DeleteEvent.js +65 -0
  53. package/modern/GithubEvents/EventTypes/ForkEvent.js +77 -0
  54. package/modern/GithubEvents/EventTypes/IssueCommentEvent.js +210 -0
  55. package/modern/GithubEvents/EventTypes/IssuesEvent.js +97 -0
  56. package/modern/GithubEvents/EventTypes/ProjectsV2ColumnEvent.js +69 -0
  57. package/modern/GithubEvents/EventTypes/ProjectsV2Event.js +74 -0
  58. package/modern/GithubEvents/EventTypes/ProjectsV2FieldEvent.js +77 -0
  59. package/modern/GithubEvents/EventTypes/ProjectsV2ItemEvent.js +79 -0
  60. package/modern/GithubEvents/EventTypes/PullRequest/CommitsList.js +99 -0
  61. package/modern/GithubEvents/EventTypes/PullRequest/FileChanges.js +182 -0
  62. package/modern/GithubEvents/EventTypes/PullRequest/PullRequestEvent.js +374 -0
  63. package/modern/GithubEvents/EventTypes/PullRequest/PullRequestView.js +132 -0
  64. package/modern/GithubEvents/EventTypes/PushEvent.js +106 -0
  65. package/modern/GithubEvents/GithubEvents.js +1454 -0
  66. package/modern/GithubEvents/index.js +2 -0
  67. package/modern/apiHandlers/getPullRequestDetails.js +120 -0
  68. package/modern/apiHandlers/index.js +1 -0
  69. package/modern/index.js +10 -0
  70. package/modern/types/github.js +1 -0
  71. package/node/GithubCalendar/GithubCalendar.js +337 -0
  72. package/node/GithubCalendar/index.js +9 -0
  73. package/node/GithubEvents/EventTypes/CreateEvent.js +80 -0
  74. package/node/GithubEvents/EventTypes/DeleteEvent.js +73 -0
  75. package/node/GithubEvents/EventTypes/ForkEvent.js +85 -0
  76. package/node/GithubEvents/EventTypes/IssueCommentEvent.js +218 -0
  77. package/node/GithubEvents/EventTypes/IssuesEvent.js +105 -0
  78. package/node/GithubEvents/EventTypes/ProjectsV2ColumnEvent.js +77 -0
  79. package/node/GithubEvents/EventTypes/ProjectsV2Event.js +82 -0
  80. package/node/GithubEvents/EventTypes/ProjectsV2FieldEvent.js +85 -0
  81. package/node/GithubEvents/EventTypes/ProjectsV2ItemEvent.js +87 -0
  82. package/node/GithubEvents/EventTypes/PullRequest/CommitsList.js +107 -0
  83. package/node/GithubEvents/EventTypes/PullRequest/FileChanges.js +188 -0
  84. package/node/GithubEvents/EventTypes/PullRequest/PullRequestEvent.js +381 -0
  85. package/node/GithubEvents/EventTypes/PullRequest/PullRequestView.js +138 -0
  86. package/node/GithubEvents/EventTypes/PushEvent.js +114 -0
  87. package/node/GithubEvents/GithubEvents.js +1463 -0
  88. package/node/GithubEvents/index.js +9 -0
  89. package/node/apiHandlers/getPullRequestDetails.js +127 -0
  90. package/node/apiHandlers/index.js +13 -0
  91. package/node/index.js +27 -0
  92. package/node/types/github.js +5 -0
  93. package/package.json +71 -0
  94. package/types/github.d.ts +107 -0
  95. package/types/github.js +1 -0
@@ -0,0 +1,1463 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.ErrorDetails = ErrorDetails;
8
+ exports.default = GithubEvents;
9
+ exports.githubEventsQuery = githubEventsQuery;
10
+ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
11
+ var React = _interopRequireWildcard(require("react"));
12
+ var _requestError = require("@octokit/request-error");
13
+ var _Box = _interopRequireDefault(require("@mui/material/Box"));
14
+ var _TextField = _interopRequireDefault(require("@mui/material/TextField"));
15
+ var _Table = _interopRequireDefault(require("@mui/material/Table"));
16
+ var _TableBody = _interopRequireDefault(require("@mui/material/TableBody"));
17
+ var _TableCell = _interopRequireDefault(require("@mui/material/TableCell"));
18
+ var _TableContainer = _interopRequireDefault(require("@mui/material/TableContainer"));
19
+ var _TableHead = _interopRequireDefault(require("@mui/material/TableHead"));
20
+ var _TableRow3 = _interopRequireDefault(require("@mui/material/TableRow"));
21
+ var _Paper = _interopRequireDefault(require("@mui/material/Paper"));
22
+ var _Typography = _interopRequireDefault(require("@mui/material/Typography"));
23
+ var _CircularProgress = _interopRequireDefault(require("@mui/material/CircularProgress"));
24
+ var _Select = _interopRequireDefault(require("@mui/material/Select"));
25
+ var _MenuItem = _interopRequireDefault(require("@mui/material/MenuItem"));
26
+ var _FormControl = _interopRequireDefault(require("@mui/material/FormControl"));
27
+ var _dateFns = require("date-fns");
28
+ var _dateFnsTz = require("date-fns-tz");
29
+ var _styles = require("@mui/material/styles");
30
+ var _Autocomplete = _interopRequireDefault(require("@mui/material/Autocomplete"));
31
+ var _Pagination = _interopRequireDefault(require("@mui/material/Pagination"));
32
+ var _dynamic = _interopRequireDefault(require("next/dynamic"));
33
+ var _PullRequestEvent = _interopRequireDefault(require("./EventTypes/PullRequest/PullRequestEvent"));
34
+ var _PushEvent = _interopRequireDefault(require("./EventTypes/PushEvent"));
35
+ var _DeleteEvent = _interopRequireDefault(require("./EventTypes/DeleteEvent"));
36
+ var _CreateEvent = _interopRequireDefault(require("./EventTypes/CreateEvent"));
37
+ var _IssuesEvent = _interopRequireDefault(require("./EventTypes/IssuesEvent"));
38
+ var _IssueCommentEvent = _interopRequireDefault(require("./EventTypes/IssueCommentEvent"));
39
+ var _Chip2 = _interopRequireDefault(require("@mui/material/Chip"));
40
+ var _jsxRuntime = require("react/jsx-runtime");
41
+ var _div, _Chip, _SmalMi, _SmalMi2, _SmalMi3, _SmalMi4, _SmalMi5, _TableRow, _TableRow2;
42
+ 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); } // Extend the EventDetails interface for internal component use
43
+ // Import react-json-view dynamically to avoid SSR issues
44
+ const ReactJson = (0, _dynamic.default)(() => Promise.resolve().then(() => _interopRequireWildcard(require('react-json-view'))), {
45
+ ssr: false,
46
+ loading: () => _div || (_div = /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
47
+ children: "Loading JSON viewer..."
48
+ }))
49
+ });
50
+ const MetadataDisplay = (0, _styles.styled)(_Box.default)(({
51
+ theme
52
+ }) => {
53
+ return {
54
+ backgroundColor: 'rgba(255, 255, 255, 0.06)',
55
+ borderRadius: theme.shape.borderRadius,
56
+ boxShadow: theme.shadows[2],
57
+ padding: theme.spacing(2),
58
+ position: 'sticky',
59
+ width: '672px',
60
+ maxWidth: '692px',
61
+ minWidth: '300px',
62
+ top: '84px',
63
+ maxHeight: 'calc(100vh - 100px)',
64
+ overflow: 'auto'
65
+ };
66
+ });
67
+ function parseLinkHeader(header) {
68
+ if (!header) return {};
69
+ return header.split(',').reduce((links, part) => {
70
+ const match = part.match(/<(.+)>;\s*rel="([\w]+)"/);
71
+ if (match) {
72
+ const [, url, rel] = match;
73
+ if (rel === 'next' || rel === 'last') {
74
+ links[rel] = url;
75
+ }
76
+ }
77
+ return links;
78
+ }, {});
79
+ }
80
+ async function githubEventsQuery({
81
+ query,
82
+ githubUser,
83
+ githubToken
84
+ }) {
85
+ try {
86
+ const {
87
+ page = query.page || 1,
88
+ per_page = query.per_page || 100,
89
+ // Default to 100 per page to minimize API calls
90
+ repo,
91
+ action,
92
+ date,
93
+ description
94
+ } = query;
95
+ const queryParams = new URLSearchParams((0, _extends2.default)({
96
+ page: String(page),
97
+ per_page: String(per_page)
98
+ }, repo && {
99
+ repo
100
+ }, action && {
101
+ action
102
+ }, date && {
103
+ date
104
+ }, description && {
105
+ description
106
+ }));
107
+
108
+ // Get GitHub token from environment variables
109
+ console.log(`Fetching events for user: ${githubUser}, page: ${page}, per_page: ${per_page}`);
110
+
111
+ // Fetch all available pages from GitHub API
112
+ let allEvents = [];
113
+ let hasMore = true;
114
+ let githubPage = 1;
115
+ const maxPages = 30; // GitHub's maximum for events endpoint
116
+
117
+ while (hasMore && githubPage <= maxPages) {
118
+ console.log(`Fetching page ${githubPage}...`);
119
+ const fetchOptions = {
120
+ headers: {
121
+ 'User-Agent': 'brianstoker.com-website'
122
+ }
123
+ };
124
+ if (githubToken) {
125
+ fetchOptions.headers.Authorization = `token ${githubToken}`;
126
+ }
127
+ const response = await fetch(`https://api.github.com/users/${githubUser}/events?${queryParams}`, fetchOptions);
128
+ if (!response.ok) {
129
+ const errorText = await response.text();
130
+ console.error(`GitHub API error: ${response.status}`, errorText);
131
+ throw new Error(`GitHub API error: ${response.status} - ${errorText}`);
132
+ }
133
+ const data = await response.json();
134
+ console.log(`Page ${githubPage}: Received ${data.length} events`);
135
+ if (data.length === 0) {
136
+ hasMore = false;
137
+ } else {
138
+ allEvents = [...allEvents, ...data];
139
+ console.log(`Total events so far: ${allEvents.length}`);
140
+
141
+ // Check Link header to see if there are more pages
142
+ const linkHeader = response.headers.get('Link');
143
+ const links = parseLinkHeader(linkHeader);
144
+ hasMore = !!links.next; // Simplified logic
145
+
146
+ githubPage++;
147
+ }
148
+ }
149
+ console.log(`Final total events: ${allEvents.length}`);
150
+
151
+ // Apply filters
152
+ let filteredEvents = allEvents;
153
+ if (repo) {
154
+ filteredEvents = filteredEvents.filter(event => event.repo.name === repo);
155
+ }
156
+ if (action) {
157
+ filteredEvents = filteredEvents.filter(event => {
158
+ const eventAction = event.type.replace('Event', '');
159
+ return eventAction === action;
160
+ });
161
+ }
162
+ if (date) {
163
+ const now = new Date();
164
+ let cutoffDate;
165
+ switch (date) {
166
+ case 'today':
167
+ cutoffDate = new Date(now.setHours(0, 0, 0, 0));
168
+ break;
169
+ case 'yesterday':
170
+ cutoffDate = new Date(now);
171
+ cutoffDate.setDate(cutoffDate.getDate() - 1);
172
+ cutoffDate.setHours(0, 0, 0, 0);
173
+ break;
174
+ case 'week':
175
+ cutoffDate = new Date(now);
176
+ cutoffDate.setDate(cutoffDate.getDate() - 7);
177
+ cutoffDate.setHours(0, 0, 0, 0);
178
+ break;
179
+ case 'month':
180
+ cutoffDate = new Date(now);
181
+ cutoffDate.setMonth(cutoffDate.getMonth() - 1);
182
+ cutoffDate.setHours(0, 0, 0, 0);
183
+ break;
184
+ default:
185
+ cutoffDate = new Date(0);
186
+ }
187
+ filteredEvents = filteredEvents.filter(event => {
188
+ const eventDate = new Date(event.created_at);
189
+ return eventDate >= cutoffDate;
190
+ });
191
+ }
192
+ if (description) {
193
+ filteredEvents = filteredEvents.filter(event => {
194
+ var _event$payload$commit, _event$payload$pull_r, _event$payload$issue, _event$payload$issue2;
195
+ let eventDescription = '';
196
+ if (event.type === 'PushEvent' && (_event$payload$commit = event.payload.commits) != null && _event$payload$commit.length) {
197
+ eventDescription = `Pushed ${event.payload.commits.length} commits`;
198
+ } else if (event.type === 'PullRequestEvent' && (_event$payload$pull_r = event.payload.pull_request) != null && _event$payload$pull_r.title) {
199
+ eventDescription = event.payload.pull_request.title;
200
+ } else if (event.type === 'IssuesEvent' && (_event$payload$issue = event.payload.issue) != null && _event$payload$issue.title) {
201
+ eventDescription = event.payload.issue.title;
202
+ } else if (event.type === 'IssueCommentEvent' && (_event$payload$issue2 = event.payload.issue) != null && _event$payload$issue2.title) {
203
+ eventDescription = `Commented on issue: ${event.payload.issue.title}`;
204
+ }
205
+ return eventDescription.toLowerCase().includes(description.toLowerCase());
206
+ });
207
+ }
208
+
209
+ // Calculate pagination
210
+ const pageNum = Number(page);
211
+ const perPage = Number(per_page);
212
+ const startIndex = (pageNum - 1) * perPage;
213
+ const endIndex = startIndex + perPage;
214
+ const paginatedEvents = filteredEvents.slice(startIndex, endIndex);
215
+
216
+ // Extract unique values for filters (only on first page)
217
+ const repositories = [...new Set(allEvents.map(event => event.repo.name))].sort();
218
+ const actionTypes = [...new Set(allEvents.map(event => event.type.replace('Event', '')))].sort();
219
+
220
+ // Return paginated results with metadata
221
+ return {
222
+ events: paginatedEvents,
223
+ total: filteredEvents.length,
224
+ repositories,
225
+ actionTypes,
226
+ page: pageNum,
227
+ per_page: perPage,
228
+ total_pages: Math.ceil(filteredEvents.length / perPage),
229
+ total_fetched_events: allEvents.length,
230
+ max_pages_fetched: githubPage - 1
231
+ };
232
+ } catch (error) {
233
+ console.error('Error fetching GitHub events:', error);
234
+ throw new Error(`${error instanceof Error ? error.message : String(error)}`);
235
+ }
236
+ }
237
+ async function getEvents({
238
+ githubUser,
239
+ githubToken,
240
+ apiUrl = undefined,
241
+ query
242
+ }) {
243
+ const {
244
+ page,
245
+ perPage,
246
+ repo,
247
+ action,
248
+ description,
249
+ date
250
+ } = query;
251
+ console.log(`getEvents called - page: ${page}, perPage: ${perPage}`);
252
+ const queryParams = new URLSearchParams((0, _extends2.default)({
253
+ page: page.toString(),
254
+ per_page: perPage.toString()
255
+ }, repo && {
256
+ repo
257
+ }, action && {
258
+ action
259
+ }, date && {
260
+ date
261
+ }, description && {
262
+ description
263
+ }));
264
+ if (apiUrl) {
265
+ const url = apiUrl;
266
+ console.log(`Fetching from custom API URL: ${url}?${queryParams}`);
267
+ const response = await fetch(`${url}?${queryParams}`);
268
+ return response.json();
269
+ }
270
+ return githubEventsQuery({
271
+ query: {
272
+ page,
273
+ per_page: perPage,
274
+ repo,
275
+ action,
276
+ date,
277
+ description
278
+ },
279
+ githubUser,
280
+ githubToken
281
+ });
282
+ }
283
+ function ErrorDetails({
284
+ error
285
+ }) {
286
+ const date = (0, _dateFns.format)(new Date(), 'MMM d, yyyy h:mm a');
287
+ const [errorDetails, setErrorDetails] = React.useState({
288
+ type: 'Error: Unknown Error',
289
+ message: 'Sorry but your princess is in another castle',
290
+ status: undefined
291
+ });
292
+ React.useEffect(() => {
293
+ if (error instanceof _requestError.RequestError) {
294
+ var _error$response;
295
+ console.log('request error', error);
296
+ setErrorDetails({
297
+ type: 'Error: Request Error',
298
+ message: error.message,
299
+ status: (_error$response = error.response) == null ? void 0 : _error$response.status // Add optional chaining
300
+ });
301
+ } else if (typeof error === 'string') {
302
+ // Handle string errors
303
+ setErrorDetails({
304
+ type: 'Error',
305
+ message: error
306
+ });
307
+ } else {
308
+ // Fallback
309
+ setErrorDetails({
310
+ type: 'Unknown Error',
311
+ message: 'An unknown error occurred'
312
+ });
313
+ }
314
+ }, [error]);
315
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
316
+ sx: {
317
+ p: '8px',
318
+ display: 'content'
319
+ },
320
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
321
+ sx: {
322
+ display: 'flex',
323
+ alignItems: 'center',
324
+ gap: '16px'
325
+ },
326
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
327
+ variant: "caption",
328
+ color: "text.secondary",
329
+ children: date
330
+ }), _Chip || (_Chip = /*#__PURE__*/(0, _jsxRuntime.jsx)(_Chip2.default, {
331
+ label: 'Error',
332
+ size: "small",
333
+ color: "error"
334
+ }))]
335
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Typography.default, {
336
+ variant: "h6",
337
+ component: "h3",
338
+ sx: {
339
+ mb: 1
340
+ },
341
+ children: [errorDetails.type, " ", errorDetails.status ? `(${errorDetails.status})` : '']
342
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Box.default, {
343
+ sx: {
344
+ alignItems: 'center'
345
+ },
346
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
347
+ variant: "body2",
348
+ color: "text.secondary",
349
+ children: errorDetails.message
350
+ })
351
+ })]
352
+ });
353
+ }
354
+ const SmalMi = (0, _styles.styled)(_MenuItem.default)({
355
+ fontSize: '12px'
356
+ });
357
+ function GithubEvents({
358
+ apiUrl,
359
+ eventsPerPage = 40,
360
+ hideMetadata = false,
361
+ githubUser,
362
+ githubToken
363
+ }) {
364
+ const [events, setEvents] = React.useState([]);
365
+ const [loading, setLoading] = React.useState(true);
366
+ const [error, setError] = React.useState(null);
367
+ const [repoFilter, setRepoFilter] = React.useState('');
368
+ const [actionFilter, setActionFilter] = React.useState('');
369
+ const [repositories, setRepositories] = React.useState([]);
370
+ const [actionTypes, setActionTypes] = React.useState([]);
371
+ const [dateFilter, setDateFilter] = React.useState('');
372
+ // @ts-ignore -- setter kept for future use
373
+ const [descriptionFilter, _setDescriptionFilter] = React.useState('');
374
+ // @ts-ignore -- state kept for future use
375
+ const [_descriptions, setDescriptions] = React.useState([]);
376
+ const [page, setPage] = React.useState(1);
377
+ const [totalCount, setTotalCount] = React.useState(0);
378
+ const [cachedEvents, setCachedEvents] = React.useState([]);
379
+ const [lastUpdated, setLastUpdated] = React.useState('');
380
+ const [selectedEvent, selectEvent] = React.useState({
381
+ id: ''
382
+ });
383
+ const theme = (0, _styles.useTheme)();
384
+ const scrollRef = React.useRef(null);
385
+ // @ts-ignore -- state kept for future use
386
+ const [_showAttached, setShowAttached] = React.useState(false);
387
+ // @ts-ignore -- state kept for future use
388
+ const [_scrollTop, setScrollTop] = React.useState(0);
389
+ const initializedRef = React.useRef(false);
390
+ const isFilterChangeRef = React.useRef(false);
391
+ const isPageChangeRef = React.useRef(false);
392
+
393
+ // Create a more specific cache key with consistent format
394
+ const cacheKey = React.useMemo(() => `github_events_${githubUser.toLowerCase()}`, [githubUser]);
395
+
396
+ // Add a ref to track if we've fetched from API in this session
397
+ const fetchedThisSessionRef = React.useRef(false);
398
+
399
+ // Debug function to clear cache (for development)
400
+ // const clearCache = () => {
401
+ // console.log(`Clearing cache for ${cacheKey}`);
402
+ // localStorage.removeItem(cacheKey);
403
+ // setCachedEvents([]);
404
+ // setEvents([]);
405
+ // fetchedThisSessionRef.current = false;
406
+ // initializedRef.current = false;
407
+ // };
408
+
409
+ React.useEffect(() => {
410
+ const el = scrollRef.current;
411
+ if (!el) return;
412
+ const onScroll = () => {
413
+ setScrollTop(el.scrollTop);
414
+ setShowAttached(true);
415
+ console.log(el.scrollTop);
416
+
417
+ // Hide after 1s of inactivity
418
+ clearTimeout(onScroll.hideTimeout);
419
+ onScroll.hideTimeout = setTimeout(() => {
420
+ setShowAttached(false);
421
+ }, 1000);
422
+ };
423
+ el.addEventListener('scroll', onScroll);
424
+ return () => el.removeEventListener('scroll', onScroll);
425
+ }, []);
426
+ const buildFilterOptionsFromEvents = events => {
427
+ const uniqueRepos = new Set();
428
+ const uniqueActions = new Set();
429
+ const uniqueDescriptions = new Set();
430
+ events.forEach(event => {
431
+ uniqueRepos.add(event.repo.name);
432
+ uniqueActions.add(event.type.replace('Event', ''));
433
+ if (event.payload) {
434
+ var _event$payload$commit2, _event$payload$pull_r2, _event$payload$issue3, _event$payload$issue4;
435
+ if (event.type === 'PushEvent' && (_event$payload$commit2 = event.payload.commits) != null && _event$payload$commit2.length) {
436
+ uniqueDescriptions.add(`Pushed ${event.payload.commits.length} commits`);
437
+ } else if (event.type === 'PullRequestEvent' && (_event$payload$pull_r2 = event.payload.pull_request) != null && _event$payload$pull_r2.title) {
438
+ uniqueDescriptions.add(event.payload.pull_request.title);
439
+ } else if (event.type === 'IssuesEvent' && (_event$payload$issue3 = event.payload.issue) != null && _event$payload$issue3.title) {
440
+ uniqueDescriptions.add(event.payload.issue.title);
441
+ } else if (event.type === 'IssueCommentEvent' && (_event$payload$issue4 = event.payload.issue) != null && _event$payload$issue4.title) {
442
+ uniqueDescriptions.add(`Commented on issue: ${event.payload.issue.title}`);
443
+ }
444
+ }
445
+ });
446
+ setRepositories(Array.from(uniqueRepos).sort());
447
+ setActionTypes(Array.from(uniqueActions).sort());
448
+ setDescriptions(Array.from(uniqueDescriptions).sort());
449
+ };
450
+ const processEvents = rawEvents => {
451
+ console.log('Processing events, count:', rawEvents.length);
452
+ if (rawEvents.length === 0) {
453
+ console.log('No events to process');
454
+ return [];
455
+ }
456
+ try {
457
+ // Log sample event to debug format
458
+ if (rawEvents.length > 0) {
459
+ console.log('Sample raw event to process:', JSON.stringify(rawEvents[0]).substring(0, 500) + '...');
460
+ }
461
+ return rawEvents.map((event, index) => {
462
+ var _event$payload$commit3;
463
+ try {
464
+ var _event$repo2;
465
+ if (!event) {
466
+ console.error(`Event at index ${index} is undefined`);
467
+ return null;
468
+ }
469
+ if (!event.created_at) {
470
+ console.error(`Event at index ${index} missing created_at:`, event);
471
+ return null;
472
+ }
473
+ const dateTime = (0, _dateFnsTz.toZonedTime)((0, _dateFns.parseISO)(event.created_at), 'America/Chicago');
474
+ const date = (0, _dateFns.format)(dateTime, 'MM-dd-yyyy');
475
+ const formattedDate = (0, _dateFns.format)(dateTime, 'MMM d, yyyy h:mm a');
476
+ let action = '';
477
+ let description = '';
478
+ let link = '';
479
+ let id = event.id;
480
+ try {
481
+ switch (event.type) {
482
+ case 'PushEvent':
483
+ action = 'Push';
484
+ description = `Pushed ${((_event$payload$commit3 = event.payload.commits) == null ? void 0 : _event$payload$commit3.length) || 0} commits`;
485
+ link = `https://github.com/${event.repo.name}/commit/${event.payload.head}`;
486
+ break;
487
+ case 'PullRequestEvent':
488
+ action = 'Pull Request';
489
+ description = event.payload.pull_request.title;
490
+ link = event.payload.pull_request.html_url;
491
+ break;
492
+ case 'IssuesEvent':
493
+ action = 'Issue';
494
+ description = event.payload.issue.title;
495
+ link = event.payload.issue.html_url;
496
+ break;
497
+ case 'IssueCommentEvent':
498
+ action = 'Comment';
499
+ description = `Commented on issue: ${event.payload.issue.title}`;
500
+ link = event.payload.comment.html_url;
501
+ break;
502
+ default:
503
+ action = event.type.replace('Event', '');
504
+ description = '';
505
+ link = `https://github.com/${event.repo.name}`;
506
+ }
507
+ } catch (err) {
508
+ var _event$type, _event$repo;
509
+ console.error(`Error processing event type ${event.type} at index ${index}:`, err);
510
+ action = ((_event$type = event.type) == null ? void 0 : _event$type.replace('Event', '')) || 'Unknown';
511
+ description = 'Error processing event details';
512
+ link = (_event$repo = event.repo) != null && _event$repo.name ? `https://github.com/${event.repo.name}` : '';
513
+ }
514
+ const eventDetails = {
515
+ id: id || `event-${index}`,
516
+ date: formattedDate,
517
+ dateOnly: date,
518
+ repo: ((_event$repo2 = event.repo) == null ? void 0 : _event$repo2.name) || 'unknown-repo',
519
+ action,
520
+ actionType: event.type || 'UnknownEvent',
521
+ description,
522
+ url: link,
523
+ state: 'open',
524
+ user: '',
525
+ avatarUrl: '',
526
+ number: 0,
527
+ merged: false,
528
+ comments: 0,
529
+ commits: 0,
530
+ ref: '',
531
+ commitsList: [],
532
+ payload: event.payload
533
+ };
534
+ return eventDetails;
535
+ } catch (err) {
536
+ console.error(`Error processing event at index ${index}:`, err, event);
537
+ // Return a placeholder event to avoid breaking the UI
538
+ return {
539
+ id: `error-${index}`,
540
+ date: (0, _dateFns.format)(new Date(), 'MMM d, yyyy h:mm a'),
541
+ dateOnly: (0, _dateFns.format)(new Date(), 'MM-dd-yyyy'),
542
+ repo: 'Error processing event',
543
+ action: 'Error',
544
+ actionType: 'ErrorEvent',
545
+ description: err instanceof Error ? err.message : 'Unknown error',
546
+ url: '',
547
+ state: 'open',
548
+ user: '',
549
+ avatarUrl: '',
550
+ number: 0,
551
+ merged: false,
552
+ comments: 0,
553
+ commits: 0,
554
+ ref: '',
555
+ commitsList: [],
556
+ payload: {}
557
+ };
558
+ }
559
+ }).filter(Boolean); // Filter out any null values
560
+ } catch (err) {
561
+ console.error('Fatal error in processEvents:', err);
562
+ return [];
563
+ }
564
+ };
565
+ const filterEvents = events => {
566
+ return events.filter(event => {
567
+ const matchesRepo = !repoFilter || event.repo.name === repoFilter;
568
+ const matchesAction = !actionFilter || event.type.replace('Event', '') === actionFilter;
569
+ let matchesDescription = true;
570
+ if (descriptionFilter) {
571
+ const eventDescription = getEventDescription(event);
572
+ matchesDescription = eventDescription.includes(descriptionFilter);
573
+ }
574
+ if (dateFilter) {
575
+ const filterDate = getFilteredDate(dateFilter);
576
+ if (filterDate) {
577
+ const eventDate = new Date(event.created_at);
578
+ if (eventDate < filterDate) return false;
579
+ }
580
+ }
581
+ return matchesRepo && matchesAction && matchesDescription;
582
+ });
583
+ };
584
+ const getEventDescription = event => {
585
+ if (event.type === 'PushEvent') {
586
+ var _event$payload$commit4;
587
+ return `Pushed ${((_event$payload$commit4 = event.payload.commits) == null ? void 0 : _event$payload$commit4.length) || 0} commits`;
588
+ } else if (event.type === 'PullRequestEvent') {
589
+ return event.payload.pull_request.title;
590
+ } else if (event.type === 'IssuesEvent') {
591
+ return event.payload.issue.title;
592
+ } else if (event.type === 'IssueCommentEvent') {
593
+ return `Commented on issue: ${event.payload.issue.title}`;
594
+ }
595
+ return '';
596
+ };
597
+
598
+ // Filter events based on date
599
+ const getFilteredDate = filter => {
600
+ const now = new Date();
601
+ switch (filter) {
602
+ case 'today':
603
+ return new Date(now.setHours(0, 0, 0, 0));
604
+ case 'yesterday':
605
+ {
606
+ const yesterday = new Date(now);
607
+ yesterday.setDate(yesterday.getDate() - 1);
608
+ return yesterday;
609
+ }
610
+ case 'week':
611
+ {
612
+ const weekAgo = new Date(now);
613
+ weekAgo.setDate(weekAgo.getDate() - 7);
614
+ return weekAgo;
615
+ }
616
+ default:
617
+ return null;
618
+ }
619
+ };
620
+ const fetchAllGitHubEvents = async () => {
621
+ // Skip if we've already fetched this session
622
+ if (fetchedThisSessionRef.current) {
623
+ console.log('Already fetched events this session, using cached data');
624
+ return;
625
+ }
626
+ setLoading(true);
627
+ setError(null);
628
+ try {
629
+ console.log('Fetching ALL GitHub events (all pages)');
630
+ const allEvents = [];
631
+ let hasMore = true;
632
+ let pageNum = 1;
633
+ const maxPages = 10; // GitHub API typically limits to 10 pages max
634
+
635
+ while (hasMore && pageNum <= maxPages) {
636
+ console.log(`Fetching page ${pageNum} of GitHub events (100 per page)`);
637
+ const queryParams = (0, _extends2.default)({
638
+ page: pageNum,
639
+ perPage: 100
640
+ }, repoFilter && {
641
+ repo: repoFilter
642
+ }, actionFilter && {
643
+ action: actionFilter
644
+ }, dateFilter && {
645
+ date: dateFilter
646
+ }, descriptionFilter && {
647
+ description: descriptionFilter
648
+ });
649
+ try {
650
+ console.log(`API call for page ${pageNum}`);
651
+ const data = await getEvents({
652
+ query: queryParams,
653
+ apiUrl,
654
+ githubUser,
655
+ githubToken
656
+ });
657
+ if (data.events && data.events.length > 0) {
658
+ console.log(`Received ${data.events.length} events for page ${pageNum}`);
659
+ allEvents.push(...data.events);
660
+ pageNum++;
661
+ console.log(`Total events so far: ${allEvents.length}`);
662
+
663
+ // Check if we've reached the end
664
+ if (data.events.length < 100) {
665
+ hasMore = false;
666
+ console.log('Received less than 100 events, reached the end');
667
+ }
668
+ } else {
669
+ hasMore = false;
670
+ console.log('Received 0 events, reached the end');
671
+ }
672
+ } catch (err) {
673
+ console.error(`Error fetching page ${pageNum}:`, err);
674
+ // Break the loop on error but don't fail the whole operation
675
+ hasMore = false;
676
+ }
677
+ }
678
+ console.log(`Fetched a total of ${allEvents.length} events from ${pageNum - 1} pages`);
679
+ if (allEvents.length > 0) {
680
+ // Save all events to cache with user-specific key
681
+ setCachedEvents(allEvents);
682
+ localStorage.setItem(cacheKey, JSON.stringify({
683
+ events: allEvents,
684
+ lastFetched: Date.now(),
685
+ totalCount: allEvents.length
686
+ }));
687
+
688
+ // Mark that we've fetched this session
689
+ sessionStorage.setItem(`${cacheKey}_session_fetched`, 'true');
690
+ fetchedThisSessionRef.current = true;
691
+
692
+ // Update filter options with all data
693
+ buildFilterOptionsFromEvents(allEvents);
694
+
695
+ // Display first page
696
+ const filteredEvents = filterEvents(allEvents);
697
+ setTotalCount(filteredEvents.length);
698
+ const paginatedEvents = filteredEvents.slice(0, eventsPerPage);
699
+ const processedEvents = processEvents(paginatedEvents);
700
+ setEvents(processedEvents);
701
+
702
+ // Select the most recent event by default
703
+ if (processedEvents.length > 0) {
704
+ selectEvent(processedEvents[0]);
705
+ setTimeout(() => {
706
+ const firstRow = document.getElementById(processedEvents[0].id);
707
+ if (firstRow) {
708
+ firstRow.classList.add('selected');
709
+ }
710
+ }, 0);
711
+ }
712
+ } else {
713
+ console.log('No events found, setting empty state');
714
+ setEvents([]);
715
+ setTotalCount(0);
716
+ }
717
+ } catch (err) {
718
+ console.error('Error in fetchAllGitHubEvents:', err);
719
+ if (err instanceof _requestError.RequestError) {
720
+ setError(err);
721
+ } else if (err instanceof Error) {
722
+ setError(err.message);
723
+ } else {
724
+ setError(String(err));
725
+ }
726
+ setEvents([]);
727
+ setTotalCount(0);
728
+ } finally {
729
+ setLoading(false);
730
+ }
731
+ };
732
+ const fetchNewEvents = async () => {
733
+ // Skip if we've already fetched this session
734
+ if (fetchedThisSessionRef.current) {
735
+ console.log('Already fetched events this session, using cached data');
736
+ return;
737
+ }
738
+ setLoading(true);
739
+ try {
740
+ // First, get the most recent event date from our cache
741
+ let mostRecentDate = new Date(0);
742
+ if (cachedEvents.length > 0) {
743
+ mostRecentDate = new Date(Math.max(...cachedEvents.map(e => new Date(e.created_at).getTime())));
744
+ }
745
+ console.log('Fetching new events since', (0, _dateFns.format)(mostRecentDate, 'MMM d, yyyy h:mm a'));
746
+
747
+ // Fetch all new events
748
+ let allNewEvents = [];
749
+ let hasMore = true;
750
+ let pageNum = 1;
751
+ const maxPages = 10; // GitHub API typically limits to 10 pages max
752
+
753
+ while (hasMore && pageNum <= maxPages) {
754
+ const query = {
755
+ page: pageNum,
756
+ perPage: 100 // Maximum allowed by GitHub API
757
+ };
758
+ console.log(`Fetching page ${pageNum} of new events (100 per page)`);
759
+ try {
760
+ const data = await getEvents({
761
+ apiUrl,
762
+ githubUser,
763
+ githubToken,
764
+ query
765
+ });
766
+ if (data.events && data.events.length > 0) {
767
+ // Check if we've reached events we already have
768
+ const allOldEvents = data.events.every(event => {
769
+ const eventDate = new Date(event.created_at);
770
+ return eventDate <= mostRecentDate;
771
+ });
772
+ if (allOldEvents) {
773
+ console.log('All events on this page are already in cache, stopping fetch');
774
+ hasMore = false;
775
+ } else {
776
+ // Filter out events older than our most recent cached event
777
+ const newEvents = data.events.filter(event => {
778
+ const eventDate = new Date(event.created_at);
779
+ return eventDate > mostRecentDate;
780
+ });
781
+ allNewEvents.push(...newEvents);
782
+ console.log(`Found ${newEvents.length} new events on page ${pageNum}`);
783
+ if (data.events.length < 100) {
784
+ console.log('Received less than 100 events, reached the end');
785
+ hasMore = false;
786
+ }
787
+ pageNum++;
788
+ }
789
+ } else {
790
+ hasMore = false;
791
+ console.log('Received 0 events, reached the end');
792
+ }
793
+ } catch (err) {
794
+ console.error(`Error fetching page ${pageNum} in fetchNewEvents:`, err);
795
+ hasMore = false; // Stop on error but continue processing what we've got
796
+ }
797
+ }
798
+ if (allNewEvents.length > 0) {
799
+ console.log(`Fetched ${allNewEvents.length} new events`);
800
+
801
+ // Combine with existing events and sort by date (newest first)
802
+ const updatedEvents = [...allNewEvents, ...cachedEvents];
803
+ updatedEvents.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
804
+
805
+ // Mark that we've fetched this session
806
+ sessionStorage.setItem(`${cacheKey}_session_fetched`, 'true');
807
+ fetchedThisSessionRef.current = true;
808
+
809
+ // Update cache with new events using user-specific key
810
+ setCachedEvents(updatedEvents);
811
+ localStorage.setItem(cacheKey, JSON.stringify({
812
+ events: updatedEvents,
813
+ lastFetched: Date.now(),
814
+ totalCount: updatedEvents.length
815
+ }));
816
+
817
+ // Update UI
818
+ buildFilterOptionsFromEvents(updatedEvents);
819
+
820
+ // Display first page with updated data
821
+ const filteredEvents = filterEvents(updatedEvents);
822
+ setTotalCount(filteredEvents.length);
823
+ const paginatedEvents = filteredEvents.slice(0, eventsPerPage);
824
+ const processedEvents = processEvents(paginatedEvents);
825
+ setEvents(processedEvents);
826
+ setLastUpdated((0, _dateFns.format)(new Date(), 'MMM d, yyyy h:mm a'));
827
+ console.log('Updated display with new events');
828
+ } else {
829
+ console.log('No new events found');
830
+
831
+ // Mark that we've fetched this session even if no new events
832
+ sessionStorage.setItem(`${cacheKey}_session_fetched`, 'true');
833
+ fetchedThisSessionRef.current = true;
834
+
835
+ // Just update the last fetched time with user-specific key
836
+ const currentCache = JSON.parse(localStorage.getItem(cacheKey) || '{}');
837
+ localStorage.setItem(cacheKey, JSON.stringify((0, _extends2.default)({}, currentCache, {
838
+ lastFetched: Date.now()
839
+ })));
840
+ setLastUpdated((0, _dateFns.format)(new Date(), 'MMM d, yyyy h:mm a'));
841
+
842
+ // Use existing cached data for display
843
+ const filteredEvents = filterEvents(cachedEvents);
844
+ const paginatedEvents = filteredEvents.slice(0, eventsPerPage);
845
+ const processedEvents = processEvents(paginatedEvents);
846
+ console.log('Using existing events for display, count:', processedEvents.length);
847
+ setEvents(processedEvents);
848
+ }
849
+ } catch (err) {
850
+ console.error('Failed to fetch new events:', err);
851
+ if (err instanceof _requestError.RequestError) {
852
+ setError(err);
853
+ } else if (err instanceof Error) {
854
+ setError(err.message);
855
+ } else {
856
+ setError(String(err));
857
+ }
858
+
859
+ // Use existing cached data for display if available
860
+ if (cachedEvents.length > 0) {
861
+ console.log('Using existing cached data after error');
862
+ const filteredEvents = filterEvents(cachedEvents);
863
+ const paginatedEvents = filteredEvents.slice(0, eventsPerPage);
864
+ const processedEvents = processEvents(paginatedEvents);
865
+ setEvents(processedEvents);
866
+ }
867
+ } finally {
868
+ setLoading(false);
869
+ }
870
+ };
871
+ const fetchGitHubEvents = async (pageNum = 1, isFilterChange = false) => {
872
+ // Always use cached data for pagination and filtering
873
+ if (cachedEvents.length > 0) {
874
+ console.log(`Using ${cachedEvents.length} cached events for pagination/filtering (page ${pageNum})`);
875
+ setLoading(true);
876
+ try {
877
+ const filteredCachedEvents = filterEvents(cachedEvents);
878
+ console.log('Filtered cached events:', filteredCachedEvents.length);
879
+ const startIndex = (pageNum - 1) * eventsPerPage;
880
+ const endIndex = startIndex + eventsPerPage;
881
+ const paginatedEvents = filteredCachedEvents.slice(startIndex, endIndex);
882
+ console.log(`Showing events ${startIndex + 1}-${Math.min(endIndex, filteredCachedEvents.length)} of ${filteredCachedEvents.length}`);
883
+ const processedEvents = processEvents(paginatedEvents);
884
+ console.log('Processed events count:', processedEvents.length);
885
+ setEvents(processedEvents);
886
+ setTotalCount(filteredCachedEvents.length);
887
+
888
+ // Select the most recent event by default if none selected
889
+ if (processedEvents.length > 0 && !selectedEvent.id) {
890
+ selectEvent(processedEvents[0]);
891
+ setTimeout(() => {
892
+ const firstRow = document.getElementById(processedEvents[0].id);
893
+ if (firstRow) {
894
+ firstRow.classList.add('selected');
895
+ }
896
+ }, 0);
897
+ }
898
+ } catch (err) {
899
+ console.error('Error processing cached events:', err);
900
+ if (err instanceof _requestError.RequestError) {
901
+ setError(err);
902
+ } else if (err instanceof Error) {
903
+ setError(err.message);
904
+ } else {
905
+ setError(String(err));
906
+ }
907
+ } finally {
908
+ setLoading(false);
909
+ }
910
+ return;
911
+ }
912
+
913
+ // If we don't have cached data, fetch from API
914
+ console.log('No cached data available in component state, fetching from API');
915
+ fetchAllGitHubEvents();
916
+ };
917
+
918
+ // Single initialization effect to handle all initial data loading
919
+ React.useEffect(() => {
920
+ // Skip if already initialized
921
+ if (initializedRef.current) {
922
+ console.log('Component already initialized, skipping initialization');
923
+ return;
924
+ }
925
+ initializedRef.current = true;
926
+ console.log('Initializing GithubEvents component once');
927
+ console.log(`Using cache key: "${cacheKey}" for GitHub user: ${githubUser}`);
928
+
929
+ // Check session storage to see if we've already fetched this session
930
+ const sessionKey = `${cacheKey}_session_fetched`;
931
+ const fetchedThisSession = sessionStorage.getItem(sessionKey) === 'true';
932
+ console.log('Already fetched this session:', fetchedThisSession);
933
+ fetchedThisSessionRef.current = fetchedThisSession;
934
+
935
+ // Debug all localStorage keys to make sure we're looking at the right one
936
+ console.log('All localStorage keys:', Object.keys(localStorage));
937
+ const cached = localStorage.getItem(cacheKey);
938
+ console.log(`LocalStorage for "${cacheKey}" exists:`, !!cached);
939
+ if (cached) {
940
+ try {
941
+ const parsedCache = JSON.parse(cached);
942
+ console.log('Cache parsed successfully, events count:', parsedCache.events.length);
943
+ console.log('Last fetch time:', new Date(parsedCache.lastFetched).toLocaleString());
944
+ if (!Array.isArray(parsedCache.events) || parsedCache.events.length === 0) {
945
+ console.log('Cached events array is empty or invalid, fetching all events');
946
+ fetchAllGitHubEvents();
947
+ return;
948
+ }
949
+
950
+ // Set cached events state
951
+ setCachedEvents(parsedCache.events);
952
+ setTotalCount(parsedCache.totalCount || parsedCache.events.length);
953
+ buildFilterOptionsFromEvents(parsedCache.events);
954
+
955
+ // Format last updated time
956
+ const lastFetchDate = new Date(parsedCache.lastFetched);
957
+ setLastUpdated((0, _dateFns.format)(lastFetchDate, 'MMM d, yyyy h:mm a'));
958
+
959
+ // Check if we should refresh cache (if it's been more than 8 hours and we haven't fetched this session)
960
+ const hoursSinceLastFetch = (Date.now() - parsedCache.lastFetched) / (1000 * 60 * 60);
961
+ console.log('Hours since last fetch:', hoursSinceLastFetch.toFixed(2));
962
+ console.log('Should refresh cache:', hoursSinceLastFetch >= 8 && !fetchedThisSession);
963
+
964
+ // Apply initial filtering to cached events and display them first
965
+ const filteredCachedEvents = filterEvents(parsedCache.events);
966
+ console.log('Filtered events count:', filteredCachedEvents.length);
967
+ const paginatedEvents = filteredCachedEvents.slice(0, eventsPerPage);
968
+ console.log('Paginated events for display:', paginatedEvents.length);
969
+ const processedEvents = processEvents(paginatedEvents);
970
+ setEvents(processedEvents);
971
+ setLoading(false);
972
+
973
+ // Only fetch new events if it's been more than 8 hours AND we haven't fetched this session
974
+ if (hoursSinceLastFetch >= 8 && !fetchedThisSession) {
975
+ console.log('Cache is stale (>= 8 hours old), fetching new events in background');
976
+ // Fetch new events in background
977
+ setTimeout(() => {
978
+ fetchNewEvents();
979
+ // Mark that we've fetched this session
980
+ sessionStorage.setItem(sessionKey, 'true');
981
+ fetchedThisSessionRef.current = true;
982
+ }, 100);
983
+ } else {
984
+ console.log('Using cached events, no need to refresh');
985
+ }
986
+
987
+ // Select the most recent event by default
988
+ if (processedEvents.length > 0) {
989
+ selectEvent(processedEvents[0]);
990
+ setTimeout(() => {
991
+ const firstRow = document.getElementById(processedEvents[0].id);
992
+ if (firstRow) {
993
+ firstRow.classList.add('selected');
994
+ }
995
+ }, 0);
996
+ } else {
997
+ console.log('No events to display after filtering/pagination');
998
+ }
999
+ } catch (err) {
1000
+ console.error('Failed to parse cached events, fetching new data:', err);
1001
+ fetchAllGitHubEvents();
1002
+ }
1003
+ } else {
1004
+ console.log('No cache found, fetching ALL GitHub events for first time');
1005
+ fetchAllGitHubEvents();
1006
+ }
1007
+ }, [cacheKey, githubUser, eventsPerPage]);
1008
+
1009
+ // Update the filter and pagination effect handlers
1010
+ React.useEffect(() => {
1011
+ // Skip the first render and only respond to actual filter changes
1012
+ if (!initializedRef.current) {
1013
+ console.log('Filter change ignored - component not initialized yet');
1014
+ return;
1015
+ }
1016
+ if (!isFilterChangeRef.current) {
1017
+ console.log('First filter change detected, just setting flag');
1018
+ isFilterChangeRef.current = true;
1019
+ return;
1020
+ }
1021
+ console.log('Filter changed, updating events with the following filters:');
1022
+ console.log(' Repository:', repoFilter || 'None');
1023
+ console.log(' Action type:', actionFilter || 'None');
1024
+ console.log(' Date filter:', dateFilter || 'None');
1025
+ console.log(' Description:', descriptionFilter || 'None');
1026
+ if (page !== 1) {
1027
+ console.log('Resetting to page 1 due to filter change');
1028
+ setPage(1);
1029
+ } else {
1030
+ console.log('Already on page 1, applying filters');
1031
+ fetchGitHubEvents(1, true);
1032
+ }
1033
+ }, [repoFilter, actionFilter, dateFilter, descriptionFilter]);
1034
+
1035
+ // Unified effect to handle page changes
1036
+ React.useEffect(() => {
1037
+ // Skip the first render and only respond to actual page changes
1038
+ if (!initializedRef.current) {
1039
+ console.log('Page change ignored - component not initialized yet');
1040
+ return;
1041
+ }
1042
+ if (!isPageChangeRef.current) {
1043
+ console.log('First page change detected, just setting flag');
1044
+ isPageChangeRef.current = true;
1045
+ return;
1046
+ }
1047
+ console.log(`Page changed to ${page}, fetching events`);
1048
+ fetchGitHubEvents(page, false);
1049
+ }, [page]);
1050
+ const totalPages = React.useMemo(() => {
1051
+ return Math.ceil(totalCount / eventsPerPage);
1052
+ }, [totalCount]);
1053
+ const getTimeOnly = date => {
1054
+ const parsed = (0, _dateFns.parse)(date, 'MMM d, yyyy h:mm a', new Date());
1055
+ return (0, _dateFns.format)(parsed, 'h:mm a');
1056
+ };
1057
+ let latestDateDisplayed = null;
1058
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
1059
+ sx: {
1060
+ display: 'flex',
1061
+ flexDirection: 'column',
1062
+ gap: 1
1063
+ },
1064
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
1065
+ sx: {
1066
+ mb: 1,
1067
+ display: 'flex',
1068
+ justifyContent: 'space-between',
1069
+ alignItems: 'end'
1070
+ },
1071
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
1072
+ sx: {
1073
+ display: 'flex',
1074
+ gap: .5,
1075
+ flexDirection: 'column'
1076
+ },
1077
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_Typography.default, {
1078
+ variant: "subtitle1",
1079
+ fontWeight: "semiBold",
1080
+ children: [githubUser, "'s Events"]
1081
+ }), lastUpdated && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Typography.default, {
1082
+ variant: "caption",
1083
+ color: "text.secondary",
1084
+ children: ["Last updated: ", lastUpdated]
1085
+ })]
1086
+ }), totalCount > eventsPerPage && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Pagination.default, {
1087
+ count: totalPages,
1088
+ page: page,
1089
+ onChange: (_, value) => setPage(value),
1090
+ size: "small",
1091
+ sx: {
1092
+ '& .MuiPaginationItem-root': {
1093
+ color: theme.palette.text.secondary,
1094
+ borderColor: theme.palette.divider
1095
+ }
1096
+ }
1097
+ })]
1098
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
1099
+ sx: {
1100
+ display: 'flex',
1101
+ gap: '8px',
1102
+ '& .metadata-display': {
1103
+ width: 'max-content',
1104
+ display: 'flex',
1105
+ padding: '0px'
1106
+ },
1107
+ '@media (max-width:813px)': {
1108
+ '& .metadata-display': {
1109
+ display: 'none'
1110
+ }
1111
+ },
1112
+ '@media (max-width:340px)': {
1113
+ '& .metadata-display': {
1114
+ display: 'none'
1115
+ }
1116
+ }
1117
+ },
1118
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Box.default, {
1119
+ sx: {
1120
+ minWidth: '340px',
1121
+ flexShrink: 0,
1122
+ display: 'block',
1123
+ position: 'relative'
1124
+ },
1125
+ className: "master-container",
1126
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_TableContainer.default, {
1127
+ component: _Paper.default,
1128
+ sx: {
1129
+ mb: 4,
1130
+ borderRadius: 0,
1131
+ position: 'relative'
1132
+ },
1133
+ className: "overflow-visible",
1134
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Table.default, {
1135
+ size: "small",
1136
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_TableHead.default, {
1137
+ sx: {
1138
+ padding: '6px 8px'
1139
+ },
1140
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_TableRow3.default, {
1141
+ sx: {
1142
+ padding: '6px 8px'
1143
+ },
1144
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_TableCell.default, {
1145
+ sx: {
1146
+ padding: '6px 8px'
1147
+ },
1148
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
1149
+ sx: {
1150
+ display: 'flex',
1151
+ flexDirection: 'column',
1152
+ gap: 1
1153
+ },
1154
+ children: ["Date", /*#__PURE__*/(0, _jsxRuntime.jsx)(_FormControl.default, {
1155
+ size: "small",
1156
+ fullWidth: true,
1157
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Select.default, {
1158
+ value: dateFilter,
1159
+ onChange: e => setDateFilter(e.target.value),
1160
+ displayEmpty: true,
1161
+ sx: {
1162
+ '& .MuiSelect-select': {
1163
+ py: 0.5,
1164
+ fontSize: '12px'
1165
+ }
1166
+ },
1167
+ children: [_SmalMi || (_SmalMi = /*#__PURE__*/(0, _jsxRuntime.jsx)(SmalMi, {
1168
+ value: "",
1169
+ children: "All time"
1170
+ })), _SmalMi2 || (_SmalMi2 = /*#__PURE__*/(0, _jsxRuntime.jsx)(SmalMi, {
1171
+ value: "today",
1172
+ children: "Today"
1173
+ })), _SmalMi3 || (_SmalMi3 = /*#__PURE__*/(0, _jsxRuntime.jsx)(SmalMi, {
1174
+ value: "yesterday",
1175
+ children: "Yesterday"
1176
+ })), _SmalMi4 || (_SmalMi4 = /*#__PURE__*/(0, _jsxRuntime.jsx)(SmalMi, {
1177
+ value: "week",
1178
+ children: "Week"
1179
+ })), _SmalMi5 || (_SmalMi5 = /*#__PURE__*/(0, _jsxRuntime.jsx)(SmalMi, {
1180
+ value: "month",
1181
+ children: "Month"
1182
+ }))]
1183
+ })
1184
+ })]
1185
+ })
1186
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_TableCell.default, {
1187
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
1188
+ sx: {
1189
+ display: 'flex',
1190
+ flexDirection: 'column',
1191
+ gap: 1
1192
+ },
1193
+ children: ["Repository", /*#__PURE__*/(0, _jsxRuntime.jsx)(_Autocomplete.default, {
1194
+ size: "small",
1195
+ options: repositories,
1196
+ value: repoFilter,
1197
+ onChange: (_, newValue) => setRepoFilter(newValue || ''),
1198
+ renderInput: params => /*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, (0, _extends2.default)({}, params, {
1199
+ placeholder: "All",
1200
+ sx: {
1201
+ '& .MuiInputBase-root': {
1202
+ height: '32px',
1203
+ minHeight: '32px',
1204
+ fontSize: '12px',
1205
+ p: '0 8px',
1206
+ '& input': {
1207
+ p: '2.5px 4px'
1208
+ },
1209
+ '& fieldset': {
1210
+ borderColor: 'rgba(255, 255, 255, 0.23)'
1211
+ }
1212
+ }
1213
+ }
1214
+ })),
1215
+ slotProps: {
1216
+ paper: {
1217
+ sx: {
1218
+ fontSize: '12px!important',
1219
+ '& .MuiAutocomplete-listbox': {
1220
+ '& .MuiAutocomplete-option': {
1221
+ whiteSpace: 'nowrap',
1222
+ overflow: 'visible',
1223
+ textOverflow: 'ellipsis',
1224
+ fontSize: '12px!important',
1225
+ width: '100%'
1226
+ }
1227
+ }
1228
+ }
1229
+ }
1230
+ },
1231
+ freeSolo: true,
1232
+ selectOnFocus: true,
1233
+ clearOnBlur: true,
1234
+ sx: {
1235
+ '& .MuiOutlinedInput-root': {
1236
+ p: 0
1237
+ }
1238
+ }
1239
+ })]
1240
+ })
1241
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_TableCell.default, {
1242
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
1243
+ sx: {
1244
+ display: 'flex',
1245
+ flexDirection: 'column',
1246
+ gap: 1
1247
+ },
1248
+ children: ["Type", /*#__PURE__*/(0, _jsxRuntime.jsx)(_Autocomplete.default, {
1249
+ size: "small",
1250
+ options: actionTypes,
1251
+ value: actionFilter,
1252
+ onChange: (_, newValue) => setActionFilter(newValue || ''),
1253
+ renderInput: params => /*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, (0, _extends2.default)({}, params, {
1254
+ placeholder: "All",
1255
+ sx: {
1256
+ '& .MuiInputBase-root': {
1257
+ height: '32px',
1258
+ minHeight: '32px',
1259
+ fontSize: '12px',
1260
+ p: '0 8px',
1261
+ '& input': {
1262
+ p: '2.5px 4px'
1263
+ },
1264
+ '& fieldset': {
1265
+ borderColor: 'rgba(255, 255, 255, 0.23)'
1266
+ }
1267
+ }
1268
+ }
1269
+ })),
1270
+ freeSolo: true,
1271
+ selectOnFocus: true,
1272
+ clearOnBlur: true,
1273
+ slotProps: {
1274
+ paper: {
1275
+ sx: {
1276
+ fontSize: '12px!important',
1277
+ '& .MuiAutocomplete-listbox': {
1278
+ '& .MuiAutocomplete-option': {
1279
+ whiteSpace: 'nowrap',
1280
+ overflow: 'hidden',
1281
+ textOverflow: 'ellipsis',
1282
+ fontSize: '12px!important'
1283
+ }
1284
+ }
1285
+ }
1286
+ }
1287
+ },
1288
+ sx: {
1289
+ '& .MuiOutlinedInput-root': {
1290
+ p: 0
1291
+ }
1292
+ }
1293
+ })]
1294
+ })
1295
+ })]
1296
+ })
1297
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_TableBody.default, {
1298
+ sx: {
1299
+ cursor: 'pointer',
1300
+ '& tr:hover td': {
1301
+ backgroundColor: theme.palette.action.hover
1302
+ }
1303
+ },
1304
+ children: [events.map((event, index) => {
1305
+ const showDateRow = event.dateOnly !== latestDateDisplayed;
1306
+ latestDateDisplayed = event.dateOnly;
1307
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(React.Fragment, {
1308
+ children: [showDateRow && /*#__PURE__*/(0, _jsxRuntime.jsx)(_TableRow3.default, {
1309
+ style: {
1310
+ backgroundColor: theme.palette.mode === 'light' ? 'color-mix(in oklab, rgba(0, 97, 194, 0.5) 25%, rgba(235, 235, 235, 0.5))' : 'color-mix(in oklab, rgba(102, 179, 255, 0.5) 25%, rgba(31, 31, 31, 0.5))'
1311
+ },
1312
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_TableCell.default, {
1313
+ colSpan: 4,
1314
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
1315
+ variant: "subtitle2",
1316
+ fontWeight: "semiBold",
1317
+ children: event.dateOnly
1318
+ })
1319
+ })
1320
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_TableRow3.default, {
1321
+ id: event.id,
1322
+ sx: {
1323
+ '& td': {
1324
+ backgroundColor: theme.palette.background.paper,
1325
+ transition: 'all 1s cubic-bezier(1.1, 1.4, 2.1, 1.1, 0.8, 0.7,0.6,0.5,0.4,0.3,0.2,0.1,0.05)'
1326
+ },
1327
+ '&.selected td': {
1328
+ backgroundColor: theme.palette.action.selected,
1329
+ transition: 'all 0.3s cubic-bezier(1.1, 1.4, 2.1, 1.1, 0.8, 0.7,0.6,0.5,0.4,0.3,0.2,0.1,0.05)'
1330
+ },
1331
+ '&.hover td': {
1332
+ backgroundColor: theme.palette.action.hover,
1333
+ transition: 'all 0.3s cubic-bezier(1.1, 1.4, 2.1, 1.1, 0.8, 0.7,0.6,0.5,0.4,0.3,0.2,0.1,0.05)'
1334
+ },
1335
+ '&.selected.hover td': {
1336
+ backgroundColor: theme.palette.action.selected,
1337
+ transition: 'all 0.3s cubic-bezier(1.1, 1.4, 2.1, 1.1, 0.8, 0.7,0.6,0.5,0.4,0.3,0.2,0.1,0.05)'
1338
+ }
1339
+ },
1340
+ onClick: e => {
1341
+ e.preventDefault();
1342
+ const newSelectedRow = e.currentTarget;
1343
+ if (newSelectedRow) {
1344
+ if (selectedEvent.id) {
1345
+ const oldSelectedRow = document.getElementById(selectedEvent.id);
1346
+ if (oldSelectedRow) {
1347
+ oldSelectedRow.classList.remove('selected');
1348
+ }
1349
+ }
1350
+ newSelectedRow.classList.add('selected');
1351
+ selectEvent(event);
1352
+ }
1353
+ },
1354
+ onMouseEnter: e => {
1355
+ const closestRow = e.currentTarget;
1356
+ if (closestRow) {
1357
+ closestRow.classList.add('hover');
1358
+ }
1359
+ },
1360
+ onMouseLeave: e => {
1361
+ const closestRow = e.currentTarget;
1362
+ if (closestRow) {
1363
+ closestRow.classList.remove('hover');
1364
+ }
1365
+ },
1366
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_TableCell.default, {
1367
+ children: getTimeOnly(event.date)
1368
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_TableCell.default, {
1369
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
1370
+ onClick: e => e.stopPropagation(),
1371
+ style: {
1372
+ textDecoration: 'none',
1373
+ color: theme.palette.primary.main,
1374
+ cursor: 'pointer'
1375
+ },
1376
+ children: event.repo && event.repo.includes('/') ? event.repo.split('/')[1] : event.repo
1377
+ })
1378
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_TableCell.default, {
1379
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
1380
+ onClick: e => e.stopPropagation(),
1381
+ style: {
1382
+ textDecoration: 'none',
1383
+ color: theme.palette.primary.main,
1384
+ cursor: 'pointer'
1385
+ },
1386
+ children: event.action
1387
+ })
1388
+ })]
1389
+ })]
1390
+ }, event.id || `event-${index}`);
1391
+ }), events.length === 0 && !loading && (_TableRow || (_TableRow = /*#__PURE__*/(0, _jsxRuntime.jsx)(_TableRow3.default, {
1392
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_TableCell.default, {
1393
+ colSpan: 4,
1394
+ align: "center",
1395
+ children: "No events found"
1396
+ })
1397
+ }))), loading && (_TableRow2 || (_TableRow2 = /*#__PURE__*/(0, _jsxRuntime.jsx)(_TableRow3.default, {
1398
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_TableCell.default, {
1399
+ colSpan: 4,
1400
+ align: "center",
1401
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_CircularProgress.default, {
1402
+ size: 40
1403
+ })
1404
+ })
1405
+ })))]
1406
+ })]
1407
+ })
1408
+ })
1409
+ }), !hideMetadata && selectedEvent.id && /*#__PURE__*/(0, _jsxRuntime.jsx)(MetadataDisplay, {
1410
+ className: "metadata-display",
1411
+ sx: {
1412
+ backgroundColor: 'rgba(255, 255, 255, 0.06)',
1413
+ borderRadiusBottomLeft: theme.shape.borderRadius,
1414
+ borderRadiusBottomRight: theme.shape.borderRadius,
1415
+ borderRadiusTopLeft: 0,
1416
+ borderRadiusTopRight: 0,
1417
+ boxShadow: theme.shadows[2],
1418
+ position: 'sticky',
1419
+ width: 'fit-content',
1420
+ maxWidth: '692px',
1421
+ minWidth: '300px',
1422
+ top: '84px',
1423
+ maxHeight: 'calc(100vh - 100px)',
1424
+ overflow: 'auto',
1425
+ height: 'fit-content'
1426
+ },
1427
+ children: error ? /*#__PURE__*/(0, _jsxRuntime.jsx)(ErrorDetails, {
1428
+ error: error
1429
+ }) : selectedEvent.actionType === 'PullRequestEvent' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_PullRequestEvent.default, {
1430
+ event: selectedEvent
1431
+ }) : selectedEvent.actionType === 'PushEvent' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_PushEvent.default, {
1432
+ event: selectedEvent
1433
+ }) : selectedEvent.actionType === 'DeleteEvent' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_DeleteEvent.default, {
1434
+ event: selectedEvent
1435
+ }) : selectedEvent.actionType === 'CreateEvent' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_CreateEvent.default, {
1436
+ event: selectedEvent
1437
+ }) : selectedEvent.actionType === 'IssuesEvent' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_IssuesEvent.default, {
1438
+ event: selectedEvent
1439
+ }) : selectedEvent.actionType === 'IssueCommentEvent' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_IssueCommentEvent.default, {
1440
+ event: selectedEvent
1441
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(ReactJson, {
1442
+ src: selectedEvent,
1443
+ name: false,
1444
+ theme: "monokai",
1445
+ displayDataTypes: false,
1446
+ enableClipboard: false,
1447
+ displayObjectSize: false,
1448
+ collapsed: 1,
1449
+ collapseStringsAfterLength: 50,
1450
+ style: {
1451
+ backgroundColor: 'transparent',
1452
+ fontSize: '0.875rem',
1453
+ fontFamily: 'monospace',
1454
+ padding: '8px',
1455
+ borderRadius: '4px',
1456
+ overflow: 'auto',
1457
+ maxHeight: 'calc(100vh - 200px)'
1458
+ }
1459
+ })
1460
+ })]
1461
+ })]
1462
+ });
1463
+ }