pict-section-recordset 1.0.43 → 1.0.44
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/example_applications/simple_entity/Simple-RecordSet-Application.js +198 -3
- package/example_applications/simple_entity/html/index.html +6 -0
- package/package.json +2 -2
- package/source/providers/Filter-Data-Provider.js +371 -0
- package/source/providers/RecordSet-Link-Manager.js +9 -1
- package/source/providers/RecordSet-RecordProvider-Base.js +1 -1
- package/source/providers/RecordSet-RecordProvider-MeadowEndpoints.js +2 -0
- package/source/services/RecordsSet-MetaController.js +39 -0
- package/source/templates/Pict-Template-FilterInstanceViews.js +11 -7
- package/source/views/RecordSet-Filters.js +78 -45
- package/source/views/filters/RecordSet-Filter-Base.js +19 -1
- package/source/views/filters/RecordSet-Filter-ExternalJoinSelectedValue.js +270 -0
- package/source/views/filters/RecordSet-Filter-ExternalJoinSelectedValueList.js +277 -0
- package/source/views/filters/RecordSet-Filter-InternalJoinSelectedValue.js +270 -0
- package/source/views/filters/RecordSet-Filter-InternalJoinSelectedValueList.js +277 -0
- package/source/views/filters/index.js +4 -0
- package/types/providers/Filter-Data-Provider.d.ts +120 -0
- package/types/providers/Filter-Data-Provider.d.ts.map +1 -0
- package/types/providers/RecordSet-Link-Manager.d.ts +10 -5
- package/types/providers/RecordSet-Link-Manager.d.ts.map +1 -1
- package/types/providers/RecordSet-RecordProvider-MeadowEndpoints.d.ts.map +1 -1
- package/types/services/RecordsSet-MetaController.d.ts +36 -7
- package/types/services/RecordsSet-MetaController.d.ts.map +1 -1
- package/types/templates/Pict-Template-FilterInstanceViews.d.ts +1 -1
- package/types/templates/Pict-Template-FilterInstanceViews.d.ts.map +1 -1
- package/types/views/RecordSet-Filters.d.ts +10 -0
- package/types/views/RecordSet-Filters.d.ts.map +1 -1
- package/types/views/filters/RecordSet-Filter-Base.d.ts +10 -0
- package/types/views/filters/RecordSet-Filter-Base.d.ts.map +1 -1
- package/types/views/filters/RecordSet-Filter-ExternalJoinSelectedValue.d.ts +24 -0
- package/types/views/filters/RecordSet-Filter-ExternalJoinSelectedValue.d.ts.map +1 -0
- package/types/views/filters/RecordSet-Filter-ExternalJoinSelectedValueList.d.ts +24 -0
- package/types/views/filters/RecordSet-Filter-ExternalJoinSelectedValueList.d.ts.map +1 -0
- package/types/views/filters/RecordSet-Filter-InternalJoinSelectedValue.d.ts +24 -0
- package/types/views/filters/RecordSet-Filter-InternalJoinSelectedValue.d.ts.map +1 -0
- package/types/views/filters/RecordSet-Filter-InternalJoinSelectedValueList.d.ts +24 -0
- package/types/views/filters/RecordSet-Filter-InternalJoinSelectedValueList.d.ts.map +1 -0
- package/types/views/filters/index.d.ts +4 -0
|
@@ -96,6 +96,8 @@ class RecordSetMetacontroller extends libFableServiceProviderBase
|
|
|
96
96
|
*/
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
|
+
* @param {string} pRecordSet - The RecordSet name to get the configuration for.
|
|
100
|
+
*
|
|
99
101
|
* @return {Record<string, any>} - The registered configuration for the RecordSet
|
|
100
102
|
*/
|
|
101
103
|
getRecordSetConfiguration(pRecordSet)
|
|
@@ -103,6 +105,9 @@ class RecordSetMetacontroller extends libFableServiceProviderBase
|
|
|
103
105
|
return this.recordSetProviderConfigurations[pRecordSet];
|
|
104
106
|
}
|
|
105
107
|
|
|
108
|
+
/**
|
|
109
|
+
* @param {Record<string, any>} pRecordSetConfiguration - The RecordSet configuration to load.
|
|
110
|
+
*/
|
|
106
111
|
loadRecordSetConfiguration(pRecordSetConfiguration)
|
|
107
112
|
{
|
|
108
113
|
if (typeof pRecordSetConfiguration !== 'object')
|
|
@@ -208,6 +213,9 @@ class RecordSetMetacontroller extends libFableServiceProviderBase
|
|
|
208
213
|
return tmpProvider;
|
|
209
214
|
}
|
|
210
215
|
|
|
216
|
+
/**
|
|
217
|
+
* @param {Array<Record<string, any>>} pRecordSetConfigurationArray - An array of RecordSet configurations to load.
|
|
218
|
+
*/
|
|
211
219
|
loadRecordSetConfigurationArray(pRecordSetConfigurationArray)
|
|
212
220
|
{
|
|
213
221
|
if (!Array.isArray(pRecordSetConfigurationArray))
|
|
@@ -229,6 +237,11 @@ class RecordSetMetacontroller extends libFableServiceProviderBase
|
|
|
229
237
|
}
|
|
230
238
|
}
|
|
231
239
|
|
|
240
|
+
/**
|
|
241
|
+
* @param {Record<string, any> | string} pRecordSet - The RecordSet configuration or hash to load dynamically.
|
|
242
|
+
* @param {string} [pEntity] - (optional) The Entity type to use (defaults to the RecordSet name if not provided).
|
|
243
|
+
* @param {string} [pDefaultFilter] - (optional) The default filter to use.
|
|
244
|
+
*/
|
|
232
245
|
loadRecordSetDynamically(pRecordSet, pEntity, pDefaultFilter)
|
|
233
246
|
{
|
|
234
247
|
if (typeof(pRecordSet) === 'object')
|
|
@@ -238,6 +251,11 @@ class RecordSetMetacontroller extends libFableServiceProviderBase
|
|
|
238
251
|
|
|
239
252
|
return this.fable.providers[tmpRecordSetProviderHash].initializeAsync((pError) =>
|
|
240
253
|
{
|
|
254
|
+
if (pError)
|
|
255
|
+
{
|
|
256
|
+
this.log.error(`RecordSet [${pRecordSet.RecordSet}] dynamically loaded with error: ${pError.message || pError}`, { Stack: pError.stack });
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
241
259
|
this.log.trace(`RecordSet [${pRecordSet.RecordSet} dynamically loaded.`);
|
|
242
260
|
})
|
|
243
261
|
}
|
|
@@ -264,6 +282,11 @@ class RecordSetMetacontroller extends libFableServiceProviderBase
|
|
|
264
282
|
return this.fable.providers[tmpRecordSetProviderHash].initializeAsync(
|
|
265
283
|
(pError) =>
|
|
266
284
|
{
|
|
285
|
+
if (pError)
|
|
286
|
+
{
|
|
287
|
+
this.log.error(`RecordSet [${tmpRecordSet}] dynamically loaded with error: ${pError.message || pError}`, { Stack: pError.stack });
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
267
290
|
this.log.trace(`RecordSet [${tmpRecordSetConfiguration.RecordSet} dynamically loaded.`);
|
|
268
291
|
});
|
|
269
292
|
}
|
|
@@ -272,6 +295,9 @@ class RecordSetMetacontroller extends libFableServiceProviderBase
|
|
|
272
295
|
return false;
|
|
273
296
|
}
|
|
274
297
|
|
|
298
|
+
/**
|
|
299
|
+
* @param {Record<string, any>} pRoutePayload - The route payload containing the RecordSet and optional Entity and DefaultFilter.
|
|
300
|
+
*/
|
|
275
301
|
handleLoadDynamicRecordSetRoute(pRoutePayload)
|
|
276
302
|
{
|
|
277
303
|
if (typeof(pRoutePayload) != 'object')
|
|
@@ -287,6 +313,9 @@ class RecordSetMetacontroller extends libFableServiceProviderBase
|
|
|
287
313
|
return this.loadRecordSetDynamically(tmpRecordSet, tmpEntity, tmpDefaultFilter);
|
|
288
314
|
}
|
|
289
315
|
|
|
316
|
+
/**
|
|
317
|
+
* @param {import('pict-router')} pPictRouter - The Pict Router to add the routes to.
|
|
318
|
+
*/
|
|
290
319
|
addRoutes(pPictRouter)
|
|
291
320
|
{
|
|
292
321
|
pPictRouter.addRoute('/PSRS/:RecordSet/LoadDynamic', this.handleLoadDynamicRecordSetRoute.bind(this));
|
|
@@ -295,6 +324,9 @@ class RecordSetMetacontroller extends libFableServiceProviderBase
|
|
|
295
324
|
return true;
|
|
296
325
|
}
|
|
297
326
|
|
|
327
|
+
/**
|
|
328
|
+
* @param {string} pCapability - The capability to check for.
|
|
329
|
+
*/
|
|
298
330
|
async checkSession(pCapability)
|
|
299
331
|
{
|
|
300
332
|
for (const sessionProvider of this.sessionProviders)
|
|
@@ -307,6 +339,13 @@ class RecordSetMetacontroller extends libFableServiceProviderBase
|
|
|
307
339
|
return true;
|
|
308
340
|
}
|
|
309
341
|
|
|
342
|
+
/**
|
|
343
|
+
* @param {string} pNameTemplate - The name template for the record link.
|
|
344
|
+
* @param {string} pURLTemplate - The URL template for the record link.
|
|
345
|
+
* @param {boolean} pDefault - Whether this is a default link template.
|
|
346
|
+
*
|
|
347
|
+
* @return {Record<string, any>} - The link template object that was added.
|
|
348
|
+
*/
|
|
310
349
|
addRecordLinkTemplate(pNameTemplate, pURLTemplate, pDefault)
|
|
311
350
|
{
|
|
312
351
|
return this.fable.providers.RecordSetLinkManager.addRecordLinkTemplate(pNameTemplate, pURLTemplate, pDefault);
|
|
@@ -30,17 +30,22 @@ class PictTemplateFilterInstanceViewInstruction extends libPictTemplate
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
_getViewForFilterClause(pClause)
|
|
34
34
|
{
|
|
35
|
-
|
|
35
|
+
let tmpViewHash = `PRSP-FilterType-${pClause.Type}`;
|
|
36
|
+
const tmpCustomViewHash = `${tmpViewHash}-${pClause.CustomFilterViewHash}`;
|
|
37
|
+
if (tmpCustomViewHash in this.pict.views)
|
|
38
|
+
{
|
|
39
|
+
tmpViewHash = tmpCustomViewHash;
|
|
40
|
+
}
|
|
36
41
|
/** @type {import('../views/filters/RecordSet-Filter-Base.js')} */
|
|
37
42
|
let tmpView = this.pict.views[tmpViewHash];
|
|
38
43
|
if (!tmpView)
|
|
39
44
|
{
|
|
40
|
-
const tmpViewPrototype = libFilterViews[
|
|
45
|
+
const tmpViewPrototype = libFilterViews[pClause.Type] || libFilterViews.Base;
|
|
41
46
|
if (!tmpViewPrototype)
|
|
42
47
|
{
|
|
43
|
-
this.pict.log.error(`Pict: Filter Instance Views Template Render: No view prototype found for filter type [${
|
|
48
|
+
this.pict.log.error(`Pict: Filter Instance Views Template Render: No view prototype found for filter type [${pClause.Type}]`);
|
|
44
49
|
return null;
|
|
45
50
|
}
|
|
46
51
|
//FIXME: is this safe? will this view get rendered at other times?
|
|
@@ -103,11 +108,10 @@ class PictTemplateFilterInstanceViewInstruction extends libPictTemplate
|
|
|
103
108
|
const tmpClauses = this.pict.Bundle._ActiveFilterState?.[pRecord.RecordSet]?.FilterClauses || [];
|
|
104
109
|
//FIXME: lookup by hash instead?
|
|
105
110
|
for (let i = 0; i < tmpClauses.length; i++)
|
|
106
|
-
//for (const tmpClauses of this.pict.Bundle._ActiveFilterState?.[pRecord.RecordSet]?.FilterClauses || [])
|
|
107
111
|
{
|
|
108
112
|
const tmpClause = tmpClauses[i];
|
|
109
113
|
/** @type {import('../views/filters/RecordSet-Filter-Base.js')} */
|
|
110
|
-
const tmpView = this.
|
|
114
|
+
const tmpView = this._getViewForFilterClause(tmpClause);
|
|
111
115
|
if (!tmpView)
|
|
112
116
|
{
|
|
113
117
|
continue;
|
|
@@ -182,7 +186,7 @@ class PictTemplateFilterInstanceViewInstruction extends libPictTemplate
|
|
|
182
186
|
{
|
|
183
187
|
const tmpClause = tmpClauses[i];
|
|
184
188
|
/** @type {import('../views/filters/RecordSet-Filter-Base.js')} */
|
|
185
|
-
const tmpView = this.
|
|
189
|
+
const tmpView = this._getViewForFilterClause(tmpClause);
|
|
186
190
|
if (!tmpView)
|
|
187
191
|
{
|
|
188
192
|
continue;
|
|
@@ -148,61 +148,61 @@ const _DEFAULT_CONFIGURATION_SUBSET_Filter =
|
|
|
148
148
|
//FIXME: export this from PSF?
|
|
149
149
|
const libPictViewDynamicForm = require('pict-section-form/source/views/Pict-View-DynamicForm.js');
|
|
150
150
|
|
|
151
|
-
|
|
151
|
+
const DynamicInputViewSectionDefinition = (
|
|
152
152
|
{
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
super(pFable, tmpOptions, pServiceHash);
|
|
157
|
-
/** @type {import('fable') & import('pict') & { PictSectionRecordSet: import('../Pict-Section-RecordSet.js') }} */
|
|
158
|
-
this.pict;
|
|
153
|
+
"Hash": "PSRSDynamicInputs",
|
|
154
|
+
"Name": "Custom Dynamic Inputs",
|
|
155
|
+
"ViewHash": "PSRSFilterProxyView",
|
|
159
156
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
"Hash": "PSRSDynamicInputs",
|
|
163
|
-
"Name": "Custom Dynamic Inputs",
|
|
164
|
-
"ViewHash": "PSRSFilterProxyView",
|
|
157
|
+
"AutoMarshalDataOnSolve": true,
|
|
158
|
+
"IncludeInMetatemplateSectionGeneration": false,
|
|
165
159
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
160
|
+
"Manifests":
|
|
161
|
+
{
|
|
162
|
+
"Section":
|
|
163
|
+
{
|
|
164
|
+
"Scope": "PSRSDynamic",
|
|
165
|
+
"Sections":
|
|
166
|
+
[
|
|
167
|
+
{
|
|
168
|
+
"Hash": "PSRSDynamicInputs",
|
|
169
|
+
"Name": "Dynamic Inputs"
|
|
170
|
+
}
|
|
171
|
+
],
|
|
172
|
+
"Descriptors":
|
|
170
173
|
{
|
|
171
|
-
"
|
|
174
|
+
"PSRS.DynamicInputPlaceholder":
|
|
172
175
|
{
|
|
173
|
-
"
|
|
174
|
-
"
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
"Hash": "PSRSDynamicInputs",
|
|
178
|
-
"Name": "Dynamic Inputs"
|
|
179
|
-
}
|
|
180
|
-
],
|
|
181
|
-
"Descriptors":
|
|
176
|
+
"Name": "DynamicInputPlaceholder",
|
|
177
|
+
"Hash": "DynamicInputPlaceholder",
|
|
178
|
+
"DataType": "String",
|
|
179
|
+
"Macro":
|
|
182
180
|
{
|
|
183
|
-
"
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
"Macro":
|
|
189
|
-
{
|
|
190
|
-
"HTMLSelector": ""
|
|
191
|
-
},
|
|
192
|
-
"PictForm":
|
|
193
|
-
{
|
|
194
|
-
"Section": "PSRSDynamicInputs"
|
|
195
|
-
}
|
|
196
|
-
}
|
|
181
|
+
"HTMLSelector": ""
|
|
182
|
+
},
|
|
183
|
+
"PictForm":
|
|
184
|
+
{
|
|
185
|
+
"Section": "PSRSDynamicInputs"
|
|
197
186
|
}
|
|
198
187
|
}
|
|
199
188
|
}
|
|
200
|
-
}
|
|
201
|
-
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
class ViewRecordSetSUBSETFilters extends libPictView
|
|
193
|
+
{
|
|
194
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
195
|
+
{
|
|
196
|
+
let tmpOptions = Object.assign({}, _DEFAULT_CONFIGURATION_SUBSET_Filter, pOptions);
|
|
197
|
+
super(pFable, tmpOptions, pServiceHash);
|
|
198
|
+
/** @type {import('fable') & import('pict') & { PictSectionRecordSet: import('../Pict-Section-RecordSet.js') }} */
|
|
199
|
+
this.pict;
|
|
200
|
+
|
|
201
|
+
if (!this.pict.views[DynamicInputViewSectionDefinition.ViewHash])
|
|
202
202
|
{
|
|
203
|
-
const tmpViewConfiguration = Object.assign({},
|
|
203
|
+
const tmpViewConfiguration = Object.assign({}, DynamicInputViewSectionDefinition);
|
|
204
204
|
this.pict.addView(tmpViewConfiguration.ViewHash, tmpViewConfiguration, libPictViewDynamicForm);
|
|
205
|
-
this.pict.views[
|
|
205
|
+
this.pict.views[DynamicInputViewSectionDefinition.ViewHash].viewMarshalDestination = 'Bundle';
|
|
206
206
|
}
|
|
207
207
|
for (const tmpView of Object.values(require('./filters')))
|
|
208
208
|
{
|
|
@@ -221,6 +221,25 @@ class ViewRecordSetSUBSETFilters extends libPictView
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
/**
|
|
225
|
+
* @return {string} - The marshalling prefix configured for filters. Usually 'Bundle.'
|
|
226
|
+
*/
|
|
227
|
+
getInformaryAddressPrefix()
|
|
228
|
+
{
|
|
229
|
+
return `${this.pict.views[DynamicInputViewSectionDefinition.ViewHash].viewMarshalDestination}.`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @param {string} pAddress - The address of the informary to get the value from.
|
|
234
|
+
*
|
|
235
|
+
* @return {any} - The value at the given address, using the informary marshalling prefix.
|
|
236
|
+
*/
|
|
237
|
+
getInformaryScopedValue(pAddress)
|
|
238
|
+
{
|
|
239
|
+
const tmpCompositeAddress = `${this.getInformaryAddressPrefix()}${pAddress}`;
|
|
240
|
+
return this.pict.resolveStateFromAddress(tmpCompositeAddress);
|
|
241
|
+
}
|
|
242
|
+
|
|
224
243
|
//NOTE: two methods below copied from the pict-section-form metacontroller
|
|
225
244
|
//TODO: consider subclassing the dynamic view to somehow mark these as filter views so we can only operate on those views
|
|
226
245
|
|
|
@@ -315,6 +334,7 @@ class ViewRecordSetSUBSETFilters extends libPictView
|
|
|
315
334
|
{
|
|
316
335
|
tmpURL = tmpURL.replace(/\/FilteredTo\//, '');
|
|
317
336
|
}
|
|
337
|
+
this.render(undefined, undefined, { RecordSet: pRecordSet, ViewContext: pViewContext });
|
|
318
338
|
this.serializeFilterExperience(this.pict.Bundle._ActiveFilterState[pRecordSet]?.FilterClauses).then((pFilterExperienceSerialized) =>
|
|
319
339
|
{
|
|
320
340
|
if (pFilterExperienceSerialized)
|
|
@@ -342,6 +362,11 @@ class ViewRecordSetSUBSETFilters extends libPictView
|
|
|
342
362
|
{
|
|
343
363
|
delete tmpClause.Value;
|
|
344
364
|
delete tmpClause.Values;
|
|
365
|
+
delete tmpClause.SearchInputValue;
|
|
366
|
+
delete tmpClause.SelectedValues;
|
|
367
|
+
delete tmpClause.SearchResults;
|
|
368
|
+
delete tmpClause.SearchResultsOffset;
|
|
369
|
+
delete tmpClause.LoadMoreEnabled;
|
|
345
370
|
}
|
|
346
371
|
}
|
|
347
372
|
this.performSearch(pRecordSet, pViewContext);
|
|
@@ -428,7 +453,15 @@ class ViewRecordSetSUBSETFilters extends libPictView
|
|
|
428
453
|
{
|
|
429
454
|
return '';
|
|
430
455
|
}
|
|
431
|
-
|
|
456
|
+
const tmpExperience = JSON.parse(JSON.stringify(pExperience));
|
|
457
|
+
for (const tmpClause of tmpExperience)
|
|
458
|
+
{
|
|
459
|
+
//FIXME: avoiding saving search results to the URL but this pattern isn't ideal
|
|
460
|
+
delete tmpClause.SearchResults;
|
|
461
|
+
delete tmpClause.SearchResultsOffset;
|
|
462
|
+
delete tmpClause.LoadMoreEnabled;
|
|
463
|
+
}
|
|
464
|
+
return this.encode(await this.compress(JSON.stringify(tmpExperience)));
|
|
432
465
|
}
|
|
433
466
|
|
|
434
467
|
/**
|
|
@@ -41,7 +41,7 @@ const _DEFAULT_CONFIGURATION_SUBSET_Filter =
|
|
|
41
41
|
Hash: 'PRSP-Filter-Base-Template',
|
|
42
42
|
Template: /*html*/`
|
|
43
43
|
<!-- DefaultPackage pict view template: [PRSP-Filter-Base-Template] -->
|
|
44
|
-
<div>
|
|
44
|
+
<div id="PRSP_Filter_Container_{~D:Record.Hash~}">
|
|
45
45
|
<button type="button"
|
|
46
46
|
onclick="_Pict.views['PRSP-Filters'].removeFilter(event, '{~D:Record.RecordSet~}', '{~D:Record.ViewContext~}', '{~D:Record.Hash~}');"
|
|
47
47
|
>
|
|
@@ -97,6 +97,24 @@ class ViewRecordSetSUBSETFilterBase extends libPictView
|
|
|
97
97
|
{
|
|
98
98
|
return 'PRSP-Filter-Base-Form';
|
|
99
99
|
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @return {string} - The prefix for the informary address.
|
|
103
|
+
*/
|
|
104
|
+
getInformaryAddressPrefix()
|
|
105
|
+
{
|
|
106
|
+
return this.pict.views['PRSP-Filters'].getInformaryAddressPrefix();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @param {string} pInformaryAddress - The address of the informary to get the value from.
|
|
111
|
+
*
|
|
112
|
+
* @return {any} - The value at the informary address.
|
|
113
|
+
*/
|
|
114
|
+
getInformaryScopedValue(pInformaryAddress)
|
|
115
|
+
{
|
|
116
|
+
return this.pict.views['PRSP-Filters'].getInformaryScopedValue(pInformaryAddress);
|
|
117
|
+
}
|
|
100
118
|
}
|
|
101
119
|
|
|
102
120
|
module.exports = ViewRecordSetSUBSETFilterBase;
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
|
|
2
|
+
const ViewRecordSetSUBSETFilterBase = require('./RecordSet-Filter-Base');
|
|
3
|
+
|
|
4
|
+
const _DEFAULT_CONFIGURATION_Filter_ExternalJoin_SelectedValue =
|
|
5
|
+
{
|
|
6
|
+
ViewIdentifier: 'PRSP-FilterType-ExternalJoinSelectedValue',
|
|
7
|
+
|
|
8
|
+
Templates:
|
|
9
|
+
[
|
|
10
|
+
{
|
|
11
|
+
Hash: 'PRSP-Filter-ExternalJoin-SelectedValue-Template',
|
|
12
|
+
Template: /*html*/`
|
|
13
|
+
<!-- DefaultPackage pict view template: [PRSP-Filter-ExternalJoin-SelectedValue-Template] -->
|
|
14
|
+
<table>
|
|
15
|
+
<tbody>
|
|
16
|
+
<td valign="top">{~T:PRSP-Filter-ExternalJoin-SelectedValue-SearchResults~}</td><td valign="top">{~T:PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues~}</td>
|
|
17
|
+
</tbody>
|
|
18
|
+
</table>
|
|
19
|
+
<!-- DefaultPackage end view template: [PRSP-Filter-ExternalJoin-SelectedValue-Template] -->
|
|
20
|
+
`
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
Hash: 'PRSP-Filter-ExternalJoin-SelectedValue-SearchResults',
|
|
24
|
+
Template: /*html*/`
|
|
25
|
+
<!-- DefaultPackage pict view template: [PRSP-Filter-ExternalJoin-SearchResults] -->
|
|
26
|
+
<form id="PRSP_Filter_{~D:Record.Hash~}_Search_Form" onsubmit="_Pict.views['{~D:Context[0].Hash~}'].performSearch(event, '{~D:Record.ClauseAddress~}', '{~D:Record.Hash~}'); return false;">
|
|
27
|
+
<input id="PRSP_Filter_{~D:Record.Hash~}_Search_Value" type="text" placeholder="Search..." value="{~D:Record.SearchInputValue~}" />
|
|
28
|
+
<button type="submit" id="PRSP_Filter_{~D:Record.Hash~}_Button_Search" onclick="_Pict.views['{~D:Context[0].Hash~}'].performSearch(event, '{~D:Record.ClauseAddress~}', '{~D:Record.Hash~}')">Search</button>
|
|
29
|
+
</form>
|
|
30
|
+
<table>
|
|
31
|
+
<thead>
|
|
32
|
+
<tr><th colspan="2">{~D:Record.Label~}</th></tr>
|
|
33
|
+
</thead>
|
|
34
|
+
<tbody>
|
|
35
|
+
{~TSWP:PRSP-Filter-ExternalJoin-SelectedValue-SearchResults-Entry:Record.SearchResults:Record~}
|
|
36
|
+
</tbody>
|
|
37
|
+
</table>
|
|
38
|
+
<button type="button" id="PRSP_Filter_{~D:Record.Hash~}_Button_LoadMore" class="is-hidden" onclick="_Pict.views['{~D:Context[0].Hash~}'].loadMore(event, '{~D:Record.ClauseAddress~}', '{~D:Record.Hash~}', {~D:Record.SearchResultsOffset:0~})">Load More</button>
|
|
39
|
+
<!-- DefaultPackage end view template: [PRSP-Filter-ExternalJoin-SearchResults] -->
|
|
40
|
+
`
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
Hash: 'PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues',
|
|
44
|
+
Template: /*html*/`
|
|
45
|
+
<!-- DefaultPackage view template: [PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues] -->
|
|
46
|
+
<table>
|
|
47
|
+
<thead>
|
|
48
|
+
<tr><th colspan="2">Selection</th></tr>
|
|
49
|
+
</thead>
|
|
50
|
+
<tbody>
|
|
51
|
+
{~TSWP:PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues-Entry:Record.SelectedValues:Record~}
|
|
52
|
+
</tbody>
|
|
53
|
+
</table>
|
|
54
|
+
<!-- DefaultPackage end view template: [PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues] -->
|
|
55
|
+
`
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
Hash: 'PRSP-Filter-ExternalJoin-SelectedValue-SearchResults-Entry',
|
|
59
|
+
Template: /*html*/`
|
|
60
|
+
<!-- DefaultPackage pict view template: [PRSP-Filter-ExternalJoin-SelectedValue-Template] -->
|
|
61
|
+
<tr><td><button onclick="_Pict.views['{~D:Context[0].Hash~}'].handleSelect(event, {~DVBK:Record.Data:Record.Payload.ExternalFilterTableLookupColumn~}, '{~D:Record.Payload.ClauseAddress~}', '{~D:Record.Payload.Hash~}')">Select</button></td><td>{~TFA:Record.Payload.ExternalRecordDisplayTemplate:Record~}</td></tr>
|
|
62
|
+
<!-- DefaultPackage end view template: [PRSP-Filter-ExternalJoin-SelectedValue-Template] -->
|
|
63
|
+
`
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
Hash: 'PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues-Entry',
|
|
67
|
+
Template: /*html*/`
|
|
68
|
+
<!-- DefaultPackage pict view template: [PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues-Entry] -->
|
|
69
|
+
<tr><td><button onclick="_Pict.views['{~D:Context[0].Hash~}'].handleRemove(event, {~DVBK:Record.Data:Record.Payload.ExternalFilterTableLookupColumn~}, '{~D:Record.Payload.ClauseAddress~}', '{~D:Record.Payload.Hash~}')">Remove</button></td><td>{~TFA:Record.Payload.ExternalRecordDisplayTemplate:Record~}</td></tr>
|
|
70
|
+
<!-- DefaultPackage end view template: [PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues-Entry] -->
|
|
71
|
+
`
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
class ViewRecordSetSUBSETFilterExternalJoinSelectedValue extends ViewRecordSetSUBSETFilterBase
|
|
77
|
+
{
|
|
78
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
79
|
+
{
|
|
80
|
+
if (!pOptions.PageSize)
|
|
81
|
+
{
|
|
82
|
+
pOptions.PageSize = 15; // default page size for search results
|
|
83
|
+
}
|
|
84
|
+
super(pFable, pOptions, pServiceHash);
|
|
85
|
+
/*
|
|
86
|
+
* show / hide the complex editor since it'll be large ?
|
|
87
|
+
* selected record lookup values
|
|
88
|
+
* using bundle to load those records (if any)
|
|
89
|
+
* templating out the selection
|
|
90
|
+
* templating out the search results
|
|
91
|
+
* controls to add search result values to selection
|
|
92
|
+
*/
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @param {Record<string, any>} pRecord
|
|
97
|
+
*/
|
|
98
|
+
prepareRecord(pRecord)
|
|
99
|
+
{
|
|
100
|
+
super.prepareRecord(pRecord);
|
|
101
|
+
|
|
102
|
+
pRecord.ClauseDescriptor.DataType = 'Number';
|
|
103
|
+
if (!pRecord.ExternalFilterTableLookupColumn)
|
|
104
|
+
{
|
|
105
|
+
pRecord.ExternalFilterTableLookupColumn = `ID${pRecord.ExternalFilterByTable}`;
|
|
106
|
+
}
|
|
107
|
+
if (!pRecord.SearchResults)
|
|
108
|
+
{
|
|
109
|
+
pRecord.SearchResults = [];
|
|
110
|
+
}
|
|
111
|
+
if (!pRecord.SelectedValues)
|
|
112
|
+
{
|
|
113
|
+
pRecord.SelectedValues = [];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
getFilterFormTemplate()
|
|
118
|
+
{
|
|
119
|
+
return 'PRSP-Filter-ExternalJoin-SelectedValue-Template';
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @param {UIEvent} pEvent
|
|
124
|
+
* @param {string} pClauseInformaryAddress
|
|
125
|
+
* @param {string} pClauseHash
|
|
126
|
+
*/
|
|
127
|
+
loadMore(pEvent, pClauseInformaryAddress, pClauseHash, pCurrentOffset = 0)
|
|
128
|
+
{
|
|
129
|
+
this.performSearch(pEvent, pClauseInformaryAddress, pClauseHash, pCurrentOffset + this.options.PageSize);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @param {UIEvent} pEvent
|
|
134
|
+
* @param {string} pClauseInformaryAddress
|
|
135
|
+
* @param {string} pClauseHash
|
|
136
|
+
* @param {number} [pOffset=0] - The offset for the search results, defaults to 0
|
|
137
|
+
*/
|
|
138
|
+
performSearch(pEvent, pClauseInformaryAddress, pClauseHash, pOffset = 0)
|
|
139
|
+
{
|
|
140
|
+
pEvent.preventDefault();
|
|
141
|
+
const tmpClause = this.getInformaryScopedValue(pClauseInformaryAddress);
|
|
142
|
+
if (!tmpClause)
|
|
143
|
+
{
|
|
144
|
+
this.pict.log.error(`[Filter-ExternalJoinSelectedValue] No clause found for address: ${pClauseInformaryAddress}`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
tmpClause.SearchResultsOffset = pOffset;
|
|
148
|
+
// get the input value (search box)
|
|
149
|
+
const tmpSearchInputValue = pOffset > 0 ? tmpClause.SearchInputValue : this.pict.ContentAssignment.readContent(`#PRSP_Filter_${tmpClause.Hash}_Search_Value`);
|
|
150
|
+
tmpClause.SearchInputValue = tmpSearchInputValue;
|
|
151
|
+
if (!tmpSearchInputValue)
|
|
152
|
+
{
|
|
153
|
+
tmpClause.SearchResults = [];
|
|
154
|
+
tmpClause.LoadMoreEnabled = false;
|
|
155
|
+
const tmpRecord = Object.assign({ ClauseAddress: pClauseInformaryAddress }, tmpClause);
|
|
156
|
+
this.prepareRecord(tmpRecord);
|
|
157
|
+
const tmpDestinationAddress = `#PRSP_Filter_Container_${pClauseHash}`;
|
|
158
|
+
this.render(null, tmpDestinationAddress, tmpRecord);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const tmpFilterByColumns = tmpClause.ExternalFilterByColumns || (tmpClause.ExternalFilterByColumn ? [ tmpClause.ExternalFilterByColumn ] : [ 'Name' ]);
|
|
162
|
+
const tmpMeadowFilter = tmpFilterByColumns.map((pColumn) => `FBVOR~${pColumn}~LK~${encodeURIComponent(`%${tmpSearchInputValue}%`)}`).join('~');
|
|
163
|
+
// bundle load the remote records and put them in the clause
|
|
164
|
+
this.pict.EntityProvider.gatherDataFromServer(
|
|
165
|
+
[
|
|
166
|
+
{
|
|
167
|
+
Entity: tmpClause.ExternalFilterByTable,
|
|
168
|
+
Filter: tmpMeadowFilter,
|
|
169
|
+
Destination: pOffset > 0 ? `${this.getInformaryAddressPrefix()}${pClauseInformaryAddress}.SearchResultsAppend` : `${this.getInformaryAddressPrefix()}${pClauseInformaryAddress}.SearchResults`,
|
|
170
|
+
RecordStartCursor: pOffset,
|
|
171
|
+
PageSize: this.options.PageSize,
|
|
172
|
+
}
|
|
173
|
+
],
|
|
174
|
+
(pError, pResult) =>
|
|
175
|
+
{
|
|
176
|
+
if (pOffset > 0 && tmpClause.SearchResultsAppend?.length > 0)
|
|
177
|
+
{
|
|
178
|
+
tmpClause.SearchResults = tmpClause.SearchResults.concat(tmpClause.SearchResultsAppend);
|
|
179
|
+
}
|
|
180
|
+
delete tmpClause.SearchResultsAppend;
|
|
181
|
+
tmpClause.SearchResultsOffset = pOffset;
|
|
182
|
+
const tmpRecord = Object.assign({ ClauseAddress: pClauseInformaryAddress }, tmpClause);
|
|
183
|
+
this.prepareRecord(tmpRecord);
|
|
184
|
+
const tmpDestinationAddress = `#PRSP_Filter_Container_${pClauseHash}`;
|
|
185
|
+
this.render(null, tmpDestinationAddress, tmpRecord);
|
|
186
|
+
const tmpLoadedRecords = pOffset > 0 ? tmpClause.SearchResultsAppend : tmpClause.SearchResults;
|
|
187
|
+
const tmpLoadMoreEnabled = tmpLoadedRecords && tmpLoadedRecords.length >= this.options.PageSize;
|
|
188
|
+
tmpClause.LoadMoreEnabled = tmpLoadMoreEnabled;
|
|
189
|
+
if (tmpClause.LoadMoreEnabled)
|
|
190
|
+
{
|
|
191
|
+
this.pict.ContentAssignment.removeClass(`#PRSP_Filter_${tmpClause.Hash}_Button_LoadMore`, 'is-hidden');
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
handleSelect(pEvent, pRecordLookupValue, pClauseInformaryAddress, pClauseHash)
|
|
197
|
+
{
|
|
198
|
+
pEvent.preventDefault();
|
|
199
|
+
const tmpClause = this.getInformaryScopedValue(pClauseInformaryAddress);
|
|
200
|
+
if (!tmpClause)
|
|
201
|
+
{
|
|
202
|
+
this.pict.log.error(`[Filter-ExternalJoinSelectedValue] No clause found for address: ${pClauseInformaryAddress}`);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const tmpRecordLookupColumn = tmpClause.ExternalFilterTableLookupColumn || `ID${tmpClause.ExternalFilterByTable}`;
|
|
206
|
+
const tmpRecordToSelect = tmpClause.SearchResults.find((r) => r[tmpRecordLookupColumn] == pRecordLookupValue);
|
|
207
|
+
if (!tmpRecordToSelect)
|
|
208
|
+
{
|
|
209
|
+
this.pict.log.error(`[Filter-ExternalJoinSelectedValue] No record found to add for value: ${pRecordLookupValue}`);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (!tmpClause.SelectedValues)
|
|
213
|
+
{
|
|
214
|
+
tmpClause.SelectedValues = [];
|
|
215
|
+
}
|
|
216
|
+
if (tmpClause.SelectedValues.some((pSV) => pSV[tmpRecordLookupColumn] == pRecordLookupValue))
|
|
217
|
+
{
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const tmpValue = tmpRecordToSelect[tmpRecordLookupColumn];
|
|
221
|
+
if (tmpValue == null)
|
|
222
|
+
{
|
|
223
|
+
this.pict.log.error(`[Filter-ExternalJoinSelectedValue] No value found in record to add: ${JSON.stringify(tmpRecordToSelect)}`);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
tmpClause.SelectedValues = [ tmpRecordToSelect ];
|
|
227
|
+
tmpClause.Values = [ tmpValue ];
|
|
228
|
+
const tmpRecord = Object.assign({ ClauseAddress: pClauseInformaryAddress }, tmpClause);
|
|
229
|
+
this.prepareRecord(tmpRecord);
|
|
230
|
+
const tmpDestinationAddress = `#PRSP_Filter_Container_${pClauseHash}`;
|
|
231
|
+
this.render(null, tmpDestinationAddress, tmpRecord);
|
|
232
|
+
if (tmpClause.LoadMoreEnabled)
|
|
233
|
+
{
|
|
234
|
+
this.pict.ContentAssignment.removeClass(`#PRSP_Filter_${tmpClause.Hash}_Button_LoadMore`, 'is-hidden');
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
handleRemove(pEvent, pRecordLookupValue, pClauseInformaryAddress, pClauseHash)
|
|
239
|
+
{
|
|
240
|
+
pEvent.preventDefault();
|
|
241
|
+
const tmpClause = this.getInformaryScopedValue(pClauseInformaryAddress);
|
|
242
|
+
if (!tmpClause)
|
|
243
|
+
{
|
|
244
|
+
this.pict.log.error(`[Filter-ExternalJoinSelectedValue] No clause found for address: ${pClauseInformaryAddress}`);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const tmpRecordLookupColumn = tmpClause.ExternalFilterTableLookupColumn || `ID${tmpClause.ExternalFilterByTable}`;
|
|
248
|
+
const tmpRecordIndexToRemove = tmpClause.SelectedValues.findIndex((r) => r[tmpRecordLookupColumn] == pRecordLookupValue);
|
|
249
|
+
if (tmpRecordIndexToRemove < 0)
|
|
250
|
+
{
|
|
251
|
+
this.pict.log.error(`[Filter-ExternalJoinSelectedValue] No record found to remove for value: ${pRecordLookupValue}`);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const tmpRecordToRemove = tmpClause.SelectedValues.splice(tmpRecordIndexToRemove, 1)[0];
|
|
255
|
+
const tmpValue = tmpRecordToRemove[tmpRecordLookupColumn];
|
|
256
|
+
tmpClause.Values = tmpClause.Values.filter((pV) => pV !== tmpValue);
|
|
257
|
+
const tmpRecord = Object.assign({ ClauseAddress: pClauseInformaryAddress }, tmpClause);
|
|
258
|
+
this.prepareRecord(tmpRecord);
|
|
259
|
+
const tmpDestinationAddress = `#PRSP_Filter_Container_${pClauseHash}`;
|
|
260
|
+
this.render(null, tmpDestinationAddress, tmpRecord);
|
|
261
|
+
if (tmpClause.LoadMoreEnabled)
|
|
262
|
+
{
|
|
263
|
+
this.pict.ContentAssignment.removeClass(`#PRSP_Filter_${tmpClause.Hash}_Button_LoadMore`, 'is-hidden');
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
module.exports = ViewRecordSetSUBSETFilterExternalJoinSelectedValue;
|
|
269
|
+
|
|
270
|
+
module.exports.default_configuration = Object.assign({}, ViewRecordSetSUBSETFilterExternalJoinSelectedValue.default_configuration, _DEFAULT_CONFIGURATION_Filter_ExternalJoin_SelectedValue);
|