mirror of https://github.com/grafana/grafana.git
165 lines
4.8 KiB
TypeScript
165 lines
4.8 KiB
TypeScript
import { css } from '@emotion/css';
|
|
import { Draggable } from '@hello-pangea/dnd';
|
|
import pluralize from 'pluralize';
|
|
import { ReactNode } from 'react';
|
|
|
|
import { GrafanaTheme2 } from '@grafana/data';
|
|
import { selectors } from '@grafana/e2e-selectors';
|
|
import { Trans, t } from '@grafana/i18n';
|
|
import { Icon, IconButton, useStyles2, Spinner, IconName } from '@grafana/ui';
|
|
import { TagBadge } from 'app/core/components/TagFilter/TagBadge';
|
|
|
|
import { PlaylistItemUI } from './types';
|
|
|
|
interface Props {
|
|
items: PlaylistItemUI[];
|
|
onDelete: (idx: number) => void;
|
|
}
|
|
|
|
export const PlaylistTableRows = ({ items, onDelete }: Props) => {
|
|
const styles = useStyles2(getStyles);
|
|
|
|
if (!items?.length) {
|
|
return (
|
|
<div>
|
|
<em>
|
|
<Trans i18nKey="playlist-edit.form.table-empty">Playlist is empty. Add dashboards below.</Trans>
|
|
</em>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const renderItem = (item: PlaylistItemUI) => {
|
|
let icon: IconName = item.type === 'dashboard_by_tag' ? 'apps' : 'tag-alt';
|
|
const info: ReactNode[] = [];
|
|
|
|
const first = item.dashboards?.[0];
|
|
if (!item.dashboards) {
|
|
info.push(<Spinner key="spinner" />);
|
|
} else if (item.type === 'dashboard_by_tag') {
|
|
info.push(<TagBadge key={item.value} label={item.value} removeIcon={false} count={0} />);
|
|
if (!first) {
|
|
icon = 'exclamation-triangle';
|
|
info.push(
|
|
<span>
|
|
{' '}
|
|
<span key="info">
|
|
<Trans i18nKey="playlist.playlist-table-rows.no-dashboards-found">No dashboards found</Trans>
|
|
</span>
|
|
</span>
|
|
);
|
|
} else {
|
|
info.push(<span key="info"> {pluralize('dashboard', item.dashboards.length, true)}</span>);
|
|
}
|
|
} else if (first) {
|
|
info.push(
|
|
item.dashboards.length > 1 ? (
|
|
<span>
|
|
{' '}
|
|
<span key="info">
|
|
<Trans i18nKey="playlist.playlist-table-rows.multiple-dashboards-found" values={{ items: item.value }}>
|
|
Multiple items found: {'{{items}}'}
|
|
</Trans>
|
|
</span>
|
|
</span>
|
|
) : (
|
|
<span key="info">{first.name ?? item.value}</span>
|
|
)
|
|
);
|
|
} else {
|
|
icon = 'exclamation-triangle';
|
|
info.push(
|
|
<span>
|
|
{' '}
|
|
<span key="info">
|
|
<Trans i18nKey="playlist.playlist-table-rows.not-found" values={{ items: item.value }}>
|
|
Not found: {'{{items}}'}
|
|
</Trans>
|
|
</span>
|
|
</span>
|
|
);
|
|
}
|
|
return (
|
|
<>
|
|
<Icon name={icon} className={styles.rightMargin} key="icon" />
|
|
{info}
|
|
</>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{items.map((item, index) => (
|
|
<Draggable key={`${index}/${item.value}`} draggableId={`${index}`} index={index}>
|
|
{(provided) => (
|
|
<div
|
|
className={styles.row}
|
|
ref={provided.innerRef}
|
|
{...provided.draggableProps}
|
|
{...provided.dragHandleProps}
|
|
role="row"
|
|
>
|
|
<div
|
|
className={styles.actions}
|
|
role="cell"
|
|
aria-label={t(
|
|
'playlist.playlist-table-rows.aria-label-playlist-item',
|
|
'Playlist item, {{itemType}}, {{itemValue}}',
|
|
{ itemType: item.type, itemValue: item.value }
|
|
)}
|
|
>
|
|
{renderItem(item)}
|
|
</div>
|
|
<div className={styles.actions}>
|
|
<IconButton
|
|
name="times"
|
|
size="md"
|
|
onClick={() => onDelete(index)}
|
|
data-testid={selectors.pages.PlaylistForm.itemDelete}
|
|
tooltip={t('playlist-edit.form.table-delete', 'Delete playlist item')}
|
|
/>
|
|
<Icon
|
|
title={t('playlist-edit.form.table-drag', 'Drag and drop to reorder')}
|
|
name="draggabledots"
|
|
size="md"
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</Draggable>
|
|
))}
|
|
</>
|
|
);
|
|
};
|
|
|
|
function getStyles(theme: GrafanaTheme2) {
|
|
return {
|
|
row: css({
|
|
padding: theme.spacing(0.75),
|
|
background: theme.colors.background.secondary,
|
|
borderRadius: theme.shape.radius.default,
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
marginBottom: '3px',
|
|
|
|
border: `1px solid ${theme.colors.border.medium}`,
|
|
'&:hover': {
|
|
border: `1px solid ${theme.colors.border.strong}`,
|
|
},
|
|
}),
|
|
rightMargin: css({
|
|
marginRight: '5px',
|
|
}),
|
|
actions: css({
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
display: 'flex',
|
|
}),
|
|
settings: css({
|
|
label: 'settings',
|
|
textAlign: 'right',
|
|
}),
|
|
};
|
|
}
|