6.0.0 • Published 21 days ago

@spscommerce/items-experience v6.0.0

Weekly downloads
-
License
-
Repository
github
Last release
21 days ago

Items Experience

The Items Experience is a collection of UI components that interact with Assortment's Items API. Using these components in multiple frontend projects will ensure a consistent user experience across SPS applications.

"Earthshaking"

-- @omnipitous

Contents

Installation

Install the package:

pnpm add @spscommerce/items-experience

The package is hosted publicly on the NPM registry, so no extra configuration or permissions are required for installing.

This package requires some Peer Dependencies that should also be installed (refer to package.json for versions):

  • @sps-woodland/content-row
  • @sps-woodland/core
  • @sps-woodland/file-upload
  • @sps-woodland/illustrations
  • @sps-woodland/key-value-set
  • @sps-woodland/page-title
  • @sps-woodland/product-bar
  • @sps-woodland/tokens
  • @sps-woodland/zero-state
  • @spscommerce/ds-react
  • @spscommerce/asst-api
  • @spscommerce/form-presets-api
  • @spscommerce/items-api
  • @spscommerce/policies-api
  • react
  • react-dom
  • react-query
  • react-router-dom (optional)

Basic Setup

Items Experience was built to be used with React Router (version 6.4 or later), but is compatible with any routing setup.

All routing options require some initial basic setup, which includes:

  • Setting up a context provider
  • Setting up API providers

Routing can be setup after the basic setup.

Context Provider

All components from Items Experience must exist within the context of ItemsExperienceBasicContextProvider.

ItemsExperienceBasicContextProvider provides common data and functions from the host app:

type ItemsExperienceBasicContextProps = {
  /**
   * `growl` from `@sps-woodland/growler`
   */
  growl: typeof growl;
  /**
   * Allows form-presets to be saved for your application
   */
  formPresetDetails: {
    appName: string;
    advancedSearchDefaultsFormName: string;
    selectedColumnsFormName: string;
  };
  /**
   * Options for advanced search.  Currently only includes standard attributes.
   */
  advancedSearchOptions: {
    /**
     * An array of standard attribute Ids that will be Pre-selected attributes in advanced search.
     */
    standardAttributes: string[];
  };
  /**
   * Optional array of available attributes. When provided, attribute select options will be filtered to this list
   */
  availableAttributeList?: string[];
  /**
   * Config options for the Items Index page
   */
  itemsIndexConfig: {
    /**
     * An array of unique attributes.
     * Affects available columns.
     */
    uniqueAttributes: string[];
    /**
     * Boolean flag to enable Stage Item feature.
     * Affects column chooser.
     */
    isStageItemEnabled: boolean;
    /**
     * Boolean flag to enable MSIS feature.
     * Affects column chooser.
     */
    isMsisUiEnabled: boolean;
    /**
     * Boolean flag to enable Media Item feature.
     */
    enableMediaItem: boolean;
    /**
     * Optional boolean to show the "Add Item" button.
     * Defaults to false.
     */
    showAddItemsBtn?: boolean;
    /**
     * Array of columns that are initially selected.
     */
    columnsInitiallySelected: { value: string; required?: boolean }[];
    /**
     * Array of columns that are initially unselected.
     */
    columnsInitiallyUnselected: { value: string }[];
    /**
     * Optional boolean to hide Status column.
     * Defaults to false.
     */
    hideStatusColumn?: boolean;
  };
  /**
   * An optional {@link QueryClient} can be passed to Items Experience.
   *
   * Note: The {@link QueryCache} will be replaced.
   *
   * It is not recommended to pass a `QueryClient` to Items Experience unless greater control is required, such as disabling retries during testing.
   * Items Experience will create its own `QueryClient`.
   */
  queryClient?: QueryClient;
  /**
   * Optional parameter for passing identity org id allowing the user to act as part of this organization.
   */
  ownerOrgId?: string;
  /**
   * Optional for Item search. Allows filtering items by the requesting application. eg. Assortment or Item XREF.
   */
  applicationType?: ApplicationType;
  /**
   * Your application, including Items Experience pages
   */
  children: React.ReactNode;
};

API Provider Setup

In addition to context providers, Items Experience requires a valid user token to make network requests. All page components will wait until a valid token has been provided before rendering to ensure there are no race conditions.

Items Experience exports a function to set the token, updateApiProviders:

import { updateApiProviders } from "@spscommerce/items-experience";

updateApiProviders(env, "user_token");

Draft Notification Setup

The forms in this package save drafts to mitigate the loss of unsaved work done by the end user. Although optional, it is recommended that the user is notified when a draft is saved. To do this, Items Experience exports triggerDraftNotifications() which must be called after every rout change.

If you are using React-Router, setup may look like this:

import { useLocation } from "react-router-dom";
import { triggerDraftNotifications } from "@spscommerce/items-experience";

export function Component() {
  // Get the current location from react-router
  const location = useLocation();

  // Call `triggerDraftNotifications` any time `location` changes
  useEffect(() => {
    triggerDraftNotifications();
  }, [location]);

  return ...
}

Routing

Items Experience consists of multiple pages, and therefore requires a routing solution. Simple routing configuration can be done with React Router, but Items Experience can also be configured to work with any router.

React Router

If your application uses React Router version 6.4, then setup can be much simpler. Items Experience exports a RouteObject that can be added to your app's existing RouteObject at any level. It uses relative routing to automatically configure navigation between pages.

ItemsExperienceBasicContextProvider and updateApiProviders are still required for setup, but ItemsExperienceUrlContextProvider is not because routing is handled automatically.

import { itemsExperienceRouteObject } from "@spscommerce/items-experience/react-router";

const router = createHashRouter([
  {
    path: "/",
    element: <Navigate to="a" />,
  },
  {
    path: "/a",
    element: <A />,
  },
  {
    path: "/b",
    element: <B />,
  },
  {
    path: "/items",
    element: <Outlet />,
    children: [itemsExperienceRouteObject()],
  },
]);

Optional parameters can be provided to itemsExperienceRouteObject, which allow Items Experience to link to external pages:

{
  errorsIndexLocation?: string;
  errorsByItemLocation?: string;
  imageSettingsLocation?: string;
  exportsConfigLocation?: string;
}

Please see src/App.tsx for a full example.

Using Your Own Router

This package exports each page as a single component so they can be used in your project's routing system. Each page component can exist under the URL of your choice within your project, but those URLs must be provided to ItemsExperienceUrlContextProps to enable navigation between pages.

ItemsExperienceUrlContextProvider provides routing data and functions from the host app. This component allows Items Experience components to integrate with your application's router:

type ItemsExperienceUrlContextProps = {
  /**
   * Your application, including Items Experience pages
   */
  children: React.ReactNode;
  /**
   * URL data and functions.
   */
  value: {
    /**
     * Path parameters for the current route
     */
    urlParams: Record<string, string | undefined>;
    /**
     * Search parameters for the current route
     */
    urlSearchParams: URLSearchParams;
    /**
     * Function to set search parameters.  Used for url state.
     * @param params Search parameters to set
     * @param replace Should the new parameters replace the current parameters (ie. not add to location history)
     * @returns void
     */
    setUrlSearchParams: (params: URLSearchParams, replace: boolean) => void;
    /**
     * A function to navigate to different url's
     * @param location The location to navigate to
     * @returns void
     */
    navigateTo: (location: string) => void;
    /**
     * Object containing strings that specify the url location of each page when routing is handled by the host app.
     * These locations allow Items Experience pages to link to each other.
     *
     * Required locations have a corresponding page component exported by Items Experience.
     * For example:
     * ```
     * // Corresponds with `errorDetailsLocation`
     * import { ErrorDetailsPage } from '@spscommerce/items-experience'
     * ```
     *
     * Optional locations link to pages that are external to Items Experience.
     * Typically, these will not be used by teams other than Assortment.
     */
    locations: {
      /**
       * Errors Index location.
       * This location is external to Items Experience and is optional.
       */
      errorsIndexLocation?: string;
      /**
       * Error Details location.
       */
      errorDetailsLocation: string;
      /**
       * Errors by Item location.
       * This location is external to Items Experience and is optional.
       */
      errorsByItemLocation?: string;
      /**
       * Imports Index location.
       */
      importsIndexLocation: string;
      /**
       * Imports Create Template location.
       */
      importsCreateTemplateLocation: string;
      /**
       * Items Index location.
       */
      itemsIndexLocation: string;
      /**
       * Item Details location.
       */
      itemDetailsLocation: string;
      /**
       * Advanced Search Defaults location.
       */
      advSearchDefaultsLocation: string;
      /**
       * Image Settings location.
       * This location is external to Items Experience and is optional.
       */
      imageSettingsLocation?: string;
      /**
       * Exports Configuration location.
       * This location is external to Items Experience and is optional.
       */
      exportsConfigLocation?: string;
    };
  };
};

Items Experience exports the following page components in each category:

  • Preferences
    • AdvancedSearchDefaultsPage
  • Errors
    • ErrorDetailsPage
  • Imports
    • ImportsCreateTemplatePage
    • ImportsIndexPage
  • Items
    • ItemsIndexPage
    • ItemDetailsPage

Some pages expect URL path parameters (ItemsExperienceUrlContextProps.value.urlParams) and are required to function as expected:

  • ErrorDetailsPage expects itemInfoId
    • ex. errors/detail/:itemInfoId
  • ItemsDetail expects id
    • ex. items/detail/:id

When Items Experience pages link to each other, these path parameters will be automatically be appended to the locations provided in ItemsExperienceUrlContextProps.value.locations. The host app needs to provide the path parameters to ItemsExperienceUrlContextProvider because Items Experience components do not have direct access to the router.

Contributing

When contributing, please keep in mind that this is a public package that is used by multiple teams. Breaking changes need to be documented (see Pull Requests and Deployment for details).

Installation

This project is part of the Assortment UI workspace and uses pnpm for package management.

Install dependencies:

pnpm i

Project Structure

lib

The lib folder contains the code that will be exported. It has two sub-folders: core and react-router. These sub-folder correspond to the two entrypoints of the package.

  • core contains the base components the Items Experience, without any routing.

  • react-router contains the react-router adapter, which is a RouteObject that can be dropped into an existing react router config

src

The src folder contains an example application that uses the Items Experience with the react-router adapter.

Running the example project:

pnpm dev

Testing

This project is set up for unit tests and end-to-end tests.

Unit Tests

This project uses Vitest with React Testing Library for unit tests. These tests will have a *.test.(ts|tsx) file extension.

Running tests in watch mode:

pnpm test

Running tests with an explorer UI:

pnpm test:ui

End-to-end Tests

This project uses Playwright for end-to-end tests. These tests will exist under the e2e folder and will have a *.spec.ts file extension.

Running tests:

pnpm test:e2e

Playwright also features a UI for step by step debugging.

Running the Playwright UI:

pnpm test:e2e-ui

Storybook

This project uses Storybook to help with development.

Running Storybook:

pnpm storybook

Pull Requests and Deployment

This projects uses Microsoft's beachball to manage semantic versioning.

Pull Requests

When opening a pull request, the build pipeline will check if a changefile is included. The build will fail if no changefile is found. To create a changefile, run the beachball:change script. The cli will ask a few questions and then generate a changefile.

When generating a changefile, the type of change must be specified:

  • Patch - bug fixes; no backwards incompatible changes.
  • Minor - small feature; backwards compatible changes.
  • None - this change does not affect the published package in any way.
  • Major - major feature; breaking changes.

Deployment

The project is not automatically deployed when a Pull Request is merged. The project must be deployed manually by running the Items Experience Publish pipeline.

When this pipeline is run, it will run the following on the main branch:

  • check lint
  • check formatting
  • run tests
  • build
  • check for changefiles
  • increment package version, delete changefiles, commit to main
  • publish the package to NPM

Rotating NPM keys

The key required to publish the package can only be valid for a maximum of 365 days. When the key expires, it must be replaced with a newly generated key. A newly key can be generated on NPM, using the spsc_asst account.

Scripts

  • dev: run the example project
  • test: run unit tests in watch mode
  • test:ui: run unit tests with the explorer UI
  • test:ci: run unit tests in CI
  • test:e2e: run the playwright e2e tests
  • test:e2e-ui: run the playwright e2e test explorer and debugger
  • lint:lib: lint the lib folder
  • lint:src: lint the src folder
  • prettier:check: check that all files are formatted correctly
  • storybook: run storybook
  • build-storybook: build deployable storybook files (not necessary to run storybook locally)
  • beachball:change: generate a changefile (at least one changefile is required for a pull request)
  • beachball:check: check that a changefile accompanies changes that are not in main (used by CI)
  • beachball:publish: publish the package (used by CI)
5.0.0

22 days ago

6.0.0

21 days ago

2.7.0

7 months ago

2.5.2

8 months ago

2.6.0

7 months ago

2.5.3

8 months ago

3.0.0

4 months ago

4.0.0

2 months ago

2.5.1

8 months ago

2.5.0

9 months ago

2.3.0

10 months ago

2.1.2

11 months ago

2.2.0

11 months ago

2.1.1

11 months ago

2.1.4

11 months ago

2.4.0

10 months ago

2.3.1

10 months ago

2.1.3

11 months ago

2.1.0

12 months ago

2.0.0

1 year ago

1.4.1

1 year ago

1.4.0

1 year ago

1.3.0

2 years ago

1.2.0

2 years ago

1.1.0

2 years ago

1.0.0

2 years ago

0.0.1-beta.10

2 years ago

0.0.1-beta.9

2 years ago

0.0.1-beta.8

2 years ago

0.0.1-beta.7

2 years ago

0.0.1-beta.6

2 years ago

0.0.1-beta.5

2 years ago

0.0.1-beta.4

2 years ago

0.0.1-beta.3

2 years ago

0.0.1-beta.2

2 years ago

0.0.1-beta.1

2 years ago

0.0.1-beta.0

2 years ago

0.0.1

2 years ago