git-history-ui 1.0.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 (64) hide show
  1. package/.eslintrc.js +21 -0
  2. package/README.md +304 -0
  3. package/demo.js +45 -0
  4. package/dist/__tests__/gitService.test.d.ts +2 -0
  5. package/dist/__tests__/gitService.test.d.ts.map +1 -0
  6. package/dist/__tests__/gitService.test.js +32 -0
  7. package/dist/__tests__/gitService.test.js.map +1 -0
  8. package/dist/backend/dev-server.d.ts +2 -0
  9. package/dist/backend/dev-server.d.ts.map +1 -0
  10. package/dist/backend/dev-server.js +16 -0
  11. package/dist/backend/dev-server.js.map +1 -0
  12. package/dist/backend/gitService.d.ts +45 -0
  13. package/dist/backend/gitService.d.ts.map +1 -0
  14. package/dist/backend/gitService.js +239 -0
  15. package/dist/backend/gitService.js.map +1 -0
  16. package/dist/backend/server.d.ts +9 -0
  17. package/dist/backend/server.d.ts.map +1 -0
  18. package/dist/backend/server.js +118 -0
  19. package/dist/backend/server.js.map +1 -0
  20. package/dist/cli.d.ts +3 -0
  21. package/dist/cli.d.ts.map +1 -0
  22. package/dist/cli.js +49 -0
  23. package/dist/cli.js.map +1 -0
  24. package/frontend/.editorconfig +17 -0
  25. package/frontend/.vscode/extensions.json +4 -0
  26. package/frontend/.vscode/launch.json +20 -0
  27. package/frontend/.vscode/tasks.json +42 -0
  28. package/frontend/README.md +59 -0
  29. package/frontend/angular.json +99 -0
  30. package/frontend/package-lock.json +10566 -0
  31. package/frontend/package.json +55 -0
  32. package/frontend/proxy.conf.json +7 -0
  33. package/frontend/public/favicon.ico +0 -0
  34. package/frontend/src/app/app.component.ts +598 -0
  35. package/frontend/src/app/app.config.ts +12 -0
  36. package/frontend/src/app/app.css +0 -0
  37. package/frontend/src/app/app.html +342 -0
  38. package/frontend/src/app/app.routes.ts +3 -0
  39. package/frontend/src/app/app.spec.ts +23 -0
  40. package/frontend/src/app/app.ts +12 -0
  41. package/frontend/src/app/components/color-palette-selector/color-palette-selector.component.ts +137 -0
  42. package/frontend/src/app/components/commit-detail/commit-detail.component.ts +327 -0
  43. package/frontend/src/app/components/commit-graph/commit-graph.component.ts +294 -0
  44. package/frontend/src/app/components/commit-list/commit-list.component.ts +199 -0
  45. package/frontend/src/app/components/diff-viewer/diff-viewer.component.ts +311 -0
  46. package/frontend/src/app/models/color-palette.models.ts +229 -0
  47. package/frontend/src/app/models/git.models.ts +39 -0
  48. package/frontend/src/app/services/git.service.ts +43 -0
  49. package/frontend/src/index.html +13 -0
  50. package/frontend/src/main.ts +6 -0
  51. package/frontend/src/styles.css +397 -0
  52. package/frontend/tsconfig.app.json +15 -0
  53. package/frontend/tsconfig.json +34 -0
  54. package/frontend/tsconfig.spec.json +14 -0
  55. package/jest.config.js +13 -0
  56. package/package.json +70 -0
  57. package/public/app.js +403 -0
  58. package/public/index.html +172 -0
  59. package/src/__tests__/gitService.test.ts +35 -0
  60. package/src/backend/dev-server.ts +14 -0
  61. package/src/backend/gitService.ts +277 -0
  62. package/src/backend/server.ts +132 -0
  63. package/src/cli.ts +56 -0
  64. package/tsconfig.json +25 -0
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "frontend",
3
+ "version": "0.0.0",
4
+ "scripts": {
5
+ "ng": "ng",
6
+ "start": "ng serve",
7
+ "build": "ng build",
8
+ "watch": "ng build --watch --configuration development",
9
+ "test": "ng test"
10
+ },
11
+ "prettier": {
12
+ "printWidth": 100,
13
+ "singleQuote": true,
14
+ "overrides": [
15
+ {
16
+ "files": "*.html",
17
+ "options": {
18
+ "parser": "angular"
19
+ }
20
+ }
21
+ ]
22
+ },
23
+ "private": true,
24
+ "dependencies": {
25
+ "@angular/common": "^20.2.1",
26
+ "@angular/compiler": "^20.2.1",
27
+ "@angular/compiler-cli": "^20.2.1",
28
+ "@angular/core": "^20.2.1",
29
+ "@angular/forms": "^20.2.1",
30
+ "@angular/platform-browser": "^20.2.1",
31
+ "@angular/platform-browser-dynamic": "^20.2.1",
32
+ "@angular/router": "^20.2.1",
33
+ "@types/d3": "^7.4.3",
34
+ "d3": "^7.9.0",
35
+ "rxjs": "~7.8.0",
36
+ "tslib": "^2.3.0",
37
+ "zone.js": "~0.15.0"
38
+ },
39
+ "devDependencies": {
40
+ "@angular-devkit/architect": "^0.2002.0",
41
+ "@angular-devkit/core": "^20.2.0",
42
+ "@angular-devkit/schematics": "^20.2.0",
43
+ "@angular/build": "^20.2.0",
44
+ "@angular/cli": "^20.2.0",
45
+ "@schematics/angular": "^20.2.0",
46
+ "@types/jasmine": "~5.1.0",
47
+ "jasmine-core": "~5.9.0",
48
+ "karma": "~6.4.0",
49
+ "karma-chrome-launcher": "~3.2.0",
50
+ "karma-coverage": "~2.2.0",
51
+ "karma-jasmine": "~5.1.0",
52
+ "karma-jasmine-html-reporter": "~2.1.0",
53
+ "typescript": "~5.9.2"
54
+ }
55
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "/api": {
3
+ "target": "http://localhost:3000",
4
+ "secure": false,
5
+ "changeOrigin": true
6
+ }
7
+ }
Binary file
@@ -0,0 +1,598 @@
1
+ import { Component, OnInit } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { HttpClientModule } from '@angular/common/http';
5
+
6
+ import { CommitListComponent } from './components/commit-list/commit-list.component';
7
+ import { CommitGraphComponent } from './components/commit-graph/commit-graph.component';
8
+ import { CommitDetailComponent } from './components/commit-detail/commit-detail.component';
9
+ import { DiffViewerComponent } from './components/diff-viewer/diff-viewer.component';
10
+ import { ColorPaletteSelectorComponent } from './components/color-palette-selector/color-palette-selector.component';
11
+ import { GitService } from './services/git.service';
12
+ import { Commit, DiffFile, GitOptions } from './models/git.models';
13
+ import { ColorPaletteId, COLOR_PALETTES, DARK_COLOR_PALETTES } from './models/color-palette.models';
14
+
15
+ @Component({
16
+ selector: 'app-root',
17
+ standalone: true,
18
+ imports: [
19
+ CommonModule,
20
+ FormsModule,
21
+ HttpClientModule,
22
+ CommitListComponent,
23
+ CommitGraphComponent,
24
+ CommitDetailComponent,
25
+ DiffViewerComponent,
26
+ ColorPaletteSelectorComponent
27
+ ],
28
+ template: `
29
+ <div class="app-container">
30
+ <!-- Header -->
31
+ <header class="header" [style.background-color]="darkMode ? '#2d2d2d' : 'white'" [style.border-bottom-color]="darkMode ? '#404040' : '#e5e7eb'">
32
+ <div class="container">
33
+ <div class="flex justify-between items-center">
34
+ <div class="flex items-center space-x-4">
35
+ <h1 class="app-title" [style.color]="darkMode ? '#e0e0e0' : '#111827'">
36
+ 📊 Git History UI
37
+ </h1>
38
+ <div class="flex items-center" style="gap: 0.5rem;">
39
+ <button [class]="currentView === 'graph' ? 'btn btn-primary' : 'btn btn-secondary'"
40
+ (click)="switchView('graph')">
41
+ Graph View
42
+ </button>
43
+ <button [class]="currentView === 'list' ? 'btn btn-primary' : 'btn btn-secondary'"
44
+ (click)="switchView('list')">
45
+ List View
46
+ </button>
47
+ </div>
48
+ </div>
49
+ <div class="flex items-center space-x-4">
50
+ <app-color-palette-selector
51
+ [selectedPalette]="selectedColorPalette"
52
+ [darkMode]="darkMode"
53
+ (paletteChange)="onColorPaletteChange($event)">
54
+ </app-color-palette-selector>
55
+ <button (click)="toggleDarkMode()" class="btn btn-secondary">
56
+ {{ darkMode ? '☀️' : '🌙' }}
57
+ </button>
58
+ <div class="search-container">
59
+ <input type="text" [(ngModel)]="searchQuery" (input)="onSearch()" placeholder="Search commits..."
60
+ class="search-input"
61
+ [style.background-color]="darkMode ? '#404040' : 'white'"
62
+ [style.color]="darkMode ? '#e0e0e0' : '#111827'"
63
+ [style.border-color]="darkMode ? '#555' : '#d1d5db'">
64
+ </div>
65
+ </div>
66
+ </div>
67
+ </div>
68
+ </header>
69
+
70
+ <!-- Filters -->
71
+ <div class="filters" [style.background-color]="darkMode ? '#2d2d2d' : 'white'" [style.border-bottom-color]="darkMode ? '#404040' : '#e5e7eb'">
72
+ <div class="container">
73
+ <div class="flex items-center space-x-4">
74
+ <div class="filter-group">
75
+ <label [style.color]="darkMode ? '#d1d5db' : '#374151'">Author:</label>
76
+ <select [(ngModel)]="selectedAuthor" (change)="onAuthorFilter()" class="filter-select"
77
+ [style.background-color]="darkMode ? '#404040' : 'white'"
78
+ [style.color]="darkMode ? '#e0e0e0' : '#111827'"
79
+ [style.border-color]="darkMode ? '#555' : '#d1d5db'">
80
+ <option value="">All authors</option>
81
+ <option *ngFor="let author of authors" [value]="author">{{ author }}</option>
82
+ </select>
83
+ </div>
84
+ <div class="filter-group">
85
+ <label [style.color]="darkMode ? '#d1d5db' : '#374151'">Since:</label>
86
+ <input type="date"
87
+ [(ngModel)]="selectedSince"
88
+ (change)="onSinceFilter()"
89
+ class="filter-input date-picker"
90
+ [style.background-color]="darkMode ? '#404040' : 'white'"
91
+ [style.color]="darkMode ? '#e0e0e0' : '#111827'"
92
+ [style.border-color]="darkMode ? '#555' : '#d1d5db'"
93
+ [style.caret-color]="darkMode ? '#e0e0e0' : '#111827'"
94
+ placeholder="Select date">
95
+ </div>
96
+ <div class="filter-group">
97
+ <label [style.color]="darkMode ? '#d1d5db' : '#374151'">File:</label>
98
+ <input type="text" [(ngModel)]="fileFilter" (input)="onFileFilter()" placeholder="Filter by file..."
99
+ class="filter-input"
100
+ [style.background-color]="darkMode ? '#404040' : 'white'"
101
+ [style.color]="darkMode ? '#e0e0e0' : '#111827'"
102
+ [style.border-color]="darkMode ? '#555' : '#d1d5db'">
103
+ </div>
104
+ </div>
105
+ </div>
106
+ </div>
107
+
108
+ <!-- Main Content -->
109
+ <main class="main-content" [style.background-color]="darkMode ? '#1a1a1a' : '#f8f9fa'">
110
+ <div class="container">
111
+ <!-- Loading -->
112
+ <div *ngIf="loading" class="loading" [style.color]="darkMode ? '#e0e0e0' : '#374151'">
113
+ <div class="spinner"></div>
114
+ <span>Loading commits...</span>
115
+ </div>
116
+
117
+ <!-- Graph View -->
118
+ <div *ngIf="!loading && currentView === 'graph'">
119
+ <app-commit-graph
120
+ [commits]="filteredCommits"
121
+ [colorPalette]="getCurrentPalette()"
122
+ (commitClick)="showCommitDetails($event)">
123
+ </app-commit-graph>
124
+ </div>
125
+
126
+ <!-- List View -->
127
+ <div *ngIf="!loading && currentView === 'list'">
128
+ <app-commit-list
129
+ [commits]="filteredCommits"
130
+ [colorPalette]="getCurrentPalette()"
131
+ (commitClick)="showCommitDetails($event)">
132
+ </app-commit-list>
133
+ </div>
134
+ </div>
135
+ </main>
136
+
137
+ <!-- Commit Detail Modal -->
138
+ <app-commit-detail *ngIf="showModal"
139
+ [commit]="selectedCommit"
140
+ [diffFiles]="diffFiles"
141
+ (close)="closeModal()"
142
+ (fileClick)="onFileClick($event)">
143
+ </app-commit-detail>
144
+
145
+ <!-- Diff Viewer Modal -->
146
+ <div *ngIf="showDiffModal" class="modal-overlay" (click)="closeDiffModal()">
147
+ <div class="modal-container" (click)="$event.stopPropagation()">
148
+ <app-diff-viewer
149
+ [fileName]="selectedFileName"
150
+ [diffFile]="selectedDiffFile"
151
+ (close)="closeDiffModal()">
152
+ </app-diff-viewer>
153
+ </div>
154
+ </div>
155
+ </div>
156
+ `,
157
+ styles: [`
158
+ .app-container {
159
+ min-height: 100vh;
160
+ background-color: #f8f9fa;
161
+ transition: background-color 0.2s ease;
162
+ }
163
+
164
+ .dark .app-container {
165
+ background-color: #1a1a1a;
166
+ }
167
+
168
+ .header {
169
+ background-color: white;
170
+ border-bottom: 1px solid #e5e7eb;
171
+ padding: 1rem 0;
172
+ transition: background-color 0.2s ease, border-bottom-color 0.2s ease;
173
+ }
174
+
175
+ .app-title {
176
+ font-size: 1.5rem;
177
+ font-weight: bold;
178
+ color: #111827;
179
+ transition: color 0.2s ease;
180
+ }
181
+
182
+ .search-container {
183
+ position: relative;
184
+ }
185
+
186
+ .search-input {
187
+ width: 16rem;
188
+ padding: 0.5rem 0.75rem;
189
+ border: 1px solid #d1d5db;
190
+ border-radius: 0.375rem;
191
+ background-color: white;
192
+ font-size: 0.875rem;
193
+ }
194
+
195
+ .filters {
196
+ background-color: white;
197
+ border-bottom: 1px solid #e5e7eb;
198
+ padding: 1rem 0;
199
+ }
200
+
201
+ .filter-group {
202
+ display: flex;
203
+ align-items: center;
204
+ gap: 0.5rem;
205
+ }
206
+
207
+ .filter-group label {
208
+ font-size: 0.875rem;
209
+ font-weight: 500;
210
+ color: #374151;
211
+ }
212
+
213
+ .filter-select, .filter-input {
214
+ padding: 0.25rem 0.5rem;
215
+ border: 1px solid #d1d5db;
216
+ border-radius: 0.25rem;
217
+ background-color: white;
218
+ font-size: 0.875rem;
219
+ }
220
+
221
+ .date-picker {
222
+ min-width: 200px;
223
+ transition: all 0.2s ease;
224
+ }
225
+
226
+ .date-picker::-webkit-calendar-picker-indicator {
227
+ filter: invert(0.5);
228
+ cursor: pointer;
229
+ transition: filter 0.2s ease;
230
+ }
231
+
232
+ .dark .date-picker::-webkit-calendar-picker-indicator {
233
+ filter: invert(1);
234
+ }
235
+
236
+ /* Dark mode styles for date picker */
237
+ .dark .date-picker {
238
+ background-color: #404040 !important;
239
+ color: #e0e0e0 !important;
240
+ border-color: #555 !important;
241
+ }
242
+
243
+ .dark .filter-input.date-picker {
244
+ background-color: #404040 !important;
245
+ color: #e0e0e0 !important;
246
+ border-color: #555 !important;
247
+ }
248
+
249
+ .dark .date-picker:focus {
250
+ outline: none;
251
+ border-color: #3b82f6;
252
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
253
+ }
254
+
255
+ /* Light mode styles for date picker */
256
+ .date-picker:focus {
257
+ outline: none;
258
+ border-color: #3b82f6;
259
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
260
+ }
261
+
262
+ /* Calendar popup styling (for browsers that support it) */
263
+ .date-picker::-webkit-datetime-edit {
264
+ color: inherit;
265
+ }
266
+
267
+ .date-picker::-webkit-datetime-edit-fields-wrapper {
268
+ color: inherit;
269
+ }
270
+
271
+ .date-picker::-webkit-datetime-edit-text {
272
+ color: inherit;
273
+ }
274
+
275
+ .date-picker::-webkit-datetime-edit-month-field,
276
+ .date-picker::-webkit-datetime-edit-day-field,
277
+ .date-picker::-webkit-datetime-edit-year-field {
278
+ color: inherit;
279
+ }
280
+
281
+ .date-picker::-webkit-datetime-edit-hour-field,
282
+ .date-picker::-webkit-datetime-edit-minute-field,
283
+ .date-picker::-webkit-datetime-edit-second-field {
284
+ color: inherit;
285
+ }
286
+
287
+ .main-content {
288
+ padding: 1.5rem 0;
289
+ transition: background-color 0.2s ease;
290
+ }
291
+
292
+ .dark .main-content {
293
+ background-color: #1a1a1a;
294
+ }
295
+
296
+ .loading {
297
+ display: flex;
298
+ justify-content: center;
299
+ align-items: center;
300
+ padding: 3rem 0;
301
+ gap: 0.75rem;
302
+ }
303
+
304
+ .spinner {
305
+ width: 2rem;
306
+ height: 2rem;
307
+ border: 2px solid #e5e7eb;
308
+ border-top: 2px solid #3b82f6;
309
+ border-radius: 50%;
310
+ animation: spin 1s linear infinite;
311
+ }
312
+
313
+ .dark .spinner {
314
+ border-color: #404040;
315
+ border-top-color: #3b82f6;
316
+ }
317
+
318
+ @keyframes spin {
319
+ 0% { transform: rotate(0deg); }
320
+ 100% { transform: rotate(360deg); }
321
+ }
322
+
323
+ .modal-overlay {
324
+ position: fixed;
325
+ inset: 0;
326
+ background-color: rgba(0, 0, 0, 0.5);
327
+ z-index: 50;
328
+ display: flex;
329
+ align-items: center;
330
+ justify-content: center;
331
+ min-height: 100vh;
332
+ padding: 1rem;
333
+ }
334
+
335
+ .modal-container {
336
+ background-color: transparent;
337
+ max-width: 90vw;
338
+ width: 100%;
339
+ max-height: 90vh;
340
+ overflow: hidden;
341
+ }
342
+
343
+ /* Dark mode styles */
344
+ .dark .app-container {
345
+ background-color: #1a1a1a !important;
346
+ }
347
+
348
+ .dark .header {
349
+ background-color: #2d2d2d !important;
350
+ border-bottom-color: #404040 !important;
351
+ }
352
+
353
+ .dark .filters {
354
+ background-color: #2d2d2d !important;
355
+ border-bottom-color: #404040 !important;
356
+ }
357
+
358
+ .dark .app-title {
359
+ color: #e0e0e0 !important;
360
+ }
361
+
362
+ .dark .search-input,
363
+ .dark .filter-select,
364
+ .dark .filter-input {
365
+ background-color: #404040;
366
+ border-color: #555;
367
+ color: #e0e0e0;
368
+ }
369
+
370
+ .dark .filter-group label {
371
+ color: #d1d5db;
372
+ }
373
+
374
+ /* Graph container dark mode */
375
+ .dark .graph-container {
376
+ background-color: #2d2d2d;
377
+ color: #e0e0e0;
378
+ }
379
+
380
+ /* SVG dark mode support */
381
+ .dark svg {
382
+ background-color: transparent;
383
+ }
384
+ `]
385
+ })
386
+ export class AppComponent implements OnInit {
387
+ commits: Commit[] = [];
388
+ filteredCommits: Commit[] = [];
389
+ authors: string[] = [];
390
+ tags: string[] = [];
391
+
392
+ currentView: 'list' | 'graph' = 'list';
393
+ darkMode = false;
394
+ selectedColorPalette: ColorPaletteId = 'default';
395
+ loading = true;
396
+ showModal = false;
397
+ selectedCommit: Commit | null = null;
398
+ diffFiles: DiffFile[] = [];
399
+
400
+ // Diff viewer properties
401
+ showDiffModal = false;
402
+ selectedFileName = '';
403
+ selectedDiffFile: DiffFile | null = null;
404
+
405
+ searchQuery = '';
406
+ selectedAuthor = '';
407
+ selectedSince = '';
408
+ fileFilter = '';
409
+
410
+ constructor(private gitService: GitService) {}
411
+
412
+ ngOnInit() {
413
+ this.initializeDarkMode();
414
+ this.initializeColorPalette();
415
+ this.loadCommits();
416
+ this.loadTags();
417
+ this.checkDarkMode();
418
+ }
419
+
420
+ loadCommits() {
421
+ this.loading = true;
422
+ this.gitService.getCommits().subscribe({
423
+ next: (commits) => {
424
+ this.commits = commits;
425
+ this.filteredCommits = commits;
426
+ this.authors = [...new Set(commits.map(c => c.author))];
427
+ this.loading = false;
428
+ },
429
+ error: (error) => {
430
+ console.error('Error loading commits:', error);
431
+ this.loading = false;
432
+ }
433
+ });
434
+ }
435
+
436
+ loadTags() {
437
+ this.gitService.getTags().subscribe({
438
+ next: (tags) => {
439
+ this.tags = tags;
440
+ },
441
+ error: (error) => {
442
+ console.error('Error loading tags:', error);
443
+ }
444
+ });
445
+ }
446
+
447
+ switchView(view: 'list' | 'graph') {
448
+ this.currentView = view;
449
+ }
450
+
451
+ toggleDarkMode() {
452
+ this.darkMode = !this.darkMode;
453
+ document.documentElement.classList.toggle('dark', this.darkMode);
454
+ document.body.classList.toggle('dark', this.darkMode);
455
+
456
+ // Save preference to localStorage
457
+ localStorage.setItem('darkMode', this.darkMode.toString());
458
+
459
+ // Debug logging
460
+ console.log('Dark mode toggled:', this.darkMode);
461
+ console.log('Document element classes:', document.documentElement.classList.toString());
462
+ console.log('Body classes:', document.body.classList.toString());
463
+
464
+ // Force a style refresh by triggering a reflow
465
+ document.body.offsetHeight;
466
+ }
467
+
468
+ checkDarkMode() {
469
+ this.darkMode = document.documentElement.classList.contains('dark');
470
+ }
471
+
472
+ initializeDarkMode() {
473
+ // Check if user has a saved preference
474
+ const savedDarkMode = localStorage.getItem('darkMode');
475
+ if (savedDarkMode !== null) {
476
+ this.darkMode = savedDarkMode === 'true';
477
+ if (this.darkMode) {
478
+ document.documentElement.classList.add('dark');
479
+ document.body.classList.add('dark');
480
+ }
481
+ }
482
+ }
483
+
484
+ initializeColorPalette() {
485
+ // Check if user has a saved color palette preference
486
+ const savedPalette = localStorage.getItem('colorPalette');
487
+ if (savedPalette && Object.keys(COLOR_PALETTES).includes(savedPalette)) {
488
+ this.selectedColorPalette = savedPalette as ColorPaletteId;
489
+ }
490
+ }
491
+
492
+ onColorPaletteChange(paletteId: ColorPaletteId) {
493
+ this.selectedColorPalette = paletteId;
494
+ localStorage.setItem('colorPalette', paletteId);
495
+ }
496
+
497
+ getCurrentPalette() {
498
+ const palettes = this.darkMode ? DARK_COLOR_PALETTES : COLOR_PALETTES;
499
+ return palettes[this.selectedColorPalette];
500
+ }
501
+
502
+ onSearch() {
503
+ this.applyFilters();
504
+ }
505
+
506
+ onAuthorFilter() {
507
+ this.applyFilters();
508
+ }
509
+
510
+ onSinceFilter() {
511
+ this.applyFilters();
512
+ console.log('Date picker dark mode:', this.darkMode);
513
+ console.log('Document dark class:', document.documentElement.classList.contains('dark'));
514
+ }
515
+
516
+
517
+
518
+ onFileFilter() {
519
+ this.applyFilters();
520
+ }
521
+
522
+ applyFilters() {
523
+ let filtered = this.commits;
524
+
525
+ if (this.searchQuery) {
526
+ const query = this.searchQuery.toLowerCase();
527
+ filtered = filtered.filter(commit =>
528
+ commit.message.toLowerCase().includes(query) ||
529
+ commit.author.toLowerCase().includes(query) ||
530
+ commit.hash.toLowerCase().includes(query)
531
+ );
532
+ }
533
+
534
+ if (this.selectedAuthor) {
535
+ filtered = filtered.filter(commit => commit.author === this.selectedAuthor);
536
+ }
537
+
538
+ if (this.selectedSince) {
539
+ const sinceDate = new Date(this.selectedSince);
540
+ if (!isNaN(sinceDate.getTime())) {
541
+ filtered = filtered.filter(commit => new Date(commit.date) >= sinceDate);
542
+ }
543
+ }
544
+
545
+ if (this.fileFilter) {
546
+ filtered = filtered.filter(commit =>
547
+ commit.files.some(f => f.toLowerCase().includes(this.fileFilter.toLowerCase()))
548
+ );
549
+ }
550
+
551
+ this.filteredCommits = filtered;
552
+ }
553
+
554
+ showCommitDetails(commit: Commit) {
555
+ this.selectedCommit = commit;
556
+ this.gitService.getDiff(commit.hash).subscribe({
557
+ next: (diff) => {
558
+ this.diffFiles = diff;
559
+ this.showModal = true;
560
+ },
561
+ error: (error) => {
562
+ console.error('Error loading diff:', error);
563
+ this.diffFiles = [];
564
+ this.showModal = true;
565
+ }
566
+ });
567
+ }
568
+
569
+ closeModal() {
570
+ this.showModal = false;
571
+ this.selectedCommit = null;
572
+ this.diffFiles = [];
573
+ }
574
+
575
+ onFileClick(file: string) {
576
+ console.log('File clicked:', file);
577
+ console.log('Available diff files:', this.diffFiles);
578
+
579
+ // Find the diff file for the selected file
580
+ const diffFile = this.diffFiles.find(df => df.file === file);
581
+ console.log('Found diff file:', diffFile);
582
+
583
+ if (diffFile) {
584
+ this.selectedFileName = file;
585
+ this.selectedDiffFile = diffFile;
586
+ this.showDiffModal = true;
587
+ console.log('Diff modal should be visible now');
588
+ } else {
589
+ console.warn('No diff found for file:', file);
590
+ }
591
+ }
592
+
593
+ closeDiffModal() {
594
+ this.showDiffModal = false;
595
+ this.selectedFileName = '';
596
+ this.selectedDiffFile = null;
597
+ }
598
+ }
@@ -0,0 +1,12 @@
1
+ import { ApplicationConfig } from '@angular/core';
2
+ import { provideRouter } from '@angular/router';
3
+ import { provideHttpClient } from '@angular/common/http';
4
+
5
+ import { routes } from './app.routes';
6
+
7
+ export const appConfig: ApplicationConfig = {
8
+ providers: [
9
+ provideRouter(routes),
10
+ provideHttpClient()
11
+ ]
12
+ };
File without changes