fix: Mobile responsiveness for Focus Tools & AI chat improvements
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
Mobile Responsiveness: - Fix headers on all Focus Tools pages (responsive text sizes, proper spacing) - Fix BodyDoublingLobby form grid (stacks on mobile) - Add shrink-0 and min-w-0 to prevent flex overflow issues AI Chat Improvements: - Add labelName parameter to createTask tool for easier label assignment - Auto-match or create labels when labelName is provided - Improve system prompt to act immediately without confirmation - Clearer instructions about using tools and handling labels - Better support for Ollama models with function calling
This commit is contained in:
@@ -134,13 +134,13 @@ export function BodyDoublingLobby() {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold flex items-center gap-2">
|
||||
<Users className="h-6 w-6 text-primary" />
|
||||
<h2 className="text-xl sm:text-2xl font-bold flex items-center gap-2">
|
||||
<Users className="h-5 w-5 sm:h-6 sm:w-6 text-primary" />
|
||||
{t('adhd.bodyDoubling.title')}
|
||||
</h2>
|
||||
<p className="text-muted-foreground">
|
||||
<p className="text-sm sm:text-base text-muted-foreground">
|
||||
{t('adhd.bodyDoubling.description')}
|
||||
</p>
|
||||
</div>
|
||||
@@ -190,7 +190,7 @@ export function BodyDoublingLobby() {
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<Label htmlFor="startsAt">{t('adhd.bodyDoubling.startTime')}</Label>
|
||||
<Input
|
||||
|
||||
@@ -80,21 +80,22 @@ export default function ADHDDashboardPage() {
|
||||
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto space-y-6">
|
||||
<div className="flex items-center gap-4 mb-6">
|
||||
<div className="flex items-center gap-3 sm:gap-4 mb-6">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setLocation('/')}
|
||||
className="shrink-0"
|
||||
>
|
||||
<ArrowLeft className="h-5 w-5" />
|
||||
</Button>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-3 rounded-xl bg-gradient-to-br from-purple-400 to-pink-500 text-white">
|
||||
<Brain className="h-6 w-6" />
|
||||
<div className="flex items-center gap-2 sm:gap-3 min-w-0">
|
||||
<div className="p-2 sm:p-3 rounded-xl bg-gradient-to-br from-purple-400 to-pink-500 text-white shrink-0">
|
||||
<Brain className="h-5 w-5 sm:h-6 sm:w-6" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold">{t('adhd.dashboard.title', 'ADHD Dashboard')}</h1>
|
||||
<p className="text-muted-foreground">{t('adhd.dashboard.subtitle', 'Tools designed for how your brain works')}</p>
|
||||
<div className="min-w-0">
|
||||
<h1 className="text-xl sm:text-2xl font-bold truncate">{t('adhd.dashboard.title', 'ADHD Dashboard')}</h1>
|
||||
<p className="text-sm sm:text-base text-muted-foreground truncate">{t('adhd.dashboard.subtitle', 'Tools designed for how your brain works')}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,21 +24,22 @@ export default function BodyDoublingPage() {
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto space-y-6">
|
||||
<div className="flex items-center gap-4 mb-6">
|
||||
<div className="flex items-center gap-3 sm:gap-4 mb-6">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setLocation('/')}
|
||||
className="shrink-0"
|
||||
>
|
||||
<ArrowLeft className="h-5 w-5" />
|
||||
</Button>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-3 rounded-xl bg-gradient-to-br from-green-400 to-teal-500 text-white">
|
||||
<Users className="h-6 w-6" />
|
||||
<div className="flex items-center gap-2 sm:gap-3 min-w-0">
|
||||
<div className="p-2 sm:p-3 rounded-xl bg-gradient-to-br from-green-400 to-teal-500 text-white shrink-0">
|
||||
<Users className="h-5 w-5 sm:h-6 sm:w-6" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold">{t('adhd.bodyDoubling.title')}</h1>
|
||||
<p className="text-muted-foreground">{t('adhd.bodyDoubling.description')}</p>
|
||||
<div className="min-w-0">
|
||||
<h1 className="text-xl sm:text-2xl font-bold">{t('adhd.bodyDoubling.title')}</h1>
|
||||
<p className="text-sm sm:text-base text-muted-foreground">{t('adhd.bodyDoubling.description')}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -28,21 +28,22 @@ export default function QuickWinsPage() {
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto space-y-6">
|
||||
<div className="flex items-center gap-4 mb-6">
|
||||
<div className="flex items-center gap-3 sm:gap-4 mb-6">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setLocation('/')}
|
||||
className="shrink-0"
|
||||
>
|
||||
<ArrowLeft className="h-5 w-5" />
|
||||
</Button>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-3 rounded-xl bg-gradient-to-br from-yellow-400 to-orange-500 text-white">
|
||||
<Zap className="h-6 w-6" />
|
||||
<div className="flex items-center gap-2 sm:gap-3 min-w-0">
|
||||
<div className="p-2 sm:p-3 rounded-xl bg-gradient-to-br from-yellow-400 to-orange-500 text-white shrink-0">
|
||||
<Zap className="h-5 w-5 sm:h-6 sm:w-6" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold">{t('adhd.quickWins.title')}</h1>
|
||||
<p className="text-muted-foreground">{t('adhd.quickWins.description')}</p>
|
||||
<div className="min-w-0">
|
||||
<h1 className="text-xl sm:text-2xl font-bold">{t('adhd.quickWins.title')}</h1>
|
||||
<p className="text-sm sm:text-base text-muted-foreground">{t('adhd.quickWins.description')}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -54,21 +54,22 @@ export default function SingleTaskPage() {
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto space-y-6">
|
||||
<div className="flex items-center gap-4 mb-6">
|
||||
<div className="flex items-center gap-3 sm:gap-4 mb-6">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setLocation('/')}
|
||||
className="shrink-0"
|
||||
>
|
||||
<ArrowLeft className="h-5 w-5" />
|
||||
</Button>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-3 rounded-xl bg-gradient-to-br from-blue-400 to-indigo-500 text-white">
|
||||
<Focus className="h-6 w-6" />
|
||||
<div className="flex items-center gap-2 sm:gap-3 min-w-0">
|
||||
<div className="p-2 sm:p-3 rounded-xl bg-gradient-to-br from-blue-400 to-indigo-500 text-white shrink-0">
|
||||
<Focus className="h-5 w-5 sm:h-6 sm:w-6" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold">{t('adhd.singleTask.title')}</h1>
|
||||
<p className="text-muted-foreground">{t('adhd.singleTask.description')}</p>
|
||||
<div className="min-w-0">
|
||||
<h1 className="text-xl sm:text-2xl font-bold">{t('adhd.singleTask.title')}</h1>
|
||||
<p className="text-sm sm:text-base text-muted-foreground">{t('adhd.singleTask.description')}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { chromium } from '@playwright/test';
|
||||
|
||||
async function openBrowser() {
|
||||
const browser = await chromium.launch({
|
||||
headless: false,
|
||||
slowMo: 100
|
||||
});
|
||||
|
||||
const context = await browser.newContext();
|
||||
const page = await context.newPage();
|
||||
|
||||
// Navigate to app
|
||||
await page.goto('http://localhost:2100');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Check if we need to login
|
||||
const loginInput = page.locator('input[name="username"]');
|
||||
if (await loginInput.isVisible({ timeout: 3000 }).catch(() => false)) {
|
||||
console.log('Logging in as admin...');
|
||||
await page.fill('input[name="username"]', 'admin');
|
||||
await page.fill('input[name="password"]', 'admin');
|
||||
await page.click('button[type="submit"]');
|
||||
await page.waitForTimeout(2000);
|
||||
console.log('Logged in! Browser is open.');
|
||||
} else {
|
||||
console.log('Already logged in or different page. Browser is open.');
|
||||
}
|
||||
|
||||
// Keep browser open
|
||||
console.log('Press Ctrl+C to close the browser.');
|
||||
await new Promise(() => {}); // Keep running indefinitely
|
||||
}
|
||||
|
||||
openBrowser().catch(console.error);
|
||||
Generated
+2376
-1845
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './tests',
|
||||
fullyParallel: false,
|
||||
forbidOnly: !!process.env.CI,
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
workers: 1,
|
||||
reporter: 'list',
|
||||
use: {
|
||||
baseURL: 'http://localhost:2100',
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
],
|
||||
timeout: 120000,
|
||||
});
|
||||
+55
-14
@@ -60,15 +60,26 @@ Answer the user's questions based on this context. Be concise, helpful, and frie
|
||||
### 🛠️ AVAILABLE TOOLS
|
||||
You can create, search, update, and delete tasks using the provided tools.
|
||||
|
||||
**CRITICAL: ALWAYS USE TOOLS IMMEDIATELY**
|
||||
- When the user asks to create a task, IMMEDIATELY call createTask - DO NOT ask for confirmation.
|
||||
- When the user provides multiple tasks, call createTask for EACH task in parallel.
|
||||
- Never say "I will create..." or "Should I create..." - just DO IT.
|
||||
|
||||
**1. Task Management**
|
||||
- **Create**: Use 'createTask'. Title is required.
|
||||
- *Labels*: Use 'labelName' parameter with the label text (e.g., "Work", "Personal", "Shopping"). The system will automatically match or create the label.
|
||||
- *Bulk Creation*: If the user provides a list of tasks, call 'createTask' multiple times in parallel.
|
||||
- *Relative Dates*: Understand natural language! "Morgen" = Tomorrow, "Next Friday" = Date of next Friday. Always calculate the specific ISO string based on 'Current Date/Time'.
|
||||
- *Priority*: Infer priority from context. Urgent/important = high, regular = medium, minor = low.
|
||||
- *Returns*: The tool returns the created Task ID. Remember this ID for immediate edits.
|
||||
- **Update/Delete**: First SEARCH for the task ID using 'searchTasks' (search by title), then use 'updateTask' or 'deleteTask'.
|
||||
- *Editing Recently Created*: If the user says "Change that to...", refer to the ID of the task you just created.
|
||||
- *Delete All*: Search all, then delete each.
|
||||
- **Labels**: Use 'getLabels' tags.
|
||||
|
||||
### 🏷️ LABEL RULES
|
||||
- When the user mentions a category like "Work task", "Personal errand", "Shopping item" - use the labelName parameter.
|
||||
- Common labels: Work, Personal, Shopping, Health, Finance, Home, Family, Study
|
||||
- The system automatically matches existing labels or creates new ones.
|
||||
|
||||
### 🛡️ SAFETY RULES
|
||||
- **DELETION CONFIRMATION**: Before using 'deleteTask', you MUST:
|
||||
@@ -89,10 +100,12 @@ You can create, search, update, and delete tasks using the provided tools.
|
||||
### 📅 DATE & TIME RULES
|
||||
- **"Today"**: Use the 'Current Date/Time' context.
|
||||
- **"Morgen" / "Tomorrow"**: Add 1 day to Current Date.
|
||||
- **"Next week"**: Add 7 days to Current Date.
|
||||
- **Scheduling**: When using 'scheduleTask', inform the user specifically *when* you scheduled it.
|
||||
|
||||
|
||||
IMPORTANT: Do NOT show Task IDs to the user. Reference tasks by Title.
|
||||
CRITICAL: After executing tools, provide a concise summary of your actions.`;
|
||||
CRITICAL: After executing tools, provide a concise summary of your actions.
|
||||
CRITICAL: ACT IMMEDIATELY. Do not ask for confirmation before creating tasks.`;
|
||||
}
|
||||
|
||||
// Variable replacement if using stored template
|
||||
@@ -311,19 +324,20 @@ CRITICAL: After executing tools, provide a concise summary of your actions.`;
|
||||
type: "function",
|
||||
function: {
|
||||
name: "createTask",
|
||||
description: "Create a new task for the user.",
|
||||
description: "Create a new task for the user. ALWAYS call this tool immediately when the user asks to create a task - do not ask for confirmation first.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
title: { type: "string", description: "The title of the task (required)." },
|
||||
description: { type: "string" },
|
||||
priority: { type: "string", enum: ["low", "medium", "high"] },
|
||||
status: { type: "string", enum: ["todo", "inProgress", "done"] },
|
||||
dueDate: { type: "string", description: "ISO 8601 format (YYYY-MM-DD)." },
|
||||
labelId: { type: "string" },
|
||||
description: { type: "string", description: "Optional task description." },
|
||||
priority: { type: "string", enum: ["low", "medium", "high"], description: "Task priority. Default: medium." },
|
||||
status: { type: "string", enum: ["todo", "inProgress", "done"], description: "Task status. Default: todo." },
|
||||
dueDate: { type: "string", description: "Due date in ISO 8601 format (YYYY-MM-DD). Calculate from relative dates like 'tomorrow', 'next week'." },
|
||||
labelId: { type: "string", description: "The label ID (UUID). Use getLabels first to find the correct ID." },
|
||||
labelName: { type: "string", description: "Alternative: Label name (e.g., 'Work', 'Personal'). Will be matched or created automatically." },
|
||||
estimatedDuration: { type: "integer", description: "Estimated duration in minutes." },
|
||||
parentTaskId: { type: "string" },
|
||||
startDate: { type: "string" }
|
||||
parentTaskId: { type: "string", description: "Parent task ID for subtasks." },
|
||||
startDate: { type: "string", description: "Start date in ISO 8601 format." }
|
||||
},
|
||||
required: ["title"]
|
||||
}
|
||||
@@ -523,13 +537,40 @@ CRITICAL: After executing tools, provide a concise summary of your actions.`;
|
||||
result = { success: true, labelId: newLabel.id, message: "Label created." };
|
||||
}
|
||||
} else if (fnName === "createTask") {
|
||||
// Handle labelName -> labelId conversion
|
||||
let resolvedLabelId = args.labelId || null;
|
||||
let labelMessage = "";
|
||||
|
||||
if (!resolvedLabelId && args.labelName) {
|
||||
const labels = await this.storage.getLabels(user.id);
|
||||
const matchedLabel = labels.find(l =>
|
||||
l.name.toLowerCase() === args.labelName.toLowerCase() ||
|
||||
l.name.toLowerCase().includes(args.labelName.toLowerCase()) ||
|
||||
args.labelName.toLowerCase().includes(l.name.toLowerCase())
|
||||
);
|
||||
|
||||
if (matchedLabel) {
|
||||
resolvedLabelId = matchedLabel.id;
|
||||
labelMessage = ` with label "${matchedLabel.name}"`;
|
||||
} else {
|
||||
// Create new label if not found
|
||||
const newLabel = await this.storage.createLabel({
|
||||
name: args.labelName,
|
||||
color: "#6366f1",
|
||||
creatorId: user.id
|
||||
});
|
||||
resolvedLabelId = newLabel.id;
|
||||
labelMessage = ` with new label "${args.labelName}"`;
|
||||
}
|
||||
}
|
||||
|
||||
const taskData = {
|
||||
title: args.title,
|
||||
description: args.description || null,
|
||||
priority: args.priority || "medium",
|
||||
status: args.status || "todo",
|
||||
dueDate: args.dueDate ? new Date(args.dueDate) : null,
|
||||
labelId: args.labelId || null,
|
||||
labelId: resolvedLabelId,
|
||||
estimatedDuration: args.estimatedDuration || null,
|
||||
parentTaskId: args.parentTaskId || null,
|
||||
startDate: args.startDate ? new Date(args.startDate) : null,
|
||||
@@ -541,10 +582,10 @@ CRITICAL: After executing tools, provide a concise summary of your actions.`;
|
||||
action: "CREATE",
|
||||
entityType: "TASK",
|
||||
entityId: createdTask.id,
|
||||
details: { title: createdTask.title },
|
||||
details: { title: createdTask.title, labelId: resolvedLabelId },
|
||||
source: "AI"
|
||||
});
|
||||
result = { success: true, taskId: createdTask.id, message: "Task created." };
|
||||
result = { success: true, taskId: createdTask.id, message: `Task created${labelMessage}.` };
|
||||
} else if (fnName === "searchTasks") {
|
||||
const tasks = await this.storage.searchTasks(args.query, user.id);
|
||||
const labels = await this.storage.getLabels(user.id);
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
{
|
||||
"status": "failed",
|
||||
"failedTests": [
|
||||
"5e4c35f9f3e132884f88-fffc858497b1fef540d4"
|
||||
]
|
||||
"failedTests": []
|
||||
}
|
||||
-324
@@ -1,324 +0,0 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e6]:
|
||||
- list [ref=e8]:
|
||||
- listitem [ref=e9]:
|
||||
- button "Logo TaskFlow Personal" [ref=e10] [cursor=pointer]:
|
||||
- img "Logo" [ref=e12]
|
||||
- generic [ref=e13]:
|
||||
- generic [ref=e14]: TaskFlow
|
||||
- generic [ref=e15]: Personal
|
||||
- list [ref=e17]:
|
||||
- listitem [ref=e18]:
|
||||
- button "Focus" [ref=e19] [cursor=pointer]:
|
||||
- img [ref=e20]
|
||||
- generic [ref=e24]: Focus
|
||||
- listitem [ref=e25]:
|
||||
- button "Tasks" [ref=e26] [cursor=pointer]:
|
||||
- img [ref=e27]
|
||||
- generic [ref=e30]: Tasks
|
||||
- listitem [ref=e31]:
|
||||
- button "Calendar" [ref=e32] [cursor=pointer]:
|
||||
- img [ref=e33]
|
||||
- generic [ref=e35]: Calendar
|
||||
- listitem [ref=e36]:
|
||||
- button "Week" [ref=e37] [cursor=pointer]:
|
||||
- img [ref=e38]
|
||||
- generic [ref=e39]: Week
|
||||
- listitem [ref=e40]:
|
||||
- button "Unscheduled Tasks" [ref=e41] [cursor=pointer]:
|
||||
- img [ref=e42]
|
||||
- generic [ref=e46]: Unscheduled Tasks
|
||||
- listitem [ref=e47]:
|
||||
- button "Kanban" [ref=e48] [cursor=pointer]:
|
||||
- img [ref=e49]
|
||||
- generic [ref=e54]: Kanban
|
||||
- listitem [ref=e55]:
|
||||
- button "Achievements" [ref=e56] [cursor=pointer]:
|
||||
- img [ref=e57]
|
||||
- generic [ref=e63]: Achievements
|
||||
- listitem [ref=e64]:
|
||||
- button "Leaderboard" [ref=e65] [cursor=pointer]:
|
||||
- img [ref=e66]
|
||||
- generic [ref=e69]: Leaderboard
|
||||
- listitem [ref=e70]:
|
||||
- button "AI Chat" [ref=e71] [cursor=pointer]:
|
||||
- img [ref=e72]
|
||||
- generic [ref=e75]: AI Chat
|
||||
- listitem [ref=e76]:
|
||||
- button "Settings" [ref=e77] [cursor=pointer]:
|
||||
- img [ref=e78]
|
||||
- generic [ref=e81]: Settings
|
||||
- generic [ref=e82]:
|
||||
- generic [ref=e83] [cursor=pointer]:
|
||||
- generic [ref=e84]:
|
||||
- generic [ref=e85]:
|
||||
- img [ref=e87]
|
||||
- generic [ref=e93]:
|
||||
- text: Level 4
|
||||
- generic [ref=e94]: Artisan
|
||||
- generic [ref=e95]:
|
||||
- img [ref=e96]
|
||||
- generic [ref=e98]: "2"
|
||||
- generic [ref=e99]:
|
||||
- generic [ref=e100]:
|
||||
- generic [ref=e101]: 884 XP
|
||||
- generic [ref=e102]: 1000 XP
|
||||
- progressbar [ref=e103]
|
||||
- generic [ref=e105]:
|
||||
- button "theme.light" [ref=e107] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e108]: theme.light
|
||||
- button "Notifications" [ref=e110] [cursor=pointer]:
|
||||
- img
|
||||
- button "Logout" [ref=e112] [cursor=pointer]:
|
||||
- img
|
||||
- button "Toggle Sidebar" [ref=e114] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e115]: Toggle Sidebar
|
||||
- button "Toggle Sidebar" [ref=e116] [cursor=pointer]
|
||||
- main [ref=e117]:
|
||||
- generic [ref=e118]:
|
||||
- main [ref=e119]:
|
||||
- generic [ref=e120]:
|
||||
- heading "Settings" [level=1] [ref=e122]
|
||||
- generic [ref=e123]:
|
||||
- generic [ref=e124]:
|
||||
- generic [ref=e125]:
|
||||
- img [ref=e126]
|
||||
- text: Account
|
||||
- generic [ref=e129]: Manage your account settings
|
||||
- generic [ref=e130]:
|
||||
- generic [ref=e131]:
|
||||
- paragraph [ref=e132]: Username
|
||||
- paragraph [ref=e133]: admin
|
||||
- generic [ref=e134]:
|
||||
- paragraph [ref=e135]: Email
|
||||
- generic [ref=e136]:
|
||||
- paragraph [ref=e137]: admin@example.com
|
||||
- button [ref=e138] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e139]:
|
||||
- paragraph [ref=e140]: User ID
|
||||
- paragraph [ref=e141]: 3aa35824-197c-43d2-bdde-3fbe0bdc0d4b
|
||||
- button "Change Password" [ref=e143] [cursor=pointer]
|
||||
- generic [ref=e144]:
|
||||
- generic [ref=e145]:
|
||||
- generic [ref=e146]:
|
||||
- img [ref=e147]
|
||||
- text: Notifications
|
||||
- generic [ref=e150]: Get alerted about upcoming and overdue tasks.
|
||||
- generic [ref=e152]:
|
||||
- generic [ref=e153]:
|
||||
- paragraph [ref=e154]: Enable Browser Notifications
|
||||
- paragraph [ref=e155]: Permission denied by browser. Please reset site permissions.
|
||||
- switch [disabled] [ref=e156]
|
||||
- generic [ref=e157]:
|
||||
- generic [ref=e158]:
|
||||
- generic [ref=e159]:
|
||||
- img [ref=e160]
|
||||
- text: Social & Privacy
|
||||
- generic [ref=e163]: Manage your visibility and social features
|
||||
- generic [ref=e164]:
|
||||
- generic [ref=e165]:
|
||||
- generic [ref=e166]:
|
||||
- paragraph [ref=e167]: Public Leaderboard
|
||||
- paragraph [ref=e168]: Show my profile on the global leaderboard
|
||||
- switch [ref=e169] [cursor=pointer]
|
||||
- generic [ref=e170]:
|
||||
- generic [ref=e171]:
|
||||
- paragraph [ref=e172]: Allow others to find me
|
||||
- paragraph [ref=e173]: Allow users to search for me to share tasks
|
||||
- switch [ref=e174] [cursor=pointer]
|
||||
- generic [ref=e175]:
|
||||
- generic [ref=e176]:
|
||||
- paragraph [ref=e177]: Enable AI Assistant
|
||||
- paragraph [ref=e178]: Allow the AI assistant to help you with tasks and organization.
|
||||
- switch [checked] [ref=e179] [cursor=pointer]
|
||||
- generic [ref=e180]:
|
||||
- generic [ref=e181]:
|
||||
- paragraph [ref=e182]: Two-Factor Authentication
|
||||
- paragraph [ref=e183]: Secure your account with email-based 2FA
|
||||
- switch [ref=e184] [cursor=pointer]
|
||||
- button "Share access to all tasks..." [ref=e186] [cursor=pointer]:
|
||||
- img
|
||||
- text: Share access to all tasks...
|
||||
- generic [ref=e187]:
|
||||
- generic [ref=e188]:
|
||||
- generic [ref=e189]:
|
||||
- img [ref=e190]
|
||||
- text: Language
|
||||
- generic [ref=e193]: Choose your preferred language
|
||||
- combobox [ref=e195] [cursor=pointer]:
|
||||
- generic: English
|
||||
- img [ref=e196]
|
||||
- generic [ref=e198]:
|
||||
- generic [ref=e200]:
|
||||
- generic [ref=e201]:
|
||||
- generic [ref=e202]:
|
||||
- img [ref=e203]
|
||||
- text: Task Labels
|
||||
- generic [ref=e206]: Create and manage labels to organize your tasks
|
||||
- button "Create Label" [ref=e207] [cursor=pointer]:
|
||||
- img
|
||||
- text: Create Label
|
||||
- generic [ref=e209]:
|
||||
- generic [ref=e211]:
|
||||
- generic [ref=e214]: Work
|
||||
- generic [ref=e215]:
|
||||
- button [ref=e216] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e217] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e219]:
|
||||
- generic [ref=e222]: Personal
|
||||
- generic [ref=e223]:
|
||||
- button [ref=e224] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e225] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e227]:
|
||||
- generic [ref=e230]: Urgent
|
||||
- generic [ref=e231]:
|
||||
- button [ref=e232] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e233] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e235]:
|
||||
- generic [ref=e238]: Study
|
||||
- generic [ref=e239]:
|
||||
- button [ref=e240] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e241] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e243]:
|
||||
- generic [ref=e246]: DockerTestLabel
|
||||
- generic [ref=e247]:
|
||||
- button [ref=e248] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e249] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e251]:
|
||||
- generic [ref=e254]: DockerTestLabel
|
||||
- generic [ref=e255]:
|
||||
- button "Share Label" [ref=e256] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e257] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e258] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e260]:
|
||||
- generic [ref=e263]: DockerFinalLabel
|
||||
- generic [ref=e264]:
|
||||
- button "Share Label" [ref=e265] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e266] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e267] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e269]:
|
||||
- generic [ref=e272]: Work
|
||||
- generic [ref=e273]:
|
||||
- button "Share Label" [ref=e274] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e275] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e276] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e278]:
|
||||
- generic [ref=e281]: Personal
|
||||
- generic [ref=e282]:
|
||||
- button "Share Label" [ref=e283] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e284] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e285] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e287]:
|
||||
- generic [ref=e290]: Work
|
||||
- generic [ref=e291]:
|
||||
- button "Share Label" [ref=e292] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e293] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e294] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e296]:
|
||||
- generic [ref=e299]: Personal
|
||||
- generic [ref=e300]:
|
||||
- button "Share Label" [ref=e301] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e302] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e303] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e305]:
|
||||
- generic [ref=e308]: Work
|
||||
- generic [ref=e309]:
|
||||
- button "Share Label" [ref=e310] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e311] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e312] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e314]:
|
||||
- generic [ref=e317]: Personal
|
||||
- generic [ref=e318]:
|
||||
- button "Share Label" [ref=e319] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e320] [cursor=pointer]:
|
||||
- img
|
||||
- button [ref=e321] [cursor=pointer]:
|
||||
- img
|
||||
- generic [ref=e322]:
|
||||
- generic [ref=e323]:
|
||||
- generic [ref=e324]:
|
||||
- img [ref=e325]
|
||||
- text: Project Templates
|
||||
- generic [ref=e329]: Use templates to quickly create projects
|
||||
- button "Manage Templates" [ref=e331] [cursor=pointer]:
|
||||
- img
|
||||
- text: Manage Templates
|
||||
- generic [ref=e332]:
|
||||
- generic [ref=e333]:
|
||||
- generic [ref=e334]:
|
||||
- img [ref=e335]
|
||||
- text: Data Export
|
||||
- generic [ref=e340]: Download your data as a JSON file.
|
||||
- generic [ref=e341]:
|
||||
- generic [ref=e342]:
|
||||
- checkbox "Tasks" [checked] [ref=e343] [cursor=pointer]:
|
||||
- generic:
|
||||
- img
|
||||
- generic [ref=e344]: Tasks
|
||||
- generic [ref=e345]:
|
||||
- checkbox "Labels" [checked] [ref=e346] [cursor=pointer]:
|
||||
- generic:
|
||||
- img
|
||||
- generic [ref=e347]: Labels
|
||||
- generic [ref=e348]:
|
||||
- checkbox "System Settings (Admin)" [ref=e349] [cursor=pointer]
|
||||
- generic [ref=e350]: System Settings (Admin)
|
||||
- button "Export Data" [ref=e352] [cursor=pointer]:
|
||||
- img
|
||||
- text: Export Data
|
||||
- generic [ref=e353]:
|
||||
- generic [ref=e354]:
|
||||
- generic [ref=e355]:
|
||||
- img [ref=e356]
|
||||
- text: Admin Settings
|
||||
- generic [ref=e359]: System administration and configuration
|
||||
- generic [ref=e360]:
|
||||
- button "Manage Users" [ref=e361] [cursor=pointer]:
|
||||
- img
|
||||
- text: Manage Users
|
||||
- button "System Settings (AI/SMTP)" [ref=e362] [cursor=pointer]:
|
||||
- img
|
||||
- text: System Settings (AI/SMTP)
|
||||
- button [ref=e364] [cursor=pointer]:
|
||||
- img
|
||||
- region "Notifications (F8)":
|
||||
- list
|
||||
```
|
||||
Reference in New Issue
Block a user