hale-commenting-system 2.2.0 → 2.2.2

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 (99) hide show
  1. package/.claude/settings.local.json +7 -0
  2. package/.editorconfig +17 -0
  3. package/.eslintrc.js +75 -0
  4. package/.github/ISSUE_TEMPLATE/bug_report.md +23 -0
  5. package/.github/workflows/ci.yaml +51 -0
  6. package/.prettierignore +1 -0
  7. package/.prettierrc +4 -0
  8. package/GITHUB_OAUTH_ENV_TEMPLATE.md +53 -0
  9. package/LICENSE +21 -0
  10. package/README.md +92 -21
  11. package/package.json +74 -50
  12. package/scripts/README.md +42 -0
  13. package/scripts/integrate.js +472 -0
  14. package/src/app/AppLayout/AppLayout.tsx +248 -0
  15. package/src/app/Comments/Comments.tsx +273 -0
  16. package/src/app/Dashboard/Dashboard.tsx +10 -0
  17. package/src/app/NotFound/NotFound.tsx +35 -0
  18. package/src/app/Settings/General/GeneralSettings.tsx +16 -0
  19. package/src/app/Settings/Profile/ProfileSettings.tsx +18 -0
  20. package/src/app/Support/Support.tsx +50 -0
  21. package/src/app/__snapshots__/app.test.tsx.snap +524 -0
  22. package/src/app/app.css +11 -0
  23. package/src/app/app.test.tsx +55 -0
  24. package/src/app/bgimages/Patternfly-Logo.svg +28 -0
  25. package/src/app/commenting-system/components/CommentOverlay.tsx +93 -0
  26. package/src/app/commenting-system/components/CommentPanel.tsx +534 -0
  27. package/src/app/commenting-system/components/CommentPin.tsx +60 -0
  28. package/src/app/commenting-system/components/DetailsTab.tsx +516 -0
  29. package/src/app/commenting-system/components/FloatingWidget.tsx +130 -0
  30. package/src/app/commenting-system/components/JiraTab.tsx +696 -0
  31. package/src/app/commenting-system/contexts/CommentContext.tsx +1033 -0
  32. package/src/app/commenting-system/contexts/GitHubAuthContext.tsx +84 -0
  33. package/{dist/index.d.ts → src/app/commenting-system/index.ts} +5 -4
  34. package/src/app/commenting-system/services/githubAdapter.ts +359 -0
  35. package/src/app/commenting-system/types/index.ts +27 -0
  36. package/src/app/commenting-system/utils/version.ts +19 -0
  37. package/src/app/index.tsx +22 -0
  38. package/src/app/routes.tsx +81 -0
  39. package/src/app/utils/useDocumentTitle.ts +13 -0
  40. package/src/favicon.png +0 -0
  41. package/src/index.html +18 -0
  42. package/src/index.tsx +25 -0
  43. package/src/test/setup.ts +33 -0
  44. package/src/typings.d.ts +12 -0
  45. package/stylePaths.js +14 -0
  46. package/tsconfig.json +34 -0
  47. package/vitest.config.ts +19 -0
  48. package/webpack.common.js +139 -0
  49. package/webpack.dev.js +318 -0
  50. package/webpack.prod.js +38 -0
  51. package/bin/detect.d.ts +0 -10
  52. package/bin/detect.js +0 -134
  53. package/bin/generators.d.ts +0 -20
  54. package/bin/generators.js +0 -272
  55. package/bin/hale-commenting.js +0 -4
  56. package/bin/index.d.ts +0 -2
  57. package/bin/index.js +0 -61
  58. package/bin/onboarding.d.ts +0 -1
  59. package/bin/onboarding.js +0 -395
  60. package/bin/postinstall.d.ts +0 -2
  61. package/bin/postinstall.js +0 -65
  62. package/bin/validators.d.ts +0 -2
  63. package/bin/validators.js +0 -66
  64. package/dist/cli/detect.d.ts +0 -10
  65. package/dist/cli/detect.js +0 -134
  66. package/dist/cli/generators.d.ts +0 -20
  67. package/dist/cli/generators.js +0 -272
  68. package/dist/cli/index.d.ts +0 -2
  69. package/dist/cli/index.js +0 -61
  70. package/dist/cli/onboarding.d.ts +0 -1
  71. package/dist/cli/onboarding.js +0 -395
  72. package/dist/cli/postinstall.d.ts +0 -2
  73. package/dist/cli/postinstall.js +0 -65
  74. package/dist/cli/validators.d.ts +0 -2
  75. package/dist/cli/validators.js +0 -66
  76. package/dist/components/CommentOverlay.d.ts +0 -2
  77. package/dist/components/CommentOverlay.js +0 -101
  78. package/dist/components/CommentPanel.d.ts +0 -6
  79. package/dist/components/CommentPanel.js +0 -334
  80. package/dist/components/CommentPin.d.ts +0 -11
  81. package/dist/components/CommentPin.js +0 -64
  82. package/dist/components/DetailsTab.d.ts +0 -2
  83. package/dist/components/DetailsTab.js +0 -380
  84. package/dist/components/FloatingWidget.d.ts +0 -8
  85. package/dist/components/FloatingWidget.js +0 -128
  86. package/dist/components/JiraTab.d.ts +0 -2
  87. package/dist/components/JiraTab.js +0 -507
  88. package/dist/contexts/CommentContext.d.ts +0 -30
  89. package/dist/contexts/CommentContext.js +0 -891
  90. package/dist/contexts/GitHubAuthContext.d.ts +0 -13
  91. package/dist/contexts/GitHubAuthContext.js +0 -96
  92. package/dist/index.js +0 -27
  93. package/dist/services/githubAdapter.d.ts +0 -56
  94. package/dist/services/githubAdapter.js +0 -321
  95. package/dist/types/index.d.ts +0 -25
  96. package/dist/types/index.js +0 -2
  97. package/dist/utils/version.d.ts +0 -1
  98. package/dist/utils/version.js +0 -23
  99. package/templates/webpack-middleware.js +0 -226
@@ -0,0 +1,472 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Hale Commenting System - Auto Integration Script
5
+ *
6
+ * This script automatically integrates the commenting system into a PatternFly React Seed project
7
+ * by modifying the necessary files using AST parsing.
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const { execSync } = require('child_process');
13
+
14
+ // Check if required dependencies are available
15
+ let parser, traverse, generate, types;
16
+ try {
17
+ const babel = require('@babel/core');
18
+ parser = babel.parse;
19
+ traverse = require('@babel/traverse').default;
20
+ generate = require('@babel/generator').default;
21
+ types = require('@babel/types');
22
+ } catch (e) {
23
+ console.error('❌ Error: @babel/core, @babel/traverse, and @babel/generator are required.');
24
+ console.error(' Please install: npm install --save-dev @babel/core @babel/traverse @babel/generator @babel/types');
25
+ process.exit(1);
26
+ }
27
+
28
+ const readline = require('readline');
29
+
30
+ const rl = readline.createInterface({
31
+ input: process.stdin,
32
+ output: process.stdout
33
+ });
34
+
35
+ function question(prompt) {
36
+ return new Promise((resolve) => {
37
+ rl.question(prompt, resolve);
38
+ });
39
+ }
40
+
41
+ function findFile(filename, startDir = process.cwd()) {
42
+ const possiblePaths = [
43
+ path.join(startDir, filename),
44
+ path.join(startDir, 'src', filename),
45
+ path.join(startDir, 'src', 'app', filename),
46
+ // Support for AppLayout subdirectory
47
+ path.join(startDir, 'src', 'app', 'AppLayout', filename),
48
+ ];
49
+
50
+ for (const filePath of possiblePaths) {
51
+ if (fs.existsSync(filePath)) {
52
+ return filePath;
53
+ }
54
+ }
55
+ return null;
56
+ }
57
+
58
+ function getPackageVersion() {
59
+ try {
60
+ // Get the script's directory and find package.json relative to it
61
+ const scriptDir = __dirname || path.dirname(require.resolve('./integrate.js'));
62
+ const packageJsonPath = path.join(scriptDir, '..', 'package.json');
63
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
64
+ return packageJson.version || 'unknown';
65
+ } catch (e) {
66
+ // Fallback: try to find package.json in current working directory or parent
67
+ try {
68
+ const cwdPackageJson = path.join(process.cwd(), 'package.json');
69
+ if (fs.existsSync(cwdPackageJson)) {
70
+ const packageJson = JSON.parse(fs.readFileSync(cwdPackageJson, 'utf8'));
71
+ if (packageJson.name === 'hale-commenting-system') {
72
+ return packageJson.version || 'unknown';
73
+ }
74
+ }
75
+ } catch (e2) {
76
+ // ignore
77
+ }
78
+ return 'unknown';
79
+ }
80
+ }
81
+
82
+ function modifyIndexTsx(filePath) {
83
+ const content = fs.readFileSync(filePath, 'utf8');
84
+
85
+ // Check if already integrated
86
+ if (content.includes('CommentProvider') && content.includes('GitHubAuthProvider')) {
87
+ console.log(' ⚠️ Already integrated (providers found)');
88
+ return false;
89
+ }
90
+
91
+ try {
92
+ const ast = parser(content, {
93
+ sourceType: 'module',
94
+ plugins: ['typescript', 'jsx', 'decorators-legacy', 'classProperties']
95
+ });
96
+
97
+ let hasCommentProvider = false;
98
+ let hasGitHubAuthProvider = false;
99
+ let hasCommentImport = false;
100
+ let routerElement = null;
101
+
102
+ // Check existing imports and find Router element
103
+ traverse(ast, {
104
+ ImportDeclaration(path) {
105
+ const source = path.node.source.value;
106
+ if (source.includes('commenting-system') || source.includes('@app/commenting-system')) {
107
+ hasCommentImport = true;
108
+ // Check if providers are imported
109
+ path.node.specifiers.forEach(spec => {
110
+ if (spec.imported && spec.imported.name === 'CommentProvider') {
111
+ hasCommentProvider = true;
112
+ }
113
+ if (spec.imported && spec.imported.name === 'GitHubAuthProvider') {
114
+ hasGitHubAuthProvider = true;
115
+ }
116
+ });
117
+ }
118
+ },
119
+ JSXElement(path) {
120
+ if (path.node.openingElement.name.name === 'Router') {
121
+ routerElement = path;
122
+ }
123
+ }
124
+ });
125
+
126
+ // Add imports if missing
127
+ if (!hasCommentImport) {
128
+ // Find last import declaration
129
+ let lastImportIndex = -1;
130
+ for (let i = ast.program.body.length - 1; i >= 0; i--) {
131
+ if (ast.program.body[i].type === 'ImportDeclaration') {
132
+ lastImportIndex = i;
133
+ break;
134
+ }
135
+ }
136
+ const importIndex = lastImportIndex >= 0 ? lastImportIndex + 1 : 0;
137
+
138
+ const providerImports = types.importDeclaration(
139
+ [
140
+ types.importSpecifier(types.identifier('CommentProvider'), types.identifier('CommentProvider')),
141
+ types.importSpecifier(types.identifier('GitHubAuthProvider'), types.identifier('GitHubAuthProvider'))
142
+ ],
143
+ types.stringLiteral('@app/commenting-system')
144
+ );
145
+
146
+ ast.program.body.splice(importIndex, 0, providerImports);
147
+ } else if (!hasCommentProvider || !hasGitHubAuthProvider) {
148
+ // Update existing import
149
+ traverse(ast, {
150
+ ImportDeclaration(path) {
151
+ const source = path.node.source.value;
152
+ if (source.includes('commenting-system') || source.includes('@app/commenting-system')) {
153
+ const specifiers = path.node.specifiers || [];
154
+ if (!hasCommentProvider) {
155
+ specifiers.push(types.importSpecifier(types.identifier('CommentProvider'), types.identifier('CommentProvider')));
156
+ }
157
+ if (!hasGitHubAuthProvider) {
158
+ specifiers.push(types.importSpecifier(types.identifier('GitHubAuthProvider'), types.identifier('GitHubAuthProvider')));
159
+ }
160
+ path.node.specifiers = specifiers;
161
+ }
162
+ }
163
+ });
164
+ }
165
+
166
+ // Wrap Router content with providers
167
+ if (routerElement) {
168
+ const routerChildren = routerElement.node.children;
169
+
170
+ // Check if already wrapped
171
+ if (routerChildren.length > 0 &&
172
+ routerChildren[0].type === 'JSXElement' &&
173
+ routerChildren[0].openingElement.name.name === 'GitHubAuthProvider') {
174
+ console.log(' ⚠️ Already integrated (providers found in JSX)');
175
+ return false;
176
+ }
177
+
178
+ // Create provider wrappers
179
+ const commentProvider = types.jsxElement(
180
+ types.jsxOpeningElement(types.jsxIdentifier('CommentProvider'), []),
181
+ types.jsxClosingElement(types.jsxIdentifier('CommentProvider')),
182
+ routerChildren
183
+ );
184
+
185
+ const gitHubAuthProvider = types.jsxElement(
186
+ types.jsxOpeningElement(types.jsxIdentifier('GitHubAuthProvider'), []),
187
+ types.jsxClosingElement(types.jsxIdentifier('GitHubAuthProvider')),
188
+ [commentProvider]
189
+ );
190
+
191
+ routerElement.node.children = [gitHubAuthProvider];
192
+ }
193
+
194
+ const output = generate(ast, {
195
+ retainLines: false,
196
+ compact: false
197
+ }, content);
198
+
199
+ fs.writeFileSync(filePath, output.code);
200
+ return true;
201
+ } catch (error) {
202
+ console.error(` ❌ Error modifying ${filePath}:`, error.message);
203
+ return false;
204
+ }
205
+ }
206
+
207
+ function modifyRoutesTsx(filePath) {
208
+ const content = fs.readFileSync(filePath, 'utf8');
209
+
210
+ // Check if Comments route already exists
211
+ if (content.includes("label: 'Comments'") || content.includes('label: "Comments"')) {
212
+ console.log(' ⚠️ Already integrated (Comments route found)');
213
+ return false;
214
+ }
215
+
216
+ try {
217
+ const ast = parser(content, {
218
+ sourceType: 'module',
219
+ plugins: ['typescript', 'jsx', 'decorators-legacy', 'classProperties']
220
+ });
221
+
222
+ let routesArray = null;
223
+
224
+ traverse(ast, {
225
+ VariableDeclarator(path) {
226
+ if (path.node.id.name === 'routes' && path.node.init.type === 'ArrayExpression') {
227
+ routesArray = path.node.init;
228
+ }
229
+ }
230
+ });
231
+
232
+ if (routesArray) {
233
+ // Add Comments route group
234
+ const commentsRoute = types.objectExpression([
235
+ types.objectProperty(types.identifier('label'), types.stringLiteral('Comments')),
236
+ types.objectProperty(types.identifier('routes'), types.arrayExpression([]))
237
+ ]);
238
+
239
+ routesArray.elements.push(commentsRoute);
240
+ }
241
+
242
+ const output = generate(ast, {
243
+ retainLines: false,
244
+ compact: false
245
+ }, content);
246
+
247
+ fs.writeFileSync(filePath, output.code);
248
+ return true;
249
+ } catch (error) {
250
+ console.error(` ❌ Error modifying ${filePath}:`, error.message);
251
+ return false;
252
+ }
253
+ }
254
+
255
+ function modifyAppLayoutTsx(filePath) {
256
+ const content = fs.readFileSync(filePath, 'utf8');
257
+
258
+ // Check if already integrated
259
+ if (content.includes('CommentPanel') && content.includes('CommentOverlay')) {
260
+ console.log(' ⚠️ Already integrated (CommentPanel/CommentOverlay found)');
261
+ return false;
262
+ }
263
+
264
+ try {
265
+ const ast = parser(content, {
266
+ sourceType: 'module',
267
+ plugins: ['typescript', 'jsx', 'decorators-legacy', 'classProperties']
268
+ });
269
+
270
+ let hasCommentImport = false;
271
+ let pageElement = null;
272
+
273
+ // Check imports and find Page element
274
+ traverse(ast, {
275
+ ImportDeclaration(path) {
276
+ const source = path.node.source.value;
277
+ if (source.includes('commenting-system') || source.includes('@app/commenting-system')) {
278
+ hasCommentImport = true;
279
+ // Check if components are imported
280
+ const specifiers = path.node.specifiers || [];
281
+ const hasCommentPanel = specifiers.some(s =>
282
+ s.imported && (s.imported.name === 'CommentPanel' || s.local.name === 'CommentPanel')
283
+ );
284
+ const hasCommentOverlay = specifiers.some(s =>
285
+ s.imported && (s.imported.name === 'CommentOverlay' || s.local.name === 'CommentOverlay')
286
+ );
287
+
288
+ if (!hasCommentPanel) {
289
+ specifiers.push(types.importSpecifier(types.identifier('CommentPanel'), types.identifier('CommentPanel')));
290
+ }
291
+ if (!hasCommentOverlay) {
292
+ specifiers.push(types.importSpecifier(types.identifier('CommentOverlay'), types.identifier('CommentOverlay')));
293
+ }
294
+ path.node.specifiers = specifiers;
295
+ }
296
+ },
297
+ JSXElement(path) {
298
+ if (path.node.openingElement.name.name === 'Page') {
299
+ pageElement = path;
300
+ }
301
+ }
302
+ });
303
+
304
+ // Add imports if missing
305
+ if (!hasCommentImport) {
306
+ // Find last import declaration
307
+ let lastImportIndex = -1;
308
+ for (let i = ast.program.body.length - 1; i >= 0; i--) {
309
+ if (ast.program.body[i].type === 'ImportDeclaration') {
310
+ lastImportIndex = i;
311
+ break;
312
+ }
313
+ }
314
+ const importIndex = lastImportIndex >= 0 ? lastImportIndex + 1 : 0;
315
+
316
+ const componentImports = types.importDeclaration(
317
+ [
318
+ types.importSpecifier(types.identifier('CommentPanel'), types.identifier('CommentPanel')),
319
+ types.importSpecifier(types.identifier('CommentOverlay'), types.identifier('CommentOverlay'))
320
+ ],
321
+ types.stringLiteral('@app/commenting-system')
322
+ );
323
+
324
+ ast.program.body.splice(importIndex, 0, componentImports);
325
+ }
326
+
327
+ // Wrap Page children with CommentPanel and CommentOverlay
328
+ if (pageElement) {
329
+ const pageChildren = pageElement.node.children;
330
+
331
+ // Check if already wrapped
332
+ if (pageChildren.length > 0 &&
333
+ pageChildren[0].type === 'JSXElement' &&
334
+ pageChildren[0].openingElement.name.name === 'CommentPanel') {
335
+ console.log(' ⚠️ Already integrated (CommentPanel found in JSX)');
336
+ return false;
337
+ }
338
+
339
+ // Create CommentOverlay
340
+ const commentOverlay = types.jsxElement(
341
+ types.jsxOpeningElement(types.jsxIdentifier('CommentOverlay'), [], true),
342
+ null,
343
+ []
344
+ );
345
+
346
+ // Create CommentPanel wrapping children and CommentOverlay
347
+ const commentPanel = types.jsxElement(
348
+ types.jsxOpeningElement(types.jsxIdentifier('CommentPanel'), []),
349
+ types.jsxClosingElement(types.jsxIdentifier('CommentPanel')),
350
+ [commentOverlay, ...pageChildren]
351
+ );
352
+
353
+ pageElement.node.children = [commentPanel];
354
+ }
355
+
356
+ const output = generate(ast, {
357
+ retainLines: false,
358
+ compact: false
359
+ }, content);
360
+
361
+ fs.writeFileSync(filePath, output.code);
362
+ return true;
363
+ } catch (error) {
364
+ console.error(` ❌ Error modifying ${filePath}:`, error.message);
365
+ return false;
366
+ }
367
+ }
368
+
369
+ async function main() {
370
+ const version = getPackageVersion();
371
+ const title = `Hale Commenting System (v.${version})`;
372
+ const titleLength = title.length;
373
+ const borderLength = Math.max(titleLength + 4, 54);
374
+ const padding = Math.floor((borderLength - titleLength - 2) / 2);
375
+
376
+ console.log('\n' + '╔' + '═'.repeat(borderLength - 2) + '╗');
377
+ console.log('║' + ' '.repeat(padding) + title + ' '.repeat(borderLength - titleLength - padding - 2) + '║');
378
+ console.log('╚' + '═'.repeat(borderLength - 2) + '╝\n');
379
+
380
+ console.log('We\'ll automatically integrate the commenting system into your project.\n');
381
+ console.log('This will modify the following files:');
382
+ console.log(' • src/app/index.tsx');
383
+ console.log(' • src/app/routes.tsx');
384
+ console.log(' • src/app/AppLayout/AppLayout.tsx\n');
385
+
386
+ const answer = await question('Continue? (Y/n) ');
387
+
388
+ if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== '' && answer.toLowerCase() !== 'yes') {
389
+ console.log('\n❌ Integration cancelled.');
390
+ rl.close();
391
+ return;
392
+ }
393
+
394
+ console.log('\n✓ Scanning project structure...');
395
+
396
+ const indexPath = findFile('index.tsx');
397
+ const routesPath = findFile('routes.tsx');
398
+ const appLayoutPath = findFile('AppLayout/AppLayout.tsx') || findFile('AppLayout.tsx');
399
+
400
+ if (!indexPath) {
401
+ console.error('❌ Could not find src/app/index.tsx');
402
+ rl.close();
403
+ process.exit(1);
404
+ }
405
+ if (!routesPath) {
406
+ console.error('❌ Could not find src/app/routes.tsx');
407
+ rl.close();
408
+ process.exit(1);
409
+ }
410
+ if (!appLayoutPath) {
411
+ console.error('❌ Could not find src/app/AppLayout/AppLayout.tsx');
412
+ rl.close();
413
+ process.exit(1);
414
+ }
415
+
416
+ console.log('✓ Modifying files...\n');
417
+
418
+ let successCount = 0;
419
+ let skippedCount = 0;
420
+
421
+ // Modify index.tsx
422
+ console.log(`📝 ${indexPath}`);
423
+ if (modifyIndexTsx(indexPath)) {
424
+ console.log(' ✅ Added providers');
425
+ successCount++;
426
+ } else {
427
+ skippedCount++;
428
+ }
429
+
430
+ // Modify routes.tsx
431
+ console.log(`\n📝 ${routesPath}`);
432
+ if (modifyRoutesTsx(routesPath)) {
433
+ console.log(' ✅ Added Comments route');
434
+ successCount++;
435
+ } else {
436
+ skippedCount++;
437
+ }
438
+
439
+ // Modify AppLayout.tsx
440
+ console.log(`\n📝 ${appLayoutPath}`);
441
+ if (modifyAppLayoutTsx(appLayoutPath)) {
442
+ console.log(' ✅ Added CommentPanel and CommentOverlay');
443
+ successCount++;
444
+ } else {
445
+ skippedCount++;
446
+ }
447
+
448
+ console.log('\n╔══════════════════════════════════════════════════════════╗');
449
+ console.log('║ ✅ Integration Complete! ║');
450
+ console.log('╚══════════════════════════════════════════════════════════╝\n');
451
+
452
+ if (successCount > 0) {
453
+ console.log(`✓ Modified ${successCount} file(s)`);
454
+ }
455
+ if (skippedCount > 0) {
456
+ console.log(`⚠️ ${skippedCount} file(s) already integrated or skipped`);
457
+ }
458
+
459
+ console.log('\nNext steps:');
460
+ console.log(' 1. Restart your dev server: npm run start:dev');
461
+ console.log(' 2. The commenting system will be active automatically');
462
+ console.log(' 3. Click anywhere on the page to create comments\n');
463
+
464
+ rl.close();
465
+ }
466
+
467
+ main().catch((error) => {
468
+ console.error('\n❌ Integration failed:', error.message);
469
+ rl.close();
470
+ process.exit(1);
471
+ });
472
+