Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/console/src/_locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -766,22 +766,22 @@
"timeEstimate": { "label": "Time estimate" },
"deadline": { "label": "Deadline" }
},
"states": { "todo": "To do", "inProgress": "In progress", "done": "Done" },
"states": { "backlog": "Backlog", "todo": "To do", "inProgress": "In progress", "done": "Done", "canceled": "Canceled", "duplicate": "Duplicate" },
"priorities": { "urgent": "Urgent", "high": "High", "medium": "Medium", "low": "Low" },
"messages": { "created": "Task created successfully.", "updated": "Task updated successfully." },
"errors": { "create": "Failed to create task", "update": "Failed to update task" },
"actions": { "create": "Create task", "update": "Update task" }
},
"tasksCard": {
"states": { "all": "All", "todo": "To do", "inProgress": "In progress", "done": "Done" },
"states": { "all": "All", "backlog": "Backlog", "todo": "To do", "inProgress": "In progress", "done": "Done", "canceled": "Canceled", "duplicate": "Duplicate" },
"empty": "No tasks",
"error": { "title": "Error", "reorder": "Failed to reorder task." },
"dragInstructions": {
"all": "Drag and drop to reorder tasks or move them between states",
"state": "Drag and drop to reorder tasks"
},
"deleteConfirmation": "Are you sure you want to delete this task?",
"actions": { "moveToInProgress": "Move to In progress", "moveToDone": "Move to Done", "edit": "Edit", "delete": "Delete" }
"actions": { "moveToTodo": "Move to To do", "moveToInProgress": "Move to In progress", "moveToDone": "Move to Done", "edit": "Edit", "delete": "Delete" }
},
"deleteTrustCenterReferenceDialog": {
"title": "Delete Reference",
Expand Down
11 changes: 9 additions & 2 deletions apps/console/src/_locales/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -1297,7 +1297,10 @@
"states": {
"todo": "À faire",
"inProgress": "En cours",
"done": "Terminé"
"done": "Terminé",
"backlog": "Backlog",
"canceled": "Annulé",
"duplicate": "Doublon"
},
"priorities": {
"urgent": "Urgente",
Expand All @@ -1323,7 +1326,10 @@
"all": "Toutes",
"todo": "À faire",
"inProgress": "En cours",
"done": "Terminé"
"done": "Terminé",
"backlog": "Backlog",
"canceled": "Annulé",
"duplicate": "Doublon"
},
"empty": "Aucune tâche",
"error": {
Expand All @@ -1336,6 +1342,7 @@
},
"deleteConfirmation": "Voulez-vous vraiment supprimer cette tâche ?",
"actions": {
"moveToTodo": "Déplacer vers À faire",
"moveToInProgress": "Déplacer vers En cours",
"moveToDone": "Déplacer vers Terminé",
"edit": "Modifier",
Expand Down
11 changes: 9 additions & 2 deletions apps/console/src/_locales/nl-NL.json
Original file line number Diff line number Diff line change
Expand Up @@ -1297,7 +1297,10 @@
"states": {
"todo": "Te doen",
"inProgress": "In uitvoering",
"done": "Voltooid"
"done": "Voltooid",
"backlog": "Backlog",
"canceled": "Geannuleerd",
"duplicate": "Duplicaat"
},
"priorities": {
"urgent": "Urgent",
Expand All @@ -1323,7 +1326,10 @@
"all": "Alle",
"todo": "Te doen",
"inProgress": "In uitvoering",
"done": "Voltooid"
"done": "Voltooid",
"backlog": "Backlog",
"canceled": "Geannuleerd",
"duplicate": "Duplicaat"
},
"empty": "Geen taken",
"error": {
Expand All @@ -1336,6 +1342,7 @@
},
"deleteConfirmation": "Weet u zeker dat u deze taak wilt verwijderen?",
"actions": {
"moveToTodo": "Verplaatsen naar Te doen",
"moveToInProgress": "Verplaatsen naar In uitvoering",
"moveToDone": "Verplaatsen naar Voltooid",
"edit": "Bewerken",
Expand Down
20 changes: 19 additions & 1 deletion apps/console/src/components/tasks/TaskFormDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export const taskUpdateMutation = graphql`
}
`;

export const taskStates = ["TODO", "IN_PROGRESS", "DONE"] as const;
export const taskStates = ["BACKLOG", "TODO", "IN_PROGRESS", "DONE", "CANCELED", "DUPLICATE"] as const;
export const taskPriorities = ["URGENT", "HIGH", "MEDIUM", "LOW"] as const;

const createTaskSchema = z.object({
Expand Down Expand Up @@ -284,6 +284,12 @@ export default function TaskFormDialog(props: Props) {
value={field.value}
onValueChange={field.onChange}
>
<Option value="BACKLOG">

@cubic-dev-ai cubic-dev-ai Bot Aug 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: A newly created task can never use the new BACKLOG state because this selector is rendered only while editing, and the create mutation/API always defaults tasks to TODO. Expose the initial state in the create flow and pass it through CreateTaskInput if backlog is intended to represent work that has not started.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/console/src/components/tasks/TaskFormDialog.tsx, line 287:

<comment>A newly created task can never use the new `BACKLOG` state because this selector is rendered only while editing, and the create mutation/API always defaults tasks to `TODO`. Expose the initial state in the create flow and pass it through `CreateTaskInput` if backlog is intended to represent work that has not started.</comment>

<file context>
@@ -284,6 +284,12 @@ export default function TaskFormDialog(props: Props) {
                       value={field.value}
                       onValueChange={field.onChange}
                     >
+                      <Option value="BACKLOG">
+                        <span className="flex items-center gap-2">
+                          <TaskStateIcon state="BACKLOG" />
</file context>
Fix with cubic

<span className="flex items-center gap-2">
<TaskStateIcon state="BACKLOG" />
{t("taskFormDialog.states.backlog")}
</span>
</Option>
<Option value="TODO">
<span className="flex items-center gap-2">
<TaskStateIcon state="TODO" />
Expand All @@ -302,6 +308,18 @@ export default function TaskFormDialog(props: Props) {
{t("taskFormDialog.states.done")}
</span>
</Option>
<Option value="CANCELED">
<span className="flex items-center gap-2">
<TaskStateIcon state="CANCELED" />
{t("taskFormDialog.states.canceled")}
</span>
</Option>
<Option value="DUPLICATE">
<span className="flex items-center gap-2">
<TaskStateIcon state="DUPLICATE" />
{t("taskFormDialog.states.duplicate")}
</span>
</Option>
</Select>
)}
/>
Expand Down
16 changes: 12 additions & 4 deletions apps/console/src/components/tasks/TasksCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
IconCircleCheck,
IconCircleProgress,
IconPencil,
IconRadioUnchecked,
IconTrashCan,
PriorityLevel,
TabBadge,
Expand Down Expand Up @@ -64,11 +65,14 @@ import type {
import type { TasksCardOrganizationQuery } from "#/__generated__/core/TasksCardOrganizationQuery.graphql";
import TaskFormDialog, {
taskPriorities,
taskStates,
taskUpdateMutation,
} from "#/components/tasks/TaskFormDialog";
import { updateStoreCounter } from "#/hooks/useMutationWithIncrement";
import { useOrganizationId } from "#/hooks/useOrganizationId";

type TaskState = (typeof taskStates)[number];

function resolveDropPriority(
dragged: TaskPriority,
above?: TaskPriority,
Expand Down Expand Up @@ -206,9 +210,12 @@ export function TasksCard({ tasks, connectionId, canReorder, refetch }: Props) {
};

const stateHashes = [
{ hash: "backlog", label: t("tasksCard.states.backlog"), state: "BACKLOG" },
{ hash: "todo", label: t("tasksCard.states.todo"), state: "TODO" },
{ hash: "in-progress", label: t("tasksCard.states.inProgress"), state: "IN_PROGRESS" },
{ hash: "done", label: t("tasksCard.states.done"), state: "DONE" },
{ hash: "canceled", label: t("tasksCard.states.canceled"), state: "CANCELED" },
Comment thread
SachaProbo marked this conversation as resolved.
{ hash: "duplicate", label: t("tasksCard.states.duplicate"), state: "DUPLICATE" },
] as const;

const hashes = [
Expand Down Expand Up @@ -319,7 +326,7 @@ export function TasksCard({ tasks, connectionId, canReorder, refetch }: Props) {

// Determine if state changed (All tab cross-section drop).
const newState = targetState && targetState !== draggedTask.state
? targetState as "TODO" | "IN_PROGRESS" | "DONE"
? targetState as TaskState
: undefined;

// Only change priority for same-state reorder, never for cross-section drops.
Expand Down Expand Up @@ -390,7 +397,7 @@ export function TasksCard({ tasks, connectionId, canReorder, refetch }: Props) {

const displayTasks = applyPreviewOrder(filteredTasks);

const renderTaskRow = (node: (typeof tasks)[number]["node"], sectionState?: "TODO" | "IN_PROGRESS" | "DONE") => {
const renderTaskRow = (node: (typeof tasks)[number]["node"], sectionState?: TaskState) => {
const task = readTask(node);
return (
<TaskRow
Expand Down Expand Up @@ -475,7 +482,7 @@ export function TasksCard({ tasks, connectionId, canReorder, refetch }: Props) {
type TaskRowProps = {
fKey: TasksCard_TaskRowFragment$key | TaskFormDialogFragment$key;
connectionId: string;
sectionState?: "TODO" | "IN_PROGRESS" | "DONE";
sectionState?: TaskState;
canDrag?: boolean;
isDragging?: boolean;
isGhost?: boolean;
Expand Down Expand Up @@ -538,11 +545,12 @@ function TaskRow(props: TaskRowProps) {
const displayState = props.sectionState ?? task.state;

const nextStepConfig: Record<string, {
state: "IN_PROGRESS" | "DONE";
state: TaskState;
label: string;
icon: typeof IconCircleProgress;
className: string;
}> = {
BACKLOG: { state: "TODO", label: t("tasksCard.actions.moveToTodo"), icon: IconRadioUnchecked, className: "text-txt-quaternary" },
TODO: { state: "IN_PROGRESS", label: t("tasksCard.actions.moveToInProgress"), icon: IconCircleProgress, className: "text-txt-warning" },
IN_PROGRESS: { state: "DONE", label: t("tasksCard.actions.moveToDone"), icon: IconCircleCheck, className: "text-txt-accent" },
};
Expand Down
3 changes: 3 additions & 0 deletions e2e/console/task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,9 +327,12 @@ func TestTask_StateEnum(t *testing.T) {
Create()

states := []string{
"BACKLOG",
"TODO",
"IN_PROGRESS",
"DONE",
"CANCELED",
"DUPLICATE",
}

for _, state := range states {
Expand Down
20 changes: 16 additions & 4 deletions packages/n8n-node/nodes/Probo/actions/task/update.operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,29 @@ export const description: INodeProperties[] = [
value: '',
},
{
name: 'Todo',
value: 'TODO',
name: 'Backlog',
value: 'BACKLOG',
},
{
name: 'In Progress',
value: 'IN_PROGRESS',
name: 'Canceled',
value: 'CANCELED',
},
{
name: 'Done',
value: 'DONE',
},
{
name: 'Duplicate',
value: 'DUPLICATE',
},
{
name: 'In Progress',
value: 'IN_PROGRESS',
},
{
name: 'Todo',
value: 'TODO',
},
],
default: '',
description: 'The state of the task',
Expand Down
18 changes: 18 additions & 0 deletions packages/ui/src/Atoms/Icons/TaskStateIcon.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ export default {

type Story = StoryObj<typeof TaskStateIcon>;

export const Backlog: Story = {
args: {
state: "BACKLOG",
},
};

export const Default: Story = {
args: {
state: "TODO",
Expand All @@ -47,3 +53,15 @@ export const Done: Story = {
state: "DONE",
},
};

export const Canceled: Story = {
args: {
state: "CANCELED",
},
};

export const Duplicate: Story = {
args: {
state: "DUPLICATE",
},
};
13 changes: 12 additions & 1 deletion packages/ui/src/Atoms/Icons/TaskStateIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,32 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import { IconArchive } from "./IconArchive";
import { IconCircleCheck } from "./IconCircleCheck";
import { IconCircleProgress } from "./IconCircleProgress";
import { IconCircleX } from "./IconCircleX";
import { IconRadioUnchecked } from "./IconRadioUnchecked";
import { IconSquareBehindSquare2 } from "./IconSquareBehindSquare2";

export type TaskState = "BACKLOG" | "TODO" | "IN_PROGRESS" | "DONE" | "CANCELED" | "DUPLICATE";

type Props = {
state: "TODO" | "IN_PROGRESS" | "DONE";
state: TaskState;
};

export function TaskStateIcon({ state }: Props) {
switch (state) {
case "BACKLOG":
return <IconArchive size={16} className="text-txt-tertiary" />;
case "TODO":
return <IconRadioUnchecked size={16} className="text-txt-quaternary" />;
case "IN_PROGRESS":
return <IconCircleProgress size={16} className="text-txt-warning" />;
case "DONE":
return <IconCircleCheck size={16} className="text-txt-accent" />;
case "CANCELED":
return <IconCircleX size={16} className="text-txt-danger" />;
case "DUPLICATE":
return <IconSquareBehindSquare2 size={16} className="text-txt-secondary" />;
}
}
1 change: 1 addition & 0 deletions packages/ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export { ControlItem } from "./Atoms/ControlItem/ControlItem";
export { InfiniteScrollTrigger } from "./Atoms/InfiniteScrollTrigger/InfiniteScrollTrigger";
export { PriorityLevel } from "./Atoms/PriorityLevel/PriorityLevel";
export { TaskStateIcon } from "./Atoms/Icons/TaskStateIcon";
export type { TaskState } from "./Atoms/Icons/TaskStateIcon";
export { Checkbox } from "./Atoms/Checkbox/Checkbox";
export { Toggle } from "./Atoms/Toggle/Toggle";
export {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/task/update/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ func NewCmdUpdate(f *cmdutil.Factory) *cobra.Command {

cmd.Flags().StringVar(&flagName, "name", "", "Task name")
cmd.Flags().StringVar(&flagDescription, "description", "", "Task description")
cmd.Flags().StringVar(&flagState, "state", "", "Task state: TODO, IN_PROGRESS, DONE")
cmd.Flags().StringVar(&flagState, "state", "", "Task state: BACKLOG, TODO, IN_PROGRESS, DONE, CANCELED, DUPLICATE")
cmd.Flags().StringVar(&flagPriority, "priority", "", "Task priority: URGENT, HIGH, MEDIUM, LOW")
cmd.Flags().StringVar(&flagTimeEstimate, "time-estimate", "", "Time estimate")
cmd.Flags().StringVar(&flagDeadline, "deadline", "", "Deadline")
Expand Down
23 changes: 23 additions & 0 deletions pkg/coredata/migrations/20260828T133808Z.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-- Copyright (c) 2026 Probo Inc <hello@probo.com>.
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.

ALTER TYPE task_state ADD VALUE 'BACKLOG' BEFORE 'TODO';
ALTER TYPE task_state ADD VALUE 'CANCELED';
ALTER TYPE task_state ADD VALUE 'DUPLICATE';
11 changes: 10 additions & 1 deletion pkg/coredata/task_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ type (
)

const (
TaskStateBacklog TaskState = "BACKLOG"
TaskStateTodo TaskState = "TODO"
TaskStateInProgress TaskState = "IN_PROGRESS"
TaskStateDone TaskState = "DONE"
TaskStateCanceled TaskState = "CANCELED"
TaskStateDuplicate TaskState = "DUPLICATE"
)

var (
Expand All @@ -43,18 +46,24 @@ var (

func TaskStates() []TaskState {
return []TaskState{
TaskStateBacklog,
TaskStateTodo,
TaskStateInProgress,
TaskStateDone,
TaskStateCanceled,
TaskStateDuplicate,
}
}

func (v TaskState) IsValid() bool {
switch v {
case
TaskStateBacklog,
TaskStateTodo,
TaskStateInProgress,
TaskStateDone:
TaskStateDone,
TaskStateCanceled,
TaskStateDuplicate:
return true
}

Expand Down
Loading
Loading