git-history-ui 1.0.1 → 1.0.3

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 (51) hide show
  1. package/README.md +45 -244
  2. package/dist/backend/server.d.ts.map +1 -1
  3. package/dist/backend/server.js +30 -10
  4. package/dist/backend/server.js.map +1 -1
  5. package/dist/config/paths.d.ts +14 -0
  6. package/dist/config/paths.d.ts.map +1 -0
  7. package/dist/config/paths.js +35 -0
  8. package/dist/config/paths.js.map +1 -0
  9. package/package.json +8 -1
  10. package/public/index.html +0 -1
  11. package/.eslintrc.js +0 -21
  12. package/demo.js +0 -45
  13. package/frontend/.editorconfig +0 -17
  14. package/frontend/.vscode/extensions.json +0 -4
  15. package/frontend/.vscode/launch.json +0 -20
  16. package/frontend/.vscode/tasks.json +0 -42
  17. package/frontend/README.md +0 -59
  18. package/frontend/angular.json +0 -99
  19. package/frontend/package-lock.json +0 -10566
  20. package/frontend/package.json +0 -55
  21. package/frontend/proxy.conf.json +0 -7
  22. package/frontend/public/favicon.ico +0 -0
  23. package/frontend/src/app/app.component.ts +0 -598
  24. package/frontend/src/app/app.config.ts +0 -12
  25. package/frontend/src/app/app.css +0 -0
  26. package/frontend/src/app/app.html +0 -342
  27. package/frontend/src/app/app.routes.ts +0 -3
  28. package/frontend/src/app/app.spec.ts +0 -23
  29. package/frontend/src/app/app.ts +0 -12
  30. package/frontend/src/app/components/color-palette-selector/color-palette-selector.component.ts +0 -137
  31. package/frontend/src/app/components/commit-detail/commit-detail.component.ts +0 -327
  32. package/frontend/src/app/components/commit-graph/commit-graph.component.ts +0 -294
  33. package/frontend/src/app/components/commit-list/commit-list.component.ts +0 -199
  34. package/frontend/src/app/components/diff-viewer/diff-viewer.component.ts +0 -311
  35. package/frontend/src/app/models/color-palette.models.ts +0 -229
  36. package/frontend/src/app/models/git.models.ts +0 -39
  37. package/frontend/src/app/services/git.service.ts +0 -43
  38. package/frontend/src/index.html +0 -13
  39. package/frontend/src/main.ts +0 -6
  40. package/frontend/src/styles.css +0 -397
  41. package/frontend/tsconfig.app.json +0 -15
  42. package/frontend/tsconfig.json +0 -34
  43. package/frontend/tsconfig.spec.json +0 -14
  44. package/jest.config.js +0 -26
  45. package/src/__tests__/gitService.test.ts +0 -533
  46. package/src/__tests__/setup.ts +0 -25
  47. package/src/backend/dev-server.ts +0 -14
  48. package/src/backend/gitService.ts +0 -277
  49. package/src/backend/server.ts +0 -132
  50. package/src/cli.ts +0 -56
  51. package/tsconfig.json +0 -25
@@ -1,277 +0,0 @@
1
- import simpleGit, { SimpleGit, LogResult, DefaultLogFields } from 'simple-git';
2
- import path from 'path';
3
-
4
- export interface Commit {
5
- hash: string;
6
- author: string;
7
- date: string;
8
- message: string;
9
- files: string[];
10
- parents: string[];
11
- branches: string[];
12
- tags: string[];
13
- }
14
-
15
- export interface DiffFile {
16
- file: string;
17
- additions: number;
18
- deletions: number;
19
- changes: string;
20
- }
21
-
22
- export interface BlameLine {
23
- line: number;
24
- hash: string;
25
- author: string;
26
- date: string;
27
- content: string;
28
- }
29
-
30
- export interface GitOptions {
31
- file?: string;
32
- since?: string;
33
- author?: string;
34
- limit?: number;
35
- }
36
-
37
- export class GitService {
38
- private git: SimpleGit;
39
-
40
- constructor() {
41
- this.git = simpleGit();
42
- }
43
-
44
- async getCommits(options: GitOptions = {}): Promise<Commit[]> {
45
- try {
46
- const logOptions = {
47
- maxCount: options.limit || 100
48
- };
49
-
50
- let log: LogResult<DefaultLogFields>;
51
-
52
- if (options.file) {
53
- log = await this.git.log({
54
- ...logOptions,
55
- file: options.file
56
- });
57
- } else if (options.since) {
58
- log = await this.git.log({
59
- ...logOptions,
60
- from: options.since
61
- });
62
- } else if (options.author) {
63
- log = await this.git.log({
64
- ...logOptions,
65
- author: options.author
66
- });
67
- } else {
68
- log = await this.git.log(logOptions);
69
- }
70
-
71
- const commits: Commit[] = await Promise.all(
72
- log.all.map(async (commit) => {
73
- const [branches, tags] = await Promise.all([
74
- this.getBranchesForCommit(commit.hash),
75
- this.getTagsForCommit(commit.hash)
76
- ]);
77
-
78
- return {
79
- hash: commit.hash,
80
- author: commit.author_name,
81
- date: commit.date,
82
- message: commit.message,
83
- files: await this.getFilesForCommit(commit.hash),
84
- parents: [], // We'll get this from git show if needed
85
- branches,
86
- tags
87
- };
88
- })
89
- );
90
-
91
- return commits;
92
- } catch (error) {
93
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
94
- throw new Error(`Failed to get commits: ${errorMessage}`);
95
- }
96
- }
97
-
98
- async getCommit(hash: string): Promise<Commit> {
99
- try {
100
- const log = await this.git.log({
101
- from: hash,
102
- to: hash,
103
- maxCount: 1
104
- });
105
-
106
- if (log.all.length === 0) {
107
- throw new Error('Commit not found');
108
- }
109
-
110
- const commit = log.all[0];
111
- const [branches, tags] = await Promise.all([
112
- this.getBranchesForCommit(hash),
113
- this.getTagsForCommit(hash)
114
- ]);
115
-
116
- return {
117
- hash: commit.hash,
118
- author: commit.author_name,
119
- date: commit.date,
120
- message: commit.message,
121
- files: await this.getFilesForCommit(hash),
122
- parents: [], // We'll get this from git show if needed
123
- branches,
124
- tags
125
- };
126
- } catch (error) {
127
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
128
- throw new Error(`Failed to get commit: ${errorMessage}`);
129
- }
130
- }
131
-
132
- async getDiff(hash: string): Promise<DiffFile[]> {
133
- try {
134
- const diff = await this.git.diff([hash + '^', hash]);
135
- return this.parseDiff(diff);
136
- } catch (error) {
137
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
138
- throw new Error(`Failed to get diff: ${errorMessage}`);
139
- }
140
- }
141
-
142
- async getBlame(filePath: string): Promise<BlameLine[]> {
143
- try {
144
- const blame = await this.git.raw(['blame', '--porcelain', filePath]);
145
- return this.parseBlame(blame);
146
- } catch (error) {
147
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
148
- throw new Error(`Failed to get blame: ${errorMessage}`);
149
- }
150
- }
151
-
152
- async getTags(): Promise<string[]> {
153
- try {
154
- const tags = await this.git.tags();
155
- return tags.all;
156
- } catch (error) {
157
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
158
- throw new Error(`Failed to get tags: ${errorMessage}`);
159
- }
160
- }
161
-
162
- async getBranches(): Promise<string[]> {
163
- try {
164
- const branches = await this.git.branch();
165
- return branches.all;
166
- } catch (error) {
167
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
168
- throw new Error(`Failed to get branches: ${errorMessage}`);
169
- }
170
- }
171
-
172
- private async getFilesForCommit(hash: string): Promise<string[]> {
173
- try {
174
- const diff = await this.git.diff([hash + '^', hash, '--name-only']);
175
- return diff.split('\n').filter(Boolean);
176
- } catch (error) {
177
- return [];
178
- }
179
- }
180
-
181
- private async getBranchesForCommit(hash: string): Promise<string[]> {
182
- try {
183
- const branches = await this.git.branch(['--contains', hash]);
184
- return branches.all;
185
- } catch (error) {
186
- return [];
187
- }
188
- }
189
-
190
- private async getTagsForCommit(hash: string): Promise<string[]> {
191
- try {
192
- const tags = await this.git.raw(['tag', '--contains', hash]);
193
- return tags.split('\n').filter(Boolean);
194
- } catch (error) {
195
- return [];
196
- }
197
- }
198
-
199
- private parseDiff(diff: string): DiffFile[] {
200
- const files: DiffFile[] = [];
201
- const lines = diff.split('\n');
202
- let currentFile: DiffFile | null = null;
203
- let currentFileLines: string[] = [];
204
-
205
- for (const line of lines) {
206
- if (line.startsWith('diff --git')) {
207
- if (currentFile) {
208
- currentFile.changes = currentFileLines.join('\n');
209
- files.push(currentFile);
210
- }
211
- const fileMatch = line.match(/b\/(.+)$/);
212
- currentFile = {
213
- file: fileMatch ? fileMatch[1] : '',
214
- additions: 0,
215
- deletions: 0,
216
- changes: ''
217
- };
218
- currentFileLines = [];
219
- } else if (line.startsWith('+') && !line.startsWith('+++')) {
220
- if (currentFile) currentFile.additions++;
221
- currentFileLines.push(line);
222
- } else if (line.startsWith('-') && !line.startsWith('---')) {
223
- if (currentFile) currentFile.deletions++;
224
- currentFileLines.push(line);
225
- } else if (line.startsWith('@@') || line.startsWith('---') || line.startsWith('+++') || line.trim() === '') {
226
- // Include git diff headers and context lines
227
- currentFileLines.push(line);
228
- } else if (line.startsWith(' ')) {
229
- // Context lines (unchanged)
230
- currentFileLines.push(line);
231
- }
232
- }
233
-
234
- if (currentFile) {
235
- currentFile.changes = currentFileLines.join('\n');
236
- files.push(currentFile);
237
- }
238
-
239
- return files;
240
- }
241
-
242
- private parseBlame(blame: string): BlameLine[] {
243
- const lines: BlameLine[] = [];
244
- const blameLines = blame.split('\n');
245
- let currentLine: BlameLine | null = null;
246
-
247
- for (const line of blameLines) {
248
- if (line.startsWith('author ')) {
249
- if (currentLine) {
250
- lines.push(currentLine);
251
- }
252
- const hash = blameLines[blameLines.indexOf(line) - 1].split(' ')[0];
253
- const author = line.substring(7);
254
- const dateLine = blameLines[blameLines.indexOf(line) + 1];
255
- const date = dateLine.startsWith('author-time ')
256
- ? new Date(parseInt(dateLine.substring(12)) * 1000).toISOString()
257
- : '';
258
-
259
- currentLine = {
260
- line: lines.length + 1,
261
- hash,
262
- author,
263
- date,
264
- content: ''
265
- };
266
- } else if (line.startsWith('\t') && currentLine) {
267
- currentLine.content = line.substring(1);
268
- }
269
- }
270
-
271
- if (currentLine) {
272
- lines.push(currentLine);
273
- }
274
-
275
- return lines;
276
- }
277
- }
@@ -1,132 +0,0 @@
1
- import express from 'express';
2
- import cors from 'cors';
3
- import { createServer } from 'http';
4
- import { Server } from 'socket.io';
5
- import path from 'path';
6
- import { GitService } from './gitService';
7
-
8
- export interface ServerOptions {
9
- port?: number;
10
- host?: string;
11
- file?: string;
12
- since?: string;
13
- author?: string;
14
- }
15
-
16
- export async function startServer(
17
- port: number = 3000,
18
- host: string = 'localhost',
19
- options: Partial<ServerOptions> = {}
20
- ) {
21
- const app = express();
22
- const server = createServer(app);
23
- const io = new Server(server, {
24
- cors: {
25
- origin: "*",
26
- methods: ["GET", "POST"]
27
- }
28
- });
29
-
30
- const gitService = new GitService();
31
-
32
- // Middleware
33
- app.use(cors());
34
- app.use(express.json());
35
-
36
- // Serve Angular build files
37
- app.use(express.static(path.join(__dirname, '../../frontend/dist/frontend/browser')));
38
-
39
- // Serve public folder as fallback
40
- app.use(express.static(path.join(__dirname, '../../public')));
41
-
42
- // API Routes
43
- app.get('/api/commits', async (req, res) => {
44
- try {
45
- const { file, since, author, limit = '100' } = req.query;
46
- const commits = await gitService.getCommits({
47
- file: file as string,
48
- since: since as string,
49
- author: author as string,
50
- limit: parseInt(limit as string)
51
- });
52
- res.json(commits);
53
- } catch (error) {
54
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
55
- res.status(500).json({ error: errorMessage });
56
- }
57
- });
58
-
59
- app.get('/api/commit/:hash', async (req, res) => {
60
- try {
61
- const { hash } = req.params;
62
- const commit = await gitService.getCommit(hash);
63
- res.json(commit);
64
- } catch (error) {
65
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
66
- res.status(500).json({ error: errorMessage });
67
- }
68
- });
69
-
70
- app.get('/api/diff/:hash', async (req, res) => {
71
- try {
72
- const { hash } = req.params;
73
- const diff = await gitService.getDiff(hash);
74
- res.json(diff);
75
- } catch (error) {
76
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
77
- res.status(500).json({ error: errorMessage });
78
- }
79
- });
80
-
81
- app.get('/api/blame/:file', async (req, res) => {
82
- try {
83
- const { file } = req.params;
84
- const blame = await gitService.getBlame(file);
85
- res.json(blame);
86
- } catch (error) {
87
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
88
- res.status(500).json({ error: errorMessage });
89
- }
90
- });
91
-
92
- app.get('/api/tags', async (req, res) => {
93
- try {
94
- const tags = await gitService.getTags();
95
- res.json(tags);
96
- } catch (error) {
97
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
98
- res.status(500).json({ error: errorMessage });
99
- }
100
- });
101
-
102
- app.get('/api/branches', async (req, res) => {
103
- try {
104
- const branches = await gitService.getBranches();
105
- res.json(branches);
106
- } catch (error) {
107
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
108
- res.status(500).json({ error: errorMessage });
109
- }
110
- });
111
-
112
- // Serve the main HTML file for Angular routing
113
- app.get('*', (req, res) => {
114
- res.sendFile(path.join(__dirname, '../../frontend/dist/frontend/browser/index.html'));
115
- });
116
-
117
- // Socket.IO for real-time updates
118
- io.on('connection', (socket) => {
119
- console.log('Client connected');
120
-
121
- socket.on('disconnect', () => {
122
- console.log('Client disconnected');
123
- });
124
- });
125
-
126
- return new Promise<void>((resolve) => {
127
- server.listen(port, host, () => {
128
- console.log(`Server running on http://${host}:${port}`);
129
- resolve();
130
- });
131
- });
132
- }
package/src/cli.ts DELETED
@@ -1,56 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { Command } from 'commander';
4
- import chalk from 'chalk';
5
- import open from 'open';
6
- import { startServer } from './backend/server';
7
-
8
- const program = new Command();
9
-
10
- program
11
- .name('git-history-ui')
12
- .description('Beautiful git history visualization in your browser')
13
- .version('1.0.0');
14
-
15
- program
16
- .option('-p, --port <number>', 'port to run server on', '3000')
17
- .option('-f, --file <path>', 'show history only for a specific file')
18
- .option('-s, --since <ref>', 'show commits since a specific reference (e.g., v2.0.0)')
19
- .option('-a, --author <name>', 'filter commits by author')
20
- .option('--no-open', 'do not automatically open browser')
21
- .option('--host <host>', 'host to bind to', 'localhost');
22
-
23
- program.parse();
24
-
25
- const options = program.opts();
26
-
27
- async function main() {
28
- try {
29
- console.log(chalk.blue('šŸš€ Starting Git History UI...'));
30
-
31
- const port = parseInt(options.port);
32
- const serverUrl = `http://${options.host}:${port}`;
33
-
34
- // Start the server
35
- await startServer(port, options.host);
36
-
37
- console.log(chalk.green(`āœ… Server running at ${serverUrl}`));
38
-
39
- if (options.open !== false) {
40
- console.log(chalk.yellow('🌐 Opening browser...'));
41
- await open(serverUrl);
42
- }
43
-
44
- console.log(chalk.cyan('\nšŸ“ Usage:'));
45
- console.log(chalk.white(' • Use the search bar to filter commits'));
46
- console.log(chalk.white(' • Click on commits to view diffs'));
47
- console.log(chalk.white(' • Use the graph view to see branch structure'));
48
- console.log(chalk.white(' • Press Ctrl+C to stop the server'));
49
-
50
- } catch (error) {
51
- console.error(chalk.red('āŒ Error starting server:'), error);
52
- process.exit(1);
53
- }
54
- }
55
-
56
- main();
package/tsconfig.json DELETED
@@ -1,25 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "commonjs",
5
- "lib": ["ES2020"],
6
- "outDir": "./dist",
7
- "rootDir": "./src",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "resolveJsonModule": true,
13
- "declaration": true,
14
- "declarationMap": true,
15
- "sourceMap": true
16
- },
17
- "include": [
18
- "src/**/*"
19
- ],
20
- "exclude": [
21
- "node_modules",
22
- "dist",
23
- "src/frontend"
24
- ]
25
- }