@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/reportly.js CHANGED
@@ -264,6 +264,9 @@ var Reportly = (function () {
264
264
  <button type="button" class="uxbert-btn uxbert-btn-secondary" id="uxbert-cancel-btn">
265
265
  Cancel
266
266
  </button>
267
+ <button type="button" class="uxbert-btn uxbert-btn-success" id="uxbert-n8n-btn" style="display: none;">
268
+ 🚀 Send to n8n
269
+ </button>
267
270
  <button type="submit" class="uxbert-btn uxbert-btn-primary" id="uxbert-submit-btn">
268
271
  📥 Download JSON
269
272
  </button>
@@ -318,6 +321,33 @@ var Reportly = (function () {
318
321
  this.callbacks.onRetake();
319
322
  }
320
323
  });
324
+ // n8n button
325
+ const n8nBtn = this.modal.querySelector('#uxbert-n8n-btn');
326
+ n8nBtn.addEventListener('click', () => {
327
+ this.handleN8nSubmit();
328
+ });
329
+ }
330
+ handleN8nSubmit() {
331
+ if (!this.modal)
332
+ return;
333
+ const titleInput = this.modal.querySelector('#uxbert-title');
334
+ const descriptionInput = this.modal.querySelector('#uxbert-description');
335
+ const prioritySelect = this.modal.querySelector('#uxbert-priority');
336
+ const title = titleInput.value;
337
+ const description = descriptionInput.value;
338
+ const priority = prioritySelect.value;
339
+ if (!title.trim()) {
340
+ alert('Please enter an issue title');
341
+ return;
342
+ }
343
+ const issueData = {
344
+ title: title.trim(),
345
+ description: description.trim(),
346
+ priority
347
+ };
348
+ if (this.callbacks.onSendToN8n) {
349
+ this.callbacks.onSendToN8n(issueData);
350
+ }
321
351
  }
322
352
  handleSubmit() {
323
353
  if (!this.modal)
@@ -376,6 +406,14 @@ var Reportly = (function () {
376
406
  const viewportRadio = this.modal.querySelector('#uxbert-capture-viewport');
377
407
  return viewportRadio.checked ? 'viewport' : 'fullpage';
378
408
  }
409
+ setN8nButtonVisible(visible) {
410
+ if (!this.modal)
411
+ return;
412
+ const n8nBtn = this.modal.querySelector('#uxbert-n8n-btn');
413
+ if (n8nBtn) {
414
+ n8nBtn.style.display = visible ? 'inline-block' : 'none';
415
+ }
416
+ }
379
417
  reset() {
380
418
  if (!this.modal)
381
419
  return;
@@ -9455,8 +9493,6 @@ var Reportly = (function () {
9455
9493
  }
9456
9494
  async capture(mode = "fullpage") {
9457
9495
  try {
9458
- // Show loading screen
9459
- this.showLoadingScreen();
9460
9496
  // Hide UXbert UI elements before capturing
9461
9497
  this.hideUXbertElements();
9462
9498
  const originalScrollY = window.scrollY;
@@ -9475,6 +9511,8 @@ var Reportly = (function () {
9475
9511
  x: window.scrollX,
9476
9512
  y: window.scrollY,
9477
9513
  onclone: async () => {
9514
+ // Show loading screen after clone (won't appear in screenshot)
9515
+ this.showLoadingScreen();
9478
9516
  // Wait 1 second after cloning to let animations complete
9479
9517
  await this.wait(1000);
9480
9518
  },
@@ -9515,6 +9553,10 @@ var Reportly = (function () {
9515
9553
  logging: false,
9516
9554
  width: fullPageWidth,
9517
9555
  height: fullPageHeight,
9556
+ onclone: async () => {
9557
+ // Show loading screen after clone (won't appear in screenshot)
9558
+ this.showLoadingScreen();
9559
+ },
9518
9560
  ignoreElements: (element) => {
9519
9561
  // Skip cross-origin images that might cause issues
9520
9562
  if (element.tagName === "IMG") {
@@ -10158,9 +10200,213 @@ var Reportly = (function () {
10158
10200
  }
10159
10201
  }
10160
10202
 
10203
+ class N8nIntegration {
10204
+ constructor(config) {
10205
+ this.config = config || null;
10206
+ }
10207
+ /**
10208
+ * Configure n8n integration
10209
+ */
10210
+ configure(config) {
10211
+ this.config = config;
10212
+ }
10213
+ /**
10214
+ * Check if n8n integration is configured and enabled
10215
+ */
10216
+ isEnabled() {
10217
+ return !!(this.config && this.config.enabled && this.config.webhookUrl);
10218
+ }
10219
+ /**
10220
+ * Send issue data to n8n webhook
10221
+ */
10222
+ async sendToN8n(issueData) {
10223
+ if (!this.config || !this.config.webhookUrl) {
10224
+ return {
10225
+ success: false,
10226
+ message: 'n8n webhook URL is not configured',
10227
+ error: 'MISSING_CONFIG'
10228
+ };
10229
+ }
10230
+ if (!this.config.enabled) {
10231
+ return {
10232
+ success: false,
10233
+ message: 'n8n integration is disabled',
10234
+ error: 'DISABLED'
10235
+ };
10236
+ }
10237
+ try {
10238
+ // Prepare payload
10239
+ const payload = this.preparePayload(issueData);
10240
+ // Setup request headers
10241
+ const headers = {
10242
+ 'Content-Type': 'application/json',
10243
+ ...this.config.headers
10244
+ };
10245
+ // Setup timeout
10246
+ const timeout = this.config.timeout || 30000; // 30 seconds default
10247
+ const controller = new AbortController();
10248
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
10249
+ // Send request
10250
+ const response = await fetch(this.config.webhookUrl, {
10251
+ method: 'POST',
10252
+ headers,
10253
+ body: JSON.stringify(payload),
10254
+ signal: controller.signal
10255
+ });
10256
+ clearTimeout(timeoutId);
10257
+ // Check response
10258
+ if (!response.ok) {
10259
+ const errorText = await response.text().catch(() => 'Unknown error');
10260
+ return {
10261
+ success: false,
10262
+ message: `n8n webhook request failed: ${response.status} ${response.statusText}`,
10263
+ error: errorText
10264
+ };
10265
+ }
10266
+ // Parse response
10267
+ let responseData;
10268
+ try {
10269
+ responseData = await response.json();
10270
+ }
10271
+ catch (e) {
10272
+ // Some webhooks don't return JSON
10273
+ responseData = { message: 'Success' };
10274
+ }
10275
+ return {
10276
+ success: true,
10277
+ message: 'Issue sent to n8n successfully',
10278
+ workflowId: responseData.workflowId || responseData.executionId
10279
+ };
10280
+ }
10281
+ catch (error) {
10282
+ if (error instanceof Error) {
10283
+ if (error.name === 'AbortError') {
10284
+ return {
10285
+ success: false,
10286
+ message: 'Request to n8n webhook timed out',
10287
+ error: 'TIMEOUT'
10288
+ };
10289
+ }
10290
+ return {
10291
+ success: false,
10292
+ message: `Failed to send issue to n8n: ${error.message}`,
10293
+ error: error.message
10294
+ };
10295
+ }
10296
+ return {
10297
+ success: false,
10298
+ message: 'Unknown error occurred while sending to n8n',
10299
+ error: 'UNKNOWN'
10300
+ };
10301
+ }
10302
+ }
10303
+ /**
10304
+ * Prepare payload for n8n webhook
10305
+ * This formats the data in a structure that's easy to work with in n8n
10306
+ */
10307
+ preparePayload(issueData) {
10308
+ return {
10309
+ // Main issue data
10310
+ issue: {
10311
+ title: issueData.title,
10312
+ description: issueData.description,
10313
+ priority: issueData.priority,
10314
+ createdAt: issueData.createdAt
10315
+ },
10316
+ // Screenshot data (base64)
10317
+ screenshot: {
10318
+ data: issueData.screenshot,
10319
+ format: 'base64',
10320
+ mimeType: 'image/png'
10321
+ },
10322
+ // Device and browser information
10323
+ context: {
10324
+ browser: issueData.deviceInfo.browser,
10325
+ os: issueData.deviceInfo.os,
10326
+ screenResolution: issueData.deviceInfo.screenResolution,
10327
+ viewport: issueData.deviceInfo.viewport,
10328
+ url: issueData.deviceInfo.url,
10329
+ userAgent: issueData.deviceInfo.userAgent,
10330
+ language: issueData.deviceInfo.language,
10331
+ platform: issueData.deviceInfo.platform,
10332
+ cookiesEnabled: issueData.deviceInfo.cookiesEnabled,
10333
+ onLine: issueData.deviceInfo.onLine,
10334
+ timestamp: issueData.deviceInfo.timestamp
10335
+ },
10336
+ // Metadata for tracking
10337
+ metadata: {
10338
+ source: 'uxbert-reportly',
10339
+ version: '1.0.0',
10340
+ timestamp: new Date().toISOString()
10341
+ }
10342
+ };
10343
+ }
10344
+ /**
10345
+ * Test connection to n8n webhook
10346
+ */
10347
+ async testConnection() {
10348
+ if (!this.config || !this.config.webhookUrl) {
10349
+ return {
10350
+ success: false,
10351
+ message: 'n8n webhook URL is not configured',
10352
+ error: 'MISSING_CONFIG'
10353
+ };
10354
+ }
10355
+ try {
10356
+ const controller = new AbortController();
10357
+ const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout for test
10358
+ await fetch(this.config.webhookUrl, {
10359
+ method: 'HEAD',
10360
+ signal: controller.signal
10361
+ });
10362
+ clearTimeout(timeoutId);
10363
+ return {
10364
+ success: true,
10365
+ message: 'n8n webhook is reachable'
10366
+ };
10367
+ }
10368
+ catch (error) {
10369
+ return {
10370
+ success: false,
10371
+ message: 'Failed to reach n8n webhook',
10372
+ error: error instanceof Error ? error.message : 'UNKNOWN'
10373
+ };
10374
+ }
10375
+ }
10376
+ /**
10377
+ * Get current configuration
10378
+ */
10379
+ getConfig() {
10380
+ return this.config;
10381
+ }
10382
+ /**
10383
+ * Update webhook URL
10384
+ */
10385
+ setWebhookUrl(url) {
10386
+ if (!this.config) {
10387
+ this.config = {
10388
+ webhookUrl: url,
10389
+ enabled: true
10390
+ };
10391
+ }
10392
+ else {
10393
+ this.config.webhookUrl = url;
10394
+ }
10395
+ }
10396
+ /**
10397
+ * Enable/disable n8n integration
10398
+ */
10399
+ setEnabled(enabled) {
10400
+ if (this.config) {
10401
+ this.config.enabled = enabled;
10402
+ }
10403
+ }
10404
+ }
10405
+
10161
10406
  class Export {
10162
- constructor() {
10407
+ constructor(n8nConfig) {
10163
10408
  this.savedIssues = this.loadSavedIssues();
10409
+ this.n8nIntegration = new N8nIntegration(n8nConfig);
10164
10410
  }
10165
10411
  exportToJSON(issueData) {
10166
10412
  const json = JSON.stringify(issueData, null, 2);
@@ -10229,6 +10475,54 @@ var Reportly = (function () {
10229
10475
  document.body.removeChild(link);
10230
10476
  URL.revokeObjectURL(url);
10231
10477
  }
10478
+ // n8n Integration Methods
10479
+ /**
10480
+ * Send issue to n8n webhook
10481
+ */
10482
+ async sendToN8n(issueData) {
10483
+ const response = await this.n8nIntegration.sendToN8n(issueData);
10484
+ // Save to localStorage if n8n send was successful
10485
+ if (response.success) {
10486
+ this.saveIssue(issueData);
10487
+ }
10488
+ return response;
10489
+ }
10490
+ /**
10491
+ * Configure n8n integration
10492
+ */
10493
+ configureN8n(config) {
10494
+ this.n8nIntegration.configure(config);
10495
+ }
10496
+ /**
10497
+ * Check if n8n is enabled
10498
+ */
10499
+ isN8nEnabled() {
10500
+ return this.n8nIntegration.isEnabled();
10501
+ }
10502
+ /**
10503
+ * Test n8n connection
10504
+ */
10505
+ async testN8nConnection() {
10506
+ return this.n8nIntegration.testConnection();
10507
+ }
10508
+ /**
10509
+ * Get n8n configuration
10510
+ */
10511
+ getN8nConfig() {
10512
+ return this.n8nIntegration.getConfig();
10513
+ }
10514
+ /**
10515
+ * Enable/disable n8n integration
10516
+ */
10517
+ setN8nEnabled(enabled) {
10518
+ this.n8nIntegration.setEnabled(enabled);
10519
+ }
10520
+ /**
10521
+ * Set n8n webhook URL
10522
+ */
10523
+ setN8nWebhookUrl(url) {
10524
+ this.n8nIntegration.setWebhookUrl(url);
10525
+ }
10232
10526
  }
10233
10527
 
10234
10528
  function styleInject(css, ref) {
@@ -10258,7 +10552,7 @@ var Reportly = (function () {
10258
10552
  }
10259
10553
  }
10260
10554
 
10261
- 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}}";
10555
+ 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}}";
10262
10556
  styleInject(css_248z);
10263
10557
 
10264
10558
  // Main initialization file
@@ -10290,7 +10584,9 @@ var Reportly = (function () {
10290
10584
  this.state = new State();
10291
10585
  this.deviceInfo = new DeviceInfo();
10292
10586
  this.screenshot = new Screenshot();
10293
- this.export = new Export();
10587
+ // Initialize export with n8n config if provided
10588
+ const n8nConfig = userConfig.integrations?.n8n;
10589
+ this.export = new Export(n8nConfig);
10294
10590
  // Initialize UI components
10295
10591
  this.button = new Button(this.config, {
10296
10592
  onClick: () => this.handleButtonClick(),
@@ -10301,6 +10597,7 @@ var Reportly = (function () {
10301
10597
  onAnnotate: () => this.startAnnotation(),
10302
10598
  onRetake: () => this.retakeScreenshot(),
10303
10599
  onCapture: () => this.captureWithMode(),
10600
+ onSendToN8n: (issueData) => this.handleN8nSubmit(issueData),
10304
10601
  });
10305
10602
  this.toolbar = new Toolbar({
10306
10603
  onToolChange: (tool) => this.annotation?.setTool(tool),
@@ -10316,6 +10613,10 @@ var Reportly = (function () {
10316
10613
  this.modal.create();
10317
10614
  this.toolbar.create();
10318
10615
  this.annotation.createCanvas();
10616
+ // Show/hide n8n button based on configuration
10617
+ if (this.export.isN8nEnabled()) {
10618
+ this.modal.setN8nButtonVisible(true);
10619
+ }
10319
10620
  // Setup keyboard shortcuts
10320
10621
  this.setupKeyboardShortcuts();
10321
10622
  this.isInitialized = true;
@@ -10443,6 +10744,54 @@ var Reportly = (function () {
10443
10744
  alert("Failed to export issue. Please try again.");
10444
10745
  }
10445
10746
  }
10747
+ async handleN8nSubmit(issueData) {
10748
+ try {
10749
+ // Create complete issue package
10750
+ const completeIssue = {
10751
+ ...issueData,
10752
+ screenshot: this.state?.getScreenshot() || "",
10753
+ deviceInfo: this.deviceInfo.get(),
10754
+ createdAt: new Date().toISOString(),
10755
+ };
10756
+ // Show loading state
10757
+ const n8nBtn = document.querySelector('#uxbert-n8n-btn');
10758
+ if (n8nBtn) {
10759
+ n8nBtn.disabled = true;
10760
+ n8nBtn.textContent = '⏳ Sending...';
10761
+ }
10762
+ // Send to n8n
10763
+ const response = await this.export?.sendToN8n(completeIssue);
10764
+ if (response?.success) {
10765
+ // Emit event
10766
+ this.state?.emit("issue:sent-to-n8n", completeIssue);
10767
+ // Reset state
10768
+ this.state?.reset();
10769
+ this.annotation?.clear();
10770
+ this.modal?.close();
10771
+ alert("Issue sent to n8n successfully!");
10772
+ console.log("Issue sent to n8n successfully");
10773
+ }
10774
+ else {
10775
+ alert(`Failed to send to n8n: ${response?.message || 'Unknown error'}`);
10776
+ console.error("Failed to send to n8n:", response?.error);
10777
+ }
10778
+ // Reset button state
10779
+ if (n8nBtn) {
10780
+ n8nBtn.disabled = false;
10781
+ n8nBtn.textContent = '🚀 Send to n8n';
10782
+ }
10783
+ }
10784
+ catch (error) {
10785
+ console.error("Failed to send to n8n:", error);
10786
+ alert("Failed to send to n8n. Please try again.");
10787
+ // Reset button state
10788
+ const n8nBtn = document.querySelector('#uxbert-n8n-btn');
10789
+ if (n8nBtn) {
10790
+ n8nBtn.disabled = false;
10791
+ n8nBtn.textContent = '🚀 Send to n8n';
10792
+ }
10793
+ }
10794
+ }
10446
10795
  handleModalClose() {
10447
10796
  this.annotation?.hide();
10448
10797
  this.toolbar?.hide();
@@ -10471,6 +10820,24 @@ var Reportly = (function () {
10471
10820
  exportAllIssues() {
10472
10821
  this.export?.exportAllIssues();
10473
10822
  }
10823
+ // n8n Integration API methods
10824
+ configureN8n(webhookUrl, enabled = true, options) {
10825
+ this.export?.configureN8n({
10826
+ webhookUrl,
10827
+ enabled,
10828
+ headers: options?.headers,
10829
+ timeout: options?.timeout
10830
+ });
10831
+ // Update button visibility
10832
+ this.modal?.setN8nButtonVisible(enabled);
10833
+ }
10834
+ enableN8n(enabled) {
10835
+ this.export?.setN8nEnabled(enabled);
10836
+ this.modal?.setN8nButtonVisible(enabled);
10837
+ }
10838
+ testN8nConnection() {
10839
+ return this.export?.testN8nConnection() || Promise.resolve({ success: false, message: 'Not initialized' });
10840
+ }
10474
10841
  on(event, callback) {
10475
10842
  this.state?.on(event, callback);
10476
10843
  }