diff --git a/app/kubernetes/components/datatables/resource-pool-applications-datatable/resourcePoolApplicationsDatatable.html b/app/kubernetes/components/datatables/resource-pool-applications-datatable/resourcePoolApplicationsDatatable.html
deleted file mode 100644
index babdb3e46..000000000
--- a/app/kubernetes/components/datatables/resource-pool-applications-datatable/resourcePoolApplicationsDatatable.html
+++ /dev/null
@@ -1,153 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- |
-
-
- |
-
-
- |
-
-
- |
-
-
- |
-
-
-
-
-
- {{ item.Name }}
- external
- |
- {{ item.StackName || '-' }} |
- {{ item.Image | truncate: 64 }} + {{ item.Containers.length - 1 }} |
- {{ item.CPU | kubernetesApplicationCPUValue }} |
- {{ item.Memory | humansize }} |
-
-
- Loading... |
-
-
- No application available. |
-
-
-
-
-
-
-
-
diff --git a/app/kubernetes/components/datatables/resource-pool-applications-datatable/resourcePoolApplicationsDatatable.js b/app/kubernetes/components/datatables/resource-pool-applications-datatable/resourcePoolApplicationsDatatable.js
deleted file mode 100644
index 02dba5e79..000000000
--- a/app/kubernetes/components/datatables/resource-pool-applications-datatable/resourcePoolApplicationsDatatable.js
+++ /dev/null
@@ -1,13 +0,0 @@
-angular.module('portainer.kubernetes').component('kubernetesResourcePoolApplicationsDatatable', {
- templateUrl: './resourcePoolApplicationsDatatable.html',
- controller: 'KubernetesResourcePoolApplicationsDatatableController',
- bindings: {
- titleText: '@',
- titleIcon: '@',
- dataset: '<',
- tableKey: '@',
- orderBy: '@',
- reverseOrder: '<',
- refreshCallback: '<',
- },
-});
diff --git a/app/kubernetes/components/datatables/resource-pool-applications-datatable/resourcePoolApplicationsDatatableController.js b/app/kubernetes/components/datatables/resource-pool-applications-datatable/resourcePoolApplicationsDatatableController.js
deleted file mode 100644
index e97cf734d..000000000
--- a/app/kubernetes/components/datatables/resource-pool-applications-datatable/resourcePoolApplicationsDatatableController.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import KubernetesApplicationHelper from 'Kubernetes/helpers/application';
-
-angular.module('portainer.docker').controller('KubernetesResourcePoolApplicationsDatatableController', [
- '$scope',
- '$controller',
- 'DatatableService',
- function ($scope, $controller, DatatableService) {
- angular.extend(this, $controller('GenericDatatableController', { $scope: $scope }));
-
- this.isExternalApplication = function (item) {
- return KubernetesApplicationHelper.isExternalApplication(item);
- };
-
- this.$onInit = function () {
- 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();
- };
- },
-]);
diff --git a/app/kubernetes/filters/applicationFilters.js b/app/kubernetes/filters/applicationFilters.js
index 4b1c97649..c6c354394 100644
--- a/app/kubernetes/filters/applicationFilters.js
+++ b/app/kubernetes/filters/applicationFilters.js
@@ -1,13 +1,11 @@
-import _ from 'lodash-es';
+import { cpuHumanValue } from '@/react/kubernetes/applications/utils/cpuHumanValue';
import { nodeAffinityValues } from './application';
angular
.module('portainer.kubernetes')
.filter('kubernetesApplicationCPUValue', function () {
'use strict';
- return function (value) {
- return _.round(value, 2);
- };
+ return cpuHumanValue;
})
.filter('kubernetesApplicationDataAccessPolicyIcon', function () {
'use strict';
diff --git a/app/kubernetes/react/components/namespaces.ts b/app/kubernetes/react/components/namespaces.ts
index 0f42c5164..3a3c445c1 100644
--- a/app/kubernetes/react/components/namespaces.ts
+++ b/app/kubernetes/react/components/namespaces.ts
@@ -3,11 +3,11 @@ import angular from 'angular';
import { r2a } from '@/react-tools/react2angular';
import { withUIRouter } from '@/react-tools/withUIRouter';
import { NamespacesDatatable } from '@/react/kubernetes/namespaces/ListView/NamespacesDatatable';
+import { NamespaceAppsDatatable } from '@/react/kubernetes/namespaces/ItemView/NamespaceAppsDatatable';
import { withCurrentUser } from '@/react-tools/withCurrentUser';
export const namespacesModule = angular
.module('portainer.kubernetes.react.components.namespaces', [])
-
.component(
'kubernetesNamespacesDatatable',
r2a(withUIRouter(withCurrentUser(NamespacesDatatable)), [
@@ -15,4 +15,12 @@ export const namespacesModule = angular
'onRemove',
'onRefresh',
])
+ )
+ .component(
+ 'kubernetesNamespaceApplicationsDatatable',
+ r2a(withUIRouter(withCurrentUser(NamespaceAppsDatatable)), [
+ 'dataset',
+ 'isLoading',
+ 'onRefresh',
+ ])
).name;
diff --git a/app/kubernetes/views/resource-pools/edit/resourcePool.html b/app/kubernetes/views/resource-pools/edit/resourcePool.html
index eb77d2ffb..e531ecacc 100644
--- a/app/kubernetes/views/resource-pools/edit/resourcePool.html
+++ b/app/kubernetes/views/resource-pools/edit/resourcePool.html
@@ -309,18 +309,8 @@
-
diff --git a/app/react/kubernetes/applications/utils/cpuHumanValue.ts b/app/react/kubernetes/applications/utils/cpuHumanValue.ts
new file mode 100644
index 000000000..d5d611ef1
--- /dev/null
+++ b/app/react/kubernetes/applications/utils/cpuHumanValue.ts
@@ -0,0 +1,5 @@
+import _ from 'lodash';
+
+export function cpuHumanValue(value: number) {
+ return _.round(value, 2);
+}
diff --git a/app/react/kubernetes/namespaces/ItemView/.keep b/app/react/kubernetes/namespaces/ItemView/.keep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/app/react/kubernetes/namespaces/ItemView/NamespaceAppsDatatable.tsx b/app/react/kubernetes/namespaces/ItemView/NamespaceAppsDatatable.tsx
new file mode 100644
index 000000000..dd7f2b572
--- /dev/null
+++ b/app/react/kubernetes/namespaces/ItemView/NamespaceAppsDatatable.tsx
@@ -0,0 +1,55 @@
+import { Code } from 'lucide-react';
+
+import { Datatable, TableSettingsMenu } from '@@/datatables';
+import { useRepeater } from '@@/datatables/useRepeater';
+import { TableSettingsMenuAutoRefresh } from '@@/datatables/TableSettingsMenuAutoRefresh';
+import { useTableStateWithStorage } from '@@/datatables/useTableState';
+import {
+ BasicTableSettings,
+ refreshableSettings,
+ RefreshableTableSettings,
+} from '@@/datatables/types';
+
+import { NamespaceApp } from './types';
+import { columns } from './columns';
+
+interface TableSettings extends BasicTableSettings, RefreshableTableSettings {}
+
+export function NamespaceAppsDatatable({
+ dataset,
+ onRefresh,
+ isLoading,
+}: {
+ dataset: Array;
+ onRefresh: () => void;
+ isLoading: boolean;
+}) {
+ const tableState = useTableStateWithStorage(
+ 'kube-namespace-apps',
+ 'Name',
+ (set) => ({
+ ...refreshableSettings(set),
+ })
+ );
+ useRepeater(tableState.autoRefreshRate, onRefresh);
+
+ return (
+ (
+
+
+
+ )}
+ />
+ );
+}
diff --git a/app/react/kubernetes/namespaces/ItemView/columns.tsx b/app/react/kubernetes/namespaces/ItemView/columns.tsx
new file mode 100644
index 000000000..cc61d3152
--- /dev/null
+++ b/app/react/kubernetes/namespaces/ItemView/columns.tsx
@@ -0,0 +1,55 @@
+import { createColumnHelper } from '@tanstack/react-table';
+
+import { humanize, truncate } from '@/portainer/filters/filters';
+
+import { Link } from '@@/Link';
+import { ExternalBadge } from '@@/Badge/ExternalBadge';
+
+import { isExternalApplication } from '../../applications/utils';
+import { cpuHumanValue } from '../../applications/utils/cpuHumanValue';
+
+import { NamespaceApp } from './types';
+
+const columnHelper = createColumnHelper();
+
+export const columns = [
+ columnHelper.accessor('Name', {
+ header: 'Name',
+ cell: ({ row: { original: item } }) => (
+ <>
+
+ {item.Name}
+
+ {isExternalApplication({ metadata: item.Metadata }) && (
+
+
+
+ )}
+ >
+ ),
+ }),
+ columnHelper.accessor('StackName', {
+ header: 'Stack',
+ cell: ({ getValue }) => getValue() || '-',
+ }),
+ columnHelper.accessor('Image', {
+ header: 'Image',
+ cell: ({ row: { original: item } }) => (
+ <>
+ {truncate(item.Image, 64)}
+ {item.Containers?.length > 1 && <>+ {item.Containers.length - 1}>}
+ >
+ ),
+ }),
+ columnHelper.accessor('CPU', {
+ header: 'CPU',
+ cell: ({ getValue }) => cpuHumanValue(getValue()),
+ }),
+ columnHelper.accessor('Memory', {
+ header: 'Memory',
+ cell: ({ getValue }) => humanize(getValue()),
+ }),
+];
diff --git a/app/react/kubernetes/namespaces/ItemView/types.ts b/app/react/kubernetes/namespaces/ItemView/types.ts
new file mode 100644
index 000000000..02cd68470
--- /dev/null
+++ b/app/react/kubernetes/namespaces/ItemView/types.ts
@@ -0,0 +1,6 @@
+import { KubernetesApplication } from '@/kubernetes/models/application/models';
+
+export interface NamespaceApp extends KubernetesApplication {
+ CPU: number;
+ Memory: number;
+}