import AppLayout from "components/AppLayout"; import Chip from "components/Chip"; import Button from "components/Inputs/Button"; import ContentPanel, { ContentPanelWidthSizes, } from "components/Panels/ContentPanel"; import ToolTip from "components/ToolTip"; import { DevGetContentsQuery, Enum_Componentsetstextset_Status, } from "graphql/generated"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { getReadySdk } from "graphql/sdk"; import { Immutable } from "helpers/types"; import { GetStaticPropsContext } from "next"; interface Props extends AppStaticProps { contents: DevGetContentsQuery; } export default function CheckupContents(props: Immutable<Props>): JSX.Element { const { contents } = props; const testReport = testingContent(contents); const contentPanel = ( <ContentPanel width={ContentPanelWidthSizes.large}> {<h2 className="text-2xl">{testReport.title}</h2>} <div className="grid grid-cols-[2em,3em,2fr,1fr,0.5fr,0.5fr,2fr] gap-2 items-center my-4"> <p></p> <p></p> <p className="font-headers">Ref</p> <p className="font-headers">Name</p> <p className="font-headers">Type</p> <p className="font-headers">Severity</p> <p className="font-headers">Description</p> </div> {testReport.lines.map((line, index) => ( <div key={index} className="grid grid-cols-[2em,3em,2fr,1fr,0.5fr,0.5fr,2fr] gap-2 items-center mb-2 justify-items-start" > <Button href={line.frontendUrl} target="_blank" className="text-xs w-4" > F </Button> <Button href={line.backendUrl} target="_blank" className="text-xs w-4" > B </Button> <p>{line.subitems.join(" -> ")}</p> <p>{line.name}</p> <Chip>{line.type}</Chip> <Chip className={ line.severity === "Very High" ? "bg-[#f00] !opacity-100 font-bold" : line.severity === "High" ? "bg-[#ff6600] !opacity-100 font-bold" : line.severity === "Medium" ? "bg-[#fff344] !opacity-100" : "" } > {line.severity} </Chip> <ToolTip content={line.recommandation} placement="left"> <p>{line.description}</p> </ToolTip> </div> ))} </ContentPanel> ); return ( <AppLayout navTitle={"Checkup"} contentPanel={contentPanel} {...props} /> ); } export async function getStaticProps( context: GetStaticPropsContext ): Promise<{ notFound: boolean } | { props: Props }> { const sdk = getReadySdk(); const contents = await sdk.devGetContents(); const props: Props = { ...(await getAppStaticProps(context)), contents: contents, }; return { props: props, }; } type Report = { title: string; lines: ReportLine[]; }; type ReportLine = { subitems: string[]; name: string; type: "Error" | "Improvement" | "Missing"; severity: "High" | "Low" | "Medium" | "Very High" | "Very Low"; description: string; recommandation: string; backendUrl: string; frontendUrl: string; }; function testingContent(contents: Immutable<Props["contents"]>): Report { const report: Report = { title: "Contents", lines: [], }; contents.contents?.data.map((content) => { if (content.attributes) { const backendUrl = `${process.env.NEXT_PUBLIC_URL_CMS}/admin/content-manager/collectionType/api::content.content/${content.id}`; const frontendUrl = `${process.env.NEXT_PUBLIC_URL_SELF}/contents/${content.attributes.slug}`; if (content.attributes.categories?.data.length === 0) { report.lines.push({ subitems: [content.attributes.slug], name: "No Category", type: "Missing", severity: "Medium", description: "The Content has no Category.", recommandation: "Select a Category in relation with the Content", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!content.attributes.type?.data?.id) { report.lines.push({ subitems: [content.attributes.slug], name: "No Category", type: "Missing", severity: "Medium", description: "The Content has no Type.", recommandation: 'If unsure, use the "Other" Type.', backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (content.attributes.ranged_contents?.data.length === 0) { report.lines.push({ subitems: [content.attributes.slug], name: "No Ranged Content", type: "Improvement", severity: "Low", description: "The Content has no Ranged Content.", recommandation: "If this Content is available in one or multiple Library Item(s), create a Range Content to connect the Content to its Library Item(s).", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if ( content.attributes.next_recommended?.data?.id === content.id || content.attributes.previous_recommended?.data?.id === content.id ) { report.lines.push({ subitems: [content.attributes.slug], name: "Self Recommendation", type: "Error", severity: "Very High", description: "The Content is referring to itself as a Next or Previous Recommended.", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!content.attributes.thumbnail?.data?.id) { report.lines.push({ subitems: [content.attributes.slug], name: "No Thumbnail", type: "Missing", severity: "High", description: "The Content has no Thumbnail.", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (content.attributes.titles?.length === 0) { report.lines.push({ subitems: [content.attributes.slug], name: "No Titles", type: "Missing", severity: "High", description: "The Content has no Titles.", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } else { const titleLanguages: string[] = []; content.attributes.titles?.map((title, titleIndex) => { if (title && content.attributes) { if (title.language?.data?.id) { if (title.language.data.id in titleLanguages) { report.lines.push({ subitems: [ content.attributes.slug, `Title ${titleIndex.toString()}`, ], name: "Duplicate Language", type: "Error", severity: "High", description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } else { titleLanguages.push(title.language.data.id); } } else { report.lines.push({ subitems: [ content.attributes.slug, `Title ${titleIndex.toString()}`, ], name: "No Language", type: "Error", severity: "Very High", description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!title.description) { report.lines.push({ subitems: [ content.attributes.slug, `Title ${titleIndex.toString()}`, ], name: "No Description", type: "Missing", severity: "Medium", description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } } }); } if ( content.attributes.text_set?.length === 0 && content.attributes.audio_set?.length === 0 && content.attributes.video_set?.length === 0 ) { report.lines.push({ subitems: [content.attributes.slug], name: "No Sets", type: "Missing", severity: "Medium", description: "The Content has no Sets.", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } else { if (content.attributes.video_set?.length === 0) { report.lines.push({ subitems: [content.attributes.slug], name: "No Video Sets", type: "Missing", severity: "Very Low", description: "The Content has no Video Sets.", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (content.attributes.audio_set?.length === 0) { report.lines.push({ subitems: [content.attributes.slug], name: "No Audio Sets", type: "Missing", severity: "Very Low", description: "The Content has no Audio Sets.", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (content.attributes.text_set?.length === 0) { report.lines.push({ subitems: [content.attributes.slug], name: "No Text Set", type: "Missing", severity: "Medium", description: "The Content has no Text Set.", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } else { const textSetLanguages: string[] = []; content.attributes.text_set?.map((textSet, textSetIndex) => { if (content.attributes && textSet) { if (textSet.language?.data?.id) { if (textSet.language.data.id in textSetLanguages) { report.lines.push({ subitems: [ content.attributes.slug, `TextSet ${textSetIndex.toString()}`, ], name: "Duplicate Language", type: "Error", severity: "High", description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } else { textSetLanguages.push(textSet.language.data.id); } } else { report.lines.push({ subitems: [ content.attributes.slug, `TextSet ${textSetIndex.toString()}`, ], name: "No Language", type: "Error", severity: "Very High", description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!textSet.source_language?.data?.id) { report.lines.push({ subitems: [ content.attributes.slug, `TextSet ${textSetIndex.toString()}`, ], name: "No Source Language", type: "Error", severity: "High", description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (textSet.status !== Enum_Componentsetstextset_Status.Done) { report.lines.push({ subitems: [ content.attributes.slug, `TextSet ${textSetIndex.toString()}`, ], name: "Not Done Status", type: "Improvement", severity: "Low", description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!textSet.text || textSet.text.length < 10) { report.lines.push({ subitems: [ content.attributes.slug, `TextSet ${textSetIndex.toString()}`, ], name: "No Text", type: "Missing", severity: "Medium", description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if ( textSet.source_language?.data?.id === textSet.language?.data?.id ) { if (textSet.transcribers?.data.length === 0) { report.lines.push({ subitems: [ content.attributes.slug, `TextSet ${textSetIndex.toString()}`, ], name: "No Transcribers", type: "Missing", severity: "High", description: "The Content is a Transcription but doesn't credit any Transcribers.", recommandation: "Add the appropriate Transcribers.", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if ( textSet.translators?.data && textSet.translators.data.length > 0 ) { report.lines.push({ subitems: [ content.attributes.slug, `TextSet ${textSetIndex.toString()}`, ], name: "Credited Translators", type: "Error", severity: "High", description: "The Content is a Transcription but credits one or more Translators.", recommandation: "If appropriate, create a Translation Text Set with the Translator credited there.", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } } else { if (textSet.translators?.data.length === 0) { report.lines.push({ subitems: [ content.attributes.slug, `TextSet ${textSetIndex.toString()}`, ], name: "No Translators", type: "Missing", severity: "High", description: "The Content is a Transcription but doesn't credit any Translators.", recommandation: "Add the appropriate Translators.", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if ( textSet.transcribers?.data && textSet.transcribers.data.length > 0 ) { report.lines.push({ subitems: [ content.attributes.slug, `TextSet ${textSetIndex.toString()}`, ], name: "Credited Transcribers", type: "Error", severity: "High", description: "The Content is a Translation but credits one or more Transcribers.", recommandation: "If appropriate, create a Transcription Text Set with the Transcribers credited there.", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } } } }); } } } }); return report; }