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.
Files changed (69) hide show
  1. package/package.json +5 -1
  2. package/source/providers/Filter-Data-Provider.js +16 -5
  3. package/source/views/Filter-PersistenceView.js +150 -35
  4. package/source/views/RecordSet-Filters.js +230 -28
  5. package/source/views/filters/RecordSet-Filter-Base.js +86 -8
  6. package/source/views/read/RecordSet-Read.js +308 -2
  7. package/types/providers/Filter-Data-Provider.d.ts +1 -1
  8. package/types/providers/Filter-Data-Provider.d.ts.map +1 -1
  9. package/types/views/Filter-PersistenceView.d.ts +23 -2
  10. package/types/views/Filter-PersistenceView.d.ts.map +1 -1
  11. package/types/views/RecordSet-Filters.d.ts +26 -1
  12. package/types/views/RecordSet-Filters.d.ts.map +1 -1
  13. package/types/views/filters/RecordSet-Filter-Base.d.ts +14 -0
  14. package/types/views/filters/RecordSet-Filter-Base.d.ts.map +1 -1
  15. package/types/views/list/RecordSet-List.d.ts.map +1 -1
  16. package/types/views/read/RecordSet-Read.d.ts +51 -0
  17. package/types/views/read/RecordSet-Read.d.ts.map +1 -1
  18. package/.vscode/launch.json +0 -46
  19. package/CONTRIBUTING.md +0 -50
  20. package/debug/Harness.js +0 -0
  21. package/docs/.nojekyll +0 -0
  22. package/docs/README.md +0 -76
  23. package/docs/_brand.json +0 -18
  24. package/docs/_cover.md +0 -11
  25. package/docs/_sidebar.md +0 -19
  26. package/docs/_version.json +0 -7
  27. package/docs/api-reference.md +0 -233
  28. package/docs/filters.md +0 -151
  29. package/docs/index.html +0 -38
  30. package/docs/record-providers.md +0 -155
  31. package/docs/retold-catalog.json +0 -87
  32. package/docs/retold-keyword-index.json +0 -5227
  33. package/docs/views/create/README.md +0 -181
  34. package/docs/views/dashboard/README.md +0 -308
  35. package/docs/views/list/README.md +0 -260
  36. package/docs/views/read/README.md +0 -216
  37. package/eslint.config.mjs +0 -10
  38. package/example_applications/README.md +0 -39
  39. package/example_applications/ServeExamples.js +0 -82
  40. package/example_applications/bookstore/.quackage.json +0 -9
  41. package/example_applications/bookstore/Bookstore-Application-Configuration.json +0 -4
  42. package/example_applications/bookstore/Bookstore-Application.js +0 -671
  43. package/example_applications/bookstore/css/bookstore.css +0 -729
  44. package/example_applications/bookstore/css/pure.min.css +0 -11
  45. package/example_applications/bookstore/html/index.html +0 -46
  46. package/example_applications/bookstore/package.json +0 -34
  47. package/example_applications/bookstore/providers/PictRouter-Bookstore.json +0 -32
  48. package/example_applications/bookstore/views/PictView-Bookstore-Content-About.json +0 -21
  49. package/example_applications/bookstore/views/PictView-Bookstore-Content-Legal.json +0 -21
  50. package/example_applications/bookstore/views/PictView-Bookstore-Dashboard.js +0 -147
  51. package/example_applications/bookstore/views/PictView-Bookstore-Layout.js +0 -85
  52. package/example_applications/bookstore/views/PictView-Bookstore-Login.js +0 -58
  53. package/example_applications/bookstore/views/PictView-Bookstore-Navigation.js +0 -228
  54. package/example_applications/index.html +0 -50
  55. package/example_applications/mocks/book-edit-view.html +0 -173
  56. package/example_applications/mocks/book-read-view.html +0 -166
  57. package/example_applications/mocks/list-view.html +0 -185
  58. package/example_applications/package.json +0 -16
  59. package/example_applications/simple_entity/.quackage.json +0 -9
  60. package/example_applications/simple_entity/README-Simple-RecordSet.md +0 -8
  61. package/example_applications/simple_entity/Simple-RecordSet-Application.js +0 -887
  62. package/example_applications/simple_entity/html/index.html +0 -207
  63. package/example_applications/simple_entity/package.json +0 -27
  64. package/test/PictSectionRecordSet-Basic_tests.js +0 -205
  65. package/test/PictSectionRecordSet-Filter-Data-Provider_tests.js +0 -263
  66. package/test/PictSectionRecordSet-Filter-InstanceViews-Render_tests.js +0 -328
  67. package/test/PictSectionRecordSet-RecordProvider-Meadow_tests.js +0 -216
  68. package/tsconfig.build.json +0 -16
  69. 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
- CSS: false,
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
- <button type="button"
46
- onclick="_Pict.views['PRSP-Filters'].removeFilter(event, '{~D:Record.RecordSet~}', '{~D:Record.ViewContext~}', '{~D:Record.Hash~}');"
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: false,
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> &middot; {~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(), 'CreatingIDUser', 'UpdatingIDUser', 'DeletingIDUser', 'Deleted', 'CreateDate', 'UpdateDate', 'DeleteDate', 'Deleted'];
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":"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"}
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
- saveFilterPersistenceSettings(event: Event, pCallback?: Function): boolean;
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: boolean;
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":";AAuFA;IAEC,2DASC;IAJA,yBAA4B;IAC5B,2BAA8B;IAC9B,+BAAqC;IACrC,qCAAwC;IAIzC;;;;;;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,qCAJW,KAAK,yBAEH,OAAO,CA4BnB;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"}
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":";AA6MA;IAEC,2DAuCC;IAnCA,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;IAQhC,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;;;;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,QAUhB;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;IAmDD;;;;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;;;;;AAxtBD,kCAAkC;AAClC,oDADW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA6J5B"}
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
  */