@crowdin/app-project-module 2.3.0 → 2.5.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.
- package/out/modules/file-processing/handlers/custom-file-format.d.ts +2 -1
- package/out/modules/file-processing/handlers/custom-file-format.js +12 -9
- package/out/modules/file-processing/handlers/file-download.js +10 -2
- package/out/modules/file-processing/handlers/pre-post-process.js +7 -6
- package/out/modules/file-processing/handlers/translations-alignment.js +7 -2
- package/out/modules/file-processing/index.js +2 -0
- package/out/modules/file-processing/util/files.js +2 -1
- package/out/modules/file-processing/util/signed-url.d.ts +2 -0
- package/out/modules/file-processing/util/signed-url.js +27 -0
- package/out/static/ui/main.bundle.js +1632 -1563
- package/out/static/ui/main.bundle.js.map +1 -1
- package/package.json +5 -2
|
@@ -875,7 +875,29 @@
|
|
|
875
875
|
return values.filter((value) => value !== '');
|
|
876
876
|
}
|
|
877
877
|
|
|
878
|
-
const
|
|
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 = '―';
|
|
879
901
|
const getDefaultScheduleModalState = () => ({
|
|
880
902
|
type: null,
|
|
881
903
|
showNewFiles: true,
|
|
@@ -885,1592 +907,1770 @@
|
|
|
885
907
|
selectedFiles: true,
|
|
886
908
|
allFolderFiles: false,
|
|
887
909
|
});
|
|
888
|
-
const
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
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;
|
|
892
935
|
}
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
...(field.dependencySettings ? { 'data-dependency': field.dependencySettings } : {}),
|
|
900
|
-
};
|
|
901
|
-
switch (field.type) {
|
|
902
|
-
case 'checkbox':
|
|
903
|
-
return (jsxRuntimeExports.jsx("crowdin-checkbox", { ref: registerSettingsField(field.key), ...commonProps, value: "false", "use-switch": true, ...(field.defaultValue === true ? { checked: String(field.defaultValue) } : {}), onChange: settingsFieldChange }));
|
|
904
|
-
case 'select':
|
|
905
|
-
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) => {
|
|
906
|
-
const isSelected = Array.isArray(field.defaultValue)
|
|
907
|
-
? field.defaultValue.includes(option.value)
|
|
908
|
-
: field.defaultValue === option.value;
|
|
909
|
-
return (jsxRuntimeExports.jsx("option", { value: option.value, ...(isSelected ? { selected: true } : {}), children: option.label }, option.value));
|
|
910
|
-
}) }));
|
|
911
|
-
case 'text':
|
|
912
|
-
return (jsxRuntimeExports.jsx("crowdin-input", { ref: registerSettingsField(field.key), ...commonProps, "with-fixed-height": true, value: field.defaultValue || '', onChange: settingsFieldChange }));
|
|
913
|
-
case 'textarea':
|
|
914
|
-
return (jsxRuntimeExports.jsx("crowdin-textarea", { ref: registerSettingsField(field.key), ...commonProps, value: field.defaultValue || '', onChange: settingsFieldChange }));
|
|
915
|
-
case 'notice':
|
|
916
|
-
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 || '' } }));
|
|
917
|
-
default:
|
|
918
|
-
return null;
|
|
936
|
+
modal.style.display = 'block';
|
|
937
|
+
modal.open();
|
|
938
|
+
}
|
|
939
|
+
function closeModal(modal) {
|
|
940
|
+
if (!modal) {
|
|
941
|
+
return;
|
|
919
942
|
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
const fileType = '1';
|
|
927
|
-
const branchType = '2';
|
|
928
|
-
const JOB_TYPE = {
|
|
929
|
-
updateCrowdin: 'updateCrowdin',
|
|
930
|
-
updateIntegration: 'updateIntegration',
|
|
931
|
-
updateTargetLanguages: 'updateTargetLanguages',
|
|
932
|
-
integrationSyncSettingsSave: 'integrationSyncSettingsSave',
|
|
933
|
-
crowdinSyncSettingsSave: 'crowdinSyncSettingsSave',
|
|
934
|
-
integrationSettingsSave: 'integrationSettingsSave',
|
|
935
|
-
};
|
|
936
|
-
const JOB_STATUS = {
|
|
937
|
-
created: 'created',
|
|
938
|
-
inProgress: 'inProgress',
|
|
939
|
-
failed: 'failed',
|
|
940
|
-
canceled: 'canceled',
|
|
941
|
-
finished: 'finished',
|
|
942
|
-
};
|
|
943
|
-
const silentJobs = [JOB_TYPE.integrationSettingsSave];
|
|
944
|
-
const appComponent = reactExports.useRef(null);
|
|
945
|
-
const asyncProgressRef = reactExports.useRef(null);
|
|
946
|
-
const infoModalRef = reactExports.useRef(null);
|
|
947
|
-
const subscriptionModal = reactExports.useRef(null);
|
|
948
|
-
const settingsModalRef = reactExports.useRef(null);
|
|
949
|
-
const scheduleModalRef = reactExports.useRef(null);
|
|
950
|
-
const selectedFilesCheckboxRef = reactExports.useRef(null);
|
|
951
|
-
const allFolderFilesCheckboxRef = reactExports.useRef(null);
|
|
952
|
-
const newFilesCheckboxRef = reactExports.useRef(null);
|
|
953
|
-
const languageModal = reactExports.useRef(null);
|
|
954
|
-
const languageSelectRef = reactExports.useRef(null);
|
|
955
|
-
const permissionsModalRef = reactExports.useRef(null);
|
|
956
|
-
const userErrorsTableRef = reactExports.useRef(null);
|
|
957
|
-
const userErrorDetailModalRef = reactExports.useRef(null);
|
|
943
|
+
modal.style.display = 'none';
|
|
944
|
+
modal.close();
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/// <reference path="../../../../ui/types.d.ts" />
|
|
948
|
+
function usePermissions({ userId, hasOrganization, permissionsModalRef }) {
|
|
958
949
|
const usersSelectRef = reactExports.useRef(null);
|
|
959
|
-
const
|
|
960
|
-
const refreshDependencies = useFieldDependencies(configurationFields);
|
|
961
|
-
const crowdinFilesToUpdateTargetLanguages = reactExports.useRef([]);
|
|
962
|
-
const asyncJobs = reactExports.useRef({});
|
|
963
|
-
const project = reactExports.useRef({});
|
|
964
|
-
const crowdinData = reactExports.useRef([]);
|
|
965
|
-
const fileToSync = reactExports.useRef([]);
|
|
966
|
-
const syncData = reactExports.useRef(null);
|
|
967
|
-
const subscriptionLink = reactExports.useRef('');
|
|
968
|
-
const hasLoadMoreElements = reactExports.useRef(false);
|
|
969
|
-
const savedIntegrationData = reactExports.useRef(null);
|
|
970
|
-
const currentOpenedFolders = reactExports.useRef(null);
|
|
971
|
-
const [modalLoaders, setModalLoaders] = reactExports.useState({});
|
|
972
|
-
const [languageModalState, setLanguageModalState] = reactExports.useState(null);
|
|
950
|
+
const [isLoading, setIsLoading] = reactExports.useState(false);
|
|
973
951
|
const [permissionUserOptions, setPermissionUserOptions] = reactExports.useState([]);
|
|
974
952
|
const [permissionsSelectedValue, setPermissionsSelectedValue] = reactExports.useState('[]');
|
|
975
953
|
const [permissionsSummary, setPermissionsSummary] = reactExports.useState(null);
|
|
976
954
|
const [isPermissionsConfirmVisible, setIsPermissionsConfirmVisible] = reactExports.useState(false);
|
|
977
|
-
const [isNoticeVisible, setIsNoticeVisible] = reactExports.useState(false);
|
|
978
|
-
const [isSettingsSaveDisabled, setIsSettingsSaveDisabled] = reactExports.useState(false);
|
|
979
|
-
const [scheduleModalState, setScheduleModalState] = reactExports.useState(getDefaultScheduleModalState);
|
|
980
|
-
const [isScheduleSaveDisabled, setIsScheduleSaveDisabled] = reactExports.useState(false);
|
|
981
|
-
const [subscriptionInfo, setSubscriptionInfo] = reactExports.useState(null);
|
|
982
|
-
const [isErrorLogsVisible, setIsErrorLogsVisible] = reactExports.useState(false);
|
|
983
|
-
const [selectedUserError, setSelectedUserError] = reactExports.useState(null);
|
|
984
|
-
reactExports.useEffect(() => {
|
|
985
|
-
// Event listeners
|
|
986
|
-
const listeners = {
|
|
987
|
-
refreshFilesList: (e) => {
|
|
988
|
-
if (e.detail.refreshIntegration) {
|
|
989
|
-
getIntegrationData({ hardReload: true });
|
|
990
|
-
}
|
|
991
|
-
else if (e.detail.refreshCrowdin) {
|
|
992
|
-
getCrowdinData();
|
|
993
|
-
}
|
|
994
|
-
},
|
|
995
|
-
crowdinFilesFolderToggled: (event) => {
|
|
996
|
-
if (event.detail.componentId === 'crowdin-files' && event.detail.isOpen && event.detail.type === '1') {
|
|
997
|
-
getFileProgress(event.detail.id);
|
|
998
|
-
}
|
|
999
|
-
if (integrationOneLevelFetching) {
|
|
1000
|
-
if (event.detail.componentId === 'integration-files' && event.detail.isOpen) {
|
|
1001
|
-
getIntegrationData({ parentId: event.detail.id, recursion: event.detail.recursion });
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
},
|
|
1005
|
-
uploadFilesToCrowdin: uploadFilesToCrowdin,
|
|
1006
|
-
uploadFilesToIntegration: uploadFilesToIntegration,
|
|
1007
|
-
cancelAsyncAction: (e) => {
|
|
1008
|
-
cancelJob(e.detail);
|
|
1009
|
-
},
|
|
1010
|
-
keydown: (event) => {
|
|
1011
|
-
if (event.keyCode === 27) {
|
|
1012
|
-
closeModal(permissionsModalRef.current);
|
|
1013
|
-
closeModal(infoModalRef.current);
|
|
1014
|
-
closeModal(settingsModalRef.current);
|
|
1015
|
-
closeModal(scheduleModalRef.current);
|
|
1016
|
-
if (languageModal.current) {
|
|
1017
|
-
closeModal(languageModal.current);
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
},
|
|
1021
|
-
loadMoreClick: async (e) => {
|
|
1022
|
-
var _a;
|
|
1023
|
-
const loadMoreFile = e.detail;
|
|
1024
|
-
const fileComponent = (_a = appComponent.current) === null || _a === void 0 ? void 0 : _a.querySelector('#integration-files');
|
|
1025
|
-
if (!fileComponent) {
|
|
1026
|
-
return;
|
|
1027
|
-
}
|
|
1028
|
-
await fileComponent.setLoadMoreLoading(loadMoreFile.id, true);
|
|
1029
|
-
getIntegrationData({ parentId: e.detail.parent_id, paginationData: e.detail.pagination }).finally(async () => {
|
|
1030
|
-
await fileComponent.setLoadMoreLoading(loadMoreFile.id, false);
|
|
1031
|
-
});
|
|
1032
|
-
},
|
|
1033
|
-
};
|
|
1034
|
-
if (integrationSearchListener) {
|
|
1035
|
-
listeners['integrationFilterChange'] = async (event) => {
|
|
1036
|
-
const isEmptySearch = !event.detail || event.detail.trim() === '';
|
|
1037
|
-
if (isEmptySearch && savedIntegrationData.current && hasLoadMoreElements.current) {
|
|
1038
|
-
appComponent.current.setIntegrationFilesData(savedIntegrationData.current);
|
|
1039
|
-
appComponent.current.setIntegrationOpenedFolders(currentOpenedFolders.current);
|
|
1040
|
-
return;
|
|
1041
|
-
}
|
|
1042
|
-
if (!isEmptySearch && hasLoadMoreElements.current) {
|
|
1043
|
-
savedIntegrationData.current = await appComponent.current.getIntegrationFilesData();
|
|
1044
|
-
currentOpenedFolders.current = await appComponent.current.getIntegrationOpenedFolders();
|
|
1045
|
-
}
|
|
1046
|
-
getIntegrationData({ search: event.detail });
|
|
1047
|
-
};
|
|
1048
|
-
}
|
|
1049
|
-
if (integrationPagination) {
|
|
1050
|
-
listeners['fileListEnd'] = (e) => {
|
|
1051
|
-
getIntegrationData({ page: e.detail.page });
|
|
1052
|
-
};
|
|
1053
|
-
}
|
|
1054
|
-
if (withCronSync || webhooks) {
|
|
1055
|
-
listeners['integrationScheduleSync'] = setIntegrationScheduleSync;
|
|
1056
|
-
listeners['crowdinScheduleSync'] = setCrowdinScheduleSync;
|
|
1057
|
-
listeners['crowdinDisableSync'] = disableCrowdinSync;
|
|
1058
|
-
listeners['integrationDisableSync'] = disableIntegrationSync;
|
|
1059
|
-
}
|
|
1060
|
-
for (const [event, handler] of Object.entries(listeners)) {
|
|
1061
|
-
document.body.addEventListener(event, handler);
|
|
1062
|
-
}
|
|
1063
|
-
// Initial data fetch
|
|
1064
|
-
getCrowdinData();
|
|
1065
|
-
getIntegrationData({});
|
|
1066
|
-
getActiveJobs();
|
|
1067
|
-
if (checkSubscription) {
|
|
1068
|
-
getSubscriptionInfo();
|
|
1069
|
-
}
|
|
1070
|
-
setIsNoticeVisible(Boolean(notice) && localStorage.getItem('revised_notice') !== '1');
|
|
1071
|
-
return () => {
|
|
1072
|
-
for (const [event, handler] of Object.entries(listeners)) {
|
|
1073
|
-
document.body.removeEventListener(event, handler);
|
|
1074
|
-
}
|
|
1075
|
-
};
|
|
1076
|
-
}, []);
|
|
1077
|
-
reactExports.useEffect(() => {
|
|
1078
|
-
var _a;
|
|
1079
|
-
if (!languageModalState || !((_a = languageSelectRef.current) === null || _a === void 0 ? void 0 : _a.setValue)) {
|
|
1080
|
-
return;
|
|
1081
|
-
}
|
|
1082
|
-
languageSelectRef.current.setValue(languageModalState.languages.map((language) => language.id));
|
|
1083
|
-
}, [languageModalState]);
|
|
1084
955
|
reactExports.useEffect(() => {
|
|
1085
956
|
if (usersSelectRef.current) {
|
|
1086
957
|
usersSelectRef.current.value = permissionsSelectedValue;
|
|
1087
958
|
}
|
|
1088
959
|
}, [permissionUserOptions, permissionsSelectedValue]);
|
|
1089
|
-
reactExports.useEffect(() => {
|
|
1090
|
-
syncScheduleCheckbox(selectedFilesCheckboxRef.current, {
|
|
1091
|
-
checked: scheduleModalState.selectedFiles,
|
|
1092
|
-
});
|
|
1093
|
-
syncScheduleCheckbox(allFolderFilesCheckboxRef.current, {
|
|
1094
|
-
checked: scheduleModalState.allFolderFiles,
|
|
1095
|
-
hidden: !scheduleModalState.showAllFolderFiles,
|
|
1096
|
-
});
|
|
1097
|
-
syncScheduleCheckbox(newFilesCheckboxRef.current, {
|
|
1098
|
-
checked: scheduleModalState.newFiles,
|
|
1099
|
-
hidden: !scheduleModalState.showNewFiles,
|
|
1100
|
-
clearSelection: scheduleModalState.newFilesClearSelection,
|
|
1101
|
-
});
|
|
1102
|
-
}, [scheduleModalState]);
|
|
1103
|
-
// Expose centralized API to global scope for main.js compatibility
|
|
1104
|
-
reactExports.useEffect(() => {
|
|
1105
|
-
window.app = {
|
|
1106
|
-
subscriptionModal: subscriptionModal,
|
|
1107
|
-
subscriptionLink: subscriptionLink,
|
|
1108
|
-
openModal: openModal,
|
|
1109
|
-
};
|
|
1110
|
-
return () => {
|
|
1111
|
-
delete window.app;
|
|
1112
|
-
};
|
|
1113
|
-
}, []);
|
|
1114
960
|
// crowdin-users-select doesn't trigger onChange reliably, using native event listener instead
|
|
1115
961
|
reactExports.useEffect(() => {
|
|
1116
962
|
const selectElement = usersSelectRef.current;
|
|
1117
|
-
if (selectElement) {
|
|
1118
|
-
|
|
1119
|
-
checkUsers();
|
|
1120
|
-
};
|
|
1121
|
-
selectElement.addEventListener('change', handleChange);
|
|
1122
|
-
return () => {
|
|
1123
|
-
selectElement.removeEventListener('change', handleChange);
|
|
1124
|
-
};
|
|
963
|
+
if (!selectElement) {
|
|
964
|
+
return;
|
|
1125
965
|
}
|
|
966
|
+
const handleChange = () => checkUsers();
|
|
967
|
+
selectElement.addEventListener('change', handleChange);
|
|
968
|
+
return () => selectElement.removeEventListener('change', handleChange);
|
|
1126
969
|
}, []);
|
|
1127
|
-
function
|
|
1128
|
-
|
|
1129
|
-
.
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
.catch((e) => catchRejection(e, e.error || 'Looks like you are not logged in'));
|
|
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;
|
|
1134
976
|
}
|
|
1135
|
-
function
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
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));
|
|
1150
1015
|
}
|
|
1151
|
-
|
|
1152
|
-
|
|
1016
|
+
catch (e) {
|
|
1017
|
+
catchRejection(e, "Can't fetch users");
|
|
1018
|
+
}
|
|
1019
|
+
finally {
|
|
1020
|
+
setTimeout(() => setIsLoading(false), 500);
|
|
1153
1021
|
}
|
|
1154
|
-
return item;
|
|
1155
1022
|
}
|
|
1156
|
-
function
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
const dirPromise = fetch('api/crowdin/files' + restParams + '&mode=directories')
|
|
1164
|
-
.then(checkResponse)
|
|
1165
|
-
.then((directories) => {
|
|
1166
|
-
var _a;
|
|
1167
|
-
const dirTree = directories.map(transformCrowdinItemToTree);
|
|
1168
|
-
crowdinData.current = dirTree;
|
|
1169
|
-
(_a = appComponent.current) === null || _a === void 0 ? void 0 : _a.setCrowdinFilesData(dirTree);
|
|
1170
|
-
return dirTree;
|
|
1171
|
-
});
|
|
1172
|
-
const filesPromise = fetch('api/crowdin/files' + restParams + '&mode=files').then(checkResponse);
|
|
1173
|
-
const projectPromise = fetch('api/crowdin/project' + restParams).then(checkResponse);
|
|
1174
|
-
return Promise.all([dirPromise, filesPromise, projectPromise]);
|
|
1175
|
-
})
|
|
1176
|
-
.then(([dirTree, files, projectData]) => {
|
|
1177
|
-
var _a, _b, _c;
|
|
1178
|
-
const fileTree = files.map(transformCrowdinItemToTree);
|
|
1179
|
-
crowdinData.current = [...dirTree, ...fileTree];
|
|
1180
|
-
(_a = appComponent.current) === null || _a === void 0 ? void 0 : _a.setCrowdinFilesData(crowdinData.current);
|
|
1181
|
-
project.current = projectData;
|
|
1182
|
-
const languagesSorted = project.current.targetLanguages
|
|
1183
|
-
.map((language) => ({
|
|
1184
|
-
sourceLanguageId: projectData.sourceLanguage.editorCode,
|
|
1185
|
-
projectEditorLink: projectData.projectEditorLink,
|
|
1186
|
-
...language,
|
|
1187
|
-
}))
|
|
1188
|
-
.sort((a, b) => a.name.localeCompare(b.name));
|
|
1189
|
-
if (project.current.inContext && ((_b = config.current) === null || _b === void 0 ? void 0 : _b.inContext)) {
|
|
1190
|
-
languagesSorted.push({ ...project.current.inContextPseudoLanguage, inContext: true });
|
|
1191
|
-
}
|
|
1192
|
-
setLanguagesForTranslation(languagesSorted);
|
|
1193
|
-
(_c = appComponent.current) === null || _c === void 0 ? void 0 : _c.setCrowdinLanguagesData(languagesSorted);
|
|
1194
|
-
});
|
|
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;
|
|
1195
1030
|
}
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
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,
|
|
1221
1072
|
});
|
|
1222
1073
|
}
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
if (withCronSync || webhooks) {
|
|
1226
|
-
return getSyncSettings('crowdin');
|
|
1227
|
-
}
|
|
1228
|
-
})
|
|
1229
|
-
.catch((e) => catchRejection(e, "Can't fetch Crowdin data"))
|
|
1230
|
-
.finally(() => appComponent.current.setAttribute('is-crowdin-loading', false));
|
|
1231
|
-
}
|
|
1232
|
-
function getIntegrationData({ hardReload = false, parentId = '', search = '', page = 0, recursion = false, paginationData } = {}, recursionState = null) {
|
|
1233
|
-
if (!paginationData) {
|
|
1234
|
-
appComponent.current.setAttribute('is-integration-loading', true);
|
|
1074
|
+
catch (e) {
|
|
1075
|
+
catchRejection(e, (e === null || e === void 0 ? void 0 : e.error) || "Can't invite users");
|
|
1235
1076
|
}
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
name: e.name,
|
|
1253
|
-
id: e.id,
|
|
1254
|
-
customContent: e.customContent,
|
|
1255
|
-
labels: e.labels,
|
|
1256
|
-
disabled: e.disabled,
|
|
1257
|
-
tooltip: e.tooltip,
|
|
1258
|
-
pagination: e.pagination,
|
|
1259
|
-
};
|
|
1260
|
-
if (e.type) {
|
|
1261
|
-
item.isNew = e.isNew;
|
|
1262
|
-
item.isUpdated = e.isUpdated;
|
|
1263
|
-
item.notSynced = e.notSynced;
|
|
1264
|
-
item.synced = e.synced;
|
|
1265
|
-
item.type = e.type;
|
|
1266
|
-
item.node_type = fileType;
|
|
1267
|
-
}
|
|
1268
|
-
else {
|
|
1269
|
-
item.node_type = e.nodeType || folderType;
|
|
1270
|
-
}
|
|
1271
|
-
return item;
|
|
1272
|
-
});
|
|
1273
|
-
if ((!paginationData && !parentId && !search) || hardReload) {
|
|
1274
|
-
hasLoadMoreElements.current = tree.some((item) => item.node_type === 'load-more');
|
|
1275
|
-
}
|
|
1276
|
-
const appIntegrationFiles = appComponent.current.querySelector('#integration-files');
|
|
1277
|
-
if (hardReload) {
|
|
1278
|
-
appComponent.current.setIntegrationFilesData(tree);
|
|
1279
|
-
}
|
|
1280
|
-
else if (tree.length) {
|
|
1281
|
-
appComponent.current.pushIntegrationFilesData(tree).then(() => {
|
|
1282
|
-
if (parentId) {
|
|
1283
|
-
appIntegrationFiles.getSelected().then(async (selection) => {
|
|
1284
|
-
const selectedIds = selection === null || selection === void 0 ? void 0 : selection.filter((node) => node).map(({ id }) => id.toString());
|
|
1285
|
-
const filteredNodes = tree.filter((node) => !selectedIds.includes(node.id.toString()) &&
|
|
1286
|
-
selectedIds.includes(node.parent_id.toString()));
|
|
1287
|
-
if (filteredNodes === null || filteredNodes === void 0 ? void 0 : filteredNodes.length) {
|
|
1288
|
-
const filteredNodesId = filteredNodes.map(({ id }) => id.toString());
|
|
1289
|
-
await appIntegrationFiles.setSelected(filteredNodesId);
|
|
1290
|
-
}
|
|
1291
|
-
});
|
|
1292
|
-
}
|
|
1293
|
-
});
|
|
1294
|
-
}
|
|
1295
|
-
if (integrationPagination) {
|
|
1296
|
-
if (stopPagination) {
|
|
1297
|
-
appIntegrationFiles.setAttribute('load-more-disabled', true);
|
|
1298
|
-
}
|
|
1299
|
-
else {
|
|
1300
|
-
appIntegrationFiles.setAttribute('load-more-disabled', false);
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
|
-
if (search) {
|
|
1304
|
-
const openIds = files.filter((e) => !e.type).map((e) => e.id);
|
|
1305
|
-
appComponent.current.setIntegrationOpenedFolders(openIds);
|
|
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;
|
|
1306
1093
|
}
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
}
|
|
1318
|
-
if (parentId) {
|
|
1319
|
-
recursionStateLocal.openedFolders.add(parentId);
|
|
1320
|
-
}
|
|
1321
|
-
const folderItems = files.filter(isFolder);
|
|
1322
|
-
if (folderItems.length === 0) {
|
|
1323
|
-
return Promise.resolve();
|
|
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;
|
|
1324
1104
|
}
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
...currentOpenedFolders,
|
|
1329
|
-
...recursionStateLocal.openedFolders,
|
|
1330
|
-
]);
|
|
1331
|
-
const recursivePromises = folderItems.map(async (folder) => {
|
|
1332
|
-
recursionStateLocal.calls++;
|
|
1333
|
-
try {
|
|
1334
|
-
return getIntegrationData({ parentId: folder.id, recursion: true }, recursionState);
|
|
1335
|
-
}
|
|
1336
|
-
finally {
|
|
1337
|
-
recursionStateLocal.calls--;
|
|
1338
|
-
if (recursionStateLocal.calls === 0) {
|
|
1339
|
-
recursionStateLocal.setLoading(false);
|
|
1340
|
-
}
|
|
1341
|
-
}
|
|
1342
|
-
});
|
|
1343
|
-
return Promise.all(recursivePromises);
|
|
1344
|
-
}
|
|
1345
|
-
})
|
|
1346
|
-
.then(() => {
|
|
1347
|
-
if (withCronSync || webhooks) {
|
|
1348
|
-
getSyncSettings('integration');
|
|
1105
|
+
showToast('Users successfully updated');
|
|
1106
|
+
hideConfirmUsersBlock();
|
|
1107
|
+
closeModal(permissionsModalRef.current);
|
|
1349
1108
|
}
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
.finally(() => {
|
|
1353
|
-
if (!recursionStateLocal && !recursion) {
|
|
1354
|
-
appComponent.current.setAttribute('is-integration-loading', false);
|
|
1109
|
+
catch (e) {
|
|
1110
|
+
catchRejection(e, (e === null || e === void 0 ? void 0 : e.error) || "Can't invite users");
|
|
1355
1111
|
}
|
|
1356
|
-
|
|
1357
|
-
|
|
1112
|
+
finally {
|
|
1113
|
+
setTimeout(() => setIsLoading(false), 500);
|
|
1358
1114
|
}
|
|
1359
1115
|
});
|
|
1360
1116
|
}
|
|
1361
|
-
function
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
.filter(Boolean);
|
|
1382
|
-
if (provider === 'crowdin') {
|
|
1383
|
-
const changedItems = getChangedItems(crowdinData.current || []);
|
|
1384
|
-
if (changedItems.length) {
|
|
1385
|
-
const changedById = new Map(changedItems.map((item) => [`${item.id}`, item]));
|
|
1386
|
-
crowdinData.current = (crowdinData.current || []).map((item) => changedById.get(`${item.id}`) || item);
|
|
1387
|
-
(_a = appComponent.current) === null || _a === void 0 ? void 0 : _a.updateCrowdinFileData(changedItems);
|
|
1388
|
-
}
|
|
1389
|
-
return;
|
|
1390
|
-
}
|
|
1391
|
-
const integrationData = await ((_c = (_b = appComponent.current) === null || _b === void 0 ? void 0 : _b.getIntegrationFilesData) === null || _c === void 0 ? void 0 : _c.call(_b));
|
|
1392
|
-
if (Array.isArray(integrationData)) {
|
|
1393
|
-
const changedItems = getChangedItems(integrationData);
|
|
1394
|
-
if (changedItems.length) {
|
|
1395
|
-
(_d = appComponent.current) === null || _d === void 0 ? void 0 : _d.updateIntegrationFileData(changedItems);
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
async function fetchSyncSettingsFiles(provider) {
|
|
1400
|
-
const restParams = await checkOrigin();
|
|
1401
|
-
const res = await fetch(`/api/sync-settings/${provider}` + restParams).then(checkResponse);
|
|
1402
|
-
return Array.isArray(res) ? res : [];
|
|
1403
|
-
}
|
|
1404
|
-
async function refreshAutoSyncPausedIndicatorsAndWarning() {
|
|
1405
|
-
const [crowdinSyncSettings, integrationSyncSettings] = await Promise.all([
|
|
1406
|
-
fetchSyncSettingsFiles('crowdin'),
|
|
1407
|
-
fetchSyncSettingsFiles('integration'),
|
|
1408
|
-
]);
|
|
1409
|
-
await applyAutoSyncPausedMarkers('crowdin', crowdinSyncSettings);
|
|
1410
|
-
await applyAutoSyncPausedMarkers('integration', integrationSyncSettings);
|
|
1411
|
-
if (isScheduleDisabled() && (crowdinSyncSettings.length || integrationSyncSettings.length)) {
|
|
1412
|
-
showToast('Auto Sync is configured for some files, but sync schedule is disabled in app settings.');
|
|
1413
|
-
}
|
|
1414
|
-
}
|
|
1415
|
-
function getSyncSettings(provider) {
|
|
1416
|
-
checkOrigin()
|
|
1417
|
-
.then((restParams) => fetch(`/api/sync-settings/${provider}` + restParams))
|
|
1418
|
-
.then(checkResponse)
|
|
1419
|
-
.then(async (res) => {
|
|
1420
|
-
if (provider === 'crowdin') {
|
|
1421
|
-
if (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.crowdin) {
|
|
1422
|
-
appComponent.current.setCrowdinScheduleSync(res, true, true);
|
|
1423
|
-
}
|
|
1424
|
-
else {
|
|
1425
|
-
appComponent.current.setCrowdinScheduleSync(res);
|
|
1426
|
-
}
|
|
1427
|
-
}
|
|
1428
|
-
else {
|
|
1429
|
-
if (syncNewElements === null || syncNewElements === void 0 ? void 0 : syncNewElements.integration) {
|
|
1430
|
-
appComponent.current.setIntegrationScheduleSync(res, true, true);
|
|
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
|
+
},
|
|
1431
1137
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
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
|
+
});
|
|
1446
1162
|
}
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1163
|
+
return {
|
|
1164
|
+
usersSelectRef,
|
|
1165
|
+
isLoading,
|
|
1166
|
+
permissionUserOptions,
|
|
1167
|
+
permissionsSelectedValue,
|
|
1168
|
+
permissionsSummary,
|
|
1169
|
+
isPermissionsConfirmVisible,
|
|
1170
|
+
showPermissionsDialog,
|
|
1171
|
+
inviteUsers,
|
|
1172
|
+
};
|
|
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) {
|
|
1460
1199
|
return;
|
|
1461
1200
|
}
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
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);
|
|
1465
1209
|
}
|
|
1466
|
-
|
|
1467
|
-
|
|
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) {
|
|
1468
1218
|
return;
|
|
1469
1219
|
}
|
|
1220
|
+
checkbox.checked = checked;
|
|
1221
|
+
checkbox.value = checked;
|
|
1222
|
+
if (hidden) {
|
|
1223
|
+
checkbox.setAttribute('hidden', '');
|
|
1224
|
+
}
|
|
1470
1225
|
else {
|
|
1471
|
-
|
|
1226
|
+
checkbox.removeAttribute('hidden');
|
|
1472
1227
|
}
|
|
1473
|
-
if (
|
|
1474
|
-
|
|
1228
|
+
if (clearSelection) {
|
|
1229
|
+
checkbox.setAttribute('clear-selection', '');
|
|
1475
1230
|
}
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
return;
|
|
1231
|
+
else {
|
|
1232
|
+
checkbox.removeAttribute('clear-selection');
|
|
1479
1233
|
}
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
id: f.id,
|
|
1486
|
-
type: f.type,
|
|
1487
|
-
parentId: f.parent_id,
|
|
1488
|
-
nodeType: f.node_type,
|
|
1489
|
-
isUpdated: f.isUpdated,
|
|
1490
|
-
}));
|
|
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);
|
|
1491
1239
|
}
|
|
1492
1240
|
else {
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
name: f.name,
|
|
1497
|
-
id: f.id,
|
|
1498
|
-
type: f.type,
|
|
1499
|
-
parentId: f.parent_id,
|
|
1500
|
-
isUpdated: f.isUpdated,
|
|
1501
|
-
}));
|
|
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));
|
|
1502
1244
|
}
|
|
1503
|
-
|
|
1504
|
-
.then((restParams) => fetch(`api/crowdin/update${restParams}&uploadTranslations=${uploadTranslations}&languages=${languages}&forcePushSources=${forcePushSources}`, {
|
|
1505
|
-
method: 'POST',
|
|
1506
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1507
|
-
body: JSON.stringify(req),
|
|
1508
|
-
}))
|
|
1509
|
-
.then(checkResponse)
|
|
1510
|
-
.then((res) => {
|
|
1511
|
-
checkJob({
|
|
1512
|
-
jobId: res === null || res === void 0 ? void 0 : res.jobId,
|
|
1513
|
-
jobType: JOB_TYPE.updateCrowdin,
|
|
1514
|
-
});
|
|
1515
|
-
})
|
|
1516
|
-
.catch((e) => catchRejection(e, "Can't upload templates to Crowdin"));
|
|
1517
|
-
}
|
|
1518
|
-
function getActiveJobs() {
|
|
1519
|
-
checkOrigin()
|
|
1520
|
-
.then((restParams) => fetch(`api/jobs${restParams}`))
|
|
1521
|
-
.then(checkResponse)
|
|
1522
|
-
.then((jobs) => {
|
|
1523
|
-
if (!Array.isArray(jobs)) {
|
|
1524
|
-
return;
|
|
1525
|
-
}
|
|
1526
|
-
jobs.forEach((job) => {
|
|
1527
|
-
switch (job.type) {
|
|
1528
|
-
case JOB_TYPE.updateCrowdin:
|
|
1529
|
-
case JOB_TYPE.updateTargetLanguages:
|
|
1530
|
-
appComponent.current.setAttribute('is-to-crowdin-process', true);
|
|
1531
|
-
break;
|
|
1532
|
-
case JOB_TYPE.updateIntegration:
|
|
1533
|
-
appComponent.current.setAttribute('is-to-integration-process', true);
|
|
1534
|
-
break;
|
|
1535
|
-
case JOB_TYPE.crowdinSyncSettingsSave:
|
|
1536
|
-
appComponent.current.setAttribute('is-crowdin-sync-settings-in-progress', true);
|
|
1537
|
-
break;
|
|
1538
|
-
case JOB_TYPE.integrationSyncSettingsSave:
|
|
1539
|
-
appComponent.current.setAttribute('is-integration-sync-settings-in-progress', true);
|
|
1540
|
-
break;
|
|
1541
|
-
}
|
|
1542
|
-
checkJob({
|
|
1543
|
-
jobId: job.id,
|
|
1544
|
-
jobType: job.type,
|
|
1545
|
-
});
|
|
1546
|
-
});
|
|
1547
|
-
})
|
|
1548
|
-
.catch((e) => catchRejection(e, 'Sync status check failed'));
|
|
1245
|
+
return found !== undefined;
|
|
1549
1246
|
}
|
|
1550
|
-
function
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
method: 'DELETE',
|
|
1558
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1559
|
-
}))
|
|
1560
|
-
.then(checkResponse)
|
|
1561
|
-
.then(() => showToast('Cancellation…'))
|
|
1562
|
-
.catch((e) => catchRejection(e, 'Sync cancellation failed'));
|
|
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
|
+
: [];
|
|
1563
1254
|
}
|
|
1564
|
-
function
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
if (!onFinally) {
|
|
1577
|
-
onFinally = () => appComponent.current.setAttribute('is-to-integration-process', false);
|
|
1578
|
-
}
|
|
1579
|
-
break;
|
|
1580
|
-
case JOB_TYPE.crowdinSyncSettingsSave:
|
|
1581
|
-
if (!onFinally) {
|
|
1582
|
-
onFinally = () => appComponent.current.setAttribute('is-crowdin-sync-settings-in-progress', false);
|
|
1583
|
-
}
|
|
1584
|
-
break;
|
|
1585
|
-
case JOB_TYPE.integrationSyncSettingsSave:
|
|
1586
|
-
if (!onFinally) {
|
|
1587
|
-
onFinally = () => appComponent.current.setAttribute('is-integration-sync-settings-in-progress', false);
|
|
1588
|
-
}
|
|
1589
|
-
break;
|
|
1590
|
-
}
|
|
1591
|
-
checkOrigin()
|
|
1592
|
-
.then((restParams) => fetch('api/jobs' + restParams + '&jobId=' + jobId))
|
|
1593
|
-
.then(checkResponse)
|
|
1594
|
-
.then((job) => {
|
|
1595
|
-
const isFailed = [JOB_STATUS.failed, JOB_STATUS.canceled].includes(job.status);
|
|
1596
|
-
const progress = isFailed || JOB_STATUS.finished === job.status ? 100 : job.progress;
|
|
1597
|
-
const info = JOB_STATUS.canceled === job.status ? `Cancelled\n${job.info || ''}` : job.info;
|
|
1598
|
-
if (!silentJobs.find((type) => type === jobType)) {
|
|
1599
|
-
pushJobs([
|
|
1600
|
-
{
|
|
1601
|
-
id: job.id,
|
|
1602
|
-
title: job.title,
|
|
1603
|
-
progress,
|
|
1604
|
-
info,
|
|
1605
|
-
isFailed,
|
|
1606
|
-
},
|
|
1607
|
-
]);
|
|
1608
|
-
}
|
|
1609
|
-
if (isFailed) {
|
|
1610
|
-
if (onError) {
|
|
1611
|
-
onError();
|
|
1612
|
-
}
|
|
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';
|
|
1613
1267
|
}
|
|
1614
|
-
else if (
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
}, asyncProgress.checkInterval);
|
|
1618
|
-
return;
|
|
1268
|
+
else if (!found && newFileStatus === 'checked') {
|
|
1269
|
+
newFileStatus = 'clear-selection';
|
|
1270
|
+
break;
|
|
1619
1271
|
}
|
|
1620
1272
|
else {
|
|
1621
|
-
|
|
1622
|
-
onSuccess(job);
|
|
1623
|
-
}
|
|
1624
|
-
}
|
|
1625
|
-
if (onFinally) {
|
|
1626
|
-
onFinally(job);
|
|
1627
|
-
}
|
|
1628
|
-
})
|
|
1629
|
-
.catch((e) => {
|
|
1630
|
-
if (onFinally) {
|
|
1631
|
-
onFinally();
|
|
1632
|
-
}
|
|
1633
|
-
if (!silentJobs.find((type) => type === jobType)) {
|
|
1634
|
-
pushJobs([
|
|
1635
|
-
{
|
|
1636
|
-
id: jobId,
|
|
1637
|
-
isFailed: true,
|
|
1638
|
-
},
|
|
1639
|
-
]);
|
|
1273
|
+
newFileStatus = 'unChecked';
|
|
1640
1274
|
}
|
|
1641
|
-
showToast('Sync status check failed');
|
|
1642
|
-
});
|
|
1643
|
-
}
|
|
1644
|
-
function pushJobs(jobs) {
|
|
1645
|
-
const el = asyncProgressRef.current;
|
|
1646
|
-
if (el && el.pushJobs) {
|
|
1647
|
-
el.pushJobs(jobs);
|
|
1648
|
-
jobs.forEach((job) => (asyncJobs.current[job.id] = job));
|
|
1649
|
-
}
|
|
1650
|
-
else {
|
|
1651
|
-
setTimeout(() => {
|
|
1652
|
-
pushJobs(jobs);
|
|
1653
|
-
}, 300);
|
|
1654
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);
|
|
1655
1287
|
}
|
|
1656
|
-
function
|
|
1657
|
-
var _a, _b, _c
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
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);
|
|
1668
1318
|
}
|
|
1669
|
-
else if (
|
|
1670
|
-
|
|
1671
|
-
|
|
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
|
+
}
|
|
1672
1343
|
}
|
|
1673
|
-
|
|
1674
|
-
|
|
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');
|
|
1675
1350
|
return;
|
|
1676
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
|
+
}
|
|
1677
1368
|
else {
|
|
1678
|
-
|
|
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();
|
|
1679
1376
|
}
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
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
|
+
}
|
|
1683
1391
|
}
|
|
1684
|
-
appComponent.current.setAttribute('is-to-integration-process', true);
|
|
1685
|
-
const req = {};
|
|
1686
|
-
Object.keys(files)
|
|
1687
|
-
.filter((id) => crowdinData.current.find((c) => c.id === id).node_type === fileType)
|
|
1688
|
-
.forEach((id) => (req[id] = files[id]));
|
|
1689
|
-
checkOrigin()
|
|
1690
|
-
.then((restParams) => fetch(`api/integration/update${restParams}&forcePushTranslations=${forcePushTranslations}`, {
|
|
1691
|
-
method: 'POST',
|
|
1692
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1693
|
-
body: JSON.stringify(req),
|
|
1694
|
-
}))
|
|
1695
|
-
.then(checkResponse)
|
|
1696
|
-
.then((res) => {
|
|
1697
|
-
checkJob({
|
|
1698
|
-
jobId: res === null || res === void 0 ? void 0 : res.jobId,
|
|
1699
|
-
jobType: JOB_TYPE.updateIntegration,
|
|
1700
|
-
});
|
|
1701
|
-
})
|
|
1702
|
-
.catch((e) => catchRejection(e, `Can't upload files to ${name}`));
|
|
1703
1392
|
}
|
|
1704
|
-
function
|
|
1705
|
-
|
|
1706
|
-
|
|
1393
|
+
async function setCrowdinScheduleSync(e) {
|
|
1394
|
+
var _a;
|
|
1395
|
+
if (e.detail.length === 0) {
|
|
1396
|
+
showToast('Select templates which will be pushed to Crowdin');
|
|
1707
1397
|
return;
|
|
1708
1398
|
}
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
.
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
.
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
.catch((e) => catchRejection(e, "Can't sync files to Crowdin"));
|
|
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');
|
|
1728
1417
|
}
|
|
1729
|
-
function
|
|
1730
|
-
if (
|
|
1731
|
-
showToast('Select
|
|
1418
|
+
async function disableIntegrationSync(e) {
|
|
1419
|
+
if (e.detail.length === 0) {
|
|
1420
|
+
showToast('Select templates which will be pushed to Crowdin');
|
|
1732
1421
|
return;
|
|
1733
1422
|
}
|
|
1734
|
-
appComponent.current.setAttribute('is-
|
|
1735
|
-
const
|
|
1736
|
-
|
|
1737
|
-
.
|
|
1738
|
-
|
|
1739
|
-
id: f.id,
|
|
1740
|
-
type: f.type,
|
|
1741
|
-
parentId: f.parent_id,
|
|
1742
|
-
}));
|
|
1743
|
-
checkOrigin()
|
|
1744
|
-
.then((restParams) => fetch(`api/integration/update${restParams}&matchFromIntegration=true`, {
|
|
1745
|
-
method: 'POST',
|
|
1746
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1747
|
-
body: JSON.stringify(req),
|
|
1748
|
-
}))
|
|
1749
|
-
.then(checkResponse)
|
|
1750
|
-
.then((res) => {
|
|
1751
|
-
checkJob({
|
|
1752
|
-
jobId: res === null || res === void 0 ? void 0 : res.jobId,
|
|
1753
|
-
jobType: JOB_TYPE.updateIntegration,
|
|
1754
|
-
});
|
|
1755
|
-
})
|
|
1756
|
-
.catch((e) => catchRejection(e, `Can't sync translations to ${name}`));
|
|
1757
|
-
}
|
|
1758
|
-
function openLanguageModal() {
|
|
1759
|
-
setLanguageModalState((state) => {
|
|
1760
|
-
var _a, _b;
|
|
1761
|
-
return ({
|
|
1762
|
-
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 : [],
|
|
1763
|
-
action: 'syncToCrowdin',
|
|
1764
|
-
});
|
|
1765
|
-
});
|
|
1766
|
-
openModal(languageModal.current);
|
|
1767
|
-
}
|
|
1768
|
-
function openLanguageModalForCrowdinFiles() {
|
|
1769
|
-
setLanguageModalState((state) => {
|
|
1770
|
-
var _a, _b;
|
|
1771
|
-
return ({
|
|
1772
|
-
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 : [],
|
|
1773
|
-
action: 'updateCrowdinTargetLanguages',
|
|
1774
|
-
});
|
|
1775
|
-
});
|
|
1776
|
-
openModal(languageModal.current);
|
|
1777
|
-
}
|
|
1778
|
-
async function uploadFilesToCrowdinWithExcludedLanguages() {
|
|
1779
|
-
const selectedLanguages = await languageSelectRef.current.getValue();
|
|
1780
|
-
closeModal(languageModal.current);
|
|
1781
|
-
uploadFilesToCrowdin({ detail: fileToSync.current }, selectedLanguages);
|
|
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');
|
|
1782
1428
|
}
|
|
1783
|
-
async function
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
const fileIds = Object.keys(crowdinFilesToUpdateTargetLanguages.current).map((id) => parseInt(id, 10));
|
|
1787
|
-
if (fileIds.length === 0) {
|
|
1788
|
-
showToast('Select files to update');
|
|
1429
|
+
async function disableCrowdinSync(e) {
|
|
1430
|
+
if (e.detail.length === 0) {
|
|
1431
|
+
showToast('Select templates which will be pushed to Crowdin');
|
|
1789
1432
|
return;
|
|
1790
1433
|
}
|
|
1791
|
-
appComponent.current.setAttribute('is-
|
|
1792
|
-
|
|
1793
|
-
.
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
body: JSON.stringify({ fileIds, languages: selectedLanguages }),
|
|
1797
|
-
}))
|
|
1798
|
-
.then(checkResponse)
|
|
1799
|
-
.then((res) => {
|
|
1800
|
-
checkJob({
|
|
1801
|
-
jobId: res === null || res === void 0 ? void 0 : res.jobId,
|
|
1802
|
-
jobType: JOB_TYPE.updateTargetLanguages,
|
|
1803
|
-
});
|
|
1804
|
-
})
|
|
1805
|
-
.catch((e) => catchRejection(e, "Can't update files target languages"));
|
|
1806
|
-
}
|
|
1807
|
-
function setLanguagesForTranslation(languages, action = 'syncToCrowdin') {
|
|
1808
|
-
setLanguageModalState({ languages, action });
|
|
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');
|
|
1809
1439
|
}
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
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);
|
|
1814
1460
|
}
|
|
1815
|
-
function
|
|
1816
|
-
if (
|
|
1817
|
-
return
|
|
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];
|
|
1818
1474
|
}
|
|
1819
|
-
const ownerFullName = user.name || ((user.first_name || '') + ' ' + (user.last_name || '')).trim();
|
|
1820
|
-
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;
|
|
1821
1475
|
}
|
|
1822
|
-
function
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
});
|
|
1835
|
-
}),
|
|
1836
|
-
new Promise((resolve) => {
|
|
1837
|
-
AP.getUsers((res) => {
|
|
1838
|
-
const users = Object.values(res).filter((user) => user.id !== Number(userId));
|
|
1839
|
-
resolve(users);
|
|
1840
|
-
});
|
|
1841
|
-
}),
|
|
1842
|
-
])
|
|
1843
|
-
.then(([managers, users]) => {
|
|
1844
|
-
const parsedManagers = (JSON.parse(managers) || []);
|
|
1845
|
-
const availableUsers = users;
|
|
1846
|
-
const validUserIds = new Set(availableUsers.map((user) => `${user.id}`));
|
|
1847
|
-
const filteredManagers = parsedManagers.filter((id) => validUserIds.has(id));
|
|
1848
|
-
setPermissionUserOptions(availableUsers.map((user) => ({
|
|
1849
|
-
id: String(user.id),
|
|
1850
|
-
label: getUserFullName(user),
|
|
1851
|
-
})));
|
|
1852
|
-
setPermissionsSelectedValue(JSON.stringify(filteredManagers));
|
|
1853
|
-
})
|
|
1854
|
-
.catch((e) => catchRejection(e, "Can't fetch users"))
|
|
1855
|
-
.finally(() => unsetLoader('#permissions-modal'));
|
|
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
|
+
};
|
|
1856
1488
|
}
|
|
1857
|
-
function
|
|
1858
|
-
var _a;
|
|
1859
|
-
|
|
1860
|
-
(_a =
|
|
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');
|
|
1861
1494
|
}
|
|
1862
|
-
function
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
.
|
|
1879
|
-
.
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
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
|
+
},
|
|
1886
1584
|
});
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
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
|
+
}
|
|
1891
1600
|
});
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
const newUserEmails = checkUsersResponse.newUserEmails.map((email) => ({ name: email }));
|
|
1896
|
-
const newProjectManagers = [
|
|
1897
|
-
...newUserEmails,
|
|
1898
|
-
...checkUsersResponse.newProjectManagers.map((user) => ({
|
|
1899
|
-
name: getUserFullName(user),
|
|
1900
|
-
})),
|
|
1901
|
-
];
|
|
1902
|
-
const newApplicationAccessUsers = [
|
|
1903
|
-
...newUserEmails,
|
|
1904
|
-
...checkUsersResponse.newApplicationAccessUsers.map((user) => ({
|
|
1905
|
-
name: getUserFullName(user),
|
|
1906
|
-
})),
|
|
1907
|
-
];
|
|
1908
|
-
const newApplicationManagers = [
|
|
1909
|
-
...newUserEmails,
|
|
1910
|
-
...Object.values(allUsers)
|
|
1911
|
-
.filter((user) => users.some((id) => +id === user.id) && !appManagers.some((id) => +id === user.id))
|
|
1912
|
-
.map((user) => ({ name: getUserFullName(user) })),
|
|
1913
|
-
];
|
|
1914
|
-
prepareUsersConfirmBlock({
|
|
1915
|
-
...checkUsersResponse,
|
|
1916
|
-
newUserEmails,
|
|
1917
|
-
newProjectManagers,
|
|
1918
|
-
newApplicationAccessUsers,
|
|
1919
|
-
newApplicationManagers,
|
|
1920
|
-
});
|
|
1921
|
-
})
|
|
1922
|
-
.catch((e) => catchRejection(e, (e === null || e === void 0 ? void 0 : e.error) || "Can't invite users"))
|
|
1923
|
-
.finally(() => unsetLoader('#permissions-modal'));
|
|
1924
|
-
}
|
|
1925
|
-
function inviteUsers() {
|
|
1926
|
-
setLoader('#permissions-modal');
|
|
1927
|
-
const select = usersSelectRef.current;
|
|
1928
|
-
const users = JSON.parse(select.value);
|
|
1929
|
-
const user_ids = users.filter((id) => parseInt(id));
|
|
1930
|
-
const emails = users.filter((id) => !parseInt(id));
|
|
1931
|
-
const params = { user_ids, emails };
|
|
1932
|
-
AP.inviteUsers(params, (res) => {
|
|
1933
|
-
var _a;
|
|
1934
|
-
if (!res.success) {
|
|
1935
|
-
catchRejection(res, ((_a = res === null || res === void 0 ? void 0 : res.error) === null || _a === void 0 ? void 0 : _a.message) || "Can't invite users");
|
|
1936
|
-
unsetLoader('#permissions-modal');
|
|
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);
|
|
1937
1604
|
return;
|
|
1938
1605
|
}
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
}
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
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();
|
|
1950
1619
|
}
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
closeModal(permissionsModalRef.current);
|
|
1954
|
-
})
|
|
1955
|
-
.catch((e) => catchRejection(e, (e === null || e === void 0 ? void 0 : e.error) || "Can't invite users"))
|
|
1956
|
-
.finally(() => unsetLoader('#permissions-modal'));
|
|
1957
|
-
});
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1958
1622
|
}
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1623
|
+
return {
|
|
1624
|
+
isLoading,
|
|
1625
|
+
isSettingsSaveDisabled,
|
|
1626
|
+
fillSettingsForm,
|
|
1627
|
+
saveSettings,
|
|
1628
|
+
registerSettingsField,
|
|
1629
|
+
settingsFieldChange,
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
/// <reference path="../../../../ui/types.d.ts" />
|
|
1634
|
+
function useSyncOperations({ appComponent, asyncProgressRef, config, name, integrationOneLevelFetching, integrationSearchListener, integrationPagination, withCronSync, webhooks, progressiveCrowdinFilesLoading, asyncProgress, syncNewElements, }) {
|
|
1635
|
+
const crowdinFilesToUpdateTargetLanguages = reactExports.useRef([]);
|
|
1636
|
+
const asyncJobs = reactExports.useRef({});
|
|
1637
|
+
const project = reactExports.useRef({});
|
|
1638
|
+
const crowdinData = reactExports.useRef([]);
|
|
1639
|
+
const fileToSync = reactExports.useRef([]);
|
|
1640
|
+
const hasLoadMoreElements = reactExports.useRef(false);
|
|
1641
|
+
const savedIntegrationData = reactExports.useRef(null);
|
|
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]);
|
|
1654
|
+
reactExports.useEffect(() => {
|
|
1655
|
+
const listeners = {
|
|
1656
|
+
refreshFilesList: (e) => {
|
|
1657
|
+
if (e.detail.refreshIntegration) {
|
|
1658
|
+
getIntegrationData({ hardReload: true });
|
|
1659
|
+
}
|
|
1660
|
+
else if (e.detail.refreshCrowdin) {
|
|
1661
|
+
getCrowdinData();
|
|
1979
1662
|
}
|
|
1980
|
-
: {}),
|
|
1981
|
-
project: {
|
|
1982
|
-
status: usersData.newProjectManagers.length ? 'willBeGranted' : 'granted',
|
|
1983
|
-
users: toNames(usersData.newProjectManagers),
|
|
1984
1663
|
},
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
? applicationSettingsDescription
|
|
1995
|
-
: `${applicationSettingsDescription} Only organization admins have permission to update this setting.`
|
|
1996
|
-
: applicationSettingsDescription,
|
|
1997
|
-
isWarning: hasApplicationAccessUsers && !usersData.isAdmin,
|
|
1664
|
+
crowdinFilesFolderToggled: (event) => {
|
|
1665
|
+
if (event.detail.componentId === 'crowdin-files' && event.detail.isOpen && event.detail.type === '1') {
|
|
1666
|
+
getFileProgress(event.detail.id);
|
|
1667
|
+
}
|
|
1668
|
+
if (integrationOneLevelFetching) {
|
|
1669
|
+
if (event.detail.componentId === 'integration-files' && event.detail.isOpen) {
|
|
1670
|
+
getIntegrationData({ parentId: event.detail.id, recursion: event.detail.recursion });
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1998
1673
|
},
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
1674
|
+
uploadFilesToCrowdin: uploadFilesToCrowdin,
|
|
1675
|
+
uploadFilesToIntegration: uploadFilesToIntegration,
|
|
1676
|
+
cancelAsyncAction: (e) => {
|
|
1677
|
+
cancelJob(e.detail);
|
|
2002
1678
|
},
|
|
2003
|
-
|
|
1679
|
+
loadMoreClick: async (e) => {
|
|
1680
|
+
var _a;
|
|
1681
|
+
const loadMoreFile = e.detail;
|
|
1682
|
+
const fileComponent = (_a = appComponent.current) === null || _a === void 0 ? void 0 : _a.querySelector('#integration-files');
|
|
1683
|
+
if (!fileComponent) {
|
|
1684
|
+
return;
|
|
1685
|
+
}
|
|
1686
|
+
await fileComponent.setLoadMoreLoading(loadMoreFile.id, true);
|
|
1687
|
+
try {
|
|
1688
|
+
await getIntegrationData({ parentId: e.detail.parent_id, paginationData: e.detail.pagination });
|
|
1689
|
+
}
|
|
1690
|
+
finally {
|
|
1691
|
+
await fileComponent.setLoadMoreLoading(loadMoreFile.id, false);
|
|
1692
|
+
}
|
|
1693
|
+
},
|
|
1694
|
+
};
|
|
1695
|
+
if (integrationSearchListener) {
|
|
1696
|
+
listeners['integrationFilterChange'] = async (event) => {
|
|
1697
|
+
const isEmptySearch = !event.detail || event.detail.trim() === '';
|
|
1698
|
+
if (isEmptySearch && savedIntegrationData.current && hasLoadMoreElements.current) {
|
|
1699
|
+
appComponent.current.setIntegrationFilesData(savedIntegrationData.current);
|
|
1700
|
+
appComponent.current.setIntegrationOpenedFolders(currentOpenedFolders.current);
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1703
|
+
if (!isEmptySearch && hasLoadMoreElements.current) {
|
|
1704
|
+
savedIntegrationData.current = await appComponent.current.getIntegrationFilesData();
|
|
1705
|
+
currentOpenedFolders.current = await appComponent.current.getIntegrationOpenedFolders();
|
|
1706
|
+
}
|
|
1707
|
+
getIntegrationData({ search: event.detail });
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
if (integrationPagination) {
|
|
1711
|
+
listeners['fileListEnd'] = (e) => {
|
|
1712
|
+
getIntegrationData({ page: e.detail.page });
|
|
1713
|
+
};
|
|
1714
|
+
}
|
|
1715
|
+
for (const [event, handler] of Object.entries(listeners)) {
|
|
1716
|
+
document.body.addEventListener(event, handler);
|
|
1717
|
+
}
|
|
1718
|
+
getCrowdinData();
|
|
1719
|
+
getIntegrationData({});
|
|
1720
|
+
getActiveJobs();
|
|
1721
|
+
return () => {
|
|
1722
|
+
for (const [event, handler] of Object.entries(listeners)) {
|
|
1723
|
+
document.body.removeEventListener(event, handler);
|
|
1724
|
+
}
|
|
1725
|
+
};
|
|
1726
|
+
}, []);
|
|
1727
|
+
function transformCrowdinItemToTree(e) {
|
|
1728
|
+
const item = {
|
|
1729
|
+
parent_id: e.parentId ? e.parentId : '0',
|
|
1730
|
+
name: e.name,
|
|
1731
|
+
id: e.id,
|
|
1732
|
+
customContent: e.customContent,
|
|
1733
|
+
labels: e.labels,
|
|
1734
|
+
disabled: e.disabled,
|
|
1735
|
+
tooltip: e.tooltip,
|
|
1736
|
+
};
|
|
1737
|
+
if (e.type) {
|
|
1738
|
+
item.type = e.type;
|
|
1739
|
+
item.node_type = FILE_TYPE;
|
|
1740
|
+
item.failed = e.failed;
|
|
1741
|
+
item.excludedTargetLanguages = e.excludedTargetLanguages;
|
|
1742
|
+
}
|
|
1743
|
+
else {
|
|
1744
|
+
item.node_type = e.nodeType || FOLDER_TYPE;
|
|
1745
|
+
}
|
|
1746
|
+
return item;
|
|
1747
|
+
}
|
|
1748
|
+
async function getCrowdinData() {
|
|
1749
|
+
var _a, _b, _c, _d, _f;
|
|
1750
|
+
(_a = appComponent.current) === null || _a === void 0 ? void 0 : _a.setAttribute('is-crowdin-loading', 'true');
|
|
1751
|
+
try {
|
|
1752
|
+
const restParams = await checkOrigin();
|
|
1753
|
+
if (progressiveCrowdinFilesLoading) {
|
|
1754
|
+
const dirPromise = fetch('api/crowdin/files' + restParams + '&mode=directories')
|
|
1755
|
+
.then(checkResponse)
|
|
1756
|
+
.then((directories) => {
|
|
1757
|
+
var _a;
|
|
1758
|
+
const dirTree = directories.map(transformCrowdinItemToTree);
|
|
1759
|
+
crowdinData.current = dirTree;
|
|
1760
|
+
(_a = appComponent.current) === null || _a === void 0 ? void 0 : _a.setCrowdinFilesData(dirTree);
|
|
1761
|
+
return dirTree;
|
|
1762
|
+
});
|
|
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
|
+
]);
|
|
1768
|
+
const fileTree = files.map(transformCrowdinItemToTree);
|
|
1769
|
+
crowdinData.current = [...dirTree, ...fileTree];
|
|
1770
|
+
(_b = appComponent.current) === null || _b === void 0 ? void 0 : _b.setCrowdinFilesData(crowdinData.current);
|
|
1771
|
+
project.current = projectData;
|
|
1772
|
+
const languagesSorted = project.current.targetLanguages
|
|
1773
|
+
.map((language) => ({
|
|
1774
|
+
sourceLanguageId: projectData.sourceLanguage.editorCode,
|
|
1775
|
+
projectEditorLink: projectData.projectEditorLink,
|
|
1776
|
+
...language,
|
|
1777
|
+
}))
|
|
1778
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
1779
|
+
if (project.current.inContext && ((_c = config.current) === null || _c === void 0 ? void 0 : _c.inContext)) {
|
|
1780
|
+
languagesSorted.push({ ...project.current.inContextPseudoLanguage, inContext: true });
|
|
1781
|
+
}
|
|
1782
|
+
setLanguagesForTranslation(languagesSorted);
|
|
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
|
+
]);
|
|
1790
|
+
const tree = files.map(transformCrowdinItemToTree);
|
|
1791
|
+
crowdinData.current = tree;
|
|
1792
|
+
appComponent.current.setCrowdinFilesData(tree);
|
|
1793
|
+
project.current = projectData;
|
|
1794
|
+
const languagesSorted = project.current.targetLanguages
|
|
1795
|
+
.map((language) => ({
|
|
1796
|
+
sourceLanguageId: projectData.sourceLanguage.editorCode,
|
|
1797
|
+
projectEditorLink: projectData.projectEditorLink,
|
|
1798
|
+
...language,
|
|
1799
|
+
}))
|
|
1800
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
1801
|
+
if (project.current.inContext && ((_f = config.current) === null || _f === void 0 ? void 0 : _f.inContext)) {
|
|
1802
|
+
languagesSorted.push({ ...project.current.inContextPseudoLanguage, inContext: true });
|
|
1803
|
+
}
|
|
1804
|
+
setLanguagesForTranslation(languagesSorted);
|
|
1805
|
+
appComponent.current.setCrowdinLanguagesData(languagesSorted);
|
|
1806
|
+
}
|
|
1807
|
+
if (withCronSync || webhooks) {
|
|
1808
|
+
await getSyncSettings('crowdin');
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
catch (e) {
|
|
1812
|
+
catchRejection(e, "Can't fetch Crowdin data");
|
|
1813
|
+
}
|
|
1814
|
+
finally {
|
|
1815
|
+
appComponent.current.setAttribute('is-crowdin-loading', false);
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
async function getIntegrationData({ hardReload = false, parentId = '', search = '', page = 0, recursion = false, paginationData } = {}, recursionState = null) {
|
|
1819
|
+
if (!paginationData) {
|
|
1820
|
+
appComponent.current.setAttribute('is-integration-loading', true);
|
|
1821
|
+
}
|
|
1822
|
+
let recursionStateLocal = recursionState;
|
|
1823
|
+
try {
|
|
1824
|
+
const restParams = await checkOrigin();
|
|
1825
|
+
let url = `api/integration/data${restParams}&parent_id=${encodeURIComponent(parentId)}&search=${encodeURIComponent(search)}&page=${page}`;
|
|
1826
|
+
if (paginationData) {
|
|
1827
|
+
url += `&paginationData=${encodeURIComponent(JSON.stringify(paginationData))}`;
|
|
1828
|
+
}
|
|
1829
|
+
const res = await checkResponse(await fetch(url));
|
|
1830
|
+
const files = res.data;
|
|
1831
|
+
const stopPagination = res.stopPagination;
|
|
1832
|
+
const tree = files.map((e) => {
|
|
1833
|
+
const item = {
|
|
1834
|
+
parent_id: e.parentId ? e.parentId : '0',
|
|
1835
|
+
name: e.name,
|
|
1836
|
+
id: e.id,
|
|
1837
|
+
customContent: e.customContent,
|
|
1838
|
+
labels: e.labels,
|
|
1839
|
+
disabled: e.disabled,
|
|
1840
|
+
tooltip: e.tooltip,
|
|
1841
|
+
pagination: e.pagination,
|
|
1842
|
+
};
|
|
1843
|
+
if (e.type) {
|
|
1844
|
+
item.isNew = e.isNew;
|
|
1845
|
+
item.isUpdated = e.isUpdated;
|
|
1846
|
+
item.notSynced = e.notSynced;
|
|
1847
|
+
item.synced = e.synced;
|
|
1848
|
+
item.type = e.type;
|
|
1849
|
+
item.node_type = FILE_TYPE;
|
|
1850
|
+
}
|
|
1851
|
+
else {
|
|
1852
|
+
item.node_type = e.nodeType || FOLDER_TYPE;
|
|
1853
|
+
}
|
|
1854
|
+
return item;
|
|
1855
|
+
});
|
|
1856
|
+
if ((!paginationData && !parentId && !search) || hardReload) {
|
|
1857
|
+
hasLoadMoreElements.current = tree.some((item) => item.node_type === 'load-more');
|
|
1858
|
+
}
|
|
1859
|
+
const appIntegrationFiles = appComponent.current.querySelector('#integration-files');
|
|
1860
|
+
if (hardReload) {
|
|
1861
|
+
appComponent.current.setIntegrationFilesData(tree);
|
|
1862
|
+
}
|
|
1863
|
+
else if (tree.length) {
|
|
1864
|
+
appComponent.current.pushIntegrationFilesData(tree).then(async () => {
|
|
1865
|
+
if (parentId) {
|
|
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
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1877
|
+
if (integrationPagination) {
|
|
1878
|
+
if (stopPagination) {
|
|
1879
|
+
appIntegrationFiles.setAttribute('load-more-disabled', true);
|
|
1880
|
+
}
|
|
1881
|
+
else {
|
|
1882
|
+
appIntegrationFiles.setAttribute('load-more-disabled', false);
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
if (search) {
|
|
1886
|
+
const openIds = files.filter((e) => !e.type).map((e) => e.id);
|
|
1887
|
+
appComponent.current.setIntegrationOpenedFolders(openIds);
|
|
1888
|
+
}
|
|
1889
|
+
if (recursion) {
|
|
1890
|
+
if (!recursionStateLocal) {
|
|
1891
|
+
recursionStateLocal = {
|
|
1892
|
+
openedFolders: new Set(),
|
|
1893
|
+
calls: 0,
|
|
1894
|
+
setLoading(isLoading) {
|
|
1895
|
+
appComponent.current.setAttribute('is-integration-loading', isLoading);
|
|
1896
|
+
},
|
|
1897
|
+
};
|
|
1898
|
+
recursionStateLocal.setLoading(true);
|
|
1899
|
+
}
|
|
1900
|
+
if (parentId) {
|
|
1901
|
+
recursionStateLocal.openedFolders.add(parentId);
|
|
1902
|
+
}
|
|
1903
|
+
const folderItems = files.filter(isFolder);
|
|
1904
|
+
if (folderItems.length === 0) {
|
|
1905
|
+
return;
|
|
1906
|
+
}
|
|
1907
|
+
folderItems.forEach((folder) => recursionStateLocal.openedFolders.add(folder.id));
|
|
1908
|
+
const openedFoldersNow = await appComponent.current.getIntegrationOpenedFolders();
|
|
1909
|
+
appComponent.current.setIntegrationOpenedFolders([
|
|
1910
|
+
...openedFoldersNow,
|
|
1911
|
+
...recursionStateLocal.openedFolders,
|
|
1912
|
+
]);
|
|
1913
|
+
await Promise.all(folderItems.map(async (folder) => {
|
|
1914
|
+
recursionStateLocal.calls++;
|
|
1915
|
+
try {
|
|
1916
|
+
await getIntegrationData({ parentId: folder.id, recursion: true }, recursionState);
|
|
1917
|
+
}
|
|
1918
|
+
finally {
|
|
1919
|
+
recursionStateLocal.calls--;
|
|
1920
|
+
if (recursionStateLocal.calls === 0) {
|
|
1921
|
+
recursionStateLocal.setLoading(false);
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
}));
|
|
1925
|
+
}
|
|
1926
|
+
if (withCronSync || webhooks) {
|
|
1927
|
+
await getSyncSettings('integration');
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
catch (e) {
|
|
1931
|
+
catchRejection(e, `Can't fetch ${name} templates`);
|
|
1932
|
+
}
|
|
1933
|
+
finally {
|
|
1934
|
+
if (!recursionStateLocal && !recursion) {
|
|
1935
|
+
appComponent.current.setAttribute('is-integration-loading', false);
|
|
1936
|
+
}
|
|
1937
|
+
else if (recursionStateLocal && recursionStateLocal.calls === 0) {
|
|
1938
|
+
appComponent.current.setAttribute('is-integration-loading', false);
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
function isScheduleDisabled(currentConfig = config.current) {
|
|
1943
|
+
var _a;
|
|
1944
|
+
return String((_a = currentConfig === null || currentConfig === void 0 ? void 0 : currentConfig.schedule) !== null && _a !== void 0 ? _a : '0') === '0';
|
|
2004
1945
|
}
|
|
2005
|
-
function
|
|
2006
|
-
|
|
2007
|
-
|
|
1946
|
+
async function applyAutoSyncPausedMarkers(provider, syncSettingsFiles = []) {
|
|
1947
|
+
var _a, _b, _c, _d;
|
|
1948
|
+
const isDisabled = isScheduleDisabled();
|
|
1949
|
+
const configuredIds = new Set((Array.isArray(syncSettingsFiles) ? syncSettingsFiles : []).map((item) => `${item.id}`));
|
|
1950
|
+
const getChangedItems = (tree = []) => tree
|
|
1951
|
+
.map((item) => {
|
|
1952
|
+
const nextScheduleDisabled = Boolean(item.schedule) && isDisabled && configuredIds.has(`${item.id}`);
|
|
1953
|
+
const currentScheduleDisabled = Boolean(item.scheduleDisabled);
|
|
1954
|
+
if (currentScheduleDisabled === nextScheduleDisabled) {
|
|
1955
|
+
return null;
|
|
1956
|
+
}
|
|
1957
|
+
return { ...item, scheduleDisabled: nextScheduleDisabled };
|
|
1958
|
+
})
|
|
1959
|
+
.filter(Boolean);
|
|
1960
|
+
if (provider === 'crowdin') {
|
|
1961
|
+
const changedItems = getChangedItems(crowdinData.current || []);
|
|
1962
|
+
if (changedItems.length) {
|
|
1963
|
+
const changedById = new Map(changedItems.map((item) => [`${item.id}`, item]));
|
|
1964
|
+
crowdinData.current = (crowdinData.current || []).map((item) => changedById.get(`${item.id}`) || item);
|
|
1965
|
+
(_a = appComponent.current) === null || _a === void 0 ? void 0 : _a.updateCrowdinFileData(changedItems);
|
|
1966
|
+
}
|
|
1967
|
+
return;
|
|
1968
|
+
}
|
|
1969
|
+
const integrationData = await ((_c = (_b = appComponent.current) === null || _b === void 0 ? void 0 : _b.getIntegrationFilesData) === null || _c === void 0 ? void 0 : _c.call(_b));
|
|
1970
|
+
if (Array.isArray(integrationData)) {
|
|
1971
|
+
const changedItems = getChangedItems(integrationData);
|
|
1972
|
+
if (changedItems.length) {
|
|
1973
|
+
(_d = appComponent.current) === null || _d === void 0 ? void 0 : _d.updateIntegrationFileData(changedItems);
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
2008
1976
|
}
|
|
2009
|
-
function
|
|
2010
|
-
const
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
}, 500);
|
|
1977
|
+
async function fetchSyncSettingsFiles(provider) {
|
|
1978
|
+
const restParams = await checkOrigin();
|
|
1979
|
+
const res = await fetch(`/api/sync-settings/${provider}` + restParams).then(checkResponse);
|
|
1980
|
+
return Array.isArray(res) ? res : [];
|
|
2014
1981
|
}
|
|
2015
|
-
function
|
|
2016
|
-
const
|
|
2017
|
-
|
|
2018
|
-
|
|
1982
|
+
async function refreshAutoSyncPausedIndicatorsAndWarning() {
|
|
1983
|
+
const [crowdinSyncSettings, integrationSyncSettings] = await Promise.all([
|
|
1984
|
+
fetchSyncSettingsFiles('crowdin'),
|
|
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.');
|
|
1991
|
+
}
|
|
2019
1992
|
}
|
|
2020
|
-
function
|
|
2021
|
-
|
|
2022
|
-
|
|
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);
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
else {
|
|
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);
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
await applyAutoSyncPausedMarkers(provider, res);
|
|
2023
2014
|
}
|
|
2024
|
-
|
|
2025
|
-
|
|
2015
|
+
catch (e) {
|
|
2016
|
+
catchRejection(e, "Can't fetch file progress");
|
|
2026
2017
|
}
|
|
2018
|
+
}
|
|
2019
|
+
async function getFileProgress(fileId) {
|
|
2027
2020
|
try {
|
|
2028
|
-
const
|
|
2029
|
-
|
|
2021
|
+
const restParams = await checkOrigin();
|
|
2022
|
+
const res = await checkResponse(await fetch(`api/crowdin/file-progress/${fileId}` + restParams));
|
|
2023
|
+
appComponent.current.addCrowdinFileProgress(res);
|
|
2030
2024
|
}
|
|
2031
2025
|
catch (e) {
|
|
2032
|
-
|
|
2026
|
+
catchRejection(e, "Can't fetch file progress");
|
|
2033
2027
|
}
|
|
2034
2028
|
}
|
|
2035
|
-
function
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
function syncScheduleCheckbox(checkbox, { checked, hidden = false, clearSelection = false, }) {
|
|
2049
|
-
if (!checkbox) {
|
|
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') {
|
|
2035
|
+
files = event.detail.files;
|
|
2036
|
+
uploadTranslations = true;
|
|
2037
|
+
forcePushSources = true;
|
|
2038
|
+
}
|
|
2039
|
+
else if (((_b = event.detail) === null || _b === void 0 ? void 0 : _b.action) === 'excludedTargetLanguages') {
|
|
2040
|
+
fileToSync.current = event.detail.files;
|
|
2041
|
+
openLanguageModal();
|
|
2050
2042
|
return;
|
|
2051
2043
|
}
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2044
|
+
else if (((_c = event.detail) === null || _c === void 0 ? void 0 : _c.action) === 'forcePushSources') {
|
|
2045
|
+
files = event.detail.files;
|
|
2046
|
+
forcePushSources = true;
|
|
2047
|
+
}
|
|
2048
|
+
else if (((_d = event.detail) === null || _d === void 0 ? void 0 : _d.action) === 'syncTranslationsToIntegration') {
|
|
2049
|
+
syncTranslationsToIntegration(event.detail.files);
|
|
2050
|
+
return;
|
|
2056
2051
|
}
|
|
2057
2052
|
else {
|
|
2058
|
-
|
|
2053
|
+
files = event.detail;
|
|
2059
2054
|
}
|
|
2060
|
-
if (
|
|
2061
|
-
|
|
2055
|
+
if (languages.length > 0) {
|
|
2056
|
+
forcePushSources = true;
|
|
2057
|
+
}
|
|
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');
|
|
2060
|
+
return;
|
|
2061
|
+
}
|
|
2062
|
+
appComponent.current.setAttribute('is-to-crowdin-process', true);
|
|
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
|
+
}));
|
|
2062
2073
|
}
|
|
2063
2074
|
else {
|
|
2064
|
-
|
|
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
|
+
}));
|
|
2084
|
+
}
|
|
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 });
|
|
2093
|
+
}
|
|
2094
|
+
catch (e) {
|
|
2095
|
+
catchRejection(e, "Can't upload templates to Crowdin");
|
|
2065
2096
|
}
|
|
2066
2097
|
}
|
|
2067
|
-
function
|
|
2068
|
-
|
|
2069
|
-
const
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
if (el.hasAttribute('is-multi')) {
|
|
2073
|
-
el.value = JSON.stringify(value);
|
|
2074
|
-
}
|
|
2075
|
-
else {
|
|
2076
|
-
el.value = JSON.stringify([value]);
|
|
2077
|
-
}
|
|
2078
|
-
}
|
|
2079
|
-
else if (el.tagName.toLowerCase() === 'crowdin-checkbox') {
|
|
2080
|
-
el.checked = !!value;
|
|
2081
|
-
}
|
|
2082
|
-
else if (el.tagName.toLowerCase() === 'crowdin-textarea') {
|
|
2083
|
-
el.value = value;
|
|
2084
|
-
el.setValue(value);
|
|
2085
|
-
}
|
|
2086
|
-
else {
|
|
2087
|
-
el.value = value;
|
|
2088
|
-
}
|
|
2089
|
-
triggerEvent(el, 'change');
|
|
2090
|
-
}
|
|
2091
|
-
});
|
|
2092
|
-
setTimeout(refreshDependencies, 100);
|
|
2093
|
-
}
|
|
2094
|
-
function saveSettings() {
|
|
2095
|
-
setLoader('#settings-modal');
|
|
2096
|
-
const configReq = {};
|
|
2097
|
-
configurationFields === null || configurationFields === void 0 ? void 0 : configurationFields.forEach((tab) => {
|
|
2098
|
-
tab.fields.forEach((field) => {
|
|
2099
|
-
if (!field.key) {
|
|
2100
|
-
return;
|
|
2101
|
-
}
|
|
2102
|
-
const el = settingsFieldRefs.current[field.key];
|
|
2103
|
-
if (!el) {
|
|
2104
|
-
return;
|
|
2105
|
-
}
|
|
2106
|
-
const tagName = el.tagName.toLowerCase();
|
|
2107
|
-
if (tagName === 'crowdin-select') {
|
|
2108
|
-
const value = parseCrowdinSelectValue(el.value);
|
|
2109
|
-
configReq[field.key] = el.hasAttribute('is-multi') ? value : value[0];
|
|
2110
|
-
return;
|
|
2111
|
-
}
|
|
2112
|
-
if (tagName === 'crowdin-checkbox') {
|
|
2113
|
-
configReq[field.key] = !!el.checked;
|
|
2114
|
-
return;
|
|
2115
|
-
}
|
|
2116
|
-
configReq[field.key] = el.value;
|
|
2117
|
-
});
|
|
2118
|
-
});
|
|
2119
|
-
let isValidationError = false;
|
|
2120
|
-
let isSettingsSaveJobPending = false;
|
|
2121
|
-
let isSettingsSaveFailed = false;
|
|
2122
|
-
setIsSettingsSaveDisabled(true);
|
|
2123
|
-
checkOrigin()
|
|
2124
|
-
.then((restParams) => fetch('api/settings' + restParams, {
|
|
2125
|
-
method: 'POST',
|
|
2126
|
-
headers: { 'Content-Type': 'application/json' },
|
|
2127
|
-
body: JSON.stringify({ config: configReq }),
|
|
2128
|
-
}))
|
|
2129
|
-
.then(checkResponse)
|
|
2130
|
-
.then((res) => {
|
|
2131
|
-
if (res === null || res === void 0 ? void 0 : res.jobId) {
|
|
2132
|
-
isSettingsSaveJobPending = true;
|
|
2133
|
-
checkJob({
|
|
2134
|
-
jobId: res.jobId,
|
|
2135
|
-
jobType: JOB_TYPE.integrationSettingsSave,
|
|
2136
|
-
onSuccess: () => {
|
|
2137
|
-
showToast('Settings successfully saved');
|
|
2138
|
-
config.current = configReq;
|
|
2139
|
-
refreshAutoSyncPausedIndicatorsAndWarning().catch((e) => catchRejection(e, "Can't fetch sync settings warning"));
|
|
2140
|
-
},
|
|
2141
|
-
onError: () => {
|
|
2142
|
-
isSettingsSaveFailed = true;
|
|
2143
|
-
showToast("Can't save settings");
|
|
2144
|
-
},
|
|
2145
|
-
onFinally: () => {
|
|
2146
|
-
unsetLoader('#settings-modal');
|
|
2147
|
-
setIsSettingsSaveDisabled(false);
|
|
2148
|
-
if (!isValidationError && !isSettingsSaveFailed) {
|
|
2149
|
-
closeModal(settingsModalRef.current);
|
|
2150
|
-
if (reloadOnConfigSave) {
|
|
2151
|
-
getIntegrationData({ hardReload: true });
|
|
2152
|
-
getCrowdinData();
|
|
2153
|
-
}
|
|
2154
|
-
}
|
|
2155
|
-
},
|
|
2156
|
-
});
|
|
2157
|
-
return;
|
|
2158
|
-
}
|
|
2159
|
-
showToast('Settings successfully saved');
|
|
2160
|
-
config.current = configReq;
|
|
2161
|
-
refreshAutoSyncPausedIndicatorsAndWarning().catch((e) => catchRejection(e, "Can't fetch sync settings warning"));
|
|
2162
|
-
})
|
|
2163
|
-
.catch((e) => {
|
|
2164
|
-
var _a, _b, _c, _d;
|
|
2165
|
-
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') {
|
|
2166
|
-
Object.keys((_b = e === null || e === void 0 ? void 0 : e.error) === null || _b === void 0 ? void 0 : _b.details).forEach((key) => {
|
|
2167
|
-
var _a;
|
|
2168
|
-
const el = settingsFieldRefs.current[key];
|
|
2169
|
-
if (el) {
|
|
2170
|
-
el.setAttribute('error', 'true');
|
|
2171
|
-
el.setAttribute('error-text', (_a = e === null || e === void 0 ? void 0 : e.error) === null || _a === void 0 ? void 0 : _a.details[key]);
|
|
2172
|
-
}
|
|
2173
|
-
});
|
|
2174
|
-
isValidationError = true;
|
|
2175
|
-
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");
|
|
2176
|
-
setIsSettingsSaveDisabled(false);
|
|
2177
|
-
return;
|
|
2178
|
-
}
|
|
2179
|
-
catchRejection(e, "Can't save settings");
|
|
2180
|
-
})
|
|
2181
|
-
.finally(() => {
|
|
2182
|
-
if (isSettingsSaveJobPending) {
|
|
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)) {
|
|
2183
2103
|
return;
|
|
2184
2104
|
}
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
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:
|
|
2192
2121
|
}
|
|
2193
|
-
|
|
2194
|
-
|
|
2122
|
+
checkJob({ jobId: job.id, jobType: job.type });
|
|
2123
|
+
});
|
|
2124
|
+
}
|
|
2125
|
+
catch (e) {
|
|
2126
|
+
catchRejection(e, 'Sync status check failed');
|
|
2127
|
+
}
|
|
2195
2128
|
}
|
|
2196
|
-
function
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2129
|
+
async function cancelJob(jobId) {
|
|
2130
|
+
var _a;
|
|
2131
|
+
if ((_a = asyncJobs.current[jobId]) === null || _a === void 0 ? void 0 : _a.isFailed) {
|
|
2132
|
+
return;
|
|
2133
|
+
}
|
|
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…');
|
|
2141
|
+
}
|
|
2142
|
+
catch (e) {
|
|
2143
|
+
catchRejection(e, 'Sync cancellation failed');
|
|
2144
|
+
}
|
|
2207
2145
|
}
|
|
2208
|
-
async function
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
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
|
+
};
|
|
2155
|
+
}
|
|
2156
|
+
break;
|
|
2157
|
+
case JOB_TYPE.updateIntegration:
|
|
2158
|
+
if (!onFinally) {
|
|
2159
|
+
onFinally = () => appComponent.current.setAttribute('is-to-integration-process', false);
|
|
2160
|
+
}
|
|
2161
|
+
break;
|
|
2162
|
+
case JOB_TYPE.crowdinSyncSettingsSave:
|
|
2163
|
+
if (!onFinally) {
|
|
2164
|
+
onFinally = () => appComponent.current.setAttribute('is-crowdin-sync-settings-in-progress', false);
|
|
2165
|
+
}
|
|
2166
|
+
break;
|
|
2167
|
+
case JOB_TYPE.integrationSyncSettingsSave:
|
|
2168
|
+
if (!onFinally) {
|
|
2169
|
+
onFinally = () => appComponent.current.setAttribute('is-integration-sync-settings-in-progress', false);
|
|
2170
|
+
}
|
|
2171
|
+
break;
|
|
2222
2172
|
}
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
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 }]);
|
|
2226
2181
|
}
|
|
2227
|
-
|
|
2228
|
-
|
|
2182
|
+
if (isFailed) {
|
|
2183
|
+
if (onError) {
|
|
2184
|
+
onError();
|
|
2185
|
+
}
|
|
2229
2186
|
}
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
if (integrationOneLevelFetching) {
|
|
2234
|
-
updateSyncSettings(syncedFiles, 'schedule', 'integration', selectedFiles ? getIntegrationFoldersToExpand(syncData.current, syncedFiles) : []);
|
|
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);
|
|
2189
|
+
return;
|
|
2235
2190
|
}
|
|
2236
2191
|
else {
|
|
2237
|
-
if (
|
|
2238
|
-
|
|
2239
|
-
.filter((file) => file.node_type === folderType)
|
|
2240
|
-
.map((file) => ({
|
|
2241
|
-
...file,
|
|
2242
|
-
nodeType: file.node_type,
|
|
2243
|
-
parentId: file.parent_id,
|
|
2244
|
-
}));
|
|
2245
|
-
updateSyncSettings(syncedFiles, 'schedule', 'integration', integrationExpandedFolders);
|
|
2246
|
-
}
|
|
2247
|
-
else {
|
|
2248
|
-
updateSyncSettings(syncedFiles, 'schedule', 'integration');
|
|
2192
|
+
if (onSuccess) {
|
|
2193
|
+
onSuccess(job);
|
|
2249
2194
|
}
|
|
2250
2195
|
}
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
}
|
|
2254
|
-
async function openScheduleModal(type, options = {}) {
|
|
2255
|
-
var _a, _b, _c, _d;
|
|
2256
|
-
const { showAllFolderFiles = false, showNewFiles = true } = options;
|
|
2257
|
-
let newFileStatus = 'unChecked';
|
|
2258
|
-
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 === '0');
|
|
2259
|
-
const integrationFiles = (_c = appComponent.current) === null || _c === void 0 ? void 0 : _c.querySelector('#integration-files');
|
|
2260
|
-
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 === '0');
|
|
2261
|
-
for (let i = 0; i < selectedIntegrationFolders.length; i++) {
|
|
2262
|
-
const selectedElement = selectedIntegrationFolders[i];
|
|
2263
|
-
const found = integrationSyncFolders.some((integrationElement) => integrationElement.id === selectedElement.id);
|
|
2264
|
-
if (found) {
|
|
2265
|
-
newFileStatus = 'checked';
|
|
2196
|
+
if (onFinally) {
|
|
2197
|
+
onFinally(job);
|
|
2266
2198
|
}
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2199
|
+
}
|
|
2200
|
+
catch (_e) {
|
|
2201
|
+
if (onFinally) {
|
|
2202
|
+
onFinally();
|
|
2270
2203
|
}
|
|
2271
|
-
|
|
2272
|
-
|
|
2204
|
+
if (!silentJobs.find((type) => type === jobType)) {
|
|
2205
|
+
pushJobs([{ id: jobId, isFailed: true }]);
|
|
2273
2206
|
}
|
|
2207
|
+
showToast('Sync status check failed');
|
|
2274
2208
|
}
|
|
2275
|
-
setScheduleModalState({
|
|
2276
|
-
type,
|
|
2277
|
-
showAllFolderFiles,
|
|
2278
|
-
showNewFiles,
|
|
2279
|
-
newFiles: showNewFiles && newFileStatus === 'checked',
|
|
2280
|
-
newFilesClearSelection: showNewFiles && newFileStatus === 'clear-selection',
|
|
2281
|
-
selectedFiles: true,
|
|
2282
|
-
allFolderFiles: false,
|
|
2283
|
-
});
|
|
2284
|
-
setIsScheduleSaveDisabled(false);
|
|
2285
|
-
openModal(scheduleModalRef.current);
|
|
2286
|
-
}
|
|
2287
|
-
function onChangeAutoSynchronizationOptions() {
|
|
2288
|
-
var _a, _b, _c;
|
|
2289
|
-
const nextState = {
|
|
2290
|
-
newFiles: scheduleModalState.showNewFiles ? !!((_a = newFilesCheckboxRef.current) === null || _a === void 0 ? void 0 : _a.checked) : false,
|
|
2291
|
-
selectedFiles: !!((_b = selectedFilesCheckboxRef.current) === null || _b === void 0 ? void 0 : _b.checked),
|
|
2292
|
-
allFolderFiles: scheduleModalState.showAllFolderFiles
|
|
2293
|
-
? !!((_c = allFolderFilesCheckboxRef.current) === null || _c === void 0 ? void 0 : _c.checked)
|
|
2294
|
-
: false,
|
|
2295
|
-
};
|
|
2296
|
-
setScheduleModalState((currentState) => ({
|
|
2297
|
-
...currentState,
|
|
2298
|
-
...nextState,
|
|
2299
|
-
newFilesClearSelection: false,
|
|
2300
|
-
}));
|
|
2301
|
-
setIsScheduleSaveDisabled(!nextState.newFiles && !nextState.selectedFiles && !nextState.allFolderFiles);
|
|
2302
2209
|
}
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
if (
|
|
2306
|
-
|
|
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));
|
|
2307
2215
|
}
|
|
2308
2216
|
else {
|
|
2309
|
-
|
|
2310
|
-
const folders = files.filter((file) => file.node_type === folderType || file.node_type === branchType);
|
|
2311
|
-
isFolder = folders.find((folder) => selectedFiles.hasOwnProperty(folder.id));
|
|
2217
|
+
setTimeout(() => pushJobs(jobs), 300);
|
|
2312
2218
|
}
|
|
2313
|
-
return isFolder !== undefined;
|
|
2314
2219
|
}
|
|
2315
|
-
async function
|
|
2316
|
-
var _a;
|
|
2317
|
-
|
|
2318
|
-
|
|
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;
|
|
2227
|
+
}
|
|
2228
|
+
else if (((_b = event.detail) === null || _b === void 0 ? void 0 : _b.action) === 'excludedTargetLanguages') {
|
|
2229
|
+
crowdinFilesToUpdateTargetLanguages.current = event.detail.files;
|
|
2230
|
+
openLanguageModalForCrowdinFiles();
|
|
2319
2231
|
return;
|
|
2320
2232
|
}
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
const showAllFolderFiles = hasLoadMoreElements.current; // показуємо All files якщо є hasLoadMoreElements
|
|
2329
|
-
if (shouldShowModal) {
|
|
2330
|
-
await openScheduleModal('integration', { showNewFiles, showAllFolderFiles });
|
|
2331
|
-
return;
|
|
2332
|
-
}
|
|
2333
|
-
appComponent.current.setIntegrationScheduleSync(e.detail);
|
|
2334
|
-
appComponent.current.setIntegrationFilesHasSyncOption(true);
|
|
2335
|
-
syncedFiles = await appComponent.current.getIntegrationScheduleSync(true);
|
|
2233
|
+
else if (((_c = event.detail) === null || _c === void 0 ? void 0 : _c.action) === 'syncSourcesToCrowdin') {
|
|
2234
|
+
syncToCrowdinFromCrowdinFiles(event.detail.files, false);
|
|
2235
|
+
return;
|
|
2236
|
+
}
|
|
2237
|
+
else if (((_d = event.detail) === null || _d === void 0 ? void 0 : _d.action) === 'syncTranslationsToCrowdin') {
|
|
2238
|
+
syncToCrowdinFromCrowdinFiles(event.detail.files, true);
|
|
2239
|
+
return;
|
|
2336
2240
|
}
|
|
2337
2241
|
else {
|
|
2338
|
-
|
|
2339
|
-
const isFolder = await hasFolder(e.detail);
|
|
2340
|
-
if (hasLoadMoreElements.current && isFolder) {
|
|
2341
|
-
await openScheduleModal('integration', { showNewFiles: false, showAllFolderFiles: true });
|
|
2342
|
-
return;
|
|
2343
|
-
}
|
|
2344
|
-
syncedFiles = await appComponent.current.getIntegrationScheduleSync();
|
|
2242
|
+
files = event.detail;
|
|
2345
2243
|
}
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2244
|
+
if (Object.keys(event.detail).length === 0 || !event.detail) {
|
|
2245
|
+
showToast(`Select files which will be uploaded to ${name}`);
|
|
2246
|
+
return;
|
|
2349
2247
|
}
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
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}`);
|
|
2364
2264
|
}
|
|
2365
2265
|
}
|
|
2366
|
-
async function
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
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');
|
|
2370
2269
|
return;
|
|
2371
2270
|
}
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
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 });
|
|
2284
|
+
}
|
|
2285
|
+
catch (e) {
|
|
2286
|
+
catchRejection(e, "Can't sync files to Crowdin");
|
|
2387
2287
|
}
|
|
2388
|
-
appComponent.current.setAttribute('is-crowdin-sync-settings-in-progress', true);
|
|
2389
|
-
updateSyncSettings(syncedFiles, 'schedule', 'crowdin');
|
|
2390
2288
|
}
|
|
2391
|
-
async function
|
|
2392
|
-
if (
|
|
2393
|
-
showToast('Select
|
|
2289
|
+
async function syncTranslationsToIntegration(files) {
|
|
2290
|
+
if (!files || files.length === 0) {
|
|
2291
|
+
showToast('Select files to sync');
|
|
2394
2292
|
return;
|
|
2395
2293
|
}
|
|
2396
|
-
appComponent.current.setAttribute('is-integration-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
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 });
|
|
2400
2306
|
}
|
|
2401
|
-
|
|
2402
|
-
|
|
2307
|
+
catch (e) {
|
|
2308
|
+
catchRejection(e, `Can't sync translations to ${name}`);
|
|
2403
2309
|
}
|
|
2404
|
-
updateSyncSettings(syncedFiles, 'schedule', 'integration');
|
|
2405
2310
|
}
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
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');
|
|
2409
2342
|
return;
|
|
2410
2343
|
}
|
|
2411
|
-
appComponent.current.setAttribute('is-crowdin-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
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 });
|
|
2415
2353
|
}
|
|
2416
|
-
|
|
2417
|
-
|
|
2354
|
+
catch (e) {
|
|
2355
|
+
catchRejection(e, "Can't update files target languages");
|
|
2418
2356
|
}
|
|
2419
|
-
updateSyncSettings(syncedFiles, 'schedule', 'crowdin');
|
|
2420
2357
|
}
|
|
2421
|
-
function
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
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
|
+
}));
|
|
2437
2376
|
checkJob({
|
|
2438
2377
|
jobId: res === null || res === void 0 ? void 0 : res.jobId,
|
|
2439
2378
|
jobType: JOB_TYPE[`${provider}SyncSettingsSave`],
|
|
2440
2379
|
});
|
|
2441
|
-
}
|
|
2442
|
-
|
|
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 });
|
|
2443
2424
|
}
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
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) }),
|
|
2453
2522
|
});
|
|
2454
2523
|
}
|
|
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
|
+
}
|
|
2455
2659
|
function closeAlert(suffix) {
|
|
2456
|
-
const alertName = suffix ;
|
|
2457
2660
|
setIsNoticeVisible(false);
|
|
2458
|
-
localStorage.setItem(`revised_${
|
|
2661
|
+
localStorage.setItem(`revised_${suffix !== null && suffix !== void 0 ? suffix : name}`, '1');
|
|
2459
2662
|
}
|
|
2460
|
-
function showErrorLogs() {
|
|
2663
|
+
async function showErrorLogs() {
|
|
2461
2664
|
setIsErrorLogsVisible(true);
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
.then((res) => {
|
|
2665
|
+
try {
|
|
2666
|
+
const restParams = await checkOrigin();
|
|
2667
|
+
const res = await checkResponse(await fetch('api/user-errors' + restParams));
|
|
2466
2668
|
const table = userErrorsTableRef.current;
|
|
2467
|
-
const clickRow = (
|
|
2669
|
+
const clickRow = (_field, _index, item) => {
|
|
2468
2670
|
setSelectedUserError(item);
|
|
2469
2671
|
openModal(userErrorDetailModalRef.current);
|
|
2470
2672
|
};
|
|
2471
|
-
const formatDate = (
|
|
2472
|
-
return item.formattedDate;
|
|
2473
|
-
};
|
|
2673
|
+
const formatDate = (_field, _index, item) => item.formattedDate;
|
|
2474
2674
|
if (table.setTableConfig) {
|
|
2475
2675
|
table.setTableConfig({
|
|
2476
2676
|
defaultSortingColumn: 'createdAt',
|
|
@@ -2483,156 +2683,25 @@
|
|
|
2483
2683
|
clickFn: clickRow,
|
|
2484
2684
|
formatFn: formatDate,
|
|
2485
2685
|
},
|
|
2486
|
-
{
|
|
2487
|
-
|
|
2488
|
-
name: 'Action',
|
|
2489
|
-
clickFn: clickRow,
|
|
2490
|
-
},
|
|
2491
|
-
{
|
|
2492
|
-
field: 'message',
|
|
2493
|
-
name: 'Message',
|
|
2494
|
-
clickFn: clickRow,
|
|
2495
|
-
},
|
|
2686
|
+
{ field: 'action', name: 'Action', clickFn: clickRow },
|
|
2687
|
+
{ field: 'message', name: 'Message', clickFn: clickRow },
|
|
2496
2688
|
],
|
|
2497
2689
|
});
|
|
2498
2690
|
}
|
|
2499
2691
|
table.setTableData(JSON.stringify(res));
|
|
2500
2692
|
table.setAttribute('is-loading', false);
|
|
2501
|
-
})
|
|
2502
|
-
.catch((e) => catchRejection(e, "Can't fetch error logs"));
|
|
2503
|
-
}
|
|
2504
|
-
function showIntegration() {
|
|
2505
|
-
setIsErrorLogsVisible(false);
|
|
2506
|
-
}
|
|
2507
|
-
function isJSON(string) {
|
|
2508
|
-
try {
|
|
2509
|
-
JSON.parse(string);
|
|
2510
|
-
return true;
|
|
2511
2693
|
}
|
|
2512
2694
|
catch (e) {
|
|
2513
|
-
|
|
2514
|
-
}
|
|
2515
|
-
}
|
|
2516
|
-
function getUserErrorDetail(error) {
|
|
2517
|
-
const data = JSON.parse(error.data);
|
|
2518
|
-
const preClassName = 'block rounded bg-[#eceff1] p-4 text-[87.5%] text-[#212529]';
|
|
2519
|
-
const rows = [
|
|
2520
|
-
{ label: 'Action', value: error.action },
|
|
2521
|
-
{
|
|
2522
|
-
label: 'Message',
|
|
2523
|
-
value: isJSON(error.message) ? jsxRuntimeExports.jsx("pre", { className: preClassName, children: error.message }) : error.message,
|
|
2524
|
-
},
|
|
2525
|
-
{ label: 'Date/time', value: error.formattedDate },
|
|
2526
|
-
];
|
|
2527
|
-
if (data.requestParams) {
|
|
2528
|
-
rows.push({ label: 'Method', value: data.requestParams.method });
|
|
2529
|
-
}
|
|
2530
|
-
if (data.responseData) {
|
|
2531
|
-
rows.push({
|
|
2532
|
-
label: 'Response Data',
|
|
2533
|
-
value: jsxRuntimeExports.jsx("pre", { className: preClassName, children: JSON.stringify(data.responseData, null, 2) }),
|
|
2534
|
-
});
|
|
2535
|
-
}
|
|
2536
|
-
if (data.appData) {
|
|
2537
|
-
if (Array.isArray(data.appData)) {
|
|
2538
|
-
rows.push({
|
|
2539
|
-
label: 'App Data',
|
|
2540
|
-
value: jsxRuntimeExports.jsx("pre", { className: preClassName, children: JSON.stringify(data.appData, null, 2) }),
|
|
2541
|
-
});
|
|
2542
|
-
}
|
|
2543
|
-
else if (typeof data.appData === 'object') {
|
|
2544
|
-
for (const key in data.appData) {
|
|
2545
|
-
rows.push({
|
|
2546
|
-
label: key.charAt(0).toUpperCase() + key.slice(1),
|
|
2547
|
-
value: jsxRuntimeExports.jsx("pre", { className: preClassName, children: JSON.stringify(data.appData[key], null, 2) }),
|
|
2548
|
-
});
|
|
2549
|
-
}
|
|
2550
|
-
}
|
|
2551
|
-
else {
|
|
2552
|
-
rows.push({ label: 'App Data', value: data.appData });
|
|
2553
|
-
}
|
|
2554
|
-
}
|
|
2555
|
-
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))) }) }) }));
|
|
2556
|
-
}
|
|
2557
|
-
function renderPermissionStatus(status) {
|
|
2558
|
-
switch (status) {
|
|
2559
|
-
case 'willBeGranted':
|
|
2560
|
-
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" }));
|
|
2561
|
-
case 'willBeRegistered':
|
|
2562
|
-
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" }));
|
|
2563
|
-
case 'actionRequired':
|
|
2564
|
-
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" }));
|
|
2565
|
-
case 'granted':
|
|
2566
|
-
default:
|
|
2567
|
-
return jsxRuntimeExports.jsx("crowdin-p", { children: EMPTY_PERMISSION_VALUE });
|
|
2568
|
-
}
|
|
2569
|
-
}
|
|
2570
|
-
function renderPermissionUsers(row) {
|
|
2571
|
-
if (!row || row.users.length === 0) {
|
|
2572
|
-
return row ? renderPermissionStatus(row.status) : null;
|
|
2573
|
-
}
|
|
2574
|
-
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))) }));
|
|
2575
|
-
}
|
|
2576
|
-
function renderPermissionRowDescription(row) {
|
|
2577
|
-
if (!(row === null || row === void 0 ? void 0 : row.description)) {
|
|
2578
|
-
return null;
|
|
2579
|
-
}
|
|
2580
|
-
return (jsxRuntimeExports.jsx("div", { className: row.isWarning
|
|
2581
|
-
? 'mt-1 text-xs text-[var(--crowdin-warning)]'
|
|
2582
|
-
: 'mt-1 text-xs text-[var(--crowdin-text-muted)]', children: row.description }));
|
|
2583
|
-
}
|
|
2584
|
-
function openModal(modal) {
|
|
2585
|
-
if (!modal) {
|
|
2586
|
-
return;
|
|
2587
|
-
}
|
|
2588
|
-
modal.style.display = 'block';
|
|
2589
|
-
modal.open();
|
|
2590
|
-
}
|
|
2591
|
-
function closeModal(modal) {
|
|
2592
|
-
if (!modal) {
|
|
2593
|
-
return;
|
|
2695
|
+
catchRejection(e, "Can't fetch error logs");
|
|
2594
2696
|
}
|
|
2595
|
-
modal.style.display = 'none';
|
|
2596
|
-
modal.close();
|
|
2597
2697
|
}
|
|
2598
|
-
function
|
|
2599
|
-
|
|
2600
|
-
const el = (eventOrElement === null || eventOrElement === void 0 ? void 0 : eventOrElement.currentTarget) || (eventOrElement === null || eventOrElement === void 0 ? void 0 : eventOrElement.target) || eventOrElement;
|
|
2601
|
-
(_a = el === null || el === void 0 ? void 0 : el.removeAttribute) === null || _a === void 0 ? void 0 : _a.call(el, 'error');
|
|
2602
|
-
(_b = el === null || el === void 0 ? void 0 : el.removeAttribute) === null || _b === void 0 ? void 0 : _b.call(el, 'error-text');
|
|
2698
|
+
function showIntegration() {
|
|
2699
|
+
setIsErrorLogsVisible(false);
|
|
2603
2700
|
}
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
if (subscriptionInfo === null || subscriptionInfo === void 0 ? void 0 : subscriptionInfo.subscribeLink) {
|
|
2609
|
-
window.open(subscriptionInfo.subscribeLink, '_blank', 'noopener,noreferrer');
|
|
2610
|
-
}
|
|
2611
|
-
}, 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: () => showIntegration(), children: "Integration" }) }), jsxRuntimeExports.jsx("span", { style: { display: isErrorLogsVisible ? 'none' : undefined }, children: 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: () => openModal(infoModalRef.current), children: infoModal.title })), configurationFields && (jsxRuntimeExports.jsx("crowdin-button", { "icon-before": "settings", onClick: () => {
|
|
2612
|
-
openModal(settingsModalRef.current);
|
|
2613
|
-
fillSettingsForm();
|
|
2614
|
-
}, 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("div", { style: { display: isErrorLogsVisible ? 'none' : undefined }, children: 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)
|
|
2615
|
-
? { 'integration-schedule': 'true' }
|
|
2616
|
-
: {}), ...(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
|
|
2617
|
-
? { 'integration-button-menu-items': integrationButtonMenuItems }
|
|
2618
|
-
: {}), ...(((_b = crowdinButtonMenuItems === null || crowdinButtonMenuItems === void 0 ? void 0 : crowdinButtonMenuItems.length) !== null && _b !== void 0 ? _b : 0) > 0
|
|
2619
|
-
? { 'crowdin-button-menu-items': crowdinButtonMenuItems }
|
|
2620
|
-
: {}), ...((filtering === null || filtering === void 0 ? void 0 : filtering.crowdinLanguages) ? { 'crowdin-filter': true } : {}), ...((filtering === null || filtering === void 0 ? void 0 : filtering.integrationFilterConfig)
|
|
2621
|
-
? {
|
|
2622
|
-
'integration-filter': true,
|
|
2623
|
-
'integration-filter-config': filtering.integrationFilterConfig,
|
|
2624
|
-
}
|
|
2625
|
-
: {}) }) }), 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." })] })] }), jsxRuntimeExports.jsx("crowdin-toasts", {}), jsxRuntimeExports.jsx("crowdin-async-progress", { ref: asyncProgressRef, 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', '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: () => integrationLogout(), children: "Log out" })] })] }), jsxRuntimeExports.jsxs("crowdin-modal", { ref: permissionsModalRef, 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: modalLoaders['permissions-modal']
|
|
2626
|
-
? 'absolute inset-0 z-[4] flex items-center justify-center bg-white/30'
|
|
2627
|
-
: '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: isPermissionsConfirmVisible ? '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) &&
|
|
2628
|
-
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) &&
|
|
2629
|
-
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) &&
|
|
2630
|
-
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) &&
|
|
2631
|
-
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: () => inviteUsers(), children: "Save" }) })] }), excludedTargetLanguages && (jsxRuntimeExports.jsx("crowdin-modal", { ref: languageModal, 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: () => updateCrowdinFilesTargetLanguages(), children: "Update Target Languages" }) }), jsxRuntimeExports.jsx("span", { hidden: languageModalState.action !== 'syncToCrowdin', children: jsxRuntimeExports.jsx("crowdin-button", { id: "upload-exclude-languages", outlined: true, onClick: () => uploadFilesToCrowdinWithExcludedLanguages(), 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 })] }) }) })] })] })) })), infoModal && (jsxRuntimeExports.jsx("crowdin-modal", { ref: infoModalRef, 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", { ref: settingsModalRef, style: { display: 'none' }, id: "settings-modal", "modal-width": "65", "modal-title": "Settings", "close-button-title": "Close", children: [jsxRuntimeExports.jsx("div", { className: modalLoaders['settings-modal']
|
|
2632
|
-
? 'absolute inset-0 z-[4] flex items-center justify-center bg-white/30'
|
|
2633
|
-
: '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
|
|
2634
|
-
? { 'data-dependency': field.dependencySettings }
|
|
2635
|
-
: {}) })] }, field.key || `${tabIndex}-${fieldIndex}`))) }) }, tabIndex))) }) }), jsxRuntimeExports.jsx("div", { slot: "footer", children: jsxRuntimeExports.jsx("crowdin-button", { id: "settings-save-btn", outlined: true, disabled: isSettingsSaveDisabled, 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", { ref: scheduleModalRef, 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: () => onChangeAutoSynchronizationOptions() }), 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: () => onChangeAutoSynchronizationOptions() }), 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: () => onChangeAutoSynchronizationOptions() }), jsxRuntimeExports.jsx("div", { slot: "footer", children: jsxRuntimeExports.jsx("crowdin-button", { outlined: true, id: "save-schedule-sync", disabled: isScheduleSaveDisabled, onClick: () => saveScheduleSync(), children: "Save" }) })] })), jsxRuntimeExports.jsx("crowdin-modal", { ref: userErrorDetailModalRef, style: { display: 'none' }, id: "user-error-detail", "close-button-title": "Close", "close-button": "true", children: selectedUserError && getUserErrorDetail(selectedUserError) })] }));
|
|
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 })] }));
|
|
2636
2705
|
};
|
|
2637
2706
|
|
|
2638
2707
|
initializeCrowdinIframeContext();
|