mirror of https://github.com/portainer/portainer
fix(kube-tables): update table accessor fns [EE-5464] (#8920)
* fix(services): update accessor fns [EE-5464] * small fixes --------- Co-authored-by: testa113 <testa113>pull/8720/head
parent
22f4c5d650
commit
42fce1ec57
|
@ -21,6 +21,7 @@ import { useTableState } from '@@/datatables/useTableState';
|
||||||
import { useMutationDeleteServices, useServices } from '../service';
|
import { useMutationDeleteServices, useServices } from '../service';
|
||||||
import { Service } from '../types';
|
import { Service } from '../types';
|
||||||
import { DefaultDatatableSettings } from '../../datatables/DefaultDatatableSettings';
|
import { DefaultDatatableSettings } from '../../datatables/DefaultDatatableSettings';
|
||||||
|
import { isSystemNamespace } from '../../namespaces/utils';
|
||||||
|
|
||||||
import { columns } from './columns';
|
import { columns } from './columns';
|
||||||
import { createStore } from './datatable-store';
|
import { createStore } from './datatable-store';
|
||||||
|
@ -40,7 +41,7 @@ export function ServicesDatatable() {
|
||||||
const filteredServices = servicesQuery.data?.filter(
|
const filteredServices = servicesQuery.data?.filter(
|
||||||
(service) =>
|
(service) =>
|
||||||
(isAdmin && tableState.showSystemResources) ||
|
(isAdmin && tableState.showSystemResources) ||
|
||||||
!KubernetesNamespaceHelper.isSystemNamespace(service.Namespace)
|
!isSystemNamespace(service.Namespace)
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,38 +1,41 @@
|
||||||
import { columnHelper } from './helper';
|
import { columnHelper } from './helper';
|
||||||
|
|
||||||
export const clusterIP = columnHelper.accessor('ClusterIPs', {
|
export const clusterIP = columnHelper.accessor(
|
||||||
header: 'Cluster IP',
|
(row) => row.ClusterIPs?.join(','),
|
||||||
id: 'clusterIP',
|
{
|
||||||
cell: ({ getValue }) => {
|
header: 'Cluster IP',
|
||||||
const clusterIPs = getValue();
|
id: 'clusterIP',
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const clusterIPs = row.original.ClusterIPs;
|
||||||
|
|
||||||
if (!clusterIPs?.length) {
|
if (!clusterIPs?.length) {
|
||||||
return '-';
|
return '-';
|
||||||
}
|
|
||||||
return clusterIPs.map((ip) => <div key={ip}>{ip}</div>);
|
|
||||||
},
|
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
);
|
return clusterIPs.map((ip) => <div key={ip}>{ip}</div>);
|
||||||
},
|
},
|
||||||
});
|
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,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -2,19 +2,22 @@ import { formatDate } from '@/portainer/filters/filters';
|
||||||
|
|
||||||
import { columnHelper } from './helper';
|
import { columnHelper } from './helper';
|
||||||
|
|
||||||
export const created = columnHelper.accessor('CreationTimestamp', {
|
export const created = columnHelper.accessor(
|
||||||
header: 'Created',
|
(row) => {
|
||||||
id: 'created',
|
const owner = row.Labels?.['io.portainer.kubernetes.application.owner'];
|
||||||
cell: ({ row, getValue }) => {
|
const date = formatDate(row.CreationTimestamp);
|
||||||
const date = formatDate(getValue());
|
return owner ? `${date} by ${owner}` : date;
|
||||||
|
|
||||||
const owner =
|
|
||||||
row.original.Labels?.['io.portainer.kubernetes.application.owner'];
|
|
||||||
|
|
||||||
if (owner) {
|
|
||||||
return `${date} by ${owner}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 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;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -8,14 +8,14 @@ import { columnHelper } from './helper';
|
||||||
export const externalIP = columnHelper.accessor(
|
export const externalIP = columnHelper.accessor(
|
||||||
(row) => {
|
(row) => {
|
||||||
if (row.Type === 'ExternalName') {
|
if (row.Type === 'ExternalName') {
|
||||||
return row.ExternalName;
|
return row.ExternalName || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row.ExternalIPs?.length) {
|
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',
|
header: 'External IP',
|
||||||
|
|
|
@ -1,37 +1,53 @@
|
||||||
import { Authorized } from '@/react/hooks/useUser';
|
import { Authorized } from '@/react/hooks/useUser';
|
||||||
import KubernetesNamespaceHelper from '@/kubernetes/helpers/namespaceHelper';
|
import { isSystemNamespace } from '@/react/kubernetes/namespaces/utils';
|
||||||
|
|
||||||
import { columnHelper } from './helper';
|
import { columnHelper } from './helper';
|
||||||
|
|
||||||
export const name = columnHelper.accessor('Name', {
|
export const name = columnHelper.accessor(
|
||||||
header: 'Name',
|
(row) => {
|
||||||
id: 'name',
|
let name = row.Name;
|
||||||
cell: ({ row, getValue }) => {
|
|
||||||
const name = getValue();
|
|
||||||
const isSystem = KubernetesNamespaceHelper.isSystemNamespace(
|
|
||||||
row.original.Namespace
|
|
||||||
);
|
|
||||||
|
|
||||||
const isExternal =
|
const isExternal =
|
||||||
!row.original.Labels ||
|
!row.Labels || !row.Labels['io.portainer.kubernetes.application.owner'];
|
||||||
!row.original.Labels['io.portainer.kubernetes.application.owner'];
|
const isSystem = isSystemNamespace(row.Namespace);
|
||||||
|
|
||||||
return (
|
if (isExternal && !isSystem) {
|
||||||
<Authorized authorizations="K8sServiceW" childrenUnauthorized={name}>
|
name = `${name} external`;
|
||||||
{name}
|
}
|
||||||
|
|
||||||
{isSystem && (
|
if (isSystem) {
|
||||||
<span className="label label-info image-tag label-margins">
|
name = `${name} system`;
|
||||||
system
|
}
|
||||||
</span>
|
return name;
|
||||||
)}
|
|
||||||
|
|
||||||
{isExternal && !isSystem && (
|
|
||||||
<span className="label label-primary image-tag label-margins">
|
|
||||||
external
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</Authorized>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
});
|
{
|
||||||
|
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 (
|
||||||
|
<Authorized authorizations="K8sServiceW" childrenUnauthorized={name}>
|
||||||
|
{name}
|
||||||
|
|
||||||
|
{isSystem && (
|
||||||
|
<span className="label label-info image-tag label-margins">
|
||||||
|
system
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isExternal && !isSystem && (
|
||||||
|
<span className="label label-primary image-tag label-margins">
|
||||||
|
external
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</Authorized>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -4,7 +4,12 @@ import { columnHelper } from './helper';
|
||||||
|
|
||||||
export const ports = columnHelper.accessor(
|
export const ports = columnHelper.accessor(
|
||||||
(row) =>
|
(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: () => (
|
header: () => (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import { columnHelper } from './helper';
|
import { columnHelper } from './helper';
|
||||||
|
|
||||||
export const targetPorts = columnHelper.accessor(
|
export const targetPorts = columnHelper.accessor(
|
||||||
(row) => row.Ports.map((port) => `${port.TargetPort}`),
|
(row) => row.Ports.map((port) => port.TargetPort).join(','),
|
||||||
{
|
{
|
||||||
header: 'Target Ports',
|
header: 'Target Ports',
|
||||||
id: 'targetPorts',
|
id: 'targetPorts',
|
||||||
cell: ({ getValue }) => {
|
cell: ({ row }) => {
|
||||||
const ports = getValue();
|
const ports = row.original.Ports.map((port) => port.TargetPort);
|
||||||
|
|
||||||
if (!ports.length) {
|
if (!ports.length) {
|
||||||
return '-';
|
return '-';
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,18 +2,21 @@ import { formatDate } from '@/portainer/filters/filters';
|
||||||
|
|
||||||
import { columnHelper } from './helper';
|
import { columnHelper } from './helper';
|
||||||
|
|
||||||
export const created = columnHelper.accessor('CreationDate', {
|
export const created = columnHelper.accessor(
|
||||||
header: 'Created',
|
(row) => {
|
||||||
cell: ({ row, getValue }) => {
|
const owner = row.Labels?.['io.portainer.kubernetes.ingress.owner'];
|
||||||
const date = formatDate(getValue());
|
const date = formatDate(row.CreationDate);
|
||||||
const owner =
|
return owner ? `${date} by ${owner}` : date;
|
||||||
row.original.Labels?.['io.portainer.kubernetes.ingress.owner'];
|
|
||||||
|
|
||||||
if (owner) {
|
|
||||||
return `${date} by ${owner}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 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',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -4,18 +4,28 @@ import { AlertTriangle, ArrowRight } from 'lucide-react';
|
||||||
import { Icon } from '@@/Icon';
|
import { Icon } from '@@/Icon';
|
||||||
import { Badge } from '@@/Badge';
|
import { Badge } from '@@/Badge';
|
||||||
|
|
||||||
import { Ingress, TLS, Path } from '../../types';
|
import { Ingress, TLS } from '../../types';
|
||||||
|
|
||||||
import { columnHelper } from './helper';
|
import { columnHelper } from './helper';
|
||||||
|
|
||||||
export const ingressRules = columnHelper.accessor('Paths', {
|
export const ingressRules = columnHelper.accessor(
|
||||||
header: 'Rules and Paths',
|
({ Paths, TLS }) =>
|
||||||
id: 'ingressRules',
|
// return an accessor function with all the useful text to search for
|
||||||
cell: Cell,
|
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<Ingress, Path[] | undefined>) {
|
function Cell({ row }: CellContext<Ingress, string>) {
|
||||||
const paths = getValue();
|
const paths = row.original.Paths;
|
||||||
|
|
||||||
if (!paths) {
|
if (!paths) {
|
||||||
return <div />;
|
return <div />;
|
||||||
|
|
Loading…
Reference in New Issue