DEV: Cancel popup should abort request (#497)
This commit is contained in:
parent
484fd1435b
commit
6a30b06a55
|
@ -11,12 +11,9 @@ import DTextarea from "discourse/components/d-textarea";
|
|||
import autoFocus from "discourse/modifiers/auto-focus";
|
||||
import icon from "discourse-common/helpers/d-icon";
|
||||
import i18n from "discourse-common/helpers/i18n";
|
||||
import { IMAGE_MARKDOWN_REGEX } from "../../lib/utilities";
|
||||
|
||||
export default class AiImageCaptionContainer extends Component {
|
||||
@service imageCaptionPopup;
|
||||
@service appEvents;
|
||||
@service composer;
|
||||
|
||||
@action
|
||||
updateCaption(event) {
|
||||
|
@ -26,22 +23,7 @@ export default class AiImageCaptionContainer extends Component {
|
|||
|
||||
@action
|
||||
saveCaption() {
|
||||
const index = this.imageCaptionPopup.imageIndex;
|
||||
const matchingPlaceholder =
|
||||
this.composer.model.reply.match(IMAGE_MARKDOWN_REGEX);
|
||||
|
||||
if (matchingPlaceholder) {
|
||||
const match = matchingPlaceholder[index];
|
||||
const replacement = match.replace(
|
||||
IMAGE_MARKDOWN_REGEX,
|
||||
`![${this.imageCaptionPopup.newCaption}|$2$3$4]($5)`
|
||||
);
|
||||
|
||||
if (match) {
|
||||
this.appEvents.trigger("composer:replace-text", match, replacement);
|
||||
}
|
||||
}
|
||||
|
||||
this.imageCaptionPopup.updateCaption();
|
||||
this.hidePopup();
|
||||
}
|
||||
|
||||
|
@ -63,6 +45,11 @@ export default class AiImageCaptionContainer extends Component {
|
|||
@action
|
||||
hidePopup() {
|
||||
this.imageCaptionPopup.showPopup = false;
|
||||
if (this.imageCaptionPopup._request) {
|
||||
this.imageCaptionPopup._request.abort();
|
||||
this.imageCaptionPopup._request = null;
|
||||
this.imageCaptionPopup.toggleLoadingState(false);
|
||||
}
|
||||
}
|
||||
|
||||
<template>
|
||||
|
@ -91,7 +78,7 @@ export default class AiImageCaptionContainer extends Component {
|
|||
@action={{this.saveCaption}}
|
||||
/>
|
||||
<DButton
|
||||
class="btn-flat"
|
||||
class="btn-flat cancel-request"
|
||||
@label="cancel"
|
||||
@action={{this.hidePopup}}
|
||||
/>
|
||||
|
|
|
@ -1,10 +1,43 @@
|
|||
import { tracked } from "@glimmer/tracking";
|
||||
import Service from "@ember/service";
|
||||
import Service, { inject as service } from "@ember/service";
|
||||
import { IMAGE_MARKDOWN_REGEX } from "../lib/utilities";
|
||||
|
||||
export default class ImageCaptionPopup extends Service {
|
||||
@service composer;
|
||||
@service appEvents;
|
||||
|
||||
@tracked showPopup = false;
|
||||
@tracked imageIndex = null;
|
||||
@tracked imageSrc = null;
|
||||
@tracked newCaption = null;
|
||||
@tracked loading = false;
|
||||
@tracked popupTrigger = null;
|
||||
@tracked _request = null;
|
||||
|
||||
updateCaption() {
|
||||
const matchingPlaceholder =
|
||||
this.composer.model.reply.match(IMAGE_MARKDOWN_REGEX);
|
||||
|
||||
if (matchingPlaceholder) {
|
||||
const match = matchingPlaceholder[this.imageIndex];
|
||||
const replacement = match.replace(
|
||||
IMAGE_MARKDOWN_REGEX,
|
||||
`![${this.newCaption}|$2$3$4]($5)`
|
||||
);
|
||||
|
||||
if (match) {
|
||||
this.appEvents.trigger("composer:replace-text", match, replacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toggleLoadingState(loading) {
|
||||
if (loading) {
|
||||
this.popupTrigger?.classList.add("disabled");
|
||||
return (this.loading = true);
|
||||
}
|
||||
|
||||
this.popupTrigger?.classList.remove("disabled");
|
||||
return (this.loading = false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ import { ajax } from "discourse/lib/ajax";
|
|||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { apiInitializer } from "discourse/lib/api";
|
||||
import I18n from "discourse-i18n";
|
||||
import { IMAGE_MARKDOWN_REGEX } from "../discourse/lib/utilities";
|
||||
|
||||
export default apiInitializer("1.25.0", (api) => {
|
||||
const buttonAttrs = {
|
||||
|
@ -10,10 +9,7 @@ export default apiInitializer("1.25.0", (api) => {
|
|||
icon: "discourse-sparkles",
|
||||
class: "generate-caption",
|
||||
};
|
||||
const imageCaptionPopup = api.container.lookup("service:imageCaptionPopup");
|
||||
const settings = api.container.lookup("service:site-settings");
|
||||
const appEvents = api.container.lookup("service:app-events");
|
||||
const site = api.container.lookup("site:main");
|
||||
|
||||
if (!settings.ai_helper_enabled_features.includes("image_caption")) {
|
||||
return;
|
||||
|
@ -23,7 +19,15 @@ export default apiInitializer("1.25.0", (api) => {
|
|||
buttonAttrs.class,
|
||||
buttonAttrs.icon,
|
||||
(event) => {
|
||||
if (event.target.classList.contains("generate-caption")) {
|
||||
const imageCaptionPopup = api.container.lookup(
|
||||
"service:imageCaptionPopup"
|
||||
);
|
||||
|
||||
imageCaptionPopup.popupTrigger = event.target;
|
||||
|
||||
if (
|
||||
imageCaptionPopup.popupTrigger.classList.contains("generate-caption")
|
||||
) {
|
||||
const buttonWrapper = event.target.closest(".button-wrapper");
|
||||
const imageIndex = parseInt(
|
||||
buttonWrapper.getAttribute("data-image-index"),
|
||||
|
@ -34,20 +38,24 @@ export default apiInitializer("1.25.0", (api) => {
|
|||
.querySelector("img")
|
||||
.getAttribute("src");
|
||||
|
||||
imageCaptionPopup.loading = true;
|
||||
imageCaptionPopup.toggleLoadingState(true);
|
||||
|
||||
const site = api.container.lookup("site:main");
|
||||
if (!site.mobileView) {
|
||||
imageCaptionPopup.showPopup = !imageCaptionPopup.showPopup;
|
||||
}
|
||||
|
||||
event.target.classList.add("disabled");
|
||||
imageCaptionPopup._request = ajax(
|
||||
`/discourse-ai/ai-helper/caption_image`,
|
||||
{
|
||||
method: "POST",
|
||||
data: {
|
||||
image_url: imageSrc,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
ajax(`/discourse-ai/ai-helper/caption_image`, {
|
||||
method: "POST",
|
||||
data: {
|
||||
image_url: imageSrc,
|
||||
},
|
||||
})
|
||||
imageCaptionPopup._request
|
||||
.then(({ caption }) => {
|
||||
imageCaptionPopup.imageSrc = imageSrc;
|
||||
imageCaptionPopup.imageIndex = imageIndex;
|
||||
|
@ -55,22 +63,12 @@ export default apiInitializer("1.25.0", (api) => {
|
|||
|
||||
if (site.mobileView) {
|
||||
// Auto-saves caption on mobile view
|
||||
const composer = api.container.lookup("service:composer");
|
||||
|
||||
const matchingPlaceholder =
|
||||
composer.model.reply.match(IMAGE_MARKDOWN_REGEX);
|
||||
const match = matchingPlaceholder[imageIndex];
|
||||
const replacement = match.replace(
|
||||
IMAGE_MARKDOWN_REGEX,
|
||||
`![${imageCaptionPopup.newCaption}|$2$3$4]($5)`
|
||||
);
|
||||
appEvents.trigger("composer:replace-text", match, replacement);
|
||||
imageCaptionPopup.updateCaption();
|
||||
}
|
||||
})
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => {
|
||||
imageCaptionPopup.loading = false;
|
||||
event.target.classList.remove("disabled");
|
||||
imageCaptionPopup.toggleLoadingState(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,15 @@ RSpec.describe "AI image caption", type: :system, js: true do
|
|||
wait_for { page.find(".image-wrapper img")["alt"] == caption_with_attrs }
|
||||
expect(page.find(".image-wrapper img")["alt"]).to eq(caption_with_attrs)
|
||||
end
|
||||
|
||||
it "should allow you to cancel a caption request" do
|
||||
visit("/latest")
|
||||
page.find("#create-topic").click
|
||||
attach_file([file_path]) { composer.click_toolbar_button("upload") }
|
||||
popup.click_generate_caption
|
||||
popup.cancel_caption
|
||||
expect(popup).to have_no_disabled_generate_button
|
||||
end
|
||||
end
|
||||
|
||||
context "when triggering caption with AI on mobile", mobile: true do
|
||||
|
|
|
@ -18,6 +18,14 @@ module PageObjects
|
|||
def save_caption
|
||||
find("#{CAPTION_POPUP_SELECTOR} .btn-primary").click
|
||||
end
|
||||
|
||||
def cancel_caption
|
||||
find("#{CAPTION_POPUP_SELECTOR} .cancel-request").click
|
||||
end
|
||||
|
||||
def has_no_disabled_generate_button?
|
||||
page.has_no_css?("#{GENERATE_CAPTION_SELECTOR}.disabled", visible: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue