feat(core): show stop modal if clickoutside during generating (#12227)

### TL;DR

feat: show stop model if click-outside during ai generating

>CLOSE AI-89

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Added a confirmation dialog when attempting to stop AI content generation by clicking outside the panel, ensuring users can confirm or cancel the stop action.

- **Tests**
  - Introduced an end-to-end test to verify the confirmation dialog appears and AI generation stops as expected when clicking outside during generation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
yoyoyohamapi
2025-05-14 03:16:55 +00:00
parent 291bb9c449
commit f737327f12
2 changed files with 48 additions and 1 deletions

View File

@@ -113,7 +113,11 @@ export class AffineAIPanelWidget extends WidgetComponent {
};
private readonly _clickOutside = () => {
this._discardWithConfirmation();
if (this.state === 'generating') {
this._stopWithConfirmation();
} else {
this._discardWithConfirmation();
}
};
private _discardModalAbort: AbortController | null = null;
@@ -169,6 +173,16 @@ export class AffineAIPanelWidget extends WidgetComponent {
ctx: unknown = null;
private readonly _stopWithConfirmation = () => {
this.showStopModal()
.then(stop => {
if (stop) {
this.stopGenerating();
}
})
.catch(console.error);
};
private readonly _discardWithConfirmation = () => {
if (this.state === 'hidden') {
return;
@@ -275,6 +289,24 @@ export class AffineAIPanelWidget extends WidgetComponent {
this._autoUpdatePosition(reference);
};
showStopModal = () => {
const notification = this.host.std.getOptional(NotificationProvider);
if (!notification) {
return Promise.resolve(true);
}
this._clearDiscardModal();
this._discardModalAbort = new AbortController();
return notification
.confirm({
title: 'Stop generating',
message: 'AI is generating content. Do you want to stop generating?',
cancelText: 'Cancel',
confirmText: 'Stop',
abort: this._abortController.signal,
})
.finally(() => (this._discardModalAbort = null));
};
showDiscardModal = () => {
const notification = this.host.std.getOptional(NotificationProvider);
if (!notification) {