• 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

0.0
/packages/js/src/general/app.js
1
import { Transition } from "@headlessui/react";
2
import { AdjustmentsIcon, BellIcon, ChartPieIcon, ClipboardCheckIcon } from "@heroicons/react/outline";
3
import { useDispatch, useSelect } from "@wordpress/data";
4
import { useCallback, useEffect } from "@wordpress/element";
5
import { __ } from "@wordpress/i18n";
6
import { addQueryArgs } from "@wordpress/url";
7
import { Notifications, SidebarNavigation, useSvgAria } from "@yoast/ui-library";
8
import PropTypes from "prop-types";
9
import { Link, Outlet, useLocation } from "react-router-dom";
10
import { Notice, LlmTxtOptInContainer } from "./components";
11
import { STORE_NAME } from "./constants";
12
import WebinarPromoNotification from "../components/WebinarPromoNotification";
13
import { deleteMigratingNotices } from "../helpers/migrateNotices";
14
import { useNotificationCountSync, useSelectGeneralPage } from "./hooks";
15
import { MenuItemLink, YoastLogo } from "../shared-admin/components";
16
import { ROUTES } from "./routes";
17

18
/**
19
 * @param {string} [idSuffix] Extra id suffix. Can prevent double IDs on the page.
20
 * @returns {JSX.Element} The menu element.
21
 */
22
const Menu = ( { idSuffix = "" } ) => {
×
23
        const svgAriaProps = useSvgAria();
×
24
        const isPremium = useSelectGeneralPage( "selectPreference", [], "isPremium" );
×
NEW
25
        const isTaskListFeatureEnabled = useSelectGeneralPage( "selectIsTaskListEnabled", [] );
×
26

27
        return <>
×
28
                <header className="yst-px-3 yst-mb-6 yst-space-y-6">
29
                        <Link
30
                                id={ `link-yoast-logo${ idSuffix }` }
31
                                to="/"
32
                                className="yst-inline-block yst-rounded-md focus:yst-ring-primary-500"
33
                                aria-label={ `Yoast SEO${ isPremium ? " Premium" : "" }` }
×
34
                        >
35
                                <YoastLogo className="yst-w-40" { ...svgAriaProps } />
36
                        </Link>
37
                </header>
38
                <ul className="yst-mt-1 yst-px-0.5 yst-space-y-4">
39
                        <MenuItemLink
40
                                to={ ROUTES.dashboard }
41
                                label={ <>
42
                                        <ChartPieIcon className="yst-sidebar-navigation__icon yst-w-6 yst-h-6" />
43
                                        { __( "Dashboard", "wordpress-seo" ) }
44
                                </> }
45
                                idSuffix={ idSuffix }
46
                                className="yst-gap-3"
47
                        />
48
                        { isTaskListFeatureEnabled && <MenuItemLink
×
49
                                to={ ROUTES.taskList }
50
                                label={ <>
51
                                        <ClipboardCheckIcon className="yst-sidebar-navigation__icon yst-w-6 yst-h-6" />
52
                                        { __( "Task list", "wordpress-seo" ) }
53
                                </> }
54
                                idSuffix={ idSuffix }
55
                                className="yst-gap-3"
56
                        /> }
57
                        <MenuItemLink
58
                                to={ ROUTES.alertCenter }
59
                                label={ <>
60
                                        <BellIcon className="yst-sidebar-navigation__icon yst-w-6 yst-h-6" />
61
                                        { __( "Alert center", "wordpress-seo" ) }
62
                                </> }
63
                                idSuffix={ idSuffix }
64
                                className="yst-gap-3"
65
                        />
66
                        <MenuItemLink
67
                                to={ ROUTES.firstTimeConfiguration }
68
                                label={ <>
69
                                        <AdjustmentsIcon className="yst-sidebar-navigation__icon yst-w-6 yst-h-6" />
70
                                        { __( "First-time configuration", "wordpress-seo" ) }
71
                                </> }
72
                                idSuffix={ idSuffix }
73
                                className="yst-gap-3"
74
                        />
75
                </ul>
76
        </>;
77
};
78
Menu.propTypes = {
×
79
        idSuffix: PropTypes.string,
80
};
81

82
/**
83
 * @returns {JSX.Element} The app component.
84
 */
85
const App = () => {
×
86
        const notices = useSelect( select => select( STORE_NAME ).selectNotices(), [] );
×
87

88
        useEffect( () => {
×
89
                deleteMigratingNotices( notices );
×
90
        }, [ notices ] );
91

92
        const { pathname } = useLocation();
×
93
        const alertToggleError = useSelectGeneralPage( "selectAlertToggleError", [], [] );
×
94
        const { setAlertToggleError } = useDispatch( STORE_NAME );
×
95
        useNotificationCountSync();
×
96

97
        const handleDismiss = useCallback( () => {
×
98
                setAlertToggleError( null );
×
99
        }, [ setAlertToggleError ] );
100

101
        const linkParams = useSelect( select => select( STORE_NAME ).selectLinkParams(), [] );
×
102
        const webinarIntroSettingsUrl = addQueryArgs( "https://yoa.st/webinar-intro-settings", linkParams );
×
103

104
        return (
×
105
                <>
106
                        <SidebarNavigation activePath={ pathname }>
107
                                <SidebarNavigation.Mobile
108
                                        openButtonId="button-open-dashboard-navigation-mobile"
109
                                        closeButtonId="button-close-dashboard-navigation-mobile"
110
                                        /* translators: Hidden accessibility text. */
111
                                        openButtonScreenReaderText={ __( "Open dashboard navigation", "wordpress-seo" ) }
112
                                        /* translators: Hidden accessibility text. */
113
                                        closeButtonScreenReaderText={ __( "Close dashboard navigation", "wordpress-seo" ) }
114
                                        aria-label={ __( "Dashboard navigation", "wordpress-seo" ) }
115
                                >
116
                                        <Menu idSuffix="-mobile" />
117
                                </SidebarNavigation.Mobile>
118
                                <div className="yst-p-4 min-[783px]:yst-p-8 yst-flex yst-gap-4">
119
                                        <aside className="yst-sidebar yst-sidebar-nav yst-shrink-0 yst-hidden min-[783px]:yst-block yst-pb-6 yst-bottom-0 yst-w-56">
120
                                                <SidebarNavigation.Sidebar>
121
                                                        <Menu />
122
                                                </SidebarNavigation.Sidebar>
123
                                        </aside>
124
                                        <div className="yst-grow yst-max-w-page">
125
                                                <div className="yst-space-y-6 yst-mb-8 xl:yst-mb-0">
126
                                                        <main>
127
                                                                <Transition
128
                                                                        key={ pathname }
129
                                                                        appear={ true }
130
                                                                        show={ true }
131
                                                                        enter="yst-transition-opacity yst-delay-100 yst-duration-300"
132
                                                                        enterFrom="yst-opacity-0"
133
                                                                        enterTo="yst-opacity-100"
134
                                                                >
135
                                                                        { pathname !== ROUTES.firstTimeConfiguration && <div>
×
136
                                                                                <WebinarPromoNotification store={ STORE_NAME } url={ webinarIntroSettingsUrl } image={ null } />
137
                                                                                { notices.length > 0 && <div className={ notices.filter( notice => ! notice.isDismissed ).length > 0 ? "yst-space-y-3 yoast-general-page-notices" : "yst-hidden" }> {
×
138
                                                                                        notices.map( ( notice, index ) =>
139
                                                                                                <Notice
×
140
                                                                                                        key={ index }
141
                                                                                                        id={ notice.id || "yoast-general-page-notice-" + index }
×
142
                                                                                                        title={ notice.header }
143
                                                                                                        isDismissable={ notice.isDismissable }
144
                                                                                                        className={ notice.isDismissed ? "yst-hidden" : "" }
×
145
                                                                                                >
146
                                                                                                        { notice.content }
147
                                                                                                </Notice>
148
                                                                                        )
149
                                                                                }
150
                                                                                </div> }
151
                                                                        </div> }
152
                                                                        <Outlet />
153
                                                                </Transition>
154
                                                        </main>
155
                                                </div>
156
                                        </div>
157
                                </div>
158
                        </SidebarNavigation>
159
                        <Notifications
160
                                className="yst-mx-[calc(50%-50vw)] yst-transition-all yst-start-48"
161
                                position="bottom-left"
162
                        >
163
                                <LlmTxtOptInContainer />
164
                                { alertToggleError && <Notifications.Notification
×
165
                                        id="toggle-alert-error"
166
                                        title={ __( "Something went wrong", "wordpress-seo" ) }
167
                                        variant="error"
168
                                        dismissScreenReaderLabel={ __( "Dismiss", "wordpress-seo" ) }
169
                                        size="large"
170
                                        autoDismiss={ 4000 }
171
                                        onDismiss={ handleDismiss }
172
                                >
173
                                        { alertToggleError.type === "error"
×
174
                                                ? __( "This problem can't be hidden at this time. Please try again later.", "wordpress-seo" )
175
                                                : __( "This notification can't be hidden at this time. Please try again later.", "wordpress-seo" )
176
                                        }
177
                                </Notifications.Notification>
178
                                }
179
                        </Notifications>
180
                </>
181
        );
182
};
183

184
export default App;
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