hale-commenting-system 2.0.3 → 2.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.
- package/README.md +16 -207
- package/bin/detect.d.ts +1 -0
- package/bin/detect.js +62 -0
- package/bin/generators.d.ts +18 -0
- package/bin/generators.js +193 -0
- package/bin/hale-commenting.js +4 -0
- package/bin/index.d.ts +2 -0
- package/bin/index.js +61 -0
- package/bin/onboarding.d.ts +1 -0
- package/bin/onboarding.js +170 -0
- package/bin/postinstall.d.ts +2 -0
- package/bin/postinstall.js +65 -0
- package/bin/validators.d.ts +2 -0
- package/bin/validators.js +66 -0
- package/dist/cli/detect.d.ts +1 -0
- package/dist/cli/detect.js +62 -0
- package/dist/cli/generators.d.ts +18 -0
- package/dist/cli/generators.js +193 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +61 -0
- package/dist/cli/onboarding.d.ts +1 -0
- package/dist/cli/onboarding.js +170 -0
- package/dist/cli/postinstall.d.ts +2 -0
- package/dist/cli/postinstall.js +65 -0
- package/dist/cli/validators.d.ts +2 -0
- package/dist/cli/validators.js +66 -0
- package/dist/components/CommentOverlay.d.ts +2 -0
- package/dist/components/CommentOverlay.js +101 -0
- package/dist/components/CommentPanel.d.ts +6 -0
- package/dist/components/CommentPanel.js +334 -0
- package/dist/components/CommentPin.d.ts +11 -0
- package/dist/components/CommentPin.js +64 -0
- package/dist/components/DetailsTab.d.ts +2 -0
- package/dist/components/DetailsTab.js +380 -0
- package/dist/components/FloatingWidget.d.ts +8 -0
- package/dist/components/FloatingWidget.js +128 -0
- package/dist/components/JiraTab.d.ts +2 -0
- package/dist/components/JiraTab.js +507 -0
- package/dist/contexts/CommentContext.d.ts +30 -0
- package/dist/contexts/CommentContext.js +891 -0
- package/dist/contexts/GitHubAuthContext.d.ts +13 -0
- package/dist/contexts/GitHubAuthContext.js +96 -0
- package/dist/index.d.ts +10 -97
- package/dist/index.js +26 -786
- package/dist/services/githubAdapter.d.ts +56 -0
- package/dist/services/githubAdapter.js +321 -0
- package/dist/types/index.d.ts +25 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/version.d.ts +1 -0
- package/dist/utils/version.js +23 -0
- package/package.json +39 -38
- package/templates/webpack-middleware.js +226 -0
- package/cli/dist/index.js +0 -370
- package/cli/dist/index.js.map +0 -1
- package/dist/index.d.mts +0 -97
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -759
- package/dist/index.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,16 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Hale Commenting System
|
|
2
2
|
|
|
3
|
-
A
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- 📌 **Visual Comment Pins** - Click anywhere on your app to add comment threads
|
|
8
|
-
- 💾 **LocalStorage Persistence** - Comments persist across page refreshes
|
|
9
|
-
- 🔄 **Threaded Conversations** - Add multiple replies to each comment pin
|
|
10
|
-
- 📦 **Version Management** - Filter comments by prototype version
|
|
11
|
-
- 🎨 **PatternFly UI** - Built with PatternFly React components
|
|
12
|
-
- 🧙 **CLI Wizard** - Automated setup with `npx hale-commenting-system init`
|
|
13
|
-
- 🚀 **Zero Configuration** - No backend, no auth, no setup hassle
|
|
3
|
+
A commenting system for PatternFly Seed projects with GitHub and Jira integration.
|
|
14
4
|
|
|
15
5
|
## Installation
|
|
16
6
|
|
|
@@ -18,212 +8,31 @@ A local-first React commenting system with localStorage persistence. Perfect for
|
|
|
18
8
|
npm install hale-commenting-system
|
|
19
9
|
```
|
|
20
10
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Run the interactive setup wizard:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
npx hale-commenting-system init
|
|
27
|
-
```
|
|
11
|
+
After installation, the onboarding flow will automatically start to help you configure GitHub OAuth and Jira integration.
|
|
28
12
|
|
|
29
|
-
|
|
30
|
-
1. Detect your React project
|
|
31
|
-
2. Auto-integrate the commenting system into your App component
|
|
32
|
-
3. You're done! Start your dev server and click anywhere to add comments
|
|
13
|
+
## Features
|
|
33
14
|
|
|
34
|
-
|
|
15
|
+
- **GitHub Integration**: Comments sync to GitHub Issues
|
|
16
|
+
- **Jira Integration**: Link Jira tickets to pages/sections
|
|
17
|
+
- **Details Tab**: Store design goals and context
|
|
18
|
+
- **Floating Widget**: Draggable commenting interface
|
|
19
|
+
- **PatternFly Seed**: Auto-detects and integrates with PF Seed projects
|
|
35
20
|
|
|
36
|
-
|
|
37
|
-
- Page refreshes
|
|
38
|
-
- Browser restarts
|
|
39
|
-
- Dev server restarts
|
|
21
|
+
## Requirements
|
|
40
22
|
|
|
41
|
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
- Quick feedback sessions
|
|
45
|
-
- Testing before adding a backend
|
|
23
|
+
- PatternFly Seed project
|
|
24
|
+
- GitHub account with OAuth app
|
|
25
|
+
- Jira access (Red Hat Jira: issues.redhat.com)
|
|
46
26
|
|
|
47
27
|
## Usage
|
|
48
28
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
### View Mode (Default)
|
|
52
|
-
- Click the "Show Pins" toggle to see existing comment pins
|
|
53
|
-
- Click on pins to view threads and replies
|
|
54
|
-
- Read-only, no editing
|
|
55
|
-
|
|
56
|
-
### Comment Mode
|
|
57
|
-
- Click "Enable Commenting" to enter edit mode
|
|
58
|
-
- Your cursor becomes a crosshair
|
|
59
|
-
- Click anywhere to create a new comment thread
|
|
60
|
-
- Click pins to add replies, edit, or delete
|
|
61
|
-
|
|
62
|
-
### Keyboard Shortcuts
|
|
63
|
-
- Press `Enter` in the comment textarea to submit
|
|
64
|
-
- Press `Esc` to close the comment drawer
|
|
65
|
-
|
|
66
|
-
## Manual Integration
|
|
67
|
-
|
|
68
|
-
If the CLI doesn't work for your project, you can manually integrate:
|
|
69
|
-
|
|
70
|
-
```tsx
|
|
71
|
-
import React from 'react';
|
|
72
|
-
import { BrowserRouter as Router } from 'react-router-dom';
|
|
73
|
-
import {
|
|
74
|
-
CommentProvider,
|
|
75
|
-
CommentOverlay,
|
|
76
|
-
CommentDrawer,
|
|
77
|
-
VersionProvider
|
|
78
|
-
} from 'hale-commenting-system';
|
|
79
|
-
|
|
80
|
-
function App() {
|
|
81
|
-
const [selectedThreadId, setSelectedThreadId] = React.useState<string | null>(null);
|
|
82
|
-
|
|
83
|
-
return (
|
|
84
|
-
<Router>
|
|
85
|
-
<VersionProvider>
|
|
86
|
-
<CommentProvider>
|
|
87
|
-
<CommentDrawer
|
|
88
|
-
selectedThreadId={selectedThreadId}
|
|
89
|
-
onThreadSelect={setSelectedThreadId}
|
|
90
|
-
>
|
|
91
|
-
<CommentOverlay
|
|
92
|
-
selectedThreadId={selectedThreadId}
|
|
93
|
-
onThreadSelect={setSelectedThreadId}
|
|
94
|
-
/>
|
|
95
|
-
{/* Your app content */}
|
|
96
|
-
</CommentDrawer>
|
|
97
|
-
</CommentProvider>
|
|
98
|
-
</VersionProvider>
|
|
99
|
-
</Router>
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## API
|
|
105
|
-
|
|
106
|
-
### `<CommentProvider>`
|
|
107
|
-
Root provider that manages comment state and localStorage persistence.
|
|
108
|
-
|
|
109
|
-
### `<CommentOverlay>`
|
|
110
|
-
Invisible overlay that handles click events for creating new comments.
|
|
111
|
-
|
|
112
|
-
**Props:**
|
|
113
|
-
- `selectedThreadId: string | null` - Currently selected thread ID
|
|
114
|
-
- `onThreadSelect: (id: string | null) => void` - Callback when a thread is selected
|
|
115
|
-
|
|
116
|
-
### `<CommentDrawer>`
|
|
117
|
-
Sidebar drawer that displays the selected thread and its replies.
|
|
29
|
+
The package will automatically guide you through setup on installation. For manual setup, run:
|
|
118
30
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
- `onThreadSelect: (id: string | null) => void` - Callback to close the drawer
|
|
122
|
-
- `children: React.ReactNode` - Your app content
|
|
123
|
-
|
|
124
|
-
### `useComments()` Hook
|
|
125
|
-
|
|
126
|
-
Access comment state and actions:
|
|
127
|
-
|
|
128
|
-
```tsx
|
|
129
|
-
import { useComments } from 'hale-commenting-system';
|
|
130
|
-
|
|
131
|
-
function MyComponent() {
|
|
132
|
-
const {
|
|
133
|
-
threads, // All comment threads
|
|
134
|
-
showPins, // Whether pins are visible
|
|
135
|
-
enableCommenting, // Whether commenting mode is active
|
|
136
|
-
toggleShowPins, // Toggle pin visibility
|
|
137
|
-
toggleEnableCommenting, // Toggle commenting mode
|
|
138
|
-
addThread, // Create a new thread
|
|
139
|
-
addReply, // Add a reply to a thread
|
|
140
|
-
updateComment, // Update a comment
|
|
141
|
-
deleteComment, // Delete a comment
|
|
142
|
-
deleteThread, // Delete a thread
|
|
143
|
-
clearAllThreads, // Clear all comments
|
|
144
|
-
getThreadsForRoute // Get comments for current route
|
|
145
|
-
} = useComments();
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
## Version Management
|
|
150
|
-
|
|
151
|
-
The system supports filtering comments by version (useful for iterating on prototypes):
|
|
152
|
-
|
|
153
|
-
```tsx
|
|
154
|
-
import { VersionProvider, useVersion } from 'hale-commenting-system';
|
|
155
|
-
|
|
156
|
-
function App() {
|
|
157
|
-
return (
|
|
158
|
-
<VersionProvider>
|
|
159
|
-
<CommentProvider>
|
|
160
|
-
{/* Your app */}
|
|
161
|
-
</CommentProvider>
|
|
162
|
-
</VersionProvider>
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// In your component
|
|
167
|
-
function MyComponent() {
|
|
168
|
-
const { currentVersion, setCurrentVersion } = useVersion();
|
|
169
|
-
|
|
170
|
-
// Comments are automatically filtered by version
|
|
171
|
-
return (
|
|
172
|
-
<select value={currentVersion} onChange={(e) => setCurrentVersion(e.target.value)}>
|
|
173
|
-
<option value="1">Version 1</option>
|
|
174
|
-
<option value="2">Version 2</option>
|
|
175
|
-
<option value="3">Version 3 (current)</option>
|
|
176
|
-
</select>
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
## TypeScript
|
|
182
|
-
|
|
183
|
-
The package includes full TypeScript definitions:
|
|
184
|
-
|
|
185
|
-
```tsx
|
|
186
|
-
import type { Thread, Comment } from 'hale-commenting-system';
|
|
187
|
-
|
|
188
|
-
interface Thread {
|
|
189
|
-
id: string;
|
|
190
|
-
x: number;
|
|
191
|
-
y: number;
|
|
192
|
-
route: string;
|
|
193
|
-
comments: Comment[];
|
|
194
|
-
version?: string;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
interface Comment {
|
|
198
|
-
id: string;
|
|
199
|
-
author?: string;
|
|
200
|
-
text: string;
|
|
201
|
-
createdAt: string;
|
|
202
|
-
}
|
|
31
|
+
```bash
|
|
32
|
+
npx hale-commenting-system init
|
|
203
33
|
```
|
|
204
34
|
|
|
205
|
-
## Browser Compatibility
|
|
206
|
-
|
|
207
|
-
Works in all modern browsers that support:
|
|
208
|
-
- localStorage
|
|
209
|
-
- React 18+
|
|
210
|
-
- ES2020+
|
|
211
|
-
|
|
212
|
-
## Roadmap
|
|
213
|
-
|
|
214
|
-
This is the MVP (local-only) version. Future enhancements:
|
|
215
|
-
- [ ] Backend sync (GitHub Issues, GitLab, custom)
|
|
216
|
-
- [ ] OAuth authentication
|
|
217
|
-
- [ ] Real-time collaboration
|
|
218
|
-
- [ ] Export/import comments
|
|
219
|
-
- [ ] Comment notifications
|
|
220
|
-
- [ ] Rich text editing
|
|
221
|
-
- [ ] File attachments
|
|
222
|
-
|
|
223
35
|
## License
|
|
224
36
|
|
|
225
37
|
MIT
|
|
226
38
|
|
|
227
|
-
## Author
|
|
228
|
-
|
|
229
|
-
Justin Hale
|
package/bin/detect.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function detectPatternFlySeed(): boolean;
|
package/bin/detect.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.detectPatternFlySeed = detectPatternFlySeed;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
function detectPatternFlySeed() {
|
|
40
|
+
const cwd = process.cwd();
|
|
41
|
+
// Check for webpack config files
|
|
42
|
+
const hasWebpack = fs.existsSync(path.join(cwd, 'webpack.config.js')) ||
|
|
43
|
+
fs.existsSync(path.join(cwd, 'webpack.dev.js')) ||
|
|
44
|
+
fs.existsSync(path.join(cwd, 'webpack.common.js'));
|
|
45
|
+
// Check for src/app directory
|
|
46
|
+
const hasAppDir = fs.existsSync(path.join(cwd, 'src', 'app'));
|
|
47
|
+
// Check for PatternFly dependencies in package.json
|
|
48
|
+
let hasPatternFly = false;
|
|
49
|
+
try {
|
|
50
|
+
const packageJsonPath = path.join(cwd, 'package.json');
|
|
51
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
52
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
53
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
54
|
+
hasPatternFly = !!(deps['@patternfly/react-core'] ||
|
|
55
|
+
deps['@patternfly/react-icons']);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Ignore errors
|
|
60
|
+
}
|
|
61
|
+
return hasWebpack && hasAppDir && hasPatternFly;
|
|
62
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface GitHubConfig {
|
|
2
|
+
clientId: string;
|
|
3
|
+
clientSecret: string;
|
|
4
|
+
owner: string;
|
|
5
|
+
repo: string;
|
|
6
|
+
}
|
|
7
|
+
interface JiraConfig {
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
apiToken: string;
|
|
10
|
+
email?: string;
|
|
11
|
+
}
|
|
12
|
+
interface Config {
|
|
13
|
+
github: GitHubConfig;
|
|
14
|
+
jira: JiraConfig;
|
|
15
|
+
}
|
|
16
|
+
export declare function generateFiles(config: Config): Promise<void>;
|
|
17
|
+
export declare function integrateIntoProject(): Promise<void>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.generateFiles = generateFiles;
|
|
37
|
+
exports.integrateIntoProject = integrateIntoProject;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
async function generateFiles(config) {
|
|
41
|
+
const cwd = process.cwd();
|
|
42
|
+
// Generate .env file (client-safe)
|
|
43
|
+
const envPath = path.join(cwd, '.env');
|
|
44
|
+
const envContent = `# GitHub OAuth (client-side; safe to expose)
|
|
45
|
+
VITE_GITHUB_CLIENT_ID=${config.github.clientId}
|
|
46
|
+
|
|
47
|
+
# Target repo for Issues/Comments
|
|
48
|
+
VITE_GITHUB_OWNER=${config.github.owner}
|
|
49
|
+
VITE_GITHUB_REPO=${config.github.repo}
|
|
50
|
+
|
|
51
|
+
# Jira Base URL
|
|
52
|
+
VITE_JIRA_BASE_URL=${config.jira.baseUrl}
|
|
53
|
+
`;
|
|
54
|
+
// Check if .env exists and append or create
|
|
55
|
+
if (fs.existsSync(envPath)) {
|
|
56
|
+
const existing = fs.readFileSync(envPath, 'utf-8');
|
|
57
|
+
// Only add if not already present
|
|
58
|
+
if (!existing.includes('VITE_GITHUB_CLIENT_ID')) {
|
|
59
|
+
fs.appendFileSync(envPath, '\n' + envContent);
|
|
60
|
+
console.log(' ✅ Updated .env file');
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
console.log(' ⚠️ .env already contains commenting system config');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
fs.writeFileSync(envPath, envContent);
|
|
68
|
+
console.log(' ✅ Created .env file');
|
|
69
|
+
}
|
|
70
|
+
// Generate .env.server file (secrets)
|
|
71
|
+
const envServerPath = path.join(cwd, '.env.server');
|
|
72
|
+
let envServerContent = `# GitHub OAuth Client Secret (server-only)
|
|
73
|
+
GITHUB_CLIENT_SECRET=${config.github.clientSecret}
|
|
74
|
+
|
|
75
|
+
# Jira API Token (server-only)
|
|
76
|
+
JIRA_API_TOKEN=${config.jira.apiToken}
|
|
77
|
+
`;
|
|
78
|
+
if (config.jira.email) {
|
|
79
|
+
envServerContent += `JIRA_EMAIL=${config.jira.email}\n`;
|
|
80
|
+
}
|
|
81
|
+
if (fs.existsSync(envServerPath)) {
|
|
82
|
+
const existing = fs.readFileSync(envServerPath, 'utf-8');
|
|
83
|
+
if (!existing.includes('GITHUB_CLIENT_SECRET')) {
|
|
84
|
+
fs.appendFileSync(envServerPath, '\n' + envServerContent);
|
|
85
|
+
console.log(' ✅ Updated .env.server file');
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
console.log(' ⚠️ .env.server already contains commenting system config');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
fs.writeFileSync(envServerPath, envServerContent);
|
|
93
|
+
console.log(' ✅ Created .env.server file');
|
|
94
|
+
}
|
|
95
|
+
// Ensure .env.server is in .gitignore
|
|
96
|
+
const gitignorePath = path.join(cwd, '.gitignore');
|
|
97
|
+
if (fs.existsSync(gitignorePath)) {
|
|
98
|
+
const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
|
|
99
|
+
if (!gitignore.includes('.env.server')) {
|
|
100
|
+
fs.appendFileSync(gitignorePath, '\n.env.server\n');
|
|
101
|
+
console.log(' ✅ Added .env.server to .gitignore');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
fs.writeFileSync(gitignorePath, '.env.server\n');
|
|
106
|
+
console.log(' ✅ Created .gitignore with .env.server');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function integrateIntoProject() {
|
|
110
|
+
const cwd = process.cwd();
|
|
111
|
+
const webpackDevPath = path.join(cwd, 'webpack.dev.js');
|
|
112
|
+
if (!fs.existsSync(webpackDevPath)) {
|
|
113
|
+
console.error(' ❌ webpack.dev.js not found. Cannot auto-integrate.');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// Read webpack.dev.js
|
|
117
|
+
let webpackContent = fs.readFileSync(webpackDevPath, 'utf-8');
|
|
118
|
+
// Check if already integrated
|
|
119
|
+
if (webpackContent.includes('/api/github-oauth-callback') || webpackContent.includes('/api/jira-issue')) {
|
|
120
|
+
console.log(' ⚠️ webpack.dev.js already appears to have commenting system integration');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
// Read the template
|
|
124
|
+
// In compiled output, templates will be in the package root
|
|
125
|
+
const packageRoot = path.resolve(__dirname, '../../..');
|
|
126
|
+
const templatePath = path.join(packageRoot, 'templates', 'webpack-middleware.js');
|
|
127
|
+
if (!fs.existsSync(templatePath)) {
|
|
128
|
+
console.log(' ⚠️ Template file not found. Manual integration required.');
|
|
129
|
+
console.log(' See README for webpack.dev.js integration instructions.\n');
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const templateContent = fs.readFileSync(templatePath, 'utf-8');
|
|
133
|
+
// Find the setupMiddlewares function and inject our code
|
|
134
|
+
// Look for: setupMiddlewares: (middlewares, devServer) => {
|
|
135
|
+
const setupMiddlewaresRegex = /(setupMiddlewares\s*:\s*\([^)]+\)\s*=>\s*\{)/;
|
|
136
|
+
const match = webpackContent.match(setupMiddlewaresRegex);
|
|
137
|
+
if (!match) {
|
|
138
|
+
console.log(' ⚠️ Could not find setupMiddlewares in webpack.dev.js');
|
|
139
|
+
console.log(' 📋 Manual integration required. See templates/webpack-middleware.js\n');
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
// Find where to inject (after express.json() setup, before return middlewares)
|
|
143
|
+
const expressJsonMatch = webpackContent.match(/devServer\.app\.use\(express\.json\(\)\);/);
|
|
144
|
+
if (expressJsonMatch) {
|
|
145
|
+
// Inject after express.json()
|
|
146
|
+
const insertIndex = expressJsonMatch.index + expressJsonMatch[0].length;
|
|
147
|
+
const before = webpackContent.substring(0, insertIndex);
|
|
148
|
+
const after = webpackContent.substring(insertIndex);
|
|
149
|
+
// Extract just the middleware code from template (skip comments)
|
|
150
|
+
const middlewareCode = templateContent
|
|
151
|
+
.replace(/^\/\/.*$/gm, '') // Remove comment lines
|
|
152
|
+
.trim()
|
|
153
|
+
.split('\n')
|
|
154
|
+
.filter(line => line.trim() && !line.trim().startsWith('//'))
|
|
155
|
+
.join('\n');
|
|
156
|
+
webpackContent = before + '\n\n' + middlewareCode + '\n' + after;
|
|
157
|
+
fs.writeFileSync(webpackDevPath, webpackContent);
|
|
158
|
+
console.log(' ✅ Updated webpack.dev.js with server middleware');
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
// Try to inject at the beginning of setupMiddlewares
|
|
162
|
+
const insertIndex = match.index + match[0].length;
|
|
163
|
+
const before = webpackContent.substring(0, insertIndex);
|
|
164
|
+
const after = webpackContent.substring(insertIndex);
|
|
165
|
+
// Add dotenv loading and express setup if not present
|
|
166
|
+
let middlewareCode = templateContent.trim();
|
|
167
|
+
// Check if dotenv is already loaded
|
|
168
|
+
if (!webpackContent.includes('dotenv.config')) {
|
|
169
|
+
middlewareCode = `// Load env vars for local OAuth/token exchange
|
|
170
|
+
try {
|
|
171
|
+
const dotenv = require('dotenv');
|
|
172
|
+
dotenv.config({ path: path.resolve(__dirname, '.env') });
|
|
173
|
+
dotenv.config({ path: path.resolve(__dirname, '.env.server'), override: true });
|
|
174
|
+
} catch (e) {
|
|
175
|
+
// no-op
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const express = require('express');
|
|
179
|
+
devServer.app.use(express.json());
|
|
180
|
+
|
|
181
|
+
` + middlewareCode;
|
|
182
|
+
}
|
|
183
|
+
else if (!webpackContent.includes('express.json()')) {
|
|
184
|
+
middlewareCode = `const express = require('express');
|
|
185
|
+
devServer.app.use(express.json());
|
|
186
|
+
|
|
187
|
+
` + middlewareCode;
|
|
188
|
+
}
|
|
189
|
+
webpackContent = before + '\n\n' + middlewareCode + '\n' + after;
|
|
190
|
+
fs.writeFileSync(webpackDevPath, webpackContent);
|
|
191
|
+
console.log(' ✅ Updated webpack.dev.js with server middleware');
|
|
192
|
+
}
|
|
193
|
+
}
|
package/bin/index.d.ts
ADDED
package/bin/index.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
const detect = __importStar(require("./detect"));
|
|
38
|
+
const onboarding = __importStar(require("./onboarding"));
|
|
39
|
+
const args = process.argv.slice(2);
|
|
40
|
+
const command = args[0] || 'init';
|
|
41
|
+
async function main() {
|
|
42
|
+
if (command === 'init') {
|
|
43
|
+
// Check if we're in a PatternFly Seed project
|
|
44
|
+
const isPFSeed = detect.detectPatternFlySeed();
|
|
45
|
+
if (!isPFSeed) {
|
|
46
|
+
console.error('❌ Error: This package is designed for PatternFly Seed projects.');
|
|
47
|
+
console.error('Please run this command from a PatternFly Seed project directory.');
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
console.log('🚀 Hale Commenting System - Onboarding\n');
|
|
51
|
+
await onboarding.runOnboarding();
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
console.log('Usage: hale-commenting-system [init]');
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
main().catch((error) => {
|
|
59
|
+
console.error('❌ Error:', error.message);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runOnboarding(): Promise<void>;
|