chore(frontend): drop dead settings toggle, types, and store list-surface
Drift-audit Group 7 frontend cleanup (no behavioral change): - SettingsView: remove the 'auto-consolidate task bodies' toggle and its saveAutoConsolidate handler. The auto_consolidate_tasks setting has zero backend readers (curator removed in Phase 8); the control did nothing. - AppSettings type: drop the dead assistant_name / default_model hints (kept the open string index signature the store actually uses). Delete the fully orphaned types/chat.ts (zero importers). - notes/tasks Pinia stores: remove the list/filter/sort/pagination surface that backed the removed /notes and /tasks list views (verified no consumer uses the tasks/notes arrays, refresh, or any filter/sort/pagination method). Kept currentNote/currentTask, loading, fetch/create/update/delete, convert, patchStatus, startPlanning, backlinks, tags. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,66 +2,16 @@ import { ref } from "vue";
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { apiGet, apiPost, apiPut, apiDelete } from "@/api/client";
|
import { apiGet, apiPost, apiPut, apiDelete } from "@/api/client";
|
||||||
import { useToastStore } from "@/stores/toast";
|
import { useToastStore } from "@/stores/toast";
|
||||||
import type { Note, NoteListResponse } from "@/types/note";
|
import type { Note } from "@/types/note";
|
||||||
|
|
||||||
|
// Single-note + mutation surface. The list/filter/sort/pagination surface that
|
||||||
|
// backed the removed /notes list view was dropped in the 2026-06-02 drift-audit
|
||||||
|
// cleanup (no consumers — KnowledgeView and the editors use single-entity and
|
||||||
|
// mutation methods only).
|
||||||
export const useNotesStore = defineStore("notes", () => {
|
export const useNotesStore = defineStore("notes", () => {
|
||||||
const notes = ref<Note[]>([]);
|
|
||||||
const currentNote = ref<Note | null>(null);
|
const currentNote = ref<Note | null>(null);
|
||||||
const total = ref(0);
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
// Filter / pagination / sort state
|
|
||||||
const activeTagFilters = ref<string[]>([]);
|
|
||||||
const limit = ref(20);
|
|
||||||
const offset = ref(0);
|
|
||||||
const sortField = ref("updated_at");
|
|
||||||
const sortOrder = ref<"asc" | "desc">("desc");
|
|
||||||
const searchQuery = ref("");
|
|
||||||
|
|
||||||
async function refresh() {
|
|
||||||
loading.value = true;
|
|
||||||
try {
|
|
||||||
const searchParams = new URLSearchParams();
|
|
||||||
if (searchQuery.value) searchParams.set("q", searchQuery.value);
|
|
||||||
for (const t of activeTagFilters.value) {
|
|
||||||
searchParams.append("tag", t);
|
|
||||||
}
|
|
||||||
searchParams.set("sort", sortField.value);
|
|
||||||
searchParams.set("order", sortOrder.value);
|
|
||||||
searchParams.set("limit", String(limit.value));
|
|
||||||
searchParams.set("offset", String(offset.value));
|
|
||||||
|
|
||||||
const qs = searchParams.toString();
|
|
||||||
const data = await apiGet<NoteListResponse>(
|
|
||||||
`/api/notes${qs ? `?${qs}` : ""}`
|
|
||||||
);
|
|
||||||
notes.value = data.notes;
|
|
||||||
total.value = data.total;
|
|
||||||
} catch (e) {
|
|
||||||
useToastStore().show("Failed to load notes", "error");
|
|
||||||
throw e;
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchNotes(params?: {
|
|
||||||
q?: string;
|
|
||||||
tag?: string[];
|
|
||||||
sort?: string;
|
|
||||||
order?: string;
|
|
||||||
limit?: number;
|
|
||||||
offset?: number;
|
|
||||||
}) {
|
|
||||||
if (params?.q !== undefined) searchQuery.value = params.q || "";
|
|
||||||
if (params?.tag) activeTagFilters.value = params.tag;
|
|
||||||
if (params?.sort) sortField.value = params.sort;
|
|
||||||
if (params?.order) sortOrder.value = params.order as "asc" | "desc";
|
|
||||||
if (params?.limit) limit.value = params.limit;
|
|
||||||
if (params?.offset !== undefined) offset.value = params.offset;
|
|
||||||
await refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchNote(id: number) {
|
async function fetchNote(id: number) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
@@ -110,7 +60,6 @@ export const useNotesStore = defineStore("notes", () => {
|
|||||||
async function deleteNote(id: number) {
|
async function deleteNote(id: number) {
|
||||||
try {
|
try {
|
||||||
await apiDelete(`/api/notes/${id}`);
|
await apiDelete(`/api/notes/${id}`);
|
||||||
notes.value = notes.value.filter((n) => n.id !== id);
|
|
||||||
if (currentNote.value?.id === id) {
|
if (currentNote.value?.id === id) {
|
||||||
currentNote.value = null;
|
currentNote.value = null;
|
||||||
}
|
}
|
||||||
@@ -120,50 +69,6 @@ export const useNotesStore = defineStore("notes", () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addTagFilter(tag: string) {
|
|
||||||
if (!activeTagFilters.value.includes(tag)) {
|
|
||||||
activeTagFilters.value.push(tag);
|
|
||||||
offset.value = 0;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeTagFilter(tag: string) {
|
|
||||||
activeTagFilters.value = activeTagFilters.value.filter((t) => t !== tag);
|
|
||||||
offset.value = 0;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearTagFilters() {
|
|
||||||
activeTagFilters.value = [];
|
|
||||||
offset.value = 0;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setTagFilters(tags: string[]) {
|
|
||||||
activeTagFilters.value = [...tags];
|
|
||||||
offset.value = 0;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSort(field: string, order: "asc" | "desc") {
|
|
||||||
sortField.value = field;
|
|
||||||
sortOrder.value = order;
|
|
||||||
offset.value = 0;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setOffset(newOffset: number) {
|
|
||||||
offset.value = newOffset;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSearch(q: string) {
|
|
||||||
searchQuery.value = q;
|
|
||||||
offset.value = 0;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function resolveTitle(title: string): Promise<Note> {
|
async function resolveTitle(title: string): Promise<Note> {
|
||||||
return await apiPost<Note>("/api/notes/resolve-title", { title });
|
return await apiPost<Note>("/api/notes/resolve-title", { title });
|
||||||
}
|
}
|
||||||
@@ -216,29 +121,12 @@ export const useNotesStore = defineStore("notes", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
notes,
|
|
||||||
currentNote,
|
currentNote,
|
||||||
total,
|
|
||||||
loading,
|
loading,
|
||||||
activeTagFilters,
|
|
||||||
limit,
|
|
||||||
offset,
|
|
||||||
sortField,
|
|
||||||
sortOrder,
|
|
||||||
searchQuery,
|
|
||||||
fetchNotes,
|
|
||||||
fetchNote,
|
fetchNote,
|
||||||
createNote,
|
createNote,
|
||||||
updateNote,
|
updateNote,
|
||||||
deleteNote,
|
deleteNote,
|
||||||
addTagFilter,
|
|
||||||
removeTagFilter,
|
|
||||||
clearTagFilters,
|
|
||||||
setTagFilters,
|
|
||||||
setSort,
|
|
||||||
setOffset,
|
|
||||||
setSearch,
|
|
||||||
refresh,
|
|
||||||
resolveTitle,
|
resolveTitle,
|
||||||
convertToTask,
|
convertToTask,
|
||||||
convertToNote,
|
convertToNote,
|
||||||
|
|||||||
@@ -2,53 +2,15 @@ import { ref } from "vue";
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { apiGet, apiPost, apiPut, apiPatch, apiDelete } from "@/api/client";
|
import { apiGet, apiPost, apiPut, apiPatch, apiDelete } from "@/api/client";
|
||||||
import { useToastStore } from "@/stores/toast";
|
import { useToastStore } from "@/stores/toast";
|
||||||
import type { Task, TaskListResponse, TaskStatus, TaskPriority, StartPlanningResult } from "@/types/task";
|
import type { Task, TaskStatus, TaskPriority, StartPlanningResult } from "@/types/task";
|
||||||
|
|
||||||
|
// Single-task + mutation surface. The list/filter/sort/pagination surface that
|
||||||
|
// backed the removed /tasks list view was dropped in the 2026-06-02 drift-audit
|
||||||
|
// cleanup (no consumers — ProjectView's kanban keeps its own local task list).
|
||||||
export const useTasksStore = defineStore("tasks", () => {
|
export const useTasksStore = defineStore("tasks", () => {
|
||||||
const tasks = ref<Task[]>([]);
|
|
||||||
const currentTask = ref<Task | null>(null);
|
const currentTask = ref<Task | null>(null);
|
||||||
const total = ref(0);
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
// Filter / pagination / sort state
|
|
||||||
const activeTagFilters = ref<string[]>([]);
|
|
||||||
const statusFilter = ref<TaskStatus[]>([]);
|
|
||||||
const priorityFilter = ref<TaskPriority[]>([]);
|
|
||||||
const limit = ref(20);
|
|
||||||
const offset = ref(0);
|
|
||||||
const sortField = ref("updated_at");
|
|
||||||
const sortOrder = ref<"asc" | "desc">("desc");
|
|
||||||
const searchQuery = ref("");
|
|
||||||
|
|
||||||
async function refresh() {
|
|
||||||
loading.value = true;
|
|
||||||
try {
|
|
||||||
const searchParams = new URLSearchParams();
|
|
||||||
if (searchQuery.value) searchParams.set("q", searchQuery.value);
|
|
||||||
for (const t of activeTagFilters.value) {
|
|
||||||
searchParams.append("tag", t);
|
|
||||||
}
|
|
||||||
for (const s of statusFilter.value) searchParams.append("status", s);
|
|
||||||
for (const p of priorityFilter.value) searchParams.append("priority", p);
|
|
||||||
searchParams.set("sort", sortField.value);
|
|
||||||
searchParams.set("order", sortOrder.value);
|
|
||||||
searchParams.set("limit", String(limit.value));
|
|
||||||
searchParams.set("offset", String(offset.value));
|
|
||||||
|
|
||||||
const qs = searchParams.toString();
|
|
||||||
const data = await apiGet<TaskListResponse>(
|
|
||||||
`/api/tasks${qs ? `?${qs}` : ""}`
|
|
||||||
);
|
|
||||||
tasks.value = data.tasks;
|
|
||||||
total.value = data.total;
|
|
||||||
} catch (e) {
|
|
||||||
useToastStore().show("Failed to load tasks", "error");
|
|
||||||
throw e;
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchTask(id: number) {
|
async function fetchTask(id: number) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
@@ -102,10 +64,6 @@ export const useTasksStore = defineStore("tasks", () => {
|
|||||||
async function patchStatus(id: number, status: TaskStatus): Promise<Task> {
|
async function patchStatus(id: number, status: TaskStatus): Promise<Task> {
|
||||||
try {
|
try {
|
||||||
const task = await apiPatch<Task>(`/api/tasks/${id}/status`, { status });
|
const task = await apiPatch<Task>(`/api/tasks/${id}/status`, { status });
|
||||||
const idx = tasks.value.findIndex((t) => t.id === id);
|
|
||||||
if (idx !== -1) {
|
|
||||||
tasks.value[idx] = task;
|
|
||||||
}
|
|
||||||
if (currentTask.value?.id === id) {
|
if (currentTask.value?.id === id) {
|
||||||
currentTask.value = task;
|
currentTask.value = task;
|
||||||
}
|
}
|
||||||
@@ -119,7 +77,6 @@ export const useTasksStore = defineStore("tasks", () => {
|
|||||||
async function deleteTask(id: number) {
|
async function deleteTask(id: number) {
|
||||||
try {
|
try {
|
||||||
await apiDelete(`/api/tasks/${id}`);
|
await apiDelete(`/api/tasks/${id}`);
|
||||||
tasks.value = tasks.value.filter((t) => t.id !== id);
|
|
||||||
if (currentTask.value?.id === id) {
|
if (currentTask.value?.id === id) {
|
||||||
currentTask.value = null;
|
currentTask.value = null;
|
||||||
}
|
}
|
||||||
@@ -144,83 +101,14 @@ export const useTasksStore = defineStore("tasks", () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setStatusFilter(statuses: TaskStatus[]) {
|
|
||||||
statusFilter.value = statuses;
|
|
||||||
offset.value = 0;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setPriorityFilter(priorities: TaskPriority[]) {
|
|
||||||
priorityFilter.value = priorities;
|
|
||||||
offset.value = 0;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
function addTagFilter(tag: string) {
|
|
||||||
if (!activeTagFilters.value.includes(tag)) {
|
|
||||||
activeTagFilters.value.push(tag);
|
|
||||||
offset.value = 0;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeTagFilter(tag: string) {
|
|
||||||
activeTagFilters.value = activeTagFilters.value.filter((t) => t !== tag);
|
|
||||||
offset.value = 0;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearTagFilters() {
|
|
||||||
activeTagFilters.value = [];
|
|
||||||
offset.value = 0;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSort(field: string, order: "asc" | "desc") {
|
|
||||||
sortField.value = field;
|
|
||||||
sortOrder.value = order;
|
|
||||||
offset.value = 0;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setOffset(newOffset: number) {
|
|
||||||
offset.value = newOffset;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSearch(q: string) {
|
|
||||||
searchQuery.value = q;
|
|
||||||
offset.value = 0;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tasks,
|
|
||||||
currentTask,
|
currentTask,
|
||||||
total,
|
|
||||||
loading,
|
loading,
|
||||||
activeTagFilters,
|
|
||||||
statusFilter,
|
|
||||||
priorityFilter,
|
|
||||||
limit,
|
|
||||||
offset,
|
|
||||||
sortField,
|
|
||||||
sortOrder,
|
|
||||||
searchQuery,
|
|
||||||
refresh,
|
|
||||||
fetchTask,
|
fetchTask,
|
||||||
createTask,
|
createTask,
|
||||||
updateTask,
|
updateTask,
|
||||||
patchStatus,
|
patchStatus,
|
||||||
deleteTask,
|
deleteTask,
|
||||||
startPlanning,
|
startPlanning,
|
||||||
setStatusFilter,
|
|
||||||
setPriorityFilter,
|
|
||||||
addTagFilter,
|
|
||||||
removeTagFilter,
|
|
||||||
clearTagFilters,
|
|
||||||
setSort,
|
|
||||||
setOffset,
|
|
||||||
setSearch,
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
export interface GenerationTiming {
|
|
||||||
total_ms: number;
|
|
||||||
intent_ms: number | null;
|
|
||||||
ttft_ms: number | null;
|
|
||||||
generation_ms: number | null;
|
|
||||||
tools: Array<{ name: string; ms: number }>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ToolCallRecord {
|
|
||||||
function: string;
|
|
||||||
arguments: Record<string, unknown>;
|
|
||||||
result: { success: boolean; type?: string; data?: Record<string, unknown>; error?: string; suggested_tags?: string[]; requires_confirmation?: boolean; similar_note?: { id: number; title: string } };
|
|
||||||
status: "running" | "success" | "error" | "declined";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ToolPendingRecord {
|
|
||||||
function: string;
|
|
||||||
arguments: Record<string, unknown>;
|
|
||||||
label?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Message {
|
|
||||||
id: number;
|
|
||||||
conversation_id: number;
|
|
||||||
role: "system" | "user" | "assistant";
|
|
||||||
content: string;
|
|
||||||
status?: "complete" | "generating" | "error";
|
|
||||||
context_note_id: number | null;
|
|
||||||
context_note_title?: string | null;
|
|
||||||
tool_calls?: ToolCallRecord[] | null;
|
|
||||||
metadata?: Record<string, unknown> | null;
|
|
||||||
created_at: string;
|
|
||||||
timing?: GenerationTiming;
|
|
||||||
thinking?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SendMessageResponse {
|
|
||||||
assistant_message_id: number;
|
|
||||||
status: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Conversation {
|
|
||||||
id: number;
|
|
||||||
title: string;
|
|
||||||
model: string;
|
|
||||||
message_count: number;
|
|
||||||
rag_project_id: number | null;
|
|
||||||
created_at: string;
|
|
||||||
updated_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ConversationDetail extends Conversation {
|
|
||||||
messages: Message[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ContextMeta {
|
|
||||||
context_note_id: number | null;
|
|
||||||
context_note_title: string | null;
|
|
||||||
auto_notes: { id: number; title: string; score?: number | null; auto_injected?: boolean }[];
|
|
||||||
auto_injected_notes?: { id: number; title: string; score?: number | null }[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OllamaStatus {
|
|
||||||
ollama: "available" | "unavailable";
|
|
||||||
model: "loaded" | "cold" | "not_found";
|
|
||||||
default_model: string;
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
|
// Settings are free-form string key/value pairs keyed by setting name; the
|
||||||
|
// backend has no fixed schema, so this is an open string map. (The former
|
||||||
|
// assistant_name/default_model hints were dead after the Phase-8 chat removal.)
|
||||||
export interface AppSettings {
|
export interface AppSettings {
|
||||||
assistant_name?: string;
|
|
||||||
default_model?: string;
|
|
||||||
[key: string]: string | undefined;
|
[key: string]: string | undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,25 +14,10 @@ const toastStore = useToastStore();
|
|||||||
const userTimezone = ref("");
|
const userTimezone = ref("");
|
||||||
const savingTimezone = ref(false);
|
const savingTimezone = ref(false);
|
||||||
const timezoneSaved = ref(false);
|
const timezoneSaved = ref(false);
|
||||||
const autoConsolidateTasks = ref(true);
|
|
||||||
const savingAutoConsolidate = ref(false);
|
|
||||||
const trashRetentionDays = ref("90");
|
const trashRetentionDays = ref("90");
|
||||||
const savingRetention = ref(false);
|
const savingRetention = ref(false);
|
||||||
const retentionSaved = ref(false);
|
const retentionSaved = ref(false);
|
||||||
|
|
||||||
async function saveAutoConsolidate() {
|
|
||||||
savingAutoConsolidate.value = true;
|
|
||||||
try {
|
|
||||||
await apiPut('/api/settings', {
|
|
||||||
auto_consolidate_tasks: autoConsolidateTasks.value ? "true" : "false",
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
toastStore.show('Failed to save setting', 'error');
|
|
||||||
} finally {
|
|
||||||
savingAutoConsolidate.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// think_enabled setting removed 2026-05-23. The chat+curator architecture
|
// think_enabled setting removed 2026-05-23. The chat+curator architecture
|
||||||
// has tools=[] on the chat model; think on a no-tools conversational pass
|
// has tools=[] on the chat model; think on a no-tools conversational pass
|
||||||
// is pure latency cost. See generation_task.py:run_generation comment for
|
// is pure latency cost. See generation_task.py:run_generation comment for
|
||||||
@@ -403,8 +388,6 @@ onMounted(async () => {
|
|||||||
const allSettings = await apiGet<Record<string, string>>("/api/settings");
|
const allSettings = await apiGet<Record<string, string>>("/api/settings");
|
||||||
userTimezone.value = allSettings.user_timezone ?? "";
|
userTimezone.value = allSettings.user_timezone ?? "";
|
||||||
trashRetentionDays.value = allSettings.trash_retention_days ?? "90";
|
trashRetentionDays.value = allSettings.trash_retention_days ?? "90";
|
||||||
// Default true if unset; explicit "false" disables auto-consolidation.
|
|
||||||
autoConsolidateTasks.value = (allSettings.auto_consolidate_tasks ?? "true") !== "false";
|
|
||||||
if (allSettings.notify_task_reminders !== undefined) {
|
if (allSettings.notify_task_reminders !== undefined) {
|
||||||
notifyTaskReminders.value = allSettings.notify_task_reminders !== "false";
|
notifyTaskReminders.value = allSettings.notify_task_reminders !== "false";
|
||||||
}
|
}
|
||||||
@@ -992,29 +975,6 @@ function formatUserDate(iso: string): string {
|
|||||||
|
|
||||||
<!-- ── General ── -->
|
<!-- ── General ── -->
|
||||||
<div v-show="activeTab === 'general'" class="settings-grid">
|
<div v-show="activeTab === 'general'" class="settings-grid">
|
||||||
<!-- Tasks -->
|
|
||||||
<section class="settings-section full-width">
|
|
||||||
<h2>Tasks</h2>
|
|
||||||
<p class="section-desc">
|
|
||||||
Task bodies are auto-summarized from accumulated work logs. The summary runs every few logs, plus on task close.
|
|
||||||
</p>
|
|
||||||
<div class="field">
|
|
||||||
<label class="checkbox-label">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
v-model="autoConsolidateTasks"
|
|
||||||
:disabled="savingAutoConsolidate"
|
|
||||||
@change="saveAutoConsolidate"
|
|
||||||
/>
|
|
||||||
Auto-consolidate task bodies
|
|
||||||
</label>
|
|
||||||
<p class="field-hint">
|
|
||||||
When off, the task body is only refreshed when you click "Re-consolidate"
|
|
||||||
on a task. Existing summaries remain in place.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- Timezone -->
|
<!-- Timezone -->
|
||||||
<section class="settings-section full-width">
|
<section class="settings-section full-width">
|
||||||
<h2>Timezone</h2>
|
<h2>Timezone</h2>
|
||||||
|
|||||||
Reference in New Issue
Block a user