Skip to content

Commit

Permalink
CAUSEWAY-3815: implements column action specific routing
Browse files Browse the repository at this point in the history
  • Loading branch information
andi-huber committed Nov 26, 2024
1 parent 0109d99 commit 18f5a57
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 173 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2923,10 +2923,8 @@ public static class Wicket {
* That is, collections of domain objects are presented in the UI as tables,
* where corresponding domain object actions are gathered into an additional
* (typically trailing) column (labeled 'action-column').
* <p>
* Defaults to disabled, while we are still working on this feature [CAUSEWAY-3815].
*/
private boolean actionColumnEnabled = false;
private boolean actionColumnEnabled = true;

/**
* Whether actions, that on click will show a dialog,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,17 @@ public record ActionModel(
* @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; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,11 @@
import org.apache.causeway.core.security.authentication.logout.LogoutMenu.LoginRedirect;
import org.apache.causeway.viewer.wicket.model.models.FormExecutor.ActionResultResponseType;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import lombok.experimental.Accessors;

@AllArgsConstructor @Getter @Accessors(fluent=true) //java record candidate
public class ActionResultModel {
private final ActionResultResponseType responseType;
private final ManagedObject resultAdapter;
public record ActionResultModel(
ActionResultResponseType responseType,
ManagedObject resultAdapter) {

public static ActionResultModel determineFor(
@NonNull final ActionModel actionModel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.cycle.RequestCycle;

import org.springframework.lang.Nullable;

Expand All @@ -29,7 +28,6 @@
import org.apache.causeway.viewer.wicket.model.models.ActionModel;
import org.apache.causeway.viewer.wicket.ui.pages.obj.DomainObjectPage;

import lombok.Getter;
import lombok.NonNull;

/**
Expand All @@ -38,14 +36,30 @@
* {@link #withHandler(IRequestHandler) redirect} to a
* handler (eg a download).
*/
public class ActionResultResponse {

@Getter
private final ActionResultResponseHandlingStrategy handlingStrategy;
private final IRequestHandler handler;
private final PageRedirectRequest<?> pageRedirect;
private final AjaxRequestTarget target;
private final String url;
public record ActionResultResponse(
ActionResultResponseHandlingStrategy handlingStrategy,
/**
* Populated only if {@link #handlingStrategy()}
* is {@link ActionResultResponseHandlingStrategy#SCHEDULE_HANDLER}
*/
IRequestHandler handler,
/**
* Populated only if {@link #handlingStrategy()}
* is {@link ActionResultResponseHandlingStrategy#REDIRECT_TO_PAGE}
*/
PageRedirectRequest<?> pageRedirect,
/**
* Populated only if {@link #handlingStrategy()} is
* either {@link ActionResultResponseHandlingStrategy#OPEN_URL_IN_NEW_BROWSER_WINDOW}
* or {@link ActionResultResponseHandlingStrategy#OPEN_URL_IN_SAME_BROWSER_WINDOW}
*/
AjaxRequestTarget ajaxTarget,
/**
* Populated only if {@link #handlingStrategy()} is
* either {@link ActionResultResponseHandlingStrategy#OPEN_URL_IN_NEW_BROWSER_WINDOW}
* or {@link ActionResultResponseHandlingStrategy#OPEN_URL_IN_SAME_BROWSER_WINDOW}
*/
String url) {

public static ActionResultResponse toDomainObjectPage(final @NonNull ManagedObject entityOrViewmodel) {
var pageRedirectRequest = PageRedirectRequest.forPageClassAndBookmark(
Expand All @@ -71,109 +85,13 @@ static ActionResultResponse toPage(final PageRedirectRequest<?> page) {
}

static ActionResultResponse openUrlInBrowser(
final AjaxRequestTarget target,
final AjaxRequestTarget ajaxTarget,
final String url,
final @NonNull OpenUrlStrategy openUrlStrategy) {
return new ActionResultResponse(
openUrlStrategy.isNewWindow()
? ActionResultResponseHandlingStrategy.OPEN_URL_IN_NEW_BROWSER_WINDOW
: ActionResultResponseHandlingStrategy.OPEN_URL_IN_SAME_BROWSER_WINDOW,
null, null, target, url);
}

ActionResultResponse(
final ActionResultResponseHandlingStrategy strategy,
final IRequestHandler handler,
final PageRedirectRequest<?> pageRedirect,
final AjaxRequestTarget target,
final String url) {
this.handlingStrategy = strategy;
this.handler = handler;
this.pageRedirect = pageRedirect;
this.target = target;
this.url = url;
}

//TODO[CAUSEWAY-3815] WIP should create URL from current page then open in new browser
ActionResultResponse withForceNewBrowserWindow() {
var url = this.url!=null
? this.url
: RequestCycle.get().getRequest().getOriginalUrl().toString();

return new ActionResultResponse(
ActionResultResponseHandlingStrategy.OPEN_URL_IN_NEW_BROWSER_WINDOW,
handler, pageRedirect, target, url);
}

//TODO[CAUSEWAY-3815] WIP should force reload the entire page (or do a proper partial page update (AJAX) of the originating table)
ActionResultResponse withForceReload() {
return this;
}

/**
* Populated only if {@link #getHandlingStrategy() handling strategy}
* is {@link ActionResultResponseHandlingStrategy#SCHEDULE_HANDLER}
*/
public IRequestHandler getHandler() {
return handler;
null, null, ajaxTarget, url);
}

/**
* Populated only if {@link #getHandlingStrategy() handling strategy}
* is {@link ActionResultResponseHandlingStrategy#REDIRECT_TO_PAGE}
*/
public PageRedirectRequest<?> getPageRedirect() {
return pageRedirect;
}

/**
* Populated only if {@link #getHandlingStrategy() handling strategy} is
* either {@link ActionResultResponseHandlingStrategy#OPEN_URL_IN_NEW_BROWSER_WINDOW}
* or {@link ActionResultResponseHandlingStrategy#OPEN_URL_IN_SAME_BROWSER_WINDOW}
*/
public AjaxRequestTarget getAjaxTarget() {
return target;
}

/**
* Populated only if {@link #getHandlingStrategy() handling strategy} is
* either {@link ActionResultResponseHandlingStrategy#OPEN_URL_IN_NEW_BROWSER_WINDOW}
* or {@link ActionResultResponseHandlingStrategy#OPEN_URL_IN_SAME_BROWSER_WINDOW}
*/
public String getUrl() {
return url;
}

@Override
public String toString() {
return String.format("ActionResultResponse["
+ "handlingStrategy=%s,"
+ "requestHandler=%s,"
+ "pageRedirect=%s,"
+ "ajaxTarget=%s,"
+ "url=%s"
+ "]",
handlingStrategy.name(),
handler,
pageRedirect,
target,
url);
}

/** introduced for debugging */
public String toStringMultiline() {
return String.format("ActionResultResponse {\n"
+ "\thandlingStrategy=%s,\n"
+ "\trequestHandler=%s,\n"
+ "\tpageRedirect=%s,\n"
+ "\tajaxTarget=%s,\n"
+ "\turl=%s\n"
+ "}",
handlingStrategy.name(),
handler,
pageRedirect,
target,
url);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.time.Duration;

import org.apache.wicket.Component;
import org.apache.wicket.Page;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.AbstractAjaxBehavior;
import org.apache.wicket.request.IRequestHandler;
Expand Down Expand Up @@ -58,7 +57,7 @@ public void handleResults(
MetaModelContext.instance().ifPresent(mmc->mmc.getTransactionService().flushTransaction());

// "redirect-after-post"
resultResponse.getPageRedirect().applyTo(RequestCycle.get());
resultResponse.pageRedirect().apply();
}
},
SCHEDULE_HANDLER {
Expand All @@ -67,34 +66,31 @@ public void handleResults(
final ActionResultResponse resultResponse) {

final RequestCycle requestCycle = RequestCycle.get();
AjaxRequestTarget target = requestCycle.find(AjaxRequestTarget.class).orElse(null);
var ajaxTarget = requestCycle.find(AjaxRequestTarget.class).orElse(null);

if (target == null) {
if (ajaxTarget == null) {
// non-Ajax request => just stream the Lob to the browser
// or if this is a no-arg action, there also will be no parent for the component
requestCycle.scheduleRequestHandlerAfterCurrent(resultResponse.getHandler());
requestCycle.scheduleRequestHandlerAfterCurrent(resultResponse.handler());
} else {
// otherwise,
// Ajax request => respond with a redirect to be able to stream the Lob to the client
final IRequestHandler requestHandler = resultResponse.getHandler();
if(requestHandler instanceof ResourceStreamRequestHandler) {
ResourceStreamRequestHandler scheduledHandler = (ResourceStreamRequestHandler) requestHandler;
StreamAfterAjaxResponseBehavior streamingBehavior = new StreamAfterAjaxResponseBehavior(scheduledHandler);
final Page page = target.getPage();
final IRequestHandler requestHandler = resultResponse.handler();
if(requestHandler instanceof ResourceStreamRequestHandler scheduledHandler) {
var streamingBehavior = new StreamAfterAjaxResponseBehavior(scheduledHandler);
var page = ajaxTarget.getPage();
page.add(streamingBehavior);
CharSequence callbackUrl = streamingBehavior.getCallbackUrl();
scheduleJs(target, javascriptFor_sameWindow(callbackUrl), 10);
} else if(requestHandler instanceof RedirectRequestHandlerWithOpenUrlStrategy) {
final RedirectRequestHandlerWithOpenUrlStrategy redirectHandler =
(RedirectRequestHandlerWithOpenUrlStrategy) requestHandler;
scheduleJs(ajaxTarget, javascriptFor_sameWindow(callbackUrl), 10);
} else if(requestHandler instanceof RedirectRequestHandlerWithOpenUrlStrategy redirectHandler) {

final String url = redirectHandler.getRedirectUrl();
final String fullUrl = expanded(requestCycle, url);

if(redirectHandler.getOpenUrlStrategy().isNewWindow()) {
scheduleJs(target, javascriptFor_newWindow(fullUrl), 100);
scheduleJs(ajaxTarget, javascriptFor_newWindow(fullUrl), 100);
} else {
scheduleJs(target, javascriptFor_sameWindow(fullUrl), 100);
scheduleJs(ajaxTarget, javascriptFor_sameWindow(fullUrl), 100);
}
} else {
throw _Exceptions.unrecoverable(
Expand All @@ -110,23 +106,23 @@ public void handleResults(
public void handleResults(
final ActionResultResponse resultResponse) {

final String url = resultResponse.getUrl();
final String url = resultResponse.url();
final RequestCycle requestCycle = RequestCycle.get();
final String fullUrl = expanded(requestCycle, url);

scheduleJs(resultResponse.getAjaxTarget(), javascriptFor_newWindow(fullUrl), 100);
scheduleJs(resultResponse.ajaxTarget(), javascriptFor_newWindow(fullUrl), 100);
}
},
OPEN_URL_IN_SAME_BROWSER_WINDOW {
@Override
public void handleResults(
final ActionResultResponse resultResponse) {

final String url = resultResponse.getUrl();
final String url = resultResponse.url();
final RequestCycle requestCycle = RequestCycle.get();
final String fullUrl = expanded(requestCycle, url);

scheduleJs(resultResponse.getAjaxTarget(), javascriptFor_sameWindow(fullUrl), 100);
scheduleJs(resultResponse.ajaxTarget(), javascriptFor_sameWindow(fullUrl), 100);
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*/
package org.apache.causeway.viewer.wicket.ui.actionresponse;

import org.apache.wicket.core.request.handler.BookmarkablePageRequestHandler;
import org.apache.wicket.core.request.handler.PageProvider;
import org.apache.wicket.request.component.IRequestablePage;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.mapper.parameter.PageParameters;
Expand All @@ -27,16 +29,12 @@
import org.apache.causeway.applib.services.bookmark.Bookmark;
import org.apache.causeway.viewer.wicket.model.util.PageParameterUtils;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.NonNull;

@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class PageRedirectRequest<T extends IRequestablePage> {

private final @NonNull Class<T> pageClass;
private final @Nullable PageParameters pageParameters;
private final @Nullable IRequestablePage pageInstance;
public record PageRedirectRequest<T extends IRequestablePage>(
@NonNull Class<T> pageClass,
@Nullable PageParameters pageParameters,
@Nullable IRequestablePage pageInstance) {

public static <T extends IRequestablePage> PageRedirectRequest<T> forPageClass(
final @NonNull Class<T> pageClass,
Expand All @@ -63,11 +61,16 @@ public static <T extends IRequestablePage> PageRedirectRequest<T> forPage(
return new PageRedirectRequest<>(pageClass, null, pageInstance);
}

public void applyTo(
final @Nullable RequestCycle requestCycle) {
if(requestCycle==null) {
return;
}
public String toUrl() {
var handler = new BookmarkablePageRequestHandler(
new PageProvider(pageClass, pageParameters));
return RequestCycle.get().urlFor(handler)
.toString();
}

public void apply() {
var requestCycle = RequestCycle.get();
if(requestCycle==null) return;
if(pageParameters!=null) {
requestCycle.setResponsePage(pageClass, pageParameters);
return;
Expand All @@ -79,10 +82,4 @@ public void applyTo(
requestCycle.setResponsePage(pageClass);
}

@Override
public String toString() {
return String.format("PageRedirectRequest[pageClass=%s,pageParameters=%s]",
pageClass.getName(), pageParameters);
}

}
Loading

0 comments on commit 18f5a57

Please sign in to comment.