@crowdin/app-project-module 0.85.1 → 0.86.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/integration/handlers/crowdin-update.js +13 -6
- package/out/modules/integration/handlers/integration-data.js +50 -6
- package/out/modules/integration/handlers/main.js +3 -3
- package/out/modules/integration/types.d.ts +35 -1
- package/out/modules/integration/util/cron.js +7 -0
- package/out/modules/integration/util/defaults.js +68 -4
- package/out/modules/integration/util/files.d.ts +7 -1
- package/out/modules/integration/util/files.js +79 -3
- package/out/modules/integration/util/types.d.ts +8 -0
- package/out/storage/index.d.ts +4 -1
- package/out/storage/mysql.d.ts +5 -1
- package/out/storage/mysql.js +29 -0
- package/out/storage/postgre.d.ts +5 -1
- package/out/storage/postgre.js +29 -0
- package/out/storage/sqlite.d.ts +5 -1
- package/out/storage/sqlite.js +22 -0
- package/out/views/main.handlebars +50 -40
- package/package.json +4 -2
|
@@ -19,6 +19,7 @@ const defaults_1 = require("../util/defaults");
|
|
|
19
19
|
const logger_1 = require("../../../util/logger");
|
|
20
20
|
const job_1 = require("../util/job");
|
|
21
21
|
const files_1 = require("../util/files");
|
|
22
|
+
const types_2 = require("../types");
|
|
22
23
|
function handle(config, integration) {
|
|
23
24
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
24
25
|
var _a, _b, _c;
|
|
@@ -33,6 +34,7 @@ function handle(config, integration) {
|
|
|
33
34
|
if (((_b = config.api) === null || _b === void 0 ? void 0 : _b.default) && req.body.files) {
|
|
34
35
|
req.body = req.body.files;
|
|
35
36
|
}
|
|
37
|
+
let payload = req.body;
|
|
36
38
|
const excludedTargetLanguages = yield (0, files_1.getExcludedTargetLanguages)({
|
|
37
39
|
client: req.crowdinApiClient,
|
|
38
40
|
projectId,
|
|
@@ -43,29 +45,34 @@ function handle(config, integration) {
|
|
|
43
45
|
crowdinId: req.crowdinContext.crowdinId,
|
|
44
46
|
type: types_1.JobType.UPDATE_TO_CROWDIN,
|
|
45
47
|
title: 'Sync files to Crowdin',
|
|
46
|
-
payload
|
|
48
|
+
payload,
|
|
47
49
|
res,
|
|
48
50
|
projectId,
|
|
49
51
|
client: req.crowdinApiClient,
|
|
50
52
|
jobType: types_1.JobClientType.MANUAL,
|
|
51
53
|
jobStoreType: integration.jobStoreType,
|
|
52
54
|
jobCallback: (job) => __awaiter(this, void 0, void 0, function* () {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
req.body = (0, lodash_uniqby_1.default)(req.body, 'id');
|
|
55
|
+
if (payload && (payload === null || payload === void 0 ? void 0 : payload.length)) {
|
|
56
|
+
payload = yield (0, files_1.expandFilesTree)(payload, req, integration, job);
|
|
57
|
+
payload = (0, lodash_uniqby_1.default)(payload, 'id');
|
|
57
58
|
}
|
|
58
59
|
const result = yield integration.updateCrowdin({
|
|
59
60
|
projectId,
|
|
60
61
|
client: req.crowdinApiClient,
|
|
61
62
|
credentials: req.integrationCredentials,
|
|
62
|
-
request:
|
|
63
|
+
request: payload,
|
|
63
64
|
rootFolder,
|
|
64
65
|
appSettings: req.integrationSettings,
|
|
65
66
|
uploadTranslations,
|
|
66
67
|
job,
|
|
67
68
|
excludedTargetLanguages: req.query.languages ? excludedTargetLanguages : undefined,
|
|
68
69
|
});
|
|
70
|
+
try {
|
|
71
|
+
yield (0, files_1.updateSyncedData)(req.crowdinContext.clientId, req.crowdinContext.crowdinId, payload, types_2.Provider.INTEGRATION);
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
(0, logger_1.logError)(e, req.crowdinContext);
|
|
75
|
+
}
|
|
69
76
|
let message;
|
|
70
77
|
if ((0, files_1.isExtendedResultType)(result)) {
|
|
71
78
|
message = result.message;
|
|
@@ -12,31 +12,75 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
const util_1 = require("../../../util");
|
|
13
13
|
const logger_1 = require("../../../util/logger");
|
|
14
14
|
const files_1 = require("../util/files");
|
|
15
|
+
const types_1 = require("../types");
|
|
16
|
+
const storage_1 = require("../../../storage");
|
|
15
17
|
function handle(integration) {
|
|
16
18
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
17
20
|
const { parent_id: parentId, search, page } = req.query;
|
|
18
21
|
req.logInfo('Received request to get integration data');
|
|
19
22
|
let message;
|
|
20
23
|
let stopPagination;
|
|
21
|
-
let files;
|
|
24
|
+
let files = [];
|
|
25
|
+
const { crowdinId, clientId } = req.crowdinContext;
|
|
22
26
|
try {
|
|
23
|
-
const
|
|
27
|
+
const appSettings = req.integrationSettings;
|
|
28
|
+
const result = yield integration.getIntegrationFiles(req.integrationCredentials, appSettings, parentId, search, page);
|
|
24
29
|
if ((0, files_1.isExtendedResultType)(result)) {
|
|
25
|
-
files = result.data;
|
|
30
|
+
files = result.data || [];
|
|
26
31
|
message = result.message;
|
|
27
32
|
stopPagination = result.stopPagination;
|
|
28
33
|
}
|
|
29
34
|
else {
|
|
30
|
-
files = result;
|
|
35
|
+
files = result || [];
|
|
31
36
|
}
|
|
32
37
|
files = (0, files_1.skipFilesByRegex)(files, integration.skipIntegrationNodes);
|
|
38
|
+
if (integration.filterByPathIntegrationFiles) {
|
|
39
|
+
const includePatterns = (_a = appSettings === null || appSettings === void 0 ? void 0 : appSettings.includeByFilePath) === null || _a === void 0 ? void 0 : _a.split('\n').filter(Boolean);
|
|
40
|
+
const excludePatterns = (_b = appSettings === null || appSettings === void 0 ? void 0 : appSettings.excludeByFilePath) === null || _b === void 0 ? void 0 : _b.split('\n').filter(Boolean);
|
|
41
|
+
files = (0, files_1.filterFilesByPath)(files, includePatterns, excludePatterns);
|
|
42
|
+
}
|
|
43
|
+
if (((_d = (_c = integration.filtering) === null || _c === void 0 ? void 0 : _c.integrationFileStatus) === null || _d === void 0 ? void 0 : _d.isNew) ||
|
|
44
|
+
((_f = (_e = integration.filtering) === null || _e === void 0 ? void 0 : _e.integrationFileStatus) === null || _f === void 0 ? void 0 : _f.isUpdated) ||
|
|
45
|
+
((_h = (_g = integration.filtering) === null || _g === void 0 ? void 0 : _g.integrationFileStatus) === null || _h === void 0 ? void 0 : _h.notSynced)) {
|
|
46
|
+
const syncedData = yield (0, storage_1.getStorage)().getSyncedData(clientId, crowdinId, types_1.Provider.INTEGRATION);
|
|
47
|
+
const syncedFiles = (syncedData === null || syncedData === void 0 ? void 0 : syncedData.files) ? JSON.parse(syncedData.files) : [];
|
|
48
|
+
const lastSyncTimestamp = (syncedData === null || syncedData === void 0 ? void 0 : syncedData.updatedAt) ? Number(syncedData.updatedAt) : null;
|
|
49
|
+
files = files.map((file) => {
|
|
50
|
+
var _a, _b, _c, _d, _e, _f;
|
|
51
|
+
if (!file.type) {
|
|
52
|
+
return file;
|
|
53
|
+
}
|
|
54
|
+
const notSynced = ((_b = (_a = integration.filtering) === null || _a === void 0 ? void 0 : _a.integrationFileStatus) === null || _b === void 0 ? void 0 : _b.notSynced) === true
|
|
55
|
+
? !syncedFiles.some((syncedItem) => syncedItem.id === file.id)
|
|
56
|
+
: false;
|
|
57
|
+
const isNew = ((_d = (_c = integration.filtering) === null || _c === void 0 ? void 0 : _c.integrationFileStatus) === null || _d === void 0 ? void 0 : _d.isNew) === true
|
|
58
|
+
? !syncedFiles.some((syncedItem) => syncedItem.id === file.id) &&
|
|
59
|
+
lastSyncTimestamp &&
|
|
60
|
+
file.createdAt &&
|
|
61
|
+
(typeof file.createdAt === 'string'
|
|
62
|
+
? new Date(file.createdAt).getTime()
|
|
63
|
+
: file.createdAt) > Number(lastSyncTimestamp)
|
|
64
|
+
: false;
|
|
65
|
+
const isUpdated = ((_f = (_e = integration.filtering) === null || _e === void 0 ? void 0 : _e.integrationFileStatus) === null || _f === void 0 ? void 0 : _f.isUpdated) === true
|
|
66
|
+
? lastSyncTimestamp &&
|
|
67
|
+
file.updatedAt &&
|
|
68
|
+
(typeof file.updatedAt === 'string'
|
|
69
|
+
? new Date(file.updatedAt).getTime()
|
|
70
|
+
: file.updatedAt) > Number(lastSyncTimestamp)
|
|
71
|
+
: false;
|
|
72
|
+
return Object.assign(Object.assign({}, file), { isNew,
|
|
73
|
+
notSynced,
|
|
74
|
+
isUpdated });
|
|
75
|
+
});
|
|
76
|
+
}
|
|
33
77
|
}
|
|
34
78
|
catch (e) {
|
|
35
79
|
yield (0, logger_1.handleUserError)({
|
|
36
80
|
action: 'Get External Service data',
|
|
37
81
|
error: e,
|
|
38
|
-
crowdinId
|
|
39
|
-
clientId
|
|
82
|
+
crowdinId,
|
|
83
|
+
clientId,
|
|
40
84
|
});
|
|
41
85
|
res.send({ data: [], message: (e === null || e === void 0 ? void 0 : e.message) || e });
|
|
42
86
|
throw e;
|
|
@@ -39,7 +39,7 @@ const defaults_1 = require("../util/defaults");
|
|
|
39
39
|
const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
|
|
40
40
|
function handle(config, integration) {
|
|
41
41
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
42
|
-
var _a, _b, _c;
|
|
42
|
+
var _a, _b, _c, _d;
|
|
43
43
|
const logger = req.logInfo || logger_1.log;
|
|
44
44
|
const installed = !!req.crowdinApiClient;
|
|
45
45
|
const loggedIn = !!req.integrationCredentials;
|
|
@@ -82,7 +82,7 @@ function handle(config, integration) {
|
|
|
82
82
|
}
|
|
83
83
|
options.infoModal = integration.infoModal;
|
|
84
84
|
options.syncNewElements = integration.syncNewElements;
|
|
85
|
-
options.filtering = integration.filtering;
|
|
85
|
+
options.filtering = Object.assign(Object.assign({}, integration.filtering), { integrationFilterConfig: JSON.stringify(((_c = integration.filtering) === null || _c === void 0 ? void 0 : _c.integrationFilterConfig) || []) });
|
|
86
86
|
options.withCronSync = integration.withCronSync;
|
|
87
87
|
options.webhooks = integration.webhooks
|
|
88
88
|
? {
|
|
@@ -103,7 +103,7 @@ function handle(config, integration) {
|
|
|
103
103
|
: null;
|
|
104
104
|
options.notice = integration.notice;
|
|
105
105
|
options.asyncProgress = {
|
|
106
|
-
checkInterval: ((
|
|
106
|
+
checkInterval: ((_d = integration.asyncProgress) === null || _d === void 0 ? void 0 : _d.checkInterval) || 1000,
|
|
107
107
|
};
|
|
108
108
|
logger(`Routing user to ${view} view`);
|
|
109
109
|
return res.render(view, options);
|
|
@@ -107,8 +107,36 @@ export interface IntegrationLogic extends ModuleKey {
|
|
|
107
107
|
crowdin: boolean;
|
|
108
108
|
integration: boolean;
|
|
109
109
|
};
|
|
110
|
+
/**
|
|
111
|
+
* Enable file filtering
|
|
112
|
+
*/
|
|
110
113
|
filtering?: {
|
|
111
|
-
crowdinLanguages
|
|
114
|
+
crowdinLanguages?: boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Configuration for integration file filtering
|
|
117
|
+
*/
|
|
118
|
+
integrationFilterConfig?: any;
|
|
119
|
+
/**
|
|
120
|
+
* Enable file status filtering
|
|
121
|
+
*/
|
|
122
|
+
integrationFileStatus?: {
|
|
123
|
+
/**
|
|
124
|
+
* Enable file filtering by "isNew" status
|
|
125
|
+
*/
|
|
126
|
+
isNew?: boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Enable file filtering by "isUpdated" status
|
|
129
|
+
*/
|
|
130
|
+
isUpdated?: boolean;
|
|
131
|
+
/**
|
|
132
|
+
* Enable file filtering by "failed" status
|
|
133
|
+
*/
|
|
134
|
+
failed?: boolean;
|
|
135
|
+
/**
|
|
136
|
+
* Enable file filtering by "notSynced" status
|
|
137
|
+
*/
|
|
138
|
+
notSynced?: boolean;
|
|
139
|
+
};
|
|
112
140
|
};
|
|
113
141
|
/**
|
|
114
142
|
* Enable integration folder open event
|
|
@@ -130,6 +158,10 @@ export interface IntegrationLogic extends ModuleKey {
|
|
|
130
158
|
* Enable the option to upload file for translation into selected languages.
|
|
131
159
|
*/
|
|
132
160
|
excludedTargetLanguages?: boolean;
|
|
161
|
+
/**
|
|
162
|
+
* Enable the option to add 'Exclude paths' and 'Include paths' text fields to integration settings
|
|
163
|
+
*/
|
|
164
|
+
filterByPathIntegrationFiles?: boolean;
|
|
133
165
|
/**
|
|
134
166
|
* function to get crowdin file translation progress
|
|
135
167
|
*/
|
|
@@ -305,6 +337,7 @@ export interface File {
|
|
|
305
337
|
labels?: LabelTreeElement[];
|
|
306
338
|
failed?: boolean;
|
|
307
339
|
excludedTargetLanguages?: string[];
|
|
340
|
+
path?: string;
|
|
308
341
|
}
|
|
309
342
|
export interface Folder {
|
|
310
343
|
id: string;
|
|
@@ -313,6 +346,7 @@ export interface Folder {
|
|
|
313
346
|
nodeType?: IntegrationTreeElementType;
|
|
314
347
|
customContent?: string;
|
|
315
348
|
labels?: LabelTreeElement[];
|
|
349
|
+
path?: string;
|
|
316
350
|
}
|
|
317
351
|
export type TreeItem = File | Folder;
|
|
318
352
|
/**
|
|
@@ -43,6 +43,7 @@ const types_1 = require("../types");
|
|
|
43
43
|
const job_1 = require("./job");
|
|
44
44
|
const types_2 = require("./types");
|
|
45
45
|
const subscription_1 = require("../../../util/subscription");
|
|
46
|
+
const files_1 = require("./files");
|
|
46
47
|
function runJob({ config, integration, job, }) {
|
|
47
48
|
return __awaiter(this, void 0, void 0, function* () {
|
|
48
49
|
(0, logger_1.log)(`Starting cron job with expression [${job.expression}]`);
|
|
@@ -106,6 +107,12 @@ function runUpdateProviderJob({ integrationId, crowdinId, type, title, payload,
|
|
|
106
107
|
};
|
|
107
108
|
if (type === types_2.JobType.UPDATE_TO_CROWDIN) {
|
|
108
109
|
yield integration.updateCrowdin(updateParams);
|
|
110
|
+
try {
|
|
111
|
+
yield (0, files_1.updateSyncedData)(integrationId, crowdinId, payload, types_1.Provider.INTEGRATION);
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
(0, logger_1.logError)(e, context);
|
|
115
|
+
}
|
|
109
116
|
}
|
|
110
117
|
else if (type === types_2.JobType.UPDATE_TO_INTEGRATION) {
|
|
111
118
|
yield integration.updateIntegration(updateParams);
|
|
@@ -57,7 +57,7 @@ function getOauthRoute(integration) {
|
|
|
57
57
|
}
|
|
58
58
|
exports.getOauthRoute = getOauthRoute;
|
|
59
59
|
function applyIntegrationModuleDefaults(config, integration) {
|
|
60
|
-
var _a, _b;
|
|
60
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
61
61
|
if (!integration.getCrowdinFiles) {
|
|
62
62
|
integration.getCrowdinFiles = (projectId, client, rootFolder) => __awaiter(this, void 0, void 0, function* () {
|
|
63
63
|
const allBranches = (yield client.sourceFilesApi.withFetchAll().listProjectBranches(projectId)).data.map((d) => d.data);
|
|
@@ -139,9 +139,13 @@ function applyIntegrationModuleDefaults(config, integration) {
|
|
|
139
139
|
],
|
|
140
140
|
};
|
|
141
141
|
}
|
|
142
|
+
if ((integration.filterByPathIntegrationFiles === undefined || integration.filterByPathIntegrationFiles) &&
|
|
143
|
+
!integration.integrationOneLevelFetching) {
|
|
144
|
+
integration.filterByPathIntegrationFiles = true;
|
|
145
|
+
}
|
|
142
146
|
const getUserSettings = integration.getConfiguration;
|
|
143
147
|
integration.getConfiguration = (projectId, crowdinClient, integrationCredentials) => __awaiter(this, void 0, void 0, function* () {
|
|
144
|
-
var
|
|
148
|
+
var _m, _o;
|
|
145
149
|
let fields = [];
|
|
146
150
|
const project = (yield crowdinClient.projectsGroupsApi.getProject(projectId));
|
|
147
151
|
if (getUserSettings) {
|
|
@@ -190,7 +194,7 @@ function applyIntegrationModuleDefaults(config, integration) {
|
|
|
190
194
|
},
|
|
191
195
|
],
|
|
192
196
|
});
|
|
193
|
-
if ((
|
|
197
|
+
if ((_m = integration.syncNewElements) === null || _m === void 0 ? void 0 : _m.crowdin) {
|
|
194
198
|
defaultSettings.push({
|
|
195
199
|
key: 'new-crowdin-files',
|
|
196
200
|
label: 'Automatically sync new translations from Crowdin',
|
|
@@ -198,7 +202,7 @@ function applyIntegrationModuleDefaults(config, integration) {
|
|
|
198
202
|
dependencySettings: JSON.stringify([{ '#schedule-settings': { type: '!equal', value: ['0'] } }]),
|
|
199
203
|
});
|
|
200
204
|
}
|
|
201
|
-
if ((
|
|
205
|
+
if ((_o = integration.syncNewElements) === null || _o === void 0 ? void 0 : _o.integration) {
|
|
202
206
|
defaultSettings.push({
|
|
203
207
|
key: 'new-integration-files',
|
|
204
208
|
label: `Automatically sync new content from ${config.name}`,
|
|
@@ -245,6 +249,21 @@ function applyIntegrationModuleDefaults(config, integration) {
|
|
|
245
249
|
],
|
|
246
250
|
});
|
|
247
251
|
}
|
|
252
|
+
if (integration.filterByPathIntegrationFiles) {
|
|
253
|
+
defaultSettings.push({
|
|
254
|
+
label: 'File Filters',
|
|
255
|
+
}, {
|
|
256
|
+
key: 'includeByFilePath',
|
|
257
|
+
label: 'Source files path',
|
|
258
|
+
type: 'textarea',
|
|
259
|
+
helpText: 'Enter the file path patterns to include files for synchronization. Use wildcard selectors like `*` and `**` to match multiple files. Example: `/pages/**',
|
|
260
|
+
}, {
|
|
261
|
+
key: 'excludeByFilePath',
|
|
262
|
+
label: 'Ignore files or folders',
|
|
263
|
+
type: 'textarea',
|
|
264
|
+
helpText: 'Enter the path patterns for files or folders to exclude. Use wildcard selectors like `*` and `**` to match multiple files. Example: `/drafts/**`',
|
|
265
|
+
});
|
|
266
|
+
}
|
|
248
267
|
return [...defaultSettings, ...fields];
|
|
249
268
|
});
|
|
250
269
|
if (!integration.checkConnection) {
|
|
@@ -258,6 +277,51 @@ function applyIntegrationModuleDefaults(config, integration) {
|
|
|
258
277
|
if (!((_b = integration.filtering) === null || _b === void 0 ? void 0 : _b.hasOwnProperty('crowdinLanguages'))) {
|
|
259
278
|
integration.filtering = Object.assign(Object.assign({}, (integration.filtering || {})), { crowdinLanguages: true });
|
|
260
279
|
}
|
|
280
|
+
integration.filtering.integrationFileStatus = Object.assign({ notSynced: true }, integration.filtering.integrationFileStatus);
|
|
281
|
+
if (!((_c = integration.filtering) === null || _c === void 0 ? void 0 : _c.hasOwnProperty('integrationFilterConfig'))) {
|
|
282
|
+
const filterItems = [
|
|
283
|
+
{
|
|
284
|
+
value: 'all',
|
|
285
|
+
label: 'All',
|
|
286
|
+
},
|
|
287
|
+
];
|
|
288
|
+
if ((_e = (_d = integration.filtering) === null || _d === void 0 ? void 0 : _d.integrationFileStatus) === null || _e === void 0 ? void 0 : _e.isNew) {
|
|
289
|
+
filterItems.push({
|
|
290
|
+
value: 'isNew',
|
|
291
|
+
label: 'New',
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
if ((_g = (_f = integration.filtering) === null || _f === void 0 ? void 0 : _f.integrationFileStatus) === null || _g === void 0 ? void 0 : _g.isUpdated) {
|
|
295
|
+
filterItems.push({
|
|
296
|
+
value: 'isUpdated',
|
|
297
|
+
label: 'Modified',
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
if ((_j = (_h = integration.filtering) === null || _h === void 0 ? void 0 : _h.integrationFileStatus) === null || _j === void 0 ? void 0 : _j.failed) {
|
|
301
|
+
filterItems.push({
|
|
302
|
+
value: 'failed',
|
|
303
|
+
label: 'Sync Error',
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
if ((_l = (_k = integration.filtering) === null || _k === void 0 ? void 0 : _k.integrationFileStatus) === null || _l === void 0 ? void 0 : _l.notSynced) {
|
|
307
|
+
filterItems.push({
|
|
308
|
+
value: 'notSynced',
|
|
309
|
+
label: 'Never Synced',
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
integration.filtering = Object.assign(Object.assign({}, (integration.filtering || {})), { integrationFilterConfig: filterItems.length > 1
|
|
313
|
+
? [
|
|
314
|
+
{
|
|
315
|
+
key: 'file',
|
|
316
|
+
type: 'list_single',
|
|
317
|
+
label: 'File',
|
|
318
|
+
items: filterItems,
|
|
319
|
+
defaultValue: 'all',
|
|
320
|
+
defaultLabel: 'All',
|
|
321
|
+
},
|
|
322
|
+
]
|
|
323
|
+
: [] });
|
|
324
|
+
}
|
|
261
325
|
if (!integration.userErrorLifetimeDays) {
|
|
262
326
|
integration.userErrorLifetimeDays = 30;
|
|
263
327
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ExtendedResult, IntegrationFile, IntegrationLogic, IntegrationRequest, SkipIntegrationNodes, TreeItem, UpdateIntegrationRequest } from '../types';
|
|
1
|
+
import { ExtendedResult, IntegrationFile, IntegrationLogic, IntegrationRequest, SkipIntegrationNodes, TreeItem, UpdateIntegrationRequest, Provider } from '../types';
|
|
2
2
|
import { JobClient } from './types';
|
|
3
3
|
import Crowdin from '@crowdin/crowdin-api-client';
|
|
4
4
|
import { SourceFilesModel } from '@crowdin/crowdin-api-client';
|
|
@@ -17,3 +17,9 @@ export declare function getExcludedTargetLanguages({ client, projectId, language
|
|
|
17
17
|
languages: string[];
|
|
18
18
|
}): Promise<string[]>;
|
|
19
19
|
export declare function filterLanguages(request: UpdateIntegrationRequest, files: SourceFilesModel.File[]): UpdateIntegrationRequest;
|
|
20
|
+
export declare function buildPath(file: TreeItem, files: TreeItem[]): string;
|
|
21
|
+
export declare function getParentPaths(filePath: string): Set<string>;
|
|
22
|
+
export declare function getParentFiles(allFiles: TreeItem[], fileCollection: TreeItem[]): TreeItem[];
|
|
23
|
+
export declare function filterFilesByPatterns(files: TreeItem[], patterns: string[]): TreeItem[];
|
|
24
|
+
export declare function filterFilesByPath(files: TreeItem[], includePatterns?: string[], excludePatterns?: string[]): TreeItem[];
|
|
25
|
+
export declare function updateSyncedData(clientId: string, crowdinId: string, payload: any[], provider?: Provider): Promise<void>;
|
|
@@ -8,11 +8,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.filterLanguages = exports.getExcludedTargetLanguages = exports.markUnsyncedFiles = exports.isExtendedResultType = exports.expandFilesTree = exports.skipFilesByRegex = void 0;
|
|
13
|
-
const types_1 = require("
|
|
15
|
+
exports.updateSyncedData = exports.filterFilesByPath = exports.filterFilesByPatterns = exports.getParentFiles = exports.getParentPaths = exports.buildPath = exports.filterLanguages = exports.getExcludedTargetLanguages = exports.markUnsyncedFiles = exports.isExtendedResultType = exports.expandFilesTree = exports.skipFilesByRegex = void 0;
|
|
16
|
+
const types_1 = require("../types");
|
|
17
|
+
const types_2 = require("./types");
|
|
14
18
|
const storage_1 = require("../../../storage");
|
|
15
19
|
const util_1 = require("../../../util");
|
|
20
|
+
const minimatch_1 = require("minimatch");
|
|
21
|
+
const lodash_uniqby_1 = __importDefault(require("lodash.uniqby"));
|
|
16
22
|
function skipFilesByRegex(files, skipIntegrationNodes) {
|
|
17
23
|
if (!Array.isArray(files)) {
|
|
18
24
|
return [];
|
|
@@ -34,7 +40,7 @@ exports.skipFilesByRegex = skipFilesByRegex;
|
|
|
34
40
|
function expandFilesTree(nodes, req, integration, job) {
|
|
35
41
|
var _a;
|
|
36
42
|
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
-
if (job &&
|
|
43
|
+
if (job && types_2.JobStatus.CANCELED === ((_a = (yield job.get())) === null || _a === void 0 ? void 0 : _a.status)) {
|
|
38
44
|
throw new Error('Job canceled');
|
|
39
45
|
}
|
|
40
46
|
const files = nodes.filter((file) => file.nodeType === undefined || file.nodeType === '1');
|
|
@@ -121,3 +127,73 @@ function filterLanguages(request, files) {
|
|
|
121
127
|
return result;
|
|
122
128
|
}
|
|
123
129
|
exports.filterLanguages = filterLanguages;
|
|
130
|
+
function buildPath(file, files) {
|
|
131
|
+
const filePath = `/${file.name}`;
|
|
132
|
+
if (!file.parentId) {
|
|
133
|
+
return filePath;
|
|
134
|
+
}
|
|
135
|
+
const parent = files.find((f) => f.id === file.parentId);
|
|
136
|
+
if (!parent) {
|
|
137
|
+
return filePath;
|
|
138
|
+
}
|
|
139
|
+
const parentPath = buildPath(parent, files);
|
|
140
|
+
return `${parentPath}${filePath}`;
|
|
141
|
+
}
|
|
142
|
+
exports.buildPath = buildPath;
|
|
143
|
+
function getParentPaths(filePath) {
|
|
144
|
+
const parentPaths = new Set();
|
|
145
|
+
const parts = filePath.split('/');
|
|
146
|
+
let currentPath = '';
|
|
147
|
+
for (let i = 1; i < parts.length - 1; i++) {
|
|
148
|
+
currentPath += '/' + parts[i];
|
|
149
|
+
parentPaths.add(currentPath);
|
|
150
|
+
}
|
|
151
|
+
return parentPaths;
|
|
152
|
+
}
|
|
153
|
+
exports.getParentPaths = getParentPaths;
|
|
154
|
+
function getParentFiles(allFiles, fileCollection) {
|
|
155
|
+
const parentPaths = new Set();
|
|
156
|
+
fileCollection
|
|
157
|
+
.filter((file) => !!file.path)
|
|
158
|
+
.forEach((file) => {
|
|
159
|
+
const paths = getParentPaths(file.path);
|
|
160
|
+
paths.forEach((path) => parentPaths.add(path));
|
|
161
|
+
});
|
|
162
|
+
return allFiles.filter((file) => file.path && parentPaths.has(file.path));
|
|
163
|
+
}
|
|
164
|
+
exports.getParentFiles = getParentFiles;
|
|
165
|
+
function filterFilesByPatterns(files, patterns) {
|
|
166
|
+
return files.filter((file) => patterns.some((pattern) => (0, minimatch_1.minimatch)(file.path || '', pattern.trim())));
|
|
167
|
+
}
|
|
168
|
+
exports.filterFilesByPatterns = filterFilesByPatterns;
|
|
169
|
+
function filterFilesByPath(files, includePatterns, excludePatterns) {
|
|
170
|
+
const filesWithPaths = files.map((file) => (Object.assign(Object.assign({}, file), { path: buildPath(file, files) })));
|
|
171
|
+
let filteredFiles = [...filesWithPaths];
|
|
172
|
+
if (includePatterns === null || includePatterns === void 0 ? void 0 : includePatterns.length) {
|
|
173
|
+
const includedFiles = filterFilesByPatterns(filteredFiles, includePatterns);
|
|
174
|
+
const parentFiles = getParentFiles(filesWithPaths, includedFiles);
|
|
175
|
+
filteredFiles = [...new Set([...includedFiles, ...parentFiles])];
|
|
176
|
+
}
|
|
177
|
+
if (excludePatterns === null || excludePatterns === void 0 ? void 0 : excludePatterns.length) {
|
|
178
|
+
const excludedFiles = filterFilesByPatterns(filteredFiles, excludePatterns);
|
|
179
|
+
const remainingFiles = filteredFiles.filter((file) => !excludedFiles.includes(file));
|
|
180
|
+
const parentFiles = getParentFiles(filesWithPaths, remainingFiles);
|
|
181
|
+
filteredFiles = [...new Set([...remainingFiles, ...parentFiles])];
|
|
182
|
+
}
|
|
183
|
+
return filteredFiles;
|
|
184
|
+
}
|
|
185
|
+
exports.filterFilesByPath = filterFilesByPath;
|
|
186
|
+
function updateSyncedData(clientId, crowdinId, payload, provider = types_1.Provider.INTEGRATION) {
|
|
187
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
188
|
+
const existingSyncedData = yield (0, storage_1.getStorage)().getSyncedData(clientId, crowdinId, provider);
|
|
189
|
+
if (existingSyncedData) {
|
|
190
|
+
const existingFiles = JSON.parse(existingSyncedData.files);
|
|
191
|
+
const mergedFiles = (0, lodash_uniqby_1.default)([...existingFiles, ...payload], 'id');
|
|
192
|
+
yield (0, storage_1.getStorage)().updateSyncedData(JSON.stringify(mergedFiles), clientId, crowdinId, provider);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
yield (0, storage_1.getStorage)().saveSyncedData(JSON.stringify(payload), clientId, crowdinId, provider);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
exports.updateSyncedData = updateSyncedData;
|
|
@@ -113,3 +113,11 @@ export interface UnsyncedFiles {
|
|
|
113
113
|
files: string;
|
|
114
114
|
}
|
|
115
115
|
export type GetUnsyncedFiles = Pick<UnsyncedFiles, 'integrationId' | 'crowdinId'>;
|
|
116
|
+
export interface IntegrationSyncedData {
|
|
117
|
+
id: number;
|
|
118
|
+
integrationId: string;
|
|
119
|
+
crowdinId: string;
|
|
120
|
+
type: string;
|
|
121
|
+
updatedAt: string;
|
|
122
|
+
files?: any;
|
|
123
|
+
}
|
package/out/storage/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IntegrationConfig, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings, IntegrationWebhooks, Provider } from '../modules/integration/types';
|
|
2
2
|
import { Config, CrowdinCredentials, UnauthorizedConfig } from '../types';
|
|
3
|
-
import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetFileTranslationCacheByLanguageParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams, GetFileTranslationCache, UnsyncedFiles, GetUnsyncedFiles } from '../modules/integration/util/types';
|
|
3
|
+
import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetFileTranslationCacheByLanguageParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams, GetFileTranslationCache, UnsyncedFiles, GetUnsyncedFiles, IntegrationSyncedData } from '../modules/integration/util/types';
|
|
4
4
|
import { UserErrors } from './types';
|
|
5
5
|
export declare const TABLES: {
|
|
6
6
|
crowdin_credentials: string;
|
|
@@ -79,6 +79,9 @@ export interface Storage {
|
|
|
79
79
|
}, params?: any[]): Promise<any[]>;
|
|
80
80
|
updateRecord(tableName: string, data: Record<string, any>, whereClause: string, params?: any[]): Promise<void>;
|
|
81
81
|
deleteRecord(tableName: string, whereClause: string, params?: any[]): Promise<void>;
|
|
82
|
+
saveSyncedData(files: any, integrationId: string, crowdinId: string, type: string): Promise<void>;
|
|
83
|
+
updateSyncedData(files: any, integrationId: string, crowdinId: string, type: string): Promise<void>;
|
|
84
|
+
getSyncedData(integrationId: string, crowdinId: string, type: string): Promise<IntegrationSyncedData | undefined>;
|
|
82
85
|
}
|
|
83
86
|
export declare function initialize(config: Config | UnauthorizedConfig): Promise<void>;
|
|
84
87
|
export declare function getStorage(): Storage;
|
package/out/storage/mysql.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Storage } from '.';
|
|
2
2
|
import { CrowdinCredentials } from '../types';
|
|
3
|
-
import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetFileTranslationCacheByLanguageParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams, GetFileTranslationCache, UnsyncedFiles, GetUnsyncedFiles } from '../modules/integration/util/types';
|
|
3
|
+
import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetFileTranslationCacheByLanguageParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams, GetFileTranslationCache, UnsyncedFiles, GetUnsyncedFiles, IntegrationSyncedData } from '../modules/integration/util/types';
|
|
4
4
|
import { IntegrationConfig, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings, IntegrationWebhooks } from '../modules/integration/types';
|
|
5
5
|
import { UserErrors } from './types';
|
|
6
6
|
export interface MySQLStorageConfig {
|
|
@@ -29,6 +29,7 @@ export declare class MySQLStorage implements Storage {
|
|
|
29
29
|
job: string;
|
|
30
30
|
translation_file_cache: string;
|
|
31
31
|
unsynced_files: string;
|
|
32
|
+
synced_data: string;
|
|
32
33
|
};
|
|
33
34
|
constructor(config: MySQLStorageConfig);
|
|
34
35
|
executeQuery<T>(command: (connection: any) => Promise<T>): Promise<T>;
|
|
@@ -95,4 +96,7 @@ export declare class MySQLStorage implements Storage {
|
|
|
95
96
|
}, params?: any[]): Promise<any[]>;
|
|
96
97
|
updateRecord(tableName: string, data: Record<string, any>, whereClause: string, params?: any[]): Promise<void>;
|
|
97
98
|
deleteRecord(tableName: string, whereClause: string, params?: any[]): Promise<void>;
|
|
99
|
+
saveSyncedData(files: any, integrationId: string, crowdinId: string, type: string): Promise<void>;
|
|
100
|
+
updateSyncedData(files: any, integrationId: string, crowdinId: string, type: string): Promise<void>;
|
|
101
|
+
getSyncedData(integrationId: string, crowdinId: string, type: string): Promise<IntegrationSyncedData | undefined>;
|
|
98
102
|
}
|
package/out/storage/mysql.js
CHANGED
|
@@ -116,6 +116,14 @@ class MySQLStorage {
|
|
|
116
116
|
integration_id varchar(255) not null,
|
|
117
117
|
crowdin_id varchar(255) not null,
|
|
118
118
|
files text
|
|
119
|
+
)`,
|
|
120
|
+
synced_data: `(
|
|
121
|
+
id int auto_increment primary key,
|
|
122
|
+
files text,
|
|
123
|
+
integration_id varchar(255) not null,
|
|
124
|
+
crowdin_id varchar(255) not null,
|
|
125
|
+
type varchar(255) not null,
|
|
126
|
+
updated_at varchar(255) null,
|
|
119
127
|
)`,
|
|
120
128
|
};
|
|
121
129
|
this.config = config;
|
|
@@ -841,5 +849,26 @@ class MySQLStorage {
|
|
|
841
849
|
}));
|
|
842
850
|
});
|
|
843
851
|
}
|
|
852
|
+
saveSyncedData(files, integrationId, crowdinId, type) {
|
|
853
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
854
|
+
yield this.dbPromise;
|
|
855
|
+
yield this.executeQuery((connection) => connection.execute('INSERT INTO synced_data(files, integration_id, crowdin_id, type, updated_at) VALUES (?, ?, ?, ?, ?)', [files, integrationId, crowdinId, type, Date.now().toString()]));
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
updateSyncedData(files, integrationId, crowdinId, type) {
|
|
859
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
860
|
+
yield this.dbPromise;
|
|
861
|
+
yield this.executeQuery((connection) => connection.execute('UPDATE synced_data SET files = ?, updated_at = ? WHERE integration_id = ? AND crowdin_id = ? AND type = ?', [files, Date.now().toString(), integrationId, crowdinId, type]));
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
getSyncedData(integrationId, crowdinId, type) {
|
|
865
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
866
|
+
yield this.dbPromise;
|
|
867
|
+
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
868
|
+
const [rows] = yield connection.execute('SELECT id, files, integration_id as "integrationId", crowdin_id as "crowdinId", type, updated_at as "updatedAt" FROM synced_data WHERE integration_id = ? AND crowdin_id = ? AND type = ?', [integrationId, crowdinId, type]);
|
|
869
|
+
return (rows || [])[0];
|
|
870
|
+
}));
|
|
871
|
+
});
|
|
872
|
+
}
|
|
844
873
|
}
|
|
845
874
|
exports.MySQLStorage = MySQLStorage;
|
package/out/storage/postgre.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Client } from 'pg';
|
|
|
2
2
|
import { Storage } from '.';
|
|
3
3
|
import { CrowdinCredentials } from '../types';
|
|
4
4
|
import { IntegrationConfig, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings, IntegrationWebhooks } from '../modules/integration/types';
|
|
5
|
-
import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetFileTranslationCacheByLanguageParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams, GetFileTranslationCache, UnsyncedFiles, GetUnsyncedFiles } from '../modules/integration/util/types';
|
|
5
|
+
import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetFileTranslationCacheByLanguageParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams, GetFileTranslationCache, UnsyncedFiles, GetUnsyncedFiles, IntegrationSyncedData } from '../modules/integration/util/types';
|
|
6
6
|
import { UserErrors } from './types';
|
|
7
7
|
export interface PostgreStorageConfig {
|
|
8
8
|
host?: string;
|
|
@@ -39,6 +39,7 @@ export declare class PostgreStorage implements Storage {
|
|
|
39
39
|
job: string;
|
|
40
40
|
translation_file_cache: string;
|
|
41
41
|
unsynced_files: string;
|
|
42
|
+
synced_data: string;
|
|
42
43
|
};
|
|
43
44
|
tableIndexes: TableIndexes;
|
|
44
45
|
constructor(config: PostgreStorageConfig, directoryPath: string | null);
|
|
@@ -110,5 +111,8 @@ export declare class PostgreStorage implements Storage {
|
|
|
110
111
|
}, params?: any[]): Promise<any[]>;
|
|
111
112
|
updateRecord(tableName: string, data: Record<string, any>, whereClause: string, params?: any[]): Promise<void>;
|
|
112
113
|
deleteRecord(tableName: string, whereClause: string, params?: any[]): Promise<void>;
|
|
114
|
+
saveSyncedData(files: any, integrationId: string, crowdinId: string, type: string): Promise<void>;
|
|
115
|
+
updateSyncedData(files: any, integrationId: string, crowdinId: string, type: string): Promise<void>;
|
|
116
|
+
getSyncedData(integrationId: string, crowdinId: string, type: string): Promise<IntegrationSyncedData | undefined>;
|
|
113
117
|
}
|
|
114
118
|
export {};
|
package/out/storage/postgre.js
CHANGED
|
@@ -119,6 +119,14 @@ class PostgreStorage {
|
|
|
119
119
|
integration_id varchar not null,
|
|
120
120
|
crowdin_id varchar not null,
|
|
121
121
|
files varchar
|
|
122
|
+
)`,
|
|
123
|
+
synced_data: `(
|
|
124
|
+
id serial primary key,
|
|
125
|
+
files varchar,
|
|
126
|
+
integration_id varchar not null,
|
|
127
|
+
crowdin_id varchar not null,
|
|
128
|
+
type varchar not null,
|
|
129
|
+
updated_at varchar null
|
|
122
130
|
)`,
|
|
123
131
|
};
|
|
124
132
|
this.tableIndexes = {
|
|
@@ -889,5 +897,26 @@ class PostgreStorage {
|
|
|
889
897
|
}));
|
|
890
898
|
});
|
|
891
899
|
}
|
|
900
|
+
saveSyncedData(files, integrationId, crowdinId, type) {
|
|
901
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
902
|
+
yield this.dbPromise;
|
|
903
|
+
yield this.executeQuery((client) => client.query('INSERT INTO synced_data(files, integration_id, crowdin_id, type, updated_at) VALUES ($1, $2, $3, $4, $5)', [files, integrationId, crowdinId, type, Date.now().toString()]));
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
updateSyncedData(files, integrationId, crowdinId, type) {
|
|
907
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
908
|
+
yield this.dbPromise;
|
|
909
|
+
yield this.executeQuery((client) => client.query('UPDATE synced_data SET files = $1, updated_at = $2 WHERE integration_id = $3 AND crowdin_id = $4 AND type = $5', [files, Date.now().toString(), integrationId, crowdinId, type]));
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
getSyncedData(integrationId, crowdinId, type) {
|
|
913
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
914
|
+
yield this.dbPromise;
|
|
915
|
+
return this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
|
|
916
|
+
const res = yield client.query('SELECT id, files, integration_id as "integrationId", crowdin_id as "crowdinId", type, updated_at as "updatedAt" FROM synced_data WHERE integration_id = $1 AND crowdin_id = $2 AND type = $3', [integrationId, crowdinId, type]);
|
|
917
|
+
return res === null || res === void 0 ? void 0 : res.rows[0];
|
|
918
|
+
}));
|
|
919
|
+
});
|
|
920
|
+
}
|
|
892
921
|
}
|
|
893
922
|
exports.PostgreStorage = PostgreStorage;
|
package/out/storage/sqlite.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Storage } from '.';
|
|
2
2
|
import { CrowdinCredentials } from '../types';
|
|
3
3
|
import { IntegrationConfig, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings, IntegrationWebhooks } from '../modules/integration/types';
|
|
4
|
-
import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetFileTranslationCacheByLanguageParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams, GetFileTranslationCache, UnsyncedFiles, GetUnsyncedFiles } from '../modules/integration/util/types';
|
|
4
|
+
import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetFileTranslationCacheByLanguageParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams, GetFileTranslationCache, UnsyncedFiles, GetUnsyncedFiles, IntegrationSyncedData } from '../modules/integration/util/types';
|
|
5
5
|
import { UserErrors } from './types';
|
|
6
6
|
export interface SQLiteStorageConfig {
|
|
7
7
|
dbFolder: string;
|
|
@@ -24,6 +24,7 @@ export declare class SQLiteStorage implements Storage {
|
|
|
24
24
|
job: string;
|
|
25
25
|
translation_file_cache: string;
|
|
26
26
|
unsynced_files: string;
|
|
27
|
+
synced_data: string;
|
|
27
28
|
};
|
|
28
29
|
constructor(config: SQLiteStorageConfig);
|
|
29
30
|
private _run;
|
|
@@ -98,4 +99,7 @@ export declare class SQLiteStorage implements Storage {
|
|
|
98
99
|
}, params?: any[]): Promise<any[]>;
|
|
99
100
|
updateRecord(tableName: string, data: Record<string, any>, whereClause: string, params?: any[]): Promise<void>;
|
|
100
101
|
deleteRecord(tableName: string, whereClause: string, params?: any[]): Promise<void>;
|
|
102
|
+
saveSyncedData(files: any, integrationId: string, crowdinId: string, type: string): Promise<void>;
|
|
103
|
+
updateSyncedData(files: any, integrationId: string, crowdinId: string, type: string): Promise<void>;
|
|
104
|
+
getSyncedData(integrationId: string, crowdinId: string, type: string): Promise<IntegrationSyncedData | undefined>;
|
|
101
105
|
}
|
package/out/storage/sqlite.js
CHANGED
|
@@ -115,6 +115,14 @@ class SQLiteStorage {
|
|
|
115
115
|
integration_id varchar not null,
|
|
116
116
|
crowdin_id varchar not null,
|
|
117
117
|
files varchar null
|
|
118
|
+
)`,
|
|
119
|
+
synced_data: `(
|
|
120
|
+
id integer not null primary key autoincrement,
|
|
121
|
+
files varchar null,
|
|
122
|
+
integration_id varchar not null,
|
|
123
|
+
crowdin_id varchar not null,
|
|
124
|
+
type varchar not null,
|
|
125
|
+
updated_at varchar null
|
|
118
126
|
)`,
|
|
119
127
|
};
|
|
120
128
|
this.config = config;
|
|
@@ -751,5 +759,19 @@ class SQLiteStorage {
|
|
|
751
759
|
yield this.run(query, params);
|
|
752
760
|
});
|
|
753
761
|
}
|
|
762
|
+
saveSyncedData(files, integrationId, crowdinId, type) {
|
|
763
|
+
return this.run('INSERT INTO synced_data(files, integration_id, crowdin_id, type, updated_at) VALUES (?, ?, ?, ?, ?)', [files, integrationId, crowdinId, type, Date.now().toString()]);
|
|
764
|
+
}
|
|
765
|
+
updateSyncedData(files, integrationId, crowdinId, type) {
|
|
766
|
+
return this.run('UPDATE synced_data SET files = ?, updated_at = ? WHERE integration_id = ? AND crowdin_id = ? AND type = ?', [files, Date.now().toString(), integrationId, crowdinId, type]);
|
|
767
|
+
}
|
|
768
|
+
getSyncedData(integrationId, crowdinId, type) {
|
|
769
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
770
|
+
const row = yield this.get('SELECT id, files, integration_id as integrationId, crowdin_id as crowdinId, type, updated_at as updatedAt FROM synced_data WHERE integration_id = ? AND crowdin_id = ? AND type = ?', [integrationId, crowdinId, type]);
|
|
771
|
+
if (row) {
|
|
772
|
+
return row;
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
}
|
|
754
776
|
}
|
|
755
777
|
exports.SQLiteStorage = SQLiteStorage;
|
|
@@ -54,44 +54,48 @@
|
|
|
54
54
|
</div>
|
|
55
55
|
</div>
|
|
56
56
|
<crowdin-simple-integration
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
57
|
+
async-progress
|
|
58
|
+
{{#if syncNewElements.crowdin}}
|
|
59
|
+
skip-crowdin-auto-schedule
|
|
60
|
+
{{/if}}
|
|
61
|
+
{{#if syncNewElements.integration}}
|
|
62
|
+
skip-integration-auto-schedule
|
|
63
|
+
{{/if}}
|
|
64
|
+
{{#or withCronSync.crowdin webhooks.crowdin}}
|
|
65
|
+
crowdin-schedule="true"
|
|
66
|
+
{{/or}}
|
|
67
|
+
{{#or withCronSync.integration webhooks.integration}}
|
|
68
|
+
integration-schedule="true"
|
|
69
|
+
{{/or}}
|
|
70
|
+
{{#if integrationOneLevelFetching}}
|
|
71
|
+
integration-one-level-fetching="true"
|
|
72
|
+
{{/if}}
|
|
73
|
+
{{#if integrationSearchListener}}
|
|
74
|
+
allow-integration-filter-change-listener="true"
|
|
75
|
+
{{/if}}
|
|
76
|
+
{{#if integrationPagination}}
|
|
77
|
+
integration-load-more-files="true"
|
|
78
|
+
{{/if}}
|
|
79
|
+
integration-name="{{name}}"
|
|
80
|
+
integration-logo="logo.png"
|
|
81
|
+
{{#if uploadTranslations}}
|
|
82
|
+
{{#if excludedTargetLanguages}}
|
|
83
|
+
integration-button-menu-items='[{"label":"Sync translations", "title":"Sync translations to Crowdin", "action":"uploadTranslations"}, {"label":"Select target languages", "title":"Upload file for translation into selected languages", "action":"excludedTargetLanguages"}]'
|
|
84
|
+
{{else}}
|
|
85
|
+
integration-button-menu-items='[{"label":"Sync translations", "title":"Sync translations to Crowdin", "action":"uploadTranslations"}]'
|
|
86
|
+
{{/if}}
|
|
87
|
+
{{else}}
|
|
88
|
+
{{#if excludedTargetLanguages}}
|
|
89
|
+
integration-button-menu-items='[{"label":"Select target languages", "title":"Upload file for translation into selected languages", "action":"excludedTargetLanguages"}]'
|
|
90
|
+
{{/if}}
|
|
91
|
+
{{/if}}
|
|
92
|
+
{{#if filtering.crowdinLanguages}}
|
|
93
|
+
crowdin-filter
|
|
94
|
+
{{/if}}
|
|
95
|
+
{{#if filtering.integrationFilterConfig}}
|
|
96
|
+
integration-filter
|
|
97
|
+
integration-filter-config='{{filtering.integrationFilterConfig}}'
|
|
98
|
+
{{/if}}
|
|
95
99
|
>
|
|
96
100
|
</crowdin-simple-integration>
|
|
97
101
|
<div id="user-errors" class="hidden">
|
|
@@ -582,6 +586,9 @@
|
|
|
582
586
|
labels: e.labels,
|
|
583
587
|
};
|
|
584
588
|
if (e.type) {
|
|
589
|
+
item.isNew = e.isNew;
|
|
590
|
+
item.isUpdated = e.isUpdated;
|
|
591
|
+
item.notSynced = e.notSynced;
|
|
585
592
|
item.type = e.type;
|
|
586
593
|
item.node_type = fileType;
|
|
587
594
|
} else {
|
|
@@ -1135,7 +1142,7 @@
|
|
|
1135
1142
|
{{#if configurationFields}}
|
|
1136
1143
|
const settingsModal = document.getElementById('settings-modal');
|
|
1137
1144
|
const settingsSaveBtn = document.getElementById('settings-save-btn');
|
|
1138
|
-
let config = JSON.parse('{{{config}}}');
|
|
1145
|
+
let config = JSON.parse('{{{config}}}'.replace(/\n/g, '\\n'));
|
|
1139
1146
|
const newCrowdinFiles = config?.['new-crowdin-files'];
|
|
1140
1147
|
const newIntegrationFiles = config?.['new-integration-files'];
|
|
1141
1148
|
|
|
@@ -1157,6 +1164,9 @@
|
|
|
1157
1164
|
}
|
|
1158
1165
|
} else if (el.tagName.toLowerCase() === 'crowdin-checkbox') {
|
|
1159
1166
|
el.checked = !!value;
|
|
1167
|
+
} else if (el.tagName.toLowerCase() === 'crowdin-textarea') {
|
|
1168
|
+
el.value = value;
|
|
1169
|
+
el.setValue(value);
|
|
1160
1170
|
} else {
|
|
1161
1171
|
el.value = value;
|
|
1162
1172
|
}
|
|
@@ -1169,7 +1179,7 @@
|
|
|
1169
1179
|
function saveSettings() {
|
|
1170
1180
|
setLoader('#settings-modal');
|
|
1171
1181
|
const settingsElements = Array.from(document.getElementById('modal-content').children);
|
|
1172
|
-
const tags = ['crowdin-checkbox', 'crowdin-select', 'crowdin-input'];
|
|
1182
|
+
const tags = ['crowdin-checkbox', 'crowdin-select', 'crowdin-input', 'crowdin-textarea'];
|
|
1173
1183
|
const configReq = {};
|
|
1174
1184
|
settingsElements
|
|
1175
1185
|
.filter(e => tags.includes(e.tagName.toLowerCase()))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crowdin/app-project-module",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.86.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",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"@aws-sdk/client-s3": "^3.758.0",
|
|
23
23
|
"@aws-sdk/s3-request-presigner": "^3.758.0",
|
|
24
24
|
"@crowdin/crowdin-apps-functions": "^0.12.0",
|
|
25
|
-
"@crowdin/logs-formatter": "^2.1.
|
|
25
|
+
"@crowdin/logs-formatter": "^2.1.8",
|
|
26
26
|
"@godaddy/terminus": "^4.12.1",
|
|
27
27
|
"@monaco-editor/react": "^4.7.0",
|
|
28
28
|
"amqplib": "^0.10.5",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"lodash.isstring": "^4.0.1",
|
|
35
35
|
"lodash.snakecase": "^4.1.1",
|
|
36
36
|
"lodash.uniqby": "^4.7.0",
|
|
37
|
+
"minimatch": "^10.0.1",
|
|
37
38
|
"mysql2": "^3.12.0",
|
|
38
39
|
"node-cron": "^3.0.3",
|
|
39
40
|
"pg": "^8.13.3",
|
|
@@ -68,6 +69,7 @@
|
|
|
68
69
|
"@types/lodash.isstring": "^4.0.9",
|
|
69
70
|
"@types/lodash.snakecase": "^4.1.9",
|
|
70
71
|
"@types/lodash.uniqby": "^4.7.9",
|
|
72
|
+
"@types/minimatch": "^5.1.2",
|
|
71
73
|
"@types/node": "^16.18.126",
|
|
72
74
|
"@types/node-cron": "^3.0.11",
|
|
73
75
|
"@types/pg": "^8.11.11",
|