diff --git a/changelog.d/20250124_143705_klakhov_copy_frame_name_button.md b/changelog.d/20250124_143705_klakhov_copy_frame_name_button.md new file mode 100644 index 000000000000..4c76c5f80724 --- /dev/null +++ b/changelog.d/20250124_143705_klakhov_copy_frame_name_button.md @@ -0,0 +1,4 @@ +### Added + +- A button to copy a filename of the image into the clipboard + () diff --git a/cvat-ui/src/components/annotation-page/styles.scss b/cvat-ui/src/components/annotation-page/styles.scss index 42583c1121ec..daebce15aa7d 100644 --- a/cvat-ui/src/components/annotation-page/styles.scss +++ b/cvat-ui/src/components/annotation-page/styles.scss @@ -186,7 +186,8 @@ .cvat-player-frame-url-icon, .cvat-player-delete-frame, -.cvat-player-restore-frame { +.cvat-player-restore-frame, +.cvat-player-copy-frame-name-icon { opacity: 0.7; color: $objects-bar-icons-color; @@ -199,9 +200,10 @@ } } -.cvat-player-delete-frame, -.cvat-player-restore-frame { - margin-left: $grid-unit-size * 2; +.cvat-player-frame-actions { + span:not(:first-child) { + margin-left: $grid-unit-size; + } } .cvat-player-frame-selector { diff --git a/cvat-ui/src/components/annotation-page/top-bar/player-navigation.tsx b/cvat-ui/src/components/annotation-page/top-bar/player-navigation.tsx index 8c72a2ce6e4f..7b74ca2a5c07 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/player-navigation.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/player-navigation.tsx @@ -8,7 +8,7 @@ import React, { } from 'react'; import { Row, Col } from 'antd/lib/grid'; -import Icon, { LinkOutlined, DeleteOutlined } from '@ant-design/icons'; +import Icon, { LinkOutlined, DeleteOutlined, CopyOutlined } from '@ant-design/icons'; import Slider from 'antd/lib/slider'; import InputNumber from 'antd/lib/input-number'; import Text from 'antd/lib/typography/Text'; @@ -39,6 +39,7 @@ interface Props { onSliderChange(value: number): void; onInputChange(value: number): void; onURLIconClick(): void; + onCopyFilenameIconClick(): void; onDeleteFrame(): void; onRestoreFrame(): void; switchNavigationBlocked(blocked: boolean): void; @@ -79,6 +80,7 @@ function PlayerNavigation(props: Props): JSX.Element { onSliderChange, onInputChange, onURLIconClick, + onCopyFilenameIconClick, onDeleteFrame, onRestoreFrame, switchNavigationBlocked, @@ -186,7 +188,10 @@ function PlayerNavigation(props: Props): JSX.Element { {frameFilename} - + + + + diff --git a/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx b/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx index a50af9299d37..aabdaaef1626 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx @@ -61,6 +61,7 @@ interface Props { onSliderChange(value: number): void; onInputChange(value: number): void; onURLIconClick(): void; + onCopyFilenameIconClick(): void; onUndoClick(): void; onRedoClick(): void; onFinishDraw(): void; @@ -117,6 +118,7 @@ export default function AnnotationTopBarComponent(props: Props): JSX.Element { onSliderChange, onInputChange, onURLIconClick, + onCopyFilenameIconClick, onUndoClick, onRedoClick, onFinishDraw, @@ -171,6 +173,7 @@ export default function AnnotationTopBarComponent(props: Props): JSX.Element { onSliderChange={onSliderChange} onInputChange={onInputChange} onURLIconClick={onURLIconClick} + onCopyFilenameIconClick={onCopyFilenameIconClick} onDeleteFrame={onDeleteFrame} onRestoreFrame={onRestoreFrame} switchNavigationBlocked={switchNavigationBlocked} diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx index c31b9d2804bd..39a8909bf539 100644 --- a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx +++ b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx @@ -31,6 +31,7 @@ import { import { Canvas, CanvasMode } from 'cvat-canvas-wrapper'; import { Canvas3d } from 'cvat-canvas3d-wrapper'; import { filterApplicableLabels } from 'utils/filter-applicable-labels'; +import { toClipboard } from 'utils/to-clipboard'; interface OwnProps { readonly: boolean; @@ -233,16 +234,7 @@ class ObjectItemContainer extends React.PureComponent { const search = `frame=${frameNumber}&type=${objectState.objectType}&serverID=${objectState.serverID}`; const url = `${origin}${pathname}?${search}`; - const fallback = (): void => { - // eslint-disable-next-line - window.prompt('Browser Clipboard API not allowed, please copy manually', url); - }; - - if (window.isSecureContext) { - window.navigator.clipboard.writeText(url).catch(fallback); - } else { - fallback(); - } + toClipboard(url); }; private switchOrientation = (): void => { 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 5c1c971beb5b..354e88b0ad42 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 @@ -41,6 +41,7 @@ import isAbleToChangeFrame from 'utils/is-able-to-change-frame'; import { KeyMap } from 'utils/mousetrap-react'; import { switchToolsBlockerState } from 'actions/settings-actions'; import { writeLatestFrame } from 'utils/remember-latest-frame'; +import { toClipboard } from 'utils/to-clipboard'; interface StateToProps { jobInstance: Job; @@ -567,16 +568,13 @@ class AnnotationTopBarContainer extends React.PureComponent { const { origin, pathname } = window.location; const url = `${origin}${pathname}?frame=${frameNumber}`; - const fallback = (): void => { - // eslint-disable-next-line - window.prompt('Browser Clipboard API not allowed, please copy manually', url); - }; + toClipboard(url); + }; - if (window.isSecureContext) { - window.navigator.clipboard.writeText(url).catch(fallback); - } else { - fallback(); - } + private onCopyFilenameIconClick = (): void => { + const { frameFilename } = this.props; + + toClipboard(frameFilename); }; private onDeleteFrame = (): void => { @@ -670,6 +668,7 @@ class AnnotationTopBarContainer extends React.PureComponent { onSliderChange={this.onChangePlayerSliderValue} onInputChange={this.onChangePlayerInputValue} onURLIconClick={this.onURLIconClick} + onCopyFilenameIconClick={this.onCopyFilenameIconClick} onDeleteFrame={this.onDeleteFrame} onRestoreFrame={this.onRestoreFrame} changeWorkspace={this.changeWorkspace} diff --git a/cvat-ui/src/utils/to-clipboard.ts b/cvat-ui/src/utils/to-clipboard.ts new file mode 100644 index 000000000000..bc2a125577ef --- /dev/null +++ b/cvat-ui/src/utils/to-clipboard.ts @@ -0,0 +1,16 @@ +// Copyright (C) CVAT.ai Corporation +// +// SPDX-License-Identifier: MIT + +export function toClipboard(text: string): void { + const fallback = (): void => { + // eslint-disable-next-line + window.prompt('Browser Clipboard API not allowed, please copy manually', text); + }; + + if (window.isSecureContext) { + window.navigator.clipboard.writeText(text).catch(fallback); + } else { + fallback(); + } +} diff --git a/site/content/en/docs/manual/basics/CVAT-annotation-Interface/navbar.md b/site/content/en/docs/manual/basics/CVAT-annotation-Interface/navbar.md index 034f6b9aad3f..8bebf7be4327 100644 --- a/site/content/en/docs/manual/basics/CVAT-annotation-Interface/navbar.md +++ b/site/content/en/docs/manual/basics/CVAT-annotation-Interface/navbar.md @@ -60,16 +60,18 @@ Use the following buttons, to save your work, undo changes, and move tasks to do Overview of how to navigate through frames within the interface, with detailed descriptions provided in the table below. -![Navigation Controls](/images/image008.jpg) +![Navigation Controls](/images/navigation_controls.png) -| Function                                                                         | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | +| Function | Description | | ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Go to the first**/**last frame**

![First last frame controls](/images/image036.jpg)             | Navigate to the first or the last frame of the sequence.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | -| **Go back with a step**/**Go next with a step**

![Go to a step controls](/images/image037.jpg) | Move to the previous or next frame by a predefined step.

Shortcuts:
  • **C** — previous frame.
  • **V** — next frame.

    Default step size is `10` frames. To modify this, navigate to **Nickname** > **Settings** > **Player Step**.                                                                                                                                                                                                                                                                                                                                                                                                                                         | -| **Go back**/**Go next**

    ![Go back and go forth controls](/images/go_back_next.png)                     | Navigate to the neighboring frames.

    Shortcuts:
  • **D** — previous frame.
  • **F** — next frame.

    **Go back**/**Go next** buttons are customizable:

    ![](/images/go_back_custom.png)

    To customize, right-click on the button and select one of three options (left to right):
    1. The default setting moves to the next or previous frame (step size is 1 frame).
    2. Move to the next or previous frame that contains objects (e.g., filtered). For more information, refer to [Filters](/docs/manual/advanced/filter).
    3. Move to the next or previous frame without annotations. Use this option to quickly locate missed frames.
    . | -| **Play**/**Pause**

    ![Play and pause](/images/image041.jpg)                               | Switch between playing and pausing the sequence of frames or set of images.
    Shortcut: **Space**.
    To adjust the playback speed, go to **Nickname** > **Settings** > **Player Speed**.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | -| **Go to the specific frame**

    ![Go to the specific frame](/images/image060.jpg)                     | Enter the number of the frame you want to go to and press **Enter**.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | -| **Delete frame**

    ![Delete frame](/images/delete_frame.png)                             | Click to delete current frame.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | +| **Go to the first**/**last frame**

    ![First last frame controls](/images/image036.jpg) | Navigate to the first or the last frame of the sequence. | +| **Go back with a step**/**Go next with a step**

    ![Go to a step controls](/images/image037.jpg) | Move to the previous or next frame by a predefined step.

    Shortcuts:
  • **C** — previous frame.
  • **V** — next frame.

    Default step size is `10` frames. To modify this, navigate to **Nickname** > **Settings** > **Player Step**. | +| **Go back**/**Go next**

    ![Go back and go forth controls](/images/go_back_next.png) | Navigate to the neighboring frames.

    Shortcuts:
  • **D** — previous frame.
  • **F** — next frame.

    **Go back**/**Go next** buttons are customizable:

    ![](/images/go_back_custom.png)

    To customize, right-click on the button and select one of three options (left to right):
    1. The default setting moves to the next or previous frame (step size is 1 frame).
    2. Move to the next or previous frame that contains objects (e.g., filtered). For more information, refer to [Filters](/docs/manual/advanced/filter).
    3. Move to the next or previous frame without annotations. Use this option to quickly locate missed frames.
    . | +| **Play**/**Pause**

    ![Play and pause](/images/image041.jpg) | Switch between playing and pausing the sequence of frames or set of images.
    Shortcut: **Space**.
    To adjust the playback speed, go to **Nickname** > **Settings** > **Player Speed**. | +| **Go to the specific frame**

    ![Go to the specific frame](/images/image060.jpg) | Enter the number of the frame you want to go to and press **Enter**. | +| **Copy frame name**

    ![Copy frame name](/images/navigation_icons_copy_filename.png) | Click to copy frame name to the clipboard. | +| **Copy frame link**

    ![Delete frame](/images/navigation_icons_copy_link.png) | Click to copy link to the frame. | +| **Delete frame**

    ![Delete frame](/images/navigation_icons_delete_frame.png) | Click to delete or restore current frame. | ## Job information and Annotation Mode switcher diff --git a/site/content/en/images/delete_frame.jpg b/site/content/en/images/delete_frame.jpg deleted file mode 100644 index 1e095d521c42..000000000000 Binary files a/site/content/en/images/delete_frame.jpg and /dev/null differ diff --git a/site/content/en/images/delete_frame.png b/site/content/en/images/delete_frame.png deleted file mode 100644 index aa7ebf54808c..000000000000 Binary files a/site/content/en/images/delete_frame.png and /dev/null differ diff --git a/site/content/en/images/image008.jpg b/site/content/en/images/image008.jpg deleted file mode 100644 index c446c0295e36..000000000000 Binary files a/site/content/en/images/image008.jpg and /dev/null differ diff --git a/site/content/en/images/navigation_controls.png b/site/content/en/images/navigation_controls.png new file mode 100644 index 000000000000..31fa9fc5dd4a Binary files /dev/null and b/site/content/en/images/navigation_controls.png differ diff --git a/site/content/en/images/navigation_icons_copy_filename.png b/site/content/en/images/navigation_icons_copy_filename.png new file mode 100644 index 000000000000..8c0c1b5fb533 Binary files /dev/null and b/site/content/en/images/navigation_icons_copy_filename.png differ diff --git a/site/content/en/images/navigation_icons_copy_link.png b/site/content/en/images/navigation_icons_copy_link.png new file mode 100644 index 000000000000..564ae46ac4c0 Binary files /dev/null and b/site/content/en/images/navigation_icons_copy_link.png differ diff --git a/site/content/en/images/navigation_icons_delete_frame.png b/site/content/en/images/navigation_icons_delete_frame.png new file mode 100644 index 000000000000..327368cf6f2a Binary files /dev/null and b/site/content/en/images/navigation_icons_delete_frame.png differ