Broadleaf Microservices
  • v1.0.0-latest-prod

Release Notes for 1.10.0 and Patches

Important Updates

  • Now supports Node 18. Node 14 has reached end-of-life and we recommend upgrading to Node 18 as soon as possible since Node 16 reaches end of life in September 2023.

    • Upgrading Node is not required to use this update.

Features & Enhancements

1.10.0

  • Display shipment info for a fulfillment if present at OrderFulfillment.shipment

  • Added support for rendering the Catalog Selector as part of the basic ListGrid Form Row Action similar to what the Clone action does for Products

    • This allows users to define arbitrary form actions besides cloning on list grids using metadata for Catalog entities.

  • Added "moreThan" and "lessThan" validation methods for number fields to support validating that a field is more/less than a set value.

  • Added various accessibility enhancements such as missing aria attributes and motion-reduce styles

  • Added 404 component when a route is not found rather than redirecting the user to the homepage and obfuscating the issue

  • Added the ability to manage content items from within other items.

    • Also, allows the user to create items "inline" that are considered "embedded" within the parent item

  • Added ability to enable Dev Settings mode per-user instead of only globally

    • Dev Settings allows users of the Admin to view the Metadata JSON used to render various components

    • Globally, this can be enabled using VITE_ENABLE_DEV_SETTINGS. Setting this to true will enable dev settings for all users.

    • The specific security scope required for a user to be able to use Dev Settings when VITE_ENABLE_DEV_SETTINGS is false can be specified using VITE_DEV_SETTINGS_SCOPE.

      • Default is DEV_SETTINGS. A user would then need to have the ALL_DEV_SETTINGS permission to view dev settings.

1.10.1

  • Added new custom form actions for updating Order Fulfillment properties.

New Modal Form Action for Fulfillments

We introduced a new form action to allow defining custom actions against an Order Fulfillment. Examples are defining in metadata an action to update the Shipment info on the Fulfillment or updating a Fulfillment’s Address. This can be referenced for the FulfillmentView (type FULFILLMENT) or ItemsOrderViewSection (type ORDER_ITEM) using the action type of MODAL_FORM.

Example configuration for an action to add Shipment info to Order Fulfillment
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.broadleafcommerce.metadata.dsl.core.OperationType;
import com.broadleafcommerce.metadata.dsl.core.extension.fields.DateField;
import com.broadleafcommerce.metadata.dsl.core.utils.Actions;
import com.broadleafcommerce.metadata.dsl.core.utils.Conditionals;
import com.broadleafcommerce.metadata.dsl.core.utils.Endpoints;
import com.broadleafcommerce.metadata.dsl.core.utils.Fields;
import com.broadleafcommerce.metadata.dsl.core.utils.ValidationMethods;
import com.broadleafcommerce.metadata.dsl.core.utils.ValidationSchemas;
import com.broadleafcommerce.metadata.dsl.registry.ComponentSource;
import com.broadleafcommerce.order.metadata.autoconfigure.OrderServicesMetadataAutoConfiguration;
import com.broadleafcommerce.order.metadata.dsl.extension.views.FulfillmentView;
import com.broadleafcommerce.order.metadata.dsl.extension.views.OrderView;
import com.broadleafcommerce.order.metadata.support.OrderFulfillmentStatuses;
import com.broadleafcommerce.order.metadata.support.OrderIds;
import com.broadleafcommerce.order.metadata.support.OrderPaths;
import com.broadleafcommerce.order.metadata.support.OrderProps;
import com.broadleafcommerce.order.metadata.support.OrderScopes;

import java.util.List;

import lombok.RequiredArgsConstructor;
import lombok.experimental.UtilityClass;

@Configuration
@RequiredArgsConstructor
@AutoConfigureAfter(OrderServicesMetadataAutoConfiguration.class)
public class OrderMetadataAutoConfiguration {

    @UtilityClass
    static class ShipmentProps {
        public final String SHIPMENT = "shipment";
        public final String TRACKING_NUMBER = SHIPMENT +  ".trackingNumber";
        public final String TRACKING_URL = SHIPMENT + ".trackingUrl";
        public final String SHIP_DATE = SHIPMENT + ".shipDate";
        public final String SHIPPER_TYPE = SHIPMENT + ".shipperType";
    }

    @Bean
    public ComponentSource addCustomFulfillmentAction() {
        return registry -> {
            FulfillmentView<?> fulfillmentView =
                    (FulfillmentView<?>) registry.get(OrderIds.FULFILLMENT_DETAILS);
            fulfillmentView
                    .addAction("MODAL_FORM", Actions.action()
                            .label("order.actions.add-shipment.label")
                            .operationType(OperationType.UPDATE)
                            .placement("PRIMARY")
                            .type("MODAL_FORM")
                            // since actions don't normally have conditionals, they need to be
                            // as an attribute if needed added
                            .attribute("conditionals", List.of(
                                    Conditionals.when(OrderProps.OrderFulfillment.STATUS)
                                            .equalTo(OrderFulfillmentStatuses.FULFILLED)))
                            .addEndpoint("UPDATE", Endpoints.put()
                                    .uri(OrderPaths.ORDER_FULFILLMENTS + "/${fulfillment.id}")
                                    .scope(OrderScopes.ORDER_FULFILLMENT))
                            .addComponent(ShipmentProps.TRACKING_NUMBER, Fields.string()
                                    .name(ShipmentProps.TRACKING_NUMBER)
                                    .label("order.fields.shipment.tracking-number.label")
                                    .order(1))
                            .addComponent(ShipmentProps.TRACKING_URL, Fields.string()
                                    .name(ShipmentProps.TRACKING_URL)
                                    .label("order.fields.shipment.tracking-url.label")
                                    .order(2)
                                    .validationSchema(ValidationSchemas.string()
                                            .method(ValidationMethods.urlAbsoluteOrRelative(
                                                    "order.fields.shipment.tracking-url.valid"))))
                            .addComponent(ShipmentProps.SHIP_DATE, Fields.date()
                                    .name(ShipmentProps.SHIP_DATE)
                                    .label("order.fields.shipment.ship-date.label")
                                    .defaultStartOf(DateField.DateStartUnit.DAY)
                                    .order(3))
                            .addComponent(ShipmentProps.SHIPPER_TYPE, Fields.string()
                                    .name(ShipmentProps.SHIPPER_TYPE)
                                    .label("order.fields.shipment.shipper-type.label")
                                    .order(4)));
        };
    }

    @Bean
    public ComponentSource addCustomItemOrderAction() {
        return registry -> {
            OrderView<?> orderView =
                    (OrderView<?>) registry.get(OrderIds.DETAILS);
            orderView
                    .getItemsSection()
                    .addAction("MODAL_FORM", Actions.action()
                            .label("order.actions.add-shipment.label")
                            .operationType(OperationType.UPDATE)
                            .placement("CARD")
                            .type("MODAL_FORM")
                            // since actions don't normally have conditionals, they need to be added
                            // as an attribute if needed
                            .attribute("conditionals", List.of(
                                    Conditionals.when(OrderProps.OrderFulfillment.STATUS)
                                            .equalTo(OrderFulfillmentStatuses.FULFILLED)))
                            .addEndpoint("UPDATE", Endpoints.put()
                                    .uri(OrderPaths.ORDER_FULFILLMENTS + "/${fulfillment.id}")
                                    .scope(OrderScopes.ORDER_FULFILLMENT))
                            .addComponent(ShipmentProps.TRACKING_NUMBER, Fields.string()
                                    .name(ShipmentProps.TRACKING_NUMBER)
                                    .label("order.fields.shipment.tracking-number.label")
                                    .order(1))
                            .addComponent(ShipmentProps.TRACKING_URL, Fields.string()
                                    .name(ShipmentProps.TRACKING_URL)
                                    .label("order.fields.shipment.tracking-url.label")
                                    .order(2)
                                    .validationSchema(ValidationSchemas.string()
                                            .method(ValidationMethods.urlAbsoluteOrRelative(
                                                    "order.fields.shipment.tracking-url.valid"))))
                            .addComponent(ShipmentProps.SHIP_DATE, Fields.date()
                                    .name(ShipmentProps.SHIP_DATE)
                                    .label("order.fields.shipment.ship-date.label")
                                    .defaultStartOf(DateField.DateStartUnit.DAY)
                                    .order(3))
                            .addComponent(ShipmentProps.SHIPPER_TYPE, Fields.string()
                                    .name(ShipmentProps.SHIPPER_TYPE)
                                    .label("order.fields.shipment.shipper-type.label")
                                    .order(4)));
        };
    }

}
Example translatable text
order.fields.shipment.tracking-number.label=Tracking Number
order.fields.shipment.tracking-url.label=Tracking URL
order.fields.shipment.tracking-url.valid=Must be a valid url
order.fields.shipment.ship-date.label=Ship Date
order.fields.shipment.shipper-type.label=Carrier

order.actions.add-shipment.label=Add Shipping Info

1.10.2

  • Added the ability to reverse the colors of values for boolean column.

    • This is typically used when wanting to swap the colors for true and false—true becoming red and false becoming green.

    • In metadata, add .attribute("swapColors", true);.

  • Added dropdown display for Fulfillment Adjustments Total to allow showing the breakdown in Order Details screens.

    • This allows showing the codes used to apply a discount and the amount of the related discount.

  • Added "reason code" select field when created Return Authorizations for Orders.

    • The reason values should be passed in on the action in metadata as the statusChangeReasons attribute: CreateReturnAction.attributes("statusChangeReasons", ReturnChangeReasonsEnum.toOptions()).

  • Added trackable (catalog, tenant, sandbox) information to entity forms' states to allow targeting by conditions.

    • This allows something like a metadata conditional that restricts a field or group to a specific application or tenant context:

      .conditional(Conditionals.when("$tracking.tenantId")
              .equalTo("tenant_id"))
  • Made FulfillmentCardHeader component overridable.

    • To do so, register a component with type blFulfillmentCardHeader.

  • Made FulfillmentViewDetails component overridable.

    • To do so, register a component with type blFulfillmentViewDetails.

  • Made sub-components of FulfillmentCardBody and FulfillmentCardHeader component overridable.

    • To do so, register a component with a type that is the sub-component’s name prefixed with bl.

  • Made FulfillmentItemSummary and sub-components overridable.

1.10.3

  • Enhanced modal forms so that the header and footer are fixed relative to the viewport and only the body scrolls so that the submit button and modal title are always visible.

  • Created a component called JSON Payload which converts the form values into a serialized JSON text — added the component to EntityView which by default is shown for Content Model.

1.10.4

  • Added a Catalog Selector to Lookup Fields that can be displayed if the lookup entity is Catalog-trackable.

    • The selector is only displayed in the Tenant context and is not needed in the Application context to read Catalog entities.

    • The selector can be displayed as a sibling to the Lookup Field using .catalogSelector() or removed using .removeCatalogSelector(). Default is to display it except in rule builders.

    • The selector is always displayed in the Modal. To enable the modal use .modalSearch(UnaryOperator<LookupFieldModal<?>> fn) in metadata

  • Enhanced Variants Grid component on Product forms

    • Now allows setting the display order for the variant option fields (e.g., the selectors for options like color and size) using metadata instead of hardcoding it.

      • Use variantOptionsOrder(int), default order is 3000 so that they display after the name and SKU fields.

    • Added the ability to display an unsaved-changes prompt before closing the Variant update modal form.

      • Use displayUnsavedChangesPrompt(boolean) in the metadata.

      • Default is true.

  • Enhanced DerivedField component

    • Now allows deriving values other than strings.

      • Use .fieldType(String) to specify.

      • Default is DerivedField.SupportedFieldTypes.STRING.

      • Supports: Boolean, Color Picker, Date, Decimal, HTML, Integer, Long, Money, String Array, and Text Area

    • Allow specifying more transformation types for strings

      • Upper, lower, start, and pascal case and capitalize

    • Allow specifying if a derived field’s value should actually be persisted or if the derived value should only be displayed in the UI. This is used in the case of Variants where they inherit prices and name from the Product when not set explicitly.

      • Use .persist(boolean).

      • Default is true.

    • Display derived fields as read-only while they are deriving their value with an edit button to allow overriding the value explicitly.

    • Display a "reset" button next to a modified field to re-derive the value (essentially unsetting the override).

  • Introduced Derived Column component

    • Takes a source and columnType similar to DerivedField

    • Can set deriveIfNull(boolean) to allow deriving the value if the column’s value is null.

      • Default is false.

    • Does not support transformations like DerivedField

  • Added .env property to enable or disable display of navigation filter

  • Added an Application Selector to be displayed in a modal if the lookup field is application-discriminated

    • Added a footer component for decorated lookup fields, where the ModalToggle is displayed when the modalToggleAtFooter metadata attribute is true

  • Added Product Business Types

    • Represents the first step in creating a product. A product cannot change its business type.

    • Product Business Types provide a base set of attributes for products when they are created — for example, the type Clothing would have attributes such as Color, Size. Creating a product under this type would assign these attributes to the product.

1.10.5

  • Added Message component type

    • Registered Message component in metadata

    • Added WarningMessage component

  • Added ability to customize the HelpText icon based on a type.

1.10.5

  • Added ability for MoneyField fields to inherit currency based on the following priority (first being highest) : catalog, entity catalog, application, then tenant.

Bug Fixes

1.10.0

  • Fixed issue with inline filters are covered by listgrid headers

  • Fixed Content Item translations including non-translatable fields

  • Fixed cache name conflict between auth state and transaction caches

  • Fixed not reloading content items and models when Profile is changed

  • Fixed errors for resident grid collections not rendering correctly when there’s a field validation error for one of the collection’s fields

  • Fixed error when trying to select a Variation for a "Single Variation" Item Choice Product Option

  • Fixed content item dropdown not populating options when field type is reference

  • Fixed tooltip for the Applications in the Application Selector not rendering correctly

  • Fixed support for populating a Currency field’s value based on the value of another field

    • For example, Offer#currency specifies the currency of the offer, which will be used as currencyCode for the other money fields, but, if the Offer#currency field is being edited, an error will be thrown immediately for the other money fields since the currencyCode is not yet complete and invalid.

  • Fixed not being upload assets for Theme Fields.

  • Fixed issue where a Date column in a resident grid or similar component would throw an error when the entity was updated.

1.10.1

  • Fixed issue with implicit filters not applying introduced in 1.9.2.

  • Addressed some typescript type import issues and access to the useContextParams hook for the Fulfillment and Order Items view components

  • Fixed validation of URLs that can be absolute or relative. Before, we were not validating that relative paths had to start with a slash.

1.10.2

  • Fixed not being able to make a FieldArrayGrid type field readonly using metadata.

  • Fixed not being able to make ResidentGridCollections readonly using metadata.

  • Fixed catalogs not being hydrated at the tenant level on the first page render.

    • This fixes an issue where some dropdowns were not populating.

  • ActionListGridImport now gets contextParams from props instead of initializing them as empty.

    • This fixes an issue where imported entities were created with incorrect tracking details.

  • Fixed the Category and Menu Search pages not displaying results correctly. Added column classifier from metadata headers to be included as grid headers.

1.10.3

  • Fixed line number misalignment for HTML fields when viewing the raw HTML

  • Fixed HTML field editor toolbar dropdowns being cut off by subsequent group components

    • Instead, the toolbar will display tools in a row

  • Fixed HTML field editor applying inline styles on pasted content in Safari.

    • Inline styles are blocked by the default style-source Content Security Policy

  • Fixed HTML Editor adding inline styles to image tags without user input that caused Content Security Policy violations.

  • Fixed bug where Process button is enabled when Customer Segment update form is in a dirty state. Process button now is disabled when form is dirty.

  • Fixed issue where Preview Changes button on Content Item page does not link to the expected preview of the storefront page. Added preview path template combining Content Model URI and Content Item URI, as well as a default path leading to the storefront homepage.

  • Fixed issues with some typescript types not being resolved.

    • Typescript was not rewriting import aliases with relative paths in declaration files.

  • Fixed issues when using ESM files instead of UMD where custom components using Broadleaf contexts could not resolve the contexts.

    • This could lead to not being able to send requests to Broadleaf endpoints from custom components because they could not hook into the auth or tracking contexts.

  • Fixed color issues with the language selector in the Admin Settings dropdown.

  • Fixed issues with using Prettier and Typescript together in the Admin Starter.

  • Fixed issues when using Jest and Typescript together in the Admin Starter.

  • Fixed the Admin version displayed when running the app so that it shows the version of the @broadleaf/admin-components library instead of the version of the Admin Starter itself.

  • Added the ability to create new values for AttributeChoice options when creating a Variant derived from a VARIANT_DISTINGUISHING option.

  • Fixed issues with displaying rules targeting Cart in the Content Zone Default Content grid.

    • Query nodes with multi fields were making multiple API requests for fields which did not have multiple values, thus failing to properly hydrate the value string in the grid when showing the display rule. Fixed by differentiating the hyrdating method for multi (assume display rule value object is an array, call hydration endpoint for each value and aggregate results) & non-multi fields (call hydration endpoint by passing display rule value object as a whole).

    • Money values in display rule were not being properly displayed. Fixed by differentiating creation of display rule text for money values.

  • Fixed issue where the Collapsible Group error message was displayed as a text block instead of a tooltip.

  • Fixed issue where the single quote character was not being escaped properly in the RSQL queries.

  • Enhanced modal forms so that the header and footer are fixed relative to the viewport and only the body scrolls so that the submit button and modal title are always visible.

1.10.4

  • Fixed list grid header z-index when scrolling since it’s sticky

  • Fixed $0 order total appearing blank in order list grid

  • Fixed issue where form values within collapsible groups in modals disappeared when closing and reopening the modal.

    • Remove unnecessary cleanup function, clearValuesForDescendFields.

  • Fixed Admin language dropdown options overflow display issue by updating styles to render options list to full width

  • Fixed dropdown menu changing position when hovering over options by updating react-select dependency version

  • Fixed application selector input text color being unreadable

  • Fixed custom query builder filters being ignored in export maintenance view when creating a new export and filtering what entities to include, e.g., when filtering which Products to include in an export.

  • Fixed implicit filter and custom query builder filters not working together. Either cq or query_builder param names now work for both in many places around Admin, e.g., when adding new catalogs or profiles to an Application.

  • Fixed catalog selector paging issues

  • Fixed allowed locale resolution and export important Provider and Gateway components as components

    • Fixed VITE_ALLOWED_LOCALES property not being honored by Environment service

    • AdminProvider component now takes the same arguments as I18nProvider

export interface AdminProviderProps {
  /** the allowed locales for the I18nProvider  */
  allowedLocales?: Array<string>;
  /** the default locale for the I18nProvider  */
  defaultLocale?: string;
  /**
   * The set of {@link GatewayComponent} that this provider is responsible for rendering.
   */
  gatewayComponents: Array<Function | object>;
  /** the messages for the I18nProvider  */
  messages?: object;
}
  • TenantGateway, I18nProvider, GlobalProviders, GatewayProvider, ComponentRouter, and AuthGateway components should now be exported from the component module: import { components } from '@broadleaf/admin-components';

    • These are components that are used to compose AdminProvider.

    • These were formerly only exported as "unstable" but have been moved to "components".

      • Fixed DatePicker time display issue found for MacOs Monterey

      • Fixed issue with the display of delete change summaries

      • Fixed issue where regex logic for Allowed Values value fields was not evaluating using passed flags — regex logic now extracts flags from regex string if present to use them for matching

1.10.5

  • Fixed wrong currency symbols displayed on MoneyField fields.

    • Fixed Offer fields' currency symbols displaying inaccurate currency if a catalog-discriminated entity (e.g. Product) was visited before

    • Fixed MoneyField fields without an amount value displaying default tenant currency instead of a specified one.