Broadleaf Microservices
  • v1.0.0-latest-prod

Release Notes for 1.9.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.9.0

  • Allow field level restrictions based on user permissions. To restrict a field or group, specify the required security scope using .scope('SCOPE') in metadata.

    • The field or group will be read-only if the user only has READ permissions for the scope.

    • The field or group will be editable otherwise for CREATE, UPDATE, or ALL.

  • Introduced support for multi-architecture builds of the components library

  • Upgraded base node version to 14

  • Added support for right-to-left text flow

    • This is to support languages like Arabic in the admin.

    • Primarily this was a matter of a few CSS changes and updated the dir attribute on the <body> to "rtl".

  • Language Selector and Timezone display have been moved to a settings dropdown menu next to the profile menu dropdown

  • Added component names as class names to most named and common components to make overriding styles easier

1.9.1

  • Added fees total to admin order summary view

  • Enabled filtering catalog and sandbox selector results via backend

    • The CatalogSelector in the CatalogRibbon is now just like the SandboxSelector to allow more user-friendly display and filtering of options

  • Added additional locale labels for dropdowns

  • Added Rule column type for list grids to handle RuleBuilder fields

  • Added RSQL column type

  • Made modal error more visible

  • Added translation provider for Content Item Field Data

  • Made list grids scrollable

  • Added payment distribution details to the OMS order screens

1.9.2

  • 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.9.3

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

1.9.4

  • Added support for targeting tracking context by metadata conditionals.

    • This can allow some fields or groups to be hidden in different contexts like tenant, application, or catalog.

    • Example:

      • Conditionals.when("$tracking.tenantId").equalTo("tenant_id")

      • Conditionals.when("$tracking.applicationId").equalTo("app_id")

      • Conditionals.when("$tracking.catalog.currentCatalogId").equalTo("catalog_id")

  • Made FulfillmentItemSummary, FulfillmentCardBody, FulfillmentCardHeader, and sub-components overridable in OMS screens.

    • This makes use of the enableOverrides mechanic where a component can be overridden by registering a new component with a key of the form blComponentName, e.g., blButton.

  • Enabled Trigger Form Component to update the form state after submission.

    • Set attribute useResponse to true in metadata.

  • Enabled Trigger Form Component to be a Primary action.

    • Previously it was only secondary (same placement as most delete actions for entity forms).

  • Added support for none type transformation when using a Derived Field.

    • Before the source field’s value would always undergo some type of text transformation: kebab, camel, or snake.

  • Added new external type, FIELD_GROUP, that allows fetching a single entity with an endpoint and displaying its fields nested inside another entity’s form.

    • Before there were only lookups which only show an entity’s name and grids for lists for external components.

    • This could be used for reading an associated, one-to-one entity, grouping its fields together.

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

Bug Fixes

1.9.0

  • Fixed order summary fields not displaying

1.9.1

  • Fixed issue where import request page breaks if selected import file is removed

  • Fixed resident list grid not detecting row deletion dirty state

  • Fixed issue where types were in the root dist/

    • Root dist/ isn’t part of the actual source we distribute, it needed to be in the sub modules that we publish

  • Fixed "add filter" button not displayed on empty query builder

  • Fixed issues with asset dropzone validation

    • Fixed error handling when a file dragged onto the asset dropzone is of the wrong mime type

    • Fixed asset browser not passing dropzone props to specify the accept value

  • Fixed WYSIWYG editor not allowing editing after applying styles

  • Fixed augmentation validation section

    • Previously, the "Footer" section of a FieldArrayGroup would only show if the group is not empty, which causes the add button to not show for new items

  • Fixed default values triggering dirty state on category form

  • Fixed asset grid pagination not working

  • Fixed issue where you can get "stuck" in translations mode when navigating away from an entity’s context

    • Now, translation-mode will automatically disable when leaving an entity’s context, e.g., going from Product Browse to Product Update will not exit translation mode, but going from a Product screen to a Price List screen will

1.9.2

  • 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.9.3

  • 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.9.4

  • Fixed validation of the augmentation field validations not triggering.

    • This is relevant when adding a new custom field in the Admin using the "Customize Form" action.

    • Before, invalid validation methods could be specified because validation did not trigger.

  • Fixed product read not being triggered when change summaries change.

    • After a product change is saved, the app will poll the change summaries endpoint to make sure the changes have propagated before refreshing the product’s state.

  • 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 columns not rendering for Category Search Grid

  • Fixed My Changes list grid not paginating

  • Fixed not being able to set read-only conditions for External fields such as ExternalGridCollection or ProductPriceDataGridCollection

  • Fixed dynamic fields not updating initial form state

  • Fixed display value of list grid filters not updating when modified

    • When the value of an existing filter was updated, the active filters continued to display the value from when the filter was first added