git-history-ui 1.0.2 → 1.0.4

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 (54) hide show
  1. package/README.md +7 -7
  2. package/build/frontend/index.html +13 -0
  3. package/build/frontend/main-44CFNHDH.js +8 -0
  4. package/build/frontend/polyfills-5CFQRCPP.js +2 -0
  5. package/build/frontend/styles-26JPPBSI.css +1 -0
  6. package/dist/backend/server.d.ts.map +1 -1
  7. package/dist/backend/server.js +19 -5
  8. package/dist/backend/server.js.map +1 -1
  9. package/package.json +8 -2
  10. package/.dockerignore +0 -19
  11. package/.eslintrc.js +0 -21
  12. package/Dockerfile +0 -29
  13. package/demo.js +0 -45
  14. package/frontend/.editorconfig +0 -17
  15. package/frontend/.vscode/extensions.json +0 -4
  16. package/frontend/.vscode/launch.json +0 -20
  17. package/frontend/.vscode/tasks.json +0 -42
  18. package/frontend/README.md +0 -59
  19. package/frontend/angular.json +0 -99
  20. package/frontend/package-lock.json +0 -11272
  21. package/frontend/package.json +0 -58
  22. package/frontend/postcss.config.js +0 -6
  23. package/frontend/proxy.conf.json +0 -7
  24. package/frontend/src/app/app.component.ts +0 -598
  25. package/frontend/src/app/app.config.ts +0 -12
  26. package/frontend/src/app/app.css +0 -0
  27. package/frontend/src/app/app.html +0 -342
  28. package/frontend/src/app/app.routes.ts +0 -3
  29. package/frontend/src/app/app.spec.ts +0 -23
  30. package/frontend/src/app/app.ts +0 -12
  31. package/frontend/src/app/components/color-palette-selector/color-palette-selector.component.ts +0 -137
  32. package/frontend/src/app/components/commit-detail/commit-detail.component.ts +0 -327
  33. package/frontend/src/app/components/commit-graph/commit-graph.component.ts +0 -294
  34. package/frontend/src/app/components/commit-list/commit-list.component.ts +0 -199
  35. package/frontend/src/app/components/diff-viewer/diff-viewer.component.ts +0 -311
  36. package/frontend/src/app/models/color-palette.models.ts +0 -229
  37. package/frontend/src/app/models/git.models.ts +0 -39
  38. package/frontend/src/app/services/git.service.ts +0 -43
  39. package/frontend/src/index.html +0 -13
  40. package/frontend/src/main.ts +0 -6
  41. package/frontend/src/styles.css +0 -401
  42. package/frontend/tailwind.config.js +0 -11
  43. package/frontend/tsconfig.app.json +0 -15
  44. package/frontend/tsconfig.json +0 -34
  45. package/frontend/tsconfig.spec.json +0 -14
  46. package/jest.config.js +0 -26
  47. package/src/__tests__/gitService.test.ts +0 -533
  48. package/src/__tests__/setup.ts +0 -25
  49. package/src/backend/dev-server.ts +0 -14
  50. package/src/backend/gitService.ts +0 -277
  51. package/src/backend/server.ts +0 -140
  52. package/src/cli.ts +0 -56
  53. package/tsconfig.json +0 -25
  54. /package/{frontend/public → build/frontend}/favicon.ico +0 -0
@@ -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,140 +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
-
24
- // CORS configuration
25
- const corsOptions = {
26
- origin: process.env.NODE_ENV === 'production'
27
- ? ['http://localhost:4200', 'http://localhost:3000', 'http://127.0.0.1:4200', 'http://127.0.0.1:3000']
28
- : true,
29
- credentials: true,
30
- methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
31
- allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With']
32
- };
33
-
34
- const io = new Server(server, {
35
- cors: corsOptions
36
- });
37
-
38
- const gitService = new GitService();
39
-
40
- // Middleware
41
- app.use(cors(corsOptions));
42
- app.use(express.json());
43
-
44
- // Serve Angular build files
45
- app.use(express.static(path.join(__dirname, '../../frontend/dist/frontend/browser')));
46
-
47
- // Serve public folder as fallback
48
- app.use(express.static(path.join(__dirname, '../../public')));
49
-
50
- // API Routes
51
- app.get('/api/commits', async (req, res) => {
52
- try {
53
- const { file, since, author, limit = '100' } = req.query;
54
- const commits = await gitService.getCommits({
55
- file: file as string,
56
- since: since as string,
57
- author: author as string,
58
- limit: parseInt(limit as string)
59
- });
60
- res.json(commits);
61
- } catch (error) {
62
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
63
- res.status(500).json({ error: errorMessage });
64
- }
65
- });
66
-
67
- app.get('/api/commit/:hash', async (req, res) => {
68
- try {
69
- const { hash } = req.params;
70
- const commit = await gitService.getCommit(hash);
71
- res.json(commit);
72
- } catch (error) {
73
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
74
- res.status(500).json({ error: errorMessage });
75
- }
76
- });
77
-
78
- app.get('/api/diff/:hash', async (req, res) => {
79
- try {
80
- const { hash } = req.params;
81
- const diff = await gitService.getDiff(hash);
82
- res.json(diff);
83
- } catch (error) {
84
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
85
- res.status(500).json({ error: errorMessage });
86
- }
87
- });
88
-
89
- app.get('/api/blame/:file', async (req, res) => {
90
- try {
91
- const { file } = req.params;
92
- const blame = await gitService.getBlame(file);
93
- res.json(blame);
94
- } catch (error) {
95
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
96
- res.status(500).json({ error: errorMessage });
97
- }
98
- });
99
-
100
- app.get('/api/tags', async (req, res) => {
101
- try {
102
- const tags = await gitService.getTags();
103
- res.json(tags);
104
- } catch (error) {
105
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
106
- res.status(500).json({ error: errorMessage });
107
- }
108
- });
109
-
110
- app.get('/api/branches', async (req, res) => {
111
- try {
112
- const branches = await gitService.getBranches();
113
- res.json(branches);
114
- } catch (error) {
115
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
116
- res.status(500).json({ error: errorMessage });
117
- }
118
- });
119
-
120
- // Serve the main HTML file for Angular routing
121
- app.get('*', (req, res) => {
122
- res.sendFile(path.join(__dirname, '../../frontend/dist/frontend/browser/index.html'));
123
- });
124
-
125
- // Socket.IO for real-time updates
126
- io.on('connection', (socket) => {
127
- console.log('Client connected');
128
-
129
- socket.on('disconnect', () => {
130
- console.log('Client disconnected');
131
- });
132
- });
133
-
134
- return new Promise<void>((resolve) => {
135
- server.listen(port, host, () => {
136
- console.log(`Server running on http://${host}:${port}`);
137
- resolve();
138
- });
139
- });
140
- }
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
- }