From a781e1cee16dfb9a083f5c896a95c2568871a6b7 Mon Sep 17 00:00:00 2001 From: Vitaliy Nishukov Date: Mon, 5 Oct 2020 14:17:06 +0300 Subject: [PATCH] UI improvements (#2238) * Layout grid * Changelog notes * License headers * Get rid of fixed layot in nested components * Multiple grids * Multiple grids HF * Grid use react-hotkeys * Cleanup and test fix * Version up * Notifications overlay fix --- CHANGELOG.md | 1 + cvat-ui/package-lock.json | 2 +- cvat-ui/package.json | 2 +- cvat-ui/src/base.scss | 9 ++++ cvat-ui/src/components/cvat-app.tsx | 45 +++++++++-------- cvat-ui/src/components/header/styles.scss | 2 +- .../components/layout-grid/layout-grid.tsx | 35 +++++++++++++ .../src/components/layout-grid/styles.scss | 49 +++++++++++++++++++ cvat-ui/src/components/task-page/styles.scss | 1 - cvat-ui/src/components/tasks-page/styles.scss | 1 - cvat-ui/src/index.html | 30 +++++++----- cvat-ui/src/index.tsx | 34 ++++++------- cvat-ui/src/styles.scss | 15 ++++++ .../case_2_register_user_change_pass.js | 25 +++++++--- .../integration/case_6_image_scale_fit.js | 10 ++-- 15 files changed, 189 insertions(+), 72 deletions(-) create mode 100644 cvat-ui/src/components/layout-grid/layout-grid.tsx create mode 100644 cvat-ui/src/components/layout-grid/styles.scss diff --git a/CHANGELOG.md b/CHANGELOG.md index e1c7a1ec..fb4379b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.2.0] - Unreleased ### Added +- Added layout grids toggling ('ctrl + alt + Enter') - Added password reset functionality () - Ability to work with data on the fly (https://github.com/opencv/cvat/pull/2007) - Annotation in process outline color wheel () diff --git a/cvat-ui/package-lock.json b/cvat-ui/package-lock.json index 97d0994a..61b5a1a0 100644 --- a/cvat-ui/package-lock.json +++ b/cvat-ui/package-lock.json @@ -1,6 +1,6 @@ { "name": "cvat-ui", - "version": "1.9.9", + "version": "1.9.10", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/cvat-ui/package.json b/cvat-ui/package.json index e0043a0e..84ab39d3 100644 --- a/cvat-ui/package.json +++ b/cvat-ui/package.json @@ -1,6 +1,6 @@ { "name": "cvat-ui", - "version": "1.9.9", + "version": "1.9.10", "description": "CVAT single-page application", "main": "src/index.tsx", "scripts": { diff --git a/cvat-ui/src/base.scss b/cvat-ui/src/base.scss index 86bae731..11764340 100644 --- a/cvat-ui/src/base.scss +++ b/cvat-ui/src/base.scss @@ -2,6 +2,15 @@ // // SPDX-License-Identifier: MIT +$grid-unit-size: 8px; + +$header-height: $grid-unit-size * 7; + +$layout-sm-grid-size: $grid-unit-size / 2; +$layout-lg-grid-size: $grid-unit-size * 2; +$layout-sm-grid-color: rgba(0, 0, 0, 0.15); +$layout-lg-grid-color: rgba(0, 0, 0, 0.15); + $header-color: #d8d8d8; $text-color: #303030; $hover-menu-color: rgba(24, 144, 255, 0.05); diff --git a/cvat-ui/src/components/cvat-app.tsx b/cvat-ui/src/components/cvat-app.tsx index cd928f8b..b497e69d 100644 --- a/cvat-ui/src/components/cvat-app.tsx +++ b/cvat-ui/src/components/cvat-app.tsx @@ -3,35 +3,35 @@ // SPDX-License-Identifier: MIT import 'antd/dist/antd.css'; -import '../styles.scss'; -import React from 'react'; -import { Switch, Route, Redirect } from 'react-router'; -import { withRouter, RouteComponentProps } from 'react-router-dom'; -import { GlobalHotKeys, ExtendedKeyMapOptions, configure } from 'react-hotkeys'; -import Spin from 'antd/lib/spin'; +import { Col, Row } from 'antd/lib/grid'; import Layout from 'antd/lib/layout'; -import { Row, Col } from 'antd/lib/grid'; -import Text from 'antd/lib/typography/Text'; +import Modal from 'antd/lib/modal'; import notification from 'antd/lib/notification'; - +import Spin from 'antd/lib/spin'; +import Text from 'antd/lib/typography/Text'; import GlobalErrorBoundary from 'components/global-error-boundary/global-error-boundary'; +import Header from 'components/header/header'; +import ResetPasswordPageConfirmComponent from 'components/reset-password-confirm-page/reset-password-confirm-page'; +import ResetPasswordPageComponent from 'components/reset-password-page/reset-password-page'; import ShorcutsDialog from 'components/shortcuts-dialog/shortcuts-dialog'; -import TasksPageContainer from 'containers/tasks-page/tasks-page'; -import CreateTaskPageContainer from 'containers/create-task-page/create-task-page'; -import TaskPageContainer from 'containers/task-page/task-page'; -import ModelsPageContainer from 'containers/models-page/models-page'; import AnnotationPageContainer from 'containers/annotation-page/annotation-page'; +import CreateTaskPageContainer from 'containers/create-task-page/create-task-page'; import LoginPageContainer from 'containers/login-page/login-page'; +import ModelsPageContainer from 'containers/models-page/models-page'; import RegisterPageContainer from 'containers/register-page/register-page'; -import ResetPasswordPageComponent from 'components/reset-password-page/reset-password-page'; -import ResetPasswordPageConfirmComponent from 'components/reset-password-confirm-page/reset-password-confirm-page'; -import Header from 'components/header/header'; -import { customWaViewHit } from 'utils/enviroment'; -import showPlatformNotification, { stopNotifications, platformInfo } from 'utils/platform-checker'; - +import TaskPageContainer from 'containers/task-page/task-page'; +import TasksPageContainer from 'containers/tasks-page/tasks-page'; import getCore from 'cvat-core-wrapper'; +import React from 'react'; +import { configure, ExtendedKeyMapOptions, GlobalHotKeys } from 'react-hotkeys'; +import { Redirect, Route, Switch } from 'react-router'; +import { RouteComponentProps, withRouter } from 'react-router-dom'; import { NotificationsState } from 'reducers/interfaces'; -import Modal from 'antd/lib/modal'; +import { customWaViewHit } from 'utils/enviroment'; +import showPlatformNotification, { platformInfo, stopNotifications } from 'utils/platform-checker'; +import '../styles.scss'; + + interface CVATAppProps { loadFormats: () => void; @@ -255,7 +255,7 @@ class CVATApplication extends React.PureComponent - { isModelPluginActive - && } + {isModelPluginActive && } diff --git a/cvat-ui/src/components/header/styles.scss b/cvat-ui/src/components/header/styles.scss index 134cb488..32dcca89 100644 --- a/cvat-ui/src/components/header/styles.scss +++ b/cvat-ui/src/components/header/styles.scss @@ -9,7 +9,7 @@ padding-left: 0; padding-right: 0; line-height: 0; - height: 44px; + height: $header-height; background: $header-color; } diff --git a/cvat-ui/src/components/layout-grid/layout-grid.tsx b/cvat-ui/src/components/layout-grid/layout-grid.tsx new file mode 100644 index 00000000..9fa35326 --- /dev/null +++ b/cvat-ui/src/components/layout-grid/layout-grid.tsx @@ -0,0 +1,35 @@ +// Copyright (C) 2020 Intel Corporation +// +// SPDX-License-Identifier: MIT + +import React, { useCallback, useState } from 'react'; +import ReactDOM from 'react-dom'; +import { GlobalHotKeys } from 'react-hotkeys'; +import './styles.scss'; + +const LayoutGrid = (): React.ReactPortal => { + const [showGrid, setShowGrid] = useState(false); + + const keyMap = { + TOGGLE_LAYOUT_GRID: 'ctrl+alt+enter', + }; + + const toggleLayoutGrid = useCallback((): void => { + setShowGrid((prevState: boolean) => !prevState); + }, [showGrid]); + + const handlers = { + TOGGLE_LAYOUT_GRID: toggleLayoutGrid, + }; + + const portalContent: JSX.Element = ( + + {showGrid &&
} + {showGrid &&
} + + ); + + return ReactDOM.createPortal(portalContent, document.getElementById('layout-grid') as HTMLElement); +}; + +export default LayoutGrid; diff --git a/cvat-ui/src/components/layout-grid/styles.scss b/cvat-ui/src/components/layout-grid/styles.scss new file mode 100644 index 00000000..1f4bb24e --- /dev/null +++ b/cvat-ui/src/components/layout-grid/styles.scss @@ -0,0 +1,49 @@ +// Copyright (C) 2020 Intel Corporation +// +// SPDX-License-Identifier: MIT + +@import './../../base.scss'; + +.grid { + display: grid; + + &::before, + &::after { + content: ''; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100vw; + } + + &.sm { + grid-template-rows: repeat(1000, $layout-sm-grid-size); + grid-template-columns: repeat(1000, $layout-sm-grid-size); + + &::before, + &::after { + background: linear-gradient(to right, $layout-sm-grid-color 1px, transparent 1px); + background-size: $layout-sm-grid-size; + } + + &::after { + transform: rotate(90deg); + } + } + + &.lg { + grid-template-rows: repeat(1000, $layout-lg-grid-size); + grid-template-columns: repeat(1000, $layout-lg-grid-size); + + &::before, + &::after { + background: linear-gradient(to right, $layout-lg-grid-color 1px, transparent 1px); + background-size: $layout-lg-grid-size; + } + + &::after { + transform: rotate(90deg); + } + } +} diff --git a/cvat-ui/src/components/task-page/styles.scss b/cvat-ui/src/components/task-page/styles.scss index fd218c50..2674edac 100644 --- a/cvat-ui/src/components/task-page/styles.scss +++ b/cvat-ui/src/components/task-page/styles.scss @@ -8,7 +8,6 @@ overflow-y: auto; height: 90%; width: 100%; - position: fixed; .cvat-task-details { width: 100%; diff --git a/cvat-ui/src/components/tasks-page/styles.scss b/cvat-ui/src/components/tasks-page/styles.scss index 623b7633..a6e2f302 100644 --- a/cvat-ui/src/components/tasks-page/styles.scss +++ b/cvat-ui/src/components/tasks-page/styles.scss @@ -8,7 +8,6 @@ padding-top: 15px; padding-bottom: 40px; height: 100%; - position: fixed; width: 100%; > div:nth-child(1) { diff --git a/cvat-ui/src/index.html b/cvat-ui/src/index.html index 5a7b61a0..4a8bec9b 100644 --- a/cvat-ui/src/index.html +++ b/cvat-ui/src/index.html @@ -5,17 +5,21 @@ --> - - - - - - - - Computer Vision Annotation Tool - + - -
- - + + + + + + + Computer Vision Annotation Tool + + + +
+
+ + + \ No newline at end of file diff --git a/cvat-ui/src/index.tsx b/cvat-ui/src/index.tsx index 83c58469..0700e947 100644 --- a/cvat-ui/src/index.tsx +++ b/cvat-ui/src/index.tsx @@ -2,30 +2,25 @@ // // SPDX-License-Identifier: MIT +import { getAboutAsync } from 'actions/about-actions'; +import { authorizedAsync, loadAuthActionsAsync } from 'actions/auth-actions'; +import { getFormatsAsync } from 'actions/formats-actions'; +import { getModelsAsync } from 'actions/models-actions'; +import { getPluginsAsync } from 'actions/plugins-actions'; +import { switchSettingsDialog } from 'actions/settings-actions'; +import { shortcutsActions } from 'actions/shortcuts-actions'; +import { getUserAgreementsAsync } from 'actions/useragreements-actions'; +import { getUsersAsync } from 'actions/users-actions'; +import CVATApplication from 'components/cvat-app'; +import LayoutGrid from 'components/layout-grid/layout-grid'; +import logger, { LogType } from 'cvat-logger'; +import createCVATStore, { getCVATStore } from 'cvat-store'; import React from 'react'; import ReactDOM from 'react-dom'; -import { connect, Provider } from 'react-redux'; import { ExtendedKeyMapOptions } from 'react-hotkeys'; +import { connect, Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; - -import CVATApplication from 'components/cvat-app'; - import createRootReducer from 'reducers/root-reducer'; -import createCVATStore, { getCVATStore } from 'cvat-store'; -import logger, { LogType } from 'cvat-logger'; - -import { - authorizedAsync, - loadAuthActionsAsync, -} from 'actions/auth-actions'; -import { getFormatsAsync } from 'actions/formats-actions'; -import { getPluginsAsync } from 'actions/plugins-actions'; -import { getUsersAsync } from 'actions/users-actions'; -import { getAboutAsync } from 'actions/about-actions'; -import { getModelsAsync } from 'actions/models-actions'; -import { getUserAgreementsAsync } from 'actions/useragreements-actions'; -import { shortcutsActions } from 'actions/shortcuts-actions'; -import { switchSettingsDialog } from 'actions/settings-actions'; import { resetErrors, resetMessages } from './actions/notification-actions'; import { CombinedState, NotificationsState } from './reducers/interfaces'; @@ -136,6 +131,7 @@ ReactDOM.render( + ), document.getElementById('root'), diff --git a/cvat-ui/src/styles.scss b/cvat-ui/src/styles.scss index 284b2772..c00a4236 100644 --- a/cvat-ui/src/styles.scss +++ b/cvat-ui/src/styles.scss @@ -39,6 +39,12 @@ hr { } } +.ant-notification { + top: $header-height !important; + right: 0 !important; + margin-right: 0; +} + .cvat-info-circle-icon { color: $info-icon-color; } @@ -53,3 +59,12 @@ hr { display: grid; min-width: 1280px; } + +#layout-grid { + overflow: hidden; + position: fixed; + top: 0; + left: 0; + z-index: 9999; + pointer-events: none; +} diff --git a/tests/cypress/integration/case_2_register_user_change_pass.js b/tests/cypress/integration/case_2_register_user_change_pass.js index 972293ea..d5691e9f 100644 --- a/tests/cypress/integration/case_2_register_user_change_pass.js +++ b/tests/cypress/integration/case_2_register_user_change_pass.js @@ -6,14 +6,25 @@ /// +const randomString = (isPassword) => { + let result = ''; + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; + for (let i = 0; i <= 8; i++) { + result += characters.charAt( + Math.floor(Math.random() * characters.length), + ); + } + return isPassword ? `${result}${Math.floor(Math.random() * 10)}` : result; +}; + context('Register user, change password, login with new password', () => { - const caseId = '2' - const firstName = 'First name' - const lastName = 'Last name' - const userName = 'Username' - const emailAddr = `${userName}@local.local` - const password = 'UfdU21!dds' - const newPassword = 'dKl3j49sd@jjk' + const caseId = '2'; + const firstName = `${randomString()}`; + const lastName = `${randomString()}`; + const userName = `${randomString()}`; + const emailAddr = `${userName}@local.local`; + const password = `${randomString(true)}`; + const newPassword = `${randomString(true)}`; before(() => { cy.visit('auth/register') diff --git a/tests/cypress/integration/case_6_image_scale_fit.js b/tests/cypress/integration/case_6_image_scale_fit.js index 11887e1e..67a5aac6 100644 --- a/tests/cypress/integration/case_6_image_scale_fit.js +++ b/tests/cypress/integration/case_6_image_scale_fit.js @@ -32,17 +32,17 @@ context('Check if the image is scaled and then fitted', () => { describe(`Testing "${labelName}"`, () => { it('Scale image', () => { cy.get('#cvat_canvas_background') - .should('have.attr', 'style').and('contain', 'scale(1.065)') + .should('have.attr', 'style').and('contain', 'scale(1.05)') cy.get('.cvat-canvas-container') - .trigger('wheel', {deltaY: 5}) + .trigger('wheel', {deltaY: 5}) cy.get('#cvat_canvas_background') - .should('have.attr', 'style').and('contain', 'scale(0.8875)') + .should('have.attr', 'style').and('contain', 'scale(0.875)') }) it('Fit image', () => { cy.get('#cvat_canvas_content') - .dblclick() + .dblclick() cy.get('#cvat_canvas_background') - .should('have.attr', 'style').and('contain', 'scale(1.065)') + .should('have.attr', 'style').and('contain', 'scale(1.05)') }) }) })