@crowdin/app-project-module 0.79.1 → 0.80.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/index.js +1 -1
- package/out/modules/ai-prompt-provider/handlers/compile.js +13 -1
- package/out/modules/ai-prompt-provider/index.js +1 -1
- package/out/modules/ai-prompt-provider/types.d.ts +1 -1
- package/out/modules/manifest.js +1 -1
- package/out/storage/index.d.ts +11 -0
- package/out/storage/mysql.d.ts +11 -0
- package/out/storage/mysql.js +178 -38
- package/out/storage/postgre.d.ts +11 -0
- package/out/storage/postgre.js +67 -0
- package/out/storage/sqlite.d.ts +11 -0
- package/out/storage/sqlite.js +51 -0
- package/out/types.d.ts +2 -0
- package/out/views/main.handlebars +180 -180
- package/package.json +1 -1
package/out/index.js
CHANGED
|
@@ -191,7 +191,7 @@ function addCrowdinEndpoints(app, clientConfig) {
|
|
|
191
191
|
webhooks.register({ config, app });
|
|
192
192
|
workflowStepType.register({ config, app });
|
|
193
193
|
addFormSchema({ config, app });
|
|
194
|
-
return Object.assign(Object.assign({}, exports.metadataStore), { establishCrowdinConnection: (authRequest, moduleKey) => {
|
|
194
|
+
return Object.assign(Object.assign({}, exports.metadataStore), { storage: storage.getStorage(), establishCrowdinConnection: (authRequest, moduleKey) => {
|
|
195
195
|
let jwtToken = '';
|
|
196
196
|
if (typeof authRequest === 'string') {
|
|
197
197
|
jwtToken = authRequest;
|
|
@@ -8,13 +8,25 @@ 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 __rest = (this && this.__rest) || function (s, e) {
|
|
12
|
+
var t = {};
|
|
13
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
14
|
+
t[p] = s[p];
|
|
15
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
16
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
17
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
18
|
+
t[p[i]] = s[p[i]];
|
|
19
|
+
}
|
|
20
|
+
return t;
|
|
21
|
+
};
|
|
11
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
23
|
const util_1 = require("../../../util");
|
|
13
24
|
const logger_1 = require("../../../util/logger");
|
|
14
25
|
function handle(aiPromptProvider) {
|
|
15
26
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
16
27
|
try {
|
|
17
|
-
const
|
|
28
|
+
const _a = req.body, { options, payload } = _a, body = __rest(_a, ["options", "payload"]);
|
|
29
|
+
const compiledPrompt = yield aiPromptProvider.compile(options, payload, req.crowdinApiClient, req.crowdinContext, body);
|
|
18
30
|
res.send({ data: { content: compiledPrompt } });
|
|
19
31
|
}
|
|
20
32
|
catch (e) {
|
|
@@ -20,7 +20,7 @@ function register({ config, app }) {
|
|
|
20
20
|
checkSubscriptionExpiration: true,
|
|
21
21
|
moduleKey: config.aiPromptProvider.key,
|
|
22
22
|
}), (0, compile_1.default)(config.aiPromptProvider));
|
|
23
|
-
if (config.aiPromptProvider.formSchema) {
|
|
23
|
+
if (config.aiPromptProvider.formSchema || config.aiPromptProvider.uiPath) {
|
|
24
24
|
app.use('/prompt-provider/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true, moduleType: config.aiPromptProvider.key }), (0, render_ui_module_1.default)(config.aiPromptProvider));
|
|
25
25
|
}
|
|
26
26
|
app.get((0, util_1.getLogoUrl)(config.aiPromptProvider, '/ai-prompt-provider'), (req, res) => { var _a; return res.sendFile(((_a = config.aiPromptProvider) === null || _a === void 0 ? void 0 : _a.imagePath) || config.imagePath); });
|
|
@@ -4,5 +4,5 @@ export interface AiPromptProviderModule extends UiModule {
|
|
|
4
4
|
/**
|
|
5
5
|
* generates prompt text based on provided options
|
|
6
6
|
*/
|
|
7
|
-
compile: (options: any, payload: any, client: Crowdin, context: CrowdinContextInfo) => Promise<string>;
|
|
7
|
+
compile: (options: any, payload: any, client: Crowdin, context: CrowdinContextInfo, requestData: any) => Promise<string>;
|
|
8
8
|
}
|
package/out/modules/manifest.js
CHANGED
|
@@ -240,7 +240,7 @@ function handle(config) {
|
|
|
240
240
|
// prevent possible overrides of the other modules
|
|
241
241
|
config.aiPromptProvider = Object.assign(Object.assign({}, config.aiPromptProvider), { key: config.identifier + '-ai-prompt-provider' });
|
|
242
242
|
modules['ai-prompt-provider'] = [
|
|
243
|
-
Object.assign({ key: config.aiPromptProvider.key, name: config.aiPromptProvider.name || config.name, logo: (0, util_1.getLogoUrl)(config.aiPromptProvider, '/ai-prompt-provider'), compileUrl: '/prompt-provider/compile' }, (
|
|
243
|
+
Object.assign({ key: config.aiPromptProvider.key, name: config.aiPromptProvider.name || config.name, logo: (0, util_1.getLogoUrl)(config.aiPromptProvider, '/ai-prompt-provider'), compileUrl: '/prompt-provider/compile' }, (config.aiPromptProvider.formSchema || config.aiPromptProvider.uiPath
|
|
244
244
|
? {
|
|
245
245
|
configuratorUrl: '/prompt-provider/settings/' + (config.aiPromptProvider.fileName || 'index.html'),
|
|
246
246
|
}
|
package/out/storage/index.d.ts
CHANGED
|
@@ -68,6 +68,17 @@ export interface Storage {
|
|
|
68
68
|
saveUnsyncedFiles(params: UnsyncedFiles): Promise<void>;
|
|
69
69
|
getUnsyncedFiles(params: GetUnsyncedFiles): Promise<UnsyncedFiles | undefined>;
|
|
70
70
|
updateUnsyncedFiles(params: UnsyncedFiles): Promise<void>;
|
|
71
|
+
registerCustomTable(tableName: string, schema: Record<string, string>): Promise<void>;
|
|
72
|
+
insertRecord(tableName: string, data: Record<string, any>): Promise<void>;
|
|
73
|
+
selectRecords(tableName: string, options?: {
|
|
74
|
+
columns?: string[];
|
|
75
|
+
whereClause?: string;
|
|
76
|
+
orderBy?: string;
|
|
77
|
+
limit?: number;
|
|
78
|
+
distinct?: boolean;
|
|
79
|
+
}, params?: any[]): Promise<any[]>;
|
|
80
|
+
updateRecord(tableName: string, data: Record<string, any>, whereClause: string, params?: any[]): Promise<void>;
|
|
81
|
+
deleteRecord(tableName: string, whereClause: string, params?: any[]): Promise<void>;
|
|
71
82
|
}
|
|
72
83
|
export declare function initialize(config: Config | UnauthorizedConfig): Promise<void>;
|
|
73
84
|
export declare function getStorage(): Storage;
|
package/out/storage/mysql.d.ts
CHANGED
|
@@ -84,4 +84,15 @@ export declare class MySQLStorage implements Storage {
|
|
|
84
84
|
saveUnsyncedFiles({ integrationId, crowdinId, files }: UnsyncedFiles): Promise<void>;
|
|
85
85
|
updateUnsyncedFiles({ integrationId, crowdinId, files }: UnsyncedFiles): Promise<void>;
|
|
86
86
|
getUnsyncedFiles({ integrationId, crowdinId }: GetUnsyncedFiles): Promise<UnsyncedFiles | undefined>;
|
|
87
|
+
registerCustomTable(tableName: string, schema: Record<string, string>): Promise<void>;
|
|
88
|
+
insertRecord(tableName: string, data: Record<string, any>): Promise<void>;
|
|
89
|
+
selectRecords(tableName: string, options?: {
|
|
90
|
+
columns?: string[];
|
|
91
|
+
whereClause?: string;
|
|
92
|
+
orderBy?: string;
|
|
93
|
+
limit?: number;
|
|
94
|
+
distinct?: boolean;
|
|
95
|
+
}, params?: any[]): Promise<any[]>;
|
|
96
|
+
updateRecord(tableName: string, data: Record<string, any>, whereClause: string, params?: any[]): Promise<void>;
|
|
97
|
+
deleteRecord(tableName: string, whereClause: string, params?: any[]): Promise<void>;
|
|
87
98
|
}
|
package/out/storage/mysql.js
CHANGED
|
@@ -433,9 +433,17 @@ class MySQLStorage {
|
|
|
433
433
|
}
|
|
434
434
|
deleteWebhooks(fileIds, integrationId, crowdinId, provider) {
|
|
435
435
|
return __awaiter(this, void 0, void 0, function* () {
|
|
436
|
+
if (!fileIds.length) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
436
439
|
yield this.dbPromise;
|
|
437
440
|
const placeholders = fileIds.map(() => '?').join(',');
|
|
438
|
-
yield this.executeQuery((connection) => connection.execute(`DELETE
|
|
441
|
+
yield this.executeQuery((connection) => connection.execute(`DELETE
|
|
442
|
+
FROM webhooks
|
|
443
|
+
WHERE file_id IN (${placeholders})
|
|
444
|
+
AND integration_id = ?
|
|
445
|
+
AND crowdin_id = ?
|
|
446
|
+
AND provider = ?`, [...fileIds, integrationId, crowdinId, provider]));
|
|
439
447
|
});
|
|
440
448
|
}
|
|
441
449
|
getAllUserErrors(crowdinId, integrationId) {
|
|
@@ -448,7 +456,9 @@ class MySQLStorage {
|
|
|
448
456
|
whereIntegrationCondition = 'integration_id = ?';
|
|
449
457
|
params.push(integrationId);
|
|
450
458
|
}
|
|
451
|
-
const [rows] = yield connection.execute(`SELECT id, action, message, data, created_at as "createdAt"
|
|
459
|
+
const [rows] = yield connection.execute(`SELECT id, action, message, data, created_at as "createdAt"
|
|
460
|
+
FROM user_errors
|
|
461
|
+
WHERE crowdin_id = ? AND ${whereIntegrationCondition}`, params);
|
|
452
462
|
return rows || [];
|
|
453
463
|
}));
|
|
454
464
|
});
|
|
@@ -469,7 +479,11 @@ class MySQLStorage {
|
|
|
469
479
|
whereIntegrationCondition = 'integration_id = ?';
|
|
470
480
|
params.push(integrationId);
|
|
471
481
|
}
|
|
472
|
-
return connection.execute(`DELETE
|
|
482
|
+
return connection.execute(`DELETE
|
|
483
|
+
FROM user_errors
|
|
484
|
+
WHERE created_at < ?
|
|
485
|
+
AND crowdin_id = ?
|
|
486
|
+
AND ${whereIntegrationCondition}`, params);
|
|
473
487
|
});
|
|
474
488
|
});
|
|
475
489
|
}
|
|
@@ -522,7 +536,7 @@ class MySQLStorage {
|
|
|
522
536
|
yield this.executeQuery((connection) => connection.execute(`
|
|
523
537
|
INSERT INTO job(id, integration_id, crowdin_id, type, payload, title, created_at)
|
|
524
538
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
525
|
-
|
|
539
|
+
`, [id, integrationId, crowdinId, type, payload, title, Date.now().toString()]));
|
|
526
540
|
return id;
|
|
527
541
|
});
|
|
528
542
|
}
|
|
@@ -564,7 +578,7 @@ class MySQLStorage {
|
|
|
564
578
|
UPDATE job
|
|
565
579
|
SET ${updateFields.join(', ')}
|
|
566
580
|
WHERE id = ?
|
|
567
|
-
|
|
581
|
+
`, updateParams));
|
|
568
582
|
});
|
|
569
583
|
}
|
|
570
584
|
getJob({ id }) {
|
|
@@ -572,11 +586,23 @@ class MySQLStorage {
|
|
|
572
586
|
yield this.dbPromise;
|
|
573
587
|
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
574
588
|
const [rows] = yield connection.execute(`
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
589
|
+
SELECT id,
|
|
590
|
+
integration_id as "integrationId",
|
|
591
|
+
crowdin_id as "crowdinId",
|
|
592
|
+
type,
|
|
593
|
+
payload,
|
|
594
|
+
progress,
|
|
595
|
+
status,
|
|
596
|
+
title,
|
|
597
|
+
info,
|
|
598
|
+
data,
|
|
599
|
+
attempt,
|
|
600
|
+
created_at as "createdAt",
|
|
601
|
+
updated_at as "updatedAt",
|
|
602
|
+
finished_at as "finishedAt"
|
|
603
|
+
FROM job
|
|
604
|
+
WHERE id = ?
|
|
605
|
+
`, [id]);
|
|
580
606
|
return (rows || [])[0];
|
|
581
607
|
}));
|
|
582
608
|
});
|
|
@@ -586,11 +612,25 @@ class MySQLStorage {
|
|
|
586
612
|
yield this.dbPromise;
|
|
587
613
|
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
588
614
|
const [rows] = yield connection.execute(`
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
615
|
+
SELECT id,
|
|
616
|
+
integration_id as "integrationId",
|
|
617
|
+
crowdin_id as "crowdinId",
|
|
618
|
+
type,
|
|
619
|
+
payload,
|
|
620
|
+
progress,
|
|
621
|
+
status,
|
|
622
|
+
title,
|
|
623
|
+
info,
|
|
624
|
+
data,
|
|
625
|
+
attempt,
|
|
626
|
+
created_at as "createdAt",
|
|
627
|
+
updated_at as "updatedAt",
|
|
628
|
+
finished_at as "finishedAt"
|
|
629
|
+
FROM job
|
|
630
|
+
WHERE integration_id = ?
|
|
631
|
+
AND crowdin_id = ?
|
|
632
|
+
AND finished_at is NULL
|
|
633
|
+
`, [integrationId, crowdinId]);
|
|
594
634
|
return rows || [];
|
|
595
635
|
}));
|
|
596
636
|
});
|
|
@@ -606,11 +646,24 @@ class MySQLStorage {
|
|
|
606
646
|
yield this.dbPromise;
|
|
607
647
|
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
608
648
|
const [rows] = yield connection.execute(`
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
649
|
+
SELECT id,
|
|
650
|
+
integration_id as "integrationId",
|
|
651
|
+
crowdin_id as "crowdinId",
|
|
652
|
+
type,
|
|
653
|
+
payload,
|
|
654
|
+
progress,
|
|
655
|
+
status,
|
|
656
|
+
title,
|
|
657
|
+
info,
|
|
658
|
+
data,
|
|
659
|
+
attempt,
|
|
660
|
+
created_at as "createdAt",
|
|
661
|
+
updated_at as "updatedAt",
|
|
662
|
+
finished_at as "finishedAt"
|
|
663
|
+
FROM job
|
|
664
|
+
WHERE status IN (?, ?)
|
|
665
|
+
AND finished_at is NULL
|
|
666
|
+
`, [types_1.JobStatus.IN_PROGRESS, types_1.JobStatus.CREATED]);
|
|
614
667
|
return rows || [];
|
|
615
668
|
}));
|
|
616
669
|
});
|
|
@@ -621,7 +674,7 @@ class MySQLStorage {
|
|
|
621
674
|
yield this.executeQuery((connection) => connection.execute(`
|
|
622
675
|
INSERT INTO translation_file_cache(integration_id, crowdin_id, file_id, language_id, etag)
|
|
623
676
|
VALUES (?, ?, ?, ?, ?)
|
|
624
|
-
|
|
677
|
+
`, [integrationId, crowdinId, fileId, languageId, etag]));
|
|
625
678
|
});
|
|
626
679
|
}
|
|
627
680
|
getFileTranslationCache({ integrationId, crowdinId, fileId, }) {
|
|
@@ -629,10 +682,16 @@ class MySQLStorage {
|
|
|
629
682
|
yield this.dbPromise;
|
|
630
683
|
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
631
684
|
const [rows] = yield connection.execute(`
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
685
|
+
SELECT integration_id as "integrationId",
|
|
686
|
+
crowdin_id as "crowdinId",
|
|
687
|
+
file_id as "fileId",
|
|
688
|
+
language_id as "languageId",
|
|
689
|
+
etag
|
|
690
|
+
FROM translation_file_cache
|
|
691
|
+
WHERE integration_id = ?
|
|
692
|
+
AND crowdin_id = ?
|
|
693
|
+
AND file_id = ?
|
|
694
|
+
`, [integrationId, crowdinId, fileId]);
|
|
636
695
|
return rows || [];
|
|
637
696
|
}));
|
|
638
697
|
});
|
|
@@ -642,10 +701,17 @@ class MySQLStorage {
|
|
|
642
701
|
yield this.dbPromise;
|
|
643
702
|
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
644
703
|
const [rows] = yield connection.execute(`
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
704
|
+
SELECT integration_id as "integrationId",
|
|
705
|
+
crowdin_id as "crowdinId",
|
|
706
|
+
file_id as "fileId",
|
|
707
|
+
language_id as "languageId",
|
|
708
|
+
etag
|
|
709
|
+
FROM translation_file_cache
|
|
710
|
+
WHERE integration_id = ?
|
|
711
|
+
AND crowdin_id = ?
|
|
712
|
+
AND file_id = ?
|
|
713
|
+
AND language_id = ?
|
|
714
|
+
`, [integrationId, crowdinId, fileId, languageId]);
|
|
649
715
|
return (rows || [])[0];
|
|
650
716
|
}));
|
|
651
717
|
});
|
|
@@ -656,8 +722,11 @@ class MySQLStorage {
|
|
|
656
722
|
yield this.executeQuery((connection) => connection.execute(`
|
|
657
723
|
UPDATE translation_file_cache
|
|
658
724
|
SET etag = ?
|
|
659
|
-
WHERE integration_id = ?
|
|
660
|
-
|
|
725
|
+
WHERE integration_id = ?
|
|
726
|
+
AND crowdin_id = ?
|
|
727
|
+
AND file_id = ?
|
|
728
|
+
AND language_id = ?
|
|
729
|
+
`, [etag, integrationId, crowdinId, fileId, languageId]));
|
|
661
730
|
});
|
|
662
731
|
}
|
|
663
732
|
saveUnsyncedFiles({ integrationId, crowdinId, files }) {
|
|
@@ -666,7 +735,7 @@ class MySQLStorage {
|
|
|
666
735
|
yield this.executeQuery((connection) => connection.execute(`
|
|
667
736
|
INSERT INTO unsynced_files(integration_id, crowdin_id, files)
|
|
668
737
|
VALUES (?, ?, ?,)
|
|
669
|
-
|
|
738
|
+
`, [integrationId, crowdinId, files]));
|
|
670
739
|
});
|
|
671
740
|
}
|
|
672
741
|
updateUnsyncedFiles({ integrationId, crowdinId, files }) {
|
|
@@ -675,8 +744,9 @@ class MySQLStorage {
|
|
|
675
744
|
yield this.executeQuery((connection) => connection.execute(`
|
|
676
745
|
UPDATE unsynced_files
|
|
677
746
|
SET files = ?
|
|
678
|
-
WHERE integration_id = ?
|
|
679
|
-
|
|
747
|
+
WHERE integration_id = ?
|
|
748
|
+
AND crowdin_id = ?
|
|
749
|
+
`, [files, integrationId, crowdinId]));
|
|
680
750
|
});
|
|
681
751
|
}
|
|
682
752
|
getUnsyncedFiles({ integrationId, crowdinId }) {
|
|
@@ -684,13 +754,83 @@ class MySQLStorage {
|
|
|
684
754
|
yield this.dbPromise;
|
|
685
755
|
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
686
756
|
const [rows] = yield connection.execute(`
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
757
|
+
SELECT fileIds
|
|
758
|
+
FROM unsynced_files
|
|
759
|
+
WHERE integration_id = ?
|
|
760
|
+
AND crowdin_id = ?
|
|
761
|
+
`, [integrationId, crowdinId]);
|
|
691
762
|
return (rows || [])[0];
|
|
692
763
|
}));
|
|
693
764
|
});
|
|
694
765
|
}
|
|
766
|
+
registerCustomTable(tableName, schema) {
|
|
767
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
768
|
+
const columns = Object.entries(schema)
|
|
769
|
+
.map(([col, def]) => `${col} ${def}`)
|
|
770
|
+
.join(', ');
|
|
771
|
+
const query = `CREATE TABLE IF NOT EXISTS ${tableName}
|
|
772
|
+
(
|
|
773
|
+
${columns}
|
|
774
|
+
);`;
|
|
775
|
+
yield this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
776
|
+
yield connection.execute(query);
|
|
777
|
+
return;
|
|
778
|
+
}));
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
insertRecord(tableName, data) {
|
|
782
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
783
|
+
const columns = Object.keys(data).join(', ');
|
|
784
|
+
const placeholders = Object.keys(data)
|
|
785
|
+
.map(() => '?')
|
|
786
|
+
.join(', ');
|
|
787
|
+
const values = Object.values(data);
|
|
788
|
+
const query = `INSERT INTO ${tableName} (${columns})
|
|
789
|
+
VALUES (${placeholders});`;
|
|
790
|
+
yield this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
791
|
+
yield connection.execute(query, values);
|
|
792
|
+
return;
|
|
793
|
+
}));
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
selectRecords(tableName, options = {}, params = []) {
|
|
797
|
+
var _a;
|
|
798
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
799
|
+
const columns = ((_a = options.columns) === null || _a === void 0 ? void 0 : _a.length) ? options.columns.join(', ') : '*';
|
|
800
|
+
const distinctKeyword = options.distinct ? 'DISTINCT ' : '';
|
|
801
|
+
const whereClause = options.whereClause ? ` ${options.whereClause}` : '';
|
|
802
|
+
const orderByClause = options.orderBy ? ` ORDER BY ${options.orderBy}` : '';
|
|
803
|
+
const limitClause = options.limit ? ` LIMIT ${options.limit}` : '';
|
|
804
|
+
const query = `SELECT ${distinctKeyword}${columns} FROM ${tableName}${whereClause}${orderByClause}${limitClause};`;
|
|
805
|
+
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
806
|
+
const [rows] = yield connection.execute(query, params);
|
|
807
|
+
return rows;
|
|
808
|
+
}));
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
updateRecord(tableName, data, whereClause, params = []) {
|
|
812
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
813
|
+
const setClause = Object.keys(data)
|
|
814
|
+
.map((key) => `${key} = ?`)
|
|
815
|
+
.join(', ');
|
|
816
|
+
const values = Object.values(data);
|
|
817
|
+
const query = `UPDATE ${tableName}
|
|
818
|
+
SET ${setClause} ${whereClause};`;
|
|
819
|
+
yield this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
820
|
+
yield connection.execute(query, [...values, ...params]);
|
|
821
|
+
return;
|
|
822
|
+
}));
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
deleteRecord(tableName, whereClause, params = []) {
|
|
826
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
827
|
+
const query = `DELETE
|
|
828
|
+
FROM ${tableName} ${whereClause};`;
|
|
829
|
+
yield this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
830
|
+
yield connection.execute(query, params);
|
|
831
|
+
return;
|
|
832
|
+
}));
|
|
833
|
+
});
|
|
834
|
+
}
|
|
695
835
|
}
|
|
696
836
|
exports.MySQLStorage = MySQLStorage;
|
package/out/storage/postgre.d.ts
CHANGED
|
@@ -99,5 +99,16 @@ export declare class PostgreStorage implements Storage {
|
|
|
99
99
|
saveUnsyncedFiles({ integrationId, crowdinId, files }: UnsyncedFiles): Promise<void>;
|
|
100
100
|
updateUnsyncedFiles({ integrationId, crowdinId, files }: UnsyncedFiles): Promise<void>;
|
|
101
101
|
getUnsyncedFiles({ integrationId, crowdinId }: GetUnsyncedFiles): Promise<UnsyncedFiles | undefined>;
|
|
102
|
+
registerCustomTable(tableName: string, schema: Record<string, string>): Promise<void>;
|
|
103
|
+
insertRecord(tableName: string, data: Record<string, any>): Promise<void>;
|
|
104
|
+
selectRecords(tableName: string, options?: {
|
|
105
|
+
columns?: string[];
|
|
106
|
+
whereClause?: string;
|
|
107
|
+
orderBy?: string;
|
|
108
|
+
limit?: number;
|
|
109
|
+
distinct?: boolean;
|
|
110
|
+
}, params?: any[]): Promise<any[]>;
|
|
111
|
+
updateRecord(tableName: string, data: Record<string, any>, whereClause: string, params?: any[]): Promise<void>;
|
|
112
|
+
deleteRecord(tableName: string, whereClause: string, params?: any[]): Promise<void>;
|
|
102
113
|
}
|
|
103
114
|
export {};
|
package/out/storage/postgre.js
CHANGED
|
@@ -516,6 +516,9 @@ class PostgreStorage {
|
|
|
516
516
|
}
|
|
517
517
|
deleteWebhooks(fileIds, integrationId, crowdinId, provider) {
|
|
518
518
|
return __awaiter(this, void 0, void 0, function* () {
|
|
519
|
+
if (!fileIds.length) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
519
522
|
let index = 0;
|
|
520
523
|
const placeholders = fileIds.map(() => `$${++index}`).join(',');
|
|
521
524
|
yield this.dbPromise;
|
|
@@ -813,5 +816,69 @@ class PostgreStorage {
|
|
|
813
816
|
}));
|
|
814
817
|
});
|
|
815
818
|
}
|
|
819
|
+
registerCustomTable(tableName, schema) {
|
|
820
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
821
|
+
const columns = Object.entries(schema)
|
|
822
|
+
.map(([col, def]) => `"${col}" ${def}`)
|
|
823
|
+
.join(', ');
|
|
824
|
+
const query = `CREATE TABLE IF NOT EXISTS "${tableName}" (${columns});`;
|
|
825
|
+
yield this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
|
|
826
|
+
yield client.query(query);
|
|
827
|
+
return;
|
|
828
|
+
}));
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
insertRecord(tableName, data) {
|
|
832
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
833
|
+
const columns = Object.keys(data)
|
|
834
|
+
.map((col) => `"${col}"`)
|
|
835
|
+
.join(', ');
|
|
836
|
+
const placeholders = Object.keys(data)
|
|
837
|
+
.map((_, i) => `$${i + 1}`)
|
|
838
|
+
.join(', ');
|
|
839
|
+
const values = Object.values(data);
|
|
840
|
+
const query = `INSERT INTO "${tableName}" (${columns}) VALUES (${placeholders});`;
|
|
841
|
+
yield this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
|
|
842
|
+
yield client.query(query, values);
|
|
843
|
+
return;
|
|
844
|
+
}));
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
selectRecords(tableName, options = {}, params = []) {
|
|
848
|
+
var _a;
|
|
849
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
850
|
+
const columns = ((_a = options.columns) === null || _a === void 0 ? void 0 : _a.length) ? options.columns.join(', ') : '*';
|
|
851
|
+
const distinctKeyword = options.distinct ? 'DISTINCT ' : '';
|
|
852
|
+
const whereClause = options.whereClause ? ` ${options.whereClause}` : '';
|
|
853
|
+
const orderByClause = options.orderBy ? ` ORDER BY ${options.orderBy}` : '';
|
|
854
|
+
const limitClause = options.limit ? ` LIMIT ${options.limit}` : '';
|
|
855
|
+
const query = `SELECT ${distinctKeyword}${columns} FROM ${tableName}${whereClause}${orderByClause}${limitClause};`;
|
|
856
|
+
return this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
|
|
857
|
+
const res = yield client.query(query, params);
|
|
858
|
+
return res.rows;
|
|
859
|
+
}));
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
updateRecord(tableName, data, whereClause, params = []) {
|
|
863
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
864
|
+
const keys = Object.keys(data);
|
|
865
|
+
const setClause = keys.map((key, index) => `"${key}" = $${index + 1}`).join(', ');
|
|
866
|
+
const values = Object.values(data);
|
|
867
|
+
const query = `UPDATE "${tableName}" SET ${setClause} ${whereClause};`;
|
|
868
|
+
yield this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
|
|
869
|
+
yield client.query(query, [...values, ...params]);
|
|
870
|
+
return;
|
|
871
|
+
}));
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
deleteRecord(tableName, whereClause, params = []) {
|
|
875
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
876
|
+
const query = `DELETE FROM ${tableName} ${whereClause};`;
|
|
877
|
+
yield this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
|
|
878
|
+
yield client.query(query, params);
|
|
879
|
+
return;
|
|
880
|
+
}));
|
|
881
|
+
});
|
|
882
|
+
}
|
|
816
883
|
}
|
|
817
884
|
exports.PostgreStorage = PostgreStorage;
|
package/out/storage/sqlite.d.ts
CHANGED
|
@@ -87,4 +87,15 @@ export declare class SQLiteStorage implements Storage {
|
|
|
87
87
|
saveUnsyncedFiles({ integrationId, crowdinId, files }: UnsyncedFiles): Promise<void>;
|
|
88
88
|
updateUnsyncedFiles({ integrationId, crowdinId, files }: UnsyncedFiles): Promise<void>;
|
|
89
89
|
getUnsyncedFiles({ integrationId, crowdinId }: GetUnsyncedFiles): Promise<UnsyncedFiles | undefined>;
|
|
90
|
+
registerCustomTable(tableName: string, schema: Record<string, string>): Promise<void>;
|
|
91
|
+
insertRecord(tableName: string, data: Record<string, any>): Promise<void>;
|
|
92
|
+
selectRecords(tableName: string, options?: {
|
|
93
|
+
columns?: string[];
|
|
94
|
+
whereClause?: string;
|
|
95
|
+
orderBy?: string;
|
|
96
|
+
limit?: number;
|
|
97
|
+
distinct?: boolean;
|
|
98
|
+
}, params?: any[]): Promise<any[]>;
|
|
99
|
+
updateRecord(tableName: string, data: Record<string, any>, whereClause: string, params?: any[]): Promise<void>;
|
|
100
|
+
deleteRecord(tableName: string, whereClause: string, params?: any[]): Promise<void>;
|
|
90
101
|
}
|
package/out/storage/sqlite.js
CHANGED
|
@@ -489,6 +489,9 @@ class SQLiteStorage {
|
|
|
489
489
|
}
|
|
490
490
|
deleteWebhooks(fileIds, integrationId, crowdinId, provider) {
|
|
491
491
|
return __awaiter(this, void 0, void 0, function* () {
|
|
492
|
+
if (!fileIds.length) {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
492
495
|
const placeholders = fileIds.map(() => '?').join(',');
|
|
493
496
|
return this.run(`DELETE FROM webhooks WHERE file_id IN (${placeholders}) AND integration_id = ? AND crowdin_id = ? AND provider = ?`, [...fileIds, integrationId, crowdinId, provider]);
|
|
494
497
|
});
|
|
@@ -691,5 +694,53 @@ class SQLiteStorage {
|
|
|
691
694
|
}
|
|
692
695
|
});
|
|
693
696
|
}
|
|
697
|
+
registerCustomTable(tableName, schema) {
|
|
698
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
699
|
+
const columns = Object.entries(schema)
|
|
700
|
+
.map(([col, def]) => `${col} ${def}`)
|
|
701
|
+
.join(', ');
|
|
702
|
+
const query = `CREATE TABLE IF NOT EXISTS ${tableName} (${columns});`;
|
|
703
|
+
yield this.run(query, []);
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
insertRecord(tableName, data) {
|
|
707
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
708
|
+
const columns = Object.keys(data).join(', ');
|
|
709
|
+
const placeholders = Object.keys(data)
|
|
710
|
+
.map(() => '?')
|
|
711
|
+
.join(', ');
|
|
712
|
+
const values = Object.values(data);
|
|
713
|
+
const query = `INSERT INTO ${tableName} (${columns}) VALUES (${placeholders});`;
|
|
714
|
+
return this.run(query, values);
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
selectRecords(tableName, options = {}, params = []) {
|
|
718
|
+
var _a;
|
|
719
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
720
|
+
const columns = ((_a = options.columns) === null || _a === void 0 ? void 0 : _a.length) ? options.columns.join(', ') : '*';
|
|
721
|
+
const distinctKeyword = options.distinct ? 'DISTINCT ' : '';
|
|
722
|
+
const whereClause = options.whereClause ? ` ${options.whereClause}` : '';
|
|
723
|
+
const orderByClause = options.orderBy ? ` ORDER BY ${options.orderBy}` : '';
|
|
724
|
+
const limitClause = options.limit ? ` LIMIT ${options.limit}` : '';
|
|
725
|
+
const query = `SELECT ${distinctKeyword}${columns} FROM ${tableName}${whereClause}${orderByClause}${limitClause};`;
|
|
726
|
+
return this.each(query, params);
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
updateRecord(tableName, data, whereClause, params = []) {
|
|
730
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
731
|
+
const setClause = Object.keys(data)
|
|
732
|
+
.map((key) => `${key} = ?`)
|
|
733
|
+
.join(', ');
|
|
734
|
+
const values = Object.values(data);
|
|
735
|
+
const query = `UPDATE ${tableName} SET ${setClause} ${whereClause};`;
|
|
736
|
+
yield this.run(query, [...values, ...params]);
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
deleteRecord(tableName, whereClause, params = []) {
|
|
740
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
741
|
+
const query = `DELETE FROM ${tableName} ${whereClause};`;
|
|
742
|
+
yield this.run(query, params);
|
|
743
|
+
});
|
|
744
|
+
}
|
|
694
745
|
}
|
|
695
746
|
exports.SQLiteStorage = SQLiteStorage;
|
package/out/types.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { CustomSpellcheckerModule } from './modules/custom-spell-check/types';
|
|
|
7
7
|
import { EditorPanels } from './modules/editor-right-panel/types';
|
|
8
8
|
import { CustomFileFormatLogic, FilePostExportLogic, FilePostImportLogic, FilePreExportLogic, FilePreImportLogic } from './modules/file-processing/types';
|
|
9
9
|
import { IntegrationLogic } from './modules/integration/types';
|
|
10
|
+
import { Storage } from './storage';
|
|
10
11
|
import { MySQLStorageConfig } from './storage/mysql';
|
|
11
12
|
import { PostgreStorageConfig } from './storage/postgre';
|
|
12
13
|
import { ApiModule } from './modules/api/types';
|
|
@@ -353,6 +354,7 @@ export interface CrowdinAppUtilities extends CrowdinMetadataStore {
|
|
|
353
354
|
client: Crowdin;
|
|
354
355
|
extra: Record<string, any>;
|
|
355
356
|
}>;
|
|
357
|
+
storage: Storage;
|
|
356
358
|
}
|
|
357
359
|
export interface CrowdinMetadataStore {
|
|
358
360
|
saveMetadata: (id: string, metadata: any, crowdinId?: string) => Promise<void>;
|
|
@@ -919,6 +919,186 @@
|
|
|
919
919
|
}
|
|
920
920
|
}
|
|
921
921
|
|
|
922
|
+
function hideConfirmUsersBlock() {
|
|
923
|
+
const confirmUsersBlock = document.querySelector('.confirm-users-block');
|
|
924
|
+
confirmUsersBlock.classList.add('hidden');
|
|
925
|
+
|
|
926
|
+
const permissionsModal = document.getElementById('permissions-modal');
|
|
927
|
+
permissionsModal.setAttribute('body-overflow-unset', true)
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
function showPermissionsDialog() {
|
|
931
|
+
hideConfirmUsersBlock();
|
|
932
|
+
openModal(permissions)
|
|
933
|
+
setLoader('#permissions-modal');
|
|
934
|
+
const select = document.getElementById('users');
|
|
935
|
+
|
|
936
|
+
select.value = '[]';
|
|
937
|
+
|
|
938
|
+
checkOrigin()
|
|
939
|
+
.then(restParams => fetch('api/users' + restParams))
|
|
940
|
+
.then(checkResponse)
|
|
941
|
+
.then((res) => {
|
|
942
|
+
let userOptions = res.data.users.map(user => `<option value="${user.id}">${sanitizeHTML(user.name)}</option>`).join('');
|
|
943
|
+
select.innerHTML = userOptions;
|
|
944
|
+
select.value = JSON.stringify(res.data.managers);
|
|
945
|
+
})
|
|
946
|
+
.catch(e => catchRejection(e, 'Can\'t fetch users'))
|
|
947
|
+
.finally(() => unsetLoader('#permissions-modal'));
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
function showConfirmUsersBlock() {
|
|
951
|
+
const confirmUsersBlock = document.querySelector('.confirm-users-block');
|
|
952
|
+
confirmUsersBlock.classList.remove('hidden');
|
|
953
|
+
|
|
954
|
+
const permissionsModal = document.getElementById('permissions-modal');
|
|
955
|
+
permissionsModal.removeAttribute('body-overflow-unset')
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
async function inviteUsers(onlyCheck = true) {
|
|
959
|
+
setLoader('#permissions-modal');
|
|
960
|
+
|
|
961
|
+
const select = document.getElementById('users');
|
|
962
|
+
|
|
963
|
+
if (onlyCheck && select.value === '[]') {
|
|
964
|
+
hideConfirmUsersBlock();
|
|
965
|
+
unsetLoader('#permissions-modal');
|
|
966
|
+
return;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
const params = {
|
|
970
|
+
users: JSON.parse(select.value),
|
|
971
|
+
onlyCheck,
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
checkOrigin()
|
|
975
|
+
.then(restParams => fetch('api/invite-users' + restParams, {
|
|
976
|
+
method: 'POST',
|
|
977
|
+
headers: { 'Content-Type': 'application/json' },
|
|
978
|
+
body: JSON.stringify(params)
|
|
979
|
+
}))
|
|
980
|
+
.then(checkResponse)
|
|
981
|
+
.then((response) => {
|
|
982
|
+
if (!onlyCheck) {
|
|
983
|
+
showToast('Users successfully updated');
|
|
984
|
+
hideConfirmUsersBlock();
|
|
985
|
+
closeModal(permissions);
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
prepareUsersConfirmBlock(response.data);
|
|
990
|
+
})
|
|
991
|
+
.catch(e => {
|
|
992
|
+
catchRejection(e, e?.error || 'Can\'t invite users')
|
|
993
|
+
})
|
|
994
|
+
.finally(() => unsetLoader('#permissions-modal'));
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
function prepareUsersConfirmBlock(usersData) {
|
|
998
|
+
showConfirmUsersBlock();
|
|
999
|
+
|
|
1000
|
+
const organizationInvite = document.querySelector('.organization-invite');
|
|
1001
|
+
const projectInvite = document.querySelector('.project-invite');
|
|
1002
|
+
const applicationCredentialsInvite = document.querySelector('.application-credentials-invite');
|
|
1003
|
+
|
|
1004
|
+
const grantedElement = '<crowdin-p>―</crowdin-p>';
|
|
1005
|
+
const willGrantedElement = '<span class="badge badge-will-be-granted">Will Be Granted</span>';
|
|
1006
|
+
const notAvailableElement = '<span class="badge badge-not-available">Action Required</span>';
|
|
1007
|
+
|
|
1008
|
+
// only in enterprise
|
|
1009
|
+
if (organizationInvite) {
|
|
1010
|
+
const organizationWillGrantElement = `<span class="badge badge-will-be-granted">Will Be Registered</span>`;
|
|
1011
|
+
|
|
1012
|
+
processUsersWhoWillBeInvited(organizationInvite, usersData.usersWhoWillBeInvitedToOrganization, organizationWillGrantElement, grantedElement);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
processUsersWhoWillBeInvited(projectInvite, usersData.usersWhoWillBeInvitedToProject, willGrantedElement, grantedElement);
|
|
1016
|
+
processUsersWhoWillBeInvited(applicationCredentialsInvite, usersData.usersWhoNotIssetInIntegration, willGrantedElement, grantedElement);
|
|
1017
|
+
|
|
1018
|
+
processUsersWhoWillBeInvitedApplicationSettings(usersData, willGrantedElement, grantedElement, notAvailableElement);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
function processUsersWhoWillBeInvited(element, users, grantMessage, alreadyGrantedMessage) {
|
|
1022
|
+
const tooltip = element.querySelector('.status');
|
|
1023
|
+
const userList = element.querySelector('.affected-users');
|
|
1024
|
+
|
|
1025
|
+
if (users.length) {
|
|
1026
|
+
tooltip.innerHTML = grantMessage;
|
|
1027
|
+
|
|
1028
|
+
let affectedUsers = '<ul>';
|
|
1029
|
+
for (const user of users) {
|
|
1030
|
+
affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
|
|
1031
|
+
}
|
|
1032
|
+
affectedUsers += '</ul>';
|
|
1033
|
+
userList.innerHTML = affectedUsers;
|
|
1034
|
+
} else {
|
|
1035
|
+
tooltip.innerHTML = alreadyGrantedMessage;
|
|
1036
|
+
userList.innerHTML = alreadyGrantedMessage;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
function processUsersWhoWillBeInvitedApplicationSettings(usersData, willGrantedElement, grantedElement, notAvailableElement) {
|
|
1041
|
+
const applicationSettingsInvite = document.querySelector('.application-settings-invite');
|
|
1042
|
+
|
|
1043
|
+
const tooltip = applicationSettingsInvite.querySelector('.status');
|
|
1044
|
+
const description = applicationSettingsInvite.querySelector('.permission-description');
|
|
1045
|
+
const userList = applicationSettingsInvite.querySelector('.affected-users');
|
|
1046
|
+
|
|
1047
|
+
let descriptionMessage = 'This can be configured in organization settings (Apps section).';
|
|
1048
|
+
description.classList.remove('text-warning');
|
|
1049
|
+
description.innerText = descriptionMessage;
|
|
1050
|
+
|
|
1051
|
+
let affectedUsers = '<ul>';
|
|
1052
|
+
|
|
1053
|
+
if (!usersData.editApplicationAvailable) {
|
|
1054
|
+
descriptionMessage += ' The application doesn\'t have permission to update this setting.';
|
|
1055
|
+
descriptionMessage += usersData.isAdmin ? ' Please reinstall the app.' : ' Please ask the organization admin to reinstall the app.';
|
|
1056
|
+
|
|
1057
|
+
description.classList.add('text-warning');
|
|
1058
|
+
description.innerText = descriptionMessage;
|
|
1059
|
+
|
|
1060
|
+
tooltip.innerHTML = notAvailableElement;
|
|
1061
|
+
for (const user of usersData.usersWhoNotIssetInApplicationInstallation) {
|
|
1062
|
+
affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
|
|
1063
|
+
}
|
|
1064
|
+
userList.innerHTML = affectedUsers + '</ul>';
|
|
1065
|
+
} else if (!usersData.usersWhoNotIssetInApplicationInstallation.length) {
|
|
1066
|
+
tooltip.innerHTML = grantedElement;
|
|
1067
|
+
userList.innerHTML = grantedElement;
|
|
1068
|
+
} else {
|
|
1069
|
+
if (usersData.isAdmin) {
|
|
1070
|
+
tooltip.innerHTML = willGrantedElement;
|
|
1071
|
+
for (const user of usersData.usersWhoNotIssetInApplicationInstallation) {
|
|
1072
|
+
affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
|
|
1073
|
+
}
|
|
1074
|
+
userList.innerHTML = affectedUsers + '</ul>';
|
|
1075
|
+
} else {
|
|
1076
|
+
descriptionMessage += ' Only organization admins have permission to update this setting.';
|
|
1077
|
+
|
|
1078
|
+
description.classList.add('text-warning');
|
|
1079
|
+
description.innerText = descriptionMessage;
|
|
1080
|
+
|
|
1081
|
+
tooltip.innerHTML = notAvailableElement;
|
|
1082
|
+
for (const user of usersData.usersWhoNotIssetInApplicationInstallation) {
|
|
1083
|
+
affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
|
|
1084
|
+
}
|
|
1085
|
+
userList.innerHTML = affectedUsers + '</ul>';
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
function setLoader(id) {
|
|
1091
|
+
const loader = document.querySelector(`${id} .loader`);
|
|
1092
|
+
loader.classList.remove('hidden');
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
function unsetLoader(id) {
|
|
1096
|
+
const loader = document.querySelector(`${id} .loader`);
|
|
1097
|
+
setTimeout(function() {
|
|
1098
|
+
loader.classList.add('hidden');
|
|
1099
|
+
}, 500)
|
|
1100
|
+
}
|
|
1101
|
+
|
|
922
1102
|
{{#if configurationFields}}
|
|
923
1103
|
const settingsModal = document.getElementById('settings-modal');
|
|
924
1104
|
const settingsSaveBtn = document.getElementById('settings-save-btn');
|
|
@@ -998,186 +1178,6 @@
|
|
|
998
1178
|
{{/if}}
|
|
999
1179
|
});
|
|
1000
1180
|
}
|
|
1001
|
-
|
|
1002
|
-
function showConfirmUsersBlock() {
|
|
1003
|
-
const confirmUsersBlock = document.querySelector('.confirm-users-block');
|
|
1004
|
-
confirmUsersBlock.classList.remove('hidden');
|
|
1005
|
-
|
|
1006
|
-
const permissionsModal = document.getElementById('permissions-modal');
|
|
1007
|
-
permissionsModal.removeAttribute('body-overflow-unset')
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
function hideConfirmUsersBlock() {
|
|
1011
|
-
const confirmUsersBlock = document.querySelector('.confirm-users-block');
|
|
1012
|
-
confirmUsersBlock.classList.add('hidden');
|
|
1013
|
-
|
|
1014
|
-
const permissionsModal = document.getElementById('permissions-modal');
|
|
1015
|
-
permissionsModal.setAttribute('body-overflow-unset', true)
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
function showPermissionsDialog() {
|
|
1019
|
-
hideConfirmUsersBlock();
|
|
1020
|
-
openModal(permissions)
|
|
1021
|
-
setLoader('#permissions-modal');
|
|
1022
|
-
const select = document.getElementById('users');
|
|
1023
|
-
|
|
1024
|
-
select.value = '[]';
|
|
1025
|
-
|
|
1026
|
-
checkOrigin()
|
|
1027
|
-
.then(restParams => fetch('api/users' + restParams))
|
|
1028
|
-
.then(checkResponse)
|
|
1029
|
-
.then((res) => {
|
|
1030
|
-
let userOptions = res.data.users.map(user => `<option value="${user.id}">${sanitizeHTML(user.name)}</option>`).join('');
|
|
1031
|
-
select.innerHTML = userOptions;
|
|
1032
|
-
select.value = JSON.stringify(res.data.managers);
|
|
1033
|
-
})
|
|
1034
|
-
.catch(e => catchRejection(e, 'Can\'t fetch users'))
|
|
1035
|
-
.finally(() => unsetLoader('#permissions-modal'));
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
async function inviteUsers(onlyCheck = true) {
|
|
1039
|
-
setLoader('#permissions-modal');
|
|
1040
|
-
|
|
1041
|
-
const select = document.getElementById('users');
|
|
1042
|
-
|
|
1043
|
-
if (onlyCheck && select.value === '[]') {
|
|
1044
|
-
hideConfirmUsersBlock();
|
|
1045
|
-
unsetLoader('#permissions-modal');
|
|
1046
|
-
return;
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
const params = {
|
|
1050
|
-
users: JSON.parse(select.value),
|
|
1051
|
-
onlyCheck,
|
|
1052
|
-
};
|
|
1053
|
-
|
|
1054
|
-
checkOrigin()
|
|
1055
|
-
.then(restParams => fetch('api/invite-users' + restParams, {
|
|
1056
|
-
method: 'POST',
|
|
1057
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1058
|
-
body: JSON.stringify(params)
|
|
1059
|
-
}))
|
|
1060
|
-
.then(checkResponse)
|
|
1061
|
-
.then((response) => {
|
|
1062
|
-
if (!onlyCheck) {
|
|
1063
|
-
showToast('Users successfully updated');
|
|
1064
|
-
hideConfirmUsersBlock();
|
|
1065
|
-
closeModal(permissions);
|
|
1066
|
-
return;
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
prepareUsersConfirmBlock(response.data);
|
|
1070
|
-
})
|
|
1071
|
-
.catch(e => {
|
|
1072
|
-
catchRejection(e, e?.error || 'Can\'t invite users')
|
|
1073
|
-
})
|
|
1074
|
-
.finally(() => unsetLoader('#permissions-modal'));
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
function prepareUsersConfirmBlock(usersData) {
|
|
1078
|
-
showConfirmUsersBlock();
|
|
1079
|
-
|
|
1080
|
-
const organizationInvite = document.querySelector('.organization-invite');
|
|
1081
|
-
const projectInvite = document.querySelector('.project-invite');
|
|
1082
|
-
const applicationCredentialsInvite = document.querySelector('.application-credentials-invite');
|
|
1083
|
-
|
|
1084
|
-
const grantedElement = '<crowdin-p>―</crowdin-p>';
|
|
1085
|
-
const willGrantedElement = '<span class="badge badge-will-be-granted">Will Be Granted</span>';
|
|
1086
|
-
const notAvailableElement = '<span class="badge badge-not-available">Action Required</span>';
|
|
1087
|
-
|
|
1088
|
-
// only in enterprise
|
|
1089
|
-
if (organizationInvite) {
|
|
1090
|
-
const organizationWillGrantElement = `<span class="badge badge-will-be-granted">Will Be Registered</span>`;
|
|
1091
|
-
|
|
1092
|
-
processUsersWhoWillBeInvited(organizationInvite, usersData.usersWhoWillBeInvitedToOrganization, organizationWillGrantElement, grantedElement);
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
processUsersWhoWillBeInvited(projectInvite, usersData.usersWhoWillBeInvitedToProject, willGrantedElement, grantedElement);
|
|
1096
|
-
processUsersWhoWillBeInvited(applicationCredentialsInvite, usersData.usersWhoNotIssetInIntegration, willGrantedElement, grantedElement);
|
|
1097
|
-
|
|
1098
|
-
processUsersWhoWillBeInvitedApplicationSettings(usersData, willGrantedElement, grantedElement, notAvailableElement);
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
function processUsersWhoWillBeInvited(element, users, grantMessage, alreadyGrantedMessage) {
|
|
1102
|
-
const tooltip = element.querySelector('.status');
|
|
1103
|
-
const userList = element.querySelector('.affected-users');
|
|
1104
|
-
|
|
1105
|
-
if (users.length) {
|
|
1106
|
-
tooltip.innerHTML = grantMessage;
|
|
1107
|
-
|
|
1108
|
-
let affectedUsers = '<ul>';
|
|
1109
|
-
for (const user of users) {
|
|
1110
|
-
affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
|
|
1111
|
-
}
|
|
1112
|
-
affectedUsers += '</ul>';
|
|
1113
|
-
userList.innerHTML = affectedUsers;
|
|
1114
|
-
} else {
|
|
1115
|
-
tooltip.innerHTML = alreadyGrantedMessage;
|
|
1116
|
-
userList.innerHTML = alreadyGrantedMessage;
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
function processUsersWhoWillBeInvitedApplicationSettings(usersData, willGrantedElement, grantedElement, notAvailableElement) {
|
|
1121
|
-
const applicationSettingsInvite = document.querySelector('.application-settings-invite');
|
|
1122
|
-
|
|
1123
|
-
const tooltip = applicationSettingsInvite.querySelector('.status');
|
|
1124
|
-
const description = applicationSettingsInvite.querySelector('.permission-description');
|
|
1125
|
-
const userList = applicationSettingsInvite.querySelector('.affected-users');
|
|
1126
|
-
|
|
1127
|
-
let descriptionMessage = 'This can be configured in organization settings (Apps section).';
|
|
1128
|
-
description.classList.remove('text-warning');
|
|
1129
|
-
description.innerText = descriptionMessage;
|
|
1130
|
-
|
|
1131
|
-
let affectedUsers = '<ul>';
|
|
1132
|
-
|
|
1133
|
-
if (!usersData.editApplicationAvailable) {
|
|
1134
|
-
descriptionMessage += ' The application doesn\'t have permission to update this setting.';
|
|
1135
|
-
descriptionMessage += usersData.isAdmin ? ' Please reinstall the app.' : ' Please ask the organization admin to reinstall the app.';
|
|
1136
|
-
|
|
1137
|
-
description.classList.add('text-warning');
|
|
1138
|
-
description.innerText = descriptionMessage;
|
|
1139
|
-
|
|
1140
|
-
tooltip.innerHTML = notAvailableElement;
|
|
1141
|
-
for (const user of usersData.usersWhoNotIssetInApplicationInstallation) {
|
|
1142
|
-
affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
|
|
1143
|
-
}
|
|
1144
|
-
userList.innerHTML = affectedUsers + '</ul>';
|
|
1145
|
-
} else if (!usersData.usersWhoNotIssetInApplicationInstallation.length) {
|
|
1146
|
-
tooltip.innerHTML = grantedElement;
|
|
1147
|
-
userList.innerHTML = grantedElement;
|
|
1148
|
-
} else {
|
|
1149
|
-
if (usersData.isAdmin) {
|
|
1150
|
-
tooltip.innerHTML = willGrantedElement;
|
|
1151
|
-
for (const user of usersData.usersWhoNotIssetInApplicationInstallation) {
|
|
1152
|
-
affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
|
|
1153
|
-
}
|
|
1154
|
-
userList.innerHTML = affectedUsers + '</ul>';
|
|
1155
|
-
} else {
|
|
1156
|
-
descriptionMessage += ' Only organization admins have permission to update this setting.';
|
|
1157
|
-
|
|
1158
|
-
description.classList.add('text-warning');
|
|
1159
|
-
description.innerText = descriptionMessage;
|
|
1160
|
-
|
|
1161
|
-
tooltip.innerHTML = notAvailableElement;
|
|
1162
|
-
for (const user of usersData.usersWhoNotIssetInApplicationInstallation) {
|
|
1163
|
-
affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
|
|
1164
|
-
}
|
|
1165
|
-
userList.innerHTML = affectedUsers + '</ul>';
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
function setLoader(id) {
|
|
1171
|
-
const loader = document.querySelector(`${id} .loader`);
|
|
1172
|
-
loader.classList.remove('hidden');
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
function unsetLoader(id) {
|
|
1176
|
-
const loader = document.querySelector(`${id} .loader`);
|
|
1177
|
-
setTimeout(function() {
|
|
1178
|
-
loader.classList.add('hidden');
|
|
1179
|
-
}, 500)
|
|
1180
|
-
}
|
|
1181
1181
|
{{else}}
|
|
1182
1182
|
const settingsModal = undefined;
|
|
1183
1183
|
{{/if}}
|
package/package.json
CHANGED