@masterteam/system-settings 0.0.22 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/i18n/ar.json +601 -442
- package/assets/i18n/en.json +601 -442
- package/assets/system-settings.css +1 -1
- package/fesm2022/{masterteam-system-settings-email-delivery-shell-oTWOzKWj.mjs → masterteam-system-settings-email-delivery-shell-D9NShoTc.mjs} +260 -17
- package/fesm2022/masterteam-system-settings-email-delivery-shell-D9NShoTc.mjs.map +1 -0
- package/fesm2022/{masterteam-system-settings-masterteam-system-settings-7I4TfgwP.mjs → masterteam-system-settings-masterteam-system-settings-C51hZw-Q.mjs} +1251 -13
- package/fesm2022/masterteam-system-settings-masterteam-system-settings-C51hZw-Q.mjs.map +1 -0
- package/fesm2022/masterteam-system-settings.mjs +1 -1
- package/package.json +3 -3
- package/types/masterteam-system-settings.d.ts +308 -5
- package/fesm2022/masterteam-system-settings-email-delivery-shell-oTWOzKWj.mjs.map +0 -1
- package/fesm2022/masterteam-system-settings-masterteam-system-settings-7I4TfgwP.mjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, inject, ChangeDetectionStrategy, Component, signal, computed, DestroyRef } from '@angular/core';
|
|
3
|
-
import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
2
|
+
import { input, inject, ChangeDetectionStrategy, Component, signal, computed, DestroyRef, effect, untracked, HostListener } from '@angular/core';
|
|
3
|
+
import { toSignal, takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
|
|
4
4
|
import { ActivatedRoute, Router } from '@angular/router';
|
|
5
5
|
import { TranslocoDirective, TranslocoService } from '@jsverse/transloco';
|
|
6
6
|
import { Breadcrumb } from '@masterteam/components/breadcrumb';
|
|
@@ -8,12 +8,12 @@ import { EmptyState } from '@masterteam/components/empty-state';
|
|
|
8
8
|
import { Page } from '@masterteam/components/page';
|
|
9
9
|
import { ToastService } from '@masterteam/components/toast';
|
|
10
10
|
import { Tooltip } from '@masterteam/components/tooltip';
|
|
11
|
-
import { E as EmailDeliveryFacade, i as isConnectionTestAttempt, a as EmailDeliveryStatus, g as getEmailDeliveryStatusMap, b as EMAIL_DELIVERY_ATTEMPT_STATUSES, c as createEmailTestRequestId, d as areEmailTestRecipientsValid, p as parseEmailTestRecipients, e as isEmailTestRequestPending, f as EMAIL_DELIVERY_PERMISSIONS } from './masterteam-system-settings-masterteam-system-settings-
|
|
11
|
+
import { E as EmailDeliveryFacade, i as isConnectionTestAttempt, a as EmailDeliveryStatus, g as getEmailDeliveryStatusMap, b as EMAIL_DELIVERY_ATTEMPT_STATUSES, c as createEmailTestRequestId, d as areEmailTestRecipientsValid, p as parseEmailTestRecipients, e as isEmailTestRequestPending, f as EMAIL_DELIVERY_PERMISSIONS, h as EmailLayoutFacade, j as EMAIL_LAYOUT_CONTENT_SLOT, k as EMAIL_LAYOUT_MAX_BYTES, r as readLayoutErrorDiagnostics, l as EmailVisualEditor, m as EmailHtmlPreview } from './masterteam-system-settings-masterteam-system-settings-C51hZw-Q.mjs';
|
|
12
12
|
import { Icon } from '@masterteam/icons';
|
|
13
13
|
import { Button } from '@masterteam/components/button';
|
|
14
14
|
import { ModalService } from '@masterteam/components/modal';
|
|
15
15
|
import { Table } from '@masterteam/components/table';
|
|
16
|
-
import { take, timer, of, map, switchMap, finalize } from 'rxjs';
|
|
16
|
+
import { take, timer, of, map, switchMap, finalize, Subject, merge, debounceTime, distinctUntilChanged, catchError, startWith } from 'rxjs';
|
|
17
17
|
import { DatePipe, DOCUMENT } from '@angular/common';
|
|
18
18
|
import { ModalRef } from '@masterteam/components/dialog';
|
|
19
19
|
import * as i1 from '@angular/forms';
|
|
@@ -26,7 +26,7 @@ import { TextareaFieldConfig, TextFieldConfig, ToggleFieldConfig, ValidatorConfi
|
|
|
26
26
|
import { DynamicForm } from '@masterteam/forms/dynamic-form';
|
|
27
27
|
import { Menu } from '@masterteam/components/menu';
|
|
28
28
|
import * as i1$1 from 'primeng/skeleton';
|
|
29
|
-
import { SkeletonModule } from 'primeng/skeleton';
|
|
29
|
+
import { SkeletonModule, Skeleton } from 'primeng/skeleton';
|
|
30
30
|
|
|
31
31
|
class EmailOperatorReasonDialog {
|
|
32
32
|
itemName = input.required(...(ngDevMode ? [{ debugName: "itemName" }] : /* istanbul ignore next */ []));
|
|
@@ -338,7 +338,7 @@ class EmailDeliveryAttempts {
|
|
|
338
338
|
return this.transloco.translate(`email-delivery.${key}`);
|
|
339
339
|
}
|
|
340
340
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: EmailDeliveryAttempts, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
341
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: EmailDeliveryAttempts, isStandalone: true, selector: "mt-email-delivery-attempts", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'email-delivery'\">\r\n <section class=\"space-y-4\" aria-label=\"{{ t('activity-title') }}\">\r\n <mt-table\r\n [data]=\"rows()\"\r\n [columns]=\"columns()\"\r\n [rowActions]=\"actions()\"\r\n [filters]=\"tableFilters()\"\r\n [loading]=\"facade.attemptsLoading()\"\r\n [generalSearch]=\"true\"\r\n [showFilters]=\"true\"\r\n [emptyTitle]=\"t('no-attempts-title')\"\r\n [emptyDescription]=\"t('no-attempts-description')\"\r\n filterMode=\"column\"\r\n dataKey=\"id\"\r\n actionShape=\"popover\"\r\n [clickableRows]=\"true\"\r\n storageKey=\"email-delivery-attempts\"\r\n (filtersChange)=\"onFiltersChange($event)\"\r\n (rowClick)=\"openDetails($event)\"\r\n >\r\n <ng-template #captionEnd>\r\n <mt-button\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n icon=\"arrow.refresh-cw-01\"\r\n [label]=\"t('refresh')\"\r\n [loading]=\"facade.attemptsLoading()\"\r\n (onClick)=\"refresh()\"\r\n />\r\n </ng-template>\r\n </mt-table>\r\n\r\n @if (facade.attemptsNextCursor()) {\r\n <div class=\"flex justify-center\">\r\n <mt-button\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n [label]=\"t('load-more')\"\r\n [loading]=\"facade.attemptsLoading()\"\r\n (onClick)=\"loadMore()\"\r\n />\r\n </div>\r\n }\r\n </section>\r\n</ng-container>\r\n", dependencies: [{ 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: 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
341
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: EmailDeliveryAttempts, isStandalone: true, selector: "mt-email-delivery-attempts", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'email-delivery'\">\r\n <section class=\"space-y-4\" aria-label=\"{{ t('activity-title') }}\">\r\n <mt-table\r\n [data]=\"rows()\"\r\n [columns]=\"columns()\"\r\n [rowActions]=\"actions()\"\r\n [filters]=\"tableFilters()\"\r\n [loading]=\"facade.attemptsLoading()\"\r\n [generalSearch]=\"true\"\r\n [showFilters]=\"true\"\r\n [emptyTitle]=\"t('no-attempts-title')\"\r\n [emptyDescription]=\"t('no-attempts-description')\"\r\n filterMode=\"column\"\r\n dataKey=\"id\"\r\n actionShape=\"popover\"\r\n [clickableRows]=\"true\"\r\n storageKey=\"email-delivery-attempts\"\r\n (filtersChange)=\"onFiltersChange($event)\"\r\n (rowClick)=\"openDetails($event)\"\r\n >\r\n <ng-template #captionEnd>\r\n <mt-button\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n icon=\"arrow.refresh-cw-01\"\r\n [label]=\"t('refresh')\"\r\n [loading]=\"facade.attemptsLoading()\"\r\n (onClick)=\"refresh()\"\r\n />\r\n </ng-template>\r\n </mt-table>\r\n\r\n @if (facade.attemptsNextCursor()) {\r\n <div class=\"flex justify-center\">\r\n <mt-button\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n [label]=\"t('load-more')\"\r\n [loading]=\"facade.attemptsLoading()\"\r\n (onClick)=\"loadMore()\"\r\n />\r\n </div>\r\n }\r\n </section>\r\n</ng-container>\r\n", dependencies: [{ 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: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "clickableRows", "generalSearch", "lazyLocalSearch", "showFilters", "filterMode", "filterCloseOnOutsideClick", "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", "externalFiltersActive", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm", "groupBy", "sortField", "sortDirection"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "emptyAction", "filtersCleared", "rowActionsRequested", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange", "groupByChange", "sortFieldChange", "sortDirectionChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
342
342
|
}
|
|
343
343
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: EmailDeliveryAttempts, decorators: [{
|
|
344
344
|
type: Component,
|
|
@@ -525,7 +525,7 @@ class EmailDeliveryHostEvidence {
|
|
|
525
525
|
return this.transloco.translate(`email-delivery.${key}`);
|
|
526
526
|
}
|
|
527
527
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: EmailDeliveryHostEvidence, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
528
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: EmailDeliveryHostEvidence, isStandalone: true, selector: "mt-email-delivery-host-evidence", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'email-delivery'\">\r\n <section class=\"space-y-3\" aria-labelledby=\"host-evidence-heading\">\r\n <div\r\n class=\"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\"\r\n >\r\n <div>\r\n <h3 id=\"host-evidence-heading\" class=\"font-semibold text-color\">\r\n {{ t(\"host-evidence-title\") }}\r\n </h3>\r\n <p class=\"mt-1 text-sm text-muted-color\">\r\n {{ t(\"host-evidence-description\") }}\r\n </p>\r\n </div>\r\n <mt-button\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n icon=\"arrow.refresh-cw-01\"\r\n [label]=\"t('rebuild-evidence-index')\"\r\n [disabled]=\"!facade.managementAvailable()\"\r\n [loading]=\"facade.mutationLoading() === 'rebuild-evidence'\"\r\n (onClick)=\"confirmRebuild()\"\r\n />\r\n </div>\r\n\r\n @if (facade.hostEvidenceScanBudgetExhausted()) {\r\n <div\r\n class=\"rounded-md border border-amber-200 bg-amber-50 p-3 text-sm text-amber-950\"\r\n role=\"status\"\r\n >\r\n {{ t(\"scan-budget-exhausted\") }}\r\n </div>\r\n }\r\n\r\n <mt-table\r\n [data]=\"rows()\"\r\n [columns]=\"columns()\"\r\n [rowActions]=\"actions()\"\r\n [loading]=\"facade.hostEvidenceLoading()\"\r\n [generalSearch]=\"true\"\r\n [showFilters]=\"true\"\r\n [emptyTitle]=\"t('no-evidence-title')\"\r\n [emptyDescription]=\"t('no-evidence-description')\"\r\n filterMode=\"column\"\r\n actionShape=\"popover\"\r\n dataKey=\"evidenceRowId\"\r\n storageKey=\"email-delivery-host-evidence\"\r\n />\r\n\r\n @if (facade.hostEvidenceNextCursor()) {\r\n <div class=\"flex justify-center\">\r\n <mt-button\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n [label]=\"t('load-more')\"\r\n [loading]=\"facade.hostEvidenceLoading()\"\r\n (onClick)=\"loadMore()\"\r\n />\r\n </div>\r\n }\r\n </section>\r\n</ng-container>\r\n", dependencies: [{ 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: 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
528
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: EmailDeliveryHostEvidence, isStandalone: true, selector: "mt-email-delivery-host-evidence", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'email-delivery'\">\r\n <section class=\"space-y-3\" aria-labelledby=\"host-evidence-heading\">\r\n <div\r\n class=\"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\"\r\n >\r\n <div>\r\n <h3 id=\"host-evidence-heading\" class=\"font-semibold text-color\">\r\n {{ t(\"host-evidence-title\") }}\r\n </h3>\r\n <p class=\"mt-1 text-sm text-muted-color\">\r\n {{ t(\"host-evidence-description\") }}\r\n </p>\r\n </div>\r\n <mt-button\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n icon=\"arrow.refresh-cw-01\"\r\n [label]=\"t('rebuild-evidence-index')\"\r\n [disabled]=\"!facade.managementAvailable()\"\r\n [loading]=\"facade.mutationLoading() === 'rebuild-evidence'\"\r\n (onClick)=\"confirmRebuild()\"\r\n />\r\n </div>\r\n\r\n @if (facade.hostEvidenceScanBudgetExhausted()) {\r\n <div\r\n class=\"rounded-md border border-amber-200 bg-amber-50 p-3 text-sm text-amber-950\"\r\n role=\"status\"\r\n >\r\n {{ t(\"scan-budget-exhausted\") }}\r\n </div>\r\n }\r\n\r\n <mt-table\r\n [data]=\"rows()\"\r\n [columns]=\"columns()\"\r\n [rowActions]=\"actions()\"\r\n [loading]=\"facade.hostEvidenceLoading()\"\r\n [generalSearch]=\"true\"\r\n [showFilters]=\"true\"\r\n [emptyTitle]=\"t('no-evidence-title')\"\r\n [emptyDescription]=\"t('no-evidence-description')\"\r\n filterMode=\"column\"\r\n actionShape=\"popover\"\r\n dataKey=\"evidenceRowId\"\r\n storageKey=\"email-delivery-host-evidence\"\r\n />\r\n\r\n @if (facade.hostEvidenceNextCursor()) {\r\n <div class=\"flex justify-center\">\r\n <mt-button\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n [label]=\"t('load-more')\"\r\n [loading]=\"facade.hostEvidenceLoading()\"\r\n (onClick)=\"loadMore()\"\r\n />\r\n </div>\r\n }\r\n </section>\r\n</ng-container>\r\n", dependencies: [{ 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: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "clickableRows", "generalSearch", "lazyLocalSearch", "showFilters", "filterMode", "filterCloseOnOutsideClick", "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", "externalFiltersActive", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm", "groupBy", "sortField", "sortDirection"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "emptyAction", "filtersCleared", "rowActionsRequested", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange", "groupByChange", "sortFieldChange", "sortDirectionChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
529
529
|
}
|
|
530
530
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: EmailDeliveryHostEvidence, decorators: [{
|
|
531
531
|
type: Component,
|
|
@@ -650,7 +650,7 @@ class EmailDeliveryQuarantine {
|
|
|
650
650
|
return this.transloco.translate(`email-delivery.${key}`);
|
|
651
651
|
}
|
|
652
652
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: EmailDeliveryQuarantine, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
653
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: EmailDeliveryQuarantine, isStandalone: true, selector: "mt-email-delivery-quarantine", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'email-delivery'\">\r\n <section class=\"space-y-3\" aria-labelledby=\"quarantine-heading\">\r\n <div>\r\n <h3 id=\"quarantine-heading\" class=\"font-semibold text-color\">\r\n {{ t(\"quarantine-title\") }}\r\n </h3>\r\n <p class=\"mt-1 text-sm text-muted-color\">\r\n {{ t(\"quarantine-description\") }}\r\n </p>\r\n </div>\r\n\r\n <mt-table\r\n [data]=\"rows()\"\r\n [columns]=\"columns()\"\r\n [rowActions]=\"actions()\"\r\n [loading]=\"facade.quarantineLoading()\"\r\n [generalSearch]=\"true\"\r\n [showFilters]=\"true\"\r\n [emptyTitle]=\"t('no-quarantine-title')\"\r\n [emptyDescription]=\"t('no-quarantine-description')\"\r\n filterMode=\"column\"\r\n actionShape=\"popover\"\r\n dataKey=\"itemId\"\r\n storageKey=\"email-delivery-quarantine\"\r\n />\r\n\r\n @if (facade.quarantineNextCursor()) {\r\n <div class=\"flex justify-center\">\r\n <mt-button\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n [label]=\"t('load-more')\"\r\n [loading]=\"facade.quarantineLoading()\"\r\n (onClick)=\"loadMore()\"\r\n />\r\n </div>\r\n }\r\n </section>\r\n</ng-container>\r\n", dependencies: [{ 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: 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
653
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: EmailDeliveryQuarantine, isStandalone: true, selector: "mt-email-delivery-quarantine", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'email-delivery'\">\r\n <section class=\"space-y-3\" aria-labelledby=\"quarantine-heading\">\r\n <div>\r\n <h3 id=\"quarantine-heading\" class=\"font-semibold text-color\">\r\n {{ t(\"quarantine-title\") }}\r\n </h3>\r\n <p class=\"mt-1 text-sm text-muted-color\">\r\n {{ t(\"quarantine-description\") }}\r\n </p>\r\n </div>\r\n\r\n <mt-table\r\n [data]=\"rows()\"\r\n [columns]=\"columns()\"\r\n [rowActions]=\"actions()\"\r\n [loading]=\"facade.quarantineLoading()\"\r\n [generalSearch]=\"true\"\r\n [showFilters]=\"true\"\r\n [emptyTitle]=\"t('no-quarantine-title')\"\r\n [emptyDescription]=\"t('no-quarantine-description')\"\r\n filterMode=\"column\"\r\n actionShape=\"popover\"\r\n dataKey=\"itemId\"\r\n storageKey=\"email-delivery-quarantine\"\r\n />\r\n\r\n @if (facade.quarantineNextCursor()) {\r\n <div class=\"flex justify-center\">\r\n <mt-button\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n [label]=\"t('load-more')\"\r\n [loading]=\"facade.quarantineLoading()\"\r\n (onClick)=\"loadMore()\"\r\n />\r\n </div>\r\n }\r\n </section>\r\n</ng-container>\r\n", dependencies: [{ 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: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "clickableRows", "generalSearch", "lazyLocalSearch", "showFilters", "filterMode", "filterCloseOnOutsideClick", "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", "externalFiltersActive", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm", "groupBy", "sortField", "sortDirection"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "emptyAction", "filtersCleared", "rowActionsRequested", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange", "groupByChange", "sortFieldChange", "sortDirectionChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
654
654
|
}
|
|
655
655
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: EmailDeliveryQuarantine, decorators: [{
|
|
656
656
|
type: Component,
|
|
@@ -2041,7 +2041,7 @@ class EmailDeliveryConnections {
|
|
|
2041
2041
|
return this.transloco.translate(`email-delivery.${key}`);
|
|
2042
2042
|
}
|
|
2043
2043
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: EmailDeliveryConnections, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2044
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: EmailDeliveryConnections, isStandalone: true, selector: "mt-email-delivery-connections", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'email-delivery'\">\r\n <section class=\"space-y-4\" aria-label=\"{{ t('connections-title') }}\">\r\n @if (\r\n !facade.statusLoading() &&\r\n !facade.catalogLoading() &&\r\n facade.providers().length === 0\r\n ) {\r\n <mt-empty-state\r\n illustration=\"none\"\r\n [title]=\"t('no-providers-title')\"\r\n [description]=\"t('no-providers-description')\"\r\n />\r\n } @else {\r\n <mt-table\r\n [data]=\"rows()\"\r\n [columns]=\"columns()\"\r\n [rowActions]=\"rowActions()\"\r\n [loading]=\"\r\n facade.statusLoading() ||\r\n facade.connectionsLoading() ||\r\n facade.catalogLoading()\r\n \"\r\n [generalSearch]=\"true\"\r\n [showFilters]=\"true\"\r\n [emptyTitle]=\"t('no-connections-title')\"\r\n [emptyDescription]=\"t('no-connections-description')\"\r\n [emptyActionLabel]=\"canCreate() ? t('create-connection') : undefined\"\r\n emptyActionIcon=\"general.plus\"\r\n filterMode=\"column\"\r\n actionShape=\"popover\"\r\n [clickableRows]=\"true\"\r\n dataKey=\"id\"\r\n storageKey=\"email-delivery-connections\"\r\n (emptyAction)=\"createConnection()\"\r\n (rowClick)=\"openDetails($event)\"\r\n >\r\n <ng-template #captionEnd>\r\n @if (canCreate()) {\r\n <mt-button\r\n [label]=\"t('create-connection')\"\r\n icon=\"general.plus\"\r\n (onClick)=\"createConnection()\"\r\n />\r\n }\r\n </ng-template>\r\n </mt-table>\r\n }\r\n </section>\r\n</ng-container>\r\n", dependencies: [{ 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: EmptyState, selector: "mt-empty-state", inputs: ["variant", "illustration", "title", "description", "actionLabel", "actionIcon"], outputs: ["actionClick"] }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2044
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: EmailDeliveryConnections, isStandalone: true, selector: "mt-email-delivery-connections", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'email-delivery'\">\r\n <section class=\"space-y-4\" aria-label=\"{{ t('connections-title') }}\">\r\n @if (\r\n !facade.statusLoading() &&\r\n !facade.catalogLoading() &&\r\n facade.providers().length === 0\r\n ) {\r\n <mt-empty-state\r\n illustration=\"none\"\r\n [title]=\"t('no-providers-title')\"\r\n [description]=\"t('no-providers-description')\"\r\n />\r\n } @else {\r\n <mt-table\r\n [data]=\"rows()\"\r\n [columns]=\"columns()\"\r\n [rowActions]=\"rowActions()\"\r\n [loading]=\"\r\n facade.statusLoading() ||\r\n facade.connectionsLoading() ||\r\n facade.catalogLoading()\r\n \"\r\n [generalSearch]=\"true\"\r\n [showFilters]=\"true\"\r\n [emptyTitle]=\"t('no-connections-title')\"\r\n [emptyDescription]=\"t('no-connections-description')\"\r\n [emptyActionLabel]=\"canCreate() ? t('create-connection') : undefined\"\r\n emptyActionIcon=\"general.plus\"\r\n filterMode=\"column\"\r\n actionShape=\"popover\"\r\n [clickableRows]=\"true\"\r\n dataKey=\"id\"\r\n storageKey=\"email-delivery-connections\"\r\n (emptyAction)=\"createConnection()\"\r\n (rowClick)=\"openDetails($event)\"\r\n >\r\n <ng-template #captionEnd>\r\n @if (canCreate()) {\r\n <mt-button\r\n [label]=\"t('create-connection')\"\r\n icon=\"general.plus\"\r\n (onClick)=\"createConnection()\"\r\n />\r\n }\r\n </ng-template>\r\n </mt-table>\r\n }\r\n </section>\r\n</ng-container>\r\n", dependencies: [{ 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: EmptyState, selector: "mt-empty-state", inputs: ["variant", "illustration", "title", "description", "actionLabel", "actionIcon"], outputs: ["actionClick"] }, { kind: "component", type: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "clickableRows", "generalSearch", "lazyLocalSearch", "showFilters", "filterMode", "filterCloseOnOutsideClick", "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", "externalFiltersActive", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm", "groupBy", "sortField", "sortDirection"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "emptyAction", "filtersCleared", "rowActionsRequested", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange", "groupByChange", "sortFieldChange", "sortDirectionChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2045
2045
|
}
|
|
2046
2046
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: EmailDeliveryConnections, decorators: [{
|
|
2047
2047
|
type: Component,
|
|
@@ -2061,6 +2061,244 @@ function toKebabCase(value) {
|
|
|
2061
2061
|
return value.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
|
2062
2062
|
}
|
|
2063
2063
|
|
|
2064
|
+
/**
|
|
2065
|
+
* Product Settings → Email → Email design. Edits the one shared base that wraps
|
|
2066
|
+
* every notification email (logo, header, footer, typography). The source is
|
|
2067
|
+
* edited as exact HTML — no visual editor rewrites tables, inline styles,
|
|
2068
|
+
* `lang`/`dir` or the `{content}` slot — next to a live, sandboxed preview of
|
|
2069
|
+
* the server's fixed bilingual sample.
|
|
2070
|
+
*/
|
|
2071
|
+
class EmailDeliveryDesign {
|
|
2072
|
+
facade = inject(EmailLayoutFacade);
|
|
2073
|
+
confirmation = inject(ConfirmationService);
|
|
2074
|
+
toast = inject(ToastService);
|
|
2075
|
+
transloco = inject(TranslocoService);
|
|
2076
|
+
destroyRef = inject(DestroyRef);
|
|
2077
|
+
sourceControl = new FormControl('', { nonNullable: true });
|
|
2078
|
+
narrow = new FormControl(false, { nonNullable: true });
|
|
2079
|
+
narrowValue = signal(false, ...(ngDevMode ? [{ debugName: "narrowValue" }] : /* istanbul ignore next */ []));
|
|
2080
|
+
preview = signal({ status: 'idle' }, ...(ngDevMode ? [{ debugName: "preview" }] : /* istanbul ignore next */ []));
|
|
2081
|
+
/** Last successful render — kept on screen (dimmed) while the next one runs. */
|
|
2082
|
+
rendered = signal(null, ...(ngDevMode ? [{ debugName: "rendered" }] : /* istanbul ignore next */ []));
|
|
2083
|
+
previewErrorCode = computed(() => {
|
|
2084
|
+
const state = this.preview();
|
|
2085
|
+
return state.status === 'error' ? state.code : null;
|
|
2086
|
+
}, ...(ngDevMode ? [{ debugName: "previewErrorCode" }] : /* istanbul ignore next */ []));
|
|
2087
|
+
retry$ = new Subject();
|
|
2088
|
+
writeDiagnostics = signal([], ...(ngDevMode ? [{ debugName: "writeDiagnostics" }] : /* istanbul ignore next */ []));
|
|
2089
|
+
slotCount = computed(() => this.facade.draft().split(EMAIL_LAYOUT_CONTENT_SLOT).length - 1, ...(ngDevMode ? [{ debugName: "slotCount" }] : /* istanbul ignore next */ []));
|
|
2090
|
+
byteSize = computed(() => new TextEncoder().encode(this.facade.draft()).length, ...(ngDevMode ? [{ debugName: "byteSize" }] : /* istanbul ignore next */ []));
|
|
2091
|
+
sizeLabel = computed(() => this.transloco.translate('email-delivery.design.size', {
|
|
2092
|
+
used: (this.byteSize() / 1024).toFixed(1),
|
|
2093
|
+
limit: EMAIL_LAYOUT_MAX_BYTES / 1024,
|
|
2094
|
+
}), ...(ngDevMode ? [{ debugName: "sizeLabel" }] : /* istanbul ignore next */ []));
|
|
2095
|
+
overLimit = computed(() => this.byteSize() > EMAIL_LAYOUT_MAX_BYTES, ...(ngDevMode ? [{ debugName: "overLimit" }] : /* istanbul ignore next */ []));
|
|
2096
|
+
/** The size only matters, and is only shown, close to the limit. */
|
|
2097
|
+
nearLimit = computed(() => this.byteSize() >= EMAIL_LAYOUT_MAX_BYTES * 0.8, ...(ngDevMode ? [{ debugName: "nearLimit" }] : /* istanbul ignore next */ []));
|
|
2098
|
+
/** A preview only counts while it was rendered from exactly the current draft. */
|
|
2099
|
+
freshPreview = computed(() => {
|
|
2100
|
+
const state = this.preview();
|
|
2101
|
+
return state.status === 'ready' && state.body === this.facade.draft()
|
|
2102
|
+
? state.result
|
|
2103
|
+
: null;
|
|
2104
|
+
}, ...(ngDevMode ? [{ debugName: "freshPreview" }] : /* istanbul ignore next */ []));
|
|
2105
|
+
/** The preview ran against a newer live revision than this draft started from. */
|
|
2106
|
+
baselineMoved = computed(() => {
|
|
2107
|
+
const result = this.freshPreview();
|
|
2108
|
+
const snapshot = this.facade.snapshot();
|
|
2109
|
+
return (!!result && !!snapshot && result.effectiveRevision !== snapshot.revision);
|
|
2110
|
+
}, ...(ngDevMode ? [{ debugName: "baselineMoved" }] : /* istanbul ignore next */ []));
|
|
2111
|
+
blockingDiagnostics = computed(() => (this.facade.snapshot()?.diagnostics ?? []).filter((diagnostic) => diagnostic.severity === 'error'), ...(ngDevMode ? [{ debugName: "blockingDiagnostics" }] : /* istanbul ignore next */ []));
|
|
2112
|
+
canPublish = computed(() => {
|
|
2113
|
+
const snapshot = this.facade.snapshot();
|
|
2114
|
+
return (!!snapshot &&
|
|
2115
|
+
(this.facade.dirty() || snapshot.source !== 'published') &&
|
|
2116
|
+
!!this.freshPreview() &&
|
|
2117
|
+
!this.baselineMoved() &&
|
|
2118
|
+
this.slotCount() === 1 &&
|
|
2119
|
+
!this.overLimit() &&
|
|
2120
|
+
!this.facade.conflict() &&
|
|
2121
|
+
this.facade.saving() === null);
|
|
2122
|
+
}, ...(ngDevMode ? [{ debugName: "canPublish" }] : /* istanbul ignore next */ []));
|
|
2123
|
+
publishBlockedReason = computed(() => {
|
|
2124
|
+
if (this.canPublish() || this.facade.saving())
|
|
2125
|
+
return '';
|
|
2126
|
+
const key = this.overLimit()
|
|
2127
|
+
? 'size-limit'
|
|
2128
|
+
: this.slotCount() !== 1
|
|
2129
|
+
? 'slot'
|
|
2130
|
+
: this.facade.conflict() || this.baselineMoved()
|
|
2131
|
+
? 'conflict'
|
|
2132
|
+
: !this.freshPreview()
|
|
2133
|
+
? 'preview-required'
|
|
2134
|
+
: 'no-changes';
|
|
2135
|
+
return this.transloco.translate(`email-delivery.design.publish-blocked.${key}`);
|
|
2136
|
+
}, ...(ngDevMode ? [{ debugName: "publishBlockedReason" }] : /* istanbul ignore next */ []));
|
|
2137
|
+
constructor() {
|
|
2138
|
+
// The facade owns the draft so it survives tab switches; mirror it into
|
|
2139
|
+
// the textarea only when it changed from outside (reload, publish, discard).
|
|
2140
|
+
effect(() => {
|
|
2141
|
+
const draft = this.facade.draft();
|
|
2142
|
+
untracked(() => {
|
|
2143
|
+
if (this.sourceControl.value !== draft) {
|
|
2144
|
+
this.sourceControl.setValue(draft, { emitEvent: false });
|
|
2145
|
+
}
|
|
2146
|
+
});
|
|
2147
|
+
});
|
|
2148
|
+
this.sourceControl.valueChanges
|
|
2149
|
+
.pipe(takeUntilDestroyed())
|
|
2150
|
+
.subscribe((value) => this.facade.draft.set(value));
|
|
2151
|
+
this.narrow.valueChanges
|
|
2152
|
+
.pipe(takeUntilDestroyed())
|
|
2153
|
+
.subscribe((value) => this.narrowValue.set(value));
|
|
2154
|
+
// One preview stream per editor: a pause in typing cancels the previous
|
|
2155
|
+
// request and renders the current draft; Retry re-renders the same draft.
|
|
2156
|
+
const draft$ = toObservable(this.facade.draft);
|
|
2157
|
+
merge(draft$.pipe(debounceTime(500), distinctUntilChanged()), this.retry$.pipe(map(() => this.facade.draft())))
|
|
2158
|
+
.pipe(switchMap((body) => {
|
|
2159
|
+
if (!this.facade.snapshot())
|
|
2160
|
+
return of({ status: 'idle' });
|
|
2161
|
+
return this.facade.preview(body).pipe(map((result) => ({ status: 'ready', body, result })), catchError((error) => of({
|
|
2162
|
+
status: 'error',
|
|
2163
|
+
body,
|
|
2164
|
+
code: this.facade.readErrorCode(error),
|
|
2165
|
+
})), startWith({ status: 'updating', body }));
|
|
2166
|
+
}), takeUntilDestroyed())
|
|
2167
|
+
.subscribe((state) => {
|
|
2168
|
+
this.preview.set(state);
|
|
2169
|
+
if (state.status === 'ready')
|
|
2170
|
+
this.rendered.set(state.result);
|
|
2171
|
+
});
|
|
2172
|
+
}
|
|
2173
|
+
ngOnInit() {
|
|
2174
|
+
// Unsaved edits from an earlier visit to this tab are kept; otherwise
|
|
2175
|
+
// always start from what is live now.
|
|
2176
|
+
if (this.facade.dirty()) {
|
|
2177
|
+
this.retry$.next();
|
|
2178
|
+
}
|
|
2179
|
+
else {
|
|
2180
|
+
this.reload();
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
onBeforeUnload(event) {
|
|
2184
|
+
if (this.facade.dirty() || this.facade.saving()) {
|
|
2185
|
+
event.preventDefault();
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
reload() {
|
|
2189
|
+
this.facade
|
|
2190
|
+
.load()
|
|
2191
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
2192
|
+
.subscribe({
|
|
2193
|
+
next: () => this.retry$.next(),
|
|
2194
|
+
error: () => undefined,
|
|
2195
|
+
});
|
|
2196
|
+
}
|
|
2197
|
+
retryPreview() {
|
|
2198
|
+
this.retry$.next();
|
|
2199
|
+
}
|
|
2200
|
+
discard() {
|
|
2201
|
+
if (!this.facade.dirty())
|
|
2202
|
+
return;
|
|
2203
|
+
// Discarded edits cannot be brought back, so ask the same question as
|
|
2204
|
+
// leaving the page.
|
|
2205
|
+
this.confirmation.confirm({
|
|
2206
|
+
type: 'dialog',
|
|
2207
|
+
header: this.t('leave.header'),
|
|
2208
|
+
message: this.t('leave.message'),
|
|
2209
|
+
acceptLabel: this.t('leave.discard'),
|
|
2210
|
+
rejectLabel: this.t('leave.stay'),
|
|
2211
|
+
acceptButton: { severity: 'danger' },
|
|
2212
|
+
accept: () => {
|
|
2213
|
+
this.facade.discard();
|
|
2214
|
+
this.writeDiagnostics.set([]);
|
|
2215
|
+
},
|
|
2216
|
+
});
|
|
2217
|
+
}
|
|
2218
|
+
publish() {
|
|
2219
|
+
if (!this.canPublish())
|
|
2220
|
+
return;
|
|
2221
|
+
this.confirmation.confirm({
|
|
2222
|
+
header: this.t('confirm-publish.header'),
|
|
2223
|
+
message: this.t('confirm-publish.message'),
|
|
2224
|
+
icon: 'communication.mail-01',
|
|
2225
|
+
acceptLabel: this.t('actions.publish'),
|
|
2226
|
+
accept: () => this.facade.publish().subscribe({
|
|
2227
|
+
next: () => {
|
|
2228
|
+
this.writeDiagnostics.set([]);
|
|
2229
|
+
this.toast.success(this.t('published'));
|
|
2230
|
+
this.retry$.next();
|
|
2231
|
+
},
|
|
2232
|
+
error: (error) => this.onWriteError(error),
|
|
2233
|
+
}),
|
|
2234
|
+
});
|
|
2235
|
+
}
|
|
2236
|
+
restorePrevious() {
|
|
2237
|
+
if (this.facade.saving())
|
|
2238
|
+
return;
|
|
2239
|
+
this.confirmation.confirm({
|
|
2240
|
+
header: this.t('confirm-restore.header'),
|
|
2241
|
+
message: this.t(this.facade.dirty()
|
|
2242
|
+
? 'confirm-restore.message-dirty'
|
|
2243
|
+
: 'confirm-restore.message'),
|
|
2244
|
+
icon: 'arrow.refresh-cw-01',
|
|
2245
|
+
acceptLabel: this.t('actions.restore'),
|
|
2246
|
+
accept: () => this.facade.restorePrevious().subscribe({
|
|
2247
|
+
next: () => {
|
|
2248
|
+
this.writeDiagnostics.set([]);
|
|
2249
|
+
this.toast.success(this.t('restored'));
|
|
2250
|
+
this.retry$.next();
|
|
2251
|
+
},
|
|
2252
|
+
error: (error) => this.onWriteError(error),
|
|
2253
|
+
}),
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2256
|
+
resolveConflict(keepDraft) {
|
|
2257
|
+
this.facade
|
|
2258
|
+
.reloadLatest(keepDraft)
|
|
2259
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
2260
|
+
.subscribe({ next: () => this.retry$.next(), error: () => undefined });
|
|
2261
|
+
}
|
|
2262
|
+
describeDiagnostic(diagnostic) {
|
|
2263
|
+
return this.facade.describeDiagnostic(diagnostic);
|
|
2264
|
+
}
|
|
2265
|
+
describeCode(code) {
|
|
2266
|
+
return this.facade.describeCode(code);
|
|
2267
|
+
}
|
|
2268
|
+
onWriteError(error) {
|
|
2269
|
+
this.writeDiagnostics.set(readLayoutErrorDiagnostics(error));
|
|
2270
|
+
if (this.facade.conflict())
|
|
2271
|
+
return; // the banner explains it
|
|
2272
|
+
this.toast.error(this.facade.describeCode(this.facade.readErrorCode(error)));
|
|
2273
|
+
}
|
|
2274
|
+
t(key) {
|
|
2275
|
+
return this.transloco.translate(`email-delivery.design.${key}`);
|
|
2276
|
+
}
|
|
2277
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: EmailDeliveryDesign, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2278
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: EmailDeliveryDesign, isStandalone: true, selector: "mt-email-delivery-design", host: { listeners: { "window:beforeunload": "onBeforeUnload($event)" } }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'email-delivery.design'\">\n @if (facade.loading() && !facade.snapshot()) {\n <div class=\"grid grid-cols-1 gap-4 xl:grid-cols-2\" aria-live=\"polite\">\n <p-skeleton width=\"100%\" height=\"32rem\" borderRadius=\"0.375rem\" />\n <p-skeleton width=\"100%\" height=\"32rem\" borderRadius=\"0.375rem\" />\n </div>\n } @else if (facade.loadFailed() && !facade.snapshot()) {\n <mt-empty-state\n illustration=\"none\"\n [title]=\"t('load-error-title')\"\n [description]=\"describeCode(facade.loadErrorCode())\"\n [actionLabel]=\"t('actions.retry')\"\n actionIcon=\"arrow.refresh-cw-01\"\n (actionClick)=\"reload()\"\n />\n } @else if (facade.snapshot(); as snapshot) {\n <div class=\"flex min-w-0 flex-col gap-4\">\n <!-- Status and actions -->\n <div\n class=\"flex flex-wrap items-center justify-between gap-3 rounded-md border border-surface bg-content px-4 py-3\"\n >\n <div class=\"flex min-w-0 flex-wrap items-center gap-2 text-sm\">\n <span\n class=\"rounded-md border border-surface bg-surface-50 px-2 py-0.5 font-medium\"\n >\n {{ t(\"source.\" + snapshot.source) }}\n @if (snapshot.revision > 0) {\n \u00B7 {{ t(\"revision\", { revision: snapshot.revision }) }}\n }\n </span>\n @if (facade.dirty()) {\n <span\n class=\"rounded-md border border-amber-200 bg-amber-50 px-2 py-0.5 font-medium text-amber-700\"\n >\n {{ t(\"unsaved\") }}\n </span>\n }\n </div>\n <div class=\"flex flex-wrap items-center gap-2\">\n @if (snapshot.canRestore) {\n <mt-button\n icon=\"arrow.refresh-cw-01\"\n [label]=\"t('actions.restore')\"\n severity=\"secondary\"\n variant=\"outlined\"\n [loading]=\"facade.saving() === 'restore'\"\n [disabled]=\"facade.saving() !== null\"\n (onClick)=\"restorePrevious()\"\n />\n }\n <mt-button\n [label]=\"t('actions.discard')\"\n severity=\"secondary\"\n variant=\"text\"\n [disabled]=\"!facade.dirty() || facade.saving() !== null\"\n (onClick)=\"discard()\"\n />\n <mt-button\n icon=\"general.check\"\n [label]=\"t('actions.publish')\"\n [tooltip]=\"publishBlockedReason()\"\n [loading]=\"facade.saving() === 'publish'\"\n [disabled]=\"!canPublish()\"\n (onClick)=\"publish()\"\n />\n </div>\n </div>\n\n @if (facade.conflict() || baselineMoved()) {\n <div\n class=\"flex flex-wrap items-center justify-between gap-3 rounded-md border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-700\"\n role=\"alert\"\n >\n <span>{{ t(\"conflict\") }}</span>\n <div class=\"flex flex-wrap gap-2\">\n <mt-button\n [label]=\"t('actions.keep-mine')\"\n size=\"small\"\n severity=\"secondary\"\n variant=\"outlined\"\n (onClick)=\"resolveConflict(true)\"\n />\n <mt-button\n [label]=\"t('actions.load-latest')\"\n size=\"small\"\n severity=\"secondary\"\n (onClick)=\"resolveConflict(false)\"\n />\n </div>\n </div>\n }\n\n @if (blockingDiagnostics().length > 0) {\n <div\n class=\"rounded-md border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\n role=\"alert\"\n >\n <p class=\"font-medium\">{{ t(\"blocked\") }}</p>\n <ul class=\"mt-1 list-disc ps-5\">\n @for (diagnostic of blockingDiagnostics(); track $index) {\n <li>{{ describeDiagnostic(diagnostic) }}</li>\n }\n </ul>\n </div>\n }\n\n @if (writeDiagnostics().length > 0) {\n <div\n class=\"rounded-md border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\n role=\"alert\"\n >\n <ul class=\"list-disc ps-5\">\n @for (diagnostic of writeDiagnostics(); track $index) {\n <li>{{ describeDiagnostic(diagnostic) }}</li>\n }\n </ul>\n </div>\n }\n\n <div class=\"grid min-w-0 grid-cols-1 gap-4 xl:grid-cols-2\">\n <!-- HTML source -->\n <section\n class=\"flex min-w-0 flex-col overflow-hidden rounded-md border border-surface bg-content\"\n >\n <header\n class=\"flex items-center justify-between gap-2 border-b border-surface bg-surface-50 px-4 py-2.5\"\n >\n <h3 class=\"text-sm font-semibold\">{{ t(\"source-title\") }}</h3>\n @if (nearLimit()) {\n <span\n class=\"text-xs\"\n [class.text-red-600]=\"overLimit()\"\n [class.text-amber-700]=\"!overLimit()\"\n >{{ sizeLabel() }}</span\n >\n }\n </header>\n <div class=\"flex flex-col gap-2 p-4\">\n <mt-email-visual-editor\n [formControl]=\"sourceControl\"\n [label]=\"t('source-label')\"\n [hint]=\"t('source-hint')\"\n [layout]=\"true\"\n [approvedImageOrigins]=\"snapshot.approvedImageOrigins\"\n height=\"34rem\"\n />\n @if (slotCount() !== 1) {\n <p class=\"text-sm text-red-600\" role=\"alert\">\n {{ t(slotCount() === 0 ? \"slot-missing\" : \"slot-duplicate\") }}\n </p>\n }\n </div>\n </section>\n\n <!-- Live preview -->\n <section\n class=\"flex min-w-0 flex-col overflow-hidden rounded-md border border-surface bg-content\"\n >\n <header\n class=\"flex flex-wrap items-center justify-between gap-2 border-b border-surface bg-surface-50 px-4 py-2.5\"\n >\n <div class=\"flex items-center gap-2\">\n <h3 class=\"text-sm font-semibold\">{{ t(\"preview-title\") }}</h3>\n <span class=\"text-xs text-muted-color\" aria-live=\"polite\">{{\n preview().status === \"updating\" ? t(\"preview-updating\") : \"\"\n }}</span>\n </div>\n <mt-toggle-field [formControl]=\"narrow\" [label]=\"t('narrow')\" />\n </header>\n <div class=\"flex flex-col gap-3 p-4\">\n @if (preview().status === \"error\") {\n <div\n class=\"flex flex-wrap items-center justify-between gap-3 rounded-md border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\n role=\"alert\"\n >\n <span>{{ describeCode(previewErrorCode()) }}</span>\n <mt-button\n [label]=\"t('actions.retry')\"\n size=\"small\"\n severity=\"secondary\"\n variant=\"outlined\"\n (onClick)=\"retryPreview()\"\n />\n </div>\n }\n <!-- 39rem = the editor frame (34rem) plus its label and toolbar, so\n both columns end level. -->\n @if (rendered(); as rendered) {\n <div\n class=\"mx-auto w-full overflow-hidden rounded-md border border-surface transition-opacity\"\n [class.max-w-[375px]]=\"narrowValue()\"\n [class.opacity-60]=\"!freshPreview()\"\n >\n <mt-email-html-preview\n [html]=\"rendered.html\"\n [showImages]=\"true\"\n [approvedImageOrigins]=\"rendered.approvedImageOrigins\"\n [title]=\"t('preview-title')\"\n height=\"39rem\"\n />\n </div>\n @if (rendered.diagnostics.length > 0) {\n <ul class=\"list-disc ps-5 text-sm text-amber-700\">\n @for (diagnostic of rendered.diagnostics; track $index) {\n <li>{{ describeDiagnostic(diagnostic) }}</li>\n }\n </ul>\n }\n } @else if (preview().status !== \"error\") {\n <p-skeleton width=\"100%\" height=\"39rem\" borderRadius=\"0.375rem\" />\n }\n </div>\n </section>\n </div>\n </div>\n }\n</ng-container>\n", dependencies: [{ kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { 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: EmptyState, selector: "mt-empty-state", inputs: ["variant", "illustration", "title", "description", "actionLabel", "actionIcon"], outputs: ["actionClick"] }, { kind: "component", type: EmailVisualEditor, selector: "mt-email-visual-editor", inputs: ["label", "hint", "placeholders", "layout", "height", "direction", "starter", "approvedImageOrigins"], outputs: ["focused"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: EmailHtmlPreview, selector: "mt-email-html-preview", inputs: ["html", "showImages", "approvedImageOrigins", "fragment", "direction", "title", "height"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2279
|
+
}
|
|
2280
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: EmailDeliveryDesign, decorators: [{
|
|
2281
|
+
type: Component,
|
|
2282
|
+
args: [{ selector: 'mt-email-delivery-design', imports: [
|
|
2283
|
+
TranslocoDirective,
|
|
2284
|
+
ReactiveFormsModule,
|
|
2285
|
+
Button,
|
|
2286
|
+
EmptyState,
|
|
2287
|
+
EmailVisualEditor,
|
|
2288
|
+
ToggleField,
|
|
2289
|
+
Skeleton,
|
|
2290
|
+
EmailHtmlPreview,
|
|
2291
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t; prefix: 'email-delivery.design'\">\n @if (facade.loading() && !facade.snapshot()) {\n <div class=\"grid grid-cols-1 gap-4 xl:grid-cols-2\" aria-live=\"polite\">\n <p-skeleton width=\"100%\" height=\"32rem\" borderRadius=\"0.375rem\" />\n <p-skeleton width=\"100%\" height=\"32rem\" borderRadius=\"0.375rem\" />\n </div>\n } @else if (facade.loadFailed() && !facade.snapshot()) {\n <mt-empty-state\n illustration=\"none\"\n [title]=\"t('load-error-title')\"\n [description]=\"describeCode(facade.loadErrorCode())\"\n [actionLabel]=\"t('actions.retry')\"\n actionIcon=\"arrow.refresh-cw-01\"\n (actionClick)=\"reload()\"\n />\n } @else if (facade.snapshot(); as snapshot) {\n <div class=\"flex min-w-0 flex-col gap-4\">\n <!-- Status and actions -->\n <div\n class=\"flex flex-wrap items-center justify-between gap-3 rounded-md border border-surface bg-content px-4 py-3\"\n >\n <div class=\"flex min-w-0 flex-wrap items-center gap-2 text-sm\">\n <span\n class=\"rounded-md border border-surface bg-surface-50 px-2 py-0.5 font-medium\"\n >\n {{ t(\"source.\" + snapshot.source) }}\n @if (snapshot.revision > 0) {\n \u00B7 {{ t(\"revision\", { revision: snapshot.revision }) }}\n }\n </span>\n @if (facade.dirty()) {\n <span\n class=\"rounded-md border border-amber-200 bg-amber-50 px-2 py-0.5 font-medium text-amber-700\"\n >\n {{ t(\"unsaved\") }}\n </span>\n }\n </div>\n <div class=\"flex flex-wrap items-center gap-2\">\n @if (snapshot.canRestore) {\n <mt-button\n icon=\"arrow.refresh-cw-01\"\n [label]=\"t('actions.restore')\"\n severity=\"secondary\"\n variant=\"outlined\"\n [loading]=\"facade.saving() === 'restore'\"\n [disabled]=\"facade.saving() !== null\"\n (onClick)=\"restorePrevious()\"\n />\n }\n <mt-button\n [label]=\"t('actions.discard')\"\n severity=\"secondary\"\n variant=\"text\"\n [disabled]=\"!facade.dirty() || facade.saving() !== null\"\n (onClick)=\"discard()\"\n />\n <mt-button\n icon=\"general.check\"\n [label]=\"t('actions.publish')\"\n [tooltip]=\"publishBlockedReason()\"\n [loading]=\"facade.saving() === 'publish'\"\n [disabled]=\"!canPublish()\"\n (onClick)=\"publish()\"\n />\n </div>\n </div>\n\n @if (facade.conflict() || baselineMoved()) {\n <div\n class=\"flex flex-wrap items-center justify-between gap-3 rounded-md border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-700\"\n role=\"alert\"\n >\n <span>{{ t(\"conflict\") }}</span>\n <div class=\"flex flex-wrap gap-2\">\n <mt-button\n [label]=\"t('actions.keep-mine')\"\n size=\"small\"\n severity=\"secondary\"\n variant=\"outlined\"\n (onClick)=\"resolveConflict(true)\"\n />\n <mt-button\n [label]=\"t('actions.load-latest')\"\n size=\"small\"\n severity=\"secondary\"\n (onClick)=\"resolveConflict(false)\"\n />\n </div>\n </div>\n }\n\n @if (blockingDiagnostics().length > 0) {\n <div\n class=\"rounded-md border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\n role=\"alert\"\n >\n <p class=\"font-medium\">{{ t(\"blocked\") }}</p>\n <ul class=\"mt-1 list-disc ps-5\">\n @for (diagnostic of blockingDiagnostics(); track $index) {\n <li>{{ describeDiagnostic(diagnostic) }}</li>\n }\n </ul>\n </div>\n }\n\n @if (writeDiagnostics().length > 0) {\n <div\n class=\"rounded-md border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\n role=\"alert\"\n >\n <ul class=\"list-disc ps-5\">\n @for (diagnostic of writeDiagnostics(); track $index) {\n <li>{{ describeDiagnostic(diagnostic) }}</li>\n }\n </ul>\n </div>\n }\n\n <div class=\"grid min-w-0 grid-cols-1 gap-4 xl:grid-cols-2\">\n <!-- HTML source -->\n <section\n class=\"flex min-w-0 flex-col overflow-hidden rounded-md border border-surface bg-content\"\n >\n <header\n class=\"flex items-center justify-between gap-2 border-b border-surface bg-surface-50 px-4 py-2.5\"\n >\n <h3 class=\"text-sm font-semibold\">{{ t(\"source-title\") }}</h3>\n @if (nearLimit()) {\n <span\n class=\"text-xs\"\n [class.text-red-600]=\"overLimit()\"\n [class.text-amber-700]=\"!overLimit()\"\n >{{ sizeLabel() }}</span\n >\n }\n </header>\n <div class=\"flex flex-col gap-2 p-4\">\n <mt-email-visual-editor\n [formControl]=\"sourceControl\"\n [label]=\"t('source-label')\"\n [hint]=\"t('source-hint')\"\n [layout]=\"true\"\n [approvedImageOrigins]=\"snapshot.approvedImageOrigins\"\n height=\"34rem\"\n />\n @if (slotCount() !== 1) {\n <p class=\"text-sm text-red-600\" role=\"alert\">\n {{ t(slotCount() === 0 ? \"slot-missing\" : \"slot-duplicate\") }}\n </p>\n }\n </div>\n </section>\n\n <!-- Live preview -->\n <section\n class=\"flex min-w-0 flex-col overflow-hidden rounded-md border border-surface bg-content\"\n >\n <header\n class=\"flex flex-wrap items-center justify-between gap-2 border-b border-surface bg-surface-50 px-4 py-2.5\"\n >\n <div class=\"flex items-center gap-2\">\n <h3 class=\"text-sm font-semibold\">{{ t(\"preview-title\") }}</h3>\n <span class=\"text-xs text-muted-color\" aria-live=\"polite\">{{\n preview().status === \"updating\" ? t(\"preview-updating\") : \"\"\n }}</span>\n </div>\n <mt-toggle-field [formControl]=\"narrow\" [label]=\"t('narrow')\" />\n </header>\n <div class=\"flex flex-col gap-3 p-4\">\n @if (preview().status === \"error\") {\n <div\n class=\"flex flex-wrap items-center justify-between gap-3 rounded-md border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\n role=\"alert\"\n >\n <span>{{ describeCode(previewErrorCode()) }}</span>\n <mt-button\n [label]=\"t('actions.retry')\"\n size=\"small\"\n severity=\"secondary\"\n variant=\"outlined\"\n (onClick)=\"retryPreview()\"\n />\n </div>\n }\n <!-- 39rem = the editor frame (34rem) plus its label and toolbar, so\n both columns end level. -->\n @if (rendered(); as rendered) {\n <div\n class=\"mx-auto w-full overflow-hidden rounded-md border border-surface transition-opacity\"\n [class.max-w-[375px]]=\"narrowValue()\"\n [class.opacity-60]=\"!freshPreview()\"\n >\n <mt-email-html-preview\n [html]=\"rendered.html\"\n [showImages]=\"true\"\n [approvedImageOrigins]=\"rendered.approvedImageOrigins\"\n [title]=\"t('preview-title')\"\n height=\"39rem\"\n />\n </div>\n @if (rendered.diagnostics.length > 0) {\n <ul class=\"list-disc ps-5 text-sm text-amber-700\">\n @for (diagnostic of rendered.diagnostics; track $index) {\n <li>{{ describeDiagnostic(diagnostic) }}</li>\n }\n </ul>\n }\n } @else if (preview().status !== \"error\") {\n <p-skeleton width=\"100%\" height=\"39rem\" borderRadius=\"0.375rem\" />\n }\n </div>\n </section>\n </div>\n </div>\n }\n</ng-container>\n" }]
|
|
2292
|
+
}], ctorParameters: () => [], propDecorators: { onBeforeUnload: [{
|
|
2293
|
+
type: HostListener,
|
|
2294
|
+
args: ['window:beforeunload', ['$event']]
|
|
2295
|
+
}] } });
|
|
2296
|
+
|
|
2297
|
+
const EMAIL_DELIVERY_TABS = [
|
|
2298
|
+
'connections',
|
|
2299
|
+
'activity',
|
|
2300
|
+
'design',
|
|
2301
|
+
];
|
|
2064
2302
|
class EmailDeliveryShell {
|
|
2065
2303
|
route = inject(ActivatedRoute);
|
|
2066
2304
|
router = inject(Router);
|
|
@@ -2077,6 +2315,7 @@ class EmailDeliveryShell {
|
|
|
2077
2315
|
return [
|
|
2078
2316
|
{ label: this.t('tabs.connections'), value: 'connections' },
|
|
2079
2317
|
{ label: this.t('tabs.activity'), value: 'activity' },
|
|
2318
|
+
{ label: this.t('tabs.design'), value: 'design' },
|
|
2080
2319
|
];
|
|
2081
2320
|
}, ...(ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []));
|
|
2082
2321
|
/**
|
|
@@ -2118,7 +2357,7 @@ class EmailDeliveryShell {
|
|
|
2118
2357
|
}, ...(ngDevMode ? [{ debugName: "readinessHint" }] : /* istanbul ignore next */ []));
|
|
2119
2358
|
constructor() {
|
|
2120
2359
|
this.route.queryParamMap.pipe(takeUntilDestroyed()).subscribe((params) => {
|
|
2121
|
-
this.activeTab.set(params.get('tab')
|
|
2360
|
+
this.activeTab.set(toTab(params.get('tab')));
|
|
2122
2361
|
});
|
|
2123
2362
|
}
|
|
2124
2363
|
ngOnInit() {
|
|
@@ -2144,7 +2383,7 @@ class EmailDeliveryShell {
|
|
|
2144
2383
|
});
|
|
2145
2384
|
}
|
|
2146
2385
|
onTabChange(value) {
|
|
2147
|
-
if (value
|
|
2386
|
+
if (!EMAIL_DELIVERY_TABS.includes(value))
|
|
2148
2387
|
return;
|
|
2149
2388
|
void this.router.navigate([], {
|
|
2150
2389
|
relativeTo: this.route,
|
|
@@ -2156,9 +2395,7 @@ class EmailDeliveryShell {
|
|
|
2156
2395
|
void this.router.navigate([PRODUCT_SETTINGS_ROUTE]);
|
|
2157
2396
|
}
|
|
2158
2397
|
syncTabFromUrl() {
|
|
2159
|
-
this.activeTab.set(this.route.snapshot.queryParamMap.get('tab')
|
|
2160
|
-
? 'activity'
|
|
2161
|
-
: 'connections');
|
|
2398
|
+
this.activeTab.set(toTab(this.route.snapshot.queryParamMap.get('tab')));
|
|
2162
2399
|
}
|
|
2163
2400
|
handleAuthorizationCallback() {
|
|
2164
2401
|
const query = this.route.snapshot.queryParamMap;
|
|
@@ -2194,7 +2431,7 @@ class EmailDeliveryShell {
|
|
|
2194
2431
|
return this.transloco.translate(`email-delivery.${key}`);
|
|
2195
2432
|
}
|
|
2196
2433
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: EmailDeliveryShell, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2197
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: EmailDeliveryShell, isStandalone: true, selector: "mt-email-delivery-shell", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'email-delivery'\">\
|
|
2434
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: EmailDeliveryShell, isStandalone: true, selector: "mt-email-delivery-shell", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'email-delivery'\">\n <mt-page\n [title]=\"t('title')\"\n avatarIcon=\"communication.mail-01\"\n [avatarStyle]=\"{\n '--p-avatar-background': 'var(--p-blue-100)',\n '--p-avatar-color': 'var(--p-blue-700)',\n }\"\n [tabs]=\"canView() ? tabs() : []\"\n [activeTab]=\"activeTab()\"\n contentClass=\"min-h-0 max-[1025px]:p-4 max-[640px]:p-3\"\n backButton\n (backButtonClick)=\"goBack()\"\n (tabChange)=\"onTabChange($event)\"\n >\n <!-- Declared unconditionally: a content query cannot reach a template that\n only exists inside a control-flow block, so the condition lives here. -->\n <ng-template #titleEnd>\n @if (canView() && readiness(); as state) {\n <span class=\"shrink-0\" [mtTooltip]=\"readinessHint()\">\n <mt-email-delivery-status kind=\"readiness\" [value]=\"state\" />\n </span>\n }\n </ng-template>\n\n @if (facade.permissionsLoading()) {\n <div class=\"p-6 text-sm text-muted-color\" aria-live=\"polite\">\n {{ t(\"access-checking\") }}\n </div>\n } @else if (canView()) {\n <div\n class=\"flex min-h-0 flex-col gap-4 [&_.mt-actions-column]:w-[5rem] [&_mt-card]:rounded-md [&_mt-table_:has(>.p-datatable)]:rounded-md\"\n >\n <mt-breadcrumb\n [items]=\"breadcrumbItems()\"\n styleClass=\"mx-1 flex justify-start\"\n />\n\n @if (activeTab() === \"activity\") {\n <mt-email-delivery-activity />\n } @else if (activeTab() === \"design\") {\n <mt-email-delivery-design />\n } @else {\n <mt-email-delivery-connections />\n }\n </div>\n } @else if (facade.permissionsError()) {\n <!-- A failed access read is not a denial; say so and offer the retry,\n otherwise a transient 500 reads as \"you do not have access\". -->\n <mt-empty-state\n illustration=\"none\"\n [title]=\"t('access-error-title')\"\n [description]=\"t('access-error-description')\"\n [actionLabel]=\"t('access-retry')\"\n actionIcon=\"arrow.refresh-cw-01\"\n (actionClick)=\"retryPermissions()\"\n />\n } @else {\n <mt-empty-state\n illustration=\"none\"\n [title]=\"t('access-denied-title')\"\n [description]=\"t('access-denied-description')\"\n />\n }\n </mt-page>\n</ng-container>\n", dependencies: [{ kind: "component", type: Page, selector: "mt-page", inputs: ["backButton", "backButtonIcon", "avatarIcon", "avatarStyle", "avatarShape", "title", "tabs", "activeTab", "contentClass", "contentId"], outputs: ["backButtonClick", "tabChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Breadcrumb, selector: "mt-breadcrumb", inputs: ["items", "styleClass"], outputs: ["onItemClick"] }, { kind: "component", type: EmptyState, selector: "mt-empty-state", inputs: ["variant", "illustration", "title", "description", "actionLabel", "actionIcon"], outputs: ["actionClick"] }, { kind: "directive", type: Tooltip, selector: "[mtTooltip]" }, { kind: "component", type: EmailDeliveryStatus, selector: "mt-email-delivery-status", inputs: ["value", "kind"] }, { kind: "component", type: EmailDeliveryConnections, selector: "mt-email-delivery-connections" }, { kind: "component", type: EmailDeliveryActivity, selector: "mt-email-delivery-activity" }, { kind: "component", type: EmailDeliveryDesign, selector: "mt-email-delivery-design" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2198
2435
|
}
|
|
2199
2436
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: EmailDeliveryShell, decorators: [{
|
|
2200
2437
|
type: Component,
|
|
@@ -2207,9 +2444,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
2207
2444
|
EmailDeliveryStatus,
|
|
2208
2445
|
EmailDeliveryConnections,
|
|
2209
2446
|
EmailDeliveryActivity,
|
|
2210
|
-
|
|
2447
|
+
EmailDeliveryDesign,
|
|
2448
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t; prefix: 'email-delivery'\">\n <mt-page\n [title]=\"t('title')\"\n avatarIcon=\"communication.mail-01\"\n [avatarStyle]=\"{\n '--p-avatar-background': 'var(--p-blue-100)',\n '--p-avatar-color': 'var(--p-blue-700)',\n }\"\n [tabs]=\"canView() ? tabs() : []\"\n [activeTab]=\"activeTab()\"\n contentClass=\"min-h-0 max-[1025px]:p-4 max-[640px]:p-3\"\n backButton\n (backButtonClick)=\"goBack()\"\n (tabChange)=\"onTabChange($event)\"\n >\n <!-- Declared unconditionally: a content query cannot reach a template that\n only exists inside a control-flow block, so the condition lives here. -->\n <ng-template #titleEnd>\n @if (canView() && readiness(); as state) {\n <span class=\"shrink-0\" [mtTooltip]=\"readinessHint()\">\n <mt-email-delivery-status kind=\"readiness\" [value]=\"state\" />\n </span>\n }\n </ng-template>\n\n @if (facade.permissionsLoading()) {\n <div class=\"p-6 text-sm text-muted-color\" aria-live=\"polite\">\n {{ t(\"access-checking\") }}\n </div>\n } @else if (canView()) {\n <div\n class=\"flex min-h-0 flex-col gap-4 [&_.mt-actions-column]:w-[5rem] [&_mt-card]:rounded-md [&_mt-table_:has(>.p-datatable)]:rounded-md\"\n >\n <mt-breadcrumb\n [items]=\"breadcrumbItems()\"\n styleClass=\"mx-1 flex justify-start\"\n />\n\n @if (activeTab() === \"activity\") {\n <mt-email-delivery-activity />\n } @else if (activeTab() === \"design\") {\n <mt-email-delivery-design />\n } @else {\n <mt-email-delivery-connections />\n }\n </div>\n } @else if (facade.permissionsError()) {\n <!-- A failed access read is not a denial; say so and offer the retry,\n otherwise a transient 500 reads as \"you do not have access\". -->\n <mt-empty-state\n illustration=\"none\"\n [title]=\"t('access-error-title')\"\n [description]=\"t('access-error-description')\"\n [actionLabel]=\"t('access-retry')\"\n actionIcon=\"arrow.refresh-cw-01\"\n (actionClick)=\"retryPermissions()\"\n />\n } @else {\n <mt-empty-state\n illustration=\"none\"\n [title]=\"t('access-denied-title')\"\n [description]=\"t('access-denied-description')\"\n />\n }\n </mt-page>\n</ng-container>\n" }]
|
|
2211
2449
|
}], ctorParameters: () => [] });
|
|
2212
2450
|
const PRODUCT_SETTINGS_ROUTE = '/control-panel/product-settings';
|
|
2451
|
+
function toTab(value) {
|
|
2452
|
+
return EMAIL_DELIVERY_TABS.includes(value)
|
|
2453
|
+
? value
|
|
2454
|
+
: 'connections';
|
|
2455
|
+
}
|
|
2213
2456
|
|
|
2214
2457
|
export { EmailDeliveryShell };
|
|
2215
|
-
//# sourceMappingURL=masterteam-system-settings-email-delivery-shell-
|
|
2458
|
+
//# sourceMappingURL=masterteam-system-settings-email-delivery-shell-D9NShoTc.mjs.map
|