diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f95eeab3b94..cb0c298be44f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- TDB +- Fixed multiple tasks moving () +- Fixed task creating CLI parameter () ### Security diff --git a/components/analytics/logstash/logstash.conf b/components/analytics/logstash/logstash.conf index 5afd6e3fce2c..67ef24b3973d 100644 --- a/components/analytics/logstash/logstash.conf +++ b/components/analytics/logstash/logstash.conf @@ -124,7 +124,7 @@ output { if [type] == "client" { elasticsearch { hosts => ["${LOGSTASH_OUTPUT_HOST}"] - index => "cvat.client" + index => "%{[@metadata][target_index_client]}" user => "${LOGSTASH_OUTPUT_USER:}" password => "${LOGSTASH_OUTPUT_PASS:}" manage_template => false @@ -132,7 +132,7 @@ output { } else if [type] == "server" { elasticsearch { hosts => ["${LOGSTASH_OUTPUT_HOST}"] - index => "cvat.server" + index => "%{[@metadata][target_index_server]}" user => "${LOGSTASH_OUTPUT_USER:}" password => "${LOGSTASH_OUTPUT_PASS:}" manage_template => false diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx index 2543a3ef56ea..d993af71cc0c 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx @@ -229,6 +229,7 @@ class OpenCVControlComponent extends React.PureComponent({}); const initValues = (): void => { + const labelValues: { [key: string]: LabelMapperItemValue } = {}; if (task) { - const labelValues: { [key: string]: LabelMapperItemValue } = {}; task.labels.forEach((label: any) => { labelValues[label.id] = { labelId: label.id, @@ -43,8 +43,8 @@ export default function MoveTaskModal(): JSX.Element { clearAttributes: true, }; }); - setLabelMap(labelValues); } + setLabelMap(labelValues); }; const onCancel = (): void => { diff --git a/cvat-ui/src/utils/opencv-wrapper/histogram-equalization.ts b/cvat-ui/src/utils/opencv-wrapper/histogram-equalization.ts index 7bf339667800..ff7687debf7a 100644 --- a/cvat-ui/src/utils/opencv-wrapper/histogram-equalization.ts +++ b/cvat-ui/src/utils/opencv-wrapper/histogram-equalization.ts @@ -60,8 +60,7 @@ export default class HistogramEqualizationImplementation implements HistogramEqu this.hashFrame(imgData, frameNumber); return imgData; } catch (e) { - console.log('Histogram equalization error', e); - return src; + throw new Error(e.toString()); } finally { if (matImage) matImage.delete(); if (channels) channels.delete(); diff --git a/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts b/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts index cc18cecbdad7..4afb3e34dabc 100644 --- a/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts +++ b/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts @@ -20,7 +20,7 @@ export interface Contours { } export interface ImgProc { - hist: () => HistogramEqualization + hist: () => HistogramEqualization; } export class OpenCVWrapper { @@ -41,10 +41,6 @@ export class OpenCVWrapper { const contentLength = response.headers.get('Content-Length'); const { body } = response; - if (contentLength === null) { - throw new Error('Content length is null, but necessary'); - } - if (body === null) { throw new Error('Response body is null, but necessary'); } @@ -64,7 +60,9 @@ export class OpenCVWrapper { if (value instanceof Uint8Array) { decodedScript += decoder.decode(value); receivedLength += value.length; - const percentage = (receivedLength * 100) / +(contentLength as string); + // Cypress workaround: content-length is always zero in cypress, it is done optional here + // Just progress bar will be disabled + const percentage = contentLength ? (receivedLength * 100) / +(contentLength as string) : 0; onProgress(+percentage.toFixed(0)); } } diff --git a/site/content/en/docs/manual/advanced/cli.md b/site/content/en/docs/manual/advanced/cli.md index 2738cfcea0f6..1b2f5f3b4a79 100644 --- a/site/content/en/docs/manual/advanced/cli.md +++ b/site/content/en/docs/manual/advanced/cli.md @@ -12,7 +12,7 @@ comprehensive CVAT administration tool in the future. Overview of functionality: -- Create a new task (supports name, bug tracker, labels JSON, local/share/remote files) +- Create a new task (supports name, bug tracker, project, labels JSON, local/share/remote files) - Delete tasks (supports deleting a list of task IDs) - List all tasks (supports basic CSV or JSON output) - Download JPEG frames (supports a list of frame IDs) diff --git a/tests/cypress/integration/actions_tasks/case_100_settings_default_number_of_points_in_polygon_approximation.js b/tests/cypress/integration/actions_tasks/case_100_settings_default_number_of_points_in_polygon_approximation.js index 819cb4a9bec1..3191502ba1f3 100644 --- a/tests/cypress/integration/actions_tasks/case_100_settings_default_number_of_points_in_polygon_approximation.js +++ b/tests/cypress/integration/actions_tasks/case_100_settings_default_number_of_points_in_polygon_approximation.js @@ -5,6 +5,7 @@ /// import { taskName } from '../../support/const'; +import { generateString } from '../../support/utils'; context('Settings. Default number of points in polygon approximation.', () => { const caseId = '100'; @@ -26,14 +27,6 @@ context('Settings. Default number of points in polygon approximation.', () => { }); } - function generateString(countPointsToMove) { - let action = ''; - for (let i = 0; i < countPointsToMove; i++) { - action += '{rightarrow}'; - } - return action; - } - before(() => { cy.openTaskJob(taskName); }); @@ -43,7 +36,7 @@ context('Settings. Default number of points in polygon approximation.', () => { testOpenSettingsWorkspace(); cy.get('.cvat-workspace-settings-approx-poly-threshold') .find('[role="slider"]') - .type(generateString(4)) + .type(generateString(4, 'rightarrow')) .then((slider) => { const sliderAttrValueNow = slider.attr('aria-valuenow'); const sliderAttrValuemin = slider.attr('aria-valuemin'); diff --git a/tests/cypress/integration/actions_tasks/case_102_create_link_shape_frame.js b/tests/cypress/integration/actions_tasks/case_102_create_link_shape_frame.js new file mode 100644 index 000000000000..fe2003236b64 --- /dev/null +++ b/tests/cypress/integration/actions_tasks/case_102_create_link_shape_frame.js @@ -0,0 +1,63 @@ +// Copyright (C) 2021 Intel Corporation +// +// SPDX-License-Identifier: MIT + +/// + +import { taskName, labelName } from '../../support/const'; + +context('Create a link for shape, frame.', () => { + const caseId = '102'; + const createRectangleShape2Points = { + points: 'By 2 Points', + type: 'Shape', + labelName: labelName, + firstX: 250, + firstY: 350, + secondX: 350, + secondY: 450, + }; + + before(() => { + cy.openTaskJob(taskName); + cy.createRectangle(createRectangleShape2Points); + cy.saveJob('PATCH', 200, `case${caseId}`); + }); + + describe(`Testing case "${caseId}"`, () => { + it('Create a link for a shape, for a frame.', () => { + cy.window().then(win => { + cy.stub(win, 'prompt').returns(win.prompt).as('copyToClipboardPromptShape'); + }); + cy.get('#cvat-objects-sidebar-state-item-1').find('[aria-label="more"]').trigger('mouseover'); + cy.get('#cvat_canvas_shape_1').should('have.class', 'cvat_canvas_shape_activated') + cy.get('.cvat-object-item-menu').last().should('be.visible').contains('button', 'Create object URL').click(); + cy.get('@copyToClipboardPromptShape').should('be.called'); + cy.get('@copyToClipboardPromptShape').then(prompt => { + const url = prompt.args[0][1]; + expect(url).include('frame='); + expect(url).include('type='); + expect(url).include('serverID='); + cy.visit(url); + cy.closeModalUnsupportedPlatform(); + cy.get('.cvat-canvas-container').should('be.visible'); + cy.get('#cvat_canvas_shape_1').should('be.visible'); + }); + + cy.window().then(win => { + cy.stub(win, 'prompt').returns(win.prompt).as('copyToClipboardPromptFrame'); + }); + cy.get('.cvat-player-frame-url-icon').click(); + cy.get('@copyToClipboardPromptFrame').should('be.called'); + cy.get('@copyToClipboardPromptFrame').then(prompt => { + const url = prompt.args[0][1]; + expect(url).include('frame='); + expect(url).not.include('type='); + expect(url).not.include('serverID='); + cy.visit(url); + cy.get('.cvat-canvas-container').should('be.visible'); + cy.get('#cvat_canvas_shape_1').should('be.visible'); + }); + }); + }); +}); diff --git a/tests/cypress/integration/actions_tasks2/case_101_opencv_basic_actions.js b/tests/cypress/integration/actions_tasks2/case_101_opencv_basic_actions.js new file mode 100644 index 000000000000..95268fb58869 --- /dev/null +++ b/tests/cypress/integration/actions_tasks2/case_101_opencv_basic_actions.js @@ -0,0 +1,117 @@ +// Copyright (C) 2021 Intel Corporation +// +// SPDX-License-Identifier: MIT + +/// + +import { taskName, labelName } from '../../support/const'; +import { generateString } from '../../support/utils'; + +context('OpenCV. Intelligent cissors. Histogram Equalization.', () => { + const caseId = '101'; + const newLabel = `Case ${caseId}` + const createOpencvShape = { + labelName: labelName, + pointsMap: [ + { x: 200, y: 200 }, + { x: 250, y: 200 }, + { x: 300, y: 250 }, + { x: 350, y: 300 }, + { x: 300, y: 350 }, + ], + }; + const createOpencvShapeSecondLabel = { + labelName: newLabel, + pointsMap: [ + { x: 300, y: 200 }, + { x: 350, y: 200 }, + { x: 400, y: 250 }, + { x: 450, y: 300 }, + { x: 400, y: 350 }, + ], + finishWithButton: true, + }; + const keyCodeN = 78; + const pointsMap = [ + { x: 300, y: 400 }, + { x: 350, y: 500 }, + { x: 400, y: 450 }, + { x: 450, y: 500 }, + { x: 400, y: 550 }, + ]; + + function openOpencvControlPopover() { + cy.get('body').focus(); + cy.get('.cvat-tools-control').trigger('mouseleave').trigger('mouseout').trigger('mouseover'); + } + + before(() => { + cy.openTask(taskName); + cy.addNewLabel(newLabel); + cy.openJob(); + }); + + describe(`Testing case "${caseId}"`, () => { + it('Load OpenCV.', () => { + openOpencvControlPopover(); + cy.get('.cvat-opencv-control-popover-visible').find('.cvat-opencv-initialization-button').click(); + // Intelligent cissors button be visible + cy.get('.cvat-opencv-drawing-tool').should('exist').and('be.visible'); + }); + + it('Create a shape with "Intelligent cissors". Create the second shape with the label change and "Done" button.', () => { + cy.opencvCreateShape(createOpencvShape); + cy.opencvCreateShape(createOpencvShapeSecondLabel); + }); + + it('Change the number of points when the shape is drawn. Cancel drawing.', () => { + openOpencvControlPopover(); + cy.get('.cvat-opencv-drawing-tool').click(); + pointsMap.forEach((element) => { + cy.get('.cvat-canvas-container').click(element.x, element.y); + }); + cy.get('.cvat_canvas_interact_intermediate_shape').then((intermediateShape) => { + // Get count of points + const intermediateShapeNumberPointsBeforeChange = intermediateShape.attr('points').split(' ').length; + // Change number of points + cy.get('.cvat-approx-poly-threshold-wrapper') + .find('[role="slider"]') + .type(generateString(4, 'rightarrow')); + cy.get('.cvat_canvas_interact_intermediate_shape').then((intermediateShape) => { + // Get count of points againe + const intermediateShapeNumberPointsAfterChange = intermediateShape.attr('points').split(' ').length; + // expected 7 to be below 10 + expect(intermediateShapeNumberPointsBeforeChange).to.be.lt(intermediateShapeNumberPointsAfterChange); + }); + }); + cy.get('body').type('{Esc}'); // Cancel drawing + cy.get('.cvat_canvas_interact_intermediate_shape').should('not.exist'); + cy.get('.cvat_canvas_shape').should('have.length', 2); + }); + + it('Check "Histogram Equalization" feature.', () => { + openOpencvControlPopover(); + cy.get('.cvat-opencv-control-popover-visible').contains('[role="tab"]', 'Image').click(); + cy.get('.cvat-opencv-image-tool').click().should('have.class', 'cvat-opencv-image-tool-active').trigger('mouseout'); + cy.get('.cvat-notification-notice-opencv-processing-error').should('not.exist'); + cy.get('.cvat-opencv-image-tool').click().should('not.have.class', 'cvat-opencv-image-tool-active').trigger('mouseout'); + }); + + // Waiting for fix https://github.com/openvinotoolkit/cvat/issues/3474 + it.skip('Redraw the shape created with "Intelligent cissors".', () => { + cy.get('.cvat-canvas-container').click(); + cy.get('.cvat-opencv-control-popover').should('be.hidden'); + cy.get('#cvat_canvas_shape_1') + .trigger('mousemove') + .trigger('mouseover') + .should('have.class', 'cvat_canvas_shape_activated'); + cy.get('body').trigger('keydown', { keyCode: keyCodeN, shiftKey: true }).trigger('keyup'); + cy.get('.cvat-tools-control').should('have.attr', 'tabindex'); + createOpencvShape.pointsMap.forEach((el) => { + cy.get('.cvat-canvas-container') + .click(el.x + 150, el.y + 50) + }); + cy.get('body').trigger('keydown', { keyCode: keyCodeN }).trigger('keyup'); + }); + }); +}); diff --git a/tests/cypress/integration/actions_tasks2/case_23_canvas_grid_feature.js b/tests/cypress/integration/actions_tasks2/case_23_canvas_grid_feature.js index 81cd9cdcffc7..0eb350ae02d0 100644 --- a/tests/cypress/integration/actions_tasks2/case_23_canvas_grid_feature.js +++ b/tests/cypress/integration/actions_tasks2/case_23_canvas_grid_feature.js @@ -5,6 +5,7 @@ /// import { taskName } from '../../support/const'; +import { generateString } from '../../support/utils'; context('Canvas grid feature', () => { const caseId = '23'; @@ -12,14 +13,6 @@ context('Canvas grid feature', () => { const gridColor = 'Black'; const gridOpacity = 80; - function generateString(countPointsToMove) { - let action = ''; - for (let i = 0; i < countPointsToMove; i++) { - action += '{leftarrow}'; - } - return action; - } - before(() => { cy.openTaskJob(taskName); cy.get('.cvat-canvas-image-setups-trigger').click(); @@ -44,7 +37,7 @@ context('Canvas grid feature', () => { }); it('Set "Grid opacity" to 80%.', () => { cy.get('.cvat-image-setups-grid-opacity-input').within(() => { - cy.get('[role="slider"]').type(generateString(20)); // Moving the slider to the left up to 80. + cy.get('[role="slider"]').type(generateString(20, 'leftarrow')); // Moving the slider to the left up to 80. cy.get('[role="slider"]').should('have.attr', 'aria-valuenow', gridOpacity); }); }); diff --git a/tests/cypress/integration/actions_tasks2/case_26_canvas_brightness_contrast_saturation_feature.js b/tests/cypress/integration/actions_tasks2/case_26_canvas_brightness_contrast_saturation_feature.js index ed3437107512..3beb25a45731 100644 --- a/tests/cypress/integration/actions_tasks2/case_26_canvas_brightness_contrast_saturation_feature.js +++ b/tests/cypress/integration/actions_tasks2/case_26_canvas_brightness_contrast_saturation_feature.js @@ -5,6 +5,7 @@ /// import { taskName } from '../../support/const'; +import { generateString } from '../../support/utils'; context('Canvas brightness/contrast/saturation feature', () => { const caseId = '26'; @@ -17,14 +18,6 @@ context('Canvas brightness/contrast/saturation feature', () => { '.cvat-image-setups-saturation', ]; - function generateStringCountAction(countAction) { - let stringAction = ''; - for (let i = 0; i < countAction; i++) { - stringAction += '{rightarrow}'; - } - return stringAction; - } - function checkStateValuesInBackground(expectedValue) { cy.get('#cvat_canvas_background') .should('have.attr', 'style') @@ -41,7 +34,7 @@ context('Canvas brightness/contrast/saturation feature', () => { describe(`Testing case "${caseId}"`, () => { it('Check apply of settings', () => { - let stringAction = generateStringCountAction(countActionMoveSlider); + let stringAction = generateString(countActionMoveSlider, 'rightarrow'); cy.get('.cvat-canvas-image-setups-content').within(() => { cy.wrap(classNameSliders).each(($el) => { cy.wrap($el) diff --git a/tests/cypress/support/commands_opencv.js b/tests/cypress/support/commands_opencv.js new file mode 100644 index 000000000000..8378c574b2a6 --- /dev/null +++ b/tests/cypress/support/commands_opencv.js @@ -0,0 +1,51 @@ +// Copyright (C) 2021 Intel Corporation +// +// SPDX-License-Identifier: MIT + +/// + +let selectedValueGlobal = ''; + +Cypress.Commands.add('opencvCreateShape', (opencvShapeParams) => { + if (!opencvShapeParams.reDraw) { + cy.get('body').focus(); + cy.get('.cvat-tools-control').trigger('mouseleave').trigger('mouseout').trigger('mouseover'); + cy.switchLabel(opencvShapeParams.labelName, 'opencv-control'); + cy.get('.cvat-opencv-control-popover-visible').within(() => { + cy.get('.ant-select-selection-item').then(($labelValue) => { + selectedValueGlobal = $labelValue.text(); + }); + }); + cy.get('.cvat-opencv-drawing-tool').click(); + } + opencvShapeParams.pointsMap.forEach((element) => { + cy.get('.cvat-canvas-container').click(element.x, element.y); + }); + if (opencvShapeParams.finishWithButton) { + cy.contains('span', 'Done').click(); + } else { + const keyCodeN = 78; + cy.get('.cvat-canvas-container') + .trigger('keydown', { keyCode: keyCodeN }) + .trigger('keyup', { keyCode: keyCodeN }); + } + cy.opncvCheckObjectParameters('POLYGON'); +}); + +Cypress.Commands.add('opncvCheckObjectParameters', (objectType) => { + let listCanvasShapeId = []; + cy.document().then((doc) => { + const listCanvasShape = Array.from(doc.querySelectorAll('.cvat_canvas_shape')); + for (let i = 0; i < listCanvasShape.length; i++) { + listCanvasShapeId.push(listCanvasShape[i].id.match(/\d+$/)); + } + const maxId = Math.max(...listCanvasShapeId); + cy.get(`#cvat_canvas_shape_${maxId}`).should('be.visible'); + cy.get(`#cvat-objects-sidebar-state-item-${maxId}`) + .should('contain', maxId) + .and('contain', objectType) + .within(() => { + cy.get('.ant-select-selection-item').should('have.text', selectedValueGlobal); + }); + }); +}); diff --git a/tests/cypress/support/index.js b/tests/cypress/support/index.js index 5c8880df3e2b..c146c98e5c54 100644 --- a/tests/cypress/support/index.js +++ b/tests/cypress/support/index.js @@ -8,6 +8,7 @@ require('./commands_review_pipeline'); require('./commands_canvas3d'); require('./commands_filters_feature'); require('./commands_models'); +require('./commands_opencv'); require('@cypress/code-coverage/support'); require('cypress-plugin-tab'); diff --git a/tests/cypress/support/utils.js b/tests/cypress/support/utils.js new file mode 100644 index 000000000000..975d61e217a9 --- /dev/null +++ b/tests/cypress/support/utils.js @@ -0,0 +1,11 @@ +// Copyright (C) 2021 Intel Corporation +// +// SPDX-License-Identifier: MIT + +export function generateString(countPointsToMove, arrow) { + let action = ''; + for (let i = 0; i < countPointsToMove; i++) { + action += `{${arrow}}`; + } + return action; +} diff --git a/utils/cli/core/definition.py b/utils/cli/core/definition.py index bab3cacb067a..daf174e7fce3 100644 --- a/utils/cli/core/definition.py +++ b/utils/cli/core/definition.py @@ -113,7 +113,7 @@ def argparse(s): help='string or file containing JSON labels specification' ) task_create_parser.add_argument( - '--project', + '--project_id', default=None, type=int, help='project ID if project exists'