@crowdin/app-project-module 0.85.0 → 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.
@@ -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;
@@ -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
  }
@@ -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;
@@ -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 {};
@@ -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;
@@ -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
  }
@@ -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
- 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 existing translations from {{name}} to Crowdin. Falls back to heuristics if string keys are not defined. Accuracy may vary.", "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 existing translations from {{name}} to Crowdin. Falls back to heuristics if string keys are not defined. Accuracy may vary.", "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}}
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.85.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.7",
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",