@salesforcedevs/docs-components 1.17.0-hack-alpha4 → 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 +1 -1
- package/src/modules/doc/commentPopup/README.md +294 -0
- package/src/modules/doc/commentPopup/commentDevHelper.ts +321 -0
- package/src/modules/doc/commentPopup/commentPopup.css +91 -0
- package/src/modules/doc/commentPopup/commentPopup.html +20 -1
- package/src/modules/doc/commentPopup/commentPopup.ts +325 -34
- package/src/modules/doc/commentPopup/commentUtils.ts +382 -0
- package/src/modules/doc/heading/heading.css +12 -382
- package/src/modules/doc/heading/heading.html +28 -150
- package/src/modules/doc/heading/heading.ts +4 -204
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
// Utility functions for managing comments in localStorage
|
|
2
|
+
// This file provides helper functions for comment management
|
|
3
|
+
|
|
4
|
+
export interface Comment {
|
|
5
|
+
email: string;
|
|
6
|
+
comment_text: string;
|
|
7
|
+
timestamp: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ApiCommentPayload {
|
|
11
|
+
branch: string;
|
|
12
|
+
file_path: string;
|
|
13
|
+
heading_title: string;
|
|
14
|
+
start_line: string;
|
|
15
|
+
end_line: string;
|
|
16
|
+
comment: {
|
|
17
|
+
comment_text: string;
|
|
18
|
+
email: string;
|
|
19
|
+
timestamp: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
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
|
+
|
|
34
|
+
const COMMENTS_STORAGE_KEY = "dsc_comments";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Export all comments from localStorage to a JSON file
|
|
38
|
+
*/
|
|
39
|
+
export function exportCommentsToFile(): void {
|
|
40
|
+
try {
|
|
41
|
+
const commentsData = localStorage.getItem(COMMENTS_STORAGE_KEY);
|
|
42
|
+
if (!commentsData) {
|
|
43
|
+
console.log("No comments found in localStorage");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const comments = JSON.parse(commentsData);
|
|
48
|
+
const dataStr = JSON.stringify(comments, null, 2);
|
|
49
|
+
const dataBlob = new Blob([dataStr], { type: "application/json" });
|
|
50
|
+
|
|
51
|
+
const link = document.createElement("a");
|
|
52
|
+
link.href = URL.createObjectURL(dataBlob);
|
|
53
|
+
link.download = `dsc-comments-${
|
|
54
|
+
new Date().toISOString().split("T")[0]
|
|
55
|
+
}.json`;
|
|
56
|
+
link.click();
|
|
57
|
+
|
|
58
|
+
console.log("Comments exported successfully");
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error("Error exporting comments:", error);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Import comments from a JSON file to localStorage
|
|
66
|
+
*/
|
|
67
|
+
export function importCommentsFromFile(file: File): Promise<void> {
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
const reader = new FileReader();
|
|
70
|
+
|
|
71
|
+
reader.onload = (event) => {
|
|
72
|
+
try {
|
|
73
|
+
const content = event.target?.result as string;
|
|
74
|
+
const comments = JSON.parse(content);
|
|
75
|
+
|
|
76
|
+
// Validate the structure
|
|
77
|
+
if (typeof comments === "object" && comments !== null) {
|
|
78
|
+
localStorage.setItem(
|
|
79
|
+
COMMENTS_STORAGE_KEY,
|
|
80
|
+
JSON.stringify(comments)
|
|
81
|
+
);
|
|
82
|
+
console.log("Comments imported successfully");
|
|
83
|
+
resolve();
|
|
84
|
+
} else {
|
|
85
|
+
reject(new Error("Invalid comments file format"));
|
|
86
|
+
}
|
|
87
|
+
} catch (error) {
|
|
88
|
+
reject(new Error("Failed to parse comments file"));
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
reader.onerror = () => {
|
|
93
|
+
reject(new Error("Failed to read file"));
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
reader.readAsText(file);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get all comments from localStorage
|
|
102
|
+
*/
|
|
103
|
+
export function getAllComments(): Record<string, Comment[]> {
|
|
104
|
+
try {
|
|
105
|
+
const commentsData = localStorage.getItem(COMMENTS_STORAGE_KEY);
|
|
106
|
+
return commentsData ? JSON.parse(commentsData) : {};
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error("Error reading comments from localStorage:", error);
|
|
109
|
+
return {};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get comments for a specific location
|
|
115
|
+
*/
|
|
116
|
+
export function getCommentsForLocation(
|
|
117
|
+
branch: string,
|
|
118
|
+
filePath: string,
|
|
119
|
+
headingTitle: string
|
|
120
|
+
): Comment[] {
|
|
121
|
+
try {
|
|
122
|
+
const allComments = getAllComments();
|
|
123
|
+
const commentKey = `${branch}_${filePath}_${headingTitle}`;
|
|
124
|
+
return allComments[commentKey] || [];
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error("Error getting comments for location:", error);
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
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
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Clear all comments from localStorage
|
|
195
|
+
*/
|
|
196
|
+
export function clearAllComments(): void {
|
|
197
|
+
try {
|
|
198
|
+
localStorage.removeItem(COMMENTS_STORAGE_KEY);
|
|
199
|
+
console.log("All comments cleared from localStorage");
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error("Error clearing comments:", error);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Get statistics about stored comments
|
|
207
|
+
*/
|
|
208
|
+
export function getCommentsStats(): {
|
|
209
|
+
totalLocations: number;
|
|
210
|
+
totalComments: number;
|
|
211
|
+
branches: string[];
|
|
212
|
+
locations: Array<{
|
|
213
|
+
key: string;
|
|
214
|
+
branch: string;
|
|
215
|
+
filePath: string;
|
|
216
|
+
headingTitle: string;
|
|
217
|
+
commentCount: number;
|
|
218
|
+
lastComment?: string;
|
|
219
|
+
}>;
|
|
220
|
+
} {
|
|
221
|
+
try {
|
|
222
|
+
const allComments = getAllComments();
|
|
223
|
+
const locations = Object.keys(allComments);
|
|
224
|
+
let totalComments = 0;
|
|
225
|
+
const branches = new Set<string>();
|
|
226
|
+
|
|
227
|
+
const locationStats = locations.map((key) => {
|
|
228
|
+
const [branch, filePath, headingTitle] = key.split("_", 3);
|
|
229
|
+
const comments = allComments[key];
|
|
230
|
+
totalComments += comments.length;
|
|
231
|
+
branches.add(branch);
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
key,
|
|
235
|
+
branch,
|
|
236
|
+
filePath,
|
|
237
|
+
headingTitle,
|
|
238
|
+
commentCount: comments.length,
|
|
239
|
+
lastComment:
|
|
240
|
+
comments.length > 0
|
|
241
|
+
? comments[comments.length - 1].timestamp
|
|
242
|
+
: undefined
|
|
243
|
+
};
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
totalLocations: locations.length,
|
|
248
|
+
totalComments,
|
|
249
|
+
branches: Array.from(branches),
|
|
250
|
+
locations: locationStats
|
|
251
|
+
};
|
|
252
|
+
} catch (error) {
|
|
253
|
+
console.error("Error getting comments stats:", error);
|
|
254
|
+
return {
|
|
255
|
+
totalLocations: 0,
|
|
256
|
+
totalComments: 0,
|
|
257
|
+
branches: [],
|
|
258
|
+
locations: []
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Convert localStorage comments to API format for backend migration
|
|
265
|
+
*/
|
|
266
|
+
export function convertToApiFormat(): Array<{
|
|
267
|
+
branch: string;
|
|
268
|
+
file_path: string;
|
|
269
|
+
heading_title: string;
|
|
270
|
+
start_line: string;
|
|
271
|
+
end_line: string;
|
|
272
|
+
comments: Comment[];
|
|
273
|
+
}> {
|
|
274
|
+
try {
|
|
275
|
+
const allComments = getAllComments();
|
|
276
|
+
const apiFormat: Array<{
|
|
277
|
+
branch: string;
|
|
278
|
+
file_path: string;
|
|
279
|
+
heading_title: string;
|
|
280
|
+
start_line: string;
|
|
281
|
+
end_line: string;
|
|
282
|
+
comments: Comment[];
|
|
283
|
+
}> = [];
|
|
284
|
+
|
|
285
|
+
Object.keys(allComments).forEach((key) => {
|
|
286
|
+
const [branch, file_path, heading_title] = key.split("_", 3);
|
|
287
|
+
if (branch && file_path && heading_title) {
|
|
288
|
+
apiFormat.push({
|
|
289
|
+
branch,
|
|
290
|
+
file_path,
|
|
291
|
+
heading_title,
|
|
292
|
+
start_line: "",
|
|
293
|
+
end_line: "",
|
|
294
|
+
comments: allComments[key]
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
return apiFormat;
|
|
300
|
+
} catch (error) {
|
|
301
|
+
console.error("Error converting to API format:", error);
|
|
302
|
+
return [];
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Add a comment to localStorage
|
|
308
|
+
*/
|
|
309
|
+
export function addComment(payload: ApiCommentPayload): void {
|
|
310
|
+
try {
|
|
311
|
+
const existingData = localStorage.getItem(COMMENTS_STORAGE_KEY);
|
|
312
|
+
const allComments = existingData ? JSON.parse(existingData) : {};
|
|
313
|
+
|
|
314
|
+
const commentKey = `${payload.branch}_${payload.file_path}_${payload.heading_title}`;
|
|
315
|
+
|
|
316
|
+
if (!allComments[commentKey]) {
|
|
317
|
+
allComments[commentKey] = [];
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
allComments[commentKey].push(payload.comment);
|
|
321
|
+
localStorage.setItem(COMMENTS_STORAGE_KEY, JSON.stringify(allComments));
|
|
322
|
+
|
|
323
|
+
console.log("Comment added successfully");
|
|
324
|
+
} catch (error) {
|
|
325
|
+
console.error("Error adding comment:", error);
|
|
326
|
+
throw error;
|
|
327
|
+
}
|
|
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
|
+
}
|