Change text copy to use fallback (#811)
This commit is contained in:
@@ -2,6 +2,7 @@ import { useState } from "react";
|
|||||||
import { Button } from "./button";
|
import { Button } from "./button";
|
||||||
import { Input } from "./input";
|
import { Input } from "./input";
|
||||||
import { CheckIcon, CopyIcon } from "@radix-ui/react-icons";
|
import { CheckIcon, CopyIcon } from "@radix-ui/react-icons";
|
||||||
|
import { copyText } from "@/util/copyText";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
value: string;
|
value: string;
|
||||||
@@ -22,14 +23,15 @@ function HiddenCopyableInput({ value }: Props) {
|
|||||||
size="sm"
|
size="sm"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
onClick={async () => {
|
onClick={() => {
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
setHidden(false);
|
setHidden(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await navigator.clipboard.writeText(value);
|
copyText(value).then(() => {
|
||||||
setCopied(true);
|
setCopied(true);
|
||||||
setTimeout(() => setCopied(false), 3000);
|
setTimeout(() => setCopied(false), 3000);
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!hidden && !copied && <CopyIcon className="mr-2 h-4 w-4" />}
|
{!hidden && !copied && <CopyIcon className="mr-2 h-4 w-4" />}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import {
|
|||||||
import { OrganizationApiResponse } from "@/api/types";
|
import { OrganizationApiResponse } from "@/api/types";
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
import { MAX_STEPS_DEFAULT } from "../constants";
|
import { MAX_STEPS_DEFAULT } from "../constants";
|
||||||
|
import { copyText } from "@/util/copyText";
|
||||||
|
|
||||||
const createNewTaskFormSchema = z
|
const createNewTaskFormSchema = z
|
||||||
.object({
|
.object({
|
||||||
@@ -487,10 +488,11 @@ function CreateNewTaskForm({ initialValues }: Props) {
|
|||||||
"x-api-key": apiCredential ?? "<your-api-key>",
|
"x-api-key": apiCredential ?? "<your-api-key>",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await navigator.clipboard.writeText(curl);
|
copyText(curl).then(() => {
|
||||||
toast({
|
toast({
|
||||||
title: "Copied cURL",
|
title: "Copied cURL",
|
||||||
description: "cURL copied to clipboard",
|
description: "cURL copied to clipboard",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import {
|
|||||||
import { OrganizationApiResponse } from "@/api/types";
|
import { OrganizationApiResponse } from "@/api/types";
|
||||||
import { MAX_STEPS_DEFAULT } from "../constants";
|
import { MAX_STEPS_DEFAULT } from "../constants";
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
|
import { copyText } from "@/util/copyText";
|
||||||
|
|
||||||
const savedTaskFormSchema = z
|
const savedTaskFormSchema = z
|
||||||
.object({
|
.object({
|
||||||
@@ -629,10 +630,11 @@ function SavedTaskForm({ initialValues }: Props) {
|
|||||||
"x-api-key": apiCredential ?? "<your-api-key>",
|
"x-api-key": apiCredential ?? "<your-api-key>",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await navigator.clipboard.writeText(curl);
|
copyText(curl).then(() => {
|
||||||
toast({
|
toast({
|
||||||
title: "Copied cURL",
|
title: "Copied cURL",
|
||||||
description: "cURL copied to clipboard",
|
description: "cURL copied to clipboard",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import { taskIsFinalized } from "@/api/utils";
|
|||||||
import fetchToCurl from "fetch-to-curl";
|
import fetchToCurl from "fetch-to-curl";
|
||||||
import { apiBaseUrl } from "@/util/env";
|
import { apiBaseUrl } from "@/util/env";
|
||||||
import { useApiCredential } from "@/hooks/useApiCredential";
|
import { useApiCredential } from "@/hooks/useApiCredential";
|
||||||
|
import { copyText } from "@/util/copyText";
|
||||||
|
|
||||||
function createTaskRequestObject(values: TaskApiResponse) {
|
function createTaskRequestObject(values: TaskApiResponse) {
|
||||||
return {
|
return {
|
||||||
@@ -142,12 +143,13 @@ function TaskDetails() {
|
|||||||
"x-api-key": apiCredential ?? "<your-api-key>",
|
"x-api-key": apiCredential ?? "<your-api-key>",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
navigator.clipboard.writeText(curl);
|
copyText(curl).then(() => {
|
||||||
toast({
|
toast({
|
||||||
variant: "success",
|
variant: "success",
|
||||||
title: "Copied to Clipboard",
|
title: "Copied to Clipboard",
|
||||||
description:
|
description:
|
||||||
"The cURL command has been copied to your clipboard.",
|
"The cURL command has been copied to your clipboard.",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
25
skyvern-frontend/src/util/copyText.ts
Normal file
25
skyvern-frontend/src/util/copyText.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* Progressively enhanced text copying
|
||||||
|
* https://web.dev/patterns/clipboard/copy-text
|
||||||
|
*/
|
||||||
|
async function copyText(text: string): Promise<void> {
|
||||||
|
if ("clipboard" in navigator) {
|
||||||
|
return navigator.clipboard.writeText(text);
|
||||||
|
} else {
|
||||||
|
const textArea = document.createElement("textarea");
|
||||||
|
textArea.value = text;
|
||||||
|
textArea.style.opacity = "0";
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.focus();
|
||||||
|
textArea.select();
|
||||||
|
const success = document.execCommand("copy");
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
if (success) {
|
||||||
|
return Promise.resolve();
|
||||||
|
} else {
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { copyText };
|
||||||
Reference in New Issue
Block a user