import { type FC, useState } from 'react'; import { List, ListItem, ListItemButton, ListItemIcon, ListItemText, styled, } from '@mui/material'; import { useNavigate } from 'react-router-dom'; import { FeatureArchiveDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveDialog'; import { FeatureArchiveNotAllowedDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveNotAllowedDialog'; import { formatDateYMD } from 'utils/formatDate'; import { parseISO } from 'date-fns'; import { DependencyRow } from './DependencyRow'; import { useLocationSettings } from 'hooks/useLocationSettings'; import { useShowDependentFeatures } from './useShowDependentFeatures'; import { FeatureLifecycle } from '../FeatureLifecycle/FeatureLifecycle'; import { MarkCompletedDialogue } from '../FeatureLifecycle/MarkCompletedDialogue'; import { TagRow } from './TagRow'; import { capitalizeFirst } from 'utils/capitalizeFirst'; import { Collaborators } from './Collaborators'; import { EnvironmentVisibilityMenu } from './EnvironmentVisibilityMenu/EnvironmentVisibilityMenu'; import { Truncator } from 'component/common/Truncator/Truncator'; import type { FeatureLink, IFeatureToggle, } from '../../../../../interfaces/featureToggle'; import AddIcon from '@mui/icons-material/Add'; import { useUiFlag } from 'hooks/useUiFlag'; import { Badge } from 'component/common/Badge/Badge'; import LinkIcon from '@mui/icons-material/Link'; import { UPDATE_FEATURE } from '../../../../providers/AccessProvider/permissions'; import PermissionButton from 'component/common/PermissionButton/PermissionButton'; import { AddLinkDialogue } from './AddLinkDialogue'; import { useFeatureLinkApi } from 'hooks/api/actions/useFeatureLinkApi/useFeatureLinkApi'; import useToast from 'hooks/useToast'; import { useFeature } from 'hooks/api/getters/useFeature/useFeature'; import { formatUnknownError } from 'utils/formatUnknownError'; import { ExtraActions } from './ExtraActions'; const StyledMetaDataContainer = styled('div')(({ theme }) => ({ padding: theme.spacing(3), borderRadius: theme.shape.borderRadiusLarge, backgroundColor: theme.palette.background.paper, display: 'flex', flexDirection: 'column', gap: theme.spacing(2), width: '350px', border: `1px solid ${theme.palette.divider}`, [theme.breakpoints.down('md')]: { width: '100%', }, marginBottom: theme.spacing(2), })); const StyledTitle = styled('h2')(({ theme }) => ({ fontSize: theme.typography.body1.fontSize, fontWeight: theme.typography.fontWeightBold, marginBottom: theme.spacing(0.5), })); const StyledBody = styled('div')({ display: 'flex', flexDirection: 'column', }); export const StyledMetaDataItem = styled('div')(({ theme }) => ({ display: 'flex', alignItems: 'center', justifyContent: 'space-between', minHeight: theme.spacing(4.5), fontSize: theme.fontSizes.smallBody, })); export const StyledMetaDataItemLabel = styled('span')(({ theme }) => ({ color: theme.palette.text.secondary, marginRight: theme.spacing(1), })); const StyledMetaDataItemText = styled('span')({ overflowWrap: 'anywhere', }); export const StyledMetaDataItemValue = styled('div')(({ theme }) => ({ display: 'flex', alignItems: 'center', gap: theme.spacing(1), })); export const StyledListItemIcon = styled(ListItemIcon)(({ theme }) => ({ minWidth: theme.spacing(5), })); type FeatureOverviewMetaDataProps = { hiddenEnvironments?: string[]; onEnvironmentVisibilityChange?: (environment: string) => void; feature: IFeatureToggle; onChange: () => void; }; interface FeatureLinksProps { links: FeatureLink[]; project: string; feature: string; } const FeatureLinks: FC = ({ links, project, feature }) => { const [showAddLinkDialogue, setShowAddLinkDialogue] = useState(false); const { deleteLink, loading } = useFeatureLinkApi(project, feature); const { setToastData, setToastApiError } = useToast(); const { refetchFeature } = useFeature(project, feature); const addLinkButton = ( } permission={UPDATE_FEATURE} projectId={project} variant='text' onClick={() => setShowAddLinkDialogue(true)} > Add link ); const renderLinkItems = () => ( {links.map((link) => ( {}} onDelete={async () => { try { await deleteLink(link.id); setToastData({ text: 'Link removed', type: 'success', }); refetchFeature(); } catch (error) { setToastApiError(formatUnknownError(error)); } }} /> } key={link.id} disablePadding dense > ))} ); const emptyStateContent = ( <> You can now add links{' '} New Gather relevant links for external resources such as issue trackers, code repositories or analytics tooling
{addLinkButton}
); const linksContent = ( <> Resources {renderLinkItems()}
{addLinkButton}
); return ( <> {links.length === 0 ? emptyStateContent : linksContent} setShowAddLinkDialogue(false)} /> ); }; const FeatureOverviewMetaData: FC = ({ hiddenEnvironments, onEnvironmentVisibilityChange, feature, onChange, }) => { const { locationSettings } = useLocationSettings(); const navigate = useNavigate(); const [archiveDialogOpen, setArchiveDialogOpen] = useState(false); const [markCompletedDialogueOpen, setMarkCompletedDialogueOpen] = useState(false); const { project, description, type } = feature; const showDependentFeatures = useShowDependentFeatures(project); const featureLinksEnabled = useUiFlag('featureLinks'); return ( <> {featureLinksEnabled ? ( ) : null}
Flag details {description ? ( {description} ) : null}
Flag type: {capitalizeFirst(type || ' ')} flag {feature.lifecycle ? ( Lifecycle: setArchiveDialogOpen(true)} onComplete={() => setMarkCompletedDialogueOpen(true) } onUncomplete={onChange} /> ) : null} Created: {formatDateYMD( parseISO(feature.createdAt), locationSettings.locale, )} {feature.createdBy ? ( Created by: {feature.createdBy?.name} ) : null} {feature.collaborators?.users && feature.collaborators?.users.length > 0 ? ( Collaborators: ) : null} {showDependentFeatures ? ( ) : null} {onEnvironmentVisibilityChange ? ( ) : null}
{feature.children.length > 0 ? ( setArchiveDialogOpen(false)} /> ) : ( { navigate(`/projects/${feature.project}`); }} onClose={() => setArchiveDialogOpen(false)} projectId={feature.project} featureIds={[feature.name]} /> )} {feature.project ? ( ) : null} ); }; export default FeatureOverviewMetaData;