• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / wordpress-seo / 8218b111533b92ec47f94130a94bcd0102263a45

01 Dec 2025 09:48AM UTC coverage: 53.092%. First build
8218b111533b92ec47f94130a94bcd0102263a45

push

github

web-flow
Merge pull request #22759 from Yoast/feature/task-list

Feature/task list

8697 of 16050 branches covered (54.19%)

Branch coverage included in aggregate %.

98 of 605 new or added lines in 51 files covered. (16.2%)

32413 of 61381 relevant lines covered (52.81%)

46976.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.76
/packages/dashboard-frontend/src/task-list/components/task-row.js
1
import { CheckCircleIcon } from "@heroicons/react/solid";
2
import { ChevronRightIcon } from "@heroicons/react/outline";
3
import { Table, useSvgAria, SkeletonLoader, useToggleState } from "@yoast/ui-library";
4
import { Priority } from "./priority";
5
import { Duration } from "./duration";
6
import { TaskBadge } from "./task-badge";
7
import { Ellipse } from "../../icons";
8
import { __ } from "@wordpress/i18n";
9
import classNames from "classnames";
10
import { useMemo } from "react";
11

12
const badgeOptions = [ "premium", "woo", "ai" ];
22✔
13

14
/**
15
 * The LoadingTaskRow component to display a loading state for a task row.
16
 *
17
 * @param {string} title Title of the task or a placeholder title.
18
 * @returns {JSX.Element} The LoadingTaskRow component.
19
 */
20
const LoadingTaskRow = ( { title } ) => {
22✔
NEW
21
        const svgAriaProps = useSvgAria();
×
NEW
22
        return <Table.Row>
×
23
                <Table.Cell className="yst-font-medium yst-text-slate-800">
24
                        <div className="yst-flex yst-items-center yst-gap-2">
25
                                <Ellipse className="yst-w-4 yst-text-slate-200" { ...svgAriaProps } />
26
                                <SkeletonLoader className="yst-h-[18px]">{ title }</SkeletonLoader>
27
                        </div>
28
                </Table.Cell>
29
                <Table.Cell>
30
                        <Duration isLoading={ true } />
31
                </Table.Cell>
32
                <Table.Cell>
33
                        <div className="yst-flex yst-justify-between">
34
                                <Priority isLoading={ true } />
35
                                <ChevronRightIcon
36
                                        className="yst-w-4 yst-text-slate-600 rtl:yst-rotate-180"
37
                                        { ...svgAriaProps }
38
                                />
39
                        </div>
40
                </Table.Cell>
41
        </Table.Row>;
42
};
43

44
/**
45
 * The TaskRow component to display a task in a table row.
46
 *
47
 * @param {string} title Title of the task.
48
 * @param {number} duration Estimated duration to complete the task.
49
 * @param {string} priority Priority of the task: 'low', 'medium', 'high'.
50
 * @param {string} [badge] An optional badge to display next to the task title: `premium`, `woo`, `ai`.
51
 * @param {boolean} isCompleted Whether the task is completed.
52
 * @param {Function} onClick Function to call when the row is clicked.
53
 * @param {JSX.Element} [children] Optional children elements for the task modal.
54
 *
55
 * @returns {JSX.Element} The TaskRow component.
56
 */
57
export const TaskRow = ( { title, duration, priority, badge, isCompleted, onClick, children } ) => {
22✔
58
        const svgAriaProps = useSvgAria();
16✔
59
        const [ isButtonFocused, , ,handleButtonFocus, handleButtonBlur ] = useToggleState( false );
16✔
60

61
        const cellBackground = useMemo( () => isButtonFocused ? "yst-bg-slate-50" : "group-hover:yst-bg-slate-50", [ isButtonFocused ] );
16!
62

63
        return (
16✔
64
                <Table.Row className="yst-cursor-pointer yst-group" onClick={ onClick } aria-label={ __( "Open task modal", "wordpress-seo" ) }>
65
                        <Table.Cell className={ cellBackground }>
66
                                <div className="yst-flex yst-items-center yst-gap-2">
67
                                        { isCompleted
8✔
68
                                                ? <CheckCircleIcon className="yst-w-4 yst-text-green-500 yst-shrink-0" { ...svgAriaProps } />
69
                                                : <Ellipse className="yst-w-4 yst-text-slate-200 yst-shrink-0" { ...svgAriaProps } /> }
70
                                        <button
71
                                                aria-haspopup="dialog"
72
                                                type="button"
73
                                                className={ classNames(
74
                                                        "yst-font-medium focus:yst-outline-none focus-visible:yst-outline-none yst-text-start",
75
                                                        isCompleted ? "yst-text-slate-500" : "yst-text-slate-800 hover:yst-text-slate-900",
8✔
76
                                                        isButtonFocused ? "yst-underline" : "group-hover:yst-underline"
8!
77
                                                ) }
78
                                                onFocus={ handleButtonFocus }
79
                                                onBlur={ handleButtonBlur }
80
                                        >
81
                                                { title }
82
                                                <span className="yst-sr-only">
83
                                                        { isCompleted ? __( "(Completed)", "wordpress-seo" ) : __( "(Not completed)", "wordpress-seo" ) }
8✔
84
                                                </span>
85
                                        </button>
86
                                        { badgeOptions.includes( badge ) && <TaskBadge type={ badge } /> }
15✔
87
                                </div>
88
                        </Table.Cell>
89
                        <Table.Cell
90
                                className={ classNames( cellBackground,
91
                                        isCompleted ? "yst-opacity-50" : "" ) }
8✔
92
                        >
93
                                <Duration minutes={ duration } />
94
                        </Table.Cell>
95
                        <Table.Cell
96
                                className={ classNames( "yst-pe-5",
97
                                        cellBackground ) }
98
                        >
99
                                <div className="yst-flex yst-justify-between">
100
                                        <Priority level={ priority } className={ isCompleted ? "yst-opacity-50" : "" } />
8✔
101
                                        <ChevronRightIcon
102
                                                className={ classNames( "yst-w-4 yst-text-slate-600 rtl:yst-rotate-180 yst-transition yst-duration-300 yst-ease-in-out yst-shrink-0",
103
                                                        isButtonFocused ? "yst-text-slate-800 yst-translate-x-2" : "group-hover:yst-text-slate-800 group-hover:yst-translate-x-2"
8!
104
                                                ) } { ...svgAriaProps }
105
                                        />
106
                                </div>
107
                                { children }
108
                        </Table.Cell>
109
                </Table.Row>
110
        );
111
};
112

113
TaskRow.Loading = LoadingTaskRow;
22✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc