@praxisui/crud 10.0.0-rc.24 → 10.0.0-rc.26
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/README.md +15 -0
- package/ai/component-registry.json +2 -2
- package/fesm2022/praxisui-crud.mjs +444 -265
- package/package.json +7 -7
- package/types/praxisui-crud.d.ts +24 -0
package/README.md
CHANGED
|
@@ -370,6 +370,21 @@ and materializes them in the contextual bulk selection toolbar:
|
|
|
370
370
|
`persistOnDataUpdate: true` table refreshes, and re-fetches capabilities
|
|
371
371
|
when `refresh.capabilities === true`.
|
|
372
372
|
|
|
373
|
+
`CANCEL_REQUESTED` stays pending: requesting cancellation does not imply that the
|
|
374
|
+
server finished. The dialogs keep one execution-tracking subscription, prevent
|
|
375
|
+
duplicate cancellation and accept final results only from canonical terminal
|
|
376
|
+
snapshots. Once terminal, late polling or cancellation callbacks cannot downgrade
|
|
377
|
+
the result. Terminal status is not proof of full success; partial totals and
|
|
378
|
+
reconciliation diagnostics remain visible.
|
|
379
|
+
|
|
380
|
+
If tracking fails or expires, the dialogs show an unknown outcome rather than a
|
|
381
|
+
completed result: server effects may already exist. The explicit resume action
|
|
382
|
+
only reads the same execution with the original proposal/key; it never repeats
|
|
383
|
+
confirmation or evaluation. The person can close this state with `success:false`
|
|
384
|
+
and the last snapshot, without claiming that no effects committed. Tracking ends
|
|
385
|
+
when the dialog closes or is destroyed. Retaining intention/key custody across
|
|
386
|
+
reopening or reload remains a separate requirement, not a guarantee of this flow.
|
|
387
|
+
|
|
373
388
|
Unavailable bulk operations (`availability.allowed === false`) remain visible
|
|
374
389
|
but disabled in the bulk toolbar with their canonical translated reason tooltip.
|
|
375
390
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "1.0.0",
|
|
3
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"generatedAt": "2026-10-15T19:07:41.629Z",
|
|
4
4
|
"packageName": "@praxisui/crud",
|
|
5
|
-
"packageVersion": "10.0.0-rc.
|
|
5
|
+
"packageVersion": "10.0.0-rc.26",
|
|
6
6
|
"sourceRegistry": "praxis-component-registry-ingestion",
|
|
7
7
|
"sourceRegistryVersion": "1.0.0",
|
|
8
8
|
"componentCount": 2,
|
|
@@ -4,10 +4,10 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
|
4
4
|
import { HttpClient } from '@angular/common/http';
|
|
5
5
|
import { Router, ActivatedRoute, RouterLink } from '@angular/router';
|
|
6
6
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
7
|
-
import { firstValueFrom, BehaviorSubject
|
|
7
|
+
import { Subscription, firstValueFrom, BehaviorSubject } from 'rxjs';
|
|
8
8
|
import { take, filter } from 'rxjs/operators';
|
|
9
9
|
import * as i2$1 from '@praxisui/core';
|
|
10
|
-
import { PraxisBulkClientService, generateBulkIdempotencyKey, API_URL, SafeExpressionEvaluator, buildApiUrl, ASYNC_CONFIG_STORAGE, GlobalConfigService, CrudOperationResolutionService, LoggerService, SurfaceNavigationError, fillUndefined, GenericCrudService, SETTINGS_PANEL_DATA,
|
|
10
|
+
import { PraxisBulkClientService, PraxisI18nService, generateBulkIdempotencyKey, isBulkExecutionTerminal, API_URL, SafeExpressionEvaluator, buildApiUrl, ASYNC_CONFIG_STORAGE, GlobalConfigService, CrudOperationResolutionService, LoggerService, SurfaceNavigationError, fillUndefined, GenericCrudService, SETTINGS_PANEL_DATA, buildBaseColumnFromDef, PraxisIconDirective, providePraxisI18nConfig, SchemaNormalizerService, createDefaultTableConfig, PraxisWidgetEventBus, EnterpriseRuntimeContextService, GLOBAL_SURFACE_SERVICE, SurfaceOutletRegistryService, ComponentKeyService, ResourceDiscoveryService, ResourceActionOpenAdapterService, ResourceSurfaceOpenAdapterService, composeHeadersWithVersion, normalizeSurfaceOperationContext, translateUnavailableWorkflowMessage, isSurfaceNavigationError, translateSurfaceNavigationRejected, normalizeUnknownError, EmptyStateCardComponent, RESOURCE_DISCOVERY_I18N_CONFIG, SURFACE_DRAWER_REF, SURFACE_DRAWER_CONTENT_DATA, PraxisIconButtonComponent, PraxisResourceIdentityComponent, ComponentMetadataRegistry, PraxisCustomizationModeService } from '@praxisui/core';
|
|
11
11
|
export { createDynamicRecord, extractRecordId, isDynamicDataRecord, resolveDataField } from '@praxisui/core';
|
|
12
12
|
import * as i1 from '@angular/common';
|
|
13
13
|
import { CommonModule } from '@angular/common';
|
|
@@ -42,11 +42,121 @@ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
|
|
42
42
|
import * as i9 from '@angular/material/tabs';
|
|
43
43
|
import { MatTabsModule } from '@angular/material/tabs';
|
|
44
44
|
|
|
45
|
+
const PRAXIS_CRUD_RUNTIME_I18N_NAMESPACE = 'praxisCrudRuntime';
|
|
46
|
+
const PRAXIS_CRUD_RUNTIME_I18N_CONFIG = {
|
|
47
|
+
namespaces: {
|
|
48
|
+
[PRAXIS_CRUD_RUNTIME_I18N_NAMESPACE]: {
|
|
49
|
+
'pt-BR': {
|
|
50
|
+
'crud.bulk.tracking': 'Acompanhando execução em lote...',
|
|
51
|
+
'crud.bulk.trackingUnavailable': 'Não foi possível acompanhar a execução.',
|
|
52
|
+
'crud.bulk.effectsMayExist': 'A execução pode continuar e já ter produzido efeitos no servidor. Retome a consulta desta execução antes de iniciar outra intenção.',
|
|
53
|
+
'crud.bulk.resumeTracking': 'Retomar acompanhamento',
|
|
54
|
+
'crud.bulk.closeUnknown': 'Fechar sem confirmar conclusão',
|
|
55
|
+
'crud.bulk.cancelRequest': 'Solicitar cancelamento',
|
|
56
|
+
'crud.bulk.requestingCancel': 'Solicitando cancelamento...',
|
|
57
|
+
'crud.bulk.cancelRequested': 'Cancelamento solicitado. Aguardando confirmação do servidor.',
|
|
58
|
+
'crud.emptyState.title': 'Conecte o CRUD a um recurso',
|
|
59
|
+
'crud.emptyState.description': 'Informe os metadados (resourcePath / schema) ou forneça metadata.data para habilitar a tabela e as ações.',
|
|
60
|
+
'crud.emptyState.primaryAction': 'Configurar metadados',
|
|
61
|
+
'crud.table.emptyState.initial.title': 'Sem registros em {label}',
|
|
62
|
+
'crud.table.emptyState.initial.titleFallback': 'Nenhum registro disponível.',
|
|
63
|
+
'crud.table.emptyState.initial.descriptionWithToolbarAction': 'Use "{action}" na barra da tabela para adicionar o primeiro registro quando houver informações para cadastrar.',
|
|
64
|
+
'crud.table.emptyState.filtered.title': 'Nenhum resultado encontrado.',
|
|
65
|
+
'crud.table.emptyState.filtered.description': 'Revise os filtros ou ajuste o termo de busca.',
|
|
66
|
+
'crud.preferences.resetSuccess': 'Overrides de CRUD redefinidos',
|
|
67
|
+
'crud.actions.create': 'Adicionar',
|
|
68
|
+
'crud.actions.view': 'Ver',
|
|
69
|
+
'crud.actions.edit': 'Editar',
|
|
70
|
+
'crud.actions.delete': 'Excluir',
|
|
71
|
+
'crud.actions.default': 'ação',
|
|
72
|
+
'crud.actions.opening': 'Abrindo {action}…',
|
|
73
|
+
'crud.surface.openFailed': 'Não foi possível abrir {title}. Tente novamente ou confirme se esse recurso continua disponível.',
|
|
74
|
+
'crud.dialog.recordContextLabel': 'Registro em edição',
|
|
75
|
+
'crud.dialog.viewRecordContextLabel': 'Registro em consulta',
|
|
76
|
+
'crud.dialog.relatedContextLabel': 'Vinculado a',
|
|
77
|
+
'crud.delete.confirmMessage': 'Esta ação não pode ser desfeita. Deseja continuar?',
|
|
78
|
+
'crud.delete.cancel': 'Cancelar',
|
|
79
|
+
},
|
|
80
|
+
'en-US': {
|
|
81
|
+
'crud.bulk.tracking': 'Tracking bulk execution...',
|
|
82
|
+
'crud.bulk.trackingUnavailable': 'Execution tracking is unavailable.',
|
|
83
|
+
'crud.bulk.effectsMayExist': 'The execution may continue and may already have produced server effects. Resume this execution before starting another intent.',
|
|
84
|
+
'crud.bulk.resumeTracking': 'Resume tracking',
|
|
85
|
+
'crud.bulk.closeUnknown': 'Close without confirming completion',
|
|
86
|
+
'crud.bulk.cancelRequest': 'Request cancellation',
|
|
87
|
+
'crud.bulk.requestingCancel': 'Requesting cancellation...',
|
|
88
|
+
'crud.bulk.cancelRequested': 'Cancellation requested. Waiting for server confirmation.',
|
|
89
|
+
'crud.emptyState.title': 'Connect CRUD to a resource',
|
|
90
|
+
'crud.emptyState.description': 'Provide metadata (resourcePath / schema) or metadata.data to enable the table and actions.',
|
|
91
|
+
'crud.emptyState.primaryAction': 'Configure metadata',
|
|
92
|
+
'crud.table.emptyState.initial.title': 'No records in {label}',
|
|
93
|
+
'crud.table.emptyState.initial.titleFallback': 'No records available.',
|
|
94
|
+
'crud.table.emptyState.initial.descriptionWithToolbarAction': 'Use "{action}" in the table toolbar to add the first record when there is information to register.',
|
|
95
|
+
'crud.table.emptyState.filtered.title': 'No results found.',
|
|
96
|
+
'crud.table.emptyState.filtered.description': 'Review the filters or adjust the search term.',
|
|
97
|
+
'crud.preferences.resetSuccess': 'CRUD overrides reset',
|
|
98
|
+
'crud.actions.create': 'Add',
|
|
99
|
+
'crud.actions.view': 'View',
|
|
100
|
+
'crud.actions.edit': 'Edit',
|
|
101
|
+
'crud.actions.delete': 'Delete',
|
|
102
|
+
'crud.actions.default': 'action',
|
|
103
|
+
'crud.actions.opening': 'Opening {action}…',
|
|
104
|
+
'crud.surface.openFailed': 'Could not open {title}. Try again or confirm that this resource is still available.',
|
|
105
|
+
'crud.dialog.recordContextLabel': 'Record being edited',
|
|
106
|
+
'crud.dialog.viewRecordContextLabel': 'Record being viewed',
|
|
107
|
+
'crud.dialog.relatedContextLabel': 'Related to',
|
|
108
|
+
'crud.delete.confirmMessage': 'This action cannot be undone. Do you want to continue?',
|
|
109
|
+
'crud.delete.cancel': 'Cancel',
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
function getCrudRuntimeDictionary(locale) {
|
|
115
|
+
const dictionaries = PRAXIS_CRUD_RUNTIME_I18N_CONFIG.namespaces?.[PRAXIS_CRUD_RUNTIME_I18N_NAMESPACE];
|
|
116
|
+
if (!dictionaries) {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
const normalized = String(locale || '').trim();
|
|
120
|
+
const candidates = [
|
|
121
|
+
normalized,
|
|
122
|
+
normalized.toLowerCase(),
|
|
123
|
+
normalized.includes('-') ? normalized.split('-')[0] : '',
|
|
124
|
+
normalized.includes('_') ? normalized.split('_')[0] : '',
|
|
125
|
+
'pt-BR',
|
|
126
|
+
'pt-br',
|
|
127
|
+
'en-US',
|
|
128
|
+
'en-us',
|
|
129
|
+
].filter(Boolean);
|
|
130
|
+
for (const candidate of candidates) {
|
|
131
|
+
const dictionary = dictionaries[candidate];
|
|
132
|
+
if (dictionary && typeof dictionary === 'object') {
|
|
133
|
+
return dictionary;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
function resolveCrudRuntimeFallback(key, locale) {
|
|
139
|
+
return getCrudRuntimeDictionary(locale || 'pt-BR')?.[key];
|
|
140
|
+
}
|
|
141
|
+
function translateCrudRuntimeText(i18n, key, fallback, params, locale) {
|
|
142
|
+
const effectiveLocale = locale || i18n.getLocale?.() || i18n.getFallbackLocale?.() || 'pt-BR';
|
|
143
|
+
const runtimeFallback = resolveCrudRuntimeFallback(key, effectiveLocale)
|
|
144
|
+
|| resolveCrudRuntimeFallback(key, i18n.getFallbackLocale?.())
|
|
145
|
+
|| fallback
|
|
146
|
+
|| key;
|
|
147
|
+
return i18n.t(key, params, runtimeFallback, PRAXIS_CRUD_RUNTIME_I18N_NAMESPACE);
|
|
148
|
+
}
|
|
149
|
+
|
|
45
150
|
class PraxisBulkOperationDialogComponent {
|
|
46
151
|
data;
|
|
47
152
|
dialogRef = inject((MatDialogRef));
|
|
48
153
|
bulkClient = inject(PraxisBulkClientService);
|
|
49
154
|
destroyRef = inject(DestroyRef);
|
|
155
|
+
i18n = inject(PraxisI18nService);
|
|
156
|
+
trackingUnavailable = signal(false, ...(ngDevMode ? [{ debugName: "trackingUnavailable" }] : /* istanbul ignore next */ []));
|
|
157
|
+
trackingSubscription = null;
|
|
158
|
+
executionGeneration = 0;
|
|
159
|
+
trackingClosed = false;
|
|
50
160
|
parametersForm;
|
|
51
161
|
step = signal('PARAMETERS', ...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
|
|
52
162
|
proposal = signal(null, ...(ngDevMode ? [{ debugName: "proposal" }] : /* istanbul ignore next */ []));
|
|
@@ -74,6 +184,10 @@ class PraxisBulkOperationDialogComponent {
|
|
|
74
184
|
};
|
|
75
185
|
constructor(data) {
|
|
76
186
|
this.data = data;
|
|
187
|
+
this.destroyRef.onDestroy(() => {
|
|
188
|
+
this.executionGeneration++;
|
|
189
|
+
this.stopExecutionTracking();
|
|
190
|
+
});
|
|
77
191
|
this.action = data.action;
|
|
78
192
|
this.targets = data.targets || [];
|
|
79
193
|
}
|
|
@@ -383,51 +497,103 @@ class PraxisBulkOperationDialogComponent {
|
|
|
383
497
|
onConfirm() {
|
|
384
498
|
const prop = this.proposal();
|
|
385
499
|
const bulkContract = this.action.execution?.bulk;
|
|
386
|
-
if (!prop || !bulkContract)
|
|
500
|
+
if (!prop || !bulkContract || this.trackingClosed || this.step() === 'CONFIRMING')
|
|
387
501
|
return;
|
|
502
|
+
const generation = ++this.executionGeneration;
|
|
503
|
+
this.stopExecutionTracking();
|
|
504
|
+
this.execution.set(null);
|
|
505
|
+
this.executionItems.set([]);
|
|
506
|
+
this.trackingUnavailable.set(false);
|
|
507
|
+
this.cancellingExecution.set(false);
|
|
388
508
|
this.step.set('CONFIRMING');
|
|
389
509
|
this.errorMessage.set(null);
|
|
390
|
-
if (!this.confirmationIdempotencyKey)
|
|
510
|
+
if (!this.confirmationIdempotencyKey)
|
|
391
511
|
this.confirmationIdempotencyKey = generateBulkIdempotencyKey();
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
endpointKey: this.data.endpointKey,
|
|
395
|
-
apiUrlEntry: this.data.apiUrlEntry,
|
|
396
|
-
idempotencyKey: this.confirmationIdempotencyKey,
|
|
397
|
-
};
|
|
398
|
-
this.bulkClient
|
|
399
|
-
.confirm(bulkContract.confirmationOperation, prop.proposalId, requestOptions)
|
|
512
|
+
const requestOptions = this.executionRequestOptions();
|
|
513
|
+
this.bulkClient.confirm(bulkContract.confirmationOperation, prop.proposalId, requestOptions)
|
|
400
514
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
401
515
|
.subscribe({
|
|
402
|
-
next:
|
|
403
|
-
this.
|
|
404
|
-
const isTerminal = typeof this.bulkClient.isTerminalStatus === 'function'
|
|
405
|
-
? this.bulkClient.isTerminalStatus(execution.status)
|
|
406
|
-
: execution.status !== 'QUEUED' && execution.status !== 'RUNNING';
|
|
407
|
-
if (!isTerminal && bulkContract.executionOperation && typeof this.bulkClient.waitForExecution === 'function') {
|
|
408
|
-
this.bulkClient
|
|
409
|
-
.waitForExecution(bulkContract.executionOperation, execution.executionId, 1000, 60000, requestOptions)
|
|
410
|
-
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
411
|
-
.subscribe({
|
|
412
|
-
next: (finalExec) => {
|
|
413
|
-
this.finalizeExecution(finalExec);
|
|
414
|
-
},
|
|
415
|
-
error: (err) => {
|
|
416
|
-
this.errorMessage.set(err?.error?.message || err?.message || 'Falha ao acompanhar execução em lote.');
|
|
417
|
-
this.step.set('RESULT');
|
|
418
|
-
},
|
|
419
|
-
});
|
|
516
|
+
next: exec => {
|
|
517
|
+
if (!this.isCurrentExecution(exec, generation))
|
|
420
518
|
return;
|
|
519
|
+
if (isBulkExecutionTerminal(exec.status))
|
|
520
|
+
this.finalizeExecution(exec);
|
|
521
|
+
else {
|
|
522
|
+
this.execution.set(exec);
|
|
523
|
+
this.startExecutionTracking(exec, requestOptions);
|
|
421
524
|
}
|
|
422
|
-
this.finalizeExecution(execution);
|
|
423
525
|
},
|
|
424
|
-
error:
|
|
526
|
+
error: err => {
|
|
527
|
+
if (generation !== this.executionGeneration || this.destroyRef.destroyed)
|
|
528
|
+
return;
|
|
425
529
|
this.errorMessage.set(err?.error?.message || err?.message || 'Falha ao confirmar execução em lote.');
|
|
426
530
|
this.step.set('PREVIEW');
|
|
427
531
|
},
|
|
428
532
|
});
|
|
429
533
|
}
|
|
534
|
+
executionRequestOptions() {
|
|
535
|
+
return { endpointKey: this.data.endpointKey, apiUrlEntry: this.data.apiUrlEntry,
|
|
536
|
+
idempotencyKey: this.confirmationIdempotencyKey };
|
|
537
|
+
}
|
|
538
|
+
isCurrentExecution(exec, generation) {
|
|
539
|
+
const current = this.execution();
|
|
540
|
+
return !this.trackingClosed && !this.destroyRef.destroyed && generation === this.executionGeneration
|
|
541
|
+
&& this.step() === 'CONFIRMING'
|
|
542
|
+
&& (!current || (current.executionId === exec.executionId && !isBulkExecutionTerminal(current.status)));
|
|
543
|
+
}
|
|
544
|
+
stopExecutionTracking() {
|
|
545
|
+
this.trackingSubscription?.unsubscribe();
|
|
546
|
+
this.trackingSubscription = null;
|
|
547
|
+
}
|
|
548
|
+
markTrackingUnavailable() {
|
|
549
|
+
this.stopExecutionTracking();
|
|
550
|
+
this.trackingUnavailable.set(true);
|
|
551
|
+
this.errorMessage.set(this.tx('crud.bulk.trackingUnavailable'));
|
|
552
|
+
}
|
|
553
|
+
startExecutionTracking(exec, options) {
|
|
554
|
+
const contract = this.action.execution?.bulk;
|
|
555
|
+
if (!this.isCurrentExecution(exec, this.executionGeneration) || this.trackingSubscription)
|
|
556
|
+
return;
|
|
557
|
+
if (!contract?.executionOperation || typeof this.bulkClient.waitForExecution !== 'function') {
|
|
558
|
+
this.markTrackingUnavailable();
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
this.trackingUnavailable.set(false);
|
|
562
|
+
this.errorMessage.set(null);
|
|
563
|
+
const generation = this.executionGeneration;
|
|
564
|
+
// Install the owner BEFORE subscribing: a synchronous terminal/error can
|
|
565
|
+
// close it before the inner subscription is returned and added.
|
|
566
|
+
const owner = new Subscription();
|
|
567
|
+
this.trackingSubscription = owner;
|
|
568
|
+
owner.add(this.bulkClient.waitForExecution(contract.executionOperation, exec.executionId, 1000, 60000, options)
|
|
569
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
570
|
+
.subscribe({
|
|
571
|
+
next: result => {
|
|
572
|
+
if (this.isCurrentExecution(result, generation))
|
|
573
|
+
this.finalizeExecution(result);
|
|
574
|
+
},
|
|
575
|
+
error: () => {
|
|
576
|
+
if (this.isCurrentExecution(exec, generation))
|
|
577
|
+
this.markTrackingUnavailable();
|
|
578
|
+
},
|
|
579
|
+
}));
|
|
580
|
+
}
|
|
581
|
+
resumeTracking() {
|
|
582
|
+
const exec = this.execution();
|
|
583
|
+
if (!this.trackingUnavailable() || !exec || isBulkExecutionTerminal(exec.status))
|
|
584
|
+
return;
|
|
585
|
+
this.startExecutionTracking(exec, this.executionRequestOptions());
|
|
586
|
+
}
|
|
587
|
+
tx(key) {
|
|
588
|
+
return translateCrudRuntimeText(this.i18n, key);
|
|
589
|
+
}
|
|
430
590
|
finalizeExecution(exec) {
|
|
591
|
+
if (!isBulkExecutionTerminal(exec.status) || !this.isCurrentExecution(exec, this.executionGeneration))
|
|
592
|
+
return;
|
|
593
|
+
this.stopExecutionTracking();
|
|
594
|
+
this.trackingUnavailable.set(false);
|
|
595
|
+
this.cancellingExecution.set(false);
|
|
596
|
+
this.errorMessage.set(null);
|
|
431
597
|
this.execution.set(exec);
|
|
432
598
|
const inlineItems = Array.isArray(exec.items)
|
|
433
599
|
? exec.items
|
|
@@ -442,7 +608,7 @@ class PraxisBulkOperationDialogComponent {
|
|
|
442
608
|
loadExecutionResults(cursor) {
|
|
443
609
|
const exec = this.execution();
|
|
444
610
|
const bulkContract = this.action.execution?.bulk;
|
|
445
|
-
if (!exec ||
|
|
611
|
+
if (!exec || !isBulkExecutionTerminal(exec.status) ||
|
|
446
612
|
!bulkContract?.resultsOperation ||
|
|
447
613
|
typeof this.bulkClient.getExecutionResults !== 'function') {
|
|
448
614
|
return;
|
|
@@ -474,38 +640,33 @@ class PraxisBulkOperationDialogComponent {
|
|
|
474
640
|
}
|
|
475
641
|
canCancelExecution() {
|
|
476
642
|
const exec = this.execution();
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
const isTerminal = typeof this.bulkClient.isTerminalStatus === 'function'
|
|
482
|
-
? this.bulkClient.isTerminalStatus(exec.status)
|
|
483
|
-
: exec.status !== 'QUEUED' && exec.status !== 'RUNNING';
|
|
484
|
-
return !isTerminal;
|
|
643
|
+
return !this.trackingClosed && !this.destroyRef.destroyed
|
|
644
|
+
&& this.step() === 'CONFIRMING' && !!exec && !!this.action.execution?.bulk?.cancelOperation
|
|
645
|
+
&& !this.cancellingExecution() && exec.status !== 'CANCEL_REQUESTED'
|
|
646
|
+
&& !isBulkExecutionTerminal(exec.status);
|
|
485
647
|
}
|
|
486
648
|
onCancelActiveExecution() {
|
|
487
649
|
const exec = this.execution();
|
|
488
|
-
const
|
|
489
|
-
if (!this.canCancelExecution() ||
|
|
490
|
-
!exec ||
|
|
491
|
-
!bulkContract?.cancelOperation ||
|
|
492
|
-
typeof this.bulkClient.cancel !== 'function') {
|
|
650
|
+
const contract = this.action.execution?.bulk;
|
|
651
|
+
if (!this.canCancelExecution() || !exec || !contract?.cancelOperation)
|
|
493
652
|
return;
|
|
494
|
-
}
|
|
495
653
|
this.cancellingExecution.set(true);
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
apiUrlEntry: this.data.apiUrlEntry,
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
.subscribe({
|
|
504
|
-
next: (cancelledExec) => {
|
|
654
|
+
const generation = this.executionGeneration;
|
|
655
|
+
this.bulkClient.cancel(contract.cancelOperation, exec.executionId, {
|
|
656
|
+
endpointKey: this.data.endpointKey, apiUrlEntry: this.data.apiUrlEntry,
|
|
657
|
+
}).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
|
658
|
+
next: result => {
|
|
659
|
+
if (!this.isCurrentExecution(result, generation))
|
|
660
|
+
return;
|
|
505
661
|
this.cancellingExecution.set(false);
|
|
506
|
-
|
|
662
|
+
if (isBulkExecutionTerminal(result.status))
|
|
663
|
+
this.finalizeExecution(result);
|
|
664
|
+
else
|
|
665
|
+
this.execution.set(result);
|
|
507
666
|
},
|
|
508
|
-
error:
|
|
667
|
+
error: err => {
|
|
668
|
+
if (!this.isCurrentExecution(exec, generation))
|
|
669
|
+
return;
|
|
509
670
|
this.cancellingExecution.set(false);
|
|
510
671
|
this.errorMessage.set(err?.error?.message || err?.message || 'Falha ao solicitar cancelamento da execução em lote.');
|
|
511
672
|
},
|
|
@@ -513,10 +674,11 @@ class PraxisBulkOperationDialogComponent {
|
|
|
513
674
|
}
|
|
514
675
|
onCloseSuccess() {
|
|
515
676
|
const exec = this.execution();
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
const
|
|
519
|
-
|
|
677
|
+
if (!exec || !isBulkExecutionTerminal(exec.status))
|
|
678
|
+
return;
|
|
679
|
+
const status = exec.status;
|
|
680
|
+
const confirmed = exec.totals.confirmed;
|
|
681
|
+
const isSuccess = status === 'COMPLETED' ||
|
|
520
682
|
status === 'COMPLETED_WITH_ERRORS' ||
|
|
521
683
|
confirmed > 0;
|
|
522
684
|
this.dialogRef.close({
|
|
@@ -526,14 +688,25 @@ class PraxisBulkOperationDialogComponent {
|
|
|
526
688
|
});
|
|
527
689
|
}
|
|
528
690
|
onCancel() {
|
|
691
|
+
if (this.trackingClosed)
|
|
692
|
+
return;
|
|
529
693
|
if (this.step() === 'RESULT') {
|
|
530
694
|
this.onCloseSuccess();
|
|
531
695
|
return;
|
|
532
696
|
}
|
|
697
|
+
if (this.step() === 'CONFIRMING') {
|
|
698
|
+
if (!this.trackingUnavailable())
|
|
699
|
+
return;
|
|
700
|
+
this.trackingClosed = true;
|
|
701
|
+
this.executionGeneration++;
|
|
702
|
+
this.stopExecutionTracking();
|
|
703
|
+
this.dialogRef.close({ success: false, execution: this.execution(), results: this.executionItems() });
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
533
706
|
this.dialogRef.close({ success: false });
|
|
534
707
|
}
|
|
535
708
|
onEscape(event) {
|
|
536
|
-
if (this.step() !== 'CONFIRMING' && this.step() !== 'EVALUATING') {
|
|
709
|
+
if ((this.step() !== 'CONFIRMING' || this.trackingUnavailable()) && this.step() !== 'EVALUATING') {
|
|
537
710
|
event?.preventDefault();
|
|
538
711
|
this.onCancel();
|
|
539
712
|
}
|
|
@@ -551,7 +724,7 @@ class PraxisBulkOperationDialogComponent {
|
|
|
551
724
|
</p>
|
|
552
725
|
</div>
|
|
553
726
|
</div>
|
|
554
|
-
<button mat-icon-button (click)="onCancel()" [disabled]="step() === 'CONFIRMING'" aria-label="Fechar diálogo">
|
|
727
|
+
<button mat-icon-button (click)="onCancel()" [disabled]="step() === 'CONFIRMING' && !trackingUnavailable()" aria-label="Fechar diálogo">
|
|
555
728
|
<mat-icon>close</mat-icon>
|
|
556
729
|
</button>
|
|
557
730
|
</div>
|
|
@@ -712,17 +885,23 @@ class PraxisBulkOperationDialogComponent {
|
|
|
712
885
|
<!-- Passo de Confirmação em Progresso -->
|
|
713
886
|
@if (step() === 'CONFIRMING') {
|
|
714
887
|
<div class="praxis-bulk-dialog__loading">
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
888
|
+
@if (trackingUnavailable()) {
|
|
889
|
+
<div role="alert">
|
|
890
|
+
<strong>{{ tx('crud.bulk.trackingUnavailable') }}</strong>
|
|
891
|
+
<p>{{ tx('crud.bulk.effectsMayExist') }}</p>
|
|
892
|
+
</div>
|
|
893
|
+
<button mat-stroked-button type="button" data-testid="bulk-execution-resume" (click)="resumeTracking()">
|
|
894
|
+
{{ tx('crud.bulk.resumeTracking') }}
|
|
895
|
+
</button>
|
|
896
|
+
<button mat-button type="button" (click)="onCancel()">{{ tx('crud.bulk.closeUnknown') }}</button>
|
|
897
|
+
} @else {
|
|
898
|
+
<mat-spinner diameter="40" />
|
|
899
|
+
<p role="status">{{ execution()?.status === 'CANCEL_REQUESTED' ? tx('crud.bulk.cancelRequested') : tx('crud.bulk.tracking') }}</p>
|
|
900
|
+
}
|
|
901
|
+
@if (canCancelExecution() || cancellingExecution()) {
|
|
902
|
+
<button mat-stroked-button color="warn" type="button"
|
|
903
|
+
(click)="onCancelActiveExecution()" [disabled]="cancellingExecution()">
|
|
904
|
+
{{ cancellingExecution() ? tx('crud.bulk.requestingCancel') : tx('crud.bulk.cancelRequest') }}
|
|
726
905
|
</button>
|
|
727
906
|
}
|
|
728
907
|
</div>
|
|
@@ -803,7 +982,7 @@ class PraxisBulkOperationDialogComponent {
|
|
|
803
982
|
}
|
|
804
983
|
|
|
805
984
|
<!-- Erro Geral -->
|
|
806
|
-
@if (errorMessage()) {
|
|
985
|
+
@if (errorMessage() && !trackingUnavailable()) {
|
|
807
986
|
<div class="praxis-bulk-dialog__alert praxis-bulk-dialog__alert--error">
|
|
808
987
|
<mat-icon>error</mat-icon>
|
|
809
988
|
<div class="alert-content">
|
|
@@ -869,7 +1048,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
869
1048
|
</p>
|
|
870
1049
|
</div>
|
|
871
1050
|
</div>
|
|
872
|
-
<button mat-icon-button (click)="onCancel()" [disabled]="step() === 'CONFIRMING'" aria-label="Fechar diálogo">
|
|
1051
|
+
<button mat-icon-button (click)="onCancel()" [disabled]="step() === 'CONFIRMING' && !trackingUnavailable()" aria-label="Fechar diálogo">
|
|
873
1052
|
<mat-icon>close</mat-icon>
|
|
874
1053
|
</button>
|
|
875
1054
|
</div>
|
|
@@ -1030,17 +1209,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
1030
1209
|
<!-- Passo de Confirmação em Progresso -->
|
|
1031
1210
|
@if (step() === 'CONFIRMING') {
|
|
1032
1211
|
<div class="praxis-bulk-dialog__loading">
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1212
|
+
@if (trackingUnavailable()) {
|
|
1213
|
+
<div role="alert">
|
|
1214
|
+
<strong>{{ tx('crud.bulk.trackingUnavailable') }}</strong>
|
|
1215
|
+
<p>{{ tx('crud.bulk.effectsMayExist') }}</p>
|
|
1216
|
+
</div>
|
|
1217
|
+
<button mat-stroked-button type="button" data-testid="bulk-execution-resume" (click)="resumeTracking()">
|
|
1218
|
+
{{ tx('crud.bulk.resumeTracking') }}
|
|
1219
|
+
</button>
|
|
1220
|
+
<button mat-button type="button" (click)="onCancel()">{{ tx('crud.bulk.closeUnknown') }}</button>
|
|
1221
|
+
} @else {
|
|
1222
|
+
<mat-spinner diameter="40" />
|
|
1223
|
+
<p role="status">{{ execution()?.status === 'CANCEL_REQUESTED' ? tx('crud.bulk.cancelRequested') : tx('crud.bulk.tracking') }}</p>
|
|
1224
|
+
}
|
|
1225
|
+
@if (canCancelExecution() || cancellingExecution()) {
|
|
1226
|
+
<button mat-stroked-button color="warn" type="button"
|
|
1227
|
+
(click)="onCancelActiveExecution()" [disabled]="cancellingExecution()">
|
|
1228
|
+
{{ cancellingExecution() ? tx('crud.bulk.requestingCancel') : tx('crud.bulk.cancelRequest') }}
|
|
1044
1229
|
</button>
|
|
1045
1230
|
}
|
|
1046
1231
|
</div>
|
|
@@ -1121,7 +1306,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
1121
1306
|
}
|
|
1122
1307
|
|
|
1123
1308
|
<!-- Erro Geral -->
|
|
1124
|
-
@if (errorMessage()) {
|
|
1309
|
+
@if (errorMessage() && !trackingUnavailable()) {
|
|
1125
1310
|
<div class="praxis-bulk-dialog__alert praxis-bulk-dialog__alert--error">
|
|
1126
1311
|
<mat-icon>error</mat-icon>
|
|
1127
1312
|
<div class="alert-content">
|
|
@@ -1180,6 +1365,11 @@ class PraxisBulkEditDialogComponent {
|
|
|
1180
1365
|
dialogRef = inject((MatDialogRef));
|
|
1181
1366
|
bulkClient = inject(PraxisBulkClientService);
|
|
1182
1367
|
destroyRef = inject(DestroyRef);
|
|
1368
|
+
i18n = inject(PraxisI18nService);
|
|
1369
|
+
trackingUnavailable = signal(false, ...(ngDevMode ? [{ debugName: "trackingUnavailable" }] : /* istanbul ignore next */ []));
|
|
1370
|
+
trackingSubscription = null;
|
|
1371
|
+
executionGeneration = 0;
|
|
1372
|
+
trackingClosed = false;
|
|
1183
1373
|
step = signal('FIELDS', ...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
|
|
1184
1374
|
fieldRows = signal([], ...(ngDevMode ? [{ debugName: "fieldRows" }] : /* istanbul ignore next */ []));
|
|
1185
1375
|
proposal = signal(null, ...(ngDevMode ? [{ debugName: "proposal" }] : /* istanbul ignore next */ []));
|
|
@@ -1207,6 +1397,10 @@ class PraxisBulkEditDialogComponent {
|
|
|
1207
1397
|
}
|
|
1208
1398
|
constructor(data) {
|
|
1209
1399
|
this.data = data;
|
|
1400
|
+
this.destroyRef.onDestroy(() => {
|
|
1401
|
+
this.executionGeneration++;
|
|
1402
|
+
this.stopExecutionTracking();
|
|
1403
|
+
});
|
|
1210
1404
|
this.contract = data.bulkContract;
|
|
1211
1405
|
this.targets = data.targets || [];
|
|
1212
1406
|
this.writableFields = data.bulkContract.editableFields?.writableFields || [];
|
|
@@ -1636,51 +1830,104 @@ class PraxisBulkEditDialogComponent {
|
|
|
1636
1830
|
}
|
|
1637
1831
|
onConfirm() {
|
|
1638
1832
|
const prop = this.proposal();
|
|
1639
|
-
|
|
1833
|
+
const bulkContract = this.contract;
|
|
1834
|
+
if (!prop || !bulkContract || this.trackingClosed || this.step() === 'CONFIRMING')
|
|
1640
1835
|
return;
|
|
1836
|
+
const generation = ++this.executionGeneration;
|
|
1837
|
+
this.stopExecutionTracking();
|
|
1838
|
+
this.execution.set(null);
|
|
1839
|
+
this.executionItems.set([]);
|
|
1840
|
+
this.trackingUnavailable.set(false);
|
|
1841
|
+
this.cancellingExecution.set(false);
|
|
1641
1842
|
this.step.set('CONFIRMING');
|
|
1642
1843
|
this.errorMessage.set(null);
|
|
1643
|
-
if (!this.confirmationIdempotencyKey)
|
|
1844
|
+
if (!this.confirmationIdempotencyKey)
|
|
1644
1845
|
this.confirmationIdempotencyKey = generateBulkIdempotencyKey();
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
endpointKey: this.data.endpointKey,
|
|
1648
|
-
apiUrlEntry: this.data.apiUrlEntry,
|
|
1649
|
-
idempotencyKey: this.confirmationIdempotencyKey,
|
|
1650
|
-
};
|
|
1651
|
-
this.bulkClient
|
|
1652
|
-
.confirm(this.contract.confirmationOperation, prop.proposalId, requestOptions)
|
|
1846
|
+
const requestOptions = this.executionRequestOptions();
|
|
1847
|
+
this.bulkClient.confirm(bulkContract.confirmationOperation, prop.proposalId, requestOptions)
|
|
1653
1848
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
1654
1849
|
.subscribe({
|
|
1655
|
-
next:
|
|
1656
|
-
this.
|
|
1657
|
-
const isTerminal = typeof this.bulkClient.isTerminalStatus === 'function'
|
|
1658
|
-
? this.bulkClient.isTerminalStatus(exec.status)
|
|
1659
|
-
: exec.status !== 'QUEUED' && exec.status !== 'RUNNING';
|
|
1660
|
-
if (!isTerminal && this.contract.executionOperation && typeof this.bulkClient.waitForExecution === 'function') {
|
|
1661
|
-
this.bulkClient
|
|
1662
|
-
.waitForExecution(this.contract.executionOperation, exec.executionId, 1000, 60000, requestOptions)
|
|
1663
|
-
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
1664
|
-
.subscribe({
|
|
1665
|
-
next: (finalExec) => {
|
|
1666
|
-
this.finalizeExecution(finalExec);
|
|
1667
|
-
},
|
|
1668
|
-
error: (err) => {
|
|
1669
|
-
this.errorMessage.set(err?.error?.message || err?.message || 'Falha ao acompanhar execução em lote.');
|
|
1670
|
-
this.step.set('RESULT');
|
|
1671
|
-
},
|
|
1672
|
-
});
|
|
1850
|
+
next: exec => {
|
|
1851
|
+
if (!this.isCurrentExecution(exec, generation))
|
|
1673
1852
|
return;
|
|
1853
|
+
if (isBulkExecutionTerminal(exec.status))
|
|
1854
|
+
this.finalizeExecution(exec);
|
|
1855
|
+
else {
|
|
1856
|
+
this.execution.set(exec);
|
|
1857
|
+
this.startExecutionTracking(exec, requestOptions);
|
|
1674
1858
|
}
|
|
1675
|
-
this.finalizeExecution(exec);
|
|
1676
1859
|
},
|
|
1677
|
-
error:
|
|
1860
|
+
error: err => {
|
|
1861
|
+
if (generation !== this.executionGeneration || this.destroyRef.destroyed)
|
|
1862
|
+
return;
|
|
1678
1863
|
this.errorMessage.set(err?.error?.message || err?.message || 'Falha ao confirmar alterações em lote.');
|
|
1679
1864
|
this.step.set('PREVIEW');
|
|
1680
1865
|
},
|
|
1681
1866
|
});
|
|
1682
1867
|
}
|
|
1868
|
+
executionRequestOptions() {
|
|
1869
|
+
return { endpointKey: this.data.endpointKey, apiUrlEntry: this.data.apiUrlEntry,
|
|
1870
|
+
idempotencyKey: this.confirmationIdempotencyKey };
|
|
1871
|
+
}
|
|
1872
|
+
isCurrentExecution(exec, generation) {
|
|
1873
|
+
const current = this.execution();
|
|
1874
|
+
return !this.trackingClosed && !this.destroyRef.destroyed && generation === this.executionGeneration
|
|
1875
|
+
&& this.step() === 'CONFIRMING'
|
|
1876
|
+
&& (!current || (current.executionId === exec.executionId && !isBulkExecutionTerminal(current.status)));
|
|
1877
|
+
}
|
|
1878
|
+
stopExecutionTracking() {
|
|
1879
|
+
this.trackingSubscription?.unsubscribe();
|
|
1880
|
+
this.trackingSubscription = null;
|
|
1881
|
+
}
|
|
1882
|
+
markTrackingUnavailable() {
|
|
1883
|
+
this.stopExecutionTracking();
|
|
1884
|
+
this.trackingUnavailable.set(true);
|
|
1885
|
+
this.errorMessage.set(this.tx('crud.bulk.trackingUnavailable'));
|
|
1886
|
+
}
|
|
1887
|
+
startExecutionTracking(exec, options) {
|
|
1888
|
+
const contract = this.contract;
|
|
1889
|
+
if (!this.isCurrentExecution(exec, this.executionGeneration) || this.trackingSubscription)
|
|
1890
|
+
return;
|
|
1891
|
+
if (!contract?.executionOperation || typeof this.bulkClient.waitForExecution !== 'function') {
|
|
1892
|
+
this.markTrackingUnavailable();
|
|
1893
|
+
return;
|
|
1894
|
+
}
|
|
1895
|
+
this.trackingUnavailable.set(false);
|
|
1896
|
+
this.errorMessage.set(null);
|
|
1897
|
+
const generation = this.executionGeneration;
|
|
1898
|
+
// Install the owner BEFORE subscribing: a synchronous terminal/error can
|
|
1899
|
+
// close it before the inner subscription is returned and added.
|
|
1900
|
+
const owner = new Subscription();
|
|
1901
|
+
this.trackingSubscription = owner;
|
|
1902
|
+
owner.add(this.bulkClient.waitForExecution(contract.executionOperation, exec.executionId, 1000, 60000, options)
|
|
1903
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
1904
|
+
.subscribe({
|
|
1905
|
+
next: result => {
|
|
1906
|
+
if (this.isCurrentExecution(result, generation))
|
|
1907
|
+
this.finalizeExecution(result);
|
|
1908
|
+
},
|
|
1909
|
+
error: () => {
|
|
1910
|
+
if (this.isCurrentExecution(exec, generation))
|
|
1911
|
+
this.markTrackingUnavailable();
|
|
1912
|
+
},
|
|
1913
|
+
}));
|
|
1914
|
+
}
|
|
1915
|
+
resumeTracking() {
|
|
1916
|
+
const exec = this.execution();
|
|
1917
|
+
if (!this.trackingUnavailable() || !exec || isBulkExecutionTerminal(exec.status))
|
|
1918
|
+
return;
|
|
1919
|
+
this.startExecutionTracking(exec, this.executionRequestOptions());
|
|
1920
|
+
}
|
|
1921
|
+
tx(key) {
|
|
1922
|
+
return translateCrudRuntimeText(this.i18n, key);
|
|
1923
|
+
}
|
|
1683
1924
|
finalizeExecution(exec) {
|
|
1925
|
+
if (!isBulkExecutionTerminal(exec.status) || !this.isCurrentExecution(exec, this.executionGeneration))
|
|
1926
|
+
return;
|
|
1927
|
+
this.stopExecutionTracking();
|
|
1928
|
+
this.trackingUnavailable.set(false);
|
|
1929
|
+
this.cancellingExecution.set(false);
|
|
1930
|
+
this.errorMessage.set(null);
|
|
1684
1931
|
this.execution.set(exec);
|
|
1685
1932
|
const inlineItems = Array.isArray(exec.items)
|
|
1686
1933
|
? exec.items
|
|
@@ -1694,7 +1941,7 @@ class PraxisBulkEditDialogComponent {
|
|
|
1694
1941
|
}
|
|
1695
1942
|
loadExecutionResults(cursor) {
|
|
1696
1943
|
const exec = this.execution();
|
|
1697
|
-
if (!exec ||
|
|
1944
|
+
if (!exec || !isBulkExecutionTerminal(exec.status) ||
|
|
1698
1945
|
!this.contract?.resultsOperation ||
|
|
1699
1946
|
typeof this.bulkClient.getExecutionResults !== 'function') {
|
|
1700
1947
|
return;
|
|
@@ -1726,36 +1973,33 @@ class PraxisBulkEditDialogComponent {
|
|
|
1726
1973
|
}
|
|
1727
1974
|
canCancelExecution() {
|
|
1728
1975
|
const exec = this.execution();
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
? this.bulkClient.isTerminalStatus(exec.status)
|
|
1734
|
-
: exec.status !== 'QUEUED' && exec.status !== 'RUNNING';
|
|
1735
|
-
return !isTerminal;
|
|
1976
|
+
return !this.trackingClosed && !this.destroyRef.destroyed
|
|
1977
|
+
&& this.step() === 'CONFIRMING' && !!exec && !!this.contract?.cancelOperation
|
|
1978
|
+
&& !this.cancellingExecution() && exec.status !== 'CANCEL_REQUESTED'
|
|
1979
|
+
&& !isBulkExecutionTerminal(exec.status);
|
|
1736
1980
|
}
|
|
1737
1981
|
onCancelActiveExecution() {
|
|
1738
1982
|
const exec = this.execution();
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
!this.contract?.cancelOperation ||
|
|
1742
|
-
typeof this.bulkClient.cancel !== 'function') {
|
|
1983
|
+
const contract = this.contract;
|
|
1984
|
+
if (!this.canCancelExecution() || !exec || !contract?.cancelOperation)
|
|
1743
1985
|
return;
|
|
1744
|
-
}
|
|
1745
1986
|
this.cancellingExecution.set(true);
|
|
1746
|
-
const
|
|
1747
|
-
|
|
1748
|
-
apiUrlEntry: this.data.apiUrlEntry,
|
|
1749
|
-
}
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
.subscribe({
|
|
1754
|
-
next: (cancelledExec) => {
|
|
1987
|
+
const generation = this.executionGeneration;
|
|
1988
|
+
this.bulkClient.cancel(contract.cancelOperation, exec.executionId, {
|
|
1989
|
+
endpointKey: this.data.endpointKey, apiUrlEntry: this.data.apiUrlEntry,
|
|
1990
|
+
}).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
|
1991
|
+
next: result => {
|
|
1992
|
+
if (!this.isCurrentExecution(result, generation))
|
|
1993
|
+
return;
|
|
1755
1994
|
this.cancellingExecution.set(false);
|
|
1756
|
-
|
|
1995
|
+
if (isBulkExecutionTerminal(result.status))
|
|
1996
|
+
this.finalizeExecution(result);
|
|
1997
|
+
else
|
|
1998
|
+
this.execution.set(result);
|
|
1757
1999
|
},
|
|
1758
|
-
error:
|
|
2000
|
+
error: err => {
|
|
2001
|
+
if (!this.isCurrentExecution(exec, generation))
|
|
2002
|
+
return;
|
|
1759
2003
|
this.cancellingExecution.set(false);
|
|
1760
2004
|
this.errorMessage.set(err?.error?.message || err?.message || 'Falha ao solicitar cancelamento da execução em lote.');
|
|
1761
2005
|
},
|
|
@@ -1763,10 +2007,11 @@ class PraxisBulkEditDialogComponent {
|
|
|
1763
2007
|
}
|
|
1764
2008
|
onCloseSuccess() {
|
|
1765
2009
|
const exec = this.execution();
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
const
|
|
1769
|
-
|
|
2010
|
+
if (!exec || !isBulkExecutionTerminal(exec.status))
|
|
2011
|
+
return;
|
|
2012
|
+
const status = exec.status;
|
|
2013
|
+
const confirmed = exec.totals.confirmed;
|
|
2014
|
+
const isSuccess = status === 'COMPLETED' ||
|
|
1770
2015
|
status === 'COMPLETED_WITH_ERRORS' ||
|
|
1771
2016
|
confirmed > 0;
|
|
1772
2017
|
this.dialogRef.close({
|
|
@@ -1776,14 +2021,25 @@ class PraxisBulkEditDialogComponent {
|
|
|
1776
2021
|
});
|
|
1777
2022
|
}
|
|
1778
2023
|
onCancel() {
|
|
2024
|
+
if (this.trackingClosed)
|
|
2025
|
+
return;
|
|
1779
2026
|
if (this.step() === 'RESULT') {
|
|
1780
2027
|
this.onCloseSuccess();
|
|
1781
2028
|
return;
|
|
1782
2029
|
}
|
|
2030
|
+
if (this.step() === 'CONFIRMING') {
|
|
2031
|
+
if (!this.trackingUnavailable())
|
|
2032
|
+
return;
|
|
2033
|
+
this.trackingClosed = true;
|
|
2034
|
+
this.executionGeneration++;
|
|
2035
|
+
this.stopExecutionTracking();
|
|
2036
|
+
this.dialogRef.close({ success: false, execution: this.execution(), results: this.executionItems() });
|
|
2037
|
+
return;
|
|
2038
|
+
}
|
|
1783
2039
|
this.dialogRef.close({ success: false });
|
|
1784
2040
|
}
|
|
1785
2041
|
onEscape(event) {
|
|
1786
|
-
if (this.step() !== 'CONFIRMING' && this.step() !== 'EVALUATING') {
|
|
2042
|
+
if ((this.step() !== 'CONFIRMING' || this.trackingUnavailable()) && this.step() !== 'EVALUATING') {
|
|
1787
2043
|
event?.preventDefault();
|
|
1788
2044
|
this.onCancel();
|
|
1789
2045
|
}
|
|
@@ -1821,7 +2077,7 @@ class PraxisBulkEditDialogComponent {
|
|
|
1821
2077
|
<p id="praxis-bulk-edit-dialog-subtitle" class="praxis-bulk-edit-dialog__subtitle">{{ dialogSubtitle }}</p>
|
|
1822
2078
|
</div>
|
|
1823
2079
|
</div>
|
|
1824
|
-
<button mat-icon-button (click)="onCancel()" [disabled]="step() === 'CONFIRMING'" aria-label="Fechar diálogo">
|
|
2080
|
+
<button mat-icon-button (click)="onCancel()" [disabled]="step() === 'CONFIRMING' && !trackingUnavailable()" aria-label="Fechar diálogo">
|
|
1825
2081
|
<mat-icon>close</mat-icon>
|
|
1826
2082
|
</button>
|
|
1827
2083
|
</div>
|
|
@@ -2058,17 +2314,23 @@ class PraxisBulkEditDialogComponent {
|
|
|
2058
2314
|
<!-- Confirmação em Andamento -->
|
|
2059
2315
|
@if (step() === 'CONFIRMING') {
|
|
2060
2316
|
<div class="praxis-bulk-edit-dialog__loading">
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2317
|
+
@if (trackingUnavailable()) {
|
|
2318
|
+
<div role="alert">
|
|
2319
|
+
<strong>{{ tx('crud.bulk.trackingUnavailable') }}</strong>
|
|
2320
|
+
<p>{{ tx('crud.bulk.effectsMayExist') }}</p>
|
|
2321
|
+
</div>
|
|
2322
|
+
<button mat-stroked-button type="button" data-testid="bulk-execution-resume" (click)="resumeTracking()">
|
|
2323
|
+
{{ tx('crud.bulk.resumeTracking') }}
|
|
2324
|
+
</button>
|
|
2325
|
+
<button mat-button type="button" (click)="onCancel()">{{ tx('crud.bulk.closeUnknown') }}</button>
|
|
2326
|
+
} @else {
|
|
2327
|
+
<mat-spinner diameter="40" />
|
|
2328
|
+
<p role="status">{{ execution()?.status === 'CANCEL_REQUESTED' ? tx('crud.bulk.cancelRequested') : tx('crud.bulk.tracking') }}</p>
|
|
2329
|
+
}
|
|
2330
|
+
@if (canCancelExecution() || cancellingExecution()) {
|
|
2331
|
+
<button mat-stroked-button color="warn" type="button"
|
|
2332
|
+
(click)="onCancelActiveExecution()" [disabled]="cancellingExecution()">
|
|
2333
|
+
{{ cancellingExecution() ? tx('crud.bulk.requestingCancel') : tx('crud.bulk.cancelRequest') }}
|
|
2072
2334
|
</button>
|
|
2073
2335
|
}
|
|
2074
2336
|
</div>
|
|
@@ -2144,7 +2406,7 @@ class PraxisBulkEditDialogComponent {
|
|
|
2144
2406
|
</div>
|
|
2145
2407
|
}
|
|
2146
2408
|
|
|
2147
|
-
@if (errorMessage()) {
|
|
2409
|
+
@if (errorMessage() && !trackingUnavailable()) {
|
|
2148
2410
|
<div class="praxis-bulk-edit-dialog__alert praxis-bulk-edit-dialog__alert--error">
|
|
2149
2411
|
<mat-icon>error</mat-icon>
|
|
2150
2412
|
<div class="alert-content">
|
|
@@ -2211,7 +2473,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
2211
2473
|
<p id="praxis-bulk-edit-dialog-subtitle" class="praxis-bulk-edit-dialog__subtitle">{{ dialogSubtitle }}</p>
|
|
2212
2474
|
</div>
|
|
2213
2475
|
</div>
|
|
2214
|
-
<button mat-icon-button (click)="onCancel()" [disabled]="step() === 'CONFIRMING'" aria-label="Fechar diálogo">
|
|
2476
|
+
<button mat-icon-button (click)="onCancel()" [disabled]="step() === 'CONFIRMING' && !trackingUnavailable()" aria-label="Fechar diálogo">
|
|
2215
2477
|
<mat-icon>close</mat-icon>
|
|
2216
2478
|
</button>
|
|
2217
2479
|
</div>
|
|
@@ -2448,17 +2710,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
2448
2710
|
<!-- Confirmação em Andamento -->
|
|
2449
2711
|
@if (step() === 'CONFIRMING') {
|
|
2450
2712
|
<div class="praxis-bulk-edit-dialog__loading">
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2713
|
+
@if (trackingUnavailable()) {
|
|
2714
|
+
<div role="alert">
|
|
2715
|
+
<strong>{{ tx('crud.bulk.trackingUnavailable') }}</strong>
|
|
2716
|
+
<p>{{ tx('crud.bulk.effectsMayExist') }}</p>
|
|
2717
|
+
</div>
|
|
2718
|
+
<button mat-stroked-button type="button" data-testid="bulk-execution-resume" (click)="resumeTracking()">
|
|
2719
|
+
{{ tx('crud.bulk.resumeTracking') }}
|
|
2720
|
+
</button>
|
|
2721
|
+
<button mat-button type="button" (click)="onCancel()">{{ tx('crud.bulk.closeUnknown') }}</button>
|
|
2722
|
+
} @else {
|
|
2723
|
+
<mat-spinner diameter="40" />
|
|
2724
|
+
<p role="status">{{ execution()?.status === 'CANCEL_REQUESTED' ? tx('crud.bulk.cancelRequested') : tx('crud.bulk.tracking') }}</p>
|
|
2725
|
+
}
|
|
2726
|
+
@if (canCancelExecution() || cancellingExecution()) {
|
|
2727
|
+
<button mat-stroked-button color="warn" type="button"
|
|
2728
|
+
(click)="onCancelActiveExecution()" [disabled]="cancellingExecution()">
|
|
2729
|
+
{{ cancellingExecution() ? tx('crud.bulk.requestingCancel') : tx('crud.bulk.cancelRequest') }}
|
|
2462
2730
|
</button>
|
|
2463
2731
|
}
|
|
2464
2732
|
</div>
|
|
@@ -2534,7 +2802,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
2534
2802
|
</div>
|
|
2535
2803
|
}
|
|
2536
2804
|
|
|
2537
|
-
@if (errorMessage()) {
|
|
2805
|
+
@if (errorMessage() && !trackingUnavailable()) {
|
|
2538
2806
|
<div class="praxis-bulk-edit-dialog__alert praxis-bulk-edit-dialog__alert--error">
|
|
2539
2807
|
<mat-icon>error</mat-icon>
|
|
2540
2808
|
<div class="alert-content">
|
|
@@ -4170,95 +4438,6 @@ function assertCrudMetadata(meta, options = {}) {
|
|
|
4170
4438
|
});
|
|
4171
4439
|
}
|
|
4172
4440
|
|
|
4173
|
-
const PRAXIS_CRUD_RUNTIME_I18N_NAMESPACE = 'praxisCrudRuntime';
|
|
4174
|
-
const PRAXIS_CRUD_RUNTIME_I18N_CONFIG = {
|
|
4175
|
-
namespaces: {
|
|
4176
|
-
[PRAXIS_CRUD_RUNTIME_I18N_NAMESPACE]: {
|
|
4177
|
-
'pt-BR': {
|
|
4178
|
-
'crud.emptyState.title': 'Conecte o CRUD a um recurso',
|
|
4179
|
-
'crud.emptyState.description': 'Informe os metadados (resourcePath / schema) ou forneça metadata.data para habilitar a tabela e as ações.',
|
|
4180
|
-
'crud.emptyState.primaryAction': 'Configurar metadados',
|
|
4181
|
-
'crud.table.emptyState.initial.title': 'Sem registros em {label}',
|
|
4182
|
-
'crud.table.emptyState.initial.titleFallback': 'Nenhum registro disponível.',
|
|
4183
|
-
'crud.table.emptyState.initial.descriptionWithToolbarAction': 'Use "{action}" na barra da tabela para adicionar o primeiro registro quando houver informações para cadastrar.',
|
|
4184
|
-
'crud.table.emptyState.filtered.title': 'Nenhum resultado encontrado.',
|
|
4185
|
-
'crud.table.emptyState.filtered.description': 'Revise os filtros ou ajuste o termo de busca.',
|
|
4186
|
-
'crud.preferences.resetSuccess': 'Overrides de CRUD redefinidos',
|
|
4187
|
-
'crud.actions.create': 'Adicionar',
|
|
4188
|
-
'crud.actions.view': 'Ver',
|
|
4189
|
-
'crud.actions.edit': 'Editar',
|
|
4190
|
-
'crud.actions.delete': 'Excluir',
|
|
4191
|
-
'crud.actions.default': 'ação',
|
|
4192
|
-
'crud.actions.opening': 'Abrindo {action}…',
|
|
4193
|
-
'crud.surface.openFailed': 'Não foi possível abrir {title}. Tente novamente ou confirme se esse recurso continua disponível.',
|
|
4194
|
-
'crud.dialog.recordContextLabel': 'Registro em edição',
|
|
4195
|
-
'crud.dialog.viewRecordContextLabel': 'Registro em consulta',
|
|
4196
|
-
'crud.dialog.relatedContextLabel': 'Vinculado a',
|
|
4197
|
-
'crud.delete.confirmMessage': 'Esta ação não pode ser desfeita. Deseja continuar?',
|
|
4198
|
-
'crud.delete.cancel': 'Cancelar',
|
|
4199
|
-
},
|
|
4200
|
-
'en-US': {
|
|
4201
|
-
'crud.emptyState.title': 'Connect CRUD to a resource',
|
|
4202
|
-
'crud.emptyState.description': 'Provide metadata (resourcePath / schema) or metadata.data to enable the table and actions.',
|
|
4203
|
-
'crud.emptyState.primaryAction': 'Configure metadata',
|
|
4204
|
-
'crud.table.emptyState.initial.title': 'No records in {label}',
|
|
4205
|
-
'crud.table.emptyState.initial.titleFallback': 'No records available.',
|
|
4206
|
-
'crud.table.emptyState.initial.descriptionWithToolbarAction': 'Use "{action}" in the table toolbar to add the first record when there is information to register.',
|
|
4207
|
-
'crud.table.emptyState.filtered.title': 'No results found.',
|
|
4208
|
-
'crud.table.emptyState.filtered.description': 'Review the filters or adjust the search term.',
|
|
4209
|
-
'crud.preferences.resetSuccess': 'CRUD overrides reset',
|
|
4210
|
-
'crud.actions.create': 'Add',
|
|
4211
|
-
'crud.actions.view': 'View',
|
|
4212
|
-
'crud.actions.edit': 'Edit',
|
|
4213
|
-
'crud.actions.delete': 'Delete',
|
|
4214
|
-
'crud.actions.default': 'action',
|
|
4215
|
-
'crud.actions.opening': 'Opening {action}…',
|
|
4216
|
-
'crud.surface.openFailed': 'Could not open {title}. Try again or confirm that this resource is still available.',
|
|
4217
|
-
'crud.dialog.recordContextLabel': 'Record being edited',
|
|
4218
|
-
'crud.dialog.viewRecordContextLabel': 'Record being viewed',
|
|
4219
|
-
'crud.dialog.relatedContextLabel': 'Related to',
|
|
4220
|
-
'crud.delete.confirmMessage': 'This action cannot be undone. Do you want to continue?',
|
|
4221
|
-
'crud.delete.cancel': 'Cancel',
|
|
4222
|
-
},
|
|
4223
|
-
},
|
|
4224
|
-
},
|
|
4225
|
-
};
|
|
4226
|
-
function getCrudRuntimeDictionary(locale) {
|
|
4227
|
-
const dictionaries = PRAXIS_CRUD_RUNTIME_I18N_CONFIG.namespaces?.[PRAXIS_CRUD_RUNTIME_I18N_NAMESPACE];
|
|
4228
|
-
if (!dictionaries) {
|
|
4229
|
-
return undefined;
|
|
4230
|
-
}
|
|
4231
|
-
const normalized = String(locale || '').trim();
|
|
4232
|
-
const candidates = [
|
|
4233
|
-
normalized,
|
|
4234
|
-
normalized.toLowerCase(),
|
|
4235
|
-
normalized.includes('-') ? normalized.split('-')[0] : '',
|
|
4236
|
-
normalized.includes('_') ? normalized.split('_')[0] : '',
|
|
4237
|
-
'pt-BR',
|
|
4238
|
-
'pt-br',
|
|
4239
|
-
'en-US',
|
|
4240
|
-
'en-us',
|
|
4241
|
-
].filter(Boolean);
|
|
4242
|
-
for (const candidate of candidates) {
|
|
4243
|
-
const dictionary = dictionaries[candidate];
|
|
4244
|
-
if (dictionary && typeof dictionary === 'object') {
|
|
4245
|
-
return dictionary;
|
|
4246
|
-
}
|
|
4247
|
-
}
|
|
4248
|
-
return undefined;
|
|
4249
|
-
}
|
|
4250
|
-
function resolveCrudRuntimeFallback(key, locale) {
|
|
4251
|
-
return getCrudRuntimeDictionary(locale || 'pt-BR')?.[key];
|
|
4252
|
-
}
|
|
4253
|
-
function translateCrudRuntimeText(i18n, key, fallback, params, locale) {
|
|
4254
|
-
const effectiveLocale = locale || i18n.getLocale?.() || i18n.getFallbackLocale?.() || 'pt-BR';
|
|
4255
|
-
const runtimeFallback = resolveCrudRuntimeFallback(key, effectiveLocale)
|
|
4256
|
-
|| resolveCrudRuntimeFallback(key, i18n.getFallbackLocale?.())
|
|
4257
|
-
|| fallback
|
|
4258
|
-
|| key;
|
|
4259
|
-
return i18n.t(key, params, runtimeFallback, PRAXIS_CRUD_RUNTIME_I18N_NAMESPACE);
|
|
4260
|
-
}
|
|
4261
|
-
|
|
4262
4441
|
const PRAXIS_CRUD_AUTHORING_I18N_NAMESPACE = 'praxisCrudAuthoring';
|
|
4263
4442
|
const PRAXIS_CRUD_AUTHORING_I18N_CONFIG = {
|
|
4264
4443
|
namespaces: {
|
|
@@ -13351,8 +13530,8 @@ function lowerFirstLetter(value) {
|
|
|
13351
13530
|
}
|
|
13352
13531
|
|
|
13353
13532
|
var dynamicFormDialogHost_component = /*#__PURE__*/Object.freeze({
|
|
13354
|
-
|
|
13355
|
-
|
|
13533
|
+
__proto__: null,
|
|
13534
|
+
DynamicFormDialogHostComponent: DynamicFormDialogHostComponent
|
|
13356
13535
|
});
|
|
13357
13536
|
|
|
13358
13537
|
class PraxisCrudWidgetConfigEditor {
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisui/crud",
|
|
3
|
-
"version": "10.0.0-rc.
|
|
3
|
+
"version": "10.0.0-rc.26",
|
|
4
4
|
"description": "CRUD building blocks for Praxis UI: integrates dynamic forms and tables with unified configuration and services.",
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"@angular/common": "^21.0.0",
|
|
7
7
|
"@angular/core": "^21.0.0",
|
|
8
|
-
"@praxisui/dynamic-form": "^10.0.0-rc.
|
|
9
|
-
"@praxisui/table": "^10.0.0-rc.
|
|
10
|
-
"@praxisui/core": "^10.0.0-rc.
|
|
11
|
-
"@praxisui/dynamic-fields": "^10.0.0-rc.
|
|
12
|
-
"@praxisui/settings-panel": "^10.0.0-rc.
|
|
8
|
+
"@praxisui/dynamic-form": "^10.0.0-rc.26",
|
|
9
|
+
"@praxisui/table": "^10.0.0-rc.26",
|
|
10
|
+
"@praxisui/core": "^10.0.0-rc.26",
|
|
11
|
+
"@praxisui/dynamic-fields": "^10.0.0-rc.26",
|
|
12
|
+
"@praxisui/settings-panel": "^10.0.0-rc.26",
|
|
13
13
|
"@angular/cdk": "^21.0.0",
|
|
14
14
|
"@angular/forms": "^21.0.0",
|
|
15
15
|
"@angular/material": "^21.0.0",
|
|
16
16
|
"@angular/router": "^21.0.0",
|
|
17
|
-
"@praxisui/ai": "^10.0.0-rc.
|
|
17
|
+
"@praxisui/ai": "^10.0.0-rc.26",
|
|
18
18
|
"rxjs": "~7.8.0"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
package/types/praxisui-crud.d.ts
CHANGED
|
@@ -1291,6 +1291,11 @@ declare class PraxisBulkOperationDialogComponent implements OnInit {
|
|
|
1291
1291
|
private readonly dialogRef;
|
|
1292
1292
|
private readonly bulkClient;
|
|
1293
1293
|
private readonly destroyRef;
|
|
1294
|
+
private readonly i18n;
|
|
1295
|
+
protected readonly trackingUnavailable: _angular_core.WritableSignal<boolean>;
|
|
1296
|
+
private trackingSubscription;
|
|
1297
|
+
private executionGeneration;
|
|
1298
|
+
private trackingClosed;
|
|
1294
1299
|
parametersForm?: PraxisDynamicForm;
|
|
1295
1300
|
readonly step: _angular_core.WritableSignal<BulkDialogStep>;
|
|
1296
1301
|
readonly proposal: _angular_core.WritableSignal<_praxisui_core.BulkProposal | null>;
|
|
@@ -1330,6 +1335,13 @@ declare class PraxisBulkOperationDialogComponent implements OnInit {
|
|
|
1330
1335
|
onEvaluate(): void;
|
|
1331
1336
|
loadProposalResults(cursor?: string): void;
|
|
1332
1337
|
onConfirm(): void;
|
|
1338
|
+
private executionRequestOptions;
|
|
1339
|
+
private isCurrentExecution;
|
|
1340
|
+
private stopExecutionTracking;
|
|
1341
|
+
private markTrackingUnavailable;
|
|
1342
|
+
private startExecutionTracking;
|
|
1343
|
+
protected resumeTracking(): void;
|
|
1344
|
+
protected tx(key: string): string;
|
|
1333
1345
|
private finalizeExecution;
|
|
1334
1346
|
loadExecutionResults(cursor?: string): void;
|
|
1335
1347
|
canCancelExecution(): boolean;
|
|
@@ -1365,6 +1377,11 @@ declare class PraxisBulkEditDialogComponent {
|
|
|
1365
1377
|
private readonly dialogRef;
|
|
1366
1378
|
private readonly bulkClient;
|
|
1367
1379
|
private readonly destroyRef;
|
|
1380
|
+
private readonly i18n;
|
|
1381
|
+
protected readonly trackingUnavailable: _angular_core.WritableSignal<boolean>;
|
|
1382
|
+
private trackingSubscription;
|
|
1383
|
+
private executionGeneration;
|
|
1384
|
+
private trackingClosed;
|
|
1368
1385
|
readonly step: _angular_core.WritableSignal<BulkEditStep>;
|
|
1369
1386
|
readonly fieldRows: _angular_core.WritableSignal<EditableFieldRow[]>;
|
|
1370
1387
|
readonly proposal: _angular_core.WritableSignal<_praxisui_core.BulkProposal | null>;
|
|
@@ -1414,6 +1431,13 @@ declare class PraxisBulkEditDialogComponent {
|
|
|
1414
1431
|
onEvaluate(): void;
|
|
1415
1432
|
loadProposalResults(cursor?: string): void;
|
|
1416
1433
|
onConfirm(): void;
|
|
1434
|
+
private executionRequestOptions;
|
|
1435
|
+
private isCurrentExecution;
|
|
1436
|
+
private stopExecutionTracking;
|
|
1437
|
+
private markTrackingUnavailable;
|
|
1438
|
+
private startExecutionTracking;
|
|
1439
|
+
protected resumeTracking(): void;
|
|
1440
|
+
protected tx(key: string): string;
|
|
1417
1441
|
private finalizeExecution;
|
|
1418
1442
|
loadExecutionResults(cursor?: string): void;
|
|
1419
1443
|
canCancelExecution(): boolean;
|