Skip to content

Commit

Permalink
Using modern browser API to copy links to clipboard (#8285)
Browse files Browse the repository at this point in the history
  • Loading branch information
bsekachev authored Aug 9, 2024
1 parent 26f1f78 commit 4dae854
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 75 deletions.
1 change: 0 additions & 1 deletion cvat-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
"@uiw/react-md-editor": "^3.22.0",
"antd": "5.17.1",
"chart.js": "^4.3.0",
"copy-to-clipboard": "^3.3.1",
"cvat-canvas": "link:./../cvat-canvas",
"cvat-canvas3d": "link:./../cvat-canvas3d",
"cvat-core": "link:./../cvat-core",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import React from 'react';
import Button from 'antd/lib/button';
import { MenuProps } from 'antd/lib/menu';
import Icon, {
LinkOutlined, CopyOutlined, BlockOutlined, RetweetOutlined, DeleteOutlined, EditOutlined,
} from '@ant-design/icons';
Expand All @@ -15,7 +16,6 @@ import {
import CVATTooltip from 'components/common/cvat-tooltip';
import { ObjectType, ShapeType, ColorBy } from 'reducers';
import { DimensionType, Job } from 'cvat-core-wrapper';
import { MenuProps } from 'antd';

interface Props {
readonly: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ interface Props {
activate(activeElementID?: number): void;
copy(): void;
propagate(): void;
createURL(): void;
switchOrientation(): void;
createURL(): void;
toBackground(): void;
toForeground(): void;
remove(): void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,12 @@ import Text from 'antd/lib/typography/Text';
import Paragraph from 'antd/lib/typography/Paragraph';
import Collapse from 'antd/lib/collapse';
import TextArea from 'antd/lib/input/TextArea';
import copy from 'copy-to-clipboard';
import ErrorStackParser from 'error-stack-parser';

import { ThunkDispatch } from 'utils/redux';
import { resetAfterErrorAsync } from 'actions/boundaries-actions';
import { CombinedState } from 'reducers';
import logger, { EventScope } from 'cvat-logger';
import CVATTooltip from 'components/common/cvat-tooltip';
import config from 'config';
import { saveLogsAsync } from 'actions/annotation-actions';

Expand Down Expand Up @@ -161,24 +159,12 @@ class GlobalErrorBoundary extends React.PureComponent<Props, State> {
<Text strong>What should I do?</Text>
</Paragraph>
<ul>
<li>
<CVATTooltip title='Copied!' trigger='click'>
{/* eslint-disable-next-line */}
<a
onClick={() => copy(message)}
>
{' '}
Copy
{' '}
</a>
</CVATTooltip>
the error message to clipboard
</li>
<li>
Notify an administrator or submit the issue directly on
<a href={config.GITHUB_URL}> GitHub. </a>
Please, provide also:
<ul>
<li>Full error message above</li>
<li>Steps to reproduce the issue</li>
<li>Your operating system and browser version</li>
<li>CVAT version</li>
Expand Down
38 changes: 2 additions & 36 deletions cvat-ui/src/components/task-page/job-list.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
// Copyright (C) 2020-2022 Intel Corporation
// Copyright (C) 2023 CVAT.ai Corporation
// Copyright (C) 2023-2024 CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

import React, { useCallback, useEffect, useState } from 'react';
import jsonLogic from 'json-logic-js';
import _ from 'lodash';
import copy from 'copy-to-clipboard';
import { Indexable, JobsQuery } from 'reducers';
import { useHistory } from 'react-router';
import { Row, Col } from 'antd/lib/grid';
import Text from 'antd/lib/typography/Text';
import Pagination from 'antd/lib/pagination';
import Empty from 'antd/lib/empty';
import Button from 'antd/lib/button';
import { CopyOutlined, PlusOutlined } from '@ant-design/icons';
import { PlusOutlined } from '@ant-design/icons';
import { Task, Job } from 'cvat-core-wrapper';
import JobItem from 'components/job-item/job-item';
import CVATTooltip from 'components/common/cvat-tooltip';
import {
SortingComponent, ResourceFilterHOC, defaultVisibility, updateHistoryFromQuery,
} from 'components/resource-sorting-filtering';
Expand Down Expand Up @@ -107,38 +105,6 @@ function JobListComponent(props: Props): JSX.Element {
<Col>
<Text className='cvat-text-color cvat-jobs-header'> Jobs </Text>
</Col>
<CVATTooltip trigger='click' title='Copied to clipboard!'>
<Button
className='cvat-copy-job-details-button'
type='link'
onClick={(): void => {
let serialized = '';
const [latestJob] = [...taskInstance.jobs].reverse();
for (const job of taskInstance.jobs) {
const baseURL = window.location.origin;
serialized += `Job #${job.id}`.padEnd(`${latestJob.id}`.length + 6, ' ');
serialized += `: ${baseURL}/tasks/${taskInstance.id}/jobs/${job.id}`.padEnd(
`${latestJob.id}`.length + baseURL.length + 8,
' ',
);
serialized += `: [${job.startFrame}-${job.stopFrame}]`.padEnd(
`${latestJob.startFrame}${latestJob.stopFrame}`.length + 5,
' ',
);

if (job.assignee) {
serialized += `\t assigned to "${job.assignee.username}"`;
}

serialized += '\n';
}
copy(serialized);
}}
>
<CopyOutlined />
Copy
</Button>
</CVATTooltip>
</Row>
<Row>
<SortingComponent
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// Copyright (C) 2021-2022 Intel Corporation
// Copyright (C) 2022-2023 CVAT.ai Corporation
// Copyright (C) 2022-2024 CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

import React from 'react';
import copy from 'copy-to-clipboard';
import { connect } from 'react-redux';

import {
Expand Down Expand Up @@ -233,7 +232,17 @@ class ObjectItemContainer extends React.PureComponent<Props, State> {

const search = `frame=${frameNumber}&type=${objectState.objectType}&serverID=${objectState.serverID}`;
const url = `${origin}${pathname}?${search}`;
copy(url);

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();
}
};

private switchOrientation = (): void => {
Expand Down Expand Up @@ -413,8 +422,8 @@ class ObjectItemContainer extends React.PureComponent<Props, State> {
activate={this.activate}
remove={this.remove}
copy={this.copy}
propagate={this.propagate}
createURL={this.createURL}
propagate={this.propagate}
switchOrientation={this.switchOrientation}
toBackground={this.toBackground}
toForeground={this.toForeground}
Expand Down
13 changes: 11 additions & 2 deletions cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import React from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router';
import { RouteComponentProps } from 'react-router-dom';
import copy from 'copy-to-clipboard';

import {
changeFrameAsync,
Expand Down Expand Up @@ -551,7 +550,17 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
const { frameNumber } = this.props;
const { origin, pathname } = window.location;
const url = `${origin}${pathname}?frame=${frameNumber}`;
copy(url);

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();
}
};

private onDeleteFrame = (): void => {
Expand Down
38 changes: 26 additions & 12 deletions tests/cypress/e2e/actions_tasks/case_102_create_link_shape_frame.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@

import { taskName, labelName } from '../../support/const';

Cypress.automation('remote:debugger:protocol', {
command: 'Browser.grantPermissions',
params: {
permissions: ['clipboardReadWrite', 'clipboardSanitizedWrite'],
origin: window.location.origin,
},
});

context('Create a link for shape, frame.', () => {
const caseId = '102';
const createRectangleShape2Points = {
Expand All @@ -27,13 +35,16 @@ context('Create a link for shape, frame.', () => {

describe(`Testing case "${caseId}"`, () => {
it('Create a link for a shape.', () => {
cy.window().then((win) => {
cy.stub(win, 'prompt').returns(win.prompt).as('copyToClipboardPromptShape');
});
cy.window()
.its('navigator.clipboard')
.then((clipboard) => {
cy.spy(clipboard, 'writeText').as('copyTextToClipboard');
});

cy.interactAnnotationObjectMenu('#cvat-objects-sidebar-state-item-1', 'Create object URL');
cy.get('@copyToClipboardPromptShape').should('be.called');
cy.get('@copyToClipboardPromptShape').then((prompt) => {
const url = prompt.args[0][1];
cy.get('@copyTextToClipboard').should('be.called');
cy.get('@copyTextToClipboard').then((stub) => {
const url = stub.args[0][0];
expect(url).include('frame=');
expect(url).include('type=');
expect(url).include('serverID=');
Expand All @@ -44,13 +55,16 @@ context('Create a link for shape, frame.', () => {
});

it('Create a link for a frame.', () => {
cy.window().then((win) => {
cy.stub(win, 'prompt').returns(win.prompt).as('copyToClipboardPromptFrame');
});
cy.window()
.its('navigator.clipboard')
.then((clipboard) => {
cy.spy(clipboard, 'writeText').as('copyTextToClipboard');
});

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];
cy.get('@copyTextToClipboard').should('be.called');
cy.get('@copyTextToClipboard').then((stub) => {
const url = stub.args[0][0];
expect(url).include('frame=');
expect(url).not.include('type=');
expect(url).not.include('serverID=');
Expand Down
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4184,7 +4184,7 @@ cookie@^0.4.0:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==

copy-to-clipboard@^3.3.1, copy-to-clipboard@^3.3.3:
copy-to-clipboard@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0"
integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==
Expand Down Expand Up @@ -4418,7 +4418,7 @@ [email protected]:
three "^0.156.1"

"cvat-canvas@link:./cvat-canvas":
version "2.20.3"
version "2.20.6"
dependencies:
"@types/polylabel" "^1.0.5"
polylabel "^1.1.0"
Expand All @@ -4429,7 +4429,7 @@ [email protected]:
svg.select.js "3.0.1"

"cvat-core@link:./cvat-core":
version "15.0.6"
version "15.1.0"
dependencies:
axios "^1.6.0"
axios-retry "^4.0.0"
Expand Down

0 comments on commit 4dae854

Please sign in to comment.