@crowdin/app-project-module 2.2.0 → 2.4.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.
Files changed (45) hide show
  1. package/out/middlewares/ui-module.js +1 -2
  2. package/out/modules/about.d.ts +4 -0
  3. package/out/modules/about.js +25 -3
  4. package/out/static/css/styles.css +2 -342
  5. package/out/static/ui/about.bundle.js +542 -0
  6. package/out/static/ui/about.bundle.js.map +1 -0
  7. package/out/static/ui/error.bundle.js +120 -2
  8. package/out/static/ui/error.bundle.js.map +1 -1
  9. package/out/static/ui/form.bundle.js +164 -12
  10. package/out/static/ui/form.bundle.js.map +1 -1
  11. package/out/static/ui/install.bundle.js +8 -2
  12. package/out/static/ui/install.bundle.js.map +1 -1
  13. package/out/static/ui/login.bundle.js +425 -35
  14. package/out/static/ui/login.bundle.js.map +1 -1
  15. package/out/static/ui/main.bundle.js +1798 -1377
  16. package/out/static/ui/main.bundle.js.map +1 -1
  17. package/out/static/ui/oauth.bundle.js +8 -2
  18. package/out/static/ui/oauth.bundle.js.map +1 -1
  19. package/out/static/ui/subscription.bundle.js +542 -0
  20. package/out/static/ui/subscription.bundle.js.map +1 -0
  21. package/out/storage/drizzle/postgresql/migrations/0002_equal_skrulls.sql +3 -0
  22. package/out/storage/drizzle/postgresql/migrations/meta/0002_snapshot.json +646 -0
  23. package/out/storage/drizzle/postgresql/migrations/meta/_journal.json +7 -0
  24. package/out/storage/drizzle/postgresql/schema.js +2 -1
  25. package/out/storage/drizzle/sqlite/migrations/0001_new_rhodey.sql +26 -0
  26. package/out/storage/drizzle/sqlite/migrations/meta/0001_snapshot.json +687 -0
  27. package/out/storage/drizzle/sqlite/migrations/meta/_journal.json +7 -0
  28. package/out/storage/drizzle/sqlite/schema.js +2 -1
  29. package/out/util/jsx-renderer.d.ts +2 -1
  30. package/out/util/jsx-renderer.js +8 -8
  31. package/out/views/FormPage.js +2 -2
  32. package/out/views/index.d.ts +0 -2
  33. package/out/views/index.js +1 -5
  34. package/out/views/layout/Head.js +0 -10
  35. package/package.json +5 -2
  36. package/out/static/css/about.css +0 -128
  37. package/out/static/css/crowdin-ui-colors.css +0 -115
  38. package/out/static/js/dependent.js +0 -315
  39. package/out/static/js/main.js +0 -96
  40. package/out/static/js/polyfills/fetch.js +0 -494
  41. package/out/static/js/polyfills/promise.js +0 -375
  42. package/out/views/AboutPage.d.ts +0 -10
  43. package/out/views/AboutPage.js +0 -88
  44. package/out/views/SubscriptionPage.d.ts +0 -7
  45. package/out/views/SubscriptionPage.js +0 -26
@@ -518,80 +518,1140 @@
518
518
 
519
519
  var clientExports = requireClient();
520
520
 
521
+ /// <reference path="../types.d.ts" />
522
+ const postPromises = {};
523
+ let isInitialized = false;
524
+ let origin = null;
525
+ let clientId = null;
526
+ let restParams = '';
527
+ function parseJson(value) {
528
+ try {
529
+ return JSON.parse(value);
530
+ }
531
+ catch {
532
+ return undefined;
533
+ }
534
+ }
535
+ function handleMessage(event) {
536
+ if (event.origin !== window.location.origin || typeof event.data !== 'string') {
537
+ return;
538
+ }
539
+ const eventData = parseJson(event.data);
540
+ if (!(eventData === null || eventData === void 0 ? void 0 : eventData.uid)) {
541
+ return;
542
+ }
543
+ const postPromise = postPromises[eventData.uid];
544
+ if (postPromise) {
545
+ delete postPromises[eventData.uid];
546
+ if (postPromise.timer) {
547
+ clearTimeout(postPromise.timer);
548
+ }
549
+ postPromise.resolve(eventData.data);
550
+ }
551
+ }
552
+ function initializeCrowdinIframeContext() {
553
+ if (isInitialized) {
554
+ return;
555
+ }
556
+ const urlParams = new URLSearchParams(window.location.search);
557
+ origin = urlParams.get('origin');
558
+ clientId = urlParams.get('client_id');
559
+ restParams = window.location.search;
560
+ JSON.parse(window.name);
561
+ window.addEventListener('message', handleMessage);
562
+ isInitialized = true;
563
+ }
564
+ function ensureInitialized() {
565
+ if (!isInitialized) {
566
+ initializeCrowdinIframeContext();
567
+ }
568
+ }
569
+ function showToast(message) {
570
+ if (message) {
571
+ const toasts = document.querySelector('crowdin-toasts');
572
+ if (toasts && toasts.pushToasts) {
573
+ toasts.pushToasts([message]);
574
+ }
575
+ }
576
+ }
577
+ function reloadLocation() {
578
+ ensureInitialized();
579
+ window.location.href =
580
+ window.location.protocol + '//' + window.location.host + window.location.pathname + restParams;
581
+ }
582
+ function catchRejection(e, message) {
583
+ var _a;
584
+ // session expired
585
+ if (e.code && e.code === 401) {
586
+ reloadLocation();
587
+ return;
588
+ }
589
+ // payment required
590
+ if (e.code && e.code === 402 && ((_a = window.app) === null || _a === void 0 ? void 0 : _a.subscriptionModal.current)) {
591
+ if (window.app.subscriptionLink) {
592
+ window.app.subscriptionLink.current = e.message || message;
593
+ }
594
+ window.app.openModal(window.app.subscriptionModal.current);
595
+ return;
596
+ }
597
+ showToast(e.message || message);
598
+ }
599
+ function checkResponse(response) {
600
+ return new Promise((resolve, reject) => {
601
+ if (response.status === 204) {
602
+ return resolve(undefined);
603
+ }
604
+ response
605
+ .json()
606
+ .then((res) => {
607
+ if (![200, 201, 202, 304].includes(response.status)) {
608
+ reject(res);
609
+ }
610
+ else {
611
+ if (res.message) {
612
+ setTimeout(() => showToast(res.message), 100);
613
+ }
614
+ resolve(res);
615
+ }
616
+ })
617
+ .catch((e) => {
618
+ reject(e);
619
+ });
620
+ });
621
+ }
622
+ function checkOrigin() {
623
+ ensureInitialized();
624
+ return new Promise((resolve) => {
625
+ AP.getJwtToken((jwtToken) => {
626
+ restParams = `?origin=${origin}&client_id=${clientId}&jwtToken=${jwtToken}`;
627
+ resolve(restParams);
628
+ });
629
+ });
630
+ }
631
+
632
+ function readPageProps() {
633
+ const element = document.getElementById('__PAGE_PROPS__');
634
+ return JSON.parse((element === null || element === void 0 ? void 0 : element.textContent) || '{}');
635
+ }
636
+
521
637
  var reactExports = requireReact();
522
638
 
523
- const renderConfigField = (field, settingsFieldChange, suffix = 'settings') => {
524
- var _a;
525
- if (!field.key) {
526
- return field.labelHtml ? (jsxRuntimeExports.jsx("crowdin-p", { ...(field.dependencySettings ? { 'data-dependency': field.dependencySettings } : {}), dangerouslySetInnerHTML: { __html: field.labelHtml } })) : (jsxRuntimeExports.jsx("crowdin-p", { ...(field.dependencySettings ? { 'data-dependency': field.dependencySettings } : {}), children: field.label }));
639
+ const dependencyShowClassName = 'dependency-show';
640
+ const events = ['input', 'change'];
641
+ function useFieldDependencies(refreshKey) {
642
+ const cleanupRef = reactExports.useRef(() => undefined);
643
+ const refreshDependencies = reactExports.useCallback(() => {
644
+ cleanupRef.current();
645
+ cleanupRef.current = initializeFieldDependencies();
646
+ }, []);
647
+ reactExports.useEffect(() => {
648
+ refreshDependencies();
649
+ return () => {
650
+ cleanupRef.current();
651
+ cleanupRef.current = () => undefined;
652
+ };
653
+ }, [refreshDependencies, refreshKey]);
654
+ return refreshDependencies;
655
+ }
656
+ function initializeFieldDependencies(root = document) {
657
+ const cleanupCallbacks = [];
658
+ const fields = Array.from(root.querySelectorAll('[data-dependency]'));
659
+ fields.forEach((field) => {
660
+ const dependency = field.dataset.dependency;
661
+ if (!dependency) {
662
+ return;
663
+ }
664
+ try {
665
+ const conditions = JSON.parse(dependency);
666
+ applyDependencyState(field, conditions);
667
+ cleanupCallbacks.push(...bindDependencyListeners(field, conditions));
668
+ }
669
+ catch (e) {
670
+ console.error('[Dependencies] Error parsing conditions for field:', field, e);
671
+ }
672
+ });
673
+ return () => {
674
+ cleanupCallbacks.forEach((cleanup) => cleanup());
675
+ };
676
+ }
677
+ function bindDependencyListeners(field, conditions) {
678
+ const cleanupCallbacks = [];
679
+ conditions.forEach((rules) => {
680
+ Object.keys(rules).forEach((selector) => {
681
+ const element = document.querySelector(selector);
682
+ if (!element) {
683
+ return;
684
+ }
685
+ events.forEach((event) => {
686
+ const listener = () => applyDependencyState(field, conditions);
687
+ element.addEventListener(event, listener);
688
+ cleanupCallbacks.push(() => element.removeEventListener(event, listener));
689
+ });
690
+ });
691
+ });
692
+ return cleanupCallbacks;
693
+ }
694
+ function applyDependencyState(field, conditions) {
695
+ if (checkConditions(conditions)) {
696
+ field.classList.add(dependencyShowClassName);
527
697
  }
528
- const commonProps = {
529
- id: `${field.key}-${suffix}`,
530
- _key: field.key,
531
- label: field.label,
532
- ...(field.helpText ? { 'help-text': field.helpText } : {}),
533
- ...(field.helpTextHtml ? { 'help-text-html': field.helpTextHtml } : {}),
534
- ...(field.dependencySettings ? { 'data-dependency': field.dependencySettings } : {}),
698
+ else {
699
+ field.classList.remove(dependencyShowClassName);
700
+ }
701
+ }
702
+ function checkConditions(conditions) {
703
+ return conditions.every((conditionObj) => {
704
+ const selectors = Object.keys(conditionObj);
705
+ return selectors.every((selector) => evaluateDependencyRule(selector, conditionObj[selector]));
706
+ });
707
+ }
708
+ function evaluateDependencyRule(selector, condition) {
709
+ const type = condition.type;
710
+ const currentValue = getValue(selector);
711
+ const checkValue = typeof condition.value === 'undefined' ? false : condition.value;
712
+ let minValue = typeof condition.min === 'undefined' ? false : Number.parseInt(String(condition.min), 10);
713
+ let maxValue = typeof condition.max === 'undefined' ? false : Number.parseInt(String(condition.max), 10);
714
+ const allowEmpty = typeof condition.empty === 'undefined' ? false : condition.empty;
715
+ const isEmpty = !allowEmpty && currentValue.length < 1;
716
+ const likeSelector = typeof condition.like === 'undefined' ? false : condition.like;
717
+ const likeSelectorValue = getValue(likeSelector);
718
+ const regExpPattern = typeof condition.pattern === 'undefined' ? false : condition.pattern;
719
+ const regExpModifier = typeof condition.modifier === 'undefined' ? 'gi' : condition.modifier;
720
+ const sign = typeof condition.sign === 'undefined' ? false : condition.sign;
721
+ const strict = typeof condition.strict === 'undefined' ? false : condition.strict;
722
+ const emptyTypes = ['empty', 'blank'];
723
+ const notEmptyTypes = ['!empty', 'notEmpty', 'not-empty', 'notempty'];
724
+ const equalTypes = ['equal', '=', '==', '==='];
725
+ const notEqualTypes = ['!equal', '!=', '!==', '!===', 'notEqual', 'not-equal', 'notequal'];
726
+ const regularExpressionTypes = ['regexp', 'exp', 'expression', 'match'];
727
+ if (type && emptyTypes.includes(type)) {
728
+ return currentValue.length < 1;
729
+ }
730
+ if (type && notEmptyTypes.includes(type)) {
731
+ return currentValue.length > 0;
732
+ }
733
+ if (type && equalTypes.includes(type)) {
734
+ if (isEmpty) {
735
+ return false;
736
+ }
737
+ if (likeSelector) {
738
+ return strict
739
+ ? likeSelectorValue.every((value) => currentValue.includes(value))
740
+ : likeSelectorValue.some((value) => currentValue.includes(value));
741
+ }
742
+ if (strict) {
743
+ if (checkValue && Array.isArray(checkValue)) {
744
+ return checkValue.every((value) => currentValue.includes(value));
745
+ }
746
+ if (checkValue && !Array.isArray(checkValue)) {
747
+ return currentValue.includes(checkValue);
748
+ }
749
+ }
750
+ else {
751
+ if (checkValue && Array.isArray(checkValue)) {
752
+ return checkValue.some((value) => currentValue.includes(value));
753
+ }
754
+ if (checkValue && !Array.isArray(checkValue)) {
755
+ return currentValue.includes(checkValue);
756
+ }
757
+ }
758
+ }
759
+ if (type && notEqualTypes.includes(type)) {
760
+ if (isEmpty) {
761
+ return false;
762
+ }
763
+ if (likeSelector) {
764
+ return strict
765
+ ? likeSelectorValue.every((value) => !currentValue.includes(value))
766
+ : likeSelectorValue.some((value) => !currentValue.includes(value));
767
+ }
768
+ if (strict) {
769
+ if (checkValue && Array.isArray(checkValue)) {
770
+ return checkValue.every((value) => !currentValue.includes(value));
771
+ }
772
+ if (checkValue && !Array.isArray(checkValue)) {
773
+ return !currentValue.includes(checkValue);
774
+ }
775
+ }
776
+ else {
777
+ if (checkValue && Array.isArray(checkValue)) {
778
+ return checkValue.some((value) => !currentValue.includes(value));
779
+ }
780
+ if (checkValue && !Array.isArray(checkValue)) {
781
+ return !currentValue.includes(checkValue);
782
+ }
783
+ }
784
+ }
785
+ if (type && regularExpressionTypes.includes(type) && regExpPattern) {
786
+ if (isEmpty) {
787
+ return false;
788
+ }
789
+ const exp = new RegExp(regExpPattern, regExpModifier);
790
+ return currentValue.every((value) => exp.test(String(value)));
791
+ }
792
+ if (type === 'length') {
793
+ if (isEmpty) {
794
+ return false;
795
+ }
796
+ if (checkValue && Array.isArray(checkValue)) {
797
+ minValue = Number.parseInt(String(checkValue[0]), 10);
798
+ maxValue = typeof checkValue[1] === 'undefined' ? false : Number.parseInt(String(checkValue[1]), 10);
799
+ }
800
+ if (checkValue && !Array.isArray(checkValue)) {
801
+ minValue = Number.parseInt(String(checkValue), 10);
802
+ maxValue = false;
803
+ }
804
+ const minBoundary = minValue === false ? 0 : minValue;
805
+ const maxBoundary = maxValue === false ? 0 : maxValue;
806
+ return currentValue.every((value) => {
807
+ const valueLength = String(value).length;
808
+ if (!maxValue) {
809
+ return valueLength >= minBoundary;
810
+ }
811
+ if (!minValue) {
812
+ return valueLength <= maxBoundary;
813
+ }
814
+ return valueLength >= minBoundary && valueLength <= maxBoundary;
815
+ });
816
+ }
817
+ if (type === 'range') {
818
+ if (isEmpty) {
819
+ return false;
820
+ }
821
+ if (checkValue && Array.isArray(checkValue)) {
822
+ minValue = Number.parseInt(String(checkValue[0]), 10);
823
+ maxValue = typeof checkValue[1] === 'undefined' ? false : Number.parseInt(String(checkValue[1]), 10);
824
+ }
825
+ const minBoundary = minValue === false ? 0 : minValue;
826
+ const maxBoundary = maxValue === false ? 0 : maxValue;
827
+ return currentValue.every((value) => {
828
+ const numericValue = Number.parseInt(String(value), 10);
829
+ if (!maxValue) {
830
+ return numericValue > minBoundary;
831
+ }
832
+ if (!minValue) {
833
+ return numericValue < maxBoundary;
834
+ }
835
+ return numericValue > minBoundary && numericValue < maxBoundary;
836
+ });
837
+ }
838
+ if (type === 'compare' && sign && checkValue) {
839
+ if (isEmpty) {
840
+ return false;
841
+ }
842
+ const numericCheckValue = Number.parseInt(String(checkValue), 10);
843
+ switch (sign) {
844
+ case '<':
845
+ return currentValue.every((value) => Number.parseInt(String(value), 10) < numericCheckValue);
846
+ case '<=':
847
+ return currentValue.every((value) => Number.parseInt(String(value), 10) <= numericCheckValue);
848
+ case '>':
849
+ return currentValue.every((value) => Number.parseInt(String(value), 10) > numericCheckValue);
850
+ case '>=':
851
+ return currentValue.every((value) => Number.parseInt(String(value), 10) >= numericCheckValue);
852
+ case '=':
853
+ case '==':
854
+ return currentValue.every((value) => Number.parseInt(String(value), 10) === numericCheckValue);
855
+ }
856
+ }
857
+ return false;
858
+ }
859
+ function getValue(selector) {
860
+ const values = [];
861
+ if (selector && document.querySelector(selector)) {
862
+ const inputType = document.querySelector(selector).tagName.toLowerCase();
863
+ let currentSelector = selector;
864
+ if (inputType === 'crowdin-select') {
865
+ currentSelector = `${selector} option:checked`;
866
+ }
867
+ if (inputType === 'crowdin-checkbox') {
868
+ currentSelector = `${selector}:not(input)`;
869
+ }
870
+ document.querySelectorAll(currentSelector).forEach((element) => {
871
+ const value = element.value || element.checked;
872
+ values.push(value);
873
+ });
874
+ }
875
+ return values.filter((value) => value !== '');
876
+ }
877
+
878
+ const IntegrationView = ({ appComponentRef, userErrorsTableRef, name, isErrorLogsVisible, syncNewElements, withCronSync, webhooks, integrationOneLevelFetching, integrationSearchListener, integrationPagination, filtering, integrationButtonMenuItems, crowdinButtonMenuItems, }) => {
879
+ var _a, _b;
880
+ return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("div", { style: { display: isErrorLogsVisible ? 'none' : undefined }, children: jsxRuntimeExports.jsx("crowdin-simple-integration", { ref: appComponentRef, "async-progress": true, ...((syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.crowdin) ? { 'skip-crowdin-auto-schedule': true } : {}), ...((syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.integration) ? { 'skip-integration-auto-schedule': true } : {}), ...((withCronSync === null || withCronSync === void 0 ? void 0 : withCronSync.crowdin) || (webhooks === null || webhooks === void 0 ? void 0 : webhooks.crowdin) ? { 'crowdin-schedule': 'true' } : {}), ...((withCronSync === null || withCronSync === void 0 ? void 0 : withCronSync.integration) || (webhooks === null || webhooks === void 0 ? void 0 : webhooks.integration) ? { 'integration-schedule': 'true' } : {}), ...(integrationOneLevelFetching ? { 'integration-one-level-fetching': 'true' } : {}), ...(integrationSearchListener ? { 'allow-integration-filter-change-listener': 'true' } : {}), ...(integrationPagination ? { 'integration-load-more-files': 'true' } : {}), "integration-name": name, "integration-logo": "logo.png", ...(((_a = integrationButtonMenuItems === null || integrationButtonMenuItems === void 0 ? void 0 : integrationButtonMenuItems.length) !== null && _a !== void 0 ? _a : 0) > 0
881
+ ? { 'integration-button-menu-items': integrationButtonMenuItems }
882
+ : {}), ...(((_b = crowdinButtonMenuItems === null || crowdinButtonMenuItems === void 0 ? void 0 : crowdinButtonMenuItems.length) !== null && _b !== void 0 ? _b : 0) > 0
883
+ ? { 'crowdin-button-menu-items': crowdinButtonMenuItems }
884
+ : {}), ...((filtering === null || filtering === void 0 ? void 0 : filtering.crowdinLanguages) ? { 'crowdin-filter': true } : {}), ...((filtering === null || filtering === void 0 ? void 0 : filtering.integrationFilterConfig)
885
+ ? {
886
+ 'integration-filter': true,
887
+ 'integration-filter-config': filtering.integrationFilterConfig,
888
+ }
889
+ : {}) }) }), jsxRuntimeExports.jsxs("div", { id: "user-errors", style: { display: isErrorLogsVisible ? undefined : 'none' }, children: [jsxRuntimeExports.jsx("crowdin-show-as-table", { ref: userErrorsTableRef, "is-loading": true, id: "user-errors-table", "is-searchable": true, "total-records": "25", "search-placeholder": "Search something" }), jsxRuntimeExports.jsx("crowdin-alert", { children: "This table displays the most recent error logs from the past month. Logs older than one month will be automatically deleted." })] })] }));
890
+ };
891
+
892
+ const TopBar = ({ notice, isNoticeVisible, checkSubscription, subscriptionInfo, isErrorLogsVisible, isManager, infoModal, hasSettings, isOwner, onCloseNotice, onShowIntegration, onShowErrorLogs, onShowPermissions, onOpenInfoModal, onOpenSettings, onLogout, }) => {
893
+ return (jsxRuntimeExports.jsxs("div", { className: "mb-2.5 text-right", children: [notice && (jsxRuntimeExports.jsxs("crowdin-alert", { id: "notice", title: notice.title, ...(!notice.icon ? { 'no-icon': 'true' } : {}), ...(notice.type ? { type: notice.type } : {}), style: { display: isNoticeVisible ? 'block' : 'none', marginBottom: '12px' }, children: [jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center", children: jsxRuntimeExports.jsx("p", { className: "m-0", dangerouslySetInnerHTML: { __html: notice.content } }) }), notice.close && (jsxRuntimeExports.jsx("crowdin-button", { onClick: () => onCloseNotice('notice'), class: "absolute top-0 right-0", icon: true, children: "close" }))] })), checkSubscription && (jsxRuntimeExports.jsx("crowdin-alert", { id: "subscription-info", "no-icon": "true", type: "warning", style: { display: subscriptionInfo ? 'block' : 'none', marginBottom: '12px' }, children: jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center", children: [jsxRuntimeExports.jsx("p", { className: "m-0", children: subscriptionInfo ? `Your trial expires in ${subscriptionInfo.daysLeft} days.` : '' }), jsxRuntimeExports.jsx("crowdin-button", { class: "ml-2", primary: true, onClick: () => {
894
+ if (subscriptionInfo === null || subscriptionInfo === void 0 ? void 0 : subscriptionInfo.subscribeLink) {
895
+ window.open(subscriptionInfo.subscribeLink, '_blank', 'noopener,noreferrer');
896
+ }
897
+ }, children: "Subscribe" })] }) })), jsxRuntimeExports.jsxs("div", { id: "buttons", className: "flex w-full items-center justify-between", children: [jsxRuntimeExports.jsxs("div", { className: "mr-auto", children: [jsxRuntimeExports.jsx("span", { style: { display: isErrorLogsVisible ? undefined : 'none' }, children: jsxRuntimeExports.jsx("crowdin-button", { id: "show-integration-btn", "icon-before": "arrow_back", onClick: onShowIntegration, children: "Integration" }) }), jsxRuntimeExports.jsx("span", { style: { display: isErrorLogsVisible ? 'none' : undefined }, children: jsxRuntimeExports.jsx("crowdin-button", { id: "show-error-logs-btn", "icon-before": "list", onClick: onShowErrorLogs, children: "Error logs" }) })] }), isManager && (jsxRuntimeExports.jsx("crowdin-button", { "icon-before": "link", onClick: onShowPermissions, children: "Share" })), infoModal && (jsxRuntimeExports.jsx("crowdin-button", { "icon-before": "info", onClick: onOpenInfoModal, children: infoModal.title })), hasSettings && (jsxRuntimeExports.jsx("crowdin-button", { "icon-before": "settings", onClick: onOpenSettings, children: "Settings" })), jsxRuntimeExports.jsx("crowdin-button", { ...(!isOwner ? { disabled: true, title: 'Only the owner can log out' } : {}), "icon-before": "account_circle", onClick: onLogout, children: "Log out" })] })] }));
898
+ };
899
+
900
+ const EMPTY_PERMISSION_VALUE = '―';
901
+ const getDefaultScheduleModalState = () => ({
902
+ type: null,
903
+ showNewFiles: true,
904
+ showAllFolderFiles: false,
905
+ newFiles: false,
906
+ newFilesClearSelection: false,
907
+ selectedFiles: true,
908
+ allFolderFiles: false,
909
+ });
910
+ const JOB_TYPE = {
911
+ updateCrowdin: 'updateCrowdin',
912
+ updateIntegration: 'updateIntegration',
913
+ updateTargetLanguages: 'updateTargetLanguages',
914
+ integrationSyncSettingsSave: 'integrationSyncSettingsSave',
915
+ crowdinSyncSettingsSave: 'crowdinSyncSettingsSave',
916
+ integrationSettingsSave: 'integrationSettingsSave',
917
+ };
918
+ const JOB_STATUS = {
919
+ created: 'created',
920
+ inProgress: 'inProgress',
921
+ failed: 'failed',
922
+ canceled: 'canceled',
923
+ finished: 'finished',
924
+ };
925
+ const FOLDER_TYPE = '0';
926
+ const FILE_TYPE = '1';
927
+ const BRANCH_TYPE = '2';
928
+
929
+ function isFolder(e) {
930
+ return !e.type && (e.nodeType === undefined || e.nodeType === FOLDER_TYPE || e.nodeType === BRANCH_TYPE);
931
+ }
932
+ function openModal(modal) {
933
+ if (!modal) {
934
+ return;
935
+ }
936
+ modal.style.display = 'block';
937
+ modal.open();
938
+ }
939
+ function closeModal(modal) {
940
+ if (!modal) {
941
+ return;
942
+ }
943
+ modal.style.display = 'none';
944
+ modal.close();
945
+ }
946
+
947
+ /// <reference path="../../../../ui/types.d.ts" />
948
+ function usePermissions({ userId, hasOrganization, permissionsModalRef }) {
949
+ const usersSelectRef = reactExports.useRef(null);
950
+ const [isLoading, setIsLoading] = reactExports.useState(false);
951
+ const [permissionUserOptions, setPermissionUserOptions] = reactExports.useState([]);
952
+ const [permissionsSelectedValue, setPermissionsSelectedValue] = reactExports.useState('[]');
953
+ const [permissionsSummary, setPermissionsSummary] = reactExports.useState(null);
954
+ const [isPermissionsConfirmVisible, setIsPermissionsConfirmVisible] = reactExports.useState(false);
955
+ reactExports.useEffect(() => {
956
+ if (usersSelectRef.current) {
957
+ usersSelectRef.current.value = permissionsSelectedValue;
958
+ }
959
+ }, [permissionUserOptions, permissionsSelectedValue]);
960
+ // crowdin-users-select doesn't trigger onChange reliably, using native event listener instead
961
+ reactExports.useEffect(() => {
962
+ const selectElement = usersSelectRef.current;
963
+ if (!selectElement) {
964
+ return;
965
+ }
966
+ const handleChange = () => checkUsers();
967
+ selectElement.addEventListener('change', handleChange);
968
+ return () => selectElement.removeEventListener('change', handleChange);
969
+ }, []);
970
+ function getUserFullName(user) {
971
+ if (user.full_name) {
972
+ return user.full_name;
973
+ }
974
+ const ownerFullName = user.name || ((user.first_name || '') + ' ' + (user.last_name || '')).trim();
975
+ return !!ownerFullName && (user === null || user === void 0 ? void 0 : user.login) !== ownerFullName ? `${ownerFullName} (${user === null || user === void 0 ? void 0 : user.login})` : user === null || user === void 0 ? void 0 : user.login;
976
+ }
977
+ function hideConfirmUsersBlock() {
978
+ var _a;
979
+ setIsPermissionsConfirmVisible(false);
980
+ (_a = permissionsModalRef.current) === null || _a === void 0 ? void 0 : _a.setAttribute('body-overflow-unset', true);
981
+ }
982
+ function showConfirmUsersBlock() {
983
+ var _a;
984
+ setIsPermissionsConfirmVisible(true);
985
+ (_a = permissionsModalRef.current) === null || _a === void 0 ? void 0 : _a.removeAttribute('body-overflow-unset');
986
+ }
987
+ async function showPermissionsDialog() {
988
+ hideConfirmUsersBlock();
989
+ openModal(permissionsModalRef.current);
990
+ setIsLoading(true);
991
+ setPermissionsSelectedValue('[]');
992
+ try {
993
+ const [managers, users] = await Promise.all([
994
+ new Promise((resolve) => {
995
+ checkOrigin()
996
+ .then((restParams) => fetch('api/users' + restParams))
997
+ .then(checkResponse)
998
+ .then((res) => resolve(JSON.stringify(res.data.managers)));
999
+ }),
1000
+ new Promise((resolve) => {
1001
+ AP.getUsers((res) => {
1002
+ const users = Object.values(res).filter((user) => user.id !== Number(userId));
1003
+ resolve(users);
1004
+ });
1005
+ }),
1006
+ ]);
1007
+ const parsedManagers = (JSON.parse(managers) || []);
1008
+ const validUserIds = new Set(users.map((user) => `${user.id}`));
1009
+ const filteredManagers = parsedManagers.filter((id) => validUserIds.has(id));
1010
+ setPermissionUserOptions(users.map((user) => ({
1011
+ id: String(user.id),
1012
+ label: getUserFullName(user),
1013
+ })));
1014
+ setPermissionsSelectedValue(JSON.stringify(filteredManagers));
1015
+ }
1016
+ catch (e) {
1017
+ catchRejection(e, "Can't fetch users");
1018
+ }
1019
+ finally {
1020
+ setTimeout(() => setIsLoading(false), 500);
1021
+ }
1022
+ }
1023
+ async function checkUsers() {
1024
+ setIsLoading(true);
1025
+ const select = usersSelectRef.current;
1026
+ if (select.value === '[]') {
1027
+ hideConfirmUsersBlock();
1028
+ setTimeout(() => setIsLoading(false), 500);
1029
+ return;
1030
+ }
1031
+ const users = JSON.parse(select.value);
1032
+ const user_ids = users.filter((id) => parseInt(id));
1033
+ const emails = users.filter((id) => !parseInt(id));
1034
+ try {
1035
+ const [appManagers, checkUsersResponse, allUsers] = await Promise.all([
1036
+ new Promise((resolve) => {
1037
+ checkOrigin()
1038
+ .then((restParams) => fetch('api/users' + restParams))
1039
+ .then(checkResponse)
1040
+ .then((usersResponse) => resolve(usersResponse.data.managers));
1041
+ }),
1042
+ new Promise((resolve) => {
1043
+ AP.validateUsers({ user_ids, emails }, (res) => resolve(res.data));
1044
+ }),
1045
+ new Promise((resolve) => {
1046
+ AP.getUsers((res) => resolve(res));
1047
+ }),
1048
+ ]);
1049
+ const newUserEmails = checkUsersResponse.newUserEmails.map((email) => ({ name: email }));
1050
+ const newProjectManagers = [
1051
+ ...newUserEmails,
1052
+ ...checkUsersResponse.newProjectManagers.map((user) => ({ name: getUserFullName(user) })),
1053
+ ];
1054
+ const newApplicationAccessUsers = [
1055
+ ...newUserEmails,
1056
+ ...checkUsersResponse.newApplicationAccessUsers.map((user) => ({
1057
+ name: getUserFullName(user),
1058
+ })),
1059
+ ];
1060
+ const newApplicationManagers = [
1061
+ ...newUserEmails,
1062
+ ...Object.values(allUsers)
1063
+ .filter((user) => users.some((id) => +id === user.id) && !appManagers.some((id) => +id === user.id))
1064
+ .map((user) => ({ name: getUserFullName(user) })),
1065
+ ];
1066
+ prepareUsersConfirmBlock({
1067
+ ...checkUsersResponse,
1068
+ newUserEmails,
1069
+ newProjectManagers,
1070
+ newApplicationAccessUsers,
1071
+ newApplicationManagers,
1072
+ });
1073
+ }
1074
+ catch (e) {
1075
+ catchRejection(e, (e === null || e === void 0 ? void 0 : e.error) || "Can't invite users");
1076
+ }
1077
+ finally {
1078
+ setTimeout(() => setIsLoading(false), 500);
1079
+ }
1080
+ }
1081
+ function inviteUsers() {
1082
+ setIsLoading(true);
1083
+ const select = usersSelectRef.current;
1084
+ const users = JSON.parse(select.value);
1085
+ const user_ids = users.filter((id) => parseInt(id));
1086
+ const emails = users.filter((id) => !parseInt(id));
1087
+ AP.inviteUsers({ user_ids, emails }, async (res) => {
1088
+ var _a;
1089
+ if (!res.success) {
1090
+ catchRejection(res, ((_a = res === null || res === void 0 ? void 0 : res.error) === null || _a === void 0 ? void 0 : _a.message) || "Can't invite users");
1091
+ setTimeout(() => setIsLoading(false), 500);
1092
+ return;
1093
+ }
1094
+ try {
1095
+ const restParams = await checkOrigin();
1096
+ const inviteRes = await checkResponse(await fetch('api/invite-users' + restParams, {
1097
+ method: 'POST',
1098
+ headers: { 'Content-Type': 'application/json' },
1099
+ body: JSON.stringify(res.data),
1100
+ }));
1101
+ if (!inviteRes.success) {
1102
+ catchRejection(inviteRes, (inviteRes === null || inviteRes === void 0 ? void 0 : inviteRes.message) || "Can't invite users");
1103
+ return;
1104
+ }
1105
+ showToast('Users successfully updated');
1106
+ hideConfirmUsersBlock();
1107
+ closeModal(permissionsModalRef.current);
1108
+ }
1109
+ catch (e) {
1110
+ catchRejection(e, (e === null || e === void 0 ? void 0 : e.error) || "Can't invite users");
1111
+ }
1112
+ finally {
1113
+ setTimeout(() => setIsLoading(false), 500);
1114
+ }
1115
+ });
1116
+ }
1117
+ function prepareUsersConfirmBlock(usersData) {
1118
+ showConfirmUsersBlock();
1119
+ const toNames = (users = []) => users.map((user) => user.name);
1120
+ const applicationSettingsDescription = 'This can be configured in organization settings (Apps section).';
1121
+ const hasApplicationAccessUsers = usersData.newApplicationAccessUsers.length > 0;
1122
+ setPermissionsSummary({
1123
+ ...(hasOrganization
1124
+ ? {
1125
+ organization: {
1126
+ status: usersData.newUserEmails.length
1127
+ ? usersData.inviteRestricted
1128
+ ? 'actionRequired'
1129
+ : 'willBeRegistered'
1130
+ : 'granted',
1131
+ users: toNames(usersData.newUserEmails),
1132
+ description: usersData.inviteRestricted
1133
+ ? 'New user invitations are restricted to administrators.'
1134
+ : '',
1135
+ isWarning: usersData.inviteRestricted,
1136
+ },
1137
+ }
1138
+ : {}),
1139
+ project: {
1140
+ status: usersData.newProjectManagers.length ? 'willBeGranted' : 'granted',
1141
+ users: toNames(usersData.newProjectManagers),
1142
+ },
1143
+ applicationSettings: {
1144
+ status: hasApplicationAccessUsers
1145
+ ? usersData.isAdmin
1146
+ ? 'willBeGranted'
1147
+ : 'actionRequired'
1148
+ : 'granted',
1149
+ users: toNames(usersData.newApplicationAccessUsers),
1150
+ description: hasApplicationAccessUsers
1151
+ ? usersData.isAdmin
1152
+ ? applicationSettingsDescription
1153
+ : `${applicationSettingsDescription} Only organization admins have permission to update this setting.`
1154
+ : applicationSettingsDescription,
1155
+ isWarning: hasApplicationAccessUsers && !usersData.isAdmin,
1156
+ },
1157
+ applicationCredentials: {
1158
+ status: usersData.newApplicationManagers.length ? 'willBeGranted' : 'granted',
1159
+ users: toNames(usersData.newApplicationManagers),
1160
+ },
1161
+ });
1162
+ }
1163
+ return {
1164
+ usersSelectRef,
1165
+ isLoading,
1166
+ permissionUserOptions,
1167
+ permissionsSelectedValue,
1168
+ permissionsSummary,
1169
+ isPermissionsConfirmVisible,
1170
+ showPermissionsDialog,
1171
+ inviteUsers,
535
1172
  };
536
- switch (field.type) {
537
- case 'checkbox':
538
- return (jsxRuntimeExports.jsx("crowdin-checkbox", { ...commonProps, value: "false", "use-switch": true, ...(field.defaultValue === true ? { checked: String(field.defaultValue) } : {}), onChange: settingsFieldChange }));
539
- case 'select':
540
- return (jsxRuntimeExports.jsx("crowdin-select", { ...commonProps, ...(field.isMulti ? { 'is-multi': true, 'close-on-select': 'false' } : {}), ...(field.isSearchable ? { 'is-searchable': true } : {}), "is-position-fixed": true, onChange: settingsFieldChange, children: (_a = field.options) === null || _a === void 0 ? void 0 : _a.map((option) => {
541
- const isSelected = Array.isArray(field.defaultValue)
542
- ? field.defaultValue.includes(option.value)
543
- : field.defaultValue === option.value;
544
- return (jsxRuntimeExports.jsx("option", { value: option.value, ...(isSelected ? { selected: true } : {}), children: option.label }, option.value));
545
- }) }));
546
- case 'text':
547
- return (jsxRuntimeExports.jsx("crowdin-input", { ...commonProps, "with-fixed-height": true, value: field.defaultValue || '', onChange: settingsFieldChange }));
548
- case 'textarea':
549
- return (jsxRuntimeExports.jsx("crowdin-textarea", { ...commonProps, value: field.defaultValue || '', onChange: settingsFieldChange }));
550
- case 'notice':
551
- return (jsxRuntimeExports.jsx("crowdin-alert", { ...(field.noticeType ? { type: field.noticeType } : {}), ...(field.label ? { title: field.label } : {}), ...(field.noIcon ? { 'no-icon': String(field.noIcon) } : {}), ...(field.dependencySettings ? { 'data-dependency': field.dependencySettings } : {}), dangerouslySetInnerHTML: { __html: field.helpTextHtml || field.helpText || '' } }));
552
- default:
553
- return null;
1173
+ }
1174
+
1175
+ /// <reference path="../../../../ui/types.d.ts" />
1176
+ function useSchedule({ appComponent, config, scheduleModalRef, withCronSync, webhooks, syncNewElements, integrationOneLevelFetching, hasLoadMoreElements, updateSyncSettings, }) {
1177
+ const selectedFilesCheckboxRef = reactExports.useRef(null);
1178
+ const allFolderFilesCheckboxRef = reactExports.useRef(null);
1179
+ const newFilesCheckboxRef = reactExports.useRef(null);
1180
+ const syncData = reactExports.useRef(null);
1181
+ const [scheduleModalState, setScheduleModalState] = reactExports.useState(getDefaultScheduleModalState);
1182
+ const [isScheduleSaveDisabled, setIsScheduleSaveDisabled] = reactExports.useState(false);
1183
+ reactExports.useEffect(() => {
1184
+ syncScheduleCheckbox(selectedFilesCheckboxRef.current, {
1185
+ checked: scheduleModalState.selectedFiles,
1186
+ });
1187
+ syncScheduleCheckbox(allFolderFilesCheckboxRef.current, {
1188
+ checked: scheduleModalState.allFolderFiles,
1189
+ hidden: !scheduleModalState.showAllFolderFiles,
1190
+ });
1191
+ syncScheduleCheckbox(newFilesCheckboxRef.current, {
1192
+ checked: scheduleModalState.newFiles,
1193
+ hidden: !scheduleModalState.showNewFiles,
1194
+ clearSelection: scheduleModalState.newFilesClearSelection,
1195
+ });
1196
+ }, [scheduleModalState]);
1197
+ reactExports.useEffect(() => {
1198
+ if (!withCronSync && !webhooks) {
1199
+ return;
1200
+ }
1201
+ const listeners = {
1202
+ integrationScheduleSync: setIntegrationScheduleSync,
1203
+ crowdinScheduleSync: setCrowdinScheduleSync,
1204
+ crowdinDisableSync: disableCrowdinSync,
1205
+ integrationDisableSync: disableIntegrationSync,
1206
+ };
1207
+ for (const [event, handler] of Object.entries(listeners)) {
1208
+ document.body.addEventListener(event, handler);
1209
+ }
1210
+ return () => {
1211
+ for (const [event, handler] of Object.entries(listeners)) {
1212
+ document.body.removeEventListener(event, handler);
1213
+ }
1214
+ };
1215
+ }, []);
1216
+ function syncScheduleCheckbox(checkbox, { checked, hidden = false, clearSelection = false, }) {
1217
+ if (!checkbox) {
1218
+ return;
1219
+ }
1220
+ checkbox.checked = checked;
1221
+ checkbox.value = checked;
1222
+ if (hidden) {
1223
+ checkbox.setAttribute('hidden', '');
1224
+ }
1225
+ else {
1226
+ checkbox.removeAttribute('hidden');
1227
+ }
1228
+ if (clearSelection) {
1229
+ checkbox.setAttribute('clear-selection', '');
1230
+ }
1231
+ else {
1232
+ checkbox.removeAttribute('clear-selection');
1233
+ }
1234
+ }
1235
+ async function hasFolder(selectedFiles) {
1236
+ let found;
1237
+ if (Array.isArray(selectedFiles)) {
1238
+ found = selectedFiles.find((file) => file.node_type === FOLDER_TYPE || file.node_type === BRANCH_TYPE);
1239
+ }
1240
+ else {
1241
+ const files = await appComponent.current.getCrowdinFilesData();
1242
+ const folders = files.filter((file) => file.node_type === FOLDER_TYPE || file.node_type === BRANCH_TYPE);
1243
+ found = folders.find((folder) => selectedFiles.hasOwnProperty(folder.id));
1244
+ }
1245
+ return found !== undefined;
1246
+ }
1247
+ function getIntegrationFoldersToExpand(allData, syncedFiles) {
1248
+ return Array.isArray(allData)
1249
+ ? allData
1250
+ .filter((node) => node.node_type === FOLDER_TYPE &&
1251
+ !syncedFiles.find((syncedFile) => syncedFile.parent_id === node.id))
1252
+ .map((node) => ({ ...node, nodeType: node.node_type, parentId: node.parent_id }))
1253
+ : [];
1254
+ }
1255
+ async function openScheduleModal(type, options = {}) {
1256
+ var _a, _b, _c, _d;
1257
+ const { showAllFolderFiles = false, showNewFiles = true } = options;
1258
+ let newFileStatus = 'unChecked';
1259
+ const integrationSyncFolders = ((await ((_b = (_a = appComponent.current) === null || _a === void 0 ? void 0 : _a.getIntegrationScheduleSync) === null || _b === void 0 ? void 0 : _b.call(_a, true))) || []).filter((elements) => elements.node_type === FOLDER_TYPE);
1260
+ const integrationFiles = (_c = appComponent.current) === null || _c === void 0 ? void 0 : _c.querySelector('#integration-files');
1261
+ const selectedIntegrationFolders = ((await ((_d = integrationFiles === null || integrationFiles === void 0 ? void 0 : integrationFiles.getSelected) === null || _d === void 0 ? void 0 : _d.call(integrationFiles, true))) || []).filter((elements) => elements.node_type === FOLDER_TYPE);
1262
+ for (let i = 0; i < selectedIntegrationFolders.length; i++) {
1263
+ const selectedElement = selectedIntegrationFolders[i];
1264
+ const found = integrationSyncFolders.some((integrationElement) => integrationElement.id === selectedElement.id);
1265
+ if (found) {
1266
+ newFileStatus = 'checked';
1267
+ }
1268
+ else if (!found && newFileStatus === 'checked') {
1269
+ newFileStatus = 'clear-selection';
1270
+ break;
1271
+ }
1272
+ else {
1273
+ newFileStatus = 'unChecked';
1274
+ }
1275
+ }
1276
+ setScheduleModalState({
1277
+ type,
1278
+ showAllFolderFiles,
1279
+ showNewFiles,
1280
+ newFiles: showNewFiles && newFileStatus === 'checked',
1281
+ newFilesClearSelection: showNewFiles && newFileStatus === 'clear-selection',
1282
+ selectedFiles: true,
1283
+ allFolderFiles: false,
1284
+ });
1285
+ setIsScheduleSaveDisabled(false);
1286
+ openModal(scheduleModalRef.current);
1287
+ }
1288
+ function onChangeAutoSynchronizationOptions() {
1289
+ var _a, _b, _c;
1290
+ const nextState = {
1291
+ newFiles: scheduleModalState.showNewFiles ? !!((_a = newFilesCheckboxRef.current) === null || _a === void 0 ? void 0 : _a.checked) : false,
1292
+ selectedFiles: !!((_b = selectedFilesCheckboxRef.current) === null || _b === void 0 ? void 0 : _b.checked),
1293
+ allFolderFiles: scheduleModalState.showAllFolderFiles
1294
+ ? !!((_c = allFolderFilesCheckboxRef.current) === null || _c === void 0 ? void 0 : _c.checked)
1295
+ : false,
1296
+ };
1297
+ setScheduleModalState((currentState) => ({
1298
+ ...currentState,
1299
+ ...nextState,
1300
+ newFilesClearSelection: false,
1301
+ }));
1302
+ setIsScheduleSaveDisabled(!nextState.newFiles && !nextState.selectedFiles && !nextState.allFolderFiles);
1303
+ }
1304
+ async function saveScheduleSync() {
1305
+ const { type, newFiles: newFile, selectedFiles, allFolderFiles } = scheduleModalState;
1306
+ if (type === 'crowdin') {
1307
+ const crowdinFiles = await appComponent.current.getCrowdinFilesData();
1308
+ const syncedFileIds = Object.keys(syncData.current);
1309
+ const crowdinFolderIds = crowdinFiles
1310
+ .filter((file) => file.node_type === FOLDER_TYPE || file.node_type === BRANCH_TYPE)
1311
+ .filter((file) => syncedFileIds.includes(String(file.id)))
1312
+ .map((file) => String(file.id));
1313
+ appComponent.current.setCrowdinScheduleSync(syncData.current, newFile, selectedFiles);
1314
+ appComponent.current.setCrowdinFilesHasSyncOption(true);
1315
+ const syncedFiles = await appComponent.current.getCrowdinScheduleSync(true);
1316
+ appComponent.current.setAttribute('is-crowdin-sync-settings-in-progress', true);
1317
+ updateSyncSettings(syncedFiles, 'schedule', 'crowdin', [], crowdinFolderIds);
1318
+ }
1319
+ else if (type === 'integration') {
1320
+ if (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.integration) {
1321
+ appComponent.current.setIntegrationScheduleSync(syncData.current, newFile, selectedFiles);
1322
+ }
1323
+ else {
1324
+ appComponent.current.setIntegrationScheduleSync(syncData.current);
1325
+ }
1326
+ appComponent.current.setIntegrationFilesHasSyncOption(true);
1327
+ const syncedFiles = await appComponent.current.getIntegrationScheduleSync(true);
1328
+ appComponent.current.setAttribute('is-integration-sync-settings-in-progress', true);
1329
+ if (integrationOneLevelFetching) {
1330
+ updateSyncSettings(syncedFiles, 'schedule', 'integration', selectedFiles ? getIntegrationFoldersToExpand(syncData.current, syncedFiles) : []);
1331
+ }
1332
+ else {
1333
+ if (allFolderFiles) {
1334
+ const integrationExpandedFolders = syncData.current
1335
+ .filter((file) => file.node_type === FOLDER_TYPE)
1336
+ .map((file) => ({ ...file, nodeType: file.node_type, parentId: file.parent_id }));
1337
+ updateSyncSettings(syncedFiles, 'schedule', 'integration', integrationExpandedFolders);
1338
+ }
1339
+ else {
1340
+ updateSyncSettings(syncedFiles, 'schedule', 'integration');
1341
+ }
1342
+ }
1343
+ }
1344
+ closeModal(scheduleModalRef.current);
1345
+ }
1346
+ async function setIntegrationScheduleSync(e) {
1347
+ var _a;
1348
+ if (e.detail.length === 0) {
1349
+ showToast('Select templates which will be pushed to Crowdin');
1350
+ return;
1351
+ }
1352
+ let syncedFiles;
1353
+ if (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.integration) {
1354
+ const newIntegrationFiles = (_a = config.current) === null || _a === void 0 ? void 0 : _a['new-integration-files'];
1355
+ syncData.current = e.detail;
1356
+ const isFolder = await hasFolder(e.detail);
1357
+ const shouldShowModal = isFolder && !newIntegrationFiles;
1358
+ const showNewFiles = true;
1359
+ const showAllFolderFiles = hasLoadMoreElements.current;
1360
+ if (shouldShowModal) {
1361
+ await openScheduleModal('integration', { showNewFiles, showAllFolderFiles });
1362
+ return;
1363
+ }
1364
+ appComponent.current.setIntegrationScheduleSync(e.detail);
1365
+ appComponent.current.setIntegrationFilesHasSyncOption(true);
1366
+ syncedFiles = await appComponent.current.getIntegrationScheduleSync(true);
1367
+ }
1368
+ else {
1369
+ syncData.current = e.detail;
1370
+ const isFolder = await hasFolder(e.detail);
1371
+ if (hasLoadMoreElements.current && isFolder) {
1372
+ await openScheduleModal('integration', { showNewFiles: false, showAllFolderFiles: true });
1373
+ return;
1374
+ }
1375
+ syncedFiles = await appComponent.current.getIntegrationScheduleSync();
1376
+ }
1377
+ appComponent.current.setAttribute('is-integration-sync-settings-in-progress', true);
1378
+ if (integrationOneLevelFetching) {
1379
+ updateSyncSettings(syncedFiles, 'schedule', 'integration', getIntegrationFoldersToExpand(e.detail, syncedFiles));
1380
+ }
1381
+ else {
1382
+ if (hasLoadMoreElements.current) {
1383
+ const integrationExpandedFolders = e.detail
1384
+ .filter((file) => file.node_type === FOLDER_TYPE)
1385
+ .map((file) => ({ ...file, nodeType: file.node_type, parentId: file.parent_id }));
1386
+ updateSyncSettings(syncedFiles, 'schedule', 'integration', integrationExpandedFolders);
1387
+ }
1388
+ else {
1389
+ updateSyncSettings(syncedFiles, 'schedule', 'integration');
1390
+ }
1391
+ }
1392
+ }
1393
+ async function setCrowdinScheduleSync(e) {
1394
+ var _a;
1395
+ if (e.detail.length === 0) {
1396
+ showToast('Select templates which will be pushed to Crowdin');
1397
+ return;
1398
+ }
1399
+ let syncedFiles;
1400
+ if (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.crowdin) {
1401
+ const newCrowdinFiles = (_a = config.current) === null || _a === void 0 ? void 0 : _a['new-crowdin-files'];
1402
+ syncData.current = e.detail;
1403
+ const isFolder = await hasFolder(e.detail);
1404
+ if (isFolder && !newCrowdinFiles) {
1405
+ await openScheduleModal('crowdin');
1406
+ return;
1407
+ }
1408
+ appComponent.current.setCrowdinScheduleSync(e.detail);
1409
+ appComponent.current.setCrowdinFilesHasSyncOption(true);
1410
+ syncedFiles = await appComponent.current.getCrowdinScheduleSync(true);
1411
+ }
1412
+ else {
1413
+ syncedFiles = await appComponent.current.getCrowdinScheduleSync();
1414
+ }
1415
+ appComponent.current.setAttribute('is-crowdin-sync-settings-in-progress', true);
1416
+ updateSyncSettings(syncedFiles, 'schedule', 'crowdin');
1417
+ }
1418
+ async function disableIntegrationSync(e) {
1419
+ if (e.detail.length === 0) {
1420
+ showToast('Select templates which will be pushed to Crowdin');
1421
+ return;
1422
+ }
1423
+ appComponent.current.setAttribute('is-integration-sync-settings-in-progress', true);
1424
+ const syncedFiles = (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.integration)
1425
+ ? await appComponent.current.getIntegrationScheduleSync(true)
1426
+ : await appComponent.current.getIntegrationScheduleSync();
1427
+ updateSyncSettings(syncedFiles, 'schedule', 'integration');
1428
+ }
1429
+ async function disableCrowdinSync(e) {
1430
+ if (e.detail.length === 0) {
1431
+ showToast('Select templates which will be pushed to Crowdin');
1432
+ return;
1433
+ }
1434
+ appComponent.current.setAttribute('is-crowdin-sync-settings-in-progress', true);
1435
+ const syncedFiles = (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.crowdin)
1436
+ ? await appComponent.current.getCrowdinScheduleSync(true)
1437
+ : await appComponent.current.getCrowdinScheduleSync();
1438
+ updateSyncSettings(syncedFiles, 'schedule', 'crowdin');
1439
+ }
1440
+ return {
1441
+ selectedFilesCheckboxRef,
1442
+ allFolderFilesCheckboxRef,
1443
+ newFilesCheckboxRef,
1444
+ scheduleModalState,
1445
+ isScheduleSaveDisabled,
1446
+ onChangeAutoSynchronizationOptions,
1447
+ saveScheduleSync,
1448
+ };
1449
+ }
1450
+
1451
+ /// <reference path="../../../../ui/types.d.ts" />
1452
+ function useSettings({ configurationFields, config, settingsModalRef, reloadOnConfigSave, refreshDependencies, checkJob, getCrowdinData, getIntegrationData, refreshAutoSyncPausedIndicatorsAndWarning, }) {
1453
+ const settingsFieldRefs = reactExports.useRef({});
1454
+ const [isLoading, setIsLoading] = reactExports.useState(false);
1455
+ const [isSettingsSaveDisabled, setIsSettingsSaveDisabled] = reactExports.useState(false);
1456
+ function triggerEvent(el, type) {
1457
+ const e = document.createEvent('HTMLEvents');
1458
+ e.initEvent(type, false, true);
1459
+ el.dispatchEvent(e);
1460
+ }
1461
+ function parseCrowdinSelectValue(value) {
1462
+ if (Array.isArray(value)) {
1463
+ return value;
1464
+ }
1465
+ if (value === undefined || value === null || value === '') {
1466
+ return [];
1467
+ }
1468
+ try {
1469
+ const parsedValue = JSON.parse(value);
1470
+ return Array.isArray(parsedValue) ? parsedValue : [parsedValue];
1471
+ }
1472
+ catch {
1473
+ return [value];
1474
+ }
1475
+ }
1476
+ function registerSettingsField(key) {
1477
+ return (element) => {
1478
+ if (!key) {
1479
+ return;
1480
+ }
1481
+ if (element) {
1482
+ settingsFieldRefs.current[key] = element;
1483
+ }
1484
+ else {
1485
+ delete settingsFieldRefs.current[key];
1486
+ }
1487
+ };
1488
+ }
1489
+ function settingsFieldChange(eventOrElement) {
1490
+ var _a, _b;
1491
+ const el = (eventOrElement === null || eventOrElement === void 0 ? void 0 : eventOrElement.currentTarget) || (eventOrElement === null || eventOrElement === void 0 ? void 0 : eventOrElement.target) || eventOrElement;
1492
+ (_a = el === null || el === void 0 ? void 0 : el.removeAttribute) === null || _a === void 0 ? void 0 : _a.call(el, 'error');
1493
+ (_b = el === null || el === void 0 ? void 0 : el.removeAttribute) === null || _b === void 0 ? void 0 : _b.call(el, 'error-text');
1494
+ }
1495
+ function fillSettingsForm() {
1496
+ Object.entries(config.current).forEach(([key, value]) => {
1497
+ const el = settingsFieldRefs.current[key];
1498
+ if (el && (value || el.tagName.toLowerCase() === 'crowdin-checkbox')) {
1499
+ if (el.tagName.toLowerCase() === 'crowdin-select') {
1500
+ if (el.hasAttribute('is-multi')) {
1501
+ el.value = JSON.stringify(value);
1502
+ }
1503
+ else {
1504
+ el.value = JSON.stringify([value]);
1505
+ }
1506
+ }
1507
+ else if (el.tagName.toLowerCase() === 'crowdin-checkbox') {
1508
+ el.checked = !!value;
1509
+ }
1510
+ else if (el.tagName.toLowerCase() === 'crowdin-textarea') {
1511
+ el.value = value;
1512
+ el.setValue(value);
1513
+ }
1514
+ else {
1515
+ el.value = value;
1516
+ }
1517
+ triggerEvent(el, 'change');
1518
+ }
1519
+ });
1520
+ setTimeout(refreshDependencies, 100);
1521
+ }
1522
+ async function saveSettings() {
1523
+ var _a, _b, _c, _d;
1524
+ setIsLoading(true);
1525
+ const configReq = {};
1526
+ configurationFields === null || configurationFields === void 0 ? void 0 : configurationFields.forEach((tab) => {
1527
+ tab.fields.forEach((field) => {
1528
+ if (!field.key) {
1529
+ return;
1530
+ }
1531
+ const el = settingsFieldRefs.current[field.key];
1532
+ if (!el) {
1533
+ return;
1534
+ }
1535
+ const tagName = el.tagName.toLowerCase();
1536
+ if (tagName === 'crowdin-select') {
1537
+ const value = parseCrowdinSelectValue(el.value);
1538
+ configReq[field.key] = el.hasAttribute('is-multi') ? value : value[0];
1539
+ return;
1540
+ }
1541
+ if (tagName === 'crowdin-checkbox') {
1542
+ configReq[field.key] = !!el.checked;
1543
+ return;
1544
+ }
1545
+ configReq[field.key] = el.value;
1546
+ });
1547
+ });
1548
+ let isValidationError = false;
1549
+ let isSettingsSaveJobPending = false;
1550
+ let isSettingsSaveFailed = false;
1551
+ setIsSettingsSaveDisabled(true);
1552
+ try {
1553
+ const restParams = await checkOrigin();
1554
+ const res = await checkResponse(await fetch('api/settings' + restParams, {
1555
+ method: 'POST',
1556
+ headers: { 'Content-Type': 'application/json' },
1557
+ body: JSON.stringify({ config: configReq }),
1558
+ }));
1559
+ if (res === null || res === void 0 ? void 0 : res.jobId) {
1560
+ isSettingsSaveJobPending = true;
1561
+ checkJob({
1562
+ jobId: res.jobId,
1563
+ jobType: JOB_TYPE.integrationSettingsSave,
1564
+ onSuccess: () => {
1565
+ showToast('Settings successfully saved');
1566
+ config.current = configReq;
1567
+ refreshAutoSyncPausedIndicatorsAndWarning().catch((e) => catchRejection(e, "Can't fetch sync settings warning"));
1568
+ },
1569
+ onError: () => {
1570
+ isSettingsSaveFailed = true;
1571
+ showToast("Can't save settings");
1572
+ },
1573
+ onFinally: () => {
1574
+ setTimeout(() => setIsLoading(false), 500);
1575
+ setIsSettingsSaveDisabled(false);
1576
+ if (!isValidationError && !isSettingsSaveFailed) {
1577
+ closeModal(settingsModalRef.current);
1578
+ if (reloadOnConfigSave) {
1579
+ getIntegrationData({ hardReload: true });
1580
+ getCrowdinData();
1581
+ }
1582
+ }
1583
+ },
1584
+ });
1585
+ return;
1586
+ }
1587
+ showToast('Settings successfully saved');
1588
+ config.current = configReq;
1589
+ refreshAutoSyncPausedIndicatorsAndWarning().catch((e) => catchRejection(e, "Can't fetch sync settings warning"));
1590
+ }
1591
+ catch (e) {
1592
+ if ((e === null || e === void 0 ? void 0 : e.error) && ((_a = e === null || e === void 0 ? void 0 : e.error) === null || _a === void 0 ? void 0 : _a.type) === 'validation_error') {
1593
+ Object.keys((_b = e === null || e === void 0 ? void 0 : e.error) === null || _b === void 0 ? void 0 : _b.details).forEach((key) => {
1594
+ var _a;
1595
+ const el = settingsFieldRefs.current[key];
1596
+ if (el) {
1597
+ el.setAttribute('error', 'true');
1598
+ el.setAttribute('error-text', (_a = e === null || e === void 0 ? void 0 : e.error) === null || _a === void 0 ? void 0 : _a.details[key]);
1599
+ }
1600
+ });
1601
+ isValidationError = true;
1602
+ showToast(((_d = (_c = e === null || e === void 0 ? void 0 : e.error) === null || _c === void 0 ? void 0 : _c.details) === null || _d === void 0 ? void 0 : _d.message) || "Can't save settings");
1603
+ setIsSettingsSaveDisabled(false);
1604
+ return;
1605
+ }
1606
+ catchRejection(e, "Can't save settings");
1607
+ }
1608
+ finally {
1609
+ if (isSettingsSaveJobPending) {
1610
+ return;
1611
+ }
1612
+ setTimeout(() => setIsLoading(false), 500);
1613
+ setIsSettingsSaveDisabled(false);
1614
+ if (!isValidationError) {
1615
+ closeModal(settingsModalRef.current);
1616
+ if (reloadOnConfigSave) {
1617
+ getIntegrationData({ hardReload: true });
1618
+ getCrowdinData();
1619
+ }
1620
+ }
1621
+ }
554
1622
  }
555
- };
556
- const MainPage = (props) => {
557
- var _a, _b;
558
- const { name, userId, notice, checkSubscription, isManager, isOwner, infoModal, configurationFields, config: configString, syncNewElements, withCronSync, webhooks, integrationOneLevelFetching, integrationSearchListener, integrationPagination, excludedTargetLanguages, filtering, hasOrganization, zenModeUrl, asyncProgress = { checkInterval: 3000 }, reloadOnConfigSave, progressiveCrowdinFilesLoading, integrationButtonMenuItems, crowdinButtonMenuItems, } = props;
559
- const config = reactExports.useRef(configString ? JSON.parse(configString.replace(/\\n/g, '\\\\n')) : {});
560
- const folderType = '0';
561
- const fileType = '1';
562
- const branchType = '2';
563
- const JOB_TYPE = {
564
- updateCrowdin: 'updateCrowdin',
565
- updateIntegration: 'updateIntegration',
566
- updateTargetLanguages: 'updateTargetLanguages',
567
- integrationSyncSettingsSave: 'integrationSyncSettingsSave',
568
- crowdinSyncSettingsSave: 'crowdinSyncSettingsSave',
569
- integrationSettingsSave: 'integrationSettingsSave',
1623
+ return {
1624
+ isLoading,
1625
+ isSettingsSaveDisabled,
1626
+ fillSettingsForm,
1627
+ saveSettings,
1628
+ registerSettingsField,
1629
+ settingsFieldChange,
570
1630
  };
571
- const JOB_STATUS = {
572
- created: 'created',
573
- inProgress: 'inProgress',
574
- failed: 'failed',
575
- canceled: 'canceled',
576
- finished: 'finished',
577
- };
578
- const silentJobs = [JOB_TYPE.integrationSettingsSave];
579
- const appComponent = reactExports.useRef(null);
580
- const subscriptionModal = reactExports.useRef(null);
581
- const languageModal = reactExports.useRef(null);
582
- const usersSelectRef = reactExports.useRef(null);
1631
+ }
1632
+
1633
+ /// <reference path="../../../../ui/types.d.ts" />
1634
+ function useSyncOperations({ appComponent, asyncProgressRef, config, name, integrationOneLevelFetching, integrationSearchListener, integrationPagination, withCronSync, webhooks, progressiveCrowdinFilesLoading, asyncProgress, syncNewElements, }) {
583
1635
  const crowdinFilesToUpdateTargetLanguages = reactExports.useRef([]);
584
1636
  const asyncJobs = reactExports.useRef({});
585
1637
  const project = reactExports.useRef({});
586
1638
  const crowdinData = reactExports.useRef([]);
587
1639
  const fileToSync = reactExports.useRef([]);
588
- const syncData = reactExports.useRef(null);
589
- const subscriptionLink = reactExports.useRef('');
590
1640
  const hasLoadMoreElements = reactExports.useRef(false);
591
1641
  const savedIntegrationData = reactExports.useRef(null);
592
1642
  const currentOpenedFolders = reactExports.useRef(null);
1643
+ const languageModal = reactExports.useRef(null);
1644
+ const languageSelectRef = reactExports.useRef(null);
1645
+ const [languageModalState, setLanguageModalState] = reactExports.useState(null);
1646
+ const silentJobs = [JOB_TYPE.integrationSettingsSave];
1647
+ reactExports.useEffect(() => {
1648
+ var _a;
1649
+ if (!languageModalState || !((_a = languageSelectRef.current) === null || _a === void 0 ? void 0 : _a.setValue)) {
1650
+ return;
1651
+ }
1652
+ languageSelectRef.current.setValue(languageModalState.languages.map((language) => language.id));
1653
+ }, [languageModalState]);
593
1654
  reactExports.useEffect(() => {
594
- // Event listeners
595
1655
  const listeners = {
596
1656
  refreshFilesList: (e) => {
597
1657
  if (e.detail.refreshIntegration) {
@@ -616,34 +1676,20 @@
616
1676
  cancelAsyncAction: (e) => {
617
1677
  cancelJob(e.detail);
618
1678
  },
619
- keydown: (event) => {
620
- if (event.keyCode === 27) {
621
- const permissions = document.getElementById('permissions-modal');
622
- // not sure where we get users from here
623
- // @ts-ignore
624
- if (users) {
625
- closeModal(permissions);
626
- }
627
- const infoModalEl = document.getElementById('info-modal');
628
- if (infoModalEl) {
629
- closeModal(infoModalEl);
630
- }
631
- const settingsModal = document.getElementById('settings-modal');
632
- if (settingsModal) {
633
- closeModal(settingsModal);
634
- }
635
- if (languageModal.current) {
636
- closeModal(languageModal.current);
637
- }
638
- }
639
- },
640
1679
  loadMoreClick: async (e) => {
1680
+ var _a;
641
1681
  const loadMoreFile = e.detail;
642
- const fileComponent = document.getElementById('integration-files');
1682
+ const fileComponent = (_a = appComponent.current) === null || _a === void 0 ? void 0 : _a.querySelector('#integration-files');
1683
+ if (!fileComponent) {
1684
+ return;
1685
+ }
643
1686
  await fileComponent.setLoadMoreLoading(loadMoreFile.id, true);
644
- getIntegrationData({ parentId: e.detail.parent_id, paginationData: e.detail.pagination }).finally(async () => {
1687
+ try {
1688
+ await getIntegrationData({ parentId: e.detail.parent_id, paginationData: e.detail.pagination });
1689
+ }
1690
+ finally {
645
1691
  await fileComponent.setLoadMoreLoading(loadMoreFile.id, false);
646
- });
1692
+ }
647
1693
  },
648
1694
  };
649
1695
  if (integrationSearchListener) {
@@ -666,64 +1712,18 @@
666
1712
  getIntegrationData({ page: e.detail.page });
667
1713
  };
668
1714
  }
669
- if (withCronSync || webhooks) {
670
- listeners['integrationScheduleSync'] = setIntegrationScheduleSync;
671
- listeners['crowdinScheduleSync'] = setCrowdinScheduleSync;
672
- listeners['crowdinDisableSync'] = disableCrowdinSync;
673
- listeners['integrationDisableSync'] = disableIntegrationSync;
674
- }
675
1715
  for (const [event, handler] of Object.entries(listeners)) {
676
1716
  document.body.addEventListener(event, handler);
677
1717
  }
678
- // Initial data fetch
679
1718
  getCrowdinData();
680
1719
  getIntegrationData({});
681
1720
  getActiveJobs();
682
- if (checkSubscription) {
683
- getSubscriptionInfo();
684
- }
685
- if (notice) {
686
- const noticeEl = document.getElementById('notice');
687
- checkAlert(noticeEl, 'notice');
688
- }
689
1721
  return () => {
690
1722
  for (const [event, handler] of Object.entries(listeners)) {
691
1723
  document.body.removeEventListener(event, handler);
692
1724
  }
693
1725
  };
694
1726
  }, []);
695
- // Expose centralized API to global scope for main.js compatibility
696
- reactExports.useEffect(() => {
697
- window.app = {
698
- subscriptionModal: subscriptionModal,
699
- subscriptionLink: subscriptionLink,
700
- openModal: openModal,
701
- };
702
- return () => {
703
- delete window.app;
704
- };
705
- }, []);
706
- // crowdin-users-select doesn't trigger onChange reliably, using native event listener instead
707
- reactExports.useEffect(() => {
708
- const selectElement = usersSelectRef.current;
709
- if (selectElement) {
710
- const handleChange = () => {
711
- checkUsers();
712
- };
713
- selectElement.addEventListener('change', handleChange);
714
- return () => {
715
- selectElement.removeEventListener('change', handleChange);
716
- };
717
- }
718
- }, []);
719
- function integrationLogout() {
720
- checkOrigin()
721
- .then((queryParams) => fetch(`api/logout${queryParams}`, { method: 'POST' }))
722
- .then(checkResponse)
723
- .then(reloadLocation)
724
- .then(() => localStorage.removeItem(`revised_${name}`))
725
- .catch((e) => catchRejection(e, e.error || 'Looks like you are not logged in'));
726
- }
727
1727
  function transformCrowdinItemToTree(e) {
728
1728
  const item = {
729
1729
  parent_id: e.parentId ? e.parentId : '0',
@@ -736,22 +1736,21 @@
736
1736
  };
737
1737
  if (e.type) {
738
1738
  item.type = e.type;
739
- item.node_type = fileType;
1739
+ item.node_type = FILE_TYPE;
740
1740
  item.failed = e.failed;
741
1741
  item.excludedTargetLanguages = e.excludedTargetLanguages;
742
1742
  }
743
1743
  else {
744
- item.node_type = e.nodeType || folderType;
1744
+ item.node_type = e.nodeType || FOLDER_TYPE;
745
1745
  }
746
1746
  return item;
747
1747
  }
748
- function getCrowdinData() {
749
- var _a;
1748
+ async function getCrowdinData() {
1749
+ var _a, _b, _c, _d, _f;
750
1750
  (_a = appComponent.current) === null || _a === void 0 ? void 0 : _a.setAttribute('is-crowdin-loading', 'true');
751
- let promise;
752
- if (progressiveCrowdinFilesLoading) {
753
- promise = checkOrigin()
754
- .then((restParams) => {
1751
+ try {
1752
+ const restParams = await checkOrigin();
1753
+ if (progressiveCrowdinFilesLoading) {
755
1754
  const dirPromise = fetch('api/crowdin/files' + restParams + '&mode=directories')
756
1755
  .then(checkResponse)
757
1756
  .then((directories) => {
@@ -761,15 +1760,14 @@
761
1760
  (_a = appComponent.current) === null || _a === void 0 ? void 0 : _a.setCrowdinFilesData(dirTree);
762
1761
  return dirTree;
763
1762
  });
764
- const filesPromise = fetch('api/crowdin/files' + restParams + '&mode=files').then(checkResponse);
765
- const projectPromise = fetch('api/crowdin/project' + restParams).then(checkResponse);
766
- return Promise.all([dirPromise, filesPromise, projectPromise]);
767
- })
768
- .then(([dirTree, files, projectData]) => {
769
- var _a, _b, _c;
1763
+ const [dirTree, files, projectData] = await Promise.all([
1764
+ dirPromise,
1765
+ fetch('api/crowdin/files' + restParams + '&mode=files').then(checkResponse),
1766
+ fetch('api/crowdin/project' + restParams).then(checkResponse),
1767
+ ]);
770
1768
  const fileTree = files.map(transformCrowdinItemToTree);
771
1769
  crowdinData.current = [...dirTree, ...fileTree];
772
- (_a = appComponent.current) === null || _a === void 0 ? void 0 : _a.setCrowdinFilesData(crowdinData.current);
1770
+ (_b = appComponent.current) === null || _b === void 0 ? void 0 : _b.setCrowdinFilesData(crowdinData.current);
773
1771
  project.current = projectData;
774
1772
  const languagesSorted = project.current.targetLanguages
775
1773
  .map((language) => ({
@@ -778,22 +1776,17 @@
778
1776
  ...language,
779
1777
  }))
780
1778
  .sort((a, b) => a.name.localeCompare(b.name));
781
- if (project.current.inContext && ((_b = config.current) === null || _b === void 0 ? void 0 : _b.inContext)) {
1779
+ if (project.current.inContext && ((_c = config.current) === null || _c === void 0 ? void 0 : _c.inContext)) {
782
1780
  languagesSorted.push({ ...project.current.inContextPseudoLanguage, inContext: true });
783
1781
  }
784
1782
  setLanguagesForTranslation(languagesSorted);
785
- (_c = appComponent.current) === null || _c === void 0 ? void 0 : _c.setCrowdinLanguagesData(languagesSorted);
786
- });
787
- }
788
- else {
789
- promise = checkOrigin()
790
- .then((restParams) => {
791
- const filesPromise = fetch('api/crowdin/files' + restParams).then(checkResponse);
792
- const projectPromise = fetch('api/crowdin/project' + restParams).then(checkResponse);
793
- return Promise.all([filesPromise, projectPromise]);
794
- })
795
- .then(([files, projectData]) => {
796
- var _a;
1783
+ (_d = appComponent.current) === null || _d === void 0 ? void 0 : _d.setCrowdinLanguagesData(languagesSorted);
1784
+ }
1785
+ else {
1786
+ const [files, projectData] = await Promise.all([
1787
+ fetch('api/crowdin/files' + restParams).then(checkResponse),
1788
+ fetch('api/crowdin/project' + restParams).then(checkResponse),
1789
+ ]);
797
1790
  const tree = files.map(transformCrowdinItemToTree);
798
1791
  crowdinData.current = tree;
799
1792
  appComponent.current.setCrowdinFilesData(tree);
@@ -805,37 +1798,35 @@
805
1798
  ...language,
806
1799
  }))
807
1800
  .sort((a, b) => a.name.localeCompare(b.name));
808
- if (project.current.inContext && ((_a = config.current) === null || _a === void 0 ? void 0 : _a.inContext)) {
1801
+ if (project.current.inContext && ((_f = config.current) === null || _f === void 0 ? void 0 : _f.inContext)) {
809
1802
  languagesSorted.push({ ...project.current.inContextPseudoLanguage, inContext: true });
810
1803
  }
811
1804
  setLanguagesForTranslation(languagesSorted);
812
1805
  appComponent.current.setCrowdinLanguagesData(languagesSorted);
813
- });
814
- }
815
- promise
816
- .then(() => {
1806
+ }
817
1807
  if (withCronSync || webhooks) {
818
- return getSyncSettings('crowdin');
1808
+ await getSyncSettings('crowdin');
819
1809
  }
820
- })
821
- .catch((e) => catchRejection(e, "Can't fetch Crowdin data"))
822
- .finally(() => appComponent.current.setAttribute('is-crowdin-loading', false));
1810
+ }
1811
+ catch (e) {
1812
+ catchRejection(e, "Can't fetch Crowdin data");
1813
+ }
1814
+ finally {
1815
+ appComponent.current.setAttribute('is-crowdin-loading', false);
1816
+ }
823
1817
  }
824
- function getIntegrationData({ hardReload = false, parentId = '', search = '', page = 0, recursion = false, paginationData } = {}, recursionState = null) {
1818
+ async function getIntegrationData({ hardReload = false, parentId = '', search = '', page = 0, recursion = false, paginationData } = {}, recursionState = null) {
825
1819
  if (!paginationData) {
826
1820
  appComponent.current.setAttribute('is-integration-loading', true);
827
1821
  }
828
1822
  let recursionStateLocal = recursionState;
829
- return checkOrigin()
830
- .then((restParams) => {
1823
+ try {
1824
+ const restParams = await checkOrigin();
831
1825
  let url = `api/integration/data${restParams}&parent_id=${encodeURIComponent(parentId)}&search=${encodeURIComponent(search)}&page=${page}`;
832
1826
  if (paginationData) {
833
1827
  url += `&paginationData=${encodeURIComponent(JSON.stringify(paginationData))}`;
834
1828
  }
835
- return fetch(url);
836
- })
837
- .then(checkResponse)
838
- .then(async (res) => {
1829
+ const res = await checkResponse(await fetch(url));
839
1830
  const files = res.data;
840
1831
  const stopPagination = res.stopPagination;
841
1832
  const tree = files.map((e) => {
@@ -855,10 +1846,10 @@
855
1846
  item.notSynced = e.notSynced;
856
1847
  item.synced = e.synced;
857
1848
  item.type = e.type;
858
- item.node_type = fileType;
1849
+ item.node_type = FILE_TYPE;
859
1850
  }
860
1851
  else {
861
- item.node_type = e.nodeType || folderType;
1852
+ item.node_type = e.nodeType || FOLDER_TYPE;
862
1853
  }
863
1854
  return item;
864
1855
  });
@@ -870,17 +1861,16 @@
870
1861
  appComponent.current.setIntegrationFilesData(tree);
871
1862
  }
872
1863
  else if (tree.length) {
873
- appComponent.current.pushIntegrationFilesData(tree).then(() => {
1864
+ appComponent.current.pushIntegrationFilesData(tree).then(async () => {
874
1865
  if (parentId) {
875
- appIntegrationFiles.getSelected().then(async (selection) => {
876
- const selectedIds = selection === null || selection === void 0 ? void 0 : selection.filter((node) => node).map(({ id }) => id.toString());
877
- const filteredNodes = tree.filter((node) => !selectedIds.includes(node.id.toString()) &&
878
- selectedIds.includes(node.parent_id.toString()));
879
- if (filteredNodes === null || filteredNodes === void 0 ? void 0 : filteredNodes.length) {
880
- const filteredNodesId = filteredNodes.map(({ id }) => id.toString());
881
- await appIntegrationFiles.setSelected(filteredNodesId);
882
- }
883
- });
1866
+ const selection = await appIntegrationFiles.getSelected();
1867
+ const selectedIds = selection === null || selection === void 0 ? void 0 : selection.filter((node) => node).map(({ id }) => id.toString());
1868
+ const filteredNodes = tree.filter((node) => !selectedIds.includes(node.id.toString()) &&
1869
+ selectedIds.includes(node.parent_id.toString()));
1870
+ if (filteredNodes === null || filteredNodes === void 0 ? void 0 : filteredNodes.length) {
1871
+ const filteredNodesId = filteredNodes.map(({ id }) => id.toString());
1872
+ await appIntegrationFiles.setSelected(filteredNodesId);
1873
+ }
884
1874
  }
885
1875
  });
886
1876
  }
@@ -912,18 +1902,18 @@
912
1902
  }
913
1903
  const folderItems = files.filter(isFolder);
914
1904
  if (folderItems.length === 0) {
915
- return Promise.resolve();
1905
+ return;
916
1906
  }
917
1907
  folderItems.forEach((folder) => recursionStateLocal.openedFolders.add(folder.id));
918
- const currentOpenedFolders = await appComponent.current.getIntegrationOpenedFolders();
1908
+ const openedFoldersNow = await appComponent.current.getIntegrationOpenedFolders();
919
1909
  appComponent.current.setIntegrationOpenedFolders([
920
- ...currentOpenedFolders,
1910
+ ...openedFoldersNow,
921
1911
  ...recursionStateLocal.openedFolders,
922
1912
  ]);
923
- const recursivePromises = folderItems.map(async (folder) => {
1913
+ await Promise.all(folderItems.map(async (folder) => {
924
1914
  recursionStateLocal.calls++;
925
1915
  try {
926
- return getIntegrationData({ parentId: folder.id, recursion: true }, recursionState);
1916
+ await getIntegrationData({ parentId: folder.id, recursion: true }, recursionState);
927
1917
  }
928
1918
  finally {
929
1919
  recursionStateLocal.calls--;
@@ -931,24 +1921,23 @@
931
1921
  recursionStateLocal.setLoading(false);
932
1922
  }
933
1923
  }
934
- });
935
- return Promise.all(recursivePromises);
1924
+ }));
936
1925
  }
937
- })
938
- .then(() => {
939
1926
  if (withCronSync || webhooks) {
940
- getSyncSettings('integration');
1927
+ await getSyncSettings('integration');
941
1928
  }
942
- })
943
- .catch((e) => catchRejection(e, `Can't fetch ${name} templates`))
944
- .finally(() => {
1929
+ }
1930
+ catch (e) {
1931
+ catchRejection(e, `Can't fetch ${name} templates`);
1932
+ }
1933
+ finally {
945
1934
  if (!recursionStateLocal && !recursion) {
946
1935
  appComponent.current.setAttribute('is-integration-loading', false);
947
1936
  }
948
1937
  else if (recursionStateLocal && recursionStateLocal.calls === 0) {
949
1938
  appComponent.current.setAttribute('is-integration-loading', false);
950
1939
  }
951
- });
1940
+ }
952
1941
  }
953
1942
  function isScheduleDisabled(currentConfig = config.current) {
954
1943
  var _a;
@@ -965,10 +1954,7 @@
965
1954
  if (currentScheduleDisabled === nextScheduleDisabled) {
966
1955
  return null;
967
1956
  }
968
- return {
969
- ...item,
970
- scheduleDisabled: nextScheduleDisabled,
971
- };
1957
+ return { ...item, scheduleDisabled: nextScheduleDisabled };
972
1958
  })
973
1959
  .filter(Boolean);
974
1960
  if (provider === 'crowdin') {
@@ -996,1176 +1982,695 @@
996
1982
  async function refreshAutoSyncPausedIndicatorsAndWarning() {
997
1983
  const [crowdinSyncSettings, integrationSyncSettings] = await Promise.all([
998
1984
  fetchSyncSettingsFiles('crowdin'),
999
- fetchSyncSettingsFiles('integration'),
1000
- ]);
1001
- await applyAutoSyncPausedMarkers('crowdin', crowdinSyncSettings);
1002
- await applyAutoSyncPausedMarkers('integration', integrationSyncSettings);
1003
- if (isScheduleDisabled() && (crowdinSyncSettings.length || integrationSyncSettings.length)) {
1004
- showToast('Auto Sync is configured for some files, but sync schedule is disabled in app settings.');
1005
- }
1006
- }
1007
- function getSyncSettings(provider) {
1008
- checkOrigin()
1009
- .then((restParams) => fetch(`/api/sync-settings/${provider}` + restParams))
1010
- .then(checkResponse)
1011
- .then(async (res) => {
1012
- if (provider === 'crowdin') {
1013
- if (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.crowdin) {
1014
- appComponent.current.setCrowdinScheduleSync(res, true, true);
1015
- }
1016
- else {
1017
- appComponent.current.setCrowdinScheduleSync(res);
1018
- }
1019
- }
1020
- else {
1021
- if (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.integration) {
1022
- appComponent.current.setIntegrationScheduleSync(res, true, true);
1023
- }
1024
- else {
1025
- appComponent.current.setIntegrationScheduleSync(res);
1026
- }
1027
- }
1028
- await applyAutoSyncPausedMarkers(provider, res);
1029
- })
1030
- .catch((e) => catchRejection(e, "Can't fetch file progress"));
1031
- }
1032
- function getFileProgress(fileId) {
1033
- checkOrigin()
1034
- .then((restParams) => fetch(`api/crowdin/file-progress/${fileId}` + restParams))
1035
- .then(checkResponse)
1036
- .then((res) => appComponent.current.addCrowdinFileProgress(res))
1037
- .catch((e) => catchRejection(e, "Can't fetch file progress"));
1038
- }
1039
- function uploadFilesToCrowdin(event, languages = []) {
1040
- var _a, _b, _c, _d, _e;
1041
- let files = [];
1042
- let uploadTranslations = false;
1043
- let forcePushSources = false;
1044
- if (((_a = event.detail) === null || _a === void 0 ? void 0 : _a.action) === 'uploadTranslations') {
1045
- files = event.detail.files;
1046
- uploadTranslations = true;
1047
- forcePushSources = true;
1048
- }
1049
- else if (((_b = event.detail) === null || _b === void 0 ? void 0 : _b.action) === 'excludedTargetLanguages') {
1050
- fileToSync.current = event.detail.files;
1051
- openLanguageModal();
1052
- return;
1053
- }
1054
- else if (((_c = event.detail) === null || _c === void 0 ? void 0 : _c.action) === 'forcePushSources') {
1055
- files = event.detail.files;
1056
- forcePushSources = true;
1057
- }
1058
- else if (((_d = event.detail) === null || _d === void 0 ? void 0 : _d.action) === 'syncTranslationsToIntegration') {
1059
- syncTranslationsToIntegration(event.detail.files);
1060
- return;
1061
- }
1062
- else {
1063
- files = event.detail;
1064
- }
1065
- if (languages.length > 0) {
1066
- forcePushSources = true;
1067
- }
1068
- if (((_e = event.detail) === null || _e === void 0 ? void 0 : _e.length) === 0 || !event.detail) {
1069
- showToast('Select templates which will be pushed to Crowdin');
1070
- return;
1071
- }
1072
- appComponent.current.setAttribute('is-to-crowdin-process', true);
1073
- let req;
1074
- if (integrationOneLevelFetching) {
1075
- req = files.map((f) => ({
1076
- name: f.name,
1077
- id: f.id,
1078
- type: f.type,
1079
- parentId: f.parent_id,
1080
- nodeType: f.node_type,
1081
- isUpdated: f.isUpdated,
1082
- }));
1083
- }
1084
- else {
1085
- req = files
1086
- .filter((f) => f.node_type !== folderType)
1087
- .map((f) => ({
1088
- name: f.name,
1089
- id: f.id,
1090
- type: f.type,
1091
- parentId: f.parent_id,
1092
- isUpdated: f.isUpdated,
1093
- }));
1094
- }
1095
- checkOrigin()
1096
- .then((restParams) => fetch(`api/crowdin/update${restParams}&uploadTranslations=${uploadTranslations}&languages=${languages}&forcePushSources=${forcePushSources}`, {
1097
- method: 'POST',
1098
- headers: { 'Content-Type': 'application/json' },
1099
- body: JSON.stringify(req),
1100
- }))
1101
- .then(checkResponse)
1102
- .then((res) => {
1103
- checkJob({
1104
- jobId: res === null || res === void 0 ? void 0 : res.jobId,
1105
- jobType: JOB_TYPE.updateCrowdin,
1106
- });
1107
- })
1108
- .catch((e) => catchRejection(e, "Can't upload templates to Crowdin"));
1109
- }
1110
- function getActiveJobs() {
1111
- checkOrigin()
1112
- .then((restParams) => fetch(`api/jobs${restParams}`))
1113
- .then(checkResponse)
1114
- .then((jobs) => {
1115
- if (!Array.isArray(jobs)) {
1116
- return;
1117
- }
1118
- jobs.forEach((job) => {
1119
- switch (job.type) {
1120
- case JOB_TYPE.updateCrowdin:
1121
- case JOB_TYPE.updateTargetLanguages:
1122
- appComponent.current.setAttribute('is-to-crowdin-process', true);
1123
- break;
1124
- case JOB_TYPE.updateIntegration:
1125
- appComponent.current.setAttribute('is-to-integration-process', true);
1126
- break;
1127
- case JOB_TYPE.crowdinSyncSettingsSave:
1128
- appComponent.current.setAttribute('is-crowdin-sync-settings-in-progress', true);
1129
- break;
1130
- case JOB_TYPE.integrationSyncSettingsSave:
1131
- appComponent.current.setAttribute('is-integration-sync-settings-in-progress', true);
1132
- break;
1133
- }
1134
- checkJob({
1135
- jobId: job.id,
1136
- jobType: job.type,
1137
- });
1138
- });
1139
- })
1140
- .catch((e) => catchRejection(e, 'Sync status check failed'));
1141
- }
1142
- function cancelJob(jobId) {
1143
- var _a;
1144
- if ((_a = asyncJobs.current[jobId]) === null || _a === void 0 ? void 0 : _a.isFailed) {
1145
- return;
1146
- }
1147
- checkOrigin()
1148
- .then((restParams) => fetch('api/jobs' + restParams + '&jobId=' + jobId, {
1149
- method: 'DELETE',
1150
- headers: { 'Content-Type': 'application/json' },
1151
- }))
1152
- .then(checkResponse)
1153
- .then(() => showToast('Cancellation…'))
1154
- .catch((e) => catchRejection(e, 'Sync cancellation failed'));
1155
- }
1156
- function checkJob({ jobId, jobType, onSuccess, onError, onFinally }) {
1157
- switch (jobType) {
1158
- case JOB_TYPE.updateCrowdin:
1159
- case JOB_TYPE.updateTargetLanguages:
1160
- if (!onFinally) {
1161
- onFinally = () => {
1162
- appComponent.current.setAttribute('is-to-crowdin-process', false);
1163
- getCrowdinData();
1164
- };
1165
- }
1166
- break;
1167
- case JOB_TYPE.updateIntegration:
1168
- if (!onFinally) {
1169
- onFinally = () => appComponent.current.setAttribute('is-to-integration-process', false);
1170
- }
1171
- break;
1172
- case JOB_TYPE.crowdinSyncSettingsSave:
1173
- if (!onFinally) {
1174
- onFinally = () => appComponent.current.setAttribute('is-crowdin-sync-settings-in-progress', false);
1175
- }
1176
- break;
1177
- case JOB_TYPE.integrationSyncSettingsSave:
1178
- if (!onFinally) {
1179
- onFinally = () => appComponent.current.setAttribute('is-integration-sync-settings-in-progress', false);
1180
- }
1181
- break;
1985
+ fetchSyncSettingsFiles('integration'),
1986
+ ]);
1987
+ await applyAutoSyncPausedMarkers('crowdin', crowdinSyncSettings);
1988
+ await applyAutoSyncPausedMarkers('integration', integrationSyncSettings);
1989
+ if (isScheduleDisabled() && (crowdinSyncSettings.length || integrationSyncSettings.length)) {
1990
+ showToast('Auto Sync is configured for some files, but sync schedule is disabled in app settings.');
1182
1991
  }
1183
- checkOrigin()
1184
- .then((restParams) => fetch('api/jobs' + restParams + '&jobId=' + jobId))
1185
- .then(checkResponse)
1186
- .then((job) => {
1187
- const isFailed = [JOB_STATUS.failed, JOB_STATUS.canceled].includes(job.status);
1188
- const progress = isFailed || JOB_STATUS.finished === job.status ? 100 : job.progress;
1189
- const info = JOB_STATUS.canceled === job.status ? `Cancelled\n${job.info || ''}` : job.info;
1190
- if (!silentJobs.find((type) => type === jobType)) {
1191
- pushJobs([
1192
- {
1193
- id: job.id,
1194
- title: job.title,
1195
- progress,
1196
- info,
1197
- isFailed,
1198
- },
1199
- ]);
1200
- }
1201
- if (isFailed) {
1202
- if (onError) {
1203
- onError();
1992
+ }
1993
+ async function getSyncSettings(provider) {
1994
+ try {
1995
+ const restParams = await checkOrigin();
1996
+ const res = await checkResponse(await fetch(`/api/sync-settings/${provider}` + restParams));
1997
+ if (provider === 'crowdin') {
1998
+ if (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.crowdin) {
1999
+ appComponent.current.setCrowdinScheduleSync(res, true, true);
2000
+ }
2001
+ else {
2002
+ appComponent.current.setCrowdinScheduleSync(res);
1204
2003
  }
1205
- }
1206
- else if ([JOB_STATUS.created, JOB_STATUS.inProgress].includes(job.status) && job.progress < 100) {
1207
- setTimeout(() => {
1208
- checkJob({ jobId, jobType, onSuccess, onError, onFinally });
1209
- }, asyncProgress.checkInterval);
1210
- return;
1211
2004
  }
1212
2005
  else {
1213
- if (onSuccess) {
1214
- onSuccess(job);
2006
+ if (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.integration) {
2007
+ appComponent.current.setIntegrationScheduleSync(res, true, true);
2008
+ }
2009
+ else {
2010
+ appComponent.current.setIntegrationScheduleSync(res);
1215
2011
  }
1216
2012
  }
1217
- if (onFinally) {
1218
- onFinally(job);
1219
- }
1220
- })
1221
- .catch((e) => {
1222
- if (onFinally) {
1223
- onFinally();
1224
- }
1225
- if (!silentJobs.find((type) => type === jobType)) {
1226
- pushJobs([
1227
- {
1228
- id: jobId,
1229
- isFailed: true,
1230
- },
1231
- ]);
1232
- }
1233
- showToast('Sync status check failed');
1234
- });
2013
+ await applyAutoSyncPausedMarkers(provider, res);
2014
+ }
2015
+ catch (e) {
2016
+ catchRejection(e, "Can't fetch file progress");
2017
+ }
1235
2018
  }
1236
- function pushJobs(jobs) {
1237
- const el = document.querySelector('crowdin-async-progress');
1238
- if (el && el.pushJobs) {
1239
- el.pushJobs(jobs);
1240
- jobs.forEach((job) => (asyncJobs.current[job.id] = job));
2019
+ async function getFileProgress(fileId) {
2020
+ try {
2021
+ const restParams = await checkOrigin();
2022
+ const res = await checkResponse(await fetch(`api/crowdin/file-progress/${fileId}` + restParams));
2023
+ appComponent.current.addCrowdinFileProgress(res);
1241
2024
  }
1242
- else {
1243
- setTimeout(() => {
1244
- pushJobs(jobs);
1245
- }, 300);
2025
+ catch (e) {
2026
+ catchRejection(e, "Can't fetch file progress");
1246
2027
  }
1247
2028
  }
1248
- function uploadFilesToIntegration(event) {
1249
- var _a, _b, _c, _d;
1250
- let files = {};
1251
- let forcePushTranslations = false;
1252
- if (((_a = event.detail) === null || _a === void 0 ? void 0 : _a.action) === 'forcePushTranslations') {
2029
+ async function uploadFilesToCrowdin(event, languages = []) {
2030
+ var _a, _b, _c, _d, _f;
2031
+ let files = [];
2032
+ let uploadTranslations = false;
2033
+ let forcePushSources = false;
2034
+ if (((_a = event.detail) === null || _a === void 0 ? void 0 : _a.action) === 'uploadTranslations') {
1253
2035
  files = event.detail.files;
1254
- forcePushTranslations = true;
2036
+ uploadTranslations = true;
2037
+ forcePushSources = true;
1255
2038
  }
1256
2039
  else if (((_b = event.detail) === null || _b === void 0 ? void 0 : _b.action) === 'excludedTargetLanguages') {
1257
- crowdinFilesToUpdateTargetLanguages.current = event.detail.files;
1258
- openLanguageModalForCrowdinFiles();
2040
+ fileToSync.current = event.detail.files;
2041
+ openLanguageModal();
1259
2042
  return;
1260
2043
  }
1261
- else if (((_c = event.detail) === null || _c === void 0 ? void 0 : _c.action) === 'syncSourcesToCrowdin') {
1262
- syncToCrowdinFromCrowdinFiles(event.detail.files, false);
1263
- return;
2044
+ else if (((_c = event.detail) === null || _c === void 0 ? void 0 : _c.action) === 'forcePushSources') {
2045
+ files = event.detail.files;
2046
+ forcePushSources = true;
1264
2047
  }
1265
- else if (((_d = event.detail) === null || _d === void 0 ? void 0 : _d.action) === 'syncTranslationsToCrowdin') {
1266
- syncToCrowdinFromCrowdinFiles(event.detail.files, true);
2048
+ else if (((_d = event.detail) === null || _d === void 0 ? void 0 : _d.action) === 'syncTranslationsToIntegration') {
2049
+ syncTranslationsToIntegration(event.detail.files);
1267
2050
  return;
1268
2051
  }
1269
2052
  else {
1270
2053
  files = event.detail;
1271
2054
  }
1272
- if (Object.keys(event.detail).length === 0 || !event.detail) {
1273
- showToast('Select files which will be uploaded to ${name}');
1274
- return;
2055
+ if (languages.length > 0) {
2056
+ forcePushSources = true;
1275
2057
  }
1276
- appComponent.current.setAttribute('is-to-integration-process', true);
1277
- const req = {};
1278
- Object.keys(files)
1279
- .filter((id) => crowdinData.current.find((c) => c.id === id).node_type === fileType)
1280
- .forEach((id) => (req[id] = files[id]));
1281
- checkOrigin()
1282
- .then((restParams) => fetch(`api/integration/update${restParams}&forcePushTranslations=${forcePushTranslations}`, {
1283
- method: 'POST',
1284
- headers: { 'Content-Type': 'application/json' },
1285
- body: JSON.stringify(req),
1286
- }))
1287
- .then(checkResponse)
1288
- .then((res) => {
1289
- checkJob({
1290
- jobId: res === null || res === void 0 ? void 0 : res.jobId,
1291
- jobType: JOB_TYPE.updateIntegration,
1292
- });
1293
- })
1294
- .catch((e) => catchRejection(e, `Can't upload files to ${name}`));
1295
- }
1296
- function syncToCrowdinFromCrowdinFiles(files, uploadTranslations) {
1297
- if (!files || Object.keys(files).length === 0) {
1298
- showToast('Select files to sync');
2058
+ if (((_f = event.detail) === null || _f === void 0 ? void 0 : _f.length) === 0 || !event.detail) {
2059
+ showToast('Select templates which will be pushed to Crowdin');
1299
2060
  return;
1300
2061
  }
1301
2062
  appComponent.current.setAttribute('is-to-crowdin-process', true);
1302
- const req = {};
1303
- Object.keys(files)
1304
- .filter((id) => { var _a; return ((_a = crowdinData.current.find((c) => c.id === id)) === null || _a === void 0 ? void 0 : _a.node_type) === fileType; })
1305
- .forEach((id) => (req[id] = files[id]));
1306
- checkOrigin()
1307
- .then((restParams) => fetch(`api/crowdin/update${restParams}&matchFromCrowdin=true&uploadTranslations=${uploadTranslations}`, {
1308
- method: 'POST',
1309
- headers: { 'Content-Type': 'application/json' },
1310
- body: JSON.stringify(req),
1311
- }))
1312
- .then(checkResponse)
1313
- .then((res) => {
1314
- checkJob({
1315
- jobId: res === null || res === void 0 ? void 0 : res.jobId,
1316
- jobType: JOB_TYPE.updateCrowdin,
1317
- });
1318
- })
1319
- .catch((e) => catchRejection(e, "Can't sync files to Crowdin"));
1320
- }
1321
- function syncTranslationsToIntegration(files) {
1322
- if (!files || files.length === 0) {
1323
- showToast('Select files to sync');
1324
- return;
1325
- }
1326
- appComponent.current.setAttribute('is-to-integration-process', true);
1327
- const req = files
1328
- .filter((f) => f.node_type !== folderType)
1329
- .map((f) => ({
1330
- name: f.name,
1331
- id: f.id,
1332
- type: f.type,
1333
- parentId: f.parent_id,
1334
- }));
1335
- checkOrigin()
1336
- .then((restParams) => fetch(`api/integration/update${restParams}&matchFromIntegration=true`, {
1337
- method: 'POST',
1338
- headers: { 'Content-Type': 'application/json' },
1339
- body: JSON.stringify(req),
1340
- }))
1341
- .then(checkResponse)
1342
- .then((res) => {
1343
- checkJob({
1344
- jobId: res === null || res === void 0 ? void 0 : res.jobId,
1345
- jobType: JOB_TYPE.updateIntegration,
1346
- });
1347
- })
1348
- .catch((e) => catchRejection(e, `Can't sync translations to ${name}`));
1349
- }
1350
- function openLanguageModal() {
1351
- openModal(languageModal.current);
1352
- }
1353
- function openLanguageModalForCrowdinFiles() {
1354
- const languages = project.current.targetLanguages || [];
1355
- const buttonHtml = `
1356
- <crowdin-button id="update-crowdin-target-languages" outlined">
1357
- Update Target Languages
1358
- </crowdin-button>
1359
- `;
1360
- setTimeout(() => {
1361
- const btn = document.querySelector('#update-crowdin-target-languages');
1362
- if (btn) {
1363
- btn.addEventListener('click', () => updateCrowdinFilesTargetLanguages());
1364
- }
1365
- }, 0);
1366
- setLanguagesForTranslation(languages, buttonHtml);
1367
- openModal(languageModal.current);
1368
- }
1369
- async function uploadFilesToCrowdinWithExcludedLanguages() {
1370
- const languageSelect = document.querySelector('#language-select');
1371
- const selectedLanguages = await languageSelect.getValue();
1372
- closeModal(languageModal.current);
1373
- uploadFilesToCrowdin({ detail: fileToSync.current }, selectedLanguages);
1374
- }
1375
- async function updateCrowdinFilesTargetLanguages() {
1376
- const languageSelect = document.querySelector('#language-select');
1377
- const selectedLanguages = await languageSelect.getValue();
1378
- closeModal(languageModal.current);
1379
- const fileIds = Object.keys(crowdinFilesToUpdateTargetLanguages.current).map((id) => parseInt(id, 10));
1380
- if (fileIds.length === 0) {
1381
- showToast('Select files to update');
1382
- return;
2063
+ let req;
2064
+ if (integrationOneLevelFetching) {
2065
+ req = files.map((f) => ({
2066
+ name: f.name,
2067
+ id: f.id,
2068
+ type: f.type,
2069
+ parentId: f.parent_id,
2070
+ nodeType: f.node_type,
2071
+ isUpdated: f.isUpdated,
2072
+ }));
1383
2073
  }
1384
- appComponent.current.setAttribute('is-to-crowdin-process', true);
1385
- checkOrigin()
1386
- .then((restParams) => fetch(`api/crowdin/files-target-languages${restParams}`, {
1387
- method: 'POST',
1388
- headers: { 'Content-Type': 'application/json' },
1389
- body: JSON.stringify({ fileIds, languages: selectedLanguages }),
1390
- }))
1391
- .then(checkResponse)
1392
- .then((res) => {
1393
- checkJob({
1394
- jobId: res === null || res === void 0 ? void 0 : res.jobId,
1395
- jobType: JOB_TYPE.updateTargetLanguages,
1396
- });
1397
- })
1398
- .catch((e) => catchRejection(e, "Can't update files target languages"));
1399
- }
1400
- async function setLanguagesForTranslation(languages, buttonHtml) {
1401
- const defaultButtonHtml = `
1402
- <crowdin-button id="upload-exclude-languages" outlined">
1403
- <div class="integration-icon-button">
1404
- <span>Sync to</span>
1405
- <crowdin-logo is-icon/>
1406
- </div>
1407
- </crowdin-button>
1408
- `;
1409
- setTimeout(() => {
1410
- const btn = document.querySelector('#upload-exclude-languages');
1411
- if (btn) {
1412
- btn.addEventListener('click', () => uploadFilesToCrowdinWithExcludedLanguages());
1413
- }
1414
- }, 0);
1415
- const languageIds = languages.map((language) => language.id);
1416
- if (languageModal.current) {
1417
- let modalContent = `<div>
1418
- <crowdin-select
1419
- is-multi
1420
- is-searchable
1421
- is-position-fixed
1422
- close-on-select="false"
1423
- name="languages"
1424
- id="language-select"
1425
- label="Languages"
1426
- >
1427
- `;
1428
- for (const language of languages) {
1429
- modalContent += `<option value="${language.id}">${language.name}</option>`;
1430
- }
1431
- modalContent += `
1432
- </crowdin-select>
1433
- </div>
1434
- <div slot="footer">
1435
- ${buttonHtml || defaultButtonHtml}
1436
- </div>
1437
- `;
1438
- languageModal.current.innerHTML = modalContent;
1439
- const select = document.querySelector('#language-select');
1440
- await select.setValue(languageIds);
2074
+ else {
2075
+ req = files
2076
+ .filter((f) => f.node_type !== FOLDER_TYPE)
2077
+ .map((f) => ({
2078
+ name: f.name,
2079
+ id: f.id,
2080
+ type: f.type,
2081
+ parentId: f.parent_id,
2082
+ isUpdated: f.isUpdated,
2083
+ }));
1441
2084
  }
1442
- }
1443
- function hideConfirmUsersBlock() {
1444
- const confirmUsersBlock = document.querySelector('.confirm-users-block');
1445
- confirmUsersBlock.classList.add('hidden');
1446
- const permissionsModal = document.getElementById('permissions-modal');
1447
- permissionsModal.setAttribute('body-overflow-unset', true);
1448
- }
1449
- function getUserFullName(user) {
1450
- if (user.full_name) {
1451
- return user.full_name;
2085
+ try {
2086
+ const restParams = await checkOrigin();
2087
+ const res = await checkResponse(await fetch(`api/crowdin/update${restParams}&uploadTranslations=${uploadTranslations}&languages=${languages}&forcePushSources=${forcePushSources}`, {
2088
+ method: 'POST',
2089
+ headers: { 'Content-Type': 'application/json' },
2090
+ body: JSON.stringify(req),
2091
+ }));
2092
+ checkJob({ jobId: res === null || res === void 0 ? void 0 : res.jobId, jobType: JOB_TYPE.updateCrowdin });
1452
2093
  }
1453
- const ownerFullName = user.name || ((user.first_name || '') + ' ' + (user.last_name || '')).trim();
1454
- return !!ownerFullName && (user === null || user === void 0 ? void 0 : user.login) !== ownerFullName ? `${ownerFullName} (${user === null || user === void 0 ? void 0 : user.login})` : user === null || user === void 0 ? void 0 : user.login;
1455
- }
1456
- function showPermissionsDialog() {
1457
- const permissions = document.getElementById('permissions-modal');
1458
- hideConfirmUsersBlock();
1459
- openModal(permissions);
1460
- setLoader('#permissions-modal');
1461
- const select = document.getElementById('users');
1462
- select.value = '[]';
1463
- Promise.all([
1464
- new Promise((resolve) => {
1465
- checkOrigin()
1466
- .then((restParams) => fetch('api/users' + restParams))
1467
- .then(checkResponse)
1468
- .then((res) => {
1469
- resolve(JSON.stringify(res.data.managers));
1470
- });
1471
- }),
1472
- new Promise((resolve) => {
1473
- AP.getUsers((res) => {
1474
- const users = Object.values(res).filter((user) => user.id !== Number(userId));
1475
- resolve(users);
1476
- });
1477
- }),
1478
- ])
1479
- .then(([managers, users]) => {
1480
- const parsedManagers = (JSON.parse(managers) || []);
1481
- const availableUsers = users;
1482
- const validUserIds = new Set(availableUsers.map((user) => `${user.id}`));
1483
- const filteredManagers = parsedManagers.filter((id) => validUserIds.has(id));
1484
- select.innerHTML = availableUsers
1485
- .map((user) => `<option value="${user.id}">${sanitizeHTML(getUserFullName(user))}</option>`)
1486
- .join('');
1487
- select.value = JSON.stringify(filteredManagers);
1488
- })
1489
- .catch((e) => catchRejection(e, "Can't fetch users"))
1490
- .finally(() => unsetLoader('#permissions-modal'));
1491
- }
1492
- function showConfirmUsersBlock() {
1493
- const confirmUsersBlock = document.querySelector('.confirm-users-block');
1494
- confirmUsersBlock.classList.remove('hidden');
1495
- const permissionsModal = document.getElementById('permissions-modal');
1496
- permissionsModal.removeAttribute('body-overflow-unset');
1497
- }
1498
- function checkUsers() {
1499
- setLoader('#permissions-modal');
1500
- const select = document.getElementById('users');
1501
- if (select.value === '[]') {
1502
- hideConfirmUsersBlock();
1503
- unsetLoader('#permissions-modal');
1504
- return;
2094
+ catch (e) {
2095
+ catchRejection(e, "Can't upload templates to Crowdin");
1505
2096
  }
1506
- const users = JSON.parse(select.value);
1507
- const user_ids = users.filter((id) => parseInt(id));
1508
- const emails = users.filter((id) => !parseInt(id));
1509
- const params = { user_ids, emails };
1510
- Promise.all([
1511
- new Promise((resolve) => {
1512
- checkOrigin()
1513
- .then((restParams) => fetch('api/users' + restParams))
1514
- .then(checkResponse)
1515
- .then((usersResponse) => {
1516
- resolve(usersResponse.data.managers);
1517
- });
1518
- }),
1519
- new Promise((resolve) => {
1520
- AP.validateUsers(params, (res) => {
1521
- resolve(res.data);
1522
- });
1523
- }),
1524
- new Promise((resolve) => {
1525
- AP.getUsers((res) => {
1526
- resolve(res);
1527
- });
1528
- }),
1529
- ])
1530
- .then(([appManagers, checkUsersResponse, allUsers]) => {
1531
- const newUserEmails = checkUsersResponse.newUserEmails.map((email) => ({ name: email }));
1532
- const newProjectManagers = [
1533
- ...newUserEmails,
1534
- ...checkUsersResponse.newProjectManagers.map((user) => ({
1535
- name: getUserFullName(user),
1536
- })),
1537
- ];
1538
- const newApplicationAccessUsers = [
1539
- ...newUserEmails,
1540
- ...checkUsersResponse.newApplicationAccessUsers.map((user) => ({
1541
- name: getUserFullName(user),
1542
- })),
1543
- ];
1544
- const newApplicationManagers = [
1545
- ...newUserEmails,
1546
- ...Object.values(allUsers)
1547
- .filter((user) => users.some((id) => +id === user.id) && !appManagers.some((id) => +id === user.id))
1548
- .map((user) => ({ name: getUserFullName(user) })),
1549
- ];
1550
- prepareUsersConfirmBlock({
1551
- ...checkUsersResponse,
1552
- newUserEmails,
1553
- newProjectManagers,
1554
- newApplicationAccessUsers,
1555
- newApplicationManagers,
1556
- });
1557
- })
1558
- .catch((e) => catchRejection(e, (e === null || e === void 0 ? void 0 : e.error) || "Can't invite users"))
1559
- .finally(() => unsetLoader('#permissions-modal'));
1560
2097
  }
1561
- function inviteUsers() {
1562
- setLoader('#permissions-modal');
1563
- const select = document.getElementById('users');
1564
- const users = JSON.parse(select.value);
1565
- const user_ids = users.filter((id) => parseInt(id));
1566
- const emails = users.filter((id) => !parseInt(id));
1567
- const params = { user_ids, emails };
1568
- AP.inviteUsers(params, (res) => {
1569
- var _a;
1570
- if (!res.success) {
1571
- catchRejection(res, ((_a = res === null || res === void 0 ? void 0 : res.error) === null || _a === void 0 ? void 0 : _a.message) || "Can't invite users");
1572
- unsetLoader('#permissions-modal');
2098
+ async function getActiveJobs() {
2099
+ try {
2100
+ const restParams = await checkOrigin();
2101
+ const jobs = await checkResponse(await fetch(`api/jobs${restParams}`));
2102
+ if (!Array.isArray(jobs)) {
1573
2103
  return;
1574
2104
  }
1575
- checkOrigin()
1576
- .then((restParams) => fetch('api/invite-users' + restParams, {
1577
- method: 'POST',
1578
- headers: { 'Content-Type': 'application/json' },
1579
- body: JSON.stringify(res.data),
1580
- }))
1581
- .then(checkResponse)
1582
- .then((res) => {
1583
- const permissions = document.getElementById('permissions-modal');
1584
- if (!res.success) {
1585
- catchRejection(res, (res === null || res === void 0 ? void 0 : res.message) || "Can't invite users");
1586
- return;
1587
- }
1588
- showToast('Users successfully updated');
1589
- hideConfirmUsersBlock();
1590
- closeModal(permissions);
1591
- })
1592
- .catch((e) => catchRejection(e, (e === null || e === void 0 ? void 0 : e.error) || "Can't invite users"))
1593
- .finally(() => unsetLoader('#permissions-modal'));
1594
- });
1595
- }
1596
- function prepareUsersConfirmBlock(usersData) {
1597
- showConfirmUsersBlock();
1598
- const organizationInvite = document.querySelector('.organization-invite');
1599
- const projectInvite = document.querySelector('.project-invite');
1600
- const applicationCredentialsInvite = document.querySelector('.application-credentials-invite');
1601
- const grantedElement = '<crowdin-p>&horbar;</crowdin-p>';
1602
- const willGrantedElement = '<span class="badge badge-will-be-granted">Will Be Granted</span>';
1603
- const notAvailableElement = '<span class="badge badge-not-available">Action Required</span>';
1604
- // only in enterprise
1605
- if (organizationInvite) {
1606
- const organizationWillGrantElement = '<span class="badge badge-will-be-granted">Will Be Registered</span>';
1607
- processUsersWhoWillBeInvitedToOrganization(organizationInvite, usersData, organizationWillGrantElement, grantedElement, notAvailableElement);
1608
- }
1609
- processUsersWhoWillBeInvited(projectInvite, usersData.newProjectManagers, willGrantedElement, grantedElement);
1610
- processUsersWhoWillBeInvited(applicationCredentialsInvite, usersData.newApplicationManagers, willGrantedElement, grantedElement);
1611
- processUsersWhoWillBeInvitedApplicationSettings(usersData, willGrantedElement, grantedElement, notAvailableElement);
1612
- }
1613
- function processUsersWhoWillBeInvitedToOrganization(element, usersData, willGrantedElement, alreadyGrantedMessage, notAvailableElement) {
1614
- const tooltip = element.querySelector('.status');
1615
- const description = element.querySelector('.permission-description');
1616
- const userList = element.querySelector('.affected-users');
1617
- description.classList.remove('text-warning');
1618
- description.innerText = '';
1619
- const users = usersData.newUserEmails;
1620
- if (users.length) {
1621
- if (usersData.inviteRestricted) {
1622
- description.classList.add('text-warning');
1623
- description.innerText = 'New user invitations are restricted to administrators.';
1624
- tooltip.innerHTML = notAvailableElement;
1625
- }
1626
- else {
1627
- tooltip.innerHTML = willGrantedElement;
1628
- }
1629
- let affectedUsers = '<ul>';
1630
- for (const user of users) {
1631
- affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
1632
- }
1633
- affectedUsers += '</ul>';
1634
- userList.innerHTML = affectedUsers;
2105
+ jobs.forEach((job) => {
2106
+ switch (job.type) {
2107
+ case JOB_TYPE.updateCrowdin:
2108
+ case JOB_TYPE.updateTargetLanguages:
2109
+ appComponent.current.setAttribute('is-to-crowdin-process', true);
2110
+ break;
2111
+ case JOB_TYPE.updateIntegration:
2112
+ appComponent.current.setAttribute('is-to-integration-process', true);
2113
+ break;
2114
+ case JOB_TYPE.crowdinSyncSettingsSave:
2115
+ appComponent.current.setAttribute('is-crowdin-sync-settings-in-progress', true);
2116
+ break;
2117
+ case JOB_TYPE.integrationSyncSettingsSave:
2118
+ appComponent.current.setAttribute('is-integration-sync-settings-in-progress', true);
2119
+ break;
2120
+ default:
2121
+ }
2122
+ checkJob({ jobId: job.id, jobType: job.type });
2123
+ });
1635
2124
  }
1636
- else {
1637
- tooltip.innerHTML = alreadyGrantedMessage;
1638
- userList.innerHTML = alreadyGrantedMessage;
2125
+ catch (e) {
2126
+ catchRejection(e, 'Sync status check failed');
1639
2127
  }
1640
2128
  }
1641
- function processUsersWhoWillBeInvited(element, users, grantMessage, alreadyGrantedMessage) {
1642
- const tooltip = element.querySelector('.status');
1643
- const userList = element.querySelector('.affected-users');
1644
- if (users.length) {
1645
- tooltip.innerHTML = grantMessage;
1646
- let affectedUsers = '<ul>';
1647
- for (const user of users) {
1648
- affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
1649
- }
1650
- affectedUsers += '</ul>';
1651
- userList.innerHTML = affectedUsers;
2129
+ async function cancelJob(jobId) {
2130
+ var _a;
2131
+ if ((_a = asyncJobs.current[jobId]) === null || _a === void 0 ? void 0 : _a.isFailed) {
2132
+ return;
1652
2133
  }
1653
- else {
1654
- tooltip.innerHTML = alreadyGrantedMessage;
1655
- userList.innerHTML = alreadyGrantedMessage;
1656
- }
1657
- }
1658
- function processUsersWhoWillBeInvitedApplicationSettings(usersData, willGrantedElement, grantedElement, notAvailableElement) {
1659
- const applicationSettingsInvite = document.querySelector('.application-settings-invite');
1660
- const tooltip = applicationSettingsInvite.querySelector('.status');
1661
- const description = applicationSettingsInvite.querySelector('.permission-description');
1662
- const userList = applicationSettingsInvite.querySelector('.affected-users');
1663
- let descriptionMessage = 'This can be configured in organization settings (Apps section).';
1664
- description.classList.remove('text-warning');
1665
- description.innerText = descriptionMessage;
1666
- let affectedUsers = '<ul>';
1667
- if (!usersData.newApplicationAccessUsers.length) {
1668
- tooltip.innerHTML = grantedElement;
1669
- userList.innerHTML = grantedElement;
2134
+ try {
2135
+ const restParams = await checkOrigin();
2136
+ await checkResponse(await fetch('api/jobs' + restParams + '&jobId=' + jobId, {
2137
+ method: 'DELETE',
2138
+ headers: { 'Content-Type': 'application/json' },
2139
+ }));
2140
+ showToast('Cancellation…');
1670
2141
  }
1671
- else {
1672
- if (usersData.isAdmin) {
1673
- tooltip.innerHTML = willGrantedElement;
1674
- for (const user of usersData.newApplicationAccessUsers) {
1675
- affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
1676
- }
1677
- userList.innerHTML = affectedUsers + '</ul>';
1678
- }
1679
- else {
1680
- descriptionMessage += ' Only organization admins have permission to update this setting.';
1681
- description.classList.add('text-warning');
1682
- description.innerText = descriptionMessage;
1683
- tooltip.innerHTML = notAvailableElement;
1684
- for (const user of usersData.newApplicationAccessUsers) {
1685
- affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
1686
- }
1687
- userList.innerHTML = affectedUsers + '</ul>';
1688
- }
2142
+ catch (e) {
2143
+ catchRejection(e, 'Sync cancellation failed');
1689
2144
  }
1690
2145
  }
1691
- function setLoader(id) {
1692
- const loader = document.querySelector(`${id} .loader`);
1693
- loader.classList.remove('hidden');
1694
- }
1695
- function unsetLoader(id) {
1696
- const loader = document.querySelector(`${id} .loader`);
1697
- setTimeout(function () {
1698
- loader.classList.add('hidden');
1699
- }, 500);
1700
- }
1701
- function triggerEvent(el, type) {
1702
- const e = document.createEvent('HTMLEvents');
1703
- e.initEvent(type, false, true);
1704
- el.dispatchEvent(e);
1705
- }
1706
- function fillSettingsForm() {
1707
- Object.entries(config.current).forEach(([key, value]) => {
1708
- const el = document.getElementById(`${key}-settings`);
1709
- if (el && (value || el.tagName.toLowerCase() === 'crowdin-checkbox')) {
1710
- if (el.tagName.toLowerCase() === 'crowdin-select') {
1711
- if (el.hasAttribute('is-multi')) {
1712
- el.value = JSON.stringify(value);
1713
- }
1714
- else {
1715
- el.value = JSON.stringify([value]);
1716
- }
2146
+ async function checkJob({ jobId, jobType, onSuccess, onError, onFinally }) {
2147
+ switch (jobType) {
2148
+ case JOB_TYPE.updateCrowdin:
2149
+ case JOB_TYPE.updateTargetLanguages:
2150
+ if (!onFinally) {
2151
+ onFinally = () => {
2152
+ appComponent.current.setAttribute('is-to-crowdin-process', false);
2153
+ getCrowdinData();
2154
+ };
1717
2155
  }
1718
- else if (el.tagName.toLowerCase() === 'crowdin-checkbox') {
1719
- el.checked = !!value;
2156
+ break;
2157
+ case JOB_TYPE.updateIntegration:
2158
+ if (!onFinally) {
2159
+ onFinally = () => appComponent.current.setAttribute('is-to-integration-process', false);
1720
2160
  }
1721
- else if (el.tagName.toLowerCase() === 'crowdin-textarea') {
1722
- el.value = value;
1723
- el.setValue(value);
2161
+ break;
2162
+ case JOB_TYPE.crowdinSyncSettingsSave:
2163
+ if (!onFinally) {
2164
+ onFinally = () => appComponent.current.setAttribute('is-crowdin-sync-settings-in-progress', false);
1724
2165
  }
1725
- else {
1726
- el.value = value;
2166
+ break;
2167
+ case JOB_TYPE.integrationSyncSettingsSave:
2168
+ if (!onFinally) {
2169
+ onFinally = () => appComponent.current.setAttribute('is-integration-sync-settings-in-progress', false);
1727
2170
  }
1728
- triggerEvent(el, 'change');
2171
+ break;
2172
+ }
2173
+ try {
2174
+ const restParams = await checkOrigin();
2175
+ const job = await checkResponse(await fetch('api/jobs' + restParams + '&jobId=' + jobId));
2176
+ const isFailed = [JOB_STATUS.failed, JOB_STATUS.canceled].includes(job.status);
2177
+ const progress = isFailed || JOB_STATUS.finished === job.status ? 100 : job.progress;
2178
+ const info = JOB_STATUS.canceled === job.status ? `Cancelled\n${job.info || ''}` : job.info;
2179
+ if (!silentJobs.find((type) => type === jobType)) {
2180
+ pushJobs([{ id: job.id, title: job.title, progress, info, isFailed }]);
1729
2181
  }
1730
- });
1731
- // Reinitialize dependencies after form is filled
1732
- setTimeout(() => {
1733
- if (window.initializeDependencies) {
1734
- window.initializeDependencies();
1735
- }
1736
- }, 100);
1737
- }
1738
- function saveSettings() {
1739
- const settingsSaveBtn = document.getElementById('settings-save-btn');
1740
- setLoader('#settings-modal');
1741
- const settingsElements = Array.from(document.querySelectorAll('#modal-content crowdin-tabs > div'));
1742
- const tags = ['crowdin-checkbox', 'crowdin-select', 'crowdin-input', 'crowdin-textarea'];
1743
- const configReq = {};
1744
- settingsElements.forEach((tab) => {
1745
- const formElements = Array.from(tab.querySelectorAll('.crowdin-form > *'));
1746
- formElements
1747
- .filter((e) => tags.includes(e.tagName.toLowerCase()))
1748
- .forEach((e) => {
1749
- const key = e.getAttribute('_key');
1750
- let value;
1751
- if (e.tagName.toLowerCase() === 'crowdin-select') {
1752
- value = JSON.parse(e.value);
1753
- if (!e.hasAttribute('is-multi')) {
1754
- value = value.length > 0 ? value[0] : undefined;
1755
- }
1756
- }
1757
- else if (e.tagName.toLowerCase() === 'crowdin-checkbox') {
1758
- value = !!e.checked;
1759
- }
1760
- else {
1761
- value = e.value;
2182
+ if (isFailed) {
2183
+ if (onError) {
2184
+ onError();
1762
2185
  }
1763
- configReq[key] = value;
1764
- });
1765
- });
1766
- let isValidationError = false;
1767
- let isSettingsSaveJobPending = false;
1768
- let isSettingsSaveFailed = false;
1769
- settingsSaveBtn.setAttribute('disabled', true);
1770
- checkOrigin()
1771
- .then((restParams) => fetch('api/settings' + restParams, {
1772
- method: 'POST',
1773
- headers: { 'Content-Type': 'application/json' },
1774
- body: JSON.stringify({ config: configReq }),
1775
- }))
1776
- .then(checkResponse)
1777
- .then((res) => {
1778
- if (res === null || res === void 0 ? void 0 : res.jobId) {
1779
- isSettingsSaveJobPending = true;
1780
- checkJob({
1781
- jobId: res.jobId,
1782
- jobType: JOB_TYPE.integrationSettingsSave,
1783
- onSuccess: () => {
1784
- showToast('Settings successfully saved');
1785
- config.current = configReq;
1786
- refreshAutoSyncPausedIndicatorsAndWarning().catch((e) => catchRejection(e, "Can't fetch sync settings warning"));
1787
- },
1788
- onError: () => {
1789
- isSettingsSaveFailed = true;
1790
- showToast("Can't save settings");
1791
- },
1792
- onFinally: () => {
1793
- unsetLoader('#settings-modal');
1794
- settingsSaveBtn.removeAttribute('disabled');
1795
- if (!isValidationError && !isSettingsSaveFailed) {
1796
- const settingsModal = document.getElementById('settings-modal');
1797
- closeModal(settingsModal);
1798
- if (reloadOnConfigSave) {
1799
- getIntegrationData({ hardReload: true });
1800
- getCrowdinData();
1801
- }
1802
- }
1803
- },
1804
- });
1805
- return;
1806
- }
1807
- showToast('Settings successfully saved');
1808
- config.current = configReq;
1809
- refreshAutoSyncPausedIndicatorsAndWarning().catch((e) => catchRejection(e, "Can't fetch sync settings warning"));
1810
- })
1811
- .catch((e) => {
1812
- var _a, _b, _c, _d;
1813
- if ((e === null || e === void 0 ? void 0 : e.error) && ((_a = e === null || e === void 0 ? void 0 : e.error) === null || _a === void 0 ? void 0 : _a.type) === 'validation_error') {
1814
- Object.keys((_b = e === null || e === void 0 ? void 0 : e.error) === null || _b === void 0 ? void 0 : _b.details).forEach((key) => {
1815
- var _a;
1816
- const el = document.getElementById(`${key}-settings`);
1817
- if (el) {
1818
- el.setAttribute('error', 'true');
1819
- el.setAttribute('error-text', (_a = e === null || e === void 0 ? void 0 : e.error) === null || _a === void 0 ? void 0 : _a.details[key]);
1820
- }
1821
- });
1822
- isValidationError = true;
1823
- showToast(((_d = (_c = e === null || e === void 0 ? void 0 : e.error) === null || _c === void 0 ? void 0 : _c.details) === null || _d === void 0 ? void 0 : _d.message) || "Can't save settings");
1824
- settingsSaveBtn.removeAttribute('disabled');
1825
- return;
1826
2186
  }
1827
- catchRejection(e, "Can't save settings");
1828
- })
1829
- .finally(() => {
1830
- if (isSettingsSaveJobPending) {
2187
+ else if ([JOB_STATUS.created, JOB_STATUS.inProgress].includes(job.status) && job.progress < 100) {
2188
+ setTimeout(() => checkJob({ jobId, jobType, onSuccess, onError, onFinally }), asyncProgress.checkInterval);
1831
2189
  return;
1832
2190
  }
1833
- unsetLoader('#settings-modal');
1834
- settingsSaveBtn.removeAttribute('disabled');
1835
- if (!isValidationError) {
1836
- const settingsModal = document.getElementById('settings-modal');
1837
- closeModal(settingsModal);
1838
- if (reloadOnConfigSave) {
1839
- getIntegrationData({ hardReload: true });
1840
- getCrowdinData();
1841
- }
1842
- }
1843
- });
1844
- }
1845
- function getIntegrationFoldersToExpand(allData, syncedFiles) {
1846
- return Array.isArray(allData)
1847
- ? allData
1848
- .filter((node) => node.node_type === folderType &&
1849
- !syncedFiles.find((syncedFile) => syncedFile.parent_id === node.id))
1850
- .map((node) => ({
1851
- ...node,
1852
- nodeType: node.node_type,
1853
- parentId: node.parent_id,
1854
- }))
1855
- : [];
1856
- }
1857
- async function saveScheduleSync() {
1858
- const scheduleModal = document.getElementById('confirm-schedule-modal');
1859
- const newFile = scheduleModal.querySelector('#new-files').checked || false;
1860
- const selectedFiles = scheduleModal.querySelector('#selected-files').checked || false;
1861
- const allFolderFiles = scheduleModal.querySelector('#all-folder-files').checked || false;
1862
- const type = scheduleModal.getAttribute('data-type');
1863
- if (type === 'crowdin') {
1864
- const crowdinFiles = await appComponent.current.getCrowdinFilesData();
1865
- const syncedFileIds = Object.keys(syncData.current);
1866
- const crowdinFolderIds = crowdinFiles
1867
- .filter((file) => file.node_type === folderType || file.node_type === branchType)
1868
- .filter((file) => syncedFileIds.includes(String(file.id)))
1869
- .map((file) => String(file.id));
1870
- appComponent.current.setCrowdinScheduleSync(syncData.current, newFile, selectedFiles);
1871
- appComponent.current.setCrowdinFilesHasSyncOption(true);
1872
- const syncedFiles = await appComponent.current.getCrowdinScheduleSync(true);
1873
- appComponent.current.setAttribute('is-crowdin-sync-settings-in-progress', true);
1874
- updateSyncSettings(syncedFiles, 'schedule', 'crowdin', [], crowdinFolderIds);
1875
- }
1876
- else if (type === 'integration') {
1877
- if (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.integration) {
1878
- appComponent.current.setIntegrationScheduleSync(syncData.current, newFile, selectedFiles);
1879
- }
1880
- else {
1881
- appComponent.current.setIntegrationScheduleSync(syncData.current);
1882
- }
1883
- appComponent.current.setIntegrationFilesHasSyncOption(true);
1884
- const syncedFiles = await appComponent.current.getIntegrationScheduleSync(true);
1885
- appComponent.current.setAttribute('is-integration-sync-settings-in-progress', true);
1886
- if (integrationOneLevelFetching) {
1887
- updateSyncSettings(syncedFiles, 'schedule', 'integration', selectedFiles ? getIntegrationFoldersToExpand(syncData.current, syncedFiles) : []);
1888
- }
1889
2191
  else {
1890
- if (allFolderFiles) {
1891
- const integrationExpandedFolders = syncData.current
1892
- .filter((file) => file.node_type === folderType)
1893
- .map((file) => ({
1894
- ...file,
1895
- nodeType: file.node_type,
1896
- parentId: file.parent_id,
1897
- }));
1898
- updateSyncSettings(syncedFiles, 'schedule', 'integration', integrationExpandedFolders);
1899
- }
1900
- else {
1901
- updateSyncSettings(syncedFiles, 'schedule', 'integration');
2192
+ if (onSuccess) {
2193
+ onSuccess(job);
1902
2194
  }
1903
2195
  }
1904
- }
1905
- closeModal(scheduleModal);
1906
- }
1907
- async function openScheduleModal(type, options = {}) {
1908
- var _a, _b;
1909
- const scheduleModal = document.getElementById('confirm-schedule-modal');
1910
- const { showAllFolderFiles = false, showNewFiles = true } = options;
1911
- const newFile = scheduleModal.querySelector('#new-files');
1912
- const selectedFiles = scheduleModal.querySelector('#selected-files');
1913
- const allFolderFiles = scheduleModal.querySelector('#all-folder-files');
1914
- let newFileStatus = 'unChecked';
1915
- const integrationSyncFolders = ((await ((_a = document.querySelector('crowdin-simple-integration')) === null || _a === void 0 ? void 0 : _a.getIntegrationScheduleSync(true))) ||
1916
- []).filter((elements) => elements.node_type === '0');
1917
- const selectedIntegrationFolders = ((await ((_b = document.getElementById('integration-files')) === null || _b === void 0 ? void 0 : _b.getSelected(true))) || []).filter((elements) => elements.node_type === '0');
1918
- for (let i = 0; i < selectedIntegrationFolders.length; i++) {
1919
- const selectedElement = selectedIntegrationFolders[i];
1920
- const found = integrationSyncFolders.some((integrationElement) => integrationElement.id === selectedElement.id);
1921
- if (found) {
1922
- newFileStatus = 'checked';
1923
- }
1924
- else if (!found && newFileStatus === 'checked') {
1925
- newFileStatus = 'clear-selection';
1926
- break;
1927
- }
1928
- else {
1929
- newFileStatus = 'unChecked';
2196
+ if (onFinally) {
2197
+ onFinally(job);
1930
2198
  }
1931
2199
  }
1932
- if (showNewFiles) {
1933
- newFile.removeAttribute('hidden');
1934
- if (newFileStatus === 'checked') {
1935
- newFile[newFileStatus] = true;
1936
- newFile.value = true;
1937
- newFile.removeAttribute('clear-selection');
1938
- }
1939
- else if (newFileStatus === 'clear-selection') {
1940
- newFile.checked = false;
1941
- newFile.value = false;
1942
- newFile.setAttribute(newFileStatus, '');
2200
+ catch (_e) {
2201
+ if (onFinally) {
2202
+ onFinally();
1943
2203
  }
1944
- else {
1945
- newFile.checked = false;
1946
- newFile.value = false;
1947
- newFile.removeAttribute('clear-selection');
2204
+ if (!silentJobs.find((type) => type === jobType)) {
2205
+ pushJobs([{ id: jobId, isFailed: true }]);
1948
2206
  }
2207
+ showToast('Sync status check failed');
1949
2208
  }
1950
- else {
1951
- newFile.setAttribute('hidden', '');
1952
- newFile.checked = false;
1953
- }
1954
- if (showAllFolderFiles) {
1955
- allFolderFiles.removeAttribute('hidden');
1956
- allFolderFiles.checked = false;
1957
- allFolderFiles.value = false;
1958
- }
1959
- else {
1960
- allFolderFiles.setAttribute('hidden', '');
1961
- allFolderFiles.checked = false;
1962
- }
1963
- selectedFiles.checked = true;
1964
- selectedFiles.value = true;
1965
- scheduleModal.querySelector('#save-schedule-sync').setAttribute('disabled', false);
1966
- scheduleModal.setAttribute('data-type', type);
1967
- openModal(scheduleModal);
1968
2209
  }
1969
- function onChangeAutoSynchronizationOptions() {
1970
- const newFiles = document.getElementById('new-files');
1971
- newFiles.removeAttribute('clear-selection');
1972
- const newFilesStatus = newFiles.checked || false;
1973
- const selectedFiles = document.getElementById('selected-files').checked || false;
1974
- const allFolderFiles = document.getElementById('all-folder-files').checked || false;
1975
- const buttonSaveScheduleSync = document.getElementById('save-schedule-sync');
1976
- if (newFilesStatus || selectedFiles || allFolderFiles) {
1977
- buttonSaveScheduleSync.removeAttribute('disabled');
2210
+ function pushJobs(jobs) {
2211
+ const el = asyncProgressRef.current;
2212
+ if (el && el.pushJobs) {
2213
+ el.pushJobs(jobs);
2214
+ jobs.forEach((job) => (asyncJobs.current[job.id] = job));
1978
2215
  }
1979
2216
  else {
1980
- buttonSaveScheduleSync.setAttribute('disabled', true);
2217
+ setTimeout(() => pushJobs(jobs), 300);
1981
2218
  }
1982
2219
  }
1983
- async function hasFolder(selectedFiles) {
1984
- let isFolder;
1985
- if (Array.isArray(selectedFiles)) {
1986
- isFolder = selectedFiles.find((file) => file.node_type === folderType || file.node_type === branchType);
2220
+ async function uploadFilesToIntegration(event) {
2221
+ var _a, _b, _c, _d;
2222
+ let files = {};
2223
+ let forcePushTranslations = false;
2224
+ if (((_a = event.detail) === null || _a === void 0 ? void 0 : _a.action) === 'forcePushTranslations') {
2225
+ files = event.detail.files;
2226
+ forcePushTranslations = true;
1987
2227
  }
1988
- else {
1989
- const files = await appComponent.current.getCrowdinFilesData();
1990
- const folders = files.filter((file) => file.node_type === folderType || file.node_type === branchType);
1991
- isFolder = folders.find((folder) => selectedFiles.hasOwnProperty(folder.id));
2228
+ else if (((_b = event.detail) === null || _b === void 0 ? void 0 : _b.action) === 'excludedTargetLanguages') {
2229
+ crowdinFilesToUpdateTargetLanguages.current = event.detail.files;
2230
+ openLanguageModalForCrowdinFiles();
2231
+ return;
1992
2232
  }
1993
- return isFolder !== undefined;
1994
- }
1995
- async function setIntegrationScheduleSync(e) {
1996
- var _a;
1997
- if (e.detail.length === 0) {
1998
- showToast('Select templates which will be pushed to Crowdin');
2233
+ else if (((_c = event.detail) === null || _c === void 0 ? void 0 : _c.action) === 'syncSourcesToCrowdin') {
2234
+ syncToCrowdinFromCrowdinFiles(event.detail.files, false);
1999
2235
  return;
2000
2236
  }
2001
- let syncedFiles;
2002
- if (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.integration) {
2003
- const newIntegrationFiles = (_a = config.current) === null || _a === void 0 ? void 0 : _a['new-integration-files'];
2004
- syncData.current = e.detail;
2005
- const isFolder = await hasFolder(e.detail);
2006
- const shouldShowModal = isFolder && !newIntegrationFiles;
2007
- const showNewFiles = true; // завжди показуємо New files коли є syncNewElements.integration
2008
- const showAllFolderFiles = hasLoadMoreElements.current; // показуємо All files якщо є hasLoadMoreElements
2009
- if (shouldShowModal) {
2010
- await openScheduleModal('integration', { showNewFiles, showAllFolderFiles });
2011
- return;
2012
- }
2013
- appComponent.current.setIntegrationScheduleSync(e.detail);
2014
- appComponent.current.setIntegrationFilesHasSyncOption(true);
2015
- syncedFiles = await appComponent.current.getIntegrationScheduleSync(true);
2237
+ else if (((_d = event.detail) === null || _d === void 0 ? void 0 : _d.action) === 'syncTranslationsToCrowdin') {
2238
+ syncToCrowdinFromCrowdinFiles(event.detail.files, true);
2239
+ return;
2016
2240
  }
2017
2241
  else {
2018
- syncData.current = e.detail;
2019
- const isFolder = await hasFolder(e.detail);
2020
- if (hasLoadMoreElements.current && isFolder) {
2021
- await openScheduleModal('integration', { showNewFiles: false, showAllFolderFiles: true });
2022
- return;
2023
- }
2024
- syncedFiles = await appComponent.current.getIntegrationScheduleSync();
2242
+ files = event.detail;
2025
2243
  }
2026
- appComponent.current.setAttribute('is-integration-sync-settings-in-progress', true);
2027
- if (integrationOneLevelFetching) {
2028
- updateSyncSettings(syncedFiles, 'schedule', 'integration', getIntegrationFoldersToExpand(e.detail, syncedFiles));
2244
+ if (Object.keys(event.detail).length === 0 || !event.detail) {
2245
+ showToast(`Select files which will be uploaded to ${name}`);
2246
+ return;
2029
2247
  }
2030
- else {
2031
- if (hasLoadMoreElements.current) {
2032
- const integrationExpandedFolders = e.detail
2033
- .filter((file) => file.node_type === folderType)
2034
- .map((file) => ({
2035
- ...file,
2036
- nodeType: file.node_type,
2037
- parentId: file.parent_id,
2038
- }));
2039
- updateSyncSettings(syncedFiles, 'schedule', 'integration', integrationExpandedFolders);
2040
- }
2041
- else {
2042
- updateSyncSettings(syncedFiles, 'schedule', 'integration');
2043
- }
2248
+ appComponent.current.setAttribute('is-to-integration-process', true);
2249
+ const req = {};
2250
+ Object.keys(files)
2251
+ .filter((id) => crowdinData.current.find((c) => c.id === id).node_type === FILE_TYPE)
2252
+ .forEach((id) => (req[id] = files[id]));
2253
+ try {
2254
+ const restParams = await checkOrigin();
2255
+ const res = await checkResponse(await fetch(`api/integration/update${restParams}&forcePushTranslations=${forcePushTranslations}`, {
2256
+ method: 'POST',
2257
+ headers: { 'Content-Type': 'application/json' },
2258
+ body: JSON.stringify(req),
2259
+ }));
2260
+ checkJob({ jobId: res === null || res === void 0 ? void 0 : res.jobId, jobType: JOB_TYPE.updateIntegration });
2261
+ }
2262
+ catch (e) {
2263
+ catchRejection(e, `Can't upload files to ${name}`);
2044
2264
  }
2045
2265
  }
2046
- async function setCrowdinScheduleSync(e) {
2047
- var _a;
2048
- if (e.detail.length === 0) {
2049
- showToast('Select templates which will be pushed to Crowdin');
2266
+ async function syncToCrowdinFromCrowdinFiles(files, uploadTranslations) {
2267
+ if (!files || Object.keys(files).length === 0) {
2268
+ showToast('Select files to sync');
2050
2269
  return;
2051
2270
  }
2052
- let syncedFiles;
2053
- if (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.crowdin) {
2054
- const newCrowdinFiles = (_a = config.current) === null || _a === void 0 ? void 0 : _a['new-crowdin-files'];
2055
- syncData.current = e.detail;
2056
- const isFolder = await hasFolder(e.detail);
2057
- if (isFolder && !newCrowdinFiles) {
2058
- await openScheduleModal('crowdin');
2059
- return;
2060
- }
2061
- appComponent.current.setCrowdinScheduleSync(e.detail);
2062
- appComponent.current.setCrowdinFilesHasSyncOption(true);
2063
- syncedFiles = await appComponent.current.getCrowdinScheduleSync(true);
2271
+ appComponent.current.setAttribute('is-to-crowdin-process', true);
2272
+ const req = {};
2273
+ Object.keys(files)
2274
+ .filter((id) => { var _a; return ((_a = crowdinData.current.find((c) => c.id === id)) === null || _a === void 0 ? void 0 : _a.node_type) === FILE_TYPE; })
2275
+ .forEach((id) => (req[id] = files[id]));
2276
+ try {
2277
+ const restParams = await checkOrigin();
2278
+ const res = await checkResponse(await fetch(`api/crowdin/update${restParams}&matchFromCrowdin=true&uploadTranslations=${uploadTranslations}`, {
2279
+ method: 'POST',
2280
+ headers: { 'Content-Type': 'application/json' },
2281
+ body: JSON.stringify(req),
2282
+ }));
2283
+ checkJob({ jobId: res === null || res === void 0 ? void 0 : res.jobId, jobType: JOB_TYPE.updateCrowdin });
2064
2284
  }
2065
- else {
2066
- syncedFiles = await appComponent.current.getCrowdinScheduleSync();
2285
+ catch (e) {
2286
+ catchRejection(e, "Can't sync files to Crowdin");
2067
2287
  }
2068
- appComponent.current.setAttribute('is-crowdin-sync-settings-in-progress', true);
2069
- updateSyncSettings(syncedFiles, 'schedule', 'crowdin');
2070
2288
  }
2071
- async function disableIntegrationSync(e) {
2072
- if (e.detail.length === 0) {
2073
- showToast('Select templates which will be pushed to Crowdin');
2289
+ async function syncTranslationsToIntegration(files) {
2290
+ if (!files || files.length === 0) {
2291
+ showToast('Select files to sync');
2074
2292
  return;
2075
2293
  }
2076
- appComponent.current.setAttribute('is-integration-sync-settings-in-progress', true);
2077
- let syncedFiles;
2078
- if (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.integration) {
2079
- syncedFiles = await appComponent.current.getIntegrationScheduleSync(true);
2294
+ appComponent.current.setAttribute('is-to-integration-process', true);
2295
+ const req = files
2296
+ .filter((f) => f.node_type !== FOLDER_TYPE)
2297
+ .map((f) => ({ name: f.name, id: f.id, type: f.type, parentId: f.parent_id }));
2298
+ try {
2299
+ const restParams = await checkOrigin();
2300
+ const res = await checkResponse(await fetch(`api/integration/update${restParams}&matchFromIntegration=true`, {
2301
+ method: 'POST',
2302
+ headers: { 'Content-Type': 'application/json' },
2303
+ body: JSON.stringify(req),
2304
+ }));
2305
+ checkJob({ jobId: res === null || res === void 0 ? void 0 : res.jobId, jobType: JOB_TYPE.updateIntegration });
2080
2306
  }
2081
- else {
2082
- syncedFiles = await appComponent.current.getIntegrationScheduleSync();
2307
+ catch (e) {
2308
+ catchRejection(e, `Can't sync translations to ${name}`);
2083
2309
  }
2084
- updateSyncSettings(syncedFiles, 'schedule', 'integration');
2085
2310
  }
2086
- async function disableCrowdinSync(e) {
2087
- if (e.detail.length === 0) {
2088
- showToast('Select templates which will be pushed to Crowdin');
2311
+ function openLanguageModal() {
2312
+ setLanguageModalState((state) => {
2313
+ var _a, _b;
2314
+ return ({
2315
+ languages: (_b = (_a = state === null || state === void 0 ? void 0 : state.languages) !== null && _a !== void 0 ? _a : project.current.targetLanguages) !== null && _b !== void 0 ? _b : [],
2316
+ action: 'syncToCrowdin',
2317
+ });
2318
+ });
2319
+ openModal(languageModal.current);
2320
+ }
2321
+ function openLanguageModalForCrowdinFiles() {
2322
+ setLanguageModalState((state) => {
2323
+ var _a, _b;
2324
+ return ({
2325
+ languages: (_b = (_a = state === null || state === void 0 ? void 0 : state.languages) !== null && _a !== void 0 ? _a : project.current.targetLanguages) !== null && _b !== void 0 ? _b : [],
2326
+ action: 'updateCrowdinTargetLanguages',
2327
+ });
2328
+ });
2329
+ openModal(languageModal.current);
2330
+ }
2331
+ async function uploadFilesToCrowdinWithExcludedLanguages() {
2332
+ const selectedLanguages = await languageSelectRef.current.getValue();
2333
+ closeModal(languageModal.current);
2334
+ uploadFilesToCrowdin({ detail: fileToSync.current }, selectedLanguages);
2335
+ }
2336
+ async function updateCrowdinFilesTargetLanguages() {
2337
+ const selectedLanguages = await languageSelectRef.current.getValue();
2338
+ closeModal(languageModal.current);
2339
+ const fileIds = Object.keys(crowdinFilesToUpdateTargetLanguages.current).map((id) => parseInt(id, 10));
2340
+ if (fileIds.length === 0) {
2341
+ showToast('Select files to update');
2089
2342
  return;
2090
2343
  }
2091
- appComponent.current.setAttribute('is-crowdin-sync-settings-in-progress', true);
2092
- let syncedFiles;
2093
- if (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.crowdin) {
2094
- syncedFiles = await appComponent.current.getCrowdinScheduleSync(true);
2344
+ appComponent.current.setAttribute('is-to-crowdin-process', true);
2345
+ try {
2346
+ const restParams = await checkOrigin();
2347
+ const res = await checkResponse(await fetch(`api/crowdin/files-target-languages${restParams}`, {
2348
+ method: 'POST',
2349
+ headers: { 'Content-Type': 'application/json' },
2350
+ body: JSON.stringify({ fileIds, languages: selectedLanguages }),
2351
+ }));
2352
+ checkJob({ jobId: res === null || res === void 0 ? void 0 : res.jobId, jobType: JOB_TYPE.updateTargetLanguages });
2095
2353
  }
2096
- else {
2097
- syncedFiles = await appComponent.current.getCrowdinScheduleSync();
2354
+ catch (e) {
2355
+ catchRejection(e, "Can't update files target languages");
2098
2356
  }
2099
- updateSyncSettings(syncedFiles, 'schedule', 'crowdin');
2100
2357
  }
2101
- function updateSyncSettings(files, type, provider, expandIntegrationFolders = [], folderIds = []) {
2102
- checkOrigin()
2103
- .then((restParams) => fetch('api/sync-settings' + restParams, {
2104
- method: 'POST',
2105
- headers: { 'Content-Type': 'application/json' },
2106
- body: JSON.stringify({
2107
- files,
2108
- type,
2109
- provider,
2110
- expandIntegrationFolders,
2111
- hasLoadMoreElements: hasLoadMoreElements.current,
2112
- folderIds,
2113
- }),
2114
- }))
2115
- .then(checkResponse)
2116
- .then((res) => {
2358
+ function setLanguagesForTranslation(languages, action = 'syncToCrowdin') {
2359
+ setLanguageModalState({ languages, action });
2360
+ }
2361
+ async function updateSyncSettings(files, type, provider, expandIntegrationFolders = [], folderIds = []) {
2362
+ try {
2363
+ const restParams = await checkOrigin();
2364
+ const res = await checkResponse(await fetch('api/sync-settings' + restParams, {
2365
+ method: 'POST',
2366
+ headers: { 'Content-Type': 'application/json' },
2367
+ body: JSON.stringify({
2368
+ files,
2369
+ type,
2370
+ provider,
2371
+ expandIntegrationFolders,
2372
+ hasLoadMoreElements: hasLoadMoreElements.current,
2373
+ folderIds,
2374
+ }),
2375
+ }));
2117
2376
  checkJob({
2118
2377
  jobId: res === null || res === void 0 ? void 0 : res.jobId,
2119
2378
  jobType: JOB_TYPE[`${provider}SyncSettingsSave`],
2120
2379
  });
2121
- })
2122
- .catch((e) => catchRejection(e, "Can't save schedule sync settings"));
2123
- }
2124
- function getSubscriptionInfo() {
2125
- const subscriptionInfo = document.getElementById('subscription-info');
2126
- const subscriptionInfoText = subscriptionInfo.getElementsByTagName('p')[0];
2127
- checkOrigin()
2128
- .then((restParams) => fetch('api/subscription-info' + restParams))
2129
- .then(checkResponse)
2130
- .then((res) => {
2131
- if (res.showInfo) {
2132
- subscriptionLink.current = res.subscribeLink;
2133
- subscriptionInfoText.textContent = `Your trial expires in ${res.daysLeft} days.`;
2134
- subscriptionInfo.style.display = 'block';
2135
- }
2380
+ }
2381
+ catch (e) {
2382
+ catchRejection(e, "Can't save schedule sync settings");
2383
+ }
2384
+ }
2385
+ return {
2386
+ getCrowdinData,
2387
+ getIntegrationData,
2388
+ checkJob,
2389
+ cancelJob,
2390
+ getActiveJobs,
2391
+ updateSyncSettings,
2392
+ refreshAutoSyncPausedIndicatorsAndWarning,
2393
+ uploadFilesToCrowdin,
2394
+ uploadFilesToIntegration,
2395
+ updateCrowdinFilesTargetLanguages,
2396
+ uploadFilesToCrowdinWithExcludedLanguages,
2397
+ languageModalState,
2398
+ languageModalRef: languageModal,
2399
+ languageSelectRef,
2400
+ crowdinData,
2401
+ hasLoadMoreElements,
2402
+ };
2403
+ }
2404
+
2405
+ const ExcludedLanguagesModal = ({ modalRef, languageSelectRef, languageModalState, onUpdateTargetLanguages, onSyncToCrowdin, }) => {
2406
+ return (jsxRuntimeExports.jsx("crowdin-modal", { ref: modalRef, style: { display: 'none' }, "modal-width": "50", "modal-title": "Select Target Languages for Translation", id: "excluded-languages", children: languageModalState && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("div", { children: jsxRuntimeExports.jsx("crowdin-select", { ref: languageSelectRef, "is-multi": true, "is-searchable": true, "is-position-fixed": true, "close-on-select": "false", name: "languages", id: "language-select", label: "Languages", children: languageModalState.languages.map((language) => (jsxRuntimeExports.jsx("option", { value: language.id, children: language.name }, language.id))) }) }), jsxRuntimeExports.jsxs("div", { slot: "footer", children: [jsxRuntimeExports.jsx("span", { hidden: languageModalState.action !== 'updateCrowdinTargetLanguages', children: jsxRuntimeExports.jsx("crowdin-button", { id: "update-crowdin-target-languages", outlined: true, onClick: onUpdateTargetLanguages, children: "Update Target Languages" }) }), jsxRuntimeExports.jsx("span", { hidden: languageModalState.action !== 'syncToCrowdin', children: jsxRuntimeExports.jsx("crowdin-button", { id: "upload-exclude-languages", outlined: true, onClick: onSyncToCrowdin, children: jsxRuntimeExports.jsxs("div", { className: "inline-flex items-center gap-1", children: [jsxRuntimeExports.jsx("span", { children: "Sync to" }), jsxRuntimeExports.jsx("crowdin-logo", { "is-icon": true })] }) }) })] })] })) }));
2407
+ };
2408
+
2409
+ const InfoModal = ({ modalRef, infoModal }) => {
2410
+ return (jsxRuntimeExports.jsx("crowdin-modal", { ref: modalRef, style: { display: 'none' }, id: "info-modal", "modal-width": "50", "modal-title": infoModal.title, "close-button-title": "Close", children: jsxRuntimeExports.jsx("div", { dangerouslySetInnerHTML: { __html: infoModal.content } }) }));
2411
+ };
2412
+
2413
+ function renderPermissionStatus(status) {
2414
+ switch (status) {
2415
+ case 'willBeGranted':
2416
+ return (jsxRuntimeExports.jsx("span", { className: "inline-block cursor-default rounded-[15px] bg-[var(--crowdin-info)] px-3 py-1 text-center text-xs font-medium text-[var(--crowdin-white)]", children: "Will Be Granted" }));
2417
+ case 'willBeRegistered':
2418
+ return (jsxRuntimeExports.jsx("span", { className: "inline-block cursor-default rounded-[15px] bg-[var(--crowdin-info)] px-3 py-1 text-center text-xs font-medium text-[var(--crowdin-white)]", children: "Will Be Registered" }));
2419
+ case 'actionRequired':
2420
+ return (jsxRuntimeExports.jsx("span", { className: "inline-block cursor-default rounded-[15px] bg-[var(--crowdin-warning-bg)] px-3 py-1 text-center text-xs font-medium text-[var(--crowdin-warning)]", children: "Action Required" }));
2421
+ case 'granted':
2422
+ default:
2423
+ return jsxRuntimeExports.jsx("crowdin-p", { children: EMPTY_PERMISSION_VALUE });
2424
+ }
2425
+ }
2426
+ function renderPermissionUsers(row) {
2427
+ if (!row || row.users.length === 0) {
2428
+ return row ? renderPermissionStatus(row.status) : null;
2429
+ }
2430
+ return (jsxRuntimeExports.jsx("ul", { className: "m-0 list-none p-0", children: row.users.map((user) => (jsxRuntimeExports.jsx("li", { className: "mb-1 text-sm last:mb-0", children: jsxRuntimeExports.jsx("crowdin-p", { children: user }) }, user))) }));
2431
+ }
2432
+ function renderPermissionRowDescription(row) {
2433
+ if (!(row === null || row === void 0 ? void 0 : row.description)) {
2434
+ return null;
2435
+ }
2436
+ return (jsxRuntimeExports.jsx("div", { className: row.isWarning
2437
+ ? 'mt-1 text-xs text-[var(--crowdin-warning)]'
2438
+ : 'mt-1 text-xs text-[var(--crowdin-text-muted)]', children: row.description }));
2439
+ }
2440
+ const PermissionsModal = ({ modalRef, usersSelectRef, isLoading, permissionUserOptions, isConfirmVisible, permissionsSummary, hasOrganization, zenModeUrl, onSave, }) => {
2441
+ return (jsxRuntimeExports.jsxs("crowdin-modal", { ref: modalRef, style: { display: 'none' }, id: "permissions-modal", "modal-title": "Share", "close-button-title": "Close", "close-button": true, "body-overflow-unset": true, children: [jsxRuntimeExports.jsx("div", { className: isLoading ? 'absolute inset-0 z-[4] flex items-center justify-center bg-white/30' : 'hidden', children: jsxRuntimeExports.jsx("crowdin-progress-indicator", {}) }), jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx("div", { children: jsxRuntimeExports.jsx("crowdin-users-select", { ref: usersSelectRef, "allow-new-options": true, "is-multi": true, "is-searchable": true, id: "users", label: "Users", "help-text": "Search for members by name, username, email, or invite new ones using their email.", "is-position-fixed": true, children: permissionUserOptions.map((option) => (jsxRuntimeExports.jsx("option", { value: option.id, children: option.label }, option.id))) }, "users") }), jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx("div", { className: isConfirmVisible ? 'mt-4' : 'hidden', children: jsxRuntimeExports.jsxs("table", { className: "w-full border-separate border-spacing-0", children: [jsxRuntimeExports.jsx("thead", { children: jsxRuntimeExports.jsxs("tr", { children: [jsxRuntimeExports.jsx("th", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-left text-sm", style: { width: '40%' }, children: "Access" }), jsxRuntimeExports.jsx("th", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-left text-sm", style: { width: '35%' }, children: "Users" }), jsxRuntimeExports.jsx("th", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-right text-sm", style: { width: '20%' }, children: "Upcoming changes" })] }) }), jsxRuntimeExports.jsxs("tbody", { children: [hasOrganization && (jsxRuntimeExports.jsxs("tr", { children: [jsxRuntimeExports.jsxs("td", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-left align-top", children: [jsxRuntimeExports.jsx("crowdin-p", { children: "Registration in Organization" }), renderPermissionRowDescription(permissionsSummary === null || permissionsSummary === void 0 ? void 0 : permissionsSummary.organization)] }), jsxRuntimeExports.jsx("td", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-left align-top", children: renderPermissionUsers(permissionsSummary === null || permissionsSummary === void 0 ? void 0 : permissionsSummary.organization) }), jsxRuntimeExports.jsx("td", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-right align-top", children: (permissionsSummary === null || permissionsSummary === void 0 ? void 0 : permissionsSummary.organization) &&
2442
+ renderPermissionStatus(permissionsSummary.organization.status) })] })), jsxRuntimeExports.jsxs("tr", { children: [jsxRuntimeExports.jsx("td", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-left align-top", children: jsxRuntimeExports.jsx("crowdin-p", { children: "Project Manager Access" }) }), jsxRuntimeExports.jsx("td", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-left align-top", children: renderPermissionUsers(permissionsSummary === null || permissionsSummary === void 0 ? void 0 : permissionsSummary.project) }), jsxRuntimeExports.jsx("td", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-right align-top", children: (permissionsSummary === null || permissionsSummary === void 0 ? void 0 : permissionsSummary.project) &&
2443
+ renderPermissionStatus(permissionsSummary.project.status) })] }), jsxRuntimeExports.jsxs("tr", { children: [jsxRuntimeExports.jsxs("td", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-left align-top", children: [jsxRuntimeExports.jsx("crowdin-p", { children: "Application Visibility Access" }), renderPermissionRowDescription(permissionsSummary === null || permissionsSummary === void 0 ? void 0 : permissionsSummary.applicationSettings)] }), jsxRuntimeExports.jsx("td", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-left align-top", children: renderPermissionUsers(permissionsSummary === null || permissionsSummary === void 0 ? void 0 : permissionsSummary.applicationSettings) }), jsxRuntimeExports.jsx("td", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-right align-top", children: (permissionsSummary === null || permissionsSummary === void 0 ? void 0 : permissionsSummary.applicationSettings) &&
2444
+ renderPermissionStatus(permissionsSummary.applicationSettings.status) })] }), jsxRuntimeExports.jsxs("tr", { children: [jsxRuntimeExports.jsxs("td", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-left align-top", children: [jsxRuntimeExports.jsx("crowdin-p", { children: "Access to the Integration" }), jsxRuntimeExports.jsx("div", { className: "mt-1 text-xs text-[var(--crowdin-text-muted)]", children: "This provides access to sync files and modify the current integration settings." })] }), jsxRuntimeExports.jsx("td", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-left align-top", children: renderPermissionUsers(permissionsSummary === null || permissionsSummary === void 0 ? void 0 : permissionsSummary.applicationCredentials) }), jsxRuntimeExports.jsx("td", { className: "border-b border-[var(--crowdin-border-color)] p-4 text-right align-top", children: (permissionsSummary === null || permissionsSummary === void 0 ? void 0 : permissionsSummary.applicationCredentials) &&
2445
+ renderPermissionStatus(permissionsSummary.applicationCredentials.status) })] })] })] }) }), zenModeUrl && (jsxRuntimeExports.jsx("div", { className: "mt-4", children: jsxRuntimeExports.jsx("crowdin-input", { "with-fixed-height": true, label: "Zen Mode link", "help-text": "This focused view allows you to concentrate solely on the Integrations section, eliminating other distractions.", value: zenModeUrl, name: "zenModeLink", "with-copy-button": true }) }))] })] }), jsxRuntimeExports.jsx("div", { slot: "footer", children: jsxRuntimeExports.jsx("crowdin-button", { id: "confirm-users-btn", outlined: true, onClick: onSave, children: "Save" }) })] }));
2446
+ };
2447
+
2448
+ const ScheduleModal = ({ modalRef, selectedFilesCheckboxRef, allFolderFilesCheckboxRef, newFilesCheckboxRef, scheduleModalState, isSaveDisabled, onChangeOptions, onSave, }) => {
2449
+ return (jsxRuntimeExports.jsxs("crowdin-modal", { ref: modalRef, style: { display: 'none' }, id: "confirm-schedule-modal", "modal-width": "50", "modal-title": "Synchronization options", "close-button-title": "Close", "close-button": "true", "body-overflow-unset": true, children: [jsxRuntimeExports.jsx("crowdin-checkbox", { ref: selectedFilesCheckboxRef, id: "selected-files", name: "selected-files", label: "Selected files", class: "hydrated", checked: scheduleModalState.selectedFiles, value: String(scheduleModalState.selectedFiles), onChange: onChangeOptions }), jsxRuntimeExports.jsx("crowdin-checkbox", { ref: allFolderFilesCheckboxRef, id: "all-folder-files", name: "all-folder-files", label: "All files in the folder", class: "hydrated", hidden: !scheduleModalState.showAllFolderFiles, checked: scheduleModalState.allFolderFiles, value: String(scheduleModalState.allFolderFiles), onChange: onChangeOptions }), jsxRuntimeExports.jsx("crowdin-checkbox", { ref: newFilesCheckboxRef, id: "new-files", name: "new-files", label: "New files", class: "hydrated", hidden: !scheduleModalState.showNewFiles, checked: scheduleModalState.newFiles, value: String(scheduleModalState.newFiles), ...(scheduleModalState.newFilesClearSelection ? { 'clear-selection': '' } : {}), onChange: onChangeOptions }), jsxRuntimeExports.jsx("div", { slot: "footer", children: jsxRuntimeExports.jsx("crowdin-button", { outlined: true, id: "save-schedule-sync", disabled: isSaveDisabled, onClick: onSave, children: "Save" }) })] }));
2450
+ };
2451
+
2452
+ function renderConfigField(field, settingsFieldChange, registerSettingsField, suffix = 'settings') {
2453
+ var _a;
2454
+ if (!field.key) {
2455
+ return field.labelHtml ? (jsxRuntimeExports.jsx("crowdin-p", { ...(field.dependencySettings ? { 'data-dependency': field.dependencySettings } : {}), dangerouslySetInnerHTML: { __html: field.labelHtml } })) : (jsxRuntimeExports.jsx("crowdin-p", { ...(field.dependencySettings ? { 'data-dependency': field.dependencySettings } : {}), children: field.label }));
2456
+ }
2457
+ const commonProps = {
2458
+ id: `${field.key}-${suffix}`,
2459
+ _key: field.key,
2460
+ label: field.label,
2461
+ ...(field.helpText ? { 'help-text': field.helpText } : {}),
2462
+ ...(field.helpTextHtml ? { 'help-text-html': field.helpTextHtml } : {}),
2463
+ ...(field.dependencySettings ? { 'data-dependency': field.dependencySettings } : {}),
2464
+ };
2465
+ switch (field.type) {
2466
+ case 'checkbox':
2467
+ return (jsxRuntimeExports.jsx("crowdin-checkbox", { ref: registerSettingsField(field.key), ...commonProps, value: "false", "use-switch": true, ...(field.defaultValue === true ? { checked: String(field.defaultValue) } : {}), onChange: settingsFieldChange }));
2468
+ case 'select':
2469
+ return (jsxRuntimeExports.jsx("crowdin-select", { ref: registerSettingsField(field.key), ...commonProps, ...(field.isMulti ? { 'is-multi': true, 'close-on-select': 'false' } : {}), ...(field.isSearchable ? { 'is-searchable': true } : {}), "is-position-fixed": true, onChange: settingsFieldChange, children: (_a = field.options) === null || _a === void 0 ? void 0 : _a.map((option) => {
2470
+ const isSelected = Array.isArray(field.defaultValue)
2471
+ ? field.defaultValue.includes(option.value)
2472
+ : field.defaultValue === option.value;
2473
+ return (jsxRuntimeExports.jsx("option", { value: option.value, ...(isSelected ? { selected: true } : {}), children: option.label }, option.value));
2474
+ }) }));
2475
+ case 'text':
2476
+ return (jsxRuntimeExports.jsx("crowdin-input", { ref: registerSettingsField(field.key), ...commonProps, "with-fixed-height": true, value: field.defaultValue || '', onChange: settingsFieldChange }));
2477
+ case 'textarea':
2478
+ return (jsxRuntimeExports.jsx("crowdin-textarea", { ref: registerSettingsField(field.key), ...commonProps, value: field.defaultValue || '', onChange: settingsFieldChange }));
2479
+ case 'notice':
2480
+ return (jsxRuntimeExports.jsx("crowdin-alert", { ...(field.noticeType ? { type: field.noticeType } : {}), ...(field.label ? { title: field.label } : {}), ...(field.noIcon ? { 'no-icon': String(field.noIcon) } : {}), ...(field.dependencySettings ? { 'data-dependency': field.dependencySettings } : {}), dangerouslySetInnerHTML: { __html: field.helpTextHtml || field.helpText || '' } }));
2481
+ default:
2482
+ return null;
2483
+ }
2484
+ }
2485
+ const SettingsModal = ({ modalRef, isLoading, configurationFields, isSaveDisabled, settingsFieldChange, registerSettingsField, onSave, }) => {
2486
+ return (jsxRuntimeExports.jsxs("crowdin-modal", { ref: modalRef, style: { display: 'none' }, id: "settings-modal", "modal-width": "65", "modal-title": "Settings", "close-button-title": "Close", children: [jsxRuntimeExports.jsx("div", { className: isLoading ? 'absolute inset-0 z-[4] flex items-center justify-center bg-white/30' : 'hidden', children: jsxRuntimeExports.jsx("crowdin-progress-indicator", {}) }), jsxRuntimeExports.jsx("div", { id: "modal-content", children: jsxRuntimeExports.jsx("crowdin-tabs", { "tabs-config": JSON.stringify(configurationFields.map((f) => f.name)), "active-tab": "1", children: configurationFields.map((tab, tabIndex) => (jsxRuntimeExports.jsx("div", { slot: `tab-${tabIndex + 1}`, children: jsxRuntimeExports.jsx("div", { children: tab.fields.map((field, fieldIndex) => (jsxRuntimeExports.jsxs(reactExports.Fragment, { children: [renderConfigField(field, settingsFieldChange, registerSettingsField), jsxRuntimeExports.jsx("div", { style: { padding: '8px' }, ...(field.dependencySettings
2487
+ ? { 'data-dependency': field.dependencySettings }
2488
+ : {}) })] }, field.key || `${tabIndex}-${fieldIndex}`))) }) }, tabIndex))) }) }), jsxRuntimeExports.jsx("div", { slot: "footer", children: jsxRuntimeExports.jsx("crowdin-button", { id: "settings-save-btn", outlined: true, disabled: isSaveDisabled, onClick: onSave, children: "Save" }) })] }));
2489
+ };
2490
+
2491
+ const SubscriptionModal = ({ modalRef, subscriptionLink, name, onLogout }) => {
2492
+ return (jsxRuntimeExports.jsxs("crowdin-modal", { ref: modalRef, style: { display: 'none' }, id: "subscription-modal", "modal-width": "50", "close-button": "false", children: [jsxRuntimeExports.jsx("div", { children: jsxRuntimeExports.jsxs("crowdin-alert", { type: "warning", children: ["Subscribe to continue using the ", name, " app."] }) }), jsxRuntimeExports.jsxs("div", { slot: "footer", children: [jsxRuntimeExports.jsx("crowdin-button", { primary: true, onClick: () => { var _a; return window.open((_a = subscriptionLink.current) !== null && _a !== void 0 ? _a : '', '_blank', 'noopener,noreferrer'); }, children: "Subscribe" }), jsxRuntimeExports.jsx("crowdin-button", { outlined: true, onClick: () => window.open('https://crowdin.com/contacts', '_blank', 'noopener,noreferrer'), children: "Contact us" }), jsxRuntimeExports.jsx("crowdin-button", { class: "ml-2.5", secondary: true, onClick: onLogout, children: "Log out" })] })] }));
2493
+ };
2494
+
2495
+ function isJSON(string) {
2496
+ try {
2497
+ JSON.parse(string);
2498
+ return true;
2499
+ }
2500
+ catch (e) {
2501
+ return false;
2502
+ }
2503
+ }
2504
+ function getUserErrorDetail(error) {
2505
+ const data = JSON.parse(error.data);
2506
+ const preClassName = 'block rounded bg-[#eceff1] p-4 text-[87.5%] text-[#212529]';
2507
+ const rows = [
2508
+ { label: 'Action', value: error.action },
2509
+ {
2510
+ label: 'Message',
2511
+ value: isJSON(error.message) ? jsxRuntimeExports.jsx("pre", { className: preClassName, children: error.message }) : error.message,
2512
+ },
2513
+ { label: 'Date/time', value: error.formattedDate },
2514
+ ];
2515
+ if (data.requestParams) {
2516
+ rows.push({ label: 'Method', value: data.requestParams.method });
2517
+ }
2518
+ if (data.responseData) {
2519
+ rows.push({
2520
+ label: 'Response Data',
2521
+ value: jsxRuntimeExports.jsx("pre", { className: preClassName, children: JSON.stringify(data.responseData, null, 2) }),
2136
2522
  });
2137
2523
  }
2138
- function checkAlert(alert, suffix) {
2139
- const name = suffix ;
2140
- const revised = localStorage.getItem(`revised_${name}`) === '1';
2141
- if (!revised) {
2142
- alert.style.display = 'block';
2143
- }
2144
- }
2145
- function closeAlert(el, suffix) {
2146
- const name = suffix ;
2147
- const alert = el.closest('crowdin-alert');
2148
- alert.style.display = 'none';
2149
- localStorage.setItem(`revised_${name}`, 1);
2150
- }
2151
- function showErrorLogs() {
2152
- document.getElementById('show-error-logs-btn').classList.add('hidden');
2153
- document.getElementById('show-integration-btn').classList.remove('hidden');
2154
- appComponent.current.classList.add('hidden');
2155
- document.getElementById('user-errors').classList.remove('hidden');
2156
- checkOrigin()
2157
- .then((restParams) => fetch('api/user-errors' + restParams))
2158
- .then(checkResponse)
2159
- .then((res) => {
2160
- const table = document.getElementById('user-errors-table');
2161
- const clickRow = (field, index, item) => {
2162
- const modal = document.getElementById('user-error-detail');
2163
- openModal(modal);
2164
- modal.innerHTML = getUserErrorDetail(item);
2165
- };
2166
- const formatDate = (field, index, item) => {
2167
- return item.formattedDate;
2524
+ if (data.appData) {
2525
+ if (Array.isArray(data.appData)) {
2526
+ rows.push({
2527
+ label: 'App Data',
2528
+ value: jsxRuntimeExports.jsx("pre", { className: preClassName, children: JSON.stringify(data.appData, null, 2) }),
2529
+ });
2530
+ }
2531
+ else if (typeof data.appData === 'object') {
2532
+ for (const key in data.appData) {
2533
+ rows.push({
2534
+ label: key.charAt(0).toUpperCase() + key.slice(1),
2535
+ value: jsxRuntimeExports.jsx("pre", { className: preClassName, children: JSON.stringify(data.appData[key], null, 2) }),
2536
+ });
2537
+ }
2538
+ }
2539
+ else {
2540
+ rows.push({ label: 'App Data', value: data.appData });
2541
+ }
2542
+ }
2543
+ return (jsxRuntimeExports.jsx("div", { className: "-m-6 h-auto max-h-[579px] overflow-auto", children: jsxRuntimeExports.jsx("table", { className: "w-full border-separate border-spacing-0", children: jsxRuntimeExports.jsx("tbody", { children: rows.map((row) => (jsxRuntimeExports.jsxs("tr", { children: [jsxRuntimeExports.jsx("td", { className: "min-w-[200px] p-2 px-6 align-top font-medium", children: row.label }), jsxRuntimeExports.jsx("td", { className: "break-all bg-[var(--crowdin-primary-blue-gray,#f6f6f6)] p-2 px-6 text-[var(--crowdin-body-color,rgba(38,50,56,0.87))]", children: row.value })] }, row.label))) }) }) }));
2544
+ }
2545
+ const UserErrorDetailModal = ({ modalRef, selectedUserError }) => {
2546
+ return (jsxRuntimeExports.jsx("crowdin-modal", { ref: modalRef, style: { display: 'none' }, id: "user-error-detail", "close-button-title": "Close", "close-button": "true", children: selectedUserError && getUserErrorDetail(selectedUserError) }));
2547
+ };
2548
+
2549
+ const MainPage = (props) => {
2550
+ const { name, userId, notice, checkSubscription, isManager, isOwner, infoModal, configurationFields, config: configString, syncNewElements, withCronSync, webhooks, integrationOneLevelFetching, integrationSearchListener, integrationPagination, excludedTargetLanguages, filtering, hasOrganization, zenModeUrl, asyncProgress = { checkInterval: 3000 }, reloadOnConfigSave, progressiveCrowdinFilesLoading, integrationButtonMenuItems, crowdinButtonMenuItems, } = props;
2551
+ const config = reactExports.useRef(configString ? JSON.parse(configString.replace(/\\n/g, '\\\\n')) : {});
2552
+ const appComponent = reactExports.useRef(null);
2553
+ const asyncProgressRef = reactExports.useRef(null);
2554
+ const infoModalRef = reactExports.useRef(null);
2555
+ const subscriptionModal = reactExports.useRef(null);
2556
+ const settingsModalRef = reactExports.useRef(null);
2557
+ const scheduleModalRef = reactExports.useRef(null);
2558
+ const permissionsModalRef = reactExports.useRef(null);
2559
+ const userErrorsTableRef = reactExports.useRef(null);
2560
+ const userErrorDetailModalRef = reactExports.useRef(null);
2561
+ const subscriptionLink = reactExports.useRef('');
2562
+ const refreshDependencies = useFieldDependencies(configurationFields);
2563
+ const [isNoticeVisible, setIsNoticeVisible] = reactExports.useState(false);
2564
+ const [subscriptionInfo, setSubscriptionInfo] = reactExports.useState(null);
2565
+ const [isErrorLogsVisible, setIsErrorLogsVisible] = reactExports.useState(false);
2566
+ const [selectedUserError, setSelectedUserError] = reactExports.useState(null);
2567
+ const syncOps = useSyncOperations({
2568
+ appComponent,
2569
+ asyncProgressRef,
2570
+ config,
2571
+ name,
2572
+ integrationOneLevelFetching,
2573
+ integrationSearchListener,
2574
+ integrationPagination,
2575
+ withCronSync,
2576
+ webhooks,
2577
+ progressiveCrowdinFilesLoading,
2578
+ asyncProgress,
2579
+ syncNewElements,
2580
+ });
2581
+ const permissions = usePermissions({
2582
+ userId,
2583
+ hasOrganization,
2584
+ permissionsModalRef,
2585
+ });
2586
+ const settings = useSettings({
2587
+ configurationFields,
2588
+ config,
2589
+ settingsModalRef,
2590
+ reloadOnConfigSave,
2591
+ refreshDependencies,
2592
+ checkJob: syncOps.checkJob,
2593
+ getCrowdinData: syncOps.getCrowdinData,
2594
+ getIntegrationData: syncOps.getIntegrationData,
2595
+ refreshAutoSyncPausedIndicatorsAndWarning: syncOps.refreshAutoSyncPausedIndicatorsAndWarning,
2596
+ });
2597
+ const schedule = useSchedule({
2598
+ appComponent,
2599
+ config,
2600
+ scheduleModalRef,
2601
+ withCronSync,
2602
+ webhooks,
2603
+ syncNewElements,
2604
+ integrationOneLevelFetching,
2605
+ hasLoadMoreElements: syncOps.hasLoadMoreElements,
2606
+ updateSyncSettings: syncOps.updateSyncSettings,
2607
+ });
2608
+ reactExports.useEffect(() => {
2609
+ const handleKeydown = (event) => {
2610
+ if (event.keyCode === 27) {
2611
+ closeModal(permissionsModalRef.current);
2612
+ closeModal(infoModalRef.current);
2613
+ closeModal(settingsModalRef.current);
2614
+ closeModal(scheduleModalRef.current);
2615
+ if (syncOps.languageModalRef.current) {
2616
+ closeModal(syncOps.languageModalRef.current);
2617
+ }
2618
+ }
2619
+ };
2620
+ document.body.addEventListener('keydown', handleKeydown);
2621
+ return () => document.body.removeEventListener('keydown', handleKeydown);
2622
+ }, []);
2623
+ // Expose centralized API to global scope for main.js compatibility
2624
+ reactExports.useEffect(() => {
2625
+ window.app = {
2626
+ subscriptionModal,
2627
+ subscriptionLink,
2628
+ openModal,
2629
+ };
2630
+ return () => {
2631
+ delete window.app;
2632
+ };
2633
+ }, []);
2634
+ reactExports.useEffect(() => {
2635
+ setIsNoticeVisible(Boolean(notice) && localStorage.getItem('revised_notice') !== '1');
2636
+ if (checkSubscription) {
2637
+ getSubscriptionInfo();
2638
+ }
2639
+ }, []);
2640
+ async function getSubscriptionInfo() {
2641
+ const restParams = await checkOrigin();
2642
+ const res = await checkResponse(await fetch('api/subscription-info' + restParams));
2643
+ if (res.showInfo) {
2644
+ subscriptionLink.current = res.subscribeLink;
2645
+ setSubscriptionInfo({ daysLeft: res.daysLeft, subscribeLink: res.subscribeLink });
2646
+ }
2647
+ }
2648
+ async function integrationLogout() {
2649
+ try {
2650
+ const queryParams = await checkOrigin();
2651
+ await checkResponse(await fetch(`api/logout${queryParams}`, { method: 'POST' }));
2652
+ reloadLocation();
2653
+ localStorage.removeItem(`revised_${name}`);
2654
+ }
2655
+ catch (e) {
2656
+ catchRejection(e, e.error || 'Looks like you are not logged in');
2657
+ }
2658
+ }
2659
+ function closeAlert(suffix) {
2660
+ setIsNoticeVisible(false);
2661
+ localStorage.setItem(`revised_${suffix !== null && suffix !== void 0 ? suffix : name}`, '1');
2662
+ }
2663
+ async function showErrorLogs() {
2664
+ setIsErrorLogsVisible(true);
2665
+ try {
2666
+ const restParams = await checkOrigin();
2667
+ const res = await checkResponse(await fetch('api/user-errors' + restParams));
2668
+ const table = userErrorsTableRef.current;
2669
+ const clickRow = (_field, _index, item) => {
2670
+ setSelectedUserError(item);
2671
+ openModal(userErrorDetailModalRef.current);
2168
2672
  };
2673
+ const formatDate = (_field, _index, item) => item.formattedDate;
2169
2674
  if (table.setTableConfig) {
2170
2675
  table.setTableConfig({
2171
2676
  defaultSortingColumn: 'createdAt',
@@ -2178,114 +2683,30 @@
2178
2683
  clickFn: clickRow,
2179
2684
  formatFn: formatDate,
2180
2685
  },
2181
- {
2182
- field: 'action',
2183
- name: 'Action',
2184
- clickFn: clickRow,
2185
- },
2186
- {
2187
- field: 'message',
2188
- name: 'Message',
2189
- clickFn: clickRow,
2190
- },
2686
+ { field: 'action', name: 'Action', clickFn: clickRow },
2687
+ { field: 'message', name: 'Message', clickFn: clickRow },
2191
2688
  ],
2192
2689
  });
2193
2690
  }
2194
2691
  table.setTableData(JSON.stringify(res));
2195
2692
  table.setAttribute('is-loading', false);
2196
- })
2197
- .catch((e) => catchRejection(e, "Can't fetch error logs"));
2198
- }
2199
- function showIntegration() {
2200
- document.getElementById('show-error-logs-btn').classList.remove('hidden');
2201
- document.getElementById('show-integration-btn').classList.add('hidden');
2202
- appComponent.current.classList.remove('hidden');
2203
- document.getElementById('user-errors').classList.add('hidden');
2204
- }
2205
- function isJSON(string) {
2206
- try {
2207
- JSON.parse(string);
2208
- return true;
2209
2693
  }
2210
2694
  catch (e) {
2211
- return false;
2695
+ catchRejection(e, "Can't fetch error logs");
2212
2696
  }
2213
2697
  }
2214
- function getUserErrorDetail(error) {
2215
- const data = JSON.parse(error.data);
2216
- let html = '<div class="error-detail-table"><table>';
2217
- html += `<tr><td>Action</td><td>${sanitizeHTML(error.action)}</td></tr>`;
2218
- if (isJSON(error.message)) {
2219
- html += `<tr><td>Message</td><td><pre>${sanitizeHTML(error.message)}<pre></td></tr>`;
2220
- }
2221
- else {
2222
- html += `<tr><td>Message</td><td>${sanitizeHTML(error.message)}</td></tr>`;
2223
- }
2224
- html += `<tr><td>Date/time</td><td>${sanitizeHTML(error.formattedDate)}</td></tr>`;
2225
- if (data.requestParams) {
2226
- html += `<tr><td>Method</td><td>${sanitizeHTML(data.requestParams.method)}</td></tr>`;
2227
- }
2228
- if (data.responseData) {
2229
- html += `<tr><td>Response Data</td><td><pre>${sanitizeHTML(JSON.stringify(data.responseData, null, 2))}</pre></td></tr>`;
2230
- }
2231
- if (data.appData) {
2232
- if (Array.isArray(data.appData)) {
2233
- html += `<tr><td>App Data</td><td><pre>${sanitizeHTML(JSON.stringify(data.appData, null, 2))}</pre></td></tr>`;
2234
- }
2235
- else if (typeof data.appData === 'object') {
2236
- for (const key in data.appData) {
2237
- html += `<tr><td>${sanitizeHTML(key.charAt(0).toUpperCase() + key.slice(1))}</td><td><pre>${sanitizeHTML(JSON.stringify(data.appData[key], null, 2))}</pre></td></tr>`;
2238
- }
2239
- }
2240
- else {
2241
- html += `<tr><td>App Data</td><td>${sanitizeHTML(data.appData)}</td></tr>`;
2242
- }
2243
- }
2244
- html += '</table></div>';
2245
- return html;
2246
- }
2247
- function sanitizeHTML(str) {
2248
- const tempDiv = document.createElement('div');
2249
- tempDiv.textContent = str;
2250
- return tempDiv.innerHTML;
2251
- }
2252
- function openModal(modal) {
2253
- modal.style.display = 'block';
2254
- modal.open();
2255
- }
2256
- function closeModal(modal) {
2257
- modal.style.display = 'none';
2258
- modal.close();
2259
- }
2260
- function settingsFieldChange(el) {
2261
- el.removeAttribute('error');
2262
- el.removeAttribute('error-text');
2263
- }
2264
- function isFolder(e) {
2265
- return !e.type && (e.nodeType === undefined || e.nodeType === folderType || e.nodeType === branchType);
2266
- }
2267
- return (jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsxs("div", { className: "i_w", children: [jsxRuntimeExports.jsxs("div", { className: "top", children: [notice && (jsxRuntimeExports.jsxs("crowdin-alert", { id: "notice", title: notice.title, ...(!notice.icon ? { 'no-icon': 'true' } : {}), ...(notice.type ? { type: notice.type } : {}), style: { display: 'none', marginBottom: '12px' }, children: [jsxRuntimeExports.jsx("div", { className: "box-center", children: jsxRuntimeExports.jsx("p", { className: "m-0", dangerouslySetInnerHTML: { __html: notice.content } }) }), notice.close && (jsxRuntimeExports.jsx("crowdin-button", { onClick: (e) => closeAlert(e, 'notice'), class: "dismiss-alert", icon: true, children: "close" }))] })), checkSubscription && (jsxRuntimeExports.jsx("crowdin-alert", { id: "subscription-info", "no-icon": "true", type: "warning", style: { display: 'none', marginBottom: '12px' }, children: jsxRuntimeExports.jsxs("div", { className: "box-center", children: [jsxRuntimeExports.jsx("p", { className: "m-0" }), jsxRuntimeExports.jsx("crowdin-button", { class: "ml-1", primary: true, onClick: () => window.open(subscriptionLink.current, '_blank'), children: "Subscribe" })] }) })), jsxRuntimeExports.jsxs("div", { id: "buttons", children: [jsxRuntimeExports.jsx("crowdin-button", { id: "show-integration-btn", class: "hidden", "icon-before": "arrow_back", onClick: () => showIntegration(), children: "Integration" }), jsxRuntimeExports.jsx("crowdin-button", { id: "show-error-logs-btn", "icon-before": "list", onClick: () => showErrorLogs(), children: "Error logs" }), isManager && (jsxRuntimeExports.jsx("crowdin-button", { "icon-before": "link", onClick: () => showPermissionsDialog(), children: "Share" })), infoModal && (jsxRuntimeExports.jsx("crowdin-button", { "icon-before": "info", onClick: () => {
2268
- const infoModalEl = document.getElementById('info-modal');
2269
- openModal(infoModalEl);
2270
- }, children: infoModal.title })), configurationFields && (jsxRuntimeExports.jsx("crowdin-button", { "icon-before": "settings", onClick: () => {
2271
- const settingsModal = document.getElementById('settings-modal');
2272
- openModal(settingsModal);
2273
- fillSettingsForm();
2274
- }, children: "Settings" })), jsxRuntimeExports.jsx("crowdin-button", { ...(!isOwner ? { disabled: true, title: 'Only the owner can log out' } : {}), "icon-before": "account_circle", onClick: () => integrationLogout(), children: "Log out" })] })] }), jsxRuntimeExports.jsx("crowdin-simple-integration", { ref: appComponent, "async-progress": true, ...((syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.crowdin) ? { 'skip-crowdin-auto-schedule': true } : {}), ...((syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.integration) ? { 'skip-integration-auto-schedule': true } : {}), ...((withCronSync === null || withCronSync === void 0 ? void 0 : withCronSync.crowdin) || (webhooks === null || webhooks === void 0 ? void 0 : webhooks.crowdin) ? { 'crowdin-schedule': 'true' } : {}), ...((withCronSync === null || withCronSync === void 0 ? void 0 : withCronSync.integration) || (webhooks === null || webhooks === void 0 ? void 0 : webhooks.integration) ? { 'integration-schedule': 'true' } : {}), ...(integrationOneLevelFetching ? { 'integration-one-level-fetching': 'true' } : {}), ...(integrationSearchListener ? { 'allow-integration-filter-change-listener': 'true' } : {}), ...(integrationPagination ? { 'integration-load-more-files': 'true' } : {}), "integration-name": name, "integration-logo": "logo.png", ...(((_a = integrationButtonMenuItems === null || integrationButtonMenuItems === void 0 ? void 0 : integrationButtonMenuItems.length) !== null && _a !== void 0 ? _a : 0) > 0
2275
- ? { 'integration-button-menu-items': integrationButtonMenuItems }
2276
- : {}), ...(((_b = crowdinButtonMenuItems === null || crowdinButtonMenuItems === void 0 ? void 0 : crowdinButtonMenuItems.length) !== null && _b !== void 0 ? _b : 0) > 0
2277
- ? { 'crowdin-button-menu-items': crowdinButtonMenuItems }
2278
- : {}), ...((filtering === null || filtering === void 0 ? void 0 : filtering.crowdinLanguages) ? { 'crowdin-filter': true } : {}), ...((filtering === null || filtering === void 0 ? void 0 : filtering.integrationFilterConfig)
2279
- ? {
2280
- 'integration-filter': true,
2281
- 'integration-filter-config': filtering.integrationFilterConfig,
2282
- }
2283
- : {}) }), jsxRuntimeExports.jsxs("div", { id: "user-errors", className: "hidden", children: [jsxRuntimeExports.jsx("crowdin-show-as-table", { "is-loading": true, id: "user-errors-table", "is-searchable": true, "total-records": "25", "search-placeholder": "Search something" }), jsxRuntimeExports.jsx("crowdin-alert", { children: "This table displays the most recent error logs from the past month. Logs older than one month will be automatically deleted." })] })] }), jsxRuntimeExports.jsx("crowdin-toasts", {}), jsxRuntimeExports.jsx("crowdin-async-progress", { cancelAsyncAction: "" }), jsxRuntimeExports.jsxs("crowdin-modal", { ref: subscriptionModal, style: { display: 'none' }, id: "subscription-modal", "modal-width": "50", "close-button": "false", children: [jsxRuntimeExports.jsx("div", { children: jsxRuntimeExports.jsxs("crowdin-alert", { type: "warning", children: ["Subscribe to continue using the ", name, " app."] }) }), jsxRuntimeExports.jsxs("div", { slot: "footer", children: [jsxRuntimeExports.jsx("crowdin-button", { primary: true, onClick: () => window.open(subscriptionLink.current, '_blank'), children: "Subscribe" }), jsxRuntimeExports.jsx("crowdin-button", { outlined: true, onClick: () => window.open('https://crowdin.com/contacts', '_blank'), children: "Contact us" }), jsxRuntimeExports.jsx("crowdin-button", { class: "ml-10", secondary: true, onClick: () => integrationLogout(), children: "Log out" })] })] }), jsxRuntimeExports.jsxs("crowdin-modal", { style: { display: 'none' }, id: "permissions-modal", "modal-title": "Share", "close-button-title": "Close", "close-button": true, "body-overflow-unset": true, children: [jsxRuntimeExports.jsx("div", { className: "loader hidden", children: jsxRuntimeExports.jsx("crowdin-progress-indicator", {}) }), jsxRuntimeExports.jsxs("div", { className: "permissions-modal-content", children: [jsxRuntimeExports.jsx("div", { className: "select-users-block", children: jsxRuntimeExports.jsx("crowdin-users-select", { ref: usersSelectRef, "allow-new-options": true, "is-multi": true, "is-searchable": true, id: "users", label: "Users", "help-text": "Search for members by name, username, email, or invite new ones using their email.", "is-position-fixed": true }, "users") }), jsxRuntimeExports.jsxs("div", { className: "select-users-info", children: [jsxRuntimeExports.jsx("div", { className: "confirm-users-block mt-2 hidden", children: jsxRuntimeExports.jsxs("table", { children: [jsxRuntimeExports.jsx("thead", { children: jsxRuntimeExports.jsxs("tr", { children: [jsxRuntimeExports.jsx("th", { style: { width: '40%' }, children: "Access" }), jsxRuntimeExports.jsx("th", { style: { width: '35%' }, children: "Users" }), jsxRuntimeExports.jsx("th", { className: "status", style: { width: '20%' }, children: "Upcoming changes" })] }) }), jsxRuntimeExports.jsxs("tbody", { children: [hasOrganization && (jsxRuntimeExports.jsxs("tr", { className: "organization-invite", children: [jsxRuntimeExports.jsxs("td", { children: [jsxRuntimeExports.jsx("crowdin-p", { children: "Registration in Organization" }), jsxRuntimeExports.jsx("div", { className: "permission-description" })] }), jsxRuntimeExports.jsx("td", { className: "affected-users" }), jsxRuntimeExports.jsx("td", { className: "status" })] })), jsxRuntimeExports.jsxs("tr", { className: "project-invite", children: [jsxRuntimeExports.jsx("td", { children: jsxRuntimeExports.jsx("crowdin-p", { children: "Project Manager Access" }) }), jsxRuntimeExports.jsx("td", { className: "affected-users" }), jsxRuntimeExports.jsx("td", { className: "status" })] }), jsxRuntimeExports.jsxs("tr", { className: "application-settings-invite", children: [jsxRuntimeExports.jsxs("td", { children: [jsxRuntimeExports.jsx("crowdin-p", { children: "Application Visibility Access" }), jsxRuntimeExports.jsx("div", { className: "permission-description" })] }), jsxRuntimeExports.jsx("td", { className: "affected-users" }), jsxRuntimeExports.jsx("td", { className: "status" })] }), jsxRuntimeExports.jsxs("tr", { className: "application-credentials-invite", children: [jsxRuntimeExports.jsxs("td", { children: [jsxRuntimeExports.jsx("crowdin-p", { children: "Access to the Integration" }), jsxRuntimeExports.jsx("div", { className: "permission-description", children: "This provides access to sync files and modify the current integration settings." })] }), jsxRuntimeExports.jsx("td", { className: "affected-users" }), jsxRuntimeExports.jsx("td", { className: "status" })] })] })] }) }), zenModeUrl && (jsxRuntimeExports.jsx("div", { className: "mt-2", children: jsxRuntimeExports.jsx("crowdin-input", { "with-fixed-height": true, label: "Zen Mode link", "help-text": "This focused view allows you to concentrate solely on the Integrations section, eliminating other distractions.", value: zenModeUrl, name: "zenModeLink", "with-copy-button": true }) }))] })] }), jsxRuntimeExports.jsx("div", { slot: "footer", children: jsxRuntimeExports.jsx("crowdin-button", { id: "confirm-users-btn", outlined: true, onClick: () => inviteUsers(), children: "Save" }) })] }), excludedTargetLanguages && (jsxRuntimeExports.jsx("crowdin-modal", { ref: languageModal, "modal-width": "50", "modal-title": "Select Target Languages for Translation", id: "excluded-languages" })), infoModal && (jsxRuntimeExports.jsx("crowdin-modal", { style: { display: 'none' }, id: "info-modal", "modal-width": "50", "modal-title": infoModal.title, "close-button-title": "Close", children: jsxRuntimeExports.jsx("div", { dangerouslySetInnerHTML: { __html: infoModal.content } }) })), configurationFields && (jsxRuntimeExports.jsxs("crowdin-modal", { style: { display: 'none' }, id: "settings-modal", "modal-width": "65", "modal-title": "Settings", "close-button-title": "Close", children: [jsxRuntimeExports.jsx("div", { className: "loader hidden", children: jsxRuntimeExports.jsx("crowdin-progress-indicator", {}) }), jsxRuntimeExports.jsx("div", { id: "modal-content", children: jsxRuntimeExports.jsx("crowdin-tabs", { "tabs-config": JSON.stringify(configurationFields.map((f) => f.name)), "active-tab": "1", children: configurationFields.map((tab, tabIndex) => (jsxRuntimeExports.jsx("div", { slot: `tab-${tabIndex + 1}`, children: jsxRuntimeExports.jsx("div", { className: "crowdin-form", children: tab.fields.map((field) => (jsxRuntimeExports.jsxs(reactExports.Fragment, { children: [renderConfigField(field, settingsFieldChange), jsxRuntimeExports.jsx("div", { style: { padding: '8px' }, ...(field.dependencySettings
2284
- ? { 'data-dependency': field.dependencySettings }
2285
- : {}) })] }, field.key))) }) }, tabIndex))) }) }), jsxRuntimeExports.jsx("div", { slot: "footer", children: jsxRuntimeExports.jsx("crowdin-button", { id: "settings-save-btn", outlined: true, onClick: () => saveSettings(), children: "Save" }) })] })), ((syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.crowdin) || (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.integration)) && (jsxRuntimeExports.jsxs("crowdin-modal", { style: { display: 'none' }, id: "confirm-schedule-modal", "modal-width": "50", "modal-title": "Synchronization options", "close-button-title": "Close", "close-button": "true", "body-overflow-unset": true, children: [jsxRuntimeExports.jsx("crowdin-checkbox", { id: "selected-files", name: "selected-files", label: "Selected files", class: "hydrated", onChange: () => onChangeAutoSynchronizationOptions() }), jsxRuntimeExports.jsx("crowdin-checkbox", { id: "all-folder-files", name: "all-folder-files", label: "All files in the folder", class: "hydrated", hidden: true, onChange: () => onChangeAutoSynchronizationOptions() }), jsxRuntimeExports.jsx("crowdin-checkbox", { id: "new-files", name: "new-files", label: "New files", class: "hydrated", onChange: () => onChangeAutoSynchronizationOptions() }), jsxRuntimeExports.jsx("div", { slot: "footer", children: jsxRuntimeExports.jsx("crowdin-button", { outlined: true, id: "save-schedule-sync", onClick: () => saveScheduleSync(), children: "Save" }) })] })), jsxRuntimeExports.jsx("crowdin-modal", { style: { display: 'none' }, id: "user-error-detail", "close-button-title": "Close", "close-button": "true" })] }));
2698
+ function showIntegration() {
2699
+ setIsErrorLogsVisible(false);
2700
+ }
2701
+ return (jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsxs("div", { className: "mx-auto max-w-[1420px] px-6 py-4", children: [jsxRuntimeExports.jsx(TopBar, { notice: notice, isNoticeVisible: isNoticeVisible, checkSubscription: checkSubscription, subscriptionInfo: subscriptionInfo, isErrorLogsVisible: isErrorLogsVisible, isManager: isManager, infoModal: infoModal, hasSettings: !!configurationFields, isOwner: isOwner, onCloseNotice: closeAlert, onShowIntegration: showIntegration, onShowErrorLogs: showErrorLogs, onShowPermissions: permissions.showPermissionsDialog, onOpenInfoModal: () => openModal(infoModalRef.current), onOpenSettings: () => {
2702
+ openModal(settingsModalRef.current);
2703
+ settings.fillSettingsForm();
2704
+ }, onLogout: integrationLogout }), jsxRuntimeExports.jsx(IntegrationView, { appComponentRef: appComponent, userErrorsTableRef: userErrorsTableRef, name: name, isErrorLogsVisible: isErrorLogsVisible, syncNewElements: syncNewElements, withCronSync: withCronSync, webhooks: webhooks, integrationOneLevelFetching: integrationOneLevelFetching, integrationSearchListener: integrationSearchListener, integrationPagination: integrationPagination, filtering: filtering, integrationButtonMenuItems: integrationButtonMenuItems, crowdinButtonMenuItems: crowdinButtonMenuItems })] }), jsxRuntimeExports.jsx("crowdin-toasts", {}), jsxRuntimeExports.jsx("crowdin-async-progress", { ref: asyncProgressRef, cancelAsyncAction: "" }), jsxRuntimeExports.jsx(SubscriptionModal, { modalRef: subscriptionModal, subscriptionLink: subscriptionLink, name: name, onLogout: integrationLogout }), jsxRuntimeExports.jsx(PermissionsModal, { modalRef: permissionsModalRef, usersSelectRef: permissions.usersSelectRef, isLoading: permissions.isLoading, permissionUserOptions: permissions.permissionUserOptions, isConfirmVisible: permissions.isPermissionsConfirmVisible, permissionsSummary: permissions.permissionsSummary, hasOrganization: hasOrganization, zenModeUrl: zenModeUrl, onSave: permissions.inviteUsers }), excludedTargetLanguages && (jsxRuntimeExports.jsx(ExcludedLanguagesModal, { modalRef: syncOps.languageModalRef, languageSelectRef: syncOps.languageSelectRef, languageModalState: syncOps.languageModalState, onUpdateTargetLanguages: syncOps.updateCrowdinFilesTargetLanguages, onSyncToCrowdin: syncOps.uploadFilesToCrowdinWithExcludedLanguages })), infoModal && jsxRuntimeExports.jsx(InfoModal, { modalRef: infoModalRef, infoModal: infoModal }), configurationFields && (jsxRuntimeExports.jsx(SettingsModal, { modalRef: settingsModalRef, isLoading: settings.isLoading, configurationFields: configurationFields, isSaveDisabled: settings.isSettingsSaveDisabled, settingsFieldChange: settings.settingsFieldChange, registerSettingsField: settings.registerSettingsField, onSave: settings.saveSettings })), ((syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.crowdin) || (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.integration)) && (jsxRuntimeExports.jsx(ScheduleModal, { modalRef: scheduleModalRef, selectedFilesCheckboxRef: schedule.selectedFilesCheckboxRef, allFolderFilesCheckboxRef: schedule.allFolderFilesCheckboxRef, newFilesCheckboxRef: schedule.newFilesCheckboxRef, scheduleModalState: schedule.scheduleModalState, isSaveDisabled: schedule.isScheduleSaveDisabled, onChangeOptions: schedule.onChangeAutoSynchronizationOptions, onSave: schedule.saveScheduleSync })), jsxRuntimeExports.jsx(UserErrorDetailModal, { modalRef: userErrorDetailModalRef, selectedUserError: selectedUserError })] }));
2286
2705
  };
2287
2706
 
2288
- clientExports.createRoot(document.getElementById('root')).render(jsxRuntimeExports.jsx(MainPage, { ...window.__PAGE_PROPS__ }));
2707
+ initializeCrowdinIframeContext();
2708
+ const props = readPageProps();
2709
+ clientExports.createRoot(document.getElementById('root')).render(jsxRuntimeExports.jsx(MainPage, { ...props }));
2289
2710
 
2290
2711
  })();
2291
2712
  //# sourceMappingURL=main.bundle.js.map