import { CellContext, createColumnHelper } from '@tanstack/react-table'; import { ChevronDown, ChevronRight } from 'lucide-react'; import clsx from 'clsx'; import { useState } from 'react'; import _ from 'lodash'; import UpdatesAvailable from '@/assets/ico/icon_updates-available.svg?c'; import UpToDate from '@/assets/ico/icon_up-to-date.svg?c'; import { isoDateFromTimestamp } from '@/portainer/filters/filters'; import { isBE } from '@/react/portainer/feature-flags/feature-flags.service'; import { getDashboardRoute } from '@/react/portainer/environments/utils'; import { GitCommitLink } from '@/react/portainer/gitops/GitCommitLink'; import { Button } from '@@/buttons'; import { Icon } from '@@/Icon'; import { Link } from '@@/Link'; import { DeploymentStatus, EdgeStackStatus, StatusType } from '../../types'; import { EnvironmentActions } from './EnvironmentActions'; import { ActionStatus } from './ActionStatus'; import { EdgeStackEnvironment } from './types'; const columnHelper = createColumnHelper(); export const columns = _.compact([ columnHelper.accessor('Name', { id: 'name', header: 'Name', cell({ row: { original: env } }) { const { to, params } = getDashboardRoute(env); return ( {env.Name} ); }, }), columnHelper.accessor((env) => endpointStatusLabel(env.StackStatus.Status), { id: 'status', header: 'Status', cell({ row: { original: env } }) { return ( ); }, }), columnHelper.accessor((env) => _.last(env.StackStatus.Status)?.Time, { id: 'statusDate', header: 'Time', cell({ row: { original: env } }) { return ( ); }, }), ...(isBE ? [ columnHelper.accessor((env) => endpointTargetVersionLabel(env), { id: 'targetVersion', header: 'Target version', cell: TargetVersionCell, }), columnHelper.accessor( (env) => endpointDeployedVersionLabel(env.StackStatus), { id: 'deployedVersion', header: 'Deployed version', cell: DeployedVersionCell, } ), ] : []), columnHelper.accessor( (env) => env.StackStatus.Status.find((s) => s.Type === StatusType.Error)?.Error, { id: 'error', header: 'Error', cell: ErrorCell, } ), ...(isBE ? [ columnHelper.display({ id: 'actions', header: 'Actions', cell({ row: { original: env } }) { return ; }, }), columnHelper.display({ id: 'actionStatus', header: 'Action Status', cell({ row: { original: env } }) { return ; }, }), ] : []), ]); function ErrorCell({ getValue, row, }: CellContext) { const [isExpanded, setIsExpanded] = useState(false); const value = getValue(); if (!value) { return '-'; } return ( ); } function endpointStatusLabel(statusArray: Array) { const labels = []; statusArray.forEach((status) => { if (status.Type === StatusType.Acknowledged) { labels.push('Acknowledged'); } if (status.Type === StatusType.ImagesPulled) { labels.push('Images pre-pulled'); } if (status.Type === StatusType.Running) { labels.push('Deployed'); } if (status.Type === StatusType.Error) { labels.push('Failed'); } if (status.Type === StatusType.PausedDeploying) { labels.push('Paused'); } if (status.Type === StatusType.RollingBack) { labels.push('Rolling Back'); } if (status.Type === StatusType.RolledBack) { labels.push('Rolled Back'); } }); if (!labels.length) { labels.push('Pending'); } return _.uniq(labels).join(', '); } function TargetVersionCell({ row, getValue, }: CellContext) { const value = getValue(); if (!value) { return ''; } return ( <> {row.original.TargetCommitHash ? (
) : (
{value}
)} ); } function endpointTargetVersionLabel(env: EdgeStackEnvironment) { if (env.TargetCommitHash) { return env.TargetCommitHash.slice(0, 7).toString(); } return env.TargetFileVersion.toString() || ''; } function DeployedVersionCell({ row, getValue, }: CellContext) { const value = getValue(); if (!value || value === '0') { return (
); } let statusIcon = ; if ( (row.original.TargetCommitHash && row.original.TargetCommitHash.slice(0, 7) !== value) || (!row.original.TargetCommitHash && row.original.TargetFileVersion !== value) ) { statusIcon = ; } return ( <> {row.original.TargetCommitHash ? (
{statusIcon}
) : (
{statusIcon} {value}
)} ); } function endpointDeployedVersionLabel(status: EdgeStackStatus) { if (status.DeploymentInfo?.ConfigHash) { return status.DeploymentInfo?.ConfigHash.slice(0, 7).toString(); } return status.DeploymentInfo?.FileVersion.toString() || ''; } function Status({ value }: { value: StatusType }) { const color = getStateColor(value); return (
{_.startCase(StatusType[value])}
); } function getStateColor(type: StatusType): 'orange' | 'green' | 'red' { switch (type) { case StatusType.Acknowledged: case StatusType.ImagesPulled: case StatusType.DeploymentReceived: case StatusType.Running: case StatusType.RemoteUpdateSuccess: case StatusType.Removed: return 'green'; case StatusType.Error: return 'red'; case StatusType.Pending: case StatusType.Deploying: case StatusType.Removing: case StatusType.PausedDeploying: case StatusType.RollingBack: case StatusType.RolledBack: default: return 'orange'; } }