From 4354f72f9ced78ef4e507d88949cf7780aa38229 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Mon, 21 Oct 2024 18:29:07 +0300 Subject: [PATCH 1/8] Pass quality settings to corresponding components (#8571) --- .../quality-control/quality-control-page.tsx | 14 +++++--------- .../task-quality/allocation-table.tsx | 5 ++++- .../task-quality/quality-magement-tab.tsx | 19 ++++++++----------- .../task-quality/quality-overview-tab.tsx | 4 ++-- cvat-ui/src/reducers/index.ts | 8 +++++--- 5 files changed, 24 insertions(+), 26 deletions(-) diff --git a/cvat-ui/src/components/quality-control/quality-control-page.tsx b/cvat-ui/src/components/quality-control/quality-control-page.tsx index cb00382db30..09f7cfe5e4d 100644 --- a/cvat-ui/src/components/quality-control/quality-control-page.tsx +++ b/cvat-ui/src/components/quality-control/quality-control-page.tsx @@ -17,7 +17,7 @@ import Result from 'antd/lib/result'; import { Job, JobType, QualityReport, QualitySettings, Task, - TargetMetric, TaskValidationLayout, getCore, FramesMetaData, + TaskValidationLayout, getCore, FramesMetaData, } from 'cvat-core-wrapper'; import CVATLoadingSpinner from 'components/common/loading-spinner'; import GoBackButton from 'components/common/go-back-button'; @@ -43,7 +43,6 @@ interface State { qualitySettings: { settings: QualitySettings | null; fetching: boolean; - targetMetric: TargetMetric | null; }; } @@ -107,7 +106,6 @@ const reducer = (state: State, action: ActionUnion): Stat qualitySettings: { ...state.qualitySettings, settings: action.payload.qualitySettings, - targetMetric: action.payload.qualitySettings.targetMetric, }, }; } @@ -172,7 +170,6 @@ function QualityControlPage(): JSX.Element { qualitySettings: { settings: null, fetching: false, - targetMetric: null, }, }); @@ -331,7 +328,6 @@ function QualityControlPage(): JSX.Element { qualitySettings: { settings: qualitySettings, fetching: qualitySettingsFetching, - targetMetric, }, } = state; @@ -372,18 +368,18 @@ function QualityControlPage(): JSX.Element { const tabsItems: NonNullable[0][] = []; - if (targetMetric) { + if (qualitySettings) { tabsItems.push({ key: 'overview', label: 'Overview', children: ( - + ), }); } if (gtJobInstance && gtJobMeta) { - if (validationLayout) { + if (validationLayout && qualitySettings) { tabsItems.push({ key: 'management', label: 'Management', @@ -393,9 +389,9 @@ function QualityControlPage(): JSX.Element { gtJobId={gtJobInstance.id} gtJobMeta={gtJobMeta} validationLayout={validationLayout} + qualitySettings={qualitySettings} onDeleteFrames={onDeleteFrames} onRestoreFrames={onRestoreFrames} - fetching={fetching} /> ), }); diff --git a/cvat-ui/src/components/quality-control/task-quality/allocation-table.tsx b/cvat-ui/src/components/quality-control/task-quality/allocation-table.tsx index 43ac48e4f33..914909bc90c 100644 --- a/cvat-ui/src/components/quality-control/task-quality/allocation-table.tsx +++ b/cvat-ui/src/components/quality-control/task-quality/allocation-table.tsx @@ -14,7 +14,9 @@ import { Key } from 'antd/lib/table/interface'; import Icon, { DeleteOutlined } from '@ant-design/icons'; import { RestoreIcon } from 'icons'; -import { Task, FramesMetaData, TaskValidationLayout } from 'cvat-core-wrapper'; +import { + Task, FramesMetaData, TaskValidationLayout, QualitySettings, +} from 'cvat-core-wrapper'; import CVATTooltip from 'components/common/cvat-tooltip'; import { sorter } from 'utils/quality'; @@ -23,6 +25,7 @@ interface Props { gtJobId: number; gtJobMeta: FramesMetaData; validationLayout: TaskValidationLayout; + qualitySettings: QualitySettings; onDeleteFrames: (frames: number[]) => void; onRestoreFrames: (frames: number[]) => void; } diff --git a/cvat-ui/src/components/quality-control/task-quality/quality-magement-tab.tsx b/cvat-ui/src/components/quality-control/task-quality/quality-magement-tab.tsx index b54fc19e94a..6acc2770be3 100644 --- a/cvat-ui/src/components/quality-control/task-quality/quality-magement-tab.tsx +++ b/cvat-ui/src/components/quality-control/task-quality/quality-magement-tab.tsx @@ -4,9 +4,11 @@ import React from 'react'; import { Row, Col } from 'antd/es/grid'; -import Spin from 'antd/lib/spin'; -import { FramesMetaData, Task, TaskValidationLayout } from 'cvat-core-wrapper'; +import { + FramesMetaData, QualitySettings, + Task, TaskValidationLayout, +} from 'cvat-core-wrapper'; import AllocationTable from './allocation-table'; import SummaryComponent from './summary'; @@ -15,14 +17,15 @@ interface Props { gtJobId: number; gtJobMeta: FramesMetaData; validationLayout: TaskValidationLayout; - fetching: boolean; + qualitySettings: QualitySettings; onDeleteFrames: (frames: number[]) => void; onRestoreFrames: (frames: number[]) => void; } function QualityManagementTab(props: Readonly): JSX.Element { const { - task, gtJobId, gtJobMeta, fetching, validationLayout, + task, gtJobId, gtJobMeta, + validationLayout, qualitySettings, onDeleteFrames, onRestoreFrames, } = props; @@ -32,13 +35,6 @@ function QualityManagementTab(props: Readonly): JSX.Element { return (
- { - fetching && ( -
- -
- ) - } ): JSX.Element { gtJobId={gtJobId} gtJobMeta={gtJobMeta} validationLayout={validationLayout} + qualitySettings={qualitySettings} onDeleteFrames={onDeleteFrames} onRestoreFrames={onRestoreFrames} /> diff --git a/cvat-ui/src/components/quality-control/task-quality/quality-overview-tab.tsx b/cvat-ui/src/components/quality-control/task-quality/quality-overview-tab.tsx index 7bb03ebb31e..04042a66678 100644 --- a/cvat-ui/src/components/quality-control/task-quality/quality-overview-tab.tsx +++ b/cvat-ui/src/components/quality-control/task-quality/quality-overview-tab.tsx @@ -6,13 +6,13 @@ import React from 'react'; import { useSelector } from 'react-redux'; import config from 'config'; -import { TargetMetric, Task } from 'cvat-core-wrapper'; +import { QualitySettings, Task } from 'cvat-core-wrapper'; import { CombinedState } from 'reducers'; import PaidFeaturePlaceholder from 'components/paid-feature-placeholder/paid-feature-placeholder'; interface Props { task: Task; - targetMetric: TargetMetric; + qualitySettings: QualitySettings; } function QualityOverviewTab(): JSX.Element { diff --git a/cvat-ui/src/reducers/index.ts b/cvat-ui/src/reducers/index.ts index a9b89d20cff..6c297cd5f4a 100644 --- a/cvat-ui/src/reducers/index.ts +++ b/cvat-ui/src/reducers/index.ts @@ -8,7 +8,7 @@ import { Canvas, RectDrawingMethod, CuboidDrawingMethod } from 'cvat-canvas-wrap import { Webhook, MLModel, Organization, Job, Task, Project, Label, User, QualityConflict, FramesMetaData, RQStatus, Event, Invitation, SerializedAPISchema, - Request, TargetMetric, JobValidationLayout, + Request, JobValidationLayout, QualitySettings, TaskValidationLayout, } from 'cvat-core-wrapper'; import { IntelligentScissors } from 'utils/opencv-wrapper/intelligent-scissors'; import { KeyMap, KeyMapItem } from 'utils/mousetrap-react'; @@ -269,14 +269,16 @@ export interface PluginsState { qualityControlPage: { overviewTab: ((props: { task: Task; - targetMetric: TargetMetric; + qualitySettings: QualitySettings; }) => JSX.Element)[]; allocationTable: (( props: { task: Task; - gtJob: Job; + gtJobId: number; gtJobMeta: FramesMetaData; + qualitySettings: QualitySettings; + validationLayout: TaskValidationLayout; onDeleteFrames: (frames: number[]) => void; onRestoreFrames: (frames: number[]) => void; }) => JSX.Element)[]; From 2cca2dd3cc61290aeac138443979cd28571e5846 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Tue, 22 Oct 2024 13:05:59 +0300 Subject: [PATCH 2/8] Fixed tooltips with undefined shortcuts (#8578) --- .../20241022_121246_sekachev.bs_fixed_undefined_shortcuts.md | 4 ++++ .../standard-workspace/objects-side-bar/object-item.tsx | 2 +- .../controls-side-bar/draw-shape-popover.tsx | 2 +- .../controls-side-bar/setup-tag-popover.tsx | 2 +- cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 changelog.d/20241022_121246_sekachev.bs_fixed_undefined_shortcuts.md diff --git a/changelog.d/20241022_121246_sekachev.bs_fixed_undefined_shortcuts.md b/changelog.d/20241022_121246_sekachev.bs_fixed_undefined_shortcuts.md new file mode 100644 index 00000000000..567059d5198 --- /dev/null +++ b/changelog.d/20241022_121246_sekachev.bs_fixed_undefined_shortcuts.md @@ -0,0 +1,4 @@ +### Fixed + +- Fixed some interface tooltips having 'undefined' shortcuts + () diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx index 9e6ff1f609c..30811abad1c 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx @@ -118,7 +118,7 @@ function ObjectItemComponent(props: Props): JSX.Element { propagateShortcut={normalizedKeyMap.PROPAGATE_OBJECT} toBackgroundShortcut={normalizedKeyMap.TO_BACKGROUND} toForegroundShortcut={normalizedKeyMap.TO_FOREGROUND} - removeShortcut={normalizedKeyMap.DELETE_OBJECT} + removeShortcut={normalizedKeyMap.DELETE_OBJECT_STANDARD_WORKSPACE} changeColorShortcut={normalizedKeyMap.CHANGE_OBJECT_COLOR} sliceShortcut={normalizedKeyMap.SWITCH_SLICE_MODE} changeLabel={changeLabel} diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx index 45325a7ec6a..50e7ac51183 100644 --- a/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx +++ b/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx @@ -204,7 +204,7 @@ class DrawShapePopoverContainer extends React.PureComponent { numberOfPoints={numberOfPoints} rectDrawingMethod={rectDrawingMethod} cuboidDrawingMethod={cuboidDrawingMethod} - repeatShapeShortcut={normalizedKeyMap.SWITCH_DRAW_MODE} + repeatShapeShortcut={normalizedKeyMap.SWITCH_DRAW_MODE_STANDARD_CONTROLS} onChangeLabel={this.onChangeLabel} onChangePoints={this.onChangePoints} onChangeRectDrawingMethod={this.onChangeRectDrawingMethod} diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/setup-tag-popover.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/setup-tag-popover.tsx index 392dfa11785..1c623695619 100644 --- a/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/setup-tag-popover.tsx +++ b/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/setup-tag-popover.tsx @@ -154,7 +154,7 @@ class DrawShapePopoverContainer extends React.PureComponent { diff --git a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx index 4d81fa0822c..e9d2785faf1 100644 --- a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx +++ b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx @@ -697,7 +697,7 @@ class AnnotationTopBarContainer extends React.PureComponent { redoAction={redoAction} undoShortcut={normalizedKeyMap.UNDO} redoShortcut={normalizedKeyMap.REDO} - drawShortcut={normalizedKeyMap.SWITCH_DRAW_MODE} + drawShortcut={normalizedKeyMap.SWITCH_DRAW_MODE_STANDARD_CONTROLS} switchToolsBlockerShortcut={normalizedKeyMap.SWITCH_TOOLS_BLOCKER_STATE} playPauseShortcut={normalizedKeyMap.PLAY_PAUSE} deleteFrameShortcut={normalizedKeyMap.DELETE_FRAME} From 1d4632cccbf0903056d251a4eb4190fcd517785d Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Tue, 22 Oct 2024 14:15:33 +0300 Subject: [PATCH 3/8] Remove our copy of the wait-for-it script (#8572) Nowadays it's available from the Ubuntu repositories, so install it from there. This declutters our root directory a bit, plus it makes enumerating 3rd-party dependencies easier. --- Dockerfile | 3 +- backend_entrypoint.sh | 4 +- wait-for-it.sh | 178 ------------------------------------------ wait_for_deps.sh | 6 +- 4 files changed, 7 insertions(+), 184 deletions(-) delete mode 100755 wait-for-it.sh diff --git a/Dockerfile b/Dockerfile index 8a10a34b771..00dea1de30d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -134,6 +134,7 @@ RUN apt-get update && \ supervisor \ tzdata \ unrar \ + wait-for-it \ && ln -fs /usr/share/zoneinfo/${TZ} /etc/localtime && \ dpkg-reconfigure -f noninteractive tzdata && \ rm -rf /var/lib/apt/lists/* && \ @@ -192,7 +193,7 @@ RUN python -m pip uninstall -y pip COPY cvat/nginx.conf /etc/nginx/nginx.conf COPY --chown=${USER} components /tmp/components COPY --chown=${USER} supervisord/ ${HOME}/supervisord -COPY --chown=${USER} wait-for-it.sh manage.py backend_entrypoint.sh wait_for_deps.sh ${HOME}/ +COPY --chown=${USER} manage.py backend_entrypoint.sh wait_for_deps.sh ${HOME}/ COPY --chown=${USER} utils/ ${HOME}/utils COPY --chown=${USER} cvat/ ${HOME}/cvat COPY --chown=${USER} rqscheduler.py ${HOME} diff --git a/backend_entrypoint.sh b/backend_entrypoint.sh index 39c1d7d90cc..bac37c76e5b 100755 --- a/backend_entrypoint.sh +++ b/backend_entrypoint.sh @@ -8,7 +8,7 @@ fail() { } wait_for_db() { - ~/wait-for-it.sh "${CVAT_POSTGRES_HOST}:${CVAT_POSTGRES_PORT:-5432}" -t 0 + wait-for-it "${CVAT_POSTGRES_HOST}:${CVAT_POSTGRES_PORT:-5432}" -t 0 } cmd_bash() { @@ -19,7 +19,7 @@ cmd_init() { wait_for_db ~/manage.py migrate - ~/wait-for-it.sh "${CVAT_REDIS_INMEM_HOST}:${CVAT_REDIS_INMEM_PORT:-6379}" -t 0 + wait-for-it "${CVAT_REDIS_INMEM_HOST}:${CVAT_REDIS_INMEM_PORT:-6379}" -t 0 ~/manage.py syncperiodicjobs } diff --git a/wait-for-it.sh b/wait-for-it.sh deleted file mode 100755 index 12f10ee7dcd..00000000000 --- a/wait-for-it.sh +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/env bash -# Use this script to test if a given TCP host/port are available -# https://github.com/vishnubob/wait-for-it - -cmdname=$(basename $0) - -echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } - -usage() -{ - cat << USAGE >&2 -Usage: - $cmdname host:port [-s] [-t timeout] [-- command args] - -h HOST | --host=HOST Host or IP under test - -p PORT | --port=PORT TCP port under test - Alternatively, you specify the host and port as host:port - -s | --strict Only execute subcommand if the test succeeds - -q | --quiet Don't output any status messages - -t TIMEOUT | --timeout=TIMEOUT - Timeout in seconds, zero for no timeout - -- COMMAND ARGS Execute command with args after the test finishes -USAGE - exit 1 -} - -wait_for() -{ - if [[ $TIMEOUT -gt 0 ]]; then - echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT" - else - echoerr "$cmdname: waiting for $HOST:$PORT without a timeout" - fi - start_ts=$(date +%s) - while : - do - if [[ $ISBUSY -eq 1 ]]; then - nc -z $HOST $PORT - result=$? - else - (echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1 - result=$? - fi - if [[ $result -eq 0 ]]; then - end_ts=$(date +%s) - echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds" - break - fi - sleep 1 - done - return $result -} - -wait_for_wrapper() -{ - # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 - if [[ $QUIET -eq 1 ]]; then - timeout $BUSYTIMEFLAG $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & - else - timeout $BUSYTIMEFLAG $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & - fi - PID=$! - trap "kill -INT -$PID" INT - wait $PID - RESULT=$? - if [[ $RESULT -ne 0 ]]; then - echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT" - fi - return $RESULT -} - -# process arguments -while [[ $# -gt 0 ]] -do - case "$1" in - *:* ) - hostport=(${1//:/ }) - HOST=${hostport[0]} - PORT=${hostport[1]} - shift 1 - ;; - --child) - CHILD=1 - shift 1 - ;; - -q | --quiet) - QUIET=1 - shift 1 - ;; - -s | --strict) - STRICT=1 - shift 1 - ;; - -h) - HOST="$2" - if [[ $HOST == "" ]]; then break; fi - shift 2 - ;; - --host=*) - HOST="${1#*=}" - shift 1 - ;; - -p) - PORT="$2" - if [[ $PORT == "" ]]; then break; fi - shift 2 - ;; - --port=*) - PORT="${1#*=}" - shift 1 - ;; - -t) - TIMEOUT="$2" - if [[ $TIMEOUT == "" ]]; then break; fi - shift 2 - ;; - --timeout=*) - TIMEOUT="${1#*=}" - shift 1 - ;; - --) - shift - CLI=("$@") - break - ;; - --help) - usage - ;; - *) - echoerr "Unknown argument: $1" - usage - ;; - esac -done - -if [[ "$HOST" == "" || "$PORT" == "" ]]; then - echoerr "Error: you need to provide a host and port to test." - usage -fi - -TIMEOUT=${TIMEOUT:-15} -STRICT=${STRICT:-0} -CHILD=${CHILD:-0} -QUIET=${QUIET:-0} - -# check to see if timeout is from busybox? -# check to see if timeout is from busybox? -TIMEOUT_PATH=$(realpath $(which timeout)) -if [[ $TIMEOUT_PATH =~ "busybox" ]]; then - ISBUSY=1 - BUSYTIMEFLAG="-t" -else - ISBUSY=0 - BUSYTIMEFLAG="" -fi - -if [[ $CHILD -gt 0 ]]; then - wait_for - RESULT=$? - exit $RESULT -else - if [[ $TIMEOUT -gt 0 ]]; then - wait_for_wrapper - RESULT=$? - else - wait_for - RESULT=$? - fi -fi - -if [[ $CLI != "" ]]; then - if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then - echoerr "$cmdname: strict mode, refusing to execute subprocess" - exit $RESULT - fi - exec "${CLI[@]}" -else - exit $RESULT -fi diff --git a/wait_for_deps.sh b/wait_for_deps.sh index c78950cf96c..6cf96886fd6 100755 --- a/wait_for_deps.sh +++ b/wait_for_deps.sh @@ -11,8 +11,8 @@ # but it's too resource-intensive to execute for every worker we might be running # in a container. Instead, it's in backend_entrypoint.sh. -~/wait-for-it.sh "${CVAT_POSTGRES_HOST}:${CVAT_POSTGRES_PORT:-5432}" -t 0 -~/wait-for-it.sh "${CVAT_REDIS_INMEM_HOST}:${CVAT_REDIS_INMEM_PORT}" -t 0 -~/wait-for-it.sh "${CVAT_REDIS_ONDISK_HOST}:${CVAT_REDIS_ONDISK_PORT}" -t 0 +wait-for-it "${CVAT_POSTGRES_HOST}:${CVAT_POSTGRES_PORT:-5432}" -t 0 +wait-for-it "${CVAT_REDIS_INMEM_HOST}:${CVAT_REDIS_INMEM_PORT}" -t 0 +wait-for-it "${CVAT_REDIS_ONDISK_HOST}:${CVAT_REDIS_ONDISK_PORT}" -t 0 exec "$@" From 036b17ae0eb601aeab5ac4f6b0288a638a3abc3d Mon Sep 17 00:00:00 2001 From: Alecto Date: Tue, 22 Oct 2024 13:27:28 +0200 Subject: [PATCH 4/8] Fix grafana container restart policy (#8577) ### Motivation and context Fixes #8576 ### How has this been tested? I've tried it on my CVAT installation and it works. ### Checklist - [x] I submit my changes into the `develop` branch - [x] I have created a changelog fragment - [ ] I have updated the documentation accordingly - [ ] I have added tests to cover my changes - [x] I have linked related issues (see [GitHub docs]( https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword)) ### License - [x] I submit _my code changes_ under the same [MIT License]( https://github.com/cvat-ai/cvat/blob/develop/LICENSE) that covers the project. Feel free to contact the maintainers if that's a concern. ## Summary by CodeRabbit - **New Features** - Introduced a new service, `cvat_grafana`, for enhanced Grafana container management. - Configured automatic restart and integrated with ClickHouse environment settings. - Added authentication options and plugin installations for Grafana. - Custom entrypoint script for setup of data sources and dashboards. - **Bug Fixes** - Resolved issues with the Grafana container restart policy to ensure proper management. --- changelog.d/20241022_114627_gui-u.md | 4 ++++ docker-compose.yml | 1 + 2 files changed, 5 insertions(+) create mode 100644 changelog.d/20241022_114627_gui-u.md diff --git a/changelog.d/20241022_114627_gui-u.md b/changelog.d/20241022_114627_gui-u.md new file mode 100644 index 00000000000..efa896e3328 --- /dev/null +++ b/changelog.d/20241022_114627_gui-u.md @@ -0,0 +1,4 @@ +### Fixed + +- Fix Grafana container restart policy + () diff --git a/docker-compose.yml b/docker-compose.yml index 569e163e9fe..0d3f802c82f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -329,6 +329,7 @@ services: cvat_grafana: image: grafana/grafana-oss:10.1.2 + restart: always container_name: cvat_grafana environment: <<: *clickhouse-env From 5045f6a6d80d73276f1f662fa32e9545a3acfe7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gordon=20B=C3=B6er?= <1067159+gboeer@users.noreply.github.com> Date: Tue, 22 Oct 2024 15:08:45 +0200 Subject: [PATCH 5/8] fix broken nuclio doc links (#8582) --- site/content/en/docs/manual/advanced/serverless-tutorial.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/site/content/en/docs/manual/advanced/serverless-tutorial.md b/site/content/en/docs/manual/advanced/serverless-tutorial.md index 7355d22d982..5211886208e 100644 --- a/site/content/en/docs/manual/advanced/serverless-tutorial.md +++ b/site/content/en/docs/manual/advanced/serverless-tutorial.md @@ -974,9 +974,9 @@ you can use the Ubuntu subsystem, for this do the following: [detectron2-tutorial]: https://detectron2.readthedocs.io/en/latest/tutorials/getting_started.html [retinanet-model-zoo]: https://github.com/facebookresearch/detectron2/blob/master/MODEL_ZOO.md#retinanet [faster-rcnn-function]: https://raw.githubusercontent.com/cvat-ai/cvat/38b774046d41d604ed85a521587e4bacce61b69c/serverless/tensorflow/faster_rcnn_inception_v2_coco/nuclio/function.yaml -[nuclio-doc]: https://nuclio.io/docs/latest/reference/function-configuration/function-configuration-reference/ -[nuclio-http-trigger-doc]: https://nuclio.io/docs/latest/reference/triggers/http/ -[nuclio-bkms-doc]: https://nuclio.io/docs/latest/concepts/best-practices-and-common-pitfalls/ +[nuclio-doc]: https://nuclio.io/docs/latest/reference/function-configuration/function-configuration-reference.html +[nuclio-http-trigger-doc]: https://nuclio.io/docs/latest/reference/triggers/http.html +[nuclio-bkms-doc]: https://nuclio.io/docs/latest/concepts/best-practices-and-common-pitfalls.html [retinanet-function-yaml]: https://github.com/cvat-ai/cvat/blob/b2f616859ca64687c385e636b4a25014fbb9d17c/serverless/pytorch/facebookresearch/detectron2/retinanet/nuclio/function.yaml [retinanet-main-py]: https://github.com/cvat-ai/cvat/blob/b2f616859ca64687c385e636b4a25014fbb9d17c/serverless/pytorch/facebookresearch/detectron2/retinanet/nuclio/main.py [nuclio-homepage]: https://nuclio.io/ From bcd06276811bed67e340458a4f143785e5878aaa Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Tue, 22 Oct 2024 20:04:32 +0300 Subject: [PATCH 6/8] Fix a bug where retrying an export RQ job may break scheduling (#8584) `_patched_retry` tries to schedule a copy of the current job. In particular, it copies the dependencies of the old job using `current_rq_job.dependency_ids`. Unfortunately, `dependency_ids` does not return IDs of dependency jobs, as one might expect. It actually returns the Redis _keys_ corresponding to those jobs, as bytestrings. The RQ job creation code does not support bytestrings as dependency specifiers, so it unintentionally treats them as sequences, saving the individual bytes (as integers) as the dependency job IDs. But since IDs have to be strings, the scheduler quickly crashes when it tries to use those integer "IDs" to construct Redis keys. Thankfully, we don't actually need to get the dependency IDs. `_patched_retry` is only used inside running jobs, and if a job is running, it means that all its dependencies are already completed. Thus, the newly scheduled job doesn't need to have any dependencies at all. --- .../20241022_191618_roman_fix_integer_dependencies.md | 5 +++++ cvat/apps/dataset_manager/views.py | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 changelog.d/20241022_191618_roman_fix_integer_dependencies.md diff --git a/changelog.d/20241022_191618_roman_fix_integer_dependencies.md b/changelog.d/20241022_191618_roman_fix_integer_dependencies.md new file mode 100644 index 00000000000..974f29bc63c --- /dev/null +++ b/changelog.d/20241022_191618_roman_fix_integer_dependencies.md @@ -0,0 +1,5 @@ +### Fixed + +- Fixed a bug where an export RQ job being retried may break scheduling + of new jobs + () diff --git a/cvat/apps/dataset_manager/views.py b/cvat/apps/dataset_manager/views.py index 35e40c8c03a..1dbff55ed08 100644 --- a/cvat/apps/dataset_manager/views.py +++ b/cvat/apps/dataset_manager/views.py @@ -85,7 +85,6 @@ def _patched_retry(*_1, **_2): **current_rq_job.kwargs, job_id=current_rq_job.id, meta=current_rq_job.meta, - depends_on=current_rq_job.dependency_ids, job_ttl=current_rq_job.ttl, job_result_ttl=current_rq_job.result_ttl, job_description=current_rq_job.description, From 13fac287bd34b5c7d1fa79e97cc5ddf428f54056 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Wed, 23 Oct 2024 09:23:45 +0300 Subject: [PATCH 7/8] Fix typos in UI code (#8583) --- cvat-core/src/annotations-collection.ts | 2 +- cvat-core/src/cloud-storage.ts | 2 +- cvat-core/src/frames.ts | 4 ++-- cvat-core/src/object-utils.ts | 2 +- cvat-core/src/requests-manager.ts | 2 +- cvat-core/src/server-proxy.ts | 2 +- cvat-core/src/session-implementation.ts | 4 ++-- cvat-data/src/ts/3rdparty/README.md | 4 ++-- cvat-data/src/ts/unzip_imgs.worker.ts | 2 +- cvat-ui/react_nginx.conf | 2 +- cvat-ui/src/components/model-runner-modal/object-mapper.tsx | 2 +- .../components/tasks-page/automatic-annotation-progress.tsx | 2 +- cvat-ui/src/utils/environment.ts | 2 +- cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts | 2 +- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/cvat-core/src/annotations-collection.ts b/cvat-core/src/annotations-collection.ts index 291fcc6c3e9..14879e86bcd 100644 --- a/cvat-core/src/annotations-collection.ts +++ b/cvat-core/src/annotations-collection.ts @@ -1295,7 +1295,7 @@ export default class Collection { const predicate = sign > 0 ? (frame) => frame <= frameTo : (frame) => frame >= frameTo; const update = sign > 0 ? (frame) => frame + 1 : (frame) => frame - 1; - // if not looking for an emty frame nor frame with annotations, return the next frame + // if not looking for an empty frame nor frame with annotations, return the next frame // check if deleted frames are allowed additionally if (!annotationsFilters) { let frame = frameFrom; diff --git a/cvat-core/src/cloud-storage.ts b/cvat-core/src/cloud-storage.ts index e4e4fb0e5d2..1e7cdeb8d7f 100644 --- a/cvat-core/src/cloud-storage.ts +++ b/cvat-core/src/cloud-storage.ts @@ -290,7 +290,7 @@ Object.defineProperties(CloudStorage.prototype.save, { } // update if (typeof this.id !== 'undefined') { - // provider_type and recource should not change; + // provider_type and resource should not change; // send to the server only the values that have changed const initialData: SerializedCloudStorage = {}; if (this.displayName) { diff --git a/cvat-core/src/frames.ts b/cvat-core/src/frames.ts index 1192058c11b..b29335865d0 100644 --- a/cvat-core/src/frames.ts +++ b/cvat-core/src/frames.ts @@ -683,7 +683,7 @@ export function getContextImage(jobID: number, frame: number): Promise setTimeout(checkAndExecute)); } else { @@ -775,7 +775,7 @@ export async function getFrame( // - getContextImage // - getCachedChunks // And from this idea we should call refreshJobCacheIfOutdated from each one - // Hovewer, following from the order, these methods are usually called + // However, following from the order, these methods are usually called // it may lead to even more confusing behaviour // // Usually user first receives frame, then user receives ranges and finally user receives context images diff --git a/cvat-core/src/object-utils.ts b/cvat-core/src/object-utils.ts index 0c4a3e5d814..6e7fcbbd8d8 100644 --- a/cvat-core/src/object-utils.ts +++ b/cvat-core/src/object-utils.ts @@ -60,7 +60,7 @@ export function findAngleDiff(rightAngle: number, leftAngle: number): number { angleDiff = ((angleDiff + 180) % 360) - 180; if (Math.abs(angleDiff) >= 180) { // if the main arc is bigger than 180, go another arc - // to find it, just substract absolute value from 360 and inverse sign + // to find it, just subtract absolute value from 360 and inverse sign angleDiff = 360 - Math.abs(angleDiff) * Math.sign(angleDiff) * -1; } return angleDiff; diff --git a/cvat-core/src/requests-manager.ts b/cvat-core/src/requests-manager.ts index 429c42dba2f..c348923e68b 100644 --- a/cvat-core/src/requests-manager.ts +++ b/cvat-core/src/requests-manager.ts @@ -74,7 +74,7 @@ class RequestsManager { const promise = new Promise((resolve, reject) => { const timeoutCallback = async (): Promise => { // We make sure that no more than REQUESTS_COUNT requests are sent simultaneously - // If thats the case, we re-schedule the timeout + // If that's the case, we re-schedule the timeout const timestamp = Date.now(); if (this.requestStack.length >= REQUESTS_COUNT) { const timestampToCheck = this.requestStack[this.requestStack.length - 1]; diff --git a/cvat-core/src/server-proxy.ts b/cvat-core/src/server-proxy.ts index be8d3d4fb63..eb9c15ce64b 100644 --- a/cvat-core/src/server-proxy.ts +++ b/cvat-core/src/server-proxy.ts @@ -102,7 +102,7 @@ function fetchAll(url, filter = {}): Promise { } }); - // removing possible dublicates + // removing possible duplicates const obj = result.results.reduce((acc: Record, item: any) => { acc[item.id] = item; return acc; diff --git a/cvat-core/src/session-implementation.ts b/cvat-core/src/session-implementation.ts index 47810637db3..369d0c9d539 100644 --- a/cvat-core/src/session-implementation.ts +++ b/cvat-core/src/session-implementation.ts @@ -377,7 +377,7 @@ export function implementJob(Job: typeof JobClass): typeof JobClass { } if ('annotationsFilters' in searchParameters && 'generalFilters' in searchParameters) { - throw new ArgumentError('Both annotations filters and general fiters could not be used together'); + throw new ArgumentError('Both annotations filters and general filters could not be used together'); } if (!Number.isInteger(frameFrom) || !Number.isInteger(frameTo)) { @@ -1046,7 +1046,7 @@ export function implementTask(Task: typeof TaskClass): typeof TaskClass { } if ('annotationsFilters' in searchParameters && 'generalFilters' in searchParameters) { - throw new ArgumentError('Both annotations filters and general fiters could not be used together'); + throw new ArgumentError('Both annotations filters and general filters could not be used together'); } if (!Number.isInteger(frameFrom) || !Number.isInteger(frameTo)) { diff --git a/cvat-data/src/ts/3rdparty/README.md b/cvat-data/src/ts/3rdparty/README.md index 32ff0a20ab5..2bcd37af45b 100644 --- a/cvat-data/src/ts/3rdparty/README.md +++ b/cvat-data/src/ts/3rdparty/README.md @@ -10,8 +10,8 @@ These files are from the [Broadway.js](https://github.com/mbebenita/Broadway) re Authors don't provide an npm package, so we need to store these components in our repository. We use this dependency to decode video chunks from a server and split them to frames on client side. -We need to run this package in node environent (for example for debug, or for running unit tests). -But there aren't any ways to do that (even with syntetic environment, provided for example by the package ``browser-env``). +We need to run this package in node environment (for example for debug, or for running unit tests). +But there aren't any ways to do that (even with synthetic environment, provided for example by the package ``browser-env``). For example there are issues with canvas using (webpack doesn't work with binary canvas package for node-js) and others. So, we have solved to write patch file for this library. It modifies source code a little to support our scenario of using. diff --git a/cvat-data/src/ts/unzip_imgs.worker.ts b/cvat-data/src/ts/unzip_imgs.worker.ts index 70d8299e7c3..4ca131a0995 100644 --- a/cvat-data/src/ts/unzip_imgs.worker.ts +++ b/cvat-data/src/ts/unzip_imgs.worker.ts @@ -34,7 +34,7 @@ onmessage = (e) => { .async('blob') .then((fileData) => { if (!errored) { - // do not need to read the rest of block if an error already occured + // do not need to read the rest of block if an error already occurred if (dimension === dimension2D) { createImageBitmap(fileData).then((img) => { postMessage({ diff --git a/cvat-ui/react_nginx.conf b/cvat-ui/react_nginx.conf index 5f1f4b48997..6f9437ebbd7 100644 --- a/cvat-ui/react_nginx.conf +++ b/cvat-ui/react_nginx.conf @@ -1,7 +1,7 @@ server { root /usr/share/nginx/html; - # Disable server signature to make it slighty harder for + # Disable server signature to make it slightly harder for # attackers to find known vulnerabilities. See # https://datatracker.ietf.org/doc/html/rfc9110#name-server server_tokens off; diff --git a/cvat-ui/src/components/model-runner-modal/object-mapper.tsx b/cvat-ui/src/components/model-runner-modal/object-mapper.tsx index b1bb2b889d8..530d59bc54a 100644 --- a/cvat-ui/src/components/model-runner-modal/object-mapper.tsx +++ b/cvat-ui/src/components/model-runner-modal/object-mapper.tsx @@ -40,7 +40,7 @@ function ObjectMapperComponent(props: Props): JSX.Element { const [rightValue, setRightValue] = useState(null); const setMappingWrapper = (updated: Props['defaultMapping']): void => { - // if we prefer useEffect instead of this approch + // if we prefer useEffect instead of this approach // component will be rerendered first with extras that depends on parent state // these extras will use outdated information in this case onUpdateMapping(updated); diff --git a/cvat-ui/src/components/tasks-page/automatic-annotation-progress.tsx b/cvat-ui/src/components/tasks-page/automatic-annotation-progress.tsx index 8dbb152ef9e..8b2ecd50768 100644 --- a/cvat-ui/src/components/tasks-page/automatic-annotation-progress.tsx +++ b/cvat-ui/src/components/tasks-page/automatic-annotation-progress.tsx @@ -63,7 +63,7 @@ export default function AutomaticAnnotationProgress(props: Props): JSX.Element | return (<>Unknown status received); } - return <>Automatic annotation accomplisted; + return <>Automatic annotation accomplished; })()} diff --git a/cvat-ui/src/utils/environment.ts b/cvat-ui/src/utils/environment.ts index 15a6e4178b6..9f73417199c 100644 --- a/cvat-ui/src/utils/environment.ts +++ b/cvat-ui/src/utils/environment.ts @@ -25,7 +25,7 @@ export function customWaViewHit(pageName?: string, queryString?: string, hashInf waHitFunction(pageName, queryString, hashInfo); } catch (error: any) { // eslint-disable-next-line - console.error(`Web analitycs hit function has failed. ${error.toString()}`); + console.error(`Web analytics hit function has failed. ${error.toString()}`); } } } diff --git a/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts b/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts index b2d045c3248..cc74252a824 100644 --- a/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts +++ b/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts @@ -201,7 +201,7 @@ export class OpenCVWrapper { cv.findContours(expanded, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE); for (let i = 0; i < contours.size(); i++) { const contour = contours.get(i); - // substract offset we created when copied source image + // subtract offset we created when copied source image jsContours.push(Array.from(contour.data32S as number[]).map((el) => el - 1)); contour.delete(); } From 6a2636207ef437976a194d954e55cbf59d3e950f Mon Sep 17 00:00:00 2001 From: Dmitrii Lavrukhin Date: Wed, 23 Oct 2024 11:36:18 +0400 Subject: [PATCH 8/8] Analytics access (#8509) Checkbox for granting access to analytics --- ...itrii.lavrukhin_analytics_bool_field_v3.md | 4 + cvat-core/src/server-response-types.ts | 1 + cvat-core/src/user.ts | 8 +- cvat-ui/src/components/header/header.tsx | 2 +- .../0086_profile_has_analytics_access.py | 35 ++++++ cvat/apps/engine/models.py | 15 ++- cvat/apps/engine/serializers.py | 15 ++- cvat/apps/engine/signals.py | 26 +++- cvat/apps/engine/tests/test_rest_api.py | 6 + cvat/apps/iam/admin.py | 13 ++ cvat/apps/iam/permissions.py | 18 ++- cvat/apps/log_viewer/permissions.py | 20 +++- cvat/apps/log_viewer/rules/analytics.rego | 11 +- .../rules/tests/configs/analytics.csv | 6 +- .../generators/analytics_test.gen.rego.py | 31 ++--- cvat/schema.yml | 3 + tests/python/rest_api/test_analytics.py | 15 ++- tests/python/shared/assets/cvat_db/data.json | 111 +++++++----------- tests/python/shared/assets/users.json | 21 ++++ tests/python/shared/fixtures/data.py | 19 ++- 20 files changed, 265 insertions(+), 115 deletions(-) create mode 100644 changelog.d/20241007_130122_dmitrii.lavrukhin_analytics_bool_field_v3.md create mode 100644 cvat/apps/engine/migrations/0086_profile_has_analytics_access.py diff --git a/changelog.d/20241007_130122_dmitrii.lavrukhin_analytics_bool_field_v3.md b/changelog.d/20241007_130122_dmitrii.lavrukhin_analytics_bool_field_v3.md new file mode 100644 index 00000000000..4c044836650 --- /dev/null +++ b/changelog.d/20241007_130122_dmitrii.lavrukhin_analytics_bool_field_v3.md @@ -0,0 +1,4 @@ +### Added + +- Access to /analytics can now be granted + () diff --git a/cvat-core/src/server-response-types.ts b/cvat-core/src/server-response-types.ts index e28a6f9ec71..af6cd760ed4 100644 --- a/cvat-core/src/server-response-types.ts +++ b/cvat-core/src/server-response-types.ts @@ -54,6 +54,7 @@ export interface SerializedUser { last_login?: string; date_joined?: string; email_verification_required: boolean; + has_analytics_access: boolean; } interface SerializedStorage { diff --git a/cvat-core/src/user.ts b/cvat-core/src/user.ts index 1b0eb5ecfec..6d7366151fb 100644 --- a/cvat-core/src/user.ts +++ b/cvat-core/src/user.ts @@ -1,5 +1,5 @@ // Copyright (C) 2019-2022 Intel Corporation -// Copyright (C) 2022 CVAT.ai Corporation +// Copyright (C) 2022-2024 CVAT.ai Corporation // // SPDX-License-Identifier: MIT @@ -18,6 +18,7 @@ export default class User { public readonly isSuperuser: boolean; public readonly isActive: boolean; public readonly isVerified: boolean; + public readonly hasAnalyticsAccess: boolean; constructor(initialData: SerializedUser) { const data = { @@ -33,6 +34,7 @@ export default class User { is_superuser: null, is_active: null, email_verification_required: null, + has_analytics_access: null, }; for (const property in data) { @@ -80,6 +82,9 @@ export default class User { isVerified: { get: () => !data.email_verification_required, }, + hasAnalyticsAccess: { + get: () => data.has_analytics_access, + }, }), ); } @@ -98,6 +103,7 @@ export default class User { is_superuser: this.isSuperuser, is_active: this.isActive, email_verification_required: this.isVerified, + has_analytics_access: this.hasAnalyticsAccess, }; } } diff --git a/cvat-ui/src/components/header/header.tsx b/cvat-ui/src/components/header/header.tsx index 2621edddfa2..0feeae4be57 100644 --- a/cvat-ui/src/components/header/header.tsx +++ b/cvat-ui/src/components/header/header.tsx @@ -513,7 +513,7 @@ function HeaderComponent(props: Props): JSX.Element { Models ) : null} - {isAnalyticsPluginActive && user.isSuperuser ? ( + {isAnalyticsPluginActive && user.hasAnalyticsAccess ? (