@crowdin/app-project-module 1.3.0 → 1.4.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.
@@ -1,4 +1,9 @@
1
1
  import { Response } from 'express';
2
2
  import { IntegrationLogic } from '../modules/integration/types';
3
3
  import { Config } from '../types';
4
- export default function handle(config: Config, integration: IntegrationLogic, optional?: boolean): (req: import("express").Request | import("../types").CrowdinClientRequest, res: Response, next: Function) => void;
4
+ export default function handle({ config, integration, optional, isLogout, }: {
5
+ config: Config;
6
+ integration: IntegrationLogic;
7
+ optional?: boolean;
8
+ isLogout?: boolean;
9
+ }): (req: import("express").Request | import("../types").CrowdinClientRequest, res: Response, next: Function) => void;
@@ -44,22 +44,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
44
44
  Object.defineProperty(exports, "__esModule", { value: true });
45
45
  exports.default = handle;
46
46
  const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
47
+ const users_1 = require("../modules/integration/handlers/users");
47
48
  const storage_1 = require("../storage");
48
49
  const util_1 = require("../util");
49
50
  const connection_1 = require("../util/connection");
50
51
  const jsx_renderer_1 = require("../util/jsx-renderer");
51
52
  const logger_1 = require("../util/logger");
52
- function handle(config, integration, optional = false) {
53
+ function handle({ config, integration, optional = false, isLogout = false, }) {
53
54
  return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
54
55
  let clientId = req.crowdinContext.clientId;
55
56
  const isApiCall = req === null || req === void 0 ? void 0 : req.isApiCall;
56
57
  const { organization, projectId, userId } = crowdinAppFunctions.parseCrowdinId(clientId);
57
58
  req.logInfo(`Loading integration credentials for client ${clientId}`);
58
59
  let integrationCredentials = yield (0, storage_1.getStorage)().getIntegrationCredentials(clientId);
60
+ let projectIntegrationCredentials = [];
59
61
  const ownerIds = [];
60
62
  // check if user has access to integration in settings(managers)
61
63
  if (!integrationCredentials) {
62
- const projectIntegrationCredentials = (yield (0, storage_1.getStorage)().getAllIntegrationCredentials(organization)).filter((item) => {
64
+ projectIntegrationCredentials = (yield (0, storage_1.getStorage)().getAllIntegrationCredentials(organization)).filter((item) => {
63
65
  const { organization: itemOrganization, projectId: itemProjectId } = crowdinAppFunctions.parseCrowdinId(item.id);
64
66
  return itemOrganization === organization && itemProjectId === projectId;
65
67
  });
@@ -74,6 +76,19 @@ function handle(config, integration, optional = false) {
74
76
  }
75
77
  }
76
78
  }
79
+ if (!integrationCredentials && isLogout && projectIntegrationCredentials.length) {
80
+ const canForceLogout = yield isCrowdinProjectManager({
81
+ req,
82
+ projectId,
83
+ memberId: req.crowdinContext.jwtPayload.context.user_id,
84
+ });
85
+ if (canForceLogout) {
86
+ integrationCredentials = projectIntegrationCredentials[0];
87
+ clientId = integrationCredentials.id;
88
+ req.crowdinContext.clientId = clientId;
89
+ req.canForceIntegrationLogout = true;
90
+ }
91
+ }
77
92
  }
78
93
  if (!integrationCredentials) {
79
94
  const owners = yield getIntegrationManagedBy(ownerIds, req);
@@ -85,6 +100,7 @@ function handle(config, integration, optional = false) {
85
100
  message: 'Access denied',
86
101
  owners: null,
87
102
  hideActions: false,
103
+ allowLogout: false,
88
104
  };
89
105
  if (isApiCall) {
90
106
  return res.status(errorOptions.code).json({
@@ -97,6 +113,11 @@ function handle(config, integration, optional = false) {
97
113
  errorOptions.message = 'Looks like you don’t have access';
98
114
  errorOptions.hideActions = true;
99
115
  errorOptions.owners = owners;
116
+ errorOptions.allowLogout = yield isCrowdinProjectManager({
117
+ req,
118
+ projectId,
119
+ memberId: req.crowdinContext.jwtPayload.context.user_id,
120
+ });
100
121
  }
101
122
  else {
102
123
  (0, logger_1.temporaryErrorDebug)('Access denied: integration-credentials', req);
@@ -174,3 +195,19 @@ function getIntegrationManagedBy(ownerIds, req) {
174
195
  });
175
196
  });
176
197
  }
198
+ function isCrowdinProjectManager(_a) {
199
+ return __awaiter(this, arguments, void 0, function* ({ req, projectId, memberId, }) {
200
+ try {
201
+ const canManageProject = yield (0, users_1.isManager)({
202
+ client: req.crowdinApiClient,
203
+ projectId,
204
+ memberId,
205
+ });
206
+ return !!canManageProject;
207
+ }
208
+ catch (e) {
209
+ console.warn('Failed to determine project manager role', e);
210
+ return false;
211
+ }
212
+ });
213
+ }
@@ -206,7 +206,7 @@ function addDefaultApiEndpoints(app, config) {
206
206
  optional: false,
207
207
  checkSubscriptionExpiration: true,
208
208
  moduleKey: 'crowdin-files-api',
209
- }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, crowdin_files_1.default)(config, config.projectIntegration));
209
+ }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, crowdin_files_1.default)(config, config.projectIntegration));
210
210
  /**
211
211
  * @openapi
212
212
  * /file-progress:
@@ -240,7 +240,7 @@ function addDefaultApiEndpoints(app, config) {
240
240
  optional: false,
241
241
  checkSubscriptionExpiration: true,
242
242
  moduleKey: 'file-translation-progress-api',
243
- }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, crowdin_file_progress_1.default)(config.projectIntegration));
243
+ }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, crowdin_file_progress_1.default)(config.projectIntegration));
244
244
  /**
245
245
  * @openapi
246
246
  * /integration-files:
@@ -272,7 +272,7 @@ function addDefaultApiEndpoints(app, config) {
272
272
  optional: false,
273
273
  checkSubscriptionExpiration: true,
274
274
  moduleKey: 'integration-files-api',
275
- }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, integration_data_1.default)(config.projectIntegration));
275
+ }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, integration_data_1.default)(config.projectIntegration));
276
276
  /**
277
277
  * @openapi
278
278
  * /crowdin-update:
@@ -300,7 +300,7 @@ function addDefaultApiEndpoints(app, config) {
300
300
  optional: false,
301
301
  checkSubscriptionExpiration: true,
302
302
  moduleKey: 'crowdin-update-api',
303
- }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, crowdin_update_1.default)(config, config.projectIntegration));
303
+ }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, crowdin_update_1.default)(config, config.projectIntegration));
304
304
  /**
305
305
  * @openapi
306
306
  * /integration-update:
@@ -328,7 +328,7 @@ function addDefaultApiEndpoints(app, config) {
328
328
  optional: false,
329
329
  checkSubscriptionExpiration: true,
330
330
  moduleKey: 'integration-update-api',
331
- }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, integration_update_1.default)(config, config.projectIntegration));
331
+ }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, integration_update_1.default)(config, config.projectIntegration));
332
332
  /**
333
333
  * @openapi
334
334
  * /all-jobs:
@@ -372,7 +372,7 @@ function addDefaultApiEndpoints(app, config) {
372
372
  optional: false,
373
373
  checkSubscriptionExpiration: true,
374
374
  moduleKey: 'job-list-api',
375
- }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, job_list_1.default)());
375
+ }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, job_list_1.default)());
376
376
  /**
377
377
  * @openapi
378
378
  * /job-info:
@@ -416,7 +416,7 @@ function addDefaultApiEndpoints(app, config) {
416
416
  optional: false,
417
417
  checkSubscriptionExpiration: true,
418
418
  moduleKey: 'job-info-api',
419
- }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, job_info_1.default)());
419
+ }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, job_info_1.default)());
420
420
  /**
421
421
  * @openapi
422
422
  * /jobs:
@@ -447,7 +447,7 @@ function addDefaultApiEndpoints(app, config) {
447
447
  optional: false,
448
448
  checkSubscriptionExpiration: true,
449
449
  moduleKey: 'job-get-api',
450
- }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, job_info_deprecated_1.default)(config));
450
+ }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, job_info_deprecated_1.default)(config));
451
451
  /**
452
452
  * @openapi
453
453
  * /jobs:
@@ -487,7 +487,7 @@ function addDefaultApiEndpoints(app, config) {
487
487
  optional: false,
488
488
  checkSubscriptionExpiration: true,
489
489
  moduleKey: 'job-cancel-api',
490
- }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, job_cancel_1.default)());
490
+ }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, job_cancel_1.default)());
491
491
  /**
492
492
  * @openapi
493
493
  * /settings:
@@ -513,7 +513,7 @@ function addDefaultApiEndpoints(app, config) {
513
513
  optional: false,
514
514
  checkSubscriptionExpiration: true,
515
515
  moduleKey: 'settings-api',
516
- }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, settings_1.default)());
516
+ }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, settings_1.default)());
517
517
  /**
518
518
  * @openapi
519
519
  * /settings:
@@ -536,7 +536,7 @@ function addDefaultApiEndpoints(app, config) {
536
536
  optional: false,
537
537
  checkSubscriptionExpiration: true,
538
538
  moduleKey: 'settings-update-api',
539
- }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, settings_save_1.default)(config, config.projectIntegration));
539
+ }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, settings_save_1.default)(config, config.projectIntegration));
540
540
  /**
541
541
  * @openapi
542
542
  * /sync-settings:
@@ -573,7 +573,7 @@ function addDefaultApiEndpoints(app, config) {
573
573
  optional: false,
574
574
  checkSubscriptionExpiration: true,
575
575
  moduleKey: 'sync-settings-api',
576
- }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, sync_settings_1.default)());
576
+ }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, sync_settings_1.default)());
577
577
  /**
578
578
  * @openapi
579
579
  * /sync-settings:
@@ -596,7 +596,7 @@ function addDefaultApiEndpoints(app, config) {
596
596
  optional: false,
597
597
  checkSubscriptionExpiration: true,
598
598
  moduleKey: 'sync-settings-update-api',
599
- }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, sync_settings_save_1.default)(config, config.projectIntegration));
599
+ }), (0, integration_credentials_1.default)({ config, integration: config.projectIntegration }), (0, sync_settings_save_1.default)(config, config.projectIntegration));
600
600
  if (config.projectIntegration.loginForm) {
601
601
  /**
602
602
  * @openapi
@@ -52,7 +52,8 @@ const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-function
52
52
  function handle(config, integration) {
53
53
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
54
54
  const { userId } = crowdinAppFunctions.parseCrowdinId(req.crowdinContext.clientId);
55
- if (+userId !== +req.crowdinContext.jwtPayload.sub) {
55
+ const isCredentialOwner = +userId === +req.crowdinContext.jwtPayload.sub;
56
+ if (!isCredentialOwner && !req.canForceIntegrationLogout) {
56
57
  return res.status(403).send({ error: 'Access denied' });
57
58
  }
58
59
  req.logInfo('Received integration logout request');
@@ -62,7 +62,7 @@ function register({ config, app }) {
62
62
  optional: true,
63
63
  checkSubscriptionExpiration: false,
64
64
  moduleKey: integrationLogic.key,
65
- }), (0, integration_credentials_1.default)(config, integrationLogic, true), (0, main_1.default)(config, integrationLogic));
65
+ }), (0, integration_credentials_1.default)({ config, integration: integrationLogic, optional: true }), (0, main_1.default)(config, integrationLogic));
66
66
  app.get('/api/subscription-info', json_response_1.default, (0, crowdin_client_1.default)({
67
67
  config,
68
68
  optional: false,
@@ -98,7 +98,7 @@ function register({ config, app }) {
98
98
  optional: false,
99
99
  checkSubscriptionExpiration: true,
100
100
  moduleKey: integrationLogic.key,
101
- }), (0, integration_credentials_1.default)(config, integrationLogic), (0, settings_save_1.default)(config, integrationLogic));
101
+ }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, settings_save_1.default)(config, integrationLogic));
102
102
  app.post('/api/login', (0, crowdin_client_1.default)({
103
103
  config,
104
104
  optional: false,
@@ -110,13 +110,13 @@ function register({ config, app }) {
110
110
  optional: false,
111
111
  checkSubscriptionExpiration: false,
112
112
  moduleKey: integrationLogic.key,
113
- }), (0, integration_credentials_1.default)(config, integrationLogic), (0, integration_logout_1.default)(config, integrationLogic));
113
+ }), (0, integration_credentials_1.default)({ config, integration: integrationLogic, isLogout: true }), (0, integration_logout_1.default)(config, integrationLogic));
114
114
  app.get('/api/crowdin/files', json_response_1.default, (0, crowdin_client_1.default)({
115
115
  config,
116
116
  optional: false,
117
117
  checkSubscriptionExpiration: true,
118
118
  moduleKey: integrationLogic.key,
119
- }), (0, integration_credentials_1.default)(config, integrationLogic), (0, crowdin_files_1.default)(config, integrationLogic));
119
+ }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, crowdin_files_1.default)(config, integrationLogic));
120
120
  app.get('/api/crowdin/project', json_response_1.default, (0, crowdin_client_1.default)({
121
121
  config,
122
122
  optional: false,
@@ -134,37 +134,37 @@ function register({ config, app }) {
134
134
  optional: false,
135
135
  checkSubscriptionExpiration: true,
136
136
  moduleKey: integrationLogic.key,
137
- }), (0, integration_credentials_1.default)(config, integrationLogic), (0, integration_data_1.default)(integrationLogic));
137
+ }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, integration_data_1.default)(integrationLogic));
138
138
  app.post('/api/crowdin/update', json_response_1.default, (0, crowdin_client_1.default)({
139
139
  config,
140
140
  optional: false,
141
141
  checkSubscriptionExpiration: true,
142
142
  moduleKey: integrationLogic.key,
143
- }), (0, integration_credentials_1.default)(config, integrationLogic), (0, crowdin_update_1.default)(config, integrationLogic));
143
+ }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, crowdin_update_1.default)(config, integrationLogic));
144
144
  app.post('/api/crowdin/files-target-languages', json_response_1.default, (0, crowdin_client_1.default)({
145
145
  config,
146
146
  optional: false,
147
147
  checkSubscriptionExpiration: true,
148
148
  moduleKey: integrationLogic.key,
149
- }), (0, integration_credentials_1.default)(config, integrationLogic), (0, crowdin_files_target_languages_1.default)(config, integrationLogic));
149
+ }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, crowdin_files_target_languages_1.default)(config, integrationLogic));
150
150
  app.post('/api/integration/update', json_response_1.default, (0, crowdin_client_1.default)({
151
151
  config,
152
152
  optional: false,
153
153
  checkSubscriptionExpiration: true,
154
154
  moduleKey: integrationLogic.key,
155
- }), (0, integration_credentials_1.default)(config, integrationLogic), (0, integration_update_1.default)(config, integrationLogic));
155
+ }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, integration_update_1.default)(config, integrationLogic));
156
156
  app.get('/api/sync-settings/:provider', json_response_1.default, (0, crowdin_client_1.default)({
157
157
  config,
158
158
  optional: false,
159
159
  checkSubscriptionExpiration: true,
160
160
  moduleKey: integrationLogic.key,
161
- }), (0, integration_credentials_1.default)(config, integrationLogic), (0, sync_settings_1.default)());
161
+ }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, sync_settings_1.default)());
162
162
  app.post('/api/sync-settings', json_response_1.default, (0, crowdin_client_1.default)({
163
163
  config,
164
164
  optional: false,
165
165
  checkSubscriptionExpiration: true,
166
166
  moduleKey: integrationLogic.key,
167
- }), (0, integration_credentials_1.default)(config, integrationLogic), (0, sync_settings_save_1.default)(config, integrationLogic));
167
+ }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, sync_settings_save_1.default)(config, integrationLogic));
168
168
  if (integrationLogic.oauthLogin) {
169
169
  app.get((0, defaults_1.getOauthRoute)(integrationLogic), (0, oauth_login_1.default)(config, integrationLogic));
170
170
  app.post('/api/oauth-url', json_response_1.default, (0, crowdin_client_1.default)({
@@ -226,17 +226,17 @@ function register({ config, app }) {
226
226
  optional: false,
227
227
  checkSubscriptionExpiration: true,
228
228
  moduleKey: integrationLogic.key,
229
- }), (0, integration_credentials_1.default)(config, integrationLogic), (0, user_errors_1.default)());
229
+ }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, user_errors_1.default)());
230
230
  app.get('/api/users', json_response_1.default, (0, crowdin_client_1.default)({
231
231
  config,
232
232
  optional: false,
233
233
  checkSubscriptionExpiration: true,
234
234
  moduleKey: integrationLogic.key,
235
- }), (0, integration_credentials_1.default)(config, integrationLogic), (0, users_1.default)());
235
+ }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, users_1.default)());
236
236
  app.post('/api/invite-users', json_response_1.default, (0, crowdin_client_1.default)({
237
237
  config,
238
238
  optional: false,
239
239
  checkSubscriptionExpiration: true,
240
240
  moduleKey: integrationLogic.key,
241
- }), (0, integration_credentials_1.default)(config, integrationLogic), (0, invite_users_1.default)());
241
+ }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, invite_users_1.default)());
242
242
  }
@@ -533,6 +533,7 @@ export interface UpdateTargetLanguagesRequest {
533
533
  export interface IntegrationRequest extends CrowdinClientRequest {
534
534
  integrationCredentials: any;
535
535
  integrationSettings?: any;
536
+ canForceIntegrationLogout?: boolean;
536
537
  }
537
538
  export interface CronJob {
538
539
  task: (options: {
@@ -108,7 +108,8 @@ function registerWebhooks(_a) {
108
108
  yield integration.webhooks.crowdinWebhooks({ client, projectId, available: isWebhookSync, settings });
109
109
  }
110
110
  else {
111
- const webhookName = `${config.name} application hook ${crowdinContext.jwtPayload.sub}`;
111
+ const { userId } = crowdinAppFunctions.parseCrowdinId(crowdinContext.clientId);
112
+ const webhookName = `${config.name} application hook ${userId}`;
112
113
  const webhookUrl = makeCrowdinWebhookUrl({
113
114
  config,
114
115
  integration,
@@ -166,7 +167,8 @@ function unregisterWebhooks(_a) {
166
167
  });
167
168
  }
168
169
  else {
169
- const webhookName = `${config.name} application hook ${crowdinContext.jwtPayload.sub}`;
170
+ const { userId } = crowdinAppFunctions.parseCrowdinId(crowdinContext.clientId);
171
+ const webhookName = `${config.name} application hook ${userId}`;
170
172
  const webhook = yield getCrowdinProjectWebhook({
171
173
  client,
172
174
  projectId: crowdinContext.jwtPayload.context.project_id,
@@ -212,7 +214,8 @@ function createPayload(events) {
212
214
  }
213
215
  function registerCrowdinWebhook(_a) {
214
216
  return __awaiter(this, arguments, void 0, function* ({ client, config, crowdinContext, events, url, }) {
215
- const name = `${config.name} application hook ${crowdinContext.jwtPayload.sub}`;
217
+ const { userId } = crowdinAppFunctions.parseCrowdinId(crowdinContext.clientId);
218
+ const name = `${config.name} application hook ${userId}`;
216
219
  const payload = createPayload(events);
217
220
  yield client.webhooksApi.addWebhook(crowdinContext.jwtPayload.context.project_id, {
218
221
  name,
@@ -387,7 +387,9 @@ function handle(config) {
387
387
  workflowStep.key = config.identifier + '-' + (0, util_3.getWorkflowStepKey)(workflowStep);
388
388
  }
389
389
  const uiModule = ((_b = workflowStep === null || workflowStep === void 0 ? void 0 : workflowStep.settingsUiModule) === null || _b === void 0 ? void 0 : _b.formSchema) || ((_c = workflowStep === null || workflowStep === void 0 ? void 0 : workflowStep.settingsUiModule) === null || _c === void 0 ? void 0 : _c.fileName);
390
- modules['workflow-step-type'].push(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ key: workflowStep.key, name: workflowStep.name || config.name }, ((workflowStep === null || workflowStep === void 0 ? void 0 : workflowStep.imagePath) ? { logo: (0, util_1.getLogoUrl)(config, workflowStep, `-${workflowStep.key}`) } : {})), { description: workflowStep.description || config.description, boundaries: workflowStep.boundaries }), (workflowStep.editorMode ? { editorMode: workflowStep.editorMode } : {})), { updateSettingsUrl: (0, util_3.getWorkflowStepUrl)('/workflow-step/settings', workflowStep), deleteSettingsUrl: (0, util_3.getWorkflowStepUrl)('/workflow-step/delete', workflowStep) }), (uiModule ? { url: (0, util_3.getWorkflowStepUrl)('/workflow-step', workflowStep) } : {})));
390
+ modules['workflow-step-type'].push(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ key: workflowStep.key, name: workflowStep.name || config.name }, (workflowStep.imageUrl || workflowStep.imagePath
391
+ ? { logo: (0, util_1.getLogoUrl)(config, workflowStep, `-${workflowStep.key}`) }
392
+ : {})), { description: workflowStep.description || config.description, boundaries: workflowStep.boundaries }), (workflowStep.editorMode ? { editorMode: workflowStep.editorMode } : {})), { updateSettingsUrl: (0, util_3.getWorkflowStepUrl)('/workflow-step/settings', workflowStep), deleteSettingsUrl: (0, util_3.getWorkflowStepUrl)('/workflow-step/delete', workflowStep) }), (uiModule ? { url: (0, util_3.getWorkflowStepUrl)('/workflow-step', workflowStep) } : {})));
391
393
  }
392
394
  }
393
395
  if (config.automationAction) {
@@ -41,7 +41,7 @@ function register({ config, app }) {
41
41
  checkSubscriptionExpiration: false,
42
42
  }), (0, delete_step_1.default)(workflowStep));
43
43
  // END TEMPORARY CODE
44
- if (workflowStep.imagePath) {
44
+ if (workflowStep.imagePath || workflowStep.imageUrl) {
45
45
  app.use(`/logo-${workflowStep.key}`, (0, util_2.serveLogo)(config, workflowStep));
46
46
  }
47
47
  if (workflowStep.settingsUiModule) {
@@ -518,7 +518,7 @@
518
518
 
519
519
  var clientExports = requireClient();
520
520
 
521
- const ErrorPage = ({ message, name, owners, hideActions }) => {
521
+ const ErrorPage = ({ message, name, owners, hideActions, allowLogout }) => {
522
522
  function integrationLogout() {
523
523
  checkOrigin()
524
524
  .then((queryParams) => fetch(`api/logout${queryParams}`, { method: 'POST' }))
@@ -532,7 +532,7 @@
532
532
  AP.redirect(`${context.organization_id ? '/u' : ''}/messages/create/${userId}`);
533
533
  });
534
534
  }
535
- return (jsxRuntimeExports.jsx("div", { className: "i_w", children: jsxRuntimeExports.jsx("div", { className: "error-page", children: jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsxs("div", { className: "error-page-message", children: [jsxRuntimeExports.jsx("crowdin-h3", { children: message }), owners && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("crowdin-p", { children: "This integration allows only one connection per project to ensure consistent configuration and prevent file import or synchronization issues." }), owners.length > 1 ? (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("crowdin-p", { class: "mt-2", children: "Managed by:" }), jsxRuntimeExports.jsx("ul", { children: owners.map((owner) => (jsxRuntimeExports.jsx("li", { children: jsxRuntimeExports.jsx("crowdin-a", { href: "#", onClick: () => contactUser(owner.id), children: owner.name }) }))) }), jsxRuntimeExports.jsx("crowdin-p", { class: "mt-2", children: "To request access, please contact one of the project members listed above." })] })) : (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsxs("crowdin-p", { class: "mt-2", children: ["Managed by:", ' ', jsxRuntimeExports.jsx("crowdin-a", { href: "#", onClick: () => contactUser(owners[0].id), children: owners[0].name })] }), jsxRuntimeExports.jsx("crowdin-p", { class: "mt-2", children: "To request access, please contact the project member listed above." })] }))] }))] }), !hideActions && (jsxRuntimeExports.jsxs("div", { className: "error-page-action", children: [jsxRuntimeExports.jsx("crowdin-button", { outlined: true, onClick: () => integrationLogout(), children: "Log out" }), jsxRuntimeExports.jsxs("span", { children: [' ', "or", ' ', jsxRuntimeExports.jsx("crowdin-a", { href: "https://crowdin.com/contacts", target: "_blank", children: "contact us" }), ' ', "for help"] })] }))] }) }) }));
535
+ return (jsxRuntimeExports.jsx("div", { className: "i_w", children: jsxRuntimeExports.jsx("div", { className: "error-page", children: jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsxs("div", { className: "error-page-message", children: [jsxRuntimeExports.jsx("crowdin-h3", { children: message }), owners && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("crowdin-p", { children: "This integration allows only one connection per project to ensure consistent configuration and prevent file import or synchronization issues." }), owners.length > 1 ? (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("crowdin-p", { class: "mt-2", children: "Managed by:" }), jsxRuntimeExports.jsx("ul", { children: owners.map((owner) => (jsxRuntimeExports.jsx("li", { children: jsxRuntimeExports.jsx("crowdin-a", { href: "#", onClick: () => contactUser(owner.id), children: owner.name }) }))) }), jsxRuntimeExports.jsx("crowdin-p", { class: "mt-2", children: "To request access, please contact one of the project members listed above." })] })) : (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsxs("crowdin-p", { class: "mt-2", children: ["Managed by:", ' ', jsxRuntimeExports.jsx("crowdin-a", { href: "#", onClick: () => contactUser(owners[0].id), children: owners[0].name })] }), jsxRuntimeExports.jsx("crowdin-p", { class: "mt-2", children: "To request access, please contact the project member listed above." })] }))] }))] }), allowLogout && hideActions ? (jsxRuntimeExports.jsxs("crowdin-card", { "light-filled": true, children: [jsxRuntimeExports.jsx("crowdin-alert", { type: "warning", margin: true, message: "Deleting the integration will disconnect it and reset its settings for this project." }), jsxRuntimeExports.jsx("crowdin-button", { outlined: true, onClick: () => integrationLogout(), children: "Delete Integration" })] })) : (!hideActions && (jsxRuntimeExports.jsxs("div", { className: "error-page-action", children: [jsxRuntimeExports.jsx("crowdin-button", { outlined: true, onClick: () => integrationLogout(), children: "Log out" }), jsxRuntimeExports.jsxs("span", { children: [' ', "or", ' ', jsxRuntimeExports.jsx("crowdin-a", { href: "https://crowdin.com/contacts", target: "_blank", children: "contact us" }), ' ', "for help"] })] })))] }) }) }));
536
536
  };
537
537
 
538
538
  clientExports.createRoot(document.getElementById('root')).render(jsxRuntimeExports.jsx(ErrorPage, { ...window.__PAGE_PROPS__ }));