mirror of
				https://github.com/zulip/zulip.git
				synced 2025-10-31 20:13:46 +00:00 
			
		
		
		
	integrations_dev_panel: Convert module to TypeScript.
This commit is contained in:
		| @@ -1,4 +1,6 @@ | |||||||
| import $ from "jquery"; | import $ from "jquery"; | ||||||
|  | import assert from "minimalistic-assert"; | ||||||
|  | import {z} from "zod"; | ||||||
| 
 | 
 | ||||||
| import * as channel from "../channel"; | import * as channel from "../channel"; | ||||||
| // Main JavaScript file for the integrations development panel at
 | // Main JavaScript file for the integrations development panel at
 | ||||||
| @@ -7,36 +9,81 @@ import * as channel from "../channel"; | |||||||
| // Data segment: We lazy load the requested fixtures from the backend
 | // Data segment: We lazy load the requested fixtures from the backend
 | ||||||
| // as and when required and then cache them here.
 | // as and when required and then cache them here.
 | ||||||
| 
 | 
 | ||||||
| const loaded_fixtures = new Map(); | const fixture_schema = z.record( | ||||||
|  |     z.string(), | ||||||
|  |     z.object({ | ||||||
|  |         body: z.unknown(), | ||||||
|  |         headers: z.record(z.string()), | ||||||
|  |     }), | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | type Fixtures = z.infer<typeof fixture_schema>; | ||||||
|  | 
 | ||||||
|  | type HTMLSelectOneElement = HTMLSelectElement & {type: "select-one"}; | ||||||
|  | 
 | ||||||
|  | type ClearHandlers = { | ||||||
|  |     stream_name: string; | ||||||
|  |     topic_name: string; | ||||||
|  |     URL: string; | ||||||
|  |     results_notice: string; | ||||||
|  |     bot_name: () => void; | ||||||
|  |     integration_name: () => void; | ||||||
|  |     fixture_name: () => void; | ||||||
|  |     fixture_body: () => void; | ||||||
|  |     custom_http_headers: () => void; | ||||||
|  |     results: () => void; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const integrations_api_response_schema = z.object({ | ||||||
|  |     msg: z.string(), | ||||||
|  |     responses: z.array( | ||||||
|  |         z.object({ | ||||||
|  |             status_code: z.number(), | ||||||
|  |             message: z.string(), | ||||||
|  |             fixture_name: z.optional(z.string()), | ||||||
|  |         }), | ||||||
|  |     ), | ||||||
|  |     result: z.string(), | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | type ServerResponse = z.infer<typeof integrations_api_response_schema>; | ||||||
|  | 
 | ||||||
|  | const loaded_fixtures = new Map<string, Fixtures>(); | ||||||
| const url_base = "/api/v1/external/"; | const url_base = "/api/v1/external/"; | ||||||
| 
 | 
 | ||||||
| // A map defining how to clear the various UI elements.
 | // A map defining how to clear the various UI elements.
 | ||||||
| const clear_handlers = { | const clear_handlers: ClearHandlers = { | ||||||
|     stream_name: "#stream_name", |     stream_name: "#stream_name", | ||||||
|     topic_name: "#topic_name", |     topic_name: "#topic_name", | ||||||
|     URL: "#URL", |     URL: "#URL", | ||||||
|     results_notice: "#results_notice", |     results_notice: "#results_notice", | ||||||
|     bot_name() { |     bot_name() { | ||||||
|         $("#bot_name").children()[0].selected = true; |         const bot_option = $<HTMLSelectOneElement>("select:not([multiple])#bot_name").children()[0]; | ||||||
|  |         assert(bot_option instanceof HTMLOptionElement); | ||||||
|  |         bot_option.selected = true; | ||||||
|     }, |     }, | ||||||
|     integration_name() { |     integration_name() { | ||||||
|         $("#integration_name").children()[0].selected = true; |         const integration_option = $<HTMLSelectOneElement>( | ||||||
|  |             "select:not([multiple])#integration_name", | ||||||
|  |         ).children()[0]; | ||||||
|  |         assert(integration_option instanceof HTMLOptionElement); | ||||||
|  |         integration_option.selected = true; | ||||||
|     }, |     }, | ||||||
|     fixture_name() { |     fixture_name() { | ||||||
|         $("#fixture_name").empty(); |         $("#fixture_name").empty(); | ||||||
|     }, |     }, | ||||||
|     fixture_body() { |     fixture_body() { | ||||||
|         $("#fixture_body")[0].value = ""; |         $<HTMLTextAreaElement>("textarea#fixture_body")[0]!.value = ""; | ||||||
|     }, |     }, | ||||||
|     custom_http_headers() { |     custom_http_headers() { | ||||||
|         $("#custom_http_headers")[0].value = "{}"; |         $<HTMLTextAreaElement>("textarea#custom_http_headers")[0]!.value = "{}"; | ||||||
|     }, |     }, | ||||||
|     results() { |     results() { | ||||||
|         $("#idp-results")[0].value = ""; |         $<HTMLTextAreaElement>("textarea#idp-results")[0]!.value = ""; | ||||||
|     }, |     }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| function clear_elements(elements) { | function clear_elements(elements: (keyof ClearHandlers)[]): void { | ||||||
|     // Supports strings (a selector to clear) or calling a function
 |     // Supports strings (a selector to clear) or calling a function
 | ||||||
|     // (for more complex logic).
 |     // (for more complex logic).
 | ||||||
|     for (const element_name of elements) { |     for (const element_name of elements) { | ||||||
| @@ -56,24 +103,24 @@ const results_notice_level_to_color_map = { | |||||||
|     success: "#085d44", |     success: "#085d44", | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| function set_results_notice(msg, level) { | function set_results_notice(msg: string, level: "warning" | "success"): void { | ||||||
|     $("#results_notice").text(msg).css("color", results_notice_level_to_color_map[level]); |     $("#results_notice").text(msg).css("color", results_notice_level_to_color_map[level]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function get_api_key_from_selected_bot() { | function get_api_key_from_selected_bot(): string { | ||||||
|     return $("#bot_name").val(); |     return $<HTMLSelectOneElement>("select:not([multiple])#bot_name").val()!; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function get_selected_integration_name() { | function get_selected_integration_name(): string { | ||||||
|     return $("#integration_name").val(); |     return $<HTMLSelectOneElement>("select:not([multiple])#integration_name").val()!; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function get_fixture_format(fixture_name) { | function get_fixture_format(fixture_name: string): string | undefined { | ||||||
|     return fixture_name.split(".").at(-1); |     return fixture_name.split(".").at(-1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function get_custom_http_headers() { | function get_custom_http_headers(): string | undefined { | ||||||
|     let custom_headers = $("#custom_http_headers").val(); |     let custom_headers = $<HTMLTextAreaElement>("textarea#custom_http_headers").val()!; | ||||||
|     if (custom_headers !== "") { |     if (custom_headers !== "") { | ||||||
|         // JSON.parse("") would trigger an error, as empty strings do not qualify as JSON.
 |         // JSON.parse("") would trigger an error, as empty strings do not qualify as JSON.
 | ||||||
|         try { |         try { | ||||||
| @@ -87,7 +134,7 @@ function get_custom_http_headers() { | |||||||
|     return custom_headers; |     return custom_headers; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function set_results(response) { | function set_results(response: ServerResponse): void { | ||||||
|     /* The backend returns the JSON responses for each of the |     /* The backend returns the JSON responses for each of the | ||||||
|     send_message actions included in our request (which is just 1 for |     send_message actions included in our request (which is just 1 for | ||||||
|     send, but usually is several for send all).  We display these |     send, but usually is several for send all).  We display these | ||||||
| @@ -106,14 +153,15 @@ function set_results(response) { | |||||||
|         } |         } | ||||||
|         data += "\nResponse:       " + response.message + "\n\n"; |         data += "\nResponse:       " + response.message + "\n\n"; | ||||||
|     } |     } | ||||||
|     $("#idp-results")[0].value = data; |     $<HTMLTextAreaElement>("textarea#idp-results")[0]!.value = data; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function load_fixture_body(fixture_name) { | function load_fixture_body(fixture_name: string): void { | ||||||
|     /* Given a fixture name, use the loaded_fixtures dictionary to set |     /* Given a fixture name, use the loaded_fixtures dictionary to set | ||||||
|      * the fixture body field. */ |      * the fixture body field. */ | ||||||
|     const integration_name = get_selected_integration_name(); |     const integration_name = get_selected_integration_name(); | ||||||
|     const fixture = loaded_fixtures.get(integration_name)[fixture_name]; |     const fixture = loaded_fixtures.get(integration_name)![fixture_name]; | ||||||
|  |     assert(fixture !== undefined); | ||||||
|     let fixture_body = fixture.body; |     let fixture_body = fixture.body; | ||||||
|     const headers = fixture.headers; |     const headers = fixture.headers; | ||||||
|     if (fixture_body === undefined) { |     if (fixture_body === undefined) { | ||||||
| @@ -124,18 +172,27 @@ function load_fixture_body(fixture_name) { | |||||||
|         // The 4 argument is pretty printer indentation.
 |         // The 4 argument is pretty printer indentation.
 | ||||||
|         fixture_body = JSON.stringify(fixture_body, null, 4); |         fixture_body = JSON.stringify(fixture_body, null, 4); | ||||||
|     } |     } | ||||||
|     $("#fixture_body")[0].value = fixture_body; |     assert(typeof fixture_body === "string"); | ||||||
|     $("#custom_http_headers")[0].value = JSON.stringify(headers, null, 4); |     $<HTMLTextAreaElement>("textarea#fixture_body")[0]!.value = fixture_body; | ||||||
|  |     $<HTMLTextAreaElement>("textarea#custom_http_headers")[0]!.value = JSON.stringify( | ||||||
|  |         headers, | ||||||
|  |         null, | ||||||
|  |         4, | ||||||
|  |     ); | ||||||
| 
 | 
 | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function load_fixture_options(integration_name) { | function load_fixture_options(integration_name: string): void { | ||||||
|     /* Using the integration name and loaded_fixtures object to set |     /* Using the integration name and loaded_fixtures object to set | ||||||
|     the fixture options for the fixture_names dropdown and also set |     the fixture options for the fixture_names dropdown and also set | ||||||
|     the fixture body to the first fixture by default. */ |     the fixture body to the first fixture by default. */ | ||||||
|     const fixtures_options_dropdown = $("#fixture_name")[0]; |     const fixtures_options_dropdown = $<HTMLSelectOneElement>( | ||||||
|     const fixtures_names = Object.keys(loaded_fixtures.get(integration_name)).sort(); |         "select:not([multiple])#fixture_name", | ||||||
|  |     )[0]!; | ||||||
|  |     const fixtures = loaded_fixtures.get(integration_name); | ||||||
|  |     assert(fixtures !== undefined); | ||||||
|  |     const fixtures_names = Object.keys(fixtures).sort(); | ||||||
| 
 | 
 | ||||||
|     for (const fixture_name of fixtures_names) { |     for (const fixture_name of fixtures_names) { | ||||||
|         const new_dropdown_option = document.createElement("option"); |         const new_dropdown_option = document.createElement("option"); | ||||||
| @@ -143,46 +200,48 @@ function load_fixture_options(integration_name) { | |||||||
|         new_dropdown_option.textContent = fixture_name; |         new_dropdown_option.textContent = fixture_name; | ||||||
|         fixtures_options_dropdown.add(new_dropdown_option); |         fixtures_options_dropdown.add(new_dropdown_option); | ||||||
|     } |     } | ||||||
|  |     assert(fixtures_names[0] !== undefined); | ||||||
|     load_fixture_body(fixtures_names[0]); |     load_fixture_body(fixtures_names[0]); | ||||||
| 
 | 
 | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function update_url() { | function update_url(): void { | ||||||
|     /* Construct the URL that the webhook should be targeting, using |     /* Construct the URL that the webhook should be targeting, using | ||||||
|     the bot's API key and the integration name.  The stream and topic |     the bot's API key and the integration name.  The stream and topic | ||||||
|     are both optional, and for the sake of completeness, it should be |     are both optional, and for the sake of completeness, it should be | ||||||
|     noted that the topic is irrelevant without specifying the |     noted that the topic is irrelevant without specifying the | ||||||
|     stream. */ |     stream. */ | ||||||
|     const url_field = $("#URL")[0]; |     const url_field = $<HTMLInputElement>("input#URL")[0]; | ||||||
| 
 | 
 | ||||||
|     const integration_name = get_selected_integration_name(); |     const integration_name = get_selected_integration_name(); | ||||||
|     const api_key = get_api_key_from_selected_bot(); |     const api_key = get_api_key_from_selected_bot(); | ||||||
| 
 |     assert(typeof api_key === "string"); | ||||||
|     if (integration_name === "" || api_key === "") { |     if (integration_name === "" || api_key === "") { | ||||||
|         clear_elements(["URL"]); |         clear_elements(["URL"]); | ||||||
|     } else { |     } else { | ||||||
|         const params = new URLSearchParams({api_key}); |         const params = new URLSearchParams({api_key}); | ||||||
|         const stream_name = $("#stream_name").val(); |         const stream_name = $<HTMLInputElement>("input#stream_name").val()!; | ||||||
|         if (stream_name !== "") { |         if (stream_name !== "") { | ||||||
|             params.set("stream", stream_name); |             params.set("stream", stream_name); | ||||||
|             const topic_name = $("#topic_name").val(); |             const topic_name = $<HTMLInputElement>("input#topic_name").val()!; | ||||||
|             if (topic_name !== "") { |             if (topic_name !== "") { | ||||||
|                 params.set("topic", topic_name); |                 params.set("topic", topic_name); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         const url = `${url_base}${integration_name}?${params}`; |         const url = `${url_base}${integration_name}?${params.toString()}`; | ||||||
|         url_field.value = url; |         url_field!.value = url; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return; |     return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // API callers: These methods handle communicating with the Python backend API.
 | // API callers: These methods handle communicating with the Python backend API.
 | ||||||
| function handle_unsuccessful_response(response) { | function handle_unsuccessful_response(response: JQuery.jqXHR): void { | ||||||
|     if (response.responseJSON?.msg) { |     const parsed = z.object({msg: z.string()}).safeParse(response.responseJSON); | ||||||
|  |     if (parsed.data) { | ||||||
|         const status_code = response.status; |         const status_code = response.status; | ||||||
|         set_results_notice(`Result: (${status_code}) ${response.responseJSON.msg}`, "warning"); |         set_results_notice(`Result: (${status_code}) ${parsed.data.msg}`, "warning"); | ||||||
|     } else { |     } else { | ||||||
|         // If the response is not a JSON response, then it is probably
 |         // If the response is not a JSON response, then it is probably
 | ||||||
|         // Django returning an HTML response containing a stack trace
 |         // Django returning an HTML response containing a stack trace
 | ||||||
| @@ -193,7 +252,7 @@ function handle_unsuccessful_response(response) { | |||||||
|     return; |     return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function get_fixtures(integration_name) { | function get_fixtures(integration_name: string): void { | ||||||
|     /* Request fixtures from the backend for any integrations that we |     /* Request fixtures from the backend for any integrations that we | ||||||
|     don't already have fixtures cached in loaded_fixtures). */ |     don't already have fixtures cached in loaded_fixtures). */ | ||||||
|     if (integration_name === "") { |     if (integration_name === "") { | ||||||
| @@ -215,9 +274,17 @@ function get_fixtures(integration_name) { | |||||||
|     // We don't have the fixtures for this integration; fetch them
 |     // We don't have the fixtures for this integration; fetch them
 | ||||||
|     // from the backend.  Relative URL pattern:
 |     // from the backend.  Relative URL pattern:
 | ||||||
|     // /devtools/integrations/<integration_name>/fixtures
 |     // /devtools/integrations/<integration_name>/fixtures
 | ||||||
|     channel.get({ |     void channel.get({ | ||||||
|         url: "/devtools/integrations/" + integration_name + "/fixtures", |         url: "/devtools/integrations/" + integration_name + "/fixtures", | ||||||
|         success(response) { |         success(raw_response) { | ||||||
|  |             const response = z | ||||||
|  |                 .object({ | ||||||
|  |                     result: z.string(), | ||||||
|  |                     msg: z.string(), | ||||||
|  |                     fixtures: fixture_schema, | ||||||
|  |                 }) | ||||||
|  |                 .parse(raw_response); | ||||||
|  | 
 | ||||||
|             loaded_fixtures.set(integration_name, response.fixtures); |             loaded_fixtures.set(integration_name, response.fixtures); | ||||||
|             load_fixture_options(integration_name); |             load_fixture_options(integration_name); | ||||||
|             return; |             return; | ||||||
| @@ -228,7 +295,7 @@ function get_fixtures(integration_name) { | |||||||
|     return; |     return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function send_webhook_fixture_message() { | function send_webhook_fixture_message(): void { | ||||||
|     /* Make sure that the user is sending valid JSON in the fixture |     /* Make sure that the user is sending valid JSON in the fixture | ||||||
|     body and that the URL is not empty. Then simply send the fixture |     body and that the URL is not empty. Then simply send the fixture | ||||||
|     body to the target URL. */ |     body to the target URL. */ | ||||||
| @@ -238,7 +305,7 @@ function send_webhook_fixture_message() { | |||||||
|     // then the csrf token that we have stored in the hidden input
 |     // then the csrf token that we have stored in the hidden input
 | ||||||
|     // element would have been expired, leading to an error message
 |     // element would have been expired, leading to an error message
 | ||||||
|     // when the user tries to send the fixture body.
 |     // when the user tries to send the fixture body.
 | ||||||
|     const csrftoken = $("#csrftoken").val(); |     const csrftoken = $<HTMLInputElement>("input#csrftoken").val()!; | ||||||
| 
 | 
 | ||||||
|     const url = $("#URL").val(); |     const url = $("#URL").val(); | ||||||
|     if (url === "") { |     if (url === "") { | ||||||
| @@ -246,8 +313,8 @@ function send_webhook_fixture_message() { | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     let body = $("#fixture_body").val(); |     let body = $<HTMLTextAreaElement>("textarea#fixture_body").val()!; | ||||||
|     const fixture_name = $("#fixture_name").val(); |     const fixture_name = $<HTMLSelectOneElement>("select:not([multiple])#fixture_name").val(); | ||||||
|     let is_json = false; |     let is_json = false; | ||||||
|     if (fixture_name && get_fixture_format(fixture_name) === "json") { |     if (fixture_name && get_fixture_format(fixture_name) === "json") { | ||||||
|         try { |         try { | ||||||
| @@ -262,17 +329,18 @@ function send_webhook_fixture_message() { | |||||||
| 
 | 
 | ||||||
|     const custom_headers = get_custom_http_headers(); |     const custom_headers = get_custom_http_headers(); | ||||||
| 
 | 
 | ||||||
|     channel.post({ |     void channel.post({ | ||||||
|         url: "/devtools/integrations/check_send_webhook_fixture_message", |         url: "/devtools/integrations/check_send_webhook_fixture_message", | ||||||
|         data: {url, body, custom_headers, is_json}, |         data: {url, body, custom_headers, is_json}, | ||||||
|         beforeSend(xhr) { |         beforeSend(xhr) { | ||||||
|             xhr.setRequestHeader("X-CSRFToken", csrftoken); |             xhr.setRequestHeader("X-CSRFToken", csrftoken); | ||||||
|         }, |         }, | ||||||
|         success(response) { |         success(raw_response) { | ||||||
|             // If the previous fixture body was sent successfully,
 |             // If the previous fixture body was sent successfully,
 | ||||||
|             // then we should change the success message up a bit to
 |             // then we should change the success message up a bit to
 | ||||||
|             // let the user easily know that this fixture body was
 |             // let the user easily know that this fixture body was
 | ||||||
|             // also sent successfully.
 |             // also sent successfully.
 | ||||||
|  |             const response = integrations_api_response_schema.parse(raw_response); | ||||||
|             set_results(response); |             set_results(response); | ||||||
|             if ($("#results_notice").text() === "Success!") { |             if ($("#results_notice").text() === "Success!") { | ||||||
|                 set_results_notice("Success!!!", "success"); |                 set_results_notice("Success!!!", "success"); | ||||||
| @@ -287,7 +355,7 @@ function send_webhook_fixture_message() { | |||||||
|     return; |     return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function send_all_fixture_messages() { | function send_all_fixture_messages(): void { | ||||||
|     /* Send all fixture messages for a given integration. */ |     /* Send all fixture messages for a given integration. */ | ||||||
|     const url = $("#URL").val(); |     const url = $("#URL").val(); | ||||||
|     const integration = get_selected_integration_name(); |     const integration = get_selected_integration_name(); | ||||||
| @@ -296,14 +364,15 @@ function send_all_fixture_messages() { | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const csrftoken = $("#csrftoken").val(); |     const csrftoken = $<HTMLInputElement>("input#csrftoken").val()!; | ||||||
|     channel.post({ |     void channel.post({ | ||||||
|         url: "/devtools/integrations/send_all_webhook_fixture_messages", |         url: "/devtools/integrations/send_all_webhook_fixture_messages", | ||||||
|         data: {url, integration_name: integration}, |         data: {url, integration_name: integration}, | ||||||
|         beforeSend(xhr) { |         beforeSend(xhr) { | ||||||
|             xhr.setRequestHeader("X-CSRFToken", csrftoken); |             xhr.setRequestHeader("X-CSRFToken", csrftoken); | ||||||
|         }, |         }, | ||||||
|         success(response) { |         success(raw_response) { | ||||||
|  |             const response = integrations_api_response_schema.parse(raw_response); | ||||||
|             set_results(response); |             set_results(response); | ||||||
|         }, |         }, | ||||||
|         error: handle_unsuccessful_response, |         error: handle_unsuccessful_response, | ||||||
| @@ -327,25 +396,26 @@ $(() => { | |||||||
|         "results", |         "results", | ||||||
|     ]); |     ]); | ||||||
| 
 | 
 | ||||||
|     $("#stream_name")[0].value = "Denmark"; |     $<HTMLInputElement>("input#stream_name")[0]!.value = "Denmark"; | ||||||
|     $("#topic_name")[0].value = "Integrations testing"; |     $<HTMLInputElement>("input#topic_name")[0]!.value = "Integrations testing"; | ||||||
| 
 | 
 | ||||||
|     const potential_default_bot = $("#bot_name")[0][1]; |     const potential_default_bot = $<HTMLSelectOneElement>("select:not([multiple])#bot_name")[0]![1]; | ||||||
|  |     assert(potential_default_bot instanceof HTMLOptionElement); | ||||||
|     if (potential_default_bot !== undefined) { |     if (potential_default_bot !== undefined) { | ||||||
|         potential_default_bot.selected = true; |         potential_default_bot.selected = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     $("#integration_name").on("change", function () { |     $<HTMLSelectOneElement>("select:not([multiple])#integration_name").on("change", function () { | ||||||
|         clear_elements(["custom_http_headers", "fixture_body", "fixture_name", "results_notice"]); |         clear_elements(["custom_http_headers", "fixture_body", "fixture_name", "results_notice"]); | ||||||
|         const integration_name = $(this.selectedOptions).val(); |         const integration_name = $(this.selectedOptions).val()!; | ||||||
|         get_fixtures(integration_name); |         get_fixtures(integration_name); | ||||||
|         update_url(); |         update_url(); | ||||||
|         return; |         return; | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     $("#fixture_name").on("change", function () { |     $<HTMLSelectOneElement>("select:not([multiple])#fixture_name").on("change", function () { | ||||||
|         clear_elements(["fixture_body", "results_notice"]); |         clear_elements(["fixture_body", "results_notice"]); | ||||||
|         const fixture_name = $(this.selectedOptions).val(); |         const fixture_name = $(this.selectedOptions).val()!; | ||||||
|         load_fixture_body(fixture_name); |         load_fixture_body(fixture_name); | ||||||
|         return; |         return; | ||||||
|     }); |     }); | ||||||
		Reference in New Issue
	
	Block a user