@crowdin/app-project-module 0.79.2 → 0.81.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/api/api.js +2 -2
- package/out/modules/integration/handlers/invite-users.js +18 -7
- package/out/modules/integration/index.js +4 -2
- package/out/modules/integration/types.d.ts +2 -2
- 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 +175 -38
- package/out/storage/postgre.d.ts +11 -0
- package/out/storage/postgre.js +64 -0
- package/out/storage/sqlite.d.ts +11 -0
- package/out/storage/sqlite.js +48 -0
- package/out/types.d.ts +2 -0
- package/out/views/main.handlebars +35 -2
- 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/api/api.js
CHANGED
|
@@ -499,9 +499,9 @@ function addDefaultApiEndpoints(app, config) {
|
|
|
499
499
|
checkSubscriptionExpiration: true,
|
|
500
500
|
moduleKey: config.projectIntegration.key,
|
|
501
501
|
}), (req, res) => {
|
|
502
|
-
var _a;
|
|
502
|
+
var _a, _b;
|
|
503
503
|
let fields = [];
|
|
504
|
-
if ((_a = config.projectIntegration) === null || _a === void 0 ? void 0 : _a.loginForm.fields) {
|
|
504
|
+
if ((_b = (_a = config.projectIntegration) === null || _a === void 0 ? void 0 : _a.loginForm) === null || _b === void 0 ? void 0 : _b.fields) {
|
|
505
505
|
fields = getFormFields(config === null || config === void 0 ? void 0 : config.projectIntegration.loginForm.fields);
|
|
506
506
|
}
|
|
507
507
|
res.send({ fields });
|
|
@@ -47,19 +47,25 @@ function handle() {
|
|
|
47
47
|
if (!hasManagerAccess) {
|
|
48
48
|
return res.status(403).send({ error: 'Access denied' });
|
|
49
49
|
}
|
|
50
|
+
const inviteRestricted = !isAdmin &&
|
|
51
|
+
'invite_restrict_enabled' in req.crowdinContext.jwtPayload.context &&
|
|
52
|
+
!!req.crowdinContext.jwtPayload.context.invite_restrict_enabled;
|
|
50
53
|
const usersWhoWillBeInvitedToOrganization = filterOrganizationUsers(usersToInvite);
|
|
51
54
|
const usersWhoWillBeInvitedToProject = filterProjectUsers({
|
|
55
|
+
inviteRestricted,
|
|
52
56
|
usersToInvite,
|
|
53
57
|
projectMembers,
|
|
54
58
|
organizationMembers,
|
|
55
59
|
});
|
|
56
60
|
const usersWhoNotIssetInApplicationInstallation = filterNotIssetApplicationUsers({
|
|
61
|
+
inviteRestricted,
|
|
57
62
|
usersToInvite,
|
|
58
63
|
applicationInstallation,
|
|
59
64
|
projectMembers,
|
|
60
65
|
organizationMembers,
|
|
61
66
|
});
|
|
62
67
|
const usersWhoNotIssetInIntegration = filterNotIssetIntegrationUsers({
|
|
68
|
+
inviteRestricted,
|
|
63
69
|
usersToInvite,
|
|
64
70
|
integrationCredentials,
|
|
65
71
|
projectMembers,
|
|
@@ -69,6 +75,7 @@ function handle() {
|
|
|
69
75
|
return res.send({
|
|
70
76
|
data: {
|
|
71
77
|
isAdmin,
|
|
78
|
+
inviteRestricted,
|
|
72
79
|
editApplicationAvailable: applicationInstallation !== null,
|
|
73
80
|
usersWhoWillBeInvitedToOrganization,
|
|
74
81
|
usersWhoWillBeInvitedToProject,
|
|
@@ -81,6 +88,7 @@ function handle() {
|
|
|
81
88
|
req,
|
|
82
89
|
projectId,
|
|
83
90
|
isAdmin,
|
|
91
|
+
inviteRestricted,
|
|
84
92
|
usersToInvite,
|
|
85
93
|
applicationInstallation,
|
|
86
94
|
usersWhoWillBeInvitedToOrganization,
|
|
@@ -94,10 +102,10 @@ exports.default = handle;
|
|
|
94
102
|
function filterOrganizationUsers(usersToInvite) {
|
|
95
103
|
return usersToInvite.filter((identifier) => (0, util_1.validateEmail)(identifier)).map((name) => ({ name: `${name}` }));
|
|
96
104
|
}
|
|
97
|
-
function filterProjectUsers({ usersToInvite, projectMembers, organizationMembers, }) {
|
|
105
|
+
function filterProjectUsers({ inviteRestricted, usersToInvite, projectMembers, organizationMembers, }) {
|
|
98
106
|
return usersToInvite
|
|
99
107
|
.map((identifier) => {
|
|
100
|
-
if ((0, util_1.validateEmail)(identifier)) {
|
|
108
|
+
if ((0, util_1.validateEmail)(identifier) && !inviteRestricted) {
|
|
101
109
|
return { name: `${identifier}` };
|
|
102
110
|
}
|
|
103
111
|
const user = projectMembers.find((member) => member.id === +identifier);
|
|
@@ -113,7 +121,7 @@ function filterProjectUsers({ usersToInvite, projectMembers, organizationMembers
|
|
|
113
121
|
})
|
|
114
122
|
.filter(Boolean);
|
|
115
123
|
}
|
|
116
|
-
function filterNotIssetApplicationUsers({ usersToInvite, applicationInstallation, projectMembers, organizationMembers, }) {
|
|
124
|
+
function filterNotIssetApplicationUsers({ inviteRestricted, usersToInvite, applicationInstallation, projectMembers, organizationMembers, }) {
|
|
117
125
|
let userIdentifiers = [];
|
|
118
126
|
if (!applicationInstallation) {
|
|
119
127
|
return [];
|
|
@@ -130,7 +138,7 @@ function filterNotIssetApplicationUsers({ usersToInvite, applicationInstallation
|
|
|
130
138
|
}
|
|
131
139
|
return userIdentifiers
|
|
132
140
|
.map((identifier) => {
|
|
133
|
-
if ((0, util_1.validateEmail)(identifier)) {
|
|
141
|
+
if ((0, util_1.validateEmail)(identifier) && !inviteRestricted) {
|
|
134
142
|
return { name: `${identifier}` };
|
|
135
143
|
}
|
|
136
144
|
let user;
|
|
@@ -142,7 +150,7 @@ function filterNotIssetApplicationUsers({ usersToInvite, applicationInstallation
|
|
|
142
150
|
})
|
|
143
151
|
.filter(Boolean);
|
|
144
152
|
}
|
|
145
|
-
function filterNotIssetIntegrationUsers({ usersToInvite, integrationCredentials, projectMembers, organizationMembers, }) {
|
|
153
|
+
function filterNotIssetIntegrationUsers({ inviteRestricted, usersToInvite, integrationCredentials, projectMembers, organizationMembers, }) {
|
|
146
154
|
let integrationManagers = [];
|
|
147
155
|
if (integrationCredentials === null || integrationCredentials === void 0 ? void 0 : integrationCredentials.managers) {
|
|
148
156
|
integrationManagers = JSON.parse(integrationCredentials.managers);
|
|
@@ -152,7 +160,7 @@ function filterNotIssetIntegrationUsers({ usersToInvite, integrationCredentials,
|
|
|
152
160
|
if (integrationManagers.includes(`${identifier}`)) {
|
|
153
161
|
return null;
|
|
154
162
|
}
|
|
155
|
-
if ((0, util_1.validateEmail)(identifier)) {
|
|
163
|
+
if ((0, util_1.validateEmail)(identifier) && !inviteRestricted) {
|
|
156
164
|
return { name: `${identifier}` };
|
|
157
165
|
}
|
|
158
166
|
let user;
|
|
@@ -164,9 +172,12 @@ function filterNotIssetIntegrationUsers({ usersToInvite, integrationCredentials,
|
|
|
164
172
|
})
|
|
165
173
|
.filter(Boolean);
|
|
166
174
|
}
|
|
167
|
-
function inviteUsers({ req, projectId, isAdmin, usersToInvite, applicationInstallation, usersWhoWillBeInvitedToOrganization, usersWhoWillBeInvitedToProject, usersWhoNotIssetInApplicationInstallation, }) {
|
|
175
|
+
function inviteUsers({ req, projectId, isAdmin, inviteRestricted, usersToInvite, applicationInstallation, usersWhoWillBeInvitedToOrganization, usersWhoWillBeInvitedToProject, usersWhoNotIssetInApplicationInstallation, }) {
|
|
168
176
|
return __awaiter(this, void 0, void 0, function* () {
|
|
169
177
|
const client = req.crowdinApiClient;
|
|
178
|
+
if (inviteRestricted) {
|
|
179
|
+
usersWhoWillBeInvitedToOrganization = [];
|
|
180
|
+
}
|
|
170
181
|
const alreadyAddedUserIds = yield inviteUsersToProject({
|
|
171
182
|
client,
|
|
172
183
|
projectId,
|
|
@@ -197,8 +197,10 @@ function register({ config, app }) {
|
|
|
197
197
|
}
|
|
198
198
|
// remove user errors
|
|
199
199
|
cron.schedule('0 0 * * *', () => __awaiter(this, void 0, void 0, function* () {
|
|
200
|
-
|
|
201
|
-
|
|
200
|
+
if (integrationLogic.userErrorLifetimeDays) {
|
|
201
|
+
const date = (0, util_1.getPreviousDate)(integrationLogic.userErrorLifetimeDays);
|
|
202
|
+
yield (0, storage_1.getStorage)().deleteAllUsersErrorsOlderThan(`${date.getTime()}`);
|
|
203
|
+
}
|
|
202
204
|
}));
|
|
203
205
|
if (integrationLogic.webhooks) {
|
|
204
206
|
app.post(`${integrationLogic.webhooks.crowdinWebhookUrl
|
|
@@ -6,7 +6,7 @@ export interface IntegrationLogic extends ModuleKey {
|
|
|
6
6
|
/**
|
|
7
7
|
* Customize your app login form
|
|
8
8
|
*/
|
|
9
|
-
loginForm
|
|
9
|
+
loginForm?: LoginForm;
|
|
10
10
|
/**
|
|
11
11
|
* Define login process via OAuth2 protocol
|
|
12
12
|
*/
|
|
@@ -162,7 +162,7 @@ export interface IntegrationLogic extends ModuleKey {
|
|
|
162
162
|
/**
|
|
163
163
|
* The duration for storing user errors, default is 30 days.
|
|
164
164
|
*/
|
|
165
|
-
userErrorLifetimeDays
|
|
165
|
+
userErrorLifetimeDays?: number;
|
|
166
166
|
/**
|
|
167
167
|
* When true, folder filtering during automatic translation sync is bypassed, and the file tree is returned unchanged.
|
|
168
168
|
*/
|
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
|
@@ -438,7 +438,12 @@ class MySQLStorage {
|
|
|
438
438
|
}
|
|
439
439
|
yield this.dbPromise;
|
|
440
440
|
const placeholders = fileIds.map(() => '?').join(',');
|
|
441
|
-
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]));
|
|
442
447
|
});
|
|
443
448
|
}
|
|
444
449
|
getAllUserErrors(crowdinId, integrationId) {
|
|
@@ -451,7 +456,9 @@ class MySQLStorage {
|
|
|
451
456
|
whereIntegrationCondition = 'integration_id = ?';
|
|
452
457
|
params.push(integrationId);
|
|
453
458
|
}
|
|
454
|
-
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);
|
|
455
462
|
return rows || [];
|
|
456
463
|
}));
|
|
457
464
|
});
|
|
@@ -472,7 +479,11 @@ class MySQLStorage {
|
|
|
472
479
|
whereIntegrationCondition = 'integration_id = ?';
|
|
473
480
|
params.push(integrationId);
|
|
474
481
|
}
|
|
475
|
-
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);
|
|
476
487
|
});
|
|
477
488
|
});
|
|
478
489
|
}
|
|
@@ -525,7 +536,7 @@ class MySQLStorage {
|
|
|
525
536
|
yield this.executeQuery((connection) => connection.execute(`
|
|
526
537
|
INSERT INTO job(id, integration_id, crowdin_id, type, payload, title, created_at)
|
|
527
538
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
528
|
-
|
|
539
|
+
`, [id, integrationId, crowdinId, type, payload, title, Date.now().toString()]));
|
|
529
540
|
return id;
|
|
530
541
|
});
|
|
531
542
|
}
|
|
@@ -567,7 +578,7 @@ class MySQLStorage {
|
|
|
567
578
|
UPDATE job
|
|
568
579
|
SET ${updateFields.join(', ')}
|
|
569
580
|
WHERE id = ?
|
|
570
|
-
|
|
581
|
+
`, updateParams));
|
|
571
582
|
});
|
|
572
583
|
}
|
|
573
584
|
getJob({ id }) {
|
|
@@ -575,11 +586,23 @@ class MySQLStorage {
|
|
|
575
586
|
yield this.dbPromise;
|
|
576
587
|
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
577
588
|
const [rows] = yield connection.execute(`
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
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]);
|
|
583
606
|
return (rows || [])[0];
|
|
584
607
|
}));
|
|
585
608
|
});
|
|
@@ -589,11 +612,25 @@ class MySQLStorage {
|
|
|
589
612
|
yield this.dbPromise;
|
|
590
613
|
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
591
614
|
const [rows] = yield connection.execute(`
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
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]);
|
|
597
634
|
return rows || [];
|
|
598
635
|
}));
|
|
599
636
|
});
|
|
@@ -609,11 +646,24 @@ class MySQLStorage {
|
|
|
609
646
|
yield this.dbPromise;
|
|
610
647
|
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
611
648
|
const [rows] = yield connection.execute(`
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
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]);
|
|
617
667
|
return rows || [];
|
|
618
668
|
}));
|
|
619
669
|
});
|
|
@@ -624,7 +674,7 @@ class MySQLStorage {
|
|
|
624
674
|
yield this.executeQuery((connection) => connection.execute(`
|
|
625
675
|
INSERT INTO translation_file_cache(integration_id, crowdin_id, file_id, language_id, etag)
|
|
626
676
|
VALUES (?, ?, ?, ?, ?)
|
|
627
|
-
|
|
677
|
+
`, [integrationId, crowdinId, fileId, languageId, etag]));
|
|
628
678
|
});
|
|
629
679
|
}
|
|
630
680
|
getFileTranslationCache({ integrationId, crowdinId, fileId, }) {
|
|
@@ -632,10 +682,16 @@ class MySQLStorage {
|
|
|
632
682
|
yield this.dbPromise;
|
|
633
683
|
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
634
684
|
const [rows] = yield connection.execute(`
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
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]);
|
|
639
695
|
return rows || [];
|
|
640
696
|
}));
|
|
641
697
|
});
|
|
@@ -645,10 +701,17 @@ class MySQLStorage {
|
|
|
645
701
|
yield this.dbPromise;
|
|
646
702
|
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
647
703
|
const [rows] = yield connection.execute(`
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
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]);
|
|
652
715
|
return (rows || [])[0];
|
|
653
716
|
}));
|
|
654
717
|
});
|
|
@@ -659,8 +722,11 @@ class MySQLStorage {
|
|
|
659
722
|
yield this.executeQuery((connection) => connection.execute(`
|
|
660
723
|
UPDATE translation_file_cache
|
|
661
724
|
SET etag = ?
|
|
662
|
-
WHERE integration_id = ?
|
|
663
|
-
|
|
725
|
+
WHERE integration_id = ?
|
|
726
|
+
AND crowdin_id = ?
|
|
727
|
+
AND file_id = ?
|
|
728
|
+
AND language_id = ?
|
|
729
|
+
`, [etag, integrationId, crowdinId, fileId, languageId]));
|
|
664
730
|
});
|
|
665
731
|
}
|
|
666
732
|
saveUnsyncedFiles({ integrationId, crowdinId, files }) {
|
|
@@ -669,7 +735,7 @@ class MySQLStorage {
|
|
|
669
735
|
yield this.executeQuery((connection) => connection.execute(`
|
|
670
736
|
INSERT INTO unsynced_files(integration_id, crowdin_id, files)
|
|
671
737
|
VALUES (?, ?, ?,)
|
|
672
|
-
|
|
738
|
+
`, [integrationId, crowdinId, files]));
|
|
673
739
|
});
|
|
674
740
|
}
|
|
675
741
|
updateUnsyncedFiles({ integrationId, crowdinId, files }) {
|
|
@@ -678,8 +744,9 @@ class MySQLStorage {
|
|
|
678
744
|
yield this.executeQuery((connection) => connection.execute(`
|
|
679
745
|
UPDATE unsynced_files
|
|
680
746
|
SET files = ?
|
|
681
|
-
WHERE integration_id = ?
|
|
682
|
-
|
|
747
|
+
WHERE integration_id = ?
|
|
748
|
+
AND crowdin_id = ?
|
|
749
|
+
`, [files, integrationId, crowdinId]));
|
|
683
750
|
});
|
|
684
751
|
}
|
|
685
752
|
getUnsyncedFiles({ integrationId, crowdinId }) {
|
|
@@ -687,13 +754,83 @@ class MySQLStorage {
|
|
|
687
754
|
yield this.dbPromise;
|
|
688
755
|
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
689
756
|
const [rows] = yield connection.execute(`
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
757
|
+
SELECT fileIds
|
|
758
|
+
FROM unsynced_files
|
|
759
|
+
WHERE integration_id = ?
|
|
760
|
+
AND crowdin_id = ?
|
|
761
|
+
`, [integrationId, crowdinId]);
|
|
694
762
|
return (rows || [])[0];
|
|
695
763
|
}));
|
|
696
764
|
});
|
|
697
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
|
+
}
|
|
698
835
|
}
|
|
699
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
|
@@ -816,5 +816,69 @@ class PostgreStorage {
|
|
|
816
816
|
}));
|
|
817
817
|
});
|
|
818
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
|
+
}
|
|
819
883
|
}
|
|
820
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
|
@@ -694,5 +694,53 @@ class SQLiteStorage {
|
|
|
694
694
|
}
|
|
695
695
|
});
|
|
696
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
|
+
}
|
|
697
745
|
}
|
|
698
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>;
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
integration-one-level-fetching="true"
|
|
72
72
|
{{/if}}
|
|
73
73
|
{{#if integrationSearchListener}}
|
|
74
|
-
allow-filter-change-listener="true"
|
|
74
|
+
allow-integration-filter-change-listener="true"
|
|
75
75
|
{{/if}}
|
|
76
76
|
{{#if integrationPagination}}
|
|
77
77
|
integration-load-more-files="true"
|
|
@@ -166,6 +166,7 @@
|
|
|
166
166
|
<tr class="organization-invite">
|
|
167
167
|
<td>
|
|
168
168
|
<crowdin-p>Registration in Organization</crowdin-p>
|
|
169
|
+
<div class="permission-description"></div>
|
|
169
170
|
</td>
|
|
170
171
|
<td class="affected-users"></td>
|
|
171
172
|
<td class="status"></td>
|
|
@@ -1009,7 +1010,7 @@
|
|
|
1009
1010
|
if (organizationInvite) {
|
|
1010
1011
|
const organizationWillGrantElement = `<span class="badge badge-will-be-granted">Will Be Registered</span>`;
|
|
1011
1012
|
|
|
1012
|
-
|
|
1013
|
+
processUsersWhoWillBeInvitedToOrganization(organizationInvite, usersData, organizationWillGrantElement, grantedElement, notAvailableElement);
|
|
1013
1014
|
}
|
|
1014
1015
|
|
|
1015
1016
|
processUsersWhoWillBeInvited(projectInvite, usersData.usersWhoWillBeInvitedToProject, willGrantedElement, grantedElement);
|
|
@@ -1018,6 +1019,38 @@
|
|
|
1018
1019
|
processUsersWhoWillBeInvitedApplicationSettings(usersData, willGrantedElement, grantedElement, notAvailableElement);
|
|
1019
1020
|
}
|
|
1020
1021
|
|
|
1022
|
+
function processUsersWhoWillBeInvitedToOrganization(element, usersData, willGrantedElement, alreadyGrantedMessage, notAvailableElement) {
|
|
1023
|
+
const tooltip = element.querySelector('.status');
|
|
1024
|
+
const description = element.querySelector('.permission-description');
|
|
1025
|
+
const userList = element.querySelector('.affected-users');
|
|
1026
|
+
|
|
1027
|
+
description.classList.remove('text-warning');
|
|
1028
|
+
description.innerText = '';
|
|
1029
|
+
|
|
1030
|
+
const users = usersData.usersWhoWillBeInvitedToOrganization;
|
|
1031
|
+
|
|
1032
|
+
if (users.length) {
|
|
1033
|
+
if (usersData.inviteRestricted) {
|
|
1034
|
+
description.classList.add('text-warning');
|
|
1035
|
+
description.innerText = 'New user invitations are restricted to administrators.';
|
|
1036
|
+
|
|
1037
|
+
tooltip.innerHTML = notAvailableElement;
|
|
1038
|
+
} else {
|
|
1039
|
+
tooltip.innerHTML = willGrantedElement;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
let affectedUsers = '<ul>';
|
|
1043
|
+
for (const user of users) {
|
|
1044
|
+
affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
|
|
1045
|
+
}
|
|
1046
|
+
affectedUsers += '</ul>';
|
|
1047
|
+
userList.innerHTML = affectedUsers;
|
|
1048
|
+
} else {
|
|
1049
|
+
tooltip.innerHTML = alreadyGrantedMessage;
|
|
1050
|
+
userList.innerHTML = alreadyGrantedMessage;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1021
1054
|
function processUsersWhoWillBeInvited(element, users, grantMessage, alreadyGrantedMessage) {
|
|
1022
1055
|
const tooltip = element.querySelector('.status');
|
|
1023
1056
|
const userList = element.querySelector('.affected-users');
|
package/package.json
CHANGED