Skip to content

Fix Task parent/child field visibility and list rendering #765

Description

@gaidheal1

Bug 1: "Parent task" field disappears once a parent is set, with no way to revert

frontend/src/components/TasksPanel/TasksPanel.tsx:183 gates the entire parent-task row behind:

{taskItem.parent == null && (
  <div className={styles.parentRow}>
    ...
    <select ... onChange={(event) => updateTask.mutate({ id: taskItem.id, data: { parent: ... } })}>
      ...
    </select>
  </div>
)}

Once a task has a parent, this block — label, <select>, everything — stops rendering entirely for that task's edit modal. There's no remaining UI to change the parent back to "No parent" or to a different parent; the only way out is editing the database directly.

Fix: the row (and its <select>) should always render for a task that isn't itself blocking on hasSubtasks (which already exists to prevent nesting a task that has its own children — see hasSubtasks/parentOptions a few lines above, TasksPanel.tsx:112-113). The taskItem.parent == null check should not hide the whole control; at most it affects which options make sense to offer.

Bug 2: child tasks render nested inside the parent's list item, not as independent (indented) rows

Currently, in PlayerItemList.tsx, the List's renderItem returns the parent's row and a <ul className={styles.childList}> of children's <Li>s together as one fragment (PlayerItemList.tsx:266-284):

renderItem={(item) => {
  const children = getChildren?.(item);
  return (
    <>
      {renderRow(item)}
      {children?.length ? (
        <ul className={styles.childList}>
          {children.map((child, index) => (
            <Li key={...} className={...}>{renderRow(child)}</Li>
          ))}
        </ul>
      ) : null}
    </>
  );
}}

Since List.tsx wraps whatever renderItem returns inside a single outer <Li> per top-level item (List.tsx:91-106), the children's <ul>/<Li> end up nested inside the parent's own <li> — i.e. structurally (and visually, since the parent <Li> is a bordered/card-styled item) the children render inside the parent task's box, rather than as their own rows in the list.

Requested fix: child tasks should render as independent rows directly in the list — siblings of other top-level items, not descendants of the parent's <li> — just visually indented (e.g. via a left-margin/padding modifier class) to show the parent/child relationship.

Useful building block already exists: useTasksPanel.tsx's visibleTasks (useTasksPanel.tsx:179-182) already flattens groupedTasks into [parent, ...children, parent, ...children, ...] in display order. PlayerItemList currently discards this ordering and deliberately filters children out of topLevelDisplayItems (PlayerItemList.tsx:140-145, via childIds) so they only render nested under the parent. Switching to rendering the flat, ordered list directly — with an "is this a child, indent it" check per item instead of a parent-owns-nested-children structure — would fix this without needing a new data shape.

Scope

  • frontend/src/components/TasksPanel/TasksPanel.tsx (parent-field visibility)
  • frontend/src/components/PlayerItemList/PlayerItemList.tsx and PlayerItemList.module.scss (list rendering structure — note this component is shared by Tasks/Skills/Projects/Categories/Activities panels, so check whether getChildren is used by any panel besides Tasks before changing its contract)
  • frontend/src/components/TasksPanel/useTasksPanel.tsx (getChildren, visibleTasks, topLevelTasks — may no longer all be needed in their current form once rendering flattens)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions