|
|
|
|
@ -2,9 +2,14 @@
|
|
|
|
|
//
|
|
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
|
|
|
|
|
import React from 'react';
|
|
|
|
|
import React, { useState } from 'react';
|
|
|
|
|
import { connect } from 'react-redux';
|
|
|
|
|
import Select, { SelectValue, LabeledValue } from 'antd/lib/select';
|
|
|
|
|
import Title from 'antd/lib/typography/Title';
|
|
|
|
|
import Text from 'antd/lib/typography/Text';
|
|
|
|
|
import Paragraph from 'antd/lib/typography/Paragraph';
|
|
|
|
|
import Tooltip from 'antd/lib/tooltip';
|
|
|
|
|
import Modal from 'antd/lib/modal';
|
|
|
|
|
import Icon from 'antd/lib/icon';
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
@ -16,6 +21,8 @@ import { CombinedState } from 'reducers/interfaces';
|
|
|
|
|
interface StateToProps {
|
|
|
|
|
annotationsFilters: string[];
|
|
|
|
|
annotationsFiltersHistory: string[];
|
|
|
|
|
searchForwardShortcut: string;
|
|
|
|
|
searchBackwardShortcut: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface DispatchToProps {
|
|
|
|
|
@ -30,11 +37,16 @@ function mapStateToProps(state: CombinedState): StateToProps {
|
|
|
|
|
filtersHistory: annotationsFiltersHistory,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
shortcuts: {
|
|
|
|
|
normalizedKeyMap,
|
|
|
|
|
},
|
|
|
|
|
} = state;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
annotationsFilters,
|
|
|
|
|
annotationsFiltersHistory,
|
|
|
|
|
searchForwardShortcut: normalizedKeyMap.SEARCH_FORWARD,
|
|
|
|
|
searchBackwardShortcut: normalizedKeyMap.SEARCH_BACKWARD,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -56,13 +68,74 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function filtersHelpModalContent(
|
|
|
|
|
searchForwardShortcut: string,
|
|
|
|
|
searchBackwardShortcut: string,
|
|
|
|
|
): JSX.Element {
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<Paragraph>
|
|
|
|
|
<Title level={3}>General</Title>
|
|
|
|
|
</Paragraph>
|
|
|
|
|
<Paragraph>
|
|
|
|
|
You can use filters to display only subset of objects on a frame
|
|
|
|
|
or to search objects that satisfy the filters using hotkeys
|
|
|
|
|
<Text strong>
|
|
|
|
|
{` ${searchForwardShortcut} `}
|
|
|
|
|
</Text>
|
|
|
|
|
and
|
|
|
|
|
<Text strong>
|
|
|
|
|
{` ${searchBackwardShortcut} `}
|
|
|
|
|
</Text>
|
|
|
|
|
</Paragraph>
|
|
|
|
|
<Paragraph>
|
|
|
|
|
<Text strong>Supported properties: </Text>
|
|
|
|
|
width, height, label, serverID, clientID, type, shape, occluded
|
|
|
|
|
<br />
|
|
|
|
|
<Text strong>Supported operators: </Text>
|
|
|
|
|
==, !=, >, >=, <, <=, ~=, (), & and |
|
|
|
|
|
<br />
|
|
|
|
|
<Text strong>
|
|
|
|
|
If you have double quotes in your query string,
|
|
|
|
|
please escape them using back slash: \" (see the latest example)
|
|
|
|
|
</Text>
|
|
|
|
|
<br />
|
|
|
|
|
All properties and values are case-sensitive.
|
|
|
|
|
CVAT uses json queries to perform search.
|
|
|
|
|
</Paragraph>
|
|
|
|
|
<Paragraph>
|
|
|
|
|
<Title level={3}>Examples</Title>
|
|
|
|
|
<ul>
|
|
|
|
|
<li>label=="car" | label==["road sign"]</li>
|
|
|
|
|
<li>width >= height</li>
|
|
|
|
|
<li>attr["Attribute 1"] == attr["Attribute 2"]</li>
|
|
|
|
|
<li>clientID == 50</li>
|
|
|
|
|
<li>
|
|
|
|
|
(label=="car" & attr["parked"]==true)
|
|
|
|
|
| (label=="pedestrian" & width > 150)
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
(( label==["car \"mazda\""])
|
|
|
|
|
& (attr["sunglasses"]==true
|
|
|
|
|
| (width > 150 | height > 150 & (clientID == serverID)))))
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</Paragraph>
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function AnnotationsFiltersInput(props: StateToProps & DispatchToProps): JSX.Element {
|
|
|
|
|
const {
|
|
|
|
|
annotationsFilters,
|
|
|
|
|
annotationsFiltersHistory,
|
|
|
|
|
searchForwardShortcut,
|
|
|
|
|
searchBackwardShortcut,
|
|
|
|
|
changeAnnotationsFilters,
|
|
|
|
|
} = props;
|
|
|
|
|
|
|
|
|
|
const [underCursor, setUnderCursor] = useState(false);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Select
|
|
|
|
|
className='cvat-annotations-filters-input'
|
|
|
|
|
@ -70,13 +143,36 @@ function AnnotationsFiltersInput(props: StateToProps & DispatchToProps): JSX.Ele
|
|
|
|
|
value={annotationsFilters}
|
|
|
|
|
mode='tags'
|
|
|
|
|
style={{ width: '100%' }}
|
|
|
|
|
placeholder={(
|
|
|
|
|
<>
|
|
|
|
|
<Icon type='filter' />
|
|
|
|
|
<span style={{ marginLeft: 5 }}>Annotations filter</span>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
placeholder={
|
|
|
|
|
underCursor ? (
|
|
|
|
|
<>
|
|
|
|
|
<Tooltip title='Click to open help'>
|
|
|
|
|
<Icon
|
|
|
|
|
type='filter'
|
|
|
|
|
onClick={(e: React.MouseEvent) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
Modal.info({
|
|
|
|
|
width: 700,
|
|
|
|
|
title: 'How to use filters?',
|
|
|
|
|
content: filtersHelpModalContent(
|
|
|
|
|
searchForwardShortcut,
|
|
|
|
|
searchBackwardShortcut,
|
|
|
|
|
),
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
<Icon style={{ transform: 'scale(0.9)' }} type='filter' />
|
|
|
|
|
<span style={{ marginLeft: 5 }}>Annotations filters</span>
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
onChange={changeAnnotationsFilters}
|
|
|
|
|
onMouseEnter={() => setUnderCursor(true)}
|
|
|
|
|
onMouseLeave={() => setUnderCursor(false)}
|
|
|
|
|
>
|
|
|
|
|
{annotationsFiltersHistory.map((element: string): JSX.Element => (
|
|
|
|
|
<Select.Option key={element} value={element}>{element}</Select.Option>
|
|
|
|
|
|