@gradio/core 1.1.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/src/Blocks.svelte +33 -2
  3. package/dist/src/_init.js +2 -2
  4. package/dist/src/api_docs/ApiBanner.svelte +6 -2
  5. package/dist/src/api_docs/ApiBanner.svelte.d.ts +1 -1
  6. package/dist/src/api_docs/ApiDocs.svelte +41 -25
  7. package/dist/src/api_docs/CodeSnippet.svelte +67 -170
  8. package/dist/src/api_docs/CodeSnippet.svelte.d.ts +2 -6
  9. package/dist/src/api_docs/CopyMarkdown.svelte +7 -2
  10. package/dist/src/api_docs/CopyMarkdown.svelte.d.ts +1 -1
  11. package/dist/src/api_docs/InstallSnippet.svelte +6 -1
  12. package/dist/src/api_docs/InstallSnippet.svelte.d.ts +1 -1
  13. package/dist/src/api_docs/ParametersSnippet.svelte +6 -1
  14. package/dist/src/api_docs/ParametersSnippet.svelte.d.ts +1 -1
  15. package/dist/src/api_docs/RecordingSnippet.svelte +6 -1
  16. package/dist/src/api_docs/RecordingSnippet.svelte.d.ts +1 -1
  17. package/dist/src/api_docs/ResponseSnippet.svelte +6 -1
  18. package/dist/src/api_docs/ResponseSnippet.svelte.d.ts +1 -1
  19. package/dist/src/api_docs/Settings.svelte +2 -7
  20. package/dist/src/api_docs/SettingsBanner.svelte +0 -3
  21. package/dist/src/api_docs/SkillSnippet.svelte +125 -0
  22. package/dist/src/api_docs/SkillSnippet.svelte.d.ts +20 -0
  23. package/dist/src/api_docs/img/skill.svg +10 -0
  24. package/dist/src/api_docs/utils.d.ts +0 -1
  25. package/dist/src/api_docs/utils.js +0 -22
  26. package/dist/src/dependency.d.ts +3 -1
  27. package/dist/src/dependency.js +39 -1
  28. package/dist/src/gradio_helper.js +5 -13
  29. package/dist/src/i18n.d.ts +1 -3
  30. package/dist/src/i18n.js +6 -53
  31. package/dist/src/init.svelte.js +81 -82
  32. package/package.json +49 -49
  33. package/src/Blocks.svelte +33 -2
  34. package/src/_init.ts +2 -2
  35. package/src/api_docs/ApiBanner.svelte +6 -2
  36. package/src/api_docs/ApiDocs.svelte +41 -25
  37. package/src/api_docs/CodeSnippet.svelte +67 -170
  38. package/src/api_docs/CopyMarkdown.svelte +7 -2
  39. package/src/api_docs/InstallSnippet.svelte +6 -1
  40. package/src/api_docs/ParametersSnippet.svelte +6 -1
  41. package/src/api_docs/RecordingSnippet.svelte +6 -1
  42. package/src/api_docs/ResponseSnippet.svelte +6 -1
  43. package/src/api_docs/Settings.svelte +2 -7
  44. package/src/api_docs/SettingsBanner.svelte +0 -3
  45. package/src/api_docs/SkillSnippet.svelte +125 -0
  46. package/src/api_docs/img/skill.svg +10 -0
  47. package/src/api_docs/utils.ts +0 -25
  48. package/src/dependency.ts +39 -1
  49. package/src/gradio_helper.ts +5 -17
  50. package/src/i18n.test.ts +41 -9
  51. package/src/i18n.ts +9 -62
  52. package/src/init.svelte.ts +95 -99
@@ -1,75 +1,78 @@
1
1
  <script lang="ts">
2
- import type { ComponentMeta, Dependency, Payload } from "../types";
2
+ import type { Dependency, Payload } from "../types";
3
3
  import CopyButton from "./CopyButton.svelte";
4
- import { represent_value, is_potentially_nested_file_data } from "./utils";
5
4
  import { Block } from "@gradio/atoms";
6
5
  import EndpointDetail from "./EndpointDetail.svelte";
7
6
 
8
- interface EndpointParameter {
9
- label: string;
10
- type: string;
11
- python_type: { type: string };
12
- component: string;
13
- example_input: string;
14
- serializer: string;
15
- }
16
-
17
7
  export let dependency: Dependency;
18
- export let root: string;
19
- export let api_prefix: string;
20
- export let space_id: string | null;
21
- export let endpoint_parameters: any;
22
- export let username: string | null;
23
- export let current_language: "python" | "javascript" | "bash" | "mcp";
8
+ export let current_language:
9
+ | "python"
10
+ | "javascript"
11
+ | "bash"
12
+ | "skill"
13
+ | "mcp";
24
14
  export let api_description: string | null = null;
25
15
  export let analytics: Record<string, any>;
26
16
  export let markdown_code_snippets: Record<string, Record<string, string>>;
17
+ export let code_snippets: Record<string, string>;
27
18
  export let last_api_call: Payload | null = null;
28
19
 
29
- let python_code: HTMLElement;
30
- let js_code: HTMLElement;
31
- let bash_post_code: HTMLElement;
32
- let bash_get_code: HTMLElement;
33
-
34
- let has_file_path = endpoint_parameters.some((param: EndpointParameter) =>
35
- is_potentially_nested_file_data(param.example_input)
36
- );
37
- let blob_components = ["Audio", "File", "Image", "Video"];
38
- let blob_examples: any[] = endpoint_parameters.filter(
39
- (param: EndpointParameter) => blob_components.includes(param.component)
40
- );
20
+ $: markdown_code_snippets[
21
+ dependency.api_name as keyof typeof markdown_code_snippets
22
+ ] = {
23
+ python: code_snippets.python || "",
24
+ javascript: code_snippets.javascript || "",
25
+ bash: code_snippets.bash || ""
26
+ };
41
27
 
42
- $: normalised_api_prefix = api_prefix ? api_prefix : "/";
43
- $: normalised_root = root.replace(/\/$/, "");
28
+ function escape_html(text: string): string {
29
+ return text
30
+ .replace(/&/g, "&amp;")
31
+ .replace(/</g, "&lt;")
32
+ .replace(/>/g, "&gt;");
33
+ }
44
34
 
45
- $: is_most_recently_used = last_api_call?.fn_index === dependency.id;
35
+ function highlight_python(code: string): string {
36
+ let html = escape_html(code);
37
+ html = html.replace(
38
+ /\b(from|import|print)\b/g,
39
+ '<span class="kw">$1</span>'
40
+ );
41
+ html = html.replace(
42
+ /(Client\()("[^"]*")(\))/g,
43
+ '$1<span class="str">$2</span>$3'
44
+ );
45
+ html = html.replace(
46
+ /(api_name=)("[^"]*")/g,
47
+ '$1<span class="api-name">$2</span>'
48
+ );
49
+ return html;
50
+ }
46
51
 
47
- $: actual_data =
48
- is_most_recently_used && last_api_call?.data
49
- ? last_api_call.data.filter((d) => typeof d !== "undefined")
50
- : null;
52
+ function highlight_javascript(code: string): string {
53
+ let html = escape_html(code);
54
+ html = html.replace(
55
+ /\b(import|from|const|await)\b/g,
56
+ '<span class="kw">$1</span>'
57
+ );
58
+ html = html.replace(
59
+ /(Client\.connect\()("[^"]*")(\))/g,
60
+ '$1<span class="str">$2</span>$3'
61
+ );
62
+ html = html.replace(
63
+ /(\.predict\()("[^"]*")/g,
64
+ '$1<span class="api-name">$2</span>'
65
+ );
66
+ return html;
67
+ }
51
68
 
52
- function getParameterValue(param: any, index: number): any {
53
- if (
54
- is_most_recently_used &&
55
- actual_data &&
56
- actual_data[index] !== undefined
57
- ) {
58
- return actual_data[index];
59
- }
60
- return param.parameter_has_default !== undefined &&
61
- param.parameter_has_default
62
- ? param.parameter_default
63
- : param.example_input;
69
+ function highlight_bash(code: string): string {
70
+ return escape_html(code);
64
71
  }
65
72
 
66
- $: markdown_code_snippets[
67
- dependency.api_name as keyof typeof markdown_code_snippets
68
- ] = {
69
- python: python_code?.innerText || "",
70
- javascript: js_code?.innerText || "",
71
- bash: bash_post_code?.innerText || ""
72
- };
73
+ $: python_html = highlight_python(code_snippets.python || "");
74
+ $: js_html = highlight_javascript(code_snippets.javascript || "");
75
+ $: bash_html = highlight_bash(code_snippets.bash || "");
73
76
  </script>
74
77
 
75
78
  <div class="container">
@@ -84,37 +87,9 @@
84
87
  <Block>
85
88
  <code>
86
89
  <div class="copy">
87
- <CopyButton code={python_code?.innerText} />
88
- </div>
89
- <div bind:this={python_code}>
90
- <pre><span class="highlight">from</span> gradio_client <span
91
- class="highlight">import</span
92
- > Client{#if has_file_path}, handle_file{/if}
93
-
94
- client = Client(<span class="token string">"{space_id || root}"</span
95
- >{#if username !== null}, auth=("{username}", **password**){/if})
96
- result = client.<span class="highlight">predict</span
97
- >(<!--
98
- -->{#each endpoint_parameters as param, i}<!--
99
- -->
100
- {param.parameter_name
101
- ? param.parameter_name + "="
102
- : ""}<span
103
- class:recent-value={is_most_recently_used &&
104
- actual_data?.[i] !== undefined}
105
- >{represent_value(
106
- getParameterValue(param, i),
107
- param.python_type.type,
108
- "py"
109
- )}</span
110
- >,{/each}<!--
111
-
112
- -->
113
- api_name=<span class="api-name">"/{dependency.api_name}"</span><!--
114
- -->
115
- )
116
- <span class="highlight">print</span>(result)</pre>
90
+ <CopyButton code={code_snippets.python || ""} />
117
91
  </div>
92
+ <pre>{@html python_html}</pre>
118
93
  </code>
119
94
  </Block>
120
95
  </div>
@@ -122,53 +97,9 @@ result = client.<span class="highlight">predict</span
122
97
  <Block>
123
98
  <code>
124
99
  <div class="copy">
125
- <CopyButton code={js_code?.innerText} />
126
- </div>
127
- <div bind:this={js_code}>
128
- <pre>import &lbrace; Client &rbrace; from "@gradio/client";
129
- {#each blob_examples as { component, example_input }, i}<!--
130
- -->
131
- const response_{i} = await fetch("{example_input.url}");
132
- const example{component} = await response_{i}.blob();
133
- {/each}<!--
134
- -->
135
- const client = await Client.connect(<span class="token string"
136
- >"{space_id || root}"</span
137
- >{#if username !== null}, &lbrace;auth: ["{username}", **password**]&rbrace;{/if});
138
- const result = await client.predict(<span class="api-name"
139
- >"/{dependency.api_name}"</span
140
- >, &lbrace; <!--
141
- -->{#each endpoint_parameters as param, i}<!--
142
- -->{#if blob_components.includes(param.component)}<!--
143
- -->
144
- <span
145
- class="example-inputs"
146
- >{param.parameter_name}: example{param.component}</span
147
- >, <!--
148
- --><span class="desc"><!--
149
- --></span
150
- ><!--
151
- -->{:else}<!--
152
- -->
153
- <span
154
- class="example-inputs {is_most_recently_used &&
155
- actual_data?.[i] !== undefined
156
- ? 'recent-value'
157
- : ''}"
158
- >{param.parameter_name}: {represent_value(
159
- getParameterValue(param, i),
160
- param.python_type.type,
161
- "js"
162
- )}</span
163
- >, <!--
164
- --><!--
165
- -->{/if}
166
- {/each}
167
- &rbrace;);
168
-
169
- console.log(result.data);
170
- </pre>
100
+ <CopyButton code={code_snippets.javascript || ""} />
171
101
  </div>
102
+ <pre>{@html js_html}</pre>
172
103
  </code>
173
104
  </Block>
174
105
  </div>
@@ -176,29 +107,9 @@ result = client.<span class="highlight">predict</span
176
107
  <Block>
177
108
  <code>
178
109
  <div class="copy">
179
- <CopyButton code={bash_post_code?.innerText}></CopyButton>
180
- </div>
181
-
182
- <div bind:this={bash_post_code}>
183
- <pre>curl -X POST {normalised_root}{normalised_api_prefix}/call/{dependency.api_name} -s -H "Content-Type: application/json" -d '{"{"}
184
- "data": [{#each endpoint_parameters as param, i}
185
- <!--
186
- --><span
187
- class={is_most_recently_used && actual_data?.[i] !== undefined
188
- ? "recent-value"
189
- : ""}
190
- >{represent_value(
191
- getParameterValue(param, i),
192
- param.python_type.type,
193
- "bash"
194
- )}</span
195
- >{#if i < endpoint_parameters.length - 1},
196
- {/if}
197
- {/each}
198
- ]{"}"}' \
199
- | awk -F'"' '{"{"} print $4{"}"}' \
200
- | read EVENT_ID; curl -N {normalised_root}{normalised_api_prefix}/call/{dependency.api_name}/$EVENT_ID</pre>
110
+ <CopyButton code={code_snippets.bash || ""} />
201
111
  </div>
112
+ <pre>{@html bash_html}</pre>
202
113
  </code>
203
114
  </Block>
204
115
  </div>
@@ -212,11 +123,6 @@ result = client.<span class="highlight">predict</span
212
123
  tab-size: 2;
213
124
  }
214
125
 
215
- .token.string {
216
- display: contents;
217
- color: var(--color-accent-base);
218
- }
219
-
220
126
  code {
221
127
  position: relative;
222
128
  display: block;
@@ -238,21 +144,12 @@ result = client.<span class="highlight">predict</span
238
144
  margin-bottom: var(--size-3);
239
145
  }
240
146
 
241
- .desc {
242
- color: var(--body-text-color-subdued);
243
- }
244
-
245
- .api-name {
147
+ :global(.api-name) {
246
148
  color: var(--color-accent);
247
149
  }
248
150
 
249
- .recent-value {
250
- color: #fd7b00;
251
- background: #fff4e6;
252
- border: 1px solid #ffd9b3;
253
- border-radius: var(--radius-sm);
254
- padding: 1px 4px;
255
- font-weight: var(--weight-medium);
151
+ :global(.str) {
152
+ color: var(--color-accent-base);
256
153
  }
257
154
 
258
155
  .hidden {
@@ -10,7 +10,12 @@
10
10
  import { represent_value } from "./utils";
11
11
  import type { Dependency } from "../types";
12
12
 
13
- export let current_language: "python" | "javascript" | "bash" | "mcp";
13
+ export let current_language:
14
+ | "python"
15
+ | "javascript"
16
+ | "bash"
17
+ | "skill"
18
+ | "mcp";
14
19
  export let space_id: string | null;
15
20
  export let root: string;
16
21
  export let api_count: number;
@@ -362,7 +367,7 @@ Read the documentation above so I can ask questions about it.`
362
367
  }
363
368
 
364
369
  async function copyMarkdown(
365
- current_language: "python" | "javascript" | "bash" | "mcp"
370
+ current_language: "python" | "javascript" | "bash" | "skill" | "mcp"
366
371
  ): Promise<void> {
367
372
  try {
368
373
  if (!markdown_content[current_language]) {
@@ -2,7 +2,12 @@
2
2
  import CopyButton from "./CopyButton.svelte";
3
3
  import { Block } from "@gradio/atoms";
4
4
 
5
- export let current_language: "python" | "javascript" | "bash" | "mcp";
5
+ export let current_language:
6
+ | "python"
7
+ | "javascript"
8
+ | "bash"
9
+ | "skill"
10
+ | "mcp";
6
11
 
7
12
  let py_install = "pip install gradio_client";
8
13
  let js_install = "npm i -D @gradio/client";
@@ -5,7 +5,12 @@
5
5
  export let is_running: boolean;
6
6
  export let endpoint_returns: any;
7
7
  export let js_returns: any;
8
- export let current_language: "python" | "javascript" | "bash" | "mcp";
8
+ export let current_language:
9
+ | "python"
10
+ | "javascript"
11
+ | "bash"
12
+ | "skill"
13
+ | "mcp";
9
14
  </script>
10
15
 
11
16
  <h4>
@@ -9,7 +9,12 @@
9
9
  export let short_root: string;
10
10
  export let root: string;
11
11
  export let api_prefix = "";
12
- export let current_language: "python" | "javascript" | "bash" | "mcp";
12
+ export let current_language:
13
+ | "python"
14
+ | "javascript"
15
+ | "bash"
16
+ | "skill"
17
+ | "mcp";
13
18
  export let username: string | null;
14
19
 
15
20
  let python_code: HTMLElement;
@@ -4,7 +4,12 @@
4
4
  export let is_running: boolean;
5
5
  export let endpoint_returns: any;
6
6
  export let js_returns: any;
7
- export let current_language: "python" | "javascript" | "bash" | "mcp";
7
+ export let current_language:
8
+ | "python"
9
+ | "javascript"
10
+ | "bash"
11
+ | "skill"
12
+ | "mcp";
8
13
  </script>
9
14
 
10
15
  <h4>
@@ -6,6 +6,7 @@
6
6
  import { BaseCheckbox as Checkbox } from "@gradio/checkbox";
7
7
  import { language_choices, changeLocale } from "../i18n";
8
8
  import { locale, _ } from "svelte-i18n";
9
+ import { get } from "svelte/store";
9
10
  import record from "./img/record.svg";
10
11
 
11
12
  let {
@@ -52,15 +53,9 @@
52
53
  };
53
54
  });
54
55
 
55
- let current_locale: string = $state("en");
56
+ let current_locale: string = $state(get(locale) ?? "en");
56
57
  let current_theme: "light" | "dark" | "system" = $state("system");
57
58
 
58
- locale.subscribe((value) => {
59
- if (value) {
60
- current_locale = value;
61
- }
62
- });
63
-
64
59
  function handleLanguageChange(value: string): void {
65
60
  const new_locale = value;
66
61
  changeLocale(new_locale);
@@ -2,11 +2,8 @@
2
2
  import { _ } from "svelte-i18n";
3
3
  import settings_logo from "./img/settings-logo.svg";
4
4
  import Clear from "./img/clear.svelte";
5
- import { setupi18n } from "../i18n";
6
5
 
7
6
  let { root, onclose }: { root: string; onclose?: () => void } = $props();
8
-
9
- setupi18n();
10
7
  </script>
11
8
 
12
9
  <h2>
@@ -0,0 +1,125 @@
1
+ <script lang="ts">
2
+ import { Block } from "@gradio/atoms";
3
+ import CopyButton from "./CopyButton.svelte";
4
+
5
+ export let space_id: string | null;
6
+
7
+ $: effective_space_id = space_id || "";
8
+ $: skill_id = effective_space_id.replace("/", "-");
9
+ $: install_gradio = "pip install --upgrade gradio";
10
+ $: install_cmd_claude = `gradio skills add ${effective_space_id} --claude`;
11
+ $: install_cmd_cursor = `gradio skills add ${effective_space_id} --cursor`;
12
+ $: install_cmd_codex = `gradio skills add ${effective_space_id} --codex`;
13
+
14
+ $: skill_preview = `---
15
+ name: ${skill_id}
16
+ description: Use the ${effective_space_id} Gradio Space via API. Provides Python, JavaScript, and cURL usage examples.
17
+ ---
18
+
19
+ # ${effective_space_id}
20
+
21
+ This skill describes how to use the ${effective_space_id} Gradio Space programmatically.
22
+
23
+ ## API Endpoints
24
+ ...`;
25
+ </script>
26
+
27
+ <div class="skill-content">
28
+ <p class="padded">1. Make sure you are using the latest version of Gradio:</p>
29
+ <Block>
30
+ <code>
31
+ <div class="copy">
32
+ <CopyButton code={install_gradio} />
33
+ </div>
34
+ <div>
35
+ <pre>$ {install_gradio}</pre>
36
+ </div>
37
+ </code>
38
+ </Block>
39
+
40
+ <p class="padded">
41
+ 2. Install the usage of this Space as a Skill for your coding agent by
42
+ running this in your terminal:
43
+ </p>
44
+ <Block>
45
+ <code>
46
+ <div class="copy">
47
+ <CopyButton code={install_cmd_claude} />
48
+ </div>
49
+ <div>
50
+ <pre>$ {install_cmd_claude}</pre>
51
+ </div>
52
+ </code>
53
+ </Block>
54
+ <p class="hint">
55
+ Instead of <span class="inline-code">--claude</span>, you can use
56
+ <span class="inline-code">--cursor</span>,
57
+ <span class="inline-code">--codex</span>, or
58
+ <span class="inline-code">--opencode</span>. Combine flags to install for
59
+ multiple agents. Use <span class="inline-code">--global</span> to install user-level
60
+ instead of per-project.
61
+ </p>
62
+
63
+ <p class="padded">
64
+ 3. This will add a skill to your coding agent that describes how to use this
65
+ Space via Python, JavaScript, and cURL API. The skill will look like this:
66
+ </p>
67
+ <Block>
68
+ <code>
69
+ <div class="copy">
70
+ <CopyButton code={skill_preview} />
71
+ </div>
72
+ <div>
73
+ <pre>{skill_preview}</pre>
74
+ </div>
75
+ </code>
76
+ </Block>
77
+ </div>
78
+
79
+ <style>
80
+ .skill-content {
81
+ margin-top: var(--size-2);
82
+ }
83
+
84
+ p.padded {
85
+ padding: 15px 0px;
86
+ font-size: var(--text-lg);
87
+ }
88
+
89
+ .hint {
90
+ margin-top: var(--size-2);
91
+ color: var(--body-text-color);
92
+ opacity: 0.8;
93
+ font-size: var(--text-md);
94
+ line-height: 1.6;
95
+ }
96
+
97
+ .inline-code {
98
+ display: inline;
99
+ font-family: var(--font-mono);
100
+ font-size: var(--text-md);
101
+ background: var(--background-fill-secondary);
102
+ padding: 1px 4px;
103
+ border-radius: var(--radius-sm);
104
+ }
105
+
106
+ code pre {
107
+ overflow-x: auto;
108
+ color: var(--body-text-color);
109
+ font-family: var(--font-mono);
110
+ tab-size: 2;
111
+ }
112
+
113
+ code {
114
+ position: relative;
115
+ display: block;
116
+ }
117
+
118
+ .copy {
119
+ position: absolute;
120
+ top: 0;
121
+ right: 0;
122
+ margin-top: -5px;
123
+ margin-right: -5px;
124
+ }
125
+ </style>
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="14 22 122 106" style="background-color: #ffffff;">
2
+ <rect x="22" y="28" width="106" height="94" rx="8" fill="none" stroke="#374151" stroke-width="6"/>
3
+ <rect x="22" y="28" width="106" height="20" rx="8" fill="#374151" fill-opacity="0.08"/>
4
+ <circle cx="38" cy="38" r="4" fill="#ff5f57"/>
5
+ <circle cx="52" cy="38" r="4" fill="#febc2e"/>
6
+ <circle cx="66" cy="38" r="4" fill="#28c840"/>
7
+ <text x="38" y="76" fill="#374151" font-family="monospace" font-size="22" font-weight="bold">&gt;_</text>
8
+ <rect x="38" y="88" width="50" height="4" rx="2" fill="#374151" fill-opacity="0.35"/>
9
+ <rect x="38" y="100" width="35" height="4" rx="2" fill="#374151" fill-opacity="0.2"/>
10
+ </svg>
@@ -47,31 +47,6 @@ export function represent_value(
47
47
  return stringify_except_file_function(value);
48
48
  }
49
49
 
50
- export function is_potentially_nested_file_data(obj: any): boolean {
51
- if (typeof obj === "object" && obj !== null) {
52
- if (obj.hasOwnProperty("url") && obj.hasOwnProperty("meta")) {
53
- if (
54
- typeof obj.meta === "object" &&
55
- obj.meta !== null &&
56
- obj.meta._type === "gradio.FileData"
57
- ) {
58
- return true;
59
- }
60
- }
61
- }
62
- if (typeof obj === "object" && obj !== null) {
63
- for (let key in obj) {
64
- if (typeof obj[key] === "object") {
65
- let result = is_potentially_nested_file_data(obj[key]);
66
- if (result) {
67
- return true;
68
- }
69
- }
70
- }
71
- }
72
- return false;
73
- }
74
-
75
50
  function simplify_file_data(obj: any): any {
76
51
  if (typeof obj === "object" && obj !== null && !Array.isArray(obj)) {
77
52
  if (
package/src/dependency.ts CHANGED
@@ -205,8 +205,10 @@ export class DependencyManager {
205
205
  get_state_cb: GetStateCallback;
206
206
  rerender_cb: RerenderCallback;
207
207
  log_cb: LogCallback;
208
+ on_connection_lost_cb: () => void;
208
209
 
209
210
  loading_stati = new LoadingStatus();
211
+ connection_lost = false;
210
212
 
211
213
  constructor(
212
214
  dependencies: IDependency[],
@@ -226,13 +228,15 @@ export class DependencyManager {
226
228
  duration?: number | null,
227
229
  visible?: boolean
228
230
  ) => void,
229
- add_to_api_calls: (payload: Payload) => void
231
+ add_to_api_calls: (payload: Payload) => void,
232
+ on_connection_lost_cb: () => void
230
233
  ) {
231
234
  this.add_to_api_calls = add_to_api_calls;
232
235
  this.log_cb = log_cb;
233
236
  this.update_state_cb = update_state_cb;
234
237
  this.get_state_cb = get_state_cb;
235
238
  this.rerender_cb = rerender_cb;
239
+ this.on_connection_lost_cb = on_connection_lost_cb;
236
240
  this.client = client;
237
241
  this.reload(
238
242
  dependencies,
@@ -318,6 +322,7 @@ export class DependencyManager {
318
322
  * @returns a value if there is no backend fn, a 'submission' if there is a backend fn, or null if there is no dependency
319
323
  */
320
324
  async dispatch(event_meta: DispatchFunction | DispatchEvent): Promise<void> {
325
+ if (this.connection_lost) return;
321
326
  let deps: Dependency[] | undefined;
322
327
  if (event_meta.type === "fn") {
323
328
  const dep = this.dependencies_by_fn.get(event_meta.fn_index!);
@@ -484,6 +489,19 @@ export class DependencyManager {
484
489
  });
485
490
  this.update_loading_stati_state();
486
491
  } else if (result.stage === "error") {
492
+ if (result.broken || result.session_not_found) {
493
+ if (!this.connection_lost) {
494
+ this.connection_lost = true;
495
+ this.on_connection_lost_cb();
496
+ }
497
+ this.loading_stati.update({
498
+ status: "complete",
499
+ fn_index: dep.id,
500
+ stream_state: null
501
+ });
502
+ this.update_loading_stati_state();
503
+ break submit_loop;
504
+ }
487
505
  if (Array.isArray(result?.message)) {
488
506
  result.message.forEach((m: ValidationError, i) => {
489
507
  this.update_state_cb(
@@ -806,6 +824,26 @@ export class DependencyManager {
806
824
  });
807
825
  this.update_loading_stati_state();
808
826
  this.submissions.delete(id);
827
+ // Need to trigger any dependencies that are waiting for this one to complete
828
+ const { failure, all } = this.dependencies_by_fn
829
+ .get(id)
830
+ ?.get_triggers() || { failure: [], all: [] };
831
+ failure.forEach((dep_id) => {
832
+ this.dispatch({
833
+ type: "fn",
834
+ fn_index: dep_id,
835
+ event_data: null,
836
+ target_id: id
837
+ });
838
+ });
839
+ all.forEach((dep_id) => {
840
+ this.dispatch({
841
+ type: "fn",
842
+ fn_index: dep_id,
843
+ event_data: null,
844
+ target_id: id
845
+ });
846
+ });
809
847
  }
810
848
  }
811
849
  }