diff --git a/extensions/vikunja/CHANGELOG.md b/extensions/vikunja/CHANGELOG.md index 62a7b7f0459..e6e6bbf7ecd 100644 --- a/extensions/vikunja/CHANGELOG.md +++ b/extensions/vikunja/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [Create Task Quick Action & Preselect Project] - 2026-04-22 + +- Added Cmd+N / Create Task action in the `List Tasks` view and in each task's action panel to quickly create a new task. +- When creating a task from a project context (either the currently selected project in `List Tasks` or via a task's action), the `Create Task` form is opened with that project preselected. +- `create-task` now accepts an optional `projectId` argument and also respects `launchContext.projectId` for compatibility. + +## [Default Project Preference] - 2026-04-19 + +- Add optional "Default Project" Raycast preference (`defaultProject`) to set the initial project shown in List Tasks (use "all" or a project id). +- `List Tasks` now respects the preference when opened without a launch context; explicit launch context `projectId` still takes precedence. +- Updated generated preference types and manifest to include the setting. + ## [Task Detail View, Search, and Caching] - 2026-03-25 - Task Detail view with full markdown description and metadata sidebar diff --git a/extensions/vikunja/package.json b/extensions/vikunja/package.json index dc6c7eaa715..187c77c93d5 100644 --- a/extensions/vikunja/package.json +++ b/extensions/vikunja/package.json @@ -5,6 +5,9 @@ "description": "Create and manage tasks in your self-hosted Vikunja instance", "icon": "command-icon.png", "author": "flexorflex", + "contributors": [ + "strikerlulu" + ], "categories": [ "Productivity" ], @@ -22,6 +25,12 @@ "placeholder": "Task title", "type": "text", "required": false + }, + { + "name": "projectId", + "placeholder": "Project ID (optional)", + "type": "text", + "required": false } ] }, @@ -62,6 +71,14 @@ "description": "Vikunja API token for authentication", "type": "password", "required": true + }, + { + "name": "defaultProject", + "title": "Default Project", + "description": "Default project ID to show in List Tasks. Use \"all\" to show all projects.", + "type": "textfield", + "required": false, + "placeholder": "all" } ], "dependencies": { diff --git a/extensions/vikunja/raycast-env.d.ts b/extensions/vikunja/raycast-env.d.ts deleted file mode 100644 index 3091d10074f..00000000000 --- a/extensions/vikunja/raycast-env.d.ts +++ /dev/null @@ -1,44 +0,0 @@ -/// - -/* 🚧 🚧 🚧 - * This file is auto-generated from the extension's manifest. - * Do not modify manually. Instead, update the `package.json` file. - * 🚧 🚧 🚧 */ - -/* eslint-disable @typescript-eslint/ban-types */ - -type ExtensionPreferences = { - /** Vikunja URL - Base URL of your Vikunja instance (e.g. https://tasks.example.com) */ - "apiUrl": string, - /** API Token - Vikunja API token for authentication */ - "apiToken": string -} - -/** Preferences accessible in all the extension's commands */ -declare type Preferences = ExtensionPreferences - -declare namespace Preferences { - /** Preferences accessible in the `create-task` command */ - export type CreateTask = ExtensionPreferences & {} - /** Preferences accessible in the `list-tasks` command */ - export type ListTasks = ExtensionPreferences & {} - /** Preferences accessible in the `list-projects` command */ - export type ListProjects = ExtensionPreferences & {} - /** Preferences accessible in the `search-tasks` command */ - export type SearchTasks = ExtensionPreferences & {} -} - -declare namespace Arguments { - /** Arguments passed to the `create-task` command */ - export type CreateTask = { - /** Task title */ - "title": string -} - /** Arguments passed to the `list-tasks` command */ - export type ListTasks = {} - /** Arguments passed to the `list-projects` command */ - export type ListProjects = {} - /** Arguments passed to the `search-tasks` command */ - export type SearchTasks = {} -} - diff --git a/extensions/vikunja/src/components/task-list-item.tsx b/extensions/vikunja/src/components/task-list-item.tsx index 55c03936a39..35abc7d5afd 100644 --- a/extensions/vikunja/src/components/task-list-item.tsx +++ b/extensions/vikunja/src/components/task-list-item.tsx @@ -7,6 +7,8 @@ import { showToast, Toast, useNavigation, + launchCommand, + LaunchType, } from "@raycast/api"; import { updateTask, Project, Task } from "../api"; import { formatDueDate, dueDateColor } from "../helpers/dates"; @@ -118,6 +120,25 @@ export function TaskActions({ return ( + { + try { + await launchCommand({ + name: "create-task", + type: LaunchType.UserInitiated, + arguments: { projectId: String(task.project_id) }, + }); + } catch { + showToast({ + style: Toast.Style.Failure, + title: "Failed to launch Create Task", + }); + } + }} + /> {onShowDetail && ( , + props: LaunchProps<{ + arguments: Arguments.CreateTask; + launchContext?: { projectId?: number }; + }>, ) { const [projects, setProjects] = useState([]); const [labels, setLabels] = useState([]); @@ -32,6 +35,11 @@ export default function CreateTask( const argTitle = props.arguments.title?.trim() ?? ""; const [prefillTitle, setPrefillTitle] = useState(argTitle); const [prefillReady, setPrefillReady] = useState(!!argTitle); + // Prefer projectId passed as a command argument, fallback to launch context if present + const argProjectId = props.arguments.projectId?.trim(); + const contextProjectId = argProjectId + ? parseInt(argProjectId) + : props.launchContext?.projectId; useEffect(() => { async function loadData() { @@ -175,7 +183,17 @@ export default function CreateTask( title="Description" placeholder="Optional description" /> - + {projects.map((project) => ( , ) { const initialProjectId = props.launchContext?.projectId; + const { defaultProject } = getPreferenceValues(); + const defaultPref = defaultProject ?? "all"; const [selectedProject, setSelectedProject] = useState( - initialProjectId ? String(initialProjectId) : "all", + initialProjectId ? String(initialProjectId) : defaultPref, ); const baseUrl = useMemo(() => { @@ -116,6 +122,36 @@ export default function ListTasks( return ( + { + try { + if (selectedProject && selectedProject !== "all") { + await launchCommand({ + name: "create-task", + type: LaunchType.UserInitiated, + arguments: { projectId: String(selectedProject) }, + }); + } else { + await launchCommand({ + name: "create-task", + type: LaunchType.UserInitiated, + }); + } + } catch { + showToast({ + style: Toast.Style.Failure, + title: "Failed to launch Create Task", + }); + } + }} + /> + + } searchBarAccessory={