diff --git a/apps/landing-page/markdoc/tags.tsx b/apps/landing-page/markdoc/tags.tsx index 02d7a9fe..c233caf0 100644 --- a/apps/landing-page/markdoc/tags.tsx +++ b/apps/landing-page/markdoc/tags.tsx @@ -1,4 +1,5 @@ import { Callout, QuickLink, QuickLinks, CurrentVersion } from '@devfile-web/core'; +import clsx from 'clsx'; const tags = { callout: { @@ -19,14 +20,25 @@ const tags = { src: { type: String }, alt: { type: String }, caption: { type: String }, + isZoomable: { type: Boolean, default: false }, + hasBackground: { type: Boolean, default: false }, }, - render: (props: { src: string; alt: string; caption: string }): JSX.Element => { - const { src, alt = '', caption } = props; + render: (props: { + src: string; + alt: string; + caption: string; + hasBackground: boolean; + }): JSX.Element => { + const { src, alt = '', caption, hasBackground } = props; return ( -
+
{/* eslint-disable-next-line @next/next/no-img-element */} - {alt} + {alt}
{caption}
); diff --git a/apps/landing-page/navigation.ts b/apps/landing-page/navigation.ts index 3dd2509f..1ad79909 100644 --- a/apps/landing-page/navigation.ts +++ b/apps/landing-page/navigation.ts @@ -7,15 +7,16 @@ import { RedHatIcon, } from '@devfile-web/core'; import { defaultVersion } from '@devfile-web/docs'; -import type { HeaderNavigation, FooterNavigation } from '@devfile-web/core'; +import { ViewGridIcon, BookOpenIcon, ViewListIcon } from '@heroicons/react/outline'; +import type { HeaderNavigation, FooterNavigation, NavigationElement } from '@devfile-web/core'; export { docsNavigation } from '@devfile-web/docs'; export const headerNavigation: HeaderNavigation = [ { name: 'Registry', href: 'https://registry.devfile.io' }, - { name: 'Docs', href: `/docs/${defaultVersion}/overview` }, - { name: 'Get Started', href: `/docs/${defaultVersion}/what-is-a-devfile` }, - { name: 'Github', href: 'https://github.com/orgs/devfile/repositories', image: GithubIcon }, + { name: 'Docs', href: `/docs/${defaultVersion}/what-is-a-devfile` }, + { name: 'Get Started', href: `/docs/${defaultVersion}/devfile-ecosystem` }, + { name: 'Github', href: 'https://github.com/devfile/api', image: GithubIcon }, { name: 'Slack', href: 'https://kubernetes.slack.com/archives/C02SX9E5B55', image: SlackIcon }, ]; @@ -29,12 +30,12 @@ export const footerNavigation: FooterNavigation = { links: [ { name: 'Cloud Native Computing Foundation', href: 'https://www.cncf.io' }, { name: 'Registry', href: 'https://registry.devfile.io' }, - { name: 'Documentation', href: `/docs/${defaultVersion}/overview` }, + { name: 'Documentation', href: `/docs/${defaultVersion}/what-is-a-devfile` }, ], social: [ { name: 'Github', - href: 'https://github.com/orgs/devfile/repositories', + href: 'https://github.com/devfile/api', image: GithubIcon, }, { @@ -44,3 +45,30 @@ export const footerNavigation: FooterNavigation = { }, ], }; + +export interface Custom404NavigationElement extends NavigationElement { + description: string; +} + +export type Custom404Navigation = Custom404NavigationElement[]; + +export const custom404Navigation: Custom404Navigation = [ + { + name: 'Documentation', + description: 'Learn how to integrate devfile with your app', + image: BookOpenIcon, + href: `/docs/${defaultVersion}/what-is-a-devfile`, + }, + { + name: 'API Reference', + description: 'A complete API reference for devfile', + image: ViewListIcon, + href: `/docs/${defaultVersion}/devfile-schema`, + }, + { + name: 'Registry', + description: 'Browse devfile stacks and samples', + image: ViewGridIcon, + href: 'https://registry.devfile.io', + }, +]; diff --git a/apps/landing-page/pages/404.tsx b/apps/landing-page/pages/404.tsx new file mode 100644 index 00000000..c31f5d01 --- /dev/null +++ b/apps/landing-page/pages/404.tsx @@ -0,0 +1,88 @@ +import { ChevronRightIcon } from '@heroicons/react/solid'; +import { DevfileIcon, LandingPageMeta } from '@devfile-web/core'; +import { defaultVersion } from '@devfile-web/docs'; +import { useRouter } from 'next/router'; +import Link from 'next/link'; +import { custom404Navigation } from '../navigation'; + +export function Custom404(): JSX.Element { + const router = useRouter(); + + const isDocsPage = router.asPath === '/docs'; + + return ( +
+ + {isDocsPage && ( + el.name === 'Documentation').href ?? + `/docs/${defaultVersion}/what-is-a-devfile` + }`} + /> + )} + + +
+
+ +
+
+
+

404

+

+ This page does not exist. +

+

+ The page you are looking for could not be found. +

+
+
+

+ Popular pages +

+
    + {custom404Navigation.map((link) => ( +
  • +
    + + +
    +
    +

    + + {link.name} + +

    +

    + {link.description} +

    +
    +
    +
    +
  • + ))} +
+
+ + Or go back home + +
+
+
+
+
+ ); +} + +export default Custom404; diff --git a/apps/landing-page/pages/_app.tsx b/apps/landing-page/pages/_app.tsx index d8db8b6f..39af40d9 100644 --- a/apps/landing-page/pages/_app.tsx +++ b/apps/landing-page/pages/_app.tsx @@ -14,7 +14,6 @@ import type { MarkdocNextJsPageProps } from '@markdoc/next.js'; import type { RenderableTreeNodes, Tag } from '@markdoc/markdoc'; import type { TableOfContents } from '@devfile-web/core'; import type { DocsNavigation } from '@devfile-web/docs'; -import { useRouter } from 'next/router'; import { docsNavigation, headerNavigation, footerNavigation } from '../navigation'; const analyticsConfig = { @@ -69,20 +68,13 @@ function collectHeadings( function LandingPage({ Component, pageProps }: AppProps): JSX.Element { const { markdoc } = pageProps as MarkdocNextJsPageProps; - const router = useRouter(); - const title = (markdoc?.frontmatter.title as string) ?? ''; - let pageTitle: string; - let description: string; - - if (router.asPath.includes('/docs')) { - pageTitle = - (markdoc?.frontmatter.pageTitle as string) || - `${(markdoc?.frontmatter.title as string) ?? ''} - Docs`; + const pageTitle = + (markdoc?.frontmatter.pageTitle as string) || + `${(markdoc?.frontmatter.title as string) ?? ''} - Docs`; - description = (markdoc?.frontmatter.description as string) ?? ''; - } + const pageDescription = (markdoc?.frontmatter.description as string) ?? ''; const tableOfContents = markdoc?.content ? collectHeadings(markdoc.content) : []; @@ -94,10 +86,15 @@ function LandingPage({ Component, pageProps }: AppProps): JSX.Element { docsNavigation={docsNavigation as DocsNavigation} >
-
+
- +
diff --git a/apps/landing-page/public/images/devfile-ecosystem.svg b/apps/landing-page/public/images/devfile-ecosystem.svg new file mode 100644 index 00000000..90558156 --- /dev/null +++ b/apps/landing-page/public/images/devfile-ecosystem.svg @@ -0,0 +1,4 @@ + + + +
Devfile Author
Devfile...
Devfile Registry Administrator
Devfile Reg...
Creates/Updates
Creates/...
Deploys and manages organization owned registry and stacks
Deploys and manag...
/index
/viewer
/index...
Private Devfile Registry
Private Devfile Registry
/index
/viewer
/index...
Devfile Stacks/Samples
Devfile Stacks/Samples
Tools/Clients
Devfile Catalog (UI/CLI)
Devfile Catalog (UI/CL...
Register
Register
Register
Register
Develop, Test, Deploy 
Develop, Test, Deploy 
Developers
Developers
Share (Optional)
Share (Optional)
Create
Create
  
  
Consume
Consume
Share
Share
Devfile Author
Devfile...
Creates/Updates
Creates/...
Devfile Stacks/Samples
Devfile Stacks/Samples
Publish
Publish
Legend

Public

Public
Organization
Organization
Create (Optional)
Create (Optional)
Public Devfile Community Registry
Public Devfile C...
Publish
Publish
Text is not SVG - cannot display
\ No newline at end of file diff --git a/apps/landing-page/tailwind.config.js b/apps/landing-page/tailwind.config.js index f3024106..7ef93aa2 100644 --- a/apps/landing-page/tailwind.config.js +++ b/apps/landing-page/tailwind.config.js @@ -5,7 +5,7 @@ const { join } = require('path'); /** @type {import('tailwindcss').Config} */ module.exports = { content: [ - join(__dirname, '{src,pages,components}/**/*!(*.stories|*.spec).{ts,tsx,html}'), + join(__dirname, '{src,pages,components,markdoc}/**/*!(*.stories|*.spec).{ts,tsx,html}'), ...createGlobPatternsForDependencies(__dirname), ], darkMode: 'class', diff --git a/libs/core/src/components/header/header.tsx b/libs/core/src/components/header/header.tsx index 25953d72..548ac15e 100644 --- a/libs/core/src/components/header/header.tsx +++ b/libs/core/src/components/header/header.tsx @@ -1,6 +1,10 @@ import Link from 'next/link'; import clsx from 'clsx'; import { useState, useEffect } from 'react'; +import { DotsVerticalIcon } from '@heroicons/react/outline'; +import { ChevronRightIcon } from '@heroicons/react/solid'; +import { Popover } from '@headlessui/react'; +import { useRouter } from 'next/router'; import { DevfileIcon } from '../../icons'; import { MobileNavigation } from '../mobile-navigation/mobile-navigation'; import { LandingPageSearch as Search } from '../landing-page-search/landing-page-search'; @@ -9,9 +13,13 @@ import { VersionSelector } from '../version-selector/version-selector'; import { useNavigation } from '../../hooks'; export function Header(): JSX.Element { - const { headerNavigation } = useNavigation(); + const { headerNavigation, currentSection, currentPage } = useNavigation(); const [isScrolled, setIsScrolled] = useState(false); + const router = useRouter(); + + const is404Page = router.pathname === '/404'; + const isDocsPage = router.pathname.includes('docs'); useEffect(() => { function onScroll(): void { @@ -27,7 +35,7 @@ export function Header(): JSX.Element { return (
-
- -
- - - - -

+ + +

Devfile.io

+ {!is404Page && }

-
-
- -
- - +
+ {!is404Page && } + + + + + +
+
+ {headerNavigation.map((item) => ( + + {item.name} + + ))} +
+
+ + Switch theme + + +
+
+
+
+
+
+ {headerNavigation.map((item) => ( {item.image ? ( - + ) : ( item.name )} @@ -79,6 +104,18 @@ export function Header(): JSX.Element { ))}
+ {isDocsPage && ( +
+ +
+ {currentSection?.title} + + + {currentPage?.title} + +
+
+ )}
); } diff --git a/libs/core/src/components/hero/hero.tsx b/libs/core/src/components/hero/hero.tsx index ab9eba13..1fbb2531 100644 --- a/libs/core/src/components/hero/hero.tsx +++ b/libs/core/src/components/hero/hero.tsx @@ -4,8 +4,8 @@ import clsx from 'clsx'; import type { SVGProps } from 'react'; import Highlight, { defaultProps } from '@schultzp2020/prism-react-renderer'; import type { Language } from '@schultzp2020/prism-react-renderer'; -import { defaultVersion } from '@devfile-web/docs'; import { Button } from '../button/button'; +import { useNavigation } from '../../hooks'; import { HeroBackground } from '../hero-background/hero-background'; import blurCyanImage from '../../images/blur-cyan.png'; import blurIndigoImage from '../../images/blur-indigo.png'; @@ -41,6 +41,8 @@ function TrafficLightsIcon(props: SVGProps): JSX.Element { } export function Hero(): JSX.Element { + const { headerNavigation } = useNavigation(); + return (
@@ -65,9 +67,19 @@ export function Hero(): JSX.Element { An open standard defining containerized development environments.

- - +
diff --git a/libs/core/src/components/landing-page-meta/landing-page-meta.tsx b/libs/core/src/components/landing-page-meta/landing-page-meta.tsx index ba9ddb98..7fcc7715 100644 --- a/libs/core/src/components/landing-page-meta/landing-page-meta.tsx +++ b/libs/core/src/components/landing-page-meta/landing-page-meta.tsx @@ -4,13 +4,14 @@ export interface LandingPageMetaProps { title?: string; keywords?: string; description?: string; + children?: React.ReactNode; } // @ts-ignore const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ''; export function LandingPageMeta(props: LandingPageMetaProps): JSX.Element { - const { title, keywords, description } = props; + const { title, keywords, description, children } = props; return ( @@ -27,6 +28,7 @@ export function LandingPageMeta(props: LandingPageMetaProps): JSX.Element { + {children} ); } diff --git a/libs/core/src/components/landing-page-search/landing-page-search.tsx b/libs/core/src/components/landing-page-search/landing-page-search.tsx index 74aa4d12..ef993b29 100644 --- a/libs/core/src/components/landing-page-search/landing-page-search.tsx +++ b/libs/core/src/components/landing-page-search/landing-page-search.tsx @@ -59,8 +59,8 @@ export function LandingPageSearch(): JSX.Element | null { className="group flex h-6 w-6 items-center justify-center sm:justify-start lg:h-10 lg:w-64 lg:flex-none lg:rounded-lg lg:py-2.5 lg:pl-4 lg:pr-3.5 lg:text-sm lg:ring-1 lg:ring-slate-200 lg:hover:ring-slate-300 dark:lg:bg-slate-800/75 dark:lg:ring-inset dark:lg:ring-white/5 dark:lg:hover:bg-slate-700/40 dark:lg:hover:ring-slate-500" onClick={onOpen} > - - + + Search docs {modifierKey && ( diff --git a/libs/core/src/components/mobile-navigation/mobile-navigation.tsx b/libs/core/src/components/mobile-navigation/mobile-navigation.tsx index f836974b..30d444cb 100644 --- a/libs/core/src/components/mobile-navigation/mobile-navigation.tsx +++ b/libs/core/src/components/mobile-navigation/mobile-navigation.tsx @@ -3,16 +3,12 @@ import Link from 'next/link'; import { useRouter } from 'next/router'; import { Dialog } from '@headlessui/react'; import { MenuIcon, XIcon as CloseIcon } from '@heroicons/react/outline'; -import clsx from 'clsx'; import { DevfileIcon } from '../../icons'; import { Navigation } from '../navigation/navigation'; -import { useNavigation } from '../../hooks'; export function MobileNavigation(): JSX.Element { - const { headerNavigation } = useNavigation(); - const router = useRouter(); - const [isOpen, setIsOpen] = useState(false); + const [isOpen, setIsOpen] = useState(false); useEffect(() => { if (!isOpen) return; @@ -38,7 +34,7 @@ export function MobileNavigation(): JSX.Element { className="relative" aria-label="Open navigation" > - + setIsOpen(false)} aria-label="Close navigation" > - +
-
- {headerNavigation.map((item) => ( - - {item.image ? ( - - ) : ( - item.name - )} - - ))} -
diff --git a/libs/core/src/components/theme-selector/theme-selector.tsx b/libs/core/src/components/theme-selector/theme-selector.tsx index bcb5245d..43539852 100644 --- a/libs/core/src/components/theme-selector/theme-selector.tsx +++ b/libs/core/src/components/theme-selector/theme-selector.tsx @@ -15,6 +15,7 @@ export interface Theme { export interface ThemeSelectorProps { className?: string; + isRightAligned?: boolean; } const themes = [ @@ -24,7 +25,7 @@ const themes = [ ]; export function ThemeSelector(props: ThemeSelectorProps): JSX.Element { - const { className } = props; + const { className, isRightAligned } = props; const [selectedTheme, setSelectedTheme] = useState(); @@ -52,7 +53,12 @@ export function ThemeSelector(props: ThemeSelectorProps): JSX.Element { - + {themes.map((theme) => (
-

diff --git a/libs/core/src/components/version-selector/version-selector.tsx b/libs/core/src/components/version-selector/version-selector.tsx index 06e8e358..84fc9bd9 100644 --- a/libs/core/src/components/version-selector/version-selector.tsx +++ b/libs/core/src/components/version-selector/version-selector.tsx @@ -2,6 +2,7 @@ import Link from 'next/link'; import { Menu } from '@headlessui/react'; import clsx from 'clsx'; import { useRouter } from 'next/router'; +import { ChevronDownIcon } from '@heroicons/react/outline'; import { useNavigation } from '../../hooks'; export interface VersionSelectorProps { @@ -21,12 +22,13 @@ export function VersionSelector(props: VersionSelectorProps): JSX.Element | null return ( - {selectedVersion} + {selectedVersion} + - + {docVersions.map((version) => ( >; docVersions: typeof docVersions; + currentSection?: Section; + previousPage?: Page; + currentPage?: Page; + nextPage?: Page; } const NavigationContext = createContext(undefined); @@ -49,6 +59,15 @@ export function NavigationProvider(props: NavigationProviderProps): JSX.Element [docsNavigation, selectedVersion], ); + const allLinks = useMemo( + () => versionedDocsNavigation.flatMap((section) => section.links), + [versionedDocsNavigation], + ); + const linkIndex = useMemo( + () => allLinks.findIndex((link) => link.href === router.pathname), + [allLinks, router.pathname], + ); + const value = useMemo( () => ({ headerNavigation, @@ -57,8 +76,22 @@ export function NavigationProvider(props: NavigationProviderProps): JSX.Element selectedVersion, setSelectedVersion, docVersions, + currentSection: versionedDocsNavigation.find((section_) => + section_.links.find((link) => link.href === router.pathname), + ), + previousPage: allLinks[linkIndex - 1], + currentPage: allLinks[linkIndex], + nextPage: allLinks[linkIndex + 1], }), - [versionedDocsNavigation, footerNavigation, headerNavigation, selectedVersion], + [ + headerNavigation, + footerNavigation, + versionedDocsNavigation, + selectedVersion, + allLinks, + linkIndex, + router.pathname, + ], ); return {children}; diff --git a/libs/core/src/hooks/use-table-of-contents/use-table-of-contents.tsx b/libs/core/src/hooks/use-table-of-contents/use-table-of-contents.tsx index 80e3d6e9..4beafb0c 100644 --- a/libs/core/src/hooks/use-table-of-contents/use-table-of-contents.tsx +++ b/libs/core/src/hooks/use-table-of-contents/use-table-of-contents.tsx @@ -13,11 +13,13 @@ export interface TableOfContents { } export interface UseTableOfContents { - currentSection?: string; + currentPageSection?: string; } export function useTableOfContents(tableOfContents: TableOfContents[]): UseTableOfContents { - const [currentSection, setCurrentSection] = useState(tableOfContents[0]?.id); + const [currentPageSection, setCurrentPageSection] = useState( + tableOfContents[0]?.id, + ); const getHeadings = useCallback( (tableOfContents_: TableOfContents[]) => @@ -34,6 +36,7 @@ export function useTableOfContents(tableOfContents: TableOfContents[]): UseTable const scrollMt = Number.parseFloat(style.scrollMarginTop); const top = window.scrollY + el.getBoundingClientRect().top - scrollMt; + return { id, top }; }), [], @@ -52,7 +55,7 @@ export function useTableOfContents(tableOfContents: TableOfContents[]): UseTable break; } } - setCurrentSection(current); + setCurrentPageSection(current); } window.addEventListener('scroll', onScroll, { passive: true }); onScroll(); @@ -61,7 +64,7 @@ export function useTableOfContents(tableOfContents: TableOfContents[]): UseTable }; }, [getHeadings, tableOfContents]); - return { currentSection }; + return { currentPageSection }; } export default useTableOfContents; diff --git a/libs/core/src/layouts/landing-page-layout/landing-page-layout.tsx b/libs/core/src/layouts/landing-page-layout/landing-page-layout.tsx index 791adefb..69dae235 100644 --- a/libs/core/src/layouts/landing-page-layout/landing-page-layout.tsx +++ b/libs/core/src/layouts/landing-page-layout/landing-page-layout.tsx @@ -3,7 +3,14 @@ import { useRouter } from 'next/router'; import clsx from 'clsx'; import { PencilIcon } from '@heroicons/react/solid'; import { githubDocsUrl } from '@devfile-web/docs'; -import { Navigation, Prose, LandingPageSearch as Search, Hero, Fence } from '../../components'; +import { + Navigation, + Prose, + LandingPageSearch, + Hero, + Fence, + LandingPageMeta, +} from '../../components'; import { useTableOfContents, useNavigation, useCodeblock, CodeblockProvider } from '../../hooks'; import type { TableOfContents, TableOfContentsChild } from '../../hooks'; @@ -11,26 +18,23 @@ export interface LandingPageLayoutProps { children: JSX.Element; title: string; tableOfContents: TableOfContents[]; + pageTitle: string; + pageDescription: string; } export function LandingPageLayout(props: LandingPageLayoutProps): JSX.Element { - const { children, title, tableOfContents } = props; + const { children, title, tableOfContents, pageTitle, pageDescription } = props; - const { versionedDocsNavigation, selectedVersion } = useNavigation(); + const { selectedVersion, currentSection, previousPage, currentPage, nextPage } = useNavigation(); + const { currentPageSection } = useTableOfContents(tableOfContents); const router = useRouter(); + + const is404Page = router.pathname === '/404'; const isDocsPage = router.pathname.includes('docs'); const isDevfileSchema = router.pathname.includes('/devfile-schema'); - const allLinks = versionedDocsNavigation.flatMap((section) => section.links); - const linkIndex = allLinks.findIndex((link) => link.href === router.pathname); - const previousPage = allLinks[linkIndex - 1]; - const nextPage = allLinks[linkIndex + 1]; - const section = versionedDocsNavigation.find((section_) => - section_.links.find((link) => link.href === router.pathname), - ); - const { currentSection } = useTableOfContents(tableOfContents); function isActive(TableOfContents: TableOfContents | TableOfContentsChild): boolean { - if (TableOfContents.id === currentSection) { + if (TableOfContents.id === currentPageSection) { return true; } if (!TableOfContents.children) { @@ -41,167 +45,167 @@ export function LandingPageLayout(props: LandingPageLayoutProps): JSX.Element { ); } - if (!isDocsPage) { + if (!isDocsPage || is404Page) { return children; } return ( - <> + + - {router.asPath === '/docs' && } + {router.asPath === '/docs' && } -
-
-
-
-
-
-
-
- -
- +
+
+
+
+
+
+
+
+
+
-
- {isDevfileSchema ? ( - children - ) : ( -
- {(title || section) && ( -
- {section && ( -

- {section.title} -

- )} - {title && ( -

- {title} -

- )} -
- )} - {children} -
- )} - {!isDevfileSchema && ( - - - Edit this page - - - )} -
- {previousPage && ( -
-
- Previous -
-
- - {previousPage.title} - -
-
- )} - {nextPage && ( -
-
- Next -
-
- - {nextPage.title} - -
-
+
+
+ {isDevfileSchema ? ( + children + ) : ( +
+ {(title || currentSection) && ( +
+ {currentSection && ( +

+ {currentSection.title} +

+ )} + {title && ( +

+ {title} +

+ )} +
)} - -
-
{children} + + )} + {!isDevfileSchema && ( + + + Edit this page + + + )} +
+ {previousPage && ( +
+
+ Previous +
+
+ + {previousPage.title} + +
+
)} - > - {isDevfileSchema ? ( - - ) : ( - + {nextPage && ( +
+
+ Next +
+
+ + {nextPage.title} + +
+
)} -
+ +
+
+ {isDevfileSchema ? ( + + ) : ( + + )}
- +
); } diff --git a/libs/docs/src/docs/no-version/application-developer.md b/libs/docs/src/docs/no-version/application-developer.md new file mode 100644 index 00000000..62226e3d --- /dev/null +++ b/libs/docs/src/docs/no-version/application-developer.md @@ -0,0 +1,36 @@ +--- +title: Application developer +description: Application developer +--- + +## Leverage ready to use development environments + +Don’t know where to start? The collection of devfiles in a devfile registry provides a wide range of samples and stacks with starter applications that can provide a starting point for you to use different languages and frameworks. Whether you are starting from scratch or working with an existing application, we got you covered. + +## Version development environment + +Having the devfile included as part of the application allows you to easily reproduce the development environment in the same way as any other developers in your organization. You don’t have to worry about the complexity of setting up the environment so that you can focus on developing your applications. + +## Choose your tools + +You will have the flexibility of using different development tools, but still, be able to produce the consistent output described in the devfile. Advanced developers can also customize the build when needed. + +## Reduce the discrepancies between development and production + +Using the devfiles provided by the stack providers will minimize the environmental discrepancies between different stages of development, e.g. development, staging, CI, and production. + +## Make quick turnarounds on code changes + +The inner-loop and outer-loop instructions defined in the devfile allow you to test out your code changes quickly in the tools. You will use the workflow recommended by the stack provider that is the expert on the specific runtime. + +## Tools that provide devfile support + +- [odo](https://odo.dev/) + +- [Eclipse Che](https://medium.com/eclipse-che-blog/devfile-v2-and-ide-plug-ins-in-eclipse-che-7a560ae724b1) + +## Additional resources + +- [API reference](./devfile-schema) + +- [Community registry viewer](https://registry.devfile.io/viewer) diff --git a/libs/docs/src/docs/no-version/devfile-ecosystem.md b/libs/docs/src/docs/no-version/devfile-ecosystem.md new file mode 100644 index 00000000..e42413b3 --- /dev/null +++ b/libs/docs/src/docs/no-version/devfile-ecosystem.md @@ -0,0 +1,34 @@ +--- +title: Devfile ecosystem +description: Devfile ecosystem +--- + +## Create, Share and Consume Devfiles + +Organizations looking to standardize their development environment can do so by adopting devfiles. In the simplest case, developers can just consume the devfiles that are available from the public community registry. If your organization needs custom devfiles that are authored and shared internally, then you need a role based approach so developers, devfile authors, and registry administrators can interact together. + +{% figure src="/images/devfile-ecosystem.svg" alt="Devfile ecosystem" caption="Devfile Ecosystem workflow" hasBackground="true" /%} + +### Create + +A devfile author, also known as a runtime provider, can be an individual or a group representing a runtime vendor. Devfile authors need sound knowledge of the supported runtime so they can create devfiles to build and run applications. + +If a runtime stack is not available in the public registry, an organization can choose to develop their own and keep it private for their in-house development. + +### Share + +The public community registry is managed by the community and hosted by Red Hat. Share your devfile to the public community registry so other teams can benefit from your application. + +If an organization wants to keep their own devfiles private but wishes to share with other departments, they can assign a registry administrator. The registry administrator deploys, maintains, and manages the contents of their private registry and the default list of devfile registries available in a given cluster. + +### Consume + +Developers can use the supported tools to access devfiles. Many of the existing tools offer a way to register or catalog public and private devfile registries which then allows the tool to expose the devfiles for development. + +In addition, each registry comes packaged with an index server and a registry viewer so developers can browse and view the devfile contents before deciding which ones they want to adopt. + +Developers can also extend an existing parent devfile to customize the workflow of their specific application. The devfile can be packaged as part of the application source to ensure consistent behavior when moving across different tools. + +{% callout title="Note!" %} +Tools that support the devfile spec might have varying levels of support. Check their product pages for more information. +{% /callout %} diff --git a/libs/docs/src/docs/no-version/enterprise-architect-and-runtime-provider.md b/libs/docs/src/docs/no-version/enterprise-architect-and-runtime-provider.md new file mode 100644 index 00000000..4f1eeba0 --- /dev/null +++ b/libs/docs/src/docs/no-version/enterprise-architect-and-runtime-provider.md @@ -0,0 +1,30 @@ +--- +title: Enterprise architect and runtime provider +description: Enterprise architect and runtime provider +--- + +## Define the standard way of working + +Being the expert on language and framework, you can share the recommended workflow on developing applications based on different languages and frameworks. + +## Build once, run anywhere + +Develop the application stacks once, and they will work across different tools. There is no need to build and maintain custom support for each development tool. + +## Easy sharing of workflows + +By adding the stacks or samples that you have developed to a devfile registry, application developers can easily discover the devfiles that you provide. You can also provide starter projects or samples to showcase the usage of a specific runtime or framework. + +## Governance + +Add the necessary policy settings and compliance policies as part of the devfile to ensure anyone who uses the stack will follow the same workflow. By using the parent support in the devfile, any update on these policies, security fixes, and workflow will get picked up automatically to ensure consistency. + +## Additional resources + +- [API reference](./devfile-schema) + +- [Overview](./overview) + +- [Onboarding process and requirements of the community registry](https://github.com/devfile/registry/blob/main/CONTRIBUTING.md) + +- [Community registry viewer](https://registry.devfile.io/viewer) diff --git a/libs/docs/src/docs/no-version/registry-administrator.md b/libs/docs/src/docs/no-version/registry-administrator.md new file mode 100644 index 00000000..529051dd --- /dev/null +++ b/libs/docs/src/docs/no-version/registry-administrator.md @@ -0,0 +1,24 @@ +--- +title: Registry administrator +description: Registry administrator +--- + +## Customized registry + +Provides a custom registry to enable developers to view the list of devfiles that describes the custom workflow for application development within an organization. + +## Enable a single point of management for applications built from stacks + +Controls the lifecycle of the stacks within the custom registry and pushes updated devfiles to the registry during the registry update. + +## Enforce standard on the devfiles + +Customize the registry build tools to provide extra validations to ensure the devfiles in the custom registry follow the standard of the organization. + +## Additional resources + +- [Building a custom devfile registry](./building-a-custom-devfile-registry) + +- [Deploying a devfile registry](./deploying-a-devfile-registry) + +- [Adding a registry schema](./adding-a-registry-schema) diff --git a/libs/docs/src/docs/no-version/technology-and-tool-builders.md b/libs/docs/src/docs/no-version/technology-and-tool-builders.md new file mode 100644 index 00000000..0e85498c --- /dev/null +++ b/libs/docs/src/docs/no-version/technology-and-tool-builders.md @@ -0,0 +1,30 @@ +--- +title: Technology and tool builders +description: Technology and tool builders +--- + +## Shielded from runtime specific implementation + +No need to build custom runtime support. Let the expert do the job. Runtime teams know the best way to build and run applications on their servers. + +## Zero maintenance for runtime support + +Tools will get the runtime support update for free whenever a new stack gets updated in the devfile registry. New stacks can be picked up by the tools easily without tools update. + +## Shared configuration that can be reused across different tools + +Different tools work in a slightly different way. Sometimes it is hard to convince users to switch to your tool due to configuration differences. Sharing the same devfile specification support reduces the hurdle for users to make that change. + +## Additional resources + +- [API reference](./devfile-schema) + +- [Devfile library for reading and writing to devfile](https://github.com/devfile/library) + +- [Community registry viewer](https://registry.devfile.io/viewer) + +Devfile registry library for interacting with the devfile registry, e.g. finding the list of devfiles available, metadata associated with each devfile, and downloading content of the stacks. + +- [Go Library](https://github.com/devfile/registry-support/tree/main/registry-library) + +- [REST API](https://github.com/devfile/registry-support/blob/main/index/server/registry-REST-API.adoc) diff --git a/libs/docs/src/navigation/no-version.yaml b/libs/docs/src/navigation/no-version.yaml index 2dfde9eb..4a8e927b 100644 --- a/libs/docs/src/navigation/no-version.yaml +++ b/libs/docs/src/navigation/no-version.yaml @@ -23,6 +23,18 @@ top: href: ./library - title: Resources href: ./resources + - title: Get started + links: + - title: Devfile ecosystem + href: ./devfile-ecosystem + - title: Application developer + href: ./application-developer + - title: Enterprise architect and runtime provider + href: ./enterprise-architect-and-runtime-provider + - title: Registry administrator + href: ./registry-administrator + - title: Technology and tool builders + href: ./technology-and-tool-builders bottom: - title: Registry links: diff --git a/libs/docs/src/types/index.ts b/libs/docs/src/types/index.ts index 364c379d..21409945 100644 --- a/libs/docs/src/types/index.ts +++ b/libs/docs/src/types/index.ts @@ -1,18 +1,20 @@ export const docVersions = ['2.0.0', '2.1.0', '2.2.0-alpha'] as const; +// Update the redirect in app-sre when changing the default version export const defaultVersion: DocVersions = '2.1.0'; export const githubDocsUrl = 'https://github.com/devfile/devfile-web/tree/main/libs/docs/src/docs'; export type DocVersions = typeof docVersions[number]; +export interface Page { + title: string; + href: string; + githubHref?: string; +} export interface Section { title: string; - links: { - title: string; - href: string; - githubHref?: string; - }[]; + links: Page[]; } export type VersionedDocsNavigation = Section[]; diff --git a/tools/generators/devfile-schema/index.ts b/tools/generators/devfile-schema/index.ts index 73985341..f9ecedd5 100644 --- a/tools/generators/devfile-schema/index.ts +++ b/tools/generators/devfile-schema/index.ts @@ -9,7 +9,13 @@ export default async function (host: Tree, schema: any) { host.write( `${project?.root}/src/scripts/build-directory/dist/docs/${version}/devfile-schema.tsx`, ` -import { JsonSchemaViewer, useCodeblock, Prose, LandingPageMeta as Meta } from '@devfile-web/core'; +import { + JsonSchemaViewer, + useCodeblock, + Prose, + LandingPageMeta, + useNavigation, +} from '@devfile-web/core'; import { promises as fs } from 'fs-extra'; import Link from 'next/link'; import type { GetStaticProps } from 'next'; @@ -23,25 +29,41 @@ export function DevfileSchema(props: DevfileSchemaProps): JSX.Element { const { schema } = props; const { codeblock, setCodeblock } = useCodeblock(); + const { currentSection } = useNavigation(); return ( <> - - -

- {schema.title} -

-

{schema.description}

-
- - -

Additional resources

-
    -
  • - Download the current JSON Schema -
  • -
-
+ +
+ + {(schema.title || currentSection) && ( +
+ {currentSection && ( +

+ {currentSection.title} +

+ )} + {schema.title && ( +

+ {schema.title} +

+ )} +
+ )} +

{schema.description}

+
+ + +

Additional resources

+
    +
  • + + Download the current JSON Schema + +
  • +
+
+
); }