@salesforcedevs/docs-components 1.17.0-hack-alpha5 → 1.17.0-hack-alpha6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/docs-components",
3
- "version": "1.17.0-hack-alpha5",
3
+ "version": "1.17.0-hack-alpha6",
4
4
  "description": "Docs Lightning web components for DSC",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
@@ -1,71 +1,178 @@
1
- # Comment Popup Component - Local Storage Implementation
1
+ # Comment Popup Component
2
2
 
3
- This component provides a commenting system that uses browser localStorage for data persistence while the backend API is being developed.
3
+ A Lightning Web Component that allows users to leave comments on documentation sections. The component supports both local storage (for development) and a new API format for production use.
4
4
 
5
5
  ## Features
6
6
 
7
- - ✅ **Local Storage**: Comments are stored in browser localStorage
8
- - ✅ **API-Ready**: Code structure prepared for backend integration
9
- - ✅ **Development Tools**: Helper utilities for managing comments
10
- - ✅ **Export/Import**: Ability to export comments to JSON files
11
- - ✅ **Migration Ready**: Tools to convert data for backend migration
7
+ - ✅ **New API Format**: Supports branch-based comment fetching
8
+ - ✅ **Pre-loaded Comments**: Comments are fetched when component is rendered, not when popup opens
9
+ - ✅ **Local Storage**: Comments persist across page refreshes during development
10
+ - ✅ **Form Validation**: Email format and required field validation
11
+ - ✅ **Real-time Display**: Comments appear immediately after posting
12
+ - ✅ **Timestamp Formatting**: Shows relative time (e.g., "2 hours ago")
13
+ - ✅ **Email Masking**: Protects user privacy in comment display
14
+ - ✅ **Comment Count Badge**: Shows total number of comments
15
+ - ✅ **Responsive Design**: Works on mobile and desktop
16
+ - ✅ **Keyboard Accessibility**: ESC key to close popup
17
+ - ✅ **Dark Mode Support**: Adapts to system preferences
18
+ - ✅ **Development Tools**: Helper utilities for testing
12
19
 
13
- ## How It Works
20
+ ## API Format
14
21
 
15
- ### Storage Structure
22
+ The component now supports a new API format where comments are fetched by branch and then filtered by file path and heading title.
16
23
 
17
- Comments are stored in localStorage under the key `dsc_comments` with the following structure:
24
+ ### API Endpoints
25
+
26
+ - **GET** `/get-comments?branch={branch}` - Fetch all comments for a branch
27
+ - **POST** `/post-comment` - Add a new comment
28
+
29
+ ### API Response Format
18
30
 
19
31
  ```json
20
32
  {
21
- "branch_filepath_headingtitle": [
33
+ "request_branch": "feature/documentation-updates",
34
+ "paths": [
22
35
  {
23
- "email": "user@example.com",
24
- "comment_text": "This is a comment",
25
- "timestamp": "2024-01-15T10:30:00Z"
36
+ "path": "docs/installation.md",
37
+ "titles": [
38
+ {
39
+ "title": "Installation Guide",
40
+ "comments": [
41
+ {
42
+ "email": "john.doe@example.com",
43
+ "comment_text": "This installation guide is very helpful for new users.",
44
+ "timestamp": "2024-01-15T10:30:00Z"
45
+ }
46
+ ]
47
+ }
48
+ ]
26
49
  }
27
50
  ]
28
51
  }
29
52
  ```
30
53
 
31
- ### API Payload Format
32
-
33
- When posting comments, the component uses this exact format (ready for backend):
54
+ ### API Request Format
34
55
 
35
56
  ```json
36
57
  {
37
58
  "branch": "feature/documentation-updates",
38
59
  "file_path": "docs/installation.md",
39
60
  "heading_title": "Installation Guide",
61
+ "start_line": "1",
62
+ "end_line": "50",
40
63
  "comment": {
41
- "comment_text": "This installation guide is very helpful for new users.",
42
- "email": "john.doe@example.com",
64
+ "comment_text": "This is a helpful comment.",
65
+ "email": "user@example.com",
43
66
  "timestamp": "2024-01-15T10:30:00Z"
44
67
  }
45
68
  }
46
69
  ```
47
70
 
71
+ ## Usage
72
+
73
+ ### Basic Usage
74
+
75
+ ```html
76
+ <sb-doc-comment-popup
77
+ heading-title="Installation Guide"
78
+ file-path="docs/installation.md"
79
+ current-branch="feature/documentation-updates"
80
+ start-line="1"
81
+ end-line="50"
82
+ open="false"
83
+ icon-symbol="chat"
84
+ icon-size="medium"
85
+ >
86
+ </sb-doc-comment-popup>
87
+ ```
88
+
89
+ ### Comment Loading Behavior
90
+
91
+ The component now fetches comments when it is rendered (connected to the DOM) rather than when the popup is opened. This ensures:
92
+
93
+ - **Faster Popup Opening**: Comments are already loaded when the user clicks the icon
94
+ - **Immediate Comment Count**: The comment count badge shows the correct number immediately
95
+ - **Better User Experience**: No loading delay when opening the popup
96
+
97
+ Comments are automatically refetched when any of these properties change:
98
+
99
+ - `heading-title`
100
+ - `file-path`
101
+ - `current-branch`
102
+
103
+ ### Required Properties
104
+
105
+ - `heading-title`: The title of the section being commented on
106
+ - `file-path`: The file path where the comment is located
107
+ - `current-branch`: The current git branch
108
+
109
+ ### Optional Properties
110
+
111
+ - `start-line`: Starting line number (for future line-specific comments)
112
+ - `end-line`: Ending line number (for future line-specific comments)
113
+ - `open`: Controls the popup visibility (default: false)
114
+ - `icon-symbol`: Icon symbol for the comment button (default: "chat")
115
+ - `icon-size`: Size of the comment icon (default: "medium")
116
+
117
+ ### Available Icon Symbols
118
+
119
+ - `chat` - Chat bubble icon
120
+ - `comment` - Comment icon
121
+ - `message` - Message icon
122
+ - `feedback` - Feedback icon
123
+
124
+ ### Available Icon Sizes
125
+
126
+ - `small` - Small icon
127
+ - `medium` - Medium icon (default)
128
+ - `large` - Large icon
129
+
130
+ ## Local Storage Implementation
131
+
132
+ During development, the component uses localStorage to persist comments. Comments are stored with a unique key format:
133
+
134
+ ```
135
+ {branch}_{file_path}_{heading_title}
136
+ ```
137
+
138
+ ### Local Storage Structure
139
+
140
+ ```json
141
+ {
142
+ "main_docs/installation.md_Installation Guide": [
143
+ {
144
+ "email": "user@example.com",
145
+ "comment_text": "This is a comment",
146
+ "timestamp": "2024-01-15T10:30:00Z"
147
+ }
148
+ ]
149
+ }
150
+ ```
151
+
48
152
  ## Development Tools
49
153
 
50
- ### Console Commands
154
+ The component includes development tools for testing and managing comments during development.
51
155
 
52
- When the component is loaded, you can access these functions in the browser console:
156
+ ### Console Commands
53
157
 
54
158
  ```javascript
55
159
  // Export all comments to a JSON file
56
160
  CommentDevHelper.exportCommentsToFile();
57
161
 
58
- // Clear all comments from localStorage
59
- CommentDevHelper.clearAllComments();
162
+ // Add sample comments matching the new API format
163
+ CommentDevHelper.addSampleCommentsForNewApi();
60
164
 
61
165
  // Get statistics about stored comments
62
166
  CommentDevHelper.getCommentsStats();
63
167
 
64
- // Convert comments to API format (for backend migration)
65
- CommentDevHelper.convertToApiFormat();
168
+ // Clear all comments from localStorage
169
+ CommentDevHelper.clearAllComments();
170
+
171
+ // Test the API response format
172
+ CommentDevHelper.testApiResponseFormat();
66
173
 
67
- // Add a sample comment for testing
68
- CommentDevHelper.addSampleComment();
174
+ // Simulate API call for a specific branch
175
+ CommentDevHelper.simulateApiCall("main");
69
176
 
70
177
  // Show all comments in console
71
178
  CommentDevHelper.showAllComments();
@@ -73,140 +180,115 @@ CommentDevHelper.showAllComments();
73
180
 
74
181
  ### Development UI
75
182
 
76
- In development mode (localhost), a floating UI will appear in the top-right corner with buttons to:
77
-
78
- - Export comments
79
- - Clear all comments
80
- - View statistics
81
- - Show API format
82
-
83
- ## Migration to Backend
183
+ The component automatically creates a development UI when running on localhost. This UI provides buttons for:
84
184
 
85
- When the backend is ready, follow these steps:
86
-
87
- ### 1. Export Current Comments
88
-
89
- ```javascript
90
- // Export all comments to JSON file
91
- CommentDevHelper.exportCommentsToFile();
92
- ```
185
+ - Adding sample comments
186
+ - Testing API response format
187
+ - Exporting comments
188
+ - Clearing all comments
189
+ - Viewing statistics
93
190
 
94
- ### 2. Convert to API Format
191
+ ## Migration to Backend API
95
192
 
96
- ```javascript
97
- // Get comments in API format
98
- const apiFormat = CommentDevHelper.convertToApiFormat();
99
- console.log(apiFormat);
100
- ```
193
+ When the backend API is ready, follow these steps to migrate from localStorage:
101
194
 
102
- ### 3. Uncomment API Code
195
+ 1. **Uncomment API calls**: In `commentPopup.ts`, uncomment the API implementation sections
196
+ 2. **Comment localStorage calls**: Comment out the localStorage implementation sections
197
+ 3. **Update API endpoints**: Ensure the API endpoints match your backend
198
+ 4. **Test API integration**: Use the development tools to test API calls
103
199
 
104
- In `commentPopup.ts`, uncomment the API implementation sections:
200
+ ### Example Migration
105
201
 
106
202
  ```typescript
107
- // Remove the localStorage implementation and uncomment:
108
- /*
109
- const response = await fetch('/post-comment', {
110
- method: 'POST',
203
+ // Before (localStorage)
204
+ await this.saveCommentToLocalStorage(payload);
205
+
206
+ // After (API)
207
+ const response = await fetch("/post-comment", {
208
+ method: "POST",
111
209
  headers: {
112
- 'Content-Type': 'application/json'
210
+ "Content-Type": "application/json"
113
211
  },
114
212
  body: JSON.stringify(payload)
115
213
  });
116
- */
117
214
  ```
118
215
 
119
- ### 4. Update Endpoints
216
+ ## Testing
120
217
 
121
- Update the API endpoints in the component:
218
+ ### Storybook Stories
122
219
 
123
- - POST: `/post-comment` (for adding comments)
124
- - GET: `/api/comments` (for fetching comments)
220
+ The component includes comprehensive Storybook stories for testing:
125
221
 
126
- ## File Structure
222
+ 1. **Base**: Basic component functionality
223
+ 2. **WithNewApiFormatComments**: Testing with new API format
224
+ 3. **MultipleBranchesAndFiles**: Testing multiple branches and files
225
+ 4. **FormValidation**: Testing form validation features
127
226
 
128
- ```
129
- commentPopup/
130
- ├── commentPopup.ts # Main component
131
- ├── commentPopup.html # Template
132
- ├── commentPopup.css # Styles
133
- ├── commentUtils.ts # Utility functions
134
- ├── commentDevHelper.ts # Development tools
135
- └── README.md # This file
136
- ```
137
-
138
- ## Usage
227
+ ### Jest Tests
139
228
 
140
- ### Basic Usage
229
+ Run the test suite:
141
230
 
142
- ```html
143
- <c-comment-popup
144
- heading-title="Installation Guide"
145
- file-path="docs/installation.md"
146
- current-branch="main"
147
- >
148
- </c-comment-popup>
231
+ ```bash
232
+ npm test commentPopup.test.ts
149
233
  ```
150
234
 
151
- ### Required Properties
235
+ The test suite covers:
152
236
 
153
- - `heading-title`: The title of the section being commented on
154
- - `file-path`: The file path where the comment is located
155
- - `current-branch`: The current git branch
237
+ - Component initialization
238
+ - Form validation
239
+ - Local storage operations
240
+ - API response format handling
241
+ - Comment operations
242
+ - UI interactions
243
+ - Error handling
244
+ - Lifecycle methods
156
245
 
157
- ### Optional Properties
246
+ ## Troubleshooting
158
247
 
159
- - `start-line`: Starting line number (for future line-specific comments)
160
- - `end-line`: Ending line number (for future line-specific comments)
161
- - `open`: Boolean to control popup visibility
248
+ ### Common Issues
162
249
 
163
- ## Events
250
+ 1. **Comments not appearing**: Check that `heading-title`, `file-path`, and `current-branch` are set correctly
251
+ 2. **Form validation errors**: Ensure email format is valid and all required fields are filled
252
+ 3. **localStorage errors**: Check browser console for localStorage quota exceeded errors
253
+ 4. **API integration issues**: Verify API endpoints and response format match expected structure
164
254
 
165
- The component dispatches these events:
255
+ ### Debug Commands
166
256
 
167
257
  ```javascript
168
- // When a comment is added
169
- element.addEventListener("commentadded", (event) => {
170
- console.log("New comment:", event.detail);
171
- });
172
- ```
258
+ // Check current comments
259
+ console.log(CommentDevHelper.getAllComments());
173
260
 
174
- ## Browser Compatibility
261
+ // Check component state
262
+ console.log(element.comments);
263
+ console.log(element.email);
264
+ console.log(element.comment);
175
265
 
176
- - Modern browsers with localStorage support
177
- - IE10+ (with polyfills if needed)
178
-
179
- ## Storage Limits
180
-
181
- - localStorage typically has a 5-10MB limit
182
- - Comments are stored as JSON strings
183
- - Monitor storage usage with `CommentDevHelper.getCommentsStats()`
184
-
185
- ## Troubleshooting
266
+ // Test API response parsing
267
+ CommentDevHelper.testApiResponseFormat();
268
+ ```
186
269
 
187
- ### Comments Not Appearing
270
+ ## Browser Support
188
271
 
189
- 1. Check browser console for errors
190
- 2. Verify localStorage is enabled
191
- 3. Check if the comment key matches: `branch_filepath_headingtitle`
272
+ - Chrome 60+
273
+ - Firefox 55+
274
+ - Safari 12+
275
+ - Edge 79+
192
276
 
193
- ### Storage Issues
277
+ ## Dependencies
194
278
 
195
- 1. Clear localStorage: `CommentDevHelper.clearAllComments()`
196
- 2. Export existing comments before clearing
197
- 3. Check browser storage limits
279
+ - Lightning Web Components (LWC)
280
+ - TypeScript
281
+ - Jest (for testing)
198
282
 
199
- ### Development UI Not Showing
283
+ ## Contributing
200
284
 
201
- 1. Ensure you're on localhost
202
- 2. Check if the UI was manually closed
203
- 3. Refresh the page to recreate the UI
285
+ 1. Fork the repository
286
+ 2. Create a feature branch
287
+ 3. Make your changes
288
+ 4. Add tests for new functionality
289
+ 5. Update documentation
290
+ 6. Submit a pull request
204
291
 
205
- ## Future Enhancements
292
+ ## License
206
293
 
207
- - [ ] Line-specific comments
208
- - [ ] Comment threading/replies
209
- - [ ] Comment moderation
210
- - [ ] User authentication integration
211
- - [ ] Real-time comment updates
212
- - [ ] Comment search and filtering
294
+ This component is part of the Salesforce Developer Documentation Components package.
@@ -9,7 +9,10 @@ import {
9
9
  clearAllComments,
10
10
  getCommentsStats,
11
11
  convertToApiFormat,
12
- addComment
12
+ addComment,
13
+ getCommentsForBranch,
14
+ fetchCommentsForBranch,
15
+ extractCommentsFromApiResponse
13
16
  } from "./commentUtils";
14
17
 
15
18
  // Make functions available globally for console access
@@ -21,7 +24,10 @@ if (typeof window !== "undefined") {
21
24
  clearAllComments,
22
25
  getCommentsStats,
23
26
  convertToApiFormat,
24
- addComment
27
+ addComment,
28
+ getCommentsForBranch,
29
+ fetchCommentsForBranch,
30
+ extractCommentsFromApiResponse
25
31
  };
26
32
  }
27
33
 
@@ -44,7 +50,7 @@ export function createDevUI(): void {
44
50
  position: fixed;
45
51
  top: 20px;
46
52
  right: 20px;
47
- width: 300px;
53
+ width: 350px;
48
54
  background: white;
49
55
  border: 2px solid #007bff;
50
56
  border-radius: 8px;
@@ -53,6 +59,8 @@ export function createDevUI(): void {
53
59
  font-size: 14px;
54
60
  z-index: 10000;
55
61
  box-shadow: 0 4px 12px rgba(0,0,0,0.15);
62
+ max-height: 80vh;
63
+ overflow-y: auto;
56
64
  `;
57
65
 
58
66
  const stats = getCommentsStats();
@@ -65,6 +73,7 @@ export function createDevUI(): void {
65
73
 
66
74
  <div style="margin-bottom: 12px;">
67
75
  <strong>Stats:</strong><br>
76
+ Branches: ${stats.branches.length}<br>
68
77
  Locations: ${stats.totalLocations}<br>
69
78
  Total Comments: ${stats.totalComments}
70
79
  </div>
@@ -85,6 +94,14 @@ export function createDevUI(): void {
85
94
  <button onclick="console.log(CommentDevHelper.convertToApiFormat())" style="padding: 8px; background: #6f42c1; color: white; border: none; border-radius: 4px; cursor: pointer;">
86
95
  Show API Format in Console
87
96
  </button>
97
+
98
+ <button onclick="CommentDevHelper.addSampleCommentsForNewApi()" style="padding: 8px; background: #fd7e14; color: white; border: none; border-radius: 4px; cursor: pointer;">
99
+ Add Sample Comments (New API Format)
100
+ </button>
101
+
102
+ <button onclick="CommentDevHelper.testApiResponseFormat()" style="padding: 8px; background: #20c997; color: white; border: none; border-radius: 4px; cursor: pointer;">
103
+ Test API Response Format
104
+ </button>
88
105
  </div>
89
106
 
90
107
  <div style="margin-top: 12px; font-size: 12px; color: #666;">
@@ -92,7 +109,9 @@ export function createDevUI(): void {
92
109
  CommentDevHelper.exportCommentsToFile()<br>
93
110
  CommentDevHelper.clearAllComments()<br>
94
111
  CommentDevHelper.getCommentsStats()<br>
95
- CommentDevHelper.convertToApiFormat()
112
+ CommentDevHelper.convertToApiFormat()<br>
113
+ CommentDevHelper.getCommentsForBranch('main')<br>
114
+ CommentDevHelper.testApiResponseFormat()
96
115
  </div>
97
116
  `;
98
117
 
@@ -110,24 +129,134 @@ export function removeDevUI(): void {
110
129
  }
111
130
 
112
131
  /**
113
- * Add a sample comment for testing
132
+ * Add sample comments that match the new API format
114
133
  */
115
- export function addSampleComment(): void {
116
- const samplePayload = {
117
- branch: "feature/documentation-updates",
118
- file_path: "docs/installation.md",
119
- heading_title: "Installation Guide",
120
- start_line: "10",
121
- end_line: "25",
122
- comment: {
123
- comment_text: "This is a sample comment for testing purposes.",
124
- email: "test@example.com",
125
- timestamp: new Date().toISOString()
134
+ export function addSampleCommentsForNewApi(): void {
135
+ const sampleComments = [
136
+ {
137
+ branch: "feature/documentation-updates",
138
+ file_path: "docs/installation.md",
139
+ heading_title: "Installation Guide",
140
+ start_line: "1",
141
+ end_line: "50",
142
+ comment: {
143
+ comment_text:
144
+ "This installation guide is very helpful for new users.",
145
+ email: "john.doe@example.com",
146
+ timestamp: new Date(Date.now() - 3600000).toISOString() // 1 hour ago
147
+ }
148
+ },
149
+ {
150
+ branch: "feature/documentation-updates",
151
+ file_path: "docs/installation.md",
152
+ heading_title: "Installation Guide",
153
+ start_line: "1",
154
+ end_line: "50",
155
+ comment: {
156
+ comment_text:
157
+ "Consider adding troubleshooting section for common issues.",
158
+ email: "jane.smith@example.com",
159
+ timestamp: new Date(Date.now() - 1800000).toISOString() // 30 minutes ago
160
+ }
161
+ },
162
+ {
163
+ branch: "feature/documentation-updates",
164
+ file_path: "docs/installation.md",
165
+ heading_title: "Prerequisites",
166
+ start_line: "10",
167
+ end_line: "25",
168
+ comment: {
169
+ comment_text:
170
+ "The prerequisites section is clear and well-organized.",
171
+ email: "mike.wilson@example.com",
172
+ timestamp: new Date(Date.now() - 900000).toISOString() // 15 minutes ago
173
+ }
174
+ },
175
+ {
176
+ branch: "feature/documentation-updates",
177
+ file_path: "docs/api.md",
178
+ heading_title: "API Reference",
179
+ start_line: "1",
180
+ end_line: "100",
181
+ comment: {
182
+ comment_text:
183
+ "The API documentation needs more examples for authentication.",
184
+ email: "sarah.jones@example.com",
185
+ timestamp: new Date(Date.now() - 600000).toISOString() // 10 minutes ago
186
+ }
187
+ },
188
+ {
189
+ branch: "feature/documentation-updates",
190
+ file_path: "docs/api.md",
191
+ heading_title: "API Reference",
192
+ start_line: "1",
193
+ end_line: "100",
194
+ comment: {
195
+ comment_text: "Great work on the endpoint descriptions!",
196
+ email: "david.brown@example.com",
197
+ timestamp: new Date().toISOString() // now
198
+ }
199
+ },
200
+ {
201
+ branch: "main",
202
+ file_path: "docs/getting-started.md",
203
+ heading_title: "Quick Start",
204
+ start_line: "1",
205
+ end_line: "30",
206
+ comment: {
207
+ comment_text:
208
+ "This quick start guide is perfect for beginners.",
209
+ email: "alice.johnson@example.com",
210
+ timestamp: new Date(Date.now() - 7200000).toISOString() // 2 hours ago
211
+ }
126
212
  }
127
- };
213
+ ];
214
+
215
+ sampleComments.forEach((comment) => {
216
+ addComment(comment);
217
+ });
128
218
 
129
- addComment(samplePayload);
130
- console.log("Sample comment added:", samplePayload);
219
+ console.log("Added sample comments for new API format");
220
+ console.log("Sample data includes multiple branches, files, and titles");
221
+
222
+ // Refresh the page to show the new comments
223
+ setTimeout(() => {
224
+ window.location.reload();
225
+ }, 1000);
226
+ }
227
+
228
+ /**
229
+ * Test the API response format
230
+ */
231
+ export function testApiResponseFormat(): void {
232
+ console.log("=== Testing API Response Format ===");
233
+
234
+ // Test with feature/documentation-updates branch
235
+ const featureBranchResponse = getCommentsForBranch(
236
+ "feature/documentation-updates"
237
+ );
238
+ console.log("Feature branch response:", featureBranchResponse);
239
+
240
+ // Test with main branch
241
+ const mainBranchResponse = getCommentsForBranch("main");
242
+ console.log("Main branch response:", mainBranchResponse);
243
+
244
+ // Test extracting specific comments
245
+ const installationComments = extractCommentsFromApiResponse(
246
+ featureBranchResponse,
247
+ "docs/installation.md",
248
+ "Installation Guide"
249
+ );
250
+ console.log("Installation Guide comments:", installationComments);
251
+
252
+ const apiComments = extractCommentsFromApiResponse(
253
+ featureBranchResponse,
254
+ "docs/api.md",
255
+ "API Reference"
256
+ );
257
+ console.log("API Reference comments:", apiComments);
258
+
259
+ console.log("=== API Response Format Test Complete ===");
131
260
  }
132
261
 
133
262
  /**
@@ -141,6 +270,46 @@ export function showAllComments(): void {
141
270
  const stats = getCommentsStats();
142
271
  console.log("=== STATISTICS ===");
143
272
  console.table(stats.locations);
273
+
274
+ console.log("=== BRANCHES ===");
275
+ console.log("Available branches:", stats.branches);
276
+ }
277
+
278
+ /**
279
+ * Simulate API call and show response
280
+ */
281
+ export async function simulateApiCall(
282
+ branch: string = "feature/documentation-updates"
283
+ ): Promise<void> {
284
+ console.log(`=== Simulating API Call for branch: ${branch} ===`);
285
+
286
+ try {
287
+ const response = await fetchCommentsForBranch(branch);
288
+ console.log("API Response:", response);
289
+
290
+ // Show all paths and titles
291
+ response.paths.forEach((path) => {
292
+ console.log(`File: ${path.path}`);
293
+ path.titles.forEach((title) => {
294
+ console.log(
295
+ ` Title: ${title.title} (${title.comments.length} comments)`
296
+ );
297
+ });
298
+ });
299
+ } catch (error) {
300
+ console.error("API call simulation failed:", error);
301
+ }
302
+ }
303
+
304
+ // Add the helper functions to the global CommentDevHelper
305
+ if (typeof window !== "undefined") {
306
+ (window as any).CommentDevHelper = {
307
+ ...(window as any).CommentDevHelper,
308
+ addSampleCommentsForNewApi,
309
+ testApiResponseFormat,
310
+ showAllComments,
311
+ simulateApiCall
312
+ };
144
313
  }
145
314
 
146
315
  // Auto-create UI when this module is imported (in development)
@@ -20,6 +20,17 @@ interface ApiCommentPayload {
20
20
  };
21
21
  }
22
22
 
23
+ interface ApiCommentResponse {
24
+ request_branch: string;
25
+ paths: Array<{
26
+ path: string;
27
+ titles: Array<{
28
+ title: string;
29
+ comments: Comment[];
30
+ }>;
31
+ }>;
32
+ }
33
+
23
34
  // Local storage key for comments
24
35
  const COMMENTS_STORAGE_KEY = "dsc_comments";
25
36
 
@@ -31,11 +42,49 @@ export default class CommentPopup extends LightningElement {
31
42
  emailPlaceholder = "Enter your email";
32
43
  commentPlaceholder = "Enter your comment";
33
44
 
34
- @api headingTitle?: string;
35
- @api filePath?: string;
36
- @api startLine?: string;
37
- @api endLine?: string;
38
- @api currentBranch?: string;
45
+ private _headingTitle?: string;
46
+ private _filePath?: string;
47
+ private _startLine?: string;
48
+ private _endLine?: string;
49
+ private _currentBranch?: string;
50
+
51
+ @api get headingTitle() {
52
+ return this._headingTitle;
53
+ }
54
+ set headingTitle(value) {
55
+ this._headingTitle = value;
56
+ this.handlePropertyChange();
57
+ }
58
+
59
+ @api get filePath() {
60
+ return this._filePath;
61
+ }
62
+ set filePath(value) {
63
+ this._filePath = value;
64
+ this.handlePropertyChange();
65
+ }
66
+
67
+ @api get startLine() {
68
+ return this._startLine;
69
+ }
70
+ set startLine(value) {
71
+ this._startLine = value;
72
+ }
73
+
74
+ @api get endLine() {
75
+ return this._endLine;
76
+ }
77
+ set endLine(value) {
78
+ this._endLine = value;
79
+ }
80
+
81
+ @api get currentBranch() {
82
+ return this._currentBranch;
83
+ }
84
+ set currentBranch(value) {
85
+ this._currentBranch = value;
86
+ this.handlePropertyChange();
87
+ }
39
88
 
40
89
  private _open = false;
41
90
  @api get open() {
@@ -85,7 +134,12 @@ export default class CommentPopup extends LightningElement {
85
134
 
86
135
  handleIconClick() {
87
136
  this._open = !this._open;
88
- if (this._open) {
137
+ // Comments are already loaded when component is connected, no need to fetch again
138
+ }
139
+
140
+ private handlePropertyChange() {
141
+ // Only fetch comments if component has required properties
142
+ if (this._currentBranch && this._filePath && this._headingTitle) {
89
143
  this.fetchComments();
90
144
  }
91
145
  }
@@ -156,18 +210,18 @@ export default class CommentPopup extends LightningElement {
156
210
 
157
211
  private async addComment() {
158
212
  // Validate required fields before creating payload
159
- if (!this.currentBranch || !this.filePath || !this.headingTitle) {
213
+ if (!this._currentBranch || !this._filePath || !this._headingTitle) {
160
214
  throw new Error(
161
215
  "Missing required fields: branch, file_path, or heading_title"
162
216
  );
163
217
  }
164
218
 
165
219
  const payload: ApiCommentPayload = {
166
- branch: this.currentBranch,
167
- file_path: this.filePath,
168
- heading_title: this.headingTitle,
169
- start_line: this.startLine!,
170
- end_line: this.endLine!,
220
+ branch: this._currentBranch,
221
+ file_path: this._filePath,
222
+ heading_title: this._headingTitle,
223
+ start_line: this._startLine || "",
224
+ end_line: this._endLine || "",
171
225
  comment: {
172
226
  comment_text: this.comment.trim(),
173
227
  email: this.email.trim(),
@@ -308,10 +362,12 @@ export default class CommentPopup extends LightningElement {
308
362
 
309
363
  connectedCallback() {
310
364
  document.addEventListener("keydown", this.handleKeyDown.bind(this));
365
+ // Fetch comments when component is connected
366
+ this.fetchComments();
311
367
  }
312
368
 
313
369
  private async fetchComments() {
314
- if (!this.currentBranch || !this.filePath || !this.headingTitle) {
370
+ if (!this._currentBranch || !this._filePath || !this._headingTitle) {
315
371
  console.warn("Cannot fetch comments: missing required parameters");
316
372
  return;
317
373
  }
@@ -328,30 +384,23 @@ export default class CommentPopup extends LightningElement {
328
384
  // API IMPLEMENTATION (Commented until backend is ready)
329
385
  /*
330
386
  const params = new URLSearchParams({
331
- branch: this.currentBranch,
332
- file_path: this.filePath,
333
- heading_title: this.headingTitle
387
+ branch: this._currentBranch
334
388
  });
335
389
 
336
390
  console.log('Fetching comments with params:', params.toString());
337
391
 
338
- const response = await fetch(`/api/comments?${params.toString()}`);
392
+ const response = await fetch(`/get-comments?${params.toString()}`);
339
393
 
340
394
  if (!response.ok) {
341
395
  throw new Error(`Failed to fetch comments: ${response.status} ${response.statusText}`);
342
396
  }
343
397
 
344
- const data = await response.json();
345
- console.log('Fetched comments:', data);
398
+ const data: ApiCommentResponse = await response.json();
399
+ console.log('Fetched comments from API:', data);
346
400
 
347
- // Handle different response formats
348
- if (Array.isArray(data)) {
349
- this.comments = data;
350
- } else if (data && Array.isArray(data.comments)) {
351
- this.comments = data.comments;
352
- } else {
353
- this.comments = [];
354
- }
401
+ // Find comments for this specific file path and heading title
402
+ const comments = this.extractCommentsFromApiResponse(data);
403
+ this.comments = comments;
355
404
  */
356
405
  } catch (error) {
357
406
  console.error("Error fetching comments:", error);
@@ -362,6 +411,47 @@ export default class CommentPopup extends LightningElement {
362
411
  }
363
412
  }
364
413
 
414
+ private extractCommentsFromApiResponse(
415
+ data: ApiCommentResponse
416
+ ): Comment[] {
417
+ try {
418
+ // Find the path that matches our file path
419
+ const matchingPath = data.paths.find(
420
+ (path) => path.path === this._filePath
421
+ );
422
+
423
+ if (!matchingPath) {
424
+ console.log(
425
+ `No comments found for file path: ${this._filePath}`
426
+ );
427
+ return [];
428
+ }
429
+
430
+ // Find the title that matches our heading title
431
+ const matchingTitle = matchingPath.titles.find(
432
+ (title) => title.title === this._headingTitle
433
+ );
434
+
435
+ if (!matchingTitle) {
436
+ console.log(
437
+ `No comments found for heading title: ${this._headingTitle}`
438
+ );
439
+ return [];
440
+ }
441
+
442
+ console.log(
443
+ `Found ${matchingTitle.comments.length} comments for ${this._filePath} - ${this._headingTitle}`
444
+ );
445
+ return matchingTitle.comments;
446
+ } catch (error) {
447
+ console.error(
448
+ "Error extracting comments from API response:",
449
+ error
450
+ );
451
+ return [];
452
+ }
453
+ }
454
+
365
455
  private async getCommentsFromLocalStorage(): Promise<Comment[]> {
366
456
  try {
367
457
  const existingData = localStorage.getItem(COMMENTS_STORAGE_KEY);
@@ -370,7 +460,7 @@ export default class CommentPopup extends LightningElement {
370
460
  }
371
461
 
372
462
  const allComments = JSON.parse(existingData);
373
- const commentKey = `${this.currentBranch}_${this.filePath}_${this.headingTitle}`;
463
+ const commentKey = `${this._currentBranch}_${this._filePath}_${this._headingTitle}`;
374
464
 
375
465
  return allComments[commentKey] || [];
376
466
  } catch (error) {
@@ -20,6 +20,17 @@ export interface ApiCommentPayload {
20
20
  };
21
21
  }
22
22
 
23
+ export interface ApiCommentResponse {
24
+ request_branch: string;
25
+ paths: Array<{
26
+ path: string;
27
+ titles: Array<{
28
+ title: string;
29
+ comments: Comment[];
30
+ }>;
31
+ }>;
32
+ }
33
+
23
34
  const COMMENTS_STORAGE_KEY = "dsc_comments";
24
35
 
25
36
  /**
@@ -117,6 +128,68 @@ export function getCommentsForLocation(
117
128
  }
118
129
  }
119
130
 
131
+ /**
132
+ * Get all comments for a specific branch (simulating API response format)
133
+ */
134
+ export function getCommentsForBranch(branch: string): ApiCommentResponse {
135
+ try {
136
+ const allComments = getAllComments();
137
+ const branchComments: ApiCommentResponse = {
138
+ request_branch: branch,
139
+ paths: []
140
+ };
141
+
142
+ // Group comments by file path and title
143
+ const pathMap = new Map<string, Map<string, Comment[]>>();
144
+
145
+ Object.keys(allComments).forEach((key) => {
146
+ const [commentBranch, filePath, headingTitle] = key.split("_", 3);
147
+
148
+ if (commentBranch === branch) {
149
+ if (!pathMap.has(filePath)) {
150
+ pathMap.set(filePath, new Map());
151
+ }
152
+
153
+ const titleMap = pathMap.get(filePath)!;
154
+ if (!titleMap.has(headingTitle)) {
155
+ titleMap.set(headingTitle, []);
156
+ }
157
+
158
+ titleMap.get(headingTitle)!.push(...allComments[key]);
159
+ }
160
+ });
161
+
162
+ // Convert to API response format
163
+ pathMap.forEach((titleMap, filePath) => {
164
+ const titles: Array<{ title: string; comments: Comment[] }> = [];
165
+
166
+ titleMap.forEach((comments, title) => {
167
+ titles.push({
168
+ title,
169
+ comments: comments.sort(
170
+ (a, b) =>
171
+ new Date(b.timestamp).getTime() -
172
+ new Date(a.timestamp).getTime()
173
+ )
174
+ });
175
+ });
176
+
177
+ branchComments.paths.push({
178
+ path: filePath,
179
+ titles
180
+ });
181
+ });
182
+
183
+ return branchComments;
184
+ } catch (error) {
185
+ console.error("Error getting comments for branch:", error);
186
+ return {
187
+ request_branch: branch,
188
+ paths: []
189
+ };
190
+ }
191
+ }
192
+
120
193
  /**
121
194
  * Clear all comments from localStorage
122
195
  */
@@ -135,8 +208,12 @@ export function clearAllComments(): void {
135
208
  export function getCommentsStats(): {
136
209
  totalLocations: number;
137
210
  totalComments: number;
211
+ branches: string[];
138
212
  locations: Array<{
139
213
  key: string;
214
+ branch: string;
215
+ filePath: string;
216
+ headingTitle: string;
140
217
  commentCount: number;
141
218
  lastComment?: string;
142
219
  }>;
@@ -145,13 +222,19 @@ export function getCommentsStats(): {
145
222
  const allComments = getAllComments();
146
223
  const locations = Object.keys(allComments);
147
224
  let totalComments = 0;
225
+ const branches = new Set<string>();
148
226
 
149
227
  const locationStats = locations.map((key) => {
228
+ const [branch, filePath, headingTitle] = key.split("_", 3);
150
229
  const comments = allComments[key];
151
230
  totalComments += comments.length;
231
+ branches.add(branch);
152
232
 
153
233
  return {
154
234
  key,
235
+ branch,
236
+ filePath,
237
+ headingTitle,
155
238
  commentCount: comments.length,
156
239
  lastComment:
157
240
  comments.length > 0
@@ -163,6 +246,7 @@ export function getCommentsStats(): {
163
246
  return {
164
247
  totalLocations: locations.length,
165
248
  totalComments,
249
+ branches: Array.from(branches),
166
250
  locations: locationStats
167
251
  };
168
252
  } catch (error) {
@@ -170,6 +254,7 @@ export function getCommentsStats(): {
170
254
  return {
171
255
  totalLocations: 0,
172
256
  totalComments: 0,
257
+ branches: [],
173
258
  locations: []
174
259
  };
175
260
  }
@@ -198,21 +283,14 @@ export function convertToApiFormat(): Array<{
198
283
  }> = [];
199
284
 
200
285
  Object.keys(allComments).forEach((key) => {
201
- const [branch, file_path, heading_title, start_line, end_line] =
202
- key.split("_", 5);
203
- if (
204
- branch &&
205
- file_path &&
206
- heading_title &&
207
- start_line &&
208
- end_line
209
- ) {
286
+ const [branch, file_path, heading_title] = key.split("_", 3);
287
+ if (branch && file_path && heading_title) {
210
288
  apiFormat.push({
211
289
  branch,
212
290
  file_path,
213
291
  heading_title,
214
- start_line,
215
- end_line,
292
+ start_line: "",
293
+ end_line: "",
216
294
  comments: allComments[key]
217
295
  });
218
296
  }
@@ -248,3 +326,57 @@ export function addComment(payload: ApiCommentPayload): void {
248
326
  throw error;
249
327
  }
250
328
  }
329
+
330
+ /**
331
+ * Simulate API call to get comments for a branch
332
+ */
333
+ export async function fetchCommentsForBranch(
334
+ branch: string
335
+ ): Promise<ApiCommentResponse> {
336
+ try {
337
+ // Simulate API delay
338
+ await new Promise((resolve) => setTimeout(resolve, 100));
339
+
340
+ return getCommentsForBranch(branch);
341
+ } catch (error) {
342
+ console.error("Error fetching comments for branch:", error);
343
+ throw error;
344
+ }
345
+ }
346
+
347
+ /**
348
+ * Extract comments for specific file path and heading title from API response
349
+ */
350
+ export function extractCommentsFromApiResponse(
351
+ data: ApiCommentResponse,
352
+ filePath: string,
353
+ headingTitle: string
354
+ ): Comment[] {
355
+ try {
356
+ // Find the path that matches our file path
357
+ const matchingPath = data.paths.find((path) => path.path === filePath);
358
+
359
+ if (!matchingPath) {
360
+ console.log(`No comments found for file path: ${filePath}`);
361
+ return [];
362
+ }
363
+
364
+ // Find the title that matches our heading title
365
+ const matchingTitle = matchingPath.titles.find(
366
+ (title) => title.title === headingTitle
367
+ );
368
+
369
+ if (!matchingTitle) {
370
+ console.log(`No comments found for heading title: ${headingTitle}`);
371
+ return [];
372
+ }
373
+
374
+ console.log(
375
+ `Found ${matchingTitle.comments.length} comments for ${filePath} - ${headingTitle}`
376
+ );
377
+ return matchingTitle.comments;
378
+ } catch (error) {
379
+ console.error("Error extracting comments from API response:", error);
380
+ return [];
381
+ }
382
+ }