diff --git a/frontend/src/component/common/Table/cells/FeatureOverviewCell/FeatureOverviewCell.tsx b/frontend/src/component/common/Table/cells/FeatureOverviewCell/FeatureOverviewCell.tsx index abc699e5a5..79c061e556 100644 --- a/frontend/src/component/common/Table/cells/FeatureOverviewCell/FeatureOverviewCell.tsx +++ b/frontend/src/component/common/Table/cells/FeatureOverviewCell/FeatureOverviewCell.tsx @@ -13,6 +13,9 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit import { useFeature } from 'hooks/api/getters/useFeature/useFeature'; import { useLocationSettings } from 'hooks/useLocationSettings'; import { getLocalizedDateString } from '../../../util'; +import { Tag } from 'component/common/Tag/Tag'; +import type { ITag } from 'interfaces/tags'; +import { useUiFlag } from 'hooks/useUiFlag'; interface IFeatureNameCellProps { row: { @@ -36,7 +39,7 @@ const StyledFeatureLink = styled(Link)({ }, }); -const Tag = styled('button')(({ theme }) => ({ +const CustomTagButton = styled('button')(({ theme }) => ({ marginRight: theme.spacing(0.5), border: `1px solid ${theme.palette.divider}`, borderRadius: theme.shape.borderRadius, @@ -51,6 +54,22 @@ const Tag = styled('button')(({ theme }) => ({ color: 'inherit', })); +const StyledTag = styled('div')(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + marginRight: theme.spacing(0.5), + border: `1px solid ${theme.palette.divider}`, + borderRadius: theme.shape.borderRadius, + fontSize: theme.fontSizes.smallerBody, + textOverflow: 'ellipsis', + overflow: 'hidden', + textWrap: 'nowrap', + maxWidth: '250px', + padding: theme.spacing(0.25, 0.5), + cursor: 'pointer', + backgroundColor: theme.palette.neutral.light, +})); + const CappedDescription: FC<{ text: string; searchQuery: string }> = ({ text, searchQuery, @@ -80,19 +99,6 @@ const CappedDescription: FC<{ text: string; searchQuery: string }> = ({ ); }; -const CappedTag: FC<{ tag: string; children: ReactElement }> = ({ - tag, - children, -}) => { - return ( - 30} - show={{children}} - elseShow={children} - /> - ); -}; - const Container = styled(Box)(({ theme }) => ({ display: 'flex', flexDirection: 'column', @@ -158,23 +164,26 @@ const ArchivedFeatureName: FC<{ ); }; -const RestTags: FC<{ tags: string[]; onClick: (tag: string) => void }> = ({ - tags, - onClick, -}) => { +const RestTags: FC<{ + tags: ITag[]; + onClick: (tag: string) => void; + isTagTypeColorEnabled: boolean; +}> = ({ tags, onClick, isTagTypeColorEnabled }) => { return ( ( onClick(tag)} - key={tag} + onClick={() => onClick(`${tag.type}:${tag.value}`)} + key={`${tag.type}:${tag.value}`} > - {tag} + {`${tag.type}:${tag.value}`} ))} > - {tags.length} more... + + {tags.length} more... + ); }; @@ -183,30 +192,77 @@ const Tags: FC<{ tags: FeatureSearchResponseSchema['tags']; onClick: (tag: string) => void; }> = ({ tags, onClick }) => { - const [tag1, tag2, tag3, ...restTags] = (tags || []).map( - ({ type, value }) => `${type}:${value}`, - ); + const isTagTypeColorEnabled = useUiFlag('tagTypeColor'); + + if (!tags || tags.length === 0) { + return null; + } + + // Convert TagSchema to ITag for the Tag component + const tagsAsITag: ITag[] = tags.map((tag) => ({ + type: tag.type, + value: tag.value, + color: (tag as ITag).color, // Cast to ITag to get the color if available + })); + + const [tag1, tag2, tag3, ...restTags] = tagsAsITag; + + const handleTagClick = (tag: ITag) => { + onClick(`${tag.type}:${tag.value}`); + }; + + const renderCappedTag = (tag: ITag) => { + const tagFullText = `${tag.type}:${tag.value}`; + const needsTooltip = tagFullText.length > 30; + + if (isTagTypeColorEnabled) { + const tagComponent = ( + handleTagClick(tag)} + sx={{ cursor: 'pointer' }} + > + + + ); + + return needsTooltip ? ( + + {tagComponent} + + ) : ( + {tagComponent} + ); + } else { + // Fallback to simple tag rendering without color + return ( + + handleTagClick(tag)}> + {tagFullText.length > 25 + ? `${tagFullText.substring(0, 25)}…` + : tagFullText} + + + ); + } + }; return ( - {tag1 && ( - - onClick(tag1)}>{tag1} - - )} - {tag2 && ( - - onClick(tag2)}>{tag2} - - )} - {tag3 && ( - - onClick(tag3)}>{tag3} - - )} + {tag1 && renderCappedTag(tag1)} + {tag2 && renderCappedTag(tag2)} + {tag3 && renderCappedTag(tag3)} 0} - show={} + show={ + + } /> ); diff --git a/frontend/src/component/common/Tag/Tag.tsx b/frontend/src/component/common/Tag/Tag.tsx index 0632e1d52c..e71596652d 100644 --- a/frontend/src/component/common/Tag/Tag.tsx +++ b/frontend/src/component/common/Tag/Tag.tsx @@ -8,6 +8,7 @@ const StyledChip = styled(Chip)<{ $color?: string }>(({ theme, $color }) => ({ border: `1px solid ${theme.palette.divider}`, backgroundColor: theme.palette.common.white, color: theme.palette.text.primary, + height: '26px', '& .MuiChip-label': { display: 'flex', alignItems: 'center', diff --git a/src/lib/openapi/spec/deprecated-project-overview-schema.ts b/src/lib/openapi/spec/deprecated-project-overview-schema.ts index f1e1c52e16..1dbd34b0db 100644 --- a/src/lib/openapi/spec/deprecated-project-overview-schema.ts +++ b/src/lib/openapi/spec/deprecated-project-overview-schema.ts @@ -13,6 +13,7 @@ import { projectEnvironmentSchema } from './project-environment-schema'; import { createStrategyVariantSchema } from './create-strategy-variant-schema'; import { strategyVariantSchema } from './strategy-variant-schema'; import { createFeatureNamingPatternSchema } from './create-feature-naming-pattern-schema'; +import { tagSchema } from './tag-schema'; export const deprecatedProjectOverviewSchema = { $id: '#/components/schemas/deprecatedProjectOverviewSchema', @@ -136,6 +137,7 @@ export const deprecatedProjectOverviewSchema = { createStrategyVariantSchema, constraintSchema, featureSchema, + tagSchema, featureEnvironmentSchema, overrideSchema, parametersSchema, diff --git a/src/lib/openapi/spec/health-overview-schema.ts b/src/lib/openapi/spec/health-overview-schema.ts index 5224495e93..613a44b358 100644 --- a/src/lib/openapi/spec/health-overview-schema.ts +++ b/src/lib/openapi/spec/health-overview-schema.ts @@ -13,6 +13,7 @@ import { projectEnvironmentSchema } from './project-environment-schema'; import { createStrategyVariantSchema } from './create-strategy-variant-schema'; import { strategyVariantSchema } from './strategy-variant-schema'; import { createFeatureNamingPatternSchema } from './create-feature-naming-pattern-schema'; +import { tagSchema } from '../../services/tag-schema'; export const healthOverviewSchema = { $id: '#/components/schemas/healthOverviewSchema', @@ -125,6 +126,7 @@ export const healthOverviewSchema = { components: { schemas: { environmentSchema, + tagSchema, projectEnvironmentSchema, createFeatureStrategySchema, createStrategyVariantSchema, diff --git a/src/server-dev.ts b/src/server-dev.ts index 311d0efabc..257a49cf93 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -59,7 +59,7 @@ process.nextTick(async () => { teamsIntegrationChangeRequests: true, simplifyDisableFeature: true, adminNavUI: false, - tagTypeColor: true, + tagTypeColor: false, }, }, authentication: {