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

Yoast / wordpress-seo / a2d4b1b152b3258a693e3a2030465f03928c084e

26 Nov 2024 10:07AM UTC coverage: 54.128% (-0.04%) from 54.167%
a2d4b1b152b3258a693e3a2030465f03928c084e

Pull #21861

github

web-flow
Merge 3d06b3fe2 into 851d976ec
Pull Request #21861: Include metadata in the API endpoints

7593 of 13672 branches covered (55.54%)

Branch coverage included in aggregate %.

0 of 195 new or added lines in 23 files covered. (0.0%)

527 existing lines in 4 files now uncovered.

29764 of 55344 relevant lines covered (53.78%)

41469.26 hits per line

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

0.0
/packages/js/src/dashboard/scores/components/scores.js
1
import { createInterpolateElement, useEffect, useState } from "@wordpress/element";
2
import { __, sprintf } from "@wordpress/i18n";
3
import { Alert, Link, Paper, Title } from "@yoast/ui-library";
4
import { useFetch } from "../../fetch/use-fetch";
5
import { SCORE_DESCRIPTIONS } from "../score-meta";
6
import { ContentTypeFilter } from "./content-type-filter";
7
import { ScoreContent } from "./score-content";
8
import { TermFilter } from "./term-filter";
9

10
/**
11
 * @type {import("../index").ContentType} ContentType
12
 * @type {import("../index").Taxonomy} Taxonomy
13
 * @type {import("../index").Term} Term
14
 * @type {import("../index").AnalysisType} AnalysisType
15
 */
16

17
/**
18
 * @param {string|URL} endpoint The endpoint.
19
 * @param {ContentType} contentType The content type.
20
 * @param {Term?} [term] The term.
21
 * @returns {URL} The URL to get scores.
22
 */
23
const createScoresUrl = ( endpoint, contentType, term ) => {
×
24
        const searchParams = new URLSearchParams( { contentType: contentType.name } );
×
25
        if ( contentType.taxonomy?.name && term?.name ) {
×
26
                searchParams.set( "taxonomy", contentType.taxonomy.name );
×
27
                searchParams.set( "term", term.name );
×
28
        }
29
        return new URL( "?" + searchParams, endpoint );
×
30
};
31

32
// Added dummy space as content to prevent children prop warnings in the console.
33
const supportLink = <Link variant="error" href="admin.php?page=wpseo_page_support"> </Link>;
×
34

35
const TimeoutErrorMessage = createInterpolateElement(
×
36
        sprintf(
37
                /* translators: %1$s and %2$s expand to an opening/closing tag for a link to the support page. */
38
                __( "A timeout occurred, possibly due to a large number of posts or terms. In case you need further help, please take a look at our %1$sSupport page%2$s.", "wordpress-seo" ),
39
                "<supportLink>",
40
                "</supportLink>"
41
        ),
42
        {
43
                supportLink,
44
        }
45
);
46
const OtherErrorMessage = createInterpolateElement(
×
47
        sprintf(
48
                /* translators: %1$s and %2$s expand to an opening/closing tag for a link to the support page. */
49
                __( "Something went wrong. In case you need further help, please take a look at our %1$sSupport page%2$s.", "wordpress-seo" ),
50
                "<supportLink>",
51
                "</supportLink>"
52
        ),
53
        {
54
                supportLink,
55
        }
56
);
57

58
/**
59
 * @param {Error?} [error] The error.
60
 * @returns {JSX.Element} The element.
61
 */
62
const ErrorAlert = ( { error } ) => {
×
63
        if ( ! error ) {
×
64
                return null;
×
65
        }
66
        return (
×
67
                <Alert variant="error">
68
                        { error?.name === "TimeoutError"
×
69
                                ? TimeoutErrorMessage
70
                                : OtherErrorMessage
71
                        }
72
                </Alert>
73
        );
74
};
75

76
/**
77
 * @param {AnalysisType} analysisType The analysis type. Either "seo" or "readability".
78
 * @param {ContentType[]} contentTypes The content types. May not be empty.
79
 * @param {string} endpoint The endpoint or base URL.
80
 * @param {Object<string,string>} headers The headers to send with the request.
81
 * @returns {JSX.Element} The element.
82
 */
83
export const Scores = ( { analysisType, contentTypes, endpoint, headers } ) => {
×
84
        const [ selectedContentType, setSelectedContentType ] = useState( contentTypes[ 0 ] );
×
85
        const [ selectedTerm, setSelectedTerm ] = useState();
×
86

87
        const { data: scores, error, isPending } = useFetch( {
×
88
                dependencies: [ selectedContentType.name, selectedContentType?.taxonomy, selectedTerm?.name ],
89
                url: createScoresUrl( endpoint, selectedContentType, selectedTerm ),
90
                options: {
91
                        headers: {
92
                                "Content-Type": "application/json",
93
                                ...headers,
94
                        },
95
                },
96
                fetchDelay: 0,
NEW
97
                prepareData: ( data ) => data?.scores,
×
98
        } );
99

100
        useEffect( () => {
×
101
                // Reset the selected term when the selected content type changes.
102
                setSelectedTerm( undefined ); // eslint-disable-line no-undefined
×
103
        }, [ selectedContentType.name ] );
104

105
        return (
×
106
                <Paper className="yst-@container yst-grow yst-max-w-screen-sm yst-p-8">
107
                        <Title as="h2">
108
                                { analysisType === "readability"
×
109
                                        ? __( "Readability scores", "wordpress-seo" )
110
                                        : __( "SEO scores", "wordpress-seo" )
111
                                }
112
                        </Title>
113
                        <div className="yst-grid yst-grid-cols-1 @md:yst-grid-cols-2 yst-gap-6 yst-mt-4">
114
                                <ContentTypeFilter
115
                                        idSuffix={ analysisType }
116
                                        contentTypes={ contentTypes }
117
                                        selected={ selectedContentType }
118
                                        onChange={ setSelectedContentType }
119
                                />
120
                                { selectedContentType.taxonomy && selectedContentType.taxonomy?.links?.search &&
×
121
                                        <TermFilter
122
                                                idSuffix={ analysisType }
123
                                                taxonomy={ selectedContentType.taxonomy }
124
                                                selected={ selectedTerm }
125
                                                onChange={ setSelectedTerm }
126
                                        />
127
                                }
128
                        </div>
129
                        <div className="yst-mt-6">
130
                                <ErrorAlert error={ error } />
131
                                { ! error && (
×
132
                                        <ScoreContent scores={ scores } isLoading={ isPending } descriptions={ SCORE_DESCRIPTIONS[ analysisType ] } />
133
                                ) }
134
                        </div>
135
                </Paper>
136
        );
137
};
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

© 2025 Coveralls, Inc