@bugspotter/sdk 0.1.0-alpha.1
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/CHANGELOG.md +69 -0
- package/LICENSE +21 -0
- package/README.md +639 -0
- package/dist/bugspotter.min.js +2 -0
- package/dist/bugspotter.min.js.LICENSE.txt +14 -0
- package/dist/capture/base-capture.d.ts +34 -0
- package/dist/capture/base-capture.js +23 -0
- package/dist/capture/capture-lifecycle.d.ts +24 -0
- package/dist/capture/capture-lifecycle.js +2 -0
- package/dist/capture/console.d.ts +29 -0
- package/dist/capture/console.js +107 -0
- package/dist/capture/metadata.d.ts +21 -0
- package/dist/capture/metadata.js +76 -0
- package/dist/capture/network.d.ts +32 -0
- package/dist/capture/network.js +135 -0
- package/dist/capture/screenshot.d.ts +19 -0
- package/dist/capture/screenshot.js +52 -0
- package/dist/collectors/dom.d.ts +67 -0
- package/dist/collectors/dom.js +164 -0
- package/dist/collectors/index.d.ts +2 -0
- package/dist/collectors/index.js +5 -0
- package/dist/core/buffer.d.ts +50 -0
- package/dist/core/buffer.js +88 -0
- package/dist/core/circular-buffer.d.ts +42 -0
- package/dist/core/circular-buffer.js +77 -0
- package/dist/core/compress.d.ts +49 -0
- package/dist/core/compress.js +245 -0
- package/dist/core/offline-queue.d.ts +76 -0
- package/dist/core/offline-queue.js +301 -0
- package/dist/core/transport.d.ts +73 -0
- package/dist/core/transport.js +352 -0
- package/dist/core/upload-helpers.d.ts +32 -0
- package/dist/core/upload-helpers.js +79 -0
- package/dist/core/uploader.d.ts +70 -0
- package/dist/core/uploader.js +185 -0
- package/dist/index.d.ts +140 -0
- package/dist/index.esm.js +205 -0
- package/dist/index.js +244 -0
- package/dist/utils/logger.d.ts +28 -0
- package/dist/utils/logger.js +84 -0
- package/dist/utils/sanitize-patterns.d.ts +103 -0
- package/dist/utils/sanitize-patterns.js +282 -0
- package/dist/utils/sanitize.d.ts +73 -0
- package/dist/utils/sanitize.js +254 -0
- package/dist/widget/button.d.ts +33 -0
- package/dist/widget/button.js +143 -0
- package/dist/widget/components/dom-element-cache.d.ts +62 -0
- package/dist/widget/components/dom-element-cache.js +105 -0
- package/dist/widget/components/form-validator.d.ts +66 -0
- package/dist/widget/components/form-validator.js +115 -0
- package/dist/widget/components/pii-detection-display.d.ts +64 -0
- package/dist/widget/components/pii-detection-display.js +142 -0
- package/dist/widget/components/redaction-canvas.d.ts +95 -0
- package/dist/widget/components/redaction-canvas.js +230 -0
- package/dist/widget/components/screenshot-processor.d.ts +44 -0
- package/dist/widget/components/screenshot-processor.js +191 -0
- package/dist/widget/components/style-manager.d.ts +37 -0
- package/dist/widget/components/style-manager.js +296 -0
- package/dist/widget/components/template-manager.d.ts +66 -0
- package/dist/widget/components/template-manager.js +198 -0
- package/dist/widget/modal.d.ts +62 -0
- package/dist/widget/modal.js +299 -0
- package/docs/CDN.md +213 -0
- package/docs/FRAMEWORK_INTEGRATION.md +1104 -0
- package/docs/PUBLISHING.md +550 -0
- package/docs/SESSION_REPLAY.md +381 -0
- package/package.json +90 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* StyleManager
|
|
4
|
+
*
|
|
5
|
+
* Responsibility: Generate and manage CSS styles for the bug report modal
|
|
6
|
+
* Follows SRP: Only handles style generation and theming
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.StyleManager = void 0;
|
|
10
|
+
class StyleManager {
|
|
11
|
+
constructor(config = {}) {
|
|
12
|
+
this.config = {
|
|
13
|
+
primaryColor: config.primaryColor || '#007bff',
|
|
14
|
+
dangerColor: config.dangerColor || '#dc3545',
|
|
15
|
+
borderRadius: config.borderRadius || '4px',
|
|
16
|
+
fontFamily: config.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
17
|
+
zIndex: config.zIndex || 999999,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Generate complete CSS stylesheet for the modal
|
|
22
|
+
*/
|
|
23
|
+
generateStyles() {
|
|
24
|
+
return `
|
|
25
|
+
.overlay {
|
|
26
|
+
position: fixed;
|
|
27
|
+
top: 0;
|
|
28
|
+
left: 0;
|
|
29
|
+
width: 100%;
|
|
30
|
+
height: 100%;
|
|
31
|
+
background: rgba(0, 0, 0, 0.5);
|
|
32
|
+
display: flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
justify-content: center;
|
|
35
|
+
z-index: ${this.config.zIndex};
|
|
36
|
+
font-family: ${this.config.fontFamily};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.modal {
|
|
40
|
+
background: white;
|
|
41
|
+
border-radius: 8px;
|
|
42
|
+
width: 90%;
|
|
43
|
+
max-width: 600px;
|
|
44
|
+
max-height: 90vh;
|
|
45
|
+
overflow-y: auto;
|
|
46
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.header {
|
|
50
|
+
padding: 20px;
|
|
51
|
+
border-bottom: 1px solid #e0e0e0;
|
|
52
|
+
display: flex;
|
|
53
|
+
justify-content: space-between;
|
|
54
|
+
align-items: center;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.header h2 {
|
|
58
|
+
margin: 0;
|
|
59
|
+
font-size: 20px;
|
|
60
|
+
font-weight: 600;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.close {
|
|
64
|
+
background: none;
|
|
65
|
+
border: none;
|
|
66
|
+
font-size: 24px;
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
color: #666;
|
|
69
|
+
padding: 0;
|
|
70
|
+
width: 30px;
|
|
71
|
+
height: 30px;
|
|
72
|
+
display: flex;
|
|
73
|
+
align-items: center;
|
|
74
|
+
justify-content: center;
|
|
75
|
+
border-radius: ${this.config.borderRadius};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.close:hover {
|
|
79
|
+
background: #f0f0f0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.body {
|
|
83
|
+
padding: 20px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.form-group {
|
|
87
|
+
margin-bottom: 20px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.label {
|
|
91
|
+
display: block;
|
|
92
|
+
margin-bottom: 8px;
|
|
93
|
+
font-weight: 500;
|
|
94
|
+
font-size: 14px;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.input,
|
|
98
|
+
.textarea {
|
|
99
|
+
width: 100%;
|
|
100
|
+
padding: 10px;
|
|
101
|
+
border: 1px solid #ddd;
|
|
102
|
+
border-radius: ${this.config.borderRadius};
|
|
103
|
+
font-size: 14px;
|
|
104
|
+
font-family: ${this.config.fontFamily};
|
|
105
|
+
box-sizing: border-box;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.input:focus,
|
|
109
|
+
.textarea:focus {
|
|
110
|
+
outline: none;
|
|
111
|
+
border-color: ${this.config.primaryColor};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.textarea {
|
|
115
|
+
min-height: 100px;
|
|
116
|
+
resize: vertical;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.screenshot-container {
|
|
120
|
+
margin-top: 10px;
|
|
121
|
+
position: relative;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.screenshot {
|
|
125
|
+
max-width: 100%;
|
|
126
|
+
border: 1px solid #ddd;
|
|
127
|
+
border-radius: ${this.config.borderRadius};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.redaction-canvas {
|
|
131
|
+
position: absolute;
|
|
132
|
+
top: 0;
|
|
133
|
+
left: 0;
|
|
134
|
+
cursor: crosshair;
|
|
135
|
+
border: 2px solid ${this.config.primaryColor};
|
|
136
|
+
border-radius: ${this.config.borderRadius};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.redaction-controls {
|
|
140
|
+
margin-top: 10px;
|
|
141
|
+
display: flex;
|
|
142
|
+
gap: 10px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.btn-redact,
|
|
146
|
+
.btn-clear {
|
|
147
|
+
padding: 8px 16px;
|
|
148
|
+
border: 1px solid #ddd;
|
|
149
|
+
border-radius: ${this.config.borderRadius};
|
|
150
|
+
background: white;
|
|
151
|
+
cursor: pointer;
|
|
152
|
+
font-size: 14px;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.btn-redact:hover,
|
|
156
|
+
.btn-clear:hover {
|
|
157
|
+
background: #f5f5f5;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.btn-redact.active {
|
|
161
|
+
background: ${this.config.primaryColor};
|
|
162
|
+
color: white;
|
|
163
|
+
border-color: ${this.config.primaryColor};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.pii-section {
|
|
167
|
+
margin-top: 20px;
|
|
168
|
+
padding: 15px;
|
|
169
|
+
background: #fff3cd;
|
|
170
|
+
border: 1px solid #ffc107;
|
|
171
|
+
border-radius: ${this.config.borderRadius};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.pii-title {
|
|
175
|
+
margin: 0 0 10px 0;
|
|
176
|
+
font-size: 14px;
|
|
177
|
+
font-weight: 600;
|
|
178
|
+
color: #856404;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.pii-list {
|
|
182
|
+
margin: 0;
|
|
183
|
+
padding-left: 20px;
|
|
184
|
+
font-size: 13px;
|
|
185
|
+
color: #856404;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.pii-badge {
|
|
189
|
+
display: inline-block;
|
|
190
|
+
padding: 2px 8px;
|
|
191
|
+
margin: 2px;
|
|
192
|
+
background: #ffc107;
|
|
193
|
+
color: #856404;
|
|
194
|
+
border-radius: 12px;
|
|
195
|
+
font-size: 12px;
|
|
196
|
+
font-weight: 500;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.checkbox-group {
|
|
200
|
+
display: flex;
|
|
201
|
+
align-items: center;
|
|
202
|
+
gap: 8px;
|
|
203
|
+
margin-top: 15px;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.checkbox {
|
|
207
|
+
width: 18px;
|
|
208
|
+
height: 18px;
|
|
209
|
+
cursor: pointer;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.checkbox-label {
|
|
213
|
+
margin: 0;
|
|
214
|
+
font-size: 14px;
|
|
215
|
+
cursor: pointer;
|
|
216
|
+
user-select: none;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.footer {
|
|
220
|
+
padding: 20px;
|
|
221
|
+
border-top: 1px solid #e0e0e0;
|
|
222
|
+
display: flex;
|
|
223
|
+
justify-content: flex-end;
|
|
224
|
+
gap: 10px;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.btn {
|
|
228
|
+
padding: 10px 20px;
|
|
229
|
+
border: none;
|
|
230
|
+
border-radius: ${this.config.borderRadius};
|
|
231
|
+
cursor: pointer;
|
|
232
|
+
font-size: 14px;
|
|
233
|
+
font-weight: 500;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.btn-primary {
|
|
237
|
+
background: ${this.config.primaryColor};
|
|
238
|
+
color: white;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.btn-primary:hover {
|
|
242
|
+
opacity: 0.9;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.btn-primary:disabled {
|
|
246
|
+
opacity: 0.5;
|
|
247
|
+
cursor: not-allowed;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.btn-secondary {
|
|
251
|
+
background: #6c757d;
|
|
252
|
+
color: white;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.btn-secondary:hover {
|
|
256
|
+
opacity: 0.9;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.error {
|
|
260
|
+
color: ${this.config.dangerColor};
|
|
261
|
+
font-size: 12px;
|
|
262
|
+
margin-top: 4px;
|
|
263
|
+
}
|
|
264
|
+
`;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Inject styles into document head
|
|
268
|
+
*/
|
|
269
|
+
injectStyles() {
|
|
270
|
+
const styleElement = document.createElement('style');
|
|
271
|
+
styleElement.textContent = this.generateStyles();
|
|
272
|
+
document.head.appendChild(styleElement);
|
|
273
|
+
return styleElement;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Remove injected styles
|
|
277
|
+
*/
|
|
278
|
+
removeStyles(styleElement) {
|
|
279
|
+
if (styleElement && styleElement.parentNode) {
|
|
280
|
+
styleElement.parentNode.removeChild(styleElement);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Update configuration and regenerate styles
|
|
285
|
+
*/
|
|
286
|
+
updateConfig(config) {
|
|
287
|
+
this.config = Object.assign(Object.assign({}, this.config), config);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Get current configuration
|
|
291
|
+
*/
|
|
292
|
+
getConfig() {
|
|
293
|
+
return Object.assign({}, this.config);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
exports.StyleManager = StyleManager;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TemplateManager
|
|
3
|
+
*
|
|
4
|
+
* Responsibility: Generate HTML templates for modal components
|
|
5
|
+
* Follows SRP: Only handles HTML structure generation
|
|
6
|
+
*/
|
|
7
|
+
export interface TemplateConfig {
|
|
8
|
+
title?: string;
|
|
9
|
+
titlePlaceholder?: string;
|
|
10
|
+
descriptionPlaceholder?: string;
|
|
11
|
+
submitButtonText?: string;
|
|
12
|
+
cancelButtonText?: string;
|
|
13
|
+
showScreenshot?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare class TemplateManager {
|
|
16
|
+
private config;
|
|
17
|
+
constructor(config?: TemplateConfig);
|
|
18
|
+
/**
|
|
19
|
+
* Generate complete modal HTML structure
|
|
20
|
+
*/
|
|
21
|
+
generateModalHTML(screenshotDataUrl?: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Generate modal header
|
|
24
|
+
*/
|
|
25
|
+
private generateHeader;
|
|
26
|
+
/**
|
|
27
|
+
* Generate modal body with form
|
|
28
|
+
*/
|
|
29
|
+
private generateBody;
|
|
30
|
+
/**
|
|
31
|
+
* Generate title input field
|
|
32
|
+
*/
|
|
33
|
+
private generateTitleField;
|
|
34
|
+
/**
|
|
35
|
+
* Generate description textarea field
|
|
36
|
+
*/
|
|
37
|
+
private generateDescriptionField;
|
|
38
|
+
/**
|
|
39
|
+
* Generate screenshot section with redaction controls
|
|
40
|
+
*/
|
|
41
|
+
private generateScreenshotSection;
|
|
42
|
+
/**
|
|
43
|
+
* Generate PII detection section (initially hidden)
|
|
44
|
+
*/
|
|
45
|
+
private generatePIISection;
|
|
46
|
+
/**
|
|
47
|
+
* Generate modal footer with action buttons
|
|
48
|
+
*/
|
|
49
|
+
private generateFooter;
|
|
50
|
+
/**
|
|
51
|
+
* Generate PII badge HTML
|
|
52
|
+
*/
|
|
53
|
+
generatePIIBadge(type: string, count: number): string;
|
|
54
|
+
/**
|
|
55
|
+
* Escape HTML to prevent XSS
|
|
56
|
+
*/
|
|
57
|
+
private escapeHtml;
|
|
58
|
+
/**
|
|
59
|
+
* Update configuration
|
|
60
|
+
*/
|
|
61
|
+
updateConfig(config: Partial<TemplateConfig>): void;
|
|
62
|
+
/**
|
|
63
|
+
* Get current configuration
|
|
64
|
+
*/
|
|
65
|
+
getConfig(): Required<TemplateConfig>;
|
|
66
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TemplateManager
|
|
4
|
+
*
|
|
5
|
+
* Responsibility: Generate HTML templates for modal components
|
|
6
|
+
* Follows SRP: Only handles HTML structure generation
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.TemplateManager = void 0;
|
|
10
|
+
class TemplateManager {
|
|
11
|
+
constructor(config = {}) {
|
|
12
|
+
this.config = {
|
|
13
|
+
title: config.title || 'Report a Bug',
|
|
14
|
+
titlePlaceholder: config.titlePlaceholder || 'Brief description of the issue',
|
|
15
|
+
descriptionPlaceholder: config.descriptionPlaceholder || 'Detailed description of what happened...',
|
|
16
|
+
submitButtonText: config.submitButtonText || 'Submit Bug Report',
|
|
17
|
+
cancelButtonText: config.cancelButtonText || 'Cancel',
|
|
18
|
+
showScreenshot: config.showScreenshot !== false,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Generate complete modal HTML structure
|
|
23
|
+
*/
|
|
24
|
+
generateModalHTML(screenshotDataUrl) {
|
|
25
|
+
return `
|
|
26
|
+
<div class="overlay">
|
|
27
|
+
<div class="modal">
|
|
28
|
+
${this.generateHeader()}
|
|
29
|
+
${this.generateBody(screenshotDataUrl)}
|
|
30
|
+
${this.generateFooter()}
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Generate modal header
|
|
37
|
+
*/
|
|
38
|
+
generateHeader() {
|
|
39
|
+
return `
|
|
40
|
+
<div class="header">
|
|
41
|
+
<h2>${this.escapeHtml(this.config.title)}</h2>
|
|
42
|
+
<button class="close" aria-label="Close">×</button>
|
|
43
|
+
</div>
|
|
44
|
+
`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Generate modal body with form
|
|
48
|
+
*/
|
|
49
|
+
generateBody(screenshotDataUrl) {
|
|
50
|
+
return `
|
|
51
|
+
<div class="body">
|
|
52
|
+
<form class="form">
|
|
53
|
+
${this.generateTitleField()}
|
|
54
|
+
${this.generateDescriptionField()}
|
|
55
|
+
${this.config.showScreenshot && screenshotDataUrl ? this.generateScreenshotSection(screenshotDataUrl) : ''}
|
|
56
|
+
${this.generatePIISection()}
|
|
57
|
+
</form>
|
|
58
|
+
</div>
|
|
59
|
+
`;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Generate title input field
|
|
63
|
+
*/
|
|
64
|
+
generateTitleField() {
|
|
65
|
+
return `
|
|
66
|
+
<div class="form-group">
|
|
67
|
+
<label class="label" for="title">Title *</label>
|
|
68
|
+
<input
|
|
69
|
+
type="text"
|
|
70
|
+
id="title"
|
|
71
|
+
class="input"
|
|
72
|
+
placeholder="${this.escapeHtml(this.config.titlePlaceholder)}"
|
|
73
|
+
required
|
|
74
|
+
/>
|
|
75
|
+
<div class="error" id="title-error"></div>
|
|
76
|
+
</div>
|
|
77
|
+
`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Generate description textarea field
|
|
81
|
+
*/
|
|
82
|
+
generateDescriptionField() {
|
|
83
|
+
return `
|
|
84
|
+
<div class="form-group">
|
|
85
|
+
<label class="label" for="description">Description *</label>
|
|
86
|
+
<textarea
|
|
87
|
+
id="description"
|
|
88
|
+
class="textarea"
|
|
89
|
+
placeholder="${this.escapeHtml(this.config.descriptionPlaceholder)}"
|
|
90
|
+
required
|
|
91
|
+
></textarea>
|
|
92
|
+
<div class="error" id="description-error"></div>
|
|
93
|
+
</div>
|
|
94
|
+
`;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Generate screenshot section with redaction controls
|
|
98
|
+
*/
|
|
99
|
+
generateScreenshotSection(screenshotDataUrl) {
|
|
100
|
+
return `
|
|
101
|
+
<div class="form-group">
|
|
102
|
+
<label class="label">Screenshot</label>
|
|
103
|
+
<div class="screenshot-container">
|
|
104
|
+
<img
|
|
105
|
+
src="${screenshotDataUrl}"
|
|
106
|
+
alt="Bug screenshot"
|
|
107
|
+
class="screenshot"
|
|
108
|
+
id="screenshot"
|
|
109
|
+
/>
|
|
110
|
+
<canvas
|
|
111
|
+
class="redaction-canvas"
|
|
112
|
+
id="redaction-canvas"
|
|
113
|
+
style="display: none;"
|
|
114
|
+
></canvas>
|
|
115
|
+
</div>
|
|
116
|
+
<div class="redaction-controls">
|
|
117
|
+
<button
|
|
118
|
+
type="button"
|
|
119
|
+
class="btn-redact"
|
|
120
|
+
id="btn-redact"
|
|
121
|
+
>
|
|
122
|
+
✏️ Redact Area
|
|
123
|
+
</button>
|
|
124
|
+
<button
|
|
125
|
+
type="button"
|
|
126
|
+
class="btn-clear"
|
|
127
|
+
id="btn-clear"
|
|
128
|
+
>
|
|
129
|
+
🗑️ Clear Redactions
|
|
130
|
+
</button>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
`;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Generate PII detection section (initially hidden)
|
|
137
|
+
*/
|
|
138
|
+
generatePIISection() {
|
|
139
|
+
return `
|
|
140
|
+
<div class="pii-section" id="pii-section" style="display: none;">
|
|
141
|
+
<h3 class="pii-title">⚠️ Potential PII Detected</h3>
|
|
142
|
+
<div id="pii-content"></div>
|
|
143
|
+
<div class="checkbox-group">
|
|
144
|
+
<input
|
|
145
|
+
type="checkbox"
|
|
146
|
+
id="pii-confirm"
|
|
147
|
+
class="checkbox"
|
|
148
|
+
/>
|
|
149
|
+
<label for="pii-confirm" class="checkbox-label">
|
|
150
|
+
I have reviewed and redacted sensitive information
|
|
151
|
+
</label>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
`;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Generate modal footer with action buttons
|
|
158
|
+
*/
|
|
159
|
+
generateFooter() {
|
|
160
|
+
return `
|
|
161
|
+
<div class="footer">
|
|
162
|
+
<button type="button" class="btn btn-secondary" id="btn-cancel">
|
|
163
|
+
${this.escapeHtml(this.config.cancelButtonText)}
|
|
164
|
+
</button>
|
|
165
|
+
<button type="submit" class="btn btn-primary submit" id="btn-submit">
|
|
166
|
+
${this.escapeHtml(this.config.submitButtonText)}
|
|
167
|
+
</button>
|
|
168
|
+
</div>
|
|
169
|
+
`;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Generate PII badge HTML
|
|
173
|
+
*/
|
|
174
|
+
generatePIIBadge(type, count) {
|
|
175
|
+
return `<span class="bugspotter-pii-badge">${this.escapeHtml(type)}: ${count}</span>`;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Escape HTML to prevent XSS
|
|
179
|
+
*/
|
|
180
|
+
escapeHtml(text) {
|
|
181
|
+
const div = document.createElement('div');
|
|
182
|
+
div.textContent = text;
|
|
183
|
+
return div.innerHTML;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Update configuration
|
|
187
|
+
*/
|
|
188
|
+
updateConfig(config) {
|
|
189
|
+
this.config = Object.assign(Object.assign({}, this.config), config);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Get current configuration
|
|
193
|
+
*/
|
|
194
|
+
getConfig() {
|
|
195
|
+
return Object.assign({}, this.config);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
exports.TemplateManager = TemplateManager;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export interface BugReportData {
|
|
2
|
+
title: string;
|
|
3
|
+
description: string;
|
|
4
|
+
}
|
|
5
|
+
export interface PIIDetection {
|
|
6
|
+
type: string;
|
|
7
|
+
count: number;
|
|
8
|
+
}
|
|
9
|
+
export interface BugReportModalOptions {
|
|
10
|
+
onSubmit: (data: BugReportData) => void | Promise<void>;
|
|
11
|
+
onClose?: () => void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* BugReportModal
|
|
15
|
+
*
|
|
16
|
+
* Refactored to follow SOLID principles
|
|
17
|
+
* Acts as a lightweight coordinator for specialized components
|
|
18
|
+
*/
|
|
19
|
+
export declare class BugReportModal {
|
|
20
|
+
private container;
|
|
21
|
+
private shadow;
|
|
22
|
+
private options;
|
|
23
|
+
private styleManager;
|
|
24
|
+
private templateManager;
|
|
25
|
+
private domCache;
|
|
26
|
+
private validator;
|
|
27
|
+
private piiDisplay;
|
|
28
|
+
private redactionCanvas;
|
|
29
|
+
private screenshotProcessor;
|
|
30
|
+
private originalScreenshot;
|
|
31
|
+
private piiDetections;
|
|
32
|
+
private handleEscapeKey;
|
|
33
|
+
constructor(options: BugReportModalOptions);
|
|
34
|
+
/**
|
|
35
|
+
* Show the modal with optional screenshot
|
|
36
|
+
*/
|
|
37
|
+
show(screenshotDataUrl?: string): void;
|
|
38
|
+
/**
|
|
39
|
+
* Close and cleanup the modal
|
|
40
|
+
*/
|
|
41
|
+
close(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Destroy the modal (alias for close)
|
|
44
|
+
*/
|
|
45
|
+
destroy(): void;
|
|
46
|
+
private setupRedactionCanvas;
|
|
47
|
+
private attachEventListeners;
|
|
48
|
+
private validateField;
|
|
49
|
+
private checkForPII;
|
|
50
|
+
private updateSubmitButton;
|
|
51
|
+
private toggleRedactionMode;
|
|
52
|
+
private clearRedactions;
|
|
53
|
+
private handleSubmit;
|
|
54
|
+
/**
|
|
55
|
+
* Get the final screenshot (with redactions applied)
|
|
56
|
+
*/
|
|
57
|
+
getScreenshot(): string;
|
|
58
|
+
/**
|
|
59
|
+
* Handle Escape key press to close modal
|
|
60
|
+
*/
|
|
61
|
+
private onEscapeKey;
|
|
62
|
+
}
|