Skip to content

Commit 885b220

Browse files
authored
feat: implement test run options extension point (#734)
1 parent b73c66b commit 885b220

File tree

5 files changed

+98
-10
lines changed

5 files changed

+98
-10
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1+
.buttons-container {
2+
display: flex;
3+
align-items: center;
4+
flex-wrap: nowrap;
5+
}
6+
17
.retry-button {
28
composes: regular-button from global, action-button from global;
39
}
10+
11+
.run-options-button::before {
12+
border-left: none;
13+
}
14+
15+
.run-options-button-icon {
16+
transition: transform 0.1s ease-in-out;
17+
}
18+
19+
.run-options-button-icon-rotated {
20+
transform: rotate(180deg);
21+
}
22+
23+
.run-options-container {
24+
width: 450px;
25+
padding: 16px;
26+
}

lib/static/new-ui/components/RunTest/index.tsx

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1-
import React, {forwardRef} from 'react';
1+
import React, {forwardRef, useCallback, useState} from 'react';
22

33
import styles from './index.module.css';
4-
import {Button, ButtonProps, Icon, Spin} from '@gravity-ui/uikit';
5-
import {ArrowRotateRight} from '@gravity-ui/icons';
4+
import {Button, ButtonProps, Icon, Popover, Spin} from '@gravity-ui/uikit';
5+
import {ArrowRotateRight, ChevronDown} from '@gravity-ui/icons';
66
import {thunkRunTest} from '@/static/modules/actions';
77
import {useDispatch, useSelector} from 'react-redux';
88
import {RunTestsFeature} from '@/constants';
99
import {useAnalytics} from '../../hooks/useAnalytics';
1010
import type {BrowserEntity} from '@/static/new-ui/types/store';
1111
import {isFeatureAvailable} from '../../utils/features';
12+
import classNames from 'classnames';
13+
import ExtensionPoint, {getExtensionPointComponents} from '../../../components/extension-point';
14+
import * as plugins from '../../../modules/plugins';
15+
import {ExtensionPointName} from '../../constants/plugins';
1216

1317
interface RunTestProps {
1418
browser: BrowserEntity | null;
@@ -35,10 +39,45 @@ export const RunTestButton = forwardRef<HTMLButtonElement | HTMLAnchorElement, R
3539
return null;
3640
}
3741

38-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
39-
return <Button ref={ref as any} view={'action'} className={styles.retryButton} onClick={onRetryTestHandler} disabled={isRunning} style={{width: buttonText === null ? '28px' : undefined}} {...buttonProps}>
40-
{isRunning ? <Spin size={'xs'} /> : <Icon data={ArrowRotateRight}/>}{buttonText === undefined ? 'Retry' : buttonText}
41-
</Button>;
42+
const loadedPluginConfigs = plugins.getLoadedConfigs();
43+
const pluginComponents = getExtensionPointComponents(loadedPluginConfigs, ExtensionPointName.RunTestOptions);
44+
const hasRunTestOptions = pluginComponents.length > 0;
45+
const [isRunOptionsOpen, setIsRunOptionsOpen] = useState(false);
46+
const onRunOptionsOpenChange = useCallback((open: boolean) => {
47+
setIsRunOptionsOpen(open);
48+
}, []);
49+
50+
return <div className={styles.buttonsContainer}>
51+
<Button
52+
ref={ref as any} // eslint-disable-line @typescript-eslint/no-explicit-any
53+
view={'action'}
54+
className={styles.retryButton}
55+
onClick={onRetryTestHandler}
56+
disabled={isRunning}
57+
style={{width: buttonText === null ? '28px' : undefined}}
58+
pin={hasRunTestOptions ? 'round-brick' : undefined}
59+
{...buttonProps}
60+
>
61+
{isRunning ? <Spin size={'xs'} /> : <Icon data={ArrowRotateRight}/>}{buttonText === undefined ? 'Retry' : buttonText}
62+
</Button>
63+
{hasRunTestOptions && <Popover
64+
onOpenChange={onRunOptionsOpenChange}
65+
content={<div className={styles.runOptionsContainer}><ExtensionPoint name={ExtensionPointName.RunTestOptions}></ExtensionPoint></div>}
66+
trigger='click'
67+
placement='bottom-end'
68+
>
69+
<Button
70+
view='action'
71+
disabled={isRunning}
72+
className={classNames(styles.retryButton, styles.runOptionsButton)}
73+
style={{width: buttonText === null ? '28px' : undefined}}
74+
pin='brick-round'
75+
{...buttonProps}
76+
>
77+
<Icon data={ChevronDown} className={classNames(styles.runOptionsButtonIcon, {[styles.runOptionsButtonIconRotated]: isRunOptionsOpen})}/>
78+
</Button>
79+
</Popover>}
80+
</div>;
4281
}
4382
);
4483

lib/static/new-ui/components/TreeActionsToolbar/index.module.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,8 @@
6868
.select-all-button {
6969
width: 34px !important;
7070
}
71+
72+
.run-options-container {
73+
width: 450px;
74+
padding: 16px;
75+
}

lib/static/new-ui/components/TreeActionsToolbar/index.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Icon, Spin} from '@gravity-ui/uikit';
1+
import {Icon, Popover, Spin} from '@gravity-ui/uikit';
22
import classNames from 'classnames';
33
import {
44
ArrowUturnCcwLeft,
@@ -12,7 +12,8 @@ import {
1212
SquareDashed,
1313
SquareMinus,
1414
ListUl,
15-
Hierarchy
15+
Hierarchy,
16+
GearPlay
1617
} from '@gravity-ui/icons';
1718
import React, {ReactNode, useMemo} from 'react';
1819
import {useDispatch, useSelector} from 'react-redux';
@@ -48,6 +49,9 @@ import {GroupBySelect} from '@/static/new-ui/features/suites/components/GroupByS
4849
import {SortBySelect} from '@/static/new-ui/features/suites/components/SortBySelect';
4950
import {thunkAcceptImages, thunkRevertImages} from '@/static/modules/actions/screenshots';
5051
import {useAnalytics} from '@/static/new-ui/hooks/useAnalytics';
52+
import ExtensionPoint, {getExtensionPointComponents} from '../../../components/extension-point';
53+
import {ExtensionPointName} from '../../constants/plugins';
54+
import * as plugins from '../../../modules/plugins';
5155

5256
interface TreeActionsToolbarProps {
5357
onHighlightCurrentTest?: () => void;
@@ -180,6 +184,10 @@ export function TreeActionsToolbar({onHighlightCurrentTest, className}: TreeActi
180184
const selectedOrVisible = isSelectedAtLeastOne ? 'selected' : 'visible';
181185
const areActionsDisabled = isRunning || !isInitialized;
182186

187+
const loadedPluginConfigs = plugins.getLoadedConfigs();
188+
const pluginComponents = getExtensionPointComponents(loadedPluginConfigs, ExtensionPointName.RunTestOptions);
189+
const hasRunTestOptions = pluginComponents.length > 0;
190+
183191
const getViewButtons = (): ReactNode => (
184192
<>
185193
{isRunTestsAvailable && (
@@ -197,6 +205,18 @@ export function TreeActionsToolbar({onHighlightCurrentTest, className}: TreeActi
197205
/>
198206
)
199207
)}
208+
{isRunTestsAvailable && hasRunTestOptions && <Popover
209+
content={<div className={styles.runOptionsContainer}><ExtensionPoint name={ExtensionPointName.RunTestOptions}></ExtensionPoint></div>}
210+
trigger='click'
211+
>
212+
<IconButton
213+
view='flat'
214+
disabled={isRunning || !isInitialized}
215+
className={classNames(styles.iconButton)}
216+
icon={<Icon data={GearPlay} height={14}/>}
217+
tooltip='View run options'
218+
/>
219+
</Popover>}
200220
{isEditScreensAvailable && (
201221
isUndoButtonVisible ?
202222
<IconButton className={styles.iconButton} icon={<Icon data={ArrowUturnCcwLeft} />} tooltip={`Undo accepting ${selectedOrVisible} screenshots`} view={'flat'} onClick={handleUndo} disabled={areActionsDisabled}></IconButton> :
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export enum ExtensionPointName {
22
SettingsPanel = 'settings-panel',
3-
ResultMeta = 'result_meta'
3+
ResultMeta = 'result_meta',
4+
RunTestOptions = 'run-test-options'
45
}

0 commit comments

Comments
 (0)