diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index 579b88053f..0e30c15254 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -31,8 +31,9 @@ import { SidebarDivider, SidebarSearchField, SidebarSpace, - SidebarUserBadge, + SidebarUserSettings, SidebarThemeToggle, + SidebarPinButton, } from '@backstage/core'; import { NavLink } from 'react-router-dom'; @@ -90,7 +91,8 @@ const Root: FC<{}> = ({ children }) => ( - + + {children} diff --git a/packages/core/src/layout/Sidebar/Items.tsx b/packages/core/src/layout/Sidebar/Items.tsx index ddd71cc189..0a875c9035 100644 --- a/packages/core/src/layout/Sidebar/Items.tsx +++ b/packages/core/src/layout/Sidebar/Items.tsx @@ -59,6 +59,7 @@ const useStyles = makeStyles(theme => { fontWeight: 'bold', whiteSpace: 'nowrap', lineHeight: 1.0, + flex: '3 1 auto', }, iconContainer: { boxSizing: 'border-box', @@ -84,6 +85,11 @@ const useStyles = makeStyles(theme => { searchContainer: { width: drawerWidthOpen - iconContainerWidth, }, + secondaryAction: { + width: theme.spacing(6), + textAlign: 'center', + marginRight: theme.spacing(1), + }, selected: { '&$root': { borderLeft: `solid ${selectedIndicatorWidth}px #9BF0E1`, @@ -148,7 +154,6 @@ export const SidebarItem: FC = ({ ); } - return ( = ({ {text} )} - {children} +
{children}
); }; diff --git a/packages/core/src/layout/Sidebar/LoggedUserBadge.tsx b/packages/core/src/layout/Sidebar/LoggedUserBadge.tsx deleted file mode 100644 index d0c3dc62c2..0000000000 --- a/packages/core/src/layout/Sidebar/LoggedUserBadge.tsx +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React, { FC, useState, useEffect } from 'react'; -import { makeStyles, Theme } from '@material-ui/core/styles'; -import { sidebarConfig } from './config'; -import { - Avatar, - ListItem, - ListItemAvatar, - ListItemText, - Popover, - List, - ListItemIcon, - ListItemSecondaryAction, - IconButton, - Tooltip, - Typography, -} from '@material-ui/core'; -import { blueGrey } from '@material-ui/core/colors'; -import { useSetState } from 'react-use'; -import { Skeleton } from '@material-ui/lab'; -import { useApi, googleAuthApiRef, ProfileInfo } from '@backstage/core-api'; -import LogoutIcon from '@material-ui/icons/PowerSettingsNew'; -import ControlPointIcon from '@material-ui/icons/ControlPoint'; -import AccountCircleIcon from '@material-ui/icons/AccountCircle'; - -const useStyles = makeStyles(theme => { - const { drawerWidthOpen, userBadgeDiameter } = sidebarConfig; - return { - root: { - width: drawerWidthOpen, - display: 'flex', - alignItems: 'center', - paddingLeft: 18, - paddingTop: 14, - paddingBottom: 14, - color: '#b5b5b5', - }, - avatar: { - width: userBadgeDiameter, - height: userBadgeDiameter, - marginRight: 8, - }, - purple: { - color: theme.palette.getContrastText(blueGrey[500]), - backgroundColor: blueGrey[500], - }, - listItemText: { - overflow: 'hidden', - textOverflow: 'ellipsis', - }, - }; -}); - -const SessionListItem: FC<{ - classes: any; - loading: boolean; - title: string; - icon: any; - user: any; - onSignIn: Function; - onSignOut: Function; -}> = ({ - classes, - loading, - title, - icon, - user, - onSignIn, - onSignOut, - ...props -}) => { - if (loading) { - return ( - - - - - } - secondary={} - /> - - - - - - - ); - } - - // TODO: Not functional yet to sign in from the sidebar - if (!user) { - return ( - - {icon} - - - - onSignIn()}> - - - - - - ); - } - - const { id, avatarUrl, avatarAlt } = user; - - return ( - - - - {avatarAlt && avatarAlt[0].toUpperCase()} - - - - {id} - - } - secondary={title} - /> - - - onSignOut()}> - - - - - - ); -}; - -const useGoogleLoginState = (open: boolean) => { - const googleAuth = useApi(googleAuthApiRef); - const [loading, setLoading] = useState(true); - const [profile, setProfile] = useState(); - - useEffect(() => { - let didCancel = false; - - if (open) { - googleAuth.getProfile().then(_profile => { - if (!didCancel) { - setProfile(_profile); - setLoading(false); - } - }); - } - - return () => { - didCancel = true; - }; - }, [open, googleAuth]); - - if (loading) { - return { loading: true }; - } - return { loading: false, isLoggedIn: !!profile, profile }; -}; - -type Props = { - email: string; - imageUrl?: string; - name?: string; - collapsedMode?: boolean; -}; - -export const LoggedUserBadge: FC = ({ - imageUrl, - name, - email, - collapsedMode = false, -}) => { - const [state, setState] = useSetState({ - open: false, - anchorEl: null, - }); - const googleAuth = useApi(googleAuthApiRef); - const googleLogin = useGoogleLoginState(state.open); - - const handleOpen = (event: { - preventDefault: () => void; - currentTarget: any; - }) => { - // This prevents ghost click. - event.preventDefault(); - setState({ - open: true, - anchorEl: event.currentTarget, - }); - }; - - const handleClose = () => { - setState({ - open: false, - }); - }; - - const handleGoogleSignIn = () => { - googleAuth.getIdToken(); - handleClose(); - }; - - const handleGoogleSignOut = () => { - googleAuth.logout(); - }; - - const classes = useStyles(); - const avatarFallback = email.charAt(0).toUpperCase() + email.slice(1); - const emailTrimmed = email.split('@')[0]; - const displayEmail = - emailTrimmed.charAt(0).toUpperCase() + emailTrimmed.slice(1); - const displayName = name ?? displayEmail; - - return ( - <> - - - - {imageUrl ? ( - - ) : ( - - {avatarFallback[0]} - - )} - - {!collapsedMode && ( - - {displayName} - - } - /> - )} - - - - - - - - - ); -}; diff --git a/packages/core/src/layout/Sidebar/UserBadge.tsx b/packages/core/src/layout/Sidebar/PinButton.tsx similarity index 61% rename from packages/core/src/layout/Sidebar/UserBadge.tsx rename to packages/core/src/layout/Sidebar/PinButton.tsx index d3e02d26cc..8c52eeb24d 100644 --- a/packages/core/src/layout/Sidebar/UserBadge.tsx +++ b/packages/core/src/layout/Sidebar/PinButton.tsx @@ -14,35 +14,32 @@ * limitations under the License. */ -import React, { FC, useContext, useEffect, useState } from 'react'; +import React, { FC, useContext } from 'react'; import { makeStyles } from '@material-ui/core'; -import AccountCircleIcon from '@material-ui/icons/AccountCircle'; -import { SidebarContext } from './config'; -import { SidebarItem } from './Items'; -import { LoggedUserBadge } from './LoggedUserBadge'; import DoubleArrowIcon from '@material-ui/icons/DoubleArrow'; +import { SidebarContext } from './config'; import { BackstageTheme } from '@backstage/theme'; import { SidebarPinStateContext } from './Page'; -import { useApi, googleAuthApiRef, ProfileInfo } from '@backstage/core-api'; const ARROW_BUTTON_SIZE = 20; const useStyles = makeStyles(theme => { return { root: { position: 'relative', + alignSelf: 'stretch', }, arrowButtonWrapper: { position: 'absolute', right: 0, width: ARROW_BUTTON_SIZE, height: ARROW_BUTTON_SIZE, - top: `calc(50% - ${ARROW_BUTTON_SIZE / 2}px)`, + top: -(theme.spacing(6) + ARROW_BUTTON_SIZE) / 2, display: 'flex', alignItems: 'center', justifyContent: 'center', borderRadius: '2px 0px 0px 2px', - background: theme.palette.pinSidebarButton.icon, - color: theme.palette.pinSidebarButton.background, + background: theme.palette.pinSidebarButton.background, + color: theme.palette.pinSidebarButton.icon, border: 'none', outline: 'none', cursor: 'pointer', @@ -53,37 +50,15 @@ const useStyles = makeStyles(theme => { }; }); -export const SidebarUserBadge: FC<{}> = () => { +export const SidebarPinButton: FC<{}> = () => { const { isOpen } = useContext(SidebarContext); const { isPinned, toggleSidebarPinState } = useContext( SidebarPinStateContext, ); const classes = useStyles({ isPinned }); - const googleAuth = useApi(googleAuthApiRef); - const [profile, setProfile] = useState(); - - useEffect(() => { - // TODO(soapraj): How to observe if the user is logged in - // TODO(soapraj): List all the providers supported by the app and let user log in from here - googleAuth.getProfile({ optional: true }).then(googleProfile => { - setProfile(googleProfile); - }); - }, [googleAuth]); return (
- {profile ? ( - <> - - - ) : ( - - )} {isOpen && (