pict-section-recordset 1.0.70 → 1.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/package.json +5 -1
- package/source/providers/Filter-Data-Provider.js +16 -5
- package/source/views/Filter-PersistenceView.js +150 -35
- package/source/views/RecordSet-Filters.js +230 -28
- package/source/views/filters/RecordSet-Filter-Base.js +86 -8
- package/source/views/read/RecordSet-Read.js +308 -2
- package/types/providers/Filter-Data-Provider.d.ts +1 -1
- package/types/providers/Filter-Data-Provider.d.ts.map +1 -1
- package/types/views/Filter-PersistenceView.d.ts +23 -2
- package/types/views/Filter-PersistenceView.d.ts.map +1 -1
- package/types/views/RecordSet-Filters.d.ts +26 -1
- package/types/views/RecordSet-Filters.d.ts.map +1 -1
- package/types/views/filters/RecordSet-Filter-Base.d.ts +14 -0
- package/types/views/filters/RecordSet-Filter-Base.d.ts.map +1 -1
- package/types/views/list/RecordSet-List.d.ts.map +1 -1
- package/types/views/read/RecordSet-Read.d.ts +51 -0
- package/types/views/read/RecordSet-Read.d.ts.map +1 -1
- package/.vscode/launch.json +0 -46
- package/CONTRIBUTING.md +0 -50
- package/debug/Harness.js +0 -0
- package/docs/.nojekyll +0 -0
- package/docs/README.md +0 -76
- package/docs/_brand.json +0 -18
- package/docs/_cover.md +0 -11
- package/docs/_sidebar.md +0 -19
- package/docs/_version.json +0 -7
- package/docs/api-reference.md +0 -233
- package/docs/filters.md +0 -151
- package/docs/index.html +0 -38
- package/docs/record-providers.md +0 -155
- package/docs/retold-catalog.json +0 -87
- package/docs/retold-keyword-index.json +0 -5227
- package/docs/views/create/README.md +0 -181
- package/docs/views/dashboard/README.md +0 -308
- package/docs/views/list/README.md +0 -260
- package/docs/views/read/README.md +0 -216
- package/eslint.config.mjs +0 -10
- package/example_applications/README.md +0 -39
- package/example_applications/ServeExamples.js +0 -82
- package/example_applications/bookstore/.quackage.json +0 -9
- package/example_applications/bookstore/Bookstore-Application-Configuration.json +0 -4
- package/example_applications/bookstore/Bookstore-Application.js +0 -671
- package/example_applications/bookstore/css/bookstore.css +0 -729
- package/example_applications/bookstore/css/pure.min.css +0 -11
- package/example_applications/bookstore/html/index.html +0 -46
- package/example_applications/bookstore/package.json +0 -34
- package/example_applications/bookstore/providers/PictRouter-Bookstore.json +0 -32
- package/example_applications/bookstore/views/PictView-Bookstore-Content-About.json +0 -21
- package/example_applications/bookstore/views/PictView-Bookstore-Content-Legal.json +0 -21
- package/example_applications/bookstore/views/PictView-Bookstore-Dashboard.js +0 -147
- package/example_applications/bookstore/views/PictView-Bookstore-Layout.js +0 -85
- package/example_applications/bookstore/views/PictView-Bookstore-Login.js +0 -58
- package/example_applications/bookstore/views/PictView-Bookstore-Navigation.js +0 -228
- package/example_applications/index.html +0 -50
- package/example_applications/mocks/book-edit-view.html +0 -173
- package/example_applications/mocks/book-read-view.html +0 -166
- package/example_applications/mocks/list-view.html +0 -185
- package/example_applications/package.json +0 -16
- package/example_applications/simple_entity/.quackage.json +0 -9
- package/example_applications/simple_entity/README-Simple-RecordSet.md +0 -8
- package/example_applications/simple_entity/Simple-RecordSet-Application.js +0 -887
- package/example_applications/simple_entity/html/index.html +0 -207
- package/example_applications/simple_entity/package.json +0 -27
- package/test/PictSectionRecordSet-Basic_tests.js +0 -205
- package/test/PictSectionRecordSet-Filter-Data-Provider_tests.js +0 -263
- package/test/PictSectionRecordSet-Filter-InstanceViews-Render_tests.js +0 -328
- package/test/PictSectionRecordSet-RecordProvider-Meadow_tests.js +0 -216
- package/tsconfig.build.json +0 -16
- package/tsconfig.json +0 -16
|
@@ -20,7 +20,49 @@ const _DEFAULT_CONFIGURATION_SUBSET_Filter =
|
|
|
20
20
|
AutoSolveWithApp: false,
|
|
21
21
|
AutoSolveOrdinal: 0,
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
// Themeable filter-clause chrome. Every filter type renders through the shared
|
|
24
|
+
// PRSP-Filter-Base-Template wrapper below (each type only plugs in its own value
|
|
25
|
+
// input via getFilterFormTemplate()), so styling it here themes every clause for
|
|
26
|
+
// every host app. This view (PRSP-FilterType-Base) is always constructed, and
|
|
27
|
+
// pict-view registers a view's CSS into the global cascade at construction, so
|
|
28
|
+
// these rules apply to all clauses regardless of which type rendered them.
|
|
29
|
+
//
|
|
30
|
+
// Host apps brand by defining the --theme-color-* tokens; the hardcoded values are
|
|
31
|
+
// sensible fallbacks. CSS-first: native <select>s are de-nativized with
|
|
32
|
+
// appearance:none + a custom chevron rather than swapped for a combobox widget
|
|
33
|
+
// (that is a later upgrade with cross-browser quirks of its own).
|
|
34
|
+
CSS: /*css*/`
|
|
35
|
+
.prsp-filters-clauses { display: flex; flex-direction: column; gap: 0.5rem; }
|
|
36
|
+
|
|
37
|
+
.prsp-filter { display: flex; align-items: flex-end; gap: 0.5rem; }
|
|
38
|
+
.prsp-filter *, .prsp-filter *::before, .prsp-filter *::after { box-sizing: border-box; }
|
|
39
|
+
.prsp-filter-body { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.4rem 0.75rem; }
|
|
40
|
+
|
|
41
|
+
/* Inputs rendered by pict-section-form inside a clause. Match the consolidated
|
|
42
|
+
control's search box so clauses stop looking like bare native controls. */
|
|
43
|
+
.prsp-filter label { font: inherit; font-size: 0.78rem; font-weight: 600; display: block;
|
|
44
|
+
margin: 0 0 0.2rem; color: var(--theme-color-text-secondary, #45505f); }
|
|
45
|
+
.prsp-filter input, .prsp-filter select, .prsp-filter textarea { font: inherit; font-size: 0.92rem; width: 100%;
|
|
46
|
+
padding: 0.45rem 0.7rem; border-radius: 8px; border: 1px solid var(--theme-color-border-default, #d7dce3);
|
|
47
|
+
background: var(--theme-color-background-primary, #fff); color: var(--theme-color-text-primary, #1f2733); }
|
|
48
|
+
.prsp-filter input:focus, .prsp-filter select:focus, .prsp-filter textarea:focus { outline: none;
|
|
49
|
+
border-color: var(--theme-color-brand-primary, #156dd1);
|
|
50
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--theme-color-brand-primary, #156dd1) 16%, transparent); }
|
|
51
|
+
/* De-nativize the <select>: drop the platform arrow, add a themed chevron + room for it. */
|
|
52
|
+
.prsp-filter select { appearance: none; -webkit-appearance: none; -moz-appearance: none; cursor: pointer;
|
|
53
|
+
padding-right: 1.9rem;
|
|
54
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7686' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
|
|
55
|
+
background-repeat: no-repeat; background-position: right 0.6rem center; background-size: 1.05em; }
|
|
56
|
+
|
|
57
|
+
/* Remove (trash) control — one per clause, inherited by every filter type. */
|
|
58
|
+
.prsp-filter-remove { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
|
|
59
|
+
width: 2.05rem; height: 2.05rem; padding: 0; cursor: pointer; line-height: 1;
|
|
60
|
+
border-radius: 8px; border: 1px solid var(--theme-color-border-default, #d7dce3);
|
|
61
|
+
background: var(--theme-color-background-primary, #fff); color: var(--theme-color-text-muted, #6b7686); }
|
|
62
|
+
.prsp-filter-remove:hover { border-color: var(--theme-color-status-error, #d64545); color: var(--theme-color-status-error, #d64545);
|
|
63
|
+
background: color-mix(in srgb, var(--theme-color-status-error, #d64545) 12%, transparent); }
|
|
64
|
+
.prsp-filter-remove .pict-icon { font-size: 1.05rem; }
|
|
65
|
+
`,
|
|
24
66
|
CSSPriority: 500,
|
|
25
67
|
|
|
26
68
|
Manifests: {},
|
|
@@ -38,16 +80,21 @@ const _DEFAULT_CONFIGURATION_SUBSET_Filter =
|
|
|
38
80
|
`
|
|
39
81
|
},
|
|
40
82
|
{
|
|
83
|
+
// The shared clause wrapper for every filter type. The type view plugs its own
|
|
84
|
+
// value input in via getFilterFormTemplate(); the themed remove control is
|
|
85
|
+
// inherited here (calls the base removeClause() method, reached through the
|
|
86
|
+
// always-registered PRSP-FilterType-<Type> view) so no host app re-implements one.
|
|
41
87
|
Hash: 'PRSP-Filter-Base-Template',
|
|
42
88
|
Template: /*html*/`
|
|
43
89
|
<!-- DefaultPackage pict view template: [PRSP-Filter-Base-Template] -->
|
|
44
|
-
<div id="PRSP_Filter_Container_{~D:Record.Hash~}">
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
90
|
+
<div class="prsp-filter" id="PRSP_Filter_Container_{~D:Record.Hash~}" data-i-filter-hash="{~D:Record.Hash~}">
|
|
91
|
+
<div class="prsp-filter-body">
|
|
92
|
+
{~TBR:Context[0].getFilterFormTemplate()~}
|
|
93
|
+
</div>
|
|
94
|
+
<button type="button" class="prsp-filter-remove" title="Remove this filter" aria-label="Remove this filter"
|
|
95
|
+
onclick="_Pict.views['PRSP-FilterType-{~D:Record.Type~}'].removeClause(event, '{~D:Record.RecordSet~}', '{~D:Record.ViewContext~}', '{~D:Record.Hash~}');">
|
|
96
|
+
{~I:Trash~}
|
|
49
97
|
</button>
|
|
50
|
-
{~TBR:Context[0].getFilterFormTemplate()~}
|
|
51
98
|
</div>
|
|
52
99
|
<!-- DefaultPackage end view template: [PRSP-Filter-Base-Template] -->
|
|
53
100
|
`
|
|
@@ -99,6 +146,38 @@ class ViewRecordSetSUBSETFilterBase extends libPictView
|
|
|
99
146
|
return 'PRSP-Filter-Base-Form';
|
|
100
147
|
}
|
|
101
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Remove this filter clause from its record set and re-render the filter control.
|
|
151
|
+
*
|
|
152
|
+
* Lives on the base view so every filter type inherits a single, themeable remove
|
|
153
|
+
* affordance and no host application has to re-implement one. Delegates to the
|
|
154
|
+
* consolidated control view (the canonical re-render path) and falls back to the
|
|
155
|
+
* record-set provider directly if that view is somehow unavailable.
|
|
156
|
+
*
|
|
157
|
+
* @param {Event} pEvent - The DOM event that triggered the removal.
|
|
158
|
+
* @param {string} pRecordSet - The record set being filtered.
|
|
159
|
+
* @param {string} pViewContext - The view context for the filter (e.g. List, Dashboard).
|
|
160
|
+
* @param {string} pHash - The hash of the specific filter clause to remove.
|
|
161
|
+
*/
|
|
162
|
+
removeClause(pEvent, pRecordSet, pViewContext, pHash)
|
|
163
|
+
{
|
|
164
|
+
if (pEvent)
|
|
165
|
+
{
|
|
166
|
+
pEvent.preventDefault();
|
|
167
|
+
}
|
|
168
|
+
const tmpFiltersView = this.pict.views['PRSP-Filters'];
|
|
169
|
+
if (tmpFiltersView && typeof tmpFiltersView.removeFilter === 'function')
|
|
170
|
+
{
|
|
171
|
+
return tmpFiltersView.removeFilter(pEvent, pRecordSet, pViewContext, pHash);
|
|
172
|
+
}
|
|
173
|
+
// Fallback: the consolidated control view isn't present, so remove directly.
|
|
174
|
+
const tmpProvider = this.pict.providers[`RSP-Provider-${pRecordSet}`];
|
|
175
|
+
if (tmpProvider && typeof tmpProvider.removeFilterClause === 'function')
|
|
176
|
+
{
|
|
177
|
+
tmpProvider.removeFilterClause(pHash);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
102
181
|
/**
|
|
103
182
|
* @return {string} - The prefix for the informary address.
|
|
104
183
|
*/
|
|
@@ -121,4 +200,3 @@ class ViewRecordSetSUBSETFilterBase extends libPictView
|
|
|
121
200
|
module.exports = ViewRecordSetSUBSETFilterBase;
|
|
122
201
|
|
|
123
202
|
module.exports.default_configuration = _DEFAULT_CONFIGURATION_SUBSET_Filter;
|
|
124
|
-
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
const libPictRecordSetRecordView = require('../RecordSet-RecordBaseView.js');
|
|
2
2
|
|
|
3
|
+
// Identity + audit field names stamped on (virtually) every Meadow entity. These are
|
|
4
|
+
// surfaced through the record audit header (the first-class activity line + the Details
|
|
5
|
+
// modal), not inline in the record body. The entity's own ID/GUID field names are added
|
|
6
|
+
// at suppression time via the provider's getIDField()/getGUIDField().
|
|
7
|
+
const _AUDIT_FIELD_NAMES = ['CreatingIDUser', 'UpdatingIDUser', 'DeletingIDUser', 'Deleted', 'CreateDate', 'UpdateDate', 'DeleteDate'];
|
|
8
|
+
|
|
3
9
|
/** @type {Record<string, any>} */
|
|
4
10
|
const _DEFAULT_CONFIGURATION__Read = (
|
|
5
11
|
{
|
|
@@ -22,7 +28,32 @@ const _DEFAULT_CONFIGURATION__Read = (
|
|
|
22
28
|
AutoSolveWithApp: false,
|
|
23
29
|
AutoSolveOrdinal: 0,
|
|
24
30
|
|
|
25
|
-
CSS:
|
|
31
|
+
CSS: /*css*/`
|
|
32
|
+
.prsp-audit-header { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin: 0 0 1rem; }
|
|
33
|
+
.prsp-audit-line { display: inline-flex; align-items: center; gap: 0.4rem; color: var(--theme-color-text-muted, #6b7686); font-size: 0.85rem; }
|
|
34
|
+
.prsp-audit-line .pict-icon { font-size: 0.8rem; }
|
|
35
|
+
.prsp-audit-line strong { color: var(--theme-color-text-secondary, #45505f); font-weight: 600; }
|
|
36
|
+
.prsp-audit-button { display: inline-flex; align-items: center; gap: 0.4rem; border: 1px solid var(--theme-color-border-default, #d7dce3); background: var(--theme-color-background-primary, #fff); color: var(--theme-color-text-muted, #6b7686); border-radius: 8px; padding: 0.35rem 0.65rem; font: inherit; font-size: 0.82rem; cursor: pointer; transition: all 0.15s ease; }
|
|
37
|
+
.prsp-audit-button:hover { border-color: var(--theme-color-brand-primary, #156dd1); color: var(--theme-color-brand-primary, #156dd1); }
|
|
38
|
+
.prsp-record-related:empty { display: none; }
|
|
39
|
+
.prsp-audit-anchor { position: relative; }
|
|
40
|
+
.prsp-audit-popover { position: absolute; top: calc(100% + 8px); right: 0; min-width: 320px; max-width: 90vw; background: var(--theme-color-background-panel, #fff); border: 1px solid var(--theme-color-border-default, #d7dce3); border-radius: 10px; box-shadow: 0 14px 36px rgba(15, 23, 42, 0.18); padding: 1rem 1.1rem; z-index: 40; display: none; }
|
|
41
|
+
.prsp-audit-popover.is-open { display: block; }
|
|
42
|
+
.prsp-audit-dl { display: grid; grid-template-columns: auto 1fr; gap: 0.6rem 1rem; align-items: baseline; margin: 0; }
|
|
43
|
+
.prsp-audit-dl dt { color: var(--theme-color-text-muted, #6b7686); font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.03em; white-space: nowrap; }
|
|
44
|
+
.prsp-audit-dl dd { margin: 0; color: var(--theme-color-text-primary, #1f2733); font-size: 0.9rem; }
|
|
45
|
+
.prsp-audit-dl dd small { color: var(--theme-color-text-muted, #6b7686); }
|
|
46
|
+
.prsp-audit-dl dd.is-deleted { color: var(--theme-color-status-error, #b62828); }
|
|
47
|
+
.prsp-audit-guid { display: inline-flex; align-items: center; gap: 0.4rem; }
|
|
48
|
+
.prsp-audit-guid code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.8rem; color: var(--theme-color-text-secondary, #45505f); background: var(--theme-color-background-secondary, #f5f6f8); padding: 0.1rem 0.4rem; border-radius: 5px; }
|
|
49
|
+
.prsp-audit-copy { border: 0; background: transparent; color: var(--theme-color-text-muted, #6b7686); cursor: pointer; padding: 0.1rem 0.3rem; border-radius: 4px; font-size: 0.85rem; }
|
|
50
|
+
.prsp-audit-copy:hover { color: var(--theme-color-brand-primary, #156dd1); }
|
|
51
|
+
/* Tufte: in view mode the record VALUES are the foreground. Read-only fields render as
|
|
52
|
+
text (not boxed inputs), so the data outweighs its labels and section chrome. */
|
|
53
|
+
.prsp-record-read input.input[readonly], .prsp-record-read input.input[disabled], .prsp-record-read textarea[readonly], .prsp-record-read textarea[disabled], .prsp-record-read select[disabled] { background: transparent !important; border-color: transparent !important; box-shadow: none !important; padding-left: 0 !important; padding-right: 0 !important; height: auto !important; min-height: 0 !important; opacity: 1 !important; cursor: default !important; color: var(--theme-color-text-primary, #1f2733) !important; -webkit-text-fill-color: var(--theme-color-text-primary, #1f2733) !important; font-weight: 600 !important; font-size: 1.1rem !important; }
|
|
54
|
+
.prsp-record-read .label { font-size: 0.68rem !important; font-weight: 600 !important; text-transform: uppercase !important; letter-spacing: 0.05em !important; color: var(--theme-color-text-muted, #6b7686) !important; margin-bottom: 0.05rem !important; }
|
|
55
|
+
.prsp-record-read .section-header { background: var(--theme-color-background-selected, #e3edfb) !important; color: var(--theme-color-brand-primary, #156dd1) !important; font-size: 0.74rem !important; font-weight: 700 !important; text-transform: uppercase !important; letter-spacing: 0.06em !important; padding: 0.4rem 0.8rem !important; border-radius: 6px !important; border-bottom: 0 !important; margin: 1.1rem 0 0.7rem !important; }
|
|
56
|
+
`,
|
|
26
57
|
CSSPriority: 500,
|
|
27
58
|
|
|
28
59
|
Templates:
|
|
@@ -227,6 +258,47 @@ const _DEFAULT_CONFIGURATION__Read = (
|
|
|
227
258
|
// TODO: Double payload pattern...
|
|
228
259
|
Template: `#/PSRS/{~D:Record.Payload.Payload.RecordSet~}/View/{~DVBK:Record.Payload.Data:Record.Payload.Payload.GUIDAddress~}`
|
|
229
260
|
},
|
|
261
|
+
// --- Record audit header (themeable; apps brand via --theme-color-* tokens) ---
|
|
262
|
+
{
|
|
263
|
+
Hash: 'PRSP-Read-RecordAuditHeader-Template',
|
|
264
|
+
Template: /*html*/`
|
|
265
|
+
<div class="prsp-audit-header">
|
|
266
|
+
<div class="prsp-audit-activity">{~TS:PRSP-Read-RecordAudit-Line-Template:AppData.PRSP_RecordAudit.ActivitySlot~}</div>
|
|
267
|
+
<div class="prsp-audit-anchor">
|
|
268
|
+
<button type="button" class="prsp-audit-button" title="Identity and audit detail" onclick="_Pict.views['RSP-RecordSet-Read'].toggleRecordAudit()">{~I:Info~}<span>Details</span></button>
|
|
269
|
+
<div class="prsp-audit-popover" id="PRSP-Read-AuditPopover">
|
|
270
|
+
<dl class="prsp-audit-dl">
|
|
271
|
+
<dt>{~D:AppData.PRSP_RecordAudit.IDFieldName~}</dt><dd><span class="prsp-audit-guid"><code>{~D:AppData.PRSP_RecordAudit.IDValue~}</code><button type="button" class="prsp-audit-copy" title="Copy" onclick="_Pict.views['RSP-RecordSet-Read'].copyValue('{~D:AppData.PRSP_RecordAudit.IDValue~}')">{~I:Copy~}</button></span></dd>
|
|
272
|
+
<dt>{~D:AppData.PRSP_RecordAudit.GUIDFieldName~}</dt><dd><span class="prsp-audit-guid"><code>{~D:AppData.PRSP_RecordAudit.GUIDValue~}</code><button type="button" class="prsp-audit-copy" title="Copy" onclick="_Pict.views['RSP-RecordSet-Read'].copyValue('{~D:AppData.PRSP_RecordAudit.GUIDValue~}')">{~I:Copy~}</button></span></dd>
|
|
273
|
+
{~TS:PRSP-Read-RecordAudit-Created-Template:AppData.PRSP_RecordAudit.CreatedSlot~}
|
|
274
|
+
{~TS:PRSP-Read-RecordAudit-Updated-Template:AppData.PRSP_RecordAudit.UpdatedSlot~}
|
|
275
|
+
{~TS:PRSP-Read-RecordAudit-Deleted-Template:AppData.PRSP_RecordAudit.DeletedSlot~}
|
|
276
|
+
</dl>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
`
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
Hash: 'PRSP-Read-RecordAudit-Line-Template',
|
|
284
|
+
Template: /*html*/`<span class="prsp-audit-line">{~I:Refresh~} {~D:Record.Label~} by <strong>{~E:User^Record.UserID^PRSP-Read-RecordAudit-UserName-Template~}</strong> · {~DateFormat:Record.Date^MMM D, YYYY - h:mm A~}</span>`
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
Hash: 'PRSP-Read-RecordAudit-UserName-Template',
|
|
288
|
+
Template: /*html*/`{~D:Record.NameFirst~} {~D:Record.NameLast~}`
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
Hash: 'PRSP-Read-RecordAudit-Created-Template',
|
|
292
|
+
Template: /*html*/`<dt>Created</dt><dd>{~DateFormat:Record.Date^MMM D, YYYY - h:mm A~} <small>by {~E:User^Record.UserID^PRSP-Read-RecordAudit-UserName-Template~}</small></dd>`
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
Hash: 'PRSP-Read-RecordAudit-Updated-Template',
|
|
296
|
+
Template: /*html*/`<dt>Last updated</dt><dd>{~DateFormat:Record.Date^MMM D, YYYY - h:mm A~} <small>by {~E:User^Record.UserID^PRSP-Read-RecordAudit-UserName-Template~}</small></dd>`
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
Hash: 'PRSP-Read-RecordAudit-Deleted-Template',
|
|
300
|
+
Template: /*html*/`<dt>Deleted</dt><dd class="is-deleted">{~DateFormat:Record.Date^MMM D, YYYY - h:mm A~} <small>by {~E:User^Record.UserID^PRSP-Read-RecordAudit-UserName-Template~}</small></dd>`
|
|
301
|
+
},
|
|
230
302
|
],
|
|
231
303
|
|
|
232
304
|
Renderables:
|
|
@@ -319,6 +391,8 @@ class viewRecordSetRead extends libPictRecordSetRecordView
|
|
|
319
391
|
this.initializeDragListener();
|
|
320
392
|
}
|
|
321
393
|
|
|
394
|
+
this.pict.CSSMap.injectCSS();
|
|
395
|
+
this._bindAuditDismiss();
|
|
322
396
|
return super.onAfterRender(pRenderable);
|
|
323
397
|
}
|
|
324
398
|
|
|
@@ -387,6 +461,222 @@ class viewRecordSetRead extends libPictRecordSetRecordView
|
|
|
387
461
|
this.fable.providers.RecordSetRouter.pictRouter.navigate(`/PSRS/${ this.RecordSet }/Edit/${ this.GUID }`);
|
|
388
462
|
}
|
|
389
463
|
|
|
464
|
+
/**
|
|
465
|
+
* Build the record audit header state — the first-class activity line plus the data the
|
|
466
|
+
* Details modal renders. Identity (ID/GUID) and the create/update/delete stamps are read
|
|
467
|
+
* straight off the fetched record; the acting-user names resolve lazily via {~E:User^…~}
|
|
468
|
+
* in the templates (cachetrax-cached), so nothing is pre-resolved here. Stored at
|
|
469
|
+
* AppData.PRSP_RecordAudit for the templates to consume.
|
|
470
|
+
*
|
|
471
|
+
* @param {Record<string, any>} pRecord - The fetched record.
|
|
472
|
+
*/
|
|
473
|
+
_prepareRecordAuditState(pRecord)
|
|
474
|
+
{
|
|
475
|
+
if (!pRecord || typeof pRecord !== 'object')
|
|
476
|
+
{
|
|
477
|
+
this.pict.AppData.PRSP_RecordAudit = false;
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
const tmpProvider = this.pict.providers[this.providerHash];
|
|
481
|
+
const tmpIDField = tmpProvider ? tmpProvider.getIDField() : 'ID';
|
|
482
|
+
const tmpGUIDField = tmpProvider ? tmpProvider.getGUIDField() : 'GUID';
|
|
483
|
+
|
|
484
|
+
const tmpHasCreate = this._validAuditDate(pRecord.CreateDate);
|
|
485
|
+
const tmpHasUpdate = this._validAuditDate(pRecord.UpdateDate) && (pRecord.UpdateDate !== pRecord.CreateDate);
|
|
486
|
+
const tmpDeleted = !!pRecord.Deleted && this._validAuditDate(pRecord.DeleteDate);
|
|
487
|
+
|
|
488
|
+
let tmpActivitySlot = [];
|
|
489
|
+
if (tmpHasUpdate)
|
|
490
|
+
{
|
|
491
|
+
tmpActivitySlot = [{ Label: 'Updated', Date: pRecord.UpdateDate, UserID: pRecord.UpdatingIDUser }];
|
|
492
|
+
}
|
|
493
|
+
else if (tmpHasCreate)
|
|
494
|
+
{
|
|
495
|
+
tmpActivitySlot = [{ Label: 'Created', Date: pRecord.CreateDate, UserID: pRecord.CreatingIDUser }];
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const tmpIDValue = (pRecord[tmpIDField] != null) ? pRecord[tmpIDField] : '';
|
|
499
|
+
this.pict.AppData.PRSP_RecordAudit =
|
|
500
|
+
{
|
|
501
|
+
RecordSet: this.RecordSet,
|
|
502
|
+
DisplayName: this._computeDisplayName(pRecord),
|
|
503
|
+
IDFieldName: tmpIDField,
|
|
504
|
+
GUIDFieldName: tmpGUIDField,
|
|
505
|
+
IDValue: tmpIDValue,
|
|
506
|
+
GUIDValue: (pRecord[tmpGUIDField] != null) ? pRecord[tmpGUIDField] : '',
|
|
507
|
+
ActivitySlot: tmpActivitySlot,
|
|
508
|
+
CreatedSlot: tmpHasCreate ? [{ Date: pRecord.CreateDate, UserID: pRecord.CreatingIDUser }] : [],
|
|
509
|
+
UpdatedSlot: tmpHasUpdate ? [{ Date: pRecord.UpdateDate, UserID: pRecord.UpdatingIDUser }] : [],
|
|
510
|
+
DeletedSlot: tmpDeleted ? [{ Date: pRecord.DeleteDate, UserID: pRecord.DeletingIDUser }] : []
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Compute a human-friendly display name for a record using an opinionated heuristic: first +
|
|
516
|
+
* last name, then a single descriptive field (FullName, Name, Title, …), else ''. Callers fall
|
|
517
|
+
* back to the GUID. Lets the page title read "Krishna Pavia Tester" instead of a raw GUID.
|
|
518
|
+
* @param {Record<string, any>} pRecord
|
|
519
|
+
* @return {string}
|
|
520
|
+
*/
|
|
521
|
+
_computeDisplayName(pRecord)
|
|
522
|
+
{
|
|
523
|
+
if (!pRecord || typeof pRecord !== 'object')
|
|
524
|
+
{
|
|
525
|
+
return '';
|
|
526
|
+
}
|
|
527
|
+
const tmpFirst = pRecord.NameFirst || pRecord.FirstName;
|
|
528
|
+
const tmpLast = pRecord.NameLast || pRecord.LastName;
|
|
529
|
+
if (tmpFirst || tmpLast)
|
|
530
|
+
{
|
|
531
|
+
return [tmpFirst, tmpLast].filter(Boolean).join(' ').trim();
|
|
532
|
+
}
|
|
533
|
+
const tmpCandidateFields = ['FullName', 'Name', 'Title', 'DisplayName', 'Label', 'Subject', 'Description', 'Code', 'Hash'];
|
|
534
|
+
for (const tmpField of tmpCandidateFields)
|
|
535
|
+
{
|
|
536
|
+
if (pRecord[tmpField] != null && String(pRecord[tmpField]).trim() !== '')
|
|
537
|
+
{
|
|
538
|
+
return String(pRecord[tmpField]).trim();
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
return '';
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Whether an audit date value is present and meaningful (guards null/empty and the Meadow
|
|
546
|
+
* "0000-00-00" zero-date sentinel).
|
|
547
|
+
* @param {any} pValue
|
|
548
|
+
* @return {boolean}
|
|
549
|
+
*/
|
|
550
|
+
_validAuditDate(pValue)
|
|
551
|
+
{
|
|
552
|
+
if (!pValue)
|
|
553
|
+
{
|
|
554
|
+
return false;
|
|
555
|
+
}
|
|
556
|
+
return String(pValue).indexOf('0000-00-00') !== 0;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* Toggle the anchored identity + audit popover open or closed. The content is rendered inline
|
|
561
|
+
* with the record (so the {~E:User^…~} names resolve during the read render); this just flips
|
|
562
|
+
* its visibility — no overlay.
|
|
563
|
+
*/
|
|
564
|
+
toggleRecordAudit()
|
|
565
|
+
{
|
|
566
|
+
const tmpPopover = document.getElementById('PRSP-Read-AuditPopover');
|
|
567
|
+
if (tmpPopover)
|
|
568
|
+
{
|
|
569
|
+
tmpPopover.classList.toggle('is-open');
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Bind the one-time document handlers that dismiss the audit popover on an outside click or
|
|
575
|
+
* Escape. Browser-level events with no inline-handler equivalent — bound once and guarded so
|
|
576
|
+
* re-renders don't stack listeners.
|
|
577
|
+
*/
|
|
578
|
+
_bindAuditDismiss()
|
|
579
|
+
{
|
|
580
|
+
if (this._auditDismissBound || typeof document === 'undefined')
|
|
581
|
+
{
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
this._auditDismissBound = true;
|
|
585
|
+
document.addEventListener('click', (pEvent) =>
|
|
586
|
+
{
|
|
587
|
+
const tmpPopover = document.getElementById('PRSP-Read-AuditPopover');
|
|
588
|
+
if (!tmpPopover || !tmpPopover.classList.contains('is-open'))
|
|
589
|
+
{
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
if (tmpPopover.contains(pEvent.target) || (pEvent.target.closest && pEvent.target.closest('.prsp-audit-button')))
|
|
593
|
+
{
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
tmpPopover.classList.remove('is-open');
|
|
597
|
+
});
|
|
598
|
+
document.addEventListener('keydown', (pEvent) =>
|
|
599
|
+
{
|
|
600
|
+
if (pEvent.key === 'Escape')
|
|
601
|
+
{
|
|
602
|
+
const tmpPopover = document.getElementById('PRSP-Read-AuditPopover');
|
|
603
|
+
if (tmpPopover)
|
|
604
|
+
{
|
|
605
|
+
tmpPopover.classList.remove('is-open');
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Copy a record value (ID or GUID) to the clipboard from the audit popover, with a toast.
|
|
613
|
+
* @param {string} pValue
|
|
614
|
+
*/
|
|
615
|
+
copyValue(pValue)
|
|
616
|
+
{
|
|
617
|
+
const tmpModal = this.pict.views['Pict-Section-Modal'];
|
|
618
|
+
const fToast = (pMessage, pType) =>
|
|
619
|
+
{
|
|
620
|
+
if (tmpModal && typeof tmpModal.toast === 'function')
|
|
621
|
+
{
|
|
622
|
+
tmpModal.toast(pMessage, { type: pType || 'success' });
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
if (typeof navigator !== 'undefined' && navigator.clipboard && navigator.clipboard.writeText)
|
|
626
|
+
{
|
|
627
|
+
navigator.clipboard.writeText(pValue).then(() => fToast('GUID copied to clipboard')).catch(() => fToast('Could not copy GUID', 'error'));
|
|
628
|
+
}
|
|
629
|
+
else
|
|
630
|
+
{
|
|
631
|
+
fToast('Could not copy GUID', 'error');
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Remove identity + audit descriptors from a (cloned) manifest so they don't render inline
|
|
637
|
+
* in the record body — they live behind the audit header's Details modal instead. Also
|
|
638
|
+
* prunes any section left with no descriptors (e.g. an emptied "Audit Trail" section). The
|
|
639
|
+
* entity's own ID/GUID field names are suppressed alongside the shared audit fields.
|
|
640
|
+
* @param {Record<string, any>} pManifest - The cloned manifest to mutate.
|
|
641
|
+
*/
|
|
642
|
+
_suppressAuditDescriptors(pManifest)
|
|
643
|
+
{
|
|
644
|
+
if (!pManifest || !pManifest.Descriptors)
|
|
645
|
+
{
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
const tmpProvider = this.pict.providers[this.providerHash];
|
|
649
|
+
const tmpSuppress = _AUDIT_FIELD_NAMES.slice();
|
|
650
|
+
if (tmpProvider)
|
|
651
|
+
{
|
|
652
|
+
tmpSuppress.push(tmpProvider.getIDField());
|
|
653
|
+
tmpSuppress.push(tmpProvider.getGUIDField());
|
|
654
|
+
}
|
|
655
|
+
for (const tmpKey of Object.keys(pManifest.Descriptors))
|
|
656
|
+
{
|
|
657
|
+
const tmpFieldName = tmpKey.split('.').pop();
|
|
658
|
+
if (tmpSuppress.indexOf(tmpFieldName) >= 0)
|
|
659
|
+
{
|
|
660
|
+
delete pManifest.Descriptors[tmpKey];
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
// Drop sections that no longer have any descriptors (so an emptied titled section like
|
|
664
|
+
// "Audit Trail" doesn't render as a bare heading).
|
|
665
|
+
if (Array.isArray(pManifest.Sections))
|
|
666
|
+
{
|
|
667
|
+
const tmpUsedSections = {};
|
|
668
|
+
for (const tmpKey of Object.keys(pManifest.Descriptors))
|
|
669
|
+
{
|
|
670
|
+
const tmpSectionHash = pManifest.Descriptors[tmpKey] && pManifest.Descriptors[tmpKey].PictForm && pManifest.Descriptors[tmpKey].PictForm.Section;
|
|
671
|
+
if (tmpSectionHash)
|
|
672
|
+
{
|
|
673
|
+
tmpUsedSections[tmpSectionHash] = true;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
pManifest.Sections = pManifest.Sections.filter((pSection) => tmpUsedSections[pSection.Hash]);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
390
680
|
onBeforeRenderRead(pRecordReadData)
|
|
391
681
|
{
|
|
392
682
|
this.formatDisplayData(pRecordReadData);
|
|
@@ -467,12 +757,19 @@ class viewRecordSetRead extends libPictRecordSetRecordView
|
|
|
467
757
|
tmpRecordReadData.RecordSchema = await this.pict.providers[pProviderHash].getRecordSchema();
|
|
468
758
|
this.pict.AppData[`${ tmpRecordReadData.RecordSet }Details`] = tmpRecordReadData.Record;
|
|
469
759
|
|
|
760
|
+
// Build the audit header state (first-class activity line + the Details modal) for this record.
|
|
761
|
+
this._prepareRecordAuditState(tmpRecordReadData.Record);
|
|
762
|
+
|
|
470
763
|
if (pRecordConfiguration.RecordSetReadManifestOnly)
|
|
471
764
|
{
|
|
472
765
|
this.pict.TemplateProvider.addTemplate(`PRSP-Read-RecordRead-Template`, /*html*/`
|
|
473
766
|
<!-- Manifest dynamic pict template: [PRSP-Read-RecordRead-Template] -->
|
|
767
|
+
<div class="prsp-record-read">
|
|
768
|
+
{~T:PRSP-Read-RecordAuditHeader-Template~}
|
|
474
769
|
<div>${ this._generateManifestTemplate(pRecordConfiguration, 'RecordRead', null, true) }</div>
|
|
475
770
|
{~T:PRSP-Read-RecordButtonBar-Template~}
|
|
771
|
+
<div class="prsp-record-related" id="PRSP-Read-Related"></div>
|
|
772
|
+
</div>
|
|
476
773
|
<!-- Manifest dynamic pict end template: [PRSP-Read-RecordRead-Template] -->
|
|
477
774
|
`);
|
|
478
775
|
}
|
|
@@ -482,8 +779,12 @@ class viewRecordSetRead extends libPictRecordSetRecordView
|
|
|
482
779
|
this.defaultManifest = await this._buildDefaultManifest(tmpRecordReadData.RecordSet);
|
|
483
780
|
this.pict.TemplateProvider.addTemplate(`PRSP-Read-RecordRead-Template`, /*html*/`
|
|
484
781
|
<!-- Manifest dynamic pict template: [PRSP-Read-RecordRead-Template] -->
|
|
782
|
+
<div class="prsp-record-read">
|
|
783
|
+
{~T:PRSP-Read-RecordAuditHeader-Template~}
|
|
485
784
|
<div>${ this._generateManifestTemplate(pRecordConfiguration, 'RecordRead', null, true, this.action, this.defaultManifest) }</div>
|
|
486
785
|
{~T:PRSP-Read-RecordButtonBar-Template~}
|
|
786
|
+
<div class="prsp-record-related" id="PRSP-Read-Related"></div>
|
|
787
|
+
</div>
|
|
487
788
|
<!-- Manifest dynamic pict end template: [PRSP-Read-RecordRead-Template] -->
|
|
488
789
|
`);
|
|
489
790
|
}
|
|
@@ -616,7 +917,7 @@ class viewRecordSetRead extends libPictRecordSetRecordView
|
|
|
616
917
|
const schema = await this.pict.providers[providerHash].getRecordSchema();
|
|
617
918
|
for (const p of Object.keys(schema.properties))
|
|
618
919
|
{
|
|
619
|
-
const exclusionSet = [this.pict.providers[this.providerHash].getIDField(), this.pict.providers[this.providerHash].getGUIDField()
|
|
920
|
+
const exclusionSet = [this.pict.providers[this.providerHash].getIDField(), this.pict.providers[this.providerHash].getGUIDField()].concat(_AUDIT_FIELD_NAMES);
|
|
620
921
|
if (exclusionSet.includes(p))
|
|
621
922
|
{
|
|
622
923
|
continue;
|
|
@@ -695,6 +996,11 @@ class viewRecordSetRead extends libPictRecordSetRecordView
|
|
|
695
996
|
tmpManifest.Descriptors[x].PictForm.InputType = 'ReadOnly';
|
|
696
997
|
}
|
|
697
998
|
}
|
|
999
|
+
// Suppress identity + audit fields from the body; they surface via the audit header's Details modal.
|
|
1000
|
+
if (config.RecordSetReadSuppressAuditFields !== false)
|
|
1001
|
+
{
|
|
1002
|
+
this._suppressAuditDescriptors(tmpManifest);
|
|
1003
|
+
}
|
|
698
1004
|
if (setBaseManifest)
|
|
699
1005
|
{
|
|
700
1006
|
this.manifest = tmpManifest;
|
|
@@ -146,7 +146,7 @@ declare class FilterDataProvider extends libPictProvider {
|
|
|
146
146
|
* @param {string} pViewContext - The current view context
|
|
147
147
|
* @return {boolean} - Returns true when the settings have been saved.
|
|
148
148
|
*/
|
|
149
|
-
saveFilterMeta(pRecordSet: string, pViewContext: string): boolean;
|
|
149
|
+
saveFilterMeta(pRecordSet: string, pViewContext: string, pSilent: any, pDisplayNameOverride: any): boolean;
|
|
150
150
|
/** ===== LAST USED Filter Experience ============= */
|
|
151
151
|
/**
|
|
152
152
|
* Save the application metadata as the last used filter experience (continually updated).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Filter-Data-Provider.d.ts","sourceRoot":"","sources":["../../source/providers/Filter-Data-Provider.js"],"names":[],"mappings":";AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuCE;AAIF;IAEC;;;;OAIG;IACH,oBAJW,OAAO,MAAM,CAAC,aACd,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,iBACnB,MAAM,EAgBhB;IARA,qBAA2B;IAC3B,aAAkB;IAMlB,6CAAgD;IAQjD,wDAAwD;IAExD;;;;;;;OAOG;IACH,uDALW,MAAM,eACN,MAAM,iBACN,MAAM,GACL,MAAM,CAgCjB;IAED;;;;;OAKG;IACH,qDAJW,MAAM,cACN,MAAM,gBACN,MAAM,
|
|
1
|
+
{"version":3,"file":"Filter-Data-Provider.d.ts","sourceRoot":"","sources":["../../source/providers/Filter-Data-Provider.js"],"names":[],"mappings":"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"}
|
|
@@ -75,7 +75,28 @@ declare class viewFilterPersistenceView extends libPictView {
|
|
|
75
75
|
* @param {function} [pCallback] - A callback function to be executed after saving the settings.
|
|
76
76
|
* @returns {boolean} - Returns true when the settings have been saved.
|
|
77
77
|
*/
|
|
78
|
-
|
|
78
|
+
/** HTML-escape a value for safe display in the modal. */
|
|
79
|
+
_escapeHTML(pValue: any): string;
|
|
80
|
+
/** Describe a single active filter clause in plain English (e.g. "Date Created between A and B"). */
|
|
81
|
+
_describeFilterClause(pClause: any): string;
|
|
82
|
+
/**
|
|
83
|
+
* @returns {{ summary: string, count: string }} A plain-English summary of the current
|
|
84
|
+
* search + filter clauses, and the matched record count (from the rendered list total).
|
|
85
|
+
*/
|
|
86
|
+
_describeCurrentFilter(): {
|
|
87
|
+
summary: string;
|
|
88
|
+
count: string;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Prompt for a name (via pict-section-modal when available) and save the current search +
|
|
92
|
+
* filters as a named experience. The modal previews the filter in plain English and the
|
|
93
|
+
* number of records it matches. Falls back to the generated name with no prompt if the
|
|
94
|
+
* modal section is not registered in the host app.
|
|
95
|
+
*
|
|
96
|
+
* @param {Event} pEvent
|
|
97
|
+
*/
|
|
98
|
+
promptSaveFilterExperience(pEvent: Event): boolean;
|
|
99
|
+
saveFilterPersistenceSettings(event: any, pCallback: any): boolean;
|
|
79
100
|
/**
|
|
80
101
|
* Sets the filter experience as the default for the current record set and view context.
|
|
81
102
|
* @param {Event} event - The event object.
|
|
@@ -112,7 +133,7 @@ declare namespace _DEFAULT_CONFIGURATION_FilterPersistenceView {
|
|
|
112
133
|
let AutoRenderOrdinal: number;
|
|
113
134
|
let AutoSolveWithApp: boolean;
|
|
114
135
|
let AutoSolveOrdinal: number;
|
|
115
|
-
let CSS:
|
|
136
|
+
let CSS: string;
|
|
116
137
|
let CSSPriority: number;
|
|
117
138
|
let Templates: {
|
|
118
139
|
Hash: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Filter-PersistenceView.d.ts","sourceRoot":"","sources":["../../source/views/Filter-PersistenceView.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"Filter-PersistenceView.d.ts","sourceRoot":"","sources":["../../source/views/Filter-PersistenceView.js"],"names":[],"mappings":";AA4EA;IAEC,2DASC;IAJA,yBAA4B;IAC5B,2BAA8B;IAC9B,+BAAqC;IACrC,qCAAwC;IAsBzC;;;;;;OAMG;IACH,8CALW,MAAM,gBACN,MAAM,wBAEJ,OAAO,CAqCnB;IAED;;;;;OAKG;IACH,8DAJW,MAAM,gBACN,MAAM,qCACN,OAAO,QA0BjB;IAED;;;;;;OAMG;IACH,oCALW,MAAM,gBACN,MAAM,wBAEJ,OAAO,CAYnB;IAED;;;OAGG;IACH,mCA2BC;IAED;;;;;;OAMG;IACH,2CALW,MAAM,gBACN,MAAM,aACN,MAAM,GACJ,OAAO,CAenB;IAED;;;;OAIG;IACH,sCAHW,KAAK,GACH,OAAO,CA6BnB;IAED;;;OAGG;IACH,4BAFa,OAAO,CAmBnB;IAED;;;OAGG;IACH,mDAFa,OAAO,CA+CnB;IAED;;;;OAIG;IACH,8CAHW,KAAK,GACH,OAAO,CAcnB;IAED;;;;OAIG;IACH,qCAHW,KAAK,mBACH,OAAO,CAqBnB;IAED;;;;;OAKG;IACH,yDAAyD;IACzD,iCAGC;IAED,qGAAqG;IACrG,4CAoBC;IAED;;;OAGG;IACH,0BAHa;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAqB9C;IAED;;;;;;;OAOG;IACH,mCAFW,KAAK,WA+Cf;IAED,mEA0BC;IAED;;;;;;OAMG;IACH,0CALW,KAAK,aACL,OAAO,yBAEL,OAAO,CAyBnB;IAED;;;OAGG;IACH,uCAFW,OAAO,QA4BjB;IAED;;;;;OAKG;IACH,uCAJW,KAAK,yBAEH,OAAO,CAsBnB;CACD"}
|
|
@@ -18,6 +18,8 @@ declare class ViewRecordSetSUBSETFilters extends libPictView {
|
|
|
18
18
|
newFilterSearchApplied: boolean;
|
|
19
19
|
addFilterCallback: Function;
|
|
20
20
|
removeFilterCallback: Function;
|
|
21
|
+
_drawerOpen: boolean;
|
|
22
|
+
_searchString: {};
|
|
21
23
|
_renderEpoch: number;
|
|
22
24
|
/**
|
|
23
25
|
* Bump the render epoch. Call this whenever the active filter clauses are
|
|
@@ -64,6 +66,27 @@ declare class ViewRecordSetSUBSETFilters extends libPictView {
|
|
|
64
66
|
* @returns {any} The result of the super.onMarshalToView() method.
|
|
65
67
|
*/
|
|
66
68
|
onMarshalToView(): any;
|
|
69
|
+
/** Toggle the slide-out filter drawer beneath the search bar. */
|
|
70
|
+
toggleFilterDrawer(): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* The current search term, read back from the active route URL (the source of truth) so
|
|
73
|
+
* the search box stays populated across re-renders and reflects bookmarked/filtered URLs.
|
|
74
|
+
* performSearch builds `.../FilteredTo/FBVOR~<field>~LK~<encoded %term%>~...` from the
|
|
75
|
+
* SearchFields, so the term is the first LK value in the FilteredTo segment.
|
|
76
|
+
*
|
|
77
|
+
* @return {string}
|
|
78
|
+
*/
|
|
79
|
+
_searchTermFromURL(): string;
|
|
80
|
+
/** The number of active (structured) filter clauses for a record set. */
|
|
81
|
+
getActiveFilterCount(pRecordSet: any): number;
|
|
82
|
+
/**
|
|
83
|
+
* Repaint the filter-bar chrome after a (re)render: the filters icon (outline vs filled
|
|
84
|
+
* + count badge), the active-filter highlight, the persisted drawer-open state, and the
|
|
85
|
+
* search input value (so applying a search no longer clears the search box).
|
|
86
|
+
*
|
|
87
|
+
* @param {string} pRecordSet
|
|
88
|
+
*/
|
|
89
|
+
_paintFilterControls(pRecordSet: string): void;
|
|
67
90
|
/**
|
|
68
91
|
* @param {Event} pEvent - The DOM event that triggered the search
|
|
69
92
|
* @param {string} pRecordSet - The record set being filtered
|
|
@@ -159,9 +182,11 @@ declare class ViewRecordSetSUBSETFilters extends libPictView {
|
|
|
159
182
|
decode(base64: string): ArrayBuffer;
|
|
160
183
|
}
|
|
161
184
|
declare namespace ViewRecordSetSUBSETFilters {
|
|
162
|
-
export { _DEFAULT_CONFIGURATION_SUBSET_Filter as default_configuration };
|
|
185
|
+
export { FilterIconOutline, FilterIconFilled, _DEFAULT_CONFIGURATION_SUBSET_Filter as default_configuration };
|
|
163
186
|
}
|
|
164
187
|
import libPictView = require("pict-view");
|
|
188
|
+
declare var FilterIconOutline: string;
|
|
189
|
+
declare var FilterIconFilled: string;
|
|
165
190
|
/** @type {Record<string, any>} */
|
|
166
191
|
declare const _DEFAULT_CONFIGURATION_SUBSET_Filter: Record<string, any>;
|
|
167
192
|
//# sourceMappingURL=RecordSet-Filters.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RecordSet-Filters.d.ts","sourceRoot":"","sources":["../../source/views/RecordSet-Filters.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"RecordSet-Filters.d.ts","sourceRoot":"","sources":["../../source/views/RecordSet-Filters.js"],"names":[],"mappings":";AAgRA;IAEC,2DA2CC;IAvCA,kHAAkH;IAClH,MADW,GAAe,GAAG,OAAO,MAAM,CAAC,GAAG;QAAE,oBAAoB,EAAE;;;;;;;;SAAsC,CAAA;KAAE,CACrG;IAeT,cAA+E;IAG/E,wCAA0E;IAK1E,gCAAmC;IACnC,4BAA6B;IAC7B,+BAAgC;IAGhC,qBAAwB;IACxB,kBAAuB;IAQvB,qBAAqB;IAGtB;;;;;OAKG;IACH,mBAFY,MAAM,CAMjB;IAED;;;OAGG;IACH,gDAGC;IAED;;;OAGG;IACH,mDAGC;IAED;;OAEG;IACH,gCAGC;IAED;;OAEG;IACH,mCAGC;IAED;;OAEG;IACH,6BAFY,MAAM,CAKjB;IAED;;;;OAIG;IACH,kCAJW,MAAM,GAEL,GAAG,CAMd;IAKD;;;OAGG;IACH,qBAFa,GAAG,CAaf;IAED;;;OAGG;IACH,mBAFa,GAAG,CAaf;IAED,iEAAiE;IACjE,8BAMC;IAED;;;;;;;OAOG;IACH,sBAFY,MAAM,CAcjB;IAED,yEAAyE;IACzE,8CAKC;IAED;;;;;;OAMG;IACH,iCAFW,MAAM,QAehB;IAED;;;;OAIG;IACH,qBAJW,KAAK,cACL,MAAM,gBACN,MAAM,QAUhB;IAED;;;;OAIG;IACH,0BAJW,MAAM,gBACN,MAAM,kBACN,MAAM,QAsDhB;IAED;;;;;OAKG;IACH,oBAJW,KAAK,cACL,MAAM,gBACN,MAAM,QAWhB;IAGD;;;;;OAKG;IACH,oBAJW,KAAK,cACL,MAAM,gBACN,MAAM,QAoBhB;IAED;;;;;MAKE;IACF,qBALW,KAAK,cACL,MAAM,gBACN,MAAM,GACJ,OAAO,CAQnB;IAED;;;;OAIG;IACH,0BAJW,KAAK,cACL,MAAM,gBACN,MAAM,QAQhB;IAED;;;;;;OAMG;IACH,kBANW,KAAK,cACL,MAAM,gBACN,MAAM,cACN,MAAM,cACN,MAAM,QAWhB;IAED;;;;;OAKG;IACH,qBALW,KAAK,cACL,MAAM,gBACN,MAAM,sBACN,MAAM,QAWhB;IAED;;;;OAIG;IACH,4BAHW,MAAM,GACL,KAAK,CAAC,GAAG,CAAC,CAMrB;IAmHD;;;;OAIG;IACH,uCAHW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAClB,OAAO,CAAC,MAAM,CAAC,CAiB1B;IAED;;;;OAIG;IACH,yCAHW,MAAM,GACL,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAUvC;IAED;;;;OAIG;IACH,iBAJW,MAAM,aACN,iBAAiB,GAChB,OAAO,CAAC,WAAW,CAAC,CAU/B;IAED;;;OAGG;IACH,sBAHW,UAAU,aACV,iBAAiB,mBAa3B;IAED;;;OAGG;IACH,oBAHW,WAAW,GACV,MAAM,CA2BjB;IAED;;;OAGG;IACH,eAHW,MAAM,GACL,WAAW,CAsCtB;CACD;;;;;;;AA75BD,kCAAkC;AAClC,oDADW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAgO5B"}
|
|
@@ -8,6 +8,20 @@ declare class ViewRecordSetSUBSETFilterBase extends libPictView {
|
|
|
8
8
|
*/
|
|
9
9
|
prepareRecord(pRecord: Record<string, any>): void;
|
|
10
10
|
getFilterFormTemplate(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Remove this filter clause from its record set and re-render the filter control.
|
|
13
|
+
*
|
|
14
|
+
* Lives on the base view so every filter type inherits a single, themeable remove
|
|
15
|
+
* affordance and no host application has to re-implement one. Delegates to the
|
|
16
|
+
* consolidated control view (the canonical re-render path) and falls back to the
|
|
17
|
+
* record-set provider directly if that view is somehow unavailable.
|
|
18
|
+
*
|
|
19
|
+
* @param {Event} pEvent - The DOM event that triggered the removal.
|
|
20
|
+
* @param {string} pRecordSet - The record set being filtered.
|
|
21
|
+
* @param {string} pViewContext - The view context for the filter (e.g. List, Dashboard).
|
|
22
|
+
* @param {string} pHash - The hash of the specific filter clause to remove.
|
|
23
|
+
*/
|
|
24
|
+
removeClause(pEvent: Event, pRecordSet: string, pViewContext: string, pHash: string): any;
|
|
11
25
|
/**
|
|
12
26
|
* @return {string} - The prefix for the informary address.
|
|
13
27
|
*/
|