refactor(kube/registries): migrate access table to react [EE-4706] (#10688)

pull/10840/head
Chaim Lev-Ari 2024-04-08 17:23:12 +03:00 committed by GitHub
parent f584bf3830
commit a00cb951bc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 74 additions and 142 deletions

View File

@ -66,6 +66,7 @@ import { applicationsModule } from './applications';
import { volumesModule } from './volumes';
import { namespacesModule } from './namespaces';
import { clusterManagementModule } from './clusterManagement';
import { registriesModule } from './registries';
export const ngModule = angular
.module('portainer.kubernetes.react.components', [
@ -73,6 +74,7 @@ export const ngModule = angular
volumesModule,
namespacesModule,
clusterManagementModule,
registriesModule,
])
.component(
'ingressClassDatatable',

View File

@ -0,0 +1,11 @@
import angular from 'angular';
import { r2a } from '@/react-tools/react2angular';
import { AccessTable } from '@/react/kubernetes/cluster/RegistryAccessView/AccessTable';
export const registriesModule = angular
.module('portainer.kubernetes.react.components.registries', [])
.component(
'kubeRegistryAccessTable',
r2a(AccessTable, ['dataset', 'onRemove'])
).name;

View File

@ -1,5 +1,4 @@
import KubernetesNamespaceHelper from 'Kubernetes/helpers/namespaceHelper';
import { confirmDeleteAccess } from '@/react/kubernetes/cluster/RegistryAccessView/ConfirmDeleteAccess';
export default class KubernetesRegistryAccessController {
/* @ngInject */
@ -32,11 +31,7 @@ export default class KubernetesRegistryAccessController {
const removeNamespaces = namespaces.map(({ value }) => value);
const nsToUpdate = this.savedResourcePools.map(({ value }) => value).filter((value) => !removeNamespaces.includes(value));
confirmDeleteAccess().then((confirmed) => {
if (confirmed) {
return this.updateNamespaces(nsToUpdate);
}
});
return this.updateNamespaces(nsToUpdate);
}
updateNamespaces(namespaces) {

View File

@ -48,17 +48,5 @@
</rd-widget>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<strings-datatable
title-text="Access"
title-icon="user-x"
table-key="access_registry_resourcepools"
dataset="$ctrl.savedResourcePools"
empty-dataset-message="No namespace has been authorized yet."
on-remove="($ctrl.handleRemove)"
column-header="Namespace"
>
</strings-datatable>
</div>
</div>
<kube-registry-access-table dataset="$ctrl.savedResourcePools" on-remove="($ctrl.handleRemove)"></kube-registry-access-table>

View File

@ -1,20 +0,0 @@
import angular from 'angular';
// import controller from './strings-datatable.controller.js';
export const stringsDatatable = {
templateUrl: './strings-datatable.html',
controller: 'GenericDatatableController',
bindings: {
titleText: '@',
titleIcon: '@',
dataset: '<',
emptyDatasetMessage: '@',
columnHeader: '@',
tableKey: '@',
onRemove: '<',
},
};
angular.module('portainer.app').component('stringsDatatable', stringsDatatable);

View File

@ -1,83 +0,0 @@
<div class="datatable">
<rd-widget>
<div class="toolBar vertical-center relative w-full flex-wrap !gap-x-5 !gap-y-1">
<div class="toolBarTitle vertical-center">
<div class="widget-icon space-right">
<pr-icon icon="$ctrl.titleIcon"></pr-icon>
</div>
{{ $ctrl.titleText }}
</div>
<div class="searchBar vertical-center">
<pr-icon icon="'search'"></pr-icon>
<input
type="text"
class="searchInput"
ng-model="$ctrl.state.textFilter"
ng-change="$ctrl.onTextFilterChange()"
placeholder="Search..."
ng-model-options="{ debounce: 300 }"
/>
</div>
<div class="actionBar">
<button
type="button"
class="btn btn-sm btn-dangerlight vertical-center"
ng-disabled="$ctrl.state.selectedItemCount === 0"
ng-click="$ctrl.onRemove($ctrl.state.selectedItems)"
>
<pr-icon icon="'trash-2'"></pr-icon>Remove
</button>
</div>
</div>
<rd-widget-body classes="no-padding">
<div class="table-responsive">
<table class="table-hover nowrap-cells table">
<thead>
<tr>
<th>
<div class="vertical-center">
<span class="md-checkbox">
<input id="select_all" type="checkbox" ng-model="$ctrl.state.selectAll" ng-change="$ctrl.selectAll()" />
<label for="select_all"></label>
</span>
<table-column-header
col-title="$ctrl.columnHeader"
can-sort="true"
is-sorted="$ctrl.state.orderBy === 'Name'"
is-sorted-desc="$ctrl.state.orderBy === 'Name' && $ctrl.state.reverseOrder"
ng-click="$ctrl.changeOrderBy('Name')"
style="display: inline-block"
></table-column-header>
</div>
</th>
</tr>
</thead>
<tbody>
<tr
dir-paginate="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit)) track by $index"
ng-class="{ active: $ctrl.state.selectedItems.includes(item) }"
>
<td>
<span class="md-checkbox">
<input
id="select_{{ $index }}"
type="checkbox"
ng-checked="$ctrl.state.selectedItems.includes(item)"
ng-disabled="$ctrl.disableRemove(item)"
ng-click="$ctrl.selectItem(item, $event)"
/>
<label for="select_{{ $index }}"></label>
</span>
{{ item.value }}
</td>
</tr>
<tr ng-if="$ctrl.state.filteredDataSet.length === 0">
<td class="text-muted text-center">{{ $ctrl.emptyDatasetMessage }}</td>
</tr>
</tbody>
</table>
</div>
</rd-widget-body>
</rd-widget>
</div>

View File

@ -0,0 +1,58 @@
import { UserX } from 'lucide-react';
import { createColumnHelper } from '@tanstack/react-table';
import { Datatable } from '@@/datatables';
import { createPersistedStore } from '@@/datatables/types';
import { useTableState } from '@@/datatables/useTableState';
import { DeleteButton } from '@@/buttons/DeleteButton';
type Item = { value: string };
const columnHelper = createColumnHelper<Item>();
const columns = [
columnHelper.accessor('value', {
header: 'Namespace',
}),
];
const tableKey = 'kube-access-table';
const store = createPersistedStore(tableKey);
export function AccessTable({
dataset,
onRemove,
}: {
dataset: Array<Item>;
onRemove: (selectedItems: Array<Item>) => void;
}) {
const tableState = useTableState(store, tableKey);
return (
<Datatable
title="Access"
titleIcon={UserX}
dataset={dataset}
columns={columns}
emptyContentLabel="No namespace has been authorized yet."
settingsManager={tableState}
renderTableActions={(selectedItems) => (
<DeleteButton
disabled={selectedItems.length === 0}
confirmMessage={
<>
<p>
This registry might be used by one or more applications inside
this environment. Removing the registry access could lead to a
service interruption for these applications.
</p>
<p>Are you sure you wish to continue?</p>
</>
}
onConfirmed={() => onRemove(selectedItems)}
/>
)}
/>
);
}

View File

@ -1,19 +0,0 @@
import { confirmDestructive } from '@@/modals/confirm';
import { buildConfirmButton } from '@@/modals/utils';
export function confirmDeleteAccess() {
return confirmDestructive({
title: 'Are you sure?',
message: (
<>
<p>
This registry might be used by one or more applications inside this
environment. Removing the registry access could lead to a service
interruption for these applications.
</p>
<p>Are you sure you wish to continue?</p>
</>
),
confirmButton: buildConfirmButton('Remove', 'danger'),
});
}