diff --git a/app/react/kubernetes/ServicesView/ServicesDatatable/ServicesDatatable.tsx b/app/react/kubernetes/ServicesView/ServicesDatatable/ServicesDatatable.tsx
index b11cc10de..050b4469e 100644
--- a/app/react/kubernetes/ServicesView/ServicesDatatable/ServicesDatatable.tsx
+++ b/app/react/kubernetes/ServicesView/ServicesDatatable/ServicesDatatable.tsx
@@ -21,6 +21,7 @@ import { useTableState } from '@@/datatables/useTableState';
import { useMutationDeleteServices, useServices } from '../service';
import { Service } from '../types';
import { DefaultDatatableSettings } from '../../datatables/DefaultDatatableSettings';
+import { isSystemNamespace } from '../../namespaces/utils';
import { columns } from './columns';
import { createStore } from './datatable-store';
@@ -40,7 +41,7 @@ export function ServicesDatatable() {
const filteredServices = servicesQuery.data?.filter(
(service) =>
(isAdmin && tableState.showSystemResources) ||
- !KubernetesNamespaceHelper.isSystemNamespace(service.Namespace)
+ !isSystemNamespace(service.Namespace)
);
return (
diff --git a/app/react/kubernetes/ServicesView/ServicesDatatable/columns/clusterIP.tsx b/app/react/kubernetes/ServicesView/ServicesDatatable/columns/clusterIP.tsx
index 6b84e7d00..452f7293b 100644
--- a/app/react/kubernetes/ServicesView/ServicesDatatable/columns/clusterIP.tsx
+++ b/app/react/kubernetes/ServicesView/ServicesDatatable/columns/clusterIP.tsx
@@ -1,38 +1,41 @@
import { columnHelper } from './helper';
-export const clusterIP = columnHelper.accessor('ClusterIPs', {
- header: 'Cluster IP',
- id: 'clusterIP',
- cell: ({ getValue }) => {
- const clusterIPs = getValue();
+export const clusterIP = columnHelper.accessor(
+ (row) => row.ClusterIPs?.join(','),
+ {
+ header: 'Cluster IP',
+ id: 'clusterIP',
+ cell: ({ row }) => {
+ const clusterIPs = row.original.ClusterIPs;
- if (!clusterIPs?.length) {
- return '-';
- }
- return clusterIPs.map((ip) =>
{ip}
);
- },
- sortingFn: (rowA, rowB) => {
- const a = rowA.original.ClusterIPs;
- const b = rowB.original.ClusterIPs;
-
- const ipA = a?.[0];
- const ipB = b?.[0];
-
- // no ip's at top, followed by 'None', then ordered by ip
- if (!ipA) return 1;
- if (!ipB) return -1;
- if (ipA === ipB) return 0;
- if (ipA === 'None') return 1;
- if (ipB === 'None') return -1;
-
- // natural sort of the ip
- return ipA.localeCompare(
- ipB,
- navigator.languages[0] || navigator.language,
- {
- numeric: true,
- ignorePunctuation: true,
+ if (!clusterIPs?.length) {
+ return '-';
}
- );
- },
-});
+ return clusterIPs.map((ip) => {ip}
);
+ },
+ sortingFn: (rowA, rowB) => {
+ const a = rowA.original.ClusterIPs;
+ const b = rowB.original.ClusterIPs;
+
+ const ipA = a?.[0];
+ const ipB = b?.[0];
+
+ // no ip's at top, followed by 'None', then ordered by ip
+ if (!ipA) return 1;
+ if (!ipB) return -1;
+ if (ipA === ipB) return 0;
+ if (ipA === 'None') return 1;
+ if (ipB === 'None') return -1;
+
+ // natural sort of the ip
+ return ipA.localeCompare(
+ ipB,
+ navigator.languages[0] || navigator.language,
+ {
+ numeric: true,
+ ignorePunctuation: true,
+ }
+ );
+ },
+ }
+);
diff --git a/app/react/kubernetes/ServicesView/ServicesDatatable/columns/created.tsx b/app/react/kubernetes/ServicesView/ServicesDatatable/columns/created.tsx
index c28627c13..d6994a3e7 100644
--- a/app/react/kubernetes/ServicesView/ServicesDatatable/columns/created.tsx
+++ b/app/react/kubernetes/ServicesView/ServicesDatatable/columns/created.tsx
@@ -2,19 +2,22 @@ import { formatDate } from '@/portainer/filters/filters';
import { columnHelper } from './helper';
-export const created = columnHelper.accessor('CreationTimestamp', {
- header: 'Created',
- id: 'created',
- cell: ({ row, getValue }) => {
- const date = formatDate(getValue());
-
- const owner =
- row.original.Labels?.['io.portainer.kubernetes.application.owner'];
-
- if (owner) {
- return `${date} by ${owner}`;
- }
-
- return date;
+export const created = columnHelper.accessor(
+ (row) => {
+ const owner = row.Labels?.['io.portainer.kubernetes.application.owner'];
+ const date = formatDate(row.CreationTimestamp);
+ return owner ? `${date} by ${owner}` : date;
},
-});
+ {
+ header: 'Created',
+ id: 'created',
+ cell: ({ row }) => {
+ const date = formatDate(row.original.CreationTimestamp);
+
+ const owner =
+ row.original.Labels?.['io.portainer.kubernetes.application.owner'];
+
+ return owner ? `${date} by ${owner}` : date;
+ },
+ }
+);
diff --git a/app/react/kubernetes/ServicesView/ServicesDatatable/columns/externalIP.tsx b/app/react/kubernetes/ServicesView/ServicesDatatable/columns/externalIP.tsx
index 84c6e9a93..7e414deb5 100644
--- a/app/react/kubernetes/ServicesView/ServicesDatatable/columns/externalIP.tsx
+++ b/app/react/kubernetes/ServicesView/ServicesDatatable/columns/externalIP.tsx
@@ -8,14 +8,14 @@ import { columnHelper } from './helper';
export const externalIP = columnHelper.accessor(
(row) => {
if (row.Type === 'ExternalName') {
- return row.ExternalName;
+ return row.ExternalName || '';
}
if (row.ExternalIPs?.length) {
- return row.ExternalIPs?.slice(0);
+ return row.ExternalIPs?.join(',') || '';
}
- return row.IngressStatus?.slice(0);
+ return row.IngressStatus?.map((status) => status.IP).join(',') || '';
},
{
header: 'External IP',
diff --git a/app/react/kubernetes/ServicesView/ServicesDatatable/columns/name.tsx b/app/react/kubernetes/ServicesView/ServicesDatatable/columns/name.tsx
index c06c99e6a..1561c7aad 100644
--- a/app/react/kubernetes/ServicesView/ServicesDatatable/columns/name.tsx
+++ b/app/react/kubernetes/ServicesView/ServicesDatatable/columns/name.tsx
@@ -1,37 +1,53 @@
import { Authorized } from '@/react/hooks/useUser';
-import KubernetesNamespaceHelper from '@/kubernetes/helpers/namespaceHelper';
+import { isSystemNamespace } from '@/react/kubernetes/namespaces/utils';
import { columnHelper } from './helper';
-export const name = columnHelper.accessor('Name', {
- header: 'Name',
- id: 'name',
- cell: ({ row, getValue }) => {
- const name = getValue();
- const isSystem = KubernetesNamespaceHelper.isSystemNamespace(
- row.original.Namespace
- );
+export const name = columnHelper.accessor(
+ (row) => {
+ let name = row.Name;
const isExternal =
- !row.original.Labels ||
- !row.original.Labels['io.portainer.kubernetes.application.owner'];
+ !row.Labels || !row.Labels['io.portainer.kubernetes.application.owner'];
+ const isSystem = isSystemNamespace(row.Namespace);
- return (
-
- {name}
+ if (isExternal && !isSystem) {
+ name = `${name} external`;
+ }
- {isSystem && (
-
- system
-
- )}
-
- {isExternal && !isSystem && (
-
- external
-
- )}
-
- );
+ if (isSystem) {
+ name = `${name} system`;
+ }
+ return name;
},
-});
+ {
+ header: 'Name',
+ id: 'Name',
+ cell: ({ row }) => {
+ const name = row.original.Name;
+ const isSystem = isSystemNamespace(row.original.Namespace);
+
+ const isExternal =
+ !row.original.Labels ||
+ !row.original.Labels['io.portainer.kubernetes.application.owner'];
+
+ return (
+
+ {name}
+
+ {isSystem && (
+
+ system
+
+ )}
+
+ {isExternal && !isSystem && (
+
+ external
+
+ )}
+
+ );
+ },
+ }
+);
diff --git a/app/react/kubernetes/ServicesView/ServicesDatatable/columns/ports.tsx b/app/react/kubernetes/ServicesView/ServicesDatatable/columns/ports.tsx
index d36061ff1..92e554460 100644
--- a/app/react/kubernetes/ServicesView/ServicesDatatable/columns/ports.tsx
+++ b/app/react/kubernetes/ServicesView/ServicesDatatable/columns/ports.tsx
@@ -4,7 +4,12 @@ import { columnHelper } from './helper';
export const ports = columnHelper.accessor(
(row) =>
- row.Ports.map((port) => `${port.Port}:${port.NodePort}/${port.Protocol}`),
+ row.Ports.map(
+ (port) =>
+ `${port.Port}${port.NodePort !== 0 ? `:${port.NodePort}` : ''}/${
+ port.Protocol
+ }`
+ ).join(',') || '-',
{
header: () => (
<>
diff --git a/app/react/kubernetes/ServicesView/ServicesDatatable/columns/targetPorts.tsx b/app/react/kubernetes/ServicesView/ServicesDatatable/columns/targetPorts.tsx
index e0d30fa14..292cff805 100644
--- a/app/react/kubernetes/ServicesView/ServicesDatatable/columns/targetPorts.tsx
+++ b/app/react/kubernetes/ServicesView/ServicesDatatable/columns/targetPorts.tsx
@@ -1,13 +1,12 @@
import { columnHelper } from './helper';
export const targetPorts = columnHelper.accessor(
- (row) => row.Ports.map((port) => `${port.TargetPort}`),
+ (row) => row.Ports.map((port) => port.TargetPort).join(','),
{
header: 'Target Ports',
id: 'targetPorts',
- cell: ({ getValue }) => {
- const ports = getValue();
-
+ cell: ({ row }) => {
+ const ports = row.original.Ports.map((port) => port.TargetPort);
if (!ports.length) {
return '-';
}
diff --git a/app/react/kubernetes/ingresses/IngressDatatable/columns/created.tsx b/app/react/kubernetes/ingresses/IngressDatatable/columns/created.tsx
index 144855256..e9d88c4a6 100644
--- a/app/react/kubernetes/ingresses/IngressDatatable/columns/created.tsx
+++ b/app/react/kubernetes/ingresses/IngressDatatable/columns/created.tsx
@@ -2,18 +2,21 @@ import { formatDate } from '@/portainer/filters/filters';
import { columnHelper } from './helper';
-export const created = columnHelper.accessor('CreationDate', {
- header: 'Created',
- cell: ({ row, getValue }) => {
- const date = formatDate(getValue());
- const owner =
- row.original.Labels?.['io.portainer.kubernetes.ingress.owner'];
-
- if (owner) {
- return `${date} by ${owner}`;
- }
-
- return date;
+export const created = columnHelper.accessor(
+ (row) => {
+ const owner = row.Labels?.['io.portainer.kubernetes.ingress.owner'];
+ const date = formatDate(row.CreationDate);
+ return owner ? `${date} by ${owner}` : date;
},
- id: 'created',
-});
+ {
+ header: 'Created',
+ cell: ({ row, getValue }) => {
+ const date = formatDate(getValue());
+ const owner =
+ row.original.Labels?.['io.portainer.kubernetes.ingress.owner'];
+
+ return owner ? `${date} by ${owner}` : date;
+ },
+ id: 'created',
+ }
+);
diff --git a/app/react/kubernetes/ingresses/IngressDatatable/columns/ingressRules.tsx b/app/react/kubernetes/ingresses/IngressDatatable/columns/ingressRules.tsx
index cedcaa338..36a9dedad 100644
--- a/app/react/kubernetes/ingresses/IngressDatatable/columns/ingressRules.tsx
+++ b/app/react/kubernetes/ingresses/IngressDatatable/columns/ingressRules.tsx
@@ -4,18 +4,28 @@ import { AlertTriangle, ArrowRight } from 'lucide-react';
import { Icon } from '@@/Icon';
import { Badge } from '@@/Badge';
-import { Ingress, TLS, Path } from '../../types';
+import { Ingress, TLS } from '../../types';
import { columnHelper } from './helper';
-export const ingressRules = columnHelper.accessor('Paths', {
- header: 'Rules and Paths',
- id: 'ingressRules',
- cell: Cell,
-});
+export const ingressRules = columnHelper.accessor(
+ ({ Paths, TLS }) =>
+ // return an accessor function with all the useful text to search for
+ Paths.map((path) => {
+ const isHttp = isHTTP(TLS || [], path.Host);
+ return `${isHttp ? 'http' : 'https'}://${path.Host}${path.Path}${
+ path.ServiceName
+ }:${path.Port} ${!path.HasService && "Service doesn't exist"}`;
+ }).join(','),
+ {
+ header: 'Rules and Paths',
+ id: 'ingressRules',
+ cell: Cell,
+ }
+);
-function Cell({ row, getValue }: CellContext) {
- const paths = getValue();
+function Cell({ row }: CellContext) {
+ const paths = row.original.Paths;
if (!paths) {
return ;