@crowdin/app-project-module 0.29.5 → 0.30.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.
@@ -11,9 +11,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const util_1 = require("../util");
13
13
  const defaults_1 = require("../util/defaults");
14
+ const synced_files_1 = require("../util/synced-files");
14
15
  function handle(config, integration) {
15
16
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
16
- var _a, _b;
17
+ var _a, _b, _c;
17
18
  const projectId = req.crowdinContext.jwtPayload.context.project_id || (req === null || req === void 0 ? void 0 : req.body.projectId);
18
19
  const uploadTranslations = req.query.uploadTranslations === 'true' || ((_a = req.body) === null || _a === void 0 ? void 0 : _a.uploadTranslations);
19
20
  (0, util_1.log)(`Updating crowdin project ${projectId}`, config.logger);
@@ -27,10 +28,18 @@ function handle(config, integration) {
27
28
  }
28
29
  const result = yield integration.updateCrowdin(projectId, req.crowdinApiClient, req.integrationCredentials, req.body, rootFolder, req.integrationSettings, uploadTranslations);
29
30
  let message;
31
+ let fileIds;
30
32
  if ((0, util_1.isExtendedResultType)(result)) {
31
33
  message = result.message;
34
+ fileIds = result.syncedFiles;
32
35
  }
33
36
  res.send({ message });
37
+ if ((_c = integration.filtering) === null || _c === void 0 ? void 0 : _c.syncStatus) {
38
+ if (!fileIds) {
39
+ fileIds = req.body.map((file) => file.id);
40
+ }
41
+ (0, synced_files_1.createOrUpdateSyncedFiles)({ config, req, fileIds });
42
+ }
34
43
  }), config.onError);
35
44
  }
36
45
  exports.default = handle;
@@ -45,6 +45,7 @@ function handle(config, integration) {
45
45
  }
46
46
  options.infoModal = integration.infoModal;
47
47
  options.syncNewElements = integration.syncNewElements;
48
+ options.filtering = integration.filtering;
48
49
  options.withCronSync = integration.withCronSync;
49
50
  options.webhooks = integration.webhooks
50
51
  ? {
@@ -0,0 +1,4 @@
1
+ /// <reference types="qs" />
2
+ import { Response } from 'express';
3
+ import { Config } from '../models';
4
+ export default function handle(config: Config): (req: 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;
@@ -0,0 +1,26 @@
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
+ const storage_1 = require("../storage");
13
+ const util_1 = require("../util");
14
+ function handle(config) {
15
+ return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
16
+ let fileIds = [];
17
+ (0, util_1.log)('Loading synced files', config.logger);
18
+ const syncedFiles = yield (0, storage_1.getStorage)().getSyncedFiles(req.crowdinContext.clientId, req.crowdinContext.crowdinId);
19
+ if (syncedFiles) {
20
+ fileIds = JSON.parse(syncedFiles.fileIds) || [];
21
+ }
22
+ (0, util_1.log)(`Returning synced files ${JSON.stringify(fileIds, null, 2)}`, config.logger);
23
+ res.send(fileIds);
24
+ }), config.onError);
25
+ }
26
+ exports.default = handle;
package/out/index.js CHANGED
@@ -67,6 +67,7 @@ const subscription_info_1 = __importDefault(require("./handlers/subscription-inf
67
67
  const subscription_paid_1 = __importDefault(require("./handlers/subscription-paid"));
68
68
  const sync_settings_1 = __importDefault(require("./handlers/sync-settings"));
69
69
  const sync_settings_save_1 = __importDefault(require("./handlers/sync-settings-save"));
70
+ const synced_files_1 = __importDefault(require("./handlers/synced-files"));
70
71
  const uninstall_1 = __importDefault(require("./handlers/uninstall"));
71
72
  const crowdin_client_1 = __importStar(require("./middlewares/crowdin-client"));
72
73
  const integration_credentials_1 = __importDefault(require("./middlewares/integration-credentials"));
@@ -145,6 +146,7 @@ function addCrowdinEndpoints(app, clientConfig) {
145
146
  app.post('/api/integration/update', json_response_1.default, (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, integrationLogic), (0, integration_update_1.default)(config, integrationLogic));
146
147
  app.get('/api/sync-settings/:provider', json_response_1.default, (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, integrationLogic), (0, sync_settings_1.default)(config));
147
148
  app.post('/api/sync-settings', json_response_1.default, (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, integrationLogic), (0, sync_settings_save_1.default)(config, integrationLogic));
149
+ app.get('/api/synced-files', json_response_1.default, (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, integrationLogic), (0, synced_files_1.default)(config));
148
150
  if (integrationLogic.oauthLogin) {
149
151
  app.get((0, defaults_1.getOauthRoute)(integrationLogic), (0, oauth_login_1.default)(config, integrationLogic));
150
152
  app.post('/api/oauth-url', json_response_1.default, (0, crowdin_client_1.default)(config, false, false), (0, oauth_url_1.default)(config, integrationLogic));
@@ -254,6 +254,10 @@ export interface IntegrationLogic {
254
254
  crowdin: boolean;
255
255
  integration: boolean;
256
256
  };
257
+ filtering?: {
258
+ crowdinLanguages: boolean;
259
+ syncStatus: boolean;
260
+ };
257
261
  /**
258
262
  * Enable integration folder open event
259
263
  */
@@ -434,6 +438,7 @@ export interface ExtendedResult<T> {
434
438
  data?: T;
435
439
  message?: string;
436
440
  stopPagination?: boolean;
441
+ syncedFiles: string[];
437
442
  }
438
443
  export type TreeItem = File | Folder;
439
444
  /**
@@ -868,4 +873,15 @@ export interface UpdateCrowdinWebhookPayloadsArgs {
868
873
  webhookData: any;
869
874
  req: Request;
870
875
  }
876
+ export interface CreateOrUpdateSyncedFilesArgs {
877
+ config: Config;
878
+ req: IntegrationRequest;
879
+ fileIds: string[];
880
+ }
881
+ export interface IntegrationSyncedFiles {
882
+ id: number;
883
+ fileIds?: any;
884
+ integrationId: string;
885
+ crowdinId: string;
886
+ }
871
887
  export {};
@@ -23,6 +23,12 @@
23
23
  margin-bottom: 10px;
24
24
  }
25
25
 
26
+ .top-button {
27
+ text-align: left;
28
+ display: flex;
29
+ justify-content: space-between;
30
+ }
31
+
26
32
  .login {
27
33
  margin-bottom: 10px;
28
34
  overflow: unset;
@@ -65,6 +71,10 @@
65
71
  margin: 12px 0 12px 0;
66
72
  }
67
73
 
74
+ #subscription-info .ce-alert {
75
+ margin-bottom: 12px;
76
+ }
77
+
68
78
  .dismiss-alert {
69
79
  position: absolute;
70
80
  top: 0;
@@ -1,4 +1,4 @@
1
- import { Config, CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings, Provider } from '../models';
1
+ import { Config, CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncedFiles, IntegrationSyncSettings, Provider } from '../models';
2
2
  export interface Storage {
3
3
  migrate(): Promise<void>;
4
4
  saveCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
@@ -25,6 +25,9 @@ export interface Storage {
25
25
  saveFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: Provider): Promise<void>;
26
26
  updateFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: Provider): Promise<void>;
27
27
  getFilesSnapshot(integrationId: string, crowdinId: string, provider: Provider): Promise<IntegrationFilesSnapshot | undefined>;
28
+ saveSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
29
+ updateSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
30
+ getSyncedFiles(integrationId: string, crowdinId: string): Promise<IntegrationSyncedFiles | undefined>;
28
31
  }
29
32
  export declare function initialize(config: Config): Promise<void>;
30
33
  export declare function getStorage(): Storage;
@@ -1,5 +1,5 @@
1
1
  import { Storage } from '.';
2
- import { CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings } from '../models';
2
+ import { CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncedFiles, IntegrationSyncSettings } from '../models';
3
3
  export interface MySQLStorageConfig {
4
4
  uri?: string;
5
5
  host?: string;
@@ -42,4 +42,7 @@ export declare class MySQLStorage implements Storage {
42
42
  saveFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: string): Promise<void>;
43
43
  updateFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: string): Promise<void>;
44
44
  getFilesSnapshot(integrationId: string, crowdinId: string, provider: string): Promise<IntegrationFilesSnapshot | undefined>;
45
+ saveSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
46
+ updateSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
47
+ getSyncedFiles(integrationId: string, crowdinId: string): Promise<IntegrationSyncedFiles | undefined>;
45
48
  }
@@ -114,6 +114,15 @@ class MySQLStorage {
114
114
  provider varchar(255) not null
115
115
  )
116
116
  `);
117
+ yield connection.execute(`
118
+ create table if not exists synced_files
119
+ (
120
+ id int auto_increment primary key,
121
+ integration_id varchar(255) not null,
122
+ crowdin_id varchar(255) not null,
123
+ file_ids text
124
+ )
125
+ `);
117
126
  });
118
127
  }
119
128
  saveCrowdinCredentials(credentials) {
@@ -297,7 +306,7 @@ class MySQLStorage {
297
306
  saveSyncSettings(files, integrationId, crowdinId, type, provider) {
298
307
  return __awaiter(this, void 0, void 0, function* () {
299
308
  yield this.dbPromise;
300
- yield this.executeQuery((connection) => connection.execute('INSERT INTO sync_settings(files, integration_id, crowdin_id, type, provider) VALUES (?, , ?, ?, ?)', [files, integrationId, crowdinId, type, provider]));
309
+ yield this.executeQuery((connection) => connection.execute('INSERT INTO sync_settings(files, integration_id, crowdin_id, type, provider) VALUES (?, ?, ?, ?, ?)', [files, integrationId, crowdinId, type, provider]));
301
310
  });
302
311
  }
303
312
  updateSyncSettings(files, integrationId, crowdinId, type, provider) {
@@ -336,5 +345,34 @@ class MySQLStorage {
336
345
  }));
337
346
  });
338
347
  }
348
+ saveSyncedFiles(fileIds, integrationId, crowdinId) {
349
+ return __awaiter(this, void 0, void 0, function* () {
350
+ yield this.dbPromise;
351
+ yield this.executeQuery((connection) => connection.execute('INSERT INTO synced_files(file_ids, integration_id, crowdin_id) VALUES (?, ?, ?)', [
352
+ fileIds,
353
+ integrationId,
354
+ crowdinId,
355
+ ]));
356
+ });
357
+ }
358
+ updateSyncedFiles(fileIds, integrationId, crowdinId) {
359
+ return __awaiter(this, void 0, void 0, function* () {
360
+ yield this.dbPromise;
361
+ yield this.executeQuery((connection) => connection.execute('UPDATE synced_files SET file_ids = ? WHERE integration_id = ? AND crowdin_id = ?', [
362
+ fileIds,
363
+ integrationId,
364
+ crowdinId,
365
+ ]));
366
+ });
367
+ }
368
+ getSyncedFiles(integrationId, crowdinId) {
369
+ return __awaiter(this, void 0, void 0, function* () {
370
+ yield this.dbPromise;
371
+ return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
372
+ const [rows] = yield connection.execute('SELECT id, file_ids as "fileIds", integration_id as "integrationId", crowdin_id as "crowdinId" FROM synced_files WHERE integration_id = ? AND crowdin_id = ?', [integrationId, crowdinId]);
373
+ return (rows || [])[0];
374
+ }));
375
+ });
376
+ }
339
377
  }
340
378
  exports.MySQLStorage = MySQLStorage;
@@ -1,6 +1,6 @@
1
1
  import { Client } from 'pg';
2
2
  import { Storage } from '.';
3
- import { CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings } from '../models';
3
+ import { CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncedFiles, IntegrationSyncSettings } from '../models';
4
4
  export interface PostgreStorageConfig {
5
5
  host?: string;
6
6
  connectionString?: string;
@@ -47,4 +47,7 @@ export declare class PostgreStorage implements Storage {
47
47
  saveFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: string): Promise<void>;
48
48
  updateFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: string): Promise<void>;
49
49
  getFilesSnapshot(integrationId: string, crowdinId: string, provider: string): Promise<IntegrationFilesSnapshot | undefined>;
50
+ saveSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
51
+ updateSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
52
+ getSyncedFiles(integrationId: string, crowdinId: string): Promise<IntegrationSyncedFiles | undefined>;
50
53
  }
@@ -128,6 +128,15 @@ class PostgreStorage {
128
128
  provider varchar not null
129
129
  )
130
130
  `);
131
+ yield client.query(`
132
+ create table if not exists synced_files
133
+ (
134
+ id serial primary key,
135
+ integration_id varchar not null,
136
+ crowdin_id varchar not null,
137
+ file_ids varchar
138
+ )
139
+ `);
131
140
  });
132
141
  }
133
142
  saveCrowdinCredentials(credentials) {
@@ -350,5 +359,34 @@ class PostgreStorage {
350
359
  }));
351
360
  });
352
361
  }
362
+ saveSyncedFiles(fileIds, integrationId, crowdinId) {
363
+ return __awaiter(this, void 0, void 0, function* () {
364
+ yield this.dbPromise;
365
+ yield this.executeQuery((client) => client.query('INSERT INTO synced_files(file_ids, integration_id, crowdin_id) VALUES ($1, $2, $3)', [
366
+ fileIds,
367
+ integrationId,
368
+ crowdinId,
369
+ ]));
370
+ });
371
+ }
372
+ updateSyncedFiles(fileIds, integrationId, crowdinId) {
373
+ return __awaiter(this, void 0, void 0, function* () {
374
+ yield this.dbPromise;
375
+ yield this.executeQuery((client) => client.query('UPDATE synced_files SET file_ids = $1 WHERE integration_id = $2 AND crowdin_id = $3', [
376
+ fileIds,
377
+ integrationId,
378
+ crowdinId,
379
+ ]));
380
+ });
381
+ }
382
+ getSyncedFiles(integrationId, crowdinId) {
383
+ return __awaiter(this, void 0, void 0, function* () {
384
+ yield this.dbPromise;
385
+ return this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
386
+ const res = yield client.query('SELECT id, file_ids as "fileIds", integration_id as "integrationId", crowdin_id as "crowdinId" FROM synced_files WHERE integration_id = $1 AND crowdin_id = $2', [integrationId, crowdinId]);
387
+ return res === null || res === void 0 ? void 0 : res.rows[0];
388
+ }));
389
+ });
390
+ }
353
391
  }
354
392
  exports.PostgreStorage = PostgreStorage;
@@ -1,5 +1,5 @@
1
1
  import { Storage } from '.';
2
- import { CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings } from '../models';
2
+ import { CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncedFiles, IntegrationSyncSettings } from '../models';
3
3
  export interface SQLiteStorageConfig {
4
4
  dbFolder: string;
5
5
  }
@@ -41,4 +41,7 @@ export declare class SQLiteStorage implements Storage {
41
41
  saveFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: string): Promise<void>;
42
42
  updateFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: string): Promise<void>;
43
43
  getFilesSnapshot(integrationId: string, crowdinId: string, provider: string): Promise<IntegrationFilesSnapshot | undefined>;
44
+ saveSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
45
+ updateSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
46
+ getSyncedFiles(integrationId: string, crowdinId: string): Promise<IntegrationSyncedFiles | undefined>;
44
47
  }
@@ -185,6 +185,15 @@ class SQLiteStorage {
185
185
  files varchar null,
186
186
  provider varchar not null
187
187
  );
188
+ `, []);
189
+ yield this._run(`
190
+ create table if not exists synced_files
191
+ (
192
+ id integer not null primary key autoincrement,
193
+ integration_id varchar not null,
194
+ crowdin_id varchar not null,
195
+ file_ids varchar null
196
+ );
188
197
  `, []);
189
198
  this._res && this._res();
190
199
  // TODO: temporary code
@@ -351,5 +360,27 @@ class SQLiteStorage {
351
360
  }
352
361
  });
353
362
  }
363
+ saveSyncedFiles(fileIds, integrationId, crowdinId) {
364
+ return this.run('INSERT INTO synced_files(file_ids, integration_id, crowdin_id) VALUES (?, ?, ?)', [
365
+ fileIds,
366
+ integrationId,
367
+ crowdinId,
368
+ ]);
369
+ }
370
+ updateSyncedFiles(fileIds, integrationId, crowdinId) {
371
+ return this.run('UPDATE synced_files SET file_ids = ? WHERE integration_id = ? AND crowdin_id = ?', [
372
+ fileIds,
373
+ integrationId,
374
+ crowdinId,
375
+ ]);
376
+ }
377
+ getSyncedFiles(integrationId, crowdinId) {
378
+ return __awaiter(this, void 0, void 0, function* () {
379
+ const row = yield this.get('SELECT id, file_ids as fileIds, integration_id as integrationId, crowdin_id as crowdinId FROM synced_files WHERE integration_id = ? AND crowdin_id = ?', [integrationId, crowdinId]);
380
+ if (row) {
381
+ return row;
382
+ }
383
+ });
384
+ }
354
385
  }
355
386
  exports.SQLiteStorage = SQLiteStorage;
@@ -0,0 +1,2 @@
1
+ import { CreateOrUpdateSyncedFilesArgs } from '../models';
2
+ export declare function createOrUpdateSyncedFiles(args: CreateOrUpdateSyncedFilesArgs): Promise<void>;
@@ -0,0 +1,31 @@
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.createOrUpdateSyncedFiles = void 0;
13
+ const storage_1 = require("../storage");
14
+ const index_1 = require("./index");
15
+ function createOrUpdateSyncedFiles(args) {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ const { config, req } = args;
18
+ let fileIds = args.fileIds;
19
+ const existingFiles = yield (0, storage_1.getStorage)().getSyncedFiles(req.crowdinContext.clientId, req.crowdinContext.crowdinId);
20
+ if (existingFiles) {
21
+ fileIds = [...new Set([...JSON.parse(existingFiles.fileIds), ...fileIds])];
22
+ (0, index_1.log)(`Updating synced files ${JSON.stringify(fileIds, null, 2)}`, config.logger);
23
+ yield (0, storage_1.getStorage)().updateSyncedFiles(JSON.stringify(fileIds), req.crowdinContext.clientId, req.crowdinContext.crowdinId);
24
+ }
25
+ else {
26
+ (0, index_1.log)(`Saving synced files ${JSON.stringify(fileIds, null, 2)}`, config.logger);
27
+ yield (0, storage_1.getStorage)().saveSyncedFiles(JSON.stringify(fileIds), req.crowdinContext.clientId, req.crowdinContext.crowdinId);
28
+ }
29
+ });
30
+ }
31
+ exports.createOrUpdateSyncedFiles = createOrUpdateSyncedFiles;
@@ -6,21 +6,36 @@
6
6
  <div class="i_w">
7
7
  <div class="top">
8
8
  {{#if checkSubscription}}
9
- <crowdin-alert id="subscription-info" no-icon="true" type="warning" style="display: none;">
9
+ <crowdin-alert id="subscription-info" no-icon="true" type="warning" style="display: none; margin-bottom: 12px;">
10
10
  <div class="box-center">
11
11
  <p class="m-0"></p>
12
12
  <crowdin-button class="ml-1" primary onclick="window.open(subscriptionLink,'_blank')">Subscribe</crowdin-button>
13
13
  </div>
14
14
  </crowdin-alert>
15
15
  {{/if}}
16
- {{#if infoModal}}
17
- <crowdin-button icon-before="info" onclick="infoModal.open();">{{infoModal.title}}</crowdin-button>
18
- {{/if}}
19
- {{#if configurationFields}}
20
- <crowdin-button icon-before="settings" onclick="settingsModal.open();fillSettingsForm();">Settings</crowdin-button>
21
- {{/if}}
22
- <crowdin-button icon-before="account_circle" onclick="integrationLogout()">Log out</crowdin-button>
23
- {{#if uploadTranslations}}
16
+ <div class="top-button">
17
+ {{#if filtering}}
18
+ <div class="integration-filter">
19
+ <crowdin-integration-filter
20
+ {{#if filtering.syncStatus}}
21
+ enable-sync-status-filter
22
+ {{/if}}
23
+ integration-logo="logo.png"
24
+ ></crowdin-integration-filter>
25
+ </div>
26
+ {{/if}}
27
+
28
+ <div>
29
+ {{#if infoModal}}
30
+ <crowdin-button icon-before="info" onclick="infoModal.open();">{{infoModal.title}}</crowdin-button>
31
+ {{/if}}
32
+ {{#if configurationFields}}
33
+ <crowdin-button icon-before="settings" onclick="settingsModal.open();fillSettingsForm();">Settings</crowdin-button>
34
+ {{/if}}
35
+ <crowdin-button icon-before="account_circle" onclick="integrationLogout()">Log out</crowdin-button>
36
+ </div>
37
+ </div>
38
+ {{#if uploadTranslations}}
24
39
  <crowdin-alert id="translation-info" no-icon="true" style="display: none;">
25
40
  <div class="box-center">
26
41
  <p class="info-text">
@@ -31,7 +46,7 @@
31
46
  </div>
32
47
  <crowdin-button onclick="closeAlert(this)" class="dismiss-alert" icon>close</crowdin-button>
33
48
  </crowdin-alert>
34
- {{/if}}
49
+ {{/if}}
35
50
  </div>
36
51
  <crowdin-simple-integration
37
52
  {{#if syncNewElements.crowdin}}
@@ -248,6 +263,11 @@
248
263
  const appComponent = document.querySelector('crowdin-simple-integration');
249
264
  const subscriptionModal = document.getElementById('subscription-modal');
250
265
 
266
+ {{#if filtering}}
267
+ let syncedFiles = [];
268
+ const filterIntegration = document.querySelector('crowdin-integration-filter');
269
+ {{/if}}
270
+
251
271
  const folderType = '0';
252
272
  const fileType = '1';
253
273
  const branchType = '2';
@@ -297,10 +317,16 @@
297
317
  .then((res) => {
298
318
  project = res;
299
319
  appComponent.setCrowdinLanguagesData(project.targetLanguages)
320
+ {{#if filtering}}
321
+ filterIntegration.setLanguages(project.targetLanguages)
322
+ {{/if}}
300
323
  })
301
324
  {{#or withCronSync webhooks}}
302
325
  .then(() => getSyncSettings('crowdin'))
303
326
  {{/or}}
327
+ {{#if filtering}}
328
+ .then(() => getSyncedFiles())
329
+ {{/if}}
304
330
  .catch(e => catchRejection(e, 'Can\'t fetch Crowdin data'))
305
331
  .finally(() => (appComponent.setAttribute('is-crowdin-loading', false)));
306
332
  }
@@ -761,6 +787,34 @@
761
787
  }
762
788
  checkAlert(translationInfo);
763
789
  {{/if}}
790
+
791
+ {{#if filtering}}
792
+ document.body.addEventListener("integrationFilterChange", filterFiles);
793
+
794
+ function filterFiles(event) {
795
+ const filter = event.detail;
796
+
797
+ if (filter.languages) {
798
+ const languageIds = filter.languages === 'all' ? [] : [filter.languages];
799
+ appComponent.filterCrowdinFilesByLanguages(languageIds);
800
+ }
801
+ if (filter.sync) {
802
+ const fileId = filter.sync === 'all' ? [] : syncedFiles;
803
+ appComponent.filterIntegrationFilesByIds(fileId, filter.sync !== 'not_synced');
804
+ }
805
+ }
806
+
807
+ function getSyncedFiles() {
808
+ checkOrigin()
809
+ .then(restParams => fetch('/api/synced-files' + restParams))
810
+ .then(checkResponse)
811
+ .then((res) => {
812
+ syncedFiles = res;
813
+ })
814
+ .catch(e => catchRejection(e, 'Can\'t fetch file progress'));
815
+ }
816
+
817
+ {{/if}}
764
818
  </script>
765
819
 
766
820
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "0.29.5",
3
+ "version": "0.30.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",