import { AlertTriangle } from 'lucide-react'; import { EnvironmentId } from '@/react/portainer/environments/types'; import { Stack, StackStatus, StackType } from '@/react/common/stacks/types'; import { Authorized } from '@/react/hooks/useUser'; import { Icon } from '@@/Icon'; import { FormSection } from '@@/form-components/FormSection'; import { useSwarmStackResources } from '../useSwarmStackServices'; import { useComposeStackContainers } from '../useComposeStackContainers'; import { StackDuplicationForm } from './StackDuplicationForm/StackDuplicationForm'; import { StackRedeployGitForm } from './StackRedeployGitForm/StackRedeployGitForm'; import { StackActions } from './StackActions'; import { AssociateStackForm } from './AssociateStackForm'; interface StackInfoTabProps { stack?: Stack; // will be loaded only if regular or orphaned stackName: string; stackFileContent?: string; isRegular?: boolean; isExternal: boolean; isOrphaned: boolean; isOrphanedRunning: boolean; environmentId: number; yamlError?: string; } export function StackInfoTab({ stack, stackName, stackFileContent, isRegular, isExternal, isOrphaned, isOrphanedRunning, environmentId, yamlError, }: StackInfoTabProps) { const status = useStackStatus({ status: stack?.Status, environmentId, name: stackName, type: stack?.Type, }); return ( <> {stackName} {stack && ( )} {stack && ( <> {isOrphaned ? ( ) : ( <> {stack.GitConfig && !stack.FromAppTemplate && ( )} {isRegular && ( )} > )} > )} > ); } function ExternalOrphanedWarning({ isExternal, isOrphaned, }: { isExternal: boolean; isOrphaned: boolean; }) { if (!isExternal && !isOrphaned) return null; return ( {isExternal && ( This stack was created outside of Portainer. Control over this stack is limited. )} {isOrphaned && ( This stack is orphaned. You can re-associate it with the current environment using the "Associate to this environment" feature. )} ); } function useStackStatus({ status, name, type, environmentId, }: { status: Stack['Status'] | undefined; name: string; type: Stack['Type'] | undefined; environmentId: EnvironmentId; }) { const servicesQuery = useSwarmStackResources(name, { enabled: type === StackType.DockerSwarm && !status, }); const containersQuery = useComposeStackContainers( { environmentId, stackName: name }, { enabled: type === StackType.DockerCompose && !status, } ); const derivedSwarmStatus = servicesQuery.data?.length ? StackStatus.Active : StackStatus.Inactive; const derivedComposeStatus = containersQuery.data?.length ? StackStatus.Active : StackStatus.Inactive; const derivedStatus = type === StackType.DockerSwarm ? derivedSwarmStatus : derivedComposeStatus; return status || derivedStatus; }
{isExternal && ( This stack was created outside of Portainer. Control over this stack is limited. )} {isOrphaned && ( This stack is orphaned. You can re-associate it with the current environment using the "Associate to this environment" feature. )}