RepositoryOverview: Adjust layout and extract necessary components out (#112190)
* RepositoryOverview: adjust layout and extract necessary components out * clean up * clean up
This commit is contained in:
@@ -3,11 +3,12 @@ import { useMemo } from 'react';
|
||||
import { intervalToAbbreviatedDurationString, TraceKeyValuePair } from '@grafana/data';
|
||||
import { t, Trans } from '@grafana/i18n';
|
||||
import { Alert, Badge, Box, Card, InteractiveTable, Spinner, Stack, Text } from '@grafana/ui';
|
||||
import { Job, Repository, SyncStatus } from 'app/api/clients/provisioning/v0alpha1';
|
||||
import { Job, Repository } from 'app/api/clients/provisioning/v0alpha1';
|
||||
import KeyValuesTable from 'app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/KeyValuesTable';
|
||||
|
||||
import { ProvisioningAlert } from '../Shared/ProvisioningAlert';
|
||||
import { useRepositoryAllJobs } from '../hooks/useRepositoryAllJobs';
|
||||
import { getStatusColor } from '../utils/repositoryStatus';
|
||||
import { formatTimestamp } from '../utils/time';
|
||||
|
||||
import { JobSummary } from './JobSummary';
|
||||
@@ -22,24 +23,12 @@ type JobCell = {
|
||||
};
|
||||
};
|
||||
|
||||
const getStatusColor = (state?: SyncStatus['state']) => {
|
||||
switch (state) {
|
||||
case 'success':
|
||||
return 'green';
|
||||
case 'working':
|
||||
return 'blue';
|
||||
case 'warning':
|
||||
return 'orange';
|
||||
case 'pending':
|
||||
return 'darkgrey';
|
||||
case 'error':
|
||||
return 'red';
|
||||
default:
|
||||
return 'darkgrey';
|
||||
}
|
||||
};
|
||||
|
||||
const getJobColumns = () => [
|
||||
{
|
||||
id: 'jobId',
|
||||
header: t('provisioning.recent-jobs.column-job-id', 'Job ID'),
|
||||
cell: ({ row: { original: job } }: JobCell) => <Text variant="body">{job.metadata?.name || ''}</Text>,
|
||||
},
|
||||
{
|
||||
id: 'status',
|
||||
header: t('provisioning.recent-jobs.column-status', 'Status'),
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import { Trans, t } from '@grafana/i18n';
|
||||
import { Stack, Alert, Text } from '@grafana/ui';
|
||||
import { HealthStatus } from 'app/api/clients/provisioning/v0alpha1';
|
||||
|
||||
interface Props {
|
||||
health: HealthStatus;
|
||||
}
|
||||
|
||||
export function RepositoryHealth({ health }: Props) {
|
||||
return (
|
||||
<Stack gap={2} direction="column" alignItems="flex-start">
|
||||
{health.healthy ? (
|
||||
<Alert
|
||||
title={t('provisioning.repository-health.title-repository-is-healthy', 'Repository is healthy')}
|
||||
severity="success"
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
<Trans i18nKey="provisioning.repository-health.no-errors-found">No errors found</Trans>
|
||||
</Alert>
|
||||
) : (
|
||||
<Alert
|
||||
title={t('provisioning.repository-health.title-repository-is-unhealthy', 'Repository is unhealthy')}
|
||||
severity="warning"
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
{health.message && health.message.length > 0 && (
|
||||
<>
|
||||
<Text>
|
||||
<Trans i18nKey="provisioning.repository-health.details">Details:</Trans>
|
||||
</Text>
|
||||
<ul>
|
||||
{health.message.map((message) => (
|
||||
<li key={message}>{message}</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</Alert>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import { css } from '@emotion/css';
|
||||
|
||||
import { t, Trans } from '@grafana/i18n';
|
||||
import { Badge, Card, Grid, Stack, Text, useStyles2 } from '@grafana/ui';
|
||||
import { Repository } from 'app/api/clients/provisioning/v0alpha1';
|
||||
|
||||
import { formatTimestamp } from '../utils/time';
|
||||
|
||||
import { CheckRepository } from './CheckRepository';
|
||||
|
||||
export function RepositoryHealthCard({ repo }: { repo: Repository }) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const status = repo.status;
|
||||
|
||||
return (
|
||||
<Card noMargin className={styles.card}>
|
||||
<Card.Heading>
|
||||
<Trans i18nKey="provisioning.repository-overview.health">Health</Trans>
|
||||
</Card.Heading>
|
||||
<Card.Description>
|
||||
<Grid columns={3} gap={1} alignItems="baseline">
|
||||
{/* Status */}
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.status">Status:</Trans>
|
||||
</Text>
|
||||
|
||||
<div className={styles.spanTwo}>
|
||||
<Badge
|
||||
color={status?.health?.healthy ? 'green' : 'red'}
|
||||
text={
|
||||
status?.health?.healthy
|
||||
? t('provisioning.repository-overview.healthy', 'Healthy')
|
||||
: t('provisioning.repository-overview.unhealthy', 'Unhealthy')
|
||||
}
|
||||
icon={status?.health?.healthy ? 'check-circle' : 'exclamation-triangle'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Checked */}
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.checked">Checked:</Trans>
|
||||
</Text>
|
||||
<div className={styles.spanTwo}>
|
||||
<Text variant="body">{formatTimestamp(status?.health?.checked)}</Text>
|
||||
</div>
|
||||
|
||||
{!!status?.health?.message?.length && (
|
||||
<>
|
||||
<div>
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.messages">Messages:</Trans>
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Stack gap={1}>
|
||||
{status.health.message.map((msg, idx) => (
|
||||
<Text key={idx} variant="body">
|
||||
{msg}
|
||||
</Text>
|
||||
))}
|
||||
</Stack>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
</Card.Description>
|
||||
<Card.Actions className={styles.actions}>
|
||||
<CheckRepository repository={repo} />
|
||||
</Card.Actions>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = () => {
|
||||
return {
|
||||
spanTwo: css({
|
||||
gridColumn: 'span 2',
|
||||
}),
|
||||
card: css({
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}),
|
||||
actions: css({
|
||||
marginTop: 'auto',
|
||||
}),
|
||||
};
|
||||
};
|
||||
@@ -1,25 +1,26 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { GrafanaEdition } from '@grafana/data/internal';
|
||||
import { Trans, t } from '@grafana/i18n';
|
||||
import { Trans } from '@grafana/i18n';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { Box, Card, CellProps, Grid, InteractiveTable, LinkButton, Stack, Text, useStyles2 } from '@grafana/ui';
|
||||
import { Repository, ResourceCount } from 'app/api/clients/provisioning/v0alpha1';
|
||||
|
||||
import { RecentJobs } from '../Job/RecentJobs';
|
||||
import { MessageList } from '../Shared/MessageList';
|
||||
import { formatTimestamp } from '../utils/time';
|
||||
|
||||
import { CheckRepository } from './CheckRepository';
|
||||
import { RepositoryHealth } from './RepositoryHealth';
|
||||
import { SyncRepository } from './SyncRepository';
|
||||
import { RepositoryHealthCard } from './RepositoryHealthCard';
|
||||
import { RepositoryPullStatusCard } from './RepositoryPullStatusCard';
|
||||
|
||||
type StatCell<T extends keyof ResourceCount = keyof ResourceCount> = CellProps<ResourceCount, ResourceCount[T]>;
|
||||
|
||||
function getColumnCount(hasWebhook: boolean): 3 | 4 {
|
||||
return hasWebhook ? 4 : 3;
|
||||
function getColumnCount(hasWebhook: boolean): { xxlColumn: 5 | 4; lgColumn: 3 | 2 } {
|
||||
return {
|
||||
xxlColumn: hasWebhook ? 5 : 4,
|
||||
lgColumn: hasWebhook ? 3 : 2,
|
||||
};
|
||||
}
|
||||
|
||||
export function RepositoryOverview({ repo }: { repo: Repository }) {
|
||||
@@ -27,7 +28,7 @@ export function RepositoryOverview({ repo }: { repo: Repository }) {
|
||||
|
||||
const status = repo.status;
|
||||
const webhookURL = getWebhookURL(repo);
|
||||
const columns = getColumnCount(Boolean(repo.status?.webhook));
|
||||
const { lgColumn, xxlColumn } = getColumnCount(Boolean(repo.status?.webhook));
|
||||
|
||||
const resourceColumns = useMemo(
|
||||
() => [
|
||||
@@ -53,7 +54,7 @@ export function RepositoryOverview({ repo }: { repo: Repository }) {
|
||||
return (
|
||||
<Box padding={2}>
|
||||
<Stack direction="column" gap={2}>
|
||||
<Grid columns={{ xs: 1, sm: 2, lg: columns }} gap={2}>
|
||||
<Grid columns={{ xs: 1, sm: 2, lg: lgColumn, xxl: xxlColumn }} gap={2} alignItems={'flex-start'}>
|
||||
<div className={styles.cardContainer}>
|
||||
<Card noMargin className={styles.card}>
|
||||
<Card.Heading>
|
||||
@@ -69,144 +70,20 @@ export function RepositoryOverview({ repo }: { repo: Repository }) {
|
||||
) : null}
|
||||
</Card.Description>
|
||||
<Card.Actions className={styles.actions}>
|
||||
<LinkButton fill="outline" size="md" href={getFolderURL(repo)} icon="folder-open">
|
||||
<LinkButton size="md" href={getFolderURL(repo)} icon="folder-open" variant="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.view-folder">View Folder</Trans>
|
||||
</LinkButton>
|
||||
</Card.Actions>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{repo.status?.health && (
|
||||
<div className={styles.cardContainer}>
|
||||
<Card noMargin className={styles.card}>
|
||||
<Card.Heading>
|
||||
<Trans i18nKey="provisioning.repository-overview.health">Health</Trans>
|
||||
</Card.Heading>
|
||||
<Card.Description>
|
||||
<RepositoryHealth health={repo.status?.health} />
|
||||
<Grid columns={12} gap={1} alignItems="baseline">
|
||||
<div className={styles.labelColumn}>
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.status">Status:</Trans>
|
||||
</Text>
|
||||
</div>
|
||||
<div className={styles.valueColumn}>
|
||||
<Text variant="body">
|
||||
{status?.health?.healthy
|
||||
? t('provisioning.repository-overview.healthy', 'Healthy')
|
||||
: t('provisioning.repository-overview.unhealthy', 'Unhealthy')}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div className={styles.labelColumn}>
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.checked">Checked:</Trans>
|
||||
</Text>
|
||||
</div>
|
||||
<div className={styles.valueColumn}>
|
||||
<Text variant="body">{formatTimestamp(status?.health?.checked)}</Text>
|
||||
</div>
|
||||
|
||||
{!!status?.health?.message?.length && (
|
||||
<>
|
||||
<div className={styles.labelColumn}>
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.messages">Messages:</Trans>
|
||||
</Text>
|
||||
</div>
|
||||
<div className={styles.valueColumn}>
|
||||
<Stack gap={1}>
|
||||
{status.health.message.map((msg, idx) => (
|
||||
<Text key={idx} variant="body">
|
||||
{msg}
|
||||
</Text>
|
||||
))}
|
||||
</Stack>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
</Card.Description>
|
||||
<Card.Actions className={styles.actions}>
|
||||
<CheckRepository repository={repo} />
|
||||
</Card.Actions>
|
||||
</Card>
|
||||
<RepositoryHealthCard repo={repo} />
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.cardContainer}>
|
||||
<Card className={styles.card} noMargin>
|
||||
<Card.Heading>
|
||||
<Trans i18nKey="provisioning.repository-overview.pull-status">Pull status</Trans>
|
||||
</Card.Heading>
|
||||
<Card.Description>
|
||||
<Grid columns={12} gap={1} alignItems="baseline">
|
||||
<div className={styles.labelColumn}>
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.status">Status:</Trans>
|
||||
</Text>
|
||||
</div>
|
||||
<div className={styles.valueColumn}>
|
||||
<Text variant="body">{status?.sync.state ?? 'N/A'}</Text>
|
||||
</div>
|
||||
|
||||
<div className={styles.labelColumn}>
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.job-id">Job ID:</Trans>
|
||||
</Text>
|
||||
</div>
|
||||
<div className={styles.valueColumn}>
|
||||
<Text variant="body">{status?.sync.job ?? 'N/A'}</Text>
|
||||
</div>
|
||||
|
||||
<div className={styles.labelColumn}>
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.last-ref">Last Ref:</Trans>
|
||||
</Text>
|
||||
</div>
|
||||
<div className={styles.valueColumn}>
|
||||
<Text variant="body">
|
||||
{status?.sync.lastRef
|
||||
? status.sync.lastRef.substring(0, 7)
|
||||
: t('provisioning.repository-overview.not-available', 'N/A')}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div className={styles.labelColumn}>
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.started">Started:</Trans>
|
||||
</Text>
|
||||
</div>
|
||||
<div className={styles.valueColumn}>
|
||||
<Text variant="body">{formatTimestamp(status?.sync.started)}</Text>
|
||||
</div>
|
||||
|
||||
<div className={styles.labelColumn}>
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.finished">Finished:</Trans>
|
||||
</Text>
|
||||
</div>
|
||||
<div className={styles.valueColumn}>
|
||||
<Text variant="body">{formatTimestamp(status?.sync.finished)}</Text>
|
||||
</div>
|
||||
|
||||
{!!status?.sync?.message?.length && (
|
||||
<>
|
||||
<div className={styles.labelColumn}>
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.messages">Messages:</Trans>
|
||||
</Text>
|
||||
</div>
|
||||
<div className={styles.valueColumn}>
|
||||
<MessageList messages={status.sync.message} variant="body" />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
</Card.Description>
|
||||
<Card.Actions className={styles.actions}>
|
||||
<SyncRepository repository={repo} />
|
||||
</Card.Actions>
|
||||
</Card>
|
||||
</div>
|
||||
{/* Webhook */}
|
||||
{repo.status?.webhook && (
|
||||
<div className={styles.cardContainer}>
|
||||
<Card noMargin className={styles.card}>
|
||||
@@ -251,6 +128,16 @@ export function RepositoryOverview({ repo }: { repo: Repository }) {
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Pull status */}
|
||||
<div
|
||||
className={cx(
|
||||
styles.pullStatusCard,
|
||||
repo.status?.webhook ? styles.pullStatusCardLgSpan3 : styles.pullStatusCardLgSpan2
|
||||
)}
|
||||
>
|
||||
<RepositoryPullStatusCard repo={repo} />
|
||||
</div>
|
||||
</Grid>
|
||||
|
||||
{/* job status is not ready for Cloud yet */}
|
||||
@@ -292,6 +179,23 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
valueColumn: css({
|
||||
gridColumn: 'span 9',
|
||||
}),
|
||||
pullStatusCard: css({
|
||||
gridColumn: 'span 2',
|
||||
|
||||
[theme.breakpoints.down('lg')]: {
|
||||
gridColumn: 'span 2',
|
||||
},
|
||||
}),
|
||||
pullStatusCardLgSpan3: css({
|
||||
[theme.breakpoints.down('xxl')]: {
|
||||
gridColumn: 'span 3',
|
||||
},
|
||||
}),
|
||||
pullStatusCardLgSpan2: css({
|
||||
[theme.breakpoints.down('xxl')]: {
|
||||
gridColumn: 'span 2',
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
import { css } from '@emotion/css';
|
||||
|
||||
import { t, Trans } from '@grafana/i18n';
|
||||
import { Badge, Card, Grid, Text, TextLink, useStyles2 } from '@grafana/ui';
|
||||
import { Repository } from 'app/api/clients/provisioning/v0alpha1';
|
||||
|
||||
import { MessageList } from '../Shared/MessageList';
|
||||
import { getRepoCommitUrl } from '../utils/git';
|
||||
import { getStatusColor, getStatusIcon } from '../utils/repositoryStatus';
|
||||
import { formatTimestamp } from '../utils/time';
|
||||
|
||||
import { SyncRepository } from './SyncRepository';
|
||||
|
||||
export function RepositoryPullStatusCard({ repo }: { repo: Repository }) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const status = repo.status;
|
||||
const statusColor = getStatusColor(status?.sync.state);
|
||||
const statusIcon = getStatusIcon(status?.sync.state);
|
||||
|
||||
const { url: lastCommitUrl, hasUrl } = getRepoCommitUrl(repo.spec, status?.sync.lastRef);
|
||||
|
||||
return (
|
||||
<Card noMargin>
|
||||
<Card.Heading>
|
||||
<Trans i18nKey="provisioning.repository-overview.pull-status">Pull status</Trans>
|
||||
</Card.Heading>
|
||||
<Card.Description>
|
||||
<Grid columns={3} gap={1} alignItems="baseline">
|
||||
{/* Status */}
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.status">Status:</Trans>
|
||||
</Text>
|
||||
<div className={styles.spanTwo}>
|
||||
<Badge icon={statusIcon} color={statusColor} text={status?.sync.state ?? 'N/A'} />
|
||||
</div>
|
||||
|
||||
{/* Job ID */}
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.job-id">Job ID:</Trans>
|
||||
</Text>
|
||||
<div className={styles.spanTwo}>
|
||||
<Text variant="body">{status?.sync.job ?? 'N/A'}</Text>
|
||||
</div>
|
||||
|
||||
{/* Last Ref */}
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.last-ref">Last Ref:</Trans>
|
||||
</Text>
|
||||
<div className={styles.spanTwo}>
|
||||
{hasUrl && lastCommitUrl ? (
|
||||
<TextLink href={lastCommitUrl} external>
|
||||
<Text variant="body">
|
||||
{status?.sync.lastRef
|
||||
? status.sync.lastRef.substring(0, 7)
|
||||
: t('provisioning.repository-overview.not-available', 'N/A')}
|
||||
</Text>
|
||||
</TextLink>
|
||||
) : (
|
||||
<Text variant="body">
|
||||
{status?.sync.lastRef
|
||||
? status.sync.lastRef.substring(0, 7)
|
||||
: t('provisioning.repository-overview.not-available', 'N/A')}
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.finished">Last successful pull:</Trans>
|
||||
</Text>
|
||||
<div className={styles.spanTwo}>
|
||||
<Text variant="body">{formatTimestamp(status?.sync.finished)}</Text>
|
||||
</div>
|
||||
|
||||
{!!status?.sync?.message?.length && (
|
||||
<>
|
||||
<Text color="secondary">
|
||||
<Trans i18nKey="provisioning.repository-overview.messages">Messages:</Trans>
|
||||
</Text>
|
||||
<div className={styles.spanTwo}>
|
||||
<MessageList messages={status.sync.message} variant="body" />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
</Card.Description>
|
||||
<Card.Actions>
|
||||
<SyncRepository repository={repo} />
|
||||
</Card.Actions>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = () => {
|
||||
return {
|
||||
spanTwo: css({
|
||||
gridColumn: 'span 2',
|
||||
}),
|
||||
};
|
||||
};
|
||||
@@ -70,3 +70,40 @@ export const getRepoHrefForProvider = (spec?: RepositorySpec) => {
|
||||
export function getHasTokenInstructions(type: RepoType): type is InstructionAvailability {
|
||||
return type === 'github' || type === 'gitlab' || type === 'bitbucket';
|
||||
}
|
||||
|
||||
export function getRepoCommitUrl(spec?: RepositorySpec, commit?: string) {
|
||||
let url: string | undefined = undefined;
|
||||
let hasUrl = false;
|
||||
|
||||
if (!spec || !spec.type || !commit) {
|
||||
return { hasUrl, url };
|
||||
}
|
||||
|
||||
const gitType = spec.type;
|
||||
|
||||
// local repositories don't have a URL
|
||||
if (gitType !== 'local' && commit) {
|
||||
switch (gitType) {
|
||||
case 'github':
|
||||
if (spec.github?.url) {
|
||||
url = `${spec.github.url}/commit/${commit}`;
|
||||
hasUrl = true;
|
||||
}
|
||||
break;
|
||||
case 'gitlab':
|
||||
if (spec.gitlab?.url) {
|
||||
url = `${spec.gitlab.url}/-/commit/${commit}`;
|
||||
hasUrl = true;
|
||||
}
|
||||
break;
|
||||
case 'bitbucket':
|
||||
if (spec.bitbucket?.url) {
|
||||
url = `${spec.bitbucket.url}/commits/${commit}`;
|
||||
hasUrl = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return { hasUrl, url };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { BadgeColor, IconName } from '@grafana/ui';
|
||||
import { SyncStatus } from 'app/api/clients/provisioning/v0alpha1';
|
||||
|
||||
export interface RepositoryStatus {
|
||||
color: BadgeColor;
|
||||
text: string;
|
||||
icon: IconName;
|
||||
tooltip?: string;
|
||||
}
|
||||
|
||||
export const getStatusColor = (state?: SyncStatus['state']) => {
|
||||
switch (state) {
|
||||
case 'success':
|
||||
return 'green';
|
||||
case 'working':
|
||||
return 'blue';
|
||||
case 'warning':
|
||||
return 'orange';
|
||||
case 'pending':
|
||||
return 'darkgrey';
|
||||
case 'error':
|
||||
return 'red';
|
||||
default:
|
||||
return 'darkgrey';
|
||||
}
|
||||
};
|
||||
|
||||
export const getStatusIcon = (state?: SyncStatus['state']): IconName => {
|
||||
switch (state) {
|
||||
case 'success':
|
||||
return 'check';
|
||||
case 'working':
|
||||
case 'warning':
|
||||
return 'exclamation-triangle';
|
||||
case 'pending':
|
||||
return 'spinner';
|
||||
case 'error':
|
||||
return 'exclamation-triangle';
|
||||
default:
|
||||
return 'exclamation-triangle';
|
||||
}
|
||||
};
|
||||
@@ -11584,6 +11584,7 @@
|
||||
"active-jobs": "active jobs",
|
||||
"column-action": "Action",
|
||||
"column-duration": "Duration",
|
||||
"column-job-id": "Job ID",
|
||||
"column-message": "Message",
|
||||
"column-started": "Started",
|
||||
"column-status": "Status",
|
||||
@@ -11602,12 +11603,6 @@
|
||||
"settings": "Settings",
|
||||
"view": "View"
|
||||
},
|
||||
"repository-health": {
|
||||
"details": "Details:",
|
||||
"no-errors-found": "No errors found",
|
||||
"title-repository-is-healthy": "Repository is healthy",
|
||||
"title-repository-is-unhealthy": "Repository is unhealthy"
|
||||
},
|
||||
"repository-link": {
|
||||
"delete-or-move-job": {
|
||||
"compare-branch": "Compare branch",
|
||||
@@ -11622,7 +11617,7 @@
|
||||
},
|
||||
"repository-overview": {
|
||||
"checked": "Checked:",
|
||||
"finished": "Finished:",
|
||||
"finished": "Last successful pull:",
|
||||
"health": "Health",
|
||||
"healthy": "Healthy",
|
||||
"job-id": "Job ID:",
|
||||
@@ -11631,7 +11626,6 @@
|
||||
"not-available": "N/A",
|
||||
"pull-status": "Pull status",
|
||||
"resources": "Resources",
|
||||
"started": "Started:",
|
||||
"status": "Status:",
|
||||
"unhealthy": "Unhealthy",
|
||||
"view-folder": "View Folder",
|
||||
|
||||
Reference in New Issue
Block a user