@crowdin/app-project-module 0.37.0 → 0.39.0

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.
@@ -33,7 +33,9 @@
33
33
  </div>
34
34
  </crowdin-alert>
35
35
  {{/if}}
36
- <div>
36
+ <div id="buttons">
37
+ <crowdin-button id="show-integration-btn" class="hidden" icon-before="arrow_back" onclick="showIntegration();">Integration</crowdin-button>
38
+ <crowdin-button id="show-error-logs-btn" icon-before="list" onclick="showErrorLogs();">Error logs</crowdin-button>
37
39
  {{#if infoModal}}
38
40
  <crowdin-button icon-before="info" onclick="infoModal.open();">{{infoModal.title}}</crowdin-button>
39
41
  {{/if}}
@@ -87,6 +89,16 @@
87
89
  {{/if}}
88
90
  >
89
91
  </crowdin-simple-integration>
92
+ <div id="user-errors" class="hidden">
93
+ <crowdin-alert title="Error Logs">This table displays the most recent error logs from the past month. Logs older than one month will be automatically deleted.</crowdin-alert>
94
+ <crowdin-show-as-table
95
+ is-loading
96
+ id="user-errors-table"
97
+ is-searchable
98
+ total-records="25"
99
+ search-placeholder="Search something"
100
+ ></crowdin-show-as-table>
101
+ </div>
90
102
  </div>
91
103
  <crowdin-toasts></crowdin-toasts>
92
104
  <crowdin-modal id="subscription-modal" modal-width="50" close-button="false">
@@ -256,6 +268,13 @@
256
268
  </div>
257
269
  </crowdin-modal>
258
270
  {{/or}}
271
+
272
+ <crowdin-modal
273
+ id="user-error-detail"
274
+ close-button-title="Close"
275
+ close-button="true"
276
+ >
277
+ </crowdin-modal>
259
278
  </body>
260
279
  <script type="text/javascript">
261
280
  document.body.addEventListener('refreshFilesList', (e) => {
@@ -491,95 +510,94 @@
491
510
  }
492
511
 
493
512
  {{#if configurationFields}}
494
- const settingsModal = document.getElementById('settings-modal');
495
- const settingsSaveBtn = document.getElementById('settings-save-btn');
496
- let config = JSON.parse('{{{config}}}');
497
-
498
- function triggerEvent(el, type) {
499
- const e = document.createEvent('HTMLEvents');
500
- e.initEvent(type, false, true);
501
- el.dispatchEvent(e);
502
- }
513
+ const settingsModal = document.getElementById('settings-modal');
514
+ const settingsSaveBtn = document.getElementById('settings-save-btn');
515
+ let config = JSON.parse('{{{config}}}');
516
+
517
+ function triggerEvent(el, type) {
518
+ const e = document.createEvent('HTMLEvents');
519
+ e.initEvent(type, false, true);
520
+ el.dispatchEvent(e);
521
+ }
503
522
 
504
- function fillSettingsForm() {
505
- Object.entries(config).forEach(([key, value]) => {
506
- const el = document.getElementById(`${key}-settings`);
507
- if (el && (value || el.tagName.toLowerCase() === 'crowdin-checkbox')) {
508
- if (el.tagName.toLowerCase() === 'crowdin-select') {
509
- if (el.hasAttribute('is-multi')) {
510
- el.value = JSON.stringify(value);
523
+ function fillSettingsForm() {
524
+ Object.entries(config).forEach(([key, value]) => {
525
+ const el = document.getElementById(`${key}-settings`);
526
+ if (el && (value || el.tagName.toLowerCase() === 'crowdin-checkbox')) {
527
+ if (el.tagName.toLowerCase() === 'crowdin-select') {
528
+ if (el.hasAttribute('is-multi')) {
529
+ el.value = JSON.stringify(value);
530
+ } else {
531
+ el.value = JSON.stringify([value]);
532
+ }
533
+ } else if (el.tagName.toLowerCase() === 'crowdin-checkbox') {
534
+ el.checked = !!value;
511
535
  } else {
512
- el.value = JSON.stringify([value]);
536
+ el.value = value;
513
537
  }
514
- } else if (el.tagName.toLowerCase() === 'crowdin-checkbox') {
515
- el.checked = !!value;
516
- } else {
517
- el.value = value;
518
- }
519
538
 
520
- triggerEvent(el, 'change');
521
- }
522
- });
523
- }
524
-
525
- function saveSettings() {
526
- setLoader();
527
- const settingsElements = Array.from(document.getElementById('modal-content').children);
528
- const tags = ['crowdin-checkbox', 'crowdin-select', 'crowdin-input'];
529
- const configReq = {};
530
- settingsElements
531
- .filter(e => tags.includes(e.tagName.toLowerCase()))
532
- .forEach(e => {
533
- const key = e.getAttribute('key');
534
- let value;
535
- if (e.tagName.toLowerCase() === 'crowdin-select') {
536
- value = JSON.parse(e.value);
537
- if (!e.hasAttribute('is-multi')) {
538
- value = value.length > 0 ? value[0] : undefined;
539
- }
540
- } else if (e.tagName.toLowerCase() === 'crowdin-checkbox') {
541
- value = !!e.checked;
542
- } else {
543
- value = e.value;
539
+ triggerEvent(el, 'change');
544
540
  }
545
- configReq[key] = value;
546
541
  });
547
- settingsSaveBtn.setAttribute('disabled', true);
548
- checkOrigin()
549
- .then(restParams => fetch('api/settings' + restParams, {
550
- method: 'POST',
551
- headers: { 'Content-Type': 'application/json' },
552
- body: JSON.stringify({ config: configReq })
553
- }))
554
- .then(checkResponse)
555
- .then(() => {
556
- showToast('Settings successfully saved');
557
- config = configReq;
558
- })
559
- .catch(e => catchRejection(e, 'Can\'t save settings'))
560
- .finally(() => {
561
- unsetLoader();
562
- settingsSaveBtn.removeAttribute('disabled');
563
- settingsModal.close();
564
- {{#if reloadOnConfigSave}}
565
- getIntegrationData(true);
566
- getCrowdinData();
567
- {{/if}}
568
- });
569
- }
542
+ }
570
543
 
571
- function setLoader() {
572
- const loader = document.querySelector('#settings-modal .loader');
573
- loader.classList.remove('hidden');
574
- }
544
+ function saveSettings() {
545
+ setLoader();
546
+ const settingsElements = Array.from(document.getElementById('modal-content').children);
547
+ const tags = ['crowdin-checkbox', 'crowdin-select', 'crowdin-input'];
548
+ const configReq = {};
549
+ settingsElements
550
+ .filter(e => tags.includes(e.tagName.toLowerCase()))
551
+ .forEach(e => {
552
+ const key = e.getAttribute('key');
553
+ let value;
554
+ if (e.tagName.toLowerCase() === 'crowdin-select') {
555
+ value = JSON.parse(e.value);
556
+ if (!e.hasAttribute('is-multi')) {
557
+ value = value.length > 0 ? value[0] : undefined;
558
+ }
559
+ } else if (e.tagName.toLowerCase() === 'crowdin-checkbox') {
560
+ value = !!e.checked;
561
+ } else {
562
+ value = e.value;
563
+ }
564
+ configReq[key] = value;
565
+ });
566
+ settingsSaveBtn.setAttribute('disabled', true);
567
+ checkOrigin()
568
+ .then(restParams => fetch('api/settings' + restParams, {
569
+ method: 'POST',
570
+ headers: { 'Content-Type': 'application/json' },
571
+ body: JSON.stringify({ config: configReq })
572
+ }))
573
+ .then(checkResponse)
574
+ .then(() => {
575
+ showToast('Settings successfully saved');
576
+ config = configReq;
577
+ })
578
+ .catch(e => catchRejection(e, 'Can\'t save settings'))
579
+ .finally(() => {
580
+ unsetLoader();
581
+ settingsSaveBtn.removeAttribute('disabled');
582
+ settingsModal.close();
583
+ {{#if reloadOnConfigSave}}
584
+ getIntegrationData(true);
585
+ getCrowdinData();
586
+ {{/if}}
587
+ });
588
+ }
575
589
 
576
- function unsetLoader() {
577
- const loader = document.querySelector('#settings-modal .loader');
578
- setTimeout(function() {
579
- loader.classList.add('hidden');
580
- }, 500)
581
- }
590
+ function setLoader() {
591
+ const loader = document.querySelector('#settings-modal .loader');
592
+ loader.classList.remove('hidden');
593
+ }
582
594
 
595
+ function unsetLoader() {
596
+ const loader = document.querySelector('#settings-modal .loader');
597
+ setTimeout(function() {
598
+ loader.classList.add('hidden');
599
+ }, 500)
600
+ }
583
601
  {{else}}
584
602
  const settingsModal = undefined;
585
603
  {{/if}}
@@ -807,6 +825,95 @@
807
825
  const notice = document.getElementById('notice');
808
826
  checkAlert(notice, 'notice');
809
827
  {{/if}}
828
+
829
+ function showErrorLogs() {
830
+ document.getElementById('show-error-logs-btn').classList.add('hidden');
831
+ document.getElementById('show-integration-btn').classList.remove('hidden');
832
+
833
+ appComponent.classList.add('hidden');
834
+ document.getElementById('user-errors').classList.remove('hidden');
835
+
836
+ checkOrigin()
837
+ .then(restParams => fetch('api/user-errors' + restParams))
838
+ .then(checkResponse)
839
+ .then((res) => {
840
+ const table = document.getElementById('user-errors-table');
841
+
842
+ const clickRow = (field, index, item) => {
843
+ const modal = document.getElementById('user-error-detail');
844
+ modal.open();
845
+ modal.innerHTML = getUserErrorDetail(item);
846
+ };
847
+
848
+ table.setTableConfig && table.setTableConfig({
849
+ defaultSortingColumn: "createdAt",
850
+ defaultSortingDir: "desc",
851
+ headerFields: [
852
+ {
853
+ field: "createdAt",
854
+ name: "Date",
855
+ isSortable: true,
856
+ clickFn: clickRow,
857
+ },
858
+ {
859
+ field: "action",
860
+ name: "Action",
861
+ clickFn: clickRow,
862
+ },
863
+ {
864
+ field: "message",
865
+ name: "Message",
866
+ clickFn: clickRow,
867
+ }
868
+ ],
869
+ });
870
+
871
+ table.setTableData(JSON.stringify(res));
872
+ table.setAttribute(`is-loading`, false);
873
+ })
874
+ .catch(e => catchRejection(e, 'Can\'t fetch error logs'));
875
+ }
876
+
877
+ function showIntegration() {
878
+ document.getElementById('show-error-logs-btn').classList.remove('hidden');
879
+ document.getElementById('show-integration-btn').classList.add('hidden');
880
+
881
+ appComponent.classList.remove('hidden');
882
+ document.getElementById('user-errors').classList.add('hidden');
883
+ }
884
+
885
+ function getUserErrorDetail(error) {
886
+ const data = JSON.parse(error.data);
887
+
888
+ let html = '<div class="error-detail-table"><table>';
889
+ html += `<tr><td>Action</td><td>${error.action}</td></tr>`;
890
+ html += `<tr><td>Message</td><td>${error.message}</td></tr>`;
891
+ html += `<tr><td>Date/time</td><td>${error.createdAt}</td></tr>`;
892
+
893
+ if (data.requestParams) {
894
+ html += `<tr><td>Method</td><td>${data.requestParams.method}</td></tr>`;
895
+ }
896
+
897
+ if (data.responseData) {
898
+ html += `<tr><td>Response Data</td><td><pre>${JSON.stringify(data.responseData, null, 2)}</pre></td></tr>`;
899
+ }
900
+
901
+ if (data.appData) {
902
+ if (Array.isArray(data.appData)) {
903
+ html += `<tr><td>App Data</td><td><pre>${JSON.stringify(data.appData, null, 2)}</pre></td></tr>`;
904
+ } else if (typeof data.appData === 'object') {
905
+ for (const key in data.appData) {
906
+ html += `<tr><td>${key.charAt(0).toUpperCase() + key.slice(1)}</td><td><pre>${JSON.stringify(data.appData[key], null, 2)}</pre></td></tr>`;
907
+ }
908
+ } else {
909
+ html += `<tr><td>App Data</td><td>${data.appData}</td></tr>`;
910
+ }
911
+ }
912
+
913
+ html += '</table></div>';
914
+
915
+ return html;
916
+ }
810
917
  </script>
811
918
 
812
919
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "0.37.0",
3
+ "version": "0.39.0",
4
4
  "description": "Module that generates for you all common endpoints for serving standalone Crowdin App",
5
5
  "main": "out/index.js",
6
6
  "types": "out/index.d.ts",
@@ -16,8 +16,8 @@
16
16
  "dependencies": {
17
17
  "@aws-sdk/client-s3": "^3.423.0",
18
18
  "@aws-sdk/s3-request-presigner": "^3.423.0",
19
- "@crowdin/crowdin-apps-functions": "0.5.1",
20
- "@crowdin/logs-formatter": "^2.0.4",
19
+ "@crowdin/crowdin-apps-functions": "0.6.0",
20
+ "@crowdin/logs-formatter": "^2.0.6",
21
21
  "@godaddy/terminus": "^4.12.1",
22
22
  "@types/pg": "^8.10.3",
23
23
  "amqplib": "^0.10.3",