feat: gate live and task actions when modules are disabled
This commit is contained in:
parent
5662f34415
commit
1952a139ae
3 changed files with 62 additions and 6 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::agent::Agent;
|
use crate::models::agent::Agent;
|
||||||
use crate::models::agent_task::AgentTask;
|
use crate::models::agent_task::AgentTask;
|
||||||
|
use crate::models::module::{ProjectModule, MODULE_AGENT_TASK_RUNNER};
|
||||||
use crate::models::project::Project;
|
use crate::models::project::Project;
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
use tauri::State;
|
use tauri::State;
|
||||||
|
|
@ -24,6 +25,13 @@ pub fn create_agent_task(
|
||||||
.lock()
|
.lock()
|
||||||
.map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?;
|
.map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?;
|
||||||
|
|
||||||
|
let enabled = ProjectModule::is_enabled(&db, &project_id, MODULE_AGENT_TASK_RUNNER)?;
|
||||||
|
if !enabled {
|
||||||
|
return Err(AppError::from(
|
||||||
|
"Le module Agent task runner est désactivé pour ce projet".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Project::get_by_id(&db, &project_id)?;
|
Project::get_by_id(&db, &project_id)?;
|
||||||
Agent::get_by_id(&db, &agent_id)?;
|
Agent::get_by_id(&db, &agent_id)?;
|
||||||
|
|
||||||
|
|
@ -59,6 +67,13 @@ pub fn retry_agent_task(state: State<'_, AppState>, task_id: String) -> Result<(
|
||||||
.map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?;
|
.map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?;
|
||||||
|
|
||||||
let task = AgentTask::get_by_id(&db, &task_id)?;
|
let task = AgentTask::get_by_id(&db, &task_id)?;
|
||||||
|
let enabled = ProjectModule::is_enabled(&db, &task.project_id, MODULE_AGENT_TASK_RUNNER)?;
|
||||||
|
if !enabled {
|
||||||
|
return Err(AppError::from(
|
||||||
|
"Le module Agent task runner est désactivé pour ce projet".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
if task.status != "error" && task.status != "cancelled" && task.status != "done" {
|
if task.status != "error" && task.status != "cancelled" && task.status != "done" {
|
||||||
return Err(AppError::from(format!(
|
return Err(AppError::from(format!(
|
||||||
"Impossible de relancer une tâche avec le statut '{}'",
|
"Impossible de relancer une tâche avec le statut '{}'",
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import {
|
||||||
createLiveSession,
|
createLiveSession,
|
||||||
listAgents,
|
listAgents,
|
||||||
listLiveMessages,
|
listLiveMessages,
|
||||||
|
listProjectModules,
|
||||||
listLiveSessions,
|
listLiveSessions,
|
||||||
sendLiveMessage,
|
sendLiveMessage,
|
||||||
} from "../../lib/api";
|
} from "../../lib/api";
|
||||||
|
|
@ -28,6 +29,7 @@ export default function ProjectLiveAgent() {
|
||||||
const [draft, setDraft] = useState("");
|
const [draft, setDraft] = useState("");
|
||||||
const [sending, setSending] = useState(false);
|
const [sending, setSending] = useState(false);
|
||||||
const [creatingSession, setCreatingSession] = useState(false);
|
const [creatingSession, setCreatingSession] = useState(false);
|
||||||
|
const [moduleEnabled, setModuleEnabled] = useState(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
const usableAgents = useMemo(
|
const usableAgents = useMemo(
|
||||||
|
|
@ -68,8 +70,14 @@ export default function ProjectLiveAgent() {
|
||||||
|
|
||||||
setError(null);
|
setError(null);
|
||||||
try {
|
try {
|
||||||
const [availableAgents] = await Promise.all([listAgents()]);
|
const [availableAgents, modules] = await Promise.all([
|
||||||
|
listAgents(),
|
||||||
|
listProjectModules(projectId),
|
||||||
|
]);
|
||||||
setAgents(availableAgents);
|
setAgents(availableAgents);
|
||||||
|
setModuleEnabled(
|
||||||
|
modules.find((mod) => mod.module_key === "ai_live_chat")?.enabled ?? true
|
||||||
|
);
|
||||||
|
|
||||||
const firstAgentId = availableAgents[0]?.id ?? "";
|
const firstAgentId = availableAgents[0]?.id ?? "";
|
||||||
setSelectedAgentId((current) => current || firstAgentId);
|
setSelectedAgentId((current) => current || firstAgentId);
|
||||||
|
|
@ -113,6 +121,10 @@ export default function ProjectLiveAgent() {
|
||||||
async function handleCreateSession(event: FormEvent) {
|
async function handleCreateSession(event: FormEvent) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (!projectId || !selectedAgentId) return;
|
if (!projectId || !selectedAgentId) return;
|
||||||
|
if (!moduleEnabled) {
|
||||||
|
setError("Le module Live chat agent est désactivé pour ce projet.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setCreatingSession(true);
|
setCreatingSession(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
@ -130,6 +142,10 @@ export default function ProjectLiveAgent() {
|
||||||
async function handleSendMessage(event: FormEvent) {
|
async function handleSendMessage(event: FormEvent) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (!selectedSessionId || !draft.trim()) return;
|
if (!selectedSessionId || !draft.trim()) return;
|
||||||
|
if (!moduleEnabled) {
|
||||||
|
setError("Le module Live chat agent est désactivé pour ce projet.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const content = draft.trim();
|
const content = draft.trim();
|
||||||
setDraft("");
|
setDraft("");
|
||||||
|
|
@ -172,6 +188,11 @@ export default function ProjectLiveAgent() {
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{!moduleEnabled && (
|
||||||
|
<div className="rounded border border-amber-200 bg-amber-50 p-2 text-sm text-amber-700">
|
||||||
|
Le module est désactivé. La lecture reste possible, mais la création de session et l'envoi de message sont bloqués.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<form onSubmit={handleCreateSession} className="rounded-lg border border-gray-200 bg-white p-4">
|
<form onSubmit={handleCreateSession} className="rounded-lg border border-gray-200 bg-white p-4">
|
||||||
<h3 className="mb-3 text-sm font-semibold text-gray-800">Nouvelle session</h3>
|
<h3 className="mb-3 text-sm font-semibold text-gray-800">Nouvelle session</h3>
|
||||||
|
|
@ -196,7 +217,7 @@ export default function ProjectLiveAgent() {
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={creatingSession || !selectedAgentId}
|
disabled={creatingSession || !selectedAgentId || !moduleEnabled}
|
||||||
className="rounded bg-blue-600 px-4 py-2 text-sm text-white hover:bg-blue-700 disabled:opacity-50"
|
className="rounded bg-blue-600 px-4 py-2 text-sm text-white hover:bg-blue-700 disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{creatingSession ? "Création..." : "Créer la session"}
|
{creatingSession ? "Création..." : "Créer la session"}
|
||||||
|
|
@ -270,7 +291,7 @@ export default function ProjectLiveAgent() {
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!selectedSessionId || sending || !draft.trim()}
|
disabled={!selectedSessionId || sending || !draft.trim() || !moduleEnabled}
|
||||||
className="rounded bg-gray-900 px-4 py-2 text-sm text-white hover:bg-black disabled:opacity-50"
|
className="rounded bg-gray-900 px-4 py-2 text-sm text-white hover:bg-black disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{sending ? "Envoi..." : "Envoyer"}
|
{sending ? "Envoi..." : "Envoyer"}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import {
|
||||||
createAgentTask,
|
createAgentTask,
|
||||||
listAgentTasks,
|
listAgentTasks,
|
||||||
listAgents,
|
listAgents,
|
||||||
|
listProjectModules,
|
||||||
retryAgentTask,
|
retryAgentTask,
|
||||||
} from "../../lib/api";
|
} from "../../lib/api";
|
||||||
import { getErrorMessage } from "../../lib/errors";
|
import { getErrorMessage } from "../../lib/errors";
|
||||||
|
|
@ -26,6 +27,7 @@ export default function ProjectTasks() {
|
||||||
const [agentId, setAgentId] = useState("");
|
const [agentId, setAgentId] = useState("");
|
||||||
const [title, setTitle] = useState("");
|
const [title, setTitle] = useState("");
|
||||||
const [description, setDescription] = useState("");
|
const [description, setDescription] = useState("");
|
||||||
|
const [moduleEnabled, setModuleEnabled] = useState(true);
|
||||||
const [creating, setCreating] = useState(false);
|
const [creating, setCreating] = useState(false);
|
||||||
const [workingTaskId, setWorkingTaskId] = useState<string | null>(null);
|
const [workingTaskId, setWorkingTaskId] = useState<string | null>(null);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
@ -40,12 +42,16 @@ export default function ProjectTasks() {
|
||||||
|
|
||||||
setError(null);
|
setError(null);
|
||||||
try {
|
try {
|
||||||
const [availableAgents, projectTasks] = await Promise.all([
|
const [availableAgents, projectTasks, modules] = await Promise.all([
|
||||||
listAgents(),
|
listAgents(),
|
||||||
listAgentTasks(projectId),
|
listAgentTasks(projectId),
|
||||||
|
listProjectModules(projectId),
|
||||||
]);
|
]);
|
||||||
setAgents(availableAgents);
|
setAgents(availableAgents);
|
||||||
setTasks(projectTasks);
|
setTasks(projectTasks);
|
||||||
|
setModuleEnabled(
|
||||||
|
modules.find((mod) => mod.module_key === "agent_task_runner")?.enabled ?? true
|
||||||
|
);
|
||||||
if (!agentId && availableAgents.length > 0) {
|
if (!agentId && availableAgents.length > 0) {
|
||||||
setAgentId(availableAgents[0].id);
|
setAgentId(availableAgents[0].id);
|
||||||
}
|
}
|
||||||
|
|
@ -95,6 +101,10 @@ export default function ProjectTasks() {
|
||||||
async function handleCreateTask(event: FormEvent) {
|
async function handleCreateTask(event: FormEvent) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (!projectId || !agentId || !title.trim()) return;
|
if (!projectId || !agentId || !title.trim()) return;
|
||||||
|
if (!moduleEnabled) {
|
||||||
|
setError("Le module Agent task runner est désactivé pour ce projet.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setCreating(true);
|
setCreating(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
@ -111,6 +121,11 @@ export default function ProjectTasks() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleRetry(taskId: string) {
|
async function handleRetry(taskId: string) {
|
||||||
|
if (!moduleEnabled) {
|
||||||
|
setError("Le module Agent task runner est désactivé pour ce projet.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setWorkingTaskId(taskId);
|
setWorkingTaskId(taskId);
|
||||||
setError(null);
|
setError(null);
|
||||||
try {
|
try {
|
||||||
|
|
@ -145,6 +160,11 @@ export default function ProjectTasks() {
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{!moduleEnabled && (
|
||||||
|
<div className="rounded border border-amber-200 bg-amber-50 p-2 text-sm text-amber-700">
|
||||||
|
Le module est désactivé. Les tâches existantes restent visibles, mais la création et la relance sont bloquées.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<form onSubmit={handleCreateTask} className="rounded-lg border border-gray-200 bg-white p-4">
|
<form onSubmit={handleCreateTask} className="rounded-lg border border-gray-200 bg-white p-4">
|
||||||
<h3 className="mb-3 text-sm font-semibold text-gray-800">Créer une tâche</h3>
|
<h3 className="mb-3 text-sm font-semibold text-gray-800">Créer une tâche</h3>
|
||||||
|
|
@ -171,7 +191,7 @@ export default function ProjectTasks() {
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={creating || !agentId || !title.trim()}
|
disabled={creating || !agentId || !title.trim() || !moduleEnabled}
|
||||||
className="rounded bg-blue-600 px-4 py-2 text-sm text-white hover:bg-blue-700 disabled:opacity-50"
|
className="rounded bg-blue-600 px-4 py-2 text-sm text-white hover:bg-blue-700 disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{creating ? "Création..." : "Créer"}
|
{creating ? "Création..." : "Créer"}
|
||||||
|
|
@ -223,7 +243,7 @@ export default function ProjectTasks() {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => void handleRetry(task.id)}
|
onClick={() => void handleRetry(task.id)}
|
||||||
disabled={workingTaskId === task.id}
|
disabled={workingTaskId === task.id || !moduleEnabled}
|
||||||
className="rounded bg-gray-900 px-3 py-1 text-xs text-white hover:bg-black disabled:opacity-50"
|
className="rounded bg-gray-900 px-3 py-1 text-xs text-white hover:bg-black disabled:opacity-50"
|
||||||
>
|
>
|
||||||
Relancer
|
Relancer
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue