This is an automated email from the ASF dual-hosted git repository. ahuber pushed a commit to branch 2877_compound.value.types in repository https://gitbox.apache.org/repos/asf/isis.git
commit 39905039254b2140a720b352622d16e24e3581fc Author: andi-huber <[email protected]> AuthorDate: Sat Oct 23 19:42:14 2021 +0200 ISIS-2871: housekeeping around ActionLink --- .../ui/components/layout/bs3/BS3GridPanel.java | 32 +++ .../widgets/linkandlabel/ActionLink.java | 269 +++++++++------------ 2 files changed, 145 insertions(+), 156 deletions(-) diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/bs3/BS3GridPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/bs3/BS3GridPanel.java index dd2126c..8f10e7f 100644 --- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/bs3/BS3GridPanel.java +++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/bs3/BS3GridPanel.java @@ -18,17 +18,27 @@ */ package org.apache.isis.viewer.wicket.ui.components.layout.bs3; +import java.util.Optional; + import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.repeater.RepeatingView; +import org.apache.isis.applib.layout.grid.Grid; import org.apache.isis.applib.layout.grid.bootstrap3.BS3Grid; import org.apache.isis.applib.layout.grid.bootstrap3.BS3Row; +import org.apache.isis.core.metamodel.facets.object.grid.GridFacet; import org.apache.isis.core.metamodel.spec.ManagedObject; +import org.apache.isis.core.metamodel.spec.ObjectSpecification; +import org.apache.isis.core.metamodel.spec.feature.ObjectAction; +import org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionMixedIn; +import org.apache.isis.viewer.wicket.model.models.ActionModel; import org.apache.isis.viewer.wicket.model.models.EntityModel; import org.apache.isis.viewer.wicket.ui.components.layout.bs3.row.Row; import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract; import org.apache.isis.viewer.wicket.ui.util.Wkt; +import lombok.val; + public class BS3GridPanel extends PanelAbstract<ManagedObject, EntityModel> { @@ -38,6 +48,28 @@ extends PanelAbstract<ManagedObject, EntityModel> { private final BS3Grid bs3Page; + public static Optional<BS3GridPanel> extraContent(final String id, final ActionModel actionModel) { + final ObjectAction action = actionModel.getAction(); + if(action instanceof ObjectActionMixedIn) { + final ObjectActionMixedIn actionMixedIn = (ObjectActionMixedIn) action; + final ObjectSpecification mixinSpec = actionMixedIn.getMixinType(); + if(mixinSpec.isViewModel()) { + val commonContext = actionModel.getCommonContext(); + final ManagedObject targetAdapterForMixin = action.realTargetAdapter(actionModel.getActionOwner()); + final GridFacet gridFacet = mixinSpec.getFacet(GridFacet.class); + final Grid gridForMixin = gridFacet.getGrid(targetAdapterForMixin); + if(gridForMixin instanceof BS3Grid) { + final BS3Grid bs3Grid = (BS3Grid) gridForMixin; + final EntityModel entityModelForMixin = + EntityModel.ofAdapter(commonContext, targetAdapterForMixin); + return Optional.of(new BS3GridPanel(id, entityModelForMixin, bs3Grid)); + } + } + } + return Optional.empty(); + } + + public BS3GridPanel(final String id, final EntityModel entityModel, final BS3Grid bs3Grid) { super(id, entityModel); this.bs3Page = bs3Grid; diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLink.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLink.java index 7744ef5..036eb74 100644 --- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLink.java +++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLink.java @@ -21,8 +21,6 @@ package org.apache.isis.viewer.wicket.ui.components.widgets.linkandlabel; import java.util.Optional; import org.apache.wicket.Application; -import org.apache.wicket.MarkupContainer; -import org.apache.wicket.Page; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.attributes.AjaxRequestAttributes; import org.apache.wicket.extensions.ajax.markup.html.AjaxIndicatorAppender; @@ -30,27 +28,19 @@ import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.request.cycle.RequestCycle; -import org.apache.isis.applib.annotation.Programmatic; -import org.apache.isis.applib.layout.grid.Grid; -import org.apache.isis.applib.layout.grid.bootstrap3.BS3Grid; import org.apache.isis.commons.internal.base._Either; import org.apache.isis.commons.internal.debug._Probe; import org.apache.isis.commons.internal.debug._Probe.EntryPoint; -import org.apache.isis.core.metamodel.facets.object.grid.GridFacet; import org.apache.isis.core.metamodel.spec.ManagedObject; -import org.apache.isis.core.metamodel.spec.ObjectSpecification; import org.apache.isis.core.metamodel.spec.feature.ObjectAction; -import org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionMixedIn; import org.apache.isis.core.runtime.context.IsisAppCommonContext; import org.apache.isis.core.security.authentication.logout.LogoutMenu.LoginRedirect; import org.apache.isis.viewer.common.model.components.ComponentType; import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings; import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettingsAccessor; import org.apache.isis.viewer.wicket.model.models.ActionModel; -import org.apache.isis.viewer.wicket.model.models.ActionPrompt; import org.apache.isis.viewer.wicket.model.models.ActionPromptProvider; import org.apache.isis.viewer.wicket.model.models.ActionPromptWithExtraContent; -import org.apache.isis.viewer.wicket.model.models.EntityModel; import org.apache.isis.viewer.wicket.model.models.FormExecutor; import org.apache.isis.viewer.wicket.model.models.PageType; import org.apache.isis.viewer.wicket.model.util.CommonContextUtils; @@ -65,11 +55,33 @@ import org.apache.isis.viewer.wicket.ui.panels.FormExecutorDefault; import org.apache.isis.viewer.wicket.ui.panels.PanelUtil; import org.apache.isis.viewer.wicket.ui.util.Wkt; -import lombok.NonNull; -import lombok.val; +import static org.apache.isis.commons.internal.base._Casts.castTo; import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons; +import lombok.NonNull; +import lombok.val; +/** + * + * @implNote <pre> + * according to + * http://wicketinaction.com/2011/11/implement-wicket-component-visibility-changes-properly/ + * and + * http://apache-wicket.1842946.n4.nabble.com/vote-release-Wicket-1-4-14-td3056628.html#a3063795 + * should be using onConfigure rather than overloading. + * eg: + * setVisible(determineIfVisible()); + * setEnabled(determineIfEnabled()); + * + * and no longer override isVisible() and isEnabled(). + * + * however, in the case of a button already rendered as visible/enabled that (due to changes + * elsewhere in the state of the server-side system) should then become invisible/disabled, it seems + * that onConfigure isn't called and so the action continues to display the prompt. + * A check is only made when hit OK of the prompt. This is too late to display a message, so (until + * figure out a better way) gonna continue to override isVisible() and isEnabled() + * </pre> + */ public final class ActionLink extends IndicatingAjaxLink<ManagedObject> { @@ -103,15 +115,6 @@ extends IndicatingAjaxLink<ManagedObject> { } } - @Override - public void onClick(final AjaxRequestTarget target) { - - _Probe.entryPoint(EntryPoint.USER_INTERACTION, "Wicket Ajax Request, " - + "originating from User clicking an Action Link."); - - doOnClick(this, target); - } - ActionModel getActionModel() { return (ActionModel) getModel(); } @@ -137,38 +140,16 @@ extends IndicatingAjaxLink<ManagedObject> { } @Override - protected void onConfigure() { - super.onConfigure(); - // according to - // http://wicketinaction.com/2011/11/implement-wicket-component-visibility-changes-properly/ - // and - // http://apache-wicket.1842946.n4.nabble.com/vote-release-Wicket-1-4-14-td3056628.html#a3063795 - // should be using onConfigure rather than overloading. - // - // eg: - // setVisible(determineIfVisible()); - // setEnabled(determineIfEnabled()); - // - // and no longer override isVisible() and isEnabled(). - // - // however, in the case of a button already rendered as visible/enabled that (due to changes - // elsewhere in the state of the server-side system) should then become invisible/disabled, it seems - // that onConfigure isn't called and so the action continues to display the prompt. - // A check is only made when hit OK of the prompt. This is too late to display a message, so (until - // figure out a better way) gonna continue to override isVisible() and isEnabled() - } - - @Override public boolean isVisible() { return getActionModel().getVisibilityConsent().isAllowed(); } @Override - @Programmatic public boolean isEnabled() { return getActionModel().getUsabilityConsent().isAllowed(); } + @SuppressWarnings("deprecation") @Override protected void onComponentTag(final ComponentTag tag) { super.onComponentTag(tag); @@ -186,140 +167,116 @@ extends IndicatingAjaxLink<ManagedObject> { return ((WicketViewerSettingsAccessor) Application.get()).getSettings(); } - /** - * @return the prompt, if not inline prompt - */ - private ActionPrompt doOnClick( - final ActionLink actionLink, - final AjaxRequestTarget target) { - - val actionModel = actionLink.getActionModel(); - val inlinePromptContext = actionModel.getInlinePromptContext(); - val promptStyle = actionModel.getPromptStyle(); - - if(inlinePromptContext == null || promptStyle.isDialog()) { - val promptProvider = ActionPromptProvider.getFrom(actionLink.getPage()); - val actionOwnerSpec = actionModel.getActionOwner().getSpecification(); - val actionPrompt = promptProvider.getActionPrompt(promptStyle, actionOwnerSpec.getBeanSort()); - - // - // previously this if/else was in the ActionParametersPanel - // - // now though we only build that panel if we know that there *are* parameters. - // - if(actionModel.hasParameters()) { - - val actionParametersPanel = (ActionParametersPanel) - getComponentFactoryRegistry() - .createComponent( - ComponentType.ACTION_PROMPT, actionPrompt.getContentId(), actionModel); - - actionParametersPanel.setShowHeader(false); - - val label = Wkt.label(actionPrompt.getTitleId(), actionModel::getFriendlyName); - actionPrompt.setTitle(label, target); - actionPrompt.setPanel(actionParametersPanel, target); - actionPrompt.showPrompt(target); - - if(actionPrompt instanceof ActionPromptWithExtraContent) { - final ActionPromptWithExtraContent promptWithExtraContent = - (ActionPromptWithExtraContent) actionPrompt; - - final ObjectAction action = actionModel.getAction(); - if(action instanceof ObjectActionMixedIn) { - final ObjectActionMixedIn actionMixedIn = (ObjectActionMixedIn) action; - final ObjectSpecification mixinSpec = actionMixedIn.getMixinType(); - - if(mixinSpec.isViewModel()) { - - val commonContext = getCommonContext(); - final ManagedObject targetAdapterForMixin = action.realTargetAdapter(actionModel.getActionOwner()); - final EntityModel entityModelForMixin = - EntityModel.ofAdapter(commonContext, targetAdapterForMixin); + @Override + public void onClick(final AjaxRequestTarget target) { - final GridFacet facet = mixinSpec.getFacet(GridFacet.class); - final Grid gridForMixin = facet.getGrid(targetAdapterForMixin); + _Probe.entryPoint(EntryPoint.USER_INTERACTION, "Wicket Ajax Request, " + + "originating from User clicking an Action Link."); - final String extraContentId = promptWithExtraContent.getExtraContentId(); + val actionModel = this.getActionModel(); - if(gridForMixin instanceof BS3Grid) { - final BS3Grid bs3Grid = (BS3Grid) gridForMixin; - final BS3GridPanel gridPanel = new BS3GridPanel(extraContentId, entityModelForMixin, bs3Grid); - promptWithExtraContent.setExtraContentPanel(gridPanel, target); - } - } - } - } - - return actionPrompt; + if(actionModel.getInlinePromptContext() == null || + actionModel.getPromptStyle().isDialog()) { + if(actionModel.hasParameters()) { + startDialogWithParams(target); } else { + executeWithoutParams(); + } + } else { + startDialogInline(target); + } + } - final Page page = actionLink.getPage(); - - // returns true - if redirecting to new page, or repainting all components. - // returns false - if invalid args; if concurrency exception; - - final FormExecutor formExecutor = - new FormExecutorDefault(_Either.left(actionModel)); - boolean succeeded = formExecutor.executeAndProcessResults(page, null, null, actionModel.isWithinPrompt()); - - if(succeeded) { - - // intercept redirect request to sign-in page - Optional.ofNullable(actionModel.getObject()) - .ifPresent(actionResultAdapter->{ - val actionResultObjectType = actionResultAdapter.getSpecification().getLogicalTypeName(); - if(LoginRedirect.LOGICAL_TYPE_NAME.equals(actionResultObjectType)) { - val commonContext = actionModel.getCommonContext(); - val pageClassRegistry = commonContext.lookupServiceElseFail(PageClassRegistry.class); - val signInPage = pageClassRegistry.getPageClass(PageType.SIGN_IN); - RequestCycle.get().setResponsePage(signInPage); - } - }); - - // else nothing to do - - // - // the formExecutor will have either redirected, or scheduled a response, - // or repainted components as required - // + private void startDialogWithParams(final AjaxRequestTarget target) { - } else { + val actionModel = this.getActionModel(); + val actionLink = this; + val promptProvider = ActionPromptProvider.getFrom(actionLink.getPage()); + val actionOwnerSpec = actionModel.getActionOwner().getSpecification(); + val actionPrompt = promptProvider.getActionPrompt(actionModel.getPromptStyle(), actionOwnerSpec.getBeanSort()); - // render the target entity again - // - // (One way this can occur is if an event subscriber has a defect and throws an exception; in which case - // the EventBus' exception handler will automatically veto. This results in a growl message rather than - // an error page, but is probably 'good enough'). - val targetAdapter = actionModel.getParentObject(); + val actionParametersPanel = (ActionParametersPanel) + getComponentFactoryRegistry() + .createComponent( + ComponentType.ACTION_PROMPT, actionPrompt.getContentId(), actionModel); - final EntityPage entityPage = EntityPage.ofAdapter(getCommonContext(), targetAdapter); + actionParametersPanel.setShowHeader(false); - getCommonContext().getTransactionService().flushTransaction(); + val label = Wkt.label(actionPrompt.getTitleId(), actionModel::getFriendlyName); + actionPrompt.setTitle(label, target); + actionPrompt.setPanel(actionParametersPanel, target); + actionPrompt.showPrompt(target); - // "redirect-after-post" - RequestCycle.get().setResponsePage(entityPage); + castTo(actionPrompt, ActionPromptWithExtraContent.class) + .ifPresent(promptWithExtraContent->{ + BS3GridPanel.extraContent(promptWithExtraContent.getExtraContentId(), actionModel) + .ifPresent(gridPanel->promptWithExtraContent.setExtraContentPanel(gridPanel, target)); + }); + } + private void executeWithoutParams() { + val actionModel = this.getActionModel(); + val actionLink = this; + val page = actionLink.getPage(); + + // returns true - if redirecting to new page, or repainting all components. + // returns false - if invalid args; if concurrency exception; + + final FormExecutor formExecutor = + new FormExecutorDefault(_Either.left(actionModel)); + boolean succeeded = formExecutor.executeAndProcessResults(page, null, null, actionModel.isWithinPrompt()); + + if(succeeded) { + + // intercept redirect request to sign-in page + Optional.ofNullable(actionModel.getObject()) + .ifPresent(actionResultAdapter->{ + val actionResultObjectType = actionResultAdapter.getSpecification().getLogicalTypeName(); + if(LoginRedirect.LOGICAL_TYPE_NAME.equals(actionResultObjectType)) { + val commonContext = actionModel.getCommonContext(); + val pageClassRegistry = commonContext.lookupServiceElseFail(PageClassRegistry.class); + val signInPage = pageClassRegistry.getPageClass(PageType.SIGN_IN); + RequestCycle.get().setResponsePage(signInPage); } - } + }); + // else nothing to do + + // + // the formExecutor will have either redirected, or scheduled a response, + // or repainted components as required + // } else { - MarkupContainer scalarTypeContainer = inlinePromptContext.getScalarTypeContainer(); + // render the target entity again + // + // (One way this can occur is if an event subscriber has a defect and throws an exception; in which case + // the EventBus' exception handler will automatically veto. This results in a growl message rather than + // an error page, but is probably 'good enough'). + val targetAdapter = actionModel.getParentObject(); + val entityPage = EntityPage.ofAdapter(getCommonContext(), targetAdapter); + getCommonContext().getTransactionService().flushTransaction(); + + // "redirect-after-post" + RequestCycle.get().setResponsePage(entityPage); + } + } - getComponentFactoryRegistry().addOrReplaceComponent(scalarTypeContainer, - ScalarPanelAbstract.ID_SCALAR_IF_REGULAR_INLINE_PROMPT_FORM, ComponentType.PARAMETERS, actionModel); + private void startDialogInline(final AjaxRequestTarget target) { - inlinePromptContext.getScalarIfRegular().setVisible(false); - inlinePromptContext.getScalarIfRegularInlinePromptForm().setVisible(true); + val actionModel = this.getActionModel(); + val inlinePromptContext = actionModel.getInlinePromptContext(); + val scalarTypeContainer = inlinePromptContext.getScalarTypeContainer(); - target.add(scalarTypeContainer); - } + getComponentFactoryRegistry().addOrReplaceComponent(scalarTypeContainer, + ScalarPanelAbstract.ID_SCALAR_IF_REGULAR_INLINE_PROMPT_FORM, ComponentType.PARAMETERS, actionModel); - return null; + inlinePromptContext.getScalarIfRegular().setVisible(false); + inlinePromptContext.getScalarIfRegularInlinePromptForm().setVisible(true); + target.add(scalarTypeContainer); } // -- DEPENDENCIES
