@mj-biz-apps/contracts-ng 0.1.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/LICENSE +183 -0
- package/dist/lib/data/entity-names.d.ts +29 -0
- package/dist/lib/data/entity-names.d.ts.map +1 -0
- package/dist/lib/data/entity-names.js +29 -0
- package/dist/lib/data/entity-names.js.map +1 -0
- package/dist/lib/data/provider.d.ts +44 -0
- package/dist/lib/data/provider.d.ts.map +1 -0
- package/dist/lib/data/provider.js +48 -0
- package/dist/lib/data/provider.js.map +1 -0
- package/dist/lib/directives/fk-navigate.directive.d.ts +63 -0
- package/dist/lib/directives/fk-navigate.directive.d.ts.map +1 -0
- package/dist/lib/directives/fk-navigate.directive.js +99 -0
- package/dist/lib/directives/fk-navigate.directive.js.map +1 -0
- package/dist/lib/form-panels/contract.panels.d.ts +124 -0
- package/dist/lib/form-panels/contract.panels.d.ts.map +1 -0
- package/dist/lib/form-panels/contract.panels.js +1167 -0
- package/dist/lib/form-panels/contract.panels.js.map +1 -0
- package/dist/lib/form-panels/organization.panels.d.ts +23 -0
- package/dist/lib/form-panels/organization.panels.d.ts.map +1 -0
- package/dist/lib/form-panels/organization.panels.js +118 -0
- package/dist/lib/form-panels/organization.panels.js.map +1 -0
- package/dist/lib/form-panels/record-files.panel.d.ts +151 -0
- package/dist/lib/form-panels/record-files.panel.d.ts.map +1 -0
- package/dist/lib/form-panels/record-files.panel.js +1046 -0
- package/dist/lib/form-panels/record-files.panel.js.map +1 -0
- package/dist/lib/form-panels/supersede.panel.d.ts +68 -0
- package/dist/lib/form-panels/supersede.panel.d.ts.map +1 -0
- package/dist/lib/form-panels/supersede.panel.js +415 -0
- package/dist/lib/form-panels/supersede.panel.js.map +1 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContract/mjbizappscontractscontract.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContract/mjbizappscontractscontract.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContract/mjbizappscontractscontract.form.component.js +196 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContract/mjbizappscontractscontract.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplate/mjbizappscontractscontracttemplate.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplate/mjbizappscontractscontracttemplate.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplate/mjbizappscontractscontracttemplate.form.component.js +120 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplate/mjbizappscontractscontracttemplate.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplateModification/mjbizappscontractscontracttemplatemodification.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplateModification/mjbizappscontractscontracttemplatemodification.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplateModification/mjbizappscontractscontracttemplatemodification.form.component.js +79 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplateModification/mjbizappscontractscontracttemplatemodification.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplateProvision/mjbizappscontractscontracttemplateprovision.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplateProvision/mjbizappscontractscontracttemplateprovision.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplateProvision/mjbizappscontractscontracttemplateprovision.form.component.js +79 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplateProvision/mjbizappscontractscontracttemplateprovision.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplateType/mjbizappscontractscontracttemplatetype.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplateType/mjbizappscontractscontracttemplatetype.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplateType/mjbizappscontractscontracttemplatetype.form.component.js +86 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractTemplateType/mjbizappscontractscontracttemplatetype.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractType/mjbizappscontractscontracttype.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractType/mjbizappscontractscontracttype.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractType/mjbizappscontractscontracttype.form.component.js +100 -0
- package/dist/lib/generated/Entities/mjBizAppsContractsContractType/mjbizappscontractscontracttype.form.component.js.map +1 -0
- package/dist/lib/generated/generated-forms.module.d.ts +23 -0
- package/dist/lib/generated/generated-forms.module.d.ts.map +1 -0
- package/dist/lib/generated/generated-forms.module.js +78 -0
- package/dist/lib/generated/generated-forms.module.js.map +1 -0
- package/dist/lib/pages/configuration.page.d.ts +83 -0
- package/dist/lib/pages/configuration.page.d.ts.map +1 -0
- package/dist/lib/pages/configuration.page.js +240 -0
- package/dist/lib/pages/configuration.page.js.map +1 -0
- package/dist/lib/pages/contract-grid.page.d.ts +169 -0
- package/dist/lib/pages/contract-grid.page.d.ts.map +1 -0
- package/dist/lib/pages/contract-grid.page.js +487 -0
- package/dist/lib/pages/contract-grid.page.js.map +1 -0
- package/dist/lib/pages/contracts-dashboard.page.d.ts +56 -0
- package/dist/lib/pages/contracts-dashboard.page.d.ts.map +1 -0
- package/dist/lib/pages/contracts-dashboard.page.js +215 -0
- package/dist/lib/pages/contracts-dashboard.page.js.map +1 -0
- package/dist/lib/pages/modifications.page.d.ts +96 -0
- package/dist/lib/pages/modifications.page.d.ts.map +1 -0
- package/dist/lib/pages/modifications.page.js +243 -0
- package/dist/lib/pages/modifications.page.js.map +1 -0
- package/dist/lib/pages/templates.page.d.ts +120 -0
- package/dist/lib/pages/templates.page.d.ts.map +1 -0
- package/dist/lib/pages/templates.page.js +258 -0
- package/dist/lib/pages/templates.page.js.map +1 -0
- package/dist/lib/sections/contracts-sections.component.d.ts +112 -0
- package/dist/lib/sections/contracts-sections.component.d.ts.map +1 -0
- package/dist/lib/sections/contracts-sections.component.js +412 -0
- package/dist/lib/sections/contracts-sections.component.js.map +1 -0
- package/dist/lib/sections/section-nav.model.d.ts +78 -0
- package/dist/lib/sections/section-nav.model.d.ts.map +1 -0
- package/dist/lib/sections/section-nav.model.js +110 -0
- package/dist/lib/sections/section-nav.model.js.map +1 -0
- package/dist/lib/sections/section-shell.component.d.ts +73 -0
- package/dist/lib/sections/section-shell.component.d.ts.map +1 -0
- package/dist/lib/sections/section-shell.component.js +170 -0
- package/dist/lib/sections/section-shell.component.js.map +1 -0
- package/dist/public-api.d.ts +44 -0
- package/dist/public-api.d.ts.map +1 -0
- package/dist/public-api.js +105 -0
- package/dist/public-api.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The Contracts dashboard — "what needs attention", not "how are we doing".
|
|
3
|
+
*
|
|
4
|
+
* DELIBERATELY NOT A CHART. This app tracks obligations; the useful question on opening it is which
|
|
5
|
+
* agreements need a person this quarter, and the honest answer is four numbers and the lists behind
|
|
6
|
+
* them. A revenue chart would be a chart about orders' data drawn on contracts' screen, and it would
|
|
7
|
+
* invite reading it as authoritative about money — which contracts explicitly is not (plan §1).
|
|
8
|
+
*
|
|
9
|
+
* Every number is a count over the layered base view's DERIVED columns, so the dashboard cannot
|
|
10
|
+
* disagree with the worklists: both read `IsAwaitingDocument`, `RenewalNoticeDeadline` and `State`
|
|
11
|
+
* from the same view. A dashboard computing its own version of "expiring soon" is how a summary and a
|
|
12
|
+
* worklist end up giving different answers to the same question.
|
|
13
|
+
*
|
|
14
|
+
* @module @mj-biz-apps/contracts-ng
|
|
15
|
+
*/
|
|
16
|
+
import { ChangeDetectorRef, Component, EventEmitter, Output, ViewEncapsulation, inject } from '@angular/core';
|
|
17
|
+
import { CommonModule } from '@angular/common';
|
|
18
|
+
import { MJC_ENTITIES } from '../data/entity-names';
|
|
19
|
+
import { ScopedRunView } from '../data/provider';
|
|
20
|
+
import * as i0 from "@angular/core";
|
|
21
|
+
const _forTrack0 = ($index, $item) => $item.Id;
|
|
22
|
+
function MJCContractsDashboardPageComponent_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
23
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
24
|
+
i0.ɵɵdomElementStart(0, "button", 7);
|
|
25
|
+
i0.ɵɵdomListener("click", function MJCContractsDashboardPageComponent_For_5_Template_button_click_0_listener() { const tile_r2 = i0.ɵɵrestoreView(_r1).$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.Open(tile_r2)); });
|
|
26
|
+
i0.ɵɵtext(1);
|
|
27
|
+
i0.ɵɵdomElementStart(2, "span", 8);
|
|
28
|
+
i0.ɵɵtext(3);
|
|
29
|
+
i0.ɵɵdomElementEnd()();
|
|
30
|
+
} if (rf & 2) {
|
|
31
|
+
const tile_r2 = ctx.$implicit;
|
|
32
|
+
i0.ɵɵclassProp("mjc-pill--active", tile_r2.Count !== null && tile_r2.Count > 0);
|
|
33
|
+
i0.ɵɵdomProperty("title", tile_r2.Hint)("disabled", !tile_r2.GoTo);
|
|
34
|
+
i0.ɵɵadvance();
|
|
35
|
+
i0.ɵɵtextInterpolate1(" ", tile_r2.Label, " ");
|
|
36
|
+
i0.ɵɵadvance(2);
|
|
37
|
+
i0.ɵɵtextInterpolate(tile_r2.Count === null ? "\u2014" : tile_r2.Count);
|
|
38
|
+
} }
|
|
39
|
+
function MJCContractsDashboardPageComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
40
|
+
i0.ɵɵdomElementStart(0, "p", 4);
|
|
41
|
+
i0.ɵɵtext(1);
|
|
42
|
+
i0.ɵɵdomElementEnd();
|
|
43
|
+
} if (rf & 2) {
|
|
44
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
45
|
+
i0.ɵɵadvance();
|
|
46
|
+
i0.ɵɵtextInterpolate(ctx_r2.LoadError);
|
|
47
|
+
} }
|
|
48
|
+
export class MJCContractsDashboardPageComponent {
|
|
49
|
+
cdr = inject(ChangeDetectorRef);
|
|
50
|
+
/** Asks the host section to switch rail pages. The dashboard does not route itself. */
|
|
51
|
+
NavigateToPage = new EventEmitter();
|
|
52
|
+
LoadError = null;
|
|
53
|
+
/**
|
|
54
|
+
* The four questions worth answering on open, in priority order.
|
|
55
|
+
*
|
|
56
|
+
* "In force without paper" leads because it is the only one that is both an obligation we are
|
|
57
|
+
* already performing and a document we cannot produce — the combination that hurts in a dispute.
|
|
58
|
+
*/
|
|
59
|
+
Tiles = [
|
|
60
|
+
{
|
|
61
|
+
Id: 'in-force-no-paper',
|
|
62
|
+
Label: 'In force without paper',
|
|
63
|
+
Hint: 'Active contracts whose type expects an executed document, with none attached',
|
|
64
|
+
Filter: `State = 'Active' AND IsAwaitingDocument = 1`,
|
|
65
|
+
GoTo: 'awaiting',
|
|
66
|
+
Count: null,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
Id: 'notice-window',
|
|
70
|
+
Label: 'Notice window closing (60 days)',
|
|
71
|
+
Hint: 'The renewal-notice deadline falls within 60 days and has not passed',
|
|
72
|
+
Filter: 'RenewalNoticeDeadline IS NOT NULL ' +
|
|
73
|
+
'AND RenewalNoticeDeadline >= CAST(GETUTCDATE() AS date) ' +
|
|
74
|
+
'AND RenewalNoticeDeadline <= DATEADD(day, 60, CAST(GETUTCDATE() AS date))',
|
|
75
|
+
GoTo: 'renewals',
|
|
76
|
+
Count: null,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
Id: 'ends-120',
|
|
80
|
+
Label: 'Ends within 120 days',
|
|
81
|
+
Hint: 'The quarter-ahead view — renew, re-paper or let expire',
|
|
82
|
+
Filter: 'DaysToEnd IS NOT NULL AND DaysToEnd BETWEEN 0 AND 120',
|
|
83
|
+
GoTo: 'renewals',
|
|
84
|
+
Count: null,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
Id: 'signed-not-started',
|
|
88
|
+
Label: 'Signed, not yet in force',
|
|
89
|
+
Hint: 'Executed with a future effective date — nothing to do until the date arrives',
|
|
90
|
+
Filter: `State = 'Executed'`,
|
|
91
|
+
GoTo: 'list',
|
|
92
|
+
Count: null,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
Id: 'modified',
|
|
96
|
+
Label: 'Modified agreements',
|
|
97
|
+
Hint: 'Carry at least one recorded deviation from the standard terms',
|
|
98
|
+
Filter: 'HasModifications = 1',
|
|
99
|
+
GoTo: 'modifications',
|
|
100
|
+
Count: null,
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
ngOnInit() {
|
|
104
|
+
void this.refresh();
|
|
105
|
+
}
|
|
106
|
+
Open(tile) {
|
|
107
|
+
if (tile.GoTo)
|
|
108
|
+
this.NavigateToPage.emit(tile.GoTo);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Count every tile concurrently.
|
|
112
|
+
*
|
|
113
|
+
* `MaxRows: 1` and read `TotalRowCount` — the count comes back without transferring rows. A tile
|
|
114
|
+
* whose query fails shows an em dash rather than a zero: "we do not know" and "there are none" are
|
|
115
|
+
* different answers, and showing 0 for the first is the kind of quiet lie a dashboard should never
|
|
116
|
+
* tell. One shared error line explains it once rather than five times.
|
|
117
|
+
*/
|
|
118
|
+
async refresh() {
|
|
119
|
+
const rv = ScopedRunView();
|
|
120
|
+
let failures = 0;
|
|
121
|
+
await Promise.all(this.Tiles.map(async (tile) => {
|
|
122
|
+
try {
|
|
123
|
+
const result = await rv.RunView({
|
|
124
|
+
EntityName: MJC_ENTITIES.Contract,
|
|
125
|
+
ExtraFilter: tile.Filter,
|
|
126
|
+
MaxRows: 1,
|
|
127
|
+
});
|
|
128
|
+
tile.Count = result?.TotalRowCount ?? 0;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
tile.Count = null;
|
|
132
|
+
failures += 1;
|
|
133
|
+
}
|
|
134
|
+
}));
|
|
135
|
+
this.LoadError = failures
|
|
136
|
+
? `${failures} of ${this.Tiles.length} counts could not be read — the tiles showing “—” are unknown, not zero.`
|
|
137
|
+
: null;
|
|
138
|
+
this.cdr.detectChanges();
|
|
139
|
+
}
|
|
140
|
+
static ɵfac = function MJCContractsDashboardPageComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJCContractsDashboardPageComponent)(); };
|
|
141
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJCContractsDashboardPageComponent, selectors: [["mjc-contracts-dashboard-page"]], outputs: { NavigateToPage: "NavigateToPage" }, decls: 15, vars: 1, consts: [[1, "mjc-page"], [1, "mjc-page__intro"], [1, "mjc-pills"], ["type", "button", 1, "mjc-pill", 3, "mjc-pill--active", "title", "disabled"], [1, "mjc-empty"], [1, "mjc-card"], [1, "mjc-card__title"], ["type", "button", 1, "mjc-pill", 3, "click", "title", "disabled"], [1, "mjc-pill__count"]], template: function MJCContractsDashboardPageComponent_Template(rf, ctx) { if (rf & 1) {
|
|
142
|
+
i0.ɵɵdomElementStart(0, "div", 0)(1, "p", 1);
|
|
143
|
+
i0.ɵɵtext(2, " What needs a person. Every number below is counted from the same view the worklists read, so this page and those pages cannot disagree. ");
|
|
144
|
+
i0.ɵɵdomElementEnd();
|
|
145
|
+
i0.ɵɵdomElementStart(3, "div", 2);
|
|
146
|
+
i0.ɵɵrepeaterCreate(4, MJCContractsDashboardPageComponent_For_5_Template, 4, 6, "button", 3, _forTrack0);
|
|
147
|
+
i0.ɵɵdomElementEnd();
|
|
148
|
+
i0.ɵɵconditionalCreate(6, MJCContractsDashboardPageComponent_Conditional_6_Template, 2, 1, "p", 4);
|
|
149
|
+
i0.ɵɵdomElementStart(7, "div", 5)(8, "h3", 6);
|
|
150
|
+
i0.ɵɵtext(9, "What this app is, and is not");
|
|
151
|
+
i0.ɵɵdomElementEnd();
|
|
152
|
+
i0.ɵɵdomElementStart(10, "p", 1);
|
|
153
|
+
i0.ɵɵtext(11, " Contracts is the record of ");
|
|
154
|
+
i0.ɵɵdomElementStart(12, "strong");
|
|
155
|
+
i0.ɵɵtext(13, "what we agreed");
|
|
156
|
+
i0.ɵɵdomElementEnd();
|
|
157
|
+
i0.ɵɵtext(14, ": the agreement, the standard terms it incorporates, the provisions negotiated away from those terms, and the executed paper. It does not bill and it does not price \u2014 orders does that, and a number here is never a number about money owed. ");
|
|
158
|
+
i0.ɵɵdomElementEnd()()();
|
|
159
|
+
} if (rf & 2) {
|
|
160
|
+
i0.ɵɵadvance(4);
|
|
161
|
+
i0.ɵɵrepeater(ctx.Tiles);
|
|
162
|
+
i0.ɵɵadvance(2);
|
|
163
|
+
i0.ɵɵconditional(ctx.LoadError ? 6 : -1);
|
|
164
|
+
} }, dependencies: [CommonModule], encapsulation: 2 });
|
|
165
|
+
}
|
|
166
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJCContractsDashboardPageComponent, [{
|
|
167
|
+
type: Component,
|
|
168
|
+
args: [{
|
|
169
|
+
selector: 'mjc-contracts-dashboard-page',
|
|
170
|
+
standalone: true,
|
|
171
|
+
encapsulation: ViewEncapsulation.None,
|
|
172
|
+
imports: [CommonModule],
|
|
173
|
+
template: `
|
|
174
|
+
<div class="mjc-page">
|
|
175
|
+
<p class="mjc-page__intro">
|
|
176
|
+
What needs a person. Every number below is counted from the same view the worklists read,
|
|
177
|
+
so this page and those pages cannot disagree.
|
|
178
|
+
</p>
|
|
179
|
+
|
|
180
|
+
<div class="mjc-pills">
|
|
181
|
+
@for (tile of Tiles; track tile.Id) {
|
|
182
|
+
<button
|
|
183
|
+
type="button"
|
|
184
|
+
class="mjc-pill"
|
|
185
|
+
[class.mjc-pill--active]="tile.Count !== null && tile.Count > 0"
|
|
186
|
+
[title]="tile.Hint"
|
|
187
|
+
[disabled]="!tile.GoTo"
|
|
188
|
+
(click)="Open(tile)">
|
|
189
|
+
{{ tile.Label }}
|
|
190
|
+
<span class="mjc-pill__count">{{ tile.Count === null ? '—' : tile.Count }}</span>
|
|
191
|
+
</button>
|
|
192
|
+
}
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
@if (LoadError) {
|
|
196
|
+
<p class="mjc-empty">{{ LoadError }}</p>
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
<div class="mjc-card">
|
|
200
|
+
<h3 class="mjc-card__title">What this app is, and is not</h3>
|
|
201
|
+
<p class="mjc-page__intro">
|
|
202
|
+
Contracts is the record of <strong>what we agreed</strong>: the agreement, the standard
|
|
203
|
+
terms it incorporates, the provisions negotiated away from those terms, and the
|
|
204
|
+
executed paper. It does not bill and it does not price — orders does that, and a number
|
|
205
|
+
here is never a number about money owed.
|
|
206
|
+
</p>
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
`,
|
|
210
|
+
}]
|
|
211
|
+
}], null, { NavigateToPage: [{
|
|
212
|
+
type: Output
|
|
213
|
+
}] }); })();
|
|
214
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJCContractsDashboardPageComponent, { className: "MJCContractsDashboardPageComponent", filePath: "lib/pages/contracts-dashboard.page.ts", lineNumber: 76 }); })();
|
|
215
|
+
//# sourceMappingURL=contracts-dashboard.page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contracts-dashboard.page.js","sourceRoot":"","sources":["../../../src/lib/pages/contracts-dashboard.page.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Every recorded deviation, across all contracts.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS IS A PAGE AT ALL. A modification is normally read on its contract, in the editor panel. But
|
|
5
|
+
* "which clauses do we keep negotiating away?" is a question about the PROVISION, not about any one
|
|
6
|
+
* contract, and it is the question that tells the business its standard terms need changing. That
|
|
7
|
+
* question has no home on a contract form.
|
|
8
|
+
*
|
|
9
|
+
* It is a rail item under Contracts rather than its own section because it is a way of READING
|
|
10
|
+
* contracts, not a separate job.
|
|
11
|
+
*
|
|
12
|
+
* The grid selects the modification entity's base view, so `Contract`, `ContractTemplateProvision` and
|
|
13
|
+
* their name columns render as names rather than UUIDs (D-23) — a grid of modification rows showing
|
|
14
|
+
* three UUIDs would be unreadable, and this is the surface that proves the rule earns its keep.
|
|
15
|
+
*
|
|
16
|
+
* @module @mj-biz-apps/contracts-ng
|
|
17
|
+
*/
|
|
18
|
+
import { OnInit } from '@angular/core';
|
|
19
|
+
import { NavigationService } from '@memberjunction/ng-shared';
|
|
20
|
+
import type { CompositeKey } from '@memberjunction/core';
|
|
21
|
+
import type { RunViewParams } from '@memberjunction/core';
|
|
22
|
+
import * as i0 from "@angular/core";
|
|
23
|
+
/** One provision and how often it has been modified. */
|
|
24
|
+
interface ProvisionTally {
|
|
25
|
+
ProvisionID: string;
|
|
26
|
+
Label: string;
|
|
27
|
+
Count: number;
|
|
28
|
+
}
|
|
29
|
+
export declare class MJCModificationsPageComponent implements OnInit {
|
|
30
|
+
private readonly cdr;
|
|
31
|
+
protected readonly navigation: NavigationService;
|
|
32
|
+
/**
|
|
33
|
+
* Open the double-clicked record.
|
|
34
|
+
*
|
|
35
|
+
* THE GRID DOES NOT NAVIGATE ITSELF. `NavigateOnDoubleClick` only controls whether it EMITS
|
|
36
|
+
* `Navigate`; acting on it is the HOST's job. Without this, a double-click merely selected the row
|
|
37
|
+
* — measured in a real browser, where it looked exactly like the grid being broken. Explorer's own
|
|
38
|
+
* host wires this for generated forms; a page hosting the grid inside a BaseResourceComponent must
|
|
39
|
+
* do it itself.
|
|
40
|
+
*/
|
|
41
|
+
OnNavigate(event: {
|
|
42
|
+
Kind?: string;
|
|
43
|
+
EntityName?: string;
|
|
44
|
+
PrimaryKey?: CompositeKey;
|
|
45
|
+
DefaultValues?: Record<string, unknown>;
|
|
46
|
+
}): void;
|
|
47
|
+
Params: RunViewParams | null;
|
|
48
|
+
TopProvisions: ProvisionTally[];
|
|
49
|
+
ActiveProvisionID: string | null;
|
|
50
|
+
/**
|
|
51
|
+
* Toolbar affordances that actually work, and one that does not.
|
|
52
|
+
*
|
|
53
|
+
* ⚠ `showFilterToggle` IS A NO-OP, and this comment used to claim the opposite. It is declared on
|
|
54
|
+
* `GridToolbarConfig` (`grid-types.ts:249`) and documented in the entity-viewer README, and it is
|
|
55
|
+
* **read nowhere in MJ** — no template branch renders a filter button. Three sibling hooks are dead
|
|
56
|
+
* the same way: the `AllowColumnFilters` input stores `_allowColumnFilters` and nothing reads it,
|
|
57
|
+
* `_filterState` is declared and never touched, and `defaultColDef.filter` is hardcoded `false`, so
|
|
58
|
+
* AG Grid's per-column filters are off with no input to turn them on. It is left set to `true` here
|
|
59
|
+
* because it costs nothing and is the flag to keep passing if MJ ever wires it up.
|
|
60
|
+
*
|
|
61
|
+
* So the ONLY filtering this page has beyond the pills is `showSearch` — which sets AG Grid's
|
|
62
|
+
* `quickFilterText`, a client-side substring match over the rows already loaded. It is not
|
|
63
|
+
* structured and not server-side. Filtering by date range / category / derived State needs a real
|
|
64
|
+
* filter popover (see `design-docs/ui-design/mockups-v2/renewal-watchlist.html`), which is ours to
|
|
65
|
+
* build; the pills stay regardless, because they encode the QUESTIONS people ask rather than
|
|
66
|
+
* predicates a user would assemble by hand.
|
|
67
|
+
*/
|
|
68
|
+
readonly GridToolbar: {
|
|
69
|
+
showSearch: boolean;
|
|
70
|
+
showFilterToggle: boolean;
|
|
71
|
+
showColumnChooser: boolean;
|
|
72
|
+
showRefresh: boolean;
|
|
73
|
+
showExport: boolean;
|
|
74
|
+
showRowCount: boolean;
|
|
75
|
+
};
|
|
76
|
+
ngOnInit(): void;
|
|
77
|
+
/** Clicking the active provision clears the filter — the way back to everything. */
|
|
78
|
+
FilterByProvision(provisionID: string): void;
|
|
79
|
+
private rebuild;
|
|
80
|
+
/**
|
|
81
|
+
* Count modifications per provision, client-side.
|
|
82
|
+
*
|
|
83
|
+
* `RunView` has no GROUP BY, so this reads the rows and tallies them in memory. That is honest at
|
|
84
|
+
* this scale — a modification is a rare, human-authored record, so the whole table is hundreds of
|
|
85
|
+
* rows for years — and it avoids adding an entity or a stored procedure for a single panel. If it
|
|
86
|
+
* ever grows past a few thousand, the right answer is an MJ Query with real SQL, not a bigger loop
|
|
87
|
+
* here; that swap is why the tally is isolated in this method.
|
|
88
|
+
*
|
|
89
|
+
* Failure is swallowed to an empty list: the panel is an aid, and the grid below it is the page.
|
|
90
|
+
*/
|
|
91
|
+
private loadTally;
|
|
92
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<MJCModificationsPageComponent, never>;
|
|
93
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<MJCModificationsPageComponent, "mjc-modifications-page", never, {}, {}, never, never, true, never>;
|
|
94
|
+
}
|
|
95
|
+
export {};
|
|
96
|
+
//# sourceMappingURL=modifications.page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modifications.page.d.ts","sourceRoot":"","sources":["../../../src/lib/pages/modifications.page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAgC,MAAM,EAA6B,MAAM,eAAe,CAAC;AAEhG,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;;AAM1D,wDAAwD;AACxD,UAAU,cAAc;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,qBA6Ca,6BAA8B,YAAW,MAAM;IACxD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IACjD,SAAS,CAAC,QAAQ,CAAC,UAAU,oBAA6B;IAE1D;;;;;;;;OAQG;IACI,UAAU,CAAC,KAAK,EAAE;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,YAAY,CAAC;QAC1B,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC3C,GAAG,IAAI;IAsBD,MAAM,EAAE,aAAa,GAAG,IAAI,CAAQ;IACpC,aAAa,EAAE,cAAc,EAAE,CAAM;IACrC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE/C;;;;;;;;;;;;;;;;;OAiBG;IACH,SAAgB,WAAW;;;;;;;MAOzB;IAGK,QAAQ,IAAI,IAAI;IAKvB,oFAAoF;IAC7E,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAKnD,OAAO,CAAC,OAAO;IASf;;;;;;;;;;OAUG;YACW,SAAS;yCAvGd,6BAA6B;2CAA7B,6BAA6B;CAmIzC"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Every recorded deviation, across all contracts.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS IS A PAGE AT ALL. A modification is normally read on its contract, in the editor panel. But
|
|
5
|
+
* "which clauses do we keep negotiating away?" is a question about the PROVISION, not about any one
|
|
6
|
+
* contract, and it is the question that tells the business its standard terms need changing. That
|
|
7
|
+
* question has no home on a contract form.
|
|
8
|
+
*
|
|
9
|
+
* It is a rail item under Contracts rather than its own section because it is a way of READING
|
|
10
|
+
* contracts, not a separate job.
|
|
11
|
+
*
|
|
12
|
+
* The grid selects the modification entity's base view, so `Contract`, `ContractTemplateProvision` and
|
|
13
|
+
* their name columns render as names rather than UUIDs (D-23) — a grid of modification rows showing
|
|
14
|
+
* three UUIDs would be unreadable, and this is the surface that proves the rule earns its keep.
|
|
15
|
+
*
|
|
16
|
+
* @module @mj-biz-apps/contracts-ng
|
|
17
|
+
*/
|
|
18
|
+
import { ChangeDetectorRef, Component, ViewEncapsulation, inject } from '@angular/core';
|
|
19
|
+
import { CommonModule } from '@angular/common';
|
|
20
|
+
import { NavigationService } from '@memberjunction/ng-shared';
|
|
21
|
+
import { BaseFormsModule } from '@memberjunction/ng-base-forms';
|
|
22
|
+
import { MJC_ENTITIES } from '../data/entity-names';
|
|
23
|
+
import { ScopedRunView } from '../data/provider';
|
|
24
|
+
import { MJCFkNavigateDirective } from '../directives/fk-navigate.directive';
|
|
25
|
+
import * as i0 from "@angular/core";
|
|
26
|
+
import * as i1 from "@memberjunction/ng-base-forms";
|
|
27
|
+
const _forTrack0 = ($index, $item) => $item.ProvisionID;
|
|
28
|
+
function MJCModificationsPageComponent_Conditional_3_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
29
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
30
|
+
i0.ɵɵelementStart(0, "button", 8);
|
|
31
|
+
i0.ɵɵlistener("click", function MJCModificationsPageComponent_Conditional_3_For_5_Template_button_click_0_listener() { const t_r2 = i0.ɵɵrestoreView(_r1).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.FilterByProvision(t_r2.ProvisionID)); });
|
|
32
|
+
i0.ɵɵtext(1);
|
|
33
|
+
i0.ɵɵelementStart(2, "span", 9);
|
|
34
|
+
i0.ɵɵtext(3);
|
|
35
|
+
i0.ɵɵelementEnd()();
|
|
36
|
+
} if (rf & 2) {
|
|
37
|
+
const t_r2 = ctx.$implicit;
|
|
38
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
39
|
+
i0.ɵɵclassProp("mjc-pill--active", t_r2.ProvisionID === ctx_r2.ActiveProvisionID);
|
|
40
|
+
i0.ɵɵattribute("aria-pressed", t_r2.ProvisionID === ctx_r2.ActiveProvisionID);
|
|
41
|
+
i0.ɵɵadvance();
|
|
42
|
+
i0.ɵɵtextInterpolate1(" ", t_r2.Label, " ");
|
|
43
|
+
i0.ɵɵadvance(2);
|
|
44
|
+
i0.ɵɵtextInterpolate(t_r2.Count);
|
|
45
|
+
} }
|
|
46
|
+
function MJCModificationsPageComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
47
|
+
i0.ɵɵelementStart(0, "div", 2)(1, "h3", 5);
|
|
48
|
+
i0.ɵɵtext(2, "Most-modified provisions");
|
|
49
|
+
i0.ɵɵelementEnd();
|
|
50
|
+
i0.ɵɵelementStart(3, "div", 6);
|
|
51
|
+
i0.ɵɵrepeaterCreate(4, MJCModificationsPageComponent_Conditional_3_For_5_Template, 4, 5, "button", 7, _forTrack0);
|
|
52
|
+
i0.ɵɵelementEnd()();
|
|
53
|
+
} if (rf & 2) {
|
|
54
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
55
|
+
i0.ɵɵadvance(4);
|
|
56
|
+
i0.ɵɵrepeater(ctx_r2.TopProvisions);
|
|
57
|
+
} }
|
|
58
|
+
export class MJCModificationsPageComponent {
|
|
59
|
+
cdr = inject(ChangeDetectorRef);
|
|
60
|
+
navigation = inject(NavigationService);
|
|
61
|
+
/**
|
|
62
|
+
* Open the double-clicked record.
|
|
63
|
+
*
|
|
64
|
+
* THE GRID DOES NOT NAVIGATE ITSELF. `NavigateOnDoubleClick` only controls whether it EMITS
|
|
65
|
+
* `Navigate`; acting on it is the HOST's job. Without this, a double-click merely selected the row
|
|
66
|
+
* — measured in a real browser, where it looked exactly like the grid being broken. Explorer's own
|
|
67
|
+
* host wires this for generated forms; a page hosting the grid inside a BaseResourceComponent must
|
|
68
|
+
* do it itself.
|
|
69
|
+
*/
|
|
70
|
+
OnNavigate(event) {
|
|
71
|
+
if (!event?.EntityName)
|
|
72
|
+
return;
|
|
73
|
+
if (event.Kind === 'record' && event.PrimaryKey) {
|
|
74
|
+
this.navigation.OpenEntityRecord(event.EntityName, event.PrimaryKey);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (event.Kind === 'new-record') {
|
|
78
|
+
// TWO kinds, and missing this one meant the toolbar's New button did NOTHING on every grid
|
|
79
|
+
// page — found in the browser, after the double-click bug had already taught me the same
|
|
80
|
+
// lesson about this component. Handling only 'record' silently dropped it.
|
|
81
|
+
//
|
|
82
|
+
// ⚠ `event.DefaultValues` is DISCARDED here, and it has nowhere to go: NavigationOptions
|
|
83
|
+
// carries no default-values field, so `OpenNewEntityRecord` cannot pre-populate. Harmless on
|
|
84
|
+
// these pages (nothing sets NewRecordValues), but it means the Organization agreements
|
|
85
|
+
// panel's pre-linking to the customer will NOT survive a New click routed through here —
|
|
86
|
+
// that panel needs its own affordance, or MJ needs the option. Written down rather than
|
|
87
|
+
// discovered later as "New forgets the customer".
|
|
88
|
+
this.navigation.OpenNewEntityRecord(event.EntityName);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
Params = null;
|
|
92
|
+
TopProvisions = [];
|
|
93
|
+
ActiveProvisionID = null;
|
|
94
|
+
/**
|
|
95
|
+
* Toolbar affordances that actually work, and one that does not.
|
|
96
|
+
*
|
|
97
|
+
* ⚠ `showFilterToggle` IS A NO-OP, and this comment used to claim the opposite. It is declared on
|
|
98
|
+
* `GridToolbarConfig` (`grid-types.ts:249`) and documented in the entity-viewer README, and it is
|
|
99
|
+
* **read nowhere in MJ** — no template branch renders a filter button. Three sibling hooks are dead
|
|
100
|
+
* the same way: the `AllowColumnFilters` input stores `_allowColumnFilters` and nothing reads it,
|
|
101
|
+
* `_filterState` is declared and never touched, and `defaultColDef.filter` is hardcoded `false`, so
|
|
102
|
+
* AG Grid's per-column filters are off with no input to turn them on. It is left set to `true` here
|
|
103
|
+
* because it costs nothing and is the flag to keep passing if MJ ever wires it up.
|
|
104
|
+
*
|
|
105
|
+
* So the ONLY filtering this page has beyond the pills is `showSearch` — which sets AG Grid's
|
|
106
|
+
* `quickFilterText`, a client-side substring match over the rows already loaded. It is not
|
|
107
|
+
* structured and not server-side. Filtering by date range / category / derived State needs a real
|
|
108
|
+
* filter popover (see `design-docs/ui-design/mockups-v2/renewal-watchlist.html`), which is ours to
|
|
109
|
+
* build; the pills stay regardless, because they encode the QUESTIONS people ask rather than
|
|
110
|
+
* predicates a user would assemble by hand.
|
|
111
|
+
*/
|
|
112
|
+
GridToolbar = {
|
|
113
|
+
showSearch: true,
|
|
114
|
+
showFilterToggle: true,
|
|
115
|
+
showColumnChooser: true,
|
|
116
|
+
showRefresh: true,
|
|
117
|
+
showExport: true,
|
|
118
|
+
showRowCount: true,
|
|
119
|
+
};
|
|
120
|
+
ngOnInit() {
|
|
121
|
+
this.rebuild();
|
|
122
|
+
void this.loadTally();
|
|
123
|
+
}
|
|
124
|
+
/** Clicking the active provision clears the filter — the way back to everything. */
|
|
125
|
+
FilterByProvision(provisionID) {
|
|
126
|
+
this.ActiveProvisionID = this.ActiveProvisionID === provisionID ? null : provisionID;
|
|
127
|
+
this.rebuild();
|
|
128
|
+
}
|
|
129
|
+
rebuild() {
|
|
130
|
+
this.Params = {
|
|
131
|
+
EntityName: MJC_ENTITIES.ContractTemplateModification,
|
|
132
|
+
ExtraFilter: this.ActiveProvisionID ? `ContractTemplateProvisionID = '${this.ActiveProvisionID}'` : '',
|
|
133
|
+
OrderBy: '__mj_CreatedAt DESC',
|
|
134
|
+
};
|
|
135
|
+
this.cdr.detectChanges();
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Count modifications per provision, client-side.
|
|
139
|
+
*
|
|
140
|
+
* `RunView` has no GROUP BY, so this reads the rows and tallies them in memory. That is honest at
|
|
141
|
+
* this scale — a modification is a rare, human-authored record, so the whole table is hundreds of
|
|
142
|
+
* rows for years — and it avoids adding an entity or a stored procedure for a single panel. If it
|
|
143
|
+
* ever grows past a few thousand, the right answer is an MJ Query with real SQL, not a bigger loop
|
|
144
|
+
* here; that swap is why the tally is isolated in this method.
|
|
145
|
+
*
|
|
146
|
+
* Failure is swallowed to an empty list: the panel is an aid, and the grid below it is the page.
|
|
147
|
+
*/
|
|
148
|
+
async loadTally() {
|
|
149
|
+
try {
|
|
150
|
+
const result = await ScopedRunView().RunView({
|
|
151
|
+
EntityName: MJC_ENTITIES.ContractTemplateModification,
|
|
152
|
+
// The base view already joins the provision's name columns (D-23), so no second read.
|
|
153
|
+
ResultType: 'simple',
|
|
154
|
+
});
|
|
155
|
+
const rows = (result?.Results ?? []);
|
|
156
|
+
const counts = new Map();
|
|
157
|
+
for (const row of rows) {
|
|
158
|
+
const id = String(row['ContractTemplateProvisionID'] ?? '');
|
|
159
|
+
if (!id)
|
|
160
|
+
continue;
|
|
161
|
+
const existing = counts.get(id);
|
|
162
|
+
if (existing) {
|
|
163
|
+
existing.Count += 1;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
// The joined name column is the provision's name field; fall back to the number so a
|
|
167
|
+
// tally never shows a blank pill.
|
|
168
|
+
const label = String(row['ContractTemplateProvision'] ?? row['ProvisionNumber'] ?? 'provision');
|
|
169
|
+
counts.set(id, { ProvisionID: id, Label: label, Count: 1 });
|
|
170
|
+
}
|
|
171
|
+
this.TopProvisions = [...counts.values()].sort((a, b) => b.Count - a.Count).slice(0, 8);
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
this.TopProvisions = [];
|
|
175
|
+
}
|
|
176
|
+
this.cdr.detectChanges();
|
|
177
|
+
}
|
|
178
|
+
static ɵfac = function MJCModificationsPageComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJCModificationsPageComponent)(); };
|
|
179
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJCModificationsPageComponent, selectors: [["mjc-modifications-page"]], decls: 6, vars: 5, consts: [[1, "mjc-page", "mjc-page--grid"], [1, "mjc-page__intro"], [1, "mjc-card"], [1, "mjc-grid-fill"], ["mjcFkNavigate", "", 3, "Navigate", "Params", "ShowToolbar", "ToolbarConfig", "NavigateOnDoubleClick"], [1, "mjc-card__title"], [1, "mjc-pills"], ["type", "button", 1, "mjc-pill", 3, "mjc-pill--active"], ["type", "button", 1, "mjc-pill", 3, "click"], [1, "mjc-pill__count"]], template: function MJCModificationsPageComponent_Template(rf, ctx) { if (rf & 1) {
|
|
180
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "p", 1);
|
|
181
|
+
i0.ɵɵtext(2, " Every deviation from standard terms that has been recorded, across all contracts. The clauses at the top are the ones the business negotiates away most often \u2014 which is the signal that a standard term needs revisiting rather than re-negotiating. ");
|
|
182
|
+
i0.ɵɵelementEnd();
|
|
183
|
+
i0.ɵɵconditionalCreate(3, MJCModificationsPageComponent_Conditional_3_Template, 6, 0, "div", 2);
|
|
184
|
+
i0.ɵɵelementStart(4, "div", 3)(5, "mj-explorer-entity-data-grid", 4);
|
|
185
|
+
i0.ɵɵlistener("Navigate", function MJCModificationsPageComponent_Template_mj_explorer_entity_data_grid_Navigate_5_listener($event) { return ctx.OnNavigate($event); });
|
|
186
|
+
i0.ɵɵelementEnd()()();
|
|
187
|
+
} if (rf & 2) {
|
|
188
|
+
i0.ɵɵadvance(3);
|
|
189
|
+
i0.ɵɵconditional(ctx.TopProvisions.length ? 3 : -1);
|
|
190
|
+
i0.ɵɵadvance(2);
|
|
191
|
+
i0.ɵɵproperty("Params", ctx.Params)("ShowToolbar", true)("ToolbarConfig", ctx.GridToolbar)("NavigateOnDoubleClick", true);
|
|
192
|
+
} }, dependencies: [CommonModule, BaseFormsModule, i1.ExplorerEntityDataGridComponent, MJCFkNavigateDirective], encapsulation: 2 });
|
|
193
|
+
}
|
|
194
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJCModificationsPageComponent, [{
|
|
195
|
+
type: Component,
|
|
196
|
+
args: [{
|
|
197
|
+
selector: 'mjc-modifications-page',
|
|
198
|
+
standalone: true,
|
|
199
|
+
encapsulation: ViewEncapsulation.None,
|
|
200
|
+
imports: [CommonModule, BaseFormsModule, MJCFkNavigateDirective],
|
|
201
|
+
template: `
|
|
202
|
+
<div class="mjc-page mjc-page--grid">
|
|
203
|
+
<p class="mjc-page__intro">
|
|
204
|
+
Every deviation from standard terms that has been recorded, across all contracts. The
|
|
205
|
+
clauses at the top are the ones the business negotiates away most often — which is the
|
|
206
|
+
signal that a standard term needs revisiting rather than re-negotiating.
|
|
207
|
+
</p>
|
|
208
|
+
|
|
209
|
+
@if (TopProvisions.length) {
|
|
210
|
+
<div class="mjc-card">
|
|
211
|
+
<h3 class="mjc-card__title">Most-modified provisions</h3>
|
|
212
|
+
<div class="mjc-pills">
|
|
213
|
+
@for (t of TopProvisions; track t.ProvisionID) {
|
|
214
|
+
<button
|
|
215
|
+
type="button"
|
|
216
|
+
class="mjc-pill"
|
|
217
|
+
[class.mjc-pill--active]="t.ProvisionID === ActiveProvisionID"
|
|
218
|
+
[attr.aria-pressed]="t.ProvisionID === ActiveProvisionID"
|
|
219
|
+
(click)="FilterByProvision(t.ProvisionID)">
|
|
220
|
+
{{ t.Label }}
|
|
221
|
+
<span class="mjc-pill__count">{{ t.Count }}</span>
|
|
222
|
+
</button>
|
|
223
|
+
}
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
<div class="mjc-grid-fill">
|
|
229
|
+
|
|
230
|
+
<mj-explorer-entity-data-grid mjcFkNavigate
|
|
231
|
+
[Params]="Params"
|
|
232
|
+
[ShowToolbar]="true"
|
|
233
|
+
[ToolbarConfig]="GridToolbar"
|
|
234
|
+
[NavigateOnDoubleClick]="true"
|
|
235
|
+
(Navigate)="OnNavigate($event)" />
|
|
236
|
+
|
|
237
|
+
</div>
|
|
238
|
+
</div>
|
|
239
|
+
`,
|
|
240
|
+
}]
|
|
241
|
+
}], null, null); })();
|
|
242
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJCModificationsPageComponent, { className: "MJCModificationsPageComponent", filePath: "lib/pages/modifications.page.ts", lineNumber: 80 }); })();
|
|
243
|
+
//# sourceMappingURL=modifications.page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modifications.page.js","sourceRoot":"","sources":["../../../src/lib/pages/modifications.page.ts"],"names":[],"mappings":"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"}
|