You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
4.4 KiB
117 lines
4.4 KiB
/** @odoo-module **/
|
|
|
|
import { patch } from "@web/core/utils/patch";
|
|
import { useService } from "@web/core/utils/hooks";
|
|
import { rpc } from "@web/core/network/rpc";
|
|
import { Component, xml, useRef, useState } from "@odoo/owl";
|
|
import { AddSnippetDialog } from "@web_editor/js/editor/add_snippet_dialog";
|
|
|
|
|
|
// Define a custom Owl component for the AI Prompt Modal
|
|
class AIPromptModal extends Component {
|
|
setup() {
|
|
this.orm = useService("orm");
|
|
this.notification = useService("notification");
|
|
this.textAreaRef = useRef('textAreaRef');
|
|
this.nameRef = useRef('snippetNameRef');
|
|
this.state = useState({
|
|
isLoading: false,
|
|
});
|
|
}
|
|
// Close the modal (disabled if a request is loading)
|
|
onClose() {
|
|
if (this.state.isLoading) {
|
|
return;
|
|
}
|
|
this.props.close();
|
|
}
|
|
async onSubmit() {
|
|
const promptValue = this.textAreaRef.el.value;
|
|
const snippetName = this.nameRef.el.value;
|
|
|
|
if (!promptValue || !snippetName) {
|
|
this.notification.add(
|
|
"Please fill in both the prompt and snippet name",
|
|
{ type: "warning" }
|
|
);
|
|
return;
|
|
}
|
|
try {
|
|
this.state.isLoading = true;
|
|
const result = await rpc('/website/generate_snippet', {
|
|
prompt: promptValue,
|
|
name: snippetName
|
|
});
|
|
if (result.error) {
|
|
this.notification.add(result.error, { type: "danger" });
|
|
} else {
|
|
this.notification.add(
|
|
"Snippet generated successfully! Refreshing snippet panel...",
|
|
{ type: "success" }
|
|
);
|
|
window.location.reload();
|
|
}
|
|
} catch (error) {
|
|
this.notification.add(
|
|
"Failed to generate snippet: " + error,
|
|
{ type: "danger" }
|
|
);
|
|
} finally {
|
|
this.state.isLoading = false;
|
|
}
|
|
this.props.close();
|
|
}
|
|
}
|
|
|
|
// Define the template for the modal
|
|
AIPromptModal.template = xml`
|
|
<div class="modal o_technical_modal d-block" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Generate Snippet with AI</h5>
|
|
<button type="button" class="btn-close" t-att-disabled="state.isLoading" t-on-click="onClose" aria-label="Close"/>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="form-group mb-3">
|
|
<label for="snippet-name" class="form-label">Snippet Name</label>
|
|
<input type="text" id="snippet-name" class="form-control" t-ref="snippetNameRef"
|
|
t-att-disabled="state.isLoading" placeholder="Enter a name for your snippet"/>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="ai-prompt" class="form-label">Enter your prompt here...</label>
|
|
<textarea id="ai-prompt" class="form-control" rows="3" t-ref="textAreaRef"
|
|
t-att-disabled="state.isLoading"/>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" t-att-disabled="state.isLoading" t-on-click="onClose">Cancel</button>
|
|
<button type="button" class="btn btn-primary" t-att-disabled="state.isLoading" t-on-click="onSubmit">
|
|
<t t-if="state.isLoading">
|
|
<span class="fa fa-spinner fa-spin me-1"></span>
|
|
Generating...
|
|
</t>
|
|
<t t-else="">Generate</t>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
// Patch the AddSnippetDialog to add the AI prompt dialog on click
|
|
const originalSetup = AddSnippetDialog.prototype.setup;
|
|
patch(AddSnippetDialog.prototype, {
|
|
setup() {
|
|
originalSetup.call(this);
|
|
this.dialog = useService("dialog");
|
|
},
|
|
async _onGenerateClick() {
|
|
this.dialog.add(AIPromptModal, {
|
|
onClose: () => {
|
|
// Refresh the snippets panel after closing
|
|
this.render();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|