This is the early access documentation preview for Custom Views. This documentation might not be in sync with our official documentation.
@/application-shell
React component that ties together all the main functionalities of the Custom Views.
Installation
Install the @commercetools-frontend/application-shell
package
npm --save install @commercetools-frontend/application-shell
Additionally, install the peer dependencies (if not present)
npm --save install @apollo/client react react-dom react-intl react-redux react-router-dom redux @testing-library/react @testing-library/react-hooks
Components
CustomViewShell
This is the main component that contains all the general logic to render a Custom View.
The CustomViewShell
component must be rendered as the top-level component of your Custom View.
Usage
We recommend to render the Custom View content as children
of <CustomViewShell>
.
The <CustomViewShell>
pre-configures the Custom View entry point routes. In addition, the entry point route is protected by the basic View permission check. This means that a user without permission from your Custom View won't be able to access the Custom View route.
You aren't required to use routes in your Custom View. You can use them if you need to have different views. For example, a Custom View with a listing page and details page.
import { CustomViewShell } from '@commercetools-frontend/application-shell';const loadMessages = async (locale) => {// ...}const AsyncApplicationRoutes = React.lazy(() => import('../../routes' /* webpackChunkName: "avengers" */));const EntryPoint = () => (<CustomViewShellapplicationMessages={loadMessages}><AsyncApplicationRoutes /></CustomViewShell>);export default EntryPoint;
Properties
applicationMessages
object or func
This is either an object containing all the translated messages, grouped by locale{ en: { Welcome: "Welcome" }, de: { Welcome: "Wilkommen" } }
or a function that returns a Promise that resolves to such an object.
The function is called with a locale
parameter. See Importing translations.
children
node
Instead of using the render
prop, render your application component as children of <CustomViewShell>
.
By doing so, the <CustomViewShell>
pre-configures the main application routes according to the entryPointUriPath
defined in the custom-application-config.json
.
This is an opt-int behavior as a replacement of the render
prop, to simplify the entry point setup.
apolloClient
ApolloClient (optional)
An optional instance of ApolloClient to be used instead of the default one. This is usually the case when you need to configure the Apollo cache. See createApolloClient
.
Hooks
useMcQuery
A React hook that wraps the useQuery hook of Apollo Client. The only difference is that useMcQuery
properly types the context
object, which is always used to define the GraphQL target
. See Data Fetching.
useMcLazyQuery
A React hook that wraps the useLazyQuery hook of Apollo Client. The only difference is that useMcLazyQuery
properly types the context
object, which is always used to define the GraphQL target
. See Data Fetching.
useMcMutation
A React hook that wraps the useMutation hook of Apollo Client. The only difference is that useMcMutation
properly types the context
object, which is always used to define the GraphQL target
. See Data Fetching.
Utilities
setupGlobalErrorListener
Configures global event listeners to catch unexpected errors and report them to Sentry. Make sure to render this in the entry-point
file.
import {setupGlobalErrorListener,CustomViewShell,} from '@commercetools-frontend/application-shell';setupGlobalErrorListener();const EntryPoint = () => {return (<CustomViewShellapolloClient={apolloClient}// ...other props/>);};
createApolloClient
Creates a new instance of the Apollo Client. Use this to extend certain functionalities of the preconfigured Apollo Client.
import { createApolloClient } from '@commercetools-frontend/application-shell';createApolloClient({// ...})
Available options are:
cache
(optional): Configuration of the Apollo cache in relation to the data requirements of your Custom View.restLink
(optional): Instance of the Apollo REST link.This feature is available from version
21.10.0
onwards.The
apollo-link-rest
and its related dependencies are not included in the@commercetools-frontend/application-shell
package and must be installed separately.When configuring the REST link, we recommend setting the
uri
using the getMcApiUrl() utility function.
To allow reusing the custom Apollo Client instance in different places, we recommend creating a separate file, for example src/apollo-client.js
, and define the configuration there.
import { createApolloClient } from '@commercetools-frontend/application-shell';const configureApollo = () =>createApolloClient({cache: {// ...}})export default configureApollo
The new Apollo Client instance must be explicitly passed to the <CustomViewShell>
.
import {CustomViewShell,} from '@commercetools-frontend/application-shell';import configureApolloClient from '../../apollo-client';const apolloClient = configureApolloClient();const EntryPoint = () => {return (<CustomViewShellapolloClient={apolloClient}// ...other props/>);};
Furthermore, in your tests you also need to create a new instance of your custom Apollo Client and pass it to the test utils.
import { renderCustomView } from '@commercetools-frontend/application-shell/test-utils';import configureApolloClient from '../../apollo-client';renderCustomView({apolloClient: configureApolloClient(),// ...});
createApolloContextForProxyForwardTo
Creates the Apollo context
object with all the required options for using the /forward-to
endpoint. See Integrate with your own API.
import {createApolloContextForProxyForwardTo,useMcQuery,} from '@commercetools-frontend/application-shell';import { useCustomViewContext } from '@commercetools-frontend/application-shell-connectors';const useExternalApiFetcher = () => {// Assuming that the `custom-application-config.json` contains the custom value:// `{ additionalEnv: { externalApiUrl: 'https://my-custom-app.com/graphql'} }`const externalApiUrl = useCustomViewContext(context => context.environment.externalApiUrl);const { loading, data, error } = useMcQuery(MyQuery, {context: createApolloContextForProxyForwardTo({// The URL to your external APIuri: externalApiUrl,// Provide custom HTTP headers (optional)headers: {'x-foo': 'bar',},// Set `"X-Forward-To-Audience-Policy"` header in the request with provided value (optional)audiencePolicy: 'forward-url-full-path',// Set `"X-Forward-To-Claims": "permissions"` header in the request (optional)includeUserPermissions: true}),});return {loading,data,error,}};
Available options are:
uri
(required): The URL of the external API to forward the request to.headers
(optional): Additional HTTP headers to be included in the request to the external API.audiencePolicy
(optional): See configuring the audience policy.includeUserPermissions
(optional): See configuring custom claims.version
(optional): See versioning.
executeHttpClientRequest
This feature is available from version 21.10.0
onwards.
This function should be used for configuring custom HTTP clients to provide all the recommended functionalities such as:
- Defining the required/recommended HTTP headers for the Merchant Center API.
- Automatically renewing the token to access a particular API.
import {executeHttpClientRequest,} from '@commercetools-frontend/application-shell';
The function accepts a callback function THttpClientFetcher
to execute the request and an optional object THttpClientConfig
for the HTTP request configuration.
The callback function THttpClientFetcher
is passed one argument with the configured request options THttpClientOptions
that you would use to configure the HTTP request for your HTTP client.
type THttpClientOptions = {credentials: 'include';/*** The HTTP headers included by default are:* - Accept* - Authorization (only in development)* - X-Application-Id* - X-Correlation-Id* - X-Project-Key* - X-User-Agent*/headers: THeaders;};type TFetcherResponse<Data> = {/*** The parsed response from the server.*/data: Data;/*** The HTTP status code from the server response.*/statusCode: number;/*** Implement a function to access the HTTP headers from the server response.*/getHeader: (headerName: string) => string | null;}type THttpClientFetcher<Data> = (options: THttpClientOptions) => Promise<THttpClientFetcherResponse<Data>>;async function executeHttpClientRequest<Data>(fetcher: THttpClientFetcher<Data>,config?: THttpClientConfig): Promise<Data>;
The THttpClientConfig
object accepts the following options:
userAgent
(optional): A custom user agent to identify the HTTP client.
We recommend to use the@commercetools/http-user-agent
package.import createHttpUserAgent from '@commercetools/http-user-agent';const userAgent = createHttpUserAgent({name: 'fetch-client',version: '2.6.0',libraryName: window.app.applicationName,contactEmail: 'support@my-company.com',});headers
(optional): Additional HTTP headers to be included in the request. The provided recommended headers won't be overwritten.forwardToConfig
(optional): Configuration for using the/proxy/forward-to
endpoint to connect to an external API.uri
(required): The URL of the external API to forward the request to.headers
(optional): Additional HTTP headers to be included in the request to the external API.audiencePolicy
(optional): See configuring the audience policy.includeUserPermissions
(optional): See configuring custom claims.version
(recommended): See versioning.
You can see some examples of integrating this with different HTTP clients:
getMcApiUrl
Returns the URL of the Merchant Center API. This is useful to configure HTTP clients that should connect to that API.
import {getMcApiUrl,} from '@commercetools-frontend/application-shell';const mcApiUrl = getMcApiUrl();// https://mc-api.<region>.commercetools.com
buildApiUrl
Returns a URL of the Merchant Center API for the given URI path. This is useful to configure the request URL without having to get the URL of the Merchant Center API.
import {buildApiUrl,} from '@commercetools-frontend/application-shell';const apiEndpoint = buildApiUrl('/proxy/ctp/channels');// https://mc-api.<region>.commercetools.com/proxy/ctp/channels
Test utils
The package provides a separate entry point with utilities for testing Custom Views.
import { /**/ } from '@commercetools-frontend/application-shell/test-utils';
Most of the utility functions are related to React Testing Library, as the recommended testing strategy.
The test-utils
simulate the components-under-test as if it was rendered by the <CustomViewShell>
and provide the necessary setup to fully test a Custom View. This includes things like Apollo, React Intl, React Router, etc.
renderCustomView
A wrapper around the render
method of the React Testing Library. All the basic setup for testing is included here.
Usage
import {renderCustomView,screen,} from '@commercetools-frontend/application-shell/test-utils';describe('rendering', () => {it('should render the authenticated users first name', async () => {renderCustomView({user: {firstName: 'Leonard',},children: <FirstName />});await screen.findByText('First name: Leonard');});});
Options
locale
string
Determines the UI language and number format. It is used to configure <IntlProvider>
. Only core messages will be available during tests, no matter the locale
. The locale can be a full IETF language tag, although the Merchant Center is currently only available in a limited set of languages.
projectKey
string
Sets the Custom View context projectKey
. The passed key gets merged with the tests default project.
projectAllAppliedPermissions
string
Sets the default project allAppliedPermissions
property. The passed array will replace the default project allAppliedPermissions
.
customViewHostUrl
string
Defines the URL the Custom View receives as part of the emulation of it being rendered in a Merchant Center built-in application.
customViewConfig
string
The configuration object used to configure the <CustomViewContextProvider>
, so the result of merging the default Custom View configuration with options.customViewConfig
.
apolloClient
ApolloClient
Pass a custom instance of Apollo client, useful when your Custom View has some custom cache policies. You can use the exported function createApolloClient
of @commercetools-frontend/application-shell
.
environment
object
Sets the customViewContext.environment
. The passed object gets merged with the tests default environment. Pass null
to completely remove the environment
, which renders the ui
as if no environment
was given.
user
object
Sets the customViewContext.user
. The passed object gets merged with the test's default user. Pass null
to completely remove the user
, which renders the ui
as if no user was authenticated.
Return values
Calling renderCustomView
returns the Result object of React Testing Library, with the addition of the following properties:
history
object
The history created by renderApp
which is passed to the router. It can be used to simulate location changes and so on.
user
object
The user
object used to configure <CustomViewContextProvider>
, so the result of merging the default user with options.user
. Note that this is not the same as customViewContext.user
. Can be undefined
when no user is authenticated (when options.user
was null
).
project
object
The project
object used to configure <CustomViewContextProvider>
, so the result of merging the default project with options.project
. Note that this is not the same as customViewContext.project
. Can be undefined
when no project was set (when options.project
was null
).
environment
object
The environment
object used to configure <CustomViewContextProvider>
, so the result of merging the default environment with options.environment
. Note that this is not the same as customViewContext.environment
. Can be undefined
when no environment was set (when options.environment
was null
).
mapResourceAccessToAppliedPermissions
Helper function to map user permissions to applied resource permissions. This is useful in testing when defining user permissions. See Testing user permissions for more information.
{project: {allAppliedPermissions: mapResourceAccessToAppliedPermissions([PERMISSIONS.View,]),},}
denormalizePermissions
Helper function to map user permissions defined as objects to a list of applied resource permissions.
{project: {allAppliedPermissions: denormalizePermissions({canView: true,}),},}