@posiwise/admin-module 0.0.203 → 0.0.204
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.
|
@@ -172,6 +172,9 @@ const ROUTERS = {
|
|
|
172
172
|
loginNotifications: `${baseUrl}/login-notifications/`,
|
|
173
173
|
incidentConfig: `${baseUrl}/incident/list/`,
|
|
174
174
|
incidentDetails: `${baseUrl}/incident/`,
|
|
175
|
+
featureFlagsConfig: `${baseUrl}/feature-flags/list/`,
|
|
176
|
+
featureFlagsDetails: `${baseUrl}/feature-flags/`,
|
|
177
|
+
featureFlagRules: `${baseUrl}/feature-flags/rules/`,
|
|
175
178
|
faqConfig: `${baseUrl}/faq/list/`,
|
|
176
179
|
faqDetails: `${baseUrl}/faq/`,
|
|
177
180
|
inviteUsers: `${baseUrl}/subscriptions/invite-user/`,
|
|
@@ -352,11 +355,11 @@ class ContactUsListComponent extends AppBaseComponent {
|
|
|
352
355
|
super.ngOnDestroy();
|
|
353
356
|
}
|
|
354
357
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: ContactUsListComponent, deps: [{ token: i0.Injector }, { token: i1.AdminService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
355
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: ContactUsListComponent, isStandalone: false, selector: "pw-contact-us-list", usesInheritance: true, ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-12 d-flex justify-content-between align-items-center text-end\">\n <h2 class=\"card-title p-0 float-start\">Contact Us</h2>\n </div>\n <div class=\"col-12 mb-3\">\n <p>The <strong>Contact US</strong> module shows all submissions from the contact forms embedded on select landing pages.<br/>\n It\u2019s your central hub to track and follow up with interested users or potential leads.</p>\n</div>\n</div>\n@if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n}\n<div class=\"primeng-datatable-container table-responsive mt-0\"\n [class.hideTable]=\"data.unfiltered_count === 0\">\n <p-table #tt\n [value]=\"data.contact_request\"\n [paginator]=\"data.object_count !== 0\"\n [rows]=\"PAGE_SIZE\"\n [totalRecords]=\"data.object_count\"\n [loading]=\"loading\"\n [lazy]=\"true\"\n [filterDelay]=\"1000\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n [customSort]=\"true\">\n <!--sort order should be default empty when page load-->\n\n <!-- Caption Header, Search Bar -->\n <ng-template pTemplate=\"caption\">\n <div class=\"search-contact\">\n <div class=\"col-12 col-sm-3\">\n <p-select\n [options]=\"[\n { label: 'Select status', value: null },\n { label: 'Open', value: false },\n { label: 'Closed', value: true }\n ]\"\n placeholder=\"Select status\"\n (onChange)=\"filterClosed($event.value)\">\n </p-select>\n </div>\n <div class=\"text-end ms-auto\">\n <i class=\"fa fa-search mt-2 me-2\" aria-hidden=\"true\"></i>\n <label for=\"contact-us-list-search\" class=\"visually-hidden\">Search</label>\n <input type=\"text\"\n id=\"contact-us-list-search\"\n name=\"contact-us-list-search\"\n pInputText\n size=\"50\"\n placeholder=\"Search\"\n [(ngModel)]=\"searchText\"\n (input)=\"tt.filterGlobal($event.target.value, 'contains')\" />\n </div>\n </div>\n </ng-template>\n\n <!-- Column Header -->\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\"\n pSortableColumn=\"created_at\">\n {{ 'Admin.ContactUs.CreatedAt' | transloco }}\n <p-sortIcon field=\"created_at\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"name\">\n {{ 'Label.Name' | transloco }}\n <p-sortIcon field=\"name\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"email\">\n {{ 'Label.Email' | transloco }}\n <p-sortIcon field=\"email\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"subject\">\n {{ 'Admin.ContactUs.Subject' | transloco }}\n <p-sortIcon field=\"subject\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"message\">\n {{ 'Admin.ContactUs.Message' | transloco }}\n <p-sortIcon field=\"message\"></p-sortIcon>\n </th>\n <th class=\"actions-list-two\"\n scope=\"true\">{{ 'Label.Actions' | transloco }}</th>\n </tr>\n </ng-template>\n\n <!-- Table Body -->\n <ng-template pTemplate=\"body\"\n let-item>\n <tr>\n <td data-head=\"created_at\">{{ item?.created_at | dateFormat }}</td>\n <td data-head=\"name\">{{ item?.name }}</td>\n <td data-head=\"email\">\n <a href=\"mailto:{{ item?.email }}\">{{ item?.email }}</a>\n </td>\n <td data-head=\"subject\">{{ item?.subject }}</td>\n <td data-head=\"message\">\n <span\n [ngbTooltip]=\"item?.message\"\n container=\"body\"\n tooltipClass=\"custom-tooltip\"\n placement=\"bottom\"\n >\n {{ item?.message | textTruncate: 200 }}\n </span>\n </td>\n <td data-head=\"Action\">\n <ul class=\"list-unstyled list-inline list-action\">\n @if (!item.closed) {\n <li\n ngbTooltip=\"Close\"\n class=\"me-2 me-sm-3\"\n (keydown.enter)=\"toggleRecord(item.id, true)\"\n (click)=\"toggleRecord(item.id, true)\">\n <i class=\"fa fa-times delete-icon\" aria-hidden=\"true\"></i>\n </li>\n }\n @if (item.closed) {\n <li\n ngbTooltip=\"Re Open\"\n class=\"me-2 me-sm-3\"\n (keydown.enter)=\"onKeyDown($event, item.id)\"\n (click)=\"toggleRecord(item.id, false)\">\n <i class=\"fa fa-retweet edit-icon\" aria-hidden=\"true\"></i>\n </li>\n }\n </ul>\n </td>\n </tr>\n </ng-template>\n </p-table>\n @if (data.object_count === 0 && data.unfiltered_count !== 0) {\n <div>\n <pw-no-data [withImage]=\"true\" [message]=\"'Search.NoDataMessage' | transloco\" [description]=\"'Search.NoDataDescription' | transloco\" >\n </pw-no-data>\n </div>\n }\n @if (data.object_count !== 0) {\n <span class=\"total-records-count\" >Total: {{ data.object_count }}</span>\n }\n</div>\n@if (data.unfiltered_count === 0 && isLoaded) {\n <div>\n <pw-no-data [withImage]=\"true\" message=\"No Contact Requests\"> </pw-no-data>\n </div>\n}\n", styles: [".search-contact{display:flex;justify-content:space-between}@media(min-width:320px)and (max-width:720px){.search-contact{display:block}}\n"], dependencies: [{ kind: "component", type: i2.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i3$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i2.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "component", type: i2.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "component", type: i3.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: i2$1.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: i1$1.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "pipe", type: i11.TranslocoPipe, name: "transloco" }, { kind: "pipe", type: i15.DateFormatPipe, name: "dateFormat" }, { kind: "pipe", type: i15.TextTruncatePipe, name: "textTruncate" }] }); }
|
|
358
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: ContactUsListComponent, isStandalone: false, selector: "pw-contact-us-list", usesInheritance: true, ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-12 d-flex justify-content-between align-items-center text-end\">\n <h2 class=\"card-title p-0 float-start\">Contact Us</h2>\n </div>\n <div class=\"col-12 mb-3\">\n <p>The <strong>Contact US</strong> module shows all submissions from the contact forms embedded on select landing pages.<br/>\n It\u2019s your central hub to track and follow up with interested users or potential leads.</p>\n</div>\n</div>\n@if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n}\n<div class=\"primeng-datatable-container table-responsive mt-0\"\n [class.hideTable]=\"data.unfiltered_count === 0\">\n <p-table #tt\n [value]=\"data.contact_request\"\n [paginator]=\"data.object_count !== 0\"\n [rows]=\"PAGE_SIZE\"\n [totalRecords]=\"data.object_count\"\n [loading]=\"loading\"\n [lazy]=\"true\"\n [filterDelay]=\"1000\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n [customSort]=\"true\">\n <!--sort order should be default empty when page load-->\n\n <!-- Caption Header, Search Bar -->\n <ng-template pTemplate=\"caption\">\n <div class=\"search-contact\">\n <div class=\"col-12 col-sm-3\">\n <p-select\n [options]=\"[\n { label: 'Select status', value: null },\n { label: 'Open', value: false },\n { label: 'Closed', value: true }\n ]\"\n placeholder=\"Select status\"\n (onChange)=\"filterClosed($event.value)\"\n appendTo=\"body\">\n </p-select>\n </div>\n <div class=\"text-end ms-auto\">\n <i class=\"fa fa-search mt-2 me-2\" aria-hidden=\"true\"></i>\n <label for=\"contact-us-list-search\" class=\"visually-hidden\">Search</label>\n <input type=\"text\"\n id=\"contact-us-list-search\"\n name=\"contact-us-list-search\"\n pInputText\n size=\"50\"\n placeholder=\"Search\"\n [(ngModel)]=\"searchText\"\n (input)=\"tt.filterGlobal($event.target.value, 'contains')\" />\n </div>\n </div>\n </ng-template>\n\n <!-- Column Header -->\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\"\n pSortableColumn=\"created_at\">\n {{ 'Admin.ContactUs.CreatedAt' | transloco }}\n <p-sortIcon field=\"created_at\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"name\">\n {{ 'Label.Name' | transloco }}\n <p-sortIcon field=\"name\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"email\">\n {{ 'Label.Email' | transloco }}\n <p-sortIcon field=\"email\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"subject\">\n {{ 'Admin.ContactUs.Subject' | transloco }}\n <p-sortIcon field=\"subject\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"message\">\n {{ 'Admin.ContactUs.Message' | transloco }}\n <p-sortIcon field=\"message\"></p-sortIcon>\n </th>\n <th class=\"actions-list-two\"\n scope=\"true\">{{ 'Label.Actions' | transloco }}</th>\n </tr>\n </ng-template>\n\n <!-- Table Body -->\n <ng-template pTemplate=\"body\"\n let-item>\n <tr>\n <td data-head=\"created_at\">{{ item?.created_at | dateFormat }}</td>\n <td data-head=\"name\">{{ item?.name }}</td>\n <td data-head=\"email\">\n <a href=\"mailto:{{ item?.email }}\">{{ item?.email }}</a>\n </td>\n <td data-head=\"subject\">{{ item?.subject }}</td>\n <td data-head=\"message\">\n <span\n [ngbTooltip]=\"item?.message\"\n container=\"body\"\n tooltipClass=\"custom-tooltip\"\n placement=\"bottom\"\n >\n {{ item?.message | textTruncate: 200 }}\n </span>\n </td>\n <td data-head=\"Action\">\n <ul class=\"list-unstyled list-inline list-action\">\n @if (!item.closed) {\n <li\n ngbTooltip=\"Close\"\n class=\"me-2 me-sm-3\"\n (keydown.enter)=\"toggleRecord(item.id, true)\"\n (click)=\"toggleRecord(item.id, true)\">\n <i class=\"fa fa-times delete-icon\" aria-hidden=\"true\"></i>\n </li>\n }\n @if (item.closed) {\n <li\n ngbTooltip=\"Re Open\"\n class=\"me-2 me-sm-3\"\n (keydown.enter)=\"onKeyDown($event, item.id)\"\n (click)=\"toggleRecord(item.id, false)\">\n <i class=\"fa fa-retweet edit-icon\" aria-hidden=\"true\"></i>\n </li>\n }\n </ul>\n </td>\n </tr>\n </ng-template>\n </p-table>\n @if (data.object_count === 0 && data.unfiltered_count !== 0) {\n <div>\n <pw-no-data [withImage]=\"true\" [message]=\"'Search.NoDataMessage' | transloco\" [description]=\"'Search.NoDataDescription' | transloco\" >\n </pw-no-data>\n </div>\n }\n @if (data.object_count !== 0) {\n <span class=\"total-records-count\" >Total: {{ data.object_count }}</span>\n }\n</div>\n@if (data.unfiltered_count === 0 && isLoaded) {\n <div>\n <pw-no-data [withImage]=\"true\" message=\"No Contact Requests\"> </pw-no-data>\n </div>\n}\n", styles: [".search-contact{display:flex;justify-content:space-between}@media(min-width:320px)and (max-width:720px){.search-contact{display:block}}\n"], dependencies: [{ kind: "component", type: i2.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i3$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i2.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "component", type: i2.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "component", type: i3.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: i2$1.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: i1$1.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "pipe", type: i11.TranslocoPipe, name: "transloco" }, { kind: "pipe", type: i15.DateFormatPipe, name: "dateFormat" }, { kind: "pipe", type: i15.TextTruncatePipe, name: "textTruncate" }] }); }
|
|
356
359
|
}
|
|
357
360
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: ContactUsListComponent, decorators: [{
|
|
358
361
|
type: Component,
|
|
359
|
-
args: [{ selector: 'pw-contact-us-list', standalone: false, template: "<div class=\"row\">\n <div class=\"col-12 d-flex justify-content-between align-items-center text-end\">\n <h2 class=\"card-title p-0 float-start\">Contact Us</h2>\n </div>\n <div class=\"col-12 mb-3\">\n <p>The <strong>Contact US</strong> module shows all submissions from the contact forms embedded on select landing pages.<br/>\n It\u2019s your central hub to track and follow up with interested users or potential leads.</p>\n</div>\n</div>\n@if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n}\n<div class=\"primeng-datatable-container table-responsive mt-0\"\n [class.hideTable]=\"data.unfiltered_count === 0\">\n <p-table #tt\n [value]=\"data.contact_request\"\n [paginator]=\"data.object_count !== 0\"\n [rows]=\"PAGE_SIZE\"\n [totalRecords]=\"data.object_count\"\n [loading]=\"loading\"\n [lazy]=\"true\"\n [filterDelay]=\"1000\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n [customSort]=\"true\">\n <!--sort order should be default empty when page load-->\n\n <!-- Caption Header, Search Bar -->\n <ng-template pTemplate=\"caption\">\n <div class=\"search-contact\">\n <div class=\"col-12 col-sm-3\">\n <p-select\n [options]=\"[\n { label: 'Select status', value: null },\n { label: 'Open', value: false },\n { label: 'Closed', value: true }\n ]\"\n placeholder=\"Select status\"\n (onChange)=\"filterClosed($event.value)\">\n </p-select>\n </div>\n <div class=\"text-end ms-auto\">\n <i class=\"fa fa-search mt-2 me-2\" aria-hidden=\"true\"></i>\n <label for=\"contact-us-list-search\" class=\"visually-hidden\">Search</label>\n <input type=\"text\"\n id=\"contact-us-list-search\"\n name=\"contact-us-list-search\"\n pInputText\n size=\"50\"\n placeholder=\"Search\"\n [(ngModel)]=\"searchText\"\n (input)=\"tt.filterGlobal($event.target.value, 'contains')\" />\n </div>\n </div>\n </ng-template>\n\n <!-- Column Header -->\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\"\n pSortableColumn=\"created_at\">\n {{ 'Admin.ContactUs.CreatedAt' | transloco }}\n <p-sortIcon field=\"created_at\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"name\">\n {{ 'Label.Name' | transloco }}\n <p-sortIcon field=\"name\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"email\">\n {{ 'Label.Email' | transloco }}\n <p-sortIcon field=\"email\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"subject\">\n {{ 'Admin.ContactUs.Subject' | transloco }}\n <p-sortIcon field=\"subject\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"message\">\n {{ 'Admin.ContactUs.Message' | transloco }}\n <p-sortIcon field=\"message\"></p-sortIcon>\n </th>\n <th class=\"actions-list-two\"\n scope=\"true\">{{ 'Label.Actions' | transloco }}</th>\n </tr>\n </ng-template>\n\n <!-- Table Body -->\n <ng-template pTemplate=\"body\"\n let-item>\n <tr>\n <td data-head=\"created_at\">{{ item?.created_at | dateFormat }}</td>\n <td data-head=\"name\">{{ item?.name }}</td>\n <td data-head=\"email\">\n <a href=\"mailto:{{ item?.email }}\">{{ item?.email }}</a>\n </td>\n <td data-head=\"subject\">{{ item?.subject }}</td>\n <td data-head=\"message\">\n <span\n [ngbTooltip]=\"item?.message\"\n container=\"body\"\n tooltipClass=\"custom-tooltip\"\n placement=\"bottom\"\n >\n {{ item?.message | textTruncate: 200 }}\n </span>\n </td>\n <td data-head=\"Action\">\n <ul class=\"list-unstyled list-inline list-action\">\n @if (!item.closed) {\n <li\n ngbTooltip=\"Close\"\n class=\"me-2 me-sm-3\"\n (keydown.enter)=\"toggleRecord(item.id, true)\"\n (click)=\"toggleRecord(item.id, true)\">\n <i class=\"fa fa-times delete-icon\" aria-hidden=\"true\"></i>\n </li>\n }\n @if (item.closed) {\n <li\n ngbTooltip=\"Re Open\"\n class=\"me-2 me-sm-3\"\n (keydown.enter)=\"onKeyDown($event, item.id)\"\n (click)=\"toggleRecord(item.id, false)\">\n <i class=\"fa fa-retweet edit-icon\" aria-hidden=\"true\"></i>\n </li>\n }\n </ul>\n </td>\n </tr>\n </ng-template>\n </p-table>\n @if (data.object_count === 0 && data.unfiltered_count !== 0) {\n <div>\n <pw-no-data [withImage]=\"true\" [message]=\"'Search.NoDataMessage' | transloco\" [description]=\"'Search.NoDataDescription' | transloco\" >\n </pw-no-data>\n </div>\n }\n @if (data.object_count !== 0) {\n <span class=\"total-records-count\" >Total: {{ data.object_count }}</span>\n }\n</div>\n@if (data.unfiltered_count === 0 && isLoaded) {\n <div>\n <pw-no-data [withImage]=\"true\" message=\"No Contact Requests\"> </pw-no-data>\n </div>\n}\n", styles: [".search-contact{display:flex;justify-content:space-between}@media(min-width:320px)and (max-width:720px){.search-contact{display:block}}\n"] }]
|
|
362
|
+
args: [{ selector: 'pw-contact-us-list', standalone: false, template: "<div class=\"row\">\n <div class=\"col-12 d-flex justify-content-between align-items-center text-end\">\n <h2 class=\"card-title p-0 float-start\">Contact Us</h2>\n </div>\n <div class=\"col-12 mb-3\">\n <p>The <strong>Contact US</strong> module shows all submissions from the contact forms embedded on select landing pages.<br/>\n It\u2019s your central hub to track and follow up with interested users or potential leads.</p>\n</div>\n</div>\n@if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n}\n<div class=\"primeng-datatable-container table-responsive mt-0\"\n [class.hideTable]=\"data.unfiltered_count === 0\">\n <p-table #tt\n [value]=\"data.contact_request\"\n [paginator]=\"data.object_count !== 0\"\n [rows]=\"PAGE_SIZE\"\n [totalRecords]=\"data.object_count\"\n [loading]=\"loading\"\n [lazy]=\"true\"\n [filterDelay]=\"1000\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n [customSort]=\"true\">\n <!--sort order should be default empty when page load-->\n\n <!-- Caption Header, Search Bar -->\n <ng-template pTemplate=\"caption\">\n <div class=\"search-contact\">\n <div class=\"col-12 col-sm-3\">\n <p-select\n [options]=\"[\n { label: 'Select status', value: null },\n { label: 'Open', value: false },\n { label: 'Closed', value: true }\n ]\"\n placeholder=\"Select status\"\n (onChange)=\"filterClosed($event.value)\"\n appendTo=\"body\">\n </p-select>\n </div>\n <div class=\"text-end ms-auto\">\n <i class=\"fa fa-search mt-2 me-2\" aria-hidden=\"true\"></i>\n <label for=\"contact-us-list-search\" class=\"visually-hidden\">Search</label>\n <input type=\"text\"\n id=\"contact-us-list-search\"\n name=\"contact-us-list-search\"\n pInputText\n size=\"50\"\n placeholder=\"Search\"\n [(ngModel)]=\"searchText\"\n (input)=\"tt.filterGlobal($event.target.value, 'contains')\" />\n </div>\n </div>\n </ng-template>\n\n <!-- Column Header -->\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\"\n pSortableColumn=\"created_at\">\n {{ 'Admin.ContactUs.CreatedAt' | transloco }}\n <p-sortIcon field=\"created_at\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"name\">\n {{ 'Label.Name' | transloco }}\n <p-sortIcon field=\"name\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"email\">\n {{ 'Label.Email' | transloco }}\n <p-sortIcon field=\"email\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"subject\">\n {{ 'Admin.ContactUs.Subject' | transloco }}\n <p-sortIcon field=\"subject\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"message\">\n {{ 'Admin.ContactUs.Message' | transloco }}\n <p-sortIcon field=\"message\"></p-sortIcon>\n </th>\n <th class=\"actions-list-two\"\n scope=\"true\">{{ 'Label.Actions' | transloco }}</th>\n </tr>\n </ng-template>\n\n <!-- Table Body -->\n <ng-template pTemplate=\"body\"\n let-item>\n <tr>\n <td data-head=\"created_at\">{{ item?.created_at | dateFormat }}</td>\n <td data-head=\"name\">{{ item?.name }}</td>\n <td data-head=\"email\">\n <a href=\"mailto:{{ item?.email }}\">{{ item?.email }}</a>\n </td>\n <td data-head=\"subject\">{{ item?.subject }}</td>\n <td data-head=\"message\">\n <span\n [ngbTooltip]=\"item?.message\"\n container=\"body\"\n tooltipClass=\"custom-tooltip\"\n placement=\"bottom\"\n >\n {{ item?.message | textTruncate: 200 }}\n </span>\n </td>\n <td data-head=\"Action\">\n <ul class=\"list-unstyled list-inline list-action\">\n @if (!item.closed) {\n <li\n ngbTooltip=\"Close\"\n class=\"me-2 me-sm-3\"\n (keydown.enter)=\"toggleRecord(item.id, true)\"\n (click)=\"toggleRecord(item.id, true)\">\n <i class=\"fa fa-times delete-icon\" aria-hidden=\"true\"></i>\n </li>\n }\n @if (item.closed) {\n <li\n ngbTooltip=\"Re Open\"\n class=\"me-2 me-sm-3\"\n (keydown.enter)=\"onKeyDown($event, item.id)\"\n (click)=\"toggleRecord(item.id, false)\">\n <i class=\"fa fa-retweet edit-icon\" aria-hidden=\"true\"></i>\n </li>\n }\n </ul>\n </td>\n </tr>\n </ng-template>\n </p-table>\n @if (data.object_count === 0 && data.unfiltered_count !== 0) {\n <div>\n <pw-no-data [withImage]=\"true\" [message]=\"'Search.NoDataMessage' | transloco\" [description]=\"'Search.NoDataDescription' | transloco\" >\n </pw-no-data>\n </div>\n }\n @if (data.object_count !== 0) {\n <span class=\"total-records-count\" >Total: {{ data.object_count }}</span>\n }\n</div>\n@if (data.unfiltered_count === 0 && isLoaded) {\n <div>\n <pw-no-data [withImage]=\"true\" message=\"No Contact Requests\"> </pw-no-data>\n </div>\n}\n", styles: [".search-contact{display:flex;justify-content:space-between}@media(min-width:320px)and (max-width:720px){.search-contact{display:block}}\n"] }]
|
|
360
363
|
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1.AdminService }, { type: i0.ChangeDetectorRef }] });
|
|
361
364
|
|
|
362
365
|
class ContactUsTabsComponent {
|
|
@@ -2713,6 +2716,371 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
2713
2716
|
}]
|
|
2714
2717
|
}] });
|
|
2715
2718
|
|
|
2719
|
+
class FeatureFlagDetailsComponent extends AppBaseComponent {
|
|
2720
|
+
constructor(injector, adminService) {
|
|
2721
|
+
super(injector);
|
|
2722
|
+
this.adminService = adminService;
|
|
2723
|
+
this.form = AppAdmin.getFeatureFlagForm();
|
|
2724
|
+
this.routers = ROUTERS;
|
|
2725
|
+
this.id = 0;
|
|
2726
|
+
this.isLoading = true;
|
|
2727
|
+
this.submitted = false;
|
|
2728
|
+
this.buttonBusy = false;
|
|
2729
|
+
this.flagTypeOptions = [];
|
|
2730
|
+
this.statusOptions = [];
|
|
2731
|
+
this.allUsers = [];
|
|
2732
|
+
this.filteredUsers = [];
|
|
2733
|
+
}
|
|
2734
|
+
ngOnInit() {
|
|
2735
|
+
this.subscriptionId = PermissionService.selectedSubscription?.id;
|
|
2736
|
+
this.loadSupportedOptions();
|
|
2737
|
+
this.loadOwners();
|
|
2738
|
+
this.route.params.subscribe(params => {
|
|
2739
|
+
this.id = +params['id'] || 0;
|
|
2740
|
+
if (this.id) {
|
|
2741
|
+
this.getFeatureFlag();
|
|
2742
|
+
}
|
|
2743
|
+
else {
|
|
2744
|
+
this.isLoading = false;
|
|
2745
|
+
}
|
|
2746
|
+
});
|
|
2747
|
+
}
|
|
2748
|
+
loadSupportedOptions() {
|
|
2749
|
+
this.adminService.getSupportedFeatureFlagOptions().subscribe(response => {
|
|
2750
|
+
this.flagTypeOptions = (response.flag_types || []).map(option => ({
|
|
2751
|
+
label: option,
|
|
2752
|
+
value: option
|
|
2753
|
+
}));
|
|
2754
|
+
this.statusOptions = (response.statuses || []).map(option => ({
|
|
2755
|
+
label: option,
|
|
2756
|
+
value: option
|
|
2757
|
+
}));
|
|
2758
|
+
});
|
|
2759
|
+
}
|
|
2760
|
+
loadOwners() {
|
|
2761
|
+
this.adminService
|
|
2762
|
+
.getUsers({}, { subscription_id: this.subscriptionId })
|
|
2763
|
+
.subscribe(response => {
|
|
2764
|
+
this.allUsers = response.users || [];
|
|
2765
|
+
this.allUsers.forEach(user => {
|
|
2766
|
+
const firstName = user.first_name ?? '';
|
|
2767
|
+
const lastName = user.last_name ?? '';
|
|
2768
|
+
user.displayName = `${firstName} ${lastName} ${user.email}`.trim();
|
|
2769
|
+
});
|
|
2770
|
+
});
|
|
2771
|
+
}
|
|
2772
|
+
searchOwners(event) {
|
|
2773
|
+
const query = event.query?.toLowerCase() || '';
|
|
2774
|
+
this.filteredUsers = !query
|
|
2775
|
+
? [...this.allUsers]
|
|
2776
|
+
: this.allUsers.filter(user => user.displayName.toLowerCase().includes(query));
|
|
2777
|
+
}
|
|
2778
|
+
get f() {
|
|
2779
|
+
return this.form.controls;
|
|
2780
|
+
}
|
|
2781
|
+
getFeatureFlag() {
|
|
2782
|
+
this.adminService.getFeatureFlagById(this.id).subscribe({
|
|
2783
|
+
next: response => {
|
|
2784
|
+
this.form.patchValue({
|
|
2785
|
+
id: response.id,
|
|
2786
|
+
key: response.key,
|
|
2787
|
+
name: response.name,
|
|
2788
|
+
description: response.description,
|
|
2789
|
+
flag_type: response.flag_type,
|
|
2790
|
+
status: response.status,
|
|
2791
|
+
owner: this.allUsers.find(user => user.email === response.owner) || response.owner,
|
|
2792
|
+
expires_at: response.expires_at ? new Date(response.expires_at) : null
|
|
2793
|
+
});
|
|
2794
|
+
},
|
|
2795
|
+
complete: () => {
|
|
2796
|
+
this.isLoading = false;
|
|
2797
|
+
}
|
|
2798
|
+
});
|
|
2799
|
+
}
|
|
2800
|
+
onSubmit() {
|
|
2801
|
+
this.form.markAllAsTouched();
|
|
2802
|
+
this.submitted = true;
|
|
2803
|
+
if (!this.form.valid) {
|
|
2804
|
+
return;
|
|
2805
|
+
}
|
|
2806
|
+
this.buttonBusy = true;
|
|
2807
|
+
const formValue = this.form.value;
|
|
2808
|
+
const payload = {
|
|
2809
|
+
...formValue,
|
|
2810
|
+
owner: typeof formValue.owner === 'string' ? formValue.owner : formValue.owner?.email
|
|
2811
|
+
};
|
|
2812
|
+
const request$ = this.id
|
|
2813
|
+
? this.adminService.updateFeatureFlag(this.id, payload)
|
|
2814
|
+
: this.adminService.createFeatureFlag(payload);
|
|
2815
|
+
request$.subscribe({
|
|
2816
|
+
next: () => {
|
|
2817
|
+
this.toast.success(this.id
|
|
2818
|
+
? 'Feature flag updated successfully.'
|
|
2819
|
+
: 'Feature flag created successfully.');
|
|
2820
|
+
this.router.navigate([this.routers.featureFlagsConfig]);
|
|
2821
|
+
},
|
|
2822
|
+
complete: () => {
|
|
2823
|
+
this.buttonBusy = false;
|
|
2824
|
+
}
|
|
2825
|
+
});
|
|
2826
|
+
}
|
|
2827
|
+
onCancel() {
|
|
2828
|
+
this.router.navigate([this.routers.featureFlagsConfig]);
|
|
2829
|
+
}
|
|
2830
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FeatureFlagDetailsComponent, deps: [{ token: i0.Injector }, { token: i1.AdminService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2831
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FeatureFlagDetailsComponent, isStandalone: false, selector: "pw-feature-flag-details", usesInheritance: true, ngImport: i0, template: "<div class=\"container-fluid pw-tab\">\n <div class=\"dashboard\">\n <div class=\"dashboard-body\">\n <div class=\"me-auto col-xs-6 mt-4\">\n <a routerLink=\"/admin/feature-flags/list\" class=\"previous\"><i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i></a>\n <h3 class=\"mt-3\">{{ id ? 'Edit' : 'Add New' }} Feature Flag</h3>\n </div>\n\n @if (isLoading) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"></p-progressSpinner>\n </div>\n }\n\n <div class=\"p-2 mt-3\">\n @if (!isLoading) {\n <form (ngSubmit)=\"onSubmit()\" [formGroup]=\"form\">\n <div class=\"row\">\n <pw-input-container class=\"col-lg-6\" label=\"Key\" name=\"key\" controlId=\"feature-flag-key\" errorMsg=\"Key is required\"\n [showTooltip]=\"true\" [tooltipText]=\"'FeatureFlag.Tooltip.Key' | transloco\">\n <input type=\"text\" id=\"feature-flag-key\" formControlName=\"key\" class=\"form-control\" [ngClass]=\"{ 'is-invalid': submitted && f['key'].errors }\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-6\" label=\"Name\" name=\"name\" controlId=\"feature-flag-name\" errorMsg=\"Name is required\"\n [showTooltip]=\"true\" [tooltipText]=\"'FeatureFlag.Tooltip.Name' | transloco\">\n <input type=\"text\" id=\"feature-flag-name\" formControlName=\"name\" class=\"form-control\" [ngClass]=\"{ 'is-invalid': submitted && f['name'].errors }\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-12\" label=\"Description\" name=\"description\" controlId=\"feature-flag-description\">\n <textarea id=\"feature-flag-description\" formControlName=\"description\" rows=\"4\" class=\"form-control\"></textarea>\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-3\" label=\"Type\" name=\"flag_type\" controlId=\"feature-flag-type\" [useAriaLabelledbyOnly]=\"true\">\n <p-select [options]=\"flagTypeOptions\" [attr.aria-labelledby]=\"'feature-flag-type-label'\" formControlName=\"flag_type\" class=\"dropdown-bg-transparent\" placeholder=\"Select type\"></p-select>\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-3\" label=\"Status\" name=\"status\" controlId=\"feature-flag-status\" [useAriaLabelledbyOnly]=\"true\">\n <p-select [options]=\"statusOptions\" [attr.aria-labelledby]=\"'feature-flag-status-label'\" formControlName=\"status\" class=\"dropdown-bg-transparent\" placeholder=\"Select status\"></p-select>\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-3\" label=\"Owner\" name=\"owner\" controlId=\"feature-flag-owner\" [useAriaLabelledbyOnly]=\"true\">\n <p-autoComplete\n [suggestions]=\"filteredUsers\"\n [attr.aria-labelledby]=\"'feature-flag-owner-label'\"\n formControlName=\"owner\"\n dataKey=\"id\"\n field=\"displayName\"\n [dropdown]=\"true\"\n (completeMethod)=\"searchOwners($event)\"\n styleClass=\"w-100\"\n placeholder=\"Search owner\"\n [multiple]=\"false\"\n autocomplete=\"off\">\n </p-autoComplete>\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-3\" label=\"Expires At\" name=\"expires_at\" controlId=\"feature-flag-expires_at\" [useAriaLabelledbyOnly]=\"true\">\n <p-calendar inputId=\"feature-flag-expires_at\" formControlName=\"expires_at\" [showIcon]=\"true\" [showTime]=\"true\" [appendTo]=\"'body'\" dateFormat=\"dd-M-yy\"></p-calendar>\n </pw-input-container>\n </div>\n\n <div class=\"row\">\n <div class=\"col-12 mt-4\">\n <div class=\"mb-3 text-end\">\n <button type=\"button\" class=\"btn btn-outline-default me-2\" (click)=\"onCancel()\">{{ 'Button.Cancel' | transloco }}</button>\n <button class=\"btn btn-primary\" [buttonBusy]=\"buttonBusy\">{{ 'Button.Save' | transloco }}</button>\n </div>\n </div>\n </div>\n </form>\n }\n </div>\n </div>\n </div>\n</div>", dependencies: [{ kind: "component", type: i5.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "component", type: i3.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "directive", type: i3$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i6.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: i1$1.InputContainerComponent, selector: "pw-input-container", inputs: ["name", "controlId", "useAriaLabelledbyOnly", "label", "labelClass", "tooltipPosition", "required", "errorMsg", "isReadOnly", "showTooltip", "tooltipText", "showTriangle", "afterLabel", "showAfterLabel", "showTriangleText", "isLeftTooltip"] }, { kind: "directive", type: i9.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i10.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i6.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i6.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "pipe", type: i11.TranslocoPipe, name: "transloco" }] }); }
|
|
2832
|
+
}
|
|
2833
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FeatureFlagDetailsComponent, decorators: [{
|
|
2834
|
+
type: Component,
|
|
2835
|
+
args: [{ selector: 'pw-feature-flag-details', standalone: false, template: "<div class=\"container-fluid pw-tab\">\n <div class=\"dashboard\">\n <div class=\"dashboard-body\">\n <div class=\"me-auto col-xs-6 mt-4\">\n <a routerLink=\"/admin/feature-flags/list\" class=\"previous\"><i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i></a>\n <h3 class=\"mt-3\">{{ id ? 'Edit' : 'Add New' }} Feature Flag</h3>\n </div>\n\n @if (isLoading) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"></p-progressSpinner>\n </div>\n }\n\n <div class=\"p-2 mt-3\">\n @if (!isLoading) {\n <form (ngSubmit)=\"onSubmit()\" [formGroup]=\"form\">\n <div class=\"row\">\n <pw-input-container class=\"col-lg-6\" label=\"Key\" name=\"key\" controlId=\"feature-flag-key\" errorMsg=\"Key is required\"\n [showTooltip]=\"true\" [tooltipText]=\"'FeatureFlag.Tooltip.Key' | transloco\">\n <input type=\"text\" id=\"feature-flag-key\" formControlName=\"key\" class=\"form-control\" [ngClass]=\"{ 'is-invalid': submitted && f['key'].errors }\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-6\" label=\"Name\" name=\"name\" controlId=\"feature-flag-name\" errorMsg=\"Name is required\"\n [showTooltip]=\"true\" [tooltipText]=\"'FeatureFlag.Tooltip.Name' | transloco\">\n <input type=\"text\" id=\"feature-flag-name\" formControlName=\"name\" class=\"form-control\" [ngClass]=\"{ 'is-invalid': submitted && f['name'].errors }\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-12\" label=\"Description\" name=\"description\" controlId=\"feature-flag-description\">\n <textarea id=\"feature-flag-description\" formControlName=\"description\" rows=\"4\" class=\"form-control\"></textarea>\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-3\" label=\"Type\" name=\"flag_type\" controlId=\"feature-flag-type\" [useAriaLabelledbyOnly]=\"true\">\n <p-select [options]=\"flagTypeOptions\" [attr.aria-labelledby]=\"'feature-flag-type-label'\" formControlName=\"flag_type\" class=\"dropdown-bg-transparent\" placeholder=\"Select type\"></p-select>\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-3\" label=\"Status\" name=\"status\" controlId=\"feature-flag-status\" [useAriaLabelledbyOnly]=\"true\">\n <p-select [options]=\"statusOptions\" [attr.aria-labelledby]=\"'feature-flag-status-label'\" formControlName=\"status\" class=\"dropdown-bg-transparent\" placeholder=\"Select status\"></p-select>\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-3\" label=\"Owner\" name=\"owner\" controlId=\"feature-flag-owner\" [useAriaLabelledbyOnly]=\"true\">\n <p-autoComplete\n [suggestions]=\"filteredUsers\"\n [attr.aria-labelledby]=\"'feature-flag-owner-label'\"\n formControlName=\"owner\"\n dataKey=\"id\"\n field=\"displayName\"\n [dropdown]=\"true\"\n (completeMethod)=\"searchOwners($event)\"\n styleClass=\"w-100\"\n placeholder=\"Search owner\"\n [multiple]=\"false\"\n autocomplete=\"off\">\n </p-autoComplete>\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-3\" label=\"Expires At\" name=\"expires_at\" controlId=\"feature-flag-expires_at\" [useAriaLabelledbyOnly]=\"true\">\n <p-calendar inputId=\"feature-flag-expires_at\" formControlName=\"expires_at\" [showIcon]=\"true\" [showTime]=\"true\" [appendTo]=\"'body'\" dateFormat=\"dd-M-yy\"></p-calendar>\n </pw-input-container>\n </div>\n\n <div class=\"row\">\n <div class=\"col-12 mt-4\">\n <div class=\"mb-3 text-end\">\n <button type=\"button\" class=\"btn btn-outline-default me-2\" (click)=\"onCancel()\">{{ 'Button.Cancel' | transloco }}</button>\n <button class=\"btn btn-primary\" [buttonBusy]=\"buttonBusy\">{{ 'Button.Save' | transloco }}</button>\n </div>\n </div>\n </div>\n </form>\n }\n </div>\n </div>\n </div>\n</div>" }]
|
|
2836
|
+
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1.AdminService }] });
|
|
2837
|
+
|
|
2838
|
+
class FeatureFlagRulesComponent extends AppBaseComponent {
|
|
2839
|
+
constructor(injector, adminService) {
|
|
2840
|
+
super(injector);
|
|
2841
|
+
this.adminService = adminService;
|
|
2842
|
+
this.routers = ROUTERS;
|
|
2843
|
+
this.ruleForm = AppAdmin.getFeatureFlagRuleForm();
|
|
2844
|
+
this.featureFlagId = 0;
|
|
2845
|
+
this.featureFlagName = '';
|
|
2846
|
+
this.isLoading = true;
|
|
2847
|
+
this.ruleSubmitted = false;
|
|
2848
|
+
this.ruleButtonBusy = false;
|
|
2849
|
+
this.rules = [];
|
|
2850
|
+
this.editingRuleId = null;
|
|
2851
|
+
this.targetTypeOptions = [];
|
|
2852
|
+
this.environmentOptions = [];
|
|
2853
|
+
this.productFeatureKeyOptions = [];
|
|
2854
|
+
}
|
|
2855
|
+
ngOnInit() {
|
|
2856
|
+
this.route.params.subscribe(params => {
|
|
2857
|
+
this.featureFlagId = +params['id'] || 0;
|
|
2858
|
+
this.loadPageData();
|
|
2859
|
+
});
|
|
2860
|
+
}
|
|
2861
|
+
get rf() {
|
|
2862
|
+
return this.ruleForm.controls;
|
|
2863
|
+
}
|
|
2864
|
+
loadPageData() {
|
|
2865
|
+
if (!this.featureFlagId) {
|
|
2866
|
+
this.isLoading = false;
|
|
2867
|
+
return;
|
|
2868
|
+
}
|
|
2869
|
+
this.isLoading = true;
|
|
2870
|
+
this.loadSupportedOptions();
|
|
2871
|
+
this.loadFeatureFlag();
|
|
2872
|
+
this.loadRules();
|
|
2873
|
+
}
|
|
2874
|
+
loadSupportedOptions() {
|
|
2875
|
+
this.adminService.getSupportedFeatureFlagRuleOptions().subscribe(response => {
|
|
2876
|
+
this.targetTypeOptions = (response.target_types || []).map(option => ({
|
|
2877
|
+
label: option,
|
|
2878
|
+
value: option
|
|
2879
|
+
}));
|
|
2880
|
+
this.environmentOptions = (response.environments || []).map(option => ({
|
|
2881
|
+
label: option,
|
|
2882
|
+
value: option
|
|
2883
|
+
}));
|
|
2884
|
+
this.productFeatureKeyOptions = (response.product_feature_keys || []).map(option => ({
|
|
2885
|
+
label: option,
|
|
2886
|
+
value: option
|
|
2887
|
+
}));
|
|
2888
|
+
});
|
|
2889
|
+
}
|
|
2890
|
+
loadFeatureFlag() {
|
|
2891
|
+
this.adminService.getFeatureFlagById(this.featureFlagId).subscribe({
|
|
2892
|
+
next: response => {
|
|
2893
|
+
this.featureFlagName = response.name || response.key || 'Feature Flag';
|
|
2894
|
+
},
|
|
2895
|
+
complete: () => {
|
|
2896
|
+
this.isLoading = false;
|
|
2897
|
+
}
|
|
2898
|
+
});
|
|
2899
|
+
}
|
|
2900
|
+
loadRules() {
|
|
2901
|
+
this.adminService.getFeatureFlagRules(this.featureFlagId).subscribe(response => {
|
|
2902
|
+
this.rules = response.feature_flag_rules || [];
|
|
2903
|
+
});
|
|
2904
|
+
}
|
|
2905
|
+
editRule(rule) {
|
|
2906
|
+
this.editingRuleId = rule.id;
|
|
2907
|
+
this.ruleForm.patchValue({
|
|
2908
|
+
environment: rule.environment,
|
|
2909
|
+
product_feature_key: rule.product_feature_key,
|
|
2910
|
+
target_type: rule.target_type,
|
|
2911
|
+
target_value: rule.target_value,
|
|
2912
|
+
enabled: rule.enabled,
|
|
2913
|
+
priority: rule.priority,
|
|
2914
|
+
rollout_percentage: rule.rollout_percentage
|
|
2915
|
+
});
|
|
2916
|
+
}
|
|
2917
|
+
resetRuleForm() {
|
|
2918
|
+
this.ruleForm.reset({
|
|
2919
|
+
environment: null,
|
|
2920
|
+
product_feature_key: null,
|
|
2921
|
+
target_type: null,
|
|
2922
|
+
target_value: '',
|
|
2923
|
+
enabled: false,
|
|
2924
|
+
priority: 0,
|
|
2925
|
+
rollout_percentage: null
|
|
2926
|
+
});
|
|
2927
|
+
this.ruleSubmitted = false;
|
|
2928
|
+
this.editingRuleId = null;
|
|
2929
|
+
}
|
|
2930
|
+
saveRule() {
|
|
2931
|
+
this.ruleForm.markAllAsTouched();
|
|
2932
|
+
this.ruleSubmitted = true;
|
|
2933
|
+
if (!this.ruleForm.valid) {
|
|
2934
|
+
return;
|
|
2935
|
+
}
|
|
2936
|
+
this.ruleButtonBusy = true;
|
|
2937
|
+
const payload = this.ruleForm.value;
|
|
2938
|
+
const request$ = this.editingRuleId
|
|
2939
|
+
? this.adminService.updateFeatureFlagRule(this.featureFlagId, this.editingRuleId, payload)
|
|
2940
|
+
: this.adminService.createFeatureFlagRule(this.featureFlagId, payload);
|
|
2941
|
+
request$.subscribe({
|
|
2942
|
+
next: () => {
|
|
2943
|
+
this.toast.success(this.editingRuleId
|
|
2944
|
+
? 'Feature flag rule updated successfully.'
|
|
2945
|
+
: 'Feature flag rule created successfully.');
|
|
2946
|
+
this.loadRules();
|
|
2947
|
+
this.resetRuleForm();
|
|
2948
|
+
},
|
|
2949
|
+
complete: () => {
|
|
2950
|
+
this.ruleButtonBusy = false;
|
|
2951
|
+
}
|
|
2952
|
+
});
|
|
2953
|
+
}
|
|
2954
|
+
deleteRule(rule) {
|
|
2955
|
+
swal.fire({
|
|
2956
|
+
title: 'Delete feature flag rule?',
|
|
2957
|
+
text: `This will remove the rule with target type ${rule.target_type}.`,
|
|
2958
|
+
icon: 'warning',
|
|
2959
|
+
showCancelButton: true,
|
|
2960
|
+
confirmButtonText: 'Delete'
|
|
2961
|
+
}).then(result => {
|
|
2962
|
+
if (!result.isConfirmed) {
|
|
2963
|
+
return;
|
|
2964
|
+
}
|
|
2965
|
+
this.adminService.deleteFeatureFlagRule(this.featureFlagId, rule.id).subscribe(() => {
|
|
2966
|
+
this.toast.success('Feature flag rule has been destroyed.');
|
|
2967
|
+
this.loadRules();
|
|
2968
|
+
if (this.editingRuleId === rule.id) {
|
|
2969
|
+
this.resetRuleForm();
|
|
2970
|
+
}
|
|
2971
|
+
});
|
|
2972
|
+
});
|
|
2973
|
+
}
|
|
2974
|
+
backToFlags() {
|
|
2975
|
+
this.router.navigate([this.routers.featureFlagsConfig]);
|
|
2976
|
+
}
|
|
2977
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FeatureFlagRulesComponent, deps: [{ token: i0.Injector }, { token: i1.AdminService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2978
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FeatureFlagRulesComponent, isStandalone: false, selector: "pw-feature-flag-rules", usesInheritance: true, ngImport: i0, template: "<div class=\"container-fluid pw-tab\">\n <div class=\"dashboard\">\n <div class=\"dashboard-body\">\n <div class=\"me-auto col-xs-6 mt-4\">\n <a [routerLink]=\"routers.featureFlagsConfig\" class=\"previous\"><i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i></a>\n <h3 class=\"mt-3\">Feature Flag Rules \u2014 {{ featureFlagName }}</h3>\n </div>\n\n @if (isLoading) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"></p-progressSpinner>\n </div>\n }\n\n @if (!isLoading) {\n <div class=\"p-2 mt-3\">\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\n <h4 class=\"mb-0\">Manage Rules</h4>\n </div>\n\n <form [formGroup]=\"ruleForm\" (ngSubmit)=\"saveRule()\" class=\"mb-4\">\n <div class=\"row\">\n <pw-input-container class=\"col-lg-4\" label=\"Environment\" name=\"environment\" controlId=\"feature-flag-rule-environment\" [useAriaLabelledbyOnly]=\"true\">\n <p-select [options]=\"environmentOptions\" formControlName=\"environment\" class=\"dropdown-bg-transparent\" placeholder=\"Select environment\"></p-select>\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-4\" label=\"Product Feature Key\" name=\"product_feature_key\" controlId=\"feature-flag-rule-product_feature_key\" [useAriaLabelledbyOnly]=\"true\">\n <p-select [options]=\"productFeatureKeyOptions\" formControlName=\"product_feature_key\" class=\"dropdown-bg-transparent\" placeholder=\"Select product feature key\"></p-select>\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-4\" label=\"Target Type\" name=\"target_type\" controlId=\"feature-flag-rule-target_type\" errorMsg=\"Target type is required\" [useAriaLabelledbyOnly]=\"true\">\n <p-select [options]=\"targetTypeOptions\" formControlName=\"target_type\" class=\"dropdown-bg-transparent\" placeholder=\"Select target type\"></p-select>\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-4\" label=\"Target Value\" name=\"target_value\" controlId=\"feature-flag-rule-target_value\"\n [showTooltip]=\"true\" [tooltipText]=\"'FeatureFlag.Tooltip.TargetValue' | transloco\">\n <input type=\"text\" id=\"feature-flag-rule-target_value\" formControlName=\"target_value\" class=\"form-control\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-4\" label=\"Priority\" name=\"priority\" controlId=\"feature-flag-rule-priority\" errorMsg=\"Priority is required\"\n [showTooltip]=\"true\" [tooltipText]=\"'FeatureFlag.Tooltip.Priority' | transloco\">\n <input type=\"number\" id=\"feature-flag-rule-priority\" formControlName=\"priority\" class=\"form-control\" [ngClass]=\"{ 'is-invalid': ruleSubmitted && rf['priority'].errors }\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-4\" label=\"Rollout Percentage\" name=\"rollout_percentage\" controlId=\"feature-flag-rule-rollout_percentage\"\n [showTooltip]=\"true\" [tooltipText]=\"'FeatureFlag.Tooltip.RolloutPercentage' | transloco\">\n <input type=\"number\" id=\"feature-flag-rule-rollout_percentage\" formControlName=\"rollout_percentage\" class=\"form-control\" min=\"0\" max=\"100\" />\n </pw-input-container>\n\n <div class=\"col-lg-3 d-flex align-items-end\">\n <div>\n <span id=\"feature-flag-rule-enabled-label\" class=\"pw-label-style\">Enabled</span><br />\n <ui-switch formControlName=\"enabled\" [attr.aria-labelledby]=\"'feature-flag-rule-enabled-label'\"></ui-switch>\n </div>\n </div>\n\n <div class=\"col-lg-9 d-flex align-items-end justify-content-end gap-2\">\n @if (editingRuleId) {\n <button type=\"button\" class=\"btn btn-outline-default\" (click)=\"resetRuleForm()\">\n Cancel editing rule\n </button>\n }\n <button type=\"submit\" class=\"btn btn-primary\" [buttonBusy]=\"ruleButtonBusy\">\n {{ editingRuleId ? 'Update Rule' : 'Add Rule' }}\n </button>\n </div>\n </div>\n </form>\n\n <div class=\"row primeng-datatable-container mt-0\">\n <div class=\"col-12 px-0\">\n <p-table [value]=\"rules\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th>Environment</th>\n <th>Product Feature Key</th>\n <th>Target Type</th>\n <th>Target Value</th>\n <th>Enabled</th>\n <th>Priority</th>\n <th>Rollout %</th>\n <th class=\"actions-list-two\">{{ 'Label.Actions' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-rule>\n <tr>\n <td>{{ rule.environment || '-' }}</td>\n <td>{{ rule.product_feature_key || '-' }}</td>\n <td>{{ rule.target_type }}</td>\n <td>{{ rule.target_value || '-' }}</td>\n <td><span class=\"badge\" [ngClass]=\"rule.enabled ? 'bg-success' : 'bg-secondary'\">{{ rule.enabled }}</span></td>\n <td>{{ rule.priority }}</td>\n <td>{{ rule.rollout_percentage ?? '-' }}</td>\n <td>\n <ul class=\"list-unstyled list-inline list-action\">\n <li ngbTooltip=\"Edit\" class=\"me-2 me-sm-2\">\n <i class=\"fa fa-edit edit-icon\" (click)=\"editRule(rule)\" aria-hidden=\"true\"></i>\n </li>\n <li ngbTooltip=\"Delete\" class=\"me-2 me-sm-2\">\n <i class=\"fa fa-trash delete-icon\" (click)=\"deleteRule(rule)\" aria-hidden=\"true\"></i>\n </li>\n </ul>\n </td>\n </tr>\n </ng-template>\n </p-table>\n @if (rules.length === 0) {\n <pw-no-data [withImage]=\"true\" [message]=\"'No feature flag rules found'\"></pw-no-data>\n }\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n</div>", dependencies: [{ kind: "component", type: i2.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i3$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: i3.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "directive", type: i2$1.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "directive", type: i3$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i6.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i6.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i6.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "component", type: i7.UiSwitchComponent, selector: "ui-switch", inputs: ["size", "color", "switchOffColor", "switchColor", "defaultBgColor", "defaultBoColor", "checkedLabel", "uncheckedLabel", "checkedTextColor", "uncheckedTextColor", "beforeChange", "ariaLabel", "checked", "disabled", "reverse", "loading"], outputs: ["change", "changeEvent", "valueChange"] }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: i1$1.InputContainerComponent, selector: "pw-input-container", inputs: ["name", "controlId", "useAriaLabelledbyOnly", "label", "labelClass", "tooltipPosition", "required", "errorMsg", "isReadOnly", "showTooltip", "tooltipText", "showTriangle", "afterLabel", "showAfterLabel", "showTriangleText", "isLeftTooltip"] }, { kind: "component", type: i1$1.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "directive", type: i9.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i10.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i6.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i6.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "pipe", type: i11.TranslocoPipe, name: "transloco" }] }); }
|
|
2979
|
+
}
|
|
2980
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FeatureFlagRulesComponent, decorators: [{
|
|
2981
|
+
type: Component,
|
|
2982
|
+
args: [{ selector: 'pw-feature-flag-rules', standalone: false, template: "<div class=\"container-fluid pw-tab\">\n <div class=\"dashboard\">\n <div class=\"dashboard-body\">\n <div class=\"me-auto col-xs-6 mt-4\">\n <a [routerLink]=\"routers.featureFlagsConfig\" class=\"previous\"><i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i></a>\n <h3 class=\"mt-3\">Feature Flag Rules \u2014 {{ featureFlagName }}</h3>\n </div>\n\n @if (isLoading) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"></p-progressSpinner>\n </div>\n }\n\n @if (!isLoading) {\n <div class=\"p-2 mt-3\">\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\n <h4 class=\"mb-0\">Manage Rules</h4>\n </div>\n\n <form [formGroup]=\"ruleForm\" (ngSubmit)=\"saveRule()\" class=\"mb-4\">\n <div class=\"row\">\n <pw-input-container class=\"col-lg-4\" label=\"Environment\" name=\"environment\" controlId=\"feature-flag-rule-environment\" [useAriaLabelledbyOnly]=\"true\">\n <p-select [options]=\"environmentOptions\" formControlName=\"environment\" class=\"dropdown-bg-transparent\" placeholder=\"Select environment\"></p-select>\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-4\" label=\"Product Feature Key\" name=\"product_feature_key\" controlId=\"feature-flag-rule-product_feature_key\" [useAriaLabelledbyOnly]=\"true\">\n <p-select [options]=\"productFeatureKeyOptions\" formControlName=\"product_feature_key\" class=\"dropdown-bg-transparent\" placeholder=\"Select product feature key\"></p-select>\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-4\" label=\"Target Type\" name=\"target_type\" controlId=\"feature-flag-rule-target_type\" errorMsg=\"Target type is required\" [useAriaLabelledbyOnly]=\"true\">\n <p-select [options]=\"targetTypeOptions\" formControlName=\"target_type\" class=\"dropdown-bg-transparent\" placeholder=\"Select target type\"></p-select>\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-4\" label=\"Target Value\" name=\"target_value\" controlId=\"feature-flag-rule-target_value\"\n [showTooltip]=\"true\" [tooltipText]=\"'FeatureFlag.Tooltip.TargetValue' | transloco\">\n <input type=\"text\" id=\"feature-flag-rule-target_value\" formControlName=\"target_value\" class=\"form-control\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-4\" label=\"Priority\" name=\"priority\" controlId=\"feature-flag-rule-priority\" errorMsg=\"Priority is required\"\n [showTooltip]=\"true\" [tooltipText]=\"'FeatureFlag.Tooltip.Priority' | transloco\">\n <input type=\"number\" id=\"feature-flag-rule-priority\" formControlName=\"priority\" class=\"form-control\" [ngClass]=\"{ 'is-invalid': ruleSubmitted && rf['priority'].errors }\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-lg-4\" label=\"Rollout Percentage\" name=\"rollout_percentage\" controlId=\"feature-flag-rule-rollout_percentage\"\n [showTooltip]=\"true\" [tooltipText]=\"'FeatureFlag.Tooltip.RolloutPercentage' | transloco\">\n <input type=\"number\" id=\"feature-flag-rule-rollout_percentage\" formControlName=\"rollout_percentage\" class=\"form-control\" min=\"0\" max=\"100\" />\n </pw-input-container>\n\n <div class=\"col-lg-3 d-flex align-items-end\">\n <div>\n <span id=\"feature-flag-rule-enabled-label\" class=\"pw-label-style\">Enabled</span><br />\n <ui-switch formControlName=\"enabled\" [attr.aria-labelledby]=\"'feature-flag-rule-enabled-label'\"></ui-switch>\n </div>\n </div>\n\n <div class=\"col-lg-9 d-flex align-items-end justify-content-end gap-2\">\n @if (editingRuleId) {\n <button type=\"button\" class=\"btn btn-outline-default\" (click)=\"resetRuleForm()\">\n Cancel editing rule\n </button>\n }\n <button type=\"submit\" class=\"btn btn-primary\" [buttonBusy]=\"ruleButtonBusy\">\n {{ editingRuleId ? 'Update Rule' : 'Add Rule' }}\n </button>\n </div>\n </div>\n </form>\n\n <div class=\"row primeng-datatable-container mt-0\">\n <div class=\"col-12 px-0\">\n <p-table [value]=\"rules\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th>Environment</th>\n <th>Product Feature Key</th>\n <th>Target Type</th>\n <th>Target Value</th>\n <th>Enabled</th>\n <th>Priority</th>\n <th>Rollout %</th>\n <th class=\"actions-list-two\">{{ 'Label.Actions' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-rule>\n <tr>\n <td>{{ rule.environment || '-' }}</td>\n <td>{{ rule.product_feature_key || '-' }}</td>\n <td>{{ rule.target_type }}</td>\n <td>{{ rule.target_value || '-' }}</td>\n <td><span class=\"badge\" [ngClass]=\"rule.enabled ? 'bg-success' : 'bg-secondary'\">{{ rule.enabled }}</span></td>\n <td>{{ rule.priority }}</td>\n <td>{{ rule.rollout_percentage ?? '-' }}</td>\n <td>\n <ul class=\"list-unstyled list-inline list-action\">\n <li ngbTooltip=\"Edit\" class=\"me-2 me-sm-2\">\n <i class=\"fa fa-edit edit-icon\" (click)=\"editRule(rule)\" aria-hidden=\"true\"></i>\n </li>\n <li ngbTooltip=\"Delete\" class=\"me-2 me-sm-2\">\n <i class=\"fa fa-trash delete-icon\" (click)=\"deleteRule(rule)\" aria-hidden=\"true\"></i>\n </li>\n </ul>\n </td>\n </tr>\n </ng-template>\n </p-table>\n @if (rules.length === 0) {\n <pw-no-data [withImage]=\"true\" [message]=\"'No feature flag rules found'\"></pw-no-data>\n }\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n</div>" }]
|
|
2983
|
+
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1.AdminService }] });
|
|
2984
|
+
|
|
2985
|
+
class FeatureFlagsListComponent extends AppBaseComponent {
|
|
2986
|
+
constructor(injector, adminService) {
|
|
2987
|
+
super(injector);
|
|
2988
|
+
this.adminService = adminService;
|
|
2989
|
+
this.PAGE_SIZE = PAGE_SIZE;
|
|
2990
|
+
this.routers = ROUTERS;
|
|
2991
|
+
this.buttonBusy = false;
|
|
2992
|
+
this.isLoaded = true;
|
|
2993
|
+
this.searchText = '';
|
|
2994
|
+
this.featureFlags = [];
|
|
2995
|
+
this.totalRecords = 0;
|
|
2996
|
+
this.page = 1;
|
|
2997
|
+
}
|
|
2998
|
+
onLazyLoad(event) {
|
|
2999
|
+
const pageDetails = HelperService.onTableLazyLoad(event);
|
|
3000
|
+
this.page = pageDetails.page;
|
|
3001
|
+
this.loadFeatureFlags({
|
|
3002
|
+
page: pageDetails.page,
|
|
3003
|
+
page_size: PAGE_SIZE,
|
|
3004
|
+
order_by: pageDetails.sortField,
|
|
3005
|
+
order_direction: pageDetails.sortOrder
|
|
3006
|
+
});
|
|
3007
|
+
}
|
|
3008
|
+
loadFeatureFlags(paging) {
|
|
3009
|
+
this.isLoaded = false;
|
|
3010
|
+
this.adminService.getFeatureFlags(paging).subscribe({
|
|
3011
|
+
next: response => {
|
|
3012
|
+
this.featureFlags = response.feature_flags ?? [];
|
|
3013
|
+
this.totalRecords = response.object_count ?? this.featureFlags.length;
|
|
3014
|
+
},
|
|
3015
|
+
complete: () => {
|
|
3016
|
+
this.isLoaded = true;
|
|
3017
|
+
}
|
|
3018
|
+
});
|
|
3019
|
+
}
|
|
3020
|
+
navigateToEdit(item) {
|
|
3021
|
+
this.router.navigate([this.routers.featureFlagsDetails + item.id], {
|
|
3022
|
+
state: { data: item }
|
|
3023
|
+
});
|
|
3024
|
+
}
|
|
3025
|
+
navigateToRules(item) {
|
|
3026
|
+
this.router.navigate([this.routers.featureFlagRules + item.id], {
|
|
3027
|
+
state: { data: item }
|
|
3028
|
+
});
|
|
3029
|
+
}
|
|
3030
|
+
onDelete(item) {
|
|
3031
|
+
swal.fire({
|
|
3032
|
+
title: 'Delete feature flag?',
|
|
3033
|
+
text: `This will remove ${item.name || item.key}.`,
|
|
3034
|
+
icon: 'warning',
|
|
3035
|
+
showCancelButton: true,
|
|
3036
|
+
confirmButtonText: 'Delete'
|
|
3037
|
+
}).then(result => {
|
|
3038
|
+
if (!result.isConfirmed) {
|
|
3039
|
+
return;
|
|
3040
|
+
}
|
|
3041
|
+
this.buttonBusy = true;
|
|
3042
|
+
this.adminService.deleteFeatureFlag(item.id).subscribe({
|
|
3043
|
+
next: () => {
|
|
3044
|
+
this.toast.success('Feature flag has been destroyed.');
|
|
3045
|
+
this.loadFeatureFlags({ page: 1, page_size: PAGE_SIZE });
|
|
3046
|
+
},
|
|
3047
|
+
complete: () => {
|
|
3048
|
+
this.buttonBusy = false;
|
|
3049
|
+
}
|
|
3050
|
+
});
|
|
3051
|
+
});
|
|
3052
|
+
}
|
|
3053
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FeatureFlagsListComponent, deps: [{ token: i0.Injector }, { token: i1.AdminService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3054
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FeatureFlagsListComponent, isStandalone: false, selector: "pw-feature-flags-list", usesInheritance: true, ngImport: i0, template: "<div class=\"row\" [class.custom-disable-wrapper]=\"buttonBusy\">\n <div class=\"col-12 d-flex flex-wrap justify-content-between align-items-center\">\n <h2 class=\"card-title p-0 float-start\">Feature Flags</h2>\n <a [routerLink]=\"[routers.featureFlagsDetails + 'add']\" class=\"btn btn-sm btn-outline-primary float-end\">\n <i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i> {{ 'Label.AddNew' | transloco }} Feature Flag\n </a>\n </div>\n <div class=\"col-12 mb-3\">\n <p>Manage feature flags for controlled rollout, testing, and admin-driven enablement.</p>\n </div>\n</div>\n\n@if (!isLoaded) {\n<div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"></p-progressSpinner>\n</div>\n}\n\n<div class=\"row primeng-datatable-container mt-0\" [class.custom-disable-wrapper]=\"buttonBusy\">\n <div class=\"col-12 px-0\">\n <p-table\n [value]=\"featureFlags\"\n [paginator]=\"totalRecords !== 0\"\n [lazy]=\"true\"\n [rows]=\"PAGE_SIZE\"\n [totalRecords]=\"totalRecords\"\n [filterDelay]=\"300\"\n (onLazyLoad)=\"onLazyLoad($event)\">\n <ng-template pTemplate=\"caption\">\n <div class=\"text-end\">\n <i class=\"fa fa-search mt-2 me-2\" aria-hidden=\"true\"></i>\n <input type=\"text\" [(ngModel)]=\"searchText\" pInputText size=\"50\" placeholder=\"Search feature flags...\" class=\"mw-90\" />\n </div>\n </ng-template>\n <ng-template pTemplate=\"header\">\n <tr>\n <th>Key</th>\n <th>Name</th>\n <th>Status</th>\n <th>Type</th>\n <th>Owner</th>\n <th>Expires</th>\n <th class=\"actions-list-two\">{{ 'Label.Actions' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-flag>\n <tr>\n <td>{{ flag.key }}</td>\n <td>{{ flag.name }}</td>\n <td><span class=\"badge bg-info\">{{ flag.status || 'draft' }}</span></td>\n <td>{{ flag.flag_type || '-' }}</td>\n <td>{{ flag.owner || '-' }}</td>\n <td>{{ flag.expires_at ? (flag.expires_at | date:'dd-MMM-yyyy HH:mm') : '-' }}</td>\n <td>\n <ul class=\"list-unstyled list-inline list-action\">\n <li ngbTooltip=\"Edit\" class=\"me-2 me-sm-2\">\n <i class=\"fa fa-edit edit-icon\" (click)=\"navigateToEdit(flag)\" aria-hidden=\"true\"></i>\n </li>\n <li ngbTooltip=\"Rules\" class=\"me-2 me-sm-2\">\n <i class=\"fa fa-list-ul edit-icon\" (click)=\"navigateToRules(flag)\" aria-hidden=\"true\"></i>\n </li>\n <li ngbTooltip=\"Delete\" class=\"me-2 me-sm-2\">\n <i class=\"fa fa-trash delete-icon\" (click)=\"onDelete(flag)\" aria-hidden=\"true\"></i>\n </li>\n </ul>\n </td>\n </tr>\n </ng-template>\n </p-table>\n @if (totalRecords === 0) {\n <pw-no-data [withImage]=\"true\" [message]=\"'No feature flags found'\"></pw-no-data>\n }\n </div>\n</div>", dependencies: [{ kind: "component", type: i2.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i3$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: i2$1.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: i1$1.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "directive", type: i10.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i3$1.DatePipe, name: "date" }, { kind: "pipe", type: i11.TranslocoPipe, name: "transloco" }] }); }
|
|
3055
|
+
}
|
|
3056
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FeatureFlagsListComponent, decorators: [{
|
|
3057
|
+
type: Component,
|
|
3058
|
+
args: [{ selector: 'pw-feature-flags-list', standalone: false, template: "<div class=\"row\" [class.custom-disable-wrapper]=\"buttonBusy\">\n <div class=\"col-12 d-flex flex-wrap justify-content-between align-items-center\">\n <h2 class=\"card-title p-0 float-start\">Feature Flags</h2>\n <a [routerLink]=\"[routers.featureFlagsDetails + 'add']\" class=\"btn btn-sm btn-outline-primary float-end\">\n <i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i> {{ 'Label.AddNew' | transloco }} Feature Flag\n </a>\n </div>\n <div class=\"col-12 mb-3\">\n <p>Manage feature flags for controlled rollout, testing, and admin-driven enablement.</p>\n </div>\n</div>\n\n@if (!isLoaded) {\n<div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"></p-progressSpinner>\n</div>\n}\n\n<div class=\"row primeng-datatable-container mt-0\" [class.custom-disable-wrapper]=\"buttonBusy\">\n <div class=\"col-12 px-0\">\n <p-table\n [value]=\"featureFlags\"\n [paginator]=\"totalRecords !== 0\"\n [lazy]=\"true\"\n [rows]=\"PAGE_SIZE\"\n [totalRecords]=\"totalRecords\"\n [filterDelay]=\"300\"\n (onLazyLoad)=\"onLazyLoad($event)\">\n <ng-template pTemplate=\"caption\">\n <div class=\"text-end\">\n <i class=\"fa fa-search mt-2 me-2\" aria-hidden=\"true\"></i>\n <input type=\"text\" [(ngModel)]=\"searchText\" pInputText size=\"50\" placeholder=\"Search feature flags...\" class=\"mw-90\" />\n </div>\n </ng-template>\n <ng-template pTemplate=\"header\">\n <tr>\n <th>Key</th>\n <th>Name</th>\n <th>Status</th>\n <th>Type</th>\n <th>Owner</th>\n <th>Expires</th>\n <th class=\"actions-list-two\">{{ 'Label.Actions' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-flag>\n <tr>\n <td>{{ flag.key }}</td>\n <td>{{ flag.name }}</td>\n <td><span class=\"badge bg-info\">{{ flag.status || 'draft' }}</span></td>\n <td>{{ flag.flag_type || '-' }}</td>\n <td>{{ flag.owner || '-' }}</td>\n <td>{{ flag.expires_at ? (flag.expires_at | date:'dd-MMM-yyyy HH:mm') : '-' }}</td>\n <td>\n <ul class=\"list-unstyled list-inline list-action\">\n <li ngbTooltip=\"Edit\" class=\"me-2 me-sm-2\">\n <i class=\"fa fa-edit edit-icon\" (click)=\"navigateToEdit(flag)\" aria-hidden=\"true\"></i>\n </li>\n <li ngbTooltip=\"Rules\" class=\"me-2 me-sm-2\">\n <i class=\"fa fa-list-ul edit-icon\" (click)=\"navigateToRules(flag)\" aria-hidden=\"true\"></i>\n </li>\n <li ngbTooltip=\"Delete\" class=\"me-2 me-sm-2\">\n <i class=\"fa fa-trash delete-icon\" (click)=\"onDelete(flag)\" aria-hidden=\"true\"></i>\n </li>\n </ul>\n </td>\n </tr>\n </ng-template>\n </p-table>\n @if (totalRecords === 0) {\n <pw-no-data [withImage]=\"true\" [message]=\"'No feature flags found'\"></pw-no-data>\n }\n </div>\n</div>" }]
|
|
3059
|
+
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1.AdminService }] });
|
|
3060
|
+
|
|
3061
|
+
class FeatureFlagsTabsComponent {
|
|
3062
|
+
constructor() {
|
|
3063
|
+
this.items = [
|
|
3064
|
+
{
|
|
3065
|
+
id: 'feature-flags',
|
|
3066
|
+
label: 'Feature Flags',
|
|
3067
|
+
icon: 'fa fa-fw fa-toggle-on',
|
|
3068
|
+
routerLink: ['/admin/feature-flags/list']
|
|
3069
|
+
}
|
|
3070
|
+
];
|
|
3071
|
+
}
|
|
3072
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FeatureFlagsTabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3073
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.6", type: FeatureFlagsTabsComponent, isStandalone: false, selector: "feature-flags-tabs", ngImport: i0, template: `<pw-tabs [items]="items"></pw-tabs>`, isInline: true, dependencies: [{ kind: "component", type: i1$1.PwTabsComponent, selector: "pw-tabs", inputs: ["items", "withSubscription"] }] }); }
|
|
3074
|
+
}
|
|
3075
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FeatureFlagsTabsComponent, decorators: [{
|
|
3076
|
+
type: Component,
|
|
3077
|
+
args: [{
|
|
3078
|
+
selector: 'feature-flags-tabs',
|
|
3079
|
+
template: `<pw-tabs [items]="items"></pw-tabs>`,
|
|
3080
|
+
standalone: false
|
|
3081
|
+
}]
|
|
3082
|
+
}] });
|
|
3083
|
+
|
|
2716
3084
|
class FeedbackQuestionsDetailsComponent extends AppBaseComponent {
|
|
2717
3085
|
constructor(injector, cdr, adminService, productService) {
|
|
2718
3086
|
super(injector);
|
|
@@ -8075,11 +8443,11 @@ class SubscriptionsListComponent extends AppBaseComponent {
|
|
|
8075
8443
|
super.ngOnDestroy();
|
|
8076
8444
|
}
|
|
8077
8445
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: SubscriptionsListComponent, deps: [{ token: i1$2.ProductService }, { token: i1.AdminService }, { token: i6.UntypedFormBuilder }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }, { token: i1$2.CommonService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8078
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: SubscriptionsListComponent, isStandalone: false, selector: "pw-subscriptions-list", viewQueries: [{ propertyName: "refProduct", first: true, predicate: ["refProduct"], descendants: true }, { propertyName: "recoverSubscriptionPasswordModal", first: true, predicate: ["recoverSubscriptionPasswordModal"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"row\">\n <div\n class=\"col-12 d-flex justify-content-between align-items-center\">\n <h2 class=\"card-title p-0 float-start\">Subscriptions</h2>\n <a class=\"btn btn-sm btn-outline-primary float-end\"\n id=\"btn-create\"\n [routerLink]=\"[routers.inviteUsers]\">\n <i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i> Invite a User to a Trial\n </a>\n </div>\n</div>\n<div class=\"p-2 mt-3\">\n <div class=\"w-100 text-center mt-3\">\n @if (!isLoaded) {\n <p-progressSpinner> </p-progressSpinner>\n }\n </div>\n <div class=\"primeng-datatable-container table-responsive mt-0\"\n [class.hideTable]=\"totalRecordsUnFiltered === 0\">\n <p-table #dt\n [value]=\"subscriptions\"\n [paginator]=\"totalRecords !== 0\"\n [rows]=\"PAGE_SIZE\"\n [lazy]=\"true\"\n [totalRecords]=\"totalRecords\"\n [loading]=\"loading\"\n [filterDelay]=\"1000\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n [customSort]=\"true\">\n <ng-template pTemplate=\"caption\">\n @if (subscriptionInsights) {\n <div class=\"row mb-4\">\n @for (temp of objectKeys(subscriptionInsights); track temp) {\n <div class=\"col-12 col-lg-3 mt-2 summary\">\n <div class=\"card\">\n <div class=\"card-body\">\n @for (item of subscriptionInsights[temp]; track item) {\n <div>\n <p class=\"mb-0 px-2\">{{ item?.title }}\n @if (item?.info) {\n <span\n [pTooltip]=\"item?.info\">\n <i class=\"fas fa-info-circle\"></i>\n </span>\n }\n </p>\n <h4 class=\"fw-bold mt-2 mb-2\">\n {{ item?.value }}\n </h4>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n }\n <div class=\"search-filter\">\n <div class=\"col-12 col-sm-4\">\n <p-multiSelect inputId=\"subscriptions-list-feature-keys\"\n placeholder=\"Select Feature Keys\"\n [showToggleAll]=\"true\"\n [showHeader]=\"true\"\n [(ngModel)]=\"selectedFeatureKeys\"\n [options]=\"searchOptions\"\n (onChange)=\"onSearchOptionChange($event)\"\n appendTo=\"body\">\n </p-multiSelect>\n </div>\n <div class=\"col-12 col-sm-4\">\n <p-select\n inputId=\"subscriptions-list-status\"\n [options]=\"subscriptionStatus\"\n [placeholder]=\"'Select status'\"\n (onChange)=\"filterByStatus($event.value)\"\n [(ngModel)]=\"status\">\n </p-select>\n </div>\n <div class=\"text-end\">\n <label for=\"subscriptions-list-search\" class=\"visually-hidden\">Search Subscription</label>\n <i class=\"fa fa-search mt-2 me-2 d-none\" aria-hidden=\"true\"></i>\n <input type=\"text\"\n id=\"subscriptions-list-search\"\n name=\"subscriptions-list-search\"\n [(ngModel)]=\"searchText\"\n pInputText\n size=\"30\"\n placeholder=\"Search Subscription...\"\n class=\"mw-90\"\n (input)=\"dt.filterGlobal($event.target.value, 'contains')\" />\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\"\n pSortableColumn=\"id\">\n {{ 'Admin.Subscriptions.Id' | transloco }}\n <p-sortIcon field=\"id\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"organisation\">\n {{ 'Admin.Subscriptions.Organization' | transloco }}\n <p-sortIcon field=\"organisation\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"contact_name\">\n {{ 'Admin.Subscriptions.ContactName' | transloco }}\n <p-sortIcon field=\"contact_name\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"contact_email\">\n {{ 'Admin.Subscriptions.ContactEmail' | transloco }}\n <p-sortIcon field=\"contact_email\"></p-sortIcon>\n </th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.Product' | transloco }}</th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.Currency' | transloco }}</th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.PricePerMonth' | transloco }}</th>\n <th scope=\"true\"\n pSortableColumn=\"stripe_customer_id\">\n {{ 'Admin.Subscriptions.Paid' | transloco }}\n <p-sortIcon field=\"stripe_customer_id\"></p-sortIcon>\n </th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.Billing' | transloco }}</th>\n <th scope=\"true\"\n class=\"expires-at-width\">\n {{ 'Admin.Subscriptions.ExpiresAt' | transloco }}\n </th>\n <th scope=\"true\"\n pSortableColumn=\"sessions_total\">\n {{ 'Admin.Subscriptions.SessionsTotal' | transloco }}\n <p-sortIcon field=\"sessions_total\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"sessions_last_month\">\n {{ 'Admin.Subscriptions.SessionsTotalLastMonth' | transloco }}\n <p-sortIcon field=\"sessions_last_month\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"deleted_at\">\n {{ 'Admin.Subscriptions.Deleted' | transloco }}\n <p-sortIcon field=\"deleted_at\"></p-sortIcon>\n </th>\n <th class=\"actions-list-two\"\n scope=\"true\">{{ 'Label.Actions' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-item>\n <tr>\n <td data-head=\"id\">{{ item.id }}</td>\n <td data-head=\"Organization\">\n <span class=\"cursor-pointer custom-break-word\"\n [pTooltip]=\"item.organisation\"\n tooltipPosition=\"top\">{{ item.organisation | textTruncate: 20 }}</span>\n </td>\n <td data-head=\"ContactName\"\n class=\"custom-break-word\">\n {{ item.contact_name }}\n </td>\n <td data-head=\"ContactEmail\">{{ item.contact_email }}</td>\n <td data-head=\"Name\">\n <span class=\"cursor-pointer custom-break-word\"\n [pTooltip]=\"item.productName\"\n tooltipPosition=\"top\">{{ item.productName }}</span>\n </td>\n <td data-head=\"Currency\">\n <span [appDynamicBadge]=\"{ itemsArray: currency, item: item.currency }\"\n color=\"blue-grey\"\n class=\"badge\">{{ item.currency }}</span>\n </td>\n <td data-head=\"Price/M\">\n <span>{{ (item.price / 100).toFixed(2) | currency:item.currency }}\n @if (item?.discount && objectKeys(item?.discount)?.length) {\n <i\n class=\"fa fa-info-circle\"\n aria-hidden=\"true\"\n [pTooltip]=\"item?.discount | json\"\n tooltipPosition=\"top\"\n ></i>\n }\n </span>\n </td>\n <td data-head=\"Paid\">\n @if (item?.unsubscribed_at) {\n <span class=\"badge bg-warning d-inline-flex align-items-center\">\n Unsub\n @if (item?.reason_to_cancel) {\n <i class=\"fa fa-info-circle ms-2\"\n [pTooltip]=\"item.reason_to_cancel\"\n tooltipPosition=\"top\"\n aria-hidden=\"true\"></i>\n }\n </span>\n }\n @if (!item?.unsubscribed_at) {\n @if ((item?.stripe_customer_id || item?.external_payment) && item?.signed_up_at) {\n <span class=\"badge bg-success\">Yes</span>\n } @else {\n <span class=\"badge bg-blue-grey\">No</span>\n }\n }\n @if (item?.pause_collection && objectKeys(item?.pause_collection)?.length) {\n <span\n class=\"ms-2\"\n [pTooltip]=\"item?.pause_collection | json\"\n tooltipPosition=\"top\">\n <i class=\"fas fa-exclamation-triangle text-warning\"></i>\n </span>\n }\n </td>\n <td data-head=\"Billing\">\n <span class=\"badge\"\n [appDynamicBadge]=\"{\n itemsArray: billingFrequency,\n item: item?.billingFrequency\n }\"\n color=\"blue-grey\">{{ item.billingFrequency }}</span>\n </td>\n <td data-head=\"Expires\">\n <span [ngClass]=\"getExpiresAtColor(item)\">{{item?.expires_at | dateFormat}}</span><br />\n <span>{{item?.created_at | sinceAgo}}</span>\n </td>\n <td data-head=\"S#\">{{ item?.sessions_total }}</td>\n <td data-head=\"S/m #\">\n <span [ngClass]=\"{\n 'text-danger fw-bold': item?.sessions_last_month < 3\n }\">{{ item?.sessions_last_month }}</span>\n </td>\n <td data-head=\"Deleted\">\n @if (item?.deleted_at) {\n <span\n class=\"badge bg-danger\">Yes</span>\n }\n @if (!item?.deleted_at) {\n <span\n class=\"badge bg-blue-grey\">No</span>\n }\n </td>\n <td data-head=\"Action\">\n <ul class=\"list-unstyled list-inline list-action\">\n <li ngbTooltip=\"Edit\"\n class=\"me-2 me-sm-3\"\n [routerLink]=\"[routers.subscriptionDetails, item.id]\">\n <i class=\"fa fa-edit edit-icon\" aria-hidden=\"true\"></i>\n </li>\n @if (item.deleted) {\n <li ngbTooltip=\"Reactivate subscription\"\n class=\"me-2 me-sm-3\"\n *rbacAllow=\"'Pages.Alpha'\"\n (keydown.enter)=\"openRecoverSubscriptionModal(item)\"\n (click)=\"openRecoverSubscriptionModal(item)\">\n <i class=\"fa fa-trash delete-icon text-success\" aria-hidden=\"true\"></i>\n </li>\n } @else {\n <li ngbTooltip=\"Delete\"\n class=\"me-2 me-sm-3\"\n *rbacAllow=\"'Pages.Admin.Subscription.Delete'\"\n (keydown.enter)=\"onDelete(item)\"\n (click)=\"onDelete(item)\">\n <i class=\"fa fa-trash delete-icon\" aria-hidden=\"true\"></i>\n </li>\n }\n </ul>\n </td>\n </tr>\n </ng-template>\n </p-table>\n @if (totalRecords === 0 && totalRecordsUnFiltered !== 0) {\n <div>\n <pw-no-data [withImage]=\"true\" [message]=\"'Search.NoDataMessage' | transloco\" [description]=\"'Search.NoDataDescription' | transloco\" >\n </pw-no-data>\n </div>\n }\n @if (totalRecords !== 0) {\n <span class=\"total-records-count\">{{ 'Label.Total' | transloco }}: {{ totalRecords }}</span>\n }\n </div>\n</div>\n@if (totalRecordsUnFiltered === 0 && isLoaded) {\n <pw-no-data [withImage]=\"true\" [message]=\"'Admin.Subscriptions.NoSubscriptionMessage' | transloco\">\n </pw-no-data>\n}\n<pw-password-validation\n #recoverSubscriptionPasswordModal\n (successEvent)=\"onRecoverConfirmed()\">\n</pw-password-validation>\n\n", styles: [":root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}@media(min-width:767px){.table-responsive td,.table-responsive th{font-size:11px!important}}.expires-at-width{width:8%}.custom-break-word{word-break:break-word!important}.summary .card{padding-bottom:0}.summary .card .card-body{padding-top:20px;text-align:center}.summary .card .card-body p,.summary .card .card-body h4{font-size:14px}@media(min-width:320px)and (max-width:720px){.primeng-datatable-container .search-filter{display:flex;flex-direction:column;gap:.5rem;justify-content:space-between}}\n"], dependencies: [{ kind: "component", type: i2.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i3$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i2.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "component", type: i2.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "directive", type: i4$2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: i3.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i7$2.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: i2$1.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "directive", type: i3$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i1$1.PasswordValidationComponent, selector: "pw-password-validation", inputs: ["confirmMessage"], outputs: ["successEvent"] }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: i1$1.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "directive", type: i9.DynamicBadgeDirective, selector: "[appDynamicBadge]", inputs: ["appDynamicBadge", "color", "colorByName", "dataName"] }, { kind: "directive", type: i9.RbacAllowDirective, selector: "[rbacAllow]", inputs: ["rbacAllow"] }, { kind: "directive", type: i10.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i3$1.JsonPipe, name: "json" }, { kind: "pipe", type: i3$1.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i11.TranslocoPipe, name: "transloco" }, { kind: "pipe", type: i15.DateFormatPipe, name: "dateFormat" }, { kind: "pipe", type: i15.SinceAgoPipe, name: "sinceAgo" }, { kind: "pipe", type: i15.TextTruncatePipe, name: "textTruncate" }] }); }
|
|
8446
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: SubscriptionsListComponent, isStandalone: false, selector: "pw-subscriptions-list", viewQueries: [{ propertyName: "refProduct", first: true, predicate: ["refProduct"], descendants: true }, { propertyName: "recoverSubscriptionPasswordModal", first: true, predicate: ["recoverSubscriptionPasswordModal"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"row\">\n <div\n class=\"col-12 d-flex justify-content-between align-items-center\">\n <h2 class=\"card-title p-0 float-start\">Subscriptions</h2>\n <a class=\"btn btn-sm btn-outline-primary float-end\"\n id=\"btn-create\"\n [routerLink]=\"[routers.inviteUsers]\">\n <i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i> Invite a User to a Trial\n </a>\n </div>\n</div>\n<div class=\"p-2 mt-3\">\n <div class=\"w-100 text-center mt-3\">\n @if (!isLoaded) {\n <p-progressSpinner> </p-progressSpinner>\n }\n </div>\n <div class=\"primeng-datatable-container table-responsive mt-0\"\n [class.hideTable]=\"totalRecordsUnFiltered === 0\">\n <p-table #dt\n [value]=\"subscriptions\"\n [paginator]=\"totalRecords !== 0\"\n [rows]=\"PAGE_SIZE\"\n [lazy]=\"true\"\n [totalRecords]=\"totalRecords\"\n [loading]=\"loading\"\n [filterDelay]=\"1000\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n [customSort]=\"true\">\n <ng-template pTemplate=\"caption\">\n @if (subscriptionInsights) {\n <div class=\"row mb-4\">\n @for (temp of objectKeys(subscriptionInsights); track temp) {\n <div class=\"col-12 col-lg-3 mt-2 summary\">\n <div class=\"card\">\n <div class=\"card-body\">\n @for (item of subscriptionInsights[temp]; track item) {\n <div>\n <p class=\"mb-0 px-2\">{{ item?.title }}\n @if (item?.info) {\n <span\n [pTooltip]=\"item?.info\">\n <i class=\"fas fa-info-circle\"></i>\n </span>\n }\n </p>\n <h4 class=\"fw-bold mt-2 mb-2\">\n {{ item?.value }}\n </h4>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n }\n <div class=\"search-filter\">\n <div class=\"col-12 col-sm-4\">\n <p-multiSelect inputId=\"subscriptions-list-feature-keys\"\n placeholder=\"Select Feature Keys\"\n [showToggleAll]=\"true\"\n [showHeader]=\"true\"\n [(ngModel)]=\"selectedFeatureKeys\"\n [options]=\"searchOptions\"\n (onChange)=\"onSearchOptionChange($event)\"\n appendTo=\"body\">\n </p-multiSelect>\n </div>\n <div class=\"col-12 col-sm-4\">\n <p-select\n inputId=\"subscriptions-list-status\"\n [options]=\"subscriptionStatus\"\n [placeholder]=\"'Select status'\"\n (onChange)=\"filterByStatus($event.value)\"\n [(ngModel)]=\"status\"\n appendTo=\"body\">\n </p-select>\n </div>\n <div class=\"text-end\">\n <label for=\"subscriptions-list-search\" class=\"visually-hidden\">Search Subscription</label>\n <i class=\"fa fa-search mt-2 me-2 d-none\" aria-hidden=\"true\"></i>\n <input type=\"text\"\n id=\"subscriptions-list-search\"\n name=\"subscriptions-list-search\"\n [(ngModel)]=\"searchText\"\n pInputText\n size=\"30\"\n placeholder=\"Search Subscription...\"\n class=\"mw-90\"\n (input)=\"dt.filterGlobal($event.target.value, 'contains')\" />\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\"\n pSortableColumn=\"id\">\n {{ 'Admin.Subscriptions.Id' | transloco }}\n <p-sortIcon field=\"id\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"organisation\">\n {{ 'Admin.Subscriptions.Organization' | transloco }}\n <p-sortIcon field=\"organisation\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"contact_name\">\n {{ 'Admin.Subscriptions.ContactName' | transloco }}\n <p-sortIcon field=\"contact_name\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"contact_email\">\n {{ 'Admin.Subscriptions.ContactEmail' | transloco }}\n <p-sortIcon field=\"contact_email\"></p-sortIcon>\n </th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.Product' | transloco }}</th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.Currency' | transloco }}</th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.PricePerMonth' | transloco }}</th>\n <th scope=\"true\"\n pSortableColumn=\"stripe_customer_id\">\n {{ 'Admin.Subscriptions.Paid' | transloco }}\n <p-sortIcon field=\"stripe_customer_id\"></p-sortIcon>\n </th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.Billing' | transloco }}</th>\n <th scope=\"true\"\n class=\"expires-at-width\">\n {{ 'Admin.Subscriptions.ExpiresAt' | transloco }}\n </th>\n <th scope=\"true\"\n pSortableColumn=\"sessions_total\">\n {{ 'Admin.Subscriptions.SessionsTotal' | transloco }}\n <p-sortIcon field=\"sessions_total\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"sessions_last_month\">\n {{ 'Admin.Subscriptions.SessionsTotalLastMonth' | transloco }}\n <p-sortIcon field=\"sessions_last_month\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"deleted_at\">\n {{ 'Admin.Subscriptions.Deleted' | transloco }}\n <p-sortIcon field=\"deleted_at\"></p-sortIcon>\n </th>\n <th class=\"actions-list-two\"\n scope=\"true\">{{ 'Label.Actions' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-item>\n <tr>\n <td data-head=\"id\">{{ item.id }}</td>\n <td data-head=\"Organization\">\n <span class=\"cursor-pointer custom-break-word\"\n [pTooltip]=\"item.organisation\"\n tooltipPosition=\"top\">{{ item.organisation | textTruncate: 20 }}</span>\n </td>\n <td data-head=\"ContactName\"\n class=\"custom-break-word\">\n {{ item.contact_name }}\n </td>\n <td data-head=\"ContactEmail\">{{ item.contact_email }}</td>\n <td data-head=\"Name\">\n <span class=\"cursor-pointer custom-break-word\"\n [pTooltip]=\"item.productName\"\n tooltipPosition=\"top\">{{ item.productName }}</span>\n </td>\n <td data-head=\"Currency\">\n <span [appDynamicBadge]=\"{ itemsArray: currency, item: item.currency }\"\n color=\"blue-grey\"\n class=\"badge\">{{ item.currency }}</span>\n </td>\n <td data-head=\"Price/M\">\n <span>{{ (item.price / 100).toFixed(2) | currency:item.currency }}\n @if (item?.discount && objectKeys(item?.discount)?.length) {\n <i\n class=\"fa fa-info-circle\"\n aria-hidden=\"true\"\n [pTooltip]=\"item?.discount | json\"\n tooltipPosition=\"top\"\n ></i>\n }\n </span>\n </td>\n <td data-head=\"Paid\">\n @if (item?.unsubscribed_at) {\n <span class=\"badge bg-warning d-inline-flex align-items-center\">\n Unsub\n @if (item?.reason_to_cancel) {\n <i class=\"fa fa-info-circle ms-2\"\n [pTooltip]=\"item.reason_to_cancel\"\n tooltipPosition=\"top\"\n aria-hidden=\"true\"></i>\n }\n </span>\n }\n @if (!item?.unsubscribed_at) {\n @if ((item?.stripe_customer_id || item?.external_payment) && item?.signed_up_at) {\n <span class=\"badge bg-success\">Yes</span>\n } @else {\n <span class=\"badge bg-blue-grey\">No</span>\n }\n }\n @if (item?.pause_collection && objectKeys(item?.pause_collection)?.length) {\n <span\n class=\"ms-2\"\n [pTooltip]=\"item?.pause_collection | json\"\n tooltipPosition=\"top\">\n <i class=\"fas fa-exclamation-triangle text-warning\"></i>\n </span>\n }\n </td>\n <td data-head=\"Billing\">\n <span class=\"badge\"\n [appDynamicBadge]=\"{\n itemsArray: billingFrequency,\n item: item?.billingFrequency\n }\"\n color=\"blue-grey\">{{ item.billingFrequency }}</span>\n </td>\n <td data-head=\"Expires\">\n <span [ngClass]=\"getExpiresAtColor(item)\">{{item?.expires_at | dateFormat}}</span><br />\n <span>{{item?.created_at | sinceAgo}}</span>\n </td>\n <td data-head=\"S#\">{{ item?.sessions_total }}</td>\n <td data-head=\"S/m #\">\n <span [ngClass]=\"{\n 'text-danger fw-bold': item?.sessions_last_month < 3\n }\">{{ item?.sessions_last_month }}</span>\n </td>\n <td data-head=\"Deleted\">\n @if (item?.deleted_at) {\n <span\n class=\"badge bg-danger\">Yes</span>\n }\n @if (!item?.deleted_at) {\n <span\n class=\"badge bg-blue-grey\">No</span>\n }\n </td>\n <td data-head=\"Action\">\n <ul class=\"list-unstyled list-inline list-action\">\n <li ngbTooltip=\"Edit\"\n class=\"me-2 me-sm-3\"\n [routerLink]=\"[routers.subscriptionDetails, item.id]\">\n <i class=\"fa fa-edit edit-icon\" aria-hidden=\"true\"></i>\n </li>\n @if (item.deleted) {\n <li ngbTooltip=\"Reactivate subscription\"\n class=\"me-2 me-sm-3\"\n *rbacAllow=\"'Pages.Alpha'\"\n (keydown.enter)=\"openRecoverSubscriptionModal(item)\"\n (click)=\"openRecoverSubscriptionModal(item)\">\n <i class=\"fa fa-trash delete-icon text-success\" aria-hidden=\"true\"></i>\n </li>\n } @else {\n <li ngbTooltip=\"Delete\"\n class=\"me-2 me-sm-3\"\n *rbacAllow=\"'Pages.Admin.Subscription.Delete'\"\n (keydown.enter)=\"onDelete(item)\"\n (click)=\"onDelete(item)\">\n <i class=\"fa fa-trash delete-icon\" aria-hidden=\"true\"></i>\n </li>\n }\n </ul>\n </td>\n </tr>\n </ng-template>\n </p-table>\n @if (totalRecords === 0 && totalRecordsUnFiltered !== 0) {\n <div>\n <pw-no-data [withImage]=\"true\" [message]=\"'Search.NoDataMessage' | transloco\" [description]=\"'Search.NoDataDescription' | transloco\" >\n </pw-no-data>\n </div>\n }\n @if (totalRecords !== 0) {\n <span class=\"total-records-count\">{{ 'Label.Total' | transloco }}: {{ totalRecords }}</span>\n }\n </div>\n</div>\n@if (totalRecordsUnFiltered === 0 && isLoaded) {\n <pw-no-data [withImage]=\"true\" [message]=\"'Admin.Subscriptions.NoSubscriptionMessage' | transloco\">\n </pw-no-data>\n}\n<pw-password-validation\n #recoverSubscriptionPasswordModal\n (successEvent)=\"onRecoverConfirmed()\">\n</pw-password-validation>\n\n", styles: [":root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}@media(min-width:767px){.table-responsive td,.table-responsive th{font-size:11px!important}}.expires-at-width{width:8%}.custom-break-word{word-break:break-word!important}.summary .card{padding-bottom:0}.summary .card .card-body{padding-top:20px;text-align:center}.summary .card .card-body p,.summary .card .card-body h4{font-size:14px}@media(min-width:320px)and (max-width:720px){.primeng-datatable-container .search-filter{display:flex;flex-direction:column;gap:.5rem;justify-content:space-between}}\n"], dependencies: [{ kind: "component", type: i2.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i3$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i2.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "component", type: i2.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "directive", type: i4$2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: i3.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i7$2.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: i2$1.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "directive", type: i3$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i1$1.PasswordValidationComponent, selector: "pw-password-validation", inputs: ["confirmMessage"], outputs: ["successEvent"] }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: i1$1.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "directive", type: i9.DynamicBadgeDirective, selector: "[appDynamicBadge]", inputs: ["appDynamicBadge", "color", "colorByName", "dataName"] }, { kind: "directive", type: i9.RbacAllowDirective, selector: "[rbacAllow]", inputs: ["rbacAllow"] }, { kind: "directive", type: i10.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i3$1.JsonPipe, name: "json" }, { kind: "pipe", type: i3$1.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i11.TranslocoPipe, name: "transloco" }, { kind: "pipe", type: i15.DateFormatPipe, name: "dateFormat" }, { kind: "pipe", type: i15.SinceAgoPipe, name: "sinceAgo" }, { kind: "pipe", type: i15.TextTruncatePipe, name: "textTruncate" }] }); }
|
|
8079
8447
|
}
|
|
8080
8448
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: SubscriptionsListComponent, decorators: [{
|
|
8081
8449
|
type: Component,
|
|
8082
|
-
args: [{ selector: 'pw-subscriptions-list', standalone: false, template: "<div class=\"row\">\n <div\n class=\"col-12 d-flex justify-content-between align-items-center\">\n <h2 class=\"card-title p-0 float-start\">Subscriptions</h2>\n <a class=\"btn btn-sm btn-outline-primary float-end\"\n id=\"btn-create\"\n [routerLink]=\"[routers.inviteUsers]\">\n <i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i> Invite a User to a Trial\n </a>\n </div>\n</div>\n<div class=\"p-2 mt-3\">\n <div class=\"w-100 text-center mt-3\">\n @if (!isLoaded) {\n <p-progressSpinner> </p-progressSpinner>\n }\n </div>\n <div class=\"primeng-datatable-container table-responsive mt-0\"\n [class.hideTable]=\"totalRecordsUnFiltered === 0\">\n <p-table #dt\n [value]=\"subscriptions\"\n [paginator]=\"totalRecords !== 0\"\n [rows]=\"PAGE_SIZE\"\n [lazy]=\"true\"\n [totalRecords]=\"totalRecords\"\n [loading]=\"loading\"\n [filterDelay]=\"1000\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n [customSort]=\"true\">\n <ng-template pTemplate=\"caption\">\n @if (subscriptionInsights) {\n <div class=\"row mb-4\">\n @for (temp of objectKeys(subscriptionInsights); track temp) {\n <div class=\"col-12 col-lg-3 mt-2 summary\">\n <div class=\"card\">\n <div class=\"card-body\">\n @for (item of subscriptionInsights[temp]; track item) {\n <div>\n <p class=\"mb-0 px-2\">{{ item?.title }}\n @if (item?.info) {\n <span\n [pTooltip]=\"item?.info\">\n <i class=\"fas fa-info-circle\"></i>\n </span>\n }\n </p>\n <h4 class=\"fw-bold mt-2 mb-2\">\n {{ item?.value }}\n </h4>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n }\n <div class=\"search-filter\">\n <div class=\"col-12 col-sm-4\">\n <p-multiSelect inputId=\"subscriptions-list-feature-keys\"\n placeholder=\"Select Feature Keys\"\n [showToggleAll]=\"true\"\n [showHeader]=\"true\"\n [(ngModel)]=\"selectedFeatureKeys\"\n [options]=\"searchOptions\"\n (onChange)=\"onSearchOptionChange($event)\"\n appendTo=\"body\">\n </p-multiSelect>\n </div>\n <div class=\"col-12 col-sm-4\">\n <p-select\n inputId=\"subscriptions-list-status\"\n [options]=\"subscriptionStatus\"\n [placeholder]=\"'Select status'\"\n (onChange)=\"filterByStatus($event.value)\"\n [(ngModel)]=\"status\">\n </p-select>\n </div>\n <div class=\"text-end\">\n <label for=\"subscriptions-list-search\" class=\"visually-hidden\">Search Subscription</label>\n <i class=\"fa fa-search mt-2 me-2 d-none\" aria-hidden=\"true\"></i>\n <input type=\"text\"\n id=\"subscriptions-list-search\"\n name=\"subscriptions-list-search\"\n [(ngModel)]=\"searchText\"\n pInputText\n size=\"30\"\n placeholder=\"Search Subscription...\"\n class=\"mw-90\"\n (input)=\"dt.filterGlobal($event.target.value, 'contains')\" />\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\"\n pSortableColumn=\"id\">\n {{ 'Admin.Subscriptions.Id' | transloco }}\n <p-sortIcon field=\"id\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"organisation\">\n {{ 'Admin.Subscriptions.Organization' | transloco }}\n <p-sortIcon field=\"organisation\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"contact_name\">\n {{ 'Admin.Subscriptions.ContactName' | transloco }}\n <p-sortIcon field=\"contact_name\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"contact_email\">\n {{ 'Admin.Subscriptions.ContactEmail' | transloco }}\n <p-sortIcon field=\"contact_email\"></p-sortIcon>\n </th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.Product' | transloco }}</th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.Currency' | transloco }}</th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.PricePerMonth' | transloco }}</th>\n <th scope=\"true\"\n pSortableColumn=\"stripe_customer_id\">\n {{ 'Admin.Subscriptions.Paid' | transloco }}\n <p-sortIcon field=\"stripe_customer_id\"></p-sortIcon>\n </th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.Billing' | transloco }}</th>\n <th scope=\"true\"\n class=\"expires-at-width\">\n {{ 'Admin.Subscriptions.ExpiresAt' | transloco }}\n </th>\n <th scope=\"true\"\n pSortableColumn=\"sessions_total\">\n {{ 'Admin.Subscriptions.SessionsTotal' | transloco }}\n <p-sortIcon field=\"sessions_total\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"sessions_last_month\">\n {{ 'Admin.Subscriptions.SessionsTotalLastMonth' | transloco }}\n <p-sortIcon field=\"sessions_last_month\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"deleted_at\">\n {{ 'Admin.Subscriptions.Deleted' | transloco }}\n <p-sortIcon field=\"deleted_at\"></p-sortIcon>\n </th>\n <th class=\"actions-list-two\"\n scope=\"true\">{{ 'Label.Actions' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-item>\n <tr>\n <td data-head=\"id\">{{ item.id }}</td>\n <td data-head=\"Organization\">\n <span class=\"cursor-pointer custom-break-word\"\n [pTooltip]=\"item.organisation\"\n tooltipPosition=\"top\">{{ item.organisation | textTruncate: 20 }}</span>\n </td>\n <td data-head=\"ContactName\"\n class=\"custom-break-word\">\n {{ item.contact_name }}\n </td>\n <td data-head=\"ContactEmail\">{{ item.contact_email }}</td>\n <td data-head=\"Name\">\n <span class=\"cursor-pointer custom-break-word\"\n [pTooltip]=\"item.productName\"\n tooltipPosition=\"top\">{{ item.productName }}</span>\n </td>\n <td data-head=\"Currency\">\n <span [appDynamicBadge]=\"{ itemsArray: currency, item: item.currency }\"\n color=\"blue-grey\"\n class=\"badge\">{{ item.currency }}</span>\n </td>\n <td data-head=\"Price/M\">\n <span>{{ (item.price / 100).toFixed(2) | currency:item.currency }}\n @if (item?.discount && objectKeys(item?.discount)?.length) {\n <i\n class=\"fa fa-info-circle\"\n aria-hidden=\"true\"\n [pTooltip]=\"item?.discount | json\"\n tooltipPosition=\"top\"\n ></i>\n }\n </span>\n </td>\n <td data-head=\"Paid\">\n @if (item?.unsubscribed_at) {\n <span class=\"badge bg-warning d-inline-flex align-items-center\">\n Unsub\n @if (item?.reason_to_cancel) {\n <i class=\"fa fa-info-circle ms-2\"\n [pTooltip]=\"item.reason_to_cancel\"\n tooltipPosition=\"top\"\n aria-hidden=\"true\"></i>\n }\n </span>\n }\n @if (!item?.unsubscribed_at) {\n @if ((item?.stripe_customer_id || item?.external_payment) && item?.signed_up_at) {\n <span class=\"badge bg-success\">Yes</span>\n } @else {\n <span class=\"badge bg-blue-grey\">No</span>\n }\n }\n @if (item?.pause_collection && objectKeys(item?.pause_collection)?.length) {\n <span\n class=\"ms-2\"\n [pTooltip]=\"item?.pause_collection | json\"\n tooltipPosition=\"top\">\n <i class=\"fas fa-exclamation-triangle text-warning\"></i>\n </span>\n }\n </td>\n <td data-head=\"Billing\">\n <span class=\"badge\"\n [appDynamicBadge]=\"{\n itemsArray: billingFrequency,\n item: item?.billingFrequency\n }\"\n color=\"blue-grey\">{{ item.billingFrequency }}</span>\n </td>\n <td data-head=\"Expires\">\n <span [ngClass]=\"getExpiresAtColor(item)\">{{item?.expires_at | dateFormat}}</span><br />\n <span>{{item?.created_at | sinceAgo}}</span>\n </td>\n <td data-head=\"S#\">{{ item?.sessions_total }}</td>\n <td data-head=\"S/m #\">\n <span [ngClass]=\"{\n 'text-danger fw-bold': item?.sessions_last_month < 3\n }\">{{ item?.sessions_last_month }}</span>\n </td>\n <td data-head=\"Deleted\">\n @if (item?.deleted_at) {\n <span\n class=\"badge bg-danger\">Yes</span>\n }\n @if (!item?.deleted_at) {\n <span\n class=\"badge bg-blue-grey\">No</span>\n }\n </td>\n <td data-head=\"Action\">\n <ul class=\"list-unstyled list-inline list-action\">\n <li ngbTooltip=\"Edit\"\n class=\"me-2 me-sm-3\"\n [routerLink]=\"[routers.subscriptionDetails, item.id]\">\n <i class=\"fa fa-edit edit-icon\" aria-hidden=\"true\"></i>\n </li>\n @if (item.deleted) {\n <li ngbTooltip=\"Reactivate subscription\"\n class=\"me-2 me-sm-3\"\n *rbacAllow=\"'Pages.Alpha'\"\n (keydown.enter)=\"openRecoverSubscriptionModal(item)\"\n (click)=\"openRecoverSubscriptionModal(item)\">\n <i class=\"fa fa-trash delete-icon text-success\" aria-hidden=\"true\"></i>\n </li>\n } @else {\n <li ngbTooltip=\"Delete\"\n class=\"me-2 me-sm-3\"\n *rbacAllow=\"'Pages.Admin.Subscription.Delete'\"\n (keydown.enter)=\"onDelete(item)\"\n (click)=\"onDelete(item)\">\n <i class=\"fa fa-trash delete-icon\" aria-hidden=\"true\"></i>\n </li>\n }\n </ul>\n </td>\n </tr>\n </ng-template>\n </p-table>\n @if (totalRecords === 0 && totalRecordsUnFiltered !== 0) {\n <div>\n <pw-no-data [withImage]=\"true\" [message]=\"'Search.NoDataMessage' | transloco\" [description]=\"'Search.NoDataDescription' | transloco\" >\n </pw-no-data>\n </div>\n }\n @if (totalRecords !== 0) {\n <span class=\"total-records-count\">{{ 'Label.Total' | transloco }}: {{ totalRecords }}</span>\n }\n </div>\n</div>\n@if (totalRecordsUnFiltered === 0 && isLoaded) {\n <pw-no-data [withImage]=\"true\" [message]=\"'Admin.Subscriptions.NoSubscriptionMessage' | transloco\">\n </pw-no-data>\n}\n<pw-password-validation\n #recoverSubscriptionPasswordModal\n (successEvent)=\"onRecoverConfirmed()\">\n</pw-password-validation>\n\n", styles: [":root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}@media(min-width:767px){.table-responsive td,.table-responsive th{font-size:11px!important}}.expires-at-width{width:8%}.custom-break-word{word-break:break-word!important}.summary .card{padding-bottom:0}.summary .card .card-body{padding-top:20px;text-align:center}.summary .card .card-body p,.summary .card .card-body h4{font-size:14px}@media(min-width:320px)and (max-width:720px){.primeng-datatable-container .search-filter{display:flex;flex-direction:column;gap:.5rem;justify-content:space-between}}\n"] }]
|
|
8450
|
+
args: [{ selector: 'pw-subscriptions-list', standalone: false, template: "<div class=\"row\">\n <div\n class=\"col-12 d-flex justify-content-between align-items-center\">\n <h2 class=\"card-title p-0 float-start\">Subscriptions</h2>\n <a class=\"btn btn-sm btn-outline-primary float-end\"\n id=\"btn-create\"\n [routerLink]=\"[routers.inviteUsers]\">\n <i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i> Invite a User to a Trial\n </a>\n </div>\n</div>\n<div class=\"p-2 mt-3\">\n <div class=\"w-100 text-center mt-3\">\n @if (!isLoaded) {\n <p-progressSpinner> </p-progressSpinner>\n }\n </div>\n <div class=\"primeng-datatable-container table-responsive mt-0\"\n [class.hideTable]=\"totalRecordsUnFiltered === 0\">\n <p-table #dt\n [value]=\"subscriptions\"\n [paginator]=\"totalRecords !== 0\"\n [rows]=\"PAGE_SIZE\"\n [lazy]=\"true\"\n [totalRecords]=\"totalRecords\"\n [loading]=\"loading\"\n [filterDelay]=\"1000\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n [customSort]=\"true\">\n <ng-template pTemplate=\"caption\">\n @if (subscriptionInsights) {\n <div class=\"row mb-4\">\n @for (temp of objectKeys(subscriptionInsights); track temp) {\n <div class=\"col-12 col-lg-3 mt-2 summary\">\n <div class=\"card\">\n <div class=\"card-body\">\n @for (item of subscriptionInsights[temp]; track item) {\n <div>\n <p class=\"mb-0 px-2\">{{ item?.title }}\n @if (item?.info) {\n <span\n [pTooltip]=\"item?.info\">\n <i class=\"fas fa-info-circle\"></i>\n </span>\n }\n </p>\n <h4 class=\"fw-bold mt-2 mb-2\">\n {{ item?.value }}\n </h4>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n }\n <div class=\"search-filter\">\n <div class=\"col-12 col-sm-4\">\n <p-multiSelect inputId=\"subscriptions-list-feature-keys\"\n placeholder=\"Select Feature Keys\"\n [showToggleAll]=\"true\"\n [showHeader]=\"true\"\n [(ngModel)]=\"selectedFeatureKeys\"\n [options]=\"searchOptions\"\n (onChange)=\"onSearchOptionChange($event)\"\n appendTo=\"body\">\n </p-multiSelect>\n </div>\n <div class=\"col-12 col-sm-4\">\n <p-select\n inputId=\"subscriptions-list-status\"\n [options]=\"subscriptionStatus\"\n [placeholder]=\"'Select status'\"\n (onChange)=\"filterByStatus($event.value)\"\n [(ngModel)]=\"status\"\n appendTo=\"body\">\n </p-select>\n </div>\n <div class=\"text-end\">\n <label for=\"subscriptions-list-search\" class=\"visually-hidden\">Search Subscription</label>\n <i class=\"fa fa-search mt-2 me-2 d-none\" aria-hidden=\"true\"></i>\n <input type=\"text\"\n id=\"subscriptions-list-search\"\n name=\"subscriptions-list-search\"\n [(ngModel)]=\"searchText\"\n pInputText\n size=\"30\"\n placeholder=\"Search Subscription...\"\n class=\"mw-90\"\n (input)=\"dt.filterGlobal($event.target.value, 'contains')\" />\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\"\n pSortableColumn=\"id\">\n {{ 'Admin.Subscriptions.Id' | transloco }}\n <p-sortIcon field=\"id\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"organisation\">\n {{ 'Admin.Subscriptions.Organization' | transloco }}\n <p-sortIcon field=\"organisation\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"contact_name\">\n {{ 'Admin.Subscriptions.ContactName' | transloco }}\n <p-sortIcon field=\"contact_name\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"contact_email\">\n {{ 'Admin.Subscriptions.ContactEmail' | transloco }}\n <p-sortIcon field=\"contact_email\"></p-sortIcon>\n </th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.Product' | transloco }}</th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.Currency' | transloco }}</th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.PricePerMonth' | transloco }}</th>\n <th scope=\"true\"\n pSortableColumn=\"stripe_customer_id\">\n {{ 'Admin.Subscriptions.Paid' | transloco }}\n <p-sortIcon field=\"stripe_customer_id\"></p-sortIcon>\n </th>\n <th scope=\"true\">{{ 'Admin.Subscriptions.Billing' | transloco }}</th>\n <th scope=\"true\"\n class=\"expires-at-width\">\n {{ 'Admin.Subscriptions.ExpiresAt' | transloco }}\n </th>\n <th scope=\"true\"\n pSortableColumn=\"sessions_total\">\n {{ 'Admin.Subscriptions.SessionsTotal' | transloco }}\n <p-sortIcon field=\"sessions_total\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"sessions_last_month\">\n {{ 'Admin.Subscriptions.SessionsTotalLastMonth' | transloco }}\n <p-sortIcon field=\"sessions_last_month\"></p-sortIcon>\n </th>\n <th scope=\"true\"\n pSortableColumn=\"deleted_at\">\n {{ 'Admin.Subscriptions.Deleted' | transloco }}\n <p-sortIcon field=\"deleted_at\"></p-sortIcon>\n </th>\n <th class=\"actions-list-two\"\n scope=\"true\">{{ 'Label.Actions' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-item>\n <tr>\n <td data-head=\"id\">{{ item.id }}</td>\n <td data-head=\"Organization\">\n <span class=\"cursor-pointer custom-break-word\"\n [pTooltip]=\"item.organisation\"\n tooltipPosition=\"top\">{{ item.organisation | textTruncate: 20 }}</span>\n </td>\n <td data-head=\"ContactName\"\n class=\"custom-break-word\">\n {{ item.contact_name }}\n </td>\n <td data-head=\"ContactEmail\">{{ item.contact_email }}</td>\n <td data-head=\"Name\">\n <span class=\"cursor-pointer custom-break-word\"\n [pTooltip]=\"item.productName\"\n tooltipPosition=\"top\">{{ item.productName }}</span>\n </td>\n <td data-head=\"Currency\">\n <span [appDynamicBadge]=\"{ itemsArray: currency, item: item.currency }\"\n color=\"blue-grey\"\n class=\"badge\">{{ item.currency }}</span>\n </td>\n <td data-head=\"Price/M\">\n <span>{{ (item.price / 100).toFixed(2) | currency:item.currency }}\n @if (item?.discount && objectKeys(item?.discount)?.length) {\n <i\n class=\"fa fa-info-circle\"\n aria-hidden=\"true\"\n [pTooltip]=\"item?.discount | json\"\n tooltipPosition=\"top\"\n ></i>\n }\n </span>\n </td>\n <td data-head=\"Paid\">\n @if (item?.unsubscribed_at) {\n <span class=\"badge bg-warning d-inline-flex align-items-center\">\n Unsub\n @if (item?.reason_to_cancel) {\n <i class=\"fa fa-info-circle ms-2\"\n [pTooltip]=\"item.reason_to_cancel\"\n tooltipPosition=\"top\"\n aria-hidden=\"true\"></i>\n }\n </span>\n }\n @if (!item?.unsubscribed_at) {\n @if ((item?.stripe_customer_id || item?.external_payment) && item?.signed_up_at) {\n <span class=\"badge bg-success\">Yes</span>\n } @else {\n <span class=\"badge bg-blue-grey\">No</span>\n }\n }\n @if (item?.pause_collection && objectKeys(item?.pause_collection)?.length) {\n <span\n class=\"ms-2\"\n [pTooltip]=\"item?.pause_collection | json\"\n tooltipPosition=\"top\">\n <i class=\"fas fa-exclamation-triangle text-warning\"></i>\n </span>\n }\n </td>\n <td data-head=\"Billing\">\n <span class=\"badge\"\n [appDynamicBadge]=\"{\n itemsArray: billingFrequency,\n item: item?.billingFrequency\n }\"\n color=\"blue-grey\">{{ item.billingFrequency }}</span>\n </td>\n <td data-head=\"Expires\">\n <span [ngClass]=\"getExpiresAtColor(item)\">{{item?.expires_at | dateFormat}}</span><br />\n <span>{{item?.created_at | sinceAgo}}</span>\n </td>\n <td data-head=\"S#\">{{ item?.sessions_total }}</td>\n <td data-head=\"S/m #\">\n <span [ngClass]=\"{\n 'text-danger fw-bold': item?.sessions_last_month < 3\n }\">{{ item?.sessions_last_month }}</span>\n </td>\n <td data-head=\"Deleted\">\n @if (item?.deleted_at) {\n <span\n class=\"badge bg-danger\">Yes</span>\n }\n @if (!item?.deleted_at) {\n <span\n class=\"badge bg-blue-grey\">No</span>\n }\n </td>\n <td data-head=\"Action\">\n <ul class=\"list-unstyled list-inline list-action\">\n <li ngbTooltip=\"Edit\"\n class=\"me-2 me-sm-3\"\n [routerLink]=\"[routers.subscriptionDetails, item.id]\">\n <i class=\"fa fa-edit edit-icon\" aria-hidden=\"true\"></i>\n </li>\n @if (item.deleted) {\n <li ngbTooltip=\"Reactivate subscription\"\n class=\"me-2 me-sm-3\"\n *rbacAllow=\"'Pages.Alpha'\"\n (keydown.enter)=\"openRecoverSubscriptionModal(item)\"\n (click)=\"openRecoverSubscriptionModal(item)\">\n <i class=\"fa fa-trash delete-icon text-success\" aria-hidden=\"true\"></i>\n </li>\n } @else {\n <li ngbTooltip=\"Delete\"\n class=\"me-2 me-sm-3\"\n *rbacAllow=\"'Pages.Admin.Subscription.Delete'\"\n (keydown.enter)=\"onDelete(item)\"\n (click)=\"onDelete(item)\">\n <i class=\"fa fa-trash delete-icon\" aria-hidden=\"true\"></i>\n </li>\n }\n </ul>\n </td>\n </tr>\n </ng-template>\n </p-table>\n @if (totalRecords === 0 && totalRecordsUnFiltered !== 0) {\n <div>\n <pw-no-data [withImage]=\"true\" [message]=\"'Search.NoDataMessage' | transloco\" [description]=\"'Search.NoDataDescription' | transloco\" >\n </pw-no-data>\n </div>\n }\n @if (totalRecords !== 0) {\n <span class=\"total-records-count\">{{ 'Label.Total' | transloco }}: {{ totalRecords }}</span>\n }\n </div>\n</div>\n@if (totalRecordsUnFiltered === 0 && isLoaded) {\n <pw-no-data [withImage]=\"true\" [message]=\"'Admin.Subscriptions.NoSubscriptionMessage' | transloco\">\n </pw-no-data>\n}\n<pw-password-validation\n #recoverSubscriptionPasswordModal\n (successEvent)=\"onRecoverConfirmed()\">\n</pw-password-validation>\n\n", styles: [":root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}@media(min-width:767px){.table-responsive td,.table-responsive th{font-size:11px!important}}.expires-at-width{width:8%}.custom-break-word{word-break:break-word!important}.summary .card{padding-bottom:0}.summary .card .card-body{padding-top:20px;text-align:center}.summary .card .card-body p,.summary .card .card-body h4{font-size:14px}@media(min-width:320px)and (max-width:720px){.primeng-datatable-container .search-filter{display:flex;flex-direction:column;gap:.5rem;justify-content:space-between}}\n"] }]
|
|
8083
8451
|
}], ctorParameters: () => [{ type: i1$2.ProductService }, { type: i1.AdminService }, { type: i6.UntypedFormBuilder }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: i1$2.CommonService }], propDecorators: { refProduct: [{
|
|
8084
8452
|
type: ViewChild,
|
|
8085
8453
|
args: ['refProduct']
|
|
@@ -10427,6 +10795,54 @@ const routes = [
|
|
|
10427
10795
|
}
|
|
10428
10796
|
]
|
|
10429
10797
|
},
|
|
10798
|
+
{
|
|
10799
|
+
path: 'feature-flags',
|
|
10800
|
+
data: {
|
|
10801
|
+
title: 'Feature Flags',
|
|
10802
|
+
permission: 'Pages.Admin'
|
|
10803
|
+
},
|
|
10804
|
+
children: [
|
|
10805
|
+
{
|
|
10806
|
+
path: '',
|
|
10807
|
+
component: FeatureFlagsTabsComponent,
|
|
10808
|
+
children: [
|
|
10809
|
+
{
|
|
10810
|
+
path: '',
|
|
10811
|
+
redirectTo: 'list',
|
|
10812
|
+
pathMatch: 'full'
|
|
10813
|
+
},
|
|
10814
|
+
{
|
|
10815
|
+
path: 'list',
|
|
10816
|
+
component: FeatureFlagsListComponent
|
|
10817
|
+
}
|
|
10818
|
+
]
|
|
10819
|
+
},
|
|
10820
|
+
{
|
|
10821
|
+
path: 'add',
|
|
10822
|
+
component: FeatureFlagDetailsComponent,
|
|
10823
|
+
data: {
|
|
10824
|
+
title: 'Add Feature Flag',
|
|
10825
|
+
permission: 'Pages.Admin'
|
|
10826
|
+
}
|
|
10827
|
+
},
|
|
10828
|
+
{
|
|
10829
|
+
path: ':id',
|
|
10830
|
+
component: FeatureFlagDetailsComponent,
|
|
10831
|
+
data: {
|
|
10832
|
+
title: 'Edit Feature Flag',
|
|
10833
|
+
permission: 'Pages.Admin'
|
|
10834
|
+
}
|
|
10835
|
+
},
|
|
10836
|
+
{
|
|
10837
|
+
path: 'rules/:id',
|
|
10838
|
+
component: FeatureFlagRulesComponent,
|
|
10839
|
+
data: {
|
|
10840
|
+
title: 'Feature Flag Rules',
|
|
10841
|
+
permission: 'Pages.Admin'
|
|
10842
|
+
}
|
|
10843
|
+
}
|
|
10844
|
+
]
|
|
10845
|
+
},
|
|
10430
10846
|
{
|
|
10431
10847
|
path: 'faq',
|
|
10432
10848
|
data: {
|
|
@@ -11225,6 +11641,10 @@ class AdminModule {
|
|
|
11225
11641
|
LoginNotificationDetailsComponent,
|
|
11226
11642
|
FeedbackQuestionsListComponent,
|
|
11227
11643
|
FeedbackQuestionsDetailsComponent,
|
|
11644
|
+
FeatureFlagsListComponent,
|
|
11645
|
+
FeatureFlagDetailsComponent,
|
|
11646
|
+
FeatureFlagRulesComponent,
|
|
11647
|
+
FeatureFlagsTabsComponent,
|
|
11228
11648
|
UserDetailsComponent,
|
|
11229
11649
|
ProductsTabComponent,
|
|
11230
11650
|
SubscriptionDetailsComponent,
|
|
@@ -11404,6 +11824,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
11404
11824
|
LoginNotificationDetailsComponent,
|
|
11405
11825
|
FeedbackQuestionsListComponent,
|
|
11406
11826
|
FeedbackQuestionsDetailsComponent,
|
|
11827
|
+
FeatureFlagsListComponent,
|
|
11828
|
+
FeatureFlagDetailsComponent,
|
|
11829
|
+
FeatureFlagRulesComponent,
|
|
11830
|
+
FeatureFlagsTabsComponent,
|
|
11407
11831
|
UserDetailsComponent,
|
|
11408
11832
|
ProductsTabComponent,
|
|
11409
11833
|
SubscriptionDetailsComponent,
|
|
@@ -11543,13 +11967,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
11543
11967
|
}] });
|
|
11544
11968
|
|
|
11545
11969
|
class AdminGuardService {
|
|
11546
|
-
constructor(userService, router, permissionService) {
|
|
11970
|
+
constructor(userService, router, featureFlagService, permissionService) {
|
|
11547
11971
|
this.userService = userService;
|
|
11548
11972
|
this.router = router;
|
|
11973
|
+
this.featureFlagService = featureFlagService;
|
|
11549
11974
|
this.permissionService = permissionService;
|
|
11550
11975
|
}
|
|
11551
11976
|
canLoad(route) {
|
|
11552
11977
|
return this.userService.getUserInfo().pipe(take(1), concatMap(user => {
|
|
11978
|
+
this.featureFlagService.user = user;
|
|
11553
11979
|
this.permissionService.user = user;
|
|
11554
11980
|
if (route.data && this.permissionService.isGranted(route.data['permission'])) {
|
|
11555
11981
|
return of(true);
|
|
@@ -11570,12 +11996,12 @@ class AdminGuardService {
|
|
|
11570
11996
|
return of(false);
|
|
11571
11997
|
}));
|
|
11572
11998
|
}
|
|
11573
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: AdminGuardService, deps: [{ token: i1$2.UserService }, { token: i10.Router }, { token: i1$2.PermissionService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
11999
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: AdminGuardService, deps: [{ token: i1$2.UserService }, { token: i10.Router }, { token: i1$2.FeatureFlagService }, { token: i1$2.PermissionService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
11574
12000
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: AdminGuardService }); }
|
|
11575
12001
|
}
|
|
11576
12002
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: AdminGuardService, decorators: [{
|
|
11577
12003
|
type: Injectable
|
|
11578
|
-
}], ctorParameters: () => [{ type: i1$2.UserService }, { type: i10.Router }, { type: i1$2.PermissionService }] });
|
|
12004
|
+
}], ctorParameters: () => [{ type: i1$2.UserService }, { type: i10.Router }, { type: i1$2.FeatureFlagService }, { type: i1$2.PermissionService }] });
|
|
11579
12005
|
|
|
11580
12006
|
// Admin
|
|
11581
12007
|
|