mirror of
https://github.com/portainer/portainer.git
synced 2025-07-25 08:19:40 +02:00
feat(edge/stacks): increase status transparency [EE-5554] (#9094)
This commit is contained in:
parent
db61fb149b
commit
0bcb57568c
45 changed files with 1305 additions and 316 deletions
|
@ -38,10 +38,10 @@ export function DeploymentCounter({
|
|||
return (
|
||||
<span
|
||||
className={clsx(styles.root, {
|
||||
[styles.statusOk]: type === 'Ok',
|
||||
[styles.statusError]: type === 'Error',
|
||||
[styles.statusAcknowledged]: type === 'Acknowledged',
|
||||
[styles.statusImagesPulled]: type === 'ImagesPulled',
|
||||
[styles.statusOk]: type === StatusType.Running,
|
||||
[styles.statusError]: type === StatusType.Error,
|
||||
[styles.statusAcknowledged]: type === StatusType.Acknowledged,
|
||||
[styles.statusImagesPulled]: type === StatusType.ImagesPulled,
|
||||
[styles.statusTotal]: type === undefined,
|
||||
})}
|
||||
>
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Datatable } from '@@/datatables';
|
|||
import { useTableState } from '@@/datatables/useTableState';
|
||||
|
||||
import { useEdgeStacks } from '../../queries/useEdgeStacks';
|
||||
import { EdgeStack } from '../../types';
|
||||
import { EdgeStack, StatusType } from '../../types';
|
||||
|
||||
import { createStore } from './store';
|
||||
import { columns } from './columns';
|
||||
|
@ -51,11 +51,16 @@ export function EdgeStacksDatatable() {
|
|||
|
||||
function aggregateStackStatus(stackStatus: EdgeStack['Status']) {
|
||||
const aggregateStatus = { ok: 0, error: 0, acknowledged: 0, imagesPulled: 0 };
|
||||
return Object.values(stackStatus).reduce((acc, envStatus) => {
|
||||
acc.ok += Number(envStatus.Details.Ok);
|
||||
acc.error += Number(envStatus.Details.Error);
|
||||
acc.acknowledged += Number(envStatus.Details.Acknowledged);
|
||||
acc.imagesPulled += Number(envStatus.Details.ImagesPulled);
|
||||
return acc;
|
||||
}, aggregateStatus);
|
||||
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);
|
||||
return acc;
|
||||
}, acc),
|
||||
aggregateStatus
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
import _ from 'lodash';
|
||||
import {
|
||||
AlertTriangle,
|
||||
CheckCircle,
|
||||
type Icon as IconType,
|
||||
Loader2,
|
||||
XCircle,
|
||||
} from 'lucide-react';
|
||||
|
||||
import { Icon, IconMode } from '@@/Icon';
|
||||
|
||||
import { DeploymentStatus, EdgeStack, StatusType } from '../../types';
|
||||
|
||||
export function EdgeStackStatus({ edgeStack }: { edgeStack: EdgeStack }) {
|
||||
const status = Object.values(edgeStack.Status);
|
||||
const lastStatus = _.compact(status.map((s) => _.last(s.Status)));
|
||||
|
||||
const { icon, label, mode, spin } = getStatus(
|
||||
edgeStack.NumDeployments,
|
||||
lastStatus
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="mx-auto inline-flex items-center gap-2">
|
||||
{icon && <Icon icon={icon} spin={spin} mode={mode} />}
|
||||
{label}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function getStatus(
|
||||
numDeployments: number,
|
||||
envStatus: Array<DeploymentStatus>
|
||||
): {
|
||||
label: string;
|
||||
icon?: IconType;
|
||||
spin?: boolean;
|
||||
mode?: IconMode;
|
||||
} {
|
||||
if (envStatus.length < numDeployments) {
|
||||
return {
|
||||
label: 'Deploying',
|
||||
icon: Loader2,
|
||||
spin: true,
|
||||
mode: 'primary',
|
||||
};
|
||||
}
|
||||
|
||||
const allFailed = envStatus.every((s) => s.Type === StatusType.Error);
|
||||
|
||||
if (allFailed) {
|
||||
return {
|
||||
label: 'Failed',
|
||||
icon: XCircle,
|
||||
mode: 'danger',
|
||||
};
|
||||
}
|
||||
|
||||
const allRunning = envStatus.every((s) => s.Type === StatusType.Running);
|
||||
|
||||
if (allRunning) {
|
||||
return {
|
||||
label: 'Running',
|
||||
icon: CheckCircle,
|
||||
mode: 'success',
|
||||
};
|
||||
}
|
||||
|
||||
const hasDeploying = envStatus.some((s) => s.Type === StatusType.Deploying);
|
||||
const hasRunning = envStatus.some((s) => s.Type === StatusType.Running);
|
||||
const hasFailed = envStatus.some((s) => s.Type === StatusType.Error);
|
||||
|
||||
if (hasRunning && hasFailed && !hasDeploying) {
|
||||
return {
|
||||
label: 'Partially Running',
|
||||
icon: AlertTriangle,
|
||||
mode: 'warning',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
label: 'Deploying',
|
||||
icon: Loader2,
|
||||
spin: true,
|
||||
mode: 'primary',
|
||||
};
|
||||
}
|
|
@ -6,6 +6,9 @@ import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
|
|||
|
||||
import { buildNameColumn } from '@@/datatables/NameCell';
|
||||
|
||||
import { StatusType } from '../../types';
|
||||
import { EdgeStackStatus } from '../EdgeStackStatus';
|
||||
|
||||
import { DecoratedEdgeStack } from './types';
|
||||
import { DeploymentCounter, DeploymentCounterLink } from './DeploymentCounter';
|
||||
|
||||
|
@ -25,7 +28,7 @@ export const columns = _.compact([
|
|||
cell: ({ getValue, row }) => (
|
||||
<DeploymentCounterLink
|
||||
count={getValue()}
|
||||
type="Acknowledged"
|
||||
type={StatusType.Acknowledged}
|
||||
stackId={row.original.Id}
|
||||
/>
|
||||
),
|
||||
|
@ -39,7 +42,7 @@ export const columns = _.compact([
|
|||
cell: ({ getValue, row }) => (
|
||||
<DeploymentCounterLink
|
||||
count={getValue()}
|
||||
type="ImagesPulled"
|
||||
type={StatusType.ImagesPulled}
|
||||
stackId={row.original.Id}
|
||||
/>
|
||||
),
|
||||
|
@ -54,7 +57,7 @@ export const columns = _.compact([
|
|||
cell: ({ getValue, row }) => (
|
||||
<DeploymentCounterLink
|
||||
count={getValue()}
|
||||
type="Ok"
|
||||
type={StatusType.Running}
|
||||
stackId={row.original.Id}
|
||||
/>
|
||||
),
|
||||
|
@ -69,7 +72,7 @@ export const columns = _.compact([
|
|||
cell: ({ getValue, row }) => (
|
||||
<DeploymentCounterLink
|
||||
count={getValue()}
|
||||
type="Error"
|
||||
type={StatusType.Error}
|
||||
stackId={row.original.Id}
|
||||
/>
|
||||
),
|
||||
|
@ -79,6 +82,19 @@ export const columns = _.compact([
|
|||
className: '[&>*]:justify-center',
|
||||
},
|
||||
}),
|
||||
columnHelper.accessor('Status', {
|
||||
header: 'Status',
|
||||
cell: ({ row }) => (
|
||||
<div className="w-full text-center">
|
||||
<EdgeStackStatus edgeStack={row.original} />
|
||||
</div>
|
||||
),
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
meta: {
|
||||
className: '[&>*]:justify-center',
|
||||
},
|
||||
}),
|
||||
columnHelper.accessor('NumDeployments', {
|
||||
header: 'Deployments',
|
||||
cell: ({ getValue }) => (
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue