@crowdin/app-project-module 0.39.0 → 0.40.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/handlers/integration/crowdin-update.js +36 -17
- package/out/handlers/integration/integration-data.js +2 -0
- package/out/handlers/integration/integration-update.js +35 -17
- package/out/handlers/integration/integration-webhook.js +1 -1
- package/out/handlers/integration/job-cancel.d.ts +3 -0
- package/out/handlers/integration/job-cancel.js +28 -0
- package/out/handlers/integration/job-info.d.ts +3 -0
- package/out/handlers/integration/job-info.js +54 -0
- package/out/handlers/integration/main.js +6 -3
- package/out/handlers/integration/user-errors.d.ts +3 -0
- package/out/handlers/{user-errors.js → integration/user-errors.js} +5 -5
- package/out/index.d.ts +2 -1
- package/out/index.js +35 -27
- package/out/middlewares/crowdin-client.js +1 -0
- package/out/middlewares/ui-module.js +1 -0
- package/out/models/index.d.ts +48 -17
- package/out/models/index.js +1 -0
- package/out/models/job.d.ts +44 -0
- package/out/models/job.js +16 -0
- package/out/static/css/styles.css +1 -1
- package/out/static/js/form.js +17 -41
- package/out/static/js/main.js +1 -1
- package/out/storage/index.d.ts +6 -0
- package/out/storage/index.js +3 -0
- package/out/storage/mysql.d.ts +6 -0
- package/out/storage/mysql.js +106 -0
- package/out/storage/postgre.d.ts +6 -0
- package/out/storage/postgre.js +107 -0
- package/out/storage/sqlite.d.ts +6 -0
- package/out/storage/sqlite.js +96 -0
- package/out/util/cron.d.ts +1 -0
- package/out/util/cron.js +47 -3
- package/out/util/defaults.js +4 -11
- package/out/util/file-snapshot.js +2 -0
- package/out/util/files.d.ts +2 -1
- package/out/util/files.js +19 -1
- package/out/util/index.js +3 -1
- package/out/util/job.d.ts +12 -0
- package/out/util/job.js +88 -0
- package/out/util/logger.js +4 -0
- package/out/util/webhooks.js +50 -4
- package/out/views/main.handlebars +154 -6
- package/package.json +16 -15
- package/out/handlers/user-errors.d.ts +0 -3
package/out/util/files.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { ProcessFileString } from '../models';
|
|
2
|
+
import { ProcessFileString, SkipIntegrationNodes, TreeItem } from '../models';
|
|
3
3
|
export declare const MAX_BODY_SIZE: number;
|
|
4
4
|
export declare function storeFile(fileContent: Buffer, folder: string): Promise<string>;
|
|
5
5
|
export declare function getFileContent(url: string): Promise<Buffer>;
|
|
6
6
|
export declare function getFileStrings(url: string): Promise<ProcessFileString[]>;
|
|
7
|
+
export declare function skipFilesByRegex(files: TreeItem[] | undefined, skipIntegrationNodes?: SkipIntegrationNodes): TreeItem[];
|
package/out/util/files.js
CHANGED
|
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.getFileStrings = exports.getFileContent = exports.storeFile = exports.MAX_BODY_SIZE = void 0;
|
|
15
|
+
exports.skipFilesByRegex = exports.getFileStrings = exports.getFileContent = exports.storeFile = exports.MAX_BODY_SIZE = void 0;
|
|
16
16
|
const axios_1 = __importDefault(require("axios"));
|
|
17
17
|
const fs_1 = __importDefault(require("fs"));
|
|
18
18
|
const path_1 = __importDefault(require("path"));
|
|
@@ -45,3 +45,21 @@ function getFileStrings(url) {
|
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
47
|
exports.getFileStrings = getFileStrings;
|
|
48
|
+
function skipFilesByRegex(files, skipIntegrationNodes) {
|
|
49
|
+
if (!Array.isArray(files)) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
if (skipIntegrationNodes) {
|
|
53
|
+
files = files.filter((file) => file);
|
|
54
|
+
if (skipIntegrationNodes.fileNamePattern) {
|
|
55
|
+
const regex = new RegExp(skipIntegrationNodes.fileNamePattern);
|
|
56
|
+
files = files.filter((file) => !('type' in file) || !regex.test(file.name));
|
|
57
|
+
}
|
|
58
|
+
if (skipIntegrationNodes.folderNamePattern) {
|
|
59
|
+
const regex = new RegExp(skipIntegrationNodes.folderNamePattern);
|
|
60
|
+
files = files.filter((file) => 'type' in file || !regex.test(file.name));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return files;
|
|
64
|
+
}
|
|
65
|
+
exports.skipFilesByRegex = skipFilesByRegex;
|
package/out/util/index.js
CHANGED
|
@@ -56,7 +56,9 @@ function handleError(err, req, res) {
|
|
|
56
56
|
res.redirect('/');
|
|
57
57
|
return;
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
if (!res.headersSent) {
|
|
60
|
+
res.status(code).send({ message: (0, logger_1.getErrorMessage)(err), code });
|
|
61
|
+
}
|
|
60
62
|
});
|
|
61
63
|
}
|
|
62
64
|
function runAsyncWrapper(callback) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { JobClient, JobType } from '../models/job';
|
|
2
|
+
import { Response } from 'express';
|
|
3
|
+
export declare function runAsJob({ integrationId, crowdinId, type, title, payload, res, jobCallback, onError, }: {
|
|
4
|
+
integrationId: string;
|
|
5
|
+
crowdinId: string;
|
|
6
|
+
type: JobType;
|
|
7
|
+
title?: string;
|
|
8
|
+
payload?: any;
|
|
9
|
+
res?: Response;
|
|
10
|
+
jobCallback: (arg1: JobClient) => Promise<any>;
|
|
11
|
+
onError?: (e: any) => Promise<void>;
|
|
12
|
+
}): Promise<void>;
|
package/out/util/job.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.runAsJob = void 0;
|
|
13
|
+
const job_1 = require("../models/job");
|
|
14
|
+
const storage_1 = require("../storage");
|
|
15
|
+
const logger_1 = require("./logger");
|
|
16
|
+
const blockingJobs = {
|
|
17
|
+
[job_1.JobType.UPDATE_TO_CROWDIN]: [job_1.JobType.UPDATE_TO_CROWDIN, job_1.JobType.UPDATE_TO_INTEGRATION],
|
|
18
|
+
[job_1.JobType.UPDATE_TO_INTEGRATION]: [job_1.JobType.UPDATE_TO_CROWDIN, job_1.JobType.UPDATE_TO_INTEGRATION],
|
|
19
|
+
};
|
|
20
|
+
function runAsJob({ integrationId, crowdinId, type, title, payload, res, jobCallback, onError, }) {
|
|
21
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
const storage = (0, storage_1.getStorage)();
|
|
23
|
+
const activeJobs = yield storage.getActiveJobs({ integrationId, crowdinId });
|
|
24
|
+
if (activeJobs === null || activeJobs === void 0 ? void 0 : activeJobs.length) {
|
|
25
|
+
const existingJob = activeJobs.find((job) => blockingJobs[type].includes(job.type));
|
|
26
|
+
if (existingJob === null || existingJob === void 0 ? void 0 : existingJob.id) {
|
|
27
|
+
if (res) {
|
|
28
|
+
res.status(202).send({ jobId: existingJob.id, message: 'Job is already running' });
|
|
29
|
+
}
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const jobId = yield storage.createJob({
|
|
34
|
+
integrationId,
|
|
35
|
+
crowdinId,
|
|
36
|
+
type,
|
|
37
|
+
title: title || '',
|
|
38
|
+
payload: JSON.stringify(payload),
|
|
39
|
+
});
|
|
40
|
+
if (res) {
|
|
41
|
+
res.status(202).send({ jobId });
|
|
42
|
+
}
|
|
43
|
+
const job = {
|
|
44
|
+
get: function getJob() {
|
|
45
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
return yield storage.getJob({ id: jobId });
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
update: function updateProgress({ progress, status, info, data }) {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
const prevData = yield this.get();
|
|
52
|
+
if ((prevData === null || prevData === void 0 ? void 0 : prevData.status) === job_1.JobStatus.CANCELED) {
|
|
53
|
+
return { isCanceled: true };
|
|
54
|
+
}
|
|
55
|
+
yield storage.updateJob({
|
|
56
|
+
id: jobId,
|
|
57
|
+
progress,
|
|
58
|
+
status: status || job_1.JobStatus.IN_PROGRESS,
|
|
59
|
+
info,
|
|
60
|
+
data: JSON.stringify(data),
|
|
61
|
+
});
|
|
62
|
+
return { isCanceled: false };
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
try {
|
|
67
|
+
const data = yield jobCallback(job);
|
|
68
|
+
yield job.update({
|
|
69
|
+
progress: 100,
|
|
70
|
+
status: job_1.JobStatus.FINISHED,
|
|
71
|
+
data,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
yield job.update({
|
|
76
|
+
status: job_1.JobStatus.FAILED,
|
|
77
|
+
info: (0, logger_1.getErrorMessage)(e),
|
|
78
|
+
});
|
|
79
|
+
if (onError) {
|
|
80
|
+
yield onError(e);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
throw e;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
exports.runAsJob = runAsJob;
|
package/out/util/logger.js
CHANGED
|
@@ -67,7 +67,9 @@ function log(message, context) {
|
|
|
67
67
|
else {
|
|
68
68
|
let prefix = `[${new Date().toISOString()}]`;
|
|
69
69
|
if (context) {
|
|
70
|
+
logsFormatter.resetContext();
|
|
70
71
|
logsFormatter.setContext({
|
|
72
|
+
appIdentifier: context.appIdentifier || '',
|
|
71
73
|
project: {
|
|
72
74
|
id: context.jwtPayload.context.project_id,
|
|
73
75
|
identifier: (_a = context.jwtPayload.context.project_identifier) !== null && _a !== void 0 ? _a : '',
|
|
@@ -100,7 +102,9 @@ function logError(e, context) {
|
|
|
100
102
|
}
|
|
101
103
|
else {
|
|
102
104
|
if (context) {
|
|
105
|
+
logsFormatter.resetContext();
|
|
103
106
|
logsFormatter.setContext({
|
|
107
|
+
appIdentifier: context.appIdentifier || '',
|
|
104
108
|
project: {
|
|
105
109
|
id: context.jwtPayload.context.project_id,
|
|
106
110
|
identifier: (_a = context.jwtPayload.context.project_identifier) !== null && _a !== void 0 ? _a : '',
|
package/out/util/webhooks.js
CHANGED
|
@@ -44,6 +44,8 @@ const connection_1 = require("./connection");
|
|
|
44
44
|
const defaults_1 = require("./defaults");
|
|
45
45
|
const index_1 = require("./index");
|
|
46
46
|
const logger_1 = require("./logger");
|
|
47
|
+
const prefetchCount = 20;
|
|
48
|
+
const forceProcessDelay = 5000;
|
|
47
49
|
exports.HookEvents = {
|
|
48
50
|
fileAdded: 'file.added',
|
|
49
51
|
fileDeleted: 'file.deleted',
|
|
@@ -308,7 +310,7 @@ function listenQueueMessage(config, integration, queueUrl, queueName) {
|
|
|
308
310
|
const channel = yield connection.createChannel();
|
|
309
311
|
if (channel) {
|
|
310
312
|
yield channel.assertQueue(queueName, { durable: true });
|
|
311
|
-
yield channel.prefetch(
|
|
313
|
+
yield channel.prefetch(prefetchCount);
|
|
312
314
|
yield channel.consume(queueName, consumer(channel, config, integration), { noAck: false });
|
|
313
315
|
}
|
|
314
316
|
}
|
|
@@ -321,23 +323,67 @@ function listenQueueMessage(config, integration, queueUrl, queueName) {
|
|
|
321
323
|
}
|
|
322
324
|
exports.listenQueueMessage = listenQueueMessage;
|
|
323
325
|
function consumer(channel, config, integration) {
|
|
326
|
+
let messagesCounter = 0;
|
|
327
|
+
let webhooksInfo = {};
|
|
328
|
+
let webhooksData = [];
|
|
329
|
+
let timeoutId;
|
|
330
|
+
const resetStateVariables = () => {
|
|
331
|
+
messagesCounter = 0;
|
|
332
|
+
webhooksInfo = {};
|
|
333
|
+
webhooksData = [];
|
|
334
|
+
};
|
|
324
335
|
return function (msg) {
|
|
325
336
|
var _a;
|
|
326
337
|
return __awaiter(this, void 0, void 0, function* () {
|
|
338
|
+
messagesCounter++;
|
|
327
339
|
if (!msg) {
|
|
328
340
|
return;
|
|
329
341
|
}
|
|
342
|
+
clearTimeout(timeoutId);
|
|
330
343
|
try {
|
|
331
344
|
const data = JSON.parse(msg.content.toString());
|
|
332
345
|
const urlParam = (_a = integration.webhooks) === null || _a === void 0 ? void 0 : _a.urlParam;
|
|
333
346
|
const webhookUrlParam = data.query[urlParam];
|
|
334
|
-
const
|
|
335
|
-
|
|
347
|
+
const { clientId } = decodedUrlParam(config, webhookUrlParam);
|
|
348
|
+
if (!webhooksInfo[clientId]) {
|
|
349
|
+
webhooksInfo[clientId] = {};
|
|
350
|
+
webhooksInfo[clientId].data = [data];
|
|
351
|
+
webhooksInfo[clientId].integration = integration;
|
|
352
|
+
webhooksData.push(prepareWebhookData(config, integration, webhookUrlParam, models_1.Provider.INTEGRATION).then((res) => {
|
|
353
|
+
webhooksInfo[clientId].webhookData = res;
|
|
354
|
+
}));
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
webhooksInfo[clientId].data.push(data);
|
|
358
|
+
}
|
|
359
|
+
if (messagesCounter < prefetchCount) {
|
|
360
|
+
// if all messages are not received, wait 5 seconds to force process messages
|
|
361
|
+
timeoutId = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
|
|
362
|
+
yield processMessages(webhooksData, webhooksInfo, channel, msg);
|
|
363
|
+
resetStateVariables();
|
|
364
|
+
}), forceProcessDelay);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
clearTimeout(timeoutId);
|
|
368
|
+
yield processMessages(webhooksData, webhooksInfo, channel, msg);
|
|
369
|
+
resetStateVariables();
|
|
336
370
|
}
|
|
337
371
|
catch (e) {
|
|
338
372
|
(0, logger_1.logError)(e);
|
|
339
373
|
}
|
|
340
|
-
channel.ack(msg);
|
|
341
374
|
});
|
|
342
375
|
};
|
|
343
376
|
}
|
|
377
|
+
function processMessages(webhooksData, webhooksInfo, channel, msg) {
|
|
378
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
379
|
+
yield Promise.all(webhooksData);
|
|
380
|
+
for (const { data, integration, webhookData } of Object.values(webhooksInfo)) {
|
|
381
|
+
yield updateCrowdinFromWebhookRequest({
|
|
382
|
+
integration: integration,
|
|
383
|
+
webhookData: webhookData,
|
|
384
|
+
req: data,
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
channel.ack(msg, true);
|
|
388
|
+
});
|
|
389
|
+
}
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
{{/if}}
|
|
59
59
|
</div>
|
|
60
60
|
<crowdin-simple-integration
|
|
61
|
+
async-progress
|
|
61
62
|
{{#if syncNewElements.crowdin}}
|
|
62
63
|
skip-crowdin-auto-schedule
|
|
63
64
|
{{/if}}
|
|
@@ -90,7 +91,6 @@
|
|
|
90
91
|
>
|
|
91
92
|
</crowdin-simple-integration>
|
|
92
93
|
<div id="user-errors" class="hidden">
|
|
93
|
-
<crowdin-alert title="Error Logs">This table displays the most recent error logs from the past month. Logs older than one month will be automatically deleted.</crowdin-alert>
|
|
94
94
|
<crowdin-show-as-table
|
|
95
95
|
is-loading
|
|
96
96
|
id="user-errors-table"
|
|
@@ -98,9 +98,13 @@
|
|
|
98
98
|
total-records="25"
|
|
99
99
|
search-placeholder="Search something"
|
|
100
100
|
></crowdin-show-as-table>
|
|
101
|
+
<crowdin-alert>This table displays the most recent error logs from the past month. Logs older than one month will be automatically deleted.</crowdin-alert>
|
|
101
102
|
</div>
|
|
102
103
|
</div>
|
|
103
104
|
<crowdin-toasts></crowdin-toasts>
|
|
105
|
+
<crowdin-async-progress
|
|
106
|
+
cancelAsyncAction=""
|
|
107
|
+
></crowdin-async-progress>
|
|
104
108
|
<crowdin-modal id="subscription-modal" modal-width="50" close-button="false">
|
|
105
109
|
<div>
|
|
106
110
|
<crowdin-alert type="warning">Subscribe to continue using the {{name}} app.</crowdin-alert>
|
|
@@ -296,6 +300,9 @@
|
|
|
296
300
|
});
|
|
297
301
|
document.body.addEventListener('uploadFilesToCrowdin', uploadFilesToCrowdin);
|
|
298
302
|
document.body.addEventListener('uploadFilesToIntegration', uploadFilesToIntegration);
|
|
303
|
+
document.body.addEventListener('cancelAsyncAction', (e) => {
|
|
304
|
+
cancelJob(e.detail);
|
|
305
|
+
});
|
|
299
306
|
{{#if integrationSearchListener}}
|
|
300
307
|
document.body.addEventListener("integrationFilterChange", (event) => {
|
|
301
308
|
getIntegrationData(false, 0, event.detail);
|
|
@@ -308,11 +315,27 @@
|
|
|
308
315
|
const fileType = '1';
|
|
309
316
|
const branchType = '2';
|
|
310
317
|
|
|
318
|
+
const JOB_TYPE = {
|
|
319
|
+
updateCrowdin: 'updateCrowdin',
|
|
320
|
+
updateIntegration: 'updateIntegration',
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
const JOB_STATUS = {
|
|
324
|
+
created: 'created',
|
|
325
|
+
inProgress: 'inProgress',
|
|
326
|
+
failed: 'failed',
|
|
327
|
+
canceled: 'canceled',
|
|
328
|
+
finished: 'finished',
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
const asyncJobs = {};
|
|
332
|
+
|
|
311
333
|
let project = {};
|
|
312
334
|
let crowdinData = [];
|
|
313
335
|
|
|
314
336
|
getCrowdinData();
|
|
315
337
|
getIntegrationData();
|
|
338
|
+
getActiveJobs();
|
|
316
339
|
|
|
317
340
|
function integrationLogout() {
|
|
318
341
|
checkOrigin()
|
|
@@ -481,10 +504,131 @@
|
|
|
481
504
|
body: JSON.stringify(req)
|
|
482
505
|
}))
|
|
483
506
|
.then(checkResponse)
|
|
484
|
-
.then(() =>
|
|
485
|
-
|
|
507
|
+
.then((res) => {
|
|
508
|
+
checkJob({
|
|
509
|
+
jobId: res?.jobId,
|
|
510
|
+
jobType: JOB_TYPE.updateCrowdin,
|
|
511
|
+
})
|
|
512
|
+
})
|
|
486
513
|
.catch(e => catchRejection(e, 'Can\'t upload templates to Crowdin'))
|
|
487
|
-
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function getActiveJobs() {
|
|
517
|
+
checkOrigin()
|
|
518
|
+
.then(restParams => fetch(`api/jobs${restParams}`))
|
|
519
|
+
.then(checkResponse)
|
|
520
|
+
.then((jobs) => {
|
|
521
|
+
if (!Array.isArray(jobs)) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
jobs.forEach((job) => {
|
|
526
|
+
switch (job.type) {
|
|
527
|
+
case JOB_TYPE.updateCrowdin:
|
|
528
|
+
appComponent.setAttribute('is-to-crowdin-process', true);
|
|
529
|
+
break;
|
|
530
|
+
case JOB_TYPE.updateIntegration:
|
|
531
|
+
appComponent.setAttribute('is-to-integration-process', true);
|
|
532
|
+
break;
|
|
533
|
+
default:
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
checkJob({
|
|
537
|
+
jobId: job.id,
|
|
538
|
+
jobType: job.type,
|
|
539
|
+
})
|
|
540
|
+
})
|
|
541
|
+
})
|
|
542
|
+
.catch(e => catchRejection(e, 'Sync status check failed'))
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function cancelJob(jobId) {
|
|
546
|
+
if (asyncJobs[jobId]?.isFailed) {
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
checkOrigin()
|
|
551
|
+
.then(restParams => fetch('api/jobs' + restParams + '&job_id=' + jobId, {
|
|
552
|
+
method: 'DELETE',
|
|
553
|
+
headers: { 'Content-Type': 'application/json' },
|
|
554
|
+
}))
|
|
555
|
+
.then(checkResponse)
|
|
556
|
+
.then(() => showToast('Cancellation…'))
|
|
557
|
+
.catch(e => catchRejection(e, 'Sync cancellation failed'));
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function checkJob({jobId, jobType, onSuccess, onError, onFinally}) {
|
|
561
|
+
switch (jobType) {
|
|
562
|
+
case JOB_TYPE.updateCrowdin:
|
|
563
|
+
if (!onSuccess) {
|
|
564
|
+
onSuccess = ((job) => {
|
|
565
|
+
getCrowdinData();
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
if (!onFinally) {
|
|
570
|
+
onFinally = (() => appComponent.setAttribute('is-to-crowdin-process', false));
|
|
571
|
+
}
|
|
572
|
+
break;
|
|
573
|
+
case JOB_TYPE.updateIntegration:
|
|
574
|
+
if (!onFinally) {
|
|
575
|
+
onFinally = (() => appComponent.setAttribute('is-to-integration-process', false));
|
|
576
|
+
}
|
|
577
|
+
break;
|
|
578
|
+
default:
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
checkOrigin()
|
|
582
|
+
.then(restParams => fetch('api/jobs' + restParams + '&job_id=' + jobId))
|
|
583
|
+
.then(checkResponse)
|
|
584
|
+
.then((job) => {
|
|
585
|
+
const isFailed = [JOB_STATUS.failed, JOB_STATUS.canceled].includes(job.status);
|
|
586
|
+
const progress = isFailed || JOB_STATUS.finished === job.status ? 100 : job.progress;
|
|
587
|
+
const info = JOB_STATUS.canceled === job.status ? `Cancelled\n${job.info || ''}` : job.info;
|
|
588
|
+
|
|
589
|
+
pushJobs([ {
|
|
590
|
+
id: job.id,
|
|
591
|
+
title: job.title,
|
|
592
|
+
progress,
|
|
593
|
+
info,
|
|
594
|
+
isFailed,
|
|
595
|
+
} ]);
|
|
596
|
+
|
|
597
|
+
if (isFailed) {
|
|
598
|
+
onError && onError();
|
|
599
|
+
} else if ([JOB_STATUS.created, JOB_STATUS.inProgress].includes(job.status) && job.progress < 100) {
|
|
600
|
+
setTimeout(() => {
|
|
601
|
+
checkJob({jobId, jobType, onSuccess, onError, onFinally});
|
|
602
|
+
}, {{asyncProgress.checkInterval}});
|
|
603
|
+
return;
|
|
604
|
+
} else {
|
|
605
|
+
onSuccess && onSuccess(job);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
onFinally && onFinally(job);
|
|
609
|
+
})
|
|
610
|
+
.catch((e) => {
|
|
611
|
+
onFinally && onFinally();
|
|
612
|
+
|
|
613
|
+
pushJobs([ {
|
|
614
|
+
id: jobId,
|
|
615
|
+
isFailed: true,
|
|
616
|
+
} ]);
|
|
617
|
+
|
|
618
|
+
showToast('Sync status check failed');
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
function pushJobs(jobs) {
|
|
623
|
+
const el = document.querySelector('crowdin-async-progress');
|
|
624
|
+
if (el && el.pushJobs) {
|
|
625
|
+
el.pushJobs(jobs);
|
|
626
|
+
jobs.forEach((job) => (asyncJobs[job.id] = job));
|
|
627
|
+
} else {
|
|
628
|
+
setTimeout(() => {
|
|
629
|
+
pushJobs(jobs);
|
|
630
|
+
}, 300);
|
|
631
|
+
}
|
|
488
632
|
}
|
|
489
633
|
|
|
490
634
|
function uploadFilesToIntegration(e) {
|
|
@@ -504,9 +648,13 @@
|
|
|
504
648
|
body: JSON.stringify(req)
|
|
505
649
|
}))
|
|
506
650
|
.then(checkResponse)
|
|
507
|
-
.then(() =>
|
|
651
|
+
.then((res) => {
|
|
652
|
+
checkJob({
|
|
653
|
+
jobId: res?.jobId,
|
|
654
|
+
jobType: JOB_TYPE.updateIntegration,
|
|
655
|
+
})
|
|
656
|
+
})
|
|
508
657
|
.catch(e => catchRejection(e, 'Can\'t upload files to {{name}}'))
|
|
509
|
-
.finally(() => (appComponent.setAttribute('is-to-integration-process', false)));
|
|
510
658
|
}
|
|
511
659
|
|
|
512
660
|
{{#if configurationFields}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crowdin/app-project-module",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"description": "Module that generates for you all common endpoints for serving standalone Crowdin App",
|
|
5
5
|
"main": "out/index.js",
|
|
6
6
|
"types": "out/index.d.ts",
|
|
@@ -15,11 +15,10 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@aws-sdk/client-s3": "^3.423.0",
|
|
18
|
-
"@aws-sdk/s3-request-presigner": "^3.
|
|
18
|
+
"@aws-sdk/s3-request-presigner": "^3.484.0",
|
|
19
19
|
"@crowdin/crowdin-apps-functions": "0.6.0",
|
|
20
|
-
"@crowdin/logs-formatter": "^2.
|
|
20
|
+
"@crowdin/logs-formatter": "^2.1.1",
|
|
21
21
|
"@godaddy/terminus": "^4.12.1",
|
|
22
|
-
"@types/pg": "^8.10.3",
|
|
23
22
|
"amqplib": "^0.10.3",
|
|
24
23
|
"crypto-js": "^4.2.0",
|
|
25
24
|
"express": "4.18.2",
|
|
@@ -33,29 +32,31 @@
|
|
|
33
32
|
"uuid": "^8.3.2"
|
|
34
33
|
},
|
|
35
34
|
"devDependencies": {
|
|
36
|
-
"@babel/preset-react": "^7.
|
|
35
|
+
"@babel/preset-react": "^7.23.3",
|
|
37
36
|
"@emotion/react": "^11.11.1",
|
|
38
37
|
"@emotion/styled": "^11.11.0",
|
|
39
|
-
"@mui/icons-material": "^5.
|
|
40
|
-
"@mui/material": "^5.
|
|
41
|
-
"@rjsf/core": "^5.
|
|
42
|
-
"@rjsf/mui": "^5.
|
|
43
|
-
"@rjsf/utils": "^5.
|
|
44
|
-
"@rjsf/validator-ajv8": "^5.
|
|
38
|
+
"@mui/icons-material": "^5.15.2",
|
|
39
|
+
"@mui/material": "^5.15.2",
|
|
40
|
+
"@rjsf/core": "^5.15.1",
|
|
41
|
+
"@rjsf/mui": "^5.15.1",
|
|
42
|
+
"@rjsf/utils": "^5.15.1",
|
|
43
|
+
"@rjsf/validator-ajv8": "^5.15.1",
|
|
45
44
|
"@rollup/plugin-babel": "^6.0.4",
|
|
46
|
-
"@rollup/plugin-commonjs": "^24.0
|
|
45
|
+
"@rollup/plugin-commonjs": "^24.1.0",
|
|
47
46
|
"@rollup/plugin-json": "^6.0.0",
|
|
48
47
|
"@rollup/plugin-node-resolve": "^15.2.1",
|
|
49
|
-
"@rollup/plugin-replace": "^5.0.
|
|
48
|
+
"@rollup/plugin-replace": "^5.0.5",
|
|
50
49
|
"@rollup/plugin-terser": "^0.4.3",
|
|
51
|
-
"@types/amqplib": "^0.10.
|
|
50
|
+
"@types/amqplib": "^0.10.4",
|
|
52
51
|
"@types/crypto-js": "^4.1.3",
|
|
53
52
|
"@types/express": "4.17.18",
|
|
54
53
|
"@types/express-handlebars": "^5.3.1",
|
|
55
54
|
"@types/jest": "^29.5.5",
|
|
56
|
-
"@types/node": "^16.18.
|
|
55
|
+
"@types/node": "^16.18.69",
|
|
57
56
|
"@types/node-cron": "^3.0.9",
|
|
57
|
+
"@types/pg": "^8.10.3",
|
|
58
58
|
"@types/swagger-jsdoc": "^6.0.1",
|
|
59
|
+
"@types/uuid": "^9.0.7",
|
|
59
60
|
"@typescript-eslint/eslint-plugin": "^2.3.1",
|
|
60
61
|
"@typescript-eslint/parser": "^2.3.1",
|
|
61
62
|
"eslint": "^6.4.0",
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
/// <reference types="qs" />
|
|
2
|
-
import { Response } from 'express';
|
|
3
|
-
export default function handle(): (req: import("../models").CrowdinClientRequest | import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
|