import { User, Clock, Info } from 'lucide-react'; import moment from 'moment'; import { useEffect, useState } from 'react'; import { Pod } from 'kubernetes-types/core/v1'; import { useCurrentStateAndParams } from '@uirouter/react'; import { Authorized } from '@/react/hooks/useUser'; import { notifyError, notifySuccess } from '@/portainer/services/notifications'; import { DetailsTable } from '@@/DetailsTable'; import { Badge } from '@@/Badge'; import { Link } from '@@/Link'; import { LoadingButton } from '@@/buttons'; import { WidgetBody, Widget } from '@@/Widget'; import { InlineLoader } from '@@/InlineLoader'; import { Icon } from '@@/Icon'; import { Note } from '@@/Note'; import { isSystemNamespace } from '../../namespaces/utils'; import { appStackNameLabel, appKindToDeploymentTypeMap, appOwnerLabel, appDeployMethodLabel, appNoteAnnotation, } from '../constants'; import { applicationIsKind, bytesToReadableFormat, getResourceRequests, getRunningPods, getTotalPods, isExternalApplication, } from '../utils'; import { useApplication, usePatchApplicationMutation, } from '../application.queries'; import { Application, ApplicationPatch } from '../types'; export function ApplicationSummaryWidget() { const stateAndParams = useCurrentStateAndParams(); const { params: { namespace, name, 'resource-type': resourceType, endpointId: environmentId, }, } = stateAndParams; const { data: application, ...applicationQuery } = useApplication( environmentId, namespace, name, resourceType ); const systemNamespace = isSystemNamespace(namespace); const externalApplication = application && isExternalApplication(application); const applicationRequests = application && getResourceRequests(application); const applicationOwner = application?.metadata?.labels?.[appOwnerLabel]; const applicationDeployMethod = getApplicationDeployMethod(application); const applicationNote = application?.metadata?.annotations?.[appNoteAnnotation]; const [applicationNoteFormValues, setApplicationNoteFormValues] = useState(''); useEffect(() => { setApplicationNoteFormValues(applicationNote || ''); }, [applicationNote]); const failedCreateCondition = application?.status?.conditions?.find( (condition) => condition.reason === 'FailedCreate' ); const patchApplicationMutation = usePatchApplicationMutation( environmentId, namespace, name ); return (
{applicationQuery.isLoading && ( Loading application... )} {application && ( <> {failedCreateCondition && (
Failed to create application
{failedCreateCondition.message}
)} Name
{name} {externalApplication && !systemNamespace && ( external )}
Stack {application?.metadata?.labels?.[appStackNameLabel] || '-'} Namespace
{namespace} {systemNamespace && system}
Application type {application?.kind || '-'} {application?.kind && ( Status {applicationIsKind('Pod', application) && ( {application?.status?.phase} )} {!applicationIsKind('Pod', application) && ( {appKindToDeploymentTypeMap[application.kind]} {getRunningPods(application)} {' '} / {getTotalPods(application)} )} )} {(!!applicationRequests?.cpu || !!applicationRequests?.memoryBytes) && ( Resource reservations {!applicationIsKind('Pod', application) && (
per instance
)} {!!applicationRequests?.cpu && (
CPU {applicationRequests.cpu}
)} {!!applicationRequests?.memoryBytes && (
Memory{' '} {bytesToReadableFormat( applicationRequests.memoryBytes )}
)} )} Creation
{applicationOwner && ( {applicationOwner} )} {moment( application?.metadata?.creationTimestamp ).format('YYYY-MM-DD HH:mm:ss')} {(!externalApplication || systemNamespace) && ( Deployed from {applicationDeployMethod} )}
patchApplicationNote()} disabled={ // disable if there is no change to the note, or it's updating applicationNoteFormValues === (applicationNote || '') || patchApplicationMutation.isLoading } data-cy="k8sAppDetail-saveNoteButton" isLoading={patchApplicationMutation.isLoading} loadingText={ applicationNote ? 'Updating' : 'Saving' } > {applicationNote ? 'Update' : 'Save'} note
)}
); async function patchApplicationNote() { const patch: ApplicationPatch = [ { op: 'replace', path: `/metadata/annotations/${appNoteAnnotation}`, value: applicationNoteFormValues, }, ]; if (application?.kind) { try { await patchApplicationMutation.mutateAsync({ appKind: application.kind, patch, }); notifySuccess('Success', 'Application successfully updated'); } catch (error) { notifyError( `Failed to ${applicationNote ? 'update' : 'save'} note`, error as Error ); } } } } function getApplicationDeployMethod(application?: Application) { if (!application?.metadata?.labels?.[appDeployMethodLabel]) return 'application form'; if (application?.metadata?.labels?.[appDeployMethodLabel] === 'content') { return 'manifest'; } return application?.metadata?.labels?.[appDeployMethodLabel]; }