From d4f479b1c2bd4bb67d5e69f792b503f375d6dfc9 Mon Sep 17 00:00:00 2001 From: Peter Amstutz Date: Tue, 12 Feb 2019 16:24:56 -0500 Subject: [PATCH] 14720: Add UUID to My account page. Layout fixes. Makes a number of UI improvements related to logging in as a federated user. * My account page includes UUID * Replace "identityUrl" in user model with "username" * Rework layout of "My Account" page to reflow properly when view is narrow * Rework layout of login page, add scrolling when view is short Arvados-DCO-1.1-Signed-off-by: Peter Amstutz --- src/models/user.ts | 5 +- src/services/auth-service/auth-service.ts | 16 +- src/store/advanced-tab/advanced-tab.tsx | 6 +- src/store/auth/auth-action-session.ts | 2 +- src/store/auth/auth-action.test.ts | 12 +- src/store/auth/auth-reducer.test.ts | 10 +- .../main-app-bar/account-menu.tsx | 7 +- .../user-dialog/attributes-dialog.tsx | 6 +- src/views/login-panel/login-panel.tsx | 6 +- .../my-account-panel-root.tsx | 179 +++++++++--------- 10 files changed, 126 insertions(+), 123 deletions(-) diff --git a/src/models/user.ts b/src/models/user.ts index a7b8458b..6477dc53 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -20,7 +20,7 @@ export interface User { lastName: string; uuid: string; ownerUuid: string; - identityUrl: string; + username: string; prefs: UserPrefs; isAdmin: boolean; } @@ -35,10 +35,9 @@ export interface UserResource extends Resource { username: string; firstName: string; lastName: string; - identityUrl: string; isAdmin: boolean; prefs: UserPrefs; defaultOwnerUuid: string; isActive: boolean; writableBy: string[]; -} \ No newline at end of file +} diff --git a/src/services/auth-service/auth-service.ts b/src/services/auth-service/auth-service.ts index fff7d577..11e3e776 100644 --- a/src/services/auth-service/auth-service.ts +++ b/src/services/auth-service/auth-service.ts @@ -17,7 +17,7 @@ export const USER_LAST_NAME_KEY = 'userLastName'; export const USER_UUID_KEY = 'userUuid'; export const USER_OWNER_UUID_KEY = 'userOwnerUuid'; export const USER_IS_ADMIN = 'isAdmin'; -export const USER_IDENTITY_URL = 'identityUrl'; +export const USER_USERNAME = 'username'; export const USER_PREFS = 'prefs'; export interface UserDetailsResponse { @@ -27,7 +27,7 @@ export interface UserDetailsResponse { uuid: string; owner_uuid: string; is_admin: boolean; - identity_url: string; + username: string; prefs: UserPrefs; } @@ -69,11 +69,11 @@ export class AuthService { const uuid = this.getUuid(); const ownerUuid = this.getOwnerUuid(); const isAdmin = this.getIsAdmin(); - const identityUrl = localStorage.getItem(USER_IDENTITY_URL); + const username = localStorage.getItem(USER_USERNAME); const prefs = JSON.parse(localStorage.getItem(USER_PREFS) || '{"profile": {}}'); - return email && firstName && lastName && uuid && ownerUuid && identityUrl && prefs - ? { email, firstName, lastName, uuid, ownerUuid, isAdmin, identityUrl, prefs } + return email && firstName && lastName && uuid && ownerUuid && username && prefs + ? { email, firstName, lastName, uuid, ownerUuid, isAdmin, username, prefs } : undefined; } @@ -84,7 +84,7 @@ export class AuthService { localStorage.setItem(USER_UUID_KEY, user.uuid); localStorage.setItem(USER_OWNER_UUID_KEY, user.ownerUuid); localStorage.setItem(USER_IS_ADMIN, JSON.stringify(user.isAdmin)); - localStorage.setItem(USER_IDENTITY_URL, user.identityUrl); + localStorage.setItem(USER_USERNAME, user.username); localStorage.setItem(USER_PREFS, JSON.stringify(user.prefs)); } @@ -95,7 +95,7 @@ export class AuthService { localStorage.removeItem(USER_UUID_KEY); localStorage.removeItem(USER_OWNER_UUID_KEY); localStorage.removeItem(USER_IS_ADMIN); - localStorage.removeItem(USER_IDENTITY_URL); + localStorage.removeItem(USER_USERNAME); localStorage.removeItem(USER_PREFS); } @@ -125,7 +125,7 @@ export class AuthService { uuid: resp.data.uuid, ownerUuid: resp.data.owner_uuid, isAdmin: resp.data.is_admin, - identityUrl: resp.data.identity_url, + username: resp.data.username, prefs }; }) diff --git a/src/store/advanced-tab/advanced-tab.tsx b/src/store/advanced-tab/advanced-tab.tsx index 3d10e54a..b1f0f983 100644 --- a/src/store/advanced-tab/advanced-tab.tsx +++ b/src/store/advanced-tab/advanced-tab.tsx @@ -554,7 +554,7 @@ const keepServiceApiResponse = (apiResponse: KeepServiceResource) => { const userApiResponse = (apiResponse: UserResource) => { const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, - email, firstName, lastName, identityUrl, isActive, isAdmin, prefs, defaultOwnerUuid, username + email, firstName, lastName, username, isActive, isAdmin, prefs, defaultOwnerUuid, } = apiResponse; const response = ` "uuid": "${uuid}", @@ -566,7 +566,7 @@ const userApiResponse = (apiResponse: UserResource) => { "email": "${email}", "first_name": "${firstName}", "last_name": "${stringify(lastName)}", -"identity_url": "${identityUrl}", +"username": "${username}", "is_active": "${isActive}, "is_admin": "${isAdmin}, "prefs": "${stringifyObject(prefs)}, @@ -646,4 +646,4 @@ const linkApiResponse = (apiResponse: LinkResource) => { "properties": "${JSON.stringify(properties, null, 2)}"`; return {'{'} {response} {'\n'} {'}'}; -}; \ No newline at end of file +}; diff --git a/src/store/auth/auth-action-session.ts b/src/store/auth/auth-action-session.ts index b32e2050..986230ed 100644 --- a/src/store/auth/auth-action-session.ts +++ b/src/store/auth/auth-action-session.ts @@ -92,7 +92,7 @@ const clusterLogin = async (clusterId: string, baseUrl: string, activeSession: S ownerUuid: user.owner_uuid, email: user.email, isAdmin: user.is_admin, - identityUrl: user.identity_url, + username: user.username, prefs: user.prefs }, token: saltedToken diff --git a/src/store/auth/auth-action.test.ts b/src/store/auth/auth-action.test.ts index e5775a49..2e36b107 100644 --- a/src/store/auth/auth-action.test.ts +++ b/src/store/auth/auth-action.test.ts @@ -11,7 +11,7 @@ import { USER_LAST_NAME_KEY, USER_OWNER_UUID_KEY, USER_UUID_KEY, - USER_IS_ADMIN, USER_IDENTITY_URL, USER_PREFS + USER_IS_ADMIN, USER_USERNAME, USER_PREFS } from "~/services/auth-service/auth-service"; import 'jest-localstorage-mock'; @@ -25,8 +25,8 @@ describe('auth-actions', () => { let reducer: (state: AuthState | undefined, action: AuthAction) => any; let store: RootStore; const actions: ApiActions = { - progressFn: (id: string, working: boolean) => {}, - errorFn: (id: string, message: string) => {} + progressFn: (id: string, working: boolean) => { }, + errorFn: (id: string, message: string) => { } }; beforeEach(() => { @@ -42,7 +42,7 @@ describe('auth-actions', () => { localStorage.setItem(USER_FIRST_NAME_KEY, "John"); localStorage.setItem(USER_LAST_NAME_KEY, "Doe"); localStorage.setItem(USER_UUID_KEY, "uuid"); - localStorage.setItem(USER_IDENTITY_URL, "identityUrl"); + localStorage.setItem(USER_USERNAME, "username"); localStorage.setItem(USER_PREFS, JSON.stringify({})); localStorage.setItem(USER_OWNER_UUID_KEY, "ownerUuid"); localStorage.setItem(USER_IS_ADMIN, JSON.stringify("false")); @@ -83,7 +83,7 @@ describe('auth-actions', () => { lastName: "Doe", uuid: "uuid", ownerUuid: "ownerUuid", - identityUrl: "identityUrl", + username: "username", prefs: {}, isAdmin: false } @@ -111,5 +111,3 @@ describe('auth-actions', () => { }); */ }); - - diff --git a/src/store/auth/auth-reducer.test.ts b/src/store/auth/auth-reducer.test.ts index 773f9f82..f527edec 100644 --- a/src/store/auth/auth-reducer.test.ts +++ b/src/store/auth/auth-reducer.test.ts @@ -13,8 +13,8 @@ import { ApiActions } from "~/services/api/api-actions"; describe('auth-reducer', () => { let reducer: (state: AuthState | undefined, action: AuthAction) => any; const actions: ApiActions = { - progressFn: (id: string, working: boolean) => {}, - errorFn: (id: string, message: string) => {} + progressFn: (id: string, working: boolean) => { }, + errorFn: (id: string, message: string) => { } }; beforeAll(() => { @@ -30,7 +30,7 @@ describe('auth-reducer', () => { lastName: "Doe", uuid: "uuid", ownerUuid: "ownerUuid", - identityUrl: "identityUrl", + username: "username", prefs: {}, isAdmin: false }; @@ -64,7 +64,7 @@ describe('auth-reducer', () => { lastName: "Doe", uuid: "uuid", ownerUuid: "ownerUuid", - identityUrl: "identityUrl", + username: "username", prefs: {}, isAdmin: false }; @@ -80,7 +80,7 @@ describe('auth-reducer', () => { lastName: "Doe", uuid: "uuid", ownerUuid: "ownerUuid", - identityUrl: "identityUrl", + username: "username", prefs: {}, isAdmin: false } diff --git a/src/views-components/main-app-bar/account-menu.tsx b/src/views-components/main-app-bar/account-menu.tsx index b50ee336..2aec77e2 100644 --- a/src/views-components/main-app-bar/account-menu.tsx +++ b/src/views-components/main-app-bar/account-menu.tsx @@ -3,7 +3,7 @@ // SPDX-License-Identifier: AGPL-3.0 import * as React from "react"; -import { MenuItem } from "@material-ui/core"; +import { MenuItem, Divider } from "@material-ui/core"; import { User, getUserFullname } from "~/models/user"; import { DropdownMenu } from "~/components/dropdown-menu/dropdown-menu"; import { UserPanelIcon } from "~/components/icon/icon"; @@ -37,8 +37,8 @@ export const AccountMenu = connect(mapStateToProps)( id="account-menu" title="Account Management" key={currentRoute}> - - {getUserFullname(user)} ({user.uuid.substr(0, 5)}) + + {getUserFullname(user)} dispatch(openUserVirtualMachines())}>Virtual Machines {!user.isAdmin && dispatch(openRepositoriesPanel())}>Repositories} @@ -46,6 +46,7 @@ export const AccountMenu = connect(mapStateToProps)( dispatch(navigateToSshKeysUser)}>Ssh Keys dispatch(navigateToSiteManager)}>Site Manager dispatch(navigateToMyAccount)}>My account + dispatch(logout())}>Logout : null); diff --git a/src/views-components/user-dialog/attributes-dialog.tsx b/src/views-components/user-dialog/attributes-dialog.tsx index 11594f5e..67b267ae 100644 --- a/src/views-components/user-dialog/attributes-dialog.tsx +++ b/src/views-components/user-dialog/attributes-dialog.tsx @@ -61,7 +61,7 @@ export const UserAttributesDialog = compose( ); const attributes = (user: UserResource, classes: any) => { - const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, firstName, lastName, href, identityUrl, username } = user; + const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, firstName, lastName, href, username } = user; return ( @@ -75,7 +75,7 @@ const attributes = (user: UserResource, classes: any) => { {modifiedByClientUuid && Modified by client uuid} {uuid && uuid} {href && Href} - {identityUrl && Identity url} + {username && Username} {username && Username} @@ -88,7 +88,7 @@ const attributes = (user: UserResource, classes: any) => { {modifiedByClientUuid} {uuid} {href} - {identityUrl} + {username} {username} diff --git a/src/views/login-panel/login-panel.tsx b/src/views/login-panel/login-panel.tsx index 12c7d6c7..eac4034b 100644 --- a/src/views/login-panel/login-panel.tsx +++ b/src/views/login-panel/login-panel.tsx @@ -61,7 +61,9 @@ export const LoginPanel = withStyles(styles)( homeCluster: state.auth.homeCluster, uuidPrefix: state.auth.localCluster }))(({ classes, dispatch, remoteHosts, homeCluster, uuidPrefix }: LoginPanelProps) => - + Welcome to the Arvados Workbench @@ -98,5 +100,5 @@ export const LoginPanel = withStyles(styles)( - + )); diff --git a/src/views/my-account-panel/my-account-panel-root.tsx b/src/views/my-account-panel/my-account-panel-root.tsx index 819a16a4..e728c4eb 100644 --- a/src/views/my-account-panel/my-account-panel-root.tsx +++ b/src/views/my-account-panel/my-account-panel-root.tsx @@ -19,7 +19,7 @@ import { } from '@material-ui/core'; import { ArvadosTheme } from '~/common/custom-theme'; import { User } from "~/models/user"; -import { MY_ACCOUNT_VALIDATION} from "~/validators/validators"; +import { MY_ACCOUNT_VALIDATION } from "~/validators/validators"; type CssRules = 'root' | 'gridItem' | 'label' | 'title' | 'actions'; @@ -45,7 +45,7 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ } }); -export interface MyAccountPanelRootActionProps {} +export interface MyAccountPanelRootActionProps { } export interface MyAccountPanelRootDataProps { isPristine: boolean; @@ -54,13 +54,13 @@ export interface MyAccountPanelRootDataProps { } const RoleTypes = [ - {key: 'Bio-informatician', value: 'Bio-informatician'}, - {key: 'Data Scientist', value: 'Data Scientist'}, - {key: 'Analyst', value: 'Analyst'}, - {key: 'Researcher', value: 'Researcher'}, - {key: 'Software Developer', value: 'Software Developer'}, - {key: 'System Administrator', value: 'System Administrator'}, - {key: 'Other', value: 'Other'} + { key: 'Bio-informatician', value: 'Bio-informatician' }, + { key: 'Data Scientist', value: 'Data Scientist' }, + { key: 'Analyst', value: 'Analyst' }, + { key: 'Researcher', value: 'Researcher' }, + { key: 'Software Developer', value: 'Software Developer' }, + { key: 'System Administrator', value: 'System Administrator' }, + { key: 'Other', value: 'Other' } ]; type MyAccountPanelRootProps = InjectedFormProps & MyAccountPanelRootDataProps & WithStyles; @@ -69,93 +69,96 @@ export const MyAccountPanelRoot = withStyles(styles)( ({ classes, isValid, handleSubmit, reset, isPristine, invalid, submitting }: MyAccountPanelRootProps) => { return - User profile
- - - - - - - - - - - - - - - - - - - Role - - + + + + - - - - - - - - - + + - + + + + + + + + + + + + + + + + + Role + + + + + + + Save changes + - -
-
;} -); \ No newline at end of file + + + ; + } +); -- 2.30.2