ServiceAccounts: Updates the service accounts list page to look good in new top nav design (#52425)

This commit is contained in:
Torkel Ödegaard 2022-07-19 17:46:04 +02:00 committed by GitHub
parent 0142c8ccd1
commit 6483914815
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 36 deletions

View File

@ -11,6 +11,7 @@ export interface PageProps extends HTMLAttributes<HTMLDivElement> {
navId?: string;
navModel?: NavModel;
pageNav?: NavModelItem;
subTitle?: React.ReactNode;
layout?: PageLayoutType;
/** Something we can remove when we remove the old nav. */
toolbar?: React.ReactNode;

View File

@ -21,6 +21,7 @@ export const Page: PageType = ({
navId,
navModel: oldNavProp,
pageNav,
subTitle,
children,
className,
layout = PageLayoutType.Default,
@ -52,7 +53,7 @@ export const Page: PageType = ({
<div className={styles.pageContent}>
<CustomScrollbar autoHeightMin={'100%'} scrollTop={scrollTop} scrollRefCallback={scrollRef}>
<div className={styles.pageInner}>
{pageHeaderNav && <PageHeader navItem={pageHeaderNav} />}
{pageHeaderNav && <PageHeader navItem={pageHeaderNav} subTitle={subTitle} />}
{pageNav && pageNav.children && <PageTabs navItem={pageNav} />}
{children}
</div>

View File

@ -6,10 +6,12 @@ import { useStyles2 } from '@grafana/ui';
export interface Props {
navItem: NavModelItem;
subTitle?: React.ReactNode;
}
export function PageHeader({ navItem }: Props) {
export function PageHeader({ navItem, subTitle }: Props) {
const styles = useStyles2(getStyles);
const sub = subTitle ?? navItem.subTitle;
return (
<>
@ -17,7 +19,7 @@ export function PageHeader({ navItem }: Props) {
{navItem.img && <img className={styles.pageImg} src={navItem.img} alt={`logo for ${navItem.text}`} />}
{navItem.text}
</h1>
{navItem.subTitle && <div className={styles.pageSubTitle}>{navItem.subTitle}</div>}
{sub && <div className={styles.pageSubTitle}>{sub}</div>}
</>
);
}

View File

@ -4,6 +4,7 @@ import React, { useEffect, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { GrafanaTheme2, OrgRole } from '@grafana/data';
import { config } from '@grafana/runtime';
import { Alert, ConfirmModal, FilterInput, Icon, LinkButton, RadioButtonGroup, Tooltip, useStyles2 } from '@grafana/ui';
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
import { Page } from 'app/core/components/Page/Page';
@ -165,8 +166,24 @@ export const ServiceAccountsListPageUnconnected = ({
closeApiKeysMigrationInfo();
};
const docsLink = (
<a
className="external-link"
href="https://grafana.com/docs/grafana/latest/administration/service-accounts/"
target="_blank"
rel="noopener noreferrer"
>
here.
</a>
);
const subTitle = (
<span>
Service accounts and their tokens can be used to authenticate against the Grafana API. Find out more {docsLink}
</span>
);
return (
<Page navId="serviceaccounts">
<Page navId="serviceaccounts" subTitle={subTitle}>
<Page.Contents>
{apiKeysMigrated && showApiKeysMigrationInfo && (
<Alert
@ -176,32 +193,30 @@ export const ServiceAccountsListPageUnconnected = ({
onRemove={onMigrationInfoClose}
></Alert>
)}
<div className={styles.pageHeader}>
<h2>Service accounts</h2>
<div className={styles.apiKeyInfoLabel}>
<Tooltip
placement="bottom"
interactive
content={
<>
API keys are now service accounts with tokens. Find out more{' '}
<a href="https://grafana.com/docs/grafana/latest/administration/service-accounts/">here.</a>
</>
}
>
<Icon name="question-circle" />
</Tooltip>
<span>Looking for API keys?</span>
{!config.featureToggles.topnav && (
<div className={styles.pageHeader}>
<h2>Service accounts</h2>
<div className={styles.apiKeyInfoLabel}>
<Tooltip
placement="bottom"
interactive
content={<>API keys are now service accounts with tokens. Find out more {docsLink}</>}
>
<Icon name="question-circle" />
</Tooltip>
<span>Looking for API keys?</span>
</div>
</div>
)}
<div className="page-action-bar">
<div className="gf-form gf-form--grow">
<FilterInput
placeholder="Search service account by name"
value={query}
onChange={onQueryChange}
width={50}
/>
</div>
{!noServiceAccountsCreated && contextSrv.hasPermission(AccessControlAction.ServiceAccountsCreate) && (
<LinkButton href="org/serviceaccounts/create" variant="primary">
Add service account
</LinkButton>
)}
</div>
<div className={styles.filterRow}>
<FilterInput placeholder="Search service account by name" value={query} onChange={onQueryChange} width={50} />
<div className={styles.filterDelimiter}></div>
<RadioButtonGroup
options={[
{ label: 'All', value: ServiceAccountStateFilter.All },
@ -212,6 +227,11 @@ export const ServiceAccountsListPageUnconnected = ({
value={serviceAccountStateFilter}
className={styles.filter}
/>
{!noServiceAccountsCreated && contextSrv.hasPermission(AccessControlAction.ServiceAccountsCreate) && (
<LinkButton href="org/serviceaccounts/create" variant="primary">
Add service account
</LinkButton>
)}
</div>
{isLoading && <PageLoader />}
{!isLoading && noServiceAccountsCreated && (
@ -350,13 +370,6 @@ export const getStyles = (theme: GrafanaTheme2) => {
padding: ${theme.spacing(0.5)};
}
`,
filterRow: cx(
'page-action-bar',
css`
display: flex;
justifycontent: flex-end;
`
),
filterDelimiter: css`
flex-grow: 1;
`,