@masterteam/work-center 0.0.78 → 0.0.80
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.
|
@@ -12,10 +12,10 @@ import { StatisticCard } from '@masterteam/components/statistic-card';
|
|
|
12
12
|
import { Table } from '@masterteam/components/table';
|
|
13
13
|
import * as i1$1 from 'primeng/skeleton';
|
|
14
14
|
import { SkeletonModule } from 'primeng/skeleton';
|
|
15
|
-
import { catchError, EMPTY, map, take } from 'rxjs';
|
|
15
|
+
import { catchError, EMPTY, map, take, firstValueFrom, of } from 'rxjs';
|
|
16
16
|
import { ModalRef } from '@masterteam/components/dialog';
|
|
17
17
|
import { DrawerController } from '@masterteam/components/dynamic-drawer';
|
|
18
|
-
import { ClientForm } from '@masterteam/forms/client-form';
|
|
18
|
+
import { ClientForm, ClientFormWarningsDialog, ClientFormApiService } from '@masterteam/forms/client-form';
|
|
19
19
|
import { HttpClient } from '@angular/common/http';
|
|
20
20
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
21
21
|
import { Drawer } from '@masterteam/components/drawer';
|
|
@@ -27,7 +27,7 @@ import { EntitiesPreview, EntityPreviewBody } from '@masterteam/components/entit
|
|
|
27
27
|
import { Tabs } from '@masterteam/components/tabs';
|
|
28
28
|
import { DiscussionThread } from '@masterteam/discussion';
|
|
29
29
|
import { StructureBuilder } from '@masterteam/structure-builder';
|
|
30
|
-
import {
|
|
30
|
+
import { Icon } from '@masterteam/icons';
|
|
31
31
|
|
|
32
32
|
class WorkCenterClientFormModal {
|
|
33
33
|
modal = inject(ModalService);
|
|
@@ -93,7 +93,7 @@ class WorkCenterClientFormModal {
|
|
|
93
93
|
return undefined;
|
|
94
94
|
}
|
|
95
95
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterClientFormModal, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
96
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterClientFormModal, isStandalone: true, selector: "mt-work-center-client-form-modal", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, operationKey: { classPropertyName: "operationKey", publicName: "operationKey", isSignal: true, isRequired: false, transformFunction: null }, closeOnPendingApproval: { classPropertyName: "closeOnPendingApproval", publicName: "closeOnPendingApproval", isSignal: true, isRequired: false, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "processForm", first: true, predicate: ClientForm, descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'workCenter'\">\r\n <div [class]=\"modal.contentClass + ' p-5 flex flex-col gap-4'\">\r\n <mt-client-form\r\n [moduleKey]=\"moduleKey()\"\r\n [moduleId]=\"moduleId()\"\r\n [operationKey]=\"operationKey()\"\r\n [levelId]=\"levelId()\"\r\n [levelDataId]=\"levelDataId()\"\r\n [moduleDataId]=\"moduleDataId()\"\r\n [formMode]=\"formMode()\"\r\n [autoLoad]=\"true\"\r\n [lookups]=\"lookups()\"\r\n (submitted)=\"onSubmitted($event)\"\r\n (errored)=\"onErrored($event)\"\r\n />\r\n\r\n @if (isSubmitting()) {\r\n <div class=\"text-sm text-muted-color\">{{ t(\"modal.submitting\") }}</div>\r\n }\r\n\r\n @if (validationMessage()) {\r\n <div\r\n class=\"mt-2 rounded-lg border border-amber-200 bg-amber-50 p-3 text-sm text-amber-700\"\r\n role=\"alert\"\r\n >\r\n {{ validationMessage() }}\r\n </div>\r\n }\r\n\r\n @if (submitError()) {\r\n <div\r\n class=\"mt-2 rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-700\"\r\n role=\"alert\"\r\n >\r\n {{ submitError() }}\r\n </div>\r\n }\r\n\r\n @if (submitStatus(); as status) {\r\n <div\r\n class=\"mt-2 rounded-lg border p-3 text-sm\"\r\n [class]=\"\r\n status === 'pending'\r\n ? 'border-amber-200 bg-amber-50 text-amber-700'\r\n : 'border-emerald-200 bg-emerald-50 text-emerald-700'\r\n \"\r\n >\r\n @if (status === \"pending\") {\r\n {{ t(\"modal.requestSubmitted\") }}\r\n } @else {\r\n {{ t(\"modal.operationExecuted\") }}\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n [label]=\"t('modal.cancel')\"\r\n variant=\"outlined\"\r\n [disabled]=\"isSubmitting()\"\r\n (onClick)=\"ref.close(false)\"\r\n />\r\n <mt-button\r\n [label]=\"t('modal.submit')\"\r\n icon=\"general.check\"\r\n [disabled]=\"\r\n isSubmitting() || processForm().hasBlockingGovernanceFailure()\r\n \"\r\n (onClick)=\"onSubmit()\"\r\n />\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: ClientForm, selector: "mt-client-form", inputs: ["moduleKey", "operationKey", "moduleId", "levelId", "levelDataId", "moduleDataId", "requestSchemaId", "draftProcessId", "templateId", "preview", "forceOriginalForm", "returnUrl", "defaultValues", "submitRequestMapper", "submitTransport", "readonly", "autoLoad", "formMode", "renderMode", "showInternalStepActions", "confirmWarningsOnSubmit", "confirmWarningsOnStepChange", "silentMessages", "readonlyFieldDisplayMode", "lookups", "statuses", "ignoredFieldKeys", "disabledFieldKeys", "allowedFieldKeys"], outputs: ["loaded", "submitted", "errored", "modeDetected", "formSourceDetected", "footerStateChanged"] }] });
|
|
96
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterClientFormModal, isStandalone: true, selector: "mt-work-center-client-form-modal", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, operationKey: { classPropertyName: "operationKey", publicName: "operationKey", isSignal: true, isRequired: false, transformFunction: null }, closeOnPendingApproval: { classPropertyName: "closeOnPendingApproval", publicName: "closeOnPendingApproval", isSignal: true, isRequired: false, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "processForm", first: true, predicate: ClientForm, descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'workCenter'\">\r\n <div [class]=\"modal.contentClass + ' p-5 flex flex-col gap-4'\">\r\n <mt-client-form\r\n [moduleKey]=\"moduleKey()\"\r\n [moduleId]=\"moduleId()\"\r\n [operationKey]=\"operationKey()\"\r\n [levelId]=\"levelId()\"\r\n [levelDataId]=\"levelDataId()\"\r\n [moduleDataId]=\"moduleDataId()\"\r\n [formMode]=\"formMode()\"\r\n [autoLoad]=\"true\"\r\n [lookups]=\"lookups()\"\r\n (submitted)=\"onSubmitted($event)\"\r\n (errored)=\"onErrored($event)\"\r\n />\r\n\r\n @if (isSubmitting()) {\r\n <div class=\"text-sm text-muted-color\">{{ t(\"modal.submitting\") }}</div>\r\n }\r\n\r\n @if (validationMessage()) {\r\n <div\r\n class=\"mt-2 rounded-lg border border-amber-200 bg-amber-50 p-3 text-sm text-amber-700\"\r\n role=\"alert\"\r\n >\r\n {{ validationMessage() }}\r\n </div>\r\n }\r\n\r\n @if (submitError()) {\r\n <div\r\n class=\"mt-2 rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-700\"\r\n role=\"alert\"\r\n >\r\n {{ submitError() }}\r\n </div>\r\n }\r\n\r\n @if (submitStatus(); as status) {\r\n <div\r\n class=\"mt-2 rounded-lg border p-3 text-sm\"\r\n [class]=\"\r\n status === 'pending'\r\n ? 'border-amber-200 bg-amber-50 text-amber-700'\r\n : 'border-emerald-200 bg-emerald-50 text-emerald-700'\r\n \"\r\n >\r\n @if (status === \"pending\") {\r\n {{ t(\"modal.requestSubmitted\") }}\r\n } @else {\r\n {{ t(\"modal.operationExecuted\") }}\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n [label]=\"t('modal.cancel')\"\r\n variant=\"outlined\"\r\n [disabled]=\"isSubmitting()\"\r\n (onClick)=\"ref.close(false)\"\r\n />\r\n <mt-button\r\n [label]=\"t('modal.submit')\"\r\n icon=\"general.check\"\r\n [disabled]=\"\r\n isSubmitting() || processForm().hasBlockingGovernanceFailure()\r\n \"\r\n (onClick)=\"onSubmit()\"\r\n />\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: ClientForm, selector: "mt-client-form", inputs: ["moduleKey", "operationKey", "moduleId", "levelId", "levelDataId", "moduleDataId", "requestSchemaId", "draftProcessId", "templateId", "preview", "forceOriginalForm", "returnUrl", "defaultValues", "submitRequestMapper", "submitTransport", "readonly", "autoLoad", "formMode", "renderMode", "showInternalStepActions", "confirmWarningsOnSubmit", "confirmWarningsOnStepChange", "silentMessages", "hostMessages", "readonlyFieldDisplayMode", "lookups", "statuses", "ignoredFieldKeys", "disabledFieldKeys", "allowedFieldKeys"], outputs: ["loaded", "submitted", "errored", "modeDetected", "formSourceDetected", "footerStateChanged"] }] });
|
|
97
97
|
}
|
|
98
98
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterClientFormModal, decorators: [{
|
|
99
99
|
type: Component,
|
|
@@ -1320,6 +1320,58 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
1320
1320
|
}]
|
|
1321
1321
|
}] });
|
|
1322
1322
|
|
|
1323
|
+
/**
|
|
1324
|
+
* The channel between the client form in the modal body and the action footer,
|
|
1325
|
+
* route-scoped alongside `RuntimeActionContextStore`. It carries three things
|
|
1326
|
+
* in both directions:
|
|
1327
|
+
*
|
|
1328
|
+
* - the form's submit context, for the validate pre-flight;
|
|
1329
|
+
* - whether the form is locally complete, so the footer can gate its actions;
|
|
1330
|
+
* - the failure messages of the last action, so they can be rendered above the
|
|
1331
|
+
* form instead of squeezed beside the buttons.
|
|
1332
|
+
*/
|
|
1333
|
+
class WorkCenterActionFormStore {
|
|
1334
|
+
formContext = signal(null, ...(ngDevMode ? [{ debugName: "formContext" }] : /* istanbul ignore next */ []));
|
|
1335
|
+
formIncomplete = signal(false, ...(ngDevMode ? [{ debugName: "formIncomplete" }] : /* istanbul ignore next */ []));
|
|
1336
|
+
actionErrors = signal([], ...(ngDevMode ? [{ debugName: "actionErrors" }] : /* istanbul ignore next */ []));
|
|
1337
|
+
errorHosted = signal(false, ...(ngDevMode ? [{ debugName: "errorHosted" }] : /* istanbul ignore next */ []));
|
|
1338
|
+
context = this.formContext.asReadonly();
|
|
1339
|
+
/**
|
|
1340
|
+
* True while the on-screen form fails its own local validation — a required
|
|
1341
|
+
* field left empty, a formula error. The footer disables the actions that
|
|
1342
|
+
* commit those values rather than letting them fail server-side, since a
|
|
1343
|
+
* blocked round trip tells the approver nothing the form is not already
|
|
1344
|
+
* showing next to the offending field.
|
|
1345
|
+
*/
|
|
1346
|
+
incomplete = this.formIncomplete.asReadonly();
|
|
1347
|
+
/** One entry per failing rule; see `WorkCenterFormValidationError`. */
|
|
1348
|
+
errors = this.actionErrors.asReadonly();
|
|
1349
|
+
/**
|
|
1350
|
+
* Set while the modal body is showing the messages itself — the type
|
|
1351
|
+
* components hand them to `mt-client-form`, which renders them in its own
|
|
1352
|
+
* validation summary. The footer keeps its copy only when nothing else
|
|
1353
|
+
* claims them, so an item type with no form still reports a failure.
|
|
1354
|
+
*/
|
|
1355
|
+
hasErrorHost = this.errorHosted.asReadonly();
|
|
1356
|
+
setContext(context) {
|
|
1357
|
+
this.formContext.set(context);
|
|
1358
|
+
}
|
|
1359
|
+
setIncomplete(incomplete) {
|
|
1360
|
+
this.formIncomplete.set(incomplete);
|
|
1361
|
+
}
|
|
1362
|
+
setErrors(messages) {
|
|
1363
|
+
this.actionErrors.set(messages);
|
|
1364
|
+
}
|
|
1365
|
+
setErrorHost(hosted) {
|
|
1366
|
+
this.errorHosted.set(hosted);
|
|
1367
|
+
}
|
|
1368
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterActionFormStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1369
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterActionFormStore });
|
|
1370
|
+
}
|
|
1371
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterActionFormStore, decorators: [{
|
|
1372
|
+
type: Injectable
|
|
1373
|
+
}] });
|
|
1374
|
+
|
|
1323
1375
|
function readItemContext(details) {
|
|
1324
1376
|
const item = details.item;
|
|
1325
1377
|
if (!item || typeof item !== 'object') {
|
|
@@ -1740,7 +1792,7 @@ class WorkCenterModuleType {
|
|
|
1740
1792
|
this.actionContext?.setFormSource(null);
|
|
1741
1793
|
}
|
|
1742
1794
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterModuleType, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1743
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterModuleType, isStandalone: true, selector: "mt-work-center-module-type", inputs: { details: { classPropertyName: "details", publicName: "details", isSignal: true, isRequired: true, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "clientForm", first: true, predicate: ClientForm, descendants: true, isSignal: true }], ngImport: i0, template: "<div\r\n class=\"mt-modal-content flex h-full min-h-0 flex-col gap-4 p-4 lg:overflow-hidden\"\r\n *transloco=\"let t; prefix: 'workCenter'\"\r\n>\r\n <div\r\n class=\"flex flex-1 min-h-0 flex-col gap-4 lg:grid lg:grid-cols-[13rem_minmax(0,1fr)] lg:gap-6\"\r\n >\r\n @if (tabOptions().length > 1) {\r\n <mt-tabs\r\n [(active)]=\"activeTab\"\r\n [options]=\"tabOptions()\"\r\n mode=\"vertical\"\r\n size=\"small\"\r\n />\r\n }\r\n\r\n <div class=\"min-w-0 flex-1 min-h-0 lg:overflow-hidden\">\r\n <div\r\n class=\"h-full min-h-0 lg:overflow-hidden\"\r\n [hidden]=\"activeTab() !== 'details'\"\r\n >\r\n <div\r\n class=\"min-w-0 h-full min-h-0 lg:overflow-y-auto lg:overscroll-contain lg:pr-2\"\r\n >\r\n @if (canRenderForm()) {\r\n <mt-client-form\r\n [moduleKey]=\"moduleKey()\"\r\n [operationKey]=\"operationKey()\"\r\n [moduleId]=\"formModuleId()\"\r\n [levelId]=\"formLevelId()\"\r\n [levelDataId]=\"formLevelDataId()\"\r\n [moduleDataId]=\"moduleDataId()\"\r\n [readonly]=\"true\"\r\n [lookups]=\"formLookups()\"\r\n />\r\n } @else {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n {{ t(\"context.moduleFormUnavailable\") }}\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (!readOnly()) {\r\n <div\r\n class=\"h-full min-h-0 overflow-hidden\"\r\n [hidden]=\"activeTab() !== 'discussion'\"\r\n >\r\n @if (canRenderDiscussion()) {\r\n <div\r\n class=\"h-[32rem] min-h-[22rem] overflow-hidden rounded-lg border border-surface-200 bg-surface-50 lg:h-full lg:min-h-0\"\r\n >\r\n <mt-discussion-thread\r\n [moduleType]=\"discussionModuleType()\"\r\n [recordId]=\"resolvedInstanceId()\"\r\n [mentionSearchEndpoint]=\"'Identity/users'\"\r\n [mentionSearchParam]=\"'query'\"\r\n [mentionSearchDataPath]=\"'data'\"\r\n [uploadEndpoint]=\"'uploader'\"\r\n [attachmentDownloadEndpoint]=\"'uploader'\"\r\n [showParticipants]=\"true\"\r\n [autoMarkRead]=\"true\"\r\n [refreshIntervalMs]=\"0\"\r\n [styleClass]=\"'h-full'\"\r\n />\r\n </div>\r\n } @else {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n {{ t(\"context.moduleDiscussionUnavailable\") }}\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: ClientForm, selector: "mt-client-form", inputs: ["moduleKey", "operationKey", "moduleId", "levelId", "levelDataId", "moduleDataId", "requestSchemaId", "draftProcessId", "templateId", "preview", "forceOriginalForm", "returnUrl", "defaultValues", "submitRequestMapper", "submitTransport", "readonly", "autoLoad", "formMode", "renderMode", "showInternalStepActions", "confirmWarningsOnSubmit", "confirmWarningsOnStepChange", "silentMessages", "readonlyFieldDisplayMode", "lookups", "statuses", "ignoredFieldKeys", "disabledFieldKeys", "allowedFieldKeys"], outputs: ["loaded", "submitted", "errored", "modeDetected", "formSourceDetected", "footerStateChanged"] }, { kind: "component", type: DiscussionThread, selector: "mt-discussion-thread", inputs: ["moduleType", "recordId", "title", "subtitle", "placeholder", "pageSize", "currentUserId", "requestContext", "mentionableUsers", "mentionSearchEndpoint", "mentionSearchParam", "mentionSearchDataPath", "allowAttachments", "uploadEndpoint", "attachmentDownloadEndpoint", "showParticipants", "autoMarkRead", "refreshIntervalMs", "styleClass", "disabled"], outputs: ["loaded", "errored", "commentCreated", "commentUpdated", "commentDeleted", "readStateChanged"] }] });
|
|
1795
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterModuleType, isStandalone: true, selector: "mt-work-center-module-type", inputs: { details: { classPropertyName: "details", publicName: "details", isSignal: true, isRequired: true, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "clientForm", first: true, predicate: ClientForm, descendants: true, isSignal: true }], ngImport: i0, template: "<div\r\n class=\"mt-modal-content flex h-full min-h-0 flex-col gap-4 p-4 lg:overflow-hidden\"\r\n *transloco=\"let t; prefix: 'workCenter'\"\r\n>\r\n <div\r\n class=\"flex flex-1 min-h-0 flex-col gap-4 lg:grid lg:grid-cols-[13rem_minmax(0,1fr)] lg:gap-6\"\r\n >\r\n @if (tabOptions().length > 1) {\r\n <mt-tabs\r\n [(active)]=\"activeTab\"\r\n [options]=\"tabOptions()\"\r\n mode=\"vertical\"\r\n size=\"small\"\r\n />\r\n }\r\n\r\n <div class=\"min-w-0 flex-1 min-h-0 lg:overflow-hidden\">\r\n <div\r\n class=\"h-full min-h-0 lg:overflow-hidden\"\r\n [hidden]=\"activeTab() !== 'details'\"\r\n >\r\n <div\r\n class=\"min-w-0 h-full min-h-0 lg:overflow-y-auto lg:overscroll-contain lg:pr-2\"\r\n >\r\n @if (canRenderForm()) {\r\n <mt-client-form\r\n [moduleKey]=\"moduleKey()\"\r\n [operationKey]=\"operationKey()\"\r\n [moduleId]=\"formModuleId()\"\r\n [levelId]=\"formLevelId()\"\r\n [levelDataId]=\"formLevelDataId()\"\r\n [moduleDataId]=\"moduleDataId()\"\r\n [readonly]=\"true\"\r\n [lookups]=\"formLookups()\"\r\n />\r\n } @else {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n {{ t(\"context.moduleFormUnavailable\") }}\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (!readOnly()) {\r\n <div\r\n class=\"h-full min-h-0 overflow-hidden\"\r\n [hidden]=\"activeTab() !== 'discussion'\"\r\n >\r\n @if (canRenderDiscussion()) {\r\n <div\r\n class=\"h-[32rem] min-h-[22rem] overflow-hidden rounded-lg border border-surface-200 bg-surface-50 lg:h-full lg:min-h-0\"\r\n >\r\n <mt-discussion-thread\r\n [moduleType]=\"discussionModuleType()\"\r\n [recordId]=\"resolvedInstanceId()\"\r\n [mentionSearchEndpoint]=\"'Identity/users'\"\r\n [mentionSearchParam]=\"'query'\"\r\n [mentionSearchDataPath]=\"'data'\"\r\n [uploadEndpoint]=\"'uploader'\"\r\n [attachmentDownloadEndpoint]=\"'uploader'\"\r\n [showParticipants]=\"true\"\r\n [autoMarkRead]=\"true\"\r\n [refreshIntervalMs]=\"0\"\r\n [styleClass]=\"'h-full'\"\r\n />\r\n </div>\r\n } @else {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n {{ t(\"context.moduleDiscussionUnavailable\") }}\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: ClientForm, selector: "mt-client-form", inputs: ["moduleKey", "operationKey", "moduleId", "levelId", "levelDataId", "moduleDataId", "requestSchemaId", "draftProcessId", "templateId", "preview", "forceOriginalForm", "returnUrl", "defaultValues", "submitRequestMapper", "submitTransport", "readonly", "autoLoad", "formMode", "renderMode", "showInternalStepActions", "confirmWarningsOnSubmit", "confirmWarningsOnStepChange", "silentMessages", "hostMessages", "readonlyFieldDisplayMode", "lookups", "statuses", "ignoredFieldKeys", "disabledFieldKeys", "allowedFieldKeys"], outputs: ["loaded", "submitted", "errored", "modeDetected", "formSourceDetected", "footerStateChanged"] }, { kind: "component", type: DiscussionThread, selector: "mt-discussion-thread", inputs: ["moduleType", "recordId", "title", "subtitle", "placeholder", "pageSize", "currentUserId", "requestContext", "mentionableUsers", "mentionSearchEndpoint", "mentionSearchParam", "mentionSearchDataPath", "allowAttachments", "uploadEndpoint", "attachmentDownloadEndpoint", "showParticipants", "autoMarkRead", "refreshIntervalMs", "styleClass", "disabled"], outputs: ["loaded", "errored", "commentCreated", "commentUpdated", "commentDeleted", "readStateChanged"] }] });
|
|
1744
1796
|
}
|
|
1745
1797
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterModuleType, decorators: [{
|
|
1746
1798
|
type: Component,
|
|
@@ -2264,7 +2316,7 @@ class WorkCenterProcessPreview {
|
|
|
2264
2316
|
});
|
|
2265
2317
|
}
|
|
2266
2318
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterProcessPreview, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2267
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterProcessPreview, isStandalone: true, selector: "mt-work-center-process-preview", inputs: { requestId: { classPropertyName: "requestId", publicName: "requestId", isSignal: true, isRequired: false, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (!canRenderPreview()) {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n Process preview is not available for this item yet.\r\n </p>\r\n </div>\r\n} @else if (loading()) {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"text-sm text-surface-500\">Loading process preview...</p>\r\n </div>\r\n} @else if (error()) {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-red-300 bg-red-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-red-600\">{{ error() }}</p>\r\n </div>\r\n} @else {\r\n @if (view() === \"schema\") {\r\n @if (hasSchema()) {\r\n <div class=\"wc-process-preview-schema h-[70vh] overflow-hidden\">\r\n <mt-structure-builder\r\n class=\"h-full\"\r\n [layoutDirection]=\"'LR'\"\r\n [readonly]=\"true\"\r\n [structureMode]=\"'workflow'\"\r\n [nodeFields]=\"previewNodeFields\"\r\n [nodes]=\"schemaNodes()\"\r\n [connections]=\"schemaConnections()\"\r\n />\r\n </div>\r\n } @else {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n Process steps are not available for this item yet.\r\n </p>\r\n </div>\r\n }\r\n } @else if (hasApprovals()) {\r\n <div class=\"max-h-[70vh] overflow-y-auto\">\r\n <mt-table\r\n noCard\r\n [data]=\"approvalRows()\"\r\n [columns]=\"approvalColumns()\"\r\n storageKey=\"work-center-process-preview-table\"\r\n [showFilters]=\"false\"\r\n [generalSearch]=\"false\"\r\n [clickableRows]=\"false\"\r\n />\r\n </div>\r\n } @else {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n Process approvals data is not available for this item yet.\r\n </p>\r\n </div>\r\n }\r\n}\r\n", styles: [":host ::ng-deep .wc-process-preview-schema .wf-detail-row{align-items:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "clickableRows", "generalSearch", "lazyLocalSearch", "showFilters", "filterMode", "loading", "updating", "lazy", "lazyLocalSort", "lazyTotalRecords", "reorderableColumns", "reorderableRows", "dataKey", "storageKey", "storageMode", "persistStateExclude", "exportable", "printable", "groupable", "groupCountMap", "cellClickFilter", "freezeActions", "virtualScroll", "virtualScrollItemSize", "scrollHeight", "printTitle", "exportFilename", "actionShape", "rowActionsLoadingFn", "tableLayout", "noCard", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "emptyTitle", "emptyDescription", "emptyActionLabel", "emptyActionIcon", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm", "groupBy", "sortField", "sortDirection"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "emptyAction", "rowActionsRequested", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange", "groupByChange", "sortFieldChange", "sortDirectionChange"] }, { kind: "component", type: StructureBuilder, selector: "mt-structure-builder", inputs: ["availableNodes", "availableNodesLabel", "nodeForm", "nodeDialogFooterConfig", "connectionForm", "connectionFormulaSchemaId", "connectionFormulaConfig", "connectionGuard", "nodeActions", "nodeFields", "isAutoLayout", "readonly", "structureMode", "nodeStyle", "addModalType", "updateModalType", "addModalStyleClass", "updateModalStyleClass", "addModalHeader", "updateModalHeader", "appendTo", "availableTabsClass", "layoutDirection", "nodes", "connections", "nodeTemplate"], outputs: ["nodeActionsEvent", "action", "nodesChange", "connectionsChange"] }] });
|
|
2319
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterProcessPreview, isStandalone: true, selector: "mt-work-center-process-preview", inputs: { requestId: { classPropertyName: "requestId", publicName: "requestId", isSignal: true, isRequired: false, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (!canRenderPreview()) {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n Process preview is not available for this item yet.\r\n </p>\r\n </div>\r\n} @else if (loading()) {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"text-sm text-surface-500\">Loading process preview...</p>\r\n </div>\r\n} @else if (error()) {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-red-300 bg-red-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-red-600\">{{ error() }}</p>\r\n </div>\r\n} @else {\r\n @if (view() === \"schema\") {\r\n @if (hasSchema()) {\r\n <div class=\"wc-process-preview-schema h-[70vh] overflow-hidden\">\r\n <mt-structure-builder\r\n class=\"h-full\"\r\n [layoutDirection]=\"'LR'\"\r\n [readonly]=\"true\"\r\n [structureMode]=\"'workflow'\"\r\n [nodeFields]=\"previewNodeFields\"\r\n [nodes]=\"schemaNodes()\"\r\n [connections]=\"schemaConnections()\"\r\n />\r\n </div>\r\n } @else {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n Process steps are not available for this item yet.\r\n </p>\r\n </div>\r\n }\r\n } @else if (hasApprovals()) {\r\n <div class=\"max-h-[70vh] overflow-y-auto\">\r\n <mt-table\r\n noCard\r\n [data]=\"approvalRows()\"\r\n [columns]=\"approvalColumns()\"\r\n storageKey=\"work-center-process-preview-table\"\r\n [showFilters]=\"false\"\r\n [generalSearch]=\"false\"\r\n [clickableRows]=\"false\"\r\n />\r\n </div>\r\n } @else {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n Process approvals data is not available for this item yet.\r\n </p>\r\n </div>\r\n }\r\n}\r\n", styles: [":host ::ng-deep .wc-process-preview-schema .wf-detail-row{align-items:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "clickableRows", "generalSearch", "lazyLocalSearch", "showFilters", "filterMode", "loading", "updating", "lazy", "lazyLocalSort", "lazyTotalRecords", "reorderableColumns", "reorderableRows", "dataKey", "storageKey", "storageMode", "persistStateExclude", "exportable", "printable", "groupable", "groupCountMap", "cellClickFilter", "freezeActions", "virtualScroll", "virtualScrollItemSize", "scrollHeight", "printTitle", "exportFilename", "actionShape", "rowActionsLoadingFn", "tableLayout", "noCard", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "captionStartTemplate", "captionEndTemplate", "emptyTitle", "emptyDescription", "emptyActionLabel", "emptyActionIcon", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm", "groupBy", "sortField", "sortDirection"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "emptyAction", "rowActionsRequested", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange", "groupByChange", "sortFieldChange", "sortDirectionChange"] }, { kind: "component", type: StructureBuilder, selector: "mt-structure-builder", inputs: ["availableNodes", "availableNodesLabel", "nodeForm", "nodeDialogFooterConfig", "connectionForm", "connectionFormulaSchemaId", "connectionFormulaConfig", "connectionGuard", "nodeActions", "nodeFields", "isAutoLayout", "readonly", "structureMode", "nodeStyle", "addModalType", "updateModalType", "addModalStyleClass", "updateModalStyleClass", "addModalHeader", "updateModalHeader", "appendTo", "availableTabsClass", "layoutDirection", "nodes", "connections", "nodeTemplate"], outputs: ["nodeActionsEvent", "action", "nodesChange", "connectionsChange"] }] });
|
|
2268
2320
|
}
|
|
2269
2321
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterProcessPreview, decorators: [{
|
|
2270
2322
|
type: Component,
|
|
@@ -2286,12 +2338,26 @@ class WorkCenterProcessRequestType {
|
|
|
2286
2338
|
actionContext = inject(RuntimeActionContextStore, {
|
|
2287
2339
|
optional: true,
|
|
2288
2340
|
});
|
|
2341
|
+
formStore = inject(WorkCenterActionFormStore, {
|
|
2342
|
+
optional: true,
|
|
2343
|
+
});
|
|
2289
2344
|
transloco = inject(TranslocoService);
|
|
2290
2345
|
destroyRef = inject(DestroyRef);
|
|
2291
2346
|
details = input.required(...(ngDevMode ? [{ debugName: "details" }] : /* istanbul ignore next */ []));
|
|
2292
2347
|
lookups = input(null, ...(ngDevMode ? [{ debugName: "lookups" }] : /* istanbul ignore next */ []));
|
|
2293
2348
|
readOnly = input(false, ...(ngDevMode ? [{ debugName: "readOnly" }] : /* istanbul ignore next */ []));
|
|
2294
2349
|
clientForm = viewChild(ClientForm, ...(ngDevMode ? [{ debugName: "clientForm" }] : /* istanbul ignore next */ []));
|
|
2350
|
+
formStatus = signal(null, ...(ngDevMode ? [{ debugName: "formStatus" }] : /* istanbul ignore next */ []));
|
|
2351
|
+
/**
|
|
2352
|
+
* The last action's failure messages, shaped for `mt-client-form` so they
|
|
2353
|
+
* render in its own validation summary — the same red `p-message` list a
|
|
2354
|
+
* rejected submit produces — instead of a panel of our own above the tabs.
|
|
2355
|
+
*/
|
|
2356
|
+
actionMessages = computed(() => (this.formStore?.errors() ?? []).map((message) => ({
|
|
2357
|
+
code: 'FORMULA_FALSE',
|
|
2358
|
+
severity: 'error',
|
|
2359
|
+
message,
|
|
2360
|
+
})), ...(ngDevMode ? [{ debugName: "actionMessages" }] : /* istanbul ignore next */ []));
|
|
2295
2361
|
formLookups = computed(() => this.lookups() ?? this.facade.lookups(), ...(ngDevMode ? [{ debugName: "formLookups" }] : /* istanbul ignore next */ []));
|
|
2296
2362
|
activeTab = signal('requestDetails', ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
|
|
2297
2363
|
activeLang = signal(this.transloco.getActiveLang(), ...(ngDevMode ? [{ debugName: "activeLang" }] : /* istanbul ignore next */ []));
|
|
@@ -2355,12 +2421,57 @@ class WorkCenterProcessRequestType {
|
|
|
2355
2421
|
effect(() => {
|
|
2356
2422
|
this.actionContext?.setFormSource(this.readOnly() ? null : (this.clientForm() ?? null));
|
|
2357
2423
|
});
|
|
2424
|
+
// See the equivalent effect in `WorkCenterProcessStepType`. Gated on
|
|
2425
|
+
// `isReadonly` rather than `readOnly`, since the request form is only
|
|
2426
|
+
// editable while the request sits in `Returned`.
|
|
2427
|
+
effect(() => {
|
|
2428
|
+
this.formStore?.setContext(this.isReadonly() || !this.canRenderForm()
|
|
2429
|
+
? null
|
|
2430
|
+
: {
|
|
2431
|
+
moduleKey: this.moduleKey(),
|
|
2432
|
+
operationKey: this.operationKey(),
|
|
2433
|
+
moduleId: this.moduleId(),
|
|
2434
|
+
levelId: this.levelId(),
|
|
2435
|
+
levelDataId: this.levelDataId(),
|
|
2436
|
+
moduleDataId: this.moduleDataId(),
|
|
2437
|
+
requestSchemaId: this.requestSchemaId(),
|
|
2438
|
+
});
|
|
2439
|
+
});
|
|
2440
|
+
// `formControl.status` is not a signal, so mirror it into one — without
|
|
2441
|
+
// this the footer would keep its stale enabled/disabled state while the
|
|
2442
|
+
// approver fills the form in.
|
|
2443
|
+
effect((onCleanup) => {
|
|
2444
|
+
const form = this.clientForm();
|
|
2445
|
+
if (!form) {
|
|
2446
|
+
this.formStatus.set(null);
|
|
2447
|
+
return;
|
|
2448
|
+
}
|
|
2449
|
+
this.formStatus.set(form.formControl.status);
|
|
2450
|
+
const subscription = form.formControl.statusChanges.subscribe((status) => this.formStatus.set(status));
|
|
2451
|
+
onCleanup(() => subscription.unsubscribe());
|
|
2452
|
+
});
|
|
2453
|
+
effect(() => {
|
|
2454
|
+
const form = this.clientForm();
|
|
2455
|
+
// Read before the guards so the effect re-runs on every status change.
|
|
2456
|
+
const status = this.formStatus();
|
|
2457
|
+
this.formStore?.setIncomplete(!this.isReadonly() && !!form && status === 'INVALID' && form.isLoaded());
|
|
2458
|
+
});
|
|
2459
|
+
// The form only draws its validation summary when it has editable sections
|
|
2460
|
+
// to draw it above; without them the footer has to keep reporting failures
|
|
2461
|
+
// itself. Claim the messages only when they will actually be shown.
|
|
2462
|
+
effect(() => {
|
|
2463
|
+
const form = this.clientForm();
|
|
2464
|
+
this.formStore?.setErrorHost(!!form && form.isLoaded() && form.hasEditableFormSections());
|
|
2465
|
+
});
|
|
2358
2466
|
}
|
|
2359
2467
|
ngOnDestroy() {
|
|
2360
2468
|
this.actionContext?.setFormSource(null);
|
|
2469
|
+
this.formStore?.setContext(null);
|
|
2470
|
+
this.formStore?.setIncomplete(false);
|
|
2471
|
+
this.formStore?.setErrorHost(false);
|
|
2361
2472
|
}
|
|
2362
2473
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterProcessRequestType, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2363
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterProcessRequestType, isStandalone: true, selector: "mt-work-center-process-request-type", inputs: { details: { classPropertyName: "details", publicName: "details", isSignal: true, isRequired: true, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "clientForm", first: true, predicate: ClientForm, descendants: true, isSignal: true }], ngImport: i0, template: "<div\
|
|
2474
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterProcessRequestType, isStandalone: true, selector: "mt-work-center-process-request-type", inputs: { details: { classPropertyName: "details", publicName: "details", isSignal: true, isRequired: true, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "clientForm", first: true, predicate: ClientForm, descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"mt-modal-content flex h-full min-h-0 flex-col gap-4 p-4 lg:overflow-hidden\"\n *transloco=\"let t; prefix: 'workCenter'\"\n>\n <div\n class=\"flex flex-1 min-h-0 flex-col gap-4 lg:grid lg:grid-cols-[13rem_minmax(0,1fr)] lg:gap-6\"\n >\n @if (tabOptions().length > 1) {\n <mt-tabs\n [(active)]=\"activeTab\"\n [options]=\"tabOptions()\"\n mode=\"vertical\"\n size=\"small\"\n />\n }\n\n <div class=\"min-w-0 flex-1 min-h-0 lg:overflow-hidden\">\n <div\n class=\"h-full min-h-0 lg:overflow-hidden\"\n [hidden]=\"activeTab() !== 'requestDetails'\"\n >\n <div\n class=\"min-w-0 h-full min-h-0 lg:overflow-y-auto lg:overscroll-contain lg:pr-2\"\n >\n @if (canRenderForm()) {\n <mt-client-form\n [moduleKey]=\"moduleKey()\"\n [operationKey]=\"operationKey()\"\n [moduleId]=\"moduleId()\"\n [levelId]=\"levelId()\"\n [levelDataId]=\"levelDataId()\"\n [moduleDataId]=\"moduleDataId()\"\n [requestSchemaId]=\"requestSchemaId()\"\n [draftProcessId]=\"draftProcessId()\"\n [readonly]=\"isReadonly()\"\n [lookups]=\"formLookups()\"\n [hostMessages]=\"actionMessages()\"\n />\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.requestFormUnavailable\") }}\n </p>\n </div>\n }\n </div>\n </div>\n\n <div\n class=\"flex-1 min-h-0 overflow-auto\"\n [hidden]=\"activeTab() !== 'approvals'\"\n >\n @if (canRenderPreview()) {\n <mt-work-center-process-preview\n [requestId]=\"requestId()\"\n [view]=\"'approvals'\"\n />\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.requestPreviewUnavailable\") }}\n </p>\n </div>\n }\n </div>\n\n <div\n class=\"flex-1 min-h-0 overflow-auto\"\n [hidden]=\"activeTab() !== 'schema'\"\n >\n @if (canRenderPreview()) {\n <mt-work-center-process-preview\n [requestId]=\"requestId()\"\n [view]=\"'schema'\"\n />\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.requestPreviewUnavailable\") }}\n </p>\n </div>\n }\n </div>\n\n @if (!readOnly()) {\n <div\n class=\"h-full min-h-0 overflow-hidden\"\n [hidden]=\"activeTab() !== 'discussion'\"\n >\n @if (canRenderDiscussion()) {\n <div\n class=\"h-[32rem] min-h-[22rem] overflow-hidden rounded-lg border border-surface-200 bg-surface-50 lg:h-full lg:min-h-0\"\n >\n <mt-discussion-thread\n [moduleType]=\"'ProcessRequest'\"\n [recordId]=\"discussionRecordId()\"\n [mentionSearchEndpoint]=\"'Identity/users'\"\n [mentionSearchParam]=\"'query'\"\n [mentionSearchDataPath]=\"'data'\"\n [uploadEndpoint]=\"'uploader'\"\n [attachmentDownloadEndpoint]=\"'uploader'\"\n [showParticipants]=\"true\"\n [autoMarkRead]=\"true\"\n [refreshIntervalMs]=\"0\"\n [styleClass]=\"'h-full'\"\n />\n </div>\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.requestDiscussionUnavailable\") }}\n </p>\n </div>\n }\n </div>\n }\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: ClientForm, selector: "mt-client-form", inputs: ["moduleKey", "operationKey", "moduleId", "levelId", "levelDataId", "moduleDataId", "requestSchemaId", "draftProcessId", "templateId", "preview", "forceOriginalForm", "returnUrl", "defaultValues", "submitRequestMapper", "submitTransport", "readonly", "autoLoad", "formMode", "renderMode", "showInternalStepActions", "confirmWarningsOnSubmit", "confirmWarningsOnStepChange", "silentMessages", "hostMessages", "readonlyFieldDisplayMode", "lookups", "statuses", "ignoredFieldKeys", "disabledFieldKeys", "allowedFieldKeys"], outputs: ["loaded", "submitted", "errored", "modeDetected", "formSourceDetected", "footerStateChanged"] }, { kind: "component", type: DiscussionThread, selector: "mt-discussion-thread", inputs: ["moduleType", "recordId", "title", "subtitle", "placeholder", "pageSize", "currentUserId", "requestContext", "mentionableUsers", "mentionSearchEndpoint", "mentionSearchParam", "mentionSearchDataPath", "allowAttachments", "uploadEndpoint", "attachmentDownloadEndpoint", "showParticipants", "autoMarkRead", "refreshIntervalMs", "styleClass", "disabled"], outputs: ["loaded", "errored", "commentCreated", "commentUpdated", "commentDeleted", "readStateChanged"] }, { kind: "component", type: WorkCenterProcessPreview, selector: "mt-work-center-process-preview", inputs: ["requestId", "view"] }] });
|
|
2364
2475
|
}
|
|
2365
2476
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterProcessRequestType, decorators: [{
|
|
2366
2477
|
type: Component,
|
|
@@ -2371,7 +2482,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
2371
2482
|
ClientForm,
|
|
2372
2483
|
DiscussionThread,
|
|
2373
2484
|
WorkCenterProcessPreview,
|
|
2374
|
-
], template: "<div\
|
|
2485
|
+
], template: "<div\n class=\"mt-modal-content flex h-full min-h-0 flex-col gap-4 p-4 lg:overflow-hidden\"\n *transloco=\"let t; prefix: 'workCenter'\"\n>\n <div\n class=\"flex flex-1 min-h-0 flex-col gap-4 lg:grid lg:grid-cols-[13rem_minmax(0,1fr)] lg:gap-6\"\n >\n @if (tabOptions().length > 1) {\n <mt-tabs\n [(active)]=\"activeTab\"\n [options]=\"tabOptions()\"\n mode=\"vertical\"\n size=\"small\"\n />\n }\n\n <div class=\"min-w-0 flex-1 min-h-0 lg:overflow-hidden\">\n <div\n class=\"h-full min-h-0 lg:overflow-hidden\"\n [hidden]=\"activeTab() !== 'requestDetails'\"\n >\n <div\n class=\"min-w-0 h-full min-h-0 lg:overflow-y-auto lg:overscroll-contain lg:pr-2\"\n >\n @if (canRenderForm()) {\n <mt-client-form\n [moduleKey]=\"moduleKey()\"\n [operationKey]=\"operationKey()\"\n [moduleId]=\"moduleId()\"\n [levelId]=\"levelId()\"\n [levelDataId]=\"levelDataId()\"\n [moduleDataId]=\"moduleDataId()\"\n [requestSchemaId]=\"requestSchemaId()\"\n [draftProcessId]=\"draftProcessId()\"\n [readonly]=\"isReadonly()\"\n [lookups]=\"formLookups()\"\n [hostMessages]=\"actionMessages()\"\n />\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.requestFormUnavailable\") }}\n </p>\n </div>\n }\n </div>\n </div>\n\n <div\n class=\"flex-1 min-h-0 overflow-auto\"\n [hidden]=\"activeTab() !== 'approvals'\"\n >\n @if (canRenderPreview()) {\n <mt-work-center-process-preview\n [requestId]=\"requestId()\"\n [view]=\"'approvals'\"\n />\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.requestPreviewUnavailable\") }}\n </p>\n </div>\n }\n </div>\n\n <div\n class=\"flex-1 min-h-0 overflow-auto\"\n [hidden]=\"activeTab() !== 'schema'\"\n >\n @if (canRenderPreview()) {\n <mt-work-center-process-preview\n [requestId]=\"requestId()\"\n [view]=\"'schema'\"\n />\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.requestPreviewUnavailable\") }}\n </p>\n </div>\n }\n </div>\n\n @if (!readOnly()) {\n <div\n class=\"h-full min-h-0 overflow-hidden\"\n [hidden]=\"activeTab() !== 'discussion'\"\n >\n @if (canRenderDiscussion()) {\n <div\n class=\"h-[32rem] min-h-[22rem] overflow-hidden rounded-lg border border-surface-200 bg-surface-50 lg:h-full lg:min-h-0\"\n >\n <mt-discussion-thread\n [moduleType]=\"'ProcessRequest'\"\n [recordId]=\"discussionRecordId()\"\n [mentionSearchEndpoint]=\"'Identity/users'\"\n [mentionSearchParam]=\"'query'\"\n [mentionSearchDataPath]=\"'data'\"\n [uploadEndpoint]=\"'uploader'\"\n [attachmentDownloadEndpoint]=\"'uploader'\"\n [showParticipants]=\"true\"\n [autoMarkRead]=\"true\"\n [refreshIntervalMs]=\"0\"\n [styleClass]=\"'h-full'\"\n />\n </div>\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.requestDiscussionUnavailable\") }}\n </p>\n </div>\n }\n </div>\n }\n </div>\n </div>\n</div>\n" }]
|
|
2375
2486
|
}], ctorParameters: () => [], propDecorators: { details: [{ type: i0.Input, args: [{ isSignal: true, alias: "details", required: true }] }], lookups: [{ type: i0.Input, args: [{ isSignal: true, alias: "lookups", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], clientForm: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ClientForm), { isSignal: true }] }] } });
|
|
2376
2487
|
|
|
2377
2488
|
class WorkCenterProcessStepType {
|
|
@@ -2379,12 +2490,26 @@ class WorkCenterProcessStepType {
|
|
|
2379
2490
|
actionContext = inject(RuntimeActionContextStore, {
|
|
2380
2491
|
optional: true,
|
|
2381
2492
|
});
|
|
2493
|
+
formStore = inject(WorkCenterActionFormStore, {
|
|
2494
|
+
optional: true,
|
|
2495
|
+
});
|
|
2382
2496
|
transloco = inject(TranslocoService);
|
|
2383
2497
|
destroyRef = inject(DestroyRef);
|
|
2384
2498
|
details = input.required(...(ngDevMode ? [{ debugName: "details" }] : /* istanbul ignore next */ []));
|
|
2385
2499
|
lookups = input(null, ...(ngDevMode ? [{ debugName: "lookups" }] : /* istanbul ignore next */ []));
|
|
2386
2500
|
readOnly = input(false, ...(ngDevMode ? [{ debugName: "readOnly" }] : /* istanbul ignore next */ []));
|
|
2387
2501
|
clientForm = viewChild(ClientForm, ...(ngDevMode ? [{ debugName: "clientForm" }] : /* istanbul ignore next */ []));
|
|
2502
|
+
formStatus = signal(null, ...(ngDevMode ? [{ debugName: "formStatus" }] : /* istanbul ignore next */ []));
|
|
2503
|
+
/**
|
|
2504
|
+
* The last action's failure messages, shaped for `mt-client-form` so they
|
|
2505
|
+
* render in its own validation summary — the same red `p-message` list a
|
|
2506
|
+
* rejected submit produces — instead of a panel of our own above the tabs.
|
|
2507
|
+
*/
|
|
2508
|
+
actionMessages = computed(() => (this.formStore?.errors() ?? []).map((message) => ({
|
|
2509
|
+
code: 'FORMULA_FALSE',
|
|
2510
|
+
severity: 'error',
|
|
2511
|
+
message,
|
|
2512
|
+
})), ...(ngDevMode ? [{ debugName: "actionMessages" }] : /* istanbul ignore next */ []));
|
|
2388
2513
|
formLookups = computed(() => this.lookups() ?? this.facade.lookups(), ...(ngDevMode ? [{ debugName: "formLookups" }] : /* istanbul ignore next */ []));
|
|
2389
2514
|
activeTab = signal('form', ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
|
|
2390
2515
|
activeLang = signal(this.transloco.getActiveLang(), ...(ngDevMode ? [{ debugName: "activeLang" }] : /* istanbul ignore next */ []));
|
|
@@ -2488,12 +2613,58 @@ class WorkCenterProcessStepType {
|
|
|
2488
2613
|
effect(() => {
|
|
2489
2614
|
this.actionContext?.setFormSource(this.readOnly() ? null : (this.clientForm() ?? null));
|
|
2490
2615
|
});
|
|
2616
|
+
// Publishes what the footer's `process-submit/validate` pre-flight needs.
|
|
2617
|
+
// Only the editable case is published: on a read-only form the approver
|
|
2618
|
+
// cannot fix anything, so blocking them on a rule failure would strand the
|
|
2619
|
+
// action instead of helping.
|
|
2620
|
+
effect(() => {
|
|
2621
|
+
this.formStore?.setContext(this.readOnly() || !this.canRenderForm()
|
|
2622
|
+
? null
|
|
2623
|
+
: {
|
|
2624
|
+
moduleKey: this.moduleKey(),
|
|
2625
|
+
operationKey: this.operationKey(),
|
|
2626
|
+
moduleId: this.moduleId(),
|
|
2627
|
+
levelId: this.levelId(),
|
|
2628
|
+
levelDataId: this.levelDataId(),
|
|
2629
|
+
moduleDataId: this.moduleDataId(),
|
|
2630
|
+
requestSchemaId: this.requestSchemaId(),
|
|
2631
|
+
});
|
|
2632
|
+
});
|
|
2633
|
+
// `formControl.status` is not a signal, so mirror it into one — without
|
|
2634
|
+
// this the footer would keep its stale enabled/disabled state while the
|
|
2635
|
+
// approver fills the form in.
|
|
2636
|
+
effect((onCleanup) => {
|
|
2637
|
+
const form = this.clientForm();
|
|
2638
|
+
if (!form) {
|
|
2639
|
+
this.formStatus.set(null);
|
|
2640
|
+
return;
|
|
2641
|
+
}
|
|
2642
|
+
this.formStatus.set(form.formControl.status);
|
|
2643
|
+
const subscription = form.formControl.statusChanges.subscribe((status) => this.formStatus.set(status));
|
|
2644
|
+
onCleanup(() => subscription.unsubscribe());
|
|
2645
|
+
});
|
|
2646
|
+
effect(() => {
|
|
2647
|
+
const form = this.clientForm();
|
|
2648
|
+
// Read before the guards so the effect re-runs on every status change.
|
|
2649
|
+
const status = this.formStatus();
|
|
2650
|
+
this.formStore?.setIncomplete(!this.readOnly() && !!form && status === 'INVALID' && form.isLoaded());
|
|
2651
|
+
});
|
|
2652
|
+
// The form only draws its validation summary when it has editable sections
|
|
2653
|
+
// to draw it above; without them the footer has to keep reporting failures
|
|
2654
|
+
// itself. Claim the messages only when they will actually be shown.
|
|
2655
|
+
effect(() => {
|
|
2656
|
+
const form = this.clientForm();
|
|
2657
|
+
this.formStore?.setErrorHost(!!form && form.isLoaded() && form.hasEditableFormSections());
|
|
2658
|
+
});
|
|
2491
2659
|
}
|
|
2492
2660
|
ngOnDestroy() {
|
|
2493
2661
|
this.actionContext?.setFormSource(null);
|
|
2662
|
+
this.formStore?.setContext(null);
|
|
2663
|
+
this.formStore?.setIncomplete(false);
|
|
2664
|
+
this.formStore?.setErrorHost(false);
|
|
2494
2665
|
}
|
|
2495
2666
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterProcessStepType, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2496
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterProcessStepType, isStandalone: true, selector: "mt-work-center-process-step-type", inputs: { details: { classPropertyName: "details", publicName: "details", isSignal: true, isRequired: true, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "clientForm", first: true, predicate: ClientForm, descendants: true, isSignal: true }, { propertyName: "levelPreview", first: true, predicate: ClientInstancePreview, descendants: true, isSignal: true }], ngImport: i0, template: "<div\
|
|
2667
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterProcessStepType, isStandalone: true, selector: "mt-work-center-process-step-type", inputs: { details: { classPropertyName: "details", publicName: "details", isSignal: true, isRequired: true, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "clientForm", first: true, predicate: ClientForm, descendants: true, isSignal: true }, { propertyName: "levelPreview", first: true, predicate: ClientInstancePreview, descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"mt-modal-content flex h-full min-h-0 flex-col gap-4 p-4 lg:overflow-hidden\"\n *transloco=\"let t; prefix: 'workCenter'\"\n>\n <div\n class=\"flex flex-1 min-h-0 flex-col gap-4 lg:grid lg:grid-cols-[13rem_minmax(0,1fr)] lg:gap-6\"\n >\n @if (tabOptions().length > 1) {\n <mt-tabs\n [(active)]=\"activeTab\"\n [options]=\"tabOptions()\"\n mode=\"vertical\"\n size=\"small\"\n />\n }\n\n <div class=\"min-w-0 flex-1 min-h-0 lg:overflow-hidden\">\n <div\n class=\"h-full min-h-0 lg:overflow-hidden\"\n [hidden]=\"activeTab() !== 'form'\"\n >\n <div\n class=\"min-w-0 h-full min-h-0 lg:overflow-y-auto lg:overscroll-contain lg:pr-2\"\n >\n @if (canRenderForm()) {\n <mt-client-form\n [moduleKey]=\"moduleKey()\"\n [operationKey]=\"operationKey()\"\n [moduleId]=\"moduleId()\"\n [levelId]=\"levelId()\"\n [levelDataId]=\"levelDataId()\"\n [moduleDataId]=\"moduleDataId()\"\n [requestSchemaId]=\"requestSchemaId()\"\n [draftProcessId]=\"draftProcessId()\"\n [readonly]=\"readOnly()\"\n [lookups]=\"formLookups()\"\n [hostMessages]=\"actionMessages()\"\n />\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.processFormUnavailable\") }}\n </p>\n </div>\n }\n </div>\n </div>\n\n <div\n class=\"h-full min-h-0 lg:overflow-hidden\"\n [hidden]=\"activeTab() !== 'levelDetails'\"\n >\n @if (levelDetailsConfig(); as levelDetailsConfig) {\n <div\n class=\"min-w-0 h-full min-h-0 lg:overflow-y-auto lg:overscroll-contain lg:pr-2\"\n >\n <mt-client-instance-preview [config]=\"levelDetailsConfig\" />\n </div>\n }\n </div>\n\n <div\n class=\"flex-1 min-h-0 overflow-auto\"\n [hidden]=\"activeTab() !== 'approvals'\"\n >\n @if (canRenderPreview()) {\n <mt-work-center-process-preview\n [requestId]=\"requestId()\"\n [view]=\"'approvals'\"\n />\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.processPreviewUnavailable\") }}\n </p>\n </div>\n }\n </div>\n\n <div\n class=\"flex-1 min-h-0 overflow-auto\"\n [hidden]=\"activeTab() !== 'schema'\"\n >\n @if (canRenderPreview()) {\n <mt-work-center-process-preview\n [requestId]=\"requestId()\"\n [view]=\"'schema'\"\n />\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.processPreviewUnavailable\") }}\n </p>\n </div>\n }\n </div>\n\n @if (!readOnly()) {\n <div\n class=\"h-full min-h-0 overflow-hidden\"\n [hidden]=\"activeTab() !== 'discussion'\"\n >\n @if (canRenderDiscussion()) {\n <div\n class=\"h-[32rem] min-h-[22rem] overflow-hidden rounded-lg border border-surface-200 bg-surface-50 lg:h-full lg:min-h-0\"\n >\n <mt-discussion-thread\n [moduleType]=\"'ProcessRequest'\"\n [recordId]=\"discussionRecordId()\"\n [mentionSearchEndpoint]=\"'Identity/users'\"\n [mentionSearchParam]=\"'query'\"\n [mentionSearchDataPath]=\"'data'\"\n [uploadEndpoint]=\"'uploader'\"\n [attachmentDownloadEndpoint]=\"'uploader'\"\n [showParticipants]=\"true\"\n [autoMarkRead]=\"true\"\n [refreshIntervalMs]=\"0\"\n [styleClass]=\"'h-full'\"\n />\n </div>\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.processDiscussionUnavailable\") }}\n </p>\n </div>\n }\n </div>\n }\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: ClientForm, selector: "mt-client-form", inputs: ["moduleKey", "operationKey", "moduleId", "levelId", "levelDataId", "moduleDataId", "requestSchemaId", "draftProcessId", "templateId", "preview", "forceOriginalForm", "returnUrl", "defaultValues", "submitRequestMapper", "submitTransport", "readonly", "autoLoad", "formMode", "renderMode", "showInternalStepActions", "confirmWarningsOnSubmit", "confirmWarningsOnStepChange", "silentMessages", "hostMessages", "readonlyFieldDisplayMode", "lookups", "statuses", "ignoredFieldKeys", "disabledFieldKeys", "allowedFieldKeys"], outputs: ["loaded", "submitted", "errored", "modeDetected", "formSourceDetected", "footerStateChanged"] }, { kind: "component", type: ClientInstancePreview, selector: "mt-client-instance-preview", inputs: ["config", "hideEmptyState", "stackOnNarrow"] }, { kind: "component", type: DiscussionThread, selector: "mt-discussion-thread", inputs: ["moduleType", "recordId", "title", "subtitle", "placeholder", "pageSize", "currentUserId", "requestContext", "mentionableUsers", "mentionSearchEndpoint", "mentionSearchParam", "mentionSearchDataPath", "allowAttachments", "uploadEndpoint", "attachmentDownloadEndpoint", "showParticipants", "autoMarkRead", "refreshIntervalMs", "styleClass", "disabled"], outputs: ["loaded", "errored", "commentCreated", "commentUpdated", "commentDeleted", "readStateChanged"] }, { kind: "component", type: WorkCenterProcessPreview, selector: "mt-work-center-process-preview", inputs: ["requestId", "view"] }] });
|
|
2497
2668
|
}
|
|
2498
2669
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterProcessStepType, decorators: [{
|
|
2499
2670
|
type: Component,
|
|
@@ -2505,7 +2676,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
2505
2676
|
ClientInstancePreview,
|
|
2506
2677
|
DiscussionThread,
|
|
2507
2678
|
WorkCenterProcessPreview,
|
|
2508
|
-
], template: "<div\
|
|
2679
|
+
], template: "<div\n class=\"mt-modal-content flex h-full min-h-0 flex-col gap-4 p-4 lg:overflow-hidden\"\n *transloco=\"let t; prefix: 'workCenter'\"\n>\n <div\n class=\"flex flex-1 min-h-0 flex-col gap-4 lg:grid lg:grid-cols-[13rem_minmax(0,1fr)] lg:gap-6\"\n >\n @if (tabOptions().length > 1) {\n <mt-tabs\n [(active)]=\"activeTab\"\n [options]=\"tabOptions()\"\n mode=\"vertical\"\n size=\"small\"\n />\n }\n\n <div class=\"min-w-0 flex-1 min-h-0 lg:overflow-hidden\">\n <div\n class=\"h-full min-h-0 lg:overflow-hidden\"\n [hidden]=\"activeTab() !== 'form'\"\n >\n <div\n class=\"min-w-0 h-full min-h-0 lg:overflow-y-auto lg:overscroll-contain lg:pr-2\"\n >\n @if (canRenderForm()) {\n <mt-client-form\n [moduleKey]=\"moduleKey()\"\n [operationKey]=\"operationKey()\"\n [moduleId]=\"moduleId()\"\n [levelId]=\"levelId()\"\n [levelDataId]=\"levelDataId()\"\n [moduleDataId]=\"moduleDataId()\"\n [requestSchemaId]=\"requestSchemaId()\"\n [draftProcessId]=\"draftProcessId()\"\n [readonly]=\"readOnly()\"\n [lookups]=\"formLookups()\"\n [hostMessages]=\"actionMessages()\"\n />\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.processFormUnavailable\") }}\n </p>\n </div>\n }\n </div>\n </div>\n\n <div\n class=\"h-full min-h-0 lg:overflow-hidden\"\n [hidden]=\"activeTab() !== 'levelDetails'\"\n >\n @if (levelDetailsConfig(); as levelDetailsConfig) {\n <div\n class=\"min-w-0 h-full min-h-0 lg:overflow-y-auto lg:overscroll-contain lg:pr-2\"\n >\n <mt-client-instance-preview [config]=\"levelDetailsConfig\" />\n </div>\n }\n </div>\n\n <div\n class=\"flex-1 min-h-0 overflow-auto\"\n [hidden]=\"activeTab() !== 'approvals'\"\n >\n @if (canRenderPreview()) {\n <mt-work-center-process-preview\n [requestId]=\"requestId()\"\n [view]=\"'approvals'\"\n />\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.processPreviewUnavailable\") }}\n </p>\n </div>\n }\n </div>\n\n <div\n class=\"flex-1 min-h-0 overflow-auto\"\n [hidden]=\"activeTab() !== 'schema'\"\n >\n @if (canRenderPreview()) {\n <mt-work-center-process-preview\n [requestId]=\"requestId()\"\n [view]=\"'schema'\"\n />\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.processPreviewUnavailable\") }}\n </p>\n </div>\n }\n </div>\n\n @if (!readOnly()) {\n <div\n class=\"h-full min-h-0 overflow-hidden\"\n [hidden]=\"activeTab() !== 'discussion'\"\n >\n @if (canRenderDiscussion()) {\n <div\n class=\"h-[32rem] min-h-[22rem] overflow-hidden rounded-lg border border-surface-200 bg-surface-50 lg:h-full lg:min-h-0\"\n >\n <mt-discussion-thread\n [moduleType]=\"'ProcessRequest'\"\n [recordId]=\"discussionRecordId()\"\n [mentionSearchEndpoint]=\"'Identity/users'\"\n [mentionSearchParam]=\"'query'\"\n [mentionSearchDataPath]=\"'data'\"\n [uploadEndpoint]=\"'uploader'\"\n [attachmentDownloadEndpoint]=\"'uploader'\"\n [showParticipants]=\"true\"\n [autoMarkRead]=\"true\"\n [refreshIntervalMs]=\"0\"\n [styleClass]=\"'h-full'\"\n />\n </div>\n } @else {\n <div\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\n >\n <p class=\"max-w-md text-center text-sm text-surface-500\">\n {{ t(\"context.processDiscussionUnavailable\") }}\n </p>\n </div>\n }\n </div>\n }\n </div>\n </div>\n</div>\n" }]
|
|
2509
2680
|
}], ctorParameters: () => [], propDecorators: { details: [{ type: i0.Input, args: [{ isSignal: true, alias: "details", required: true }] }], lookups: [{ type: i0.Input, args: [{ isSignal: true, alias: "lookups", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], clientForm: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ClientForm), { isSignal: true }] }], levelPreview: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ClientInstancePreview), { isSignal: true }] }] } });
|
|
2510
2681
|
|
|
2511
2682
|
/**
|
|
@@ -2957,10 +3128,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
2957
3128
|
}, template: "<ng-container *transloco=\"let t; prefix: 'workCenter'\">\r\n @if (registeredComponent(); as registered) {\r\n <!-- Host registration wins, so a new request type no longer needs a package\r\n release. Nothing is registered by default, so the chain below is what\r\n every existing host still gets. -->\r\n <ng-container\r\n *ngComponentOutlet=\"registered; inputs: registeredInputs()\"\r\n ></ng-container>\r\n } @else if (isSchedulePublish()) {\r\n <!-- Dispatched on the OPERATION KEY, not on a new `type`: a publish request\r\n arrives as ProcessStep or ProcessRequest like any other, so the published\r\n Work Center type contract is unchanged. -->\r\n <mt-work-center-schedule-publish-type\r\n [details]=\"details()\"\r\n [readOnly]=\"readOnly()\"\r\n />\r\n } @else if (details().type === \"ProcessStep\") {\r\n <mt-work-center-process-step-type\r\n [details]=\"details()\"\r\n [lookups]=\"lookups()\"\r\n [readOnly]=\"readOnly()\"\r\n />\r\n } @else if (details().type === \"ProcessRequest\") {\r\n <mt-work-center-process-request-type\r\n [details]=\"details()\"\r\n [lookups]=\"lookups()\"\r\n [readOnly]=\"readOnly()\"\r\n />\r\n } @else if (details().type === \"EscalationInstance\") {\r\n <mt-work-center-escalation-instance-type\r\n [details]=\"details()\"\r\n [readOnly]=\"readOnly()\"\r\n />\r\n } @else if (details().type === \"Module\" || details().type === \"GeneralTask\") {\r\n <mt-work-center-module-type\r\n [details]=\"details()\"\r\n [lookups]=\"lookups()\"\r\n [readOnly]=\"readOnly()\"\r\n />\r\n } @else {\r\n <div class=\"mt-modal-content flex h-full items-center justify-center p-4\">\r\n <p class=\"text-sm text-surface-500\">{{ t(\"modal.unsupportedType\") }}</p>\r\n </div>\r\n }\r\n</ng-container>\r\n" }]
|
|
2958
3129
|
}], propDecorators: { details: [{ type: i0.Input, args: [{ isSignal: true, alias: "details", required: true }] }], lookups: [{ type: i0.Input, args: [{ isSignal: true, alias: "lookups", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }] } });
|
|
2959
3130
|
|
|
3131
|
+
/**
|
|
3132
|
+
* Carries the individual rule messages of a failed `process-submit/validate`
|
|
3133
|
+
* pre-flight, so the footer can render them as a list instead of one blob of
|
|
3134
|
+
* newline-joined text.
|
|
3135
|
+
*/
|
|
3136
|
+
class WorkCenterFormValidationError extends Error {
|
|
3137
|
+
messages;
|
|
3138
|
+
constructor(messages) {
|
|
3139
|
+
super(messages.join('\n'));
|
|
3140
|
+
this.name = 'WorkCenterFormValidationError';
|
|
3141
|
+
this.messages = messages;
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
|
|
2960
3145
|
const FORM_VALIDATION_WARNINGS = 'FormValidationWarnings';
|
|
2961
3146
|
/** Handles the process action validation handshake owned by Work Center. */
|
|
2962
3147
|
class WorkCenterActionValidationHandler {
|
|
2963
|
-
|
|
3148
|
+
modal = inject(ModalService);
|
|
2964
3149
|
runner = inject(RuntimeActionRunner);
|
|
2965
3150
|
transloco = inject(TranslocoService);
|
|
2966
3151
|
async recover(action, error, submittedPayload, defaultAfterSuccess) {
|
|
@@ -2991,16 +3176,24 @@ class WorkCenterActionValidationHandler {
|
|
|
2991
3176
|
payloadTemplate: retryPayload,
|
|
2992
3177
|
}, { defaultAfterSuccess, silent: true });
|
|
2993
3178
|
}
|
|
2994
|
-
|
|
3179
|
+
/**
|
|
3180
|
+
* One entry per failing rule, so the footer can list them instead of
|
|
3181
|
+
* rendering one newline-joined blob. A single-entry array is the normal
|
|
3182
|
+
* case — transport failures and plain envelope errors.
|
|
3183
|
+
*/
|
|
3184
|
+
resolveErrorMessages(error, fallback) {
|
|
3185
|
+
if (error instanceof WorkCenterFormValidationError) {
|
|
3186
|
+
return error.messages;
|
|
3187
|
+
}
|
|
2995
3188
|
const validationError = readProcessActionValidationError(error);
|
|
2996
3189
|
if (validationError) {
|
|
2997
3190
|
const messages = this.resolveValidationMessages(validationError);
|
|
2998
3191
|
if (messages.length)
|
|
2999
|
-
return messages
|
|
3192
|
+
return messages;
|
|
3000
3193
|
if (validationError.message)
|
|
3001
|
-
return validationError.message;
|
|
3194
|
+
return [validationError.message];
|
|
3002
3195
|
}
|
|
3003
|
-
return readHttpErrorMessage(error) ?? fallback;
|
|
3196
|
+
return [readHttpErrorMessage(error) ?? fallback];
|
|
3004
3197
|
}
|
|
3005
3198
|
resolveValidationMessages(validationError) {
|
|
3006
3199
|
const messages = [];
|
|
@@ -3009,7 +3202,7 @@ class WorkCenterActionValidationHandler {
|
|
|
3009
3202
|
if (result.passed === true && result.isEvaluationError !== true)
|
|
3010
3203
|
continue;
|
|
3011
3204
|
const message = resolveLocalizedText(result.message, this.transloco.getActiveLang()) ??
|
|
3012
|
-
readNonEmptyString(result.errorMessage);
|
|
3205
|
+
readNonEmptyString$1(result.errorMessage);
|
|
3013
3206
|
if (!message || seen.has(message))
|
|
3014
3207
|
continue;
|
|
3015
3208
|
seen.add(message);
|
|
@@ -3020,30 +3213,30 @@ class WorkCenterActionValidationHandler {
|
|
|
3020
3213
|
}
|
|
3021
3214
|
return messages;
|
|
3022
3215
|
}
|
|
3216
|
+
/**
|
|
3217
|
+
* Shared by the backend-driven acknowledgement handshake above and by the
|
|
3218
|
+
* `process-submit/validate` pre-flight in `WorkCenterActionFormValidator`.
|
|
3219
|
+
*
|
|
3220
|
+
* Uses the client form's own warnings dialog so an approver sees the exact
|
|
3221
|
+
* same prompt the normal submit path raises — same layout, same wording
|
|
3222
|
+
* around the list, only the header/question/accept label are Work Center's.
|
|
3223
|
+
*/
|
|
3023
3224
|
confirmWarnings(messages) {
|
|
3024
|
-
const warningLines = messages.map((message) => `• ${message}`).join('\n');
|
|
3025
|
-
const question = this.transloco.translate('workCenter.actions.validationWarningsQuestion');
|
|
3026
|
-
const message = warningLines ? `${warningLines}\n\n${question}` : question;
|
|
3027
3225
|
return new Promise((resolve) => {
|
|
3028
|
-
|
|
3029
|
-
const settle = (value) => {
|
|
3030
|
-
if (settled)
|
|
3031
|
-
return;
|
|
3032
|
-
settled = true;
|
|
3033
|
-
resolve(value);
|
|
3034
|
-
};
|
|
3035
|
-
this.confirmation.confirm({
|
|
3036
|
-
type: 'dialog',
|
|
3226
|
+
const ref = this.modal.openModal(ClientFormWarningsDialog, 'dialog', {
|
|
3037
3227
|
header: this.transloco.translate('workCenter.actions.validationWarningsHeader'),
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
reject: () => settle(false),
|
|
3228
|
+
width: '34rem',
|
|
3229
|
+
dismissableMask: true,
|
|
3230
|
+
inputValues: {
|
|
3231
|
+
warnings: messages.map((message) => ({ message })),
|
|
3232
|
+
question: this.transloco.translate('workCenter.actions.validationWarningsQuestion'),
|
|
3233
|
+
acceptLabel: this.transloco.translate('workCenter.actions.continueAction'),
|
|
3234
|
+
},
|
|
3046
3235
|
});
|
|
3236
|
+
// Dismissing the dialog resolves `undefined` — treated as "do not continue".
|
|
3237
|
+
ref.onClose
|
|
3238
|
+
.pipe(take(1))
|
|
3239
|
+
.subscribe((confirmed) => resolve(confirmed === true));
|
|
3047
3240
|
});
|
|
3048
3241
|
}
|
|
3049
3242
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterActionValidationHandler, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
@@ -3058,7 +3251,7 @@ function readProcessActionValidationError(error) {
|
|
|
3058
3251
|
const envelope = readRecord(body);
|
|
3059
3252
|
const errors = readRecord(envelope?.['errors']);
|
|
3060
3253
|
const details = readRecord(errors?.['details']);
|
|
3061
|
-
const kind = readNonEmptyString(details?.['kind']);
|
|
3254
|
+
const kind = readNonEmptyString$1(details?.['kind']);
|
|
3062
3255
|
if (!kind)
|
|
3063
3256
|
return null;
|
|
3064
3257
|
const validation = readRecord(details?.['validation']);
|
|
@@ -3071,13 +3264,13 @@ function readProcessActionValidationError(error) {
|
|
|
3071
3264
|
return {
|
|
3072
3265
|
kind,
|
|
3073
3266
|
requiresAcknowledgement: details?.['requiresAcknowledgement'] === true,
|
|
3074
|
-
validationWarningsToken: readNonEmptyString(details?.['validationWarningsToken']),
|
|
3075
|
-
message: readNonEmptyString(errors?.['message']),
|
|
3267
|
+
validationWarningsToken: readNonEmptyString$1(details?.['validationWarningsToken']),
|
|
3268
|
+
message: readNonEmptyString$1(errors?.['message']),
|
|
3076
3269
|
results,
|
|
3077
3270
|
};
|
|
3078
3271
|
}
|
|
3079
3272
|
function resolveLocalizedText(value, activeLang) {
|
|
3080
|
-
const direct = readNonEmptyString(value);
|
|
3273
|
+
const direct = readNonEmptyString$1(value);
|
|
3081
3274
|
if (direct)
|
|
3082
3275
|
return direct;
|
|
3083
3276
|
const record = readRecord(value);
|
|
@@ -3092,7 +3285,7 @@ function resolveLocalizedText(value, activeLang) {
|
|
|
3092
3285
|
record['en'],
|
|
3093
3286
|
record['ar'],
|
|
3094
3287
|
]) {
|
|
3095
|
-
const text = readNonEmptyString(candidate);
|
|
3288
|
+
const text = readNonEmptyString$1(candidate);
|
|
3096
3289
|
if (text)
|
|
3097
3290
|
return text;
|
|
3098
3291
|
}
|
|
@@ -3102,15 +3295,151 @@ function readHttpErrorMessage(error) {
|
|
|
3102
3295
|
const record = readRecord(error);
|
|
3103
3296
|
const body = readRecord(record?.['error']);
|
|
3104
3297
|
const errors = readRecord(body?.['errors']);
|
|
3105
|
-
return (readNonEmptyString(errors?.['message']) ??
|
|
3106
|
-
readNonEmptyString(body?.['message']) ??
|
|
3107
|
-
readNonEmptyString(record?.['message']));
|
|
3298
|
+
return (readNonEmptyString$1(errors?.['message']) ??
|
|
3299
|
+
readNonEmptyString$1(body?.['message']) ??
|
|
3300
|
+
readNonEmptyString$1(record?.['message']));
|
|
3108
3301
|
}
|
|
3109
3302
|
function readRecord(value) {
|
|
3110
3303
|
return value && typeof value === 'object'
|
|
3111
3304
|
? value
|
|
3112
3305
|
: null;
|
|
3113
3306
|
}
|
|
3307
|
+
function readNonEmptyString$1(value) {
|
|
3308
|
+
if (typeof value !== 'string')
|
|
3309
|
+
return null;
|
|
3310
|
+
const normalized = value.trim();
|
|
3311
|
+
return normalized.length ? normalized : null;
|
|
3312
|
+
}
|
|
3313
|
+
|
|
3314
|
+
const PROCEED = { status: 'proceed' };
|
|
3315
|
+
/** The payload key carrying the edited client-form values. */
|
|
3316
|
+
const FORM_VALUES_PAYLOAD_KEY = 'values';
|
|
3317
|
+
/**
|
|
3318
|
+
* Runs `process-submit/validate` before a Work Center action that submits
|
|
3319
|
+
* edited client-form values (Approve, Resubmit, …).
|
|
3320
|
+
*
|
|
3321
|
+
* Why this exists: the process action endpoints answer `200` for non-blocking
|
|
3322
|
+
* rule failures, so an approver never sees the warnings that the same values
|
|
3323
|
+
* would raise on the normal submit path. This pre-flight reproduces the
|
|
3324
|
+
* client-form submit ceremony — blocking failures stop the action, warnings
|
|
3325
|
+
* raise the acknowledge-and-continue prompt — without submitting anything.
|
|
3326
|
+
*
|
|
3327
|
+
* It is advisory only. The action endpoint stays authoritative, and the
|
|
3328
|
+
* backend-driven `FormValidationWarnings` handshake in
|
|
3329
|
+
* `WorkCenterActionValidationHandler` keeps working untouched on top of it.
|
|
3330
|
+
*/
|
|
3331
|
+
class WorkCenterActionFormValidator {
|
|
3332
|
+
api = inject(ClientFormApiService);
|
|
3333
|
+
actionContext = inject(RuntimeActionContextStore);
|
|
3334
|
+
contextStore = inject(WorkCenterActionFormStore);
|
|
3335
|
+
warnings = inject(WorkCenterActionValidationHandler);
|
|
3336
|
+
transloco = inject(TranslocoService);
|
|
3337
|
+
async validate(action) {
|
|
3338
|
+
const context = this.contextStore.context();
|
|
3339
|
+
if (!context || !submitsFormValues(action)) {
|
|
3340
|
+
return PROCEED;
|
|
3341
|
+
}
|
|
3342
|
+
const fields = this.actionContext.resolveFormValues();
|
|
3343
|
+
if (!fields.length) {
|
|
3344
|
+
return PROCEED;
|
|
3345
|
+
}
|
|
3346
|
+
const validation = await this.runValidation(context, fields);
|
|
3347
|
+
// A transport failure must not strand an otherwise valid action: the
|
|
3348
|
+
// pre-flight is advisory and the action endpoint validates again anyway.
|
|
3349
|
+
if (!validation) {
|
|
3350
|
+
return PROCEED;
|
|
3351
|
+
}
|
|
3352
|
+
const failures = (validation.results ?? []).filter(shouldSurface);
|
|
3353
|
+
const blocking = failures.filter(isBlocking);
|
|
3354
|
+
if (validation.hasBlockingFailures || blocking.length) {
|
|
3355
|
+
const messages = this.resolveMessages(blocking.length ? blocking : failures);
|
|
3356
|
+
return {
|
|
3357
|
+
status: 'blocked',
|
|
3358
|
+
error: new WorkCenterFormValidationError(messages.length
|
|
3359
|
+
? messages
|
|
3360
|
+
: [
|
|
3361
|
+
this.transloco.translate('workCenter.actions.validationBlocked'),
|
|
3362
|
+
]),
|
|
3363
|
+
};
|
|
3364
|
+
}
|
|
3365
|
+
if (!failures.length) {
|
|
3366
|
+
return PROCEED;
|
|
3367
|
+
}
|
|
3368
|
+
const confirmed = await this.warnings.confirmWarnings(this.resolveMessages(failures));
|
|
3369
|
+
return confirmed ? PROCEED : { status: 'cancelled' };
|
|
3370
|
+
}
|
|
3371
|
+
async runValidation(context, fields) {
|
|
3372
|
+
const response = await firstValueFrom(this.api
|
|
3373
|
+
.validate(buildValidationRequest(context, fields), true)
|
|
3374
|
+
.pipe(catchError(() => of(null))));
|
|
3375
|
+
return response?.data ?? null;
|
|
3376
|
+
}
|
|
3377
|
+
resolveMessages(results) {
|
|
3378
|
+
const messages = [];
|
|
3379
|
+
const seen = new Set();
|
|
3380
|
+
for (const result of results) {
|
|
3381
|
+
const message = resolveLocalizedText(result.message, this.transloco.getActiveLang()) ??
|
|
3382
|
+
readNonEmptyString(result.errorMessage);
|
|
3383
|
+
if (!message || seen.has(message))
|
|
3384
|
+
continue;
|
|
3385
|
+
seen.add(message);
|
|
3386
|
+
messages.push(message);
|
|
3387
|
+
}
|
|
3388
|
+
return messages;
|
|
3389
|
+
}
|
|
3390
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterActionFormValidator, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3391
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterActionFormValidator });
|
|
3392
|
+
}
|
|
3393
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterActionFormValidator, decorators: [{
|
|
3394
|
+
type: Injectable
|
|
3395
|
+
}] });
|
|
3396
|
+
/**
|
|
3397
|
+
* Mirrors `buildSubmitRequest` in `ClientForm`, minus the pieces a pre-flight
|
|
3398
|
+
* must never send (`templateId`) or cannot know from outside the form
|
|
3399
|
+
* (`IsSteps`, which only applies to stepped/wizard forms).
|
|
3400
|
+
*/
|
|
3401
|
+
function buildValidationRequest(context, fields) {
|
|
3402
|
+
const request = {
|
|
3403
|
+
moduleKey: context.moduleKey,
|
|
3404
|
+
operationKey: context.operationKey,
|
|
3405
|
+
fields,
|
|
3406
|
+
};
|
|
3407
|
+
if (context.moduleId != null)
|
|
3408
|
+
request.moduleId = context.moduleId;
|
|
3409
|
+
if (context.levelId != null)
|
|
3410
|
+
request.levelId = context.levelId;
|
|
3411
|
+
if (context.levelDataId != null)
|
|
3412
|
+
request.levelDataId = context.levelDataId;
|
|
3413
|
+
if (context.moduleDataId != null)
|
|
3414
|
+
request.moduleDataId = context.moduleDataId;
|
|
3415
|
+
if (context.requestSchemaId != null) {
|
|
3416
|
+
request.requestSchemaId = context.requestSchemaId;
|
|
3417
|
+
}
|
|
3418
|
+
const recordId = context.moduleDataId ??
|
|
3419
|
+
(context.moduleKey === 'LevelData' && context.operationKey !== 'Create'
|
|
3420
|
+
? context.levelDataId
|
|
3421
|
+
: undefined);
|
|
3422
|
+
if (recordId != null)
|
|
3423
|
+
request.recordId = recordId;
|
|
3424
|
+
return request;
|
|
3425
|
+
}
|
|
3426
|
+
/**
|
|
3427
|
+
* Only actions that carry the edited form values are worth validating —
|
|
3428
|
+
* Delete, Close and friends submit nothing the rules can read.
|
|
3429
|
+
*/
|
|
3430
|
+
function submitsFormValues(action) {
|
|
3431
|
+
return ((action.payloadKeys ?? []).includes(FORM_VALUES_PAYLOAD_KEY) ||
|
|
3432
|
+
(!!action.payloadTemplate &&
|
|
3433
|
+
FORM_VALUES_PAYLOAD_KEY in action.payloadTemplate));
|
|
3434
|
+
}
|
|
3435
|
+
// These two mirror `process-validation.util` in `@masterteam/forms/client-form`,
|
|
3436
|
+
// which the package does not export. Keep them in step with it.
|
|
3437
|
+
function shouldSurface(result) {
|
|
3438
|
+
return !result.passed || result.isEvaluationError === true;
|
|
3439
|
+
}
|
|
3440
|
+
function isBlocking(result) {
|
|
3441
|
+
return (result.isEvaluationError === true || (!result.passed && result.isBlocking));
|
|
3442
|
+
}
|
|
3114
3443
|
function readNonEmptyString(value) {
|
|
3115
3444
|
if (typeof value !== 'string')
|
|
3116
3445
|
return null;
|
|
@@ -3124,10 +3453,30 @@ class WorkCenterRuntimeActionExecutor {
|
|
|
3124
3453
|
actionContext = inject(RuntimeActionContextStore);
|
|
3125
3454
|
modal = inject(ModalService);
|
|
3126
3455
|
validation = inject(WorkCenterActionValidationHandler);
|
|
3456
|
+
formValidation = inject(WorkCenterActionFormValidator);
|
|
3127
3457
|
confirmDialogClass = inject(RUNTIME_ACTION_CONFIRM_DIALOG, {
|
|
3128
3458
|
optional: true,
|
|
3129
3459
|
});
|
|
3130
3460
|
async execute(action, defaultAfterSuccess) {
|
|
3461
|
+
// Pre-flight before anything else: there is no point collecting a reason
|
|
3462
|
+
// or a note for an action the form's own rules already block, and a
|
|
3463
|
+
// warning the user has to acknowledge should be the first thing they see.
|
|
3464
|
+
const preflight = await this.formValidation.validate(action);
|
|
3465
|
+
if (preflight.status === 'cancelled') {
|
|
3466
|
+
return {
|
|
3467
|
+
status: 'cancelled',
|
|
3468
|
+
actionKey: action.actionKey,
|
|
3469
|
+
afterSuccess: null,
|
|
3470
|
+
};
|
|
3471
|
+
}
|
|
3472
|
+
if (preflight.status === 'blocked') {
|
|
3473
|
+
return {
|
|
3474
|
+
status: 'error',
|
|
3475
|
+
actionKey: action.actionKey,
|
|
3476
|
+
afterSuccess: null,
|
|
3477
|
+
error: preflight.error,
|
|
3478
|
+
};
|
|
3479
|
+
}
|
|
3131
3480
|
if (action.needConfirmation &&
|
|
3132
3481
|
hasActionFormFields(action) &&
|
|
3133
3482
|
this.confirmDialogClass) {
|
|
@@ -3232,6 +3581,7 @@ class WorkCenterItemModalFooterActions {
|
|
|
3232
3581
|
transloco = inject(TranslocoService);
|
|
3233
3582
|
actionValidation = inject(WorkCenterActionValidationHandler);
|
|
3234
3583
|
actionExecutor = inject(WorkCenterRuntimeActionExecutor);
|
|
3584
|
+
formStore = inject(WorkCenterActionFormStore);
|
|
3235
3585
|
loadSub;
|
|
3236
3586
|
lastContextKey = null;
|
|
3237
3587
|
currentExecution = null;
|
|
@@ -3243,7 +3593,12 @@ class WorkCenterItemModalFooterActions {
|
|
|
3243
3593
|
reloadTick = signal(0, ...(ngDevMode ? [{ debugName: "reloadTick" }] : /* istanbul ignore next */ []));
|
|
3244
3594
|
hasResolvedLoad = signal(false, ...(ngDevMode ? [{ debugName: "hasResolvedLoad" }] : /* istanbul ignore next */ []));
|
|
3245
3595
|
loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
3246
|
-
|
|
3596
|
+
errors = this.formStore.errors;
|
|
3597
|
+
/**
|
|
3598
|
+
* The modal body renders these above the form whenever it hosts a panel; the
|
|
3599
|
+
* footer keeps its own copy only for the item types that do not.
|
|
3600
|
+
*/
|
|
3601
|
+
showFooterErrors = computed(() => !this.formStore.hasErrorHost() && this.errors().length > 0, ...(ngDevMode ? [{ debugName: "showFooterErrors" }] : /* istanbul ignore next */ []));
|
|
3247
3602
|
actionData = signal(null, ...(ngDevMode ? [{ debugName: "actionData" }] : /* istanbul ignore next */ []));
|
|
3248
3603
|
actions = signal([], ...(ngDevMode ? [{ debugName: "actions" }] : /* istanbul ignore next */ []));
|
|
3249
3604
|
pendingActionKey = signal(null, ...(ngDevMode ? [{ debugName: "pendingActionKey" }] : /* istanbul ignore next */ []));
|
|
@@ -3256,11 +3611,12 @@ class WorkCenterItemModalFooterActions {
|
|
|
3256
3611
|
label: resolveActionLabel(action),
|
|
3257
3612
|
severity: resolveActionSeverity(action.actionKey, index),
|
|
3258
3613
|
variant: resolveActionVariant(action.actionKey, index),
|
|
3614
|
+
blockedByForm: this.formStore.incomplete() && commitsFormValues(action),
|
|
3259
3615
|
})), ...(ngDevMode ? [{ debugName: "displayActions" }] : /* istanbul ignore next */ []));
|
|
3260
3616
|
shouldRender = computed(() => !!this.contextKey() &&
|
|
3261
3617
|
(!this.hasResolvedLoad() ||
|
|
3262
3618
|
this.loading() ||
|
|
3263
|
-
|
|
3619
|
+
this.showFooterErrors() ||
|
|
3264
3620
|
!!this.previewLevelTarget() ||
|
|
3265
3621
|
this.displayActions().length > 0 ||
|
|
3266
3622
|
!!this.pendingActionKey()), ...(ngDevMode ? [{ debugName: "shouldRender" }] : /* istanbul ignore next */ []));
|
|
@@ -3268,7 +3624,7 @@ class WorkCenterItemModalFooterActions {
|
|
|
3268
3624
|
effect(() => {
|
|
3269
3625
|
const contextKey = this.contextKey();
|
|
3270
3626
|
this.reloadTick();
|
|
3271
|
-
this.
|
|
3627
|
+
this.formStore.setErrors([]);
|
|
3272
3628
|
if (!contextKey) {
|
|
3273
3629
|
this.lastContextKey = null;
|
|
3274
3630
|
this.actionData.set(null);
|
|
@@ -3309,7 +3665,7 @@ class WorkCenterItemModalFooterActions {
|
|
|
3309
3665
|
this.executeGeneralTaskUpdateAction(action);
|
|
3310
3666
|
return;
|
|
3311
3667
|
}
|
|
3312
|
-
this.
|
|
3668
|
+
this.formStore.setErrors([]);
|
|
3313
3669
|
this.pendingActionKey.set(action.actionKey);
|
|
3314
3670
|
const execution = { actionKey: action.actionKey, cancelled: false };
|
|
3315
3671
|
this.currentExecution = execution;
|
|
@@ -3323,10 +3679,9 @@ class WorkCenterItemModalFooterActions {
|
|
|
3323
3679
|
return;
|
|
3324
3680
|
}
|
|
3325
3681
|
if (result.status === 'error') {
|
|
3326
|
-
|
|
3682
|
+
this.formStore.setErrors(this.actionValidation.resolveErrorMessages(result.error, this.transloco.translate('workCenter.actions.executeFailed', {
|
|
3327
3683
|
action: action.label,
|
|
3328
|
-
}));
|
|
3329
|
-
this.error.set(message);
|
|
3684
|
+
})));
|
|
3330
3685
|
return;
|
|
3331
3686
|
}
|
|
3332
3687
|
const afterSuccess = result.afterSuccess ?? 'refresh';
|
|
@@ -3364,15 +3719,19 @@ class WorkCenterItemModalFooterActions {
|
|
|
3364
3719
|
this.actions.set([]);
|
|
3365
3720
|
this.loading.set(false);
|
|
3366
3721
|
this.hasResolvedLoad.set(true);
|
|
3367
|
-
this.
|
|
3722
|
+
this.formStore.setErrors([
|
|
3723
|
+
resolveHttpErrorMessage(error, this.transloco.translate('workCenter.actions.loadActionsFailed')),
|
|
3724
|
+
]);
|
|
3368
3725
|
},
|
|
3369
3726
|
});
|
|
3370
3727
|
}
|
|
3371
3728
|
executeGeneralTaskUpdateAction(action) {
|
|
3372
|
-
this.
|
|
3729
|
+
this.formStore.setErrors([]);
|
|
3373
3730
|
const modalData = this.buildGeneralTaskUpdateModalData(action);
|
|
3374
3731
|
if (!modalData.moduleDataId) {
|
|
3375
|
-
this.
|
|
3732
|
+
this.formStore.setErrors([
|
|
3733
|
+
this.transloco.translate('workCenter.error.missingModuleDataId'),
|
|
3734
|
+
]);
|
|
3376
3735
|
return;
|
|
3377
3736
|
}
|
|
3378
3737
|
this.pendingActionKey.set(action.actionKey);
|
|
@@ -3430,14 +3789,33 @@ class WorkCenterItemModalFooterActions {
|
|
|
3430
3789
|
};
|
|
3431
3790
|
}
|
|
3432
3791
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterItemModalFooterActions, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3433
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterItemModalFooterActions, isStandalone: true, selector: "mt-work-center-item-modal-footer-actions", inputs: { contextKey: { classPropertyName: "contextKey", publicName: "contextKey", isSignal: true, isRequired: false, transformFunction: null }, previewLevelTarget: { classPropertyName: "previewLevelTarget", publicName: "previewLevelTarget", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionExecuted: "actionExecuted", previewLevelSelected: "previewLevelSelected", visibilityChange: "visibilityChange" }, host: { classAttribute: "flex w-full flex-1 flex-wrap items-center justify-end gap-2" }, providers: [WorkCenterRuntimeActionExecutor], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'workCenter'\">\n @if (shouldRender()) {\n @if (
|
|
3792
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterItemModalFooterActions, isStandalone: true, selector: "mt-work-center-item-modal-footer-actions", inputs: { contextKey: { classPropertyName: "contextKey", publicName: "contextKey", isSignal: true, isRequired: false, transformFunction: null }, previewLevelTarget: { classPropertyName: "previewLevelTarget", publicName: "previewLevelTarget", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionExecuted: "actionExecuted", previewLevelSelected: "previewLevelSelected", visibilityChange: "visibilityChange" }, host: { classAttribute: "flex w-full flex-1 flex-wrap items-center justify-end gap-2" }, providers: [WorkCenterActionFormValidator, WorkCenterRuntimeActionExecutor], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'workCenter'\">\r\n @if (shouldRender()) {\r\n <!--\r\n Only reached for item types whose body has no `mt-work-center-action-errors`\r\n panel; everywhere else the messages render above the form instead. Takes a\r\n full-width row of its own (`basis-full` against the host's flex-wrap) so a\r\n multi-rule failure is not squeezed beside the buttons.\r\n -->\r\n @if (showFooterErrors()) {\r\n <div\r\n class=\"flex basis-full items-start gap-2 rounded-lg border border-red-200 bg-red-50 px-3 py-2.5 text-start\"\r\n role=\"alert\"\r\n >\r\n <span class=\"mt-px shrink-0 text-base text-red-500\">\r\n <mt-icon icon=\"alert.alert-circle\" />\r\n </span>\r\n @if (errors().length === 1) {\r\n <p class=\"m-0 min-w-0 break-words text-sm text-red-700\" dir=\"auto\">\r\n {{ errors()[0] }}\r\n </p>\r\n } @else {\r\n <ul\r\n class=\"m-0 flex min-w-0 list-disc flex-col gap-1 ps-4 text-sm text-red-700\"\r\n >\r\n @for (message of errors(); track message) {\r\n <li class=\"break-words\" dir=\"auto\">{{ message }}</li>\r\n }\r\n </ul>\r\n }\r\n </div>\r\n } @else if (loading() && !displayActions().length) {\r\n <span class=\"me-auto text-sm text-surface-500\">{{\r\n t(\"modal.loadingActions\")\r\n }}</span>\r\n }\r\n\r\n @if (previewLevelTarget(); as previewLevelTarget) {\r\n <mt-button\r\n [label]=\"previewLevelLabel(previewLevelTarget, t)\"\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n [disabled]=\"loading() || !!pendingActionKey()\"\r\n (onClick)=\"previewLevelSelected.emit(previewLevelTarget)\"\r\n />\r\n }\r\n\r\n @for (action of displayActions(); track action.actionKey + action.url) {\r\n <mt-button\r\n [label]=\"action.label\"\r\n [severity]=\"action.severity\"\r\n [variant]=\"action.variant\"\r\n [disabled]=\"loading() || !!pendingActionKey() || action.blockedByForm\"\r\n [tooltip]=\"\r\n action.blockedByForm ? t('actions.completeRequiredFields') : ''\r\n \"\r\n [loading]=\"pendingActionKey() === action.actionKey\"\r\n (onClick)=\"executeAction(action)\"\r\n />\r\n }\r\n }\r\n</ng-container>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }] });
|
|
3434
3793
|
}
|
|
3435
3794
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterItemModalFooterActions, decorators: [{
|
|
3436
3795
|
type: Component,
|
|
3437
|
-
args: [{ selector: 'mt-work-center-item-modal-footer-actions', standalone: true, imports: [CommonModule, TranslocoDirective, Button], host: {
|
|
3796
|
+
args: [{ selector: 'mt-work-center-item-modal-footer-actions', standalone: true, imports: [CommonModule, TranslocoDirective, Button, Icon], host: {
|
|
3438
3797
|
class: 'flex w-full flex-1 flex-wrap items-center justify-end gap-2',
|
|
3439
|
-
}, providers: [WorkCenterRuntimeActionExecutor], template: "<ng-container *transloco=\"let t; prefix: 'workCenter'\">\n @if (shouldRender()) {\n @if (
|
|
3798
|
+
}, providers: [WorkCenterActionFormValidator, WorkCenterRuntimeActionExecutor], template: "<ng-container *transloco=\"let t; prefix: 'workCenter'\">\r\n @if (shouldRender()) {\r\n <!--\r\n Only reached for item types whose body has no `mt-work-center-action-errors`\r\n panel; everywhere else the messages render above the form instead. Takes a\r\n full-width row of its own (`basis-full` against the host's flex-wrap) so a\r\n multi-rule failure is not squeezed beside the buttons.\r\n -->\r\n @if (showFooterErrors()) {\r\n <div\r\n class=\"flex basis-full items-start gap-2 rounded-lg border border-red-200 bg-red-50 px-3 py-2.5 text-start\"\r\n role=\"alert\"\r\n >\r\n <span class=\"mt-px shrink-0 text-base text-red-500\">\r\n <mt-icon icon=\"alert.alert-circle\" />\r\n </span>\r\n @if (errors().length === 1) {\r\n <p class=\"m-0 min-w-0 break-words text-sm text-red-700\" dir=\"auto\">\r\n {{ errors()[0] }}\r\n </p>\r\n } @else {\r\n <ul\r\n class=\"m-0 flex min-w-0 list-disc flex-col gap-1 ps-4 text-sm text-red-700\"\r\n >\r\n @for (message of errors(); track message) {\r\n <li class=\"break-words\" dir=\"auto\">{{ message }}</li>\r\n }\r\n </ul>\r\n }\r\n </div>\r\n } @else if (loading() && !displayActions().length) {\r\n <span class=\"me-auto text-sm text-surface-500\">{{\r\n t(\"modal.loadingActions\")\r\n }}</span>\r\n }\r\n\r\n @if (previewLevelTarget(); as previewLevelTarget) {\r\n <mt-button\r\n [label]=\"previewLevelLabel(previewLevelTarget, t)\"\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n [disabled]=\"loading() || !!pendingActionKey()\"\r\n (onClick)=\"previewLevelSelected.emit(previewLevelTarget)\"\r\n />\r\n }\r\n\r\n @for (action of displayActions(); track action.actionKey + action.url) {\r\n <mt-button\r\n [label]=\"action.label\"\r\n [severity]=\"action.severity\"\r\n [variant]=\"action.variant\"\r\n [disabled]=\"loading() || !!pendingActionKey() || action.blockedByForm\"\r\n [tooltip]=\"\r\n action.blockedByForm ? t('actions.completeRequiredFields') : ''\r\n \"\r\n [loading]=\"pendingActionKey() === action.actionKey\"\r\n (onClick)=\"executeAction(action)\"\r\n />\r\n }\r\n }\r\n</ng-container>\r\n" }]
|
|
3440
3799
|
}], ctorParameters: () => [], propDecorators: { contextKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "contextKey", required: false }] }], previewLevelTarget: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewLevelTarget", required: false }] }], actionExecuted: [{ type: i0.Output, args: ["actionExecuted"] }], previewLevelSelected: [{ type: i0.Output, args: ["previewLevelSelected"] }], visibilityChange: [{ type: i0.Output, args: ["visibilityChange"] }] } });
|
|
3800
|
+
// Only the actions that commit the edited values wait on the form being
|
|
3801
|
+
// locally valid. A negative outcome — reject, return, terminate — has to stay
|
|
3802
|
+
// available precisely when the form is incomplete, and Preview / Delete carry
|
|
3803
|
+
// no values at all.
|
|
3804
|
+
const NEGATIVE_OUTCOME_ACTION_KEYS = new Set([
|
|
3805
|
+
'reject',
|
|
3806
|
+
'return',
|
|
3807
|
+
'terminate',
|
|
3808
|
+
'cancel',
|
|
3809
|
+
'close',
|
|
3810
|
+
'delete',
|
|
3811
|
+
]);
|
|
3812
|
+
function commitsFormValues(action) {
|
|
3813
|
+
if (NEGATIVE_OUTCOME_ACTION_KEYS.has(normalizeKey(action.actionKey))) {
|
|
3814
|
+
return false;
|
|
3815
|
+
}
|
|
3816
|
+
return ((action.payloadKeys ?? []).includes('values') ||
|
|
3817
|
+
(!!action.payloadTemplate && 'values' in action.payloadTemplate));
|
|
3818
|
+
}
|
|
3441
3819
|
function normalizeMethod(value) {
|
|
3442
3820
|
if (!value || typeof value !== 'string') {
|
|
3443
3821
|
return null;
|
|
@@ -3720,7 +4098,7 @@ class WorkCenterItemModalRoute {
|
|
|
3720
4098
|
};
|
|
3721
4099
|
}
|
|
3722
4100
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterItemModalRoute, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3723
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterItemModalRoute, isStandalone: true, selector: "mt-work-center-item-modal-route", inputs: { contextKey: { classPropertyName: "contextKey", publicName: "contextKey", isSignal: true, isRequired: false, transformFunction: null }, manageRouteOutlet: { classPropertyName: "manageRouteOutlet", publicName: "manageRouteOutlet", isSignal: true, isRequired: false, transformFunction: null }, showPreviewLevelAction: { classPropertyName: "showPreviewLevelAction", publicName: "showPreviewLevelAction", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, appendTo: { classPropertyName: "appendTo", publicName: "appendTo", isSignal: true, isRequired: false, transformFunction: null }, drawerStyleClass: { classPropertyName: "drawerStyleClass", publicName: "drawerStyleClass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { previewLevel: "previewLevel", closed: "closed" }, providers: [RuntimeActionContextStore], ngImport: i0, template: "<mt-drawer\r\n [visible]=\"drawerVisible()\"\r\n [loadingHeader]=\"loading()\"\r\n [title]=\"drawerTitle()\"\r\n [styleClass]=\"drawerStyleClass()\"\r\n [appendTo]=\"appendTo()\"\r\n position=\"right\"\r\n [modal]=\"true\"\r\n (visibleChange)=\"onVisibleChange($event)\"\r\n *transloco=\"let t; prefix: 'workCenter'\"\r\n>\r\n <ng-container content>\r\n @if (loading()) {\r\n <div class=\"p-4\" [class]=\"modal.contentClass\">\r\n <div class=\"flex min-h-[22rem] flex-col gap-5\">\r\n <div class=\"flex items-center gap-3\">\r\n <p-skeleton shape=\"circle\" size=\"3rem\" />\r\n <div class=\"flex flex-1 flex-col gap-2\">\r\n <p-skeleton width=\"12rem\" height=\"1rem\" />\r\n <p-skeleton width=\"8rem\" height=\"0.875rem\" />\r\n </div>\r\n </div>\r\n\r\n <div class=\"grid gap-3 md:grid-cols-2\">\r\n @for (_ of [1, 2, 3, 4]; track $index) {\r\n <p-skeleton height=\"5rem\" class=\"rounded-lg\" />\r\n }\r\n </div>\r\n\r\n <p-skeleton height=\"16rem\" class=\"rounded-lg\" />\r\n </div>\r\n </div>\r\n } @else if (error(); as errorMessage) {\r\n <div class=\"p-4\" [class]=\"modal.contentClass\">\r\n <div class=\"flex min-h-[22rem] items-center justify-center\">\r\n <p class=\"max-w-xl text-sm font-medium text-red-600\">\r\n {{ errorMessage }}\r\n </p>\r\n </div>\r\n </div>\r\n } @else if (details(); as details) {\r\n <div [class]=\"modal.contentClass + ' h-full min-h-0'\">\r\n <mt-work-center-item-modal\r\n [details]=\"details\"\r\n [lookups]=\"lookups()\"\r\n [readOnly]=\"readOnly()\"\r\n />\r\n </div>\r\n } @else {\r\n <div class=\"p-4\" [class]=\"modal.contentClass\">\r\n <div class=\"flex min-h-[22rem] items-center justify-center\">\r\n <p class=\"text-sm font-medium text-surface-500\">\r\n {{ t(\"modal.noItemSelected\") }}\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n </ng-container>\r\n\r\n @if (!readOnly() && footerActionsMounted()) {\r\n <div footer [class]=\"modal.footerClass\">\r\n <mt-work-center-item-modal-footer-actions\r\n [contextKey]=\"resolvedContextKey()\"\r\n [previewLevelTarget]=\"displayedPreviewLevelTarget()\"\r\n (actionExecuted)=\"onActionExecuted($event)\"\r\n (previewLevelSelected)=\"onPreviewLevelSelected($event)\"\r\n (visibilityChange)=\"onFooterVisibilityChange($event)\"\r\n />\r\n </div>\r\n }\r\n</mt-drawer>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Drawer, selector: "mt-drawer", inputs: ["visible", "position", "fullScreen", "closeOnEscape", "blockScroll", "dismissible", "title", "subtitle", "loadingHeader", "styleClass", "transitionOptions", "appendTo", "modal", "showMaximizeToggle", "maximizeTooltip", "restoreTooltip", "maximized"], outputs: ["visibleChange", "onShow", "onHide", "maximizedChange"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i1$1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: WorkCenterItemModal, selector: "mt-work-center-item-modal", inputs: ["details", "lookups", "readOnly"] }, { kind: "component", type: WorkCenterItemModalFooterActions, selector: "mt-work-center-item-modal-footer-actions", inputs: ["contextKey", "previewLevelTarget"], outputs: ["actionExecuted", "previewLevelSelected", "visibilityChange"] }] });
|
|
4101
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterItemModalRoute, isStandalone: true, selector: "mt-work-center-item-modal-route", inputs: { contextKey: { classPropertyName: "contextKey", publicName: "contextKey", isSignal: true, isRequired: false, transformFunction: null }, manageRouteOutlet: { classPropertyName: "manageRouteOutlet", publicName: "manageRouteOutlet", isSignal: true, isRequired: false, transformFunction: null }, showPreviewLevelAction: { classPropertyName: "showPreviewLevelAction", publicName: "showPreviewLevelAction", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, appendTo: { classPropertyName: "appendTo", publicName: "appendTo", isSignal: true, isRequired: false, transformFunction: null }, drawerStyleClass: { classPropertyName: "drawerStyleClass", publicName: "drawerStyleClass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { previewLevel: "previewLevel", closed: "closed" }, providers: [RuntimeActionContextStore, WorkCenterActionFormStore], ngImport: i0, template: "<mt-drawer\r\n [visible]=\"drawerVisible()\"\r\n [loadingHeader]=\"loading()\"\r\n [title]=\"drawerTitle()\"\r\n [styleClass]=\"drawerStyleClass()\"\r\n [appendTo]=\"appendTo()\"\r\n position=\"right\"\r\n [modal]=\"true\"\r\n (visibleChange)=\"onVisibleChange($event)\"\r\n *transloco=\"let t; prefix: 'workCenter'\"\r\n>\r\n <ng-container content>\r\n @if (loading()) {\r\n <div class=\"p-4\" [class]=\"modal.contentClass\">\r\n <div class=\"flex min-h-[22rem] flex-col gap-5\">\r\n <div class=\"flex items-center gap-3\">\r\n <p-skeleton shape=\"circle\" size=\"3rem\" />\r\n <div class=\"flex flex-1 flex-col gap-2\">\r\n <p-skeleton width=\"12rem\" height=\"1rem\" />\r\n <p-skeleton width=\"8rem\" height=\"0.875rem\" />\r\n </div>\r\n </div>\r\n\r\n <div class=\"grid gap-3 md:grid-cols-2\">\r\n @for (_ of [1, 2, 3, 4]; track $index) {\r\n <p-skeleton height=\"5rem\" class=\"rounded-lg\" />\r\n }\r\n </div>\r\n\r\n <p-skeleton height=\"16rem\" class=\"rounded-lg\" />\r\n </div>\r\n </div>\r\n } @else if (error(); as errorMessage) {\r\n <div class=\"p-4\" [class]=\"modal.contentClass\">\r\n <div class=\"flex min-h-[22rem] items-center justify-center\">\r\n <p class=\"max-w-xl text-sm font-medium text-red-600\">\r\n {{ errorMessage }}\r\n </p>\r\n </div>\r\n </div>\r\n } @else if (details(); as details) {\r\n <div [class]=\"modal.contentClass + ' h-full min-h-0'\">\r\n <mt-work-center-item-modal\r\n [details]=\"details\"\r\n [lookups]=\"lookups()\"\r\n [readOnly]=\"readOnly()\"\r\n />\r\n </div>\r\n } @else {\r\n <div class=\"p-4\" [class]=\"modal.contentClass\">\r\n <div class=\"flex min-h-[22rem] items-center justify-center\">\r\n <p class=\"text-sm font-medium text-surface-500\">\r\n {{ t(\"modal.noItemSelected\") }}\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n </ng-container>\r\n\r\n @if (!readOnly() && footerActionsMounted()) {\r\n <div footer [class]=\"modal.footerClass\">\r\n <mt-work-center-item-modal-footer-actions\r\n [contextKey]=\"resolvedContextKey()\"\r\n [previewLevelTarget]=\"displayedPreviewLevelTarget()\"\r\n (actionExecuted)=\"onActionExecuted($event)\"\r\n (previewLevelSelected)=\"onPreviewLevelSelected($event)\"\r\n (visibilityChange)=\"onFooterVisibilityChange($event)\"\r\n />\r\n </div>\r\n }\r\n</mt-drawer>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Drawer, selector: "mt-drawer", inputs: ["visible", "position", "fullScreen", "closeOnEscape", "blockScroll", "dismissible", "title", "subtitle", "loadingHeader", "styleClass", "transitionOptions", "appendTo", "modal", "showMaximizeToggle", "maximizeTooltip", "restoreTooltip", "maximized"], outputs: ["visibleChange", "onShow", "onHide", "maximizedChange"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i1$1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: WorkCenterItemModal, selector: "mt-work-center-item-modal", inputs: ["details", "lookups", "readOnly"] }, { kind: "component", type: WorkCenterItemModalFooterActions, selector: "mt-work-center-item-modal-footer-actions", inputs: ["contextKey", "previewLevelTarget"], outputs: ["actionExecuted", "previewLevelSelected", "visibilityChange"] }] });
|
|
3724
4102
|
}
|
|
3725
4103
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterItemModalRoute, decorators: [{
|
|
3726
4104
|
type: Component,
|
|
@@ -3731,7 +4109,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
3731
4109
|
SkeletonModule,
|
|
3732
4110
|
WorkCenterItemModal,
|
|
3733
4111
|
WorkCenterItemModalFooterActions,
|
|
3734
|
-
], providers: [RuntimeActionContextStore], template: "<mt-drawer\r\n [visible]=\"drawerVisible()\"\r\n [loadingHeader]=\"loading()\"\r\n [title]=\"drawerTitle()\"\r\n [styleClass]=\"drawerStyleClass()\"\r\n [appendTo]=\"appendTo()\"\r\n position=\"right\"\r\n [modal]=\"true\"\r\n (visibleChange)=\"onVisibleChange($event)\"\r\n *transloco=\"let t; prefix: 'workCenter'\"\r\n>\r\n <ng-container content>\r\n @if (loading()) {\r\n <div class=\"p-4\" [class]=\"modal.contentClass\">\r\n <div class=\"flex min-h-[22rem] flex-col gap-5\">\r\n <div class=\"flex items-center gap-3\">\r\n <p-skeleton shape=\"circle\" size=\"3rem\" />\r\n <div class=\"flex flex-1 flex-col gap-2\">\r\n <p-skeleton width=\"12rem\" height=\"1rem\" />\r\n <p-skeleton width=\"8rem\" height=\"0.875rem\" />\r\n </div>\r\n </div>\r\n\r\n <div class=\"grid gap-3 md:grid-cols-2\">\r\n @for (_ of [1, 2, 3, 4]; track $index) {\r\n <p-skeleton height=\"5rem\" class=\"rounded-lg\" />\r\n }\r\n </div>\r\n\r\n <p-skeleton height=\"16rem\" class=\"rounded-lg\" />\r\n </div>\r\n </div>\r\n } @else if (error(); as errorMessage) {\r\n <div class=\"p-4\" [class]=\"modal.contentClass\">\r\n <div class=\"flex min-h-[22rem] items-center justify-center\">\r\n <p class=\"max-w-xl text-sm font-medium text-red-600\">\r\n {{ errorMessage }}\r\n </p>\r\n </div>\r\n </div>\r\n } @else if (details(); as details) {\r\n <div [class]=\"modal.contentClass + ' h-full min-h-0'\">\r\n <mt-work-center-item-modal\r\n [details]=\"details\"\r\n [lookups]=\"lookups()\"\r\n [readOnly]=\"readOnly()\"\r\n />\r\n </div>\r\n } @else {\r\n <div class=\"p-4\" [class]=\"modal.contentClass\">\r\n <div class=\"flex min-h-[22rem] items-center justify-center\">\r\n <p class=\"text-sm font-medium text-surface-500\">\r\n {{ t(\"modal.noItemSelected\") }}\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n </ng-container>\r\n\r\n @if (!readOnly() && footerActionsMounted()) {\r\n <div footer [class]=\"modal.footerClass\">\r\n <mt-work-center-item-modal-footer-actions\r\n [contextKey]=\"resolvedContextKey()\"\r\n [previewLevelTarget]=\"displayedPreviewLevelTarget()\"\r\n (actionExecuted)=\"onActionExecuted($event)\"\r\n (previewLevelSelected)=\"onPreviewLevelSelected($event)\"\r\n (visibilityChange)=\"onFooterVisibilityChange($event)\"\r\n />\r\n </div>\r\n }\r\n</mt-drawer>\r\n" }]
|
|
4112
|
+
], providers: [RuntimeActionContextStore, WorkCenterActionFormStore], template: "<mt-drawer\r\n [visible]=\"drawerVisible()\"\r\n [loadingHeader]=\"loading()\"\r\n [title]=\"drawerTitle()\"\r\n [styleClass]=\"drawerStyleClass()\"\r\n [appendTo]=\"appendTo()\"\r\n position=\"right\"\r\n [modal]=\"true\"\r\n (visibleChange)=\"onVisibleChange($event)\"\r\n *transloco=\"let t; prefix: 'workCenter'\"\r\n>\r\n <ng-container content>\r\n @if (loading()) {\r\n <div class=\"p-4\" [class]=\"modal.contentClass\">\r\n <div class=\"flex min-h-[22rem] flex-col gap-5\">\r\n <div class=\"flex items-center gap-3\">\r\n <p-skeleton shape=\"circle\" size=\"3rem\" />\r\n <div class=\"flex flex-1 flex-col gap-2\">\r\n <p-skeleton width=\"12rem\" height=\"1rem\" />\r\n <p-skeleton width=\"8rem\" height=\"0.875rem\" />\r\n </div>\r\n </div>\r\n\r\n <div class=\"grid gap-3 md:grid-cols-2\">\r\n @for (_ of [1, 2, 3, 4]; track $index) {\r\n <p-skeleton height=\"5rem\" class=\"rounded-lg\" />\r\n }\r\n </div>\r\n\r\n <p-skeleton height=\"16rem\" class=\"rounded-lg\" />\r\n </div>\r\n </div>\r\n } @else if (error(); as errorMessage) {\r\n <div class=\"p-4\" [class]=\"modal.contentClass\">\r\n <div class=\"flex min-h-[22rem] items-center justify-center\">\r\n <p class=\"max-w-xl text-sm font-medium text-red-600\">\r\n {{ errorMessage }}\r\n </p>\r\n </div>\r\n </div>\r\n } @else if (details(); as details) {\r\n <div [class]=\"modal.contentClass + ' h-full min-h-0'\">\r\n <mt-work-center-item-modal\r\n [details]=\"details\"\r\n [lookups]=\"lookups()\"\r\n [readOnly]=\"readOnly()\"\r\n />\r\n </div>\r\n } @else {\r\n <div class=\"p-4\" [class]=\"modal.contentClass\">\r\n <div class=\"flex min-h-[22rem] items-center justify-center\">\r\n <p class=\"text-sm font-medium text-surface-500\">\r\n {{ t(\"modal.noItemSelected\") }}\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n </ng-container>\r\n\r\n @if (!readOnly() && footerActionsMounted()) {\r\n <div footer [class]=\"modal.footerClass\">\r\n <mt-work-center-item-modal-footer-actions\r\n [contextKey]=\"resolvedContextKey()\"\r\n [previewLevelTarget]=\"displayedPreviewLevelTarget()\"\r\n (actionExecuted)=\"onActionExecuted($event)\"\r\n (previewLevelSelected)=\"onPreviewLevelSelected($event)\"\r\n (visibilityChange)=\"onFooterVisibilityChange($event)\"\r\n />\r\n </div>\r\n }\r\n</mt-drawer>\r\n" }]
|
|
3735
4113
|
}], ctorParameters: () => [], propDecorators: { contextKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "contextKey", required: false }] }], manageRouteOutlet: [{ type: i0.Input, args: [{ isSignal: true, alias: "manageRouteOutlet", required: false }] }], showPreviewLevelAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPreviewLevelAction", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], appendTo: [{ type: i0.Input, args: [{ isSignal: true, alias: "appendTo", required: false }] }], drawerStyleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "drawerStyleClass", required: false }] }], previewLevel: [{ type: i0.Output, args: ["previewLevel"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
|
|
3736
4114
|
// Accepts either a plain string (e.g. `moduleKey`) or a localized
|
|
3737
4115
|
// `{ display, en, ar }` translatable, returning the display string.
|
|
@@ -4286,7 +4664,7 @@ class WorkCenterPage {
|
|
|
4286
4664
|
return normalized.length ? normalized : null;
|
|
4287
4665
|
}
|
|
4288
4666
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterPage, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4289
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterPage, isStandalone: true, selector: "mt-work-center-page", inputs: { area: { classPropertyName: "area", publicName: "area", isSignal: true, isRequired: false, transformFunction: null }, pageTitle: { classPropertyName: "pageTitle", publicName: "pageTitle", isSignal: true, isRequired: false, transformFunction: null }, menuIcon: { classPropertyName: "menuIcon", publicName: "menuIcon", isSignal: true, isRequired: false, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null }, showSidebar: { classPropertyName: "showSidebar", publicName: "showSidebar", isSignal: true, isRequired: false, transformFunction: null }, bootstrapInputs: { classPropertyName: "bootstrapInputs", publicName: "bootstrapInputs", isSignal: true, isRequired: false, transformFunction: null }, openItemDrawer: { classPropertyName: "openItemDrawer", publicName: "openItemDrawer", isSignal: true, isRequired: false, transformFunction: null }, itemReadOnly: { classPropertyName: "itemReadOnly", publicName: "itemReadOnly", isSignal: true, isRequired: false, transformFunction: null }, openItemsInModal: { classPropertyName: "openItemsInModal", publicName: "openItemsInModal", isSignal: true, isRequired: false, transformFunction: null }, itemModal: { classPropertyName: "itemModal", publicName: "itemModal", isSignal: true, isRequired: false, transformFunction: null }, generalTaskModal: { classPropertyName: "generalTaskModal", publicName: "generalTaskModal", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { runtimeFiltersChanged: "runtimeFiltersChanged", itemClicked: "itemClicked", cardSelected: "cardSelected", sortChanged: "sortChanged", groupChanged: "groupChanged" }, ngImport: i0, template: "<ng-template #headerActions>\r\n <div class=\"flex flex-wrap items-center justify-end gap-2\">\r\n <mt-property-filter-builder\r\n [schema]=\"propertyFilterSchema()\"\r\n [filters]=\"headerFilters()\"\r\n (applied)=\"onRuntimeFiltersApplied($event)\"\r\n (cleared)=\"onRuntimeFiltersCleared()\"\r\n />\r\n\r\n @if (showGeneralTaskCreateButton()) {\r\n <mt-button\r\n [label]=\"generalTaskButtonLabel()\"\r\n [icon]=\"generalTaskButtonIcon()\"\r\n size=\"small\"\r\n (onClick)=\"onGeneralTaskCreateClick()\"\r\n />\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #pageContent>\r\n <div class=\"flex flex-col gap-8\">\r\n @if (loading()) {\r\n <div\r\n class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 gap-3\"\r\n >\r\n @for (_ of [1, 2, 3, 4, 5]; track $index) {\r\n <p-skeleton height=\"6.5rem\" class=\"rounded-lg\" />\r\n }\r\n </div>\r\n } @else if (kpis().length) {\r\n <div class=\"gap-3 flex flex-wrap\">\r\n @for (kpi of kpis(); track $index) {\r\n <mt-statistic-card [data]=\"kpi\" class=\"min-w-[200px]\" />\r\n }\r\n </div>\r\n }\r\n\r\n <mt-table\r\n noCard\r\n [data]=\"rows()\"\r\n [columns]=\"tableColumns()\"\r\n tableLayout=\"auto\"\r\n [clickableRows]=\"rowsClickable()\"\r\n [loading]=\"loading()\"\r\n [showFilters]=\"true\"\r\n filterMode=\"column\"\r\n [cellClickFilter]=\"true\"\r\n [generalSearch]=\"true\"\r\n [exportable]=\"true\"\r\n [printable]=\"true\"\r\n [groupable]=\"true\"\r\n [freezeActions]=\"true\"\r\n [lazy]=\"true\"\r\n [lazyLocalSearch]=\"true\"\r\n [lazyTotalRecords]=\"totalCount()\"\r\n [pageSize]=\"context().pageSize\"\r\n [currentPage]=\"context().page - 1\"\r\n [first]=\"(context().page - 1) * context().pageSize\"\r\n [rowsPerPageOptions]=\"[10, 20, 50, 100]\"\r\n [groupCountMap]=\"groupCountMap()\"\r\n [groupBy]=\"groupBy()\"\r\n [sortField]=\"sortField()\"\r\n [sortDirection]=\"sortDirection()\"\r\n storageKey=\"work-center-page-table\"\r\n [persistStateExclude]=\"persistStateExclude\"\r\n [filters]=\"tableFilters()\"\r\n (filtersChange)=\"tableFilters.set($event)\"\r\n (groupByChange)=\"onTableGroupByChange($event)\"\r\n (lazyLoad)=\"onTableLazyLoad($event)\"\r\n (rowClick)=\"onRowClick($event)\"\r\n />\r\n </div>\r\n</ng-template>\r\n\r\n@if (showSidebar()) {\r\n <mt-client-page\r\n [menuIcon]=\"menuIcon()\"\r\n [menuTitle]=\"resolvedPageTitle()\"\r\n [menuItems]=\"menuItems()\"\r\n [menuItemsLoading]=\"loading() && !menuItems().length\"\r\n [activeItem]=\"context().selectedCardKey ?? undefined\"\r\n (menuItemClick)=\"onMenuItemClick($event)\"\r\n >\r\n <ng-template #headerClientPageEnd>\r\n <ng-container [ngTemplateOutlet]=\"headerActions\" />\r\n </ng-template>\r\n\r\n <ng-container [ngTemplateOutlet]=\"pageContent\" />\r\n </mt-client-page>\r\n} @else {\r\n <div class=\"flex h-full min-h-0 flex-col bg-surface-0\">\r\n <div\r\n class=\"flex shrink-0 items-center justify-end border-b border-surface px-7 py-4\"\r\n >\r\n <ng-container [ngTemplateOutlet]=\"headerActions\" />\r\n </div>\r\n <div class=\"min-h-0 flex-1 overflow-y-auto px-7 py-5\">\r\n <ng-container [ngTemplateOutlet]=\"pageContent\" />\r\n </div>\r\n </div>\r\n}\r\n\r\n@if (selectedItemContextKey(); as contextKey) {\r\n <mt-work-center-item-modal-route\r\n [contextKey]=\"contextKey\"\r\n [manageRouteOutlet]=\"false\"\r\n [showPreviewLevelAction]=\"false\"\r\n [readOnly]=\"itemReadOnly()\"\r\n appendTo=\"body\"\r\n drawerStyleClass=\"mt-work-center-item-drawer !w-[90vw]\"\r\n (closed)=\"selectedItemContextKey.set(null)\"\r\n />\r\n}\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: ClientPage, selector: "mt-client-page", inputs: ["menuIcon", "menuTitle", "menuItems", "menuItemsLoading", "activeItem", "collapsed", "resizable", "storageKey", "storageMode", "minSidebarWidth", "maxSidebarWidth", "defaultSidebarWidth"], outputs: ["collapsedChange", "menuItemClick", "loadChildren"] }, { kind: "component", type: PropertyFilterBuilder, selector: "mt-property-filter-builder", inputs: ["schema", "filters", "title", "buttonLabel", "disabled"], outputs: ["filtersChange", "applied", "cleared"] }, { kind: "component", type: StatisticCard, selector: "mt-statistic-card", inputs: ["data", "cardClass"] }, { kind: "component", type: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "clickableRows", "generalSearch", "lazyLocalSearch", "showFilters", "filterMode", "loading", "updating", "lazy", "lazyLocalSort", "lazyTotalRecords", "reorderableColumns", "reorderableRows", "dataKey", "storageKey", "storageMode", "persistStateExclude", "exportable", "printable", "groupable", "groupCountMap", "cellClickFilter", "freezeActions", "virtualScroll", "virtualScrollItemSize", "scrollHeight", "printTitle", "exportFilename", "actionShape", "rowActionsLoadingFn", "tableLayout", "noCard", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "emptyTitle", "emptyDescription", "emptyActionLabel", "emptyActionIcon", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm", "groupBy", "sortField", "sortDirection"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "emptyAction", "rowActionsRequested", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange", "groupByChange", "sortFieldChange", "sortDirectionChange"] }, { kind: "component", type: WorkCenterItemModalRoute, selector: "mt-work-center-item-modal-route", inputs: ["contextKey", "manageRouteOutlet", "showPreviewLevelAction", "readOnly", "appendTo", "drawerStyleClass"], outputs: ["previewLevel", "closed"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i1$1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }] });
|
|
4667
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterPage, isStandalone: true, selector: "mt-work-center-page", inputs: { area: { classPropertyName: "area", publicName: "area", isSignal: true, isRequired: false, transformFunction: null }, pageTitle: { classPropertyName: "pageTitle", publicName: "pageTitle", isSignal: true, isRequired: false, transformFunction: null }, menuIcon: { classPropertyName: "menuIcon", publicName: "menuIcon", isSignal: true, isRequired: false, transformFunction: null }, lookups: { classPropertyName: "lookups", publicName: "lookups", isSignal: true, isRequired: false, transformFunction: null }, showSidebar: { classPropertyName: "showSidebar", publicName: "showSidebar", isSignal: true, isRequired: false, transformFunction: null }, bootstrapInputs: { classPropertyName: "bootstrapInputs", publicName: "bootstrapInputs", isSignal: true, isRequired: false, transformFunction: null }, openItemDrawer: { classPropertyName: "openItemDrawer", publicName: "openItemDrawer", isSignal: true, isRequired: false, transformFunction: null }, itemReadOnly: { classPropertyName: "itemReadOnly", publicName: "itemReadOnly", isSignal: true, isRequired: false, transformFunction: null }, openItemsInModal: { classPropertyName: "openItemsInModal", publicName: "openItemsInModal", isSignal: true, isRequired: false, transformFunction: null }, itemModal: { classPropertyName: "itemModal", publicName: "itemModal", isSignal: true, isRequired: false, transformFunction: null }, generalTaskModal: { classPropertyName: "generalTaskModal", publicName: "generalTaskModal", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { runtimeFiltersChanged: "runtimeFiltersChanged", itemClicked: "itemClicked", cardSelected: "cardSelected", sortChanged: "sortChanged", groupChanged: "groupChanged" }, ngImport: i0, template: "<ng-template #headerActions>\r\n <div class=\"flex flex-wrap items-center justify-end gap-2\">\r\n <mt-property-filter-builder\r\n [schema]=\"propertyFilterSchema()\"\r\n [filters]=\"headerFilters()\"\r\n (applied)=\"onRuntimeFiltersApplied($event)\"\r\n (cleared)=\"onRuntimeFiltersCleared()\"\r\n />\r\n\r\n @if (showGeneralTaskCreateButton()) {\r\n <mt-button\r\n [label]=\"generalTaskButtonLabel()\"\r\n [icon]=\"generalTaskButtonIcon()\"\r\n size=\"small\"\r\n (onClick)=\"onGeneralTaskCreateClick()\"\r\n />\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #pageContent>\r\n <div class=\"flex flex-col gap-8\">\r\n @if (loading()) {\r\n <div\r\n class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 gap-3\"\r\n >\r\n @for (_ of [1, 2, 3, 4, 5]; track $index) {\r\n <p-skeleton height=\"6.5rem\" class=\"rounded-lg\" />\r\n }\r\n </div>\r\n } @else if (kpis().length) {\r\n <div class=\"gap-3 flex flex-wrap\">\r\n @for (kpi of kpis(); track $index) {\r\n <mt-statistic-card [data]=\"kpi\" class=\"min-w-[200px]\" />\r\n }\r\n </div>\r\n }\r\n\r\n <mt-table\r\n noCard\r\n [data]=\"rows()\"\r\n [columns]=\"tableColumns()\"\r\n tableLayout=\"auto\"\r\n [clickableRows]=\"rowsClickable()\"\r\n [loading]=\"loading()\"\r\n [showFilters]=\"true\"\r\n filterMode=\"column\"\r\n [cellClickFilter]=\"true\"\r\n [generalSearch]=\"true\"\r\n [exportable]=\"true\"\r\n [printable]=\"true\"\r\n [groupable]=\"true\"\r\n [freezeActions]=\"true\"\r\n [lazy]=\"true\"\r\n [lazyLocalSearch]=\"true\"\r\n [lazyTotalRecords]=\"totalCount()\"\r\n [pageSize]=\"context().pageSize\"\r\n [currentPage]=\"context().page - 1\"\r\n [first]=\"(context().page - 1) * context().pageSize\"\r\n [rowsPerPageOptions]=\"[10, 20, 50, 100]\"\r\n [groupCountMap]=\"groupCountMap()\"\r\n [groupBy]=\"groupBy()\"\r\n [sortField]=\"sortField()\"\r\n [sortDirection]=\"sortDirection()\"\r\n storageKey=\"work-center-page-table\"\r\n [persistStateExclude]=\"persistStateExclude\"\r\n [filters]=\"tableFilters()\"\r\n (filtersChange)=\"tableFilters.set($event)\"\r\n (groupByChange)=\"onTableGroupByChange($event)\"\r\n (lazyLoad)=\"onTableLazyLoad($event)\"\r\n (rowClick)=\"onRowClick($event)\"\r\n />\r\n </div>\r\n</ng-template>\r\n\r\n@if (showSidebar()) {\r\n <mt-client-page\r\n [menuIcon]=\"menuIcon()\"\r\n [menuTitle]=\"resolvedPageTitle()\"\r\n [menuItems]=\"menuItems()\"\r\n [menuItemsLoading]=\"loading() && !menuItems().length\"\r\n [activeItem]=\"context().selectedCardKey ?? undefined\"\r\n (menuItemClick)=\"onMenuItemClick($event)\"\r\n >\r\n <ng-template #headerClientPageEnd>\r\n <ng-container [ngTemplateOutlet]=\"headerActions\" />\r\n </ng-template>\r\n\r\n <ng-container [ngTemplateOutlet]=\"pageContent\" />\r\n </mt-client-page>\r\n} @else {\r\n <div class=\"flex h-full min-h-0 flex-col bg-surface-0\">\r\n <div\r\n class=\"flex shrink-0 items-center justify-end border-b border-surface px-7 py-4\"\r\n >\r\n <ng-container [ngTemplateOutlet]=\"headerActions\" />\r\n </div>\r\n <div class=\"min-h-0 flex-1 overflow-y-auto px-7 py-5\">\r\n <ng-container [ngTemplateOutlet]=\"pageContent\" />\r\n </div>\r\n </div>\r\n}\r\n\r\n@if (selectedItemContextKey(); as contextKey) {\r\n <mt-work-center-item-modal-route\r\n [contextKey]=\"contextKey\"\r\n [manageRouteOutlet]=\"false\"\r\n [showPreviewLevelAction]=\"false\"\r\n [readOnly]=\"itemReadOnly()\"\r\n appendTo=\"body\"\r\n drawerStyleClass=\"mt-work-center-item-drawer !w-[90vw]\"\r\n (closed)=\"selectedItemContextKey.set(null)\"\r\n />\r\n}\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: ClientPage, selector: "mt-client-page", inputs: ["menuIcon", "menuTitle", "menuItems", "menuItemsLoading", "activeItem", "collapsed", "resizable", "storageKey", "storageMode", "minSidebarWidth", "maxSidebarWidth", "defaultSidebarWidth"], outputs: ["collapsedChange", "menuItemClick", "loadChildren"] }, { kind: "component", type: PropertyFilterBuilder, selector: "mt-property-filter-builder", inputs: ["schema", "filters", "title", "buttonLabel", "disabled"], outputs: ["filtersChange", "applied", "cleared"] }, { kind: "component", type: StatisticCard, selector: "mt-statistic-card", inputs: ["data", "cardClass"] }, { kind: "component", type: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "clickableRows", "generalSearch", "lazyLocalSearch", "showFilters", "filterMode", "loading", "updating", "lazy", "lazyLocalSort", "lazyTotalRecords", "reorderableColumns", "reorderableRows", "dataKey", "storageKey", "storageMode", "persistStateExclude", "exportable", "printable", "groupable", "groupCountMap", "cellClickFilter", "freezeActions", "virtualScroll", "virtualScrollItemSize", "scrollHeight", "printTitle", "exportFilename", "actionShape", "rowActionsLoadingFn", "tableLayout", "noCard", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "captionStartTemplate", "captionEndTemplate", "emptyTitle", "emptyDescription", "emptyActionLabel", "emptyActionIcon", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm", "groupBy", "sortField", "sortDirection"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "emptyAction", "rowActionsRequested", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange", "groupByChange", "sortFieldChange", "sortDirectionChange"] }, { kind: "component", type: WorkCenterItemModalRoute, selector: "mt-work-center-item-modal-route", inputs: ["contextKey", "manageRouteOutlet", "showPreviewLevelAction", "readOnly", "appendTo", "drawerStyleClass"], outputs: ["previewLevel", "closed"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i1$1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }] });
|
|
4290
4668
|
}
|
|
4291
4669
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterPage, decorators: [{
|
|
4292
4670
|
type: Component,
|