Added link to admin page (#2068)

* Added link to admin page

* Updated version

* Updated changelog
main
Boris Sekachev 6 years ago committed by GitHub
parent 1907b7924a
commit 18cdcd5daa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [Datumaro] Dataset statistics (<https://github.com/opencv/cvat/pull/1668>)
- Ability to change label color in tasks and predefined labels (<https://github.com/opencv/cvat/pull/2014>)
- [Datumaro] Multi-dataset merge (https://github.com/opencv/cvat/pull/1695)
- Link to django admin page from UI (<https://github.com/opencv/cvat/pull/2068>)
### Changed
- Shape coordinates are rounded to 2 digits in dumped annotations (<https://github.com/opencv/cvat/pull/1970>)

@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "1.8.0",
"version": "1.8.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "1.8.0",
"version": "1.8.1",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {

@ -21,7 +21,7 @@ import ModelsPageContainer from 'containers/models-page/models-page';
import AnnotationPageContainer from 'containers/annotation-page/annotation-page';
import LoginPageContainer from 'containers/login-page/login-page';
import RegisterPageContainer from 'containers/register-page/register-page';
import HeaderContainer from 'containers/header/header';
import Header from 'components/header/header';
import { customWaViewHit } from 'utils/enviroment';
import getCore from 'cvat-core-wrapper';
@ -272,7 +272,7 @@ class CVATApplication extends React.PureComponent<CVATAppProps & RouteComponentP
return (
<GlobalErrorBoundary>
<Layout>
<HeaderContainer> </HeaderContainer>
<Header />
<Layout.Content style={{ height: '100%' }}>
<ShorcutsDialog />
<GlobalHotKeys keyMap={subKeyMap} handlers={handlers}>

@ -3,9 +3,9 @@
// SPDX-License-Identifier: MIT
import './styles.scss';
import React, { MouseEvent } from 'react';
import { RouteComponentProps } from 'react-router';
import { withRouter } from 'react-router-dom';
import React from 'react';
import { connect } from 'react-redux';
import { useHistory } from 'react-router';
import { Row, Col } from 'antd/lib/grid';
import Layout from 'antd/lib/layout';
import Icon from 'antd/lib/icon';
@ -15,50 +15,129 @@ import Dropdown from 'antd/lib/dropdown';
import Modal from 'antd/lib/modal';
import Text from 'antd/lib/typography/Text';
import { CVATLogo, AccountIcon } from 'icons';
import getCore from 'cvat-core-wrapper';
import consts from 'consts';
import { CVATLogo, AccountIcon } from 'icons';
import ChangePasswordDialog from 'components/change-password-modal/change-password-modal';
import { switchSettingsDialog as switchSettingsDialogAction } from 'actions/settings-actions';
import { logoutAsync, authActions } from 'actions/auth-actions';
import { SupportedPlugins, CombinedState } from 'reducers/interfaces';
import SettingsModal from './settings-modal/settings-modal';
interface HeaderContainerProps {
onLogout: () => void;
switchSettingsDialog: (show: boolean) => void;
switchChangePasswordDialog: (show: boolean) => void;
logoutFetching: boolean;
changePasswordFetching: boolean;
installedAnalytics: boolean;
serverHost: string;
username: string;
toolName: string;
serverVersion: string;
serverDescription: string;
coreVersion: string;
canvasVersion: string;
uiVersion: string;
const core = getCore();
interface Tool {
name: string;
description: string;
server: {
host: string;
version: string;
};
core: {
version: string;
};
canvas: {
version: string;
};
ui: {
version: string;
};
}
interface StateToProps {
user: any;
tool: Tool;
switchSettingsShortcut: string;
settingsDialogShown: boolean;
changePasswordDialogShown: boolean;
changePasswordFetching: boolean;
logoutFetching: boolean;
installedAnalytics: boolean;
renderChangePasswordItem: boolean;
}
type Props = HeaderContainerProps & RouteComponentProps;
interface DispatchToProps {
onLogout: () => void;
switchSettingsDialog: (show: boolean) => void;
switchChangePasswordDialog: (show: boolean) => void;
}
function mapStateToProps(state: CombinedState): StateToProps {
const {
auth: {
user,
fetching: logoutFetching,
fetching: changePasswordFetching,
showChangePasswordDialog: changePasswordDialogShown,
allowChangePassword: renderChangePasswordItem,
},
plugins: {
list,
},
about: {
server,
packageVersion,
},
shortcuts: {
normalizedKeyMap,
},
settings: {
showDialog: settingsDialogShown,
},
} = state;
return {
user,
tool: {
name: server.name as string,
description: server.description as string,
server: {
host: core.config.backendAPI.slice(0, -7),
version: server.version as string,
},
canvas: {
version: packageVersion.canvas,
},
core: {
version: packageVersion.core,
},
ui: {
version: packageVersion.ui,
},
},
switchSettingsShortcut: normalizedKeyMap.SWITCH_SETTINGS,
settingsDialogShown,
changePasswordDialogShown,
changePasswordFetching,
logoutFetching,
installedAnalytics: list[SupportedPlugins.ANALYTICS],
renderChangePasswordItem,
};
}
function mapDispatchToProps(dispatch: any): DispatchToProps {
return {
onLogout: (): void => dispatch(logoutAsync()),
switchSettingsDialog: (show: boolean): void => dispatch(switchSettingsDialogAction(show)),
switchChangePasswordDialog: (show: boolean): void => (
dispatch(authActions.switchChangePasswordDialog(show))
),
};
}
type Props = StateToProps & DispatchToProps;
function HeaderContainer(props: Props): JSX.Element {
const {
user,
tool,
installedAnalytics,
username,
toolName,
serverHost,
serverVersion,
serverDescription,
coreVersion,
canvasVersion,
uiVersion,
onLogout,
logoutFetching,
changePasswordFetching,
settingsDialogShown,
switchSettingsShortcut,
onLogout,
switchSettingsDialog,
switchChangePasswordDialog,
renderChangePasswordItem,
@ -72,20 +151,22 @@ function HeaderContainer(props: Props): JSX.Element {
GITHUB_URL,
} = consts;
function aboutModal(): void {
const history = useHistory();
function showAboutModal(): void {
Modal.info({
title: `${toolName}`,
title: `${tool.name}`,
content: (
<div>
<p>
{`${serverDescription}`}
{`${tool.description}`}
</p>
<p>
<Text strong>
Server version:
</Text>
<Text type='secondary'>
{` ${serverVersion}`}
{` ${tool.server.version}`}
</Text>
</p>
<p>
@ -93,7 +174,7 @@ function HeaderContainer(props: Props): JSX.Element {
Core version:
</Text>
<Text type='secondary'>
{` ${coreVersion}`}
{` ${tool.core.version}`}
</Text>
</p>
<p>
@ -101,7 +182,7 @@ function HeaderContainer(props: Props): JSX.Element {
Canvas version:
</Text>
<Text type='secondary'>
{` ${canvasVersion}`}
{` ${tool.canvas.version}`}
</Text>
</p>
<p>
@ -109,7 +190,7 @@ function HeaderContainer(props: Props): JSX.Element {
UI version:
</Text>
<Text type='secondary'>
{` ${uiVersion}`}
{` ${tool.ui.version}`}
</Text>
</p>
<Row type='flex' justify='space-around'>
@ -131,16 +212,27 @@ function HeaderContainer(props: Props): JSX.Element {
const menu = (
<Menu className='cvat-header-menu' mode='vertical'>
{user.isStaff && (
<Menu.Item
onClick={(): void => {
// false positive
// eslint-disable-next-line
window.open(`${tool.server.host}/admin`, '_blank');
}}
>
<Icon type='control' />
Admin page
</Menu.Item>
)}
<Menu.Item
title={`Press ${switchSettingsShortcut} to switch`}
onClick={
(): void => switchSettingsDialog(true)
}
onClick={() => switchSettingsDialog(true)}
>
<Icon type='setting' />
Settings
</Menu.Item>
<Menu.Item onClick={() => aboutModal()}>
<Menu.Item onClick={showAboutModal}>
<Icon type='info-circle' />
About
</Menu.Item>
@ -178,7 +270,7 @@ function HeaderContainer(props: Props): JSX.Element {
onClick={
(event: React.MouseEvent): void => {
event.preventDefault();
props.history.push('/tasks?page=1');
history.push('/tasks?page=1');
}
}
>
@ -192,7 +284,7 @@ function HeaderContainer(props: Props): JSX.Element {
onClick={
(event: React.MouseEvent): void => {
event.preventDefault();
props.history.push('/models');
history.push('/models');
}
}
>
@ -203,13 +295,13 @@ function HeaderContainer(props: Props): JSX.Element {
<Button
className='cvat-header-button'
type='link'
href={`${serverHost}/analytics/app/kibana`}
href={`${tool.server.host}/analytics/app/kibana`}
onClick={
(event: React.MouseEvent): void => {
event.preventDefault();
// false positive
// eslint-disable-next-line
window.open(`${serverHost}/analytics/app/kibana`, '_blank');
window.open(`${tool.server.host}/analytics/app/kibana`, '_blank');
}
}
>
@ -237,13 +329,13 @@ function HeaderContainer(props: Props): JSX.Element {
<Button
className='cvat-header-button'
type='link'
href={`${serverHost}/documentation/user_guide.html`}
href={`${tool.server.host}/documentation/user_guide.html`}
onClick={
(event: React.MouseEvent): void => {
event.preventDefault();
// false positive
// eslint-disable-next-line
window.open(`${serverHost}/documentation/user_guide.html`, '_blank')
window.open(`${tool.server.host}/documentation/user_guide.html`, '_blank')
}
}
>
@ -254,7 +346,7 @@ function HeaderContainer(props: Props): JSX.Element {
<span>
<Icon className='cvat-header-account-icon' component={AccountIcon} />
<Text strong>
{username.length > 14 ? `${username.slice(0, 10)} ...` : username}
{user.username.length > 14 ? `${user.username.slice(0, 10)} ...` : user.username}
</Text>
<Icon className='cvat-header-menu-icon' type='caret-down' />
</span>
@ -275,4 +367,20 @@ function HeaderContainer(props: Props): JSX.Element {
);
}
export default withRouter(HeaderContainer);
function propsAreTheSame(prevProps: Props, nextProps: Props): boolean {
let equal = true;
for (const prop in nextProps) {
if (prop in prevProps && (prevProps as any)[prop] !== (nextProps as any)[prop]) {
if (prop !== 'tool') {
equal = false;
}
}
}
return equal;
}
export default connect(
mapStateToProps,
mapDispatchToProps,
)(React.memo(HeaderContainer, propsAreTheSame));

@ -39,7 +39,7 @@ function CookieDrawer(): JSX.Element {
This site uses cookies for functionality, analytics, and advertising purposes
as described in our Cookie and Similar Technologies Notice.
To see what cookies we serve and set your preferences, please visit our
<a href='https://www.intel.com/cookies'>Cookie Consent Tool</a>
<a href='https://www.intel.com/cookies'> Cookie Consent Tool</a>
. By continuing to use our website, you agree to our use of cookies.
</Paragraph>
<Button onClick={onClose} size='large' type='primary'>

@ -138,7 +138,7 @@ class RegisterFormComponent extends React.PureComponent<RegisterFormProps> {
}],
})(
<Input
prefix={<Icon type='user-add' style={{ color: 'rgba(0,0,0,.25)' }} />}
prefix={<Icon type='user-add' style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='First name'
/>,
)}
@ -159,7 +159,7 @@ class RegisterFormComponent extends React.PureComponent<RegisterFormProps> {
}],
})(
<Input
prefix={<Icon type='user-add' style={{ color: 'rgba(0,0,0,.25)' }} />}
prefix={<Icon type='user-add' style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Last name'
/>,
)}
@ -181,7 +181,7 @@ class RegisterFormComponent extends React.PureComponent<RegisterFormProps> {
}],
})(
<Input
prefix={<Icon type='user-add' style={{ color: 'rgba(0,0,0,.25)' }} />}
prefix={<Icon type='user-add' style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Username'
/>,
)}
@ -205,7 +205,7 @@ class RegisterFormComponent extends React.PureComponent<RegisterFormProps> {
})(
<Input
autoComplete='email'
prefix={<Icon type='mail' style={{ color: 'rgba(0,0,0,.25)' }} />}
prefix={<Icon type='mail' style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Email address'
/>,
)}
@ -227,7 +227,7 @@ class RegisterFormComponent extends React.PureComponent<RegisterFormProps> {
}],
})(<Input.Password
autoComplete='new-password'
prefix={<Icon type='lock' style={{ color: 'rgba(0,0,0,.25)' }} />}
prefix={<Icon type='lock' style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Password'
/>)}
</Form.Item>
@ -248,7 +248,7 @@ class RegisterFormComponent extends React.PureComponent<RegisterFormProps> {
}],
})(<Input.Password
autoComplete='new-password'
prefix={<Icon type='lock' style={{ color: 'rgba(0,0,0,.25)' }} />}
prefix={<Icon type='lock' style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Confirm password'
/>)}
</Form.Item>
@ -279,7 +279,7 @@ class RegisterFormComponent extends React.PureComponent<RegisterFormProps> {
target='_blank'
href={userAgreement.url}
>
{userAgreement.displayText}
{` ${userAgreement.displayText}`}
</a>
</Checkbox>,
)}

@ -1,97 +0,0 @@
// Copyright (C) 2020 Intel Corporation
//
// SPDX-License-Identifier: MIT
import { connect } from 'react-redux';
import getCore from 'cvat-core-wrapper';
import HeaderComponent from 'components/header/header';
import { SupportedPlugins, CombinedState } from 'reducers/interfaces';
import { logoutAsync, authActions } from 'actions/auth-actions';
import { switchSettingsDialog } from 'actions/settings-actions';
const core = getCore();
interface StateToProps {
logoutFetching: boolean;
installedAnalytics: boolean;
username: string;
toolName: string;
serverHost: string;
serverVersion: string;
serverDescription: string;
coreVersion: string;
canvasVersion: string;
uiVersion: string;
switchSettingsShortcut: string;
settingsDialogShown: boolean;
changePasswordDialogShown: boolean;
changePasswordFetching: boolean;
renderChangePasswordItem: boolean;
}
interface DispatchToProps {
onLogout: () => void;
switchSettingsDialog: (show: boolean) => void;
switchChangePasswordDialog: (show: boolean) => void;
}
function mapStateToProps(state: CombinedState): StateToProps {
const {
auth: {
fetching: logoutFetching,
fetching: changePasswordFetching,
user: {
username,
},
showChangePasswordDialog: changePasswordDialogShown,
allowChangePassword: renderChangePasswordItem,
},
plugins: {
list,
},
about: {
server,
packageVersion,
},
shortcuts: {
normalizedKeyMap,
},
settings: {
showDialog: settingsDialogShown,
},
} = state;
return {
logoutFetching,
installedAnalytics: list[SupportedPlugins.ANALYTICS],
username,
toolName: server.name as string,
serverHost: core.config.backendAPI.slice(0, -7),
serverDescription: server.description as string,
serverVersion: server.version as string,
coreVersion: packageVersion.core,
canvasVersion: packageVersion.canvas,
uiVersion: packageVersion.ui,
switchSettingsShortcut: normalizedKeyMap.SWITCH_SETTINGS,
settingsDialogShown,
changePasswordFetching,
changePasswordDialogShown,
renderChangePasswordItem,
};
}
function mapDispatchToProps(dispatch: any): DispatchToProps {
return {
onLogout: (): void => dispatch(logoutAsync()),
switchSettingsDialog: (show: boolean): void => dispatch(switchSettingsDialog(show)),
switchChangePasswordDialog: (show: boolean): void => (
dispatch(authActions.switchChangePasswordDialog(show))
),
};
}
export default connect(
mapStateToProps,
mapDispatchToProps,
)(HeaderComponent);
Loading…
Cancel
Save