@acorex-platform/extension-project-management-jira-client 0.0.21

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.
@@ -0,0 +1,1017 @@
1
+ import { AXMIntegrationManagementModule } from '@acorex-platform/module-integration-management-client';
2
+ import { AXPIntegrationRuntimeService, AXP_INTEGRATION_SECRET_STORE, AXP_INTEGRATION_CONNECTION_ESTABLISHED, AXP_MENU_PROVIDER, AXP_STATUS_PROVIDERS, AXP_INTEGRATION_PROVIDER, AXP_INTEGRATION_RUNTIME_PROVIDER } from '@acorex-platform/framework-client/common';
3
+ import { AXP_LOGO_PROVIDER, AXP_MODULE_MANIFEST_PROVIDER, AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER } from '@acorex-platform/framework-client/core';
4
+ import { AXPEntityService, ensureListActions, actionExists, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER } from '@acorex-platform/framework-client/layout/entity';
5
+ import { provideCommandSetups } from '@acorex-platform/framework-client/runtime';
6
+ import * as i0 from '@angular/core';
7
+ import { Injectable, inject, NgModule, input, computed, ChangeDetectionStrategy, Component, signal } from '@angular/core';
8
+ import { RootConfig, AXEJiraCommandKeys, AXPAdministrationPermissionKeys, AXEJiraMenuKeys, AXE_JIRA_PROJECT_SYNC_STRATEGIES } from '@acorex-platform/extension-project-management-jira-client/contracts';
9
+ import { AXPStatusProvider, AXPSystemActionType, AXPWidgetsList, AXP_INTEGRATION_AUTH_METHOD_TYPE, AXP_INTEGRATION_CONNECTION_SCOPE, AXP_INTEGRATION_CAPABILITY, AXP_INTEGRATION_CONNECTION_STATUS } from '@acorex-platform/framework-shared/core';
10
+ import { AXPEntityCommandScope } from '@acorex-platform/framework-shared/entity';
11
+ import { RootConfig as RootConfig$1 } from '@acorex-platform/module-project-management-client/contracts';
12
+ import { trim, defaultTo } from 'lodash-es';
13
+ import { AXPCommonMenuKeys } from '@acorex-platform/module-common-client/contracts';
14
+ import * as i2 from '@acorex/components/button';
15
+ import { AXButtonModule } from '@acorex/components/button';
16
+ import * as i3 from '@acorex/components/check-box';
17
+ import { AXCheckBoxModule } from '@acorex/components/check-box';
18
+ import * as i4 from '@acorex/components/decorators';
19
+ import { AXDecoratorModule } from '@acorex/components/decorators';
20
+ import * as i5 from '@acorex/components/loading';
21
+ import { AXLoadingModule } from '@acorex/components/loading';
22
+ import { AXBasePageComponent } from '@acorex/components/page';
23
+ import * as i6 from '@acorex/components/select-box';
24
+ import { AXSelectBoxModule } from '@acorex/components/select-box';
25
+ import * as i7 from '@acorex/core/translation';
26
+ import { AXTranslationModule } from '@acorex/core/translation';
27
+ import { AsyncPipe } from '@angular/common';
28
+ import * as i1 from '@angular/forms';
29
+ import { FormsModule } from '@angular/forms';
30
+
31
+ //#endregion
32
+ //#region ---- Entity Provider ----
33
+ class AXEJiraEntityProvider {
34
+ preload() {
35
+ const module = RootConfig.module.name;
36
+ return Object.values(RootConfig.entities).map((entity) => ({
37
+ module,
38
+ entity: entity.name,
39
+ }));
40
+ }
41
+ async get(moduleName, entityName) {
42
+ if (moduleName !== RootConfig.module.name) {
43
+ return null;
44
+ }
45
+ switch (entityName) {
46
+ case RootConfig.entities.jiraInstance.name:
47
+ return (await import('@acorex-platform/extension-project-management-jira-domain')).jiraInstanceFactory();
48
+ case RootConfig.entities.jiraProject.name:
49
+ return (await import('@acorex-platform/extension-project-management-jira-domain')).jiraProjectFactory();
50
+ case RootConfig.entities.jiraIssueType.name:
51
+ return (await import('@acorex-platform/extension-project-management-jira-domain')).jiraIssueTypeFactory();
52
+ case RootConfig.entities.jiraField.name:
53
+ return (await import('@acorex-platform/extension-project-management-jira-domain')).jiraFieldFactory();
54
+ case RootConfig.entities.jiraProjectIssueType.name:
55
+ return (await import('@acorex-platform/extension-project-management-jira-domain')).jiraProjectIssueTypeFactory();
56
+ case RootConfig.entities.jiraProjectIssueTypeField.name:
57
+ return (await import('@acorex-platform/extension-project-management-jira-domain')).jiraProjectIssueTypeFieldFactory();
58
+ case RootConfig.entities.jiraWorkflowStatus.name:
59
+ return (await import('@acorex-platform/extension-project-management-jira-domain')).jiraWorkflowStatusFactory();
60
+ case RootConfig.entities.jiraIssue.name:
61
+ return (await import('@acorex-platform/extension-project-management-jira-domain')).jiraIssueFactory();
62
+ case RootConfig.entities.jiraWorklog.name:
63
+ return (await import('@acorex-platform/extension-project-management-jira-domain')).jiraWorklogFactory();
64
+ default:
65
+ return null;
66
+ }
67
+ }
68
+ async list() {
69
+ const module = RootConfig.module.name;
70
+ return Object.values(RootConfig.entities).map((entity) => ({
71
+ name: entity.name,
72
+ module,
73
+ }));
74
+ }
75
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraEntityProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
76
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraEntityProvider }); }
77
+ }
78
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraEntityProvider, decorators: [{
79
+ type: Injectable
80
+ }] });
81
+
82
+ //#region ---- Imports ----
83
+ //#endregion
84
+ //#region ---- Status Helper ----
85
+ const status = (name, title, color, options = {}) => ({
86
+ name,
87
+ title,
88
+ color,
89
+ ...options,
90
+ });
91
+ //#endregion
92
+ //#region ---- Jira Project Status Provider ----
93
+ /**
94
+ * Operational sync status for mirrored Jira projects (not Jira workflow statuses).
95
+ */
96
+ class AXEJiraProjectStatusProvider extends AXPStatusProvider {
97
+ constructor() {
98
+ super(...arguments);
99
+ this.key = 'extensions-jira.status.jira-project';
100
+ this.statuses = [
101
+ status('Active', '@extensions-jira:projects.statuses.active', 'success', {
102
+ order: 1,
103
+ generateView: true,
104
+ isInitial: true,
105
+ icon: 'fa-light fa-circle-check',
106
+ }),
107
+ status('Archived', '@extensions-jira:projects.statuses.archived', 'neutral', {
108
+ order: 2,
109
+ generateView: true,
110
+ isFinal: true,
111
+ icon: 'fa-light fa-box-archive',
112
+ }),
113
+ status('SyncError', '@extensions-jira:projects.statuses.sync-error', 'danger', {
114
+ order: 3,
115
+ generateView: true,
116
+ icon: 'fa-light fa-triangle-exclamation',
117
+ }),
118
+ ];
119
+ this.transitions = [
120
+ {
121
+ from: 'Active',
122
+ to: 'Archived',
123
+ title: '@extensions-jira:projects.transitions.archive',
124
+ },
125
+ {
126
+ from: 'Archived',
127
+ to: 'Active',
128
+ title: '@extensions-jira:projects.transitions.activate',
129
+ },
130
+ {
131
+ from: 'Active',
132
+ to: 'SyncError',
133
+ title: '@extensions-jira:projects.transitions.mark-sync-error',
134
+ },
135
+ {
136
+ from: 'SyncError',
137
+ to: 'Active',
138
+ title: '@extensions-jira:projects.transitions.resolve-sync-error',
139
+ },
140
+ ];
141
+ this.defaultStatus = 'Active';
142
+ }
143
+ }
144
+ //#endregion
145
+
146
+ //#region ---- Imports ----
147
+ //#endregion
148
+ /** Expression scope namespace (no hyphens — safe for `with (scope)` eval). */
149
+ const AXE_JIRA_EXPRESSION_SCOPE = 'JiraExtension';
150
+ //#region ---- Provider ----
151
+ class AXEJiraProjectLinkExpressionEvaluatorScopeProvider {
152
+ constructor() {
153
+ this.entityService = inject(AXPEntityService);
154
+ this.integrationRuntime = inject(AXPIntegrationRuntimeService);
155
+ }
156
+ async provide(context) {
157
+ context.addScope(AXE_JIRA_EXPRESSION_SCOPE, {
158
+ hasProjectLink: async (platformProjectIdRaw) => {
159
+ const platformProjectId = typeof platformProjectIdRaw === 'string' ? platformProjectIdRaw.trim() : '';
160
+ if (!platformProjectId) {
161
+ return false;
162
+ }
163
+ const result = await this.entityService
164
+ .withEntity(RootConfig.module.name, RootConfig.entities.jiraProject.name)
165
+ .data()
166
+ .query({
167
+ skip: 0,
168
+ take: 1,
169
+ filter: {
170
+ field: 'platformProjectId',
171
+ operator: { type: 'equal' },
172
+ value: platformProjectId,
173
+ },
174
+ });
175
+ return (result.items?.length ?? 0) > 0;
176
+ },
177
+ hasJiraConnection: async () => {
178
+ try {
179
+ await this.integrationRuntime.getConnection({ providerId: 'jira', connectionScope: 'tenant' });
180
+ return true;
181
+ }
182
+ catch {
183
+ return false;
184
+ }
185
+ },
186
+ });
187
+ }
188
+ }
189
+ //#endregion
190
+
191
+ //#region ---- Imports ----
192
+ //#endregion
193
+ const IMPORT_ORDER = 35;
194
+ const SYNC_ORDER = 36;
195
+ function buildImportAction() {
196
+ return {
197
+ name: AXEJiraCommandKeys.ProjectImportFromJira,
198
+ title: '@extensions-jira:actions.import-from-jira.title',
199
+ command: { name: AXEJiraCommandKeys.ProjectImportFromJira },
200
+ priority: 'secondary',
201
+ type: AXPSystemActionType.Import,
202
+ icon: 'fa-brands fa-jira',
203
+ scope: AXPEntityCommandScope.TypeLevel,
204
+ order: IMPORT_ORDER,
205
+ };
206
+ }
207
+ function buildSyncAction() {
208
+ return {
209
+ name: AXEJiraCommandKeys.ProjectSync,
210
+ title: '@extensions-jira:actions.sync.title',
211
+ command: {
212
+ name: AXEJiraCommandKeys.ProjectSync,
213
+ options: { platformProjectId: '{{ context.eval("id") }}' },
214
+ },
215
+ priority: 'secondary',
216
+ type: AXPSystemActionType.Sync,
217
+ icon: 'fa-light fa-arrows-rotate',
218
+ scope: AXPEntityCommandScope.Individual,
219
+ order: SYNC_ORDER,
220
+ hidden: `{{ !(await ${AXE_JIRA_EXPRESSION_SCOPE}.hasProjectLink(context.eval("id"))) }}`,
221
+ };
222
+ }
223
+ /** Adds Jira import/sync actions to ProjectManagement.Project views. */
224
+ const AXEJiraProjectEntityModifier = {
225
+ entityName: RootConfig$1.entities.project.name,
226
+ order: 50,
227
+ modifier: (ctx) => {
228
+ if (ctx.module.get() !== RootConfig$1.module.name) {
229
+ return;
230
+ }
231
+ ensureListActions(ctx);
232
+ ctx.interfaces.update((interfaces) => {
233
+ const next = (interfaces ?? {});
234
+ const master = (next['master'] ?? {});
235
+ const list = (master['list'] ?? { actions: [], views: [] });
236
+ const listActions = (list['actions'] ?? []);
237
+ if (!actionExists(listActions, AXEJiraCommandKeys.ProjectImportFromJira)) {
238
+ listActions.push(buildImportAction());
239
+ }
240
+ list['actions'] = listActions;
241
+ master['list'] = list;
242
+ const single = master['single'];
243
+ if (single) {
244
+ const singleActions = (single['actions'] ?? []);
245
+ if (!actionExists(singleActions, AXEJiraCommandKeys.ProjectSync)) {
246
+ singleActions.push(buildSyncAction());
247
+ }
248
+ single['actions'] = singleActions;
249
+ }
250
+ next['master'] = master;
251
+ return next;
252
+ });
253
+ },
254
+ };
255
+ //#endregion
256
+
257
+ //#region ---- Jira logo registry key ----
258
+ const axpJiraLogoKey = 'jira';
259
+ //#endregion
260
+
261
+ class AXEJiraIntegrationProvider {
262
+ async provide(context) {
263
+ const I18N = `@${RootConfig.config.i18n}:integration`;
264
+ context.register({
265
+ domainId: 'project-management',
266
+ id: 'jira',
267
+ module: RootConfig.module.name,
268
+ displayName: `${I18N}.display-name`,
269
+ description: `${I18N}.description`,
270
+ icon: RootConfig.module.icon,
271
+ logoKey: axpJiraLogoKey,
272
+ capabilities: [
273
+ AXP_INTEGRATION_CAPABILITY.IssueTracking,
274
+ AXP_INTEGRATION_CAPABILITY.Sync,
275
+ AXP_INTEGRATION_CAPABILITY.TimeLogging,
276
+ ],
277
+ connectionScopes: [AXP_INTEGRATION_CONNECTION_SCOPE.Tenant, AXP_INTEGRATION_CONNECTION_SCOPE.User],
278
+ allowMultipleConnections: true,
279
+ defaultConnectionKey: 'default',
280
+ connectCommandKey: AXEJiraCommandKeys.ConnectionConnect,
281
+ authMethods: [
282
+ {
283
+ type: AXP_INTEGRATION_AUTH_METHOD_TYPE.Pat,
284
+ label: `${I18N}.auth.pat.label`,
285
+ instructions: `${I18N}.auth.pat.instructions`,
286
+ supportsValidation: true,
287
+ fields: [
288
+ {
289
+ type: AXPWidgetsList.Editors.TextBox,
290
+ path: 'baseUrl',
291
+ options: { placeholder: `${I18N}.auth.pat.base-url.placeholder` },
292
+ },
293
+ {
294
+ type: AXPWidgetsList.Editors.PasswordBox,
295
+ path: 'token',
296
+ options: { placeholder: `${I18N}.auth.pat.token.placeholder` },
297
+ },
298
+ ],
299
+ },
300
+ {
301
+ type: AXP_INTEGRATION_AUTH_METHOD_TYPE.Basic,
302
+ label: `${I18N}.auth.basic.label`,
303
+ instructions: `${I18N}.auth.basic.instructions`,
304
+ supportsValidation: true,
305
+ fields: [
306
+ {
307
+ type: AXPWidgetsList.Editors.TextBox,
308
+ path: 'baseUrl',
309
+ options: { placeholder: `${I18N}.auth.basic.base-url.placeholder` },
310
+ },
311
+ {
312
+ type: AXPWidgetsList.Editors.TextBox,
313
+ path: 'username',
314
+ options: { placeholder: `${I18N}.auth.basic.username.placeholder` },
315
+ },
316
+ {
317
+ type: AXPWidgetsList.Editors.PasswordBox,
318
+ path: 'password',
319
+ options: { placeholder: `${I18N}.auth.basic.password.placeholder` },
320
+ },
321
+ ],
322
+ },
323
+ {
324
+ type: AXP_INTEGRATION_AUTH_METHOD_TYPE.ApiToken,
325
+ label: `${I18N}.auth.api-token.label`,
326
+ instructions: `${I18N}.auth.api-token.instructions`,
327
+ supportsValidation: true,
328
+ fields: [
329
+ {
330
+ type: AXPWidgetsList.Editors.TextBox,
331
+ path: 'siteUrl',
332
+ options: { placeholder: `${I18N}.auth.api-token.site-url.placeholder` },
333
+ },
334
+ {
335
+ type: AXPWidgetsList.Editors.TextBox,
336
+ path: 'email',
337
+ options: { placeholder: `${I18N}.auth.api-token.email.placeholder` },
338
+ },
339
+ {
340
+ type: AXPWidgetsList.Editors.PasswordBox,
341
+ path: 'apiToken',
342
+ options: { placeholder: `${I18N}.auth.api-token.token.placeholder` },
343
+ },
344
+ ],
345
+ },
346
+ {
347
+ type: AXP_INTEGRATION_AUTH_METHOD_TYPE.OAuth2,
348
+ label: `${I18N}.auth.oauth.label`,
349
+ instructions: `${I18N}.auth.oauth.instructions`,
350
+ usesRedirect: true,
351
+ supportsRefresh: true,
352
+ supportsRevoke: false,
353
+ supportsValidation: true,
354
+ defaultScopes: ['read:jira-work', 'read:jira-user'],
355
+ fields: [],
356
+ },
357
+ ],
358
+ });
359
+ }
360
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraIntegrationProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
361
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraIntegrationProvider }); }
362
+ }
363
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraIntegrationProvider, decorators: [{
364
+ type: Injectable
365
+ }] });
366
+
367
+ class AXEJiraIntegrationRuntimeProvider {
368
+ constructor() {
369
+ this.providerId = 'jira';
370
+ this.secretStore = inject(AXP_INTEGRATION_SECRET_STORE, { optional: true });
371
+ }
372
+ async getHooks() {
373
+ return {
374
+ validateConnection: (ctx) => this.validateConnection(ctx),
375
+ createClient: (ctx) => this.createClient(ctx),
376
+ };
377
+ }
378
+ async validateConnection(ctx) {
379
+ if (!this.secretStore) {
380
+ return { valid: false, status: AXP_INTEGRATION_CONNECTION_STATUS.Invalid, errorMessage: 'Secret store unavailable.' };
381
+ }
382
+ try {
383
+ const credentials = await this.secretStore.resolve(ctx.secretRef, ctx);
384
+ const token = credentials.token ??
385
+ credentials.apiToken ??
386
+ credentials.accessToken;
387
+ if (!trim(defaultTo(token, ''))) {
388
+ return {
389
+ valid: false,
390
+ status: AXP_INTEGRATION_CONNECTION_STATUS.Invalid,
391
+ errorMessage: 'No token available for Jira connection.',
392
+ };
393
+ }
394
+ return {
395
+ valid: true,
396
+ status: AXP_INTEGRATION_CONNECTION_STATUS.Connected,
397
+ externalAccountName: defaultTo(ctx.instanceUrl, 'Jira'),
398
+ };
399
+ }
400
+ catch {
401
+ return {
402
+ valid: false,
403
+ status: AXP_INTEGRATION_CONNECTION_STATUS.Invalid,
404
+ errorMessage: 'Failed to validate Jira credentials.',
405
+ };
406
+ }
407
+ }
408
+ async createClient(ctx) {
409
+ if (!this.secretStore) {
410
+ throw new Error('Secret store unavailable.');
411
+ }
412
+ const credentials = await this.secretStore.resolve(ctx.secretRef, ctx);
413
+ const token = credentials.token ??
414
+ credentials.apiToken ??
415
+ credentials.accessToken;
416
+ if (!trim(defaultTo(token, ''))) {
417
+ throw new Error('Jira connection has no usable token.');
418
+ }
419
+ return {
420
+ token: token,
421
+ baseUrl: defaultTo(ctx.instanceUrl, undefined),
422
+ };
423
+ }
424
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraIntegrationRuntimeProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
425
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraIntegrationRuntimeProvider }); }
426
+ }
427
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraIntegrationRuntimeProvider, decorators: [{
428
+ type: Injectable
429
+ }] });
430
+
431
+ //#region ---- Imports ----
432
+ //#endregion
433
+ //#region ---- Handler ----
434
+ class AXEJiraConnectionEstablishedHandler {
435
+ constructor() {
436
+ this.providerId = 'jira';
437
+ this.entityService = inject(AXPEntityService);
438
+ }
439
+ async onEstablished(connection) {
440
+ if (connection.connectionScope !== AXP_INTEGRATION_CONNECTION_SCOPE.Tenant) {
441
+ return;
442
+ }
443
+ const connectionKey = trim(connection.connectionKey);
444
+ if (!connectionKey) {
445
+ return;
446
+ }
447
+ const accessor = this.entityService
448
+ .withEntity(RootConfig.module.name, RootConfig.entities.jiraInstance.name)
449
+ .data();
450
+ const result = await accessor.query({
451
+ skip: 0,
452
+ take: 1,
453
+ filter: {
454
+ logic: 'and',
455
+ filters: [{ field: 'name', operator: { type: 'equal' }, value: connectionKey }],
456
+ },
457
+ });
458
+ const instance = result.items?.[0];
459
+ if (!instance || instance.integrationConnectionId === connection.id) {
460
+ return;
461
+ }
462
+ await accessor.update(instance.id, { integrationConnectionId: connection.id });
463
+ }
464
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraConnectionEstablishedHandler, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
465
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraConnectionEstablishedHandler }); }
466
+ }
467
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraConnectionEstablishedHandler, decorators: [{
468
+ type: Injectable
469
+ }] });
470
+ const provideJiraConnectionEstablishedHandler = {
471
+ provide: AXP_INTEGRATION_CONNECTION_ESTABLISHED,
472
+ useClass: AXEJiraConnectionEstablishedHandler,
473
+ multi: true,
474
+ };
475
+
476
+ const jiraLogoProvider = {
477
+ key: axpJiraLogoKey,
478
+ resolve: async (request) => ({
479
+ kind: 'component',
480
+ load: () => Promise.resolve().then(function () { return jiraLogo_component; }).then((module) => module.AXEJiraLogoComponent),
481
+ inputs: {
482
+ appearance: request.appearance,
483
+ size: request.size,
484
+ },
485
+ }),
486
+ };
487
+ const AXE_JIRA_LOGO_PROVIDER = {
488
+ provide: AXP_LOGO_PROVIDER,
489
+ useValue: jiraLogoProvider,
490
+ multi: true,
491
+ };
492
+
493
+ //#region ---- Imports ----
494
+ //#endregion
495
+ //#region ---- Manifest ----
496
+ const JiraExtensionManifest = {
497
+ name: RootConfig.module.name,
498
+ version: '1.0.0',
499
+ title: RootConfig.module.title,
500
+ icon: RootConfig.module.icon,
501
+ i18n: RootConfig.config.i18n,
502
+ type: 'integration',
503
+ domain: 'project-management',
504
+ dependencies: [],
505
+ };
506
+ //#endregion
507
+
508
+ //#region ---- Imports ----
509
+ //#endregion
510
+ //#region ---- Menu Provider ----
511
+ class AXEJiraMenuProvider {
512
+ constructor() {
513
+ this.entityService = inject(AXPEntityService);
514
+ }
515
+ async provide(context) {
516
+ const module = RootConfig.module;
517
+ const policy = {
518
+ features: [module.name],
519
+ permissions: [AXPAdministrationPermissionKeys.MaintainConnections],
520
+ };
521
+ const configMenu = context.find(AXPCommonMenuKeys.Configuration);
522
+ if (!context.find(AXEJiraMenuKeys.JiraExtensionConfig).exists) {
523
+ configMenu.addItems([
524
+ {
525
+ name: AXEJiraMenuKeys.JiraExtensionConfig,
526
+ text: '@extensions-jira:module.menus.configuration.title',
527
+ icon: module.icon,
528
+ type: 'menu',
529
+ priority: 8935,
530
+ policy,
531
+ children: [],
532
+ },
533
+ ]);
534
+ }
535
+ const jiraConfig = context.find(AXEJiraMenuKeys.JiraExtensionConfig);
536
+ const catalogPolicy = {
537
+ features: [module.name],
538
+ permissions: [AXPAdministrationPermissionKeys.ViewIntegrations],
539
+ };
540
+ jiraConfig.addItems([
541
+ {
542
+ name: AXEJiraMenuKeys.Instances,
543
+ text: RootConfig.entities.jiraInstance.titlePlural,
544
+ path: this.entityService.createPath(module.name, RootConfig.entities.jiraInstance.name),
545
+ icon: RootConfig.entities.jiraInstance.icon,
546
+ priority: 1,
547
+ policy,
548
+ },
549
+ {
550
+ name: AXEJiraMenuKeys.IssueTypes,
551
+ text: RootConfig.entities.jiraIssueType.titlePlural,
552
+ path: this.entityService.createPath(module.name, RootConfig.entities.jiraIssueType.name),
553
+ icon: RootConfig.entities.jiraIssueType.icon,
554
+ priority: 3,
555
+ policy: catalogPolicy,
556
+ },
557
+ {
558
+ name: AXEJiraMenuKeys.Fields,
559
+ text: RootConfig.entities.jiraField.titlePlural,
560
+ path: this.entityService.createPath(module.name, RootConfig.entities.jiraField.name),
561
+ icon: RootConfig.entities.jiraField.icon,
562
+ priority: 4,
563
+ policy: catalogPolicy,
564
+ },
565
+ {
566
+ name: AXEJiraMenuKeys.Issues,
567
+ text: RootConfig.entities.jiraIssue.titlePlural,
568
+ path: this.entityService.createPath(module.name, RootConfig.entities.jiraIssue.name),
569
+ icon: RootConfig.entities.jiraIssue.icon,
570
+ priority: 5,
571
+ policy: {
572
+ features: [module.name],
573
+ permissions: [AXPAdministrationPermissionKeys.ViewIntegrations],
574
+ },
575
+ },
576
+ {
577
+ name: AXEJiraMenuKeys.Worklogs,
578
+ text: RootConfig.entities.jiraWorklog.titlePlural,
579
+ path: this.entityService.createPath(module.name, RootConfig.entities.jiraWorklog.name),
580
+ icon: RootConfig.entities.jiraWorklog.icon,
581
+ priority: 6,
582
+ policy: {
583
+ features: [module.name],
584
+ permissions: [AXPAdministrationPermissionKeys.ViewIntegrations],
585
+ },
586
+ },
587
+ ]);
588
+ }
589
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraMenuProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
590
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraMenuProvider }); }
591
+ }
592
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraMenuProvider, decorators: [{
593
+ type: Injectable
594
+ }] });
595
+
596
+ //#region ---- Imports ----
597
+ //#endregion
598
+ //#region ---- Module ----
599
+ class AXEJiraExtensionModule {
600
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraExtensionModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
601
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraExtensionModule, imports: [AXMIntegrationManagementModule] }); }
602
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraExtensionModule, providers: [
603
+ AXE_JIRA_LOGO_PROVIDER,
604
+ {
605
+ provide: AXP_MODULE_MANIFEST_PROVIDER,
606
+ useValue: JiraExtensionManifest,
607
+ multi: true,
608
+ },
609
+ {
610
+ provide: AXP_MENU_PROVIDER,
611
+ useClass: AXEJiraMenuProvider,
612
+ multi: true,
613
+ },
614
+ {
615
+ provide: AXP_ENTITY_DEFINITION_LOADER,
616
+ useClass: AXEJiraEntityProvider,
617
+ multi: true,
618
+ },
619
+ {
620
+ provide: AXP_ENTITY_MODIFIER,
621
+ useValue: AXEJiraProjectEntityModifier,
622
+ multi: true,
623
+ },
624
+ {
625
+ provide: AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER,
626
+ useClass: AXEJiraProjectLinkExpressionEvaluatorScopeProvider,
627
+ multi: true,
628
+ },
629
+ {
630
+ provide: AXP_STATUS_PROVIDERS,
631
+ useClass: AXEJiraProjectStatusProvider,
632
+ multi: true,
633
+ },
634
+ {
635
+ provide: AXP_INTEGRATION_PROVIDER,
636
+ useClass: AXEJiraIntegrationProvider,
637
+ multi: true,
638
+ },
639
+ {
640
+ provide: AXP_INTEGRATION_RUNTIME_PROVIDER,
641
+ useClass: AXEJiraIntegrationRuntimeProvider,
642
+ multi: true,
643
+ },
644
+ provideJiraConnectionEstablishedHandler,
645
+ provideCommandSetups([
646
+ {
647
+ key: AXEJiraCommandKeys.ConnectionConnect,
648
+ command: () => import('./acorex-platform-extension-project-management-jira-client-connect-jira.command-DNMUeLqv.mjs').then((c) => c.ConnectJiraCommand),
649
+ },
650
+ ]),
651
+ ], imports: [AXMIntegrationManagementModule] }); }
652
+ }
653
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraExtensionModule, decorators: [{
654
+ type: NgModule,
655
+ args: [{
656
+ imports: [AXMIntegrationManagementModule],
657
+ providers: [
658
+ AXE_JIRA_LOGO_PROVIDER,
659
+ {
660
+ provide: AXP_MODULE_MANIFEST_PROVIDER,
661
+ useValue: JiraExtensionManifest,
662
+ multi: true,
663
+ },
664
+ {
665
+ provide: AXP_MENU_PROVIDER,
666
+ useClass: AXEJiraMenuProvider,
667
+ multi: true,
668
+ },
669
+ {
670
+ provide: AXP_ENTITY_DEFINITION_LOADER,
671
+ useClass: AXEJiraEntityProvider,
672
+ multi: true,
673
+ },
674
+ {
675
+ provide: AXP_ENTITY_MODIFIER,
676
+ useValue: AXEJiraProjectEntityModifier,
677
+ multi: true,
678
+ },
679
+ {
680
+ provide: AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER,
681
+ useClass: AXEJiraProjectLinkExpressionEvaluatorScopeProvider,
682
+ multi: true,
683
+ },
684
+ {
685
+ provide: AXP_STATUS_PROVIDERS,
686
+ useClass: AXEJiraProjectStatusProvider,
687
+ multi: true,
688
+ },
689
+ {
690
+ provide: AXP_INTEGRATION_PROVIDER,
691
+ useClass: AXEJiraIntegrationProvider,
692
+ multi: true,
693
+ },
694
+ {
695
+ provide: AXP_INTEGRATION_RUNTIME_PROVIDER,
696
+ useClass: AXEJiraIntegrationRuntimeProvider,
697
+ multi: true,
698
+ },
699
+ provideJiraConnectionEstablishedHandler,
700
+ provideCommandSetups([
701
+ {
702
+ key: AXEJiraCommandKeys.ConnectionConnect,
703
+ command: () => import('./acorex-platform-extension-project-management-jira-client-connect-jira.command-DNMUeLqv.mjs').then((c) => c.ConnectJiraCommand),
704
+ },
705
+ ]),
706
+ ],
707
+ }]
708
+ }] });
709
+
710
+ //#region ---- Atlassian / Jira mark vector paths ----
711
+ const AXE_JIRA_MARK_BLUE = '#2684FF';
712
+ /** Left sail */
713
+ const AXE_JIRA_MARK_LEFT_PATH = 'M7.12 11.084a.683.683 0 0 0-1.16.126L.075 22.974a.703.703 0 0 0 .63 1.018h8.19a.678.678 0 0 0 .63-.39c1.767-3.65.696-9.203-2.406-12.52z';
714
+ /** Right sail */
715
+ const AXE_JIRA_MARK_RIGHT_PATH = 'M11.434.386a15.515 15.515 0 0 0-.906 15.317l3.95 7.9a.703.703 0 0 0 .628.388h8.19a.703.703 0 0 0 .63-1.017L12.63.38a.664.664 0 0 0-1.196.006z';
716
+ //#endregion
717
+
718
+ //#region ---- Jira brand logo (owned by Jira extension) ----
719
+ class AXEJiraLogoComponent {
720
+ constructor() {
721
+ this.appearance = input('colored', /* @ts-ignore */
722
+ ...(ngDevMode ? [{ debugName: "appearance" }] : /* istanbul ignore next */ []));
723
+ this.size = input(20, /* @ts-ignore */
724
+ ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
725
+ this.leftPath = AXE_JIRA_MARK_LEFT_PATH;
726
+ this.rightPath = AXE_JIRA_MARK_RIGHT_PATH;
727
+ this.markBlue = AXE_JIRA_MARK_BLUE;
728
+ this.resolvedAppearance = computed(() => {
729
+ const value = this.appearance();
730
+ return value === 'monochrome' ? 'monochrome' : 'colored';
731
+ }, /* @ts-ignore */
732
+ ...(ngDevMode ? [{ debugName: "resolvedAppearance" }] : /* istanbul ignore next */ []));
733
+ }
734
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraLogoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
735
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXEJiraLogoComponent, isStandalone: true, selector: "axe-jira-logo", inputs: { appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "inline-flex items-center justify-center" }, ngImport: i0, template: `
736
+ @switch (resolvedAppearance()) {
737
+ @case ('monochrome') {
738
+ <svg [attr.width]="size()" [attr.height]="size()" viewBox="0 0 24 24" aria-hidden="true">
739
+ <path fill="currentColor" [attr.d]="leftPath" />
740
+ <path fill="currentColor" [attr.d]="rightPath" />
741
+ </svg>
742
+ }
743
+ @default {
744
+ <svg [attr.width]="size()" [attr.height]="size()" viewBox="0 0 24 24" aria-hidden="true">
745
+ <path [attr.fill]="markBlue" [attr.d]="leftPath" />
746
+ <path [attr.fill]="markBlue" [attr.d]="rightPath" />
747
+ </svg>
748
+ }
749
+ }
750
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.Eager }); }
751
+ }
752
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraLogoComponent, decorators: [{
753
+ type: Component,
754
+ args: [{
755
+ selector: 'axe-jira-logo',
756
+ host: { class: 'inline-flex items-center justify-center' },
757
+ changeDetection: ChangeDetectionStrategy.Eager,
758
+ template: `
759
+ @switch (resolvedAppearance()) {
760
+ @case ('monochrome') {
761
+ <svg [attr.width]="size()" [attr.height]="size()" viewBox="0 0 24 24" aria-hidden="true">
762
+ <path fill="currentColor" [attr.d]="leftPath" />
763
+ <path fill="currentColor" [attr.d]="rightPath" />
764
+ </svg>
765
+ }
766
+ @default {
767
+ <svg [attr.width]="size()" [attr.height]="size()" viewBox="0 0 24 24" aria-hidden="true">
768
+ <path [attr.fill]="markBlue" [attr.d]="leftPath" />
769
+ <path [attr.fill]="markBlue" [attr.d]="rightPath" />
770
+ </svg>
771
+ }
772
+ }
773
+ `,
774
+ }]
775
+ }], propDecorators: { appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
776
+
777
+ var jiraLogo_component = /*#__PURE__*/Object.freeze({
778
+ __proto__: null,
779
+ AXEJiraLogoComponent: AXEJiraLogoComponent
780
+ });
781
+
782
+ //#endregion
783
+ //#region ---- Component ----
784
+ class AXEJiraProjectImportPopupComponent extends AXBasePageComponent {
785
+ constructor() {
786
+ super(...arguments);
787
+ this.loading = signal(false, /* @ts-ignore */
788
+ ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
789
+ this.defaultProjectTypeId = signal('', /* @ts-ignore */
790
+ ...(ngDevMode ? [{ debugName: "defaultProjectTypeId" }] : /* istanbul ignore next */ []));
791
+ this.rows = signal([], /* @ts-ignore */
792
+ ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
793
+ this.projectTypes = [];
794
+ this.remoteProjects = [];
795
+ this.alreadyLinkedJiraIds = new Set();
796
+ this.strategyOptions = AXE_JIRA_PROJECT_SYNC_STRATEGIES.map((id) => ({
797
+ id,
798
+ title: `@extensions-jira:import.sync-strategy.${id}`,
799
+ }));
800
+ }
801
+ ngOnInit() {
802
+ super.ngOnInit();
803
+ this.defaultProjectTypeId.set(this.projectTypes[0]?.id ?? '');
804
+ this.rows.set(this.remoteProjects.map((remote) => ({
805
+ remote,
806
+ selected: !this.alreadyLinkedJiraIds.has(remote.id),
807
+ syncStrategy: 'merge',
808
+ alreadyLinked: this.alreadyLinkedJiraIds.has(remote.id),
809
+ })));
810
+ }
811
+ handleProjectTypeChange(event) {
812
+ this.defaultProjectTypeId.set(event.value ?? '');
813
+ }
814
+ toggleRow(remoteId, event) {
815
+ const selected = !!event.value;
816
+ this.rows.update((items) => items.map((row) => (row.remote.id === remoteId ? { ...row, selected } : row)));
817
+ }
818
+ changeStrategy(remoteId, event) {
819
+ const syncStrategy = event.value ?? 'merge';
820
+ this.rows.update((items) => items.map((row) => (row.remote.id === remoteId ? { ...row, syncStrategy } : row)));
821
+ }
822
+ hasSelection() {
823
+ return this.rows().some((row) => row.selected && !row.alreadyLinked);
824
+ }
825
+ confirm() {
826
+ const result = {
827
+ defaultProjectTypeId: this.defaultProjectTypeId(),
828
+ rows: this.rows()
829
+ .filter((row) => row.selected && !row.alreadyLinked)
830
+ .map((row) => ({
831
+ remote: row.remote,
832
+ selected: true,
833
+ syncStrategy: row.syncStrategy,
834
+ })),
835
+ };
836
+ this.close(result);
837
+ }
838
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraProjectImportPopupComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
839
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXEJiraProjectImportPopupComponent, isStandalone: true, selector: "axe-jira-project-import-popup", usesInheritance: true, ngImport: i0, template: `
840
+ <div class="flex flex-col gap-4 p-4 max-h-[70vh] overflow-auto">
841
+ <div class="flex flex-col gap-1">
842
+ <span class="text-sm font-medium">
843
+ {{ '@extensions-jira:import.popup.default-project-type' | translate | async }}
844
+ </span>
845
+ <ax-select-box
846
+ [dataSource]="projectTypes"
847
+ valueField="id"
848
+ textField="title"
849
+ [ngModel]="defaultProjectTypeId()"
850
+ (onValueChanged)="handleProjectTypeChange($event)"
851
+ ></ax-select-box>
852
+ </div>
853
+
854
+ @if (loading()) {
855
+ <ax-loading></ax-loading>
856
+ } @else if (rows().length === 0) {
857
+ <p class="text-sm opacity-70">
858
+ {{ '@extensions-jira:import.popup.empty' | translate | async }}
859
+ </p>
860
+ } @else {
861
+ <table class="w-full text-sm">
862
+ <thead>
863
+ <tr class="border-b">
864
+ <th class="p-2 text-start"></th>
865
+ <th class="p-2 text-start">{{ '@extensions-jira:import.popup.columns.key' | translate | async }}</th>
866
+ <th class="p-2 text-start">{{ '@extensions-jira:import.popup.columns.name' | translate | async }}</th>
867
+ <th class="p-2 text-start">{{ '@extensions-jira:import.popup.columns.strategy' | translate | async }}</th>
868
+ </tr>
869
+ </thead>
870
+ <tbody>
871
+ @for (row of rows(); track row.remote.id) {
872
+ <tr class="border-b border-opacity-20">
873
+ <td class="p-2">
874
+ <ax-check-box
875
+ [ngModel]="row.selected"
876
+ [disabled]="row.alreadyLinked"
877
+ (onValueChanged)="toggleRow(row.remote.id, $event)"
878
+ ></ax-check-box>
879
+ </td>
880
+ <td class="p-2">{{ row.remote.key }}</td>
881
+ <td class="p-2">{{ row.remote.name }}</td>
882
+ <td class="p-2">
883
+ <ax-select-box
884
+ class="min-w-40"
885
+ [dataSource]="strategyOptions"
886
+ valueField="id"
887
+ textField="title"
888
+ [ngModel]="row.syncStrategy"
889
+ [disabled]="!row.selected"
890
+ (onValueChanged)="changeStrategy(row.remote.id, $event)"
891
+ ></ax-select-box>
892
+ </td>
893
+ </tr>
894
+ }
895
+ </tbody>
896
+ </table>
897
+ }
898
+ </div>
899
+ <ax-footer>
900
+ <ax-suffix>
901
+ <ax-button
902
+ look="outline"
903
+ [text]="'@general:actions.cancel.title' | translate | async"
904
+ (onClick)="close()"
905
+ ></ax-button>
906
+ <ax-button
907
+ look="solid"
908
+ color="primary"
909
+ [disabled]="!hasSelection()"
910
+ [text]="'@extensions-jira:import.popup.confirm' | translate | async"
911
+ (onClick)="confirm()"
912
+ ></ax-button>
913
+ </ax-suffix>
914
+ </ax-footer>
915
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i3.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "isLoading", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i4.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i5.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i6.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "itemHeight", "maxVisibleItems", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed", "onItemSelected", "onItemClick"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: i7.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
916
+ }
917
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEJiraProjectImportPopupComponent, decorators: [{
918
+ type: Component,
919
+ args: [{
920
+ selector: 'axe-jira-project-import-popup',
921
+ changeDetection: ChangeDetectionStrategy.OnPush,
922
+ imports: [
923
+ AsyncPipe,
924
+ FormsModule,
925
+ AXButtonModule,
926
+ AXCheckBoxModule,
927
+ AXDecoratorModule,
928
+ AXLoadingModule,
929
+ AXSelectBoxModule,
930
+ AXTranslationModule,
931
+ ],
932
+ template: `
933
+ <div class="flex flex-col gap-4 p-4 max-h-[70vh] overflow-auto">
934
+ <div class="flex flex-col gap-1">
935
+ <span class="text-sm font-medium">
936
+ {{ '@extensions-jira:import.popup.default-project-type' | translate | async }}
937
+ </span>
938
+ <ax-select-box
939
+ [dataSource]="projectTypes"
940
+ valueField="id"
941
+ textField="title"
942
+ [ngModel]="defaultProjectTypeId()"
943
+ (onValueChanged)="handleProjectTypeChange($event)"
944
+ ></ax-select-box>
945
+ </div>
946
+
947
+ @if (loading()) {
948
+ <ax-loading></ax-loading>
949
+ } @else if (rows().length === 0) {
950
+ <p class="text-sm opacity-70">
951
+ {{ '@extensions-jira:import.popup.empty' | translate | async }}
952
+ </p>
953
+ } @else {
954
+ <table class="w-full text-sm">
955
+ <thead>
956
+ <tr class="border-b">
957
+ <th class="p-2 text-start"></th>
958
+ <th class="p-2 text-start">{{ '@extensions-jira:import.popup.columns.key' | translate | async }}</th>
959
+ <th class="p-2 text-start">{{ '@extensions-jira:import.popup.columns.name' | translate | async }}</th>
960
+ <th class="p-2 text-start">{{ '@extensions-jira:import.popup.columns.strategy' | translate | async }}</th>
961
+ </tr>
962
+ </thead>
963
+ <tbody>
964
+ @for (row of rows(); track row.remote.id) {
965
+ <tr class="border-b border-opacity-20">
966
+ <td class="p-2">
967
+ <ax-check-box
968
+ [ngModel]="row.selected"
969
+ [disabled]="row.alreadyLinked"
970
+ (onValueChanged)="toggleRow(row.remote.id, $event)"
971
+ ></ax-check-box>
972
+ </td>
973
+ <td class="p-2">{{ row.remote.key }}</td>
974
+ <td class="p-2">{{ row.remote.name }}</td>
975
+ <td class="p-2">
976
+ <ax-select-box
977
+ class="min-w-40"
978
+ [dataSource]="strategyOptions"
979
+ valueField="id"
980
+ textField="title"
981
+ [ngModel]="row.syncStrategy"
982
+ [disabled]="!row.selected"
983
+ (onValueChanged)="changeStrategy(row.remote.id, $event)"
984
+ ></ax-select-box>
985
+ </td>
986
+ </tr>
987
+ }
988
+ </tbody>
989
+ </table>
990
+ }
991
+ </div>
992
+ <ax-footer>
993
+ <ax-suffix>
994
+ <ax-button
995
+ look="outline"
996
+ [text]="'@general:actions.cancel.title' | translate | async"
997
+ (onClick)="close()"
998
+ ></ax-button>
999
+ <ax-button
1000
+ look="solid"
1001
+ color="primary"
1002
+ [disabled]="!hasSelection()"
1003
+ [text]="'@extensions-jira:import.popup.confirm' | translate | async"
1004
+ (onClick)="confirm()"
1005
+ ></ax-button>
1006
+ </ax-suffix>
1007
+ </ax-footer>
1008
+ `,
1009
+ }]
1010
+ }] });
1011
+
1012
+ /**
1013
+ * Generated bundle index. Do not edit.
1014
+ */
1015
+
1016
+ export { AXEJiraExtensionModule, AXEJiraLogoComponent, AXEJiraProjectImportPopupComponent, AXE_JIRA_LOGO_PROVIDER, AXE_JIRA_MARK_BLUE, AXE_JIRA_MARK_LEFT_PATH, AXE_JIRA_MARK_RIGHT_PATH, axpJiraLogoKey };
1017
+ //# sourceMappingURL=acorex-platform-extension-project-management-jira-client.mjs.map