mirror of https://github.com/zulip/zulip.git
devtools: Completely overhaul the frontend for the integrations devtool.
This commit also adds a small functionality change where the results of each webhook fixture message sent is now displayed to the user. With a small tweak by tabbott to fix a styling bug. Fixes #12122.
This commit is contained in:
parent
ef98211f68
commit
1a12e112d9
Binary file not shown.
Before Width: | Height: | Size: 30 KiB |
|
@ -18,6 +18,7 @@ var clear_handlers = {
|
|||
fixture_name: function () { $('#fixture_name').empty(); },
|
||||
fixture_body: function () { $("#fixture_body")[0].value = ""; },
|
||||
custom_http_headers: function () { $("#custom_http_headers")[0].value = ""; },
|
||||
results: function () { $("#idp-results")[0].value = ""; },
|
||||
};
|
||||
|
||||
function clear_elements(elements) {
|
||||
|
@ -82,6 +83,27 @@ function get_custom_http_headers() {
|
|||
return custom_headers;
|
||||
}
|
||||
|
||||
function set_results(response) {
|
||||
/* After sending a webhook fixture message, the backend will let
|
||||
us know the responses information for each of the requests sent
|
||||
(which is just 1 for send, but usually is several for send all).
|
||||
|
||||
The following is a bit messy, but it's a devtool, so ultimately OK */
|
||||
var responses = response.responses;
|
||||
|
||||
var data = "Results:\n\n";
|
||||
responses.forEach(function (response) {
|
||||
if (response.fixture_name !== undefined) {
|
||||
data += "Fixture: " + response.fixture_name;
|
||||
data += "\nStatus Code: " + response.status_code;
|
||||
} else {
|
||||
data += "Status Code: " + response.status_code;
|
||||
}
|
||||
data += "\nResponse: " + response.message + "\n\n";
|
||||
});
|
||||
$("#idp-results")[0].value = data;
|
||||
}
|
||||
|
||||
function load_fixture_body(fixture_name) {
|
||||
/* Given a fixture name, use the loaded_fixtures dictionary to set the fixture body field. */
|
||||
var integration_name = get_selected_integration_name();
|
||||
|
@ -223,10 +245,11 @@ function send_webhook_fixture_message() {
|
|||
url: "/devtools/integrations/check_send_webhook_fixture_message",
|
||||
data: {url: url, body: body, custom_headers: custom_headers, is_json: is_json},
|
||||
beforeSend: function (xhr) {xhr.setRequestHeader('X-CSRFToken', csrftoken);},
|
||||
success: function () {
|
||||
success: function (response) {
|
||||
// If the previous fixture body was sent successfully, then we should change the success
|
||||
// message up a bit to let the user easily know that this fixture body was also sent
|
||||
// successfully.
|
||||
set_results(response);
|
||||
if ($("#message")[0].innerHTML === "Success!") {
|
||||
set_message("Success!!!", "success");
|
||||
} else {
|
||||
|
@ -256,16 +279,7 @@ function send_all_fixture_messages() {
|
|||
url: "/devtools/integrations/send_all_webhook_fixture_messages",
|
||||
data: {url: url, custom_headers: custom_headers, integration_name: integration},
|
||||
beforeSend: function (xhr) {xhr.setRequestHeader('X-CSRFToken', csrftoken);},
|
||||
success: function (response) {
|
||||
// This is a somewhat sloppy construction, but ultimately, it's a devtool.
|
||||
var responses = response.responses;
|
||||
var data = "Results:\n\n";
|
||||
responses.forEach(function (response) {
|
||||
data += "Fixture: " + response.fixture_name + "\nStatus Code: ";
|
||||
data += response.status_code + "\nResponse: " + response.message + "\n\n";
|
||||
});
|
||||
$("#fixture_body")[0].value = data;
|
||||
},
|
||||
success: function (response) {set_results(response);},
|
||||
error: handle_unsuccessful_response,
|
||||
});
|
||||
|
||||
|
@ -275,7 +289,8 @@ function send_all_fixture_messages() {
|
|||
// Initialization
|
||||
$(function () {
|
||||
clear_elements(["stream_name", "topic_name", "URL", "bot_name", "integration_name",
|
||||
"fixture_name", "custom_http_headers", "fixture_body", "message"]);
|
||||
"fixture_name", "custom_http_headers", "fixture_body", "message",
|
||||
"results"]);
|
||||
|
||||
$("#stream_name")[0].value = "Denmark";
|
||||
$("#topic_name")[0].value = "Integrations Testing";
|
||||
|
@ -306,6 +321,7 @@ $(function () {
|
|||
});
|
||||
|
||||
$('#send_all_fixtures_button').click(function () {
|
||||
clear_elements(["message"]);
|
||||
send_all_fixture_messages();
|
||||
return;
|
||||
});
|
||||
|
@ -319,11 +335,3 @@ $(function () {
|
|||
});
|
||||
|
||||
}());
|
||||
|
||||
/*
|
||||
Development Notes:
|
||||
- We currently don't support non-json fixtures.
|
||||
|
||||
Possible Improvements:
|
||||
- Add support for extra keys, headers, etc.
|
||||
*/
|
||||
|
|
|
@ -1,34 +1,114 @@
|
|||
#panel_div {
|
||||
margin: auto;
|
||||
width: 720px;
|
||||
margin-top: 50px;
|
||||
border: 3px solid;
|
||||
border-color: rgb(0, 128, 0);
|
||||
padding: 10px;
|
||||
circle {
|
||||
fill: rgb(0, 0, 0);
|
||||
stroke-width: 1.93936479;
|
||||
stroke: transparent;
|
||||
}
|
||||
|
||||
path {
|
||||
fill: rgb(82, 194, 175);
|
||||
stroke: rgb(82, 194, 175);
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: rgb(220, 244, 233);
|
||||
color: rgb(46, 139, 87);
|
||||
}
|
||||
|
||||
#custom_http_headers {
|
||||
height: 200px;
|
||||
width: 700px;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
#dev-panel {
|
||||
margin-left: 3%;
|
||||
margin-right: 3%;
|
||||
padding-bottom: 15px;
|
||||
padding-top: 20px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
background-color: rgb(247, 255, 254);
|
||||
box-shadow: 8px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||
}
|
||||
|
||||
#fixture_body {
|
||||
width: 90%;
|
||||
height: 500px;
|
||||
width: 700px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
#send_fixture_button {
|
||||
float: right;
|
||||
#idp-results {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
resize: vertical;
|
||||
background-color: rgb(256, 256, 256);
|
||||
}
|
||||
|
||||
#top-navbar {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 5fr 1fr;
|
||||
}
|
||||
|
||||
#URL {
|
||||
width: 90%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.center-text {
|
||||
.buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 92%;
|
||||
margin-right: 2%;
|
||||
}
|
||||
|
||||
.centerpiece {
|
||||
font-size: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pad-top {
|
||||
padding-top: 30px;
|
||||
.inline {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
margin-right: 10%;
|
||||
}
|
||||
|
||||
.optional {
|
||||
color: rgb(128, 128, 128);
|
||||
}
|
||||
|
||||
.pad-small {
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.row1 {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin-left: 2%;
|
||||
margin-right: 2%;
|
||||
}
|
||||
|
||||
.row2 {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
margin-left: 2%;
|
||||
margin-right: 2%;
|
||||
}
|
||||
|
||||
.row3 {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
margin-left: 2%;
|
||||
margin-right: 2%;
|
||||
}
|
||||
|
||||
.row4 {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
margin-left: 2%;
|
||||
margin-right: 2%;
|
||||
}
|
||||
|
|
|
@ -233,8 +233,6 @@ approach shown above.
|
|||
### Integrations Dev Panel
|
||||
This is the GUI tool.
|
||||
|
||||
<img class="screenshot" src="/static/images/integrations/integrations_dev_panel.png" />
|
||||
|
||||
1. Run `./tools/run-dev.py` then go to http://localhost:9991/devtools/integrations/.
|
||||
|
||||
2. Set the following mandatory fields:
|
||||
|
|
|
@ -1,105 +1,115 @@
|
|||
{% extends "zerver/base.html" %}
|
||||
{% extends "zerver/portico.html" %}
|
||||
|
||||
{% block customhead %}
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{{ render_bundle('integrations-dev-panel') }}
|
||||
{{ render_bundle('portico') }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="header portico-header">
|
||||
<div class="header-main" id="top-navbar">
|
||||
<div>
|
||||
<a class="brand logo">
|
||||
<svg class="brand-logo" xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 40 40" version="1.1">
|
||||
<g transform="translate(-297.14285,-466.64792)">
|
||||
<circle cx="317.14285" cy="486.64792" r="19.030317"></circle>
|
||||
<path d="m309.24286 477.14791 14.2 0 1.6 3.9-11.2 11.9 9.6 0 1.6 3.2-14.2 0-1.6-3.9 11.2-11.9-9.6 0z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
<span>Zulip</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<input id="csrftoken" type="hidden" value="{{ csrf_token }}">
|
||||
<div class="centerpiece">Integrations Developer Panel</div>
|
||||
|
||||
<div id="panel_div">
|
||||
<div class="top-links">
|
||||
<a href="/">Go to Zulip</a>
|
||||
</div>
|
||||
|
||||
<h1 class="center-text"> Integrations Developer Panel </h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<div class="pad-small"></div>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<label><b>Stream</b></label>
|
||||
<input id="stream_name" type="text" />
|
||||
</td>
|
||||
<td>
|
||||
<label><b>Topic</b></label>
|
||||
<input id="topic_name" type="text" />
|
||||
</td>
|
||||
</tr>
|
||||
<div id="dev-panel">
|
||||
<div class="row1">
|
||||
<div>
|
||||
<label for="bot_name"><b>Bot</b></label>
|
||||
<select id="bot_name">
|
||||
<option value=""></option>
|
||||
{% for bot in bots %}
|
||||
<option value="{{ bot.api_key }}"> {{ bot.full_name }} </option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<tr>
|
||||
<td class="pad-top"><b>Bot</b></td>
|
||||
<td class="pad-top">
|
||||
<select id="bot_name">
|
||||
<option value=""></option>
|
||||
{% for bot in bots %}
|
||||
<option value="{{ bot.api_key }}"> {{ bot.full_name }} </option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<div>
|
||||
<label><b>Integration</b></label>
|
||||
<select id="integration_name">
|
||||
<option value=""></option>
|
||||
{% for integration in integrations %}
|
||||
<option value="{{ integration }}"> {{ integration }} </option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<tr>
|
||||
<td><b>Integration</b></td>
|
||||
<td>
|
||||
<select id="integration_name">
|
||||
<option value=""></option>
|
||||
{% for integration in integrations %}
|
||||
<option value="{{ integration }}"> {{ integration }} </option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<div>
|
||||
<label for="fixture_name"><b>Fixture</b></label>
|
||||
<select id="fixture_name"></select>
|
||||
</div>
|
||||
|
||||
<tr>
|
||||
<td><b>Fixture</b></td>
|
||||
<td><select id="fixture_name"></select></td>
|
||||
</tr>
|
||||
<div>
|
||||
<label class="optional"><b>Stream</b></label>
|
||||
<input id="stream_name" type="text" />
|
||||
</div>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" class="pad-top">
|
||||
<label for="URL"><b>URL</b></label>
|
||||
<input id="URL" type="text" />
|
||||
</td>
|
||||
</tr>
|
||||
<div>
|
||||
<label class="optional"><b>Topic</b></label>
|
||||
<input id="topic_name" type="text" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" class="center-text pad-top"><b>Custom HTTP Headers</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="form-group">
|
||||
<textarea id="custom_http_headers" class="form-control"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<br>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" class="center-text pad-top"><b>Fixture Body</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="form-group">
|
||||
<textarea id="fixture_body" class="form-control"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<div class="row2">
|
||||
<label for="URL"><b>URL</b> (Automatically Generated)</label>
|
||||
<input id="URL" type="text" />
|
||||
</div>
|
||||
|
||||
<tr>
|
||||
<td colspan="2"> <p id="message"></p> </td>
|
||||
</tr>
|
||||
<br>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<button id="send_all_fixtures_button" class="btn-success">Send All</button>
|
||||
</td>
|
||||
<td>
|
||||
<button id="send_fixture_button" class="btn-success">Send!</button>
|
||||
</td>
|
||||
</tr>
|
||||
<div class="row3">
|
||||
<label for="custom_http_headers"><b>Custom HTTP Headers</b></label>
|
||||
<textarea id="custom_http_headers"></textarea>
|
||||
</div>
|
||||
|
||||
</table>
|
||||
<br>
|
||||
|
||||
<div class="row4">
|
||||
<div class="col1">
|
||||
<div class="inline">
|
||||
<label for="fixture_body"><b>Fixture Body</b></label>
|
||||
<span id="message"></span>
|
||||
</div>
|
||||
<textarea id="fixture_body"></textarea>
|
||||
<div class="buttons">
|
||||
<button id="send_all_fixtures_button">Send All</button>
|
||||
<button id="send_fixture_button">Send!</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col1">
|
||||
<label for="idp-results"><b>Results</b></label>
|
||||
<textarea id="idp-results" readonly></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<br> <br> <br>
|
||||
<div class="pad-small"></div>
|
||||
<input id="csrftoken" type="hidden" value="{{ csrf_token }}">
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -41,7 +41,11 @@ class TestIntegrationsDevPanel(ZulipTestCase):
|
|||
}
|
||||
|
||||
response = self.client_post(target_url, data)
|
||||
expected_response = {'responses': [{'status_code': 200, 'message': {"result": "success", "msg": ""}}], 'result': 'success', 'msg': ''}
|
||||
response_content = ujson.loads(response.content)
|
||||
response_content["responses"][0]["message"] = ujson.loads(response_content["responses"][0]["message"])
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response_content, expected_response)
|
||||
|
||||
latest_msg = Message.objects.latest('id')
|
||||
expected_message = "[ZeroDivisionError](https://zulip.airbrake.io/projects/125209/groups/1705190192091077626): \"Error message from logger\" occurred."
|
||||
|
|
|
@ -81,7 +81,9 @@ def check_send_webhook_fixture_message(request: HttpRequest,
|
|||
custom_headers: str=REQ()) -> HttpResponse:
|
||||
response = send_webhook_fixture_message(url, body, is_json, custom_headers)
|
||||
if response.status_code == 200:
|
||||
return json_success()
|
||||
responses = [{"status_code": response.status_code,
|
||||
"message": response.content}]
|
||||
return json_success({"responses": responses})
|
||||
else:
|
||||
return response
|
||||
|
||||
|
|
Loading…
Reference in New Issue