1717import { Icon } from '@iconify/react' ;
1818import Box from '@mui/material/Box' ;
1919import Typography from '@mui/material/Typography' ;
20- import _ from 'lodash ' ;
20+ import React from 'react ' ;
2121import Link from '../common/Link' ;
2222
23- const A8R_ICON_MAP : Record < string , string > = {
24- description : 'mdi:information-outline' ,
25- owner : 'mdi:account' ,
26- chat : 'mdi:chat' ,
27- bugs : 'mdi:bug' ,
28- logs : 'mdi:chart-timeline-variant' ,
29- documentation : 'mdi:book-open-page-variant' ,
30- repository : 'mdi:github' ,
31- support : 'mdi:help-circle' ,
32- runbook : 'mdi:script-text' ,
33- incidents : 'mdi:alert-circle' ,
34- uptime : 'mdi:check-circle' ,
35- performance : 'mdi:speedometer' ,
36- dependencies : 'mdi:sitemap' ,
23+ export type A8RMetadataItem = {
24+ key : string ;
25+ label : string ;
26+ value : string ;
27+ icon : string ;
28+ isLink : boolean ;
3729} ;
3830
39- const LINKABLE_KEYS = [
31+ const A8R_ICON_MAP : Record < string , { icon : string ; label : string } > = {
32+ description : { icon : 'mdi:information-outline' , label : 'Description' } ,
33+ owner : { icon : 'mdi:account' , label : 'Owner' } ,
34+ dependencies : { icon : 'mdi:sitemap' , label : 'Dependencies' } ,
35+ chat : { icon : 'mdi:chat' , label : 'Chat' } ,
36+ bugs : { icon : 'mdi:bug' , label : 'Bugs' } ,
37+ logs : { icon : 'mdi:chart-timeline-variant' , label : 'Logs' } ,
38+ documentation : { icon : 'mdi:book-open-page-variant' , label : 'Documentation' } ,
39+ repository : { icon : 'mdi:github' , label : 'Repository' } ,
40+ support : { icon : 'mdi:help-circle' , label : 'Support' } ,
41+ runbook : { icon : 'mdi:script-text' , label : 'Runbook' } ,
42+ incidents : { icon : 'mdi:alert-circle' , label : 'Incidents' } ,
43+ uptime : { icon : 'mdi:check-circle' , label : 'Uptime' } ,
44+ performance : { icon : 'mdi:speedometer' , label : 'Performance' } ,
45+ } ;
46+
47+ const PREFERRED_ORDER = [
48+ 'description' ,
49+ 'owner' ,
50+ 'dependencies' ,
4051 'chat' ,
41- 'bugs' ,
42- 'logs' ,
4352 'documentation' ,
4453 'repository' ,
54+ 'logs' ,
55+ 'bugs' ,
4556 'support' ,
4657 'runbook' ,
4758 'incidents' ,
4859 'uptime' ,
4960 'performance' ,
5061] ;
62+
5163function isValidHttpUrl ( value : string ) {
5264 try {
5365 const url = new URL ( value ) ;
@@ -56,68 +68,52 @@ function isValidHttpUrl(value: string) {
5668 return false ;
5769 }
5870}
71+ export function getA8RMetadata ( annotations : Record < string , string > = { } ) : A8RMetadataItem [ ] {
72+ return Object . entries ( annotations )
73+ . filter ( ( [ key ] ) => key . startsWith ( 'a8r.io/' ) )
74+ . map ( ( [ key , value ] ) => {
75+ const shortKey = key . replace ( 'a8r.io/' , '' ) ;
76+ const meta = A8R_ICON_MAP [ shortKey ] ;
77+ if ( ! meta ) return null ;
78+
79+ return {
80+ key : shortKey ,
81+ label : meta . label ,
82+ value,
83+ icon : meta . icon ,
84+ isLink : isValidHttpUrl ( value ) ,
85+ } ;
86+ } )
87+ . filter ( ( v ) : v is A8RMetadataItem => Boolean ( v ) )
88+ . sort ( ( a , b ) => {
89+ const ai = PREFERRED_ORDER . indexOf ( a . key ) ;
90+ const bi = PREFERRED_ORDER . indexOf ( b . key ) ;
91+ return ( ai === - 1 ? 999 : ai ) - ( bi === - 1 ? 999 : bi ) ;
92+ } ) ;
93+ }
5994
6095export default function A8RServiceInfo ( { annotations } : { annotations ?: Record < string , string > } ) {
61- //Defining the order of annotations for user friendly display
62- const PREFERRED_ORDER = [
63- 'description' ,
64- 'owner' ,
65- 'dependencies' ,
66- 'chat' ,
67- 'documentation' ,
68- 'repository' ,
69- 'logs' ,
70- 'bugs' ,
71- 'support' ,
72- 'runbook' ,
73- 'incidents' ,
74- 'uptime' ,
75- 'performance' ,
76- ] ;
77- const a8rEntries = Object . entries ( annotations || { } )
78- . filter ( ( [ key ] ) => key . startsWith ( 'a8r.io/' ) )
79- . map ( ( [ key , value ] ) => ( {
80- type : key . replace ( 'a8r.io/' , '' ) ,
81- value,
82- originalKey : key ,
83- } ) ) ;
96+ const metadata = React . useMemo ( ( ) => getA8RMetadata ( annotations ) , [ annotations ] ) ;
8497
85- const sortedEntries = _ . sortBy ( a8rEntries , entry => {
86- const index = PREFERRED_ORDER . indexOf ( entry . type ) ;
87- return index === - 1 ? 999 : index ;
88- } ) ;
98+ if ( metadata . length === 0 ) return null ;
8999
90- if ( sortedEntries . length === 0 ) return null ;
91100 return (
92- < Box display = "flex" flexDirection = "column" gap = { 1.5 } py = { 1 } >
93- { sortedEntries . map ( ( { type, value, originalKey } ) => {
94- const icon = A8R_ICON_MAP [ type ] || 'mdi:tag-outline' ;
95- const isLink = LINKABLE_KEYS . includes ( type ) && isValidHttpUrl ( value ) ;
96- const label = _ . capitalize ( type ) ;
97- const renderedValue =
98- type === 'dependencies'
99- ? value
100- . split ( ',' )
101- . map ( s => s . trim ( ) )
102- . join ( ', ' )
103- : value ;
104-
105- return (
106- < Box key = { originalKey } display = "flex" alignItems = "center" >
107- < Icon icon = { icon } width = "20" style = { { marginRight : 8 , color : 'text.secondary' } } />
108- < Typography variant = "body2" >
109- < strong > { label } :</ strong > { ' ' }
110- { isLink ? (
111- < Link href = { value } target = "_blank" rel = "noopener" >
112- { value }
113- </ Link >
114- ) : (
115- renderedValue
116- ) }
117- </ Typography >
118- </ Box >
119- ) ;
120- } ) }
101+ < Box display = "flex" flexDirection = "column" gap = { 1.5 } >
102+ { metadata . map ( item => (
103+ < Box key = { item . key } display = "flex" alignItems = "center" >
104+ < Icon icon = { item . icon } width = "20" style = { { marginRight : 8 } } />
105+ < Typography variant = "body2" >
106+ < strong > { item . label } :</ strong > { ' ' }
107+ { item . isLink ? (
108+ < Link href = { item . value } target = "_blank" rel = "noopener noreferrer" >
109+ { item . value }
110+ </ Link >
111+ ) : (
112+ item . value
113+ ) }
114+ </ Typography >
115+ </ Box >
116+ ) ) }
121117 </ Box >
122118 ) ;
123119}
0 commit comments