mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 08:49:13 +00:00
fix(filters): export not working with Safari (#1505)
* fix(filters): export not working with Safari * speculative fix for safari --------- Co-authored-by: s0up4200 <s0up4200@pm.me>
This commit is contained in:
parent
9d08f149b4
commit
d558db231c
2 changed files with 44 additions and 53 deletions
|
@ -23,7 +23,7 @@ import {
|
||||||
import { ArrowDownTrayIcon } from "@heroicons/react/24/solid";
|
import { ArrowDownTrayIcon } from "@heroicons/react/24/solid";
|
||||||
|
|
||||||
import { FilterListContext, FilterListState } from "@utils/Context";
|
import { FilterListContext, FilterListState } from "@utils/Context";
|
||||||
import { classNames } from "@utils";
|
import { classNames, CopyTextToClipboard } from "@utils";
|
||||||
import { FilterAddForm } from "@forms";
|
import { FilterAddForm } from "@forms";
|
||||||
import { useToggle } from "@hooks/hooks";
|
import { useToggle } from "@hooks/hooks";
|
||||||
import { APIClient } from "@api/APIClient";
|
import { APIClient } from "@api/APIClient";
|
||||||
|
@ -284,17 +284,6 @@ const FilterItemDropdown = ({ filter, onToggle }: FilterItemDropdownProps) => {
|
||||||
actions: any;
|
actions: any;
|
||||||
actions_count: any;
|
actions_count: any;
|
||||||
actions_enabled_count: number;
|
actions_enabled_count: number;
|
||||||
external_script_enabled: any;
|
|
||||||
external_script_cmd: any;
|
|
||||||
external_script_args: any;
|
|
||||||
external_script_expect_status: any;
|
|
||||||
external_webhook_enabled: any;
|
|
||||||
external_webhook_host: any;
|
|
||||||
external_webhook_data: any;
|
|
||||||
external_webhook_expect_status: any;
|
|
||||||
external_webhook_retry_status: any;
|
|
||||||
external_webhook_retry_attempts: any;
|
|
||||||
external_webhook_retry_delay_seconds: any;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const completeFilter = await APIClient.filters.getByID(filter.id) as Partial<CompleteFilterType>;
|
const completeFilter = await APIClient.filters.getByID(filter.id) as Partial<CompleteFilterType>;
|
||||||
|
@ -309,17 +298,6 @@ const FilterItemDropdown = ({ filter, onToggle }: FilterItemDropdownProps) => {
|
||||||
delete completeFilter.actions_enabled_count;
|
delete completeFilter.actions_enabled_count;
|
||||||
delete completeFilter.indexers;
|
delete completeFilter.indexers;
|
||||||
delete completeFilter.actions;
|
delete completeFilter.actions;
|
||||||
delete completeFilter.external_script_enabled;
|
|
||||||
delete completeFilter.external_script_cmd;
|
|
||||||
delete completeFilter.external_script_args;
|
|
||||||
delete completeFilter.external_script_expect_status;
|
|
||||||
delete completeFilter.external_webhook_enabled;
|
|
||||||
delete completeFilter.external_webhook_host;
|
|
||||||
delete completeFilter.external_webhook_data;
|
|
||||||
delete completeFilter.external_webhook_expect_status;
|
|
||||||
delete completeFilter.external_webhook_retry_status;
|
|
||||||
delete completeFilter.external_webhook_retry_attempts;
|
|
||||||
delete completeFilter.external_webhook_retry_delay_seconds;
|
|
||||||
|
|
||||||
// Remove properties with default values from the exported filter to minimize the size of the JSON string
|
// Remove properties with default values from the exported filter to minimize the size of the JSON string
|
||||||
["enabled", "priority", "smart_episode", "resolutions", "sources", "codecs", "containers", "tags_match_logic", "except_tags_match_logic"].forEach((key) => {
|
["enabled", "priority", "smart_episode", "resolutions", "sources", "codecs", "containers", "tags_match_logic", "except_tags_match_logic"].forEach((key) => {
|
||||||
|
@ -346,40 +324,17 @@ const FilterItemDropdown = ({ filter, onToggle }: FilterItemDropdownProps) => {
|
||||||
|
|
||||||
const finalJson = discordFormat ? "```JSON\n" + json + "\n```" : json;
|
const finalJson = discordFormat ? "```JSON\n" + json + "\n```" : json;
|
||||||
|
|
||||||
const copyTextToClipboard = (text: string) => {
|
// Asynchronously call copyTextToClipboard
|
||||||
const textarea = document.createElement("textarea");
|
CopyTextToClipboard(finalJson)
|
||||||
textarea.style.position = "fixed";
|
.then(() => {
|
||||||
textarea.style.opacity = "0";
|
toast.custom((t) => <Toast type="success" body="Filter copied to clipboard!" t={t} />);
|
||||||
textarea.value = text;
|
|
||||||
document.body.appendChild(textarea);
|
|
||||||
textarea.focus();
|
|
||||||
textarea.select();
|
|
||||||
|
|
||||||
try {
|
})
|
||||||
const successful = document.execCommand("copy");
|
.catch((err) => {
|
||||||
if (successful) {
|
console.error("could not copy filter to clipboard", err);
|
||||||
toast.custom((t) => <Toast type="success" body="Filter copied to clipboard." t={t} />);
|
|
||||||
} else {
|
|
||||||
toast.custom((t) => <Toast type="error" body="Failed to copy JSON to clipboard." t={t} />);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Unable to copy text", err);
|
|
||||||
toast.custom((t) => <Toast type="error" body="Failed to copy JSON to clipboard." t={t} />);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.body.removeChild(textarea);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (navigator.clipboard) {
|
|
||||||
navigator.clipboard.writeText(finalJson).then(() => {
|
|
||||||
toast.custom((t) => <Toast type="success" body="Filter copied to clipboard." t={t} />);
|
|
||||||
}, () => {
|
|
||||||
toast.custom((t) => <Toast type="error" body="Failed to copy JSON to clipboard." t={t} />);
|
toast.custom((t) => <Toast type="error" body="Failed to copy JSON to clipboard." t={t} />);
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
copyTextToClipboard(finalJson);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
toast.custom((t) => <Toast type="error" body="Failed to get filter data." t={t} />);
|
toast.custom((t) => <Toast type="error" body="Failed to get filter data." t={t} />);
|
||||||
|
|
|
@ -152,3 +152,39 @@ export const RandomLinuxIsos = (count: number) => {
|
||||||
|
|
||||||
return Array.from({ length: count }, () => linuxIsos[Math.floor(Math.random() * linuxIsos.length)]);
|
return Array.from({ length: count }, () => linuxIsos[Math.floor(Math.random() * linuxIsos.length)]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export async function CopyTextToClipboard(text: string) {
|
||||||
|
if ("clipboard" in navigator) {
|
||||||
|
// Safari requires clipboard operations to be directly triggered by a user interaction.
|
||||||
|
// Using setTimeout with a delay of 0 ensures the clipboard operation is deferred until
|
||||||
|
// after the current call stack has cleared, effectively placing it outside of the
|
||||||
|
// immediate execution context of the user interaction event. This workaround allows
|
||||||
|
// the clipboard operation to bypass Safari's security restrictions.
|
||||||
|
setTimeout(async () => {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
console.log("Text copied to clipboard successfully.");
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Copy to clipboard unsuccessful: ", err);
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
} else {
|
||||||
|
// fallback for browsers that do not support the Clipboard API
|
||||||
|
copyTextToClipboardFallback(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyTextToClipboardFallback(text: string) {
|
||||||
|
const textarea = document.createElement("textarea");
|
||||||
|
textarea.value = text;
|
||||||
|
document.body.appendChild(textarea);
|
||||||
|
textarea.select();
|
||||||
|
try {
|
||||||
|
document.execCommand('copy');
|
||||||
|
console.log("Text copied to clipboard successfully.");
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to copy text using fallback method: ', err);
|
||||||
|
}
|
||||||
|
document.body.removeChild(textarea);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue