diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties
index b01f704ba..2556b8762 100644
--- a/backend/src/main/resources/i18n/messages.properties
+++ b/backend/src/main/resources/i18n/messages.properties
@@ -11,6 +11,7 @@
action.dashboard=Dashboard
action.logout=Logout
+action.logged-in=Logged in as {username} ({group})
action.add=Add
action.add-new=Add New
action.add-new-provider=Add a new metadata provider
diff --git a/ui/src/app/core/components/Header.js b/ui/src/app/core/components/Header.js
index ca22fe12f..01494cfea 100644
--- a/ui/src/app/core/components/Header.js
+++ b/ui/src/app/core/components/Header.js
@@ -6,13 +6,13 @@ import Navbar from 'react-bootstrap/Navbar';
import Dropdown from 'react-bootstrap/Dropdown';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faTh, faSignOutAlt, faPlusCircle, faCube, faCubes, faUsersCog } from '@fortawesome/free-solid-svg-icons';
+import { faTh, faSignOutAlt, faPlusCircle, faCube, faCubes, faUsersCog, faUser, faSpinner } from '@fortawesome/free-solid-svg-icons';
import Translate from '../../i18n/components/translate';
import { useTranslator } from '../../i18n/hooks';
import { brand } from '../../app.brand';
-import { useIsAdmin } from '../user/UserContext';
+import { useCurrentUser, useCurrentUserLoading, useIsAdmin } from '../user/UserContext';
export function Header () {
@@ -20,6 +20,9 @@ export function Header () {
const isAdmin = useIsAdmin();
+ const { username, groupId } = useCurrentUser();
+ const loading = useCurrentUserLoading();
+
return (
@@ -27,12 +30,41 @@ export function Header () {
+ {loading ?
+
+
+
+ :
+ <>
+ >
+ }
);
}
diff --git a/ui/src/app/core/user/UserContext.js b/ui/src/app/core/user/UserContext.js
index d656ac4a4..91a3ac93b 100644
--- a/ui/src/app/core/user/UserContext.js
+++ b/ui/src/app/core/user/UserContext.js
@@ -11,7 +11,7 @@ const path = '/admin/users/current';
/*eslint-disable react-hooks/exhaustive-deps*/
function UserProvider({ children }) {
- const { get, response } = useFetch(`${API_BASE_PATH}`, {
+ const { get, response, loading } = useFetch(`${API_BASE_PATH}`, {
cacheLife: 10000,
cachePolicy: 'cache-first'
});
@@ -20,18 +20,28 @@ function UserProvider({ children }) {
async function loadUser() {
const user = await get(`${path}`);
- if (response.ok) setUser(user);
+ if (response.ok) {
+ setUser(user);
+ }
}
const [user, setUser] = React.useState({});
+
+ const providerValue = React.useMemo(() => ({ user, loading }), [user, loading]);
+
return (
- {children}
+ {children}
);
}
function useCurrentUser() {
- const context = React.useContext(UserContext);
- return context;
+ const { user } = React.useContext(UserContext);
+ return user;
+}
+
+function useCurrentUserLoading() {
+ const { loading } = React.useContext(UserContext);
+ return loading;
}
function useIsAdmin() {
@@ -51,4 +61,4 @@ function useIsAdminOrInGroup() {
}
-export { UserContext, UserProvider, Consumer as UserConsumer, useCurrentUser, useIsAdmin, useIsAdminOrInGroup };
\ No newline at end of file
+export { UserContext, UserProvider, Consumer as UserConsumer, useCurrentUser, useIsAdmin, useIsAdminOrInGroup, useCurrentUserLoading };
\ No newline at end of file
diff --git a/ui/src/app/dashboard/view/Dashboard.js b/ui/src/app/dashboard/view/Dashboard.js
index d7892f028..2c9ce027b 100644
--- a/ui/src/app/dashboard/view/Dashboard.js
+++ b/ui/src/app/dashboard/view/Dashboard.js
@@ -11,10 +11,12 @@ import { SourcesTab } from './SourcesTab';
import { ProvidersTab } from './ProvidersTab';
import { AdminTab } from './AdminTab';
import { ActionsTab } from './ActionsTab';
-import { useIsAdmin } from '../../core/user/UserContext';
+import { useCurrentUserLoading, useIsAdmin } from '../../core/user/UserContext';
import useFetch from 'use-http';
import API_BASE_PATH from '../../App.constant';
import { useNonAdminSources } from '../../metadata/hooks/api';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faSpinner } from '@fortawesome/free-solid-svg-icons';
export function Dashboard () {
@@ -22,6 +24,8 @@ export function Dashboard () {
const isAdmin = useIsAdmin();
+ const loading = useCurrentUserLoading();
+
const [actions, setActions] = React.useState(0);
const [users, setUsers] = React.useState([]);
const [sources, setSources] = React.useState([]);
@@ -58,8 +62,12 @@ export function Dashboard () {
return (
-
-
);
}
diff --git a/ui/src/app/metadata/wizard/MetadataProviderTypeSelector.js b/ui/src/app/metadata/wizard/MetadataProviderTypeSelector.js
index 1312eda20..5a091b2d2 100644
--- a/ui/src/app/metadata/wizard/MetadataProviderTypeSelector.js
+++ b/ui/src/app/metadata/wizard/MetadataProviderTypeSelector.js
@@ -1,5 +1,5 @@
import React from 'react';
-import { faArrowCircleRight } from '@fortawesome/free-solid-svg-icons';
+import { faArrowCircleRight, faSpinner } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useForm } from 'react-hook-form';
@@ -14,7 +14,7 @@ export function MetadataProviderTypeSelector({ type, types = [], children}) {
const translator = useTranslator();
- const { data = [] } = useMetadataProviders({cachePolicy: 'no-cache'}, []);
+ const { data = [], loading } = useMetadataProviders({cachePolicy: 'no-cache'}, []);
const [showSelector, setShowSelector] = React.useState(true);
@@ -94,13 +94,15 @@ export function MetadataProviderTypeSelector({ type, types = [], children}) {
{errors?.name?.required && }
-
-
+
+
+ {loading && }
+
-
+
{types.map(t => )}
diff --git a/ui/src/theme/project/index.scss b/ui/src/theme/project/index.scss
index 48b875785..5402b2c96 100644
--- a/ui/src/theme/project/index.scss
+++ b/ui/src/theme/project/index.scss
@@ -43,6 +43,18 @@ nav.fixed-top {
color: #00355f;
}
+.border-md-right {
+ border-right: 1px solid silver;
+}
+
+@media (max-width: 768px) {
+
+ .border-md-right {
+ border-right: none;
+ }
+
+}
+
footer {
background-color: $white;
padding: 0 20px;