edit_bot: Migrate modal to dialog_widget.

This commit is contained in:
Ganesh Pawar
2021-07-18 12:13:09 +05:30
committed by Tim Abbott
parent 8cc781f0c8
commit edf7c0fb5a
5 changed files with 130 additions and 133 deletions

View File

@@ -176,7 +176,7 @@ async function test_edit_bot_form(page: Page): Promise<void> {
); );
await common.fill_form(page, edit_form_selector, {bot_name: "Bot one"}); await common.fill_form(page, edit_form_selector, {bot_name: "Bot one"});
const save_btn_selector = edit_form_selector + " .edit_bot_button"; const save_btn_selector = "#edit_bot_modal .dialog_submit_button";
await page.click(save_btn_selector); await page.click(save_btn_selector);
// The form gets closed on saving. So, assert it's closed by waiting for it to be hidden. // The form gets closed on saving. So, assert it's closed by waiting for it to be hidden.
@@ -186,7 +186,7 @@ async function test_edit_bot_form(page: Page): Promise<void> {
`//*[@class="btn open_edit_bot_form" and @data-email="${bot1_email}"]/ancestor::*[@class="details"]/*[@class="name" and text()="Bot one"]`, `//*[@class="btn open_edit_bot_form" and @data-email="${bot1_email}"]/ancestor::*[@class="details"]/*[@class="name" and text()="Bot one"]`,
); );
await common.wait_for_modal_to_close(page); await common.wait_for_micromodal_to_close(page);
} }
async function test_invalid_edit_bot_form(page: Page): Promise<void> { async function test_invalid_edit_bot_form(page: Page): Promise<void> {
@@ -203,7 +203,7 @@ async function test_invalid_edit_bot_form(page: Page): Promise<void> {
); );
await common.fill_form(page, edit_form_selector, {bot_name: "Bot 2"}); await common.fill_form(page, edit_form_selector, {bot_name: "Bot 2"});
const save_btn_selector = edit_form_selector + " .edit_bot_button"; const save_btn_selector = "#edit_bot_modal .dialog_submit_button";
await page.click(save_btn_selector); await page.click(save_btn_selector);
// The form should not get closed on saving. Errors should be visible on the form. // The form should not get closed on saving. Errors should be visible on the form.
@@ -213,14 +213,14 @@ async function test_invalid_edit_bot_form(page: Page): Promise<void> {
await common.get_text_from_selector(page, "div.bot_edit_errors"), await common.get_text_from_selector(page, "div.bot_edit_errors"),
"Name is already in use!", "Name is already in use!",
); );
await page.click("button.cancel_bot_button"); await page.click("#edit_bot_modal .dialog_cancel_button");
await page.waitForSelector("#edit_bot_modal", {hidden: true}); await page.waitForSelector("#edit_bot_modal", {hidden: true});
await page.waitForXPath( await page.waitForXPath(
`//*[@class="btn open_edit_bot_form" and @data-email="${bot1_email}"]/ancestor::*[@class="details"]/*[@class="name" and text()="Bot one"]`, `//*[@class="btn open_edit_bot_form" and @data-email="${bot1_email}"]/ancestor::*[@class="details"]/*[@class="name" and text()="Bot one"]`,
); );
await common.wait_for_modal_to_close(page); await common.wait_for_micromodal_to_close(page);
} }
async function test_your_bots_section(page: Page): Promise<void> { async function test_your_bots_section(page: Page): Promise<void> {

View File

@@ -10,10 +10,10 @@ import * as avatar from "./avatar";
import * as bot_data from "./bot_data"; import * as bot_data from "./bot_data";
import * as channel from "./channel"; import * as channel from "./channel";
import {csrf_token} from "./csrf"; import {csrf_token} from "./csrf";
import * as dialog_widget from "./dialog_widget";
import {DropdownListWidget} from "./dropdown_list_widget"; import {DropdownListWidget} from "./dropdown_list_widget";
import {$t} from "./i18n"; import {$t, $t_html} from "./i18n";
import * as loading from "./loading"; import * as loading from "./loading";
import * as overlays from "./overlays";
import {page_params} from "./page_params"; import {page_params} from "./page_params";
import * as people from "./people"; import * as people from "./people";
@@ -412,7 +412,6 @@ export function set_up() {
$("#active_bots_list").on("click", "button.open_edit_bot_form", (e) => { $("#active_bots_list").on("click", "button.open_edit_bot_form", (e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
overlays.open_modal("#edit_bot_modal");
const li = $(e.currentTarget).closest("li"); const li = $(e.currentTarget).closest("li");
const bot_id = Number.parseInt(li.find(".bot_info").attr("data-user-id"), 10); const bot_id = Number.parseInt(li.find(".bot_info").attr("data-user-id"), 10);
const bot = bot_data.get(bot_id); const bot = bot_data.get(bot_id);
@@ -422,112 +421,121 @@ export function set_up() {
value: user_id.toString(), value: user_id.toString(),
})); }));
$("#edit_bot_modal").empty(); const rendered_edit_bot = render_edit_bot({
$("#edit_bot_modal").append( bot,
render_edit_bot({ users_list,
bot,
users_list,
}),
);
const avatar_widget = avatar.build_bot_edit_widget($("#settings_page"));
const form = $("#settings_page .edit_bot_form");
const image = li.find(".image");
const errors = form.find(".bot_edit_errors");
const opts = {
widget_name: "bot_owner",
data: users_list,
default_text: $t({defaultMessage: "No owner"}),
value: bot.owner_id,
};
const owner_widget = new DropdownListWidget(opts);
const service = bot_data.get_services(bot_id)[0];
if (bot.bot_type.toString() === OUTGOING_WEBHOOK_BOT_TYPE) {
$("#service_data").append(
render_settings_edit_outgoing_webhook_service({
service,
}),
);
$("#edit_service_interface").val(service.interface);
}
if (bot.bot_type.toString() === EMBEDDED_BOT_TYPE) {
$("#service_data").append(
render_settings_edit_embedded_bot_service({
service,
}),
);
}
avatar_widget.clear();
form.validate({
errorClass: "text-error",
success() {
errors.hide();
},
submitHandler() {
const bot_id = Number.parseInt(form.attr("data-user-id"), 10);
const type = form.attr("data-type");
const full_name = form.find(".edit_bot_name").val();
const bot_owner_id = owner_widget.value();
const file_input = $(".edit_bot_form").find(".edit_bot_avatar_file_input");
const spinner = form.find(".edit_bot_spinner");
const edit_button = form.find(".edit_bot_button");
const formData = new FormData();
formData.append("csrfmiddlewaretoken", csrf_token);
formData.append("full_name", full_name);
formData.append("bot_owner_id", bot_owner_id);
if (type === OUTGOING_WEBHOOK_BOT_TYPE) {
const service_payload_url = $("#edit_service_base_url").val();
const service_interface = $("#edit_service_interface :selected").val();
formData.append("service_payload_url", JSON.stringify(service_payload_url));
formData.append("service_interface", service_interface);
} else if (type === EMBEDDED_BOT_TYPE) {
const config_data = {};
$("#config_edit_inputbox input").each(function () {
config_data[$(this).attr("name")] = $(this).val();
});
formData.append("config_data", JSON.stringify(config_data));
}
for (const [i, file] of Array.prototype.entries.call(file_input[0].files)) {
formData.append("file-" + i, file);
}
loading.make_indicator(spinner, {text: "Editing bot"});
edit_button.hide();
channel.patch({
url: "/json/bots/" + encodeURIComponent(bot_id),
data: formData,
cache: false,
processData: false,
contentType: false,
success(data) {
loading.destroy_indicator(spinner);
errors.hide();
edit_button.show();
avatar_widget.clear();
if (data.avatar_url) {
// Note that the avatar_url won't actually change on the backend
// when the user had a previous uploaded avatar. Only the content
// changes, so we version it to get an uncached copy.
image_version += 1;
image
.find("img")
.attr("src", data.avatar_url + "&v=" + image_version.toString());
}
overlays.close_modal("#edit_bot_modal");
},
error(xhr) {
loading.destroy_indicator(spinner);
edit_button.show();
errors.text(JSON.parse(xhr.responseText).msg).show();
},
});
},
}); });
dialog_widget.launch({
html_heading: $t_html({defaultMessage: "Edit bot"}),
html_body: rendered_edit_bot,
id: "edit_bot_modal",
on_click: () => {
$(".edit_bot_form").trigger("submit");
},
post_render: edit_bot_post_render,
loading_spinner: true,
});
function edit_bot_post_render() {
// This links the submit button to the edit bot form, so submitting this form
// by pressing Enter on an input element triggers a click on the submit button.
$("#edit_bot_modal .dialog_submit_button").attr("form", "edit_bot_form");
const avatar_widget = avatar.build_bot_edit_widget($(".edit_bot_form"));
const form = $(".edit_bot_form");
const image = li.find(".image");
const errors = form.find(".bot_edit_errors");
const opts = {
widget_name: "bot_owner",
data: users_list,
default_text: $t({defaultMessage: "No owner"}),
value: bot.owner_id,
};
const owner_widget = new DropdownListWidget(opts);
const service = bot_data.get_services(bot_id)[0];
if (bot.bot_type.toString() === OUTGOING_WEBHOOK_BOT_TYPE) {
$("#service_data").append(
render_settings_edit_outgoing_webhook_service({
service,
}),
);
$("#edit_service_interface").val(service.interface);
}
if (bot.bot_type.toString() === EMBEDDED_BOT_TYPE) {
$("#service_data").append(
render_settings_edit_embedded_bot_service({
service,
}),
);
}
avatar_widget.clear();
form.validate({
errorClass: "text-error",
success() {
errors.hide();
},
submitHandler() {
const bot_id = Number.parseInt(form.attr("data-user-id"), 10);
const type = form.attr("data-type");
const full_name = form.find(".edit_bot_name").val();
const bot_owner_id = owner_widget.value();
const file_input = $(".edit_bot_form").find(".edit_bot_avatar_file_input");
const formData = new FormData();
formData.append("csrfmiddlewaretoken", csrf_token);
formData.append("full_name", full_name);
formData.append("bot_owner_id", bot_owner_id);
if (type === OUTGOING_WEBHOOK_BOT_TYPE) {
const service_payload_url = $("#edit_service_base_url").val();
const service_interface = $("#edit_service_interface :selected").val();
formData.append("service_payload_url", JSON.stringify(service_payload_url));
formData.append("service_interface", service_interface);
} else if (type === EMBEDDED_BOT_TYPE) {
const config_data = {};
$("#config_edit_inputbox input").each(function () {
config_data[$(this).attr("name")] = $(this).val();
});
formData.append("config_data", JSON.stringify(config_data));
}
for (const [i, file] of Array.prototype.entries.call(file_input[0].files)) {
formData.append("file-" + i, file);
}
channel.patch({
url: "/json/bots/" + encodeURIComponent(bot_id),
data: formData,
cache: false,
processData: false,
contentType: false,
success(data) {
avatar_widget.clear();
if (data.avatar_url) {
// Note that the avatar_url won't actually change on the backend
// when the user had a previous uploaded avatar. Only the content
// changes, so we version it to get an uncached copy.
image_version += 1;
image
.find("img")
.attr(
"src",
data.avatar_url + "&v=" + image_version.toString(),
);
}
dialog_widget.close_modal();
},
error(xhr) {
dialog_widget.hide_dialog_spinner();
errors.text(JSON.parse(xhr.responseText).msg).show();
},
});
},
});
}
}); });
$("#active_bots_list").on("click", "a.download_bot_zuliprc", function () { $("#active_bots_list").on("click", "a.download_bot_zuliprc", function () {

View File

@@ -871,7 +871,7 @@ input[type="checkbox"] {
} }
.bot_edit_errors { .bot_edit_errors {
margin: 20px 20px 0; margin: 0;
} }
#bots_lists_navbar .active a { #bots_lists_navbar .active a {
@@ -882,8 +882,11 @@ input[type="checkbox"] {
margin-top: 5px; margin-top: 5px;
} }
.edit_bot_form_container { #edit_bot_modal {
padding: 15px; /* Ensure that the dropdown can overflow the modal. */
.modal__content {
overflow: visible;
}
} }
.edit_bot_form { .edit_bot_form {

View File

@@ -1,12 +1,8 @@
<div class="modal-header"> <form id="edit_bot_form" class="new-style edit_bot_form form-horizontal" data-target="edit-bot" data-title="{{t 'Edit bot' }}" data-user-id="{{bot.user_id}}"
<button type="button" class="close" data-dismiss="modal" aria-label="{{t 'Close' }}"><span aria-hidden="true">&times;</span></button>
<h3 class="inline-block">{{t "Edit bot" }}</h3>
</div>
<form class="edit_bot_form form-horizontal" data-target="edit-bot" data-title="{{t 'Edit bot' }}" data-user-id="{{bot.user_id}}"
data-email="{{bot.email}}" data-type="{{bot.bot_type}}"> data-email="{{bot.email}}" data-type="{{bot.bot_type}}">
<div class="bot_edit_errors alert alert-error hide"></div> <div class="bot_edit_errors alert alert-error hide"></div>
<div class="edit_bot_form_container"> <div>
<div class=""> <div>
<label>{{t "Bot email" }}</label> <label>{{t "Bot email" }}</label>
<div class="edit_bot_email">{{bot.email}}</div> <div class="edit_bot_email">{{bot.email}}</div>
</div> </div>
@@ -35,11 +31,4 @@
</div> </div>
</div> </div>
</div> </div>
<div>
<div class="modal-footer">
<div class="edit_bot_spinner"></div>
<button class="button white rounded cancel_bot_button" type="button" data-dismiss="modal">{{t "Cancel" }}</button>
<input type="submit" class="button rounded sea-green edit_bot_button" value="{{t 'Save' }}" />
</div>
</div>
</form> </form>

View File

@@ -197,8 +197,5 @@
<div class="settings-box"> <div class="settings-box">
</div> </div>
</div> </div>
<div id="edit_bot_modal" class="modal modal-bg hide fade" tabindex="-1" role="dialog"
aria-labelledby="edit_bot_modal_label" aria-hidden="true">
</div>
</div> </div>
</div> </div>