import { useCurrentStateAndParams, useRouter } from '@uirouter/react'; import { useQueryClient } from '@tanstack/react-query'; import { useEffect } from 'react'; import { StackContainersDatatable } from '@/react/docker/stacks/ItemView/StackContainersDatatable'; import { AccessControlPanel } from '@/react/portainer/access-control'; import { useStack } from '@/react/common/stacks/queries/useStack'; import { Stack, StackType } from '@/react/common/stacks/types'; import { ResourceControlViewModel } from '@/react/portainer/access-control/models/ResourceControlViewModel'; import { ResourceControlType } from '@/react/portainer/access-control/types'; import { queryKeys } from '@/react/common/stacks/queries/query-keys'; import { useIsEdgeAdmin } from '@/react/hooks/useUser'; import { notifyError } from '@/portainer/services/notifications'; import { PageHeader } from '@@/PageHeader'; import { StackDetails } from './StackDetails'; import { StackServicesDatatable } from './StackServicesDatatable'; export function ItemView() { const { isExternal, isOrphaned, isOrphanedRunning, isRegular, stackName, stackId, stackType, } = useParams(); useUnauthorizedRedirect(); const queryClient = useQueryClient(); const stackQuery = useStack(stackId, { enabled: isRegular || isOrphaned }); const stack = stackQuery.data; const resourceControl = stack?.ResourceControl ? new ResourceControlViewModel(stack.ResourceControl) : undefined; useEffect(() => { if ( isInvalidStackType({ isExternal, isOrphaned, isOrphanedRunning, stackType, }) ) { notifyError('Failure', undefined, 'Invalid type URL parameter.'); } }, [isExternal, isOrphaned, isOrphanedRunning, stackType]); return ( <> {(!isOrphaned || isOrphanedRunning) && ( <> {stackType === StackType.DockerCompose && ( )} {stackType === StackType.DockerSwarm && ( )} )} {stack && !isOrphaned && ( queryClient.invalidateQueries(queryKeys.stack(stackId)) } /> )} ); } function isInvalidStackType({ isExternal, isOrphaned, isOrphanedRunning, stackType, }: { isExternal: boolean; isOrphaned: boolean; isOrphanedRunning: boolean; stackType: StackType | undefined; }) { return ( (isExternal || (isOrphaned && isOrphanedRunning)) && (!stackType || (stackType !== StackType.DockerSwarm && stackType !== StackType.DockerCompose)) ); } function useParams() { /* TODO Check: why use stack.Name or params.stackName? why use booleans from params instead of figuring out by name/id why stack.EndpointID and not params.envId? */ const { params } = useCurrentStateAndParams(); const isRegular = params.regular === 'true'; const isExternal = params.external === 'true'; const isOrphaned = params.orphaned === 'true'; const isOrphanedRunning = params.orphanedRunning === 'true'; const stackName = params.name || ('' as string); const id = params.id ? (parseInt(params.id, 10) as Stack['Id']) : undefined; const type = ['1', '2', '3'].includes(params.type) ? (parseInt(params.type, 10) as StackType) : undefined; return { isExternal, isRegular, isOrphaned, isOrphanedRunning, stackName, stackId: id, stackType: type, }; } function useUnauthorizedRedirect() { const isAdminQuery = useIsEdgeAdmin(); const router = useRouter(); useEffect(() => { if (!isAdminQuery.isLoading && !isAdminQuery.isAdmin) { router.stateService.go('docker.dashboard'); } }, [isAdminQuery.isLoading, isAdminQuery.isAdmin, router.stateService]); }