Provisioning: Collapse repository status messages (#113666)
* Provisioning: Add collapsible pull status messages * Use text styles * Add animation * Fix error message * cleanup * a11y * more a11y
This commit is contained in:
@@ -112,7 +112,7 @@ function ExpandedRow({ row }: ExpandedRowProps) {
|
||||
const isValidState = state && ['success', 'warning', 'error'].includes(state);
|
||||
const alertProps = isValidState
|
||||
? {
|
||||
[state]: { message: row.status?.errors },
|
||||
[state]: { message: row.status?.message },
|
||||
}
|
||||
: null;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data/';
|
||||
import { t, Trans } from '@grafana/i18n';
|
||||
import { Badge, Card, Grid, Text, TextLink, useStyles2 } from '@grafana/ui';
|
||||
import { Repository } from 'app/api/clients/provisioning/v0alpha1';
|
||||
@@ -44,7 +45,10 @@ export function RepositoryPullStatusCard({ repo }: { repo: Repository }) {
|
||||
<Text variant="body">{status?.sync.job ?? 'N/A'}</Text>
|
||||
</div>
|
||||
|
||||
<div className={cx(styles.historicalData, { [styles.historicalDataOverlay]: isWorking })}>
|
||||
<div
|
||||
className={cx(styles.historicalData, { [styles.historicalDataOverlay]: isWorking })}
|
||||
aria-busy={isWorking}
|
||||
>
|
||||
{/* Last Ref */}
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.last-ref">Last Ref:</Trans>
|
||||
@@ -92,7 +96,7 @@ export function RepositoryPullStatusCard({ repo }: { repo: Repository }) {
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = () => {
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
spanTwo: css({
|
||||
gridColumn: 'span 2',
|
||||
@@ -101,6 +105,7 @@ const getStyles = () => {
|
||||
gridColumn: '1 / -1',
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'subgrid',
|
||||
gap: theme.spacing(1),
|
||||
}),
|
||||
historicalDataOverlay: css({
|
||||
opacity: 0.6,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Text, useStyles2 } from '@grafana/ui';
|
||||
import { Trans } from '@grafana/i18n';
|
||||
import { Box, Text, useStyles2 } from '@grafana/ui';
|
||||
|
||||
interface MessageListProps {
|
||||
messages: string[];
|
||||
@@ -10,19 +12,87 @@ interface MessageListProps {
|
||||
|
||||
export function MessageList({ messages, variant }: MessageListProps) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const [showFull, setShowFull] = useState(false);
|
||||
const hasMultipleMessages = messages.length > 1;
|
||||
|
||||
const handleExpand = () => {
|
||||
setShowFull(true);
|
||||
};
|
||||
|
||||
const handleCollapse = () => {
|
||||
setShowFull(false);
|
||||
};
|
||||
|
||||
const displayMessages = showFull ? messages : messages.slice(0, 1);
|
||||
|
||||
return (
|
||||
<ul className={styles.messageList}>
|
||||
{messages.map((msg, index) => (
|
||||
<li key={index}>{variant ? <Text variant={variant}>{msg}</Text> : msg}</li>
|
||||
))}
|
||||
</ul>
|
||||
<>
|
||||
<div className={cx(styles.messageListWrapper, { [styles.messageListWrapperExpanded]: showFull })}>
|
||||
<ul className={styles.messageList}>
|
||||
{displayMessages.map((msg, index) => (
|
||||
<li key={index}>
|
||||
{variant ? <Text variant={variant}>{msg}</Text> : msg}
|
||||
{!showFull && hasMultipleMessages && index === 0 && (
|
||||
<>
|
||||
{' '}
|
||||
<span aria-hidden="true">… </span>
|
||||
<span className="sr-only">
|
||||
<Trans i18nKey="provisioning.message.truncated">Message truncated</Trans>
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
className={cx(styles.showMore, styles.showMoreInline)}
|
||||
onClick={handleExpand}
|
||||
aria-expanded={false}
|
||||
>
|
||||
<Trans i18nKey="provisioning.message.show-more">show more</Trans>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
{showFull && hasMultipleMessages && (
|
||||
<Box paddingLeft={3} paddingTop={0.5}>
|
||||
<button type="button" className={styles.showMore} onClick={handleCollapse} aria-expanded={true}>
|
||||
<Trans i18nKey="provisioning.message.show-less">show less</Trans>
|
||||
</button>
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
messageListWrapper: css({
|
||||
overflow: 'hidden',
|
||||
maxHeight: '200px',
|
||||
[theme.transitions.handleMotion('no-preference', 'reduce')]: {
|
||||
transition: theme.transitions.create('max-height', {
|
||||
duration: theme.transitions.duration.standard,
|
||||
easing: theme.transitions.easing.easeInOut,
|
||||
}),
|
||||
},
|
||||
}),
|
||||
messageListWrapperExpanded: css({
|
||||
maxHeight: '9999px',
|
||||
}),
|
||||
messageList: css({
|
||||
margin: 0,
|
||||
paddingLeft: theme.spacing(3),
|
||||
listStyle: 'disc',
|
||||
}),
|
||||
showMore: css({
|
||||
backgroundColor: 'transparent',
|
||||
border: 'none',
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
textDecoration: 'underline',
|
||||
cursor: 'pointer',
|
||||
color: theme.colors.text.primary,
|
||||
}),
|
||||
showMoreInline: css({
|
||||
marginLeft: theme.spacing(0.5),
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -11763,6 +11763,11 @@
|
||||
"path-label": "Repository Path",
|
||||
"path-required": "Repository path is required"
|
||||
},
|
||||
"message": {
|
||||
"show-less": "show less",
|
||||
"show-more": "show more",
|
||||
"truncated": "Message truncated"
|
||||
},
|
||||
"mode-options": {
|
||||
"folder": {
|
||||
"description": "After setup, a new Grafana folder will be created and synced with external storage. If any resources are present in external storage, they will be provisioned to this new folder. All new resources created in this folder will be stored and versioned in external storage.",
|
||||
|
||||
Reference in New Issue
Block a user