mirror of
https://github.com/discourse/discourse-ai.git
synced 2025-02-08 04:28:18 +00:00
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 autoFocus from "discourse/modifiers/auto-focus";
|
||||||
import icon from "discourse-common/helpers/d-icon";
|
import icon from "discourse-common/helpers/d-icon";
|
||||||
import i18n from "discourse-common/helpers/i18n";
|
import i18n from "discourse-common/helpers/i18n";
|
||||||
import { IMAGE_MARKDOWN_REGEX } from "../../lib/utilities";
|
|
||||||
|
|
||||||
export default class AiImageCaptionContainer extends Component {
|
export default class AiImageCaptionContainer extends Component {
|
||||||
@service imageCaptionPopup;
|
@service imageCaptionPopup;
|
||||||
@service appEvents;
|
|
||||||
@service composer;
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
updateCaption(event) {
|
updateCaption(event) {
|
||||||
@ -26,22 +23,7 @@ export default class AiImageCaptionContainer extends Component {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
saveCaption() {
|
saveCaption() {
|
||||||
const index = this.imageCaptionPopup.imageIndex;
|
this.imageCaptionPopup.updateCaption();
|
||||||
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.hidePopup();
|
this.hidePopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +45,11 @@ export default class AiImageCaptionContainer extends Component {
|
|||||||
@action
|
@action
|
||||||
hidePopup() {
|
hidePopup() {
|
||||||
this.imageCaptionPopup.showPopup = false;
|
this.imageCaptionPopup.showPopup = false;
|
||||||
|
if (this.imageCaptionPopup._request) {
|
||||||
|
this.imageCaptionPopup._request.abort();
|
||||||
|
this.imageCaptionPopup._request = null;
|
||||||
|
this.imageCaptionPopup.toggleLoadingState(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -91,7 +78,7 @@ export default class AiImageCaptionContainer extends Component {
|
|||||||
@action={{this.saveCaption}}
|
@action={{this.saveCaption}}
|
||||||
/>
|
/>
|
||||||
<DButton
|
<DButton
|
||||||
class="btn-flat"
|
class="btn-flat cancel-request"
|
||||||
@label="cancel"
|
@label="cancel"
|
||||||
@action={{this.hidePopup}}
|
@action={{this.hidePopup}}
|
||||||
/>
|
/>
|
||||||
|
@ -1,10 +1,43 @@
|
|||||||
import { tracked } from "@glimmer/tracking";
|
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 {
|
export default class ImageCaptionPopup extends Service {
|
||||||
|
@service composer;
|
||||||
|
@service appEvents;
|
||||||
|
|
||||||
@tracked showPopup = false;
|
@tracked showPopup = false;
|
||||||
@tracked imageIndex = null;
|
@tracked imageIndex = null;
|
||||||
@tracked imageSrc = null;
|
@tracked imageSrc = null;
|
||||||
@tracked newCaption = null;
|
@tracked newCaption = null;
|
||||||
@tracked loading = false;
|
@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 { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { apiInitializer } from "discourse/lib/api";
|
import { apiInitializer } from "discourse/lib/api";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
import { IMAGE_MARKDOWN_REGEX } from "../discourse/lib/utilities";
|
|
||||||
|
|
||||||
export default apiInitializer("1.25.0", (api) => {
|
export default apiInitializer("1.25.0", (api) => {
|
||||||
const buttonAttrs = {
|
const buttonAttrs = {
|
||||||
@ -10,10 +9,7 @@ export default apiInitializer("1.25.0", (api) => {
|
|||||||
icon: "discourse-sparkles",
|
icon: "discourse-sparkles",
|
||||||
class: "generate-caption",
|
class: "generate-caption",
|
||||||
};
|
};
|
||||||
const imageCaptionPopup = api.container.lookup("service:imageCaptionPopup");
|
|
||||||
const settings = api.container.lookup("service:site-settings");
|
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")) {
|
if (!settings.ai_helper_enabled_features.includes("image_caption")) {
|
||||||
return;
|
return;
|
||||||
@ -23,7 +19,15 @@ export default apiInitializer("1.25.0", (api) => {
|
|||||||
buttonAttrs.class,
|
buttonAttrs.class,
|
||||||
buttonAttrs.icon,
|
buttonAttrs.icon,
|
||||||
(event) => {
|
(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 buttonWrapper = event.target.closest(".button-wrapper");
|
||||||
const imageIndex = parseInt(
|
const imageIndex = parseInt(
|
||||||
buttonWrapper.getAttribute("data-image-index"),
|
buttonWrapper.getAttribute("data-image-index"),
|
||||||
@ -34,20 +38,24 @@ export default apiInitializer("1.25.0", (api) => {
|
|||||||
.querySelector("img")
|
.querySelector("img")
|
||||||
.getAttribute("src");
|
.getAttribute("src");
|
||||||
|
|
||||||
imageCaptionPopup.loading = true;
|
imageCaptionPopup.toggleLoadingState(true);
|
||||||
|
|
||||||
|
const site = api.container.lookup("site:main");
|
||||||
if (!site.mobileView) {
|
if (!site.mobileView) {
|
||||||
imageCaptionPopup.showPopup = !imageCaptionPopup.showPopup;
|
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`, {
|
imageCaptionPopup._request
|
||||||
method: "POST",
|
|
||||||
data: {
|
|
||||||
image_url: imageSrc,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(({ caption }) => {
|
.then(({ caption }) => {
|
||||||
imageCaptionPopup.imageSrc = imageSrc;
|
imageCaptionPopup.imageSrc = imageSrc;
|
||||||
imageCaptionPopup.imageIndex = imageIndex;
|
imageCaptionPopup.imageIndex = imageIndex;
|
||||||
@ -55,22 +63,12 @@ export default apiInitializer("1.25.0", (api) => {
|
|||||||
|
|
||||||
if (site.mobileView) {
|
if (site.mobileView) {
|
||||||
// Auto-saves caption on mobile view
|
// Auto-saves caption on mobile view
|
||||||
const composer = api.container.lookup("service:composer");
|
imageCaptionPopup.updateCaption();
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(popupAjaxError)
|
.catch(popupAjaxError)
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
imageCaptionPopup.loading = false;
|
imageCaptionPopup.toggleLoadingState(false);
|
||||||
event.target.classList.remove("disabled");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 }
|
wait_for { page.find(".image-wrapper img")["alt"] == caption_with_attrs }
|
||||||
expect(page.find(".image-wrapper img")["alt"]).to eq(caption_with_attrs)
|
expect(page.find(".image-wrapper img")["alt"]).to eq(caption_with_attrs)
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
context "when triggering caption with AI on mobile", mobile: true do
|
context "when triggering caption with AI on mobile", mobile: true do
|
||||||
|
@ -18,6 +18,14 @@ module PageObjects
|
|||||||
def save_caption
|
def save_caption
|
||||||
find("#{CAPTION_POPUP_SELECTOR} .btn-primary").click
|
find("#{CAPTION_POPUP_SELECTOR} .btn-primary").click
|
||||||
end
|
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
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user