From d5fb29d70f78a5b4ab09052ab85859255dd71665 Mon Sep 17 00:00:00 2001 From: Alexandra Goff Date: Thu, 3 Oct 2024 11:28:58 -0700 Subject: [PATCH 1/5] chore: trigger build From 050b70e54cfe7f3051bdcdde6c29fdf19952ffdd Mon Sep 17 00:00:00 2001 From: Alexandra Goff Date: Mon, 21 Oct 2024 09:37:32 -0700 Subject: [PATCH 2/5] feat: server rendered press releases + tests (#573) * chore: trigger build * fix: reject non-matching locales * fix: force dynamic rendering * feat: server rendered press releases + tests --- .eslintignore | 3 +- app/[locale]/[...uriSegments]/page.tsx | 27 +- components/templates/NewsPage/Contacts.js | 123 +- components/templates/NewsPage/NewsArticle.js | 10 +- components/templates/NewsPage/NewsHero.js | 8 +- .../NewsPage/{index.js => client.js} | 27 +- components/templates/NewsPage/index.tsx | 62 + components/templates/NewsPage/styles.js | 16 +- cypress/e2e/press-release.cy.js | 47 + lib/api/noirlab/codegen/index.ts | 4 + lib/api/noirlab/codegen/schemas.gen.ts | 2185 +++++++++++++++++ lib/api/noirlab/codegen/services.gen.ts | 45 + lib/api/noirlab/codegen/types.gen.ts | 818 ++++++ lib/api/noirlab/index.ts | 62 +- lib/i18n/{settings.js => settings.ts} | 3 +- openapi-ts.config.ts | 20 + package.json | 7 +- yarn.lock | 333 ++- 18 files changed, 3666 insertions(+), 134 deletions(-) rename components/templates/NewsPage/{index.js => client.js} (82%) create mode 100644 components/templates/NewsPage/index.tsx create mode 100644 cypress/e2e/press-release.cy.js create mode 100644 lib/api/noirlab/codegen/index.ts create mode 100644 lib/api/noirlab/codegen/schemas.gen.ts create mode 100644 lib/api/noirlab/codegen/services.gen.ts create mode 100644 lib/api/noirlab/codegen/types.gen.ts rename lib/i18n/{settings.js => settings.ts} (85%) create mode 100644 openapi-ts.config.ts diff --git a/.eslintignore b/.eslintignore index 70368638..d6c991a5 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,5 @@ .next/* node_modules out/* -storybook-static/* \ No newline at end of file +storybook-static/* +lib/api/noirlab/codegen/* diff --git a/app/[locale]/[...uriSegments]/page.tsx b/app/[locale]/[...uriSegments]/page.tsx index 8cd55db8..f564d5d6 100644 --- a/app/[locale]/[...uriSegments]/page.tsx +++ b/app/[locale]/[...uriSegments]/page.tsx @@ -10,7 +10,7 @@ import { getEntrySectionByUri, } from "@/lib/api/entries/index"; import { getEntryDataByUri } from "@/lib/api/entry"; -import { getReleaseOpenGraph } from "@/lib/api/noirlab"; +import { generateReleaseMetadata } from "@/lib/api/noirlab"; import { resizeCantoImage } from "@/lib/api/canto/resize"; import PageTemplate from "@/components/templates/Page"; import NewsPageTemplate from "@/components/templates/NewsPage"; @@ -21,20 +21,9 @@ import StaffPageTemplate from "@/components/templates/StaffPage"; import EventPageTemplate from "@/components/templates/EventPage"; const pickFeaturedImage = async ( - locale: string, image?: any, - cantoAsset?: any, - pressReleaseId?: string + cantoAsset?: any ): Promise => { - if (pressReleaseId) { - const releaseOpenGraphImage = await getReleaseOpenGraph( - locale, - pressReleaseId - ); - - return releaseOpenGraphImage; - } - if (cantoAsset) { const { width, @@ -80,14 +69,14 @@ export async function generateMetadata( pressReleaseId, } = entry; - const featuredImage = await pickFeaturedImage( - locale, - image[0], - cantoAssetSingle[0], - pressReleaseId - ); const previousImages = (await parent).openGraph?.images || []; + if (pressReleaseId) { + return generateReleaseMetadata(pressReleaseId, locale); + } + + const featuredImage = await pickFeaturedImage(image[0], cantoAssetSingle[0]); + return { title, description: striptags(description), diff --git a/components/templates/NewsPage/Contacts.js b/components/templates/NewsPage/Contacts.js index 5183a290..ec7fb8b5 100644 --- a/components/templates/NewsPage/Contacts.js +++ b/components/templates/NewsPage/Contacts.js @@ -1,5 +1,4 @@ import PropTypes from "prop-types"; -import Link from "next/link"; import { useTranslation } from "react-i18next"; import * as Styled from "./styles"; @@ -10,73 +9,71 @@ export default function Contacts({ contacts }) { return ( <> {t(`news.contacts`)} -
+ {contacts.map((contact, i) => { const { name, affiliation, city, telephone, email } = contact; return ( - - {name && ( - - - - -
-

{name}

-
-
- )} - {affiliation && ( - - - - -
-

{affiliation}

-
-
- )} - {city && ( - - - - -
-

{city}

-
-
- )} - {telephone && ( - - - - -
- {telephone} - - {telephone} - -
-
- )} - {email && ( - - - - -
- - {email} - -
-
- )} -
+
  • + + {name && ( + + + + +
    {name}
    +
    + )} + {affiliation && ( + + + + +
    {affiliation}
    +
    + )} + {city && ( + + + + +
    {city}
    +
    + )} + {telephone && ( + + + + + + + )} + {email && ( + + + + +
    + {email} +
    +
    + )} +
    +
  • ); })} -
    + ); } diff --git a/components/templates/NewsPage/NewsArticle.js b/components/templates/NewsPage/NewsArticle.js index 9fed67d2..eee45f9f 100644 --- a/components/templates/NewsPage/NewsArticle.js +++ b/components/templates/NewsPage/NewsArticle.js @@ -22,16 +22,13 @@ export default function NewsArticle({ data }) { subtitle, contacts, links, - /* eslint-disable camelcase */ - more_information: moreInformation, - release_date: releaseDate, - /* eslint-enable camelcase */ + moreInformation, headline, releaseUrl, } = data; const { t } = useTranslation(); - const localizedDate = useDateString(date || releaseDate); + const localizedDate = useDateString(date); const { ref } = useResizeObserver({ box: "border-box", onResize: ({ height }) => { @@ -58,7 +55,7 @@ export default function NewsArticle({ data }) { {subtitle && ( {subtitle} )} - + {localizedDate} {description || headline} @@ -69,6 +66,7 @@ export default function NewsArticle({ data }) { {releaseDescription && (
    diff --git a/components/templates/NewsPage/NewsHero.js b/components/templates/NewsPage/NewsHero.js index bfe8fd75..bae03067 100644 --- a/components/templates/NewsPage/NewsHero.js +++ b/components/templates/NewsPage/NewsHero.js @@ -17,9 +17,9 @@ export default function NewsHero({ if (caption) return ( - + @@ -29,10 +29,10 @@ export default function NewsHero({ ); return ( - + diff --git a/components/templates/NewsPage/index.js b/components/templates/NewsPage/client.js similarity index 82% rename from components/templates/NewsPage/index.js rename to components/templates/NewsPage/client.js index 92021ed2..d378d12b 100644 --- a/components/templates/NewsPage/index.js +++ b/components/templates/NewsPage/client.js @@ -1,24 +1,16 @@ "use client"; import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; -import { - getSiteString, - useCustomBreadcrumbs, - makeReleaseFeature, -} from "@/lib/utils"; -import { useRelease } from "@/lib/api/noirlabReleases"; +import { useCustomBreadcrumbs } from "@/lib/utils"; import Breadcrumbs from "@/page/Breadcrumbs"; import NewsHero from "./NewsHero"; import NewsArticle from "./NewsArticle"; import NewsList from "@/dynamic/NewsList"; import NewsAside from "@/components/page/Aside/patterns/Media"; import * as Styled from "./styles"; +import { getReleaseHero } from "@/lib/api/noirlab"; export default function NewsPage({ data }) { - const { data: entryWithRelease } = useRelease( - getSiteString(data?.siteHandle || "default"), - data - ); const { contentBlocksNews = [], hero = [], @@ -32,10 +24,11 @@ export default function NewsPage({ data }) { uri, images: releaseImages, videos: releaseVideos, - } = entryWithRelease || data; + } = data; - const heroImage = - hero?.length > 0 ? hero : makeReleaseFeature(releaseImages, "banner1920"); + if (hero.length === 0 && releaseImages) { + hero.push(getReleaseHero(releaseImages)); + } const { t } = useTranslation(); @@ -74,7 +67,7 @@ export default function NewsPage({ data }) { } }); // If there is a hero then combine it with the content block media assets - if (heroBlock) mediaContentBlocks.unshift(heroBlock); + if (heroBlock && !releaseImages) mediaContentBlocks.unshift(heroBlock); // Only show the aside if there are news assets const showAside = @@ -89,14 +82,12 @@ export default function NewsPage({ data }) { - {(entryWithRelease || data) && ( - - )} + {data && } {showAside && ( = async ({ data, section, locale }) => { + const { pressReleaseId } = data; + + if (pressReleaseId) { + const { data: release, error } = await ReleasesService.releasesRetrieve({ + path: { id: pressReleaseId }, + query: { + lang: locale as Locale, + translation_mode: "fallback", + }, + }); + + if (!error && release) { + const { + title, + url: releaseUrl, + description, + headline, + subtitle, + images, + videos, + release_date: date, + more_information: moreInformation, + links, + contacts, + } = release; + + const combinedData = { + ...data, + title, + releaseUrl, + headline, + subtitle, + releaseDescription: description ? sanitizeHtml(description) : undefined, + moreInformation: moreInformation + ? sanitizeHtml(moreInformation) + : undefined, + links: links ? sanitizeHtml(links) : links, + contacts, + date, + images, + videos, + }; + + return ; + } + } + + return ; +}; + +export default NewsPage; diff --git a/components/templates/NewsPage/styles.js b/components/templates/NewsPage/styles.js index a901ba13..cb9681a0 100644 --- a/components/templates/NewsPage/styles.js +++ b/components/templates/NewsPage/styles.js @@ -102,7 +102,7 @@ export const NewsDetail = styled.div` } `; -export const Pretitle = styled.div` +export const Pretitle = styled.time` padding-bottom: 10px; `; @@ -122,18 +122,18 @@ export const ArticleHeading = styled.h3` export const ContactList = styled.ul` display: block; - + ul { - margin-top: 25px; + & > * + * { + margin-block-start: 25px; } `; -export const ContactListItem = styled.li` +export const Contact = styled.address` + font-style: normal; +`; + +export const ContactRow = styled.div` display: flex; align-items: center; - - + & { - margin-top: 10px; - } `; export const IconWrapper = styled.div` diff --git a/cypress/e2e/press-release.cy.js b/cypress/e2e/press-release.cy.js new file mode 100644 index 00000000..74b26fbb --- /dev/null +++ b/cypress/e2e/press-release.cy.js @@ -0,0 +1,47 @@ +describe("Press release", () => { + beforeEach(() => { + // Cypress starts out with a blank slate for each test + // so we must tell it to visit our website with the `cy.visit()` command. + // Since we want to visit the same URL at the start of all our tests, + // we include it in our beforeEach function so that it runs before each test + cy.visit("/news/rubin-reveal-stellar-streams"); + }); + + it("Has page metadata", () => { + cy.document() + .get('head meta[name="description"]') + .should("have.attr", "content"); + }); + it("Has a banner image", () => { + cy.get("[data-cy=hero] > img") + .invoke("attr", "alt") + .should("have.length.gt", 0); + cy.get("[data-cy=hero] > img") + .invoke("attr", "src") + .should("have.length.gt", 0); + cy.get("[data-cy=hero] > img").should("have.attr", "loading", "eager"); + }); + it("Has a headline", () => { + cy.get("h1").invoke("text").should("have.length.gt", 0); + }); + it("Has a release date", () => { + cy.get("time").invoke("text").should("have.length.gt", 0); + cy.get("time").should("have.attr", "datetime"); + }); + it("Has some text content", () => { + cy.get("[data-cy=press-release-text]") + .invoke("text") + .should("have.length.gt", 0); + }); + it("Has additional information", () => { + cy.contains("h3", "More Information") + .siblings() + .should("have.class", "c-content-rte"); + }); + it("Has links", () => { + cy.contains("h3", "Links").siblings().contains("ul"); + }); + it("Has contacts", () => { + cy.contains("h3", "Contacts").siblings().contains("li"); + }); +}); diff --git a/lib/api/noirlab/codegen/index.ts b/lib/api/noirlab/codegen/index.ts new file mode 100644 index 00000000..1cb041de --- /dev/null +++ b/lib/api/noirlab/codegen/index.ts @@ -0,0 +1,4 @@ +// This file is auto-generated by @hey-api/openapi-ts +export * from "./schemas.gen"; +export * from "./services.gen"; +export * from "./types.gen"; diff --git a/lib/api/noirlab/codegen/schemas.gen.ts b/lib/api/noirlab/codegen/schemas.gen.ts new file mode 100644 index 00000000..ed8f983d --- /dev/null +++ b/lib/api/noirlab/codegen/schemas.gen.ts @@ -0,0 +1,2185 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export const ActivitySchema = { + type: "object", + properties: { + id: { + type: "string", + description: "ID of the activity, also used in URLs", + maxLength: 50, + pattern: "^[-a-zA-Z0-9_]+$", + }, + name: { + type: "string", + maxLength: 100, + }, + title: { + type: "string", + nullable: true, + description: + "title to be displayed in the activity description when the activity is joined with other activities", + maxLength: 100, + }, + slogan: { + type: "string", + maxLength: 255, + }, + observatory: { + type: "string", + maxLength: 50, + }, + key_visual_en: { + type: "string", + readOnly: true, + }, + key_visual_es: { + type: "string", + readOnly: true, + }, + duration: { + type: "string", + description: "Format: HH:MM", + }, + safety_tech_doc: { + type: "string", + readOnly: true, + }, + conduct_tech_doc: { + type: "string", + readOnly: true, + }, + liability_tech_doc: { + type: "string", + readOnly: true, + }, + safety_tech_doc_es: { + type: "string", + readOnly: true, + }, + conduct_tech_doc_es: { + type: "string", + readOnly: true, + }, + liability_tech_doc_es: { + type: "string", + readOnly: true, + }, + group_safety_tech_doc: { + type: "string", + readOnly: true, + }, + group_liability_tech_doc: { + type: "string", + readOnly: true, + }, + group_safety_tech_doc_es: { + type: "string", + readOnly: true, + }, + group_liability_tech_doc_es: { + type: "string", + readOnly: true, + }, + }, + required: [ + "conduct_tech_doc", + "conduct_tech_doc_es", + "duration", + "group_liability_tech_doc", + "group_liability_tech_doc_es", + "group_safety_tech_doc", + "group_safety_tech_doc_es", + "id", + "key_visual_en", + "key_visual_es", + "liability_tech_doc", + "liability_tech_doc_es", + "name", + "observatory", + "safety_tech_doc", + "safety_tech_doc_es", + ], +} as const; + +export const AnnouncementSchema = { + type: "object", + properties: { + id: { + type: "string", + description: + "Ids are only allowed to contain letters, numbers, underscores or hyphens. They are used in URLs for the archive item.", + maxLength: 50, + pattern: "^[-a-zA-Z0-9_]+$", + }, + lang: { + type: "string", + title: "Language", + maxLength: 7, + }, + url: { + type: "string", + readOnly: true, + }, + title: { + type: "string", + description: + "Title is shown in browser window. Use a good informative title, since search engines normally display the title on their result pages.", + maxLength: 200, + }, + subtitle: { + type: "string", + description: "Optional subtitle to be shown just above the headline.", + maxLength: 255, + }, + description: { + type: "string", + }, + contacts: { + type: "string", + description: "Contacts", + }, + links: { + type: "string", + description: "Links", + }, + featured: { + type: "boolean", + }, + release_date: { + type: "string", + readOnly: true, + }, + programs: { + type: "array", + items: { + $ref: "#/components/schemas/Program", + }, + }, + images: { + type: "array", + items: { + $ref: "#/components/schemas/ImageMini", + }, + readOnly: true, + }, + videos: { + type: "array", + items: { + $ref: "#/components/schemas/VideoMini", + }, + readOnly: true, + }, + }, + required: [ + "id", + "images", + "programs", + "release_date", + "title", + "url", + "videos", + ], +} as const; + +export const AnnouncementMiniSchema = { + type: "object", + properties: { + id: { + type: "string", + description: + "Ids are only allowed to contain letters, numbers, underscores or hyphens. They are used in URLs for the archive item.", + maxLength: 50, + pattern: "^[-a-zA-Z0-9_]+$", + }, + lang: { + type: "string", + title: "Language", + maxLength: 7, + }, + url: { + type: "string", + readOnly: true, + }, + title: { + type: "string", + description: + "Title is shown in browser window. Use a good informative title, since search engines normally display the title on their result pages.", + maxLength: 200, + }, + subtitle: { + type: "string", + description: "Optional subtitle to be shown just above the headline.", + maxLength: 255, + }, + release_date: { + type: "string", + readOnly: true, + }, + programs: { + type: "array", + items: { + $ref: "#/components/schemas/Program", + }, + }, + main_image: { + allOf: [ + { + $ref: "#/components/schemas/ImageMini", + }, + ], + readOnly: true, + }, + }, + required: ["id", "main_image", "programs", "release_date", "title", "url"], +} as const; + +export const AuthorDescriptionSchema = { + type: "object", + properties: { + name: { + type: "string", + readOnly: true, + }, + description: { + type: "string", + description: + 'Optional description, e.g.: "Author: ", or "Interview with"', + maxLength: 100, + }, + photo: { + type: "string", + readOnly: true, + }, + static_photo: { + type: "string", + description: "Direct link to a JPG image, recommended size: 350px wide", + readOnly: true, + }, + }, + required: ["name", "photo", "static_photo"], +} as const; + +export const BlankEnumSchema = { + enum: [""], +} as const; + +export const CategorySchema = { + type: "object", + properties: { + slug: { + type: "string", + }, + name: { + type: "string", + description: "Title of query to be displayed to the user.", + maxLength: 255, + }, + logo_url: { + type: "string", + format: "uri", + nullable: true, + maxLength: 255, + }, + }, + required: ["name", "slug"], +} as const; + +export const ImageSchema = { + type: "object", + properties: { + id: { + type: "string", + description: + "Id of image - used in the URL for the image as well as the filename for the different formats.", + maxLength: 50, + pattern: "^[-a-zA-Z0-9_]+$", + }, + url: { + type: "string", + readOnly: true, + }, + lang: { + type: "string", + title: "Language", + maxLength: 7, + }, + source: { + type: "string", + description: + "Id of image - used in the URL for the image as well as the filename for the different formats.", + nullable: true, + title: "Translation source", + }, + title: { + type: "string", + description: "General descriptive title given to the image resource.", + maxLength: 255, + }, + headline: { + type: "string", + nullable: true, + description: "Short description of the full caption.", + }, + description: { + type: "string", + nullable: true, + description: + "Full caption and related description text for the image resource.", + }, + categories: { + type: "array", + items: { + $ref: "#/components/schemas/Category", + }, + }, + type: { + nullable: true, + description: `The type of image/media resource. + +* \`Observation\` - Observation +* \`Artwork\` - Artwork +* \`Photographic\` - Photographic +* \`Planetary\` - Planetary +* \`Simulation\` - Simulation +* \`Collage\` - Collage +* \`Chart\` - Chart`, + oneOf: [ + { + $ref: "#/components/schemas/TypeEnum", + }, + { + $ref: "#/components/schemas/BlankEnum", + }, + { + $ref: "#/components/schemas/NullEnum", + }, + ], + }, + credit: { + type: "string", + description: + "The minimum information that the Publisher would like to see mentioned when the resource is used.", + }, + release_date: { + type: "string", + readOnly: true, + }, + width: { + type: "integer", + maximum: 2147483647, + minimum: 0, + nullable: true, + description: "Width in pixels of the image resource.", + }, + height: { + type: "integer", + maximum: 2147483647, + minimum: 0, + nullable: true, + description: "Height in pixels of the image resource.", + }, + featured: { + type: "boolean", + }, + subject_name: { + type: "array", + items: { + type: "string", + }, + }, + resources: { + type: "array", + items: { + type: "object", + properties: { + ResourceType: { + type: "string", + }, + MediaType: { + type: "string", + }, + URL: { + type: "string", + }, + FileSize: { + type: "integer", + nullable: true, + }, + Dimensions: { + type: "array", + items: { + type: "integer", + }, + nullable: true, + }, + ProjectionType: { + type: "string", + nullable: true, + }, + }, + }, + readOnly: true, + }, + formats: { + type: "object", + properties: { + banner1920: { + type: "string", + nullable: true, + }, + eps: { + type: "string", + nullable: true, + }, + illustrator: { + type: "string", + nullable: true, + }, + illustrator_text: { + type: "string", + nullable: true, + }, + large: { + type: "string", + nullable: true, + }, + medium: { + type: "string", + nullable: true, + }, + news: { + type: "string", + nullable: true, + }, + newsfeature: { + type: "string", + nullable: true, + }, + newsmini: { + type: "string", + nullable: true, + }, + original: { + type: "string", + nullable: true, + }, + pdf: { + type: "string", + nullable: true, + }, + pl_original: { + type: "string", + nullable: true, + }, + pl_screen: { + type: "string", + nullable: true, + }, + pl_thumbs: { + type: "string", + nullable: true, + }, + portrait1080: { + type: "string", + nullable: true, + }, + poster400y: { + type: "string", + nullable: true, + }, + potwmedium: { + type: "string", + nullable: true, + }, + publicationjpg: { + type: "string", + nullable: true, + }, + publicationtiff: { + type: "string", + nullable: true, + }, + publicationtiff10k: { + type: "string", + nullable: true, + }, + publicationtiff25k: { + type: "string", + nullable: true, + }, + publicationtiff40k: { + type: "string", + nullable: true, + }, + screen: { + type: "string", + nullable: true, + }, + screen640: { + type: "string", + nullable: true, + }, + thumb150y: { + type: "string", + nullable: true, + }, + thumb300y: { + type: "string", + nullable: true, + }, + thumb350x: { + type: "string", + nullable: true, + }, + thumb700x: { + type: "string", + nullable: true, + }, + thumbs: { + type: "string", + nullable: true, + }, + wallpaper1: { + type: "string", + nullable: true, + }, + wallpaper2: { + type: "string", + nullable: true, + }, + wallpaper3: { + type: "string", + nullable: true, + }, + wallpaper4: { + type: "string", + nullable: true, + }, + wallpaper5: { + type: "string", + nullable: true, + }, + wallpaperthumbs: { + type: "string", + nullable: true, + }, + zoomable: { + type: "string", + nullable: true, + }, + }, + readOnly: true, + }, + }, + required: [ + "categories", + "formats", + "id", + "release_date", + "resources", + "subject_name", + "title", + "url", + ], +} as const; + +export const ImageItemSchema = { + oneOf: [ + { + $ref: "#/components/schemas/ImageTiny", + }, + { + $ref: "#/components/schemas/ImageMini", + }, + ], +} as const; + +export const ImageMiniSchema = { + type: "object", + properties: { + id: { + type: "string", + description: + "Id of image - used in the URL for the image as well as the filename for the different formats.", + maxLength: 50, + pattern: "^[-a-zA-Z0-9_]+$", + }, + url: { + type: "string", + readOnly: true, + }, + lang: { + type: "string", + title: "Language", + maxLength: 7, + }, + source: { + type: "string", + description: + "Id of image - used in the URL for the image as well as the filename for the different formats.", + nullable: true, + title: "Translation source", + }, + title: { + type: "string", + description: "General descriptive title given to the image resource.", + maxLength: 255, + }, + width: { + type: "integer", + maximum: 2147483647, + minimum: 0, + nullable: true, + description: "Width in pixels of the image resource.", + }, + height: { + type: "integer", + maximum: 2147483647, + minimum: 0, + nullable: true, + description: "Height in pixels of the image resource.", + }, + featured: { + type: "boolean", + }, + categories: { + type: "array", + items: { + $ref: "#/components/schemas/Category", + }, + }, + formats: { + type: "object", + properties: { + banner1920: { + type: "string", + nullable: true, + }, + eps: { + type: "string", + nullable: true, + }, + illustrator: { + type: "string", + nullable: true, + }, + illustrator_text: { + type: "string", + nullable: true, + }, + large: { + type: "string", + nullable: true, + }, + medium: { + type: "string", + nullable: true, + }, + news: { + type: "string", + nullable: true, + }, + newsfeature: { + type: "string", + nullable: true, + }, + newsmini: { + type: "string", + nullable: true, + }, + original: { + type: "string", + nullable: true, + }, + pdf: { + type: "string", + nullable: true, + }, + pl_original: { + type: "string", + nullable: true, + }, + pl_screen: { + type: "string", + nullable: true, + }, + pl_thumbs: { + type: "string", + nullable: true, + }, + portrait1080: { + type: "string", + nullable: true, + }, + poster400y: { + type: "string", + nullable: true, + }, + potwmedium: { + type: "string", + nullable: true, + }, + publicationjpg: { + type: "string", + nullable: true, + }, + publicationtiff: { + type: "string", + nullable: true, + }, + publicationtiff10k: { + type: "string", + nullable: true, + }, + publicationtiff25k: { + type: "string", + nullable: true, + }, + publicationtiff40k: { + type: "string", + nullable: true, + }, + screen: { + type: "string", + nullable: true, + }, + screen640: { + type: "string", + nullable: true, + }, + thumb150y: { + type: "string", + nullable: true, + }, + thumb300y: { + type: "string", + nullable: true, + }, + thumb350x: { + type: "string", + nullable: true, + }, + thumb700x: { + type: "string", + nullable: true, + }, + thumbs: { + type: "string", + nullable: true, + }, + wallpaper1: { + type: "string", + nullable: true, + }, + wallpaper2: { + type: "string", + nullable: true, + }, + wallpaper3: { + type: "string", + nullable: true, + }, + wallpaper4: { + type: "string", + nullable: true, + }, + wallpaper5: { + type: "string", + nullable: true, + }, + wallpaperthumbs: { + type: "string", + nullable: true, + }, + zoomable: { + type: "string", + nullable: true, + }, + }, + readOnly: true, + }, + }, + required: ["categories", "formats", "id", "title", "url"], +} as const; + +export const ImageTinySchema = { + type: "object", + properties: { + id: { + type: "string", + description: + "Id of image - used in the URL for the image as well as the filename for the different formats.", + maxLength: 50, + pattern: "^[-a-zA-Z0-9_]+$", + }, + url: { + type: "string", + readOnly: true, + }, + lang: { + type: "string", + title: "Language", + maxLength: 7, + }, + title: { + type: "string", + description: "General descriptive title given to the image resource.", + maxLength: 255, + }, + width: { + type: "integer", + maximum: 2147483647, + minimum: 0, + nullable: true, + description: "Width in pixels of the image resource.", + }, + height: { + type: "integer", + maximum: 2147483647, + minimum: 0, + nullable: true, + description: "Height in pixels of the image resource.", + }, + formats: { + type: "object", + properties: { + thumb300y: { + type: "string", + nullable: true, + }, + screen: { + type: "string", + nullable: true, + }, + thumb700x: { + type: "string", + nullable: true, + }, + }, + readOnly: true, + }, + }, + required: ["formats", "id", "title", "url"], +} as const; + +export const Model3dSchema = { + type: "object", + properties: { + id: { + type: "string", + description: + "Ids are only allowed to contain letters, numbers, underscores or hyphens. They are used in URLs for the archive item.", + maxLength: 50, + pattern: "^[-a-zA-Z0-9_]+$", + }, + title: { + type: "string", + description: + "Title is shown in browser window. Use a good informative title, since search engines normally display the title on their result pages.", + maxLength: 200, + }, + description: { + type: "string", + }, + credit: { + type: "string", + readOnly: true, + }, + priority: { + type: "integer", + maximum: 32767, + minimum: 0, + description: + "Priority of product (100 highest, 0 lowest) - high priority products are ranked higher in search results than low priority products.", + }, + release_date: { + type: "string", + readOnly: true, + }, + assets: { + type: "string", + readOnly: true, + }, + }, + required: ["assets", "credit", "id", "release_date", "title"], +} as const; + +export const NullEnumSchema = { + enum: [null], +} as const; + +export const PageSchema = { + type: "object", + properties: { + title: { + type: "string", + description: + "Title is shown in browser window. Use a good informative title, since search engines normally display the title on their result pages.", + maxLength: 200, + }, + content: { + type: "string", + }, + description: { + type: "string", + description: + "The metadata description is normally shown in search engine results, making the description an effective way of capturing users attention. Description should be a clear description of the content and less the 200 characters long. Also used when sharing page on social media", + }, + keywords: { + type: "string", + description: + "Comma-separated list of keywords for this page. Mainly used internally as search engines rarely use keywords to rank pages.", + }, + }, + required: ["title"], +} as const; + +export const PageRequestSchema = { + type: "object", + properties: { + title: { + type: "string", + minLength: 1, + description: + "Title is shown in browser window. Use a good informative title, since search engines normally display the title on their result pages.", + maxLength: 200, + }, + content: { + type: "string", + }, + description: { + type: "string", + description: + "The metadata description is normally shown in search engine results, making the description an effective way of capturing users attention. Description should be a clear description of the content and less the 200 characters long. Also used when sharing page on social media", + }, + keywords: { + type: "string", + description: + "Comma-separated list of keywords for this page. Mainly used internally as search engines rarely use keywords to rank pages.", + }, + }, + required: ["title"], +} as const; + +export const PaginatedAnnouncementMiniListSchema = { + type: "object", + properties: { + count: { + type: "integer", + example: 123, + }, + next: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=4", + }, + previous: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=2", + }, + results: { + type: "array", + items: { + $ref: "#/components/schemas/AnnouncementMini", + }, + }, + }, +} as const; + +export const PaginatedImageItemListSchema = { + type: "object", + properties: { + count: { + type: "integer", + example: 123, + }, + next: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=4", + }, + previous: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=2", + }, + results: { + type: "array", + items: { + $ref: "#/components/schemas/ImageItem", + }, + }, + }, +} as const; + +export const PaginatedImageListSchema = { + type: "object", + properties: { + count: { + type: "integer", + example: 123, + }, + next: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=4", + }, + previous: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=2", + }, + results: { + type: "array", + items: { + $ref: "#/components/schemas/Image", + }, + }, + }, +} as const; + +export const PaginatedModel3dListSchema = { + type: "object", + properties: { + count: { + type: "integer", + example: 123, + }, + next: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=4", + }, + previous: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=2", + }, + results: { + type: "array", + items: { + $ref: "#/components/schemas/Model3d", + }, + }, + }, +} as const; + +export const PaginatedPodcastListSchema = { + type: "object", + properties: { + count: { + type: "integer", + example: 123, + }, + next: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=4", + }, + previous: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=2", + }, + results: { + type: "array", + items: { + $ref: "#/components/schemas/Podcast", + }, + }, + }, +} as const; + +export const PaginatedReleaseMiniListSchema = { + type: "object", + properties: { + count: { + type: "integer", + example: 123, + }, + next: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=4", + }, + previous: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=2", + }, + results: { + type: "array", + items: { + $ref: "#/components/schemas/ReleaseMini", + }, + }, + }, +} as const; + +export const PaginatedVideoListSchema = { + type: "object", + properties: { + count: { + type: "integer", + example: 123, + }, + next: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=4", + }, + previous: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=2", + }, + results: { + type: "array", + items: { + $ref: "#/components/schemas/Video", + }, + }, + }, +} as const; + +export const PaginatedVideoMiniListSchema = { + type: "object", + properties: { + count: { + type: "integer", + example: 123, + }, + next: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=4", + }, + previous: { + type: "string", + nullable: true, + format: "uri", + example: "http://api.example.org/accounts/?page=2", + }, + results: { + type: "array", + items: { + $ref: "#/components/schemas/VideoMini", + }, + }, + }, +} as const; + +export const PatchedPageRequestSchema = { + type: "object", + properties: { + title: { + type: "string", + minLength: 1, + description: + "Title is shown in browser window. Use a good informative title, since search engines normally display the title on their result pages.", + maxLength: 200, + }, + content: { + type: "string", + }, + description: { + type: "string", + description: + "The metadata description is normally shown in search engine results, making the description an effective way of capturing users attention. Description should be a clear description of the content and less the 200 characters long. Also used when sharing page on social media", + }, + keywords: { + type: "string", + description: + "Comma-separated list of keywords for this page. Mainly used internally as search engines rarely use keywords to rank pages.", + }, + }, +} as const; + +export const PodcastSchema = { + type: "object", + properties: { + id: { + type: "string", + description: + "Ids are only allowed to contain letters, numbers, underscores or hyphens. They are used in URLs for the archive item.", + maxLength: 50, + pattern: "^[-a-zA-Z0-9_]+$", + }, + title: { + type: "string", + description: + "Title is shown in browser window. Use a good informative title, since search engines normally display the title on their result pages.", + maxLength: 200, + }, + description: { + type: "string", + }, + credit: { + type: "string", + readOnly: true, + }, + priority: { + type: "integer", + maximum: 32767, + minimum: 0, + description: + "Priority of product (100 highest, 0 lowest) - high priority products are ranked higher in search results than low priority products.", + }, + release_date: { + type: "string", + readOnly: true, + }, + assets: { + type: "string", + readOnly: true, + }, + }, + required: ["assets", "credit", "id", "release_date", "title"], +} as const; + +export const PostSchema = { + type: "object", + properties: { + id: { + type: "string", + readOnly: true, + }, + slug: { + type: "string", + description: "Used for the URL, this cannot be updated later", + maxLength: 50, + pattern: "^[-a-zA-Z0-9_]+$", + }, + url: { + type: "string", + readOnly: true, + }, + title: { + type: "string", + maxLength: 255, + }, + subtitle: { + type: "string", + description: "Optional subtitle", + maxLength: 255, + }, + banner: { + type: "string", + readOnly: true, + }, + authors: { + type: "array", + items: { + $ref: "#/components/schemas/AuthorDescription", + }, + }, + category: { + allOf: [ + { + $ref: "#/components/schemas/Category", + }, + ], + readOnly: true, + }, + lede: { + type: "string", + }, + release_date: { + type: "string", + format: "date-time", + nullable: true, + }, + }, + required: [ + "authors", + "banner", + "category", + "id", + "lede", + "slug", + "title", + "url", + ], +} as const; + +export const ProgramSchema = { + type: "object", + properties: { + slug: { + type: "string", + }, + name: { + type: "string", + description: "Title of query to be displayed to the user.", + maxLength: 255, + }, + logo_url: { + type: "string", + format: "uri", + nullable: true, + maxLength: 255, + }, + }, + required: ["name", "slug"], +} as const; + +export const ReleaseSchema = { + type: "object", + properties: { + id: { + type: "string", + description: "Id of release - e.g. heic0801. The id must be unique.", + maxLength: 50, + pattern: "^[-a-zA-Z0-9_]+$", + }, + lang: { + type: "string", + title: "Language", + maxLength: 7, + }, + url: { + type: "string", + readOnly: true, + }, + title: { + type: "string", + description: + "Title is shown in browser window. Use a good informative title, since search engines normally display the title on their result pages.", + maxLength: 255, + }, + release_type: { + type: "string", + readOnly: true, + }, + subtitle: { + type: "string", + description: "Optional subtitle to be shown just above the headline.", + maxLength: 255, + }, + headline: { + type: "string", + description: + "HTML code in lead is not allowed. The lead is further more normally shown in search engine results, making the description an effective way of capturing users attention.", + }, + release_date: { + type: "string", + readOnly: true, + }, + description: { + type: "string", + }, + notes: { + type: "string", + }, + more_information: { + type: "string", + }, + links: { + type: "string", + description: "Help text", + }, + disclaimer: { + type: "string", + description: + "Disclaimer for press release - usually e.g. retractions of previously issued press releases.", + }, + programs: { + type: "array", + items: { + $ref: "#/components/schemas/Program", + }, + }, + images: { + type: "array", + items: { + $ref: "#/components/schemas/ImageMini", + }, + readOnly: true, + }, + videos: { + type: "array", + items: { + $ref: "#/components/schemas/VideoMini", + }, + readOnly: true, + }, + contacts: { + type: "array", + items: { + $ref: "#/components/schemas/ReleaseContact", + }, + }, + }, + required: [ + "contacts", + "id", + "images", + "programs", + "release_date", + "release_type", + "title", + "url", + "videos", + ], +} as const; + +export const ReleaseContactSchema = { + type: "object", + properties: { + name: { + type: "string", + maxLength: 255, + }, + email: { + type: "string", + maxLength: 255, + }, + telephone: { + type: "string", + maxLength: 255, + }, + cellular: { + type: "string", + maxLength: 255, + }, + affiliation: { + type: "string", + maxLength: 255, + }, + address: { + type: "string", + maxLength: 255, + }, + city: { + type: "string", + maxLength: 255, + }, + state_province: { + type: "string", + maxLength: 255, + }, + postal_code: { + type: "string", + maxLength: 255, + }, + country: { + type: "string", + maxLength: 255, + }, + }, +} as const; + +export const ReleaseMiniSchema = { + type: "object", + properties: { + id: { + type: "string", + description: "Id of release - e.g. heic0801. The id must be unique.", + maxLength: 50, + pattern: "^[-a-zA-Z0-9_]+$", + }, + lang: { + type: "string", + title: "Language", + maxLength: 7, + }, + url: { + type: "string", + readOnly: true, + }, + release_type: { + type: "string", + readOnly: true, + }, + title: { + type: "string", + description: + "Title is shown in browser window. Use a good informative title, since search engines normally display the title on their result pages.", + maxLength: 255, + }, + subtitle: { + type: "string", + description: "Optional subtitle to be shown just above the headline.", + maxLength: 255, + }, + headline: { + type: "string", + description: + "HTML code in lead is not allowed. The lead is further more normally shown in search engine results, making the description an effective way of capturing users attention.", + }, + release_date: { + type: "string", + readOnly: true, + }, + programs: { + type: "array", + items: { + $ref: "#/components/schemas/Program", + }, + }, + main_image: { + allOf: [ + { + $ref: "#/components/schemas/ImageMini", + }, + ], + readOnly: true, + }, + }, + required: [ + "id", + "main_image", + "programs", + "release_date", + "release_type", + "title", + "url", + ], +} as const; + +export const ShowingSchema = { + type: "object", + properties: { + id: { + type: "integer", + readOnly: true, + }, + start_time: { + type: "string", + readOnly: true, + }, + formatted_start_time: { + type: "string", + readOnly: true, + }, + free_spaces: { + type: "integer", + }, + }, + required: ["formatted_start_time", "free_spaces", "id", "start_time"], +} as const; + +export const TypeEnumSchema = { + enum: [ + "Observation", + "Artwork", + "Photographic", + "Planetary", + "Simulation", + "Collage", + "Chart", + ], + type: "string", + description: `* \`Observation\` - Observation +* \`Artwork\` - Artwork +* \`Photographic\` - Photographic +* \`Planetary\` - Planetary +* \`Simulation\` - Simulation +* \`Collage\` - Collage +* \`Chart\` - Chart`, +} as const; + +export const VideoSchema = { + type: "object", + properties: { + id: { + type: "string", + description: + "Id of video - used in the URL for the image as well as the filename for the different formats.", + maxLength: 50, + pattern: "^[-a-zA-Z0-9_]+$", + }, + url: { + type: "string", + readOnly: true, + }, + lang: { + type: "string", + title: "Language", + maxLength: 7, + }, + source: { + type: "string", + description: + "Id of video - used in the URL for the image as well as the filename for the different formats.", + nullable: true, + title: "Translation source", + }, + title: { + type: "string", + description: "General descriptive title given to the image resource.", + maxLength: 255, + }, + headline: { + type: "string", + nullable: true, + description: "Short description of the full caption.", + }, + description: { + type: "string", + nullable: true, + description: + "Full caption and related description text for the image resource.", + }, + categories: { + type: "array", + items: { + $ref: "#/components/schemas/Category", + }, + }, + type: { + nullable: true, + description: `The type of image/media resource. + +* \`Observation\` - Observation +* \`Artwork\` - Artwork +* \`Photographic\` - Photographic +* \`Planetary\` - Planetary +* \`Simulation\` - Simulation +* \`Collage\` - Collage +* \`Chart\` - Chart`, + oneOf: [ + { + $ref: "#/components/schemas/TypeEnum", + }, + { + $ref: "#/components/schemas/BlankEnum", + }, + { + $ref: "#/components/schemas/NullEnum", + }, + ], + }, + credit: { + type: "string", + description: + "The minimum information that the Publisher would like to see mentioned when the resource is used.", + }, + release_date: { + type: "string", + readOnly: true, + }, + featured: { + type: "boolean", + }, + duration: { + type: "string", + nullable: true, + readOnly: true, + }, + youtube_video_id: { + type: "string", + nullable: true, + title: "YouTube VideoID", + maxLength: 11, + }, + use_youtube: { + type: "boolean", + title: "Use YouTube player", + }, + formats: { + type: "object", + properties: { + broadcast_sd: { + type: "string", + nullable: true, + }, + cylindrical_16kmaster: { + type: "string", + nullable: true, + }, + cylindrical_4kmaster: { + type: "string", + nullable: true, + }, + cylindrical_8kmaster: { + type: "string", + nullable: true, + }, + cylindrical_preview: { + type: "string", + nullable: true, + }, + dome_2kmaster: { + type: "string", + nullable: true, + }, + dome_2kplayback: { + type: "string", + nullable: true, + }, + dome_4kmaster: { + type: "string", + nullable: true, + }, + dome_4kplayback: { + type: "string", + nullable: true, + }, + dome_8kmaster: { + type: "string", + nullable: true, + }, + dome_mov: { + type: "string", + nullable: true, + }, + dome_preview: { + type: "string", + nullable: true, + }, + ext_highres: { + type: "string", + nullable: true, + }, + ext_playback: { + type: "string", + nullable: true, + }, + hd_1080_broadcast: { + type: "string", + nullable: true, + }, + hd_1080_screen: { + type: "string", + nullable: true, + }, + hd_1080p25_broadcast: { + type: "string", + nullable: true, + }, + hd_1080p25_screen: { + type: "string", + nullable: true, + }, + hd_and_apple: { + type: "string", + nullable: true, + }, + hd_broadcast_720p25: { + type: "string", + nullable: true, + }, + hd_broadcast_720p50: { + type: "string", + nullable: true, + }, + large_qt: { + type: "string", + nullable: true, + }, + medium_flash: { + type: "string", + nullable: true, + }, + medium_mpeg1: { + type: "string", + nullable: true, + }, + medium_podcast: { + type: "string", + nullable: true, + }, + news: { + type: "string", + nullable: true, + }, + newsfeature: { + type: "string", + nullable: true, + }, + newsmini: { + type: "string", + nullable: true, + }, + old_video: { + type: "string", + nullable: true, + }, + original: { + type: "string", + nullable: true, + }, + potwmedium: { + type: "string", + nullable: true, + }, + qtvr: { + type: "string", + nullable: true, + }, + script: { + type: "string", + nullable: true, + }, + small_flash: { + type: "string", + nullable: true, + }, + small_qt: { + type: "string", + nullable: true, + }, + thumb: { + type: "string", + nullable: true, + }, + thumb300y: { + type: "string", + nullable: true, + }, + thumb350x: { + type: "string", + nullable: true, + }, + ultra_hd: { + type: "string", + nullable: true, + }, + ultra_hd_8k_broadcast: { + type: "string", + nullable: true, + }, + ultra_hd_8k_h265: { + type: "string", + nullable: true, + }, + ultra_hd_broadcast: { + type: "string", + nullable: true, + }, + ultra_hd_h265: { + type: "string", + nullable: true, + }, + videoframe: { + type: "string", + nullable: true, + }, + vr_16kmaster: { + type: "string", + nullable: true, + }, + vr_2k_sos: { + type: "string", + nullable: true, + }, + vr_4k: { + type: "string", + nullable: true, + }, + vr_4k_sos: { + type: "string", + nullable: true, + }, + vr_4kmaster: { + type: "string", + nullable: true, + }, + vr_8k: { + type: "string", + nullable: true, + }, + vr_8kmaster: { + type: "string", + nullable: true, + }, + }, + readOnly: true, + }, + }, + required: [ + "categories", + "duration", + "formats", + "id", + "release_date", + "title", + "url", + ], +} as const; + +export const VideoMiniSchema = { + type: "object", + properties: { + id: { + type: "string", + description: + "Id of video - used in the URL for the image as well as the filename for the different formats.", + maxLength: 50, + pattern: "^[-a-zA-Z0-9_]+$", + }, + url: { + type: "string", + readOnly: true, + }, + lang: { + type: "string", + title: "Language", + maxLength: 7, + }, + source: { + type: "string", + description: + "Id of video - used in the URL for the image as well as the filename for the different formats.", + nullable: true, + title: "Translation source", + }, + title: { + type: "string", + description: "General descriptive title given to the image resource.", + maxLength: 255, + }, + featured: { + type: "boolean", + }, + duration: { + type: "string", + nullable: true, + readOnly: true, + }, + categories: { + type: "array", + items: { + $ref: "#/components/schemas/Category", + }, + }, + youtube_video_id: { + type: "string", + nullable: true, + title: "YouTube VideoID", + maxLength: 11, + }, + use_youtube: { + type: "boolean", + title: "Use YouTube player", + }, + formats: { + type: "object", + properties: { + broadcast_sd: { + type: "string", + nullable: true, + }, + cylindrical_16kmaster: { + type: "string", + nullable: true, + }, + cylindrical_4kmaster: { + type: "string", + nullable: true, + }, + cylindrical_8kmaster: { + type: "string", + nullable: true, + }, + cylindrical_preview: { + type: "string", + nullable: true, + }, + dome_2kmaster: { + type: "string", + nullable: true, + }, + dome_2kplayback: { + type: "string", + nullable: true, + }, + dome_4kmaster: { + type: "string", + nullable: true, + }, + dome_4kplayback: { + type: "string", + nullable: true, + }, + dome_8kmaster: { + type: "string", + nullable: true, + }, + dome_mov: { + type: "string", + nullable: true, + }, + dome_preview: { + type: "string", + nullable: true, + }, + ext_highres: { + type: "string", + nullable: true, + }, + ext_playback: { + type: "string", + nullable: true, + }, + hd_1080_broadcast: { + type: "string", + nullable: true, + }, + hd_1080_screen: { + type: "string", + nullable: true, + }, + hd_1080p25_broadcast: { + type: "string", + nullable: true, + }, + hd_1080p25_screen: { + type: "string", + nullable: true, + }, + hd_and_apple: { + type: "string", + nullable: true, + }, + hd_broadcast_720p25: { + type: "string", + nullable: true, + }, + hd_broadcast_720p50: { + type: "string", + nullable: true, + }, + large_qt: { + type: "string", + nullable: true, + }, + medium_flash: { + type: "string", + nullable: true, + }, + medium_mpeg1: { + type: "string", + nullable: true, + }, + medium_podcast: { + type: "string", + nullable: true, + }, + news: { + type: "string", + nullable: true, + }, + newsfeature: { + type: "string", + nullable: true, + }, + newsmini: { + type: "string", + nullable: true, + }, + old_video: { + type: "string", + nullable: true, + }, + original: { + type: "string", + nullable: true, + }, + potwmedium: { + type: "string", + nullable: true, + }, + qtvr: { + type: "string", + nullable: true, + }, + script: { + type: "string", + nullable: true, + }, + small_flash: { + type: "string", + nullable: true, + }, + small_qt: { + type: "string", + nullable: true, + }, + thumb: { + type: "string", + nullable: true, + }, + thumb300y: { + type: "string", + nullable: true, + }, + thumb350x: { + type: "string", + nullable: true, + }, + ultra_hd: { + type: "string", + nullable: true, + }, + ultra_hd_8k_broadcast: { + type: "string", + nullable: true, + }, + ultra_hd_8k_h265: { + type: "string", + nullable: true, + }, + ultra_hd_broadcast: { + type: "string", + nullable: true, + }, + ultra_hd_h265: { + type: "string", + nullable: true, + }, + videoframe: { + type: "string", + nullable: true, + }, + vr_16kmaster: { + type: "string", + nullable: true, + }, + vr_2k_sos: { + type: "string", + nullable: true, + }, + vr_4k: { + type: "string", + nullable: true, + }, + vr_4k_sos: { + type: "string", + nullable: true, + }, + vr_4kmaster: { + type: "string", + nullable: true, + }, + vr_8k: { + type: "string", + nullable: true, + }, + vr_8kmaster: { + type: "string", + nullable: true, + }, + }, + readOnly: true, + }, + }, + required: ["categories", "duration", "formats", "id", "title", "url"], +} as const; diff --git a/lib/api/noirlab/codegen/services.gen.ts b/lib/api/noirlab/codegen/services.gen.ts new file mode 100644 index 00000000..3e74a814 --- /dev/null +++ b/lib/api/noirlab/codegen/services.gen.ts @@ -0,0 +1,45 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { + createClient, + createConfig, + type Options, +} from "@hey-api/client-fetch"; +import type { + ReleasesListData, + ReleasesListError, + ReleasesListResponse, + ReleasesRetrieveData, + ReleasesRetrieveError, + ReleasesRetrieveResponse, +} from "./types.gen"; + +export const client = createClient(createConfig()); + +export class ReleasesService { + public static releasesList( + options?: Options + ) { + return (options?.client ?? client).get< + ReleasesListResponse, + ReleasesListError, + ThrowOnError + >({ + ...options, + url: "/public/api/v2/releases/", + }); + } + + public static releasesRetrieve( + options: Options + ) { + return (options?.client ?? client).get< + ReleasesRetrieveResponse, + ReleasesRetrieveError, + ThrowOnError + >({ + ...options, + url: "/public/api/v2/releases/{id}/", + }); + } +} diff --git a/lib/api/noirlab/codegen/types.gen.ts b/lib/api/noirlab/codegen/types.gen.ts new file mode 100644 index 00000000..3f361bf9 --- /dev/null +++ b/lib/api/noirlab/codegen/types.gen.ts @@ -0,0 +1,818 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type Activity = { + /** + * ID of the activity, also used in URLs + */ + id: string; + name: string; + /** + * title to be displayed in the activity description when the activity is joined with other activities + */ + title?: string | null; + slogan?: string; + observatory: string; + readonly key_visual_en: string; + readonly key_visual_es: string; + /** + * Format: HH:MM + */ + duration: string; + readonly safety_tech_doc: string; + readonly conduct_tech_doc: string; + readonly liability_tech_doc: string; + readonly safety_tech_doc_es: string; + readonly conduct_tech_doc_es: string; + readonly liability_tech_doc_es: string; + readonly group_safety_tech_doc: string; + readonly group_liability_tech_doc: string; + readonly group_safety_tech_doc_es: string; + readonly group_liability_tech_doc_es: string; +}; + +export type Announcement = { + /** + * Ids are only allowed to contain letters, numbers, underscores or hyphens. They are used in URLs for the archive item. + */ + id: string; + lang?: string; + readonly url: string; + /** + * Title is shown in browser window. Use a good informative title, since search engines normally display the title on their result pages. + */ + title: string; + /** + * Optional subtitle to be shown just above the headline. + */ + subtitle?: string; + description?: string; + /** + * Contacts + */ + contacts?: string; + /** + * Links + */ + links?: string; + featured?: boolean; + readonly release_date: string; + programs: Array; + readonly images: Array; + readonly videos: Array; +}; + +export type AnnouncementMini = { + /** + * Ids are only allowed to contain letters, numbers, underscores or hyphens. They are used in URLs for the archive item. + */ + id: string; + lang?: string; + readonly url: string; + /** + * Title is shown in browser window. Use a good informative title, since search engines normally display the title on their result pages. + */ + title: string; + /** + * Optional subtitle to be shown just above the headline. + */ + subtitle?: string; + readonly release_date: string; + programs: Array; + readonly main_image: ImageMini; +}; + +export type AuthorDescription = { + readonly name: string; + /** + * Optional description, e.g.: "Author: ", or "Interview with" + */ + description?: string; + readonly photo: string; + /** + * Direct link to a JPG image, recommended size: 350px wide + */ + readonly static_photo: string; +}; + +export type BlankEnum = ""; + +export const BlankEnum = { + EMPTY_STRING: "", +} as const; + +export type Category = { + slug: string; + /** + * Title of query to be displayed to the user. + */ + name: string; + logo_url?: string | null; +}; + +export type Image = { + /** + * Id of image - used in the URL for the image as well as the filename for the different formats. + */ + id: string; + readonly url: string; + lang?: string; + /** + * Id of image - used in the URL for the image as well as the filename for the different formats. + */ + source?: string | null; + /** + * General descriptive title given to the image resource. + */ + title: string; + /** + * Short description of the full caption. + */ + headline?: string | null; + /** + * Full caption and related description text for the image resource. + */ + description?: string | null; + categories: Array; + /** + * The type of image/media resource. + * + * * `Observation` - Observation + * * `Artwork` - Artwork + * * `Photographic` - Photographic + * * `Planetary` - Planetary + * * `Simulation` - Simulation + * * `Collage` - Collage + * * `Chart` - Chart + */ + type?: (TypeEnum | BlankEnum | NullEnum) | null; + /** + * The minimum information that the Publisher would like to see mentioned when the resource is used. + */ + credit?: string; + readonly release_date: string; + /** + * Width in pixels of the image resource. + */ + width?: number | null; + /** + * Height in pixels of the image resource. + */ + height?: number | null; + featured?: boolean; + subject_name: Array; + readonly resources: Array<{ + ResourceType?: string; + MediaType?: string; + URL?: string; + FileSize?: number | null; + Dimensions?: Array | null; + ProjectionType?: string | null; + }>; + readonly formats: { + banner1920?: string | null; + eps?: string | null; + illustrator?: string | null; + illustrator_text?: string | null; + large?: string | null; + medium?: string | null; + news?: string | null; + newsfeature?: string | null; + newsmini?: string | null; + original?: string | null; + pdf?: string | null; + pl_original?: string | null; + pl_screen?: string | null; + pl_thumbs?: string | null; + portrait1080?: string | null; + poster400y?: string | null; + potwmedium?: string | null; + publicationjpg?: string | null; + publicationtiff?: string | null; + publicationtiff10k?: string | null; + publicationtiff25k?: string | null; + publicationtiff40k?: string | null; + screen?: string | null; + screen640?: string | null; + thumb150y?: string | null; + thumb300y?: string | null; + thumb350x?: string | null; + thumb700x?: string | null; + thumbs?: string | null; + wallpaper1?: string | null; + wallpaper2?: string | null; + wallpaper3?: string | null; + wallpaper4?: string | null; + wallpaper5?: string | null; + wallpaperthumbs?: string | null; + zoomable?: string | null; + }; +}; + +export type ImageItem = ImageTiny | ImageMini; + +export type ImageMini = { + /** + * Id of image - used in the URL for the image as well as the filename for the different formats. + */ + id: string; + readonly url: string; + lang?: string; + /** + * Id of image - used in the URL for the image as well as the filename for the different formats. + */ + source?: string | null; + /** + * General descriptive title given to the image resource. + */ + title: string; + /** + * Width in pixels of the image resource. + */ + width?: number | null; + /** + * Height in pixels of the image resource. + */ + height?: number | null; + featured?: boolean; + categories: Array; + readonly formats: { + banner1920?: string | null; + eps?: string | null; + illustrator?: string | null; + illustrator_text?: string | null; + large?: string | null; + medium?: string | null; + news?: string | null; + newsfeature?: string | null; + newsmini?: string | null; + original?: string | null; + pdf?: string | null; + pl_original?: string | null; + pl_screen?: string | null; + pl_thumbs?: string | null; + portrait1080?: string | null; + poster400y?: string | null; + potwmedium?: string | null; + publicationjpg?: string | null; + publicationtiff?: string | null; + publicationtiff10k?: string | null; + publicationtiff25k?: string | null; + publicationtiff40k?: string | null; + screen?: string | null; + screen640?: string | null; + thumb150y?: string | null; + thumb300y?: string | null; + thumb350x?: string | null; + thumb700x?: string | null; + thumbs?: string | null; + wallpaper1?: string | null; + wallpaper2?: string | null; + wallpaper3?: string | null; + wallpaper4?: string | null; + wallpaper5?: string | null; + wallpaperthumbs?: string | null; + zoomable?: string | null; + }; +}; + +export type ImageTiny = { + /** + * Id of image - used in the URL for the image as well as the filename for the different formats. + */ + id: string; + readonly url: string; + lang?: string; + /** + * General descriptive title given to the image resource. + */ + title: string; + /** + * Width in pixels of the image resource. + */ + width?: number | null; + /** + * Height in pixels of the image resource. + */ + height?: number | null; + readonly formats: { + thumb300y?: string | null; + screen?: string | null; + thumb700x?: string | null; + }; +}; + +export type Model3D = { + /** + * Ids are only allowed to contain letters, numbers, underscores or hyphens. They are used in URLs for the archive item. + */ + id: string; + /** + * Title is shown in browser window. Use a good informative title, since search engines normally display the title on their result pages. + */ + title: string; + description?: string; + readonly credit: string; + /** + * Priority of product (100 highest, 0 lowest) - high priority products are ranked higher in search results than low priority products. + */ + priority?: number; + readonly release_date: string; + readonly assets: string; +}; + +export type NullEnum = unknown; + +export type Page = { + /** + * Title is shown in browser window. Use a good informative title, since search engines normally display the title on their result pages. + */ + title: string; + content?: string; + /** + * The metadata description is normally shown in search engine results, making the description an effective way of capturing users attention. Description should be a clear description of the content and less the 200 characters long. Also used when sharing page on social media + */ + description?: string; + /** + * Comma-separated list of keywords for this page. Mainly used internally as search engines rarely use keywords to rank pages. + */ + keywords?: string; +}; + +export type PageRequest = { + /** + * Title is shown in browser window. Use a good informative title, since search engines normally display the title on their result pages. + */ + title: string; + content?: string; + /** + * The metadata description is normally shown in search engine results, making the description an effective way of capturing users attention. Description should be a clear description of the content and less the 200 characters long. Also used when sharing page on social media + */ + description?: string; + /** + * Comma-separated list of keywords for this page. Mainly used internally as search engines rarely use keywords to rank pages. + */ + keywords?: string; +}; + +export type PaginatedAnnouncementMiniList = { + count?: number; + next?: string | null; + previous?: string | null; + results?: Array; +}; + +export type PaginatedImageItemList = { + count?: number; + next?: string | null; + previous?: string | null; + results?: Array; +}; + +export type PaginatedImageList = { + count?: number; + next?: string | null; + previous?: string | null; + results?: Array; +}; + +export type PaginatedModel3dList = { + count?: number; + next?: string | null; + previous?: string | null; + results?: Array; +}; + +export type PaginatedPodcastList = { + count?: number; + next?: string | null; + previous?: string | null; + results?: Array; +}; + +export type PaginatedReleaseMiniList = { + count?: number; + next?: string | null; + previous?: string | null; + results?: Array; +}; + +export type PaginatedVideoList = { + count?: number; + next?: string | null; + previous?: string | null; + results?: Array