pict-section-recordset 1.0.64 → 1.0.67
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/docs/_cover.md +1 -1
- package/docs/_version.json +7 -0
- package/docs/css/docuserve.css +277 -23
- package/docs/index.html +2 -2
- package/docs/retold-catalog.json +33 -1
- package/docs/retold-keyword-index.json +1 -1
- package/example_applications/bookstore/.quackage.json +9 -0
- package/example_applications/bookstore/Bookstore-Application-Configuration.json +4 -0
- package/example_applications/bookstore/Bookstore-Application.js +671 -0
- package/example_applications/bookstore/css/bookstore.css +729 -0
- package/example_applications/bookstore/css/pure.min.css +11 -0
- package/example_applications/bookstore/html/index.html +46 -0
- package/example_applications/bookstore/package.json +34 -0
- package/example_applications/bookstore/providers/PictRouter-Bookstore.json +32 -0
- package/example_applications/bookstore/views/PictView-Bookstore-Content-About.json +21 -0
- package/example_applications/bookstore/views/PictView-Bookstore-Content-Legal.json +21 -0
- package/example_applications/bookstore/views/PictView-Bookstore-Dashboard.js +147 -0
- package/example_applications/bookstore/views/PictView-Bookstore-Layout.js +85 -0
- package/example_applications/bookstore/views/PictView-Bookstore-Login.js +58 -0
- package/example_applications/bookstore/views/PictView-Bookstore-Navigation.js +228 -0
- package/package.json +9 -8
- package/source/services/RecordsSet-MetaController.js +22 -0
- package/source/templates/Pict-Template-FilterInstanceViews.js +143 -25
- package/source/views/RecordSet-Filters.js +25 -0
- package/test/PictSectionRecordSet-Basic_tests.js +83 -0
- package/test/PictSectionRecordSet-Filter-InstanceViews-Render_tests.js +328 -0
- package/types/Pict-Section-RecordSet.d.ts +2 -0
- package/types/providers/Filter-Data-Provider.d.ts +1 -0
- package/types/providers/Filter-Data-Provider.d.ts.map +1 -1
- package/types/providers/RecordSet-DynamicRecordsetSolver.d.ts +6 -0
- package/types/providers/RecordSet-DynamicRecordsetSolver.d.ts.map +1 -1
- package/types/providers/RecordSet-RecordProvider-MeadowEndpoints.d.ts +8 -0
- package/types/providers/RecordSet-RecordProvider-MeadowEndpoints.d.ts.map +1 -1
- package/types/providers/RecordSet-Router.d.ts +2 -0
- package/types/providers/RecordSet-Router.d.ts.map +1 -1
- package/types/services/RecordsSet-MetaController.d.ts +10 -5
- package/types/services/RecordsSet-MetaController.d.ts.map +1 -1
- package/types/templates/Pict-Template-FilterInstanceViews.d.ts +42 -2
- package/types/templates/Pict-Template-FilterInstanceViews.d.ts.map +1 -1
- package/types/templates/Pict-Template-FilterView.d.ts +0 -2
- package/types/templates/Pict-Template-FilterView.d.ts.map +1 -1
- package/types/views/Filter-PersistenceView.d.ts +31 -6
- package/types/views/Filter-PersistenceView.d.ts.map +1 -1
- package/types/views/RecordSet-Filters.d.ts +31 -0
- package/types/views/RecordSet-Filters.d.ts.map +1 -1
- package/types/views/RecordSet-RecordBaseView.d.ts +2 -0
- package/types/views/RecordSet-RecordBaseView.d.ts.map +1 -1
- package/types/views/dashboard/RecordSet-Dashboard.d.ts +2 -0
- package/types/views/dashboard/RecordSet-Dashboard.d.ts.map +1 -1
|
@@ -0,0 +1,671 @@
|
|
|
1
|
+
const libPictRecordSet = require('../../source/Pict-Section-RecordSet.js');
|
|
2
|
+
const libPictRouter = require('pict-router');
|
|
3
|
+
const libPictTemplatePreprocessor = require('pict-template-preprocessor');
|
|
4
|
+
|
|
5
|
+
// Views
|
|
6
|
+
const libViewLogin = require('./views/PictView-Bookstore-Login.js');
|
|
7
|
+
const libViewLayout = require('./views/PictView-Bookstore-Layout.js');
|
|
8
|
+
const libViewNavigation = require('./views/PictView-Bookstore-Navigation.js');
|
|
9
|
+
const libViewDashboard = require('./views/PictView-Bookstore-Dashboard.js');
|
|
10
|
+
|
|
11
|
+
class BookstoreApplication extends libPictRecordSet.PictRecordSetApplication
|
|
12
|
+
{
|
|
13
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
14
|
+
{
|
|
15
|
+
super(pFable, pOptions, pServiceHash);
|
|
16
|
+
|
|
17
|
+
// Router provider — add BEFORE recordset initialization so the RecordSet router reuses it.
|
|
18
|
+
// SkipRouteResolveOnAdd is set in the config so routes only resolve after the layout renders.
|
|
19
|
+
this.pict.addProvider('PictRouter',
|
|
20
|
+
require('./providers/PictRouter-Bookstore.json'),
|
|
21
|
+
libPictRouter);
|
|
22
|
+
|
|
23
|
+
// Login view (extends pict-section-login)
|
|
24
|
+
this.pict.addView('Bookstore-Login', libViewLogin.default_configuration, libViewLogin);
|
|
25
|
+
|
|
26
|
+
// Layout shell (sidebar navigation + content area)
|
|
27
|
+
this.pict.addView('Bookstore-Layout', libViewLayout.default_configuration, libViewLayout);
|
|
28
|
+
|
|
29
|
+
// Sidebar navigation
|
|
30
|
+
this.pict.addView('Bookstore-Navigation', libViewNavigation.default_configuration, libViewNavigation);
|
|
31
|
+
|
|
32
|
+
// Dashboard view
|
|
33
|
+
this.pict.addView('Bookstore-Dashboard', libViewDashboard.default_configuration, libViewDashboard);
|
|
34
|
+
|
|
35
|
+
// Content views (About, Legal) — pure JSON config, no JavaScript needed
|
|
36
|
+
this.pict.addView('Bookstore-About-View', require('./views/PictView-Bookstore-Content-About.json'));
|
|
37
|
+
this.pict.addView('Bookstore-Legal-View', require('./views/PictView-Bookstore-Content-Legal.json'));
|
|
38
|
+
|
|
39
|
+
// Template Preprocessor — register the service type so it can be toggled on/off
|
|
40
|
+
this.pict.addServiceType('PictTemplatePreprocessor', libPictTemplatePreprocessor);
|
|
41
|
+
|
|
42
|
+
// Track preprocessor state
|
|
43
|
+
this._preprocessorInstance = null;
|
|
44
|
+
|
|
45
|
+
// Check localStorage for saved preference and activate if enabled
|
|
46
|
+
this._initPreprocessorFromStorage();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ===== Template Preprocessor Toggle =====
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Read the saved preprocessor preference from localStorage and
|
|
53
|
+
* instantiate the preprocessor if it was previously enabled.
|
|
54
|
+
* @private
|
|
55
|
+
*/
|
|
56
|
+
_initPreprocessorFromStorage()
|
|
57
|
+
{
|
|
58
|
+
try
|
|
59
|
+
{
|
|
60
|
+
let tmpSaved = (typeof localStorage !== 'undefined') ? localStorage.getItem('bookstore-preprocessor-enabled') : null;
|
|
61
|
+
if (tmpSaved === 'true')
|
|
62
|
+
{
|
|
63
|
+
this.enablePreprocessor();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (pError)
|
|
67
|
+
{
|
|
68
|
+
// localStorage may not be available (e.g., SSR or privacy mode)
|
|
69
|
+
this.pict.log.warn('Preprocessor: Could not read localStorage preference.');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Enable the template preprocessor. Instantiates the service and
|
|
75
|
+
* saves the preference to localStorage.
|
|
76
|
+
*/
|
|
77
|
+
enablePreprocessor()
|
|
78
|
+
{
|
|
79
|
+
if (this._preprocessorInstance)
|
|
80
|
+
{
|
|
81
|
+
// Already active
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
this._preprocessorInstance = this.pict.instantiateServiceProviderWithoutRegistration('PictTemplatePreprocessor');
|
|
86
|
+
|
|
87
|
+
try
|
|
88
|
+
{
|
|
89
|
+
if (typeof localStorage !== 'undefined')
|
|
90
|
+
{
|
|
91
|
+
localStorage.setItem('bookstore-preprocessor-enabled', 'true');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch (pError)
|
|
95
|
+
{
|
|
96
|
+
// Ignore storage errors
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.pict.log.info('Template Preprocessor: ENABLED');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Disable the template preprocessor. Unwraps template functions,
|
|
104
|
+
* clears the cache, and saves the preference to localStorage.
|
|
105
|
+
*/
|
|
106
|
+
disablePreprocessor()
|
|
107
|
+
{
|
|
108
|
+
if (!this._preprocessorInstance)
|
|
109
|
+
{
|
|
110
|
+
// Already inactive
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
this._preprocessorInstance.unwrapTemplateFunctions();
|
|
115
|
+
this._preprocessorInstance.clear();
|
|
116
|
+
this._preprocessorInstance = null;
|
|
117
|
+
|
|
118
|
+
try
|
|
119
|
+
{
|
|
120
|
+
if (typeof localStorage !== 'undefined')
|
|
121
|
+
{
|
|
122
|
+
localStorage.setItem('bookstore-preprocessor-enabled', 'false');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (pError)
|
|
126
|
+
{
|
|
127
|
+
// Ignore storage errors
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
this.pict.log.info('Template Preprocessor: DISABLED');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Toggle the preprocessor on or off.
|
|
135
|
+
*
|
|
136
|
+
* @return {boolean} True if the preprocessor is now enabled
|
|
137
|
+
*/
|
|
138
|
+
togglePreprocessor()
|
|
139
|
+
{
|
|
140
|
+
if (this._preprocessorInstance)
|
|
141
|
+
{
|
|
142
|
+
this.disablePreprocessor();
|
|
143
|
+
}
|
|
144
|
+
else
|
|
145
|
+
{
|
|
146
|
+
this.enablePreprocessor();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Re-render navigation to update the toggle UI
|
|
150
|
+
if (this.pict.views['Bookstore-Navigation'])
|
|
151
|
+
{
|
|
152
|
+
this.pict.views['Bookstore-Navigation'].render();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return !!this._preprocessorInstance;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Check if the preprocessor is currently active.
|
|
160
|
+
*
|
|
161
|
+
* @return {boolean} True if active
|
|
162
|
+
*/
|
|
163
|
+
isPreprocessorEnabled()
|
|
164
|
+
{
|
|
165
|
+
return !!this._preprocessorInstance;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
onAfterInitializeAsync(fCallback)
|
|
169
|
+
{
|
|
170
|
+
// Render the login form first
|
|
171
|
+
this.pict.views['Bookstore-Login'].render();
|
|
172
|
+
|
|
173
|
+
// Inject CSS so the login section styling is applied immediately
|
|
174
|
+
this.pict.CSSMap.injectCSS();
|
|
175
|
+
|
|
176
|
+
// Check if a session already exists (e.g. cookie from a previous visit).
|
|
177
|
+
// The login view's onSessionChecked hook will call showProtectedApp()
|
|
178
|
+
// if a valid session is found.
|
|
179
|
+
this.pict.views['Bookstore-Login'].checkSession();
|
|
180
|
+
|
|
181
|
+
return super.onAfterInitializeAsync(fCallback);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ===== Application-Level Navigation =====
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Switch from the login screen to the protected application.
|
|
188
|
+
* Called by the login view after a successful login or session check.
|
|
189
|
+
*/
|
|
190
|
+
showProtectedApp()
|
|
191
|
+
{
|
|
192
|
+
// Hide the login container
|
|
193
|
+
let tmpLoginElements = this.pict.ContentAssignment.getElement('#Bookstore-Login-Container');
|
|
194
|
+
if (tmpLoginElements && tmpLoginElements.length > 0)
|
|
195
|
+
{
|
|
196
|
+
tmpLoginElements[0].style.display = 'none';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Show the protected app container
|
|
200
|
+
let tmpAppElements = this.pict.ContentAssignment.getElement('#Bookstore-App-Container');
|
|
201
|
+
if (tmpAppElements && tmpAppElements.length > 0)
|
|
202
|
+
{
|
|
203
|
+
tmpAppElements[0].style.display = 'block';
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Render the layout shell (triggers Navigation, CSS injection, and router resolve)
|
|
207
|
+
this.pict.views['Bookstore-Layout'].render();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Switch from the protected application back to the login screen.
|
|
212
|
+
* Called by the doLogout() method after the session is destroyed.
|
|
213
|
+
*/
|
|
214
|
+
showLogin()
|
|
215
|
+
{
|
|
216
|
+
// Clear session data
|
|
217
|
+
this.pict.AppData.Session = null;
|
|
218
|
+
|
|
219
|
+
// Hide the protected app container
|
|
220
|
+
let tmpAppElements = this.pict.ContentAssignment.getElement('#Bookstore-App-Container');
|
|
221
|
+
if (tmpAppElements && tmpAppElements.length > 0)
|
|
222
|
+
{
|
|
223
|
+
tmpAppElements[0].style.display = 'none';
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Show the login container
|
|
227
|
+
let tmpLoginElements = this.pict.ContentAssignment.getElement('#Bookstore-Login-Container');
|
|
228
|
+
if (tmpLoginElements && tmpLoginElements.length > 0)
|
|
229
|
+
{
|
|
230
|
+
tmpLoginElements[0].style.display = 'block';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Reset the login view state and re-render
|
|
234
|
+
let tmpLoginView = this.pict.views['Bookstore-Login'];
|
|
235
|
+
if (tmpLoginView)
|
|
236
|
+
{
|
|
237
|
+
tmpLoginView.authenticated = false;
|
|
238
|
+
tmpLoginView.sessionData = null;
|
|
239
|
+
tmpLoginView.initialRenderComplete = false;
|
|
240
|
+
tmpLoginView.render();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Render a specific content view into the content container.
|
|
246
|
+
* Used by the router for custom views (Dashboard, About, Legal).
|
|
247
|
+
*
|
|
248
|
+
* @param {string} pViewIdentifier - The view identifier to render
|
|
249
|
+
*/
|
|
250
|
+
showView(pViewIdentifier)
|
|
251
|
+
{
|
|
252
|
+
if (pViewIdentifier in this.pict.views)
|
|
253
|
+
{
|
|
254
|
+
this.pict.views[pViewIdentifier].render();
|
|
255
|
+
}
|
|
256
|
+
else
|
|
257
|
+
{
|
|
258
|
+
this.pict.log.warn('View [' + pViewIdentifier + '] not found; falling back to Dashboard.');
|
|
259
|
+
this.pict.views['Bookstore-Dashboard'].render();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Show a recordset view (List, Read, Create, Dashboard) for a given entity.
|
|
265
|
+
* Ensures the PRSP_Container exists inside the content area, then navigates.
|
|
266
|
+
*
|
|
267
|
+
* @param {string} pRecordSet - The recordset name (e.g. 'Book', 'Author')
|
|
268
|
+
* @param {string} pVerb - The verb (e.g. 'List', 'Read', 'Create', 'Dashboard')
|
|
269
|
+
*/
|
|
270
|
+
showRecordSet(pRecordSet, pVerb)
|
|
271
|
+
{
|
|
272
|
+
// Ensure the recordset container exists in the content area
|
|
273
|
+
let tmpContentElements = this.pict.ContentAssignment.getElement('#Bookstore-Content-Container');
|
|
274
|
+
if (tmpContentElements && tmpContentElements.length > 0)
|
|
275
|
+
{
|
|
276
|
+
tmpContentElements[0].innerHTML = '<div id="PRSP_Container"></div>';
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Navigate to the PSRS route
|
|
280
|
+
let tmpRoute = '/PSRS/' + pRecordSet + '/' + pVerb;
|
|
281
|
+
this.pict.providers.RecordSetRouter.navigate(tmpRoute);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Single-argument wrappers for router templates (the {~LV:...~} macro
|
|
285
|
+
// does not reliably pass multiple arguments with backtick-delimited params).
|
|
286
|
+
showBookList() { return this.showRecordSet('Book', 'List'); }
|
|
287
|
+
showAuthorList() { return this.showRecordSet('Author', 'List'); }
|
|
288
|
+
showBookStoreList() { return this.showRecordSet('BookStore', 'List'); }
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Navigate to a route using pict-router.
|
|
292
|
+
*
|
|
293
|
+
* @param {string} pRoute - The route path (e.g. '/Dashboard', '/Books')
|
|
294
|
+
*/
|
|
295
|
+
navigateTo(pRoute)
|
|
296
|
+
{
|
|
297
|
+
this.pict.providers.PictRouter.navigate(pRoute);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Log out and return to the login screen.
|
|
302
|
+
* Called from the navigation sidebar logout button.
|
|
303
|
+
*/
|
|
304
|
+
doLogout()
|
|
305
|
+
{
|
|
306
|
+
let tmpLoginView = this.pict.views['Bookstore-Login'];
|
|
307
|
+
if (tmpLoginView)
|
|
308
|
+
{
|
|
309
|
+
tmpLoginView.logout(() =>
|
|
310
|
+
{
|
|
311
|
+
this.showLogin();
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
else
|
|
315
|
+
{
|
|
316
|
+
this.showLogin();
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
module.exports = BookstoreApplication;
|
|
322
|
+
|
|
323
|
+
module.exports.default_configuration = require('./Bookstore-Application-Configuration.json');
|
|
324
|
+
|
|
325
|
+
module.exports.default_configuration.pict_configuration = (
|
|
326
|
+
{
|
|
327
|
+
"Product": "Bookstore RecordSet Application",
|
|
328
|
+
|
|
329
|
+
"PictApplicationConfiguration":
|
|
330
|
+
{
|
|
331
|
+
"AutoRenderMainViewportViewAfterInitialize": false
|
|
332
|
+
},
|
|
333
|
+
|
|
334
|
+
"Manifests":
|
|
335
|
+
{
|
|
336
|
+
"Book-View":
|
|
337
|
+
{
|
|
338
|
+
"Form": "BookViewManifest",
|
|
339
|
+
"Scope": "Book-View",
|
|
340
|
+
"Descriptors":
|
|
341
|
+
{
|
|
342
|
+
"BookDetails.Title":
|
|
343
|
+
{
|
|
344
|
+
"Name": "Title",
|
|
345
|
+
"Hash": "ViewBookTitle",
|
|
346
|
+
"DataType": "String",
|
|
347
|
+
"PictForm":
|
|
348
|
+
{
|
|
349
|
+
"Row": "1",
|
|
350
|
+
"Section": "BookView",
|
|
351
|
+
"Group": "BookView"
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
"BookDetails.Genre":
|
|
355
|
+
{
|
|
356
|
+
"Name": "Genre",
|
|
357
|
+
"Hash": "ViewBookGenre",
|
|
358
|
+
"DataType": "String",
|
|
359
|
+
"PictForm":
|
|
360
|
+
{
|
|
361
|
+
"Row": "1",
|
|
362
|
+
"Section": "BookView",
|
|
363
|
+
"Group": "BookView"
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
"BookDetails.ISBN":
|
|
367
|
+
{
|
|
368
|
+
"Name": "ISBN",
|
|
369
|
+
"Hash": "ViewBookISBN",
|
|
370
|
+
"DataType": "String",
|
|
371
|
+
"PictForm":
|
|
372
|
+
{
|
|
373
|
+
"Row": "2",
|
|
374
|
+
"Section": "BookView",
|
|
375
|
+
"Group": "BookView"
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
"BookDetails.PublicationYear":
|
|
379
|
+
{
|
|
380
|
+
"Name": "Publication Year",
|
|
381
|
+
"Hash": "ViewBookYear",
|
|
382
|
+
"DataType": "Number",
|
|
383
|
+
"PictForm":
|
|
384
|
+
{
|
|
385
|
+
"Row": "2",
|
|
386
|
+
"Section": "BookView",
|
|
387
|
+
"Group": "BookView"
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
"Sections":
|
|
392
|
+
[
|
|
393
|
+
{
|
|
394
|
+
"Name": "Book Details",
|
|
395
|
+
"Hash": "BookView",
|
|
396
|
+
"Solvers": [],
|
|
397
|
+
"ShowTitle": false,
|
|
398
|
+
"Groups": [
|
|
399
|
+
{
|
|
400
|
+
"Name": "Book Details",
|
|
401
|
+
"Hash": "BookView",
|
|
402
|
+
"Rows": [],
|
|
403
|
+
"RecordSetSolvers": [],
|
|
404
|
+
"ShowTitle": false
|
|
405
|
+
}
|
|
406
|
+
]
|
|
407
|
+
}
|
|
408
|
+
]
|
|
409
|
+
},
|
|
410
|
+
"Author-View":
|
|
411
|
+
{
|
|
412
|
+
"Form": "AuthorViewManifest",
|
|
413
|
+
"Scope": "Author-View",
|
|
414
|
+
"Descriptors":
|
|
415
|
+
{
|
|
416
|
+
"AuthorDetails.Name":
|
|
417
|
+
{
|
|
418
|
+
"Name": "Author Name",
|
|
419
|
+
"Hash": "ViewAuthorName",
|
|
420
|
+
"DataType": "String",
|
|
421
|
+
"PictForm":
|
|
422
|
+
{
|
|
423
|
+
"Row": "1",
|
|
424
|
+
"Section": "AuthorView",
|
|
425
|
+
"Group": "AuthorView"
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
"Sections":
|
|
430
|
+
[
|
|
431
|
+
{
|
|
432
|
+
"Name": "Author Details",
|
|
433
|
+
"Hash": "AuthorView",
|
|
434
|
+
"Solvers": [],
|
|
435
|
+
"ShowTitle": false,
|
|
436
|
+
"Groups": [
|
|
437
|
+
{
|
|
438
|
+
"Name": "Author Details",
|
|
439
|
+
"Hash": "AuthorView",
|
|
440
|
+
"Rows": [],
|
|
441
|
+
"RecordSetSolvers": [],
|
|
442
|
+
"ShowTitle": false
|
|
443
|
+
}
|
|
444
|
+
]
|
|
445
|
+
}
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
|
|
450
|
+
"Filters":
|
|
451
|
+
{
|
|
452
|
+
"ExternalJoinBookByAuthor":
|
|
453
|
+
{
|
|
454
|
+
"Label": "Author's Name",
|
|
455
|
+
"Type": "ExternalJoinStringMatch",
|
|
456
|
+
"ExternalFilterByColumns": [ "Name" ],
|
|
457
|
+
"DisplayName": "Author's Name",
|
|
458
|
+
|
|
459
|
+
"CoreConnectionColumn": "IDBook",
|
|
460
|
+
|
|
461
|
+
"JoinTable": "BookAuthorJoin",
|
|
462
|
+
"JoinTableExternalConnectionColumn": "IDAuthor",
|
|
463
|
+
"JoinTableCoreConnectionColumn": "IDBook",
|
|
464
|
+
|
|
465
|
+
"ExternalFilterByTable": "Author",
|
|
466
|
+
"ExternalFilterByTableConnectionColumn": "IDAuthor"
|
|
467
|
+
},
|
|
468
|
+
"ExternalJoinBookBySelectedAuthors":
|
|
469
|
+
{
|
|
470
|
+
"Label": "Authors",
|
|
471
|
+
"Type": "ExternalJoinSelectedValueList",
|
|
472
|
+
"ExternalFilterByColumns": [ "Name", "GUIDAuthor" ],
|
|
473
|
+
"DisplayName": "Authors (select)",
|
|
474
|
+
|
|
475
|
+
"MaximumSelectedExternalRecords": 5,
|
|
476
|
+
"ExternalRecordDisplayTemplate": "{~D:Record.Data.Name~}",
|
|
477
|
+
|
|
478
|
+
"CoreConnectionColumn": "IDBook",
|
|
479
|
+
|
|
480
|
+
"JoinTable": "BookAuthorJoin",
|
|
481
|
+
"JoinTableExternalConnectionColumn": "IDAuthor",
|
|
482
|
+
"JoinTableCoreConnectionColumn": "IDBook",
|
|
483
|
+
|
|
484
|
+
"ExternalFilterByTable": "Author",
|
|
485
|
+
"ExternalFilterByTableConnectionColumn": "IDAuthor"
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
|
|
489
|
+
"DefaultRecordSetConfigurations":
|
|
490
|
+
[
|
|
491
|
+
{
|
|
492
|
+
"RecordSet": "Book",
|
|
493
|
+
|
|
494
|
+
"RecordSetType": "MeadowEndpoint",
|
|
495
|
+
"RecordSetMeadowEntity": "Book",
|
|
496
|
+
|
|
497
|
+
"RecordSetIgnoreFilterFields": [ "Deleted", "DeletingIDUser", "DeleteDate", "UpdateDate" ],
|
|
498
|
+
|
|
499
|
+
"RecordSetListColumns": [
|
|
500
|
+
{
|
|
501
|
+
"Key": "Title",
|
|
502
|
+
"DisplayName": "Title"
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
"Key": "Genre",
|
|
506
|
+
"DisplayName": "Genre"
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
"Key": "ISBN",
|
|
510
|
+
"DisplayName": "ISBN"
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
"Key": "PublicationYear",
|
|
514
|
+
"DisplayName": "Year"
|
|
515
|
+
}
|
|
516
|
+
],
|
|
517
|
+
|
|
518
|
+
"FilterExperiences":
|
|
519
|
+
{
|
|
520
|
+
"FilterByAuthor":
|
|
521
|
+
{
|
|
522
|
+
"Ordinal": 1,
|
|
523
|
+
"FilterCriteriaHash": "FilterRecordsetByAuthor",
|
|
524
|
+
"Default": true
|
|
525
|
+
},
|
|
526
|
+
"AdvancedSearch":
|
|
527
|
+
{
|
|
528
|
+
"Ordinal": 2,
|
|
529
|
+
"FilterCriteriaHash": "FilterRecordsetAdvancedSearch"
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
|
|
533
|
+
"RecordSetReadManifestOnly": true,
|
|
534
|
+
"RecordSetReadDefaultManifestView": "Book-View",
|
|
535
|
+
"RecordSetReadManifestsView": [ "Book-View" ],
|
|
536
|
+
|
|
537
|
+
"RecordSetReadTabs":
|
|
538
|
+
[
|
|
539
|
+
{
|
|
540
|
+
"Type": "AttachedRecord",
|
|
541
|
+
"RecordSet": "Author",
|
|
542
|
+
"Title": "Authors",
|
|
543
|
+
"JoiningRecordSet": "BookAuthorJoin"
|
|
544
|
+
}
|
|
545
|
+
],
|
|
546
|
+
|
|
547
|
+
"RecordSetListHasExtraColumns": true,
|
|
548
|
+
"RecordSetListExtraColumnsHeaderTemplate": "<th style=\"border-bottom: 1px solid #ccc; padding: 5px; background-color: #f2f2f2; color: #333;\">Cover</th>",
|
|
549
|
+
"RecordSetListExtraColumnRowTemplate": "<td><img src=\"{~D:Record.Data.ImageURL~}\" style=\"max-width:60px; max-height:80px;\"></td>",
|
|
550
|
+
|
|
551
|
+
"SearchFields": [ "Title" ],
|
|
552
|
+
|
|
553
|
+
"RecordSetURLPrefix": "/1.0/"
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
"RecordSet": "Author",
|
|
557
|
+
|
|
558
|
+
"RecordSetType": "MeadowEndpoint",
|
|
559
|
+
"RecordSetMeadowEntity": "Author",
|
|
560
|
+
|
|
561
|
+
"RecordSetURLPrefix": "/1.0/",
|
|
562
|
+
|
|
563
|
+
"RecordSetReadManifestOnly": true,
|
|
564
|
+
"RecordSetReadManifestsView": [ "Author-View" ],
|
|
565
|
+
|
|
566
|
+
"SearchFields": [ "Name" ]
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
"RecordSet": "BookStore",
|
|
570
|
+
"Title": "Book Stores",
|
|
571
|
+
|
|
572
|
+
"RecordSetType": "MeadowEndpoint",
|
|
573
|
+
"RecordSetMeadowEntity": "BookStore",
|
|
574
|
+
|
|
575
|
+
"RecordSetURLPrefix": "/1.0/",
|
|
576
|
+
|
|
577
|
+
"RecordSetListColumns": [
|
|
578
|
+
{
|
|
579
|
+
"Key": "Name",
|
|
580
|
+
"DisplayName": "Store Name"
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
"Key": "Address",
|
|
584
|
+
"DisplayName": "Address"
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
"Key": "City",
|
|
588
|
+
"DisplayName": "City"
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
"Key": "State",
|
|
592
|
+
"DisplayName": "State"
|
|
593
|
+
}
|
|
594
|
+
],
|
|
595
|
+
|
|
596
|
+
"SearchFields": [ "Name", "City" ]
|
|
597
|
+
}
|
|
598
|
+
],
|
|
599
|
+
|
|
600
|
+
"FilterCriteria":
|
|
601
|
+
{
|
|
602
|
+
"FilterRecordsetByAuthor":
|
|
603
|
+
[
|
|
604
|
+
{
|
|
605
|
+
"FilterDefinitionHash": "ExternalJoinBookByAuthor",
|
|
606
|
+
"FilterByColumn": "IDBook"
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
"Type": "StringMatch",
|
|
610
|
+
"FilterByColumn": "Title"
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
"Type": "StringMatch",
|
|
614
|
+
"FilterByColumn": "Genre"
|
|
615
|
+
}
|
|
616
|
+
],
|
|
617
|
+
// The "Advanced Search" experience packs nine filter clauses onto a
|
|
618
|
+
// single dashboard render so the parallel filter fan-out added in
|
|
619
|
+
// Pict-Template-FilterInstanceViews is observable in practice. It
|
|
620
|
+
// also exercises a mix of filter types (ExternalJoinSelectedValueList,
|
|
621
|
+
// StringMatch, NumericRange, DateRange) so each filter family is
|
|
622
|
+
// touched at least once in the render path.
|
|
623
|
+
"FilterRecordsetAdvancedSearch":
|
|
624
|
+
[
|
|
625
|
+
{
|
|
626
|
+
"FilterDefinitionHash": "ExternalJoinBookBySelectedAuthors",
|
|
627
|
+
"FilterByColumn": "IDBook"
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
"Type": "StringMatch",
|
|
631
|
+
"FilterByColumn": "Title",
|
|
632
|
+
"Label": "Title"
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
"Type": "StringMatch",
|
|
636
|
+
"FilterByColumn": "Genre",
|
|
637
|
+
"Label": "Genre"
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
"Type": "StringMatch",
|
|
641
|
+
"FilterByColumn": "Type",
|
|
642
|
+
"Label": "Book Type"
|
|
643
|
+
},
|
|
644
|
+
{
|
|
645
|
+
"Type": "StringMatch",
|
|
646
|
+
"FilterByColumn": "Language",
|
|
647
|
+
"Label": "Language"
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
"Type": "StringMatch",
|
|
651
|
+
"FilterByColumn": "ISBN",
|
|
652
|
+
"Label": "ISBN"
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
"Type": "NumericRange",
|
|
656
|
+
"FilterByColumn": "PublicationYear",
|
|
657
|
+
"Label": "Publication Year"
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
"Type": "DateRange",
|
|
661
|
+
"FilterByColumn": "CreateDate",
|
|
662
|
+
"Label": "Added to Catalog"
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
"Type": "DateRange",
|
|
666
|
+
"FilterByColumn": "UpdateDate",
|
|
667
|
+
"Label": "Last Updated"
|
|
668
|
+
}
|
|
669
|
+
]
|
|
670
|
+
}
|
|
671
|
+
});
|