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

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.
@@ -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(),
@@ -180,59 +234,93 @@ export default class CommentPopup extends LightningElement {
180
234
  JSON.stringify(payload, null, 2)
181
235
  );
182
236
 
183
- // LOCAL STORAGE IMPLEMENTATION (Temporary until backend is ready)
237
+ // Try API first, fallback to localStorage
184
238
  try {
185
- await this.saveCommentToLocalStorage(payload);
186
- console.log("Comment saved to local storage successfully");
187
-
188
- // Refresh comments after successful save
189
- await this.fetchComments();
190
-
191
- // Dispatch custom event
192
- this.dispatchEvent(
193
- new CustomEvent("commentadded", {
194
- detail: {
195
- ...payload.comment,
196
- id: Date.now().toString() // Generate temporary ID
197
- }
198
- })
239
+ const response = await fetch(
240
+ "https://cx-helper-engine-1-114ef038858c.herokuapp.com/post-comment",
241
+ {
242
+ method: "POST",
243
+ headers: {
244
+ "Content-Type": "application/json"
245
+ },
246
+ body: JSON.stringify(payload)
247
+ }
199
248
  );
200
- } catch (error) {
201
- console.error("Error saving comment to local storage:", error);
202
- throw error;
203
- }
204
249
 
205
- // API IMPLEMENTATION (Commented until backend is ready)
206
- /*
207
- const response = await fetch('/post-comment', {
208
- method: 'POST',
209
- headers: {
210
- 'Content-Type': 'application/json'
211
- },
212
- body: JSON.stringify(payload)
213
- });
214
-
215
- if (!response.ok) {
216
- const errorText = await response.text();
217
- throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
250
+ if (response.ok) {
251
+ const responseData = await response.json();
252
+ console.log(
253
+ "Comment posted successfully via API:",
254
+ responseData
255
+ );
256
+
257
+ // Refresh comments after successful post
258
+ await this.fetchComments();
259
+
260
+ // Dispatch custom event
261
+ this.dispatchEvent(
262
+ new CustomEvent("commentadded", {
263
+ detail: {
264
+ ...payload.comment,
265
+ id: responseData.id // Include any ID returned by the API
266
+ }
267
+ })
268
+ );
269
+ } else {
270
+ console.warn(
271
+ `API call failed (${response.status}): ${response.statusText}, falling back to localStorage`
272
+ );
273
+ // Fallback to localStorage if API fails
274
+ await this.saveCommentToLocalStorage(payload);
275
+ console.log(
276
+ "Comment saved to local storage successfully (fallback)"
277
+ );
278
+
279
+ // Refresh comments after successful save
280
+ await this.fetchComments();
281
+
282
+ // Dispatch custom event
283
+ this.dispatchEvent(
284
+ new CustomEvent("commentadded", {
285
+ detail: {
286
+ ...payload.comment,
287
+ id: Date.now().toString() // Generate temporary ID
288
+ }
289
+ })
290
+ );
291
+ }
292
+ } catch (error) {
293
+ console.error(
294
+ "Error posting comment via API, falling back to localStorage:",
295
+ error
296
+ );
297
+ // Fallback to localStorage if API call throws an error
298
+ try {
299
+ await this.saveCommentToLocalStorage(payload);
300
+ console.log(
301
+ "Comment saved to local storage successfully (fallback)"
302
+ );
303
+
304
+ // Refresh comments after successful save
305
+ await this.fetchComments();
306
+
307
+ // Dispatch custom event
308
+ this.dispatchEvent(
309
+ new CustomEvent("commentadded", {
310
+ detail: {
311
+ ...payload.comment,
312
+ id: Date.now().toString() // Generate temporary ID
313
+ }
314
+ })
315
+ );
316
+ } catch (localStorageError) {
317
+ console.error(
318
+ "Error saving comment to local storage:",
319
+ localStorageError
320
+ );
321
+ throw localStorageError;
322
+ }
218
323
  }
219
-
220
- const responseData = await response.json();
221
- console.log('Comment posted successfully:', responseData);
222
-
223
- // Refresh comments after successful post
224
- await this.fetchComments();
225
-
226
- // Dispatch custom event
227
- this.dispatchEvent(
228
- new CustomEvent("commentadded", {
229
- detail: {
230
- ...payload.comment,
231
- id: responseData.id // Include any ID returned by the API
232
- }
233
- })
234
- );
235
- */
236
324
  }
237
325
 
238
326
  private async saveCommentToLocalStorage(payload: ApiCommentPayload) {
@@ -308,10 +396,12 @@ export default class CommentPopup extends LightningElement {
308
396
 
309
397
  connectedCallback() {
310
398
  document.addEventListener("keydown", this.handleKeyDown.bind(this));
399
+ // Fetch comments when component is connected
400
+ this.fetchComments();
311
401
  }
312
402
 
313
403
  private async fetchComments() {
314
- if (!this.currentBranch || !this.filePath || !this.headingTitle) {
404
+ if (!this._currentBranch || !this._filePath || !this._headingTitle) {
315
405
  console.warn("Cannot fetch comments: missing required parameters");
316
406
  return;
317
407
  }
@@ -320,48 +410,104 @@ export default class CommentPopup extends LightningElement {
320
410
  this.apiError = "";
321
411
 
322
412
  try {
323
- // LOCAL STORAGE IMPLEMENTATION (Temporary until backend is ready)
324
- const comments = await this.getCommentsFromLocalStorage();
325
- console.log("Fetched comments from localStorage:", comments);
326
- this.comments = comments;
327
-
328
- // API IMPLEMENTATION (Commented until backend is ready)
329
- /*
413
+ // API IMPLEMENTATION - Try to fetch from /get-comments endpoint
330
414
  const params = new URLSearchParams({
331
- branch: this.currentBranch,
332
- file_path: this.filePath,
333
- heading_title: this.headingTitle
415
+ branch: this._currentBranch
334
416
  });
335
417
 
336
- console.log('Fetching comments with params:', params.toString());
418
+ console.log("Fetching comments with params:", params.toString());
337
419
 
338
- const response = await fetch(`/api/comments?${params.toString()}`);
339
-
340
- if (!response.ok) {
341
- throw new Error(`Failed to fetch comments: ${response.status} ${response.statusText}`);
342
- }
420
+ const response = await fetch(
421
+ `https://cx-helper-engine-1-114ef038858c.herokuapp.com/get-comments?${params.toString()}`
422
+ );
343
423
 
344
- const data = await response.json();
345
- console.log('Fetched comments:', data);
346
-
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;
424
+ if (response.ok) {
425
+ const data: ApiCommentResponse = await response.json();
426
+ console.log("Fetched comments from API:", data);
427
+
428
+ // Find comments for this specific file path and heading title
429
+ const comments = this.extractCommentsFromApiResponse(data);
430
+ this.comments = comments;
352
431
  } else {
353
- this.comments = [];
432
+ console.warn(
433
+ `API call failed (${response.status}): ${response.statusText}, falling back to localStorage`
434
+ );
435
+ // Fallback to localStorage if API fails
436
+ const comments = await this.getCommentsFromLocalStorage();
437
+ console.log(
438
+ "Fetched comments from localStorage (fallback):",
439
+ comments
440
+ );
441
+ this.comments = comments;
354
442
  }
355
- */
356
443
  } catch (error) {
357
- console.error("Error fetching comments:", error);
358
- this.apiError = "Failed to load comments. Please try again later.";
359
- this.comments = [];
444
+ console.error(
445
+ "Error fetching comments from API, falling back to localStorage:",
446
+ error
447
+ );
448
+ // Fallback to localStorage if API call throws an error
449
+ try {
450
+ const comments = await this.getCommentsFromLocalStorage();
451
+ console.log(
452
+ "Fetched comments from localStorage (fallback):",
453
+ comments
454
+ );
455
+ this.comments = comments;
456
+ } catch (localStorageError) {
457
+ console.error(
458
+ "Error fetching comments from localStorage:",
459
+ localStorageError
460
+ );
461
+ this.apiError =
462
+ "Failed to load comments. Please try again later.";
463
+ this.comments = [];
464
+ }
360
465
  } finally {
361
466
  this.isLoading = false;
362
467
  }
363
468
  }
364
469
 
470
+ private extractCommentsFromApiResponse(
471
+ data: ApiCommentResponse
472
+ ): Comment[] {
473
+ try {
474
+ // Find the path that matches our file path
475
+ const matchingPath = data.paths.find(
476
+ (path) => path.path === this._filePath
477
+ );
478
+
479
+ if (!matchingPath) {
480
+ console.log(
481
+ `No comments found for file path: ${this._filePath}`
482
+ );
483
+ return [];
484
+ }
485
+
486
+ // Find the title that matches our heading title
487
+ const matchingTitle = matchingPath.titles.find(
488
+ (title) => title.title === this._headingTitle
489
+ );
490
+
491
+ if (!matchingTitle) {
492
+ console.log(
493
+ `No comments found for heading title: ${this._headingTitle}`
494
+ );
495
+ return [];
496
+ }
497
+
498
+ console.log(
499
+ `Found ${matchingTitle.comments.length} comments for ${this._filePath} - ${this._headingTitle}`
500
+ );
501
+ return matchingTitle.comments;
502
+ } catch (error) {
503
+ console.error(
504
+ "Error extracting comments from API response:",
505
+ error
506
+ );
507
+ return [];
508
+ }
509
+ }
510
+
365
511
  private async getCommentsFromLocalStorage(): Promise<Comment[]> {
366
512
  try {
367
513
  const existingData = localStorage.getItem(COMMENTS_STORAGE_KEY);
@@ -370,7 +516,7 @@ export default class CommentPopup extends LightningElement {
370
516
  }
371
517
 
372
518
  const allComments = JSON.parse(existingData);
373
- const commentKey = `${this.currentBranch}_${this.filePath}_${this.headingTitle}`;
519
+ const commentKey = `${this._currentBranch}_${this._filePath}_${this._headingTitle}`;
374
520
 
375
521
  return allComments[commentKey] || [];
376
522
  } 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
+ }