Merge branch 'release-1.4.0'
@ -0,0 +1,50 @@
|
||||
name: Cache
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'develop'
|
||||
|
||||
jobs:
|
||||
Caching_CVAT:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/cvat_cache_server
|
||||
key: ${{ runner.os }}-build-server-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-server-
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/cvat_cache_ui
|
||||
key: ${{ runner.os }}-build-ui-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-ui-
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1.1.2
|
||||
|
||||
- name: Caching CVAT server
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
cache-from: type=local,src=/tmp/cvat_cache_server
|
||||
cache-to: type=local,dest=/tmp/cvat_cache_server-new
|
||||
|
||||
- name: Caching CVAT UI
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.ui
|
||||
cache-from: type=local,src=/tmp/cvat_cache_ui
|
||||
cache-to: type=local,dest=/tmp/cvat_cache_ui-new
|
||||
|
||||
- name: Moving cache
|
||||
run: |
|
||||
rm -rf /tmp/cvat_cache_server
|
||||
mv /tmp/cvat_cache_server-new /tmp/cvat_cache_server
|
||||
rm -rf /tmp/cvat_cache_ui
|
||||
mv /tmp/cvat_cache_ui-new /tmp/cvat_cache_ui
|
||||
@ -0,0 +1,17 @@
|
||||
name: Cancelling Duplicates
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ['CI']
|
||||
types: ['requested']
|
||||
|
||||
jobs:
|
||||
cancel-duplicate-workflow-runs:
|
||||
name: "Cancel duplicate workflow runs"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: potiuk/cancel-workflow-runs@master
|
||||
name: "Cancel duplicate workflow runs"
|
||||
with:
|
||||
cancelMode: duplicates
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
sourceRunId: ${{ github.event.workflow_run.id }}
|
||||
@ -0,0 +1,49 @@
|
||||
name: Linter
|
||||
on: pull_request
|
||||
jobs:
|
||||
HadoLint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Run checks
|
||||
env:
|
||||
HADOLINT: "${{ github.workspace }}/hadolint"
|
||||
HADOLINT_VER: "2.1.0"
|
||||
VERIFICATION_LEVEL: "error"
|
||||
run: |
|
||||
URL="https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files"
|
||||
PR_FILES=$(curl -s -X GET -G $URL | jq -r '.[] | select(.status != "removed") | .filename')
|
||||
for file in $PR_FILES; do
|
||||
if [[ ${file} =~ 'Dockerfile' ]]; then
|
||||
changed_dockerfiles+=" ${file}"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ! -z ${changed_dockerfiles} ]]; then
|
||||
curl -sL -o ${HADOLINT} "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VER}/hadolint-Linux-x86_64" && chmod 700 ${HADOLINT}
|
||||
echo "HadoLint version: "`${HADOLINT} --version`
|
||||
echo "The files will be checked: "`echo ${changed_dockerfiles}`
|
||||
mkdir -p hadolint_report
|
||||
|
||||
${HADOLINT} --no-fail --format json ${changed_dockerfiles} > ./hadolint_report/hadolint_report.json
|
||||
get_verification_level=`cat ./hadolint_report/hadolint_report.json | jq -r '.[] | .level'`
|
||||
for line in ${get_verification_level}; do
|
||||
if [[ ${line} =~ ${VERIFICATION_LEVEL} ]]; then
|
||||
pip install json2html
|
||||
python ./tests/json_to_html.py ./hadolint_report/hadolint_report.json
|
||||
exit 1
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "No files with the \"Dockerfile*\" name found"
|
||||
fi
|
||||
|
||||
- name: Upload artifacts
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: hadolint_report
|
||||
path: hadolint_report
|
||||
@ -0,0 +1,46 @@
|
||||
name: Linter
|
||||
on: pull_request
|
||||
jobs:
|
||||
Remark:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 12
|
||||
|
||||
- name: Run checks
|
||||
run: |
|
||||
URL="https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files"
|
||||
PR_FILES=$(curl -s -X GET -G $URL | jq -r '.[] | select(.status != "removed") | .filename')
|
||||
for files in $PR_FILES; do
|
||||
extension="${files##*.}"
|
||||
if [[ $extension == 'md' ]]; then
|
||||
changed_files_remark+=" ${files}"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ! -z ${changed_files_remark} ]]; then
|
||||
npm ci
|
||||
npm install remark-cli@9.0.0 vfile-reporter-json@2.0.2
|
||||
mkdir -p remark_report
|
||||
|
||||
echo "Remark version: "`npx remark --version`
|
||||
echo "The files will be checked: "`echo ${changed_files_remark}`
|
||||
npx remark --quiet --report json --no-stdout ${changed_files_remark} 2> ./remark_report/remark_report.json
|
||||
get_report=`cat ./remark_report/remark_report.json | jq -r '.[] | select(.messages | length > 0)'`
|
||||
if [[ ! -z ${get_report} ]]; then
|
||||
pip install json2html
|
||||
python ./tests/json_to_html.py ./remark_report/remark_report.json
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "No files with the \"md\" extension found"
|
||||
fi
|
||||
|
||||
- name: Upload artifacts
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: remark_report
|
||||
path: remark_report
|
||||
@ -0,0 +1,42 @@
|
||||
name: Linter
|
||||
on: pull_request
|
||||
jobs:
|
||||
StyleLint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 12
|
||||
|
||||
- name: Run checks
|
||||
run: |
|
||||
URL="https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files"
|
||||
PR_FILES=$(curl -s -X GET -G $URL | jq -r '.[] | select(.status != "removed") | .filename')
|
||||
for files in $PR_FILES; do
|
||||
extension="${files##*.}"
|
||||
if [[ $extension == 'css' || $extension == 'scss' ]]; then
|
||||
changed_files_stylelint+=" ${files}"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ! -z ${changed_files_stylelint} ]]; then
|
||||
npm ci
|
||||
mkdir -p stylelint_report
|
||||
|
||||
echo "StyleLint version: "`npx stylelint --version`
|
||||
echo "The files will be checked: "`echo ${changed_files_stylelint}`
|
||||
npx stylelint --formatter json --output-file ./stylelint_report/stylelint_report.json ${changed_files_stylelint} || exit_code=`echo $?` || true
|
||||
pip install json2html
|
||||
python ./tests/json_to_html.py ./stylelint_report/stylelint_report.json
|
||||
exit ${exit_code}
|
||||
else
|
||||
echo "No files with the \"css|scss\" extension found"
|
||||
fi
|
||||
|
||||
- name: Upload artifacts
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: stylelint_report
|
||||
path: stylelint_report
|
||||
@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- The icon received from: https://www.svgrepo.com/svg/25187/brain -->
|
||||
<!-- License: CC0 Creative Commons License -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 463 463" width="40px" height="40px" style="enable-background:new 0 0 463 463;" xml:space="preserve">
|
||||
<g>
|
||||
<path d="M151.245,222.446C148.054,237.039,135.036,248,119.5,248c-4.142,0-7.5,3.357-7.5,7.5s3.358,7.5,7.5,7.5
|
||||
c23.774,0,43.522-17.557,46.966-40.386c14.556-1.574,27.993-8.06,38.395-18.677c2.899-2.959,2.85-7.708-0.109-10.606
|
||||
c-2.958-2.897-7.707-2.851-10.606,0.108C184.947,202.829,172.643,208,159.5,208c-26.743,0-48.5-21.757-48.5-48.5
|
||||
c0-4.143-3.358-7.5-7.5-7.5s-7.5,3.357-7.5,7.5C96,191.715,120.119,218.384,151.245,222.446z"/>
|
||||
<path d="M183,287.5c0-4.143-3.358-7.5-7.5-7.5c-35.014,0-63.5,28.486-63.5,63.5c0,0.362,0.013,0.725,0.019,1.088
|
||||
C109.23,344.212,106.39,344,103.5,344c-4.142,0-7.5,3.357-7.5,7.5s3.358,7.5,7.5,7.5c26.743,0,48.5,21.757,48.5,48.5
|
||||
c0,4.143,3.358,7.5,7.5,7.5s7.5-3.357,7.5-7.5c0-26.611-16.462-49.437-39.731-58.867c-0.178-1.699-0.269-3.418-0.269-5.133
|
||||
c0-26.743,21.757-48.5,48.5-48.5C179.642,295,183,291.643,183,287.5z"/>
|
||||
<path d="M439,223.5c0-17.075-6.82-33.256-18.875-45.156c1.909-6.108,2.875-12.426,2.875-18.844
|
||||
c0-30.874-22.152-56.659-51.394-62.329C373.841,91.6,375,85.628,375,79.5c0-19.557-11.883-36.387-28.806-43.661
|
||||
C317.999,13.383,287.162,0,263.5,0c-13.153,0-24.817,6.468-32,16.384C224.317,6.468,212.653,0,199.5,0
|
||||
c-23.662,0-54.499,13.383-82.694,35.839C99.883,43.113,88,59.943,88,79.5c0,6.128,1.159,12.1,3.394,17.671
|
||||
C62.152,102.841,40,128.626,40,159.5c0,6.418,0.965,12.735,2.875,18.844C30.82,190.244,24,206.425,24,223.5
|
||||
c0,13.348,4.149,25.741,11.213,35.975C27.872,270.087,24,282.466,24,295.5c0,23.088,12.587,44.242,32.516,55.396
|
||||
C56.173,353.748,56,356.626,56,359.5c0,31.144,20.315,58.679,49.79,68.063C118.611,449.505,141.965,463,167.5,463
|
||||
c27.995,0,52.269-16.181,64-39.674c11.731,23.493,36.005,39.674,64,39.674c25.535,0,48.889-13.495,61.71-35.437
|
||||
c29.475-9.385,49.79-36.92,49.79-68.063c0-2.874-0.173-5.752-0.516-8.604C426.413,339.742,439,318.588,439,295.5
|
||||
c0-13.034-3.872-25.413-11.213-36.025C434.851,249.241,439,236.848,439,223.5z M167.5,448c-21.029,0-40.191-11.594-50.009-30.256
|
||||
c-0.973-1.849-2.671-3.208-4.688-3.751C88.19,407.369,71,384.961,71,359.5c0-3.81,0.384-7.626,1.141-11.344
|
||||
c0.702-3.447-1.087-6.92-4.302-8.35C50.32,332.018,39,314.626,39,295.5c0-8.699,2.256-17.014,6.561-24.379
|
||||
C56.757,280.992,71.436,287,87.5,287c4.142,0,7.5-3.357,7.5-7.5s-3.358-7.5-7.5-7.5C60.757,272,39,250.243,39,223.5
|
||||
c0-14.396,6.352-27.964,17.428-37.221c2.5-2.09,3.365-5.555,2.14-8.574C56.2,171.869,55,165.744,55,159.5
|
||||
c0-26.743,21.757-48.5,48.5-48.5s48.5,21.757,48.5,48.5c0,4.143,3.358,7.5,7.5,7.5s7.5-3.357,7.5-7.5
|
||||
c0-33.642-26.302-61.243-59.421-63.355C104.577,91.127,103,85.421,103,79.5c0-13.369,8.116-24.875,19.678-29.859
|
||||
c0.447-0.133,0.885-0.307,1.308-0.527C127.568,47.752,131.447,47,135.5,47c12.557,0,23.767,7.021,29.256,18.325
|
||||
c1.81,3.727,6.298,5.281,10.023,3.47c3.726-1.809,5.28-6.296,3.47-10.022c-6.266-12.903-18.125-22.177-31.782-25.462
|
||||
C165.609,21.631,184.454,15,199.5,15c13.509,0,24.5,10.99,24.5,24.5v97.051c-6.739-5.346-15.25-8.551-24.5-8.551
|
||||
c-4.142,0-7.5,3.357-7.5,7.5s3.358,7.5,7.5,7.5c13.509,0,24.5,10.99,24.5,24.5v180.279c-9.325-12.031-22.471-21.111-37.935-25.266
|
||||
c-3.999-1.071-8.114,1.297-9.189,5.297c-1.075,4.001,1.297,8.115,5.297,9.189C206.8,343.616,224,366.027,224,391.5
|
||||
C224,422.654,198.654,448,167.5,448z M395.161,339.807c-3.215,1.43-5.004,4.902-4.302,8.35c0.757,3.718,1.141,7.534,1.141,11.344
|
||||
c0,25.461-17.19,47.869-41.803,54.493c-2.017,0.543-3.716,1.902-4.688,3.751C335.691,436.406,316.529,448,295.5,448
|
||||
c-31.154,0-56.5-25.346-56.5-56.5c0-2.109-0.098-4.2-0.281-6.271c0.178-0.641,0.281-1.314,0.281-2.012V135.5
|
||||
c0-13.51,10.991-24.5,24.5-24.5c4.142,0,7.5-3.357,7.5-7.5s-3.358-7.5-7.5-7.5c-9.25,0-17.761,3.205-24.5,8.551V39.5
|
||||
c0-13.51,10.991-24.5,24.5-24.5c15.046,0,33.891,6.631,53.033,18.311c-13.657,3.284-25.516,12.559-31.782,25.462
|
||||
c-1.81,3.727-0.256,8.214,3.47,10.022c3.726,1.81,8.213,0.257,10.023-3.47C303.733,54.021,314.943,47,327.5,47
|
||||
c4.053,0,7.933,0.752,11.514,2.114c0.422,0.22,0.86,0.393,1.305,0.526C351.883,54.624,360,66.13,360,79.5
|
||||
c0,5.921-1.577,11.627-4.579,16.645C322.302,98.257,296,125.858,296,159.5c0,4.143,3.358,7.5,7.5,7.5s7.5-3.357,7.5-7.5
|
||||
c0-26.743,21.757-48.5,48.5-48.5s48.5,21.757,48.5,48.5c0,6.244-1.2,12.369-3.567,18.205c-1.225,3.02-0.36,6.484,2.14,8.574
|
||||
C417.648,195.536,424,209.104,424,223.5c0,26.743-21.757,48.5-48.5,48.5c-4.142,0-7.5,3.357-7.5,7.5s3.358,7.5,7.5,7.5
|
||||
c16.064,0,30.743-6.008,41.939-15.879c4.306,7.365,6.561,15.68,6.561,24.379C424,314.626,412.68,332.018,395.161,339.807z"/>
|
||||
<path d="M359.5,240c-15.536,0-28.554-10.961-31.745-25.554C358.881,210.384,383,183.715,383,151.5c0-4.143-3.358-7.5-7.5-7.5
|
||||
s-7.5,3.357-7.5,7.5c0,26.743-21.757,48.5-48.5,48.5c-13.143,0-25.447-5.171-34.646-14.561c-2.898-2.958-7.647-3.007-10.606-0.108
|
||||
s-3.008,7.647-0.109,10.606c10.402,10.617,23.839,17.103,38.395,18.677C315.978,237.443,335.726,255,359.5,255
|
||||
c4.142,0,7.5-3.357,7.5-7.5S363.642,240,359.5,240z"/>
|
||||
<path d="M335.5,328c-2.89,0-5.73,0.212-8.519,0.588c0.006-0.363,0.019-0.726,0.019-1.088c0-35.014-28.486-63.5-63.5-63.5
|
||||
c-4.142,0-7.5,3.357-7.5,7.5s3.358,7.5,7.5,7.5c26.743,0,48.5,21.757,48.5,48.5c0,1.714-0.091,3.434-0.269,5.133
|
||||
C288.462,342.063,272,364.889,272,391.5c0,4.143,3.358,7.5,7.5,7.5s7.5-3.357,7.5-7.5c0-26.743,21.757-48.5,48.5-48.5
|
||||
c4.142,0,7.5-3.357,7.5-7.5S339.642,328,335.5,328z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
@ -0,0 +1,85 @@
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import Popover from 'antd/lib/popover';
|
||||
import Button from 'antd/lib/button';
|
||||
import { Row, Col } from 'antd/lib/grid';
|
||||
import Text from 'antd/lib/typography/Text';
|
||||
|
||||
import { CombinedState } from 'reducers/interfaces';
|
||||
import CVATTooltip from 'components/common/cvat-tooltip';
|
||||
|
||||
interface LabelKeySelectorPopoverProps {
|
||||
updateLabelShortcutKey(updatedKey: string, labelID: number): void;
|
||||
keyToLabelMapping: Record<string, number>;
|
||||
labelID: number;
|
||||
children: JSX.Element;
|
||||
}
|
||||
|
||||
interface LabelKeySelectorPopoverContentProps {
|
||||
updateLabelShortcutKey(updatedKey: string, labelID: number): void;
|
||||
labelID: number;
|
||||
keyToLabelMapping: Record<string, number>;
|
||||
}
|
||||
|
||||
function PopoverContent(props: LabelKeySelectorPopoverContentProps): JSX.Element {
|
||||
const { keyToLabelMapping, labelID, updateLabelShortcutKey } = props;
|
||||
const labels = useSelector((state: CombinedState) => state.annotation.job.labels);
|
||||
|
||||
return (
|
||||
<div className='cvat-label-item-setup-shortcut-popover'>
|
||||
{[['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9'], ['0']].map((arr, i_) => (
|
||||
<Row justify='space-around' gutter={[16, 16]} key={i_}>
|
||||
{arr.map((i) => {
|
||||
const previousLabelID = keyToLabelMapping[i];
|
||||
const labelName = Number.isInteger(previousLabelID) ?
|
||||
labels.filter((label: any): boolean => label.id === previousLabelID)[0]?.name ||
|
||||
'undefined' :
|
||||
'None';
|
||||
|
||||
return (
|
||||
<Col key={i} span={8}>
|
||||
<CVATTooltip title={labelName}>
|
||||
<Button onClick={() => updateLabelShortcutKey(i, labelID)}>
|
||||
<Text>{`${i}:`}</Text>
|
||||
<Text type='secondary'>{labelName}</Text>
|
||||
</Button>
|
||||
</CVATTooltip>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const MemoizedContent = React.memo(PopoverContent);
|
||||
|
||||
function LabelKeySelectorPopover(props: LabelKeySelectorPopoverProps): JSX.Element {
|
||||
const {
|
||||
children, labelID, updateLabelShortcutKey, keyToLabelMapping,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Popover
|
||||
destroyTooltipOnHide={{ keepParent: false }}
|
||||
trigger='click'
|
||||
content={(
|
||||
<MemoizedContent
|
||||
keyToLabelMapping={keyToLabelMapping}
|
||||
labelID={labelID}
|
||||
updateLabelShortcutKey={updateLabelShortcutKey}
|
||||
/>
|
||||
)}
|
||||
placement='left'
|
||||
>
|
||||
{children}
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(LabelKeySelectorPopover);
|
||||
@ -1,26 +1,106 @@
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
// Copyright (C) 2020-2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import React from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import message from 'antd/lib/message';
|
||||
|
||||
import { CombinedState } from 'reducers/interfaces';
|
||||
import { rememberObject, updateAnnotationsAsync } from 'actions/annotation-actions';
|
||||
import LabelItemContainer from 'containers/annotation-page/standard-workspace/objects-side-bar/label-item';
|
||||
import GlobalHotKeys from 'utils/mousetrap-react';
|
||||
|
||||
interface Props {
|
||||
labelIDs: number[];
|
||||
listHeight: number;
|
||||
}
|
||||
function LabelsListComponent(): JSX.Element {
|
||||
const dispatch = useDispatch();
|
||||
const labels = useSelector((state: CombinedState) => state.annotation.job.labels);
|
||||
const listHeight = useSelector((state: CombinedState) => state.annotation.tabContentHeight);
|
||||
const activatedStateID = useSelector((state: CombinedState) => state.annotation.annotations.activatedStateID);
|
||||
const states = useSelector((state: CombinedState) => state.annotation.annotations.states);
|
||||
const keyMap = useSelector((state: CombinedState) => state.shortcuts.keyMap);
|
||||
|
||||
const labelIDs = labels.map((label: any): number => label.id);
|
||||
|
||||
const [keyToLabelMapping, setKeyToLabelMapping] = useState<Record<string, number>>(
|
||||
Object.fromEntries(labelIDs.slice(0, 10).map((labelID: number, idx: number) => [(idx + 1) % 10, labelID])),
|
||||
);
|
||||
|
||||
const updateLabelShortcutKey = useCallback(
|
||||
(key: string, labelID: number) => {
|
||||
// unassign any keys assigned to the current labels
|
||||
const keyToLabelMappingCopy = { ...keyToLabelMapping };
|
||||
for (const shortKey of Object.keys(keyToLabelMappingCopy)) {
|
||||
if (keyToLabelMappingCopy[shortKey] === labelID) {
|
||||
delete keyToLabelMappingCopy[shortKey];
|
||||
}
|
||||
}
|
||||
|
||||
if (key === '—') {
|
||||
setKeyToLabelMapping(keyToLabelMappingCopy);
|
||||
return;
|
||||
}
|
||||
|
||||
export default function LabelsListComponent(props: Props): JSX.Element {
|
||||
const { listHeight, labelIDs } = props;
|
||||
// check if this key is assigned to another label
|
||||
if (key in keyToLabelMappingCopy) {
|
||||
// try to find a new key for the other label
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const adjustedI = (i + 1) % 10;
|
||||
if (!(adjustedI in keyToLabelMappingCopy)) {
|
||||
keyToLabelMappingCopy[adjustedI] = keyToLabelMappingCopy[key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
// delete assigning to the other label
|
||||
delete keyToLabelMappingCopy[key];
|
||||
}
|
||||
|
||||
// assigning to the current label
|
||||
keyToLabelMappingCopy[key] = labelID;
|
||||
setKeyToLabelMapping(keyToLabelMappingCopy);
|
||||
},
|
||||
[keyToLabelMapping],
|
||||
);
|
||||
|
||||
const subKeyMap = {
|
||||
SWITCH_LABEL: keyMap.SWITCH_LABEL,
|
||||
};
|
||||
|
||||
const handlers = {
|
||||
SWITCH_LABEL: (event: KeyboardEvent | undefined, shortcut: string) => {
|
||||
if (event) event.preventDefault();
|
||||
const labelID = keyToLabelMapping[shortcut.split('+')[1].trim()];
|
||||
const label = labels.filter((_label: any) => _label.id === labelID)[0];
|
||||
if (Number.isInteger(labelID) && label) {
|
||||
if (Number.isInteger(activatedStateID)) {
|
||||
const activatedState = states.filter((state: any) => state.clientID === activatedStateID)[0];
|
||||
if (activatedState) {
|
||||
activatedState.label = label;
|
||||
dispatch(updateAnnotationsAsync([activatedState]));
|
||||
}
|
||||
} else {
|
||||
dispatch(rememberObject({ activeLabelID: labelID }));
|
||||
message.destroy();
|
||||
message.success(`Default label was changed to "${label.name}"`);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ height: listHeight }} className='cvat-objects-sidebar-labels-list'>
|
||||
<GlobalHotKeys keyMap={subKeyMap} handlers={handlers} />
|
||||
{labelIDs.map(
|
||||
(labelID: number): JSX.Element => (
|
||||
<LabelItemContainer key={labelID} labelID={labelID} />
|
||||
<LabelItemContainer
|
||||
key={labelID}
|
||||
labelID={labelID}
|
||||
keyToLabelMapping={keyToLabelMapping}
|
||||
updateLabelShortcutKey={updateLabelShortcutKey}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(LabelsListComponent);
|
||||
|
||||
@ -1,21 +1,56 @@
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
// Copyright (C) 2020-2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import './styles.scss';
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { Row, Col } from 'antd/lib/grid';
|
||||
import Text from 'antd/lib/typography/Text';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import CreateProjectContent from './create-project-content';
|
||||
import { CombinedState } from '../../reducers/interfaces';
|
||||
import CreateProjectContext, { ICreateProjectContext } from './create-project.context';
|
||||
|
||||
export default function CreateProjectPageComponent(): JSX.Element {
|
||||
function CreateProjectPageComponent(props: StateToProps): JSX.Element {
|
||||
const { isTrainingActive } = props;
|
||||
const [projectClass, setProjectClass] = useState('');
|
||||
const [trainingEnabled, setTrainingEnabled] = useState(false);
|
||||
const [isTrainingActiveState] = useState(isTrainingActive);
|
||||
|
||||
const defaultContext: ICreateProjectContext = {
|
||||
projectClass: {
|
||||
value: projectClass,
|
||||
set: setProjectClass,
|
||||
},
|
||||
trainingEnabled: {
|
||||
value: trainingEnabled,
|
||||
set: setTrainingEnabled,
|
||||
},
|
||||
isTrainingActive: {
|
||||
value: isTrainingActiveState,
|
||||
},
|
||||
};
|
||||
return (
|
||||
<Row justify='center' align='top' className='cvat-create-task-form-wrapper'>
|
||||
<Col md={20} lg={16} xl={14} xxl={9}>
|
||||
<Text className='cvat-title'>Create a new project</Text>
|
||||
<CreateProjectContent />
|
||||
</Col>
|
||||
</Row>
|
||||
<CreateProjectContext.Provider value={defaultContext}>
|
||||
<Row justify='center' align='top' className='cvat-create-task-form-wrapper'>
|
||||
<Col md={20} lg={16} xl={14} xxl={9}>
|
||||
<Text className='cvat-title'>Create a new project</Text>
|
||||
<CreateProjectContent />
|
||||
</Col>
|
||||
</Row>
|
||||
</CreateProjectContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
interface StateToProps {
|
||||
isTrainingActive: boolean;
|
||||
}
|
||||
|
||||
function mapStateToProps(state: CombinedState): StateToProps {
|
||||
return {
|
||||
isTrainingActive: state.plugins.list.PREDICT,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(CreateProjectPageComponent);
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2020-2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
import { createContext, Dispatch, SetStateAction } from 'react';
|
||||
|
||||
export interface IState<T> {
|
||||
value: T;
|
||||
set?: Dispatch<SetStateAction<T>>;
|
||||
}
|
||||
|
||||
export function getDefaultState<T>(v: T): IState<T> {
|
||||
return {
|
||||
value: v,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
set: (value: SetStateAction<T>): void => {},
|
||||
};
|
||||
}
|
||||
|
||||
export interface ICreateProjectContext {
|
||||
projectClass: IState<string>;
|
||||
trainingEnabled: IState<boolean>;
|
||||
isTrainingActive: IState<boolean>;
|
||||
}
|
||||
|
||||
export const defaultState: ICreateProjectContext = {
|
||||
projectClass: getDefaultState<string>(''),
|
||||
trainingEnabled: getDefaultState<boolean>(false),
|
||||
isTrainingActive: getDefaultState<boolean>(false),
|
||||
};
|
||||
|
||||
export default createContext<ICreateProjectContext>(defaultState);
|
||||
@ -1,29 +0,0 @@
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import LabelsListComponent from 'components/annotation-page/standard-workspace/objects-side-bar/labels-list';
|
||||
import { CombinedState } from 'reducers/interfaces';
|
||||
|
||||
interface StateToProps {
|
||||
labelIDs: number[];
|
||||
listHeight: number;
|
||||
}
|
||||
|
||||
function mapStateToProps(state: CombinedState): StateToProps {
|
||||
const {
|
||||
annotation: {
|
||||
job: { labels },
|
||||
tabContentHeight: listHeight,
|
||||
},
|
||||
} = state;
|
||||
|
||||
return {
|
||||
labelIDs: labels.map((label: any): number => label.id),
|
||||
listHeight,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(LabelsListComponent);
|
||||
@ -1,26 +0,0 @@
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { CombinedState } from 'reducers/interfaces';
|
||||
import FiltersModalComponent from 'components/annotation-page/top-bar/filters-modal';
|
||||
|
||||
interface StateToProps {
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: CombinedState): StateToProps => {
|
||||
const {
|
||||
annotation: { filtersPanelVisible: visible },
|
||||
} = state;
|
||||
return { visible };
|
||||
};
|
||||
|
||||
function FiltersModalContainer(props: StateToProps): JSX.Element {
|
||||
const { visible } = props;
|
||||
return <FiltersModalComponent visible={visible} />;
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, null)(FiltersModalContainer);
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 172 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 88 KiB |