From 39137d1348a01d90fee89863d7f22bbec9e3b604 Mon Sep 17 00:00:00 2001 From: Paolo Date: Mon, 24 Apr 2023 17:07:40 +0200 Subject: [PATCH 01/12] Load a model in the filter component controller to have the DB functionalities ready --- application/controllers/components/Filter.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/application/controllers/components/Filter.php b/application/controllers/components/Filter.php index ab7e1493e..bde7d7ed7 100644 --- a/application/controllers/components/Filter.php +++ b/application/controllers/components/Filter.php @@ -26,6 +26,9 @@ class Filter extends FHC_Controller // Loads authentication library and starts authentication $this->load->library('AuthLib'); + // Loads the FiltersModel + $this->load->model('system/Filters_model', 'FiltersModel'); + // Loads the FilterCmptLib with HTTP GET/POST parameters $this->_startFilterCmptLib(); } From 2b363119c543e2c81d6cf2c3d2035b75e95ebcd9 Mon Sep 17 00:00:00 2001 From: cgfhtw Date: Tue, 16 May 2023 10:33:05 +0200 Subject: [PATCH 02/12] Split the component to improve the quality, readability and maintainability --- public/js/components/filter/Filter.js | 394 +++++--------------------- 1 file changed, 71 insertions(+), 323 deletions(-) diff --git a/public/js/components/filter/Filter.js b/public/js/components/filter/Filter.js index 2bf878e5a..dbf15a315 100644 --- a/public/js/components/filter/Filter.js +++ b/public/js/components/filter/Filter.js @@ -18,6 +18,8 @@ import {CoreFilterAPIs} from './API.js'; import {CoreRESTClient} from '../../RESTClient.js'; import {CoreFetchCmpt} from '../../components/Fetch.js'; +import FilterConfig from './Filter/Config.js'; +import FilterColumns from './Filter/Columns.js'; // const FILTER_COMPONENT_NEW_FILTER = 'Filter Component New Filter'; @@ -29,10 +31,14 @@ var _uuid = 0; * */ export const CoreFilterCmpt = { - emits: ['nwNewEntry'], components: { - CoreFetchCmpt + CoreFetchCmpt, + FilterConfig, + FilterColumns }, + emits: [ + 'nwNewEntry' + ], props: { title: String, sideMenu: { @@ -135,20 +141,17 @@ export const CoreFilterCmpt = { if (!this.uuid) return ''; return '-' + this.uuid; + }, + columnsForFilter() { + if (!this.filteredColumns || !this.datasetMetadata) + return []; + const filterTitles = this.filteredColumns.reduce((a,c) => { + a[c.field] = c.title; + return a; + }, {}); + return this.datasetMetadata.map(el => ({...el, ...{title: filterTitles[el.name]}})); } }, - beforeCreate() { - if (!this.tableOnly == !this.filterType) - alert('You can not have a filter-type in table-only mode!'); - }, - created() { - this.uuid = _uuid++; - if (!this.tableOnly) - this.getFilter(); // get the filter data - }, - mounted() { - this.initTabulator(); - }, methods: { initTabulator() { // Define a default tabulator options in case it was not provided @@ -230,7 +233,7 @@ export const CoreFilterCmpt = { filter.type = data.datasetMetadata[i].type; this.filterFields.push(filter); - break; + //break; } } } @@ -266,6 +269,7 @@ export const CoreFilterCmpt = { if (link == null) link = '#'; filtersArray[filtersArray.length] = { + id: filters[filtersCount].filter_id, link: link + filters[filtersCount].filter_id, description: filters[filtersCount].desc, sort: filtersCount, @@ -280,6 +284,7 @@ export const CoreFilterCmpt = { if (link == null) link = '#'; filtersArray[filtersArray.length] = { + id: personalFilters[filtersCount].filter_id, link: link + personalFilters[filtersCount].filter_id, description: personalFilters[filtersCount].desc, subscriptDescription: personalFilters[filtersCount].subscriptDescription, @@ -318,6 +323,7 @@ export const CoreFilterCmpt = { if (link == null) link = '#'; filtersArray[filtersArray.length] = { + id: filters[filtersCount].filter_id, option: filters[filtersCount].filter_id, description: filters[filtersCount].desc }; @@ -330,6 +336,7 @@ export const CoreFilterCmpt = { if (link == null) link = '#'; filtersArray[filtersArray.length] = { + id: personalFilters[filtersCount].filter_id, option: personalFilters[filtersCount].filter_id, description: personalFilters[filtersCount].desc }; @@ -366,12 +373,12 @@ export const CoreFilterCmpt = { /** * */ - handlerSaveCustomFilter: function(event) { + handlerSaveCustomFilter: function(customFilterName) { // this.startFetchCmpt( CoreFilterAPIs.saveCustomFilter, { - customFilterName: this.$refscustomFilterName.value + customFilterName }, this.getFilter ); @@ -389,150 +396,10 @@ export const CoreFilterCmpt = { this.getFilter ); }, - /** - * - */ - handlerApplyFilterFields: function(event) { - let filterFields = []; - let filterFieldDivRows = document.getElementById('filterFields').getElementsByClassName('row'); - for (let i = 0; i< filterFieldDivRows.length; i++) - { - let filterField = {}; - - for (let j = 0; j< filterFieldDivRows[i].children.length; j++) - { - let filterColumn = filterFieldDivRows[i].children[j]; - let filterColumnElement = filterColumn.children[0]; - - // If the first column then search for the fields dropdown - if (j == 0) filterColumnElement = filterColumnElement.querySelector('select[name=fieldName]'); - - // If the filter name is _not_ null and it is _not_ a new filter - if (filterColumnElement.name != null && filterColumnElement.name != FILTER_COMPONENT_NEW_FILTER) - { - // Condition - if (filterColumnElement.name == 'condition' && filterColumnElement.value == "") - { - alert("Please fill all the filter options"); - return; - } - - // Name - if (filterColumnElement.name == 'fieldName') - { - filterField.name = filterColumnElement.value; - } - // Operation - if (filterColumnElement.name == 'operation') - { - filterField.operation = filterColumnElement.value; - } - // Condition - if (filterColumnElement.name == 'condition') - { - filterField.condition = filterColumnElement.value; - } - // Option - if (filterColumnElement.name == 'option') - { - filterField.option = filterColumnElement.value; - } - } - } - - if (Object.entries(filterField).length > 0) filterFields.push(filterField); - } - - // - this.startFetchCmpt( - CoreFilterAPIs.applyFilterFields, - { - filterFields: filterFields - }, - this.getFilter - ); - }, - /** - * - */ - handlerChangeFilterField: function(oldValue, newValue) { - - // If an old filter has been changed - if (oldValue != "") - { - for (let i = 0; i < this.filterFields.length; i++) - { - if (this.filterFields[i].name == oldValue) - { - this.filterFields.splice(i, 1); - break; - } - } - } - - // Then add the new filter - for (let i = 0; i < this.datasetMetadata.length; i++) - { - if (this.datasetMetadata[i].name == newValue) - { - let filter = { - name: this.datasetMetadata[i].name, - type: this.datasetMetadata[i].type - }; - - this.filterFields.push(filter); - break; - } - } - }, - /** - * - */ - handlerAddNewFilter: function(event) { - // Adds a new empty filter - this.filterFields.push({ - name: FILTER_COMPONENT_NEW_FILTER, - type: FILTER_COMPONENT_NEW_FILTER_TYPE - }); - }, /* * */ - handlerToggleSelectedField(field) { - - // If it is a selected field - if (this.selectedFields.indexOf(field) != -1) - { - // then hide it - this.tabulator.hideColumn(field); - // and remove it from the this.selectedFields property - this.selectedFields.splice(this.selectedFields.indexOf(field), 1); - } - else // otherwise - { - // show it - this.tabulator.showColumn(field); - // and add it to the this.selectedFields property - this.selectedFields.push(field); - } - }, - /** - * - */ - handlerRemoveFilterField: function(event) { - // - this.startFetchCmpt( - CoreFilterAPIs.removeFilterField, - { - filterField: event.currentTarget.getAttribute('field-to-remove') - }, - this.getFilter - ); - }, - /** - * - */ handlerGetFilterById: function(event) { let filterId = null; @@ -550,16 +417,40 @@ export const CoreFilterCmpt = { filterId = attr.substring(1); } + this.switchFilter(filterId); + }, + switchFilter(filterId) { // Ajax call this.startFetchCmpt( CoreFilterAPIs.getFilterById, { - filterId: filterId + filterId }, this.render ); + }, + applyFilterConfig(filterFields) { + this.startFetchCmpt( + CoreFilterAPIs.applyFilterFields, + { + filterFields + }, + this.getFilter + ); } }, + beforeCreate() { + if (!this.tableOnly == !this.filterType) + alert('You can not have a filter-type in table-only mode!'); + }, + created() { + this.uuid = _uuid++; + if (!this.tableOnly) + this.getFilter(); // get the filter data + }, + mounted() { + this.initTabulator(); + }, template: ` -
-
- -
-
- -
-
-
-
+ -
-
- -
- -
-
-
- - Neuer Filter - - - - -
-
- -
- - -
-
-
- - -
-
-
- -
-
-
-
-
+ From 1568e619a585d5cb7dbf3ad7d3c2c96b8c6101b7 Mon Sep 17 00:00:00 2001 From: cgfhtw Date: Tue, 16 May 2023 10:33:31 +0200 Subject: [PATCH 03/12] Split the component to improve the quality, readability and maintainability --- public/js/components/filter/Filter/Columns.js | 83 +++++++ public/js/components/filter/Filter/Config.js | 215 ++++++++++++++++++ 2 files changed, 298 insertions(+) create mode 100644 public/js/components/filter/Filter/Columns.js create mode 100644 public/js/components/filter/Filter/Config.js diff --git a/public/js/components/filter/Filter/Columns.js b/public/js/components/filter/Filter/Columns.js new file mode 100644 index 000000000..448d05d17 --- /dev/null +++ b/public/js/components/filter/Filter/Columns.js @@ -0,0 +1,83 @@ +/** + * Copyright (C) 2022 fhcomplete.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * + */ +export default { + props: { + fields: Array, + selected: { + type: Array, + default: [] + }, + names: { + type: Array, + default: [] + } + }, + emits: [ + 'hide', + 'show' + ], + data: function() { + return { + selectedFields: [] + }; + }, + computed: { + + }, + watch: { + selected(n) { + this.selectedFields = n; + } + }, + methods: { + toggle(field) { + if (this.selectedFields.indexOf(field) != -1) + { + this.selectedFields.splice(this.selectedFields.indexOf(field), 1); + this.$emit('hide', field); + } + else + { + this.selectedFields.push(field); + this.$emit('show', field); + } + } + }, + template: ` +
+
+
+
+
+ {{ names[fieldToDisplay] || fieldToDisplay }} +
+
+
+
+
+ ` +}; + diff --git a/public/js/components/filter/Filter/Config.js b/public/js/components/filter/Filter/Config.js new file mode 100644 index 000000000..6869c1599 --- /dev/null +++ b/public/js/components/filter/Filter/Config.js @@ -0,0 +1,215 @@ +/** + * Copyright (C) 2022 fhcomplete.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +const FILTER_COMPONENT_NEW_FILTER = 'Filter Component New Filter'; + +/** + * + */ +export default { + props: { + filters: { + type: Array, + default: [] + }, + columns: { + type: Array, + default: [] + }, + fields: { + type: Array, + default: [] + } + }, + emits: [ + 'switchFilter', + 'applyFilterConfig', + 'saveCustomFilter' + ], + data: function() { + return { + currentFields: [] + }; + }, + computed: { + types() { + return this.columns.reduce((a,c) => { + let type = c.type.toLowerCase(); + if (type.indexOf('int') >= 0) + a[c.name] = 'Numeric'; + else if ( + type.indexOf('varchar') >= 0 || + type.indexOf('text') >= 0 || + type.indexOf('bpchar') >= 0 + ) + a[c.name] = 'Text'; + else if ( + type.indexOf('timestamp') >= 0 || + type.indexOf('date') >= 0 + ) + a[c.name] = 'Date'; + else + a[c.name] = ''; + return a; + }, {}); + } + }, + watch: { + fields(n) { + this.currentFields = n; + } + }, + methods: { + switchFilter(evt) { + this.$emit('switchFilter', evt.currentTarget.value); + }, + applyFilterConfig() { + const filteredFields = this.currentFields.filter(el => el.name != FILTER_COMPONENT_NEW_FILTER); + if (filteredFields.filter(el => el.condition == "").length) + alert("Please fill all the filter options"); + else + this.$emit('applyFilterConfig', filteredFields); + }, + addField(evt) { + this.currentFields.push({ + name: FILTER_COMPONENT_NEW_FILTER + }); + }, + removeField(index) { + this.currentFields.splice(index, 1); + } + }, + template: ` +
+
+
+
+ +
+
+ +
+
+
+ +
+
+ Filter {{ index + 1 }} + +
+
+ + + + + + + + + + +
+ +
+
+
+ + +
+
+
+ + +
+
+
+ +
+
+
+
+
+ ` +}; + From 38f2bb89a45a902d655971a3fec9ddaa3bb7e6cf Mon Sep 17 00:00:00 2001 From: cgfhtw Date: Tue, 16 May 2023 10:40:58 +0200 Subject: [PATCH 04/12] readability --- public/js/components/filter/Filter/Columns.js | 8 ++++---- public/js/components/filter/Filter/Config.js | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/public/js/components/filter/Filter/Columns.js b/public/js/components/filter/Filter/Columns.js index 448d05d17..ca8fc0aec 100644 --- a/public/js/components/filter/Filter/Columns.js +++ b/public/js/components/filter/Filter/Columns.js @@ -30,10 +30,10 @@ export default { default: [] } }, - emits: [ - 'hide', - 'show' - ], + emits: { + hide: ['fieldName'], + show: ['fieldName'] + }, data: function() { return { selectedFields: [] diff --git a/public/js/components/filter/Filter/Config.js b/public/js/components/filter/Filter/Config.js index 6869c1599..3c75c5a3c 100644 --- a/public/js/components/filter/Filter/Config.js +++ b/public/js/components/filter/Filter/Config.js @@ -35,11 +35,11 @@ export default { default: [] } }, - emits: [ - 'switchFilter', - 'applyFilterConfig', - 'saveCustomFilter' - ], + emits: { + switchFilter: ['filterId'], + applyFilterConfig: ['filterFields'], + saveCustomFilter: ['customFilterName'] + }, data: function() { return { currentFields: [] From 76fd4250275887e9378dc7cd952721a654d209d1 Mon Sep 17 00:00:00 2001 From: cgfhtw Date: Tue, 16 May 2023 14:12:46 +0200 Subject: [PATCH 05/12] assert valid nw-new-entry listener if side-menu is enabled --- public/js/components/filter/Filter.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/public/js/components/filter/Filter.js b/public/js/components/filter/Filter.js index dbf15a315..eb5f1a005 100644 --- a/public/js/components/filter/Filter.js +++ b/public/js/components/filter/Filter.js @@ -40,6 +40,7 @@ export const CoreFilterCmpt = { 'nwNewEntry' ], props: { + onNwNewEntry: Function, // NOTE(chris): Hack to get the nwNewEntry listener into $props title: String, sideMenu: { type: Boolean, @@ -444,6 +445,8 @@ export const CoreFilterCmpt = { alert('You can not have a filter-type in table-only mode!'); }, created() { + if (this.sideMenu && (!this.$props.onNwNewEntry || !(this.$props.onNwNewEntry instanceof Function))) + alert('"nwNewEntry" listener is mandatory when sideMenu is true'); this.uuid = _uuid++; if (!this.tableOnly) this.getFilter(); // get the filter data @@ -451,7 +454,7 @@ export const CoreFilterCmpt = { mounted() { this.initTabulator(); }, - template: ` + template: `{{$attrs}} Date: Fri, 19 May 2023 14:47:05 +0200 Subject: [PATCH 06/12] Property to Enable/disable the download button --- public/js/components/filter/Filter.js | 13 +- public/js/components/filter/Table/Download.js | 246 ++++++++++++++++++ 2 files changed, 256 insertions(+), 3 deletions(-) create mode 100644 public/js/components/filter/Table/Download.js diff --git a/public/js/components/filter/Filter.js b/public/js/components/filter/Filter.js index eb5f1a005..ae2ab9e7a 100644 --- a/public/js/components/filter/Filter.js +++ b/public/js/components/filter/Filter.js @@ -20,6 +20,7 @@ import {CoreRESTClient} from '../../RESTClient.js'; import {CoreFetchCmpt} from '../../components/Fetch.js'; import FilterConfig from './Filter/Config.js'; import FilterColumns from './Filter/Columns.js'; +import TableDownload from './Table/Download.js'; // const FILTER_COMPONENT_NEW_FILTER = 'Filter Component New Filter'; @@ -34,7 +35,8 @@ export const CoreFilterCmpt = { components: { CoreFetchCmpt, FilterConfig, - FilterColumns + FilterColumns, + TableDownload }, emits: [ 'nwNewEntry' @@ -52,7 +54,11 @@ export const CoreFilterCmpt = { }, tabulatorOptions: Object, tabulatorEvents: Array, - tableOnly: Boolean + tableOnly: Boolean, + download: { + type: [Boolean, String, Function, Array, Object], + default: false + } }, data: function() { return { @@ -454,7 +460,7 @@ export const CoreFilterCmpt = { mounted() { this.initTabulator(); }, - template: `{{$attrs}} + template: ` [ {{ filterName }} ] + . + */ + +const DEFAULT_ICONS = { + jsonLines: 'fa-file-lines', + xlsx: 'fa-file-excel', + pdf: 'fa-file-pdf', + html: 'fa-file-code', + json: 'fa-file', + csv: 'fa-file-csv' +}; +const DEFAULT_LABELS = { + jsonLines: 'Download as JSONLINES', + xlsx: 'Download as XLSX', + pdf: 'Download as PDF', + html: 'Download as HTML', + json: 'Download as JSON', + csv: 'Download as CSV ' +}; + + +/** + * + */ +export default { + props: { + tabulator: Object, + config: { + type: [Boolean, String, Function, Array, Object], + default: false + } + }, + computed: { + currentConfig() { + if (!this.config) + return false; + + let config = this.config; + + if (config instanceof Function) + return [config]; + + if (config === null) + return []; + + if (this.config === true) + config = ['csv']; + + if (Object.prototype.toString.call(config) === "[object String]") + config = config.split(','); + + if (typeof config === 'object' && !Array.isArray(config)) { + let newConfig = []; + for (var k in config) { + var v = config[k], type; + + if (!v) + continue; + + if (Object.prototype.toString.call(v) === "[object String]") { + type = this.stringToFileFormatter(v); + if (type !== null) { + newConfig.push({ + icon: 'fa-solid ' + DEFAULT_ICONS[type], + label: v === k ? DEFAULT_LABELS[type] : k, + formatter: type + }); + } else { + type = this.stringToFileFormatter(k); + if(type !== null) { + newConfig.push({ + icon: 'fa-solid ' + DEFAULT_ICONS[type], + label: v, + formatter: type + }); + } else { + alert('neither ' + k + ' nor ' + v + ' are supported download file types'); + } + } + } else if (typeof v === 'object' && !Array.isArray(v)) { + type = this.stringToFileFormatter(k); + if (type !== null) { + if (v.formatter === undefined) + v.formatter = type; + if (v.label === undefined) + v.label = DEFAULT_LABELS[type]; + if (v.icon === undefined) + v.icon = DEFAULT_ICONS[type]; + newConfig.push(v); + } else { + if (v.label === undefined) + v.label = k; + newConfig.push(v); + } + } else { + type = this.stringToFileFormatter(k); + if (type !== null) { + newConfig.push({ + icon: 'fa-solid ' + DEFAULT_ICONS[type], + label: DEFAULT_LABELS[type], + formatter: type + }); + } else { + alert(k + ' is not a supported download file type'); + } + } + } + config = newConfig; + } + + if (Array.isArray(config)) + { + config = config.map(el => { + if (Object.prototype.toString.call(el) === "[object String]") { + let formatter = this.stringToFileFormatter(el); + if (formatter === null) + return null; + return { + icon: 'fa-solid ' + DEFAULT_ICONS[formatter], + label: DEFAULT_LABELS[formatter], + formatter + }; + } + + if (el instanceof Function) + return { + formatter: el + } + + if (typeof el === 'object' && !Array.isArray(el) && el !== null) { + if (el.formatter instanceof Function) + return el; + if (this.validateFileFormatter(el.formatter)) + return el; + } + + return null; + }).filter(el => el !== null); + + if (config.length < 2) + return config; + + if (config.filter(el => el.label || el.icon).length == config.length) + return config; + + alert('Config not valid'); + } + + return []; + } + }, + methods: { + stringToFileFormatter(input) { + let lcInput = input.toLowerCase(); + + if (lcInput == 'jsonlines') + return 'jsonLines'; + + if (['xlsx', 'pdf', 'html', 'json', 'csv'].includes(lcInput)) + return lcInput; + + return null; + }, + validateFileFormatter(input) { + let formatter = this.stringToFileFormatter(input); + if (!formatter) { + alert(input + ' is not a supported file formatter'); + return false; + } + if (formatter == 'xlsx') { + if (!window.XLSX) { + alert('XLSX Library not loaded'); + return false; + } + } + if (formatter == 'pdf') { + if (!window.jspdf) { + alert('jsPDF Library not loaded'); + return false; + } + var doc = new jspdf.jsPDF({}); + if (!doc.autoTable) { + alert('jsPDF-AutoTable Plugin not loaded'); + return false; + } + } + return true; + }, + download(config) { + this.tabulator.download(config.formatter, config.file, config.options) + } + }, + template: ` + + ` +}; + From 429c595e0455baea02e272e0b72f816b708d9178 Mon Sep 17 00:00:00 2001 From: cgfhtw Date: Mon, 22 May 2023 11:59:26 +0200 Subject: [PATCH 07/12] Reload Button --- public/js/components/filter/Filter.js | 54 +++++++++++++++++++-------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/public/js/components/filter/Filter.js b/public/js/components/filter/Filter.js index ae2ab9e7a..7fbeb84bc 100644 --- a/public/js/components/filter/Filter.js +++ b/public/js/components/filter/Filter.js @@ -55,6 +55,7 @@ export const CoreFilterCmpt = { tabulatorOptions: Object, tabulatorEvents: Array, tableOnly: Boolean, + reload: Boolean, download: { type: [Boolean, String, Function, Array, Object], default: false @@ -73,6 +74,7 @@ export const CoreFilterCmpt = { filterFields: null, availableFilters: null, + selectedFilter: null, // FetchCmpt binded properties fetchCmptRefresh: false, @@ -160,6 +162,12 @@ export const CoreFilterCmpt = { } }, methods: { + reloadTable() { + if (this.tableOnly) + this.tabulator.reload(); + else + this.getFilter(); + }, initTabulator() { // Define a default tabulator options in case it was not provided let tabulatorOptions = {...{ @@ -211,8 +219,16 @@ export const CoreFilterCmpt = { * */ getFilter: function() { - // - this.startFetchCmpt(CoreFilterAPIs.getFilter, null, this.render); + if (this.selectedFilter === null) + this.startFetchCmpt(CoreFilterAPIs.getFilter, null, this.render); + else + this.startFetchCmpt( + CoreFilterAPIs.getFilterById, + { + filterId: this.selectedFilter + }, + this.render + ); }, /** * @@ -381,6 +397,7 @@ export const CoreFilterCmpt = { * */ handlerSaveCustomFilter: function(customFilterName) { + this.selectedFilter = null; // this.startFetchCmpt( CoreFilterAPIs.saveCustomFilter, @@ -394,11 +411,14 @@ export const CoreFilterCmpt = { * */ handlerRemoveCustomFilter: function(event) { + filterId = event.currentTarget.getAttribute("href").substring(1); + if (filterId === this.selectedFilter) + this.selectedFilter = null; // this.startFetchCmpt( CoreFilterAPIs.removeCustomFilter, { - filterId: event.currentTarget.getAttribute("href").substring(1) + filterId: filterId }, this.getFilter ); @@ -427,16 +447,11 @@ export const CoreFilterCmpt = { this.switchFilter(filterId); }, switchFilter(filterId) { - // Ajax call - this.startFetchCmpt( - CoreFilterAPIs.getFilterById, - { - filterId - }, - this.render - ); + this.selectedFilter = filterId; + this.getFilter(); }, applyFilterConfig(filterFields) { + this.selectedFilter = null; this.startFetchCmpt( CoreFilterAPIs.applyFilterFields, { @@ -480,11 +495,18 @@ export const CoreFilterCmpt = {
-
- [ {{ filterName }} ] - - - +
+
+ [ {{ filterName }} ] + + + +
+
+ +
Date: Tue, 23 May 2023 14:56:31 +0200 Subject: [PATCH 08/12] Slot for action buttons --- public/js/components/filter/Filter.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/public/js/components/filter/Filter.js b/public/js/components/filter/Filter.js index 7fbeb84bc..cf0fcf5e1 100644 --- a/public/js/components/filter/Filter.js +++ b/public/js/components/filter/Filter.js @@ -83,7 +83,9 @@ export const CoreFilterCmpt = { fetchCmptDataFetched: null, tabulator: null, - tableBuilt: false + tableBuilt: false, + tabulatorHasSelector: false, + selectedData: [] }; }, computed: { @@ -130,6 +132,8 @@ export const CoreFilterCmpt = { { // If the column has to be displayed or not col.visible = selectedFields.indexOf(col.field) >= 0; + if (col.formatter == 'rowSelection') + col.visible = true; if (col.hasOwnProperty('resizable')) col.resizable = col.visible; @@ -182,6 +186,9 @@ export const CoreFilterCmpt = { tabulatorOptions.columns = this.filteredColumns; } + if (tabulatorOptions.columns && tabulatorOptions.columns.filter(el => el.formatter == 'rowSelection').length) + this.tabulatorHasSelector = true; + // Start the tabulator with the build options this.tabulator = new Tabulator( this.$refs.table, @@ -195,6 +202,9 @@ export const CoreFilterCmpt = { this.tabulator.on(evt.event, evt.handler); } this.tabulator.on('tableBuilt', () => this.tableBuilt = true); + this.tabulator.on("rowSelectionChanged", data => { + this.selectedData = data; + }); if (this.tableOnly) { this.tabulator.on('tableBuilt', () => { const cols = this.tabulator.getColumns(); @@ -213,6 +223,7 @@ export const CoreFilterCmpt = { }, _updateTabulator() { this.tabulator.setData(this.filteredData); + this.tabulatorHasSelector = this.filteredColumns.filter(el => el.formatter == 'rowSelection').length; this.tabulator.setColumns(this.filteredColumns); }, /** @@ -502,10 +513,12 @@ export const CoreFilterCmpt = {
-
+
+ Mit {{selectedData.length}} ausgewählten: +
From 94a15093ac3c14788f0764158301a0eaa11e3e1b Mon Sep 17 00:00:00 2001 From: cgfhtw Date: Tue, 23 May 2023 15:26:49 +0200 Subject: [PATCH 09/12] New Button --- public/js/components/filter/Filter.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/public/js/components/filter/Filter.js b/public/js/components/filter/Filter.js index cf0fcf5e1..ed9452925 100644 --- a/public/js/components/filter/Filter.js +++ b/public/js/components/filter/Filter.js @@ -59,7 +59,11 @@ export const CoreFilterCmpt = { download: { type: [Boolean, String, Function, Array, Object], default: false - } + }, + newBtnShow: Boolean, + newBtnClass: [String, Array, Object], + newBtnDisabled: Boolean, + newBtnLabel: String }, data: function() { return { @@ -513,7 +517,11 @@ export const CoreFilterCmpt = {
-
+
+ From be331d6200bbe87d70dc8bcc79b02a3602f3719c Mon Sep 17 00:00:00 2001 From: cgfhtw Date: Wed, 24 May 2023 12:05:36 +0200 Subject: [PATCH 10/12] Styles --- public/js/components/filter/Filter.js | 20 +++++++++++-------- public/js/components/filter/Filter/Columns.js | 18 ++++++++--------- public/js/components/filter/Table/Download.js | 7 ++++--- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/public/js/components/filter/Filter.js b/public/js/components/filter/Filter.js index ed9452925..776405614 100644 --- a/public/js/components/filter/Filter.js +++ b/public/js/components/filter/Filter.js @@ -510,14 +510,8 @@ export const CoreFilterCmpt = {
-
-
- [ {{ filterName }} ] - - - -
-
+
+
+
+ [ {{ filterName }} ] + + + + + + + +
-
-
-
- {{ names[fieldToDisplay] || fieldToDisplay }} -
+
+
+ {{ names[fieldToDisplay] || fieldToDisplay }}
diff --git a/public/js/components/filter/Table/Download.js b/public/js/components/filter/Table/Download.js index 7d4512d55..057fdad5e 100644 --- a/public/js/components/filter/Table/Download.js +++ b/public/js/components/filter/Table/Download.js @@ -42,7 +42,8 @@ export default { config: { type: [Boolean, String, Function, Array, Object], default: false - } + }, + iconClass: [String, Array, Object] }, computed: { currentConfig() { @@ -215,7 +216,7 @@ export default { aria-title="Download" @click.prevent="download(currentConfig[0])" > - +