@crowdin/app-project-module 0.18.1 → 0.19.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/README.md CHANGED
@@ -87,7 +87,9 @@ const configuration = {
87
87
  crowdin: true,
88
88
  integration: true,
89
89
  },
90
- getIntegrationFiles: async (credentials, appSettings) => {
90
+ integrationOneLevelFetching: true, //turn on request when opening a directory and pass its id
91
+ integrationSearchListener: true, //turn on search listener and pass search string
92
+ getIntegrationFiles: async (credentials, appSettings, parentId, search) => {
91
93
  //here you need to fetch files/objects from integration
92
94
  return [
93
95
  {
@@ -573,6 +575,15 @@ const configuration = {
573
575
  crowdinModule.createApp(configuration);
574
576
  ```
575
577
 
578
+ By default custom file format will use `filesFolder` as a temporary folder to store huge responses. But it can be overridden:
579
+
580
+ ```javascript
581
+ configuration.customFileFormat.storeFile = (content) => {
582
+ //logic to store file, e.g. put it to AWS S3
583
+ return '<url-to-download>';
584
+ };
585
+ ```
586
+
576
587
  ### Custom MT
577
588
 
578
589
  Example of [custom mt module](https://support.crowdin.com/crowdin-apps-modules/#custom-mt-machine-translation-module).
@@ -57,8 +57,15 @@ function handleBuildFile(baseUrl, dataFolder, config, req, client, context, proj
57
57
  response.content = contentFileEncoded;
58
58
  }
59
59
  else {
60
- const storedFile = yield storeFile(res.contentFile, dataFolder);
61
- response.contentUrl = `${baseUrl}?file=${storedFile}`;
60
+ let url;
61
+ if (config.storeFile) {
62
+ url = yield config.storeFile(res.contentFile);
63
+ }
64
+ else {
65
+ const storedFile = yield storeFile(res.contentFile, dataFolder);
66
+ url = `${baseUrl}?file=${storedFile}`;
67
+ }
68
+ response.contentUrl = url;
62
69
  }
63
70
  return { response, error: res.error };
64
71
  });
@@ -80,8 +87,15 @@ function handleParseFile(baseUrl, dataFolder, config, req, client, context, proj
80
87
  response.preview = previewFileEncoded;
81
88
  }
82
89
  else {
83
- const storedFile = yield storeFile(res.previewFile, dataFolder);
84
- response.previewUrl = `${baseUrl}?file=${storedFile}`;
90
+ let url;
91
+ if (config.storeFile) {
92
+ url = yield config.storeFile(res.previewFile);
93
+ }
94
+ else {
95
+ const storedFile = yield storeFile(res.previewFile, dataFolder);
96
+ url = `${baseUrl}?file=${storedFile}`;
97
+ }
98
+ response.previewUrl = url;
85
99
  }
86
100
  }
87
101
  if (res.strings) {
@@ -100,8 +114,15 @@ function handleParseFile(baseUrl, dataFolder, config, req, client, context, proj
100
114
  response.strings = strings;
101
115
  }
102
116
  else {
103
- const storedFile = yield storeFile(stringsJson, dataFolder);
104
- response.stringsUrl = `${baseUrl}?file=${storedFile}`;
117
+ let url;
118
+ if (config.storeFile) {
119
+ url = yield config.storeFile(stringsJson);
120
+ }
121
+ else {
122
+ const storedFile = yield storeFile(stringsJson, dataFolder);
123
+ url = `${baseUrl}?file=${storedFile}`;
124
+ }
125
+ response.stringsUrl = url;
105
126
  }
106
127
  }
107
128
  return { response, error: res.error };
@@ -12,8 +12,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const util_1 = require("../util");
13
13
  function handle(config, integration) {
14
14
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
15
+ const { parent_id: parentId, search } = req.query;
15
16
  (0, util_1.log)('Recieved request to get integration data', config.logger);
16
- const files = yield integration.getIntegrationFiles(req.integrationCredentials, req.integrationSettings);
17
+ const files = yield integration.getIntegrationFiles(req.integrationCredentials, req.integrationSettings, parentId, search);
17
18
  (0, util_1.log)(`Integration data response ${JSON.stringify(files, null, 2)}`, config.logger);
18
19
  res.send(files);
19
20
  }), config.onError);
@@ -56,6 +56,8 @@ function handle(config, integration) {
56
56
  options.infoModal = integration.infoModal;
57
57
  options.withCronSync = integration.withCronSync;
58
58
  options.withWebhookSync = integration.withWebhookSync;
59
+ options.integrationOneLevelFetching = integration.integrationOneLevelFetching;
60
+ options.integrationSearchListener = integration.integrationSearchListener;
59
61
  options.checkSubscription = !(0, connection_1.isAppFree)(config);
60
62
  (0, util_1.log)(`Routing user to ${view} view`, config.logger);
61
63
  return res.render(view, options);
@@ -152,7 +152,7 @@ export interface IntegrationLogic {
152
152
  /**
153
153
  * function to get data from integration
154
154
  */
155
- getIntegrationFiles: (apiCredentials: any, config?: any) => Promise<TreeItem[]>;
155
+ getIntegrationFiles: (apiCredentials: any, config?: any, parentId?: any, search?: any) => Promise<TreeItem[]>;
156
156
  /**
157
157
  * function to update crowdin files (e.g. pull integration data to crowdin source files)
158
158
  */
@@ -188,6 +188,14 @@ export interface IntegrationLogic {
188
188
  crowdin: boolean;
189
189
  integration: boolean;
190
190
  };
191
+ /**
192
+ * Enable integration folder open event
193
+ */
194
+ integrationOneLevelFetching?: boolean;
195
+ /**
196
+ * Enable integration search event
197
+ */
198
+ integrationSearchListener?: boolean;
191
199
  }
192
200
  export declare type ConfigurationModalEntity = ConfigurationField | ConfigurationDelimeter;
193
201
  export interface ConfigurationField {
@@ -433,6 +441,10 @@ export interface CustomFileFormatLogic {
433
441
  * Used for strings export
434
442
  */
435
443
  exportStrings?: (req: Omit<ProcessFileRequest, 'jobType'>, strings: ProcessFileString[], client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<BuildFileResponse>;
444
+ /**
445
+ * Override to store huge responses (by default they will be stored in fs)
446
+ */
447
+ storeFile?: (content: string) => Promise<string>;
436
448
  }
437
449
  export interface SignaturePatterns {
438
450
  fileName?: string;
@@ -34,6 +34,12 @@
34
34
  {{#if withCronSync.integration}}
35
35
  integration-schedule="true"
36
36
  {{/if}}
37
+ {{#if integrationOneLevelFetching}}
38
+ integration-one-level-fetching="true"
39
+ {{/if}}
40
+ {{#if integrationSearchListener}}
41
+ allow-filter-change-listener="true"
42
+ {{/if}}
37
43
  integration-name="{{name}}"
38
44
  integration-logo="logo.png"
39
45
  >
@@ -136,10 +142,19 @@
136
142
  if (event.detail.componentId === 'crowdin-files' && event.detail.isOpen && event.detail.type === '1') {
137
143
  getFileProgress(event.detail.id);
138
144
  }
145
+ {{#if integrationOneLevelFetching}}
146
+ if (event.detail.componentId === 'integration-files' && event.detail.isOpen) {
147
+ getIntegrationData(event.detail.id);
148
+ }
149
+ {{/if}}
139
150
  });
140
151
  document.body.addEventListener('uploadFilesToCrowdin', uploadFilesToCrowdin);
141
152
  document.body.addEventListener('uploadFilesToIntegration', uploadFilesToIntegration);
142
-
153
+ {{#if integrationSearchListener}}
154
+ document.body.addEventListener("integrationFilterChange", (event) => {
155
+ getIntegrationData(0, event.detail);
156
+ })
157
+ {{/if}}
143
158
  const appComponent = document.querySelector('crowdin-simple-integration');
144
159
  const subscriptionModal = document.getElementById('subscription-modal');
145
160
 
@@ -197,10 +212,10 @@
197
212
  .finally(() => (appComponent.setAttribute('is-crowdin-loading', false)));
198
213
  }
199
214
 
200
- function getIntegrationData() {
215
+ function getIntegrationData(parentId = null, search = '') {
201
216
  appComponent.setAttribute('is-integration-loading', true);
202
217
  checkOrigin()
203
- .then(restParams => fetch('api/integration/data' + restParams))
218
+ .then(restParams => fetch(`api/integration/data${restParams}&parent_id=${parentId}&search=${search}`))
204
219
  .then(checkResponse)
205
220
  .then((res) => {
206
221
  const tree = res.map(e => {
@@ -217,7 +232,11 @@
217
232
  }
218
233
  return item;
219
234
  });
220
- appComponent.setIntegrationFilesData(tree);
235
+ appComponent.pushIntegrationFilesData(tree);
236
+ if (search) {
237
+ const openIds = res.filter(e => !e.type).map(e => e.id);
238
+ appComponent.setIntegrationOpenedFolders(openIds);
239
+ }
221
240
  })
222
241
  {{#if withCronSync}}
223
242
  .then(() => getSyncSettings('integration'))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "0.18.1",
3
+ "version": "0.19.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",
@@ -28,7 +28,6 @@
28
28
  "@types/express-handlebars": "^5.3.1",
29
29
  "@types/node": "^12.0.10",
30
30
  "@types/node-cron": "^3.0.0",
31
- "@types/sqlite3": "^3.1.7",
32
31
  "@typescript-eslint/eslint-plugin": "^2.3.1",
33
32
  "@typescript-eslint/parser": "^2.3.1",
34
33
  "eslint": "^6.4.0",