diff --git a/lib/ui/layers/panels/dataviews.mjs b/lib/ui/layers/panels/dataviews.mjs index 03ed3cf7d2..ad3a686291 100644 --- a/lib/ui/layers/panels/dataviews.mjs +++ b/lib/ui/layers/panels/dataviews.mjs @@ -24,62 +24,53 @@ The dataviews method returns a drawer with checkbox elements for each dataview o The dataviews will be decorated with the `mapp.ui.Dataview()` method. @param {layer} layer The decorated mapp layer object. -@property {Object} dataviews The layer dataviews. +@property {Object} layer.dataviews The layer dataviews. @return {HTMLElement} */ - export default function dataviews(layer) { + const content = []; - // Return if on mobile as dataviews are not supported. - if (mapp.utils.mobile()) return; - - // Create chkbox controls for each dataview entry. - const dataviewChkboxes = Object.entries(layer.dataviews).map(entry => { - - // The layer.dataviews{} object may include a hide flag. - if (typeof entry[1] !== 'object') return; - - // Assign key, host, and layer to dataview object. - const dataview = Object.assign(entry[1], - { - key: entry[0], - host: layer.mapview.host, - layer, - }) + for (const [key, dataview] of Object.entries(layer.dataviews)) { + // The dataview entry may be a flag. + if (typeof dataview === 'string' || dataview === true) continue; - // Prevent altering the dataview target in JSON - dataview._target ??= dataview.target + Object.assign(dataview, { + key, + layer, + host: layer.mapview.host, + }); // Find tabview element from data-id attribute. - dataview.tabview = document.querySelector(`[data-id=${dataview._target}]`) + dataview.tabview = document.querySelector(`[data-id=${dataview.target}]`); // Return if the named tabview is not found in document. - if (!dataview.tabview) return; + if (dataview.tabview) { + // Return if on mobile as dataviews are not supported. + if (mapp.utils.mobile()) return; + + dataview.show ??= () => { + // Create tab after dataview creation is complete. + dataview.tabview.dispatchEvent( + new CustomEvent('addTab', { detail: dataview }), + ); + + // Show the dataview tab. + dataview.show(); + }; + + dataview.hide ??= () => { + dataview.display = false; + dataview.remove(); + }; + } // Assign target html element for dataview. - dataview.target = mapp.utils.html.node`
` + dataview.target = mapp.utils.html.node` +
`; // Assign label for dataview.chkbox - dataview.label ??= dataview.title || dataview.key - - dataview.show ??= () => { - - // Create tab after dataview creation is complete. - dataview.tabview.dispatchEvent(new CustomEvent('addTab', { - detail: dataview - })) - - // Show the dataview tab. - dataview.show() - } - - dataview.hide ??= () => { - - dataview.display = false - - dataview.remove() - } + dataview.label ??= dataview.title || dataview.key; // Create checkbox control for dataview. dataview.chkbox = mapp.ui.elements.chkbox({ @@ -88,28 +79,27 @@ export default function dataviews(layer) { checked: !!dataview.display, disabled: dataview.disabled, onchange: (checked) => { + dataview.display = checked; - dataview.display = checked - - dataview.display - ? dataview.show() - : dataview.hide() - } - }) + dataview.display ? dataview.show() : dataview.hide(); + }, + }); if (mapp.ui.Dataview(dataview) instanceof Error) return; // Display dataview if layer and dv have display flag. - layer.display - && dataview.display - && dataview.show() + layer.display && dataview.display && dataview.show(); layer.showCallbacks.push(() => { - dataview.display && dataview.show() - }) + dataview.display && dataview.show(); + }); - return dataview.chkbox - }) + content.push(dataview.chkbox); + + if (!dataview.tabview) { + content.push(dataview.target); + } + } // The dataviews are created but no panel is returned. if (layer.dataviews.hide) return; @@ -121,8 +111,8 @@ export default function dataviews(layer) { header: mapp.utils.html`

${mapp.dictionary.layer_dataview_header}

`, - content: mapp.utils.html`${dataviewChkboxes.filter(dv => !!dv)}` - }) + content, + }); - return drawer + return drawer; } diff --git a/lib/ui/layers/view.mjs b/lib/ui/layers/view.mjs index ea1686c0d9..e8b3350103 100644 --- a/lib/ui/layers/view.mjs +++ b/lib/ui/layers/view.mjs @@ -260,6 +260,11 @@ function changeEnd(layer) { // Collapse drawer and disable layer.view. layer.view.querySelector('.layer-view.drawer').classList.remove('expanded') + const expandedDrawer = layer.view.querySelectorAll('.layer-view.drawer .expanded'); + + // Collapse any expanded elements within layer.view drawer. + [...expandedDrawer].forEach(drawer => drawer.classList.remove('expanded')) + // Disable layer display toggle. layer.displayToggle instanceof HTMLElement && layer.displayToggle.classList.add('disabled') diff --git a/lib/ui/locations/entries/dataview.mjs b/lib/ui/locations/entries/dataview.mjs index 3a874090dd..baffdca52c 100644 --- a/lib/ui/locations/entries/dataview.mjs +++ b/lib/ui/locations/entries/dataview.mjs @@ -49,35 +49,29 @@ The dataview checkbox and locationViewTarget elements will be returned if availa @property {boolean} [entry.display] The dataview display flag. @property {Function} [entry.show] The dataview show method. @property {Function} [entry.hide] The dataview hide method. -@property {HTMLElement} [entry.locationViewTarget] Dataview target for display in location.view. @return {HTMLElement} Location view dataview and checkbox. */ export default function dataview(entry) { - if (entry.value !== undefined) { - entry.data = entry.value + entry.data = entry.value; if (entry.data?.length === 0) { - - entry.data = null + entry.data = null; } - } + } if (entry.data === null) { - // The entry must be disabled if the query has run with querycheck:true and the data is null. // This is to prevent the query running over and over again getting the same result. entry._display ??= entry.display; delete entry.display; - } else { entry.display ??= entry._display; } if (entry.label) { - // Create checkbox if a label is provided. entry.chkbox = mapp.ui.elements.chkbox({ data_id: entry.key, @@ -100,7 +94,6 @@ export default function dataview(entry) { typeof entry.target === 'string' && document.getElementById(entry.target) ) { - // Assign element by ID as target. entry.target = document.getElementById(entry.target); @@ -113,7 +106,6 @@ export default function dataview(entry) { // Dataview has already been created. e.g. after the location (view) is updated, and it is not dynamic. if (entry.update && !entry.dynamic) { - if (entry.display) entry.show?.(); // Return elements to location view. @@ -145,10 +137,9 @@ export default function dataview(entry) { entry.tabview.dispatchEvent( new CustomEvent('addTab', { detail: entry, - }) + }), ); } else if (!entry.tabview) { - // Dataview will be rendered into location view. const location_class = `location ${entry.key || entry.query}`; diff --git a/public/css/elements/_drawer.css b/public/css/elements/_drawer.css index 5e339a5647..5199d03536 100644 --- a/public/css/elements/_drawer.css +++ b/public/css/elements/_drawer.css @@ -21,7 +21,7 @@ } &.expandable:not(.expanded)>*:not(.header) { - display: none; + display: none !important; } &.expanded>.header>.mask-icon.expander { diff --git a/public/css/ui.css b/public/css/ui.css index 1da042b0b7..6a3842e314 100644 --- a/public/css/ui.css +++ b/public/css/ui.css @@ -1203,7 +1203,7 @@ dialog { mask-image: url('data:image/svg+xml,%0A %0A'); } &.expandable:not(.expanded) > *:not(.header) { - display: none; + display: none !important; } &.expanded > .header > .mask-icon.expander { -webkit-mask-image: url('data:image/svg+xml,%0A %0A'); diff --git a/tests/assets/dataviews/dataviews_panel.json b/tests/assets/dataviews/dataviews_panel.json new file mode 100644 index 0000000000..4b16bef149 --- /dev/null +++ b/tests/assets/dataviews/dataviews_panel.json @@ -0,0 +1,65 @@ +{ + "dataviews": { + "test": { + "target": "tabview", + "dataview": "Json", + "query": "stores", + "display": true, + "queryparams": { + "table": true, + "layer": "stores", + "limit": 10 + }, + "toolbar": { + "queryparams": { + "limit": { + "type": "numeric" + } + } + }, + "table": { + "frozenRows": 1, + "selectable": true, + "columns": [ + { + "field": "name", + "width": 300, + "title": "Name" + } + ] + } + }, + "stores": { + "display": true, + "target": "tabview", + "query": "stores", + "viewport": true, + "dataview": "Json", + "table": { + "selectable": true, + "pagination": true, + "columns": [ + { + "field": "name", + "width": 300, + "title": "Name" + } + ] + } + }, + "json": { + "display": true, + "label": "Json", + "dataview": "Json", + "query": "select_arr", + "toolbar": { + "jsonfile": true + }, + "template": { + "key": "select_arr", + "template": "SELECT array[1, 2, 3]", + "value_only": true + } + } + } +} diff --git a/tests/lib/ui/layers/_layers.test.mjs b/tests/lib/ui/layers/_layers.test.mjs index 99f59690cd..f6c406ea7c 100644 --- a/tests/lib/ui/layers/_layers.test.mjs +++ b/tests/lib/ui/layers/_layers.test.mjs @@ -1,5 +1,6 @@ import { filters } from './filters.test.mjs'; import { filter } from './panels/filter.test.mjs'; +import { dataviews } from './panels/dataviews.test.mjs'; import { view } from './view.test.mjs'; export const layers = { @@ -7,6 +8,7 @@ export const layers = { filters, panels: { filter, + dataviews, }, view, }; diff --git a/tests/lib/ui/layers/panels/dataviews.test.mjs b/tests/lib/ui/layers/panels/dataviews.test.mjs new file mode 100644 index 0000000000..65a5814f6d --- /dev/null +++ b/tests/lib/ui/layers/panels/dataviews.test.mjs @@ -0,0 +1,34 @@ +import dataviews_panel from '../../../../assets/dataviews/dataviews_panel.json'; +export function dataviews(mapview) { + codi.describe( + { + name: 'Panel Filter test:', + id: 'ui_layers_panel_dataviews', + parentId: 'ui_layers', + }, + () => { + codi.it( + { + name: 'Create dataview panel', + parentId: 'ui_layers_panel_dataviews', + }, + () => { + const dataviews = JSON.parse(JSON.stringify(dataviews_panel)); + + const layer = { + mapview: mapview, + dataviews: dataviews.dataviews, + showCallbacks: [], + }; + + const drawer = ui.layers.panels.dataviews(layer); + + codi.assertTrue( + drawer.childNodes.length > 0, + 'Ensure that we have children being added into the panel', + ); + }, + ); + }, + ); +} diff --git a/tests/lib/ui/locations/entries/dataview.test.mjs b/tests/lib/ui/locations/entries/dataview.test.mjs new file mode 100644 index 0000000000..108115cb86 --- /dev/null +++ b/tests/lib/ui/locations/entries/dataview.test.mjs @@ -0,0 +1,40 @@ +export function dataview(mapview) { + codi.describe( + { + name: 'Dataview test', + id: 'ui_locations_entries_dataview', + parentId: 'ui_locations_entries', + }, + () => { + codi.it( + { + name: 'basic', + id: 'ui_locations_entries_dataview_basic', + parentId: 'ui_locations_entries_dataview', + }, + () => { + const expected = '
'; + const entry = { + key: 'test-dataview', + dataview: 'Json', + layer: { + mapview: mapview, + }, + data: { test: true }, + location: { + layer: {}, + }, + }; + + const result = ui.locations.entries.dataview(entry); + + codi.assertEqual( + result[3], + expected, + 'We expect to get a basic dataview div returned', + ); + }, + ); + }, + ); +}