Task work log, inline writing assistant, task editor sidebar layout
Backend: - Migration 0021: task_logs table (FK → notes + users, CASCADE, indexed) - models/task_log.py: SQLAlchemy model with to_dict() - services/task_logs.py: CRUD with ownership checks, _UNSET sentinel for optional duration clear - routes/task_logs.py: GET/POST/PATCH/DELETE /api/tasks/<id>/logs - services/tools.py: log_work LLM tool (resolves task by title, creates log entry) - services/generation_task.py: retry assist generation up to 3× on HTTP 500 Frontend: - types/task.ts: TaskLog interface - TaskLogSection.vue: chronological work log with date+time timestamps, duration badge, inline edit, autofocus - InlineAssistPanel.vue: streaming preview + diff review rendered inline in editor column - useAssist.ts: removed chatStore.chatReady gate; toast notifications for errors - NoteEditorView.vue + TaskEditorView.vue: inline assist panel, aside restricted to idle state - TaskEditorView.vue: two-column layout (editor+log left, metadata sidebar right), body defaults to Preview, sidebarOpen accordion for mobile - editor-shared.css: .assist-active-hint style Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { ref, computed, watch, type Ref } from "vue";
|
||||
import { apiPost, apiSSEStream, type SSEStreamHandle } from "@/api/client";
|
||||
import { useChatStore } from "@/stores/chat";
|
||||
import { useToastStore } from "@/stores/toast";
|
||||
import {
|
||||
parseMarkdownSections,
|
||||
type MarkdownSection,
|
||||
@@ -42,7 +42,7 @@ function computeDiff(a: string, b: string): DiffLine[] {
|
||||
}
|
||||
|
||||
export function useAssist(body: Ref<string>) {
|
||||
const chatStore = useChatStore();
|
||||
const toast = useToastStore();
|
||||
|
||||
const state = ref<AssistState>("idle");
|
||||
const sections = ref<MarkdownSection[]>([]);
|
||||
@@ -80,7 +80,6 @@ export function useAssist(body: Ref<string>) {
|
||||
() =>
|
||||
target.value !== null &&
|
||||
instruction.value.trim().length > 0 &&
|
||||
chatStore.chatReady &&
|
||||
state.value !== "streaming"
|
||||
);
|
||||
|
||||
@@ -154,6 +153,7 @@ export function useAssist(body: Ref<string>) {
|
||||
}
|
||||
if (evt.event === "error") {
|
||||
error.value = evt.data.error as string;
|
||||
toast.show("Assist failed: " + error.value, "error");
|
||||
state.value = "idle";
|
||||
streamHandle = null;
|
||||
}
|
||||
@@ -173,6 +173,7 @@ export function useAssist(body: Ref<string>) {
|
||||
}
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : "Request failed";
|
||||
toast.show("Assist failed: " + error.value, "error");
|
||||
state.value = "idle";
|
||||
streamHandle = null;
|
||||
}
|
||||
@@ -202,6 +203,7 @@ export function useAssist(body: Ref<string>) {
|
||||
const currentSlice = body.value.slice(t.startOffset, t.endOffset);
|
||||
if (currentSlice !== t.text) {
|
||||
error.value = "The document changed since this suggestion was made. Please clear and try again.";
|
||||
toast.show(error.value, "error");
|
||||
state.value = "idle";
|
||||
return body.value;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user