hale-commenting-system 2.2.6 ā 2.2.9
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.
- package/README.md +100 -75
- package/package.json +3 -3
- package/scripts/integrate.js +132 -7
package/README.md
CHANGED
|
@@ -1,109 +1,134 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Hale Commenting System
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A commenting system for PatternFly React applications that allows designers and developers to add comments directly on design pages, sync with GitHub Issues, and link Jira tickets.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- š **Pin-based commenting** - Click anywhere on a page to add a comment pin
|
|
8
|
+
- š¬ **Thread discussions** - Organize comments into threads with replies
|
|
9
|
+
- š **GitHub Integration** - Sync comments with GitHub Issues automatically
|
|
10
|
+
- š« **Jira Integration** - Link Jira tickets to specific pages or sections
|
|
11
|
+
- šØ **PatternFly Design** - Built with PatternFly React components
|
|
12
|
+
- š± **Responsive** - Works on desktop and mobile devices
|
|
13
|
+
- š **Easy Integration** - Automated setup script for seamless installation
|
|
8
14
|
|
|
9
|
-
##
|
|
15
|
+
## Installation
|
|
10
16
|
|
|
11
17
|
```bash
|
|
12
|
-
|
|
13
|
-
cd patternfly-react-seed
|
|
14
|
-
npm install && npm run start:dev
|
|
18
|
+
npm install hale-commenting-system
|
|
15
19
|
```
|
|
16
|
-
## Development scripts
|
|
17
|
-
```sh
|
|
18
|
-
# Install development/build dependencies
|
|
19
|
-
npm install
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
npm run start:dev
|
|
21
|
+
## Quick Start
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
1. **Install the package:**
|
|
24
|
+
```bash
|
|
25
|
+
npm install hale-commenting-system
|
|
26
|
+
```
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
2. **Run the integration script:**
|
|
29
|
+
```bash
|
|
30
|
+
npx hale-commenting-system init
|
|
31
|
+
```
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
3. **Follow the interactive setup:**
|
|
34
|
+
- The script will guide you through project setup
|
|
35
|
+
- Optionally configure GitHub OAuth integration
|
|
36
|
+
- Optionally configure Jira integration
|
|
37
|
+
- Configuration files (`.env` and `.env.server`) will be created automatically
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
4. **Start your dev server:**
|
|
40
|
+
```bash
|
|
41
|
+
npm run start:dev
|
|
42
|
+
```
|
|
35
43
|
|
|
36
|
-
|
|
37
|
-
npm run format
|
|
44
|
+
## Usage
|
|
38
45
|
|
|
39
|
-
|
|
40
|
-
npm run bundle-profile:analyze
|
|
46
|
+
After running the integration script, the commenting system will be available in your PatternFly React Seed application.
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
npm run start
|
|
44
|
-
```
|
|
48
|
+
### Adding Comments
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
* [Editor Config](./.editorconfig)
|
|
50
|
+
- **Click anywhere** on a page to add a comment pin
|
|
51
|
+
- **View all comments** in the "Comments" menu item in the sidebar
|
|
52
|
+
- **Reply to comments** to create discussion threads
|
|
53
|
+
- **Navigate to pins** using the "Go to pin" button in the comments view
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
### GitHub Integration (Optional)
|
|
53
56
|
|
|
54
|
-
|
|
57
|
+
When configured, comments automatically sync with GitHub Issues:
|
|
58
|
+
- Each comment thread becomes a GitHub Issue
|
|
59
|
+
- Replies sync as Issue comments
|
|
60
|
+
- Status changes (open/closed) sync between the app and GitHub
|
|
55
61
|
|
|
56
|
-
|
|
57
|
-
```js
|
|
58
|
-
import imgSrc from '@assets/images/g_sizing.png';
|
|
59
|
-
<img src={imgSrc} alt="Some image" />
|
|
60
|
-
```
|
|
62
|
+
### Jira Integration (Optional)
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
When configured, you can:
|
|
65
|
+
- Link Jira tickets to specific pages or sections
|
|
66
|
+
- View ticket details in the commenting panel
|
|
67
|
+
- Track design work alongside development tickets
|
|
63
68
|
|
|
64
|
-
|
|
65
|
-
import loader from '@app/assets/images/loader.gif';
|
|
66
|
-
<img src={loader} alt="Content loading" />
|
|
67
|
-
```
|
|
69
|
+
## Configuration
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
Inlining SVG in the app's markup is also possible.
|
|
71
|
+
The integration script creates two configuration files:
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
### `.env`
|
|
74
|
+
Contains client-side configuration (safe to commit):
|
|
75
|
+
- GitHub OAuth client ID
|
|
76
|
+
- Jira base URL
|
|
77
|
+
- Other public configuration
|
|
76
78
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
### `.env.server`
|
|
80
|
+
Contains server-side secrets (should NOT be committed):
|
|
81
|
+
- GitHub OAuth client secret
|
|
82
|
+
- Jira API tokens
|
|
83
|
+
- Other sensitive credentials
|
|
84
|
+
|
|
85
|
+
**Important:** The `.env.server` file is automatically added to `.gitignore` to prevent committing secrets.
|
|
86
|
+
|
|
87
|
+
See the generated files for detailed setup instructions.
|
|
88
|
+
|
|
89
|
+
## Requirements
|
|
90
|
+
|
|
91
|
+
- **PatternFly React Seed** project (or compatible PatternFly React application)
|
|
92
|
+
- **Node.js 18+** (required for webpack middleware with native `fetch()` support)
|
|
93
|
+
- **React 18+**
|
|
83
94
|
|
|
84
|
-
##
|
|
85
|
-
When importing CSS from a third-party package for the first time, you may encounter the error `Module parse failed: Unexpected token... You may need an appropriate loader to handle this file typ...`. You need to register the path to the stylesheet directory in [stylePaths.js](./stylePaths.js). We specify these explicitly for performance reasons to avoid webpack needing to crawl through the entire node_modules directory when parsing CSS modules.
|
|
95
|
+
## What Gets Integrated
|
|
86
96
|
|
|
87
|
-
|
|
88
|
-
* For accessibility compliance, we use [react-axe](https://github.com/dequelabs/react-axe)
|
|
89
|
-
* To keep our bundle size in check, we use [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer)
|
|
90
|
-
* To keep our code formatting in check, we use [prettier](https://github.com/prettier/prettier)
|
|
91
|
-
* To keep our code logic and test coverage in check, we use [jest](https://github.com/facebook/jest)
|
|
92
|
-
* To ensure code styles remain consistent, we use [eslint](https://eslint.org/)
|
|
97
|
+
The integration script automatically modifies your project:
|
|
93
98
|
|
|
94
|
-
|
|
95
|
-
|
|
99
|
+
1. **`src/app/index.tsx`** - Adds `CommentProvider` and `GitHubAuthProvider`
|
|
100
|
+
2. **`src/app/routes.tsx`** - Adds "Comments" route group with "View all" route
|
|
101
|
+
3. **`src/app/AppLayout/AppLayout.tsx`** - Adds `CommentPanel` and `CommentOverlay` components
|
|
102
|
+
4. **`webpack.dev.js`** - Adds middleware for GitHub OAuth and Jira API proxying
|
|
103
|
+
5. **`src/app/Comments/Comments.tsx`** - Creates the Comments view component
|
|
104
|
+
6. **`.env` and `.env.server`** - Creates configuration files
|
|
96
105
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
106
|
+
## Development
|
|
107
|
+
|
|
108
|
+
### Running Locally
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Install dependencies
|
|
112
|
+
npm install
|
|
113
|
+
|
|
114
|
+
# Start development server
|
|
115
|
+
npm run start:dev
|
|
100
116
|
```
|
|
101
117
|
|
|
118
|
+
### Building for Production
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# Run production build
|
|
122
|
+
npm run build
|
|
123
|
+
|
|
124
|
+
# Start production server
|
|
125
|
+
npm run start
|
|
126
|
+
```
|
|
102
127
|
|
|
103
|
-
|
|
128
|
+
## License
|
|
104
129
|
|
|
105
|
-
|
|
130
|
+
MIT
|
|
106
131
|
|
|
107
|
-
|
|
132
|
+
## Support
|
|
108
133
|
|
|
109
|
-
|
|
134
|
+
For issues, questions, or contributions, please visit the [repository](https://github.com/patternfly/patternfly-react-seed).
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hale-commenting-system",
|
|
3
|
-
"version": "2.2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.2.9",
|
|
4
|
+
"description": "A commenting system for PatternFly React applications that allows designers and developers to add comments directly on design pages, sync with GitHub Issues, and link Jira tickets.",
|
|
5
5
|
"repository": "https://github.com/patternfly/patternfly-react-seed.git",
|
|
6
|
-
"homepage": "https://
|
|
6
|
+
"homepage": "https://www.npmjs.com/package/hale-commenting-system",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"main": "src/app/commenting-system/index.ts",
|
|
9
9
|
"types": "src/app/commenting-system/index.ts",
|
package/scripts/integrate.js
CHANGED
|
@@ -512,6 +512,41 @@ JIRA_API_TOKEN=
|
|
|
512
512
|
}
|
|
513
513
|
}
|
|
514
514
|
|
|
515
|
+
function createCommentsComponent() {
|
|
516
|
+
const cwd = process.cwd();
|
|
517
|
+
const commentsDir = path.join(cwd, 'src', 'app', 'Comments');
|
|
518
|
+
const commentsFile = path.join(commentsDir, 'Comments.tsx');
|
|
519
|
+
|
|
520
|
+
// Check if already exists
|
|
521
|
+
if (fs.existsSync(commentsFile)) {
|
|
522
|
+
return; // Already exists, skip
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Create directory if it doesn't exist
|
|
526
|
+
if (!fs.existsSync(commentsDir)) {
|
|
527
|
+
fs.mkdirSync(commentsDir, { recursive: true });
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Read the Comments component from the package and modify the import
|
|
531
|
+
// The file is in the package at src/app/Comments/Comments.tsx
|
|
532
|
+
const scriptDir = __dirname || path.dirname(require.resolve('./integrate.js'));
|
|
533
|
+
const packageCommentsFile = path.join(scriptDir, '..', 'src', 'app', 'Comments', 'Comments.tsx');
|
|
534
|
+
|
|
535
|
+
let commentsComponentContent;
|
|
536
|
+
if (fs.existsSync(packageCommentsFile)) {
|
|
537
|
+
// Read from package and replace import path
|
|
538
|
+
commentsComponentContent = fs.readFileSync(packageCommentsFile, 'utf8')
|
|
539
|
+
.replace(/from ['"]@app\/commenting-system['"]/g, "from 'hale-commenting-system'");
|
|
540
|
+
} else {
|
|
541
|
+
// Fallback: create a minimal version (shouldn't happen if package is properly built)
|
|
542
|
+
console.log(' ā ļø Comments component not found in package, skipping creation');
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
fs.writeFileSync(commentsFile, commentsComponentContent);
|
|
547
|
+
console.log(' ā
Created Comments component');
|
|
548
|
+
}
|
|
549
|
+
|
|
515
550
|
function integrateWebpackMiddleware() {
|
|
516
551
|
const cwd = process.cwd();
|
|
517
552
|
const webpackDevPath = path.join(cwd, 'webpack.dev.js');
|
|
@@ -759,13 +794,47 @@ function integrateWebpackMiddleware() {
|
|
|
759
794
|
`;
|
|
760
795
|
|
|
761
796
|
// Find the setupMiddlewares function and inject our code
|
|
762
|
-
|
|
763
|
-
const
|
|
797
|
+
// Try multiple patterns to match different webpack.dev.js structures
|
|
798
|
+
const setupMiddlewaresPatterns = [
|
|
799
|
+
/(setupMiddlewares\s*:\s*\([^)]+\)\s*=>\s*\{)/, // Arrow function
|
|
800
|
+
/(setupMiddlewares\s*:\s*function\s*\([^)]+\)\s*\{)/, // Function declaration
|
|
801
|
+
/(setupMiddlewares\s*:\s*\([^)]+\)\s*\{)/, // Shorthand method
|
|
802
|
+
];
|
|
803
|
+
|
|
804
|
+
let match = null;
|
|
805
|
+
for (const pattern of setupMiddlewaresPatterns) {
|
|
806
|
+
match = webpackContent.match(pattern);
|
|
807
|
+
if (match) break;
|
|
808
|
+
}
|
|
764
809
|
|
|
765
810
|
if (!match) {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
811
|
+
// If setupMiddlewares doesn't exist, we need to add it to devServer config
|
|
812
|
+
// Check if devServer config exists
|
|
813
|
+
const devServerMatch = webpackContent.match(/(devServer\s*:\s*\{)/);
|
|
814
|
+
if (devServerMatch) {
|
|
815
|
+
// Add setupMiddlewares to devServer config
|
|
816
|
+
const insertIndex = devServerMatch.index + devServerMatch[0].length;
|
|
817
|
+
const before = webpackContent.substring(0, insertIndex);
|
|
818
|
+
const after = webpackContent.substring(insertIndex);
|
|
819
|
+
|
|
820
|
+
const setupMiddlewaresCode = `
|
|
821
|
+
setupMiddlewares: (middlewares, devServer) => {
|
|
822
|
+
if (!devServer || !devServer.app) {
|
|
823
|
+
return middlewares;
|
|
824
|
+
}
|
|
825
|
+
${middlewareCode}
|
|
826
|
+
return middlewares;
|
|
827
|
+
},`;
|
|
828
|
+
|
|
829
|
+
webpackContent = before + setupMiddlewaresCode + '\n' + after;
|
|
830
|
+
fs.writeFileSync(webpackDevPath, webpackContent);
|
|
831
|
+
console.log(' ā
Added setupMiddlewares to webpack.dev.js');
|
|
832
|
+
return;
|
|
833
|
+
} else {
|
|
834
|
+
console.log(' ā ļø Could not find setupMiddlewares or devServer config in webpack.dev.js');
|
|
835
|
+
console.log(' š Manual integration required. See webpack middleware documentation\n');
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
769
838
|
}
|
|
770
839
|
|
|
771
840
|
// Find where to inject (after express.json() setup, before return middlewares)
|
|
@@ -992,10 +1061,62 @@ function modifyRoutesTsx(filePath) {
|
|
|
992
1061
|
});
|
|
993
1062
|
|
|
994
1063
|
if (routesArray) {
|
|
995
|
-
//
|
|
1064
|
+
// Check if Comments component is imported
|
|
1065
|
+
let hasCommentsImport = false;
|
|
1066
|
+
let commentsImportName = 'Comments';
|
|
1067
|
+
|
|
1068
|
+
traverse(ast, {
|
|
1069
|
+
ImportDeclaration(path) {
|
|
1070
|
+
const source = path.node.source.value;
|
|
1071
|
+
if (source.includes('Comments') || source.includes('@app/Comments')) {
|
|
1072
|
+
hasCommentsImport = true;
|
|
1073
|
+
// Get the imported name
|
|
1074
|
+
path.node.specifiers.forEach(spec => {
|
|
1075
|
+
if (spec.type === 'ImportSpecifier' && spec.imported.name === 'Comments') {
|
|
1076
|
+
commentsImportName = spec.local.name;
|
|
1077
|
+
}
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
});
|
|
1082
|
+
|
|
1083
|
+
// Add Comments import if missing
|
|
1084
|
+
if (!hasCommentsImport) {
|
|
1085
|
+
let lastImportIndex = -1;
|
|
1086
|
+
for (let i = ast.program.body.length - 1; i >= 0; i--) {
|
|
1087
|
+
if (ast.program.body[i].type === 'ImportDeclaration') {
|
|
1088
|
+
lastImportIndex = i;
|
|
1089
|
+
break;
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
const importIndex = lastImportIndex >= 0 ? lastImportIndex + 1 : 0;
|
|
1093
|
+
|
|
1094
|
+
const commentsImport = types.importDeclaration(
|
|
1095
|
+
[types.importSpecifier(types.identifier('Comments'), types.identifier('Comments'))],
|
|
1096
|
+
types.stringLiteral('@app/Comments/Comments')
|
|
1097
|
+
);
|
|
1098
|
+
|
|
1099
|
+
ast.program.body.splice(importIndex, 0, commentsImport);
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
// Add Comments route group with a route to the Comments component
|
|
1103
|
+
const commentsRouteElement = types.jsxElement(
|
|
1104
|
+
types.jsxOpeningElement(types.jsxIdentifier(commentsImportName), [], true),
|
|
1105
|
+
null,
|
|
1106
|
+
[]
|
|
1107
|
+
);
|
|
1108
|
+
|
|
1109
|
+
const commentsRouteItem = types.objectExpression([
|
|
1110
|
+
types.objectProperty(types.identifier('element'), commentsRouteElement),
|
|
1111
|
+
types.objectProperty(types.identifier('exact'), types.booleanLiteral(true)),
|
|
1112
|
+
types.objectProperty(types.identifier('label'), types.stringLiteral('View all')),
|
|
1113
|
+
types.objectProperty(types.identifier('path'), types.stringLiteral('/comments')),
|
|
1114
|
+
types.objectProperty(types.identifier('title'), types.stringLiteral('Hale Commenting System | Comments'))
|
|
1115
|
+
]);
|
|
1116
|
+
|
|
996
1117
|
const commentsRoute = types.objectExpression([
|
|
997
1118
|
types.objectProperty(types.identifier('label'), types.stringLiteral('Comments')),
|
|
998
|
-
types.objectProperty(types.identifier('routes'), types.arrayExpression([]))
|
|
1119
|
+
types.objectProperty(types.identifier('routes'), types.arrayExpression([commentsRouteItem]))
|
|
999
1120
|
]);
|
|
1000
1121
|
|
|
1001
1122
|
routesArray.elements.push(commentsRoute);
|
|
@@ -1540,6 +1661,10 @@ async function main() {
|
|
|
1540
1661
|
skippedCount++;
|
|
1541
1662
|
}
|
|
1542
1663
|
|
|
1664
|
+
// Create Comments component first (needed for routes)
|
|
1665
|
+
console.log('\nš Creating Comments component...');
|
|
1666
|
+
createCommentsComponent();
|
|
1667
|
+
|
|
1543
1668
|
// Modify routes.tsx
|
|
1544
1669
|
console.log(`\nš ${routesPath}`);
|
|
1545
1670
|
if (modifyRoutesTsx(routesPath)) {
|