-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement basic suites page in new UI (#590)
* feat: incorporated react-virtual * feat: implement zoom feature and previews in tree * chore: working on new ui redux store * feat: finish suites page implementation * fix: fix poor scrolling performance * refactor: split suites page into components * refactor: remove unnecessary styles * fix: fix review issues * fix: add testplane icon * ci: try running on larger resource class
- Loading branch information
Showing
47 changed files
with
1,441 additions
and
171 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import actionNames from '../action-names'; | ||
import {SuitesPageSetCurrentSuiteAction} from '@/static/modules/reducers/suites-page'; | ||
|
||
export const suitesPageSetCurrentSuite = (suiteId: string): SuitesPageSetCurrentSuiteAction => { | ||
return {type: actionNames.SUITES_PAGE_SET_CURRENT_SUITE, payload: {suiteId}}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import actionNames from '../action-names'; | ||
|
||
export default (state, action) => { | ||
switch (action.type) { | ||
case actionNames.INIT_GUI_REPORT: | ||
case actionNames.INIT_STATIC_REPORT: | ||
return {...state, app: {...state.app, isInitialized: true}}; | ||
|
||
default: | ||
return state; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import actionNames from '../action-names'; | ||
import {State} from '@/static/new-ui/types/store'; | ||
import {Action} from '@/static/modules/actions/types'; | ||
|
||
export type SuitesPageSetCurrentSuiteAction = Action<typeof actionNames.SUITES_PAGE_SET_CURRENT_SUITE, { | ||
suiteId: string; | ||
}>; | ||
|
||
export default (state: State, action: SuitesPageSetCurrentSuiteAction): State => { | ||
switch (action.type) { | ||
case actionNames.SUITES_PAGE_SET_CURRENT_SUITE: | ||
return {...state, app: {...state.app, currentSuiteId: action.payload.suiteId}}; | ||
default: | ||
return state; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.g-root { | ||
--g-font-family-sans: 'Jost', sans-serif; | ||
} | ||
|
||
.report { | ||
font-family: var(--g-font-family-sans), sans-serif !important; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import {ThemeProvider} from '@gravity-ui/uikit'; | ||
import React, {ReactNode, StrictMode} from 'react'; | ||
import {MainLayout} from '../components/MainLayout'; | ||
import {HashRouter, Navigate, Route, Routes} from 'react-router-dom'; | ||
import {CircleInfo, Eye, ListCheck} from '@gravity-ui/icons'; | ||
import {SuitesPage} from '../features/suites/components/SuitesPage'; | ||
import {VisualChecksPage} from '../features/visual-checks/components/VisualChecksPage'; | ||
import {InfoPage} from '../features/info/components/InfoPage'; | ||
|
||
import '@gravity-ui/uikit/styles/fonts.css'; | ||
import '@gravity-ui/uikit/styles/styles.css'; | ||
import '../../new-ui.css'; | ||
import {Provider} from 'react-redux'; | ||
import store from '../../modules/store'; | ||
|
||
export function App(): ReactNode { | ||
const pages = [ | ||
{ | ||
title: 'Suites', | ||
url: '/suites', | ||
icon: ListCheck, | ||
element: <SuitesPage/>, | ||
children: [<Route key={'suite'} path=':suiteId' element= {<SuitesPage/>} />] | ||
}, | ||
{title: 'Visual Checks', url: '/visual-checks', icon: Eye, element: <VisualChecksPage/>}, | ||
{title: 'Info', url: '/info', icon: CircleInfo, element: <InfoPage/>} | ||
]; | ||
|
||
return <StrictMode> | ||
<ThemeProvider theme='light'> | ||
<Provider store={store}> | ||
<HashRouter> | ||
<MainLayout menuItems={pages}> | ||
<Routes> | ||
<Route element={<Navigate to={'/suites'}/>} path={'/'}/> | ||
{pages.map(page => <Route element={page.element} path={page.url} key={page.url}>{page.children}</Route>)} | ||
</Routes> | ||
</MainLayout> | ||
</HashRouter> | ||
</Provider> | ||
</ThemeProvider> | ||
</StrictMode>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import React, {ReactNode, useEffect} from 'react'; | ||
import {createRoot} from 'react-dom/client'; | ||
import {App} from './App'; | ||
import store from '../../modules/store'; | ||
import {finGuiReport, initGuiReport} from '../../modules/actions'; | ||
|
||
const rootEl = document.getElementById('app') as HTMLDivElement; | ||
const root = createRoot(rootEl); | ||
|
||
function Gui(): ReactNode { | ||
useEffect(() => { | ||
store.dispatch(initGuiReport()); | ||
|
||
return () => { | ||
store.dispatch(finGuiReport()); | ||
}; | ||
}, []); | ||
|
||
return <App/>; | ||
} | ||
|
||
root.render(<Gui />); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import React, {ReactNode, useEffect} from 'react'; | ||
import {createRoot} from 'react-dom/client'; | ||
import {App} from './App'; | ||
import store from '../../modules/store'; | ||
import {initStaticReport, finStaticReport} from '../../modules/actions'; | ||
|
||
const rootEl = document.getElementById('app') as HTMLDivElement; | ||
const root = createRoot(rootEl); | ||
|
||
function Report(): ReactNode { | ||
useEffect(() => { | ||
store.dispatch(initStaticReport()); | ||
|
||
return () => { | ||
store.dispatch(finStaticReport()); | ||
}; | ||
}, []); | ||
|
||
return <App/>; | ||
} | ||
|
||
root.render(<Report />); |
10 changes: 10 additions & 0 deletions
10
lib/static/new-ui/components/ImageWithMagnifier/index.module.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
.magnifier { | ||
background-color: white; | ||
background-repeat: no-repeat; | ||
border: 1px solid lightgrey; | ||
border-radius: 5px; | ||
opacity: 1; | ||
pointer-events: none; | ||
position: fixed; | ||
z-index: 1000 | ||
} |
122 changes: 122 additions & 0 deletions
122
lib/static/new-ui/components/ImageWithMagnifier/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import classnames from 'classnames'; | ||
import React, {ReactNode, useEffect, useRef, useState} from 'react'; | ||
import {createPortal} from 'react-dom'; | ||
import styles from './index.module.css'; | ||
|
||
const DEFAULT_ZOOM_LEVEL = 3; | ||
|
||
interface ImageWithMagnifierProps { | ||
src: string; | ||
alt: string; | ||
className?: string; | ||
style?: React.CSSProperties; | ||
magnifierHeight?: number; | ||
magnifierWidth?: number; | ||
zoomLevel?: number; | ||
// Used to detect parent container scrolling and update the magnifier state | ||
scrollContainerRef?: React.RefObject<HTMLElement>; | ||
} | ||
|
||
export function ImageWithMagnifier({ | ||
src, | ||
alt, | ||
className = '', | ||
style, | ||
magnifierHeight = 150, | ||
magnifierWidth = 150, | ||
zoomLevel = DEFAULT_ZOOM_LEVEL, | ||
scrollContainerRef | ||
}: ImageWithMagnifierProps): ReactNode { | ||
const [showMagnifier, setShowMagnifier] = useState(false); | ||
const [[imgWidth, imgHeight], setSize] = useState([0, 0]); | ||
const [[x, y], setXY] = useState([0, 0]); | ||
const mousePositionRef = useRef([0, 0]); | ||
const [magnifierStyle, setMagnifierStyle] = useState({}); | ||
const imgRef = useRef<HTMLImageElement>(null); | ||
|
||
const mouseEnter = (e: React.MouseEvent<HTMLImageElement>): void => { | ||
const el = e.currentTarget; | ||
|
||
const {width, height} = el.getBoundingClientRect(); | ||
setSize([width, height]); | ||
setShowMagnifier(true); | ||
mousePositionRef.current = [e.clientX, e.clientY]; | ||
}; | ||
|
||
const mouseLeave = (e: React.MouseEvent<HTMLImageElement>): void => { | ||
e.preventDefault(); | ||
setShowMagnifier(false); | ||
mousePositionRef.current = [e.clientX, e.clientY]; | ||
}; | ||
|
||
const mouseMove = (e: React.MouseEvent<HTMLImageElement>): void => { | ||
const el = e.currentTarget; | ||
const {top, left} = el.getBoundingClientRect(); | ||
|
||
const x = e.clientX - left - window.scrollX; | ||
const y = e.clientY - top - window.scrollY; | ||
|
||
setXY([x, y]); | ||
mousePositionRef.current = [e.clientX, e.clientY]; | ||
}; | ||
|
||
useEffect(() => { | ||
if (showMagnifier && scrollContainerRef?.current && imgRef?.current) { | ||
const handleScroll = (): void => { | ||
if (!imgRef.current) { | ||
return; | ||
} | ||
const [mouseX, mouseY] = mousePositionRef.current; | ||
|
||
const el = imgRef.current; | ||
const {top, left} = el.getBoundingClientRect(); | ||
|
||
const x = mouseX - left - window.scrollX; | ||
const y = mouseY - top - window.scrollY; | ||
|
||
setXY([x, y]); | ||
}; | ||
|
||
scrollContainerRef.current.addEventListener('scroll', handleScroll); | ||
|
||
return () => { | ||
scrollContainerRef.current?.removeEventListener('scroll', handleScroll); | ||
}; | ||
} | ||
|
||
return undefined; | ||
}, [showMagnifier, scrollContainerRef]); | ||
|
||
useEffect(() => { | ||
const [mouseX, mouseY] = mousePositionRef.current; | ||
|
||
setMagnifierStyle({ | ||
display: showMagnifier ? '' : 'none', | ||
height: `${magnifierHeight}px`, | ||
width: `${magnifierWidth}px`, | ||
backgroundImage: `url('${src}')`, | ||
top: `${mouseY - magnifierHeight / 2}px`, | ||
left: `${mouseX - magnifierWidth / 2}px`, | ||
backgroundSize: `${imgWidth * zoomLevel}px ${imgHeight * zoomLevel}px`, | ||
backgroundPositionX: `${-x * zoomLevel + magnifierWidth / 2}px`, | ||
backgroundPositionY: `${-y * zoomLevel + magnifierHeight / 2}px` | ||
}); | ||
}, [showMagnifier, imgWidth, imgHeight, x, y]); | ||
|
||
return <div> | ||
<img | ||
src={src} | ||
className={classnames(className)} | ||
style={style} | ||
alt={alt} | ||
onMouseEnter={(e): void => mouseEnter(e)} | ||
onMouseLeave={(e): void => mouseLeave(e)} | ||
onMouseMove={(e): void => mouseMove(e)} | ||
ref={imgRef} | ||
/> | ||
{createPortal(<div | ||
className={styles.magnifier} | ||
style={magnifierStyle} | ||
/>, document.body)} | ||
</div>; | ||
} |
Oops, something went wrong.