You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by ah...@apache.org on 2026/01/22 09:26:26 UTC

(causeway) branch 3957-tablerow.action.backport created (now 9bedbc8c377)

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a change to branch 3957-tablerow.action.backport
in repository https://gitbox.apache.org/repos/asf/causeway.git


      at 9bedbc8c377 CAUSEWAY-3957: [v2] adds table's action column (backport)

This branch includes the following new commits:

     new 9bedbc8c377 CAUSEWAY-3957: [v2] adds table's action column (backport)

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(causeway) 01/01: CAUSEWAY-3957: [v2] adds table's action column (backport)

Posted by ah...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch 3957-tablerow.action.backport
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit 9bedbc8c377af9d92b55a705d2e6f93b75d4ccd8
Author: andi-huber <ah...@apache.org>
AuthorDate: Thu Jan 22 10:26:16 2026 +0100

    CAUSEWAY-3957: [v2] adds table's action column (backport)
    
    not yet wired to show up
---
 .../applib/layout/grid/bootstrap/BSGrid.java       |   1 +
 .../core/metamodel/spec/feature/ObjectAction.java  |  23 +++
 .../spec/feature/ObjectActionContainer.java        |   5 +
 .../metamodel/spec/feature/ObjectAssociation.java  |  26 ++-
 .../specimpl/dflt/ObjectSpecificationDefault.java  |   7 +
 .../specimpl/dflt/_MembersAsColumns.java           | 205 +++++++++++++++++++++
 .../core/metamodel/util/WhereContexts.java         |  24 ++-
 .../viewer/wicket/model/models/ActionModel.java    |  26 +++
 ...tionalLinksPanel.java => ActionLinksPanel.java} |  62 +++++--
 .../AdditionalLinksAsDropDownPanel.java            |   4 +-
 .../AdditionalLinksAsListInlinePanel.java          |   4 +-
 .../entityactions/LinkAndLabelFactory.java         |   2 +-
 .../ui/components/collection/CollectionPanel.java  |   2 +-
 .../CollectionContentsAsAjaxTablePanel.java        |  10 +-
 .../ajaxtable/columns/ActionColumn.java            | 123 +++++++++++++
 .../columns/AssociationColumnAbstract.java         |   4 +-
 .../ajaxtable/columns/GenericColumnAbstract.java   |  38 ++--
 .../ajaxtable/columns/PluralColumn.java            |   4 +-
 .../ajaxtable/columns/SingularColumn.java          |   9 +-
 .../ajaxtable/columns/TitleColumn.java             |  12 +-
 .../ajaxtable/columns/ToggleboxColumn.java         |   4 +-
 .../entity/collection/EntityCollectionPanel.java   |   6 +-
 .../components/entity/fieldset/PropertyGroup.java  |  10 +-
 .../entity/header/EntityHeaderPanel.java           |   6 +-
 .../wicket/ui/components/layout/bs/col/Col.java    |   4 +-
 .../ui/components/scalars/ScalarPanelAbstract.java |  10 +-
 .../config/WicketViewerCssBundleInit.java          |   4 +-
 27 files changed, 558 insertions(+), 77 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGrid.java b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGrid.java
index e0f4ec9be22..852a2257225 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGrid.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/layout/grid/bootstrap/BSGrid.java
@@ -21,6 +21,7 @@
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.stream.Stream;
 
 import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAction.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAction.java
index a9d1ab61717..b4cda7f7fe8 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAction.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAction.java
@@ -39,8 +39,10 @@
 import org.apache.causeway.core.metamodel.consent.Consent;
 import org.apache.causeway.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.causeway.core.metamodel.consent.InteractionResultSet;
+import org.apache.causeway.core.metamodel.facets.WhereValueFacet;
 import org.apache.causeway.core.metamodel.facets.actions.action.choicesfrom.ChoicesFromFacet;
 import org.apache.causeway.core.metamodel.facets.actions.position.ActionPositionFacet;
+import org.apache.causeway.core.metamodel.facets.all.hide.HiddenFacet;
 import org.apache.causeway.core.metamodel.facets.members.iconfa.FaFacet;
 import org.apache.causeway.core.metamodel.facets.members.iconfa.FaLayersProvider;
 import org.apache.causeway.core.metamodel.facets.members.layout.group.LayoutGroupFacet;
@@ -496,6 +498,27 @@ public static Predicate<ObjectAction> choicesFromAndHavingCollectionParameterFor
                             new ObjectActionParameter.Predicates.CollectionParameter(elementType)
                             ));
         }
+        
+        /**
+         * Returns true if no {@link HiddenFacet} is found that vetoes visibility.
+         * <p>
+         * However, whereHidden={@link Where#ALL_TABLES} is used as default
+         * when no {@link HiddenFacet} is found.
+         *
+         * @see ObjectAssociation.Predicates#visibleAccordingToHiddenFacet(Where)
+         *
+         * @apiNote an alternative would be to prime the meta-model with fallback facets,
+         *      however the current approach is more heap friendly
+         */
+        public static Predicate<ObjectAction> visibleAccordingToHiddenFacet(final Where whereContext) {
+            return (final ObjectAction act) -> act.lookupFacet(HiddenFacet.class)
+                    .map(WhereValueFacet.class::cast)
+                    .map(WhereValueFacet::where)
+                    // whereHidden=ALL_TABLES is the default when not specified otherwise
+                    .or(()->Optional.of(Where.ALL_TABLES))
+                    .stream()
+                    .noneMatch(whereHidden -> whereHidden.includes(whereContext));
+        }
 
         // -- HELPER
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectActionContainer.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectActionContainer.java
index 9893050bbed..cb6ade78d65 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectActionContainer.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectActionContainer.java
@@ -140,6 +140,11 @@ default Stream<ObjectAction> streamAnyActions(final MixedIn mixedIn) {
      * @param mixedIn - whether to include mixed in actions
      */
     Stream<ObjectAction> streamRuntimeActions(MixedIn mixedIn);
+    
+    /**
+     * Actions visible in dedicated actions-column, honoring order and visibility.
+     */
+    Stream<ObjectAction> streamActionsForColumnRendering(Identifier memberIdentifier);
 
     // -- ACTION STREAM (NO INHERITANCE)
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAssociation.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAssociation.java
index b46a4083dc1..f6cb1f0d80f 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAssociation.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAssociation.java
@@ -41,6 +41,7 @@
 import org.apache.causeway.core.metamodel.object.ManagedObject;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.util.Facets;
+import org.apache.causeway.core.metamodel.util.WhereContexts;
 
 import static org.apache.causeway.applib.annotation.Where.PARENTED_TABLES;
 import static org.apache.causeway.applib.annotation.Where.STANDALONE_TABLES;
@@ -160,12 +161,6 @@ public static Predicate<ObjectAssociation> staticallyVisible(final Where where)
             };
         }
 
-        static Where whereContextFor(final Identifier memberIdentifier) {
-            return memberIdentifier.type().isAction()
-                    ? STANDALONE_TABLES
-                    : PARENTED_TABLES;
-        }
-
         /**
          * Returns true if no {@link HiddenFacet} is found that vetoes visibility.
          *
@@ -176,9 +171,24 @@ static Where whereContextFor(final Identifier memberIdentifier) {
          * @apiNote an alternative would be to prime the meta-model with fallback facets,
          *      however the current approach is more heap friendly
          */
+        @Deprecated
         public static Predicate<ObjectAssociation> visibleAccordingToHiddenFacet(
                 final Identifier memberIdentifier) {
-            val whereContext = whereContextFor(memberIdentifier);
+            return visibleAccordingToHiddenFacet(WhereContexts.collectionVariant(memberIdentifier));
+        }
+
+        /**
+         * Returns true if no {@link HiddenFacet} is found that vetoes visibility.
+         * <p>
+         * However, if it's a 1-to-Many, whereHidden={@link Where#ALL_TABLES} is used as default
+         * when no {@link HiddenFacet} is found.
+         *
+         * @see ObjectAction.Predicates#visibleAccordingToHiddenFacet(Where)
+         *
+         * @apiNote an alternative would be to prime the meta-model with fallback facets,
+         *      however the current approach is more heap friendly
+         */
+        public static Predicate<ObjectAssociation> visibleAccordingToHiddenFacet(final Where whereContext) {
             return (final ObjectAssociation assoc) -> assoc.lookupFacet(HiddenFacet.class)
                     .map(WhereValueFacet.class::cast)
                     .map(WhereValueFacet::where)
@@ -187,7 +197,7 @@ public static Predicate<ObjectAssociation> visibleAccordingToHiddenFacet(
                     .stream()
                     .noneMatch(whereHidden -> whereHidden.includes(whereContext));
         }
-
+        
         public static Predicate<ObjectAssociation> referencesParent(
                 final @Nullable ObjectSpecification parentSpec) {
             if(parentSpec == null) {
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
index b2a396b0a53..d25af74ec73 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
@@ -321,6 +321,13 @@ public final Stream<ObjectAssociation> streamAssociationsForColumnRendering(
         return new _AssociationsAsColumns(getMetaModelContext())
             .streamAssociationsForColumnRendering(this, memberIdentifier, parentObject);
     }
+    
+    @Override
+    public Stream<ObjectAction> streamActionsForColumnRendering(
+            final Identifier memberIdentifier) {
+        return new _MembersAsColumns(getMetaModelContext())
+                .streamActionsForColumnRendering(this, memberIdentifier);
+    }
 
     // -- DETERMINE INJECTABILITY
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/_MembersAsColumns.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/_MembersAsColumns.java
new file mode 100644
index 00000000000..53dae802e0f
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/_MembersAsColumns.java
@@ -0,0 +1,205 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.core.metamodel.specloader.specimpl.dflt;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.apache.causeway.applib.Identifier;
+import org.apache.causeway.applib.annotation.Where;
+import org.apache.causeway.applib.layout.component.PropertyLayoutData;
+import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
+import org.apache.causeway.applib.services.tablecol.TableColumnOrderService;
+import org.apache.causeway.applib.services.tablecol.TableColumnVisibilityService;
+import org.apache.causeway.commons.internal.base._NullSafe;
+import org.apache.causeway.commons.internal.collections._Lists;
+import org.apache.causeway.commons.internal.collections._Maps;
+import org.apache.causeway.core.metamodel.context.HasMetaModelContext;
+import org.apache.causeway.core.metamodel.context.MetaModelContext;
+import org.apache.causeway.core.metamodel.facets.object.grid.GridFacet;
+import org.apache.causeway.core.metamodel.object.ManagedObject;
+import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
+import org.apache.causeway.core.metamodel.spec.feature.MixedIn;
+import org.apache.causeway.core.metamodel.spec.feature.ObjectAction;
+import org.apache.causeway.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.causeway.core.metamodel.util.WhereContexts;
+import org.springframework.lang.NonNull;
+
+import static org.apache.causeway.applib.annotation.Where.PARENTED_TABLES;
+import static org.apache.causeway.applib.annotation.Where.STANDALONE_TABLES;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+class _MembersAsColumns implements HasMetaModelContext {
+
+    @Getter(onMethod_ = {@Override})
+    private final MetaModelContext metaModelContext;
+
+    public final Stream<ObjectAction> streamActionsForColumnRendering(
+            final ObjectSpecification elementType,
+            final Identifier memberIdentifier) {
+        if(elementType.isValue()) return Stream.empty();
+
+        return elementType.streamRuntimeActions(MixedIn.INCLUDED)
+            .filter(ObjectAction.Predicates.visibleAccordingToHiddenFacet(WhereContexts.collectionVariant(memberIdentifier)))
+            .sorted((a, b)->a.getCanonicalFriendlyName().compareTo(b.getCanonicalFriendlyName()));
+    }
+
+    /**
+     * @param parentObject not used for standalone tables and allowed to be empty for parented ones
+     */
+    public final Stream<ObjectAssociation> streamAssociationsForColumnRendering(
+            final ObjectSpecification elementType,
+            final Identifier memberIdentifier,
+            final ManagedObject parentObject) {
+
+        // the type that has the properties and collections that make up this table's columns
+        var elementClass = elementType.getCorrespondingClass();
+
+        var parentSpecIfAny = parentObject.objSpec();
+
+        var assocById = _Maps.<String, ObjectAssociation>newLinkedHashMap();
+
+        elementType.streamAssociations(MixedIn.INCLUDED)
+            .filter(ObjectAssociation.Predicates.visibleAccordingToHiddenFacet(WhereContexts.collectionVariant(memberIdentifier)))
+            .filter(ObjectAssociation.Predicates.referencesParent(parentSpecIfAny).negate())
+            .filter(assoc->filterColumnsUsingSpi(assoc, elementClass)) // optional SPI to filter columns;
+            .forEach(assoc->assocById.put(assoc.getId(), assoc));
+
+        var assocIdsInOrder = _Lists.<String>newArrayList(assocById.keySet());
+
+        // sort by order of occurrence within associated layout, if any
+        propertyIdComparator(elementType)
+            .ifPresent(assocIdsInOrder::sort);
+
+        // optional SPI to reorder columns
+        sortColumnsUsingSpi(memberIdentifier, parentObject, assocIdsInOrder, elementClass);
+
+        // add all ordered columns to the table
+        return assocIdsInOrder.stream()
+            .map(assocById::get)
+            .filter(_NullSafe::isPresent);
+    }
+
+    // -- HELPER
+
+    private boolean filterColumnsUsingSpi(
+            final ObjectAssociation assoc,
+            final Class<?> elementType) {
+        return getServiceRegistry()
+            .select(TableColumnVisibilityService.class)
+            .stream()
+            .noneMatch(x -> x.hides(elementType, assoc.getId()));
+    }
+
+    // comparator based on grid facet, that is by order of occurrence within associated layout
+    private Optional<Comparator<String>> propertyIdComparator(
+            final @NonNull ObjectSpecification elementTypeSpec) {
+
+        // same code also appears in DomainObjectPage.
+        // we need to do this here otherwise any tables will render the columns in the wrong order until at least
+        // one object of that type has been rendered via DomainObjectPage.
+        var elementTypeGridFacet = elementTypeSpec.getFacet(GridFacet.class);
+
+        if(elementTypeGridFacet == null) return Optional.empty();
+
+        // the facet should always exist, in fact
+        // just enough to ask for the metadata.
+
+        // don't pass in any object, just need the meta-data
+        var elementTypeGrid = elementTypeGridFacet.getGrid(null);
+        if(elementTypeGrid ==null) return Optional.empty();
+
+        final Map<String, Integer> propertyIdOrderWithinGrid = new HashMap<>();
+        streamPropertyLayoutData((BSGrid)elementTypeGrid)
+            .map(PropertyLayoutData::getId)
+            .forEach(propertyId->{
+                propertyIdOrderWithinGrid.put(propertyId, propertyIdOrderWithinGrid.size());
+        });
+
+        // if propertyId is mentioned within grid, put into first 'half' ordered by
+        // occurrence within grid
+        // if propertyId is not mentioned within grid, put into second 'half' ordered by
+        // propertyId (String) in natural order
+        return Optional.of(Comparator
+                .<String>comparingInt(propertyId->
+                propertyIdOrderWithinGrid.getOrDefault(propertyId, Integer.MAX_VALUE))
+                .thenComparing(Comparator.naturalOrder()));
+    }
+    
+    private Stream<PropertyLayoutData> streamPropertyLayoutData(BSGrid bsGrid) {
+    	final var properties = new ArrayList<PropertyLayoutData>();
+    	bsGrid.visit(new BSGrid.VisitorAdapter() {
+    		@Override
+    		public void visit(final PropertyLayoutData propertyLayoutData) {
+    			properties.add(propertyLayoutData);
+    		}
+    	});
+    	return properties.stream();
+    }
+
+    private void sortColumnsUsingSpi(
+            final Identifier memberIdentifier,
+            // not used for standalone tables, and allowed to be empty in parented ones
+            final ManagedObject parentObject,
+            final List<String> propertyIdsInOrder,
+            final Class<?> elementType) {
+
+        var tableColumnOrderServices = getServiceRegistry().select(TableColumnOrderService.class);
+        if(tableColumnOrderServices.isEmpty()) {
+            return;
+        }
+
+        var whereContext = whereContextFor(memberIdentifier);
+
+        tableColumnOrderServices.stream()
+        .map(tableColumnOrderService->
+            whereContext.inStandaloneTable()
+            ? tableColumnOrderService.orderStandalone(
+                    elementType,
+                    propertyIdsInOrder)
+            : tableColumnOrderService.orderParented(
+                    parentObject.getPojo(),
+                    memberIdentifier.memberLogicalName(),
+                    elementType,
+                    propertyIdsInOrder))
+        .filter(_NullSafe::isPresent)
+        .findFirst()
+        .filter(propertyReorderedIds->propertyReorderedIds!=propertyIdsInOrder) // skip if its the same object
+        .ifPresent(propertyReorderedIds->{
+            propertyIdsInOrder.clear();
+            propertyIdsInOrder.addAll(propertyReorderedIds);
+        });
+
+    }
+
+    static Where whereContextFor(final Identifier memberIdentifier) {
+        return memberIdentifier.type().isAction()
+                ? STANDALONE_TABLES
+                : PARENTED_TABLES;
+    }
+
+}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsDropDownPanel.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/WhereContexts.java
similarity index 53%
copy from viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsDropDownPanel.java
copy to core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/WhereContexts.java
index f737a93e743..42b7fb7b96b 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsDropDownPanel.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/WhereContexts.java
@@ -16,16 +16,26 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions;
+package org.apache.causeway.core.metamodel.util;
 
-import org.apache.causeway.commons.collections.Can;
-import org.apache.causeway.viewer.wicket.model.links.LinkAndLabel;
+import org.apache.causeway.applib.Identifier;
+import org.apache.causeway.applib.annotation.Where;
 
-public class AdditionalLinksAsDropDownPanel extends AdditionalLinksPanel {
+import lombok.experimental.UtilityClass;
 
-    private static final long serialVersionUID = 1L;
+@UtilityClass
+public class WhereContexts {
 
-    public AdditionalLinksAsDropDownPanel(final String id, final Can<LinkAndLabel> links) {
-        super(id, links, Style.DROPDOWN);
+    /**
+     * Utility, that detects the collection variant (standalone or parented),
+     * based on the feature {@link Identifier} of the originating feature,
+     * that is, the feature is either a plural member or a plural action result.
+     */
+    public Where collectionVariant(final Identifier featureId) {
+        var whereContext = featureId.type().isAction()
+                    ? Where.STANDALONE_TABLES
+                    : Where.PARENTED_TABLES;
+        return whereContext;
     }
+
 }
diff --git a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ActionModel.java b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ActionModel.java
index bde90e3193d..57f98fd91d1 100644
--- a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ActionModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ActionModel.java
@@ -31,6 +31,32 @@
 public interface ActionModel
 extends UiActionForm, FormExecutorContext, BookmarkableModel, IModel<ManagedObject> {
 
+    /**
+     * If underlying action, originates from an action-column, it has special page redirect semantics:
+     * <ul>
+     * <li>if action return is void or matches the originating table/collection's element-type, then just RELOAD page</li>
+     * <li>otherwise open action result page in NEW browser tab</li>
+     * </ul>
+     * @since CAUSEWAY-3815
+     */
+    public enum ColumnActionModifier {
+        /**
+         * don't interfere with the default action result route
+         */
+        NONE,
+        /**
+         * reload current page, irrespective of the action result
+         */
+        FORCE_STAY_ON_PAGE,
+        /**
+         * open the action result in a new (blank) browser tab or window
+         */
+        FORCE_NEW_BROWSER_WINDOW;
+        public boolean isNone() { return this == NONE; }
+        public boolean isForceStayOnPage() { return this == FORCE_STAY_ON_PAGE; }
+        public boolean isForceNewBrowserWindow() { return this == FORCE_NEW_BROWSER_WINDOW; }
+    }
+	
     /** Resets arguments to their fixed point default values
      * @see ActionInteractionHead#defaults(org.apache.causeway.core.metamodel.interactions.managed.ManagedAction)
      */
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksPanel.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/ActionLinksPanel.java
similarity index 62%
rename from viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksPanel.java
rename to viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/ActionLinksPanel.java
index dd8d41e4e49..742bcbbde4f 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/ActionLinksPanel.java
@@ -19,13 +19,20 @@
 package org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions;
 
 import java.util.List;
+import java.util.Optional;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import org.apache.wicket.MarkupContainer;
-
+import org.apache.causeway.applib.annotation.Where;
 import org.apache.causeway.commons.collections.Can;
+import org.apache.causeway.core.metamodel.spec.feature.ObjectAction;
 import org.apache.causeway.viewer.wicket.model.links.LinkAndLabel;
+import org.apache.causeway.viewer.wicket.model.models.ActionModel;
+import org.apache.causeway.viewer.wicket.model.models.ActionModelImpl;
+import org.apache.causeway.viewer.wicket.model.models.UiObjectWkt;
+import org.apache.causeway.viewer.wicket.model.models.ActionModel.ColumnActionModifier;
+import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.LinkAndLabelFactory.MenuLinkFactory;
 import org.apache.causeway.viewer.wicket.ui.components.menuable.MenuablePanelAbstract;
 import org.apache.causeway.viewer.wicket.ui.util.Wkt;
 import org.apache.causeway.viewer.wicket.ui.util.WktComponents;
@@ -33,7 +40,7 @@
 
 import lombok.val;
 
-public class AdditionalLinksPanel
+public abstract class ActionLinksPanel
 extends MenuablePanelAbstract {
 
     private static final long serialVersionUID = 1L;
@@ -43,27 +50,27 @@ public class AdditionalLinksPanel
     private static final String ID_ADDITIONAL_LINK_TITLE = "additionalLinkTitle";
     public  static final String ID_ADDITIONAL_LINK = "additionalLink";
 
-    public enum Style {
+    public enum ActionPanelStyle {
         INLINE_LIST {
             @Override
-            AdditionalLinksPanel newPanel(final String id, final Can<LinkAndLabel> links) {
+            ActionLinksPanel newPanel(final String id, final Can<LinkAndLabel> links) {
                 return new AdditionalLinksAsListInlinePanel(id, links);
             }
         },
         DROPDOWN {
             @Override
-            AdditionalLinksPanel newPanel(final String id, final Can<LinkAndLabel> links) {
+            ActionLinksPanel newPanel(final String id, final Can<LinkAndLabel> links) {
                 return new AdditionalLinksAsDropDownPanel(id, links);
             }
         };
-        abstract AdditionalLinksPanel newPanel(String id, Can<LinkAndLabel> links);
+        abstract ActionLinksPanel newPanel(String id, Can<LinkAndLabel> links);
     }
 
-    public static AdditionalLinksPanel addAdditionalLinks(
+    public static ActionLinksPanel addAdditionalLinks(
             final MarkupContainer markupContainer,
             final String id,
             final Can<LinkAndLabel> links,
-            final Style style) {
+            final ActionPanelStyle style) {
         if(links.isEmpty()) {
             WktComponents.permanentlyHide(markupContainer, id);
             return null;
@@ -71,10 +78,21 @@ public static AdditionalLinksPanel addAdditionalLinks(
         return Wkt.add(markupContainer, style.newPanel(id, links));
     }
 
-    protected AdditionalLinksPanel(
+    public static Optional<ActionLinksPanel> actionLinks(
+            final String id,
+            final Can<ActionModel> actionModels,
+            final ActionPanelStyle style,
+            final Where renderWhere) {
+
+        return actionModels.isEmpty()
+            ? Optional.empty()
+            : Optional.of(style.newPanel(id, actionModels.map(act->linkAndLabel(act, renderWhere))));
+    }
+    
+    protected ActionLinksPanel(
             final String id,
             final Can<LinkAndLabel> menuables,
-            final Style style) {
+            final ActionPanelStyle style) {
         super(id, menuables);
         setOutputMarkupId(true);
 
@@ -83,7 +101,7 @@ protected AdditionalLinksPanel(
 
         Wkt.listViewAdd(container, ID_ADDITIONAL_LINK_ITEM, listOfLinkAndLabels(), item->{
             val linkAndLabel = item.getModelObject();
-            item.addOrReplace(WktLinks.asAdditionalLink(item, ID_ADDITIONAL_LINK_TITLE, linkAndLabel, style==Style.DROPDOWN));
+            item.addOrReplace(WktLinks.asAdditionalLink(item, ID_ADDITIONAL_LINK_TITLE, linkAndLabel, style==ActionPanelStyle.DROPDOWN));
             if (!linkAndLabel.isVisible()) {
                 Wkt.cssAppend(item, "hidden");
             }
@@ -108,5 +126,27 @@ protected final List<LinkAndLabel> listOfLinkAndLabels() {
     public final boolean hasAnyVisibleLink() {
         return streamLinkAndLabels().anyMatch(linkAndLabel->linkAndLabel.getUiComponent().isVisible());
     }
+    
+    // -- HELPER
+    
+    private static LinkAndLabel linkAndLabel(
+    		ActionModel actionModel, Where renderWhere) {
+		//new LinkAndLabel(actionModel, new MenuLinkFactory());
+    	return null;
+    }
+    
+    private static LinkAndLabelFactory forEntityFromActionColumn(
+            final UiObjectWkt parentEntityModel,
+            final ColumnActionModifier columnActionModifier) {
+        return (ObjectAction action) -> LinkAndLabel.of( 
+        		ActionModelImpl.forEntity(
+                        parentEntityModel,
+                        action.getFeatureIdentifier(),
+                        Where.ALL_TABLES,
+//TODO BACKPORT                        columnActionModifier,
+                        null, null, null),
+        		new MenuLinkFactory());
+    }
+
 
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsDropDownPanel.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsDropDownPanel.java
index f737a93e743..668ba5c8028 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsDropDownPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsDropDownPanel.java
@@ -21,11 +21,11 @@
 import org.apache.causeway.commons.collections.Can;
 import org.apache.causeway.viewer.wicket.model.links.LinkAndLabel;
 
-public class AdditionalLinksAsDropDownPanel extends AdditionalLinksPanel {
+public class AdditionalLinksAsDropDownPanel extends ActionLinksPanel {
 
     private static final long serialVersionUID = 1L;
 
     public AdditionalLinksAsDropDownPanel(final String id, final Can<LinkAndLabel> links) {
-        super(id, links, Style.DROPDOWN);
+        super(id, links, ActionPanelStyle.DROPDOWN);
     }
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsListInlinePanel.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsListInlinePanel.java
index 359477b5db0..fce54177a81 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsListInlinePanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsListInlinePanel.java
@@ -21,11 +21,11 @@
 import org.apache.causeway.commons.collections.Can;
 import org.apache.causeway.viewer.wicket.model.links.LinkAndLabel;
 
-public class AdditionalLinksAsListInlinePanel extends AdditionalLinksPanel {
+public class AdditionalLinksAsListInlinePanel extends ActionLinksPanel {
 
     private static final long serialVersionUID = 1L;
 
     public AdditionalLinksAsListInlinePanel(final String id, final Can<LinkAndLabel> links) {
-        super(id, links, Style.INLINE_LIST);
+        super(id, links, ActionPanelStyle.INLINE_LIST);
     }
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/LinkAndLabelFactory.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/LinkAndLabelFactory.java
index fa9111179db..f771ab6dd4c 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/LinkAndLabelFactory.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/actionmenu/entityactions/LinkAndLabelFactory.java
@@ -136,7 +136,7 @@ static class AdditionalLinkFactory implements ActionLinkUiComponentFactoryWkt {
         private static final long serialVersionUID = 1L;
         @Override
         public ActionLink newActionLinkUiComponent(@NonNull final ActionModel actionModel) {
-            return ActionLink.create(AdditionalLinksPanel.ID_ADDITIONAL_LINK, actionModel);
+            return ActionLink.create(ActionLinksPanel.ID_ADDITIONAL_LINK, actionModel);
         }
     }
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/CollectionPanel.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/CollectionPanel.java
index 2cbeaa9086e..f75ac57fdeb 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/CollectionPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/CollectionPanel.java
@@ -96,7 +96,7 @@ public ToggleboxColumn getToggleboxColumn() {
             val collModel = getModel();
             val collMetaModel = collModel.getMetaModel();
             toggleboxColumn =  collMetaModel.hasAssociatedActionsWithChoicesFromThisCollection()
-                    ? Optional.of(new ToggleboxColumn(collModel.delegate()))
+                    ? Optional.of(new ToggleboxColumn(collModel.getElementType(), collModel.delegate()))
                     : Optional.empty();
         }
         return toggleboxColumn.orElse(null);
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
index 87a4c2c34de..255451032a5 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
@@ -19,6 +19,7 @@
 package org.apache.causeway.viewer.wicket.ui.components.collectioncontents.ajaxtable;
 
 import java.util.List;
+import java.util.Objects;
 
 import org.apache.wicket.Component;
 import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
@@ -27,6 +28,7 @@
 import org.apache.causeway.commons.internal.collections._Lists;
 import org.apache.causeway.core.config.CausewayConfiguration.Viewer.Wicket;
 import org.apache.causeway.core.metamodel.object.ManagedObject;
+import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.spec.feature.ObjectAssociation;
 import org.apache.causeway.core.metamodel.spec.feature.OneToManyAssociation;
 import org.apache.causeway.core.metamodel.spec.feature.OneToOneAssociation;
@@ -94,12 +96,15 @@ private void buildGui() {
             : null;
 
         val collectionModel = entityCollectionModel();
+        var elementType = Objects.requireNonNull(collectionModel.getElementType(),
+                ()->"invalid: CollectionModel without element type");
 
         // first create property columns, so we know how many columns there are
         addPropertyColumnsIfRequired(columns);
         // prepend title column, which may have distinct rendering hints,
         // based on whether there are any property columns or not
         prependTitleColumn(
+        		elementType,
                 columns,
                 collectionModel.getVariant(),
                 getWicketViewerSettings());
@@ -127,6 +132,7 @@ private MultiselectToggleProvider getMultiselectToggleProvider() {
     }
 
     private void prependTitleColumn(
+    		final ObjectSpecification elementType,
             final List<GenericColumn> columns,
             final Variant variant,
             final Wicket wktConfig) {
@@ -144,7 +150,7 @@ private void prependTitleColumn(
                             : -1 /* don't override */)
             .build();
 
-        columns.add(0, new TitleColumn(variant, contextBookmark, maxColumnTitleLength, opts));
+        columns.add(0, new TitleColumn(elementType, variant, contextBookmark, maxColumnTitleLength, opts));
     }
 
     private void addPropertyColumnsIfRequired(final List<GenericColumn> columns) {
@@ -172,6 +178,7 @@ private SingularColumn createSingularColumn(final OneToOneAssociation property)
         final String parentTypeName = property.getDeclaringType().logicalTypeName();
 
         return new SingularColumn(
+        		collectionModel.getElementType(),
                 collectionModel.getVariant(),
                 Model.of(property.getCanonicalFriendlyName()),
                 property.getId(),
@@ -185,6 +192,7 @@ private PluralColumn createPluralColumn(final OneToManyAssociation collection) {
         final String parentTypeName = collection.getDeclaringType().logicalTypeName();
 
         return new PluralColumn(
+        		collectionModel.getElementType(),
                 collectionModel.getVariant(),
                 Model.of(collection.getCanonicalFriendlyName()),
                 collection.getId(),
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ActionColumn.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ActionColumn.java
new file mode 100644
index 00000000000..c254c424b08
--- /dev/null
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ActionColumn.java
@@ -0,0 +1,123 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns;
+
+import java.util.Optional;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.model.IModel;
+import org.springframework.lang.NonNull;
+import org.apache.causeway.applib.Identifier;
+import org.apache.causeway.applib.annotation.Where;
+import org.apache.causeway.commons.collections.Can;
+import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
+import org.apache.causeway.core.metamodel.spec.feature.ObjectAction;
+import org.apache.causeway.core.metamodel.tabular.interactive.DataRow;
+import org.apache.causeway.viewer.wicket.model.models.ActionModel;
+import org.apache.causeway.viewer.wicket.model.models.ActionModel.ColumnActionModifier;
+import org.apache.causeway.viewer.wicket.model.models.UiObjectWkt;
+import org.apache.causeway.viewer.wicket.model.models.interaction.coll.DataRowWkt;
+import org.apache.causeway.viewer.wicket.model.models.EntityCollectionModel.Variant;
+import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.ActionLinksPanel;
+import org.apache.causeway.viewer.wicket.ui.util.Wkt;
+
+public final class ActionColumn
+extends GenericColumnAbstract {
+
+    private static final long serialVersionUID = 1L;
+
+    public static Optional<ActionColumn> create(
+            final @NonNull Identifier featureId,
+            final @NonNull ObjectSpecification elementType,
+            final @NonNull Variant collectionVariant) {
+    	//BACKPORT skipped
+    	//var wktConfig = elementType.getMetaModelContext().getConfiguration().getViewer().getWicket();
+        //if(!wktConfig.isActionColumnEnabled()) return Optional.empty();
+    	//----
+
+        var actions = elementType.streamActionsForColumnRendering(featureId)
+                .collect(Can.toCan());
+        if(actions.isEmpty()) return Optional.empty();
+
+        return Optional.of(new ActionColumn(elementType, actions, collectionVariant));
+    }
+
+    private final Can<String> actionIds;
+    private transient Can<ObjectAction> actions;
+    private final Variant collectionVariant;
+
+    private ActionColumn(
+            final ObjectSpecification elementType,
+            final Can<ObjectAction> actionsForColumnRendering,
+            final Variant collectionVariant) {
+        super(elementType, "Actions");
+        this.actions = actionsForColumnRendering;
+        this.actionIds = actions.map(ObjectAction::getId);
+        this.collectionVariant = collectionVariant;
+    }
+
+    @Override
+    protected Component createCellComponent(
+            final String componentId, final DataRow dataRow, IModel<Boolean> dataRowToggle) {
+    	
+        //var dataRow = dataRowWkt.getObject();
+        var rowElement = dataRow.getRowElement();
+
+        var objectModel = UiObjectWkt.ofAdapter(rowElement);
+        var elementType = elementType();
+
+//TODO BACKPORT ...        
+//        var actionModels = actions().stream()
+//            .map(act->ActionModel.forEntityFromActionColumn(act, objectModel,
+//                    determineColumnActionModifier(act, elementType)))
+//            .collect(Can.toCan());
+//
+//        return ActionLinksPanel.actionLinks(componentId, actionModels, ActionLinksPanel.ActionPanelStyle.DROPDOWN, Where.ALL_TABLES)
+//                .map(Component.class::cast)
+//                .orElseGet(()->Wkt.label(componentId, ""));
+        return new Label(componentId, "TODO");
+    }
+
+    // -- HELPER
+
+    private ColumnActionModifier determineColumnActionModifier(
+            final ObjectAction action,
+            final ObjectSpecification collectionElementType) {
+
+        // refreshing of standalone collections currently not supported
+        if(collectionVariant.isStandalone()) return ColumnActionModifier.FORCE_NEW_BROWSER_WINDOW;
+
+        return action.getElementType().isVoid()
+                || action.getElementType().isOfType(collectionElementType)
+                ? ColumnActionModifier.FORCE_STAY_ON_PAGE
+                : ColumnActionModifier.FORCE_NEW_BROWSER_WINDOW;
+    }
+
+    private Can<ObjectAction> actions() {
+        synchronized(this) {
+            if(actions==null) {
+                var elementType = elementType();
+                this.actions = actionIds.map(elementType::getActionElseFail);
+            }
+        }
+        return actions;
+    }
+
+}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/AssociationColumnAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/AssociationColumnAbstract.java
index 9d8da5a4fc4..2c4e03e65ce 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/AssociationColumnAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/AssociationColumnAbstract.java
@@ -26,6 +26,7 @@
 
 import org.apache.causeway.commons.internal.base._Strings;
 import org.apache.causeway.core.metamodel.object.ManagedObject;
+import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.viewer.wicket.model.models.EntityCollectionModel;
 import org.apache.causeway.viewer.wicket.ui.ComponentFactory;
 import org.apache.causeway.viewer.wicket.ui.app.registry.ComponentFactoryRegistry;
@@ -53,6 +54,7 @@ public abstract class AssociationColumnAbstract
     protected final String describedAs;
 
     public AssociationColumnAbstract(
+    		final ObjectSpecification elementType,
             final EntityCollectionModel.Variant collectionVariant,
             final IModel<String> columnNameModel,
             final String sortProperty,
@@ -60,7 +62,7 @@ public AssociationColumnAbstract(
             final String parentTypeName,
             final Optional<String> describedAs) {
 
-        super(columnNameModel, sortProperty);
+        super(elementType, columnNameModel, sortProperty);
         this.collectionVariant = collectionVariant;
         this.memberId = memberId;
         this.parentTypeName = parentTypeName;
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/GenericColumnAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/GenericColumnAbstract.java
index 5492b1e791d..4d4c9a4040d 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/GenericColumnAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/GenericColumnAbstract.java
@@ -18,18 +18,10 @@
  */
 package org.apache.causeway.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns;
 
-import org.apache.wicket.Application;
-import org.apache.wicket.Component;
-import org.apache.wicket.MarkupContainer;
-import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
-import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
-import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
-import org.apache.wicket.markup.repeater.Item;
-import org.apache.wicket.model.IModel;
-import org.apache.wicket.model.Model;
-
 import org.apache.causeway.applib.services.i18n.TranslationContext;
 import org.apache.causeway.core.metamodel.context.HasMetaModelContext;
+import org.apache.causeway.core.metamodel.context.MetaModelContext;
+import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.tabular.interactive.DataRow;
 import org.apache.causeway.viewer.commons.model.components.UiComponentType;
 import org.apache.causeway.viewer.wicket.model.models.interaction.coll.DataRowWkt;
@@ -38,6 +30,15 @@
 import org.apache.causeway.viewer.wicket.ui.app.registry.HasComponentFactoryRegistry;
 import org.apache.causeway.viewer.wicket.ui.components.collectioncontents.ajaxtable.CollectionContentsAsAjaxTablePanel;
 import org.apache.causeway.viewer.wicket.ui.util.Wkt;
+import org.apache.wicket.Application;
+import org.apache.wicket.Component;
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
 
 import lombok.val;
 
@@ -54,16 +55,22 @@ public abstract class GenericColumnAbstract
     private static final long serialVersionUID = 1L;
 
     private transient ComponentFactoryRegistry componentRegistry;
+    private final Class<?> elementClass;
+    private transient ObjectSpecification elementType;
 
     protected GenericColumnAbstract(
+            final ObjectSpecification elementType,
             final String columnName) {
-        this(Model.of(columnName), null);
+        this(elementType, Model.of(columnName), null);
     }
 
     protected GenericColumnAbstract(
+            final ObjectSpecification elementType,
             final IModel<String> columnNameModel,
             final String sortColumn) {
         super(columnNameModel, sortColumn);
+        this.elementType = elementType;
+        this.elementClass = elementType.getCorrespondingClass();
     }
 
     @Override
@@ -87,6 +94,15 @@ public final void populateItem(
 
     protected abstract Component createCellComponent(
             final String componentId, final DataRow dataRow, IModel<Boolean> dataRowToggle);
+    
+    public final ObjectSpecification elementType() {
+        synchronized(this) {
+            if(elementType==null) {
+                this.elementType = MetaModelContext.instanceElseFail().specForTypeElseFail(elementClass);
+            }
+        }
+        return elementType;
+    }
 
     protected ComponentFactory findComponentFactory(final UiComponentType uiComponentType, final IModel<?> model) {
         return getComponentRegistry().findComponentFactory(uiComponentType, model);
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/PluralColumn.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/PluralColumn.java
index 9cefb6e537c..36d58286613 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/PluralColumn.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/PluralColumn.java
@@ -31,6 +31,7 @@
 import org.apache.causeway.applib.services.placeholder.PlaceholderRenderService.PlaceholderLiteral;
 import org.apache.causeway.core.metamodel.object.ManagedObject;
 import org.apache.causeway.core.metamodel.object.ManagedObjects;
+import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.tabular.interactive.DataColumn;
 import org.apache.causeway.core.metamodel.tabular.interactive.DataRow;
 import org.apache.causeway.viewer.commons.model.components.UiComponentType;
@@ -62,6 +63,7 @@ public static class RenderOptions implements Serializable {
     private final RenderOptions opts;
 
     public PluralColumn(
+    		final ObjectSpecification elementType,
             final EntityCollectionModel.Variant collectionVariant,
             final IModel<String> columnNameModel,
             final String sortProperty,
@@ -69,7 +71,7 @@ public PluralColumn(
             final String parentTypeName,
             final Optional<String> describedAs,
             final RenderOptions opts) {
-        super(collectionVariant, columnNameModel, sortProperty, propertyId, parentTypeName, describedAs);
+        super(elementType, collectionVariant, columnNameModel, sortProperty, propertyId, parentTypeName, describedAs);
         this.opts = opts;
     }
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/SingularColumn.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/SingularColumn.java
index df5acf7e3f5..5eaa934c5db 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/SingularColumn.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/SingularColumn.java
@@ -20,14 +20,14 @@
 
 import java.util.Optional;
 
-import org.apache.wicket.Component;
-import org.apache.wicket.model.IModel;
-
 import org.apache.causeway.core.metamodel.commons.ViewOrEditMode;
+import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.tabular.interactive.DataRow;
 import org.apache.causeway.viewer.commons.model.components.UiComponentType;
 import org.apache.causeway.viewer.wicket.model.models.EntityCollectionModel;
 import org.apache.causeway.viewer.wicket.model.models.UiObjectWkt;
+import org.apache.wicket.Component;
+import org.apache.wicket.model.IModel;
 
 import lombok.val;
 
@@ -37,13 +37,14 @@ public final class SingularColumn
     private static final long serialVersionUID = 1L;
 
     public SingularColumn(
+    		final ObjectSpecification elementType,
             final EntityCollectionModel.Variant collectionVariant,
             final IModel<String> columnNameModel,
             final String sortProperty,
             final String propertyId,
             final String parentTypeName,
             final Optional<String> describedAs) {
-        super(collectionVariant, columnNameModel, sortProperty, propertyId, parentTypeName, describedAs);
+        super(elementType, collectionVariant, columnNameModel, sortProperty, propertyId, parentTypeName, describedAs);
     }
 
     @Override
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/TitleColumn.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/TitleColumn.java
index 42491874bc4..66d29f8be73 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/TitleColumn.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/TitleColumn.java
@@ -18,18 +18,17 @@
  */
 package org.apache.causeway.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns;
 
-import org.apache.wicket.Component;
-import org.apache.wicket.model.IModel;
-
-import org.springframework.lang.Nullable;
-
 import org.apache.causeway.applib.services.bookmark.Bookmark;
 import org.apache.causeway.core.metamodel.object.ManagedObjects;
+import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.tabular.interactive.DataRow;
 import org.apache.causeway.viewer.commons.model.components.UiComponentType;
 import org.apache.causeway.viewer.wicket.model.models.EntityCollectionModel.Variant;
 import org.apache.causeway.viewer.wicket.model.models.UiObjectWkt;
 import org.apache.causeway.viewer.wicket.model.models.ValueModel;
+import org.apache.wicket.Component;
+import org.apache.wicket.model.IModel;
+import org.springframework.lang.Nullable;
 
 import lombok.val;
 
@@ -42,12 +41,13 @@ public final class TitleColumn
     private final Bookmark contextBookmark;
 
     public TitleColumn(
+    		final ObjectSpecification elementType,
             final Variant variant,
             final Bookmark contextBookmark,
             final int maxColumnTitleLength,
             final ColumnAbbreviationOptions opts) {
 
-        super(columnName(variant, maxColumnTitleLength)); // i18n
+        super(elementType, columnName(variant, maxColumnTitleLength)); // i18n
         this.variant = variant;
         this.contextBookmark = contextBookmark;
         this.opts = opts;
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ToggleboxColumn.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ToggleboxColumn.java
index cfcdeafaf29..3dacfa5351a 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ToggleboxColumn.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ToggleboxColumn.java
@@ -25,6 +25,7 @@
 import org.apache.wicket.model.IModel;
 
 import org.apache.causeway.commons.internal.collections._Lists;
+import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.tabular.interactive.DataRow;
 import org.apache.causeway.core.metamodel.tabular.interactive.DataTableInteractive;
 import org.apache.causeway.viewer.wicket.ui.components.widgets.checkbox.ContainedToggleboxPanel;
@@ -48,8 +49,9 @@ static BulkToggle valueOf(final boolean b) {
     private IModel<DataTableInteractive> dataTableModelHolder;
 
     public ToggleboxColumn(
+    		final ObjectSpecification elementType,
             final IModel<DataTableInteractive> dataTableModelHolder) {
-        super("");
+        super(elementType, "");
         this.dataTableModelHolder = dataTableModelHolder;
     }
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/entity/collection/EntityCollectionPanel.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/entity/collection/EntityCollectionPanel.java
index f7c89d6b069..d5660d57b62 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/entity/collection/EntityCollectionPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/entity/collection/EntityCollectionPanel.java
@@ -36,7 +36,7 @@
 import org.apache.causeway.viewer.wicket.model.models.EntityCollectionModelParented;
 import org.apache.causeway.viewer.wicket.model.models.UiObjectWkt;
 import org.apache.causeway.viewer.wicket.model.util.ComponentHintKey;
-import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.AdditionalLinksPanel;
+import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.ActionLinksPanel;
 import org.apache.causeway.viewer.wicket.ui.components.collection.CollectionPanel;
 import org.apache.causeway.viewer.wicket.ui.components.collection.selector.CollectionPresentationSelectorHelper;
 import org.apache.causeway.viewer.wicket.ui.components.collection.selector.CollectionPresentationSelectorPanel;
@@ -152,8 +152,8 @@ private void buildGui() {
                 .ifPresent(description->WktTooltips.addTooltip(labelComponent, description));
 
             final Can<LinkAndLabel> links = collectionModel.getLinks();
-            AdditionalLinksPanel.addAdditionalLinks(
-                    div, ID_ADDITIONAL_LINKS, links, AdditionalLinksPanel.Style.INLINE_LIST);
+            ActionLinksPanel.addAdditionalLinks(
+                    div, ID_ADDITIONAL_LINKS, links, ActionLinksPanel.ActionPanelStyle.INLINE_LIST);
 
             createSelectorDropdownPanel(collectionModel);
             collectionPanel.setSelectorDropdownPanel(selectorDropdownPanel);
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/entity/fieldset/PropertyGroup.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/entity/fieldset/PropertyGroup.java
index 70db27c6d7e..4c41c53bc0d 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/entity/fieldset/PropertyGroup.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/entity/fieldset/PropertyGroup.java
@@ -42,7 +42,7 @@
 import org.apache.causeway.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.causeway.viewer.wicket.model.models.ScalarModel;
 import org.apache.causeway.viewer.wicket.model.models.UiObjectWkt;
-import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.AdditionalLinksPanel;
+import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.ActionLinksPanel;
 import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.LinkAndLabelFactory;
 import org.apache.causeway.viewer.wicket.ui.components.scalars.ScalarPanelAbstract;
 import org.apache.causeway.viewer.wicket.ui.panels.HasDynamicallyVisibleContent;
@@ -111,17 +111,17 @@ private List<Component> buildGui() {
         } else {
             Wkt.labelAdd(panelHeading, ID_MEMBER_GROUP_NAME, fieldSet.getName());
 
-            AdditionalLinksPanel.addAdditionalLinks(
+            ActionLinksPanel.addAdditionalLinks(
                     panelHeading, ID_ASSOCIATED_ACTION_LINKS_PANEL,
                     memberGroupActions
                         .filter(LinkAndLabel.isPositionedAt(ActionLayout.Position.PANEL)),
-                    AdditionalLinksPanel.Style.INLINE_LIST);
+                    ActionLinksPanel.ActionPanelStyle.INLINE_LIST);
 
-            AdditionalLinksPanel.addAdditionalLinks(
+            ActionLinksPanel.addAdditionalLinks(
                     panelHeading, ID_ASSOCIATED_ACTION_LINKS_PANEL_DROPDOWN,
                     memberGroupActions
                         .filter(LinkAndLabel.isPositionedAt(ActionLayout.Position.PANEL_DROPDOWN)),
-                    AdditionalLinksPanel.Style.DROPDOWN);
+                    ActionLinksPanel.ActionPanelStyle.DROPDOWN);
         }
 
         // either add the built content, or hide entire
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/entity/header/EntityHeaderPanel.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/entity/header/EntityHeaderPanel.java
index 5b8a0d2cc43..36226a38037 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/entity/header/EntityHeaderPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/entity/header/EntityHeaderPanel.java
@@ -26,7 +26,7 @@
 import org.apache.causeway.viewer.commons.model.components.UiComponentType;
 import org.apache.causeway.viewer.wicket.model.models.UiObjectWkt;
 import org.apache.causeway.viewer.wicket.ui.ComponentFactory;
-import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.AdditionalLinksPanel;
+import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.ActionLinksPanel;
 import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.LinkAndLabelFactory;
 import org.apache.causeway.viewer.wicket.ui.panels.PanelAbstract;
 import org.apache.causeway.viewer.wicket.ui.util.WktComponents;
@@ -79,9 +79,9 @@ private void buildEntityActionsGui() {
             .map(LinkAndLabelFactory.forEntity(model))
             .collect(Can.toCan());
 
-            AdditionalLinksPanel
+            ActionLinksPanel
                     .addAdditionalLinks(this, ID_ENTITY_ACTIONS, topLevelActions,
-                            AdditionalLinksPanel.Style.INLINE_LIST);
+                            ActionLinksPanel.ActionPanelStyle.INLINE_LIST);
         } else {
             WktComponents.permanentlyHide(this, ID_ENTITY_ACTIONS);
         }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/col/Col.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/col/Col.java
index 2e2072bdd00..d5212cac77b 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/col/Col.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/col/Col.java
@@ -41,7 +41,7 @@
 import org.apache.causeway.viewer.commons.model.components.UiComponentType;
 import org.apache.causeway.viewer.wicket.model.models.UiObjectWkt;
 import org.apache.causeway.viewer.wicket.ui.ComponentFactory;
-import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.AdditionalLinksPanel;
+import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.ActionLinksPanel;
 import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.LinkAndLabelFactory;
 import org.apache.causeway.viewer.wicket.ui.components.entity.collection.EntityCollectionPanelFactory.CollectionOwnerAndLayout;
 import org.apache.causeway.viewer.wicket.ui.components.entity.fieldset.PropertyGroup;
@@ -135,7 +135,7 @@ private void buildGui() {
         .collect(Can.toCan());
 
         if (!visibleActions.isEmpty()) {
-            AdditionalLinksPanel.addAdditionalLinks(actionOwner, actionIdToUse, visibleActions, AdditionalLinksPanel.Style.INLINE_LIST);
+            ActionLinksPanel.addAdditionalLinks(actionOwner, actionIdToUse, visibleActions, ActionLinksPanel.ActionPanelStyle.INLINE_LIST);
             visible = true;
         } else {
             WktComponents.permanentlyHide(actionOwner, actionIdToUse);
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
index 8c1090f0582..0aedbef4780 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
@@ -56,7 +56,7 @@
 import org.apache.causeway.viewer.commons.model.scalar.UiParameter;
 import org.apache.causeway.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.causeway.viewer.wicket.model.models.ScalarModel;
-import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.AdditionalLinksPanel;
+import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.ActionLinksPanel;
 import org.apache.causeway.viewer.wicket.ui.components.scalars.ScalarFragmentFactory.FrameFragment;
 import org.apache.causeway.viewer.wicket.ui.components.scalars.ScalarFragmentFactory.RegularFrame;
 import org.apache.causeway.viewer.wicket.ui.components.scalars.blobclob.CausewayBlobOrClobPanelAbstract;
@@ -612,15 +612,15 @@ private void addActionLinksBelowAndRight(
 
         val linksBelow = linkAndLabels
                 .filter(LinkAndLabel.isPositionedAt(ActionLayout.Position.BELOW));
-        AdditionalLinksPanel.addAdditionalLinks(
+        ActionLinksPanel.addAdditionalLinks(
                 labelIfRegular, RegularFrame.ASSOCIATED_ACTION_LINKS_BELOW.getContainerId(),
-                linksBelow, AdditionalLinksPanel.Style.INLINE_LIST);
+                linksBelow, ActionLinksPanel.ActionPanelStyle.INLINE_LIST);
 
         val linksRight = linkAndLabels
                 .filter(LinkAndLabel.isPositionedAt(ActionLayout.Position.RIGHT));
-        AdditionalLinksPanel.addAdditionalLinks(
+        ActionLinksPanel.addAdditionalLinks(
                 labelIfRegular, RegularFrame.ASSOCIATED_ACTION_LINKS_RIGHT.getContainerId(),
-                linksRight, AdditionalLinksPanel.Style.DROPDOWN);
+                linksRight, ActionLinksPanel.ActionPanelStyle.DROPDOWN);
     }
 
     /**
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/wicketapp/config/WicketViewerCssBundleInit.java b/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/wicketapp/config/WicketViewerCssBundleInit.java
index 636f273b4b0..66c235e21fd 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/wicketapp/config/WicketViewerCssBundleInit.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/wicketapp/config/WicketViewerCssBundleInit.java
@@ -28,7 +28,7 @@
 import org.apache.causeway.commons.internal.collections._Sets;
 import org.apache.causeway.viewer.wicket.model.causeway.WicketApplicationInitializer;
 import org.apache.causeway.viewer.wicket.ui.ComponentFactory;
-import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.AdditionalLinksPanel;
+import org.apache.causeway.viewer.wicket.ui.components.actionmenu.entityactions.ActionLinksPanel;
 import org.apache.causeway.viewer.wicket.ui.components.scalars.string.MultiLineStringPanel;
 import org.apache.causeway.viewer.wicket.ui.panels.PanelUtil;
 import org.apache.causeway.viewer.wicket.viewer.wicketapp.CausewayWicketApplication;
@@ -90,7 +90,7 @@ private void addSpecialCasesToCssBundle(final Set<CssResourceReference> referenc
         // references.add(PanelUtil.cssResourceReferenceFor(LinksSelectorPanelAbstract.class));
 
         // components without factories
-        references.add(PanelUtil.cssResourceReferenceFor(AdditionalLinksPanel.class));
+        references.add(PanelUtil.cssResourceReferenceFor(ActionLinksPanel.class));
 
         // non-conforming component factories
         references.add(PanelUtil.cssResourceReferenceFor(MultiLineStringPanel.class));