Spaces:
Running
Running
"""Predefined button to copy a shareable link to the current Gradio Space.""" | |
from __future__ import annotations | |
import textwrap | |
import time | |
from collections.abc import Sequence | |
from pathlib import Path | |
from typing import TYPE_CHECKING, Literal | |
from gradio_client.documentation import document | |
from gradio import utils | |
from gradio.components.base import Component | |
from gradio.components.button import Button | |
from gradio.context import get_blocks_context | |
if TYPE_CHECKING: | |
from gradio.components import Timer | |
class DeepLinkButton(Button): | |
""" | |
Creates a button that copies a shareable link to the current Gradio Space. | |
The link includes the current session hash as a query parameter. | |
""" | |
is_template = True | |
n_created = 0 | |
def __init__( | |
self, | |
value: str = "Share via Link", | |
copied_value: str = "Link Copied!", | |
*, | |
inputs: Component | Sequence[Component] | set[Component] | None = None, | |
variant: Literal["primary", "secondary"] = "secondary", | |
size: Literal["sm", "md", "lg"] = "lg", | |
icon: str | Path | None = utils.get_icon_path("link.svg"), | |
link: str | None = None, | |
visible: bool = True, | |
interactive: bool = True, | |
elem_id: str | None = None, # noqa: ARG002 | |
elem_classes: list[str] | str | None = None, | |
render: bool = True, | |
key: int | str | tuple[int | str, ...] | None = None, | |
preserved_by_key: list[str] | str | None = "value", | |
scale: int | None = None, | |
min_width: int | None = None, | |
every: Timer | float | None = None, | |
): | |
""" | |
Parameters: | |
value: The text to display on the button. | |
copied_value: The text to display on the button after the link has been copied. | |
""" | |
self.copied_value = copied_value | |
super().__init__( | |
value, | |
inputs=inputs, | |
variant=variant, | |
size=size, | |
icon=icon, | |
link=link, | |
visible=visible, | |
interactive=interactive, | |
elem_id=f"gradio-share-link-button-{self.n_created}", | |
elem_classes=elem_classes, | |
render=render, | |
key=key, | |
preserved_by_key=preserved_by_key, | |
scale=scale, | |
min_width=min_width, | |
every=every, | |
) | |
self.elem_id: str | |
self.n_created += 1 | |
if get_blocks_context(): | |
self.activate() | |
def activate(self): | |
"""Attach the click event to copy the share link.""" | |
_js = self.get_share_link(self.value, self.copied_value) | |
# Need to separate events because can't run .then in a pure js | |
# function. | |
self.click(fn=None, inputs=[], outputs=[self], js=_js) | |
self.click( | |
fn=lambda: time.sleep(1) or self.value, | |
inputs=[], | |
outputs=[self], | |
queue=False, | |
show_api=False, | |
) | |
def get_share_link( | |
self, value: str = "Share via Link", copied_value: str = "Link Copied!" | |
): | |
delete_sign_line = ( | |
"currentUrl.searchParams.delete('__sign');" if utils.get_space() else "" | |
) | |
return textwrap.dedent( | |
f""" | |
() => {{ | |
const sessionHash = window.__gradio_session_hash__; | |
fetch(`/gradio_api/deep_link?session_hash=${{sessionHash}}`) | |
.then(response => {{ | |
if (!response.ok) {{ | |
throw new Error('Network response was not ok'); | |
}} | |
return response.text(); | |
}}) | |
.then(data => {{ | |
const currentUrl = new URL(window.location.href); | |
const cleanData = data.replace(/^"|"$/g, ''); | |
if (cleanData) {{ | |
currentUrl.searchParams.set('deep_link', cleanData); | |
}} | |
{delete_sign_line} | |
navigator.clipboard.writeText(currentUrl.toString()); | |
}}) | |
.catch(error => {{ | |
console.error('Error fetching deep link:', error); | |
return "Error"; | |
}}); | |
return "BUTTON_COPIED_VALUE"; | |
}} | |
""".replace("BUTTON_DEFAULT_VALUE", value).replace( | |
"BUTTON_COPIED_VALUE", copied_value | |
) | |
).replace("ID", self.elem_id) | |