Skip to content

lsst-epo/investigations-client

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Next frontend

Next.js frontend intended to be used with the Rubin EPO craft-cms-template.

Local development

  1. Ensure that the Craft CMS container is running and functioning correctly by going to http://localhost:8080/api, if everything is working fine you should see some message about a missing GraphQL query
  2. Create a .env file in the root of your project based on the .env.local.sample
  3. Install dependencies yarn
  4. Start the dev server yarn dev

Components

Changed from previous iterations of the template, many atomic components have been removed from this repository in favor of using the @rubin-epo/epo-react-lib package.

Styling

Global styles are also imported from this library, although some of the resets and other basic styling have been preserved as SASS inside of this template.

The @rubin-epo/epo-react-lib/styles styles are added to the application in [locales]/layout using styled-components global styles helper and wrapped in a 'use client' directive. A pre-release build of the EPO React libraries is necessary for this to function.

To work correctly in the app directory, a styles registry consumes the CSS generated by styled-components, for understanding on how this works see this issue

Following that, styles.scss is imported in the same page.

import { GlobalStyles } from "@rubin-epo/epo-react-lib/styles"; // styled-components
import styles from "@/styles/styles.scss"; // SASS stuff

const RootLayout = async ({ params: { locale = fallbackLng }, children }) => {
  return (
    <html lang={locale}>
      <head></head> // empty header tag is necessary for styles
      <body>
        <UIDReset>
          <StyledComponentsRegistry>
            <GlobalStyles includeFonts={false} />
            <GlobalDataProvider>{children}</GlobalDataProvider>
          </StyledComponentsRegistry>
        </UIDReset>
      </body>
    </html>
  );
};

Components can be imported and used across the application.

import { Container } from "@rubin-epo/epo-react-lib";

export default function Component() {
  return <Container />;
}

Localization

This application is localized using a combination of i18next, Next.js, and CraftCMS. The following outlines the role each piece plays:

Next.js

At the top level of the app directory is a [locale] wildcard folder which will match the first URI segment to determine the locale.

The default locale's key is not shown in the URI, this function along with other locale detection and routing is managed by the next-intl package's middleware. The middleware will save the current locale to a cookie named NEXT_LOCALE

Example:

/ <-- English homepage

/es <-- Spanish homepage

/surveying-the-solar-system <-- English investigation landing page

/es/surveying-the-solar-system <-- Spanish investigation landing page

The locale URI segment is considered the source of truth for locale in this application.

i18next

i18next is set up to work for both server and client components in the app directory. The language config is defined in lib/i18n/settings.

Server Components

There is a server useTranslation hook in lib/i18n that can be used by server components, this hook requires passing in the namespaces and locale.

import { useTranslation } from `@\lib\i18n`

const Layout = () => {
  const { t } = await useTranslation("es", "translation");

  return <div>{t("translation:key")}</div>;
};

Client Components

A singular instance of i18next is put into a provider at the root layout. Client components rendered during the SSR pass and browser pass can access this instance with the useTranslation hook imported from react-i18next.

'use client'
import { useTranslation } from `react-i18next`

const Page = () => {
  const { t } = useTranslation();

  return <div>{t("translation:key")}</div>;
};

CraftCMS

All CMS content is localized using CraftCMS. Craft has separate sites defined for each locale that can be accessed during editing. In GraphQL queries, site is the parameter passed to Craft that will determine which locale to retrieve. For the default locale, the site is named default and for other locales it uses the two digit locale identifier.

const site = locale === "en" ? "default" : locale;
const uri = `${investigation}/${page}`;
const { data } = await queryAPI({
  query: Query,
  variables: {
    site: [site],
    uri: [uri],
  },
});

GraphQL Codegen & TypeScript

This site uses GraphQL Codegen to generate static types for data sent to and received from Craft's headless API. In short, GraphQL Codegen downloads and stores the schema from the API, then observes request definitions in components and integrates with TypeScript to type the response. Use yarn codegen to run these two processes. There is also a watcher that can be used, but this isn't set up currently.

Configuration is defined in /codegen.ts. A secret token is required to fetch any private schemas; this can be generated in the Craft backend and stored as an environment variable. For currently required schema tokens, see /.env.local.sample.

To avoid type conflicts, GraphQL Codegen should be configured to observe separate files for each schema. The current configuration is to use the public schema by default, then store components that have queries or fragments for private schemas in clearly-marked subfolders (e.g. /components/student-schema/). See the generates property in /codegen.ts for specifics. Components and Server Actions also need to make sure they import the graphql() function from the correct location; for instance:

import { graphql } from "@/gql/public-schema";

Running the client within a Docker container

Running the client within a container is a good way to test deployment in a production-like environment.

There is one crucial thing to keep in mind when configuring your local client to run in a Docker container: Docker containers run in an isolated network that have a different concept of the usage of "localhost". As such, despite the fact that the Craft CMS container may be exposed at localhost on port 8080 on the host machine (your laptop), within the client container "localhost" is local to that container. In order for the client container to be able to communicate with the Craft CMS container you need to know the Craft CMS container's gateway IP address.

Luckily, a node.js script is bundled with this code and Docker allows for arguments to be passed into a docker build command.

In order to build the Docker client image ensure the API project is running then enter the following command in the root project folder:


docker build -t epo/rubin_ui . --build-arg API_IP=$(node getApiGatewayURL) --build-arg API_PORT=8080

As mentioned, if the Craft CMS container project is not running within a Docker container before running the above command then the build may succeed, but will have broken links, images, and missing content.

Finally, once the image is built, create/start the Docker container with the following command:


docker run -p 3000:3000 epo/rubin_ui

Finding the Craft CMS container's IP address

Automated:

For your convenience, a node.js script has been included in this repo that grabs the Craft CMS container Docker gateway IP and logs it to the terminal. Ensure the Craft CMS container is running, then in the terminal enter:


node getApiGatewayURL

Manual:

  1. Ensure that the Craft CMS container is running and functioning correctly by going to http://localhost:8080/api, if everything is working fine you should see some message about a missing GraphQL query
  2. In the terminal, enter the command docker network ls and you should she text table output - under the "NAME" column verify that you see one row with the value of the Craft CMS container
  3. Enter the command docker network inspect <NAME>
  4. The ouput from the above command will be a JSON object, the gateway IP can be found at: IPAM.Config.Gateway

This IP will change between bringing up and down the container, so keep in mind that you'll need to do this step everytime you bring the Craft CMS containers down and back up.