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 @@
-
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 @@
-
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 @@
-
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;
}