vitess.io/vitess@v0.16.2/web/vtadmin/src/components/routes/shard/ShardTablets.tsx (about) 1 /** 2 * Copyright 2021 The Vitess Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import { orderBy } from 'lodash'; 18 import { useMemo } from 'react'; 19 20 import style from './ShardTablets.module.scss'; 21 import { useTablets } from '../../../hooks/api'; 22 import { formatAlias, formatDisplayType, formatState } from '../../../util/tablets'; 23 import { DataCell } from '../../dataTable/DataCell'; 24 import { DataTable } from '../../dataTable/DataTable'; 25 import { ExternalTabletLink } from '../../links/ExternalTabletLink'; 26 import { TabletLink } from '../../links/TabletLink'; 27 import { TabletServingPip } from '../../pips/TabletServingPip'; 28 29 interface Props { 30 clusterID: string; 31 keyspace: string; 32 shard: string; 33 } 34 35 const COLUMNS = ['Alias', 'Type', 'Tablet State', 'Hostname']; 36 37 export const ShardTablets: React.FunctionComponent<Props> = (props) => { 38 // TODO(doeg): add more vtadmin-api params to query tablets for only this shard. 39 // In practice, this isn't _too_ bad since this query will almost always be cached 40 // from the /api/tablets sidebar query. 41 const { data: allTablets = [], ...tq } = useTablets(); 42 43 const tablets = useMemo(() => { 44 const rows = allTablets 45 .filter( 46 (t) => 47 t.cluster?.id === props.clusterID && 48 t.tablet?.keyspace === props.keyspace && 49 t.tablet?.shard === props.shard 50 ) 51 .map((t) => ({ 52 alias: formatAlias(t.tablet?.alias), 53 clusterID: t.cluster?.id, 54 fqdn: t.FQDN, 55 hostname: t.tablet?.hostname, 56 keyspace: t.tablet?.keyspace, 57 state: formatState(t), 58 tabletType: formatDisplayType(t), 59 // underscore prefix excludes the following properties from filtering 60 _state: t.state, 61 _typeSortOrder: formatDisplayType(t) === 'PRIMARY' ? 1 : 2, 62 })); 63 return orderBy(rows, ['_typeSortOrder', 'tabletType', 'state', 'alias']); 64 }, [allTablets, props.clusterID, props.keyspace, props.shard]); 65 66 if (!tq.isLoading && !tablets.length) { 67 return ( 68 <div className={style.placeholder}> 69 <div className={style.emoji}>🏜</div> 70 <div> 71 No tablets in{' '} 72 <span className="font-mono"> 73 {props.keyspace}/{props.shard} 74 </span> 75 . 76 </div> 77 </div> 78 ); 79 } 80 81 const renderRows = (rows: typeof tablets) => { 82 return rows.map((t) => { 83 return ( 84 <tr key={t.alias}> 85 <DataCell> 86 <TabletLink alias={t.alias} clusterID={t.clusterID}> 87 {t.alias} 88 </TabletLink> 89 </DataCell> 90 91 <DataCell>{t.tabletType}</DataCell> 92 93 <DataCell> 94 <TabletServingPip state={t._state} /> {t.state} 95 </DataCell> 96 97 <DataCell> 98 <ExternalTabletLink fqdn={`//${t.fqdn}`}>{t.hostname}</ExternalTabletLink> 99 </DataCell> 100 </tr> 101 ); 102 }); 103 }; 104 105 return <DataTable columns={COLUMNS} data={tablets} renderRows={renderRows} />; 106 };