diff --git a/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/DeploymentCounter.module.css b/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/DeploymentCounter.module.css
deleted file mode 100644
index 7676eee2b..000000000
--- a/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/DeploymentCounter.module.css
+++ /dev/null
@@ -1,28 +0,0 @@
-.root {
- padding: 2px 10px;
- border-radius: 10px;
-}
-
-.status-acknowledged {
- color: #337ab7;
- background-color: rgba(51, 122, 183, 0.1);
-}
-
-.status-images-pulled {
- color: #e1a800;
- background-color: rgba(238, 192, 32, 0.1);
-}
-
-.status-ok {
- color: #23ae89;
- background-color: rgba(35, 174, 137, 0.1);
-}
-
-.status-error {
- color: #ae2323;
- background-color: rgba(174, 35, 35, 0.1);
-}
-
-.status-total {
- background-color: rgba(168, 167, 167, 0.1);
-}
diff --git a/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/DeploymentCounter.tsx b/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/DeploymentCounter.tsx
index ec25cb777..c6ea944a4 100644
--- a/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/DeploymentCounter.tsx
+++ b/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/DeploymentCounter.tsx
@@ -1,28 +1,30 @@
import clsx from 'clsx';
+import { ReactNode } from 'react';
import { Link } from '@@/Link';
+import { TooltipWithChildren } from '@@/Tip/TooltipWithChildren';
import { EdgeStack, StatusType } from '../../types';
-import styles from './DeploymentCounter.module.css';
-
export function DeploymentCounterLink({
count,
+ total,
type,
stackId,
}: {
count: number;
+ total: number;
type: StatusType;
stackId: EdgeStack['Id'];
}) {
return (
-
+
-
+
);
@@ -30,22 +32,48 @@ export function DeploymentCounterLink({
export function DeploymentCounter({
count,
+ total,
type,
}: {
count: number;
+ total: number;
type?: StatusType;
}) {
return (
-
- • {count}
-
+
+
+
);
}
+
+function getTooltip(count: number, total: number, type?: StatusType) {
+ const label = getLabel(type);
+ return `${count} of ${total} ${label}`;
+
+ function getLabel(type?: StatusType): ReactNode {
+ switch (type) {
+ case StatusType.Running:
+ return 'deployments running';
+ case StatusType.DeploymentReceived:
+ return 'deployments received';
+ case StatusType.Error:
+ return 'deployments failed';
+ case StatusType.Acknowledged:
+ return 'deployments acknowledged';
+ case StatusType.ImagesPulled:
+ return 'images pre-pulled';
+ default:
+ return '';
+ }
+ }
+}
diff --git a/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/EdgeStacksDatatable.tsx b/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/EdgeStacksDatatable.tsx
index 2e908a45f..e1f334ba7 100644
--- a/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/EdgeStacksDatatable.tsx
+++ b/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/EdgeStacksDatatable.tsx
@@ -50,15 +50,12 @@ export function EdgeStacksDatatable() {
}
function aggregateStackStatus(stackStatus: EdgeStack['Status']) {
- const aggregateStatus = { ok: 0, error: 0, acknowledged: 0, imagesPulled: 0 };
+ const aggregateStatus: Partial
> = {};
return Object.values(stackStatus).reduce(
(acc, envStatus) =>
envStatus.Status.reduce((acc, status) => {
const { Type } = status;
- acc.ok += Number(Type === StatusType.Running);
- acc.error += Number(Type === StatusType.Error);
- acc.acknowledged += Number(Type === StatusType.Acknowledged);
- acc.imagesPulled += Number(Type === StatusType.ImagesPulled);
+ acc[Type] = (acc[Type] || 0) + 1;
return acc;
}, acc),
aggregateStatus
diff --git a/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/columns.tsx b/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/columns.tsx
index b66e5aae0..b140de240 100644
--- a/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/columns.tsx
+++ b/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/columns.tsx
@@ -5,12 +5,13 @@ import { isoDateFromTimestamp } from '@/portainer/filters/filters';
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
import { buildNameColumn } from '@@/datatables/NameCell';
+import { Link } from '@@/Link';
import { StatusType } from '../../types';
import { EdgeStackStatus } from './EdgeStacksStatus';
import { DecoratedEdgeStack } from './types';
-import { DeploymentCounter, DeploymentCounterLink } from './DeploymentCounter';
+import { DeploymentCounter } from './DeploymentCounter';
const columnHelper = createColumnHelper();
@@ -21,29 +22,52 @@ export const columns = _.compact([
'edge.stacks.edit',
'stackId'
),
- columnHelper.accessor('aggregatedStatus.acknowledged', {
- header: 'Acknowledged',
- enableSorting: false,
- enableHiding: false,
- cell: ({ getValue, row }) => (
-
- ),
- meta: {
- className: '[&>*]:justify-center',
- },
- }),
- isBE &&
- columnHelper.accessor('aggregatedStatus.imagesPulled', {
- header: 'Images Pre-pulled',
+ columnHelper.accessor(
+ (item) => item.aggregatedStatus[StatusType.Acknowledged] || 0,
+ {
+ header: 'Acknowledged',
+ enableSorting: false,
+ enableHiding: false,
cell: ({ getValue, row }) => (
-
+ ),
+ meta: {
+ className: '[&>*]:justify-center',
+ },
+ }
+ ),
+ isBE &&
+ columnHelper.accessor(
+ (item) => item.aggregatedStatus[StatusType.ImagesPulled] || 0,
+ {
+ header: 'Images pre-pulled',
+ cell: ({ getValue, row }) => (
+
+ ),
+ enableSorting: false,
+ enableHiding: false,
+ meta: {
+ className: '[&>*]:justify-center',
+ },
+ }
+ ),
+ columnHelper.accessor(
+ (item) => item.aggregatedStatus[StatusType.DeploymentReceived] || 0,
+ {
+ header: 'Deployments received',
+ cell: ({ getValue, row }) => (
+
),
enableSorting: false,
@@ -51,37 +75,45 @@ export const columns = _.compact([
meta: {
className: '[&>*]:justify-center',
},
- }),
- columnHelper.accessor('aggregatedStatus.ok', {
- header: 'Deployed',
- cell: ({ getValue, row }) => (
-
- ),
- enableSorting: false,
- enableHiding: false,
- meta: {
- className: '[&>*]:justify-center',
- },
- }),
- columnHelper.accessor('aggregatedStatus.error', {
- header: 'Failed',
- cell: ({ getValue, row }) => (
-
- ),
- enableSorting: false,
- enableHiding: false,
- meta: {
- className: '[&>*]:justify-center',
- },
- }),
+ }
+ ),
+ columnHelper.accessor(
+ (item) => item.aggregatedStatus[StatusType.Error] || 0,
+ {
+ header: 'Deployments failed',
+ cell: ({ getValue, row }) => {
+ const count = getValue();
+
+ return (
+
+
+ {count > 0 && (
+
+ ({count}/{row.original.NumDeployments})
+
+ )}
+
+ );
+ },
+ enableSorting: false,
+ enableHiding: false,
+ meta: {
+ className: '[&>*]:justify-center',
+ },
+ }
+ ),
columnHelper.accessor('Status', {
header: 'Status',
cell: ({ row }) => (
@@ -95,19 +127,6 @@ export const columns = _.compact([
className: '[&>*]:justify-center',
},
}),
- columnHelper.accessor('NumDeployments', {
- header: 'Deployments',
- cell: ({ getValue }) => (
-
-
-
- ),
- enableSorting: false,
- enableHiding: false,
- meta: {
- className: '[&>*]:justify-center',
- },
- }),
columnHelper.accessor('CreationDate', {
header: 'Creation Date',
cell: ({ getValue }) => isoDateFromTimestamp(getValue()),
diff --git a/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/types.ts b/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/types.ts
index 6b1463061..89b360342 100644
--- a/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/types.ts
+++ b/app/react/edge/edge-stacks/ListView/EdgeStacksDatatable/types.ts
@@ -1,12 +1,5 @@
-import { EdgeStack } from '../../types';
-
-interface AggregateStackStatus {
- ok: number;
- error: number;
- acknowledged: number;
- imagesPulled: number;
-}
+import { EdgeStack, StatusType } from '../../types';
export type DecoratedEdgeStack = EdgeStack & {
- aggregatedStatus: AggregateStackStatus;
+ aggregatedStatus: Partial>;
};