From 5f89d70fd81e1f59e8430d6d50fde2d4a9483d21 Mon Sep 17 00:00:00 2001 From: Chaim Lev-Ari Date: Sun, 21 Apr 2024 04:47:09 +0300 Subject: [PATCH] refactor(datatables): remove angular table utilities [EE-4700] (#11634) --- app/portainer/__module.js | 1 - ...datatable-columns-visibility.controller.js | 7 - .../datatable-columns-visibility.html | 19 -- .../datatable-columns-visibility/index.js | 12 - .../filter/datatable-filter.controller.js | 19 -- .../datatables/filter/datatable-filter.html | 30 --- .../components/datatables/filter/index.js | 13 - .../datatables/genericDatatableController.js | 232 ------------------ app/portainer/components/datatables/index.js | 12 - .../components/datatables/pagination/index.js | 9 - .../datatables/pagination/pagination.html | 15 -- .../titlebar/datatable-titlebar.html | 7 - .../components/datatables/titlebar/index.js | 8 - app/portainer/services/datatableService.js | 88 ------- app/react/components/datatables/Datatable.tsx | 2 + .../components/datatables/datatable.css | 21 +- 16 files changed, 11 insertions(+), 484 deletions(-) delete mode 100644 app/portainer/components/datatables/datatable-columns-visibility/datatable-columns-visibility.controller.js delete mode 100644 app/portainer/components/datatables/datatable-columns-visibility/datatable-columns-visibility.html delete mode 100644 app/portainer/components/datatables/datatable-columns-visibility/index.js delete mode 100644 app/portainer/components/datatables/filter/datatable-filter.controller.js delete mode 100644 app/portainer/components/datatables/filter/datatable-filter.html delete mode 100644 app/portainer/components/datatables/filter/index.js delete mode 100644 app/portainer/components/datatables/genericDatatableController.js delete mode 100644 app/portainer/components/datatables/index.js delete mode 100644 app/portainer/components/datatables/pagination/index.js delete mode 100644 app/portainer/components/datatables/pagination/pagination.html delete mode 100644 app/portainer/components/datatables/titlebar/datatable-titlebar.html delete mode 100644 app/portainer/components/datatables/titlebar/index.js delete mode 100644 app/portainer/services/datatableService.js rename app/{portainer => react}/components/datatables/datatable.css (96%) diff --git a/app/portainer/__module.js b/app/portainer/__module.js index 90abd8f90..da42183eb 100644 --- a/app/portainer/__module.js +++ b/app/portainer/__module.js @@ -24,7 +24,6 @@ angular settingsModule, featureFlagModule, userActivityModule, - 'portainer.shared.datatable', servicesModule, reactModule, sidebarModule, diff --git a/app/portainer/components/datatables/datatable-columns-visibility/datatable-columns-visibility.controller.js b/app/portainer/components/datatables/datatable-columns-visibility/datatable-columns-visibility.controller.js deleted file mode 100644 index d4597e769..000000000 --- a/app/portainer/components/datatables/datatable-columns-visibility/datatable-columns-visibility.controller.js +++ /dev/null @@ -1,7 +0,0 @@ -export default class DatatableColumnsVisibilityController { - constructor() { - this.state = { - isOpen: false, - }; - } -} diff --git a/app/portainer/components/datatables/datatable-columns-visibility/datatable-columns-visibility.html b/app/portainer/components/datatables/datatable-columns-visibility/datatable-columns-visibility.html deleted file mode 100644 index 20a4160fc..000000000 --- a/app/portainer/components/datatables/datatable-columns-visibility/datatable-columns-visibility.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - diff --git a/app/portainer/components/datatables/datatable-columns-visibility/index.js b/app/portainer/components/datatables/datatable-columns-visibility/index.js deleted file mode 100644 index 22b9c4463..000000000 --- a/app/portainer/components/datatables/datatable-columns-visibility/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import angular from 'angular'; - -import controller from './datatable-columns-visibility.controller'; - -angular.module('portainer.app').component('datatableColumnsVisibility', { - templateUrl: './datatable-columns-visibility.html', - controller, - bindings: { - columns: '<', - onChange: '<', - }, -}); diff --git a/app/portainer/components/datatables/filter/datatable-filter.controller.js b/app/portainer/components/datatables/filter/datatable-filter.controller.js deleted file mode 100644 index 32c6de64d..000000000 --- a/app/portainer/components/datatables/filter/datatable-filter.controller.js +++ /dev/null @@ -1,19 +0,0 @@ -export default class DatatableFilterController { - isEnabled() { - return 0 < this.state.length && this.state.length < this.labels.length; - } - - onChangeItem(filterValue) { - if (this.isChecked(filterValue)) { - return this.onChange( - this.filterKey, - this.state.filter((v) => v !== filterValue) - ); - } - return this.onChange(this.filterKey, [...this.state, filterValue]); - } - - isChecked(filterValue) { - return this.state.includes(filterValue); - } -} diff --git a/app/portainer/components/datatables/filter/datatable-filter.html b/app/portainer/components/datatables/filter/datatable-filter.html deleted file mode 100644 index bef51f25c..000000000 --- a/app/portainer/components/datatables/filter/datatable-filter.html +++ /dev/null @@ -1,30 +0,0 @@ -
- -
- - Filter - - - -
- -
diff --git a/app/portainer/components/datatables/filter/index.js b/app/portainer/components/datatables/filter/index.js deleted file mode 100644 index 87ea3f18a..000000000 --- a/app/portainer/components/datatables/filter/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import controller from './datatable-filter.controller'; - -export const datatableFilter = { - bindings: { - labels: '<', // [{label, value}] - state: '<', // [filterValue] - filterKey: '@', - onChange: '<', - }, - controller, - templateUrl: './datatable-filter.html', - transclude: true, -}; diff --git a/app/portainer/components/datatables/genericDatatableController.js b/app/portainer/components/datatables/genericDatatableController.js deleted file mode 100644 index fd6f6c5b6..000000000 --- a/app/portainer/components/datatables/genericDatatableController.js +++ /dev/null @@ -1,232 +0,0 @@ -import _ from 'lodash-es'; -import './datatable.css'; -import { ResourceControlOwnership as RCO } from '@/react/portainer/access-control/types'; -import { isBE } from '@/react/portainer/feature-flags/feature-flags.service'; - -function isBetween(value, a, b) { - return (value >= a && value <= b) || (value >= b && value <= a); -} - -// TODO: review - refactor to use a class that can be extended -angular.module('portainer.app').controller('GenericDatatableController', [ - '$interval', - 'PaginationService', - 'DatatableService', - 'PAGINATION_MAX_ITEMS', - function ($interval, PaginationService, DatatableService, PAGINATION_MAX_ITEMS) { - this.RCO = RCO; - this.isBE = isBE; - - this.state = { - selectAll: false, - orderBy: this.orderBy, - paginatedItemLimit: PAGINATION_MAX_ITEMS, - displayTextFilter: false, - get selectedItemCount() { - return this.selectedItems.length || 0; - }, - selectedItems: [], - }; - - this.settings = { - open: false, - repeater: { - autoRefresh: false, - refreshRate: '30', - }, - }; - - this.resetSelectionState = function () { - this.state.selectAll = false; - this.state.selectedItems = []; - _.map(this.state.filteredDataSet, (item) => (item.Checked = false)); - }; - - this.onTextFilterChangeGeneric = onTextFilterChangeGeneric; - - this.onTextFilterChange = function onTextFilterChange() { - return this.onTextFilterChangeGeneric(); - }; - - function onTextFilterChangeGeneric() { - DatatableService.setDataTableTextFilters(this.tableKey, this.state.textFilter); - } - - this.changeOrderBy = function changeOrderBy(orderField) { - this.state.reverseOrder = this.state.orderBy === orderField ? !this.state.reverseOrder : false; - this.state.orderBy = orderField; - DatatableService.setDataTableOrder(this.tableKey, orderField, this.state.reverseOrder); - }; - - this.selectItem = function (item, event) { - // Handle range select using shift - if (event && event.originalEvent.shiftKey && this.state.firstClickedItem) { - const firstItemIndex = this.state.filteredDataSet.indexOf(this.state.firstClickedItem); - const lastItemIndex = this.state.filteredDataSet.indexOf(item); - const itemsInRange = _.filter(this.state.filteredDataSet, (item, index) => { - return isBetween(index, firstItemIndex, lastItemIndex); - }); - const value = this.state.firstClickedItem.Checked; - - _.forEach(itemsInRange, (i) => { - if (!this.allowSelection(i)) { - return; - } - i.Checked = value; - }); - this.state.firstClickedItem = item; - } else if (event) { - item.Checked = !item.Checked; - this.state.firstClickedItem = item; - } - this.state.selectedItems = this.uniq().filter((i) => i.Checked); - if (event && this.state.selectAll && this.state.selectedItems.length !== this.state.filteredDataSet.length) { - this.state.selectAll = false; - } - this.onSelectionChanged(); - }; - - this.selectAll = function () { - this.state.firstClickedItem = null; - for (var i = 0; i < this.state.filteredDataSet.length; i++) { - var item = this.state.filteredDataSet[i]; - if (this.allowSelection(item) && item.Checked !== this.state.selectAll) { - item.Checked = this.state.selectAll; - this.selectItem(item); - } - } - this.onSelectionChanged(); - }; - - /** - * Override this method to change the uniqness filter when selecting items - */ - this.uniq = function () { - return _.uniq(_.concat(this.state.filteredDataSet, this.state.selectedItems)); - }; - - /** - * Override this method to allow/deny selection - */ - this.allowSelection = function (/*item*/) { - return true; - }; - - /** - * Override this method to prepare data table - */ - this.prepareTableFromDataset = function () { - return; - }; - - /** - * Override this method to execute code after selection changed on datatable - */ - this.onSelectionChanged = function () { - return; - }; - - this.changePaginationLimit = function () { - PaginationService.setPaginationLimit(this.tableKey, this.state.paginatedItemLimit); - }; - - this.setDefaults = function () { - this.showTextFilter = this.showTextFilter ? this.showTextFilter : false; - this.state.reverseOrder = this.reverseOrder ? this.reverseOrder : false; - this.state.paginatedItemLimit = PaginationService.getPaginationLimit(this.tableKey); - }; - - /** - * Duplicate this function when extending GenericDatatableController - * Extending-controller's bindings are not accessible there - * For more details see the following comments - * https://github.com/portainer/portainer/pull/2877#issuecomment-503333425 - * https://github.com/portainer/portainer/pull/2877#issuecomment-503537249 - */ - this.$onInit = function $onInit() { - this.$onInitGeneric(); - }; - - this.$onInitGeneric = function $onInitGeneric() { - this.setDefaults(); - this.prepareTableFromDataset(); - - this.state.orderBy = this.orderBy; - var storedOrder = DatatableService.getDataTableOrder(this.tableKey); - if (storedOrder !== null) { - this.state.reverseOrder = storedOrder.reverse; - this.state.orderBy = storedOrder.orderBy; - } - - var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); - if (textFilter !== null) { - this.state.textFilter = textFilter; - this.onTextFilterChange(); - } - - var storedFilters = DatatableService.getDataTableFilters(this.tableKey); - if (storedFilters !== null) { - this.filters = storedFilters; - } - if (this.filters && this.filters.state) { - this.filters.state.open = false; - } - - var storedSettings = DatatableService.getDataTableSettings(this.tableKey); - if (storedSettings !== null) { - this.settings = storedSettings; - this.settings.open = false; - } - this.onSettingsRepeaterChange(); - - var storedColumnVisibility = DatatableService.getColumnVisibilitySettings(this.tableKey); - if (storedColumnVisibility !== null) { - this.columnVisibility = storedColumnVisibility; - } - }; - - /** - * REPEATER SECTION - */ - this.repeater = undefined; - - this.$onDestroy = function () { - this.stopRepeater(); - }; - - this.stopRepeater = function () { - if (angular.isDefined(this.repeater)) { - $interval.cancel(this.repeater); - this.repeater = undefined; - } - }; - - this.startRepeater = function () { - this.repeater = $interval(async () => { - await this.refreshCallback(); - this.onDataRefresh(); - }, this.settings.repeater.refreshRate * 1000); - }; - - this.onSettingsRepeaterChange = function () { - this.stopRepeater(); - if (angular.isDefined(this.refreshCallback) && this.settings.repeater.autoRefresh) { - this.startRepeater(); - $('#refreshRateChange').show(); - $('#refreshRateChange').fadeOut(1500); - } - DatatableService.setDataTableSettings(this.tableKey, this.settings); - }; - - /** - * Override this method to execute code after calling the refresh callback - */ - this.onDataRefresh = function () { - return; - }; - - /** - * !REPEATER SECTION - */ - }, -]); diff --git a/app/portainer/components/datatables/index.js b/app/portainer/components/datatables/index.js deleted file mode 100644 index c9b3c292e..000000000 --- a/app/portainer/components/datatables/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import angular from 'angular'; -import 'angular-utils-pagination'; - -import { datatableTitlebar } from './titlebar'; -import { datatablePagination } from './pagination'; -import { datatableFilter } from './filter'; - -export default angular - .module('portainer.shared.datatable', ['angularUtils.directives.dirPagination']) - .component('datatableTitlebar', datatableTitlebar) - .component('datatablePagination', datatablePagination) - .component('datatableFilter', datatableFilter).name; diff --git a/app/portainer/components/datatables/pagination/index.js b/app/portainer/components/datatables/pagination/index.js deleted file mode 100644 index 2f299755f..000000000 --- a/app/portainer/components/datatables/pagination/index.js +++ /dev/null @@ -1,9 +0,0 @@ -export const datatablePagination = { - bindings: { - onChangeLimit: '<', - limit: '<', - enableNoLimit: '<', - onChangePage: '<', - }, - templateUrl: './pagination.html', -}; diff --git a/app/portainer/components/datatables/pagination/pagination.html b/app/portainer/components/datatables/pagination/pagination.html deleted file mode 100644 index 94b46b4e2..000000000 --- a/app/portainer/components/datatables/pagination/pagination.html +++ /dev/null @@ -1,15 +0,0 @@ -
-
- - Items per page - - - -
-
diff --git a/app/portainer/components/datatables/titlebar/datatable-titlebar.html b/app/portainer/components/datatables/titlebar/datatable-titlebar.html deleted file mode 100644 index d31d8a9e6..000000000 --- a/app/portainer/components/datatables/titlebar/datatable-titlebar.html +++ /dev/null @@ -1,7 +0,0 @@ -
-
- - {{ $ctrl.title }} - -
-
diff --git a/app/portainer/components/datatables/titlebar/index.js b/app/portainer/components/datatables/titlebar/index.js deleted file mode 100644 index 43dd588f7..000000000 --- a/app/portainer/components/datatables/titlebar/index.js +++ /dev/null @@ -1,8 +0,0 @@ -export const datatableTitlebar = { - bindings: { - icon: '@', - title: '@', - feature: '@', - }, - templateUrl: './datatable-titlebar.html', -}; diff --git a/app/portainer/services/datatableService.js b/app/portainer/services/datatableService.js deleted file mode 100644 index 6692fb59a..000000000 --- a/app/portainer/services/datatableService.js +++ /dev/null @@ -1,88 +0,0 @@ -import angular from 'angular'; - -import * as sessionStorage from './session-storage'; - -angular.module('portainer.app').factory('DatatableService', DatatableServiceFactory); - -const DATATABLE_PREFIX = 'datatable_'; -const TEXT_FILTER_KEY_PREFIX = `${DATATABLE_PREFIX}text_filter_`; - -/* @ngInject */ -function DatatableServiceFactory(LocalStorage) { - return { - setDataTableSettings, - getDataTableSettings, - setDataTableTextFilters, - getDataTableTextFilters, - setDataTableFilters, - getDataTableFilters, - getDataTableOrder, - setDataTableOrder, - setDataTableExpandedItems, - setColumnVisibilitySettings, - getDataTableExpandedItems, - setDataTableSelectedItems, - getDataTableSelectedItems, - getColumnVisibilitySettings, - }; - - function setDataTableSettings(key, settings) { - LocalStorage.storeDataTableSettings(key, settings); - } - - function getDataTableSettings(key) { - return LocalStorage.getDataTableSettings(key); - } - - function setDataTableTextFilters(key, filters) { - sessionStorage.save(TEXT_FILTER_KEY_PREFIX + key, filters); - } - - function getDataTableTextFilters(key) { - return sessionStorage.get(TEXT_FILTER_KEY_PREFIX + key); - } - - function setDataTableFilters(key, filters) { - LocalStorage.storeDataTableFilters(key, filters); - } - - function getDataTableFilters(key) { - return LocalStorage.getDataTableFilters(key); - } - - function getDataTableOrder(key) { - return LocalStorage.getDataTableOrder(key); - } - - function setDataTableOrder(key, orderBy, reverse) { - var filter = { - orderBy: orderBy, - reverse: reverse, - }; - LocalStorage.storeDataTableOrder(key, filter); - } - - function setDataTableExpandedItems(key, expandedItems) { - LocalStorage.storeDataTableExpandedItems(key, expandedItems); - } - - function setColumnVisibilitySettings(key, columnVisibility) { - LocalStorage.storeColumnVisibilitySettings(key, columnVisibility); - } - - function getDataTableExpandedItems(key) { - return LocalStorage.getDataTableExpandedItems(key); - } - - function setDataTableSelectedItems(key, selectedItems) { - LocalStorage.storeDataTableSelectedItems(key, selectedItems); - } - - function getDataTableSelectedItems(key) { - return LocalStorage.getDataTableSelectedItems(key); - } - - function getColumnVisibilitySettings(key) { - return LocalStorage.getColumnVisibilitySettings(key); - } -} diff --git a/app/react/components/datatables/Datatable.tsx b/app/react/components/datatables/Datatable.tsx index e572b8892..8fb79f1d1 100644 --- a/app/react/components/datatables/Datatable.tsx +++ b/app/react/components/datatables/Datatable.tsx @@ -1,3 +1,5 @@ +import './datatable.css'; + import { Table as TableInstance, TableState, diff --git a/app/portainer/components/datatables/datatable.css b/app/react/components/datatables/datatable.css similarity index 96% rename from app/portainer/components/datatables/datatable.css rename to app/react/components/datatables/datatable.css index 84ca06d88..5d4fb8452 100644 --- a/app/portainer/components/datatables/datatable.css +++ b/app/react/components/datatables/datatable.css @@ -49,7 +49,7 @@ display: inline-flex; } -.datatable .searchBar { +.searchBar { border: 1px solid var(--border-searchbar); background: var(--bg-searchbar); border-radius: 5px; @@ -57,15 +57,10 @@ font-size: 14px; } -.datatable .searchInput { - background: none; - border: none; - width: 90%; -} - .toolBar .searchBar { margin-right: 10px; display: inline-flex; + min-height: 30px; flex-basis: 7rem; flex-grow: 1; flex-shrink: 1; @@ -74,18 +69,20 @@ max-width: 14rem; } -.datatable .searchBar input[type='text'] { - border: 0px !important; +.searchBar .searchInput { + background: none; + border: none; + width: 90%; } -.datatable .searchIcon { +.searchBar .searchIcon { @apply text-gray-7; @apply th-dark:text-gray-warm-5; margin-right: 5px; } -.datatable .searchInput:active, -.datatable .searchInput:focus { +.searchBar .searchInput:active, +.searchBar .searchInput:focus { outline: none; }