pict-section-recordset 1.7.0 → 1.8.1
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 +4 -4
- package/source/providers/RecordSet-RecordProvider-MeadowEndpoints.js +39 -6
- package/source/services/RecordsSet-MetaController.js +6 -0
- package/source/views/RecordSet-Filters.js +20 -12
- package/source/views/filters/RecordSet-Filter-EntityReference-Base.js +1 -0
- package/source/views/list/RecordSet-List-RecordListEntry.js +82 -31
- package/source/views/list/RecordSet-List-RecordListHeader.js +3 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pict-section-recordset",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "Pict dynamic record set management views",
|
|
5
5
|
"main": "source/Pict-Section-RecordSet.js",
|
|
6
6
|
"files": [
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
"browser-env": "^3.3.0",
|
|
38
38
|
"eslint": "^9.28.0",
|
|
39
39
|
"jquery": "^3.7.1",
|
|
40
|
-
"pict": "^1.0.
|
|
40
|
+
"pict": "^1.0.373",
|
|
41
41
|
"pict-application": "^1.0.34",
|
|
42
|
-
"pict-docuserve": "^1.4.
|
|
42
|
+
"pict-docuserve": "^1.4.19",
|
|
43
43
|
"pict-service-commandlineutility": "^1.0.19",
|
|
44
44
|
"quackage": "^1.3.0",
|
|
45
45
|
"typescript": "^5.9.3"
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"fable-serviceproviderbase": "^3.0.19",
|
|
49
49
|
"pict-provider": "^1.0.13",
|
|
50
50
|
"pict-router": "^1.0.10",
|
|
51
|
-
"pict-section-form": "^1.
|
|
51
|
+
"pict-section-form": "^1.1.9",
|
|
52
52
|
"pict-template": "^1.0.15",
|
|
53
53
|
"pict-view": "^1.0.68",
|
|
54
54
|
"sinon": "^21.0.1"
|
|
@@ -262,7 +262,7 @@ class MeadowEndpointsRecordSetProvider extends libRecordSetProviderBase
|
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
264
|
}
|
|
265
|
-
this.pict.EntityProvider.cacheConnectedEntityRecords(recordsReturn, IDFields, ['User', 'User'], false, () =>
|
|
265
|
+
this.pict.EntityProvider.cacheConnectedEntityRecords(recordsReturn, IDFields, ['User', 'User'], false, () =>
|
|
266
266
|
{
|
|
267
267
|
resolve({ Records: recordsReturn, Facets: { } });
|
|
268
268
|
});
|
|
@@ -304,6 +304,17 @@ class MeadowEndpointsRecordSetProvider extends libRecordSetProviderBase
|
|
|
304
304
|
return new Promise((resolve, reject) =>
|
|
305
305
|
{
|
|
306
306
|
const [ tmpClauses, tmpExperience ] = this._prepareFilterState(tmpEntity, pOptions, 'Count');
|
|
307
|
+
// The record count is identical for every page of the same filter, yet the list re-counts on each
|
|
308
|
+
// pagination click. A COUNT is expensive on some database engines, so cache it keyed by the compiled
|
|
309
|
+
// filter signature: same filter -> serve the cached count (no request); changed filter -> re-count.
|
|
310
|
+
// Mutations through this provider clear the cache (see createRecord / updateRecord / deleteRecord).
|
|
311
|
+
const tmpCountCacheKey = `${ tmpEntity }::${ JSON.stringify(tmpClauses) }`;
|
|
312
|
+
if (this._RecordSetCountCache && this._RecordSetCountCache.Key === tmpCountCacheKey)
|
|
313
|
+
{
|
|
314
|
+
// Publish the cached count to the result address so downstream consumers behave identically to a fetch.
|
|
315
|
+
this.fable.manifest.setValueByHash(this.pict, tmpExperience.ResultDestinationAddress, this._RecordSetCountCache.Count);
|
|
316
|
+
return resolve({ Count: this._RecordSetCountCache.Count });
|
|
317
|
+
}
|
|
307
318
|
if (this.options.FilterEndpointOverride)
|
|
308
319
|
{
|
|
309
320
|
// Call the filtering endpoint with the clauses and experience.
|
|
@@ -316,7 +327,9 @@ class MeadowEndpointsRecordSetProvider extends libRecordSetProviderBase
|
|
|
316
327
|
{
|
|
317
328
|
return reject(error);
|
|
318
329
|
}
|
|
319
|
-
|
|
330
|
+
const tmpCount = result?.Count || 0;
|
|
331
|
+
this.fable.manifest.setValueByHash(this.pict, tmpExperience.ResultDestinationAddress, tmpCount);
|
|
332
|
+
this._RecordSetCountCache = { Key: tmpCountCacheKey, Count: tmpCount };
|
|
320
333
|
resolve(result);
|
|
321
334
|
});
|
|
322
335
|
return;
|
|
@@ -327,7 +340,9 @@ class MeadowEndpointsRecordSetProvider extends libRecordSetProviderBase
|
|
|
327
340
|
{
|
|
328
341
|
return reject(pError);
|
|
329
342
|
}
|
|
330
|
-
|
|
343
|
+
const tmpCount = this.pict.resolveStateFromAddress(tmpExperience.ResultDestinationAddress);
|
|
344
|
+
this._RecordSetCountCache = { Key: tmpCountCacheKey, Count: tmpCount };
|
|
345
|
+
resolve({ Count: tmpCount });
|
|
331
346
|
});
|
|
332
347
|
});
|
|
333
348
|
}
|
|
@@ -354,6 +369,8 @@ class MeadowEndpointsRecordSetProvider extends libRecordSetProviderBase
|
|
|
354
369
|
{
|
|
355
370
|
return reject(error);
|
|
356
371
|
}
|
|
372
|
+
// A new record changes the total; drop the cached count so the next render re-counts.
|
|
373
|
+
this._RecordSetCountCache = null;
|
|
357
374
|
resolve(result);
|
|
358
375
|
});
|
|
359
376
|
});
|
|
@@ -381,6 +398,8 @@ class MeadowEndpointsRecordSetProvider extends libRecordSetProviderBase
|
|
|
381
398
|
{
|
|
382
399
|
return reject(error);
|
|
383
400
|
}
|
|
401
|
+
// An edit can move a record in or out of the active filter; drop the cached count to be safe.
|
|
402
|
+
this._RecordSetCountCache = null;
|
|
384
403
|
resolve(result);
|
|
385
404
|
});
|
|
386
405
|
});
|
|
@@ -408,6 +427,8 @@ class MeadowEndpointsRecordSetProvider extends libRecordSetProviderBase
|
|
|
408
427
|
{
|
|
409
428
|
return reject(error);
|
|
410
429
|
}
|
|
430
|
+
// A delete changes the total; drop the cached count so the next render re-counts.
|
|
431
|
+
this._RecordSetCountCache = null;
|
|
411
432
|
resolve(result);
|
|
412
433
|
});
|
|
413
434
|
});
|
|
@@ -477,11 +498,19 @@ class MeadowEndpointsRecordSetProvider extends libRecordSetProviderBase
|
|
|
477
498
|
const tmpFieldHumanName = this.getHumanReadableFieldName(pSchemaField);
|
|
478
499
|
const isUserAuditField = ['CreatingIDUser', 'DeletingIDUser', 'UpdatingIDUser'].includes(pSchemaField);
|
|
479
500
|
const customFilterClauses = this.options.Filters?.[pSchemaField];
|
|
480
|
-
|
|
501
|
+
// The entity's own identity column (AutoIdentity / AutoGUID) — i.e. the primary key.
|
|
502
|
+
const isOwnIdentityField = pMeadowSchemaField && (pMeadowSchemaField.Type === 'AutoIdentity' || pMeadowSchemaField.Type === 'AutoGUID');
|
|
503
|
+
const isForeignKeyLike = pSchemaField.startsWith('ID') || pSchemaField.startsWith('ParentID') || isUserAuditField || customFilterClauses;
|
|
504
|
+
if (isForeignKeyLike)
|
|
481
505
|
{
|
|
482
506
|
for (const customField of Array.isArray(customFilterClauses) ? customFilterClauses : [customFilterClauses])
|
|
483
507
|
{
|
|
484
|
-
|
|
508
|
+
// The table the picker pulls from: an explicit RemoteTable, else this
|
|
509
|
+
// recordset's declared Entity when the column is our own primary key (the PK
|
|
510
|
+
// references our own records), else the name peeled from the column for a
|
|
511
|
+
// plain foreign key. Peeling alone is the defect — a lake PK like
|
|
512
|
+
// `IDC182_HMA_MixDesign` peels to a table name that is not the entity name.
|
|
513
|
+
const remoteTableName = customField?.RemoteTable || (isOwnIdentityField ? this.options.Entity : pSchemaField.split('ID')[1]);
|
|
485
514
|
const fieldName = this.getHumanReadableFieldName(pSchemaField);
|
|
486
515
|
tmpFieldFilterClauses.push(Object.assign(
|
|
487
516
|
{
|
|
@@ -491,6 +520,7 @@ class MeadowEndpointsRecordSetProvider extends libRecordSetProviderBase
|
|
|
491
520
|
"ExternalRecordDisplayTemplate": remoteTableName === 'User' ? '{~D:Record.Data.NameFirst~} {~D:Record.Data.NameLast~}' : '{~D:Record.Name~}',
|
|
492
521
|
"CoreConnectionColumn": pSchemaField,
|
|
493
522
|
"RemoteTable": `${ remoteTableName }`,
|
|
523
|
+
"URLPrefix": this.options.URLPrefix,
|
|
494
524
|
"JoinExternalConnectionColumn": `ID${ remoteTableName }`,
|
|
495
525
|
"JoinInternalConnectionColumn": pSchemaField,
|
|
496
526
|
'DisplayName': `Selected Records`,
|
|
@@ -500,7 +530,10 @@ class MeadowEndpointsRecordSetProvider extends libRecordSetProviderBase
|
|
|
500
530
|
}, customField));
|
|
501
531
|
}
|
|
502
532
|
}
|
|
503
|
-
|
|
533
|
+
// The primary key is also a plain integer key, so it ALSO falls through to the
|
|
534
|
+
// Exact / In Range clauses below. A real foreign key gets only the picker; ordinary
|
|
535
|
+
// columns are matched by type.
|
|
536
|
+
if (!isForeignKeyLike || isOwnIdentityField)
|
|
504
537
|
{
|
|
505
538
|
switch (tmpFieldType)
|
|
506
539
|
{
|
|
@@ -186,6 +186,12 @@ class RecordSetMetacontroller extends libFableServiceProviderBase
|
|
|
186
186
|
return false;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
// Normalize the whole-row-click opt-in to a STRICT boolean. The action-cell and column-header
|
|
190
|
+
// templates branch on it with TIfAbs's TRUE/FALSE operators, which test `=== true` / `=== false`.
|
|
191
|
+
// An absent (undefined) or loose ('true') value would satisfy neither branch, leaving the actions
|
|
192
|
+
// column empty — so coerce it to a real true/false here, once, for every render path.
|
|
193
|
+
pRecordSetConfiguration.RowClickOpensRecord = (pRecordSetConfiguration.RowClickOpensRecord === true || pRecordSetConfiguration.RowClickOpensRecord === 'true');
|
|
194
|
+
|
|
189
195
|
let tmpExtraColumnHeaderTemplateHash = `RecordSet-List-ExtraColumnHeader-${pRecordSetConfiguration.RecordSet}`;
|
|
190
196
|
pRecordSetConfiguration.RecordSetListExtraColumnsHeaderTemplateHash = tmpExtraColumnHeaderTemplateHash;
|
|
191
197
|
let tmpExtraColumnRowTemplateHash = `RecordSet-List-ExtraColumnRow-${pRecordSetConfiguration.RecordSet}`;
|
|
@@ -52,11 +52,15 @@ const _DEFAULT_CONFIGURATION_SUBSET_Filter =
|
|
|
52
52
|
border: 1px solid var(--theme-color-border-default, #d7dce3); background: transparent; color: var(--theme-color-text-secondary, #45505f); }
|
|
53
53
|
.prsp-filters-btn-text:hover { background: var(--theme-color-background-tertiary, #eceef2); }
|
|
54
54
|
|
|
55
|
-
/* Slide-out drawer (CSS grid trick: 0fr -> 1fr animates height).
|
|
55
|
+
/* Slide-out drawer (CSS grid trick: 0fr -> 1fr animates height). The inner is a *pure* clip box; all the
|
|
56
|
+
visible card chrome lives on .prsp-filters-drawer-card inside it. That way, on collapse the chrome shrinks
|
|
57
|
+
*with* the animating height instead of vanishing instantly — the old rule gated padding/border/background
|
|
58
|
+
on .drawer-open, so closing the drawer stripped the card in one frame while the height still animated for
|
|
59
|
+
0.18s, making the quick-filters bar look like it popped out of the panel before disappearing. */
|
|
56
60
|
.prsp-filters-drawer { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.18s ease; }
|
|
57
61
|
.prsp-filters.drawer-open .prsp-filters-drawer { grid-template-rows: 1fr; }
|
|
58
62
|
.prsp-filters-drawer-inner { overflow: hidden; min-height: 0; }
|
|
59
|
-
.prsp-filters
|
|
63
|
+
.prsp-filters-drawer-card { margin-top: 0.6rem; padding: 0.95rem 1.1rem;
|
|
60
64
|
border: 1px solid var(--theme-color-border-light, #e8ebf0); border-radius: 10px; background: var(--theme-color-background-panel, #fff); }
|
|
61
65
|
.prsp-filters-add { position: relative; margin: 0.4rem 0 0.2rem; }
|
|
62
66
|
.prsp-addfilter-trigger { display: inline-flex; align-items: center; gap: 0.35rem; }
|
|
@@ -133,16 +137,20 @@ const _DEFAULT_CONFIGURATION_SUBSET_Filter =
|
|
|
133
137
|
</form>
|
|
134
138
|
<div class="prsp-filters-drawer" id="PRSP_Filter_Drawer">
|
|
135
139
|
<div class="prsp-filters-drawer-inner">
|
|
136
|
-
<!--
|
|
137
|
-
|
|
138
|
-
<div class="prsp-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
{~T:PRSP-SUBSET-Filters-Template-
|
|
140
|
+
<!-- The card carries all the panel chrome and lives *inside* the clip box, so it collapses
|
|
141
|
+
together with the animating height (see .prsp-filters-drawer-card in CSS). -->
|
|
142
|
+
<div class="prsp-filters-drawer-card">
|
|
143
|
+
<!-- Quick Filters: a curated, one-interaction bar painted post-render into this host
|
|
144
|
+
(empty when the record set has no quick filters → CSS :empty hides it). -->
|
|
145
|
+
<div class="prsp-quickfilters" id="PRSP_QuickFilters"></div>
|
|
146
|
+
<div id="PRSP_Filter_Instances" class="prsp-filters-clauses" onkeydown="if (event.key === 'Enter' && !event.target.closest('.pps')) { event.preventDefault(); _Pict.views['PRSP-Filters'].handleSearch(event, '{~D:Record.RecordSet~}', '{~D:Record.ViewContext~}'); }">
|
|
147
|
+
{~FIV:Record~}
|
|
148
|
+
</div>
|
|
149
|
+
{~T:PRSP-SUBSET-Filters-Template-AddFilter-Fieldset~}
|
|
150
|
+
<div class="prsp-filters-footer">
|
|
151
|
+
{~T:PRSP-SUBSET-Filters-Template-ManageFilters-Fieldset~}
|
|
152
|
+
{~T:PRSP-SUBSET-Filters-Template-DrawerActions-Fieldset~}
|
|
153
|
+
</div>
|
|
146
154
|
</div>
|
|
147
155
|
</div>
|
|
148
156
|
</div>
|
|
@@ -230,6 +230,7 @@ class ViewRecordSetSUBSETFilterEntityReferenceBase extends ViewRecordSetSUBSETFi
|
|
|
230
230
|
Destination: pOffset > 0 ? `${this.getInformaryAddressPrefix()}${pClauseInformaryAddress}.SearchResultsAppend` : `${this.getInformaryAddressPrefix()}${pClauseInformaryAddress}.SearchResults`,
|
|
231
231
|
RecordStartCursor: pOffset,
|
|
232
232
|
PageSize: this.options.PageSize,
|
|
233
|
+
URLPrefix: tmpClause.URLPrefix,
|
|
233
234
|
}
|
|
234
235
|
],
|
|
235
236
|
() =>
|
|
@@ -22,7 +22,36 @@ const _DEFAULT_CONFIGURATION_List_RecordListEntry = (
|
|
|
22
22
|
AutoSolveWithApp: false,
|
|
23
23
|
AutoSolveOrdinal: 0,
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
// Record-list row chrome. Host apps brand it via --theme-color-* tokens; the hardcoded values
|
|
26
|
+
// are fallbacks.
|
|
27
|
+
CSS: /*css*/`
|
|
28
|
+
/* Vertically center every cell's content so the text lines up with the action control (it was
|
|
29
|
+
top-aligned, which read as off next to the centered action cell). */
|
|
30
|
+
#PRSP_List_Table td { vertical-align: middle; }
|
|
31
|
+
|
|
32
|
+
/* Row-as-button (opt-in via the RowClickOpensRecord record-set config flag): clicking anywhere in the
|
|
33
|
+
row — except the action cell — follows the record's default link. */
|
|
34
|
+
.prsp-list-row.prsp-row-clickable { cursor: pointer; }
|
|
35
|
+
.prsp-list-row.prsp-row-clickable:hover { background: var(--theme-color-background-hover, var(--theme-color-background-tertiary, #f1f3f7)); }
|
|
36
|
+
|
|
37
|
+
/* Per-row action menu: a subtle three-dot trigger, revealed on row hover, that opens a small popover
|
|
38
|
+
of the record's links (View, …). Clicks inside it never trigger the row navigation. */
|
|
39
|
+
.prsp-row-actions { white-space: nowrap; text-align: right; width: 1%; }
|
|
40
|
+
.prsp-row-actions-wrap { position: relative; display: inline-block; }
|
|
41
|
+
.prsp-row-actions-trigger { display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
|
|
42
|
+
border: none; background: transparent; line-height: 1; padding: 0.2rem 0.5rem; border-radius: 6px; font-size: 1.05rem;
|
|
43
|
+
color: var(--theme-color-text-muted, #6b7686); opacity: 0; transition: opacity 0.12s ease, background 0.12s ease, color 0.12s ease; }
|
|
44
|
+
.prsp-list-row:hover .prsp-row-actions-trigger, .prsp-row-actions-wrap.open .prsp-row-actions-trigger { opacity: 1; }
|
|
45
|
+
.prsp-row-actions-trigger:hover { background: var(--theme-color-background-tertiary, #eceef2); color: var(--theme-color-text-primary, #1f2733); }
|
|
46
|
+
.prsp-row-actions-menu { position: absolute; right: 0; top: calc(100% + 2px); z-index: 30; min-width: 9rem; display: none;
|
|
47
|
+
background: var(--theme-color-background-panel, #fff); border: 1px solid var(--theme-color-border-default, #d7dce3);
|
|
48
|
+
border-radius: 9px; box-shadow: 0 10px 26px rgba(17, 24, 39, 0.16); padding: 0.25rem; text-align: left; }
|
|
49
|
+
.prsp-row-actions-wrap:hover .prsp-row-actions-menu, .prsp-row-actions-wrap.open .prsp-row-actions-menu { display: block; }
|
|
50
|
+
.prsp-row-actions-menu ul { list-style: none; margin: 0; padding: 0; }
|
|
51
|
+
.prsp-row-actions-menu li > a { display: block; padding: 0.4rem 0.65rem; border-radius: 6px; text-decoration: none; white-space: nowrap;
|
|
52
|
+
color: var(--theme-color-text-primary, #1f2733); font-size: 0.9rem; }
|
|
53
|
+
.prsp-row-actions-menu li > a:hover { background: var(--theme-color-background-tertiary, #eceef2); }
|
|
54
|
+
`,
|
|
26
55
|
CSSPriority: 500,
|
|
27
56
|
|
|
28
57
|
Templates:
|
|
@@ -36,61 +65,84 @@ const _DEFAULT_CONFIGURATION_List_RecordListEntry = (
|
|
|
36
65
|
},
|
|
37
66
|
{
|
|
38
67
|
Hash: 'PRSP-List-RecordListEntry-Template-Row',
|
|
68
|
+
// The whole row is a click target for the record's default link — opt-in via the
|
|
69
|
+
// RowClickOpensRecord record-set config flag (which adds prsp-row-clickable). The onclick
|
|
70
|
+
// only fires when that class is present, skips clicks inside the action cell, and follows
|
|
71
|
+
// the default link (data-prsp-default) only — so a host-overridden action cell with no
|
|
72
|
+
// default link makes the row click a harmless no-op.
|
|
39
73
|
Template: /*html*/`
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
74
|
+
<!-- DefaultPackage pict view template: [PRSP-List-RecordListEntry-Template] -->
|
|
75
|
+
<tr class="prsp-list-row{~NE:Record.Payload.RecordSetConfiguration.RowClickOpensRecord^ prsp-row-clickable~}" onclick="if (this.classList.contains('prsp-row-clickable') && !event.target.closest('.prsp-row-actions')) { var tmpDefaultLink = this.querySelector('.prsp-row-actions a[data-prsp-default]'); if (tmpDefaultLink) { tmpDefaultLink.click(); } }">
|
|
76
|
+
{~TSWP:PRSP-List-RecordListEntry-Template-Row-Cell:Record.Payload.TableCells:Record.Data~}
|
|
77
|
+
{~T:PRSP-List-RecordListHeader-Template-Extra-Row~}
|
|
78
|
+
{~T:PRSP-List-RecordListAction-Template-Cell~}
|
|
79
|
+
</tr>
|
|
80
|
+
<!-- DefaultPackage end view template: [PRSP-List-RecordListEntry-Template] -->
|
|
47
81
|
`
|
|
48
|
-
//
|
|
49
|
-
|
|
50
82
|
},
|
|
51
83
|
{
|
|
52
84
|
Hash: 'PRSP-List-RecordListHeader-Template-Extra-Row',
|
|
53
85
|
Template: /*html*/`
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
86
|
+
<!-- DefaultPackage pict view template: [PRSP-List-RecordListHeader-Template-Extra-Row] -->
|
|
87
|
+
{~TBR:Record.Payload.RecordSetConfiguration.RecordSetListExtraColumnRowTemplateHash~}
|
|
88
|
+
<!-- DefaultPackage end view template: [PRSP-List-RecordListHeader-Extra-Row] -->
|
|
57
89
|
`
|
|
58
|
-
// {~TBR:Record.Payload.RecordSetConfiguration.RecordSetListExtraColumnRowTemplateHash~}
|
|
59
|
-
|
|
60
90
|
},
|
|
61
91
|
{
|
|
62
92
|
Hash: 'PRSP-List-RecordListEntry-Template-Row-Cell',
|
|
63
93
|
Template: /*html*/`
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
94
|
+
<td style="border-bottom: 1px solid var(--theme-color-border-default, #ccc); padding: 5px;">
|
|
95
|
+
{~TBDA:Record.Data.PictDashboard.ValueTemplate~}
|
|
96
|
+
</td>
|
|
97
|
+
`
|
|
68
98
|
},
|
|
69
99
|
{
|
|
70
100
|
Hash: 'PRSP-List-RecordListEntry-Template-Entry-Cell-Datum',
|
|
71
101
|
Template: /*html*/`
|
|
72
|
-
|
|
73
|
-
|
|
102
|
+
<!-- DefaultPackage pict view template: [PRSP-List-RecordListEntry-Template-Entry-Cell-Datum] -->
|
|
103
|
+
`
|
|
74
104
|
},
|
|
75
105
|
{
|
|
106
|
+
// The action cell renders the three-dot hover menu when RowClickOpensRecord is set, else the
|
|
107
|
+
// original always-visible link list. (Hosts such as LIMS override this whole template; those
|
|
108
|
+
// lists keep their custom actions and — without the flag — their original row behavior.)
|
|
76
109
|
Hash: 'PRSP-List-RecordListAction-Template-Cell',
|
|
77
110
|
// FIXME: Needs a better way of getting the appropriate link templates in (likely requiring piping the RecordSet to the link manager)
|
|
78
111
|
Template: /*html*/`
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
</
|
|
83
|
-
|
|
84
|
-
|
|
112
|
+
<td class="prsp-row-actions" style="border-bottom: 1px solid var(--theme-color-border-default, #ccc); padding: 5px;">
|
|
113
|
+
{~TIfAbs:PRSP-List-RecordListAction-Menu:Record:Record.Payload.RecordSetConfiguration.RowClickOpensRecord^TRUE^~}
|
|
114
|
+
{~TIfAbs:PRSP-List-RecordListAction-List:Record:Record.Payload.RecordSetConfiguration.RowClickOpensRecord^FALSE^~}
|
|
115
|
+
</td>
|
|
116
|
+
`
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
Hash: 'PRSP-List-RecordListAction-Menu',
|
|
120
|
+
Template: /*html*/`
|
|
121
|
+
<div class="prsp-row-actions-wrap">
|
|
122
|
+
<button type="button" class="prsp-row-actions-trigger" aria-label="Actions" title="Actions" onclick="event.stopPropagation(); this.parentNode.classList.toggle('open');">{~I:More~}</button>
|
|
123
|
+
<div class="prsp-row-actions-menu">
|
|
124
|
+
<ul>
|
|
125
|
+
{~TSWP:PRSP-List-RecordListAction-Template-Cell-Datum:Pict.providers.RecordSetLinkManager.linkTemplates:Record~}
|
|
126
|
+
</ul>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
`
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
Hash: 'PRSP-List-RecordListAction-List',
|
|
133
|
+
Template: /*html*/`
|
|
134
|
+
<ul>
|
|
135
|
+
{~TSWP:PRSP-List-RecordListAction-Template-Cell-Datum:Pict.providers.RecordSetLinkManager.linkTemplates:Record~}
|
|
136
|
+
</ul>
|
|
137
|
+
`
|
|
85
138
|
},
|
|
86
139
|
{
|
|
87
140
|
Hash: 'PRSP-List-RecordListAction-Template-Cell-Datum',
|
|
88
141
|
// These use the new TemplateByReference template expression, which uses the values in these addresses to lookup the template hash then renders those template with the current Record state.
|
|
89
142
|
// This is part one of refactoring to include metatemplate resolution ase a core behavior pict itself rather than a pict-section-form capability
|
|
90
143
|
Template: /*html*/`
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
144
|
+
<li><a {~NE:Record.Data.Default^data-prsp-default="1"~} href="{~TBR:Record.Data.URL~}">{~TBR:Record.Data.Name~}</a></li>
|
|
145
|
+
`
|
|
94
146
|
},
|
|
95
147
|
],
|
|
96
148
|
|
|
@@ -119,4 +171,3 @@ class viewRecordSetListRecordListEntry extends libPictView
|
|
|
119
171
|
module.exports = viewRecordSetListRecordListEntry;
|
|
120
172
|
|
|
121
173
|
module.exports.default_configuration = _DEFAULT_CONFIGURATION_List_RecordListEntry;
|
|
122
|
-
|
|
@@ -61,11 +61,11 @@ const _DEFAULT_CONFIGURATION_List_RecordListHeader = (
|
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
63
|
Hash: 'PRSP-List-RecordListActions-Template-Header',
|
|
64
|
+
// Unlabeled, shrink-to-fit actions column: width:1% + nowrap collapses it to the width of the
|
|
65
|
+
// row's action control (the hover "⋯" trigger), and the other columns absorb the slack.
|
|
64
66
|
Template: /*html*/`
|
|
65
67
|
<!-- DefaultPackage pict view template: [PRSP-List-RecordListActions-Template-Header] -->
|
|
66
|
-
<th style="border-bottom: 1px solid var(--theme-color-border-default, #ccc); padding: 5px;
|
|
67
|
-
Actions
|
|
68
|
-
</th>
|
|
68
|
+
<th style="border-bottom: 1px solid var(--theme-color-border-default, #ccc); padding: 5px; width: 1%; white-space: nowrap; background-color: var(--theme-color-background-tertiary, #f2f2f2);"></th>
|
|
69
69
|
<!-- DefaultPackage end view template: [PRSP-List-RecordListActions-Template-Header] -->
|
|
70
70
|
`
|
|
71
71
|
},
|