@isaiahiroko/tilmart-ngx-apps-admin 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-articles.module-OeLRnPwN.mjs +154 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-articles.module-OeLRnPwN.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-audit.module-C9gvw8X2.mjs +84 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-audit.module-C9gvw8X2.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-baskets.module-_lHPl1dT.mjs +294 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-baskets.module-_lHPl1dT.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-Bvx2tVOi.mjs +224 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-Bvx2tVOi.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Ccsd8Yx3.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Ccsd8Yx3.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs +261 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-content.module-DLdKAUqc.mjs +365 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-content.module-DLdKAUqc.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CQNCSlsd.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CQNCSlsd.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-12XdV9zo.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-12XdV9zo.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-Bfgh3zE5.mjs +286 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-Bfgh3zE5.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-C6tPNlup.mjs +104 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-C6tPNlup.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-disputes.module-DmUoAS0Z.mjs +73 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-disputes.module-DmUoAS0Z.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-homepage.module-BZ3UmxE3.mjs +404 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-homepage.module-BZ3UmxE3.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-inbox.module-BZDTa1L-.mjs +290 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-inbox.module-BZDTa1L-.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-macros.module-BO4bdER2.mjs +112 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-macros.module-BO4bdER2.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-moderation.module-CZOCrias.mjs +116 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-moderation.module-CZOCrias.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-navigation.module-DoKzzRgn.mjs +281 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-navigation.module-DoKzzRgn.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-order-board.module-DIOjhptn.mjs +115 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-order-board.module-DIOjhptn.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-Ddw49QW0.mjs +185 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-Ddw49QW0.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-BhqAtTZs.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-BhqAtTZs.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payouts.module-CoiscPIZ.mjs +70 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payouts.module-CoiscPIZ.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-procurement.module-qXW-g0pf.mjs +274 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-procurement.module-qXW-g0pf.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG9uTDqX.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG9uTDqX.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-queues.module-K-zYYVFy.mjs +84 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-queues.module-K-zYYVFy.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-Hm2dO_bC.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-Hm2dO_bC.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs +104 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-Bd2gdo6_.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-Bd2gdo6_.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-rich-editor.module-DW9Gy_QQ.mjs +81 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-rich-editor.module-DW9Gy_QQ.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-BkVY06ci.mjs +105 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-BkVY06ci.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-DKeZTldO.mjs +222 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-DKeZTldO.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-shipments.module-XuaOKr8v.mjs +150 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-shipments.module-XuaOKr8v.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-DYiAkF7E.mjs +107 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-DYiAkF7E.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-trace.module-Pwr-82Rc.mjs +92 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-trace.module-Pwr-82Rc.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-users.module-Bx_7fI2g.mjs +111 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-users.module-Bx_7fI2g.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin.mjs +475 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin.mjs.map +1 -0
- package/package.json +34 -0
- package/types/isaiahiroko-tilmart-ngx-apps-admin.d.ts +32 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Component, NgModule } from '@angular/core';
|
|
3
|
+
import * as i1$1 from '@angular/router';
|
|
4
|
+
import { RouterModule } from '@angular/router';
|
|
5
|
+
import { BaseDirective, using, titleCase, SharedModule } from '@thescaffold/ngx-core';
|
|
6
|
+
import * as i1 from '@thescaffold/ngx-ui';
|
|
7
|
+
import { ElementsModule, WebgetsModule } from '@thescaffold/ngx-ui';
|
|
8
|
+
import { BehaviorSubject, takeUntil, map } from 'rxjs';
|
|
9
|
+
import * as i2 from '@angular/common';
|
|
10
|
+
|
|
11
|
+
// P7.1 — ops console section pass (PRD 6.2, TRD 9.2). A standard list
|
|
12
|
+
// view on `x-webget-collection` over `apps/commerce/warranty-claim`, matching the
|
|
13
|
+
// established admin pattern (users, routes, inbox). ops CRUD is covered
|
|
14
|
+
// by `admin:*:apps:commerce:*`.
|
|
15
|
+
class ClaimsComponent extends BaseDirective {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments);
|
|
18
|
+
this.pluralName = 'warranty claims';
|
|
19
|
+
this.dataSource = this.apiService.on('apps/commerce/warranty-claim');
|
|
20
|
+
this.columns = [
|
|
21
|
+
{ key: 'warrantyId', value: 'Warranty' },
|
|
22
|
+
{ key: 'status', value: 'Status', type: 'class', class: 'badge text-bg-light border' },
|
|
23
|
+
{ key: 'triageOutcome', value: 'Triage' },
|
|
24
|
+
{ key: 'createdAt', value: 'Opened', type: 'date' },
|
|
25
|
+
];
|
|
26
|
+
this.page = 1;
|
|
27
|
+
this.perPage = 25;
|
|
28
|
+
this.list$ = new BehaviorSubject(null);
|
|
29
|
+
this.init = () => {
|
|
30
|
+
this.list();
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
list(page = this.page, perPage = this.perPage) {
|
|
34
|
+
this.dataSource
|
|
35
|
+
.getMany({ page, perPage })
|
|
36
|
+
.pipe(takeUntil(this.$), map((response) => this.toCollection(response)))
|
|
37
|
+
.subscribe(using((data) => this.list$.next(data)));
|
|
38
|
+
}
|
|
39
|
+
toCollection(response) {
|
|
40
|
+
return {
|
|
41
|
+
title: titleCase(this.pluralName),
|
|
42
|
+
columns: this.columns,
|
|
43
|
+
rows: response?.data,
|
|
44
|
+
hasHeaders: true,
|
|
45
|
+
hasTextFilter: true,
|
|
46
|
+
page: response?.meta?.current_page,
|
|
47
|
+
perPage: response?.meta?.per_page,
|
|
48
|
+
total: response?.meta?.total,
|
|
49
|
+
onPage: (page) => this.list(page),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ClaimsComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
53
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: ClaimsComponent, isStandalone: false, selector: "x-claims", usesInheritance: true, ngImport: i0, template: `
|
|
54
|
+
<div class="x-page-head">
|
|
55
|
+
<div class="x-page-title">Warranty claims</div>
|
|
56
|
+
<div class="x-page-subtitle">Warranty claims — triage outcome, resolution and manufacturer refs.</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
@if (list$ | async; as list) {
|
|
60
|
+
<x-webget-collection [data]="list"></x-webget-collection>
|
|
61
|
+
} @else {
|
|
62
|
+
<x-element-loader></x-element-loader>
|
|
63
|
+
}
|
|
64
|
+
`, isInline: true, styles: [".x-page-head{margin-bottom:20px}.x-page-title{font-size:24px;font-weight:800;color:var(--color-text)}.x-page-subtitle{font-size:13.5px;color:var(--color-text-muted);margin-top:2px}\n"], dependencies: [{ kind: "component", type: i1.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "component", type: i1.CollectionComponent, selector: "x-webget-collection", inputs: ["data"], outputs: ["search", "filter", "refresh", "select", "page", "show"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] }); }
|
|
65
|
+
}
|
|
66
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ClaimsComponent, decorators: [{
|
|
67
|
+
type: Component,
|
|
68
|
+
args: [{ standalone: false, selector: 'x-claims', template: `
|
|
69
|
+
<div class="x-page-head">
|
|
70
|
+
<div class="x-page-title">Warranty claims</div>
|
|
71
|
+
<div class="x-page-subtitle">Warranty claims — triage outcome, resolution and manufacturer refs.</div>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
@if (list$ | async; as list) {
|
|
75
|
+
<x-webget-collection [data]="list"></x-webget-collection>
|
|
76
|
+
} @else {
|
|
77
|
+
<x-element-loader></x-element-loader>
|
|
78
|
+
}
|
|
79
|
+
`, styles: [".x-page-head{margin-bottom:20px}.x-page-title{font-size:24px;font-weight:800;color:var(--color-text)}.x-page-subtitle{font-size:13.5px;color:var(--color-text-muted);margin-top:2px}\n"] }]
|
|
80
|
+
}] });
|
|
81
|
+
|
|
82
|
+
class ClaimsModule {
|
|
83
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ClaimsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
84
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: ClaimsModule, declarations: [ClaimsComponent], imports: [SharedModule,
|
|
85
|
+
ElementsModule,
|
|
86
|
+
WebgetsModule, i1$1.RouterModule] }); }
|
|
87
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ClaimsModule, imports: [SharedModule,
|
|
88
|
+
ElementsModule,
|
|
89
|
+
WebgetsModule,
|
|
90
|
+
RouterModule.forChild([{ path: '', component: ClaimsComponent }])] }); }
|
|
91
|
+
}
|
|
92
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ClaimsModule, decorators: [{
|
|
93
|
+
type: NgModule,
|
|
94
|
+
args: [{
|
|
95
|
+
declarations: [ClaimsComponent],
|
|
96
|
+
imports: [
|
|
97
|
+
SharedModule,
|
|
98
|
+
ElementsModule,
|
|
99
|
+
WebgetsModule,
|
|
100
|
+
RouterModule.forChild([{ path: '', component: ClaimsComponent }]),
|
|
101
|
+
],
|
|
102
|
+
}]
|
|
103
|
+
}] });
|
|
104
|
+
|
|
105
|
+
export { ClaimsModule };
|
|
106
|
+
//# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-claims.module-Ccsd8Yx3.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-claims.module-Ccsd8Yx3.mjs","sources":["../../../projects/admin/src/lib/pages/claims/claims.component.ts","../../../projects/admin/src/lib/pages/claims/claims.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, titleCase, using } from '@thescaffold/ngx-core';\nimport { BehaviorSubject, map, takeUntil } from 'rxjs';\n\n// P7.1 — ops console section pass (PRD 6.2, TRD 9.2). A standard list\n// view on `x-webget-collection` over `apps/commerce/warranty-claim`, matching the\n// established admin pattern (users, routes, inbox). ops CRUD is covered\n// by `admin:*:apps:commerce:*`.\n@Component({\n standalone: false,\n selector: 'x-claims',\n template: `\n <div class=\"x-page-head\">\n <div class=\"x-page-title\">Warranty claims</div>\n <div class=\"x-page-subtitle\">Warranty claims — triage outcome, resolution and manufacturer refs.</div>\n </div>\n\n @if (list$ | async; as list) {\n <x-webget-collection [data]=\"list\"></x-webget-collection>\n } @else {\n <x-element-loader></x-element-loader>\n }\n `,\n styles: [\n `\n .x-page-head {\n margin-bottom: 20px;\n }\n .x-page-title {\n font-size: 24px;\n font-weight: 800;\n color: var(--color-text);\n }\n .x-page-subtitle {\n font-size: 13.5px;\n color: var(--color-text-muted);\n margin-top: 2px;\n }\n `,\n ],\n})\nexport class ClaimsComponent extends BaseDirective {\n pluralName = 'warranty claims';\n dataSource = this.apiService.on('apps/commerce/warranty-claim');\n\n columns = [\n { key: 'warrantyId', value: 'Warranty' },\n { key: 'status', value: 'Status', type: 'class', class: 'badge text-bg-light border' },\n { key: 'triageOutcome', value: 'Triage' },\n { key: 'createdAt', value: 'Opened', type: 'date' },\n ];\n\n page = 1;\n perPage = 25;\n\n list$ = new BehaviorSubject<any>(null);\n\n override init = () => {\n this.list();\n };\n\n list(page = this.page, perPage = this.perPage) {\n this.dataSource\n .getMany({ page, perPage })\n .pipe(\n takeUntil(this.$),\n map((response) => this.toCollection(response)),\n )\n .subscribe(using((data) => this.list$.next(data)));\n }\n\n private toCollection(response: any) {\n return {\n title: titleCase(this.pluralName),\n columns: this.columns,\n rows: response?.data,\n hasHeaders: true,\n hasTextFilter: true,\n page: response?.meta?.current_page,\n perPage: response?.meta?.per_page,\n total: response?.meta?.total,\n onPage: (page: number) => this.list(page),\n };\n }\n}\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule, WebgetsModule } from '@thescaffold/ngx-ui';\nimport { ClaimsComponent } from './claims.component';\n\n@NgModule({\n declarations: [ClaimsComponent],\n imports: [\n SharedModule,\n ElementsModule,\n WebgetsModule,\n RouterModule.forChild([{ path: '', component: ClaimsComponent }]),\n ],\n})\nexport class ClaimsModule {}\n"],"names":["i1"],"mappings":"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"}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Component, NgModule } from '@angular/core';
|
|
3
|
+
import * as i1$1 from '@angular/router';
|
|
4
|
+
import { RouterModule } from '@angular/router';
|
|
5
|
+
import { BaseDirective, using, notify, SharedModule } from '@thescaffold/ngx-core';
|
|
6
|
+
import * as i1 from '@thescaffold/ngx-ui';
|
|
7
|
+
import { ElementsModule } from '@thescaffold/ngx-ui';
|
|
8
|
+
import { BehaviorSubject, takeUntil, map } from 'rxjs';
|
|
9
|
+
import * as i2 from '@angular/common';
|
|
10
|
+
|
|
11
|
+
// P1.16 — CAT-10's "editable by ops without code". P1.11 deliberately
|
|
12
|
+
// implements a **fixed, named vocabulary** of rule kinds
|
|
13
|
+
// (`CompatibilityRuleKind`) rather than a generic condition-expression
|
|
14
|
+
// interpreter — see `pkg/catalog-workflow/compatibility.ts`'s own doc
|
|
15
|
+
// comment for why. That architecture decision sets this editor's real
|
|
16
|
+
// shape: ops can toggle a rule on/off, edit its ops-facing message/scope,
|
|
17
|
+
// and tune its `config` (currently only
|
|
18
|
+
// `array_power_vs_inverter_rating`'s `overSizingAllowancePct`) — not
|
|
19
|
+
// build new conditions from scratch. `expression.kind` itself is shown
|
|
20
|
+
// read-only for the same reason: changing it would point the row at a
|
|
21
|
+
// different evaluator with a config shape it doesn't understand.
|
|
22
|
+
//
|
|
23
|
+
// `config` is edited as raw JSON text rather than a bespoke per-kind
|
|
24
|
+
// form — six kinds, most with no config at all, doesn't yet justify a
|
|
25
|
+
// dynamic form-per-kind generator; the field is validated as JSON before
|
|
26
|
+
// save and the request is rejected client-side (with a clear message) if
|
|
27
|
+
// it doesn't parse.
|
|
28
|
+
class CompatibilityRulesComponent extends BaseDirective {
|
|
29
|
+
constructor() {
|
|
30
|
+
super(...arguments);
|
|
31
|
+
this.name = 'compatibility rule';
|
|
32
|
+
this.pluralName = 'compatibility rules';
|
|
33
|
+
this.ruleSource = this.apiService.on('apps/commerce/compatibility-rule');
|
|
34
|
+
this.rules$ = new BehaviorSubject(null);
|
|
35
|
+
this.init = () => {
|
|
36
|
+
this.load();
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
load() {
|
|
40
|
+
this.ruleSource
|
|
41
|
+
.getMany({ page: 1, perPage: 50 })
|
|
42
|
+
.pipe(takeUntil(this.$), map((response) => (response?.data ?? []).map((r) => {
|
|
43
|
+
const expression = r.expression ?? {};
|
|
44
|
+
return {
|
|
45
|
+
id: r.id,
|
|
46
|
+
name: r.name,
|
|
47
|
+
scope: r.scope ?? '',
|
|
48
|
+
kind: expression.kind ?? '—',
|
|
49
|
+
outcome: r.outcome,
|
|
50
|
+
message: r.message,
|
|
51
|
+
enabled: !!r.enabled,
|
|
52
|
+
configText: JSON.stringify(expression.config ?? {}, null, 2),
|
|
53
|
+
saving: false,
|
|
54
|
+
};
|
|
55
|
+
})))
|
|
56
|
+
.subscribe(using((rows) => this.rules$.next(rows)));
|
|
57
|
+
}
|
|
58
|
+
onConfigChange(rule, value) {
|
|
59
|
+
rule.configText = value;
|
|
60
|
+
}
|
|
61
|
+
onEnabledChange(rule, checked) {
|
|
62
|
+
rule.enabled = checked;
|
|
63
|
+
this.save(rule);
|
|
64
|
+
}
|
|
65
|
+
save(rule) {
|
|
66
|
+
let config;
|
|
67
|
+
try {
|
|
68
|
+
config = JSON.parse(rule.configText || '{}');
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
notify(`${rule.name}: config isn't valid JSON — not saved`, 'apps.admin.compatibility-rules.config', 'error');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
rule.saving = true;
|
|
75
|
+
this.ruleSource
|
|
76
|
+
.update(rule.id, {
|
|
77
|
+
enabled: rule.enabled,
|
|
78
|
+
expression: { kind: rule.kind, config },
|
|
79
|
+
})
|
|
80
|
+
.pipe(takeUntil(this.$))
|
|
81
|
+
.subscribe(using(() => {
|
|
82
|
+
rule.saving = false;
|
|
83
|
+
notify(`${rule.name} saved`, 'apps.admin.compatibility-rules.save', 'success');
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: CompatibilityRulesComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
87
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: CompatibilityRulesComponent, isStandalone: false, selector: "x-compatibility-rules", usesInheritance: true, ngImport: i0, template: `
|
|
88
|
+
<div class="x-page-head">
|
|
89
|
+
<div class="x-page-title">Compatibility rules</div>
|
|
90
|
+
<div class="x-page-subtitle">
|
|
91
|
+
CAT-10 — toggle, retitle and tune the rules
|
|
92
|
+
<code>CatalogWorkflow.evaluateCompatibility</code> runs on every
|
|
93
|
+
PDP/cart/kit-builder check. The rule <em>kind</em> is fixed per row;
|
|
94
|
+
see the note in this page's source for why.
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
@if (rules$ | async; as rules) {
|
|
99
|
+
<div class="x-rules-table">
|
|
100
|
+
<div class="x-rules-row x-rules-head">
|
|
101
|
+
<div class="x-rules-col-name">Rule</div>
|
|
102
|
+
<div class="x-rules-col-kind">Kind</div>
|
|
103
|
+
<div class="x-rules-col-outcome">Outcome</div>
|
|
104
|
+
<div class="x-rules-col-config">Config (JSON)</div>
|
|
105
|
+
<div class="x-rules-col-enabled">Enabled</div>
|
|
106
|
+
<div class="x-rules-col-action"></div>
|
|
107
|
+
</div>
|
|
108
|
+
@for (rule of rules; track rule.id) {
|
|
109
|
+
<div class="x-rules-row">
|
|
110
|
+
<div class="x-rules-col-name">
|
|
111
|
+
<div class="x-rule-name">{{ rule.name }}</div>
|
|
112
|
+
<div class="x-rule-scope">{{ rule.scope }}</div>
|
|
113
|
+
<div class="x-rule-message">{{ rule.message }}</div>
|
|
114
|
+
</div>
|
|
115
|
+
<div class="x-rules-col-kind">
|
|
116
|
+
<code>{{ rule.kind }}</code>
|
|
117
|
+
</div>
|
|
118
|
+
<div class="x-rules-col-outcome">
|
|
119
|
+
<span class="x-outcome-badge" [class]="'x-outcome-' + rule.outcome">{{
|
|
120
|
+
rule.outcome
|
|
121
|
+
}}</span>
|
|
122
|
+
</div>
|
|
123
|
+
<div class="x-rules-col-config">
|
|
124
|
+
<textarea
|
|
125
|
+
class="x-config-input"
|
|
126
|
+
rows="2"
|
|
127
|
+
[value]="rule.configText"
|
|
128
|
+
(input)="onConfigChange(rule, $any($event.target).value)"
|
|
129
|
+
></textarea>
|
|
130
|
+
</div>
|
|
131
|
+
<div class="x-rules-col-enabled">
|
|
132
|
+
<label class="x-toggle">
|
|
133
|
+
<input
|
|
134
|
+
type="checkbox"
|
|
135
|
+
[checked]="rule.enabled"
|
|
136
|
+
(change)="onEnabledChange(rule, $any($event.target).checked)"
|
|
137
|
+
/>
|
|
138
|
+
<span></span>
|
|
139
|
+
</label>
|
|
140
|
+
</div>
|
|
141
|
+
<div class="x-rules-col-action">
|
|
142
|
+
<button
|
|
143
|
+
type="button"
|
|
144
|
+
class="x-save-btn"
|
|
145
|
+
[disabled]="rule.saving"
|
|
146
|
+
(click)="save(rule)"
|
|
147
|
+
>
|
|
148
|
+
{{ rule.saving ? 'Saving…' : 'Save' }}
|
|
149
|
+
</button>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
}
|
|
153
|
+
@if (!rules.length) {
|
|
154
|
+
<div class="x-rules-empty">No compatibility rules seeded yet.</div>
|
|
155
|
+
}
|
|
156
|
+
</div>
|
|
157
|
+
} @else {
|
|
158
|
+
<x-element-loader></x-element-loader>
|
|
159
|
+
}
|
|
160
|
+
`, isInline: true, styles: [".x-page-head{margin-bottom:20px}.x-page-title{font-size:24px;font-weight:800;color:var(--color-text)}.x-page-subtitle{font-size:13.5px;color:var(--color-text-muted);margin-top:2px;max-width:640px}.x-rules-table{background:var(--color-surface);border-radius:var(--radius-lg);overflow:hidden}.x-rules-row{display:grid;grid-template-columns:1.8fr 1.2fr .8fr 1.4fr .6fr auto;gap:12px;align-items:start;padding:14px 16px;border-bottom:1px solid var(--color-border-muted)}.x-rules-row:last-child{border-bottom:0}.x-rules-head{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.4px;color:var(--color-text-muted);align-items:center}.x-rule-name{font-size:14px;font-weight:700;color:var(--color-text)}.x-rule-scope{font-family:var(--font-mono);font-size:11px;color:var(--color-text-muted);margin-top:2px}.x-rule-message{font-size:12px;color:var(--color-text-muted);margin-top:4px;line-height:1.4}.x-rules-col-kind code{font-size:11.5px;color:var(--color-text-muted)}.x-outcome-badge{display:inline-block;font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:.3px;padding:2px 8px;border-radius:var(--radius-pill, 999px);border:1px solid var(--color-border);color:var(--color-text-muted)}.x-outcome-block{color:color-mix(in srgb,var(--color-danger) 75%,black);border-color:var(--color-danger)}.x-outcome-warn{color:color-mix(in srgb,var(--color-warn) 70%,black);border-color:var(--color-warn)}.x-outcome-pass{color:color-mix(in srgb,var(--color-success) 70%,black);border-color:var(--color-success)}.x-config-input{width:100%;box-sizing:border-box;padding:6px 8px;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-bg);color:var(--color-text);font-family:var(--font-mono);font-size:11.5px;resize:vertical}.x-toggle{position:relative;display:inline-block;width:34px;height:20px}.x-toggle input{opacity:0;width:0;height:0}.x-toggle span{position:absolute;inset:0;background:var(--color-border);border-radius:999px;transition:background .15s ease}.x-toggle span:before{content:\"\";position:absolute;width:16px;height:16px;left:2px;top:2px;background:var(--color-surface);border-radius:50%;transition:transform .15s ease}.x-toggle input:checked+span{background:var(--color-accent)}.x-toggle input:checked+span:before{transform:translate(14px)}.x-save-btn{background:var(--color-accent);color:var(--color-accent-fg);border:0;border-radius:var(--radius-sm);padding:8px 12px;font-size:12.5px;font-weight:700;cursor:pointer;white-space:nowrap}.x-save-btn:disabled{opacity:.5;cursor:not-allowed}.x-rules-empty{padding:32px 16px;text-align:center;font-size:13px;color:var(--color-text-muted)}\n"], dependencies: [{ kind: "component", type: i1.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] }); }
|
|
161
|
+
}
|
|
162
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: CompatibilityRulesComponent, decorators: [{
|
|
163
|
+
type: Component,
|
|
164
|
+
args: [{ standalone: false, selector: 'x-compatibility-rules', template: `
|
|
165
|
+
<div class="x-page-head">
|
|
166
|
+
<div class="x-page-title">Compatibility rules</div>
|
|
167
|
+
<div class="x-page-subtitle">
|
|
168
|
+
CAT-10 — toggle, retitle and tune the rules
|
|
169
|
+
<code>CatalogWorkflow.evaluateCompatibility</code> runs on every
|
|
170
|
+
PDP/cart/kit-builder check. The rule <em>kind</em> is fixed per row;
|
|
171
|
+
see the note in this page's source for why.
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
|
|
175
|
+
@if (rules$ | async; as rules) {
|
|
176
|
+
<div class="x-rules-table">
|
|
177
|
+
<div class="x-rules-row x-rules-head">
|
|
178
|
+
<div class="x-rules-col-name">Rule</div>
|
|
179
|
+
<div class="x-rules-col-kind">Kind</div>
|
|
180
|
+
<div class="x-rules-col-outcome">Outcome</div>
|
|
181
|
+
<div class="x-rules-col-config">Config (JSON)</div>
|
|
182
|
+
<div class="x-rules-col-enabled">Enabled</div>
|
|
183
|
+
<div class="x-rules-col-action"></div>
|
|
184
|
+
</div>
|
|
185
|
+
@for (rule of rules; track rule.id) {
|
|
186
|
+
<div class="x-rules-row">
|
|
187
|
+
<div class="x-rules-col-name">
|
|
188
|
+
<div class="x-rule-name">{{ rule.name }}</div>
|
|
189
|
+
<div class="x-rule-scope">{{ rule.scope }}</div>
|
|
190
|
+
<div class="x-rule-message">{{ rule.message }}</div>
|
|
191
|
+
</div>
|
|
192
|
+
<div class="x-rules-col-kind">
|
|
193
|
+
<code>{{ rule.kind }}</code>
|
|
194
|
+
</div>
|
|
195
|
+
<div class="x-rules-col-outcome">
|
|
196
|
+
<span class="x-outcome-badge" [class]="'x-outcome-' + rule.outcome">{{
|
|
197
|
+
rule.outcome
|
|
198
|
+
}}</span>
|
|
199
|
+
</div>
|
|
200
|
+
<div class="x-rules-col-config">
|
|
201
|
+
<textarea
|
|
202
|
+
class="x-config-input"
|
|
203
|
+
rows="2"
|
|
204
|
+
[value]="rule.configText"
|
|
205
|
+
(input)="onConfigChange(rule, $any($event.target).value)"
|
|
206
|
+
></textarea>
|
|
207
|
+
</div>
|
|
208
|
+
<div class="x-rules-col-enabled">
|
|
209
|
+
<label class="x-toggle">
|
|
210
|
+
<input
|
|
211
|
+
type="checkbox"
|
|
212
|
+
[checked]="rule.enabled"
|
|
213
|
+
(change)="onEnabledChange(rule, $any($event.target).checked)"
|
|
214
|
+
/>
|
|
215
|
+
<span></span>
|
|
216
|
+
</label>
|
|
217
|
+
</div>
|
|
218
|
+
<div class="x-rules-col-action">
|
|
219
|
+
<button
|
|
220
|
+
type="button"
|
|
221
|
+
class="x-save-btn"
|
|
222
|
+
[disabled]="rule.saving"
|
|
223
|
+
(click)="save(rule)"
|
|
224
|
+
>
|
|
225
|
+
{{ rule.saving ? 'Saving…' : 'Save' }}
|
|
226
|
+
</button>
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
}
|
|
230
|
+
@if (!rules.length) {
|
|
231
|
+
<div class="x-rules-empty">No compatibility rules seeded yet.</div>
|
|
232
|
+
}
|
|
233
|
+
</div>
|
|
234
|
+
} @else {
|
|
235
|
+
<x-element-loader></x-element-loader>
|
|
236
|
+
}
|
|
237
|
+
`, styles: [".x-page-head{margin-bottom:20px}.x-page-title{font-size:24px;font-weight:800;color:var(--color-text)}.x-page-subtitle{font-size:13.5px;color:var(--color-text-muted);margin-top:2px;max-width:640px}.x-rules-table{background:var(--color-surface);border-radius:var(--radius-lg);overflow:hidden}.x-rules-row{display:grid;grid-template-columns:1.8fr 1.2fr .8fr 1.4fr .6fr auto;gap:12px;align-items:start;padding:14px 16px;border-bottom:1px solid var(--color-border-muted)}.x-rules-row:last-child{border-bottom:0}.x-rules-head{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.4px;color:var(--color-text-muted);align-items:center}.x-rule-name{font-size:14px;font-weight:700;color:var(--color-text)}.x-rule-scope{font-family:var(--font-mono);font-size:11px;color:var(--color-text-muted);margin-top:2px}.x-rule-message{font-size:12px;color:var(--color-text-muted);margin-top:4px;line-height:1.4}.x-rules-col-kind code{font-size:11.5px;color:var(--color-text-muted)}.x-outcome-badge{display:inline-block;font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:.3px;padding:2px 8px;border-radius:var(--radius-pill, 999px);border:1px solid var(--color-border);color:var(--color-text-muted)}.x-outcome-block{color:color-mix(in srgb,var(--color-danger) 75%,black);border-color:var(--color-danger)}.x-outcome-warn{color:color-mix(in srgb,var(--color-warn) 70%,black);border-color:var(--color-warn)}.x-outcome-pass{color:color-mix(in srgb,var(--color-success) 70%,black);border-color:var(--color-success)}.x-config-input{width:100%;box-sizing:border-box;padding:6px 8px;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-bg);color:var(--color-text);font-family:var(--font-mono);font-size:11.5px;resize:vertical}.x-toggle{position:relative;display:inline-block;width:34px;height:20px}.x-toggle input{opacity:0;width:0;height:0}.x-toggle span{position:absolute;inset:0;background:var(--color-border);border-radius:999px;transition:background .15s ease}.x-toggle span:before{content:\"\";position:absolute;width:16px;height:16px;left:2px;top:2px;background:var(--color-surface);border-radius:50%;transition:transform .15s ease}.x-toggle input:checked+span{background:var(--color-accent)}.x-toggle input:checked+span:before{transform:translate(14px)}.x-save-btn{background:var(--color-accent);color:var(--color-accent-fg);border:0;border-radius:var(--radius-sm);padding:8px 12px;font-size:12.5px;font-weight:700;cursor:pointer;white-space:nowrap}.x-save-btn:disabled{opacity:.5;cursor:not-allowed}.x-rules-empty{padding:32px 16px;text-align:center;font-size:13px;color:var(--color-text-muted)}\n"] }]
|
|
238
|
+
}] });
|
|
239
|
+
|
|
240
|
+
class CompatibilityRulesModule {
|
|
241
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: CompatibilityRulesModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
242
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: CompatibilityRulesModule, declarations: [CompatibilityRulesComponent], imports: [SharedModule,
|
|
243
|
+
ElementsModule, i1$1.RouterModule] }); }
|
|
244
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: CompatibilityRulesModule, imports: [SharedModule,
|
|
245
|
+
ElementsModule,
|
|
246
|
+
RouterModule.forChild([{ path: '', component: CompatibilityRulesComponent }])] }); }
|
|
247
|
+
}
|
|
248
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: CompatibilityRulesModule, decorators: [{
|
|
249
|
+
type: NgModule,
|
|
250
|
+
args: [{
|
|
251
|
+
declarations: [CompatibilityRulesComponent],
|
|
252
|
+
imports: [
|
|
253
|
+
SharedModule,
|
|
254
|
+
ElementsModule,
|
|
255
|
+
RouterModule.forChild([{ path: '', component: CompatibilityRulesComponent }]),
|
|
256
|
+
],
|
|
257
|
+
}]
|
|
258
|
+
}] });
|
|
259
|
+
|
|
260
|
+
export { CompatibilityRulesModule };
|
|
261
|
+
//# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs.map
|
package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs","sources":["../../../projects/admin/src/lib/pages/compatibility-rules/compatibility-rules.component.ts","../../../projects/admin/src/lib/pages/compatibility-rules/compatibility-rules.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, notify, using } from '@thescaffold/ngx-core';\nimport { BehaviorSubject, takeUntil, map } from 'rxjs';\n\ninterface RuleRowVm {\n id: string;\n name: string;\n scope: string;\n kind: string;\n outcome: string;\n message: string;\n enabled: boolean;\n configText: string;\n saving: boolean;\n}\n\n// P1.16 — CAT-10's \"editable by ops without code\". P1.11 deliberately\n// implements a **fixed, named vocabulary** of rule kinds\n// (`CompatibilityRuleKind`) rather than a generic condition-expression\n// interpreter — see `pkg/catalog-workflow/compatibility.ts`'s own doc\n// comment for why. That architecture decision sets this editor's real\n// shape: ops can toggle a rule on/off, edit its ops-facing message/scope,\n// and tune its `config` (currently only\n// `array_power_vs_inverter_rating`'s `overSizingAllowancePct`) — not\n// build new conditions from scratch. `expression.kind` itself is shown\n// read-only for the same reason: changing it would point the row at a\n// different evaluator with a config shape it doesn't understand.\n//\n// `config` is edited as raw JSON text rather than a bespoke per-kind\n// form — six kinds, most with no config at all, doesn't yet justify a\n// dynamic form-per-kind generator; the field is validated as JSON before\n// save and the request is rejected client-side (with a clear message) if\n// it doesn't parse.\n@Component({\n standalone: false,\n selector: 'x-compatibility-rules',\n template: `\n <div class=\"x-page-head\">\n <div class=\"x-page-title\">Compatibility rules</div>\n <div class=\"x-page-subtitle\">\n CAT-10 — toggle, retitle and tune the rules\n <code>CatalogWorkflow.evaluateCompatibility</code> runs on every\n PDP/cart/kit-builder check. The rule <em>kind</em> is fixed per row;\n see the note in this page's source for why.\n </div>\n </div>\n\n @if (rules$ | async; as rules) {\n <div class=\"x-rules-table\">\n <div class=\"x-rules-row x-rules-head\">\n <div class=\"x-rules-col-name\">Rule</div>\n <div class=\"x-rules-col-kind\">Kind</div>\n <div class=\"x-rules-col-outcome\">Outcome</div>\n <div class=\"x-rules-col-config\">Config (JSON)</div>\n <div class=\"x-rules-col-enabled\">Enabled</div>\n <div class=\"x-rules-col-action\"></div>\n </div>\n @for (rule of rules; track rule.id) {\n <div class=\"x-rules-row\">\n <div class=\"x-rules-col-name\">\n <div class=\"x-rule-name\">{{ rule.name }}</div>\n <div class=\"x-rule-scope\">{{ rule.scope }}</div>\n <div class=\"x-rule-message\">{{ rule.message }}</div>\n </div>\n <div class=\"x-rules-col-kind\">\n <code>{{ rule.kind }}</code>\n </div>\n <div class=\"x-rules-col-outcome\">\n <span class=\"x-outcome-badge\" [class]=\"'x-outcome-' + rule.outcome\">{{\n rule.outcome\n }}</span>\n </div>\n <div class=\"x-rules-col-config\">\n <textarea\n class=\"x-config-input\"\n rows=\"2\"\n [value]=\"rule.configText\"\n (input)=\"onConfigChange(rule, $any($event.target).value)\"\n ></textarea>\n </div>\n <div class=\"x-rules-col-enabled\">\n <label class=\"x-toggle\">\n <input\n type=\"checkbox\"\n [checked]=\"rule.enabled\"\n (change)=\"onEnabledChange(rule, $any($event.target).checked)\"\n />\n <span></span>\n </label>\n </div>\n <div class=\"x-rules-col-action\">\n <button\n type=\"button\"\n class=\"x-save-btn\"\n [disabled]=\"rule.saving\"\n (click)=\"save(rule)\"\n >\n {{ rule.saving ? 'Saving…' : 'Save' }}\n </button>\n </div>\n </div>\n }\n @if (!rules.length) {\n <div class=\"x-rules-empty\">No compatibility rules seeded yet.</div>\n }\n </div>\n } @else {\n <x-element-loader></x-element-loader>\n }\n `,\n styles: [\n `\n .x-page-head {\n margin-bottom: 20px;\n }\n .x-page-title {\n font-size: 24px;\n font-weight: 800;\n color: var(--color-text);\n }\n .x-page-subtitle {\n font-size: 13.5px;\n color: var(--color-text-muted);\n margin-top: 2px;\n max-width: 640px;\n }\n .x-rules-table {\n background: var(--color-surface);\n border-radius: var(--radius-lg);\n overflow: hidden;\n }\n .x-rules-row {\n display: grid;\n grid-template-columns: 1.8fr 1.2fr 0.8fr 1.4fr 0.6fr auto;\n gap: 12px;\n align-items: start;\n padding: 14px 16px;\n border-bottom: 1px solid var(--color-border-muted);\n }\n .x-rules-row:last-child {\n border-bottom: 0;\n }\n .x-rules-head {\n font-size: 11px;\n font-weight: 800;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n color: var(--color-text-muted);\n align-items: center;\n }\n .x-rule-name {\n font-size: 14px;\n font-weight: 700;\n color: var(--color-text);\n }\n .x-rule-scope {\n font-family: var(--font-mono);\n font-size: 11px;\n color: var(--color-text-muted);\n margin-top: 2px;\n }\n .x-rule-message {\n font-size: 12px;\n color: var(--color-text-muted);\n margin-top: 4px;\n line-height: 1.4;\n }\n .x-rules-col-kind code {\n font-size: 11.5px;\n color: var(--color-text-muted);\n }\n .x-outcome-badge {\n display: inline-block;\n font-size: 10.5px;\n font-weight: 800;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n padding: 2px 8px;\n border-radius: var(--radius-pill, 999px);\n border: 1px solid var(--color-border);\n color: var(--color-text-muted);\n }\n .x-outcome-block {\n color: color-mix(in srgb, var(--color-danger) 75%, black);\n border-color: var(--color-danger);\n }\n .x-outcome-warn {\n color: color-mix(in srgb, var(--color-warn) 70%, black);\n border-color: var(--color-warn);\n }\n .x-outcome-pass {\n color: color-mix(in srgb, var(--color-success) 70%, black);\n border-color: var(--color-success);\n }\n .x-config-input {\n width: 100%;\n box-sizing: border-box;\n padding: 6px 8px;\n border-radius: var(--radius-sm);\n border: 1px solid var(--color-border);\n background: var(--color-bg);\n color: var(--color-text);\n font-family: var(--font-mono);\n font-size: 11.5px;\n resize: vertical;\n }\n .x-toggle {\n position: relative;\n display: inline-block;\n width: 34px;\n height: 20px;\n }\n .x-toggle input {\n opacity: 0;\n width: 0;\n height: 0;\n }\n .x-toggle span {\n position: absolute;\n inset: 0;\n background: var(--color-border);\n border-radius: 999px;\n transition: background 0.15s ease;\n }\n .x-toggle span::before {\n content: '';\n position: absolute;\n width: 16px;\n height: 16px;\n left: 2px;\n top: 2px;\n background: var(--color-surface);\n border-radius: 50%;\n transition: transform 0.15s ease;\n }\n .x-toggle input:checked + span {\n background: var(--color-accent);\n }\n .x-toggle input:checked + span::before {\n transform: translateX(14px);\n }\n .x-save-btn {\n background: var(--color-accent);\n color: var(--color-accent-fg);\n border: 0;\n border-radius: var(--radius-sm);\n padding: 8px 12px;\n font-size: 12.5px;\n font-weight: 700;\n cursor: pointer;\n white-space: nowrap;\n }\n .x-save-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n .x-rules-empty {\n padding: 32px 16px;\n text-align: center;\n font-size: 13px;\n color: var(--color-text-muted);\n }\n `,\n ],\n})\nexport class CompatibilityRulesComponent extends BaseDirective {\n name = 'compatibility rule';\n pluralName = 'compatibility rules';\n private readonly ruleSource = this.apiService.on(\n 'apps/commerce/compatibility-rule',\n );\n\n rules$ = new BehaviorSubject<RuleRowVm[] | null>(null);\n\n override init = () => {\n this.load();\n };\n\n load() {\n this.ruleSource\n .getMany({ page: 1, perPage: 50 })\n .pipe(\n takeUntil(this.$),\n map((response: any) =>\n (response?.data ?? []).map((r: any): RuleRowVm => {\n const expression = r.expression ?? {};\n return {\n id: r.id,\n name: r.name,\n scope: r.scope ?? '',\n kind: expression.kind ?? '—',\n outcome: r.outcome,\n message: r.message,\n enabled: !!r.enabled,\n configText: JSON.stringify(expression.config ?? {}, null, 2),\n saving: false,\n };\n }),\n ),\n )\n .subscribe(using((rows) => this.rules$.next(rows)));\n }\n\n onConfigChange(rule: RuleRowVm, value: string) {\n rule.configText = value;\n }\n\n onEnabledChange(rule: RuleRowVm, checked: boolean) {\n rule.enabled = checked;\n this.save(rule);\n }\n\n save(rule: RuleRowVm) {\n let config: Record<string, unknown>;\n try {\n config = JSON.parse(rule.configText || '{}');\n } catch {\n notify(\n `${rule.name}: config isn't valid JSON — not saved`,\n 'apps.admin.compatibility-rules.config',\n 'error',\n );\n return;\n }\n\n rule.saving = true;\n this.ruleSource\n .update(rule.id, {\n enabled: rule.enabled,\n expression: { kind: rule.kind, config },\n } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using(() => {\n rule.saving = false;\n notify(\n `${rule.name} saved`,\n 'apps.admin.compatibility-rules.save',\n 'success',\n );\n }),\n );\n }\n}\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule } from '@thescaffold/ngx-ui';\nimport { CompatibilityRulesComponent } from './compatibility-rules.component';\n\n@NgModule({\n declarations: [CompatibilityRulesComponent],\n imports: [\n SharedModule,\n ElementsModule,\n RouterModule.forChild([{ path: '', component: CompatibilityRulesComponent }]),\n ],\n})\nexport class CompatibilityRulesModule {}\n"],"names":["i1"],"mappings":"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"}
|