Navigation: Use new page layout in Service accounts item page (#54200)

* use navId, pageNav and update alignments of service account page

* Fixing item header when feature is disabled

* Fix orgs item page

* Minor tweak to subtitle for service account item page

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
Leo 2022-08-25 13:11:30 +02:00 committed by GitHub
parent 552d3fec8d
commit 9f8cb17b01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 29 additions and 78 deletions

View File

@ -2,7 +2,7 @@
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import React from 'react'; import React from 'react';
import { GrafanaTheme2, NavModel, NavModelItem } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime'; import { config } from '@grafana/runtime';
import { CustomScrollbar, useStyles2 } from '@grafana/ui'; import { CustomScrollbar, useStyles2 } from '@grafana/ui';
@ -32,7 +32,7 @@ export const OldPage: PageType = ({
usePageTitle(navModel, pageNav); usePageTitle(navModel, pageNav);
const pageHeaderNav = getPageHeaderNav(navModel, pageNav); const pageHeaderNav = pageNav ?? navModel?.main;
return ( return (
<div className={cx(styles.wrapper, className)}> <div className={cx(styles.wrapper, className)}>
@ -59,14 +59,6 @@ export const OldPage: PageType = ({
); );
}; };
function getPageHeaderNav(navModel?: NavModel, pageNav?: NavModelItem): NavModelItem | undefined {
if (pageNav?.children && pageNav.children.length > 0) {
return pageNav;
}
return navModel?.main;
}
OldPage.Header = PageHeader; OldPage.Header = PageHeader;
OldPage.Contents = PageContents; OldPage.Contents = PageContents;
OldPage.OldNavOnly = OldNavOnly; OldPage.OldNavOnly = OldNavOnly;

View File

@ -68,6 +68,9 @@ export default function AdminEditOrgPage({ match }: Props) {
const pageNav: NavModelItem = { const pageNav: NavModelItem = {
text: orgState?.value?.name ?? '', text: orgState?.value?.name ?? '',
icon: 'shield',
breadcrumbs: [{ title: 'Orgs', url: 'admin/orgs' }],
subTitle: 'Manage settings and user roles for an organization.',
}; };
return ( return (

View File

@ -105,12 +105,16 @@ export class UserAdminPage extends PureComponent<Props> {
const isLDAPUser = user && user.isExternal && user.authLabels && user.authLabels.includes('LDAP'); const isLDAPUser = user && user.isExternal && user.authLabels && user.authLabels.includes('LDAP');
const canReadSessions = contextSrv.hasPermission(AccessControlAction.UsersAuthTokenList); const canReadSessions = contextSrv.hasPermission(AccessControlAction.UsersAuthTokenList);
const canReadLDAPStatus = contextSrv.hasPermission(AccessControlAction.LDAPStatusRead); const canReadLDAPStatus = contextSrv.hasPermission(AccessControlAction.LDAPStatusRead);
const pageNav: NavModelItem = { const pageNav: NavModelItem = {
text: user?.login ?? '', text: user?.login ?? '',
icon: 'shield',
breadcrumbs: [{ title: 'Users', url: 'admin/users' }],
subTitle: 'Manage settings for an individual user.',
}; };
return ( return (
<Page navId="global-users" pageNav={pageNav} subTitle="Manage settings for an individual user."> <Page navId="global-users" pageNav={pageNav}>
<Page.Contents isLoading={isLoading}> <Page.Contents isLoading={isLoading}>
{user && ( {user && (
<> <>

View File

@ -1,9 +1,8 @@
import { css } from '@emotion/css';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { getTimeZone, GrafanaTheme2 } from '@grafana/data'; import { getTimeZone, NavModelItem } from '@grafana/data';
import { Button, ConfirmModal, IconButton, useStyles2 } from '@grafana/ui'; import { Button, ConfirmModal, HorizontalGroup } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page'; import { Page } from 'app/core/components/Page/Page';
import { contextSrv } from 'app/core/core'; import { contextSrv } from 'app/core/core';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types'; import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
@ -71,7 +70,7 @@ export const ServiceAccountPageUnconnected = ({
const [isTokenModalOpen, setIsTokenModalOpen] = useState(false); const [isTokenModalOpen, setIsTokenModalOpen] = useState(false);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [isDisableModalOpen, setIsDisableModalOpen] = useState(false); const [isDisableModalOpen, setIsDisableModalOpen] = useState(false);
const styles = useStyles2(getStyles);
const serviceAccountId = parseInt(match.params.id, 10); const serviceAccountId = parseInt(match.params.id, 10);
const tokenActionsDisabled = const tokenActionsDisabled =
!contextSrv.hasPermission(AccessControlAction.ServiceAccountsWrite) || serviceAccount.isDisabled; !contextSrv.hasPermission(AccessControlAction.ServiceAccountsWrite) || serviceAccount.isDisabled;
@ -83,6 +82,13 @@ export const ServiceAccountPageUnconnected = ({
false false
); );
const pageNav: NavModelItem = {
text: serviceAccount.name,
img: serviceAccount.avatarUrl,
breadcrumbs: [{ title: 'Service accounts', url: 'org/serviceaccounts' }],
subTitle: 'Manage settings for an individual service account.',
};
useEffect(() => { useEffect(() => {
loadServiceAccount(serviceAccountId); loadServiceAccount(serviceAccountId);
loadServiceAccountTokens(serviceAccountId); loadServiceAccountTokens(serviceAccountId);
@ -130,24 +136,11 @@ export const ServiceAccountPageUnconnected = ({
}; };
return ( return (
<Page navId="serviceaccounts"> <Page navId="serviceaccounts" pageNav={pageNav}>
<Page.Contents isLoading={isLoading}> <Page.Contents isLoading={isLoading}>
{serviceAccount && ( <div>
<div className={styles.headerContainer}> {serviceAccount && (
<a href="org/serviceaccounts"> <HorizontalGroup spacing="md" height="auto" justify="flex-end">
<IconButton
size="xxl"
variant="secondary"
name="arrow-left"
className={styles.returnButton}
aria-label="Back to service accounts list"
/>
</a>
<div className={styles.headerAvatar}>
<img src={serviceAccount.avatarUrl} alt={`Avatar for user ${serviceAccount.name}`} />
</div>
<h3>{serviceAccount.name}</h3>
<div className={styles.buttonRow}>
<Button <Button
type={'button'} type={'button'}
variant="destructive" variant="destructive"
@ -175,10 +168,8 @@ export const ServiceAccountPageUnconnected = ({
Disable service account Disable service account
</Button> </Button>
)} )}
</div> </HorizontalGroup>
</div> )}
)}
<div className={styles.pageBody}>
{serviceAccount && ( {serviceAccount && (
<ServiceAccountProfile <ServiceAccountProfile
serviceAccount={serviceAccount} serviceAccount={serviceAccount}
@ -187,12 +178,12 @@ export const ServiceAccountPageUnconnected = ({
onChange={onProfileChange} onChange={onProfileChange}
/> />
)} )}
<div className={styles.tokensListHeader}> <HorizontalGroup justify="space-between" height="auto">
<h3>Tokens</h3> <h3>Tokens</h3>
<Button onClick={() => setIsTokenModalOpen(true)} disabled={tokenActionsDisabled}> <Button onClick={() => setIsTokenModalOpen(true)} disabled={tokenActionsDisabled}>
Add service account token Add service account token
</Button> </Button>
</div> </HorizontalGroup>
{tokens && ( {tokens && (
<ServiceAccountTokensTable <ServiceAccountTokensTable
tokens={tokens} tokens={tokens}
@ -203,6 +194,7 @@ export const ServiceAccountPageUnconnected = ({
)} )}
{canReadPermissions && <ServiceAccountPermissions serviceAccount={serviceAccount} />} {canReadPermissions && <ServiceAccountPermissions serviceAccount={serviceAccount} />}
</div> </div>
<ConfirmModal <ConfirmModal
isOpen={isDeleteModalOpen} isOpen={isDeleteModalOpen}
title="Delete service account" title="Delete service account"
@ -231,44 +223,4 @@ export const ServiceAccountPageUnconnected = ({
); );
}; };
const getStyles = (theme: GrafanaTheme2) => {
return {
headerContainer: css`
display: flex;
margin-bottom: ${theme.spacing(2)};
align-items: center;
h3 {
margin-bottom: ${theme.spacing(0.5)};
flex-grow: 1;
}
`,
headerAvatar: css`
margin-right: ${theme.spacing(1)};
margin-bottom: ${theme.spacing(0.6)};
img {
width: 25px;
height: 25px;
border-radius: 50%;
}
`,
returnButton: css`
margin-right: ${theme.spacing(1)};
`,
buttonRow: css`
> * {
margin-right: ${theme.spacing(2)};
}
`,
pageBody: css`
padding-left: ${theme.spacing(5.5)};
`,
tokensListHeader: css`
display: flex;
justify-content: space-between;
align-items: center;
`,
};
};
export const ServiceAccountPage = connector(ServiceAccountPageUnconnected); export const ServiceAccountPage = connector(ServiceAccountPageUnconnected);