Skip to content

Commit

Permalink
Merge pull request #8169 from cvat-ai/release-2.16.0
Browse files Browse the repository at this point in the history
Release v2.16.0
  • Loading branch information
cvat-bot[bot] authored Jul 16, 2024
2 parents 3da6e4f + 382837f commit 8ca0236
Show file tree
Hide file tree
Showing 183 changed files with 6,558 additions and 2,670 deletions.
57 changes: 57 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,63 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

<!-- scriv-insert-here -->

<a id='changelog-2.16.0'></a>
## \[2.16.0\] - 2024-07-15

### Added

- Set of features to track background activities: importing/exporting datasets, annotations or backups, creating tasks.
Now you may find these processes on Requests page, it allows a user to understand current status of these activities
and enhances user experience, not losing progress when the browser tab is closed
(<https://github.com/cvat-ai/cvat/pull/7537>)

- User now may update a job state from the corresponding task page
(<https://github.com/cvat-ai/cvat/pull/8102>)

- The server will now record and report last assignee update time
(<https://github.com/cvat-ai/cvat/pull/8119>)

### Changed

- "Finish the job" button on annotation view now only sets state to 'completed'.
The job stage keeps unchanged (<https://github.com/cvat-ai/cvat/pull/8102>)

- Log files for individual backend processes are now stored in ephemeral
storage of each backend container rather than in the `cvat_logs` volume
(<https://github.com/cvat-ai/cvat/pull/8121>)

- Do not reset opacity level each time frame switched if there are masks on the frame
(<https://github.com/cvat-ai/cvat/pull/8149>)

### Removed

- Renew the job button in annotation menu was removed
(<https://github.com/cvat-ai/cvat/pull/8102>)

### Fixed

- A possible crash in quality computation for tasks with skeletons and normal labels
(<https://github.com/cvat-ai/cvat/pull/8100>)

- Quality report button and timestamp alignments on quality page
(<https://github.com/cvat-ai/cvat/pull/8106>)

- Fixed display of working time in Grafana management dashboard
(<https://github.com/cvat-ai/cvat/pull/8112>)

- Fixed unexpected deletion of log files of other processes that led to OSError:
\[Errno 116\] Stale file handle error on NFS volumes
(<https://github.com/cvat-ai/cvat/pull/8121>)

- Attribute values with ":" may be displayed incorrectly on canvas
(<https://github.com/cvat-ai/cvat/pull/8137>)

- Fixed broken server Docker image build
(<https://github.com/cvat-ai/cvat/pull/8160>)

- DOMException: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded
(<https://github.com/cvat-ai/cvat/pull/8166>)

<a id='changelog-2.15.0'></a>
## \[2.15.0\] - 2024-07-02

Expand Down
9 changes: 7 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ RUN --mount=type=cache,target=/root/.cache/pip/http-v2 \
-r /tmp/cvat/requirements/${CVAT_CONFIGURATION}.txt \
-w /tmp/wheelhouse

FROM golang:1.22.3 AS build-smokescreen
FROM golang:1.22.4 AS build-smokescreen

RUN git clone --depth=1 https://github.com/stripe/smokescreen.git
RUN git clone --filter=blob:none --no-checkout https://github.com/stripe/smokescreen.git
RUN cd smokescreen && git checkout eb1ac09 && go build -o /tmp/smokescreen

FROM ${BASE_IMAGE}
Expand Down Expand Up @@ -182,6 +182,11 @@ RUN if [ "${CVAT_DEBUG_ENABLED}" = 'yes' ]; then \
python3 -m pip install --no-cache-dir debugpy; \
fi

# Removing pip due to security reasons. See: https://scout.docker.com/vulnerabilities/id/CVE-2018-20225
# The vulnerability is dubious and we don't use pip at runtime, but some vulnerability scanners mark it as a high vulnerability,
# and it was decided to remove pip from the final image
RUN python -m pip uninstall -y pip

# Install and initialize CVAT, copy all necessary files
COPY cvat/nginx.conf /etc/nginx/nginx.conf
COPY --chown=${USER} components /tmp/components
Expand Down
1 change: 1 addition & 0 deletions Dockerfile.ci
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ RUN apt-get update && \
COPY cvat/requirements/ /tmp/cvat/requirements/
COPY utils/dataset_manifest/requirements.txt /tmp/utils/dataset_manifest/requirements.txt

RUN python3 -m ensurepip
RUN DATUMARO_HEADLESS=1 python3 -m pip install --no-cache-dir -r /tmp/cvat/requirements/testing.txt

COPY cvat-core ${HOME}/cvat-core
Expand Down
2 changes: 1 addition & 1 deletion components/analytics/grafana/dashboards/management.json
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@
}
},
"queryType": "sql",
"rawSql": "SELECT\r\n user_id as User,\r\n project_id as Project,\r\n task_id as Task,\r\n job_id as Job, sum(JSONExtractUInt(payload, 'working_time')) / 1000 / 3600 as \"Working time(h)\",\r\n count() as Activity\r\nFROM events\r\nWHERE JSONHas(payload, 'working_time')\r\n AND $__timeFilter(timestamp)\r\n AND user_id IN (${users})\r\n AND (-1 IN (${projects}) OR project_id IN (${projects}))\r\n AND task_id IN (${tasks})\r\n AND job_id IN (${jobs})\r\n AND source = 'client'\r\nGROUP BY user_id, project_id, task_id, job_id",
"rawSql": "SELECT\r\n user_id as User,\r\n project_id as Project,\r\n task_id as Task,\r\n job_id as Job, sum(JSONExtractUInt(payload, 'working_time')) / 1000 / 3600 as \"Working time(h)\",\r\n count() as Activity\r\nFROM events\r\nWHERE JSONHas(payload, 'working_time')\r\n AND $__timeFilter(timestamp)\r\n AND user_id IN (${users})\r\n AND (-1 IN (${projects}) OR project_id IN (${projects}))\r\n AND task_id IN (${tasks})\r\n AND job_id IN (${jobs})\r\nGROUP BY user_id, project_id, task_id, job_id",
"refId": "A"
}
],
Expand Down
2 changes: 1 addition & 1 deletion cvat-canvas/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-canvas",
"version": "2.20.5",
"version": "2.20.6",
"type": "module",
"description": "Part of Computer Vision Annotation Tool which presents its canvas library",
"main": "src/canvas.ts",
Expand Down
16 changes: 7 additions & 9 deletions cvat-canvas/src/typescript/canvasView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2398,14 +2398,14 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.addText(state);
}
} else {
const attrNames = Object.fromEntries(state.label.attributes.map((attr) => [attr.id, attr.name]));
// check if there are updates in attributes
for (const attrID of Object.keys(state.attributes)) {
if (state.attributes[attrID] !== drawnState.attributes[+attrID]) {
if (text) {
const [span] = text.node.querySelectorAll<SVGTSpanElement>(`[attrID="${attrID}"]`);
if (span && span.textContent) {
const prefix = span.textContent.split(':').slice(0, -1).join(':');
span.textContent = `${prefix}: ${state.attributes[attrID]}`;
span.textContent = `${attrNames[attrID]}: ${state.attributes[attrID]}`;
}
}
}
Expand Down Expand Up @@ -2576,7 +2576,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
}

if (drawnState.shapeType === 'mask') {
shape.attr('opacity', `${this.configuration.shapeOpacity}`);
shape.attr('opacity', `${Math.sqrt(this.configuration.shapeOpacity)}`);
} else {
shape.attr('fill-opacity', `${this.configuration.shapeOpacity}`);
}
Expand Down Expand Up @@ -2666,7 +2666,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
}

if (state.shapeType === 'mask') {
shape.attr('opacity', `${this.configuration.selectedShapeOpacity}`);
shape.attr('opacity', `${Math.sqrt(this.configuration.selectedShapeOpacity)}`);
} else {
shape.attr('fill-opacity', `${this.configuration.selectedShapeOpacity}`);
}
Expand Down Expand Up @@ -2982,11 +2982,8 @@ export class CanvasViewImpl implements CanvasView, Listener {
const {
label, clientID, attributes, source, descriptions,
} = state;
const attrNames = label.attributes.reduce((acc: any, val: any): void => {
acc[val.id] = val.name;
return acc;
}, {});

const attrNames = Object.fromEntries(state.label.attributes.map((attr) => [attr.id, attr.name]));
if (state.shapeType === 'skeleton') {
state.elements.forEach((element: any) => {
if (!(element.clientID in this.svgTexts)) {
Expand Down Expand Up @@ -3172,7 +3169,8 @@ export class CanvasViewImpl implements CanvasView, Listener {
id: `cvat_canvas_shape_${state.clientID}`,
'shape-rendering': 'geometricprecision',
'data-z-order': state.zOrder,
opacity: colorization['fill-opacity'],
// apply sqrt function to colorization to enhance displaying the mask on the canvas
opacity: Math.sqrt(colorization['fill-opacity']),
stroke: colorization.stroke,
}).addClass('cvat_canvas_shape');
image.move(this.geometry.offset + left, this.geometry.offset + top);
Expand Down
2 changes: 1 addition & 1 deletion cvat-cli/requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
cvat-sdk~=2.15.0
cvat-sdk~=2.16.0
Pillow>=10.3.0
setuptools>=70.0.0 # not directly required, pinned by Snyk to avoid a vulnerability
2 changes: 1 addition & 1 deletion cvat-cli/src/cvat_cli/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VERSION = "2.15.0"
VERSION = "2.16.0"
2 changes: 1 addition & 1 deletion cvat-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-core",
"version": "15.0.7",
"version": "15.1.0",
"type": "module",
"description": "Part of Computer Vision Tool which presents an interface for client-side integration",
"main": "src/api.ts",
Expand Down
6 changes: 3 additions & 3 deletions cvat-core/src/annotations.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (C) 2019-2022 Intel Corporation
// Copyright (C) 2022-2023 CVAT.ai Corporation
// Copyright (C) 2022-2024 CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

Expand Down Expand Up @@ -168,9 +168,9 @@ export function importDataset(
file: File | string,
options: {
convMaskToPoly?: boolean,
updateStatusCallback?: (s: string, n: number) => void,
updateStatusCallback?: (message: string, progress: number) => void,
} = {},
): Promise<void> {
): Promise<string> {
const updateStatusCallback = options.updateStatusCallback || (() => {});
const convMaskToPoly = 'convMaskToPoly' in options ? options.convMaskToPoly : true;
const adjustedOptions = {
Expand Down
5 changes: 5 additions & 0 deletions cvat-core/src/api-implementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import config from './config';
import PluginRegistry from './plugins';
import serverProxy from './server-proxy';
import lambdaManager from './lambda-manager';
import requestsManager from './requests-manager';
import {
isBoolean,
isInteger,
Expand Down Expand Up @@ -61,6 +62,10 @@ export default function implementAPI(cvat: CVATCore): CVATCore {
implementationMixin(cvat.lambda.listen, lambdaManager.listen.bind(lambdaManager));
implementationMixin(cvat.lambda.requests, lambdaManager.requests.bind(lambdaManager));

implementationMixin(cvat.requests.list, requestsManager.list.bind(requestsManager));
implementationMixin(cvat.requests.listen, requestsManager.listen.bind(requestsManager));
implementationMixin(cvat.requests.cancel, requestsManager.cancel.bind(requestsManager));

implementationMixin(cvat.server.about, async () => {
const result = await serverProxy.server.about();
return result;
Expand Down
27 changes: 27 additions & 0 deletions cvat-core/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Organization from './organization';
import Webhook from './webhook';
import AnnotationGuide from './guide';
import BaseSingleFrameAction from './annotations-actions';
import { Request } from './request';

import * as enums from './enums';

Expand Down Expand Up @@ -286,6 +287,12 @@ function build(): CVATCore {
set globalObjectsCounter(value: number) {
config.globalObjectsCounter = value;
},
get requestsStatusDelay() {
return config.requestsStatusDelay;
},
set requestsStatusDelay(value) {
config.requestsStatusDelay = value;
},
},
client: {
version: `${pjson.version}`,
Expand Down Expand Up @@ -374,6 +381,26 @@ function build(): CVATCore {
},
},
},
requests: {
async list() {
const result = await PluginRegistry.apiWrapper(cvat.requests.list);
return result;
},
async cancel(rqID: string) {
const result = await PluginRegistry.apiWrapper(cvat.requests.cancel, rqID);
return result;
},
async listen(
rqID: string,
options: {
callback: (request: Request) => void,
initialRequest?: Request,
},
) {
const result = await PluginRegistry.apiWrapper(cvat.requests.listen, rqID, options);
return result;
},
},
classes: {
User,
Project: implementProject(Project),
Expand Down
2 changes: 2 additions & 0 deletions cvat-core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const config = {
},
onOrganizationChange: null,
globalObjectsCounter: 0,

requestsStatusDelay: null,
};

export default config;
4 changes: 3 additions & 1 deletion cvat-core/src/exceptions.ts
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -99,6 +99,8 @@ export class DataError extends Exception {}

export class ScriptingError extends Exception {}

export class RequestError extends Exception {}

export class ServerError extends Exception {
public code: number;
constructor(message, code) {
Expand Down
13 changes: 13 additions & 0 deletions cvat-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import QualityConflict from './quality-conflict';
import QualitySettings from './quality-settings';
import AnalyticsReport from './analytics-report';
import AnnotationGuide from './guide';
import { Request } from './request';
import BaseSingleFrameAction, { listActions, registerAction, runActions } from './annotations-actions';
import {
ArgumentError, DataError, Exception, ScriptingError, ServerError,
Expand Down Expand Up @@ -150,6 +151,17 @@ export default interface CVATCore {
frames: {
getMeta: any;
};
requests: {
list: () => Promise<PaginatedResource<Request>>;
listen: (
rqID: string,
options: {
callback: (request: Request) => void,
initialRequest?: Request,
}
) => Promise<Request>;
cancel: (rqID: string) => Promise<void>;
};
actions: {
list: typeof listActions;
register: typeof registerAction;
Expand All @@ -166,6 +178,7 @@ export default interface CVATCore {
};
onOrganizationChange: (newOrgId: number | null) => void | null;
globalObjectsCounter: typeof config.globalObjectsCounter;
requestsStatusDelay: typeof config.requestsStatusDelay;
},
client: {
version: string;
Expand Down
20 changes: 11 additions & 9 deletions cvat-core/src/project-implementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,39 +107,42 @@ export default function implementProject(Project: typeof ProjectClass): typeof P
});

Object.defineProperty(Project.prototype.annotations.exportDataset, 'implementation', {
value: function exportDatasetImplementation(
value: async function exportDatasetImplementation(
this: ProjectClass,
format: Parameters<typeof ProjectClass.prototype.annotations.exportDataset>[0],
saveImages: Parameters<typeof ProjectClass.prototype.annotations.exportDataset>[1],
useDefaultSettings: Parameters<typeof ProjectClass.prototype.annotations.exportDataset>[2],
targetStorage: Parameters<typeof ProjectClass.prototype.annotations.exportDataset>[3],
customName: Parameters<typeof ProjectClass.prototype.annotations.exportDataset>[4],
): ReturnType<typeof ProjectClass.prototype.annotations.exportDataset> {
return exportDataset(this, format, saveImages, useDefaultSettings, targetStorage, customName);
const rqID = await exportDataset(this, format, saveImages, useDefaultSettings, targetStorage, customName);
return rqID;
},
});

Object.defineProperty(Project.prototype.annotations.importDataset, 'implementation', {
value: function importDatasetImplementation(
value: async function importDatasetImplementation(
this: ProjectClass,
format: Parameters<typeof ProjectClass.prototype.annotations.importDataset>[0],
useDefaultSettings: Parameters<typeof ProjectClass.prototype.annotations.importDataset>[1],
sourceStorage: Parameters<typeof ProjectClass.prototype.annotations.importDataset>[2],
file: Parameters<typeof ProjectClass.prototype.annotations.importDataset>[3],
options: Parameters<typeof ProjectClass.prototype.annotations.importDataset>[4],
): ReturnType<typeof ProjectClass.prototype.annotations.importDataset> {
return importDataset(this, format, useDefaultSettings, sourceStorage, file, options);
const rqID = await importDataset(this, format, useDefaultSettings, sourceStorage, file, options);
return rqID;
},
});

Object.defineProperty(Project.prototype.backup, 'implementation', {
value: function backupImplementation(
value: async function backupImplementation(
this: ProjectClass,
targetStorage: Parameters<typeof ProjectClass.prototype.backup>[0],
useDefaultSettings: Parameters<typeof ProjectClass.prototype.backup>[1],
fileName: Parameters<typeof ProjectClass.prototype.backup>[2],
): ReturnType<typeof ProjectClass.prototype.backup> {
return serverProxy.projects.backup(this.id, targetStorage, useDefaultSettings, fileName);
const rqID = await serverProxy.projects.backup(this.id, targetStorage, useDefaultSettings, fileName);
return rqID;
},
});

Expand All @@ -149,9 +152,8 @@ export default function implementProject(Project: typeof ProjectClass): typeof P
storage: Parameters<typeof ProjectClass.restore>[0],
file: Parameters<typeof ProjectClass.restore>[1],
): ReturnType<typeof ProjectClass.restore> {
const serializedProject = await serverProxy.projects.restore(storage, file);
const labels = await serverProxy.labels.get({ project_id: serializedProject.id });
return new Project({ ...serializedProject, labels: labels.results });
const rqID = await serverProxy.projects.restore(storage, file);
return rqID;
},
});

Expand Down
Loading

0 comments on commit 8ca0236

Please sign in to comment.