@uxbertlabs/reportly 1.0.16 → 1.0.18
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/dist/core/init.d.ts +7 -0
- package/dist/core/init.d.ts.map +1 -1
- package/dist/features/export.d.ts +31 -1
- package/dist/features/export.d.ts.map +1 -1
- package/dist/features/n8n-integration.d.ts +52 -0
- package/dist/features/n8n-integration.d.ts.map +1 -0
- package/dist/features/screenshot.d.ts.map +1 -1
- package/dist/reportly.cjs.js +372 -5
- package/dist/reportly.cjs.js.map +1 -1
- package/dist/reportly.esm.js +372 -5
- package/dist/reportly.esm.js.map +1 -1
- package/dist/reportly.js +372 -5
- package/dist/reportly.js.map +1 -1
- package/dist/reportly.min.js +2 -2
- package/dist/reportly.min.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/modal.d.ts +2 -0
- package/dist/ui/modal.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/reportly.esm.js
CHANGED
@@ -261,6 +261,9 @@ class Modal {
|
|
261
261
|
<button type="button" class="uxbert-btn uxbert-btn-secondary" id="uxbert-cancel-btn">
|
262
262
|
Cancel
|
263
263
|
</button>
|
264
|
+
<button type="button" class="uxbert-btn uxbert-btn-success" id="uxbert-n8n-btn" style="display: none;">
|
265
|
+
🚀 Send to n8n
|
266
|
+
</button>
|
264
267
|
<button type="submit" class="uxbert-btn uxbert-btn-primary" id="uxbert-submit-btn">
|
265
268
|
📥 Download JSON
|
266
269
|
</button>
|
@@ -315,6 +318,33 @@ class Modal {
|
|
315
318
|
this.callbacks.onRetake();
|
316
319
|
}
|
317
320
|
});
|
321
|
+
// n8n button
|
322
|
+
const n8nBtn = this.modal.querySelector('#uxbert-n8n-btn');
|
323
|
+
n8nBtn.addEventListener('click', () => {
|
324
|
+
this.handleN8nSubmit();
|
325
|
+
});
|
326
|
+
}
|
327
|
+
handleN8nSubmit() {
|
328
|
+
if (!this.modal)
|
329
|
+
return;
|
330
|
+
const titleInput = this.modal.querySelector('#uxbert-title');
|
331
|
+
const descriptionInput = this.modal.querySelector('#uxbert-description');
|
332
|
+
const prioritySelect = this.modal.querySelector('#uxbert-priority');
|
333
|
+
const title = titleInput.value;
|
334
|
+
const description = descriptionInput.value;
|
335
|
+
const priority = prioritySelect.value;
|
336
|
+
if (!title.trim()) {
|
337
|
+
alert('Please enter an issue title');
|
338
|
+
return;
|
339
|
+
}
|
340
|
+
const issueData = {
|
341
|
+
title: title.trim(),
|
342
|
+
description: description.trim(),
|
343
|
+
priority
|
344
|
+
};
|
345
|
+
if (this.callbacks.onSendToN8n) {
|
346
|
+
this.callbacks.onSendToN8n(issueData);
|
347
|
+
}
|
318
348
|
}
|
319
349
|
handleSubmit() {
|
320
350
|
if (!this.modal)
|
@@ -373,6 +403,14 @@ class Modal {
|
|
373
403
|
const viewportRadio = this.modal.querySelector('#uxbert-capture-viewport');
|
374
404
|
return viewportRadio.checked ? 'viewport' : 'fullpage';
|
375
405
|
}
|
406
|
+
setN8nButtonVisible(visible) {
|
407
|
+
if (!this.modal)
|
408
|
+
return;
|
409
|
+
const n8nBtn = this.modal.querySelector('#uxbert-n8n-btn');
|
410
|
+
if (n8nBtn) {
|
411
|
+
n8nBtn.style.display = visible ? 'inline-block' : 'none';
|
412
|
+
}
|
413
|
+
}
|
376
414
|
reset() {
|
377
415
|
if (!this.modal)
|
378
416
|
return;
|
@@ -9452,8 +9490,6 @@ class Screenshot {
|
|
9452
9490
|
}
|
9453
9491
|
async capture(mode = "fullpage") {
|
9454
9492
|
try {
|
9455
|
-
// Show loading screen
|
9456
|
-
this.showLoadingScreen();
|
9457
9493
|
// Hide UXbert UI elements before capturing
|
9458
9494
|
this.hideUXbertElements();
|
9459
9495
|
const originalScrollY = window.scrollY;
|
@@ -9472,6 +9508,8 @@ class Screenshot {
|
|
9472
9508
|
x: window.scrollX,
|
9473
9509
|
y: window.scrollY,
|
9474
9510
|
onclone: async () => {
|
9511
|
+
// Show loading screen after clone (won't appear in screenshot)
|
9512
|
+
this.showLoadingScreen();
|
9475
9513
|
// Wait 1 second after cloning to let animations complete
|
9476
9514
|
await this.wait(1000);
|
9477
9515
|
},
|
@@ -9512,6 +9550,10 @@ class Screenshot {
|
|
9512
9550
|
logging: false,
|
9513
9551
|
width: fullPageWidth,
|
9514
9552
|
height: fullPageHeight,
|
9553
|
+
onclone: async () => {
|
9554
|
+
// Show loading screen after clone (won't appear in screenshot)
|
9555
|
+
this.showLoadingScreen();
|
9556
|
+
},
|
9515
9557
|
ignoreElements: (element) => {
|
9516
9558
|
// Skip cross-origin images that might cause issues
|
9517
9559
|
if (element.tagName === "IMG") {
|
@@ -10155,9 +10197,213 @@ class DeviceInfo {
|
|
10155
10197
|
}
|
10156
10198
|
}
|
10157
10199
|
|
10200
|
+
class N8nIntegration {
|
10201
|
+
constructor(config) {
|
10202
|
+
this.config = config || null;
|
10203
|
+
}
|
10204
|
+
/**
|
10205
|
+
* Configure n8n integration
|
10206
|
+
*/
|
10207
|
+
configure(config) {
|
10208
|
+
this.config = config;
|
10209
|
+
}
|
10210
|
+
/**
|
10211
|
+
* Check if n8n integration is configured and enabled
|
10212
|
+
*/
|
10213
|
+
isEnabled() {
|
10214
|
+
return !!(this.config && this.config.enabled && this.config.webhookUrl);
|
10215
|
+
}
|
10216
|
+
/**
|
10217
|
+
* Send issue data to n8n webhook
|
10218
|
+
*/
|
10219
|
+
async sendToN8n(issueData) {
|
10220
|
+
if (!this.config || !this.config.webhookUrl) {
|
10221
|
+
return {
|
10222
|
+
success: false,
|
10223
|
+
message: 'n8n webhook URL is not configured',
|
10224
|
+
error: 'MISSING_CONFIG'
|
10225
|
+
};
|
10226
|
+
}
|
10227
|
+
if (!this.config.enabled) {
|
10228
|
+
return {
|
10229
|
+
success: false,
|
10230
|
+
message: 'n8n integration is disabled',
|
10231
|
+
error: 'DISABLED'
|
10232
|
+
};
|
10233
|
+
}
|
10234
|
+
try {
|
10235
|
+
// Prepare payload
|
10236
|
+
const payload = this.preparePayload(issueData);
|
10237
|
+
// Setup request headers
|
10238
|
+
const headers = {
|
10239
|
+
'Content-Type': 'application/json',
|
10240
|
+
...this.config.headers
|
10241
|
+
};
|
10242
|
+
// Setup timeout
|
10243
|
+
const timeout = this.config.timeout || 30000; // 30 seconds default
|
10244
|
+
const controller = new AbortController();
|
10245
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
10246
|
+
// Send request
|
10247
|
+
const response = await fetch(this.config.webhookUrl, {
|
10248
|
+
method: 'POST',
|
10249
|
+
headers,
|
10250
|
+
body: JSON.stringify(payload),
|
10251
|
+
signal: controller.signal
|
10252
|
+
});
|
10253
|
+
clearTimeout(timeoutId);
|
10254
|
+
// Check response
|
10255
|
+
if (!response.ok) {
|
10256
|
+
const errorText = await response.text().catch(() => 'Unknown error');
|
10257
|
+
return {
|
10258
|
+
success: false,
|
10259
|
+
message: `n8n webhook request failed: ${response.status} ${response.statusText}`,
|
10260
|
+
error: errorText
|
10261
|
+
};
|
10262
|
+
}
|
10263
|
+
// Parse response
|
10264
|
+
let responseData;
|
10265
|
+
try {
|
10266
|
+
responseData = await response.json();
|
10267
|
+
}
|
10268
|
+
catch (e) {
|
10269
|
+
// Some webhooks don't return JSON
|
10270
|
+
responseData = { message: 'Success' };
|
10271
|
+
}
|
10272
|
+
return {
|
10273
|
+
success: true,
|
10274
|
+
message: 'Issue sent to n8n successfully',
|
10275
|
+
workflowId: responseData.workflowId || responseData.executionId
|
10276
|
+
};
|
10277
|
+
}
|
10278
|
+
catch (error) {
|
10279
|
+
if (error instanceof Error) {
|
10280
|
+
if (error.name === 'AbortError') {
|
10281
|
+
return {
|
10282
|
+
success: false,
|
10283
|
+
message: 'Request to n8n webhook timed out',
|
10284
|
+
error: 'TIMEOUT'
|
10285
|
+
};
|
10286
|
+
}
|
10287
|
+
return {
|
10288
|
+
success: false,
|
10289
|
+
message: `Failed to send issue to n8n: ${error.message}`,
|
10290
|
+
error: error.message
|
10291
|
+
};
|
10292
|
+
}
|
10293
|
+
return {
|
10294
|
+
success: false,
|
10295
|
+
message: 'Unknown error occurred while sending to n8n',
|
10296
|
+
error: 'UNKNOWN'
|
10297
|
+
};
|
10298
|
+
}
|
10299
|
+
}
|
10300
|
+
/**
|
10301
|
+
* Prepare payload for n8n webhook
|
10302
|
+
* This formats the data in a structure that's easy to work with in n8n
|
10303
|
+
*/
|
10304
|
+
preparePayload(issueData) {
|
10305
|
+
return {
|
10306
|
+
// Main issue data
|
10307
|
+
issue: {
|
10308
|
+
title: issueData.title,
|
10309
|
+
description: issueData.description,
|
10310
|
+
priority: issueData.priority,
|
10311
|
+
createdAt: issueData.createdAt
|
10312
|
+
},
|
10313
|
+
// Screenshot data (base64)
|
10314
|
+
screenshot: {
|
10315
|
+
data: issueData.screenshot,
|
10316
|
+
format: 'base64',
|
10317
|
+
mimeType: 'image/png'
|
10318
|
+
},
|
10319
|
+
// Device and browser information
|
10320
|
+
context: {
|
10321
|
+
browser: issueData.deviceInfo.browser,
|
10322
|
+
os: issueData.deviceInfo.os,
|
10323
|
+
screenResolution: issueData.deviceInfo.screenResolution,
|
10324
|
+
viewport: issueData.deviceInfo.viewport,
|
10325
|
+
url: issueData.deviceInfo.url,
|
10326
|
+
userAgent: issueData.deviceInfo.userAgent,
|
10327
|
+
language: issueData.deviceInfo.language,
|
10328
|
+
platform: issueData.deviceInfo.platform,
|
10329
|
+
cookiesEnabled: issueData.deviceInfo.cookiesEnabled,
|
10330
|
+
onLine: issueData.deviceInfo.onLine,
|
10331
|
+
timestamp: issueData.deviceInfo.timestamp
|
10332
|
+
},
|
10333
|
+
// Metadata for tracking
|
10334
|
+
metadata: {
|
10335
|
+
source: 'uxbert-reportly',
|
10336
|
+
version: '1.0.0',
|
10337
|
+
timestamp: new Date().toISOString()
|
10338
|
+
}
|
10339
|
+
};
|
10340
|
+
}
|
10341
|
+
/**
|
10342
|
+
* Test connection to n8n webhook
|
10343
|
+
*/
|
10344
|
+
async testConnection() {
|
10345
|
+
if (!this.config || !this.config.webhookUrl) {
|
10346
|
+
return {
|
10347
|
+
success: false,
|
10348
|
+
message: 'n8n webhook URL is not configured',
|
10349
|
+
error: 'MISSING_CONFIG'
|
10350
|
+
};
|
10351
|
+
}
|
10352
|
+
try {
|
10353
|
+
const controller = new AbortController();
|
10354
|
+
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout for test
|
10355
|
+
await fetch(this.config.webhookUrl, {
|
10356
|
+
method: 'HEAD',
|
10357
|
+
signal: controller.signal
|
10358
|
+
});
|
10359
|
+
clearTimeout(timeoutId);
|
10360
|
+
return {
|
10361
|
+
success: true,
|
10362
|
+
message: 'n8n webhook is reachable'
|
10363
|
+
};
|
10364
|
+
}
|
10365
|
+
catch (error) {
|
10366
|
+
return {
|
10367
|
+
success: false,
|
10368
|
+
message: 'Failed to reach n8n webhook',
|
10369
|
+
error: error instanceof Error ? error.message : 'UNKNOWN'
|
10370
|
+
};
|
10371
|
+
}
|
10372
|
+
}
|
10373
|
+
/**
|
10374
|
+
* Get current configuration
|
10375
|
+
*/
|
10376
|
+
getConfig() {
|
10377
|
+
return this.config;
|
10378
|
+
}
|
10379
|
+
/**
|
10380
|
+
* Update webhook URL
|
10381
|
+
*/
|
10382
|
+
setWebhookUrl(url) {
|
10383
|
+
if (!this.config) {
|
10384
|
+
this.config = {
|
10385
|
+
webhookUrl: url,
|
10386
|
+
enabled: true
|
10387
|
+
};
|
10388
|
+
}
|
10389
|
+
else {
|
10390
|
+
this.config.webhookUrl = url;
|
10391
|
+
}
|
10392
|
+
}
|
10393
|
+
/**
|
10394
|
+
* Enable/disable n8n integration
|
10395
|
+
*/
|
10396
|
+
setEnabled(enabled) {
|
10397
|
+
if (this.config) {
|
10398
|
+
this.config.enabled = enabled;
|
10399
|
+
}
|
10400
|
+
}
|
10401
|
+
}
|
10402
|
+
|
10158
10403
|
class Export {
|
10159
|
-
constructor() {
|
10404
|
+
constructor(n8nConfig) {
|
10160
10405
|
this.savedIssues = this.loadSavedIssues();
|
10406
|
+
this.n8nIntegration = new N8nIntegration(n8nConfig);
|
10161
10407
|
}
|
10162
10408
|
exportToJSON(issueData) {
|
10163
10409
|
const json = JSON.stringify(issueData, null, 2);
|
@@ -10226,6 +10472,54 @@ class Export {
|
|
10226
10472
|
document.body.removeChild(link);
|
10227
10473
|
URL.revokeObjectURL(url);
|
10228
10474
|
}
|
10475
|
+
// n8n Integration Methods
|
10476
|
+
/**
|
10477
|
+
* Send issue to n8n webhook
|
10478
|
+
*/
|
10479
|
+
async sendToN8n(issueData) {
|
10480
|
+
const response = await this.n8nIntegration.sendToN8n(issueData);
|
10481
|
+
// Save to localStorage if n8n send was successful
|
10482
|
+
if (response.success) {
|
10483
|
+
this.saveIssue(issueData);
|
10484
|
+
}
|
10485
|
+
return response;
|
10486
|
+
}
|
10487
|
+
/**
|
10488
|
+
* Configure n8n integration
|
10489
|
+
*/
|
10490
|
+
configureN8n(config) {
|
10491
|
+
this.n8nIntegration.configure(config);
|
10492
|
+
}
|
10493
|
+
/**
|
10494
|
+
* Check if n8n is enabled
|
10495
|
+
*/
|
10496
|
+
isN8nEnabled() {
|
10497
|
+
return this.n8nIntegration.isEnabled();
|
10498
|
+
}
|
10499
|
+
/**
|
10500
|
+
* Test n8n connection
|
10501
|
+
*/
|
10502
|
+
async testN8nConnection() {
|
10503
|
+
return this.n8nIntegration.testConnection();
|
10504
|
+
}
|
10505
|
+
/**
|
10506
|
+
* Get n8n configuration
|
10507
|
+
*/
|
10508
|
+
getN8nConfig() {
|
10509
|
+
return this.n8nIntegration.getConfig();
|
10510
|
+
}
|
10511
|
+
/**
|
10512
|
+
* Enable/disable n8n integration
|
10513
|
+
*/
|
10514
|
+
setN8nEnabled(enabled) {
|
10515
|
+
this.n8nIntegration.setEnabled(enabled);
|
10516
|
+
}
|
10517
|
+
/**
|
10518
|
+
* Set n8n webhook URL
|
10519
|
+
*/
|
10520
|
+
setN8nWebhookUrl(url) {
|
10521
|
+
this.n8nIntegration.setWebhookUrl(url);
|
10522
|
+
}
|
10229
10523
|
}
|
10230
10524
|
|
10231
10525
|
function styleInject(css, ref) {
|
@@ -10255,7 +10549,7 @@ function styleInject(css, ref) {
|
|
10255
10549
|
}
|
10256
10550
|
}
|
10257
10551
|
|
10258
|
-
var css_248z = ":root{--uxbert-primary:#4f46e5;--uxbert-primary-hover:#4338ca;--uxbert-danger:#ef4444;--uxbert-success:#10b981;--uxbert-bg:#fff;--uxbert-text:#1f2937;--uxbert-border:#e5e7eb;--uxbert-shadow:0 10px 25px rgba(0,0,0,.1);--uxbert-z-button:999999;--uxbert-z-modal:1000000;--uxbert-z-canvas:1000001;--uxbert-z-toolbar:1000002}[data-theme=dark]{--uxbert-bg:#1f2937;--uxbert-text:#f9fafb;--uxbert-border:#374151}.uxbert-fab{align-items:center;background:var(--uxbert-primary);border:none;border-radius:50%;box-shadow:var(--uxbert-shadow);color:#fff;cursor:pointer;display:flex;font-size:24px;height:56px;justify-content:center;position:fixed;transition:all .3s ease;width:56px;z-index:var(--uxbert-z-button)}.uxbert-fab:hover{background:var(--uxbert-primary-hover);transform:scale(1.1)}.uxbert-fab.bottom-right{bottom:24px;right:24px}.uxbert-fab.bottom-left{bottom:24px;left:24px}.uxbert-fab.top-right{right:24px;top:24px}.uxbert-fab.top-left{left:24px;top:24px}.uxbert-overlay{align-items:center;animation:fadeIn .3s ease;background:rgba(0,0,0,.5);display:none;height:100%;justify-content:center;left:0;position:fixed;top:0;width:100%;z-index:var(--uxbert-z-modal)}.uxbert-overlay.active{display:flex}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.uxbert-modal{animation:slideUp .3s ease;background:var(--uxbert-bg);border-radius:12px;box-shadow:var(--uxbert-shadow);color:var(--uxbert-text);max-height:90vh;max-width:600px;overflow-y:auto;padding:24px;width:90%}@keyframes slideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.uxbert-modal-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:20px}.uxbert-modal-title{font-size:20px;font-weight:600;margin:0}.uxbert-modal-close{align-items:center;background:none;border:none;border-radius:4px;color:var(--uxbert-text);cursor:pointer;display:flex;font-size:24px;height:32px;justify-content:center;padding:0;width:32px}.uxbert-modal-close:hover{background:var(--uxbert-border)}.uxbert-form-group{margin-bottom:16px}.uxbert-form-label{display:block;font-size:14px;font-weight:500;margin-bottom:8px}.uxbert-capture-mode{display:flex;flex-wrap:wrap;gap:12px}.uxbert-radio-label{align-items:center;border:2px solid var(--uxbert-border);border-radius:8px;cursor:pointer;display:flex;flex:1;gap:8px;min-width:140px;padding:10px 16px;transition:all .2s ease}.uxbert-radio-label:hover{background:rgba(79,70,229,.05);border-color:var(--uxbert-primary)}.uxbert-radio-label input[type=radio]{cursor:pointer;height:18px;margin:0;width:18px}.uxbert-radio-label input[type=radio]:checked{accent-color:var(--uxbert-primary)}.uxbert-radio-label:has(input[type=radio]:checked){background:rgba(79,70,229,.1);border-color:var(--uxbert-primary)}.uxbert-radio-label span{flex:1;font-size:14px;font-weight:500}.uxbert-form-input,.uxbert-form-select,.uxbert-form-textarea{background:var(--uxbert-bg);border:1px solid var(--uxbert-border);border-radius:6px;box-sizing:border-box;color:var(--uxbert-text);font-family:inherit;font-size:14px;padding:10px;width:100%}.uxbert-form-textarea{min-height:100px;resize:vertical}.uxbert-form-input:focus,.uxbert-form-select:focus,.uxbert-form-textarea:focus{border-color:var(--uxbert-primary);outline:none}.uxbert-capture-action{margin:16px 0;text-align:center}.uxbert-capture-action .uxbert-btn{min-width:200px}.uxbert-screenshot-preview{border:1px solid var(--uxbert-border);border-radius:8px;margin:16px 0;overflow:hidden}.uxbert-screenshot-preview img{display:block;width:100%}.uxbert-screenshot-actions{background:var(--uxbert-border);display:flex;gap:8px;padding:12px}.uxbert-btn{align-items:center;border:none;border-radius:6px;cursor:pointer;display:inline-flex;font-size:14px;font-weight:500;gap:8px;padding:10px 20px;transition:all .2s ease}.uxbert-btn-primary{background:var(--uxbert-primary);color:#fff}.uxbert-btn-primary:hover{background:var(--uxbert-primary-hover)}.uxbert-btn-secondary{background:var(--uxbert-border);color:var(--uxbert-text)}.uxbert-btn-secondary:hover{background:#d1d5db}.uxbert-btn-danger{background:var(--uxbert-danger);color:#fff}.uxbert-btn-danger:hover{background:#dc2626}.uxbert-modal-actions{display:flex;gap:12px;justify-content:flex-end;margin-top:20px}.uxbert-toolbar-toggle{align-items:center;background:var(--uxbert-primary);border:none;border-radius:50%;bottom:24px;box-shadow:var(--uxbert-shadow);color:#fff;cursor:pointer;display:none;font-size:24px;height:56px;justify-content:center;position:fixed;right:24px;transition:all .3s ease;width:56px;z-index:var(--uxbert-z-toolbar)}.uxbert-toolbar-toggle.active{display:flex}.uxbert-toolbar-toggle.hidden{opacity:0;pointer-events:none;transform:scale(.8)}.uxbert-toolbar-toggle:hover{background:var(--uxbert-primary-hover);transform:scale(1.1)}.uxbert-toolbar{background:var(--uxbert-bg);border-radius:12px;bottom:24px;box-shadow:var(--uxbert-shadow);display:none;flex-direction:column;gap:8px;max-height:80vh;opacity:0;overflow-y:auto;padding:16px;pointer-events:none;position:fixed;right:24px;transform:translateY(20px);transition:all .3s ease;z-index:var(--uxbert-z-toolbar)}.uxbert-toolbar.active{display:flex}.uxbert-toolbar.expanded{opacity:1;pointer-events:all;transform:translateY(0)}.uxbert-toolbar-header{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-bottom:8px}.uxbert-toolbar-title{flex:1;font-size:14px;font-weight:600}.uxbert-toolbar-exit,.uxbert-toolbar-minimize{align-items:center;background:var(--uxbert-border);border:none;border-radius:6px;color:var(--uxbert-text);cursor:pointer;display:flex;font-size:20px;font-weight:700;height:32px;justify-content:center;transition:all .2s ease;width:32px}.uxbert-toolbar-exit{background:var(--uxbert-danger);color:#fff}.uxbert-toolbar-minimize:hover{background:#d1d5db;transform:scale(1.1)}.uxbert-toolbar-exit:hover{background:#dc2626;transform:scale(1.1)}.uxbert-toolbar-tools{display:flex;flex-wrap:wrap;gap:8px}.uxbert-tool-btn{align-items:center;background:var(--uxbert-bg);border:2px solid var(--uxbert-border);border-radius:6px;cursor:pointer;display:flex;font-family:Arial,sans-serif;font-size:18px;font-weight:700;height:40px;justify-content:center;transition:all .2s ease;width:40px}.uxbert-tool-btn.active,.uxbert-tool-btn:hover{background:var(--uxbert-primary);border-color:var(--uxbert-primary);color:#fff}.uxbert-color-picker{display:flex;gap:6px;margin:8px 0}.uxbert-color-option{border:2px solid var(--uxbert-border);border-radius:50%;cursor:pointer;height:32px;transition:transform .2s ease;width:32px}.uxbert-color-option:hover{transform:scale(1.1)}.uxbert-color-option.active{border:3px solid var(--uxbert-text)}.uxbert-canvas-overlay{cursor:crosshair;display:none;left:0;position:absolute;top:0;z-index:var(--uxbert-z-canvas)}.uxbert-canvas-overlay.active{display:block}.uxbert-canvas-overlay.viewport-mode{left:0;position:fixed;top:0}.uxbert-text-input{background:hsla(0,0%,100%,.95);border:2px solid var(--uxbert-primary);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.15);color:var(--uxbert-text);font-family:Arial,sans-serif;font-size:16px;font-weight:700;min-width:200px;outline:none;padding:8px 12px;z-index:var(--uxbert-z-toolbar)}.uxbert-text-input:focus{border-color:var(--uxbert-primary-hover);box-shadow:0 4px 16px rgba(79,70,229,.3)}.uxbert-text-input::placeholder{color:#9ca3af;font-weight:400}@media (max-width:768px){.uxbert-modal{max-height:95vh;padding:16px;width:95%}.uxbert-toolbar{bottom:90px;left:16px;max-height:60vh;right:16px;width:auto}.uxbert-toolbar-toggle{bottom:16px;height:56px;right:16px;width:56px}.uxbert-fab{font-size:20px;height:48px;width:48px}.uxbert-color-picker,.uxbert-toolbar-tools{justify-content:center}}";
|
10552
|
+
var css_248z = ":root{--uxbert-primary:#4f46e5;--uxbert-primary-hover:#4338ca;--uxbert-danger:#ef4444;--uxbert-success:#10b981;--uxbert-bg:#fff;--uxbert-text:#1f2937;--uxbert-border:#e5e7eb;--uxbert-shadow:0 10px 25px rgba(0,0,0,.1);--uxbert-z-button:999999;--uxbert-z-modal:1000000;--uxbert-z-canvas:1000001;--uxbert-z-toolbar:1000002}[data-theme=dark]{--uxbert-bg:#1f2937;--uxbert-text:#f9fafb;--uxbert-border:#374151}.uxbert-fab{align-items:center;background:var(--uxbert-primary);border:none;border-radius:50%;box-shadow:var(--uxbert-shadow);color:#fff;cursor:pointer;display:flex;font-size:24px;height:56px;justify-content:center;position:fixed;transition:all .3s ease;width:56px;z-index:var(--uxbert-z-button)}.uxbert-fab:hover{background:var(--uxbert-primary-hover);transform:scale(1.1)}.uxbert-fab.bottom-right{bottom:24px;right:24px}.uxbert-fab.bottom-left{bottom:24px;left:24px}.uxbert-fab.top-right{right:24px;top:24px}.uxbert-fab.top-left{left:24px;top:24px}.uxbert-overlay{align-items:center;animation:fadeIn .3s ease;background:rgba(0,0,0,.5);display:none;height:100%;justify-content:center;left:0;position:fixed;top:0;width:100%;z-index:var(--uxbert-z-modal)}.uxbert-overlay.active{display:flex}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.uxbert-modal{animation:slideUp .3s ease;background:var(--uxbert-bg);border-radius:12px;box-shadow:var(--uxbert-shadow);color:var(--uxbert-text);max-height:90vh;max-width:600px;overflow-y:auto;padding:24px;width:90%}@keyframes slideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.uxbert-modal-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:20px}.uxbert-modal-title{font-size:20px;font-weight:600;margin:0}.uxbert-modal-close{align-items:center;background:none;border:none;border-radius:4px;color:var(--uxbert-text);cursor:pointer;display:flex;font-size:24px;height:32px;justify-content:center;padding:0;width:32px}.uxbert-modal-close:hover{background:var(--uxbert-border)}.uxbert-form-group{margin-bottom:16px}.uxbert-form-label{display:block;font-size:14px;font-weight:500;margin-bottom:8px}.uxbert-capture-mode{display:flex;flex-wrap:wrap;gap:12px}.uxbert-radio-label{align-items:center;border:2px solid var(--uxbert-border);border-radius:8px;cursor:pointer;display:flex;flex:1;gap:8px;min-width:140px;padding:10px 16px;transition:all .2s ease}.uxbert-radio-label:hover{background:rgba(79,70,229,.05);border-color:var(--uxbert-primary)}.uxbert-radio-label input[type=radio]{cursor:pointer;height:18px;margin:0;width:18px}.uxbert-radio-label input[type=radio]:checked{accent-color:var(--uxbert-primary)}.uxbert-radio-label:has(input[type=radio]:checked){background:rgba(79,70,229,.1);border-color:var(--uxbert-primary)}.uxbert-radio-label span{flex:1;font-size:14px;font-weight:500}.uxbert-form-input,.uxbert-form-select,.uxbert-form-textarea{background:var(--uxbert-bg);border:1px solid var(--uxbert-border);border-radius:6px;box-sizing:border-box;color:var(--uxbert-text);font-family:inherit;font-size:14px;padding:10px;width:100%}.uxbert-form-textarea{min-height:100px;resize:vertical}.uxbert-form-input:focus,.uxbert-form-select:focus,.uxbert-form-textarea:focus{border-color:var(--uxbert-primary);outline:none}.uxbert-capture-action{margin:16px 0;text-align:center}.uxbert-capture-action .uxbert-btn{min-width:200px}.uxbert-screenshot-preview{border:1px solid var(--uxbert-border);border-radius:8px;margin:16px 0;overflow:hidden}.uxbert-screenshot-preview img{display:block;width:100%}.uxbert-screenshot-actions{background:var(--uxbert-border);display:flex;gap:8px;padding:12px}.uxbert-btn{align-items:center;border:none;border-radius:6px;cursor:pointer;display:inline-flex;font-size:14px;font-weight:500;gap:8px;padding:10px 20px;transition:all .2s ease}.uxbert-btn-primary{background:var(--uxbert-primary);color:#fff}.uxbert-btn-primary:hover{background:var(--uxbert-primary-hover)}.uxbert-btn-secondary{background:var(--uxbert-border);color:var(--uxbert-text)}.uxbert-btn-secondary:hover{background:#d1d5db}.uxbert-btn-success{background:var(--uxbert-success);color:#fff}.uxbert-btn-success:hover{background:#059669}.uxbert-btn-danger{background:var(--uxbert-danger);color:#fff}.uxbert-btn-danger:hover{background:#dc2626}.uxbert-modal-actions{display:flex;gap:12px;justify-content:flex-end;margin-top:20px}.uxbert-toolbar-toggle{align-items:center;background:var(--uxbert-primary);border:none;border-radius:50%;bottom:24px;box-shadow:var(--uxbert-shadow);color:#fff;cursor:pointer;display:none;font-size:24px;height:56px;justify-content:center;position:fixed;right:24px;transition:all .3s ease;width:56px;z-index:var(--uxbert-z-toolbar)}.uxbert-toolbar-toggle.active{display:flex}.uxbert-toolbar-toggle.hidden{opacity:0;pointer-events:none;transform:scale(.8)}.uxbert-toolbar-toggle:hover{background:var(--uxbert-primary-hover);transform:scale(1.1)}.uxbert-toolbar{background:var(--uxbert-bg);border-radius:12px;bottom:24px;box-shadow:var(--uxbert-shadow);display:none;flex-direction:column;gap:8px;max-height:80vh;opacity:0;overflow-y:auto;padding:16px;pointer-events:none;position:fixed;right:24px;transform:translateY(20px);transition:all .3s ease;z-index:var(--uxbert-z-toolbar)}.uxbert-toolbar.active{display:flex}.uxbert-toolbar.expanded{opacity:1;pointer-events:all;transform:translateY(0)}.uxbert-toolbar-header{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-bottom:8px}.uxbert-toolbar-title{flex:1;font-size:14px;font-weight:600}.uxbert-toolbar-exit,.uxbert-toolbar-minimize{align-items:center;background:var(--uxbert-border);border:none;border-radius:6px;color:var(--uxbert-text);cursor:pointer;display:flex;font-size:20px;font-weight:700;height:32px;justify-content:center;transition:all .2s ease;width:32px}.uxbert-toolbar-exit{background:var(--uxbert-danger);color:#fff}.uxbert-toolbar-minimize:hover{background:#d1d5db;transform:scale(1.1)}.uxbert-toolbar-exit:hover{background:#dc2626;transform:scale(1.1)}.uxbert-toolbar-tools{display:flex;flex-wrap:wrap;gap:8px}.uxbert-tool-btn{align-items:center;background:var(--uxbert-bg);border:2px solid var(--uxbert-border);border-radius:6px;cursor:pointer;display:flex;font-family:Arial,sans-serif;font-size:18px;font-weight:700;height:40px;justify-content:center;transition:all .2s ease;width:40px}.uxbert-tool-btn.active,.uxbert-tool-btn:hover{background:var(--uxbert-primary);border-color:var(--uxbert-primary);color:#fff}.uxbert-color-picker{display:flex;gap:6px;margin:8px 0}.uxbert-color-option{border:2px solid var(--uxbert-border);border-radius:50%;cursor:pointer;height:32px;transition:transform .2s ease;width:32px}.uxbert-color-option:hover{transform:scale(1.1)}.uxbert-color-option.active{border:3px solid var(--uxbert-text)}.uxbert-canvas-overlay{cursor:crosshair;display:none;left:0;position:absolute;top:0;z-index:var(--uxbert-z-canvas)}.uxbert-canvas-overlay.active{display:block}.uxbert-canvas-overlay.viewport-mode{left:0;position:fixed;top:0}.uxbert-text-input{background:hsla(0,0%,100%,.95);border:2px solid var(--uxbert-primary);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.15);color:var(--uxbert-text);font-family:Arial,sans-serif;font-size:16px;font-weight:700;min-width:200px;outline:none;padding:8px 12px;z-index:var(--uxbert-z-toolbar)}.uxbert-text-input:focus{border-color:var(--uxbert-primary-hover);box-shadow:0 4px 16px rgba(79,70,229,.3)}.uxbert-text-input::placeholder{color:#9ca3af;font-weight:400}@media (max-width:768px){.uxbert-modal{max-height:95vh;padding:16px;width:95%}.uxbert-toolbar{bottom:90px;left:16px;max-height:60vh;right:16px;width:auto}.uxbert-toolbar-toggle{bottom:16px;height:56px;right:16px;width:56px}.uxbert-fab{font-size:20px;height:48px;width:48px}.uxbert-color-picker,.uxbert-toolbar-tools{justify-content:center}}";
|
10259
10553
|
styleInject(css_248z);
|
10260
10554
|
|
10261
10555
|
// Main initialization file
|
@@ -10287,7 +10581,9 @@ class Reportly {
|
|
10287
10581
|
this.state = new State();
|
10288
10582
|
this.deviceInfo = new DeviceInfo();
|
10289
10583
|
this.screenshot = new Screenshot();
|
10290
|
-
|
10584
|
+
// Initialize export with n8n config if provided
|
10585
|
+
const n8nConfig = userConfig.integrations?.n8n;
|
10586
|
+
this.export = new Export(n8nConfig);
|
10291
10587
|
// Initialize UI components
|
10292
10588
|
this.button = new Button(this.config, {
|
10293
10589
|
onClick: () => this.handleButtonClick(),
|
@@ -10298,6 +10594,7 @@ class Reportly {
|
|
10298
10594
|
onAnnotate: () => this.startAnnotation(),
|
10299
10595
|
onRetake: () => this.retakeScreenshot(),
|
10300
10596
|
onCapture: () => this.captureWithMode(),
|
10597
|
+
onSendToN8n: (issueData) => this.handleN8nSubmit(issueData),
|
10301
10598
|
});
|
10302
10599
|
this.toolbar = new Toolbar({
|
10303
10600
|
onToolChange: (tool) => this.annotation?.setTool(tool),
|
@@ -10313,6 +10610,10 @@ class Reportly {
|
|
10313
10610
|
this.modal.create();
|
10314
10611
|
this.toolbar.create();
|
10315
10612
|
this.annotation.createCanvas();
|
10613
|
+
// Show/hide n8n button based on configuration
|
10614
|
+
if (this.export.isN8nEnabled()) {
|
10615
|
+
this.modal.setN8nButtonVisible(true);
|
10616
|
+
}
|
10316
10617
|
// Setup keyboard shortcuts
|
10317
10618
|
this.setupKeyboardShortcuts();
|
10318
10619
|
this.isInitialized = true;
|
@@ -10440,6 +10741,54 @@ class Reportly {
|
|
10440
10741
|
alert("Failed to export issue. Please try again.");
|
10441
10742
|
}
|
10442
10743
|
}
|
10744
|
+
async handleN8nSubmit(issueData) {
|
10745
|
+
try {
|
10746
|
+
// Create complete issue package
|
10747
|
+
const completeIssue = {
|
10748
|
+
...issueData,
|
10749
|
+
screenshot: this.state?.getScreenshot() || "",
|
10750
|
+
deviceInfo: this.deviceInfo.get(),
|
10751
|
+
createdAt: new Date().toISOString(),
|
10752
|
+
};
|
10753
|
+
// Show loading state
|
10754
|
+
const n8nBtn = document.querySelector('#uxbert-n8n-btn');
|
10755
|
+
if (n8nBtn) {
|
10756
|
+
n8nBtn.disabled = true;
|
10757
|
+
n8nBtn.textContent = '⏳ Sending...';
|
10758
|
+
}
|
10759
|
+
// Send to n8n
|
10760
|
+
const response = await this.export?.sendToN8n(completeIssue);
|
10761
|
+
if (response?.success) {
|
10762
|
+
// Emit event
|
10763
|
+
this.state?.emit("issue:sent-to-n8n", completeIssue);
|
10764
|
+
// Reset state
|
10765
|
+
this.state?.reset();
|
10766
|
+
this.annotation?.clear();
|
10767
|
+
this.modal?.close();
|
10768
|
+
alert("Issue sent to n8n successfully!");
|
10769
|
+
console.log("Issue sent to n8n successfully");
|
10770
|
+
}
|
10771
|
+
else {
|
10772
|
+
alert(`Failed to send to n8n: ${response?.message || 'Unknown error'}`);
|
10773
|
+
console.error("Failed to send to n8n:", response?.error);
|
10774
|
+
}
|
10775
|
+
// Reset button state
|
10776
|
+
if (n8nBtn) {
|
10777
|
+
n8nBtn.disabled = false;
|
10778
|
+
n8nBtn.textContent = '🚀 Send to n8n';
|
10779
|
+
}
|
10780
|
+
}
|
10781
|
+
catch (error) {
|
10782
|
+
console.error("Failed to send to n8n:", error);
|
10783
|
+
alert("Failed to send to n8n. Please try again.");
|
10784
|
+
// Reset button state
|
10785
|
+
const n8nBtn = document.querySelector('#uxbert-n8n-btn');
|
10786
|
+
if (n8nBtn) {
|
10787
|
+
n8nBtn.disabled = false;
|
10788
|
+
n8nBtn.textContent = '🚀 Send to n8n';
|
10789
|
+
}
|
10790
|
+
}
|
10791
|
+
}
|
10443
10792
|
handleModalClose() {
|
10444
10793
|
this.annotation?.hide();
|
10445
10794
|
this.toolbar?.hide();
|
@@ -10468,6 +10817,24 @@ class Reportly {
|
|
10468
10817
|
exportAllIssues() {
|
10469
10818
|
this.export?.exportAllIssues();
|
10470
10819
|
}
|
10820
|
+
// n8n Integration API methods
|
10821
|
+
configureN8n(webhookUrl, enabled = true, options) {
|
10822
|
+
this.export?.configureN8n({
|
10823
|
+
webhookUrl,
|
10824
|
+
enabled,
|
10825
|
+
headers: options?.headers,
|
10826
|
+
timeout: options?.timeout
|
10827
|
+
});
|
10828
|
+
// Update button visibility
|
10829
|
+
this.modal?.setN8nButtonVisible(enabled);
|
10830
|
+
}
|
10831
|
+
enableN8n(enabled) {
|
10832
|
+
this.export?.setN8nEnabled(enabled);
|
10833
|
+
this.modal?.setN8nButtonVisible(enabled);
|
10834
|
+
}
|
10835
|
+
testN8nConnection() {
|
10836
|
+
return this.export?.testN8nConnection() || Promise.resolve({ success: false, message: 'Not initialized' });
|
10837
|
+
}
|
10471
10838
|
on(event, callback) {
|
10472
10839
|
this.state?.on(event, callback);
|
10473
10840
|
}
|