Skip to content

Commit

Permalink
#4226 - Display logout button on annotation page if dashboard access …
Browse files Browse the repository at this point in the history
…is disabled

- Added logout button to the annotation action bar if the menu bar is not accessible
- If menubar is accessible, the logout button should always be there
- If logging out while auto-login is enabled, make sure to pass the skip-auto-login parameter to the login page
- Allow items in the annotation action bar to grow which allows the logout button to be positioned at the far right
- Improve scaling of the annotation action bar when window is resized
  • Loading branch information
reckart committed Oct 3, 2023
1 parent 21fd88d commit 3fc4739
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
<html xmlns:wicket="http://wicket.apache.org">
<body>
<wicket:panel>
<div wicket:id="items">
<wicket:container wicket:id="items">
<wicket:container wicket:id="item"/>
</div>
</wicket:container>
</wicket:panel>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
align-items: center;

@include media-breakpoint-down(xl) {
font-size: 1vw !important;
font-size: 1.3vw !important;
}

@include media-breakpoint-down(xl) {
Expand All @@ -36,25 +36,6 @@
font-size: inherit !important;
}
}

@include media-breakpoint-down(lg) {
.btn {
padding-left: calc($input-btn-padding-x / 2);
padding-right: calc($input-btn-padding-x / 2);
}
}

> * {
padding-left: calc($grid-gutter-width / 4);
padding-right: calc($grid-gutter-width / 4);
}

@include media-breakpoint-down(xl) {
> * {
padding-left: calc($grid-gutter-width / 8);
padding-right: calc($grid-gutter-width / 8);
}
}

.btn-group, .input-group {
@extend .bg-body;
Expand All @@ -65,32 +46,23 @@

.btn-action-bar {
@extend .btn-outline-secondary;

@include media-breakpoint-down(xl) {
--bs-btn-padding-x: 1vw !important;
--bs-btn-padding-y: 0.55vw !important;
}
}

.action-bar-group {
padding: 2px;
margin-left: 0.25rem;
margin-right: 0.25rem;
padding-top: 0.25rem;
padding-bottom: 0.25rem;
background-color: var(--bs-light-border-subtle);
border-radius: 5px;
border-radius: var(--bs-border-radius);
display: flex;
flex-direction: row;
align-items: center;
flex: 0;

> * {
padding-left: calc($grid-gutter-width / 8);
padding-right: calc($grid-gutter-width / 8);
}

@include media-breakpoint-down(xl) {
> * {
padding-left: calc($grid-gutter-width / 16);
padding-right: calc($grid-gutter-width / 16);
}
}
}

.action-bar-group-title {
padding-left: calc($grid-gutter-width / 2);
padding-right: calc($grid-gutter-width / 2);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Licensed to the Technische Universität Darmstadt under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The Technische Universität Darmstadt
* 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.
*
* 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 de.tudarmstadt.ukp.clarin.webanno.ui.annotation.actionbar.closesession;

import org.apache.wicket.markup.html.panel.Panel;
import org.springframework.core.annotation.Order;

import de.tudarmstadt.ukp.clarin.webanno.api.annotation.actionbar.ActionBarExtension;
import de.tudarmstadt.ukp.clarin.webanno.api.annotation.page.AnnotationPageBase;
import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.config.AnnotationUIAutoConfiguration;
import de.tudarmstadt.ukp.inception.ui.core.menubar.MenuBar;

/**
* <p>
* This class is exposed as a Spring Component via
* {@link AnnotationUIAutoConfiguration#annotationCloseSessionActionBarExtension}.
* </p>
*/
@Order(10000)
public class CloseSessionActionBarExtension
implements ActionBarExtension
{
@Override
public boolean accepts(AnnotationPageBase aPage)
{
return aPage.visitChildren(MenuBar.class, (c, v) -> {
v.stop(!((MenuBar) c).isVisible());
});
}

@Override
public Panel createActionBarItem(String aId, AnnotationPageBase aPage)
{
return new CloseSessionPanel(aId, aPage);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<!--
Licensed to the Technische Universität Darmstadt under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The Technische Universität Darmstadt
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.
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.
-->
<html xmlns:wicket="http://wicket.apache.org">

<body>
<wicket:panel>
<div class="d-flex flex-grow-1">
<div class="flex-grow-1" />
<div class="action-bar-group">
<div class="btn-group">
<button wicket:id="logoutButton" class="btn btn-action-bar" type="button" wicket:message="title:logOut">
<div class="text-nowrap">
<i class="fas fa-sign-out-alt"/>
</div>
</button>
</div>
</div>
</div>
</wicket:panel>
</body>

</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Licensed to the Technische Universität Darmstadt under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The Technische Universität Darmstadt
* 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.
*
* 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 de.tudarmstadt.ukp.clarin.webanno.ui.annotation.actionbar.closesession;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.spring.injection.annot.SpringBean;

import de.tudarmstadt.ukp.clarin.webanno.api.annotation.page.AnnotationPageBase;
import de.tudarmstadt.ukp.clarin.webanno.security.config.LoginProperties;
import de.tudarmstadt.ukp.clarin.webanno.security.config.PreauthenticationProperties;
import de.tudarmstadt.ukp.clarin.webanno.support.lambda.LambdaAjaxLink;
import de.tudarmstadt.ukp.clarin.webanno.ui.core.logout.LogoutPanel;

public class CloseSessionPanel
extends Panel
{
private static final long serialVersionUID = -9213541738534665790L;

private @SpringBean PreauthenticationProperties preauthenticationProperties;
private @SpringBean LoginProperties securityProperties;

public CloseSessionPanel(String aId, AnnotationPageBase aPage)
{
super(aId);
queue(new LambdaAjaxLink("logoutButton", this::actionLogout));
}

private void actionLogout(AjaxRequestTarget aTarget)
{
LogoutPanel.actionLogout(this, preauthenticationProperties, securityProperties);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import de.tudarmstadt.ukp.clarin.webanno.api.ProjectService;
import de.tudarmstadt.ukp.clarin.webanno.security.UserDao;
import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.AnnotationPageMenuItem;
import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.actionbar.closesession.CloseSessionActionBarExtension;
import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.actionbar.undo.AnnotationUndoActionBarExtension;
import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.actionbar.undo.actions.ChainAnnotationActionUndoSupport;
import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.actionbar.undo.actions.FeatureValueActionUndoSupport;
Expand Down Expand Up @@ -85,4 +86,10 @@ public FeatureValueActionUndoSupport featureValueActionUndoSupport()
{
return new FeatureValueActionUndoSupport();
}

@Bean
public CloseSessionActionBarExtension closeSessionActionBarExtension()
{
return new CloseSessionActionBarExtension();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ redo=Redo
moveUp=Up
moveDown=Down
busy=Busy...
logOut=Log out

enabled=Enabled

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
public class LoginPage
extends ApplicationPageBase
{
private static final String PARAM_SKIP_AUTP_LOGIN = "skipAutoLogin";
public static final String PARAM_SKIP_AUTO_LOGIN = "skipAutoLogin";
private static final String PARAM_ERROR = "error";

private static final String PROP_RESTORE_DEFAULT_ADMIN_ACCOUNT = "restoreDefaultAdminAccount";
Expand Down Expand Up @@ -124,7 +124,7 @@ public LoginPage(PageParameters aParameters)
saml2LoginPanel.add(visibleWhen(this::isLoginAllowed));
queue(saml2LoginPanel);

var skipAutoLogin = aParameters.get(PARAM_SKIP_AUTP_LOGIN).toBoolean(false)
var skipAutoLogin = aParameters.get(PARAM_SKIP_AUTO_LOGIN).toBoolean(false)
|| tooManyUsers.getObject();

// Failed OAuth2/SAML call this page with the parameter `?error` so we display a message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
<a class="nav-link" wicket:id="logout">
<i class="fas fa-sign-out-alt"></i>
<span class="nav-link active p-0 d-none d-md-inline">
Log out
<wicket:message key="logOut"/>
</span>
</a>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@

import static de.tudarmstadt.ukp.clarin.webanno.support.lambda.LambdaBehavior.enabledWhen;
import static de.tudarmstadt.ukp.clarin.webanno.support.lambda.LambdaBehavior.visibleWhen;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.startsWith;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

import javax.servlet.http.HttpSession;

import org.apache.wicket.Component;
import org.apache.wicket.devutils.stateless.StatelessComponent;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
Expand All @@ -46,11 +46,9 @@
import de.tudarmstadt.ukp.clarin.webanno.security.model.User;
import de.tudarmstadt.ukp.clarin.webanno.support.lambda.LambdaStatelessLink;
import de.tudarmstadt.ukp.clarin.webanno.ui.core.ApplicationSession;
import de.tudarmstadt.ukp.clarin.webanno.ui.core.login.LoginPage;
import de.tudarmstadt.ukp.clarin.webanno.ui.core.users.ManageUsersPage;

/**
* A wicket panel for logout.
*/
@StatelessComponent
public class LogoutPanel
extends Panel
Expand All @@ -66,11 +64,10 @@ public LogoutPanel(String id, IModel<User> aUser)
super(id, aUser);

var logoutLink = new LambdaStatelessLink("logout", this::actionLogout);
logoutLink.add(visibleWhen(this::isLogoutEnabled));
add(logoutLink);

var logoutTimer = new WebMarkupContainer("logoutTimer");
logoutTimer.add(visibleWhen(() -> getAutoLogoutTime() > 0 && isLogoutEnabled()));
logoutTimer.add(visibleWhen(() -> getAutoLogoutTime() > 0));
add(logoutTimer);

var profileLinkParameters = new PageParameters().add(ManageUsersPage.PARAM_USER,
Expand All @@ -87,18 +84,6 @@ public LogoutPanel(String id, IModel<User> aUser)
() -> ApplicationSession.exists() && ApplicationSession.get().isSignedIn()));
}

private boolean isLogoutEnabled()
{
// Logout is disabled for external (OAuth2) users if autoLogin is enabled.
// Pre-authenticated users do not count as external users here as we may have a logout
// link from the IdP configured
if (startsWith(getModel().getObject().getRealm(), UserDao.REALM_EXTERNAL_PREFIX)) {
return isBlank(securityProperties.getAutoLogin());
}

return true;
}

@SuppressWarnings("unchecked")
public IModel<User> getModel()
{
Expand All @@ -125,15 +110,27 @@ public void renderHead(IHeaderResponse aResponse)
}

private void actionLogout()
{
actionLogout(this, preauthenticationProperties, securityProperties);
}

public static void actionLogout(Component aOwner,
PreauthenticationProperties aPreauthProperties, LoginProperties aSecProperties)
{
ApplicationSession.get().signOut();

if (preauthenticationProperties.getLogoutUrl().isPresent()) {
throw new RedirectToUrlException(preauthenticationProperties.getLogoutUrl().get());
if (aPreauthProperties.getLogoutUrl().isPresent()) {
throw new RedirectToUrlException(aPreauthProperties.getLogoutUrl().get());
}
else {
setResponsePage(getApplication().getHomePage());

if (isNotBlank(aSecProperties.getAutoLogin())) {
PageParameters parameters = new PageParameters();
parameters.set(LoginPage.PARAM_SKIP_AUTO_LOGIN, true);
aOwner.setResponsePage(LoginPage.class, parameters);
return;
}

aOwner.setResponsePage(aOwner.getApplication().getHomePage());
}

/**
Expand Down

0 comments on commit 3fc4739

Please sign in to comment.