@crowdin/app-project-module 0.92.0 → 0.94.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.
@@ -16,7 +16,7 @@ const types_1 = require("../types");
16
16
  const storage_1 = require("../../../storage");
17
17
  function handle(integration) {
18
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;
19
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
20
20
  const { parent_id: parentId, search, page } = req.query;
21
21
  req.logInfo('Received request to get integration data');
22
22
  let message;
@@ -34,15 +34,18 @@ function handle(integration) {
34
34
  else {
35
35
  files = result || [];
36
36
  }
37
- files = (0, files_1.skipFilesByRegex)(files, integration.skipIntegrationNodes);
37
+ if ((appSettings === null || appSettings === void 0 ? void 0 : appSettings.skipIntegrationNodesToggle) === true ||
38
+ ((appSettings === null || appSettings === void 0 ? void 0 : appSettings.skipIntegrationNodesToggle) === undefined && ((_a = integration.skipIntegrationNodesToggle) === null || _a === void 0 ? void 0 : _a.value))) {
39
+ files = (0, files_1.skipFilesByRegex)(files, integration.skipIntegrationNodes);
40
+ }
38
41
  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);
42
+ const includePatterns = (_b = appSettings === null || appSettings === void 0 ? void 0 : appSettings.includeByFilePath) === null || _b === void 0 ? void 0 : _b.split('\n').filter(Boolean);
43
+ const excludePatterns = (_c = appSettings === null || appSettings === void 0 ? void 0 : appSettings.excludeByFilePath) === null || _c === void 0 ? void 0 : _c.split('\n').filter(Boolean);
41
44
  files = (0, files_1.filterFilesByPath)(files, includePatterns, excludePatterns);
42
45
  }
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
+ if (((_e = (_d = integration.filtering) === null || _d === void 0 ? void 0 : _d.integrationFileStatus) === null || _e === void 0 ? void 0 : _e.isNew) ||
47
+ ((_g = (_f = integration.filtering) === null || _f === void 0 ? void 0 : _f.integrationFileStatus) === null || _g === void 0 ? void 0 : _g.isUpdated) ||
48
+ ((_j = (_h = integration.filtering) === null || _h === void 0 ? void 0 : _h.integrationFileStatus) === null || _j === void 0 ? void 0 : _j.notSynced)) {
46
49
  const syncedData = yield (0, storage_1.getStorage)().getSyncedData(clientId, crowdinId, types_1.Provider.INTEGRATION);
47
50
  const syncedFiles = (syncedData === null || syncedData === void 0 ? void 0 : syncedData.files) ? JSON.parse(syncedData.files) : [];
48
51
  const lastSyncTimestamp = (syncedData === null || syncedData === void 0 ? void 0 : syncedData.updatedAt) ? Number(syncedData.updatedAt) : null;
@@ -25,6 +25,21 @@ function handle(config, integration) {
25
25
  },
26
26
  });
27
27
  }
28
+ if (integration.validateSettings) {
29
+ const validationResult = yield integration.validateSettings({
30
+ client: req.crowdinApiClient,
31
+ credentials: req.integrationCredentials,
32
+ appSettings,
33
+ });
34
+ if (validationResult && Object.keys(validationResult).length > 0) {
35
+ return res.status(400).json({
36
+ error: {
37
+ type: 'validation_error',
38
+ details: validationResult,
39
+ },
40
+ });
41
+ }
42
+ }
28
43
  const clientId = req.crowdinContext.clientId;
29
44
  req.logInfo(`Saving settings ${JSON.stringify(appSettings, null, 2)}`);
30
45
  const integrationConfig = yield (0, storage_1.getStorage)().getIntegrationConfig(clientId);
@@ -19,6 +19,16 @@ export interface IntegrationLogic extends ModuleKey {
19
19
  * flag that defines if the app should have a dedicated root folder in Crowdin files, default 'false'
20
20
  */
21
21
  withRootFolder?: boolean;
22
+ /**
23
+ * Validate integration settings before saving
24
+ */
25
+ validateSettings?: ({ client, credentials, appSettings, }: {
26
+ client: Crowdin;
27
+ credentials: any;
28
+ appSettings: AppSettings;
29
+ }) => Promise<{
30
+ [key: string]: string;
31
+ } | null>;
22
32
  /**
23
33
  * function which will be used to check connection with integration service
24
34
  */
@@ -186,7 +196,18 @@ export interface IntegrationLogic extends ModuleKey {
186
196
  icon: boolean;
187
197
  close: boolean;
188
198
  };
199
+ /**
200
+ * Skip integration nodes
201
+ */
189
202
  skipIntegrationNodes?: SkipIntegrationNodes;
203
+ /**
204
+ * Configuration for toggling skipIntegrationNodes functionality with custom title and description
205
+ */
206
+ skipIntegrationNodesToggle?: {
207
+ title: string;
208
+ description: string;
209
+ value: boolean;
210
+ };
190
211
  /**
191
212
  * Async progress checking time interval to update job progress, im ms.
192
213
  *
@@ -287,6 +287,17 @@ function applyIntegrationModuleDefaults(config, integration) {
287
287
  helpText: 'Enter the path patterns for files or folders to exclude. Use wildcard selectors like `*` and `**` to match multiple files. Example: `/drafts/**`',
288
288
  });
289
289
  }
290
+ if (integration.skipIntegrationNodes && integration.skipIntegrationNodesToggle) {
291
+ defaultSettings.push({
292
+ key: 'skipIntegrationNodesToggle',
293
+ label: integration.skipIntegrationNodesToggle.title,
294
+ type: 'checkbox',
295
+ helpText: integration.skipIntegrationNodesToggle.description,
296
+ defaultValue: integration.skipIntegrationNodesToggle.value,
297
+ category: types_1.DefaultCategory.GENERAL,
298
+ position: 7,
299
+ });
300
+ }
290
301
  return [...defaultSettings, ...fields];
291
302
  });
292
303
  if (!integration.checkConnection) {
@@ -391,13 +402,11 @@ function getOAuthLoginFormId(clientId) {
391
402
  exports.getOAuthLoginFormId = getOAuthLoginFormId;
392
403
  function groupFieldsByCategory(fields) {
393
404
  const groupedFields = fields.reduce((acc, field) => {
394
- if ('key' in field) {
395
- const category = field.category || types_1.DefaultCategory.GENERAL;
396
- if (!acc[category]) {
397
- acc[category] = [];
398
- }
399
- acc[category].push(field);
405
+ const category = (field === null || field === void 0 ? void 0 : field.category) || types_1.DefaultCategory.GENERAL;
406
+ if (!acc[category]) {
407
+ acc[category] = [];
400
408
  }
409
+ acc[category].push(field);
401
410
  return acc;
402
411
  }, {});
403
412
  // Sort fields by position within each category
@@ -51,6 +51,7 @@ function getOneLevelFetchingFiles(integration, integrationCredentials, integrati
51
51
  });
52
52
  }
53
53
  function getIntegrationSnapshot(integration, integrationCredentials, integrationSettings) {
54
+ var _a;
54
55
  return __awaiter(this, void 0, void 0, function* () {
55
56
  let files = [];
56
57
  let integrationData = [];
@@ -59,7 +60,10 @@ function getIntegrationSnapshot(integration, integrationCredentials, integration
59
60
  if (integration.integrationOneLevelFetching) {
60
61
  files = yield getOneLevelFetchingFiles(integration, integrationCredentials, integrationSettings, files);
61
62
  }
62
- files = (0, files_1.skipFilesByRegex)(files, integration.skipIntegrationNodes);
63
+ if ((integrationSettings === null || integrationSettings === void 0 ? void 0 : integrationSettings.skipIntegrationNodesToggle) === true ||
64
+ ((integrationSettings === null || integrationSettings === void 0 ? void 0 : integrationSettings.skipIntegrationNodesToggle) === null && ((_a = integration.skipIntegrationNodesToggle) === null || _a === void 0 ? void 0 : _a.value))) {
65
+ files = (0, files_1.skipFilesByRegex)(files, integration.skipIntegrationNodes);
66
+ }
63
67
  // trick for compatibility in requests and set files
64
68
  files = files.map((file) => (Object.assign(Object.assign({}, file), { parentId: file.parent_id || file.parentId,
65
69
  // eslint-disable-next-line @typescript-eslint/camelcase