Skip to content

Commit

Permalink
feat(new-ui): enhance image labels
Browse files Browse the repository at this point in the history
  • Loading branch information
shadowusr committed Oct 2, 2024
1 parent 2478972 commit 5a5e476
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
.screenshot {
padding-right: 1px;
}

.screenshot-container {
display: flex;
flex-direction: column;
}
14 changes: 11 additions & 3 deletions lib/static/new-ui/components/AssertViewResult/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import {connect} from 'react-redux';
import {ImageEntity, State} from '@/static/new-ui/types/store';
import {DiffModeId, TestStatus} from '@/constants';
import {DiffViewer} from '../DiffViewer';
import styles from './index.module.css';
import {Screenshot} from '@/static/new-ui/components/Screenshot';
import {ImageLabel} from '@/static/new-ui/components/ImageLabel';
import {getImageDisplayedSize} from '@/static/new-ui/utils';
import styles from './index.module.css';

interface AssertViewResultProps {
result: ImageEntity;
Expand All @@ -17,9 +19,15 @@ function AssertViewResultInternal({result, diffMode, style}: AssertViewResultPro
if (result.status === TestStatus.FAIL) {
return <DiffViewer diffMode={diffMode} {...result} />;
} else if (result.status === TestStatus.ERROR) {
return <Screenshot containerStyle={style} containerClassName={styles.screenshot} image={result.actualImg} />;
return <div className={styles.screenshotContainer}>
<ImageLabel title={'Actual'} subtitle={getImageDisplayedSize(result.actualImg)} />
<Screenshot containerStyle={style} containerClassName={styles.screenshot} image={result.actualImg} />
</div>;
} else if (result.status === TestStatus.SUCCESS || result.status === TestStatus.UPDATED) {
return <Screenshot containerStyle={style} containerClassName={styles.screenshot} image={result.expectedImg} />;
return <div className={styles.screenshotContainer}>
<ImageLabel title={'Expected'} subtitle={getImageDisplayedSize(result.expectedImg)} />
<Screenshot containerStyle={style} containerClassName={styles.screenshot} image={result.expectedImg} />
</div>;
}

return null;
Expand Down
12 changes: 6 additions & 6 deletions lib/static/new-ui/components/AssertViewStatus/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, {ReactNode} from 'react';
import {ImageEntity, ImageEntityError} from '@/static/new-ui/types/store';
import {TestStatus} from '@/constants';
import {Icon} from '@gravity-ui/uikit';
import {ArrowsRotateLeft, CircleCheck, CircleDashed, CircleExclamation} from '@gravity-ui/icons';
import {FileCheck, CircleCheck, SquareExclamation, SquareXmark, FileLetterX, ArrowRightArrowLeft} from '@gravity-ui/icons';
import {isNoRefImageError} from '@/common-utils';
import styles from './index.module.css';

Expand All @@ -11,18 +11,18 @@ interface AssertViewStatusProps {
}

export function AssertViewStatus({image}: AssertViewStatusProps): ReactNode {
let status = <><Icon data={CircleDashed} width={16}/><span>Failed to compare</span></>;
let status = <><Icon data={SquareXmark} width={16}/><span>Failed to compare</span></>;

if (image === null) {
status = <><Icon data={CircleDashed} width={16}/><span>Image is absent</span></>;
status = <><Icon data={SquareExclamation} width={16}/><span>Image is absent</span></>;
} else if (image.status === TestStatus.SUCCESS) {
status = <><Icon data={CircleCheck} width={16}/><span>Images match</span></>;
} else if (isNoRefImageError((image as ImageEntityError).error)) {
status = <><Icon data={CircleExclamation} width={16}/><span>Reference not found</span></>;
status = <><Icon data={FileLetterX} width={16}/><span>Reference not found</span></>;
} else if (image.status === TestStatus.FAIL) {
status = <><Icon data={CircleExclamation} width={16}/><span>Difference detected</span></>;
status = <><Icon data={ArrowRightArrowLeft} width={16}/><span>Difference detected</span></>;
} else if (image.status === TestStatus.UPDATED) {
status = <><Icon data={ArrowsRotateLeft} width={16}/><span>Reference updated</span></>;
status = <><Icon data={FileCheck} width={16}/><span>Reference updated</span></>;
}

return <div className={styles.container}>{status}</div>;
Expand Down
6 changes: 4 additions & 2 deletions lib/static/new-ui/components/CompactAttemptPicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function CompactAttemptPicker(): ReactNode {
}

return <div className={styles.container}>
<Button view={'outlined'} onClick={onPreviousClick}><Icon data={ChevronLeft}/></Button>
<Button view={'outlined'} onClick={onPreviousClick} disabled={currentAttemptIndex === 0}><Icon data={ChevronLeft}/></Button>
<Select renderControl={({onClick, onKeyDown, ref}): React.JSX.Element => {
return <Button className={styles.attemptSelect} onClick={onClick} extraProps={{onKeyDown}} ref={ref} view={'flat'}>
Attempt <span className={styles.attemptNumber}>
Expand All @@ -63,6 +63,8 @@ export function CompactAttemptPicker(): ReactNode {
return <Select.Option key={index} value={index.toString()} content={`Attempt #${index + 1}`} data={{resultId}}></Select.Option>;
})}
</Select>
<Button view={'outlined'} onClick={onNextClick}><Icon data={ChevronRight}/></Button>
<Button view={'outlined'} onClick={onNextClick} disabled={totalAttemptsCount === null || currentAttemptIndex === totalAttemptsCount - 1}>
<Icon data={ChevronRight}/>
</Button>
</div>;
}
8 changes: 0 additions & 8 deletions lib/static/new-ui/components/DiffViewer/index.module.css
Original file line number Diff line number Diff line change
@@ -1,8 +0,0 @@
.image-label, .image-label + div {
margin-bottom: 8px;
}

.image-label-subtitle {
color: var(--g-color-private-black-400);
margin-left: 4px;
}
17 changes: 5 additions & 12 deletions lib/static/new-ui/components/DiffViewer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {SideBySideToFitMode} from '@/static/new-ui/components/DiffViewer/SideByS
import {ListMode} from '@/static/new-ui/components/DiffViewer/ListMode';
import {getDisplayedDiffPercentValue} from '@/static/new-ui/components/DiffViewer/utils';

import styles from './index.module.css';
import {ImageLabel} from '@/static/new-ui/components/ImageLabel';
import {getImageDisplayedSize} from '@/static/new-ui/utils';

interface DiffViewerProps {
actualImg: ImageFile;
Expand All @@ -31,26 +32,18 @@ interface DiffViewerProps {
}

export function DiffViewer(props: DiffViewerProps): ReactNode {
const getImageDisplayedSize = (image: ImageFile): string => `${image.size.width}×${image.size.height}`;
const getImageLabel = (title: string, subtitle?: string): ReactNode => {
return <div className={styles.imageLabel}>
<span>{title}</span>
{subtitle && <span className={styles.imageLabelSubtitle}>{subtitle}</span>}
</div>;
};

const expectedImg = Object.assign({}, props.expectedImg, {
label: getImageLabel('Expected', getImageDisplayedSize(props.expectedImg))
label: <ImageLabel title={'Expected'} subtitle={getImageDisplayedSize(props.expectedImg)} />
});
const actualImg = Object.assign({}, props.actualImg, {
label: getImageLabel('Actual', getImageDisplayedSize(props.actualImg))
label: <ImageLabel title={'Actual'} subtitle={getImageDisplayedSize(props.actualImg)} />
});
let diffSubtitle: string | undefined;
if (props.differentPixels !== undefined && props.diffRatio !== undefined) {
diffSubtitle = `${props.differentPixels}px ⋅ ${getDisplayedDiffPercentValue(props.diffRatio)}%`;
}
const diffImg = Object.assign({}, props.diffImg, {
label: getImageLabel('Diff', diffSubtitle),
label: <ImageLabel title={'Diff'} subtitle={diffSubtitle} />,
diffClusters: props.diffClusters
});

Expand Down
8 changes: 8 additions & 0 deletions lib/static/new-ui/components/ImageLabel/index.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.image-label, .image-label + div {
margin-bottom: 8px;
}

.image-label-subtitle {
color: var(--g-color-private-black-400);
margin-left: 4px;
}
14 changes: 14 additions & 0 deletions lib/static/new-ui/components/ImageLabel/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React, {ReactNode} from 'react';
import styles from './index.module.css';

interface ImageLabelProps {
title: string;
subtitle?: string;
}

export function ImageLabel({title, subtitle}: ImageLabelProps): ReactNode {
return <div className={styles.imageLabel}>
<span>{title}</span>
{subtitle && <span className={styles.imageLabelSubtitle}>{subtitle}</span>}
</div>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import React, {ReactNode} from 'react';
import {useDispatch, useSelector} from 'react-redux';

import {AssertViewResult} from '@/static/new-ui/components/AssertViewResult';
import {ImageEntity, ImageEntityError, State} from '@/static/new-ui/types/store';
import {ImageEntity, ImageEntityFail, State} from '@/static/new-ui/types/store';
import {DiffModeId, DiffModes, EditScreensFeature, TestStatus} from '@/constants';
import {acceptTest, changeDiffMode, undoAcceptImage} from '@/static/modules/actions';
import {isAcceptable, isScreenRevertable} from '@/static/modules/utils';
import {getCurrentBrowser, getCurrentResult} from '@/static/new-ui/features/suites/selectors';
import {isNoRefImageError} from '@/common-utils';
import {AssertViewStatus} from '@/static/new-ui/components/AssertViewStatus';
import styles from './index.module.css';

Expand Down Expand Up @@ -43,9 +42,10 @@ export function ScreenshotsTreeViewItem(props: ScreenshotsTreeViewItemProps): Re
};

return <div style={props.style} className={styles.container}>
{props.image.status !== TestStatus.UPDATED && props.image.status !== TestStatus.SUCCESS && <div className={styles.toolbarContainer}>
{isNoRefImageError((props.image as ImageEntityError).error) ?
<AssertViewStatus image={props.image}/> :
{props.image.status !== TestStatus.SUCCESS && <div className={styles.toolbarContainer}>
{!(props.image as ImageEntityFail).diffImg &&
<AssertViewStatus image={props.image}/>}
{(props.image as ImageEntityFail).diffImg &&
<div className={styles.diffModeContainer}>
<RadioButton onUpdate={onDiffModeChangeHandler} value={diffMode} className={styles.diffModeSwitcher}>
{Object.values(DiffModes).map(diffMode =>
Expand All @@ -62,7 +62,8 @@ export function ScreenshotsTreeViewItem(props: ScreenshotsTreeViewItemProps): Re
<Select.Option value={diffMode.id} content={diffMode.title} title={diffMode.description} key={diffMode.id}/>
)}
</Select>
</div>}
</div>
}
{isEditScreensAvailable && <div className={styles.buttonsContainer}>
{isUndoAvailable && <Button view={'action'} className={styles.acceptButton} disabled={isRunning} onClick={onScreenshotUndo}>
<Icon data={ArrowUturnCcwLeft}/>Undo
Expand Down
3 changes: 3 additions & 0 deletions lib/static/new-ui/utils/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {Spin} from '@gravity-ui/uikit';
import React from 'react';

import {TestStatus} from '@/constants';
import {ImageFile} from '@/types';

export const getIconByStatus = (status: TestStatus): React.JSX.Element => {
if (status === TestStatus.FAIL || status === TestStatus.ERROR) {
Expand All @@ -27,3 +28,5 @@ export const getFullTitleByTitleParts = (titleParts: string[]): string => {

return titleParts.join(DELIMITER).trim();
};

export const getImageDisplayedSize = (image: ImageFile): string => `${image.size.width}×${image.size.height}`;

0 comments on commit 5a5e476

Please sign in to comment.