File size: 4,754 Bytes
9c6594c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
"""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

from gradio.events import Dependency

@document()
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)
    from typing import Callable, Literal, Sequence, Any, TYPE_CHECKING
    from gradio.blocks import Block
    if TYPE_CHECKING:
        from gradio.components import Timer
        from gradio.components.base import Component