@crowdin/app-project-module 0.57.0 → 0.58.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/app-test/integration/mocks/crowdin-storage.d.ts +1 -1
- package/out/index.js +2 -0
- package/out/modules/external-qa-check/handlers/validate.d.ts +5 -0
- package/out/modules/external-qa-check/handlers/validate.js +42 -0
- package/out/modules/external-qa-check/index.d.ts +6 -0
- package/out/modules/external-qa-check/index.js +27 -0
- package/out/modules/external-qa-check/types.d.ts +56 -0
- package/out/modules/external-qa-check/types.js +2 -0
- package/out/modules/integration/util/cron.js +12 -0
- package/out/modules/integration/util/defaults.js +2 -2
- package/out/modules/manifest.js +6 -0
- package/out/types.d.ts +5 -0
- package/out/util/logger.js +1 -1
- package/out/views/main.handlebars +14 -1
- package/package.json +1 -1
|
@@ -28,7 +28,7 @@ export declare const crowdinFiles: {
|
|
|
28
28
|
type?: SourceFilesModel.FileType | undefined;
|
|
29
29
|
parserVersion?: number | undefined;
|
|
30
30
|
importOptions?: SourceFilesModel.ImportOptions | undefined;
|
|
31
|
-
exportOptions?: SourceFilesModel.
|
|
31
|
+
exportOptions?: SourceFilesModel.ExportOptions | undefined;
|
|
32
32
|
excludedTargetLanguages?: string[] | undefined;
|
|
33
33
|
attachLabelIds?: number[] | undefined;
|
|
34
34
|
};
|
package/out/index.js
CHANGED
|
@@ -65,6 +65,7 @@ const aiPromptProvider = __importStar(require("./modules/ai-prompt-provider"));
|
|
|
65
65
|
const aiTools = __importStar(require("./modules/ai-tools"));
|
|
66
66
|
const editorRightPanelApp = __importStar(require("./modules/editor-right-panel"));
|
|
67
67
|
const editorThemesApp = __importStar(require("./modules/editor-themes"));
|
|
68
|
+
const externalQaCheck = __importStar(require("./modules/external-qa-check"));
|
|
68
69
|
const fileProcessingApps = __importStar(require("./modules/file-processing"));
|
|
69
70
|
const integrationApp = __importStar(require("./modules/integration"));
|
|
70
71
|
const modalApp = __importStar(require("./modules/modal"));
|
|
@@ -170,6 +171,7 @@ function addCrowdinEndpoints(app, clientConfig) {
|
|
|
170
171
|
aiPromptProvider.register({ config, app });
|
|
171
172
|
aiTools.registerAiTools({ config, app });
|
|
172
173
|
aiTools.registerAiToolWidgets({ config, app });
|
|
174
|
+
externalQaCheck.register({ config, app });
|
|
173
175
|
addFormSchema({ config, app });
|
|
174
176
|
return Object.assign(Object.assign({}, exports.metadataStore), { establishCrowdinConnection: (authRequest) => {
|
|
175
177
|
let jwtToken = '';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/// <reference types="qs" />
|
|
2
|
+
import { Response } from 'express';
|
|
3
|
+
import { CrowdinClientRequest } from '../../../types';
|
|
4
|
+
import { ExternalQaCheckModule } from '../types';
|
|
5
|
+
export default function handle(externalQaCheck: ExternalQaCheckModule): (req: CrowdinClientRequest | 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,42 @@
|
|
|
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 util_1 = require("../../../util");
|
|
13
|
+
const logger_1 = require("../../../util/logger");
|
|
14
|
+
function handle(externalQaCheck) {
|
|
15
|
+
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
16
|
+
const body = req.body.data;
|
|
17
|
+
(0, logger_1.log)('Received request for external qa check');
|
|
18
|
+
(0, logger_1.log)(`Payload ${JSON.stringify(body, null, 2)}`);
|
|
19
|
+
try {
|
|
20
|
+
const response = yield externalQaCheck.validate({
|
|
21
|
+
client: req.crowdinApiClient,
|
|
22
|
+
file: body.file,
|
|
23
|
+
project: body.project,
|
|
24
|
+
sourceLanguage: body.sourceLanguage,
|
|
25
|
+
strings: body.strings,
|
|
26
|
+
targetLanguage: body.targetLanguage,
|
|
27
|
+
translations: body.translations,
|
|
28
|
+
});
|
|
29
|
+
res.send({
|
|
30
|
+
data: { validations: response.validations },
|
|
31
|
+
error: response.error ? { message: response.error } : undefined,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
if (req.logError) {
|
|
36
|
+
req.logError(e);
|
|
37
|
+
}
|
|
38
|
+
res.send({ error: { message: (0, logger_1.getErrorMessage)(e) } });
|
|
39
|
+
}
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
exports.default = handle;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.register = void 0;
|
|
7
|
+
const json_response_1 = __importDefault(require("../../middlewares/json-response"));
|
|
8
|
+
const ui_module_1 = __importDefault(require("../../middlewares/ui-module"));
|
|
9
|
+
const render_ui_module_1 = __importDefault(require("../../middlewares/render-ui-module"));
|
|
10
|
+
const crowdin_client_1 = __importDefault(require("../../middlewares/crowdin-client"));
|
|
11
|
+
const validate_1 = __importDefault(require("./handlers/validate"));
|
|
12
|
+
function register({ config, app }) {
|
|
13
|
+
const qaCheck = config.externalQaCheck;
|
|
14
|
+
if (!qaCheck) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (qaCheck === null || qaCheck === void 0 ? void 0 : qaCheck.batchSize) {
|
|
18
|
+
app.use('/batch-size', json_response_1.default, (req, res) => {
|
|
19
|
+
res.send({ data: { size: qaCheck.batchSize } });
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
app.use('/validate', json_response_1.default, (0, crowdin_client_1.default)(config), (0, validate_1.default)(qaCheck));
|
|
23
|
+
if (qaCheck.settingsUiModule) {
|
|
24
|
+
app.use('/settings', (0, ui_module_1.default)(config, true), (0, render_ui_module_1.default)(qaCheck.settingsUiModule));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.register = register;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Environments, UiModule } from '../../types';
|
|
2
|
+
import Crowdin, { SourceFilesModel, ProjectsGroupsModel, LanguagesModel, SourceStringsModel, StringTranslationsModel } from '@crowdin/crowdin-api-client';
|
|
3
|
+
export interface ExternalQaCheckModule extends Environments {
|
|
4
|
+
/**
|
|
5
|
+
* module description
|
|
6
|
+
*/
|
|
7
|
+
description?: string;
|
|
8
|
+
/**
|
|
9
|
+
* module name
|
|
10
|
+
*/
|
|
11
|
+
name?: string;
|
|
12
|
+
/**
|
|
13
|
+
* jobs chunk size
|
|
14
|
+
*/
|
|
15
|
+
batchSize?: number;
|
|
16
|
+
validate: ({ client, file, project, sourceLanguage, strings, targetLanguage, translations, }: {
|
|
17
|
+
client?: Crowdin;
|
|
18
|
+
file?: SourceFilesModel.File;
|
|
19
|
+
project?: ProjectsGroupsModel.Project;
|
|
20
|
+
sourceLanguage: LanguagesModel.Language;
|
|
21
|
+
strings: SourceStringsModel.String[];
|
|
22
|
+
targetLanguage: LanguagesModel.Language;
|
|
23
|
+
translations: StringTranslationsModel.StringTranslation[];
|
|
24
|
+
}) => Promise<ExternalQaCheckResponse>;
|
|
25
|
+
/**
|
|
26
|
+
* Settings UI module
|
|
27
|
+
*/
|
|
28
|
+
settingsUiModule?: UiModule;
|
|
29
|
+
}
|
|
30
|
+
export interface ExternalQaCheckRequest {
|
|
31
|
+
file: SourceFilesModel.File;
|
|
32
|
+
project: ProjectsGroupsModel.Project;
|
|
33
|
+
sourceLanguage: LanguagesModel.Language;
|
|
34
|
+
strings: SourceStringsModel.String[];
|
|
35
|
+
targetLanguage: LanguagesModel.Language;
|
|
36
|
+
translations: StringTranslationsModel.StringTranslation[];
|
|
37
|
+
}
|
|
38
|
+
interface SuggestedFix {
|
|
39
|
+
indexStart: number;
|
|
40
|
+
indexEnd: number;
|
|
41
|
+
replacement: string;
|
|
42
|
+
}
|
|
43
|
+
interface ValidationError {
|
|
44
|
+
message: string;
|
|
45
|
+
suggestedFixes?: SuggestedFix[];
|
|
46
|
+
}
|
|
47
|
+
interface Validation {
|
|
48
|
+
translationId: number;
|
|
49
|
+
passed: boolean;
|
|
50
|
+
error?: ValidationError;
|
|
51
|
+
}
|
|
52
|
+
export interface ExternalQaCheckResponse {
|
|
53
|
+
validations: Validation[];
|
|
54
|
+
error?: string;
|
|
55
|
+
}
|
|
56
|
+
export {};
|
|
@@ -241,6 +241,12 @@ function filesCron({ config, integration, period, }) {
|
|
|
241
241
|
});
|
|
242
242
|
}
|
|
243
243
|
catch (e) {
|
|
244
|
+
yield (0, logger_1.handleUserError)({
|
|
245
|
+
action: 'Auto sync files to External Service',
|
|
246
|
+
error: e,
|
|
247
|
+
crowdinId: syncSettings.crowdinId,
|
|
248
|
+
clientId: syncSettings.integrationId,
|
|
249
|
+
});
|
|
244
250
|
(0, logger_1.logError)(e, context);
|
|
245
251
|
continue;
|
|
246
252
|
}
|
|
@@ -285,6 +291,12 @@ function filesCron({ config, integration, period, }) {
|
|
|
285
291
|
});
|
|
286
292
|
}
|
|
287
293
|
catch (e) {
|
|
294
|
+
yield (0, logger_1.handleUserError)({
|
|
295
|
+
action: 'Auto sync files to Crowdin',
|
|
296
|
+
error: e,
|
|
297
|
+
crowdinId: syncSettings.crowdinId,
|
|
298
|
+
clientId: syncSettings.integrationId,
|
|
299
|
+
});
|
|
288
300
|
(0, logger_1.logError)(e, context);
|
|
289
301
|
continue;
|
|
290
302
|
}
|
|
@@ -192,7 +192,7 @@ function applyIntegrationModuleDefaults(config, integration) {
|
|
|
192
192
|
if ((_c = integration.syncNewElements) === null || _c === void 0 ? void 0 : _c.crowdin) {
|
|
193
193
|
defaultSettings.push({
|
|
194
194
|
key: 'new-crowdin-files',
|
|
195
|
-
label: '
|
|
195
|
+
label: 'Automatically sync new translations from Crowdin',
|
|
196
196
|
type: 'checkbox',
|
|
197
197
|
dependencySettings: JSON.stringify([{ '#schedule-settings': { type: '!equal', value: ['0'] } }]),
|
|
198
198
|
});
|
|
@@ -200,7 +200,7 @@ function applyIntegrationModuleDefaults(config, integration) {
|
|
|
200
200
|
if ((_d = integration.syncNewElements) === null || _d === void 0 ? void 0 : _d.integration) {
|
|
201
201
|
defaultSettings.push({
|
|
202
202
|
key: 'new-integration-files',
|
|
203
|
-
label: `
|
|
203
|
+
label: `Automatically sync new content from ${config.name}`,
|
|
204
204
|
type: 'checkbox',
|
|
205
205
|
dependencySettings: JSON.stringify([{ '#schedule-settings': { type: '!equal', value: ['0'] } }]),
|
|
206
206
|
});
|
package/out/modules/manifest.js
CHANGED
|
@@ -207,6 +207,12 @@ function handle(config) {
|
|
|
207
207
|
})));
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
|
+
if (config.externalQaCheck) {
|
|
211
|
+
const uiModule = config.externalQaCheck.settingsUiModule;
|
|
212
|
+
modules['external-qa-check'] = [
|
|
213
|
+
Object.assign(Object.assign({ key: config.identifier + '-qa-check', name: config.externalQaCheck.name || config.name, description: config.externalQaCheck.description || config.description, runQaCheckUrl: '/validate' }, (config.externalQaCheck.batchSize ? { getBatchSizeUrl: '/batch-size' } : {})), (uiModule ? { url: '/settings/' + (uiModule.fileName || 'index.html') } : {})),
|
|
214
|
+
];
|
|
215
|
+
}
|
|
210
216
|
const events = {
|
|
211
217
|
installed: '/installed',
|
|
212
218
|
uninstall: '/uninstall',
|
package/out/types.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { LogErrorFunction, LogFunction } from './util/logger';
|
|
|
15
15
|
import { AiProviderModule } from './modules/ai-provider/types';
|
|
16
16
|
import { AiPromptProviderModule } from './modules/ai-prompt-provider/types';
|
|
17
17
|
import { AiTool, AiToolWidget } from './modules/ai-tools/types';
|
|
18
|
+
import { ExternalQaCheckModule } from './modules/external-qa-check/types';
|
|
18
19
|
export interface ClientConfig extends ImagePath {
|
|
19
20
|
/**
|
|
20
21
|
* Authentication Crowdin App type: "authorization_code", "crowdin_app", "crowdin_agent". Default: "crowdin_app"
|
|
@@ -198,6 +199,10 @@ export interface ClientConfig extends ImagePath {
|
|
|
198
199
|
* AI tool_calls modules with UI widgets
|
|
199
200
|
*/
|
|
200
201
|
aiToolsWidget?: AiToolWidget | AiToolWidget[];
|
|
202
|
+
/**
|
|
203
|
+
* qa check module
|
|
204
|
+
*/
|
|
205
|
+
externalQaCheck?: ExternalQaCheckModule & ImagePath;
|
|
201
206
|
}
|
|
202
207
|
export interface Environments {
|
|
203
208
|
environments?: Environment | Environment[];
|
package/out/util/logger.js
CHANGED
|
@@ -221,7 +221,7 @@ function storeUserError({ action, error, crowdinId, clientId, }) {
|
|
|
221
221
|
if (error instanceof AppModuleError && error.appData) {
|
|
222
222
|
data.appData = error.appData;
|
|
223
223
|
}
|
|
224
|
-
yield (0, storage_1.getStorage)().saveUserError(action, error.message, JSON.stringify(data), `${Date.now()}`, crowdinId, clientId);
|
|
224
|
+
yield (0, storage_1.getStorage)().saveUserError(action, (error === null || error === void 0 ? void 0 : error.message) || JSON.stringify(error, null, 2), JSON.stringify(data), `${Date.now()}`, crowdinId, clientId);
|
|
225
225
|
});
|
|
226
226
|
}
|
|
227
227
|
function clearOldUserErrors(crowdinId, clientId) {
|
|
@@ -1141,12 +1141,25 @@
|
|
|
1141
1141
|
document.getElementById('user-errors').classList.add('hidden');
|
|
1142
1142
|
}
|
|
1143
1143
|
|
|
1144
|
+
function isJSON(string) {
|
|
1145
|
+
try {
|
|
1146
|
+
JSON.parse(string);
|
|
1147
|
+
return true;
|
|
1148
|
+
} catch (e) {
|
|
1149
|
+
return false;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1144
1153
|
function getUserErrorDetail(error) {
|
|
1145
1154
|
const data = JSON.parse(error.data);
|
|
1146
1155
|
|
|
1147
1156
|
let html = '<div class="error-detail-table"><table>';
|
|
1148
1157
|
html += `<tr><td>Action</td><td>${sanitizeHTML(error.action)}</td></tr>`;
|
|
1149
|
-
|
|
1158
|
+
if (isJSON(error.message)) {
|
|
1159
|
+
html += `<tr><td>Message</td><td><pre>${sanitizeHTML(error.message)}<pre></td></tr>`;
|
|
1160
|
+
} else {
|
|
1161
|
+
html += `<tr><td>Message</td><td>${sanitizeHTML(error.message)}</td></tr>`;
|
|
1162
|
+
}
|
|
1150
1163
|
html += `<tr><td>Date/time</td><td>${sanitizeHTML(error.createdAt)}</td></tr>`;
|
|
1151
1164
|
|
|
1152
1165
|
if (data.requestParams) {
|
package/package.json
CHANGED