From c9666f85207a0908e94ae4007d727a3ee0ad5947 Mon Sep 17 00:00:00 2001 From: Katarina Valalikova Date: Wed, 1 Apr 2020 19:10:15 +0200 Subject: [PATCH 1/5] fixing saving handlerUri + archetype for new task using "non-archetyped" task, fix for re-rendering form with relevant attributes. (MID-6150) --- .../page/admin/server/TaskBasicTabPanel.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskBasicTabPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskBasicTabPanel.java index 2e0f2ea7272..18434e765bb 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskBasicTabPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskBasicTabPanel.java @@ -8,6 +8,10 @@ import java.util.*; +import com.evolveum.midpoint.prism.PrismProperty; + +import com.evolveum.midpoint.web.component.prism.ValueStatus; + import org.apache.commons.lang.StringUtils; import org.apache.wicket.Component; import org.apache.wicket.RestartResponseException; @@ -92,6 +96,30 @@ protected void onUpdatePerformed(AjaxRequestTarget target) { } } + PrismObjectWrapperFactory wrapperFactory = TaskBasicTabPanel.this.getPageBase().findObjectWrapperFactory(getTask().asPrismObject().getDefinition()); + Task task = getPageBase().createSimpleTask(OPERATION_UPDATE_WRAPPER); + OperationResult result = task.getResult(); + WrapperContext ctx = new WrapperContext(task, result); + try { + wrapperFactory.updateWrapper(TaskBasicTabPanel.this.getModelObject(), ctx); + + //TODO ugly hack: after updateWrapper method is called, both previously set items (handlerUri and assignments) + // are marked as NOT_CHANGED with the same value. We need to find a way how to force the ValueStatus + // or change the mechanism for computing deltas. Probably only the first will work + PrismPropertyWrapper handlerWrapper = TaskBasicTabPanel.this.getModelObject().findProperty(ItemPath.create(TaskType.F_HANDLER_URI)); + handlerWrapper.getValue().setStatus(ValueStatus.ADDED); + + PrismContainerWrapper assignmentWrapper = TaskBasicTabPanel.this.getModelObject().findContainer(ItemPath.create(TaskType.F_ASSIGNMENT)); + for (PrismContainerValueWrapper assignmentWrapperValue : assignmentWrapper.getValues()) { + if (WebComponentUtil.isArchetypeAssignment(assignmentWrapperValue.getRealValue())) { + assignmentWrapperValue.setStatus(ValueStatus.ADDED); + } + } + + } catch (SchemaException e) { + LOGGER.error("Unexpected problem occurs during updating wrapper. Reason: {}", e.getMessage(), e); + } + updateHandlerPerformed(target); } From 61ac267d161d58fb74e082a0a6f31ff159099385 Mon Sep 17 00:00:00 2001 From: Katarina Valalikova Date: Wed, 1 Apr 2020 19:32:10 +0200 Subject: [PATCH 2/5] Task table - allow to delete multiple tasks (MID-6153) --- .../web/page/admin/server/TaskTablePanel.java | 1986 ++++++++--------- 1 file changed, 991 insertions(+), 995 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskTablePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskTablePanel.java index d0f0449d163..b5dbea35b24 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskTablePanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskTablePanel.java @@ -1,995 +1,991 @@ -/* - * Copyright (c) 2010-2019 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ - -package com.evolveum.midpoint.web.page.admin.server; - -import com.evolveum.midpoint.gui.api.GuiStyleConstants; -import com.evolveum.midpoint.gui.api.component.MainObjectListPanel; -import com.evolveum.midpoint.gui.api.model.ReadOnlyModel; -import com.evolveum.midpoint.gui.api.util.WebComponentUtil; -import com.evolveum.midpoint.model.api.ModelPublicConstants; -import com.evolveum.midpoint.model.api.TaskService; -import com.evolveum.midpoint.prism.xml.XmlTypeConverter; -import com.evolveum.midpoint.schema.GetOperationOptions; -import com.evolveum.midpoint.schema.SelectorOptions; -import com.evolveum.midpoint.schema.constants.SchemaConstants; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.result.OperationResultStatus; -import com.evolveum.midpoint.schema.util.TaskTypeUtil; -import com.evolveum.midpoint.schema.util.TaskWorkStateTypeUtil; -import com.evolveum.midpoint.security.api.AuthorizationConstants; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.task.api.TaskManager; -import com.evolveum.midpoint.util.exception.*; -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.web.application.AuthorizationAction; -import com.evolveum.midpoint.web.application.PageDescriptor; -import com.evolveum.midpoint.web.application.Url; -import com.evolveum.midpoint.web.component.AjaxIconButton; -import com.evolveum.midpoint.web.component.data.column.*; -import com.evolveum.midpoint.web.component.menu.cog.ButtonInlineMenuItem; -import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem; -import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItemAction; -import com.evolveum.midpoint.web.component.util.SelectableBean; -import com.evolveum.midpoint.web.component.util.SelectableBeanImpl; -import com.evolveum.midpoint.web.page.admin.server.dto.OperationResultStatusPresentationProperties; -import com.evolveum.midpoint.web.session.UserProfileStorage; -import com.evolveum.midpoint.web.util.OnePageParameterEncoder; -import com.evolveum.midpoint.xml.ns._public.common.common_3.*; - -import org.apache.wicket.Component; -import org.apache.wicket.ajax.AjaxRequestTarget; -import org.apache.wicket.behavior.AttributeAppender; -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.extensions.markup.html.repeater.data.table.IColumn; -import org.apache.wicket.extensions.markup.html.repeater.data.table.export.AbstractExportableColumn; -import org.apache.wicket.markup.html.WebMarkupContainer; -import org.apache.wicket.markup.html.WebPage; -import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.repeater.Item; -import org.apache.wicket.model.IModel; -import org.apache.wicket.model.Model; -import org.apache.wicket.model.PropertyModel; -import org.apache.wicket.request.mapper.parameter.PageParameters; -import org.jetbrains.annotations.NotNull; - -import javax.xml.datatype.XMLGregorianCalendar; -import java.util.*; -import java.util.stream.Collectors; - -@PageDescriptor( - urls = { - @Url(mountUrl = "/admin/tasks2", matchUrlForSecurity = "/admin/tasks2") - }, - action = { - @AuthorizationAction(actionUri = PageAdminTasks.AUTHORIZATION_TASKS_ALL, - label = PageAdminTasks.AUTH_TASKS_ALL_LABEL, - description = PageAdminTasks.AUTH_TASKS_ALL_DESCRIPTION), - @AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_UI_TASKS_URL, - label = "PageTasks.auth.tasks.label", - description = "PageTasks.auth.tasks.description")}) -public class TaskTablePanel extends MainObjectListPanel { - - private static final Trace LOGGER = TraceManager.getTrace(TaskTablePanel.class); - - private static final String DOT_CLASS = TaskTablePanel.class.getName() + "."; - public static final String OPERATION_SUSPEND_TASKS = DOT_CLASS + "suspendTasks"; - public static final String OPERATION_SUSPEND_TASK = DOT_CLASS + "suspendTask"; - public static final String OPERATION_RESUME_TASKS = DOT_CLASS + "resumeTasks"; - public static final String OPERATION_RESUME_TASK = DOT_CLASS + "resumeTask"; - public static final String OPERATION_DELETE_TASKS = DOT_CLASS + "deleteTasks"; - public static final String OPERATION_RECONCILE_WORKERS = DOT_CLASS + "reconcileWorkers"; - public static final String OPERATION_DELETE_WORKERS_AND_WORK_STATE = DOT_CLASS + "deleteWorkersAndWorkState"; - public static final String OPERATION_DELETE_WORK_STATE = DOT_CLASS + "deleteWorkState"; - public static final String OPERATION_DELETE_ALL_CLOSED_TASKS = DOT_CLASS + "deleteAllClosedTasks"; - public static final String OPERATION_SCHEDULE_TASKS = DOT_CLASS + "scheduleTasks"; - private static final String OPERATION_SYNCHRONIZE_TASKS = DOT_CLASS + "synchronizeTasks"; - - public static final long WAIT_FOR_TASK_STOP = 2000L; - - public TaskTablePanel(String id, UserProfileStorage.TableId tableId, Collection> options) { - super(id, TaskType.class, tableId, options); - } - - - @Override - protected void objectDetailsPerformed(AjaxRequestTarget target, TaskType object) { - taskDetailsPerformed(target, object.getOid()); - } - - @Override - protected boolean isObjectDetailsEnabled(IModel> rowModel) { - return rowModel.getObject().getValue().getOid() != null; - } - - @Override - protected List, String>> createColumns() { - return initTaskColumns(); - } - - @Override - protected List createInlineMenu() { - return createTasksInlineMenu(true); - } - - @Override - protected List createToolbarButtonsList(String buttonId) { - List buttonsList = super.createToolbarButtonsList(buttonId); - AjaxIconButton synchronizeTasks = createSynchronizeTasksButton(buttonId); - buttonsList.add(synchronizeTasks); - return buttonsList; - } - - private AjaxIconButton createSynchronizeTasksButton(String buttonId) { - AjaxIconButton synchronize = new AjaxIconButton(buttonId, new Model<>(GuiStyleConstants.CLASS_RECONCILE_MENU_ITEM), - createStringResource("pageTasks.button.synchronizeTasks")) { - - @Override - public void onClick(AjaxRequestTarget target) { - synchronizeTasksPerformed(target); - } - }; - synchronize.add(AttributeAppender.append("class", "btn btn-default btn-margin-left btn-sm")); - return synchronize; - } - - private Task createSimpleTask(String taskName) { - return getPageBase().createSimpleTask(taskName); - } - - private TaskService getTaskService() { - return getPageBase().getTaskService(); - } - - private TaskManager getTaskManager() { - return getPageBase().getTaskManager(); - } - - private void showResult(OperationResult result) { - getPageBase().showResult(result); - } - - private WebMarkupContainer getFeedbackPanel() { - return getPageBase().getFeedbackPanel(); - } - - private void navigateToNext(Class page, PageParameters parameters) { - getPageBase().navigateToNext(page, parameters); - } - - private void synchronizeTasksPerformed(AjaxRequestTarget target) { - Task opTask = createSimpleTask(OPERATION_SYNCHRONIZE_TASKS); - OperationResult result = opTask.getResult(); - - try { - getTaskService().synchronizeTasks(opTask, result); - result.computeStatus(); - if (result.isSuccess()) { // brutal hack - the subresult's message - // contains statistics - result.recordStatus(OperationResultStatus.SUCCESS, result.getLastSubresult().getMessage()); - } - } catch (RuntimeException | SchemaException | SecurityViolationException | ExpressionEvaluationException - | ObjectNotFoundException | CommunicationException | ConfigurationException e) { - result.recordFatalError(createStringResource("pageTasks.message.synchronizeTasksPerformed.fatalError").getString(), - e); - } - showResult(result); - - // refresh feedback and table - refreshTable(TaskType.class, target); - target.add(getTable()); - } - - private void taskDetailsPerformed(AjaxRequestTarget target, String oid) { - PageParameters parameters = new PageParameters(); - parameters.add(OnePageParameterEncoder.PARAMETER, oid); - navigateToNext(PageTask.class, parameters); - } - - private List, String>> initTaskColumns() { - List, String>> columns = new ArrayList<>(); - - if (!isCollectionViewPanel()){ - columns.add(createTaskCategoryColumn()); - } - columns.addAll(initCustomTaskColumns()); - - return columns; - } - - private IColumn, String> createTaskCategoryColumn() { - return new AbstractExportableColumn, String>(createStringResource("pageTasks.task.category"), TaskType.F_CATEGORY.getLocalPart()) { - - @Override - public void populateItem(Item>> item, String componentId, - final IModel> rowModel) { - item.add(new Label(componentId, - WebComponentUtil.createCategoryNameModel(TaskTablePanel.this, new PropertyModel<>(rowModel, SelectableBeanImpl.F_VALUE + "." + TaskType.F_CATEGORY.getLocalPart())))); - } - - @Override - public IModel getDataModel(IModel> rowModel) { - return WebComponentUtil.createCategoryNameModel(TaskTablePanel.this, new PropertyModel<>(rowModel, SelectableBeanImpl.F_VALUE + "." + TaskType.F_CATEGORY.getLocalPart())); - } - }; - - } - - protected List, String>> initCustomTaskColumns() { - List, String>> columns = new ArrayList<>(); - - - columns.add(createTaskExecutionStatusColumn()); - - columns.add(createProgressColumn("pageTasks.task.progress")); - columns.add(createErrorsColumn("pageTasks.task.errors")); - - columns.add(new IconColumn>(createStringResource("pageTasks.task.status"), TaskType.F_RESULT_STATUS.getLocalPart()) { - - @Override - protected DisplayType getIconDisplayType(final IModel> rowModel) { - String icon = ""; - if (rowModel != null && rowModel.getObject() != null && rowModel.getObject().getValue().getResultStatus() != null) { - icon = OperationResultStatusPresentationProperties - .parseOperationalResultStatus(rowModel.getObject().getValue().getResultStatus()).getIcon() - + " fa-lg"; - } else { - icon = OperationResultStatusPresentationProperties.UNKNOWN.getIcon() + " fa-lg"; - } - - String title = ""; - TaskType dto = rowModel.getObject().getValue(); - - if (dto != null && dto.getResultStatus() != null) { - title = createStringResource(dto.getResultStatus()).getString(); - } else { - title = createStringResource(OperationResultStatusType.UNKNOWN).getString(); - } - return WebComponentUtil.createDisplayType(icon, "", title); - } - }); - - return columns; - - } - - private EnumPropertyColumn> createTaskExecutionStatusColumn() { - return new EnumPropertyColumn>(createStringResource("pageTasks.task.execution"), TaskType.F_EXECUTION_STATUS.getLocalPart(), SelectableBeanImpl.F_VALUE + ".executionStatus") { - - @Override - protected String translate(Enum en) { - return TaskTablePanel.this.createStringResource(en).getString(); - } - }; - } - - private AbstractExportableColumn, String> createProgressColumn(String titleKey) { - return new AbstractExportableColumn, String>(createStringResource(titleKey)) { - - @Override - public void populateItem(Item>> cellItem, String componentId, final IModel> rowModel) { - if (!TaskTypeUtil.isPartitionedMaster(rowModel.getObject().getValue())) { - cellItem.add(new Label(componentId, - (IModel) () -> getProgressDescription(rowModel.getObject()))); - } else { - cellItem.add(new LinkPanel(componentId, createStringResource("PageTasks.show.child.progress")) { - - @Override - public void onClick(AjaxRequestTarget target) { - PageParameters pageParams = new PageParameters(); - pageParams.add(OnePageParameterEncoder.PARAMETER, rowModel.getObject().getValue().getOid()); - navigateToNext(PageTask.class, pageParams); - } - }); - } - - } - - @Override - public IModel getDataModel(IModel> rowModel) { - return Model.of(getProgressDescription(rowModel.getObject())); - } - }; - } - - private AbstractColumn, String> createErrorsColumn(String titleKey) { - return new AbstractColumn, String>(createStringResource(titleKey)) { - @Override - public void populateItem(Item>> cellItem, String componentId, IModel> rowModel) { - TaskType task = rowModel.getObject().getValue(); - cellItem.add(new Label(componentId, new Model<>(TaskTypeUtil.getObjectsProcessedFailures(task, getPrismContext())))); - - } - }; - } - - private String getProgressDescription(SelectableBean task) { - Long stalledSince = getStalledSince(task.getValue()); - if (stalledSince != null) { - return getString("pageTasks.stalledSince", new Date(stalledSince).toLocaleString(), getRealProgressDescription(task)); - } else { - return getRealProgressDescription(task); - } - } - - private String getRealProgressDescription(SelectableBean task) { - if (TaskTypeUtil.isWorkStateHolder(task.getValue())) { - return getBucketedTaskProgressDescription(task.getValue()); - } else { - return getPlainTaskProgressDescription(task.getValue()); - } - } - - private String getBucketedTaskProgressDescription(TaskType taskType) { - int completeBuckets = getCompleteBuckets(taskType); - Integer expectedBuckets = getExpectedBuckets(taskType); - if (expectedBuckets == null) { - return String.valueOf(completeBuckets); - } else { - return (completeBuckets*100/expectedBuckets) + "%"; - } - } - - private Integer getExpectedBuckets(TaskType taskType) { - return taskType.getWorkState() != null ? taskType.getWorkState().getNumberOfBuckets() : null; - } - - private Integer getCompleteBuckets(TaskType taskType) { - return TaskWorkStateTypeUtil.getCompleteBucketsNumber(taskType); - } - - - private String getPlainTaskProgressDescription(TaskType taskType) { - Long currentProgress = taskType.getProgress(); - if (currentProgress == null && taskType.getExpectedTotal() == null) { - return ""; // the task handler probably does not report progress at all - } else { - StringBuilder sb = new StringBuilder(); - if (currentProgress != null){ - sb.append(currentProgress); - } else { - sb.append("0"); - } - if (taskType.getExpectedTotal() != null) { - sb.append("/").append(taskType.getExpectedTotal()); - } - return sb.toString(); - } - } - - private Long getStalledSince(TaskType taskType) { - return xgc2long(taskType.getStalledSince()); - } - - private Long xgc2long(XMLGregorianCalendar gc) { - return gc != null ? XmlTypeConverter.toMillis(gc) : null; - } - - private List createTasksInlineMenu(boolean isHeader) { - List items = new ArrayList<>(); - items.add(new ButtonInlineMenuItem(createStringResource("pageTasks.button.suspendTask")) { - private static final long serialVersionUID = 1L; - - @Override - public InlineMenuItemAction initAction() { - return new ColumnMenuAction>() { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - suspendTasksPerformed(target, getRowModel()); - } - }; - } - - @Override - public String getButtonIconCssClass() { - return GuiStyleConstants.CLASS_SUSPEND_MENU_ITEM; - } - - @Override - public IModel getConfirmationMessageModel() { - String actionName = createStringResource("pageTasks.message.suspendAction").getString(); - return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); - } - - @Override - public IModel getVisible() { - IModel> rowModel = ((ColumnMenuAction) getAction()).getRowModel(); - if (rowModel == null){ - return Model.of(Boolean.TRUE); - } - SelectableBean rowModelObj = rowModel.getObject(); - boolean visible = WebComponentUtil.canSuspendTask(rowModelObj.getValue(), TaskTablePanel.this.getPageBase()); - return Model.of(visible); - } - }); - items.add(new ButtonInlineMenuItem(createStringResource("pageTasks.button.resumeTask")) { - private static final long serialVersionUID = 1L; - - @Override - public InlineMenuItemAction initAction() { - return new ColumnMenuAction>() { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - resumeTasksPerformed(target, getRowModel()); - } - }; - } - - @Override - public String getButtonIconCssClass() { - return GuiStyleConstants.CLASS_RESUME_MENU_ITEM; - } - - @Override - public IModel getConfirmationMessageModel() { - String actionName = createStringResource("pageTasks.message.resumeAction").getString(); - return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); - } - - @Override - public IModel getVisible() { - IModel> rowModel = ((ColumnMenuAction) getAction()).getRowModel(); - if (rowModel == null){ - return Model.of(Boolean.TRUE); - } - SelectableBean rowModelObj = rowModel.getObject(); - boolean visible = WebComponentUtil.canResumeTask(rowModelObj.getValue(), TaskTablePanel.this.getPageBase()); - return Model.of(visible); - } - - }); - items.add(new ButtonInlineMenuItem(createStringResource("pageTasks.button.scheduleTask")) { - private static final long serialVersionUID = 1L; - - @Override - public InlineMenuItemAction initAction() { - return new ColumnMenuAction>() { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - scheduleTasksPerformed(target, getRowModel()); - } - }; - } - - @Override - public String getButtonIconCssClass() { - return GuiStyleConstants.CLASS_START_MENU_ITEM; - } - - @Override - public IModel getConfirmationMessageModel() { - String actionName = createStringResource("pageTasks.message.runNowAction").getString(); - return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); - } - - @Override - public IModel getVisible() { - IModel> rowModel = ((ColumnMenuAction) getAction()).getRowModel(); - if (rowModel == null){ - return Model.of(Boolean.TRUE); - } - SelectableBean rowModelObj = rowModel.getObject(); - return Model.of(WebComponentUtil.canRunNowTask(rowModelObj.getValue(), TaskTablePanel.this.getPageBase())); - } - - }); - items.add(new InlineMenuItem(createStringResource("pageTasks.button.deleteTask")) { - private static final long serialVersionUID = 1L; - - @Override - public InlineMenuItemAction initAction() { - return new ColumnMenuAction>() { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - deleteTaskConfirmedPerformed(target, getRowModel()); - } - }; - } - - @Override - public IModel getConfirmationMessageModel() { - String actionName = createStringResource("pageTasks.message.deleteAction").getString(); - return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); - } - - @Override - public boolean isHeaderMenuItem() { - return false; - } - }); - - InlineMenuItem reconcileWorkers = new InlineMenuItem(createStringResource("pageTasks.button.reconcileWorkers")) { - private static final long serialVersionUID = 1L; - - @Override - public InlineMenuItemAction initAction() { - return new ColumnMenuAction>() { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - reconcileWorkersConfirmedPerformed(target, getRowModel()); - } - }; - } - @Override - public IModel getConfirmationMessageModel() { - String actionName = createStringResource("pageTasks.message.reconcileWorkersAction").getString(); - return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); - } - - @Override - public boolean isHeaderMenuItem() { - return false; - } - }; - reconcileWorkers.setVisibilityChecker(TaskTablePanel::isCoordinator); - items.add(reconcileWorkers); - - InlineMenuItem suspendRootOnly = new InlineMenuItem(createStringResource("pageTasks.button.suspendRootOnly")) { - private static final long serialVersionUID = 1L; - - @Override - public InlineMenuItemAction initAction() { - return new ColumnMenuAction>() { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - suspendRootOnly(target, getRowModel()); - } - }; - } - - @Override - public IModel getConfirmationMessageModel() { - String actionName = createStringResource("pageTasks.message.suspendAction").getString(); - return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); - } - - @Override - public boolean isHeaderMenuItem() { - return false; - } - }; - suspendRootOnly.setVisibilityChecker(TaskTablePanel::isManageableTreeRoot); - items.add(suspendRootOnly); - - InlineMenuItem resumeRootOnly = new InlineMenuItem(createStringResource("pageTasks.button.resumeRootOnly")) { - private static final long serialVersionUID = 1L; - - @Override - public InlineMenuItemAction initAction() { - return new ColumnMenuAction>() { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - resumeRootOnly(target, getRowModel()); - } - }; - } - - @Override - public IModel getConfirmationMessageModel() { - String actionName = createStringResource("pageTasks.message.resumeAction").getString(); - return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); - } - - @Override - public boolean isHeaderMenuItem() { - return false; - } - }; - resumeRootOnly.setVisibilityChecker(TaskTablePanel::isManageableTreeRoot); - items.add(resumeRootOnly); - - InlineMenuItem deleteWorkStateAndWorkers = new InlineMenuItem(createStringResource("pageTasks.button.deleteWorkersAndWorkState")) { - private static final long serialVersionUID = 1L; - - @Override - public InlineMenuItemAction initAction() { - return new ColumnMenuAction>() { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - deleteWorkersAndWorkState(target, getRowModel()); - } - }; - } - - @Override - public IModel getConfirmationMessageModel() { - String actionName = createStringResource("pageTasks.message.deleteWorkersAndWorkState").getString(); - return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); - } - - @Override - public boolean isHeaderMenuItem() { - return false; - } - }; - deleteWorkStateAndWorkers.setVisibilityChecker(TaskTablePanel::isManageableTreeRoot); - items.add(deleteWorkStateAndWorkers); - - InlineMenuItem deleteWorkState = new InlineMenuItem(createStringResource("pageTasks.button.deleteWorkState")) { - private static final long serialVersionUID = 1L; - - @Override - public InlineMenuItemAction initAction() { - return new ColumnMenuAction>() { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - deleteWorkState(target, getRowModel()); - } - }; - } - - @Override - public IModel getConfirmationMessageModel() { - String actionName = createStringResource("pageTasks.message.deleteWorkState").getString(); - return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); - } - - @Override - public IModel getVisible() { - IModel> rowModel = ((ColumnMenuAction) getAction()).getRowModel(); - if (rowModel == null){ - return Model.of(Boolean.TRUE); - } - SelectableBean rowModelObj = rowModel.getObject(); - return Model.of(WebComponentUtil.canSuspendTask(rowModelObj.getValue(), TaskTablePanel.this.getPageBase())); - } - - }; - items.add(deleteWorkState); - - if (isHeader) { - items.add(new InlineMenuItem(createStringResource("pageTasks.button.deleteAllClosedTasks")) { - private static final long serialVersionUID = 1L; - - @Override - public InlineMenuItemAction initAction() { - return new ColumnMenuAction>() { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - deleteAllClosedTasksConfirmedPerformed(target); - } - }; - } - - @Override - public IModel getConfirmationMessageModel() { - return createStringResource("pageTasks.message.deleteAllClosedTasksConfirm"); - } - - }); - - } - return items; - } - - //region Task-level actions - //TODO unify with TaskOperationUtils - private void suspendTasksPerformed(AjaxRequestTarget target, IModel> selectedTask) { - List selectedTasks = getSelectedTasks(target, selectedTask); - if (selectedTasks == null) { - return; - } - Task opTask = createSimpleTask(OPERATION_SUSPEND_TASKS); - OperationResult result = opTask.getResult(); - try { - List plainTasks = selectedTasks.stream().filter(dto -> !isManageableTreeRoot(dto)).collect(Collectors.toList()); - List trees = selectedTasks.stream().filter(dto -> isManageableTreeRoot(dto)).collect(Collectors.toList()); - boolean suspendedPlain = suspendPlainTasks(plainTasks, result, opTask); - boolean suspendedTrees = suspendTrees(trees, result, opTask); - result.computeStatus(); - if (result.isSuccess()) { - if (suspendedPlain && suspendedTrees) { - result.recordStatus(OperationResultStatus.SUCCESS, createStringResource("pageTasks.message.suspendTasksPerformed.success").getString()); - } else { - result.recordWarning( createStringResource("pageTasks.message.suspendTasksPerformed.warning").getString()); - } - } - } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | CommunicationException | ConfigurationException e) { - result.recordFatalError(createStringResource("pageTasks.message.suspendTasksPerformed.fatalError").getString(), e); - } - showResult(result); - - //refresh feedback and table - refreshTable(TaskType.class, target); - } - - private void resumeTasksPerformed(AjaxRequestTarget target, IModel> selectedTask) { - List selectedTasks = getSelectedTasks(target, selectedTask); - if (selectedTasks == null) { - return; - } - Task opTask = createSimpleTask(OPERATION_RESUME_TASKS); - OperationResult result = opTask.getResult(); - try { - List plainTasks = selectedTasks.stream().filter(dto -> !isManageableTreeRoot(dto)).collect(Collectors.toList()); - List trees = selectedTasks.stream().filter(dto -> isManageableTreeRoot(dto)).collect(Collectors.toList()); - getTaskService().resumeTasks(getOids(plainTasks), opTask, result); - for (TaskType tree : trees) { - getTaskService().resumeTaskTree(tree.getOid(), opTask, result); - } - result.computeStatus(); - if (result.isSuccess()) { - result.recordStatus(OperationResultStatus.SUCCESS, createStringResource("pageTasks.message.resumeTasksPerformed.success").getString()); - } - } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | CommunicationException | ConfigurationException e) { - result.recordFatalError(createStringResource("pageTasks.message.resumeTasksPerformed.fatalError").getString(), e); - } - showResult(result); - - //refresh feedback and table - refreshTable(TaskType.class, target); - } - - private boolean suspendPlainTasks(List plainTasks, OperationResult result, Task opTask) - throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, - CommunicationException, ConfigurationException { - if (!plainTasks.isEmpty()) { - return getTaskService().suspendTasks(getOids(plainTasks), PageTasks.WAIT_FOR_TASK_STOP, opTask, result); - } else { - return true; - } - } - - private boolean suspendTrees(List roots, OperationResult result, Task opTask) - throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, - CommunicationException, ConfigurationException { - boolean suspended = true; - if (!roots.isEmpty()) { - for (TaskType root : roots) { - boolean s = getTaskService().suspendTaskTree(root.getOid(), PageTasks.WAIT_FOR_TASK_STOP, opTask, result); - suspended = suspended && s; - } - } - return suspended; - } - - private List getSelectedTasks(AjaxRequestTarget target, IModel> selectedTask) { - List selectedTasks = new ArrayList<>(); - if (selectedTask != null) { - selectedTasks.add(selectedTask.getObject().getValue()); - } else { - selectedTasks = getSelectedObjects(); - } - - if (selectedTasks.isEmpty()) { - getSession().warn("PagetTasks.nothing.selected"); - target.add(getFeedbackPanel()); - return null; - } - - return selectedTasks; - - } - - private void scheduleTasksPerformed(AjaxRequestTarget target, IModel> selectedTask) { - - List selectedTasks = getSelectedTasks(target, selectedTask); - if (selectedTasks == null) { - return; - } - Task opTask = createSimpleTask(OPERATION_SCHEDULE_TASKS); - OperationResult result = opTask.getResult(); - try { - getTaskService().scheduleTasksNow(getOids(selectedTasks), opTask, result); - result.computeStatus(); - if (result.isSuccess()) { - result.recordStatus(OperationResultStatus.SUCCESS, createStringResource("pageTasks.message.scheduleTasksPerformed.success").getString()); - } - } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | CommunicationException | ConfigurationException e) { - result.recordFatalError(createStringResource("pageTasks.message.scheduleTasksPerformed.fatalError").getString(), e); - } - showResult(result); - - //refresh feedback and table - refreshTable(TaskType.class, target); - - } - - private void deleteTaskConfirmedPerformed(AjaxRequestTarget target, IModel> task) { - List selectedTasks = getSelectedTasks(target, task); - if (selectedTasks == null) { - return; - } - - Task opTask = createSimpleTask(OPERATION_DELETE_TASKS); - OperationResult result = opTask.getResult(); - try { - getTaskService().suspendAndDeleteTasks(getOids(selectedTasks), WAIT_FOR_TASK_STOP, true, opTask, result); - result.computeStatus(); - if (result.isSuccess()) { - result.recordStatus(OperationResultStatus.SUCCESS, - createStringResource("pageTasks.message.deleteTaskConfirmedPerformed.success").getString()); - } - } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException - | RuntimeException | CommunicationException | ConfigurationException e) { - result.recordFatalError(createStringResource("pageTasks.message.deleteTaskConfirmedPerformed.fatalError").getString(), - e); - } - showResult(result); - - // refresh feedback and table - refreshTable(TaskType.class, target); - } - - private void reconcileWorkersConfirmedPerformed(AjaxRequestTarget target, @NotNull IModel> task) { - Task opTask = createSimpleTask(OPERATION_RECONCILE_WORKERS); - OperationResult result = opTask.getResult(); - try { - getTaskService().reconcileWorkers(task.getObject().getValue().getOid(), opTask, result); - result.computeStatus(); - if (result.isSuccess() && result.getSubresults().size() == 1) { // brutal hack: to show statistics - result.setMessage(result.getSubresults().get(0).getMessage()); - } - } catch (ObjectAlreadyExistsException | ObjectNotFoundException | SchemaException | SecurityViolationException - | ExpressionEvaluationException | RuntimeException | CommunicationException | ConfigurationException e) { - result.recordFatalError( - createStringResource("pageTasks.message.reconcileWorkersConfirmedPerformed.fatalError").getString(), e); - } - showResult(result); - - refreshTable(TaskType.class, target); - } - - private void suspendRootOnly(AjaxRequestTarget target, @NotNull IModel> task) { - Task opTask = createSimpleTask(OPERATION_SUSPEND_TASK); - OperationResult result = opTask.getResult(); - try { - getTaskService().suspendTasks(Collections.singleton(task.getObject().getValue().getOid()), WAIT_FOR_TASK_STOP, opTask, result); - // TODO check whether the suspension was complete - result.computeStatus(); - } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException - | RuntimeException | CommunicationException | ConfigurationException e) { - result.recordFatalError(createStringResource("pageTasks.message.suspendRootOnly.fatalError").getString(), e); - } - showResult(result); - - refreshTable(TaskType.class, target); - } - - private void resumeRootOnly(AjaxRequestTarget target, @NotNull IModel> task) { - Task opTask = createSimpleTask(OPERATION_RESUME_TASK); - OperationResult result = opTask.getResult(); - try { - getTaskService().resumeTasks(Collections.singleton(task.getObject().getValue().getOid()), opTask, result); - result.computeStatus(); - } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException - | RuntimeException | CommunicationException | ConfigurationException e) { - result.recordFatalError(createStringResource("pageTasks.message.resumeRootOnly.fatalError").getString(), e); - } - showResult(result); - - refreshTable(TaskType.class, target); - } - - private void deleteWorkersAndWorkState(AjaxRequestTarget target, @NotNull IModel> task) { - Task opTask = createSimpleTask(OPERATION_DELETE_WORKERS_AND_WORK_STATE); - OperationResult result = opTask.getResult(); - try { - getTaskService().deleteWorkersAndWorkState(task.getObject().getValue().getOid(), true, WAIT_FOR_TASK_STOP, opTask, result); - result.computeStatus(); - } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException - | RuntimeException | CommunicationException | ConfigurationException e) { - result.recordFatalError(createStringResource("pageTasks.message.deleteWorkersAndWorkState.fatalError").getString(), - e); - } - showResult(result); - - refreshTable(TaskType.class, target); - } - - private void deleteWorkState(AjaxRequestTarget target, @NotNull IModel> task) { - Task opTask = createSimpleTask(OPERATION_DELETE_WORK_STATE); - OperationResult result = opTask.getResult(); - try { - getTaskService().deleteWorkersAndWorkState(task.getObject().getValue().getOid(), false, WAIT_FOR_TASK_STOP, opTask, result); - result.computeStatus(); - } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException - | RuntimeException | CommunicationException | ConfigurationException e) { - result.recordFatalError(createStringResource("pageTasks.message.deleteWorkState.fatalError").getString(), - e); - } - showResult(result); - - refreshTable(TaskType.class, target); - } - - private void deleteAllClosedTasksConfirmedPerformed(AjaxRequestTarget target) { - OperationResult launchResult = new OperationResult(OPERATION_DELETE_ALL_CLOSED_TASKS); - Task task = createSimpleTask(OPERATION_DELETE_ALL_CLOSED_TASKS); - - task.setHandlerUri(ModelPublicConstants.CLEANUP_TASK_HANDLER_URI); - task.setName("Closed tasks cleanup"); - - try { - CleanupPolicyType policy = new CleanupPolicyType(); - policy.setMaxAge(XmlTypeConverter.createDuration(0)); - - CleanupPoliciesType policies = new CleanupPoliciesType(getPrismContext()); - policies.setClosedTasks(policy); - task.setExtensionContainerValue(SchemaConstants.MODEL_EXTENSION_CLEANUP_POLICIES, policies); - } catch (SchemaException e) { - LOGGER.error("Error dealing with schema (task {})", task, e); - launchResult.recordFatalError( - createStringResource("pageTasks.message.deleteAllClosedTasksConfirmedPerformed.fatalError").getString(), e); - throw new IllegalStateException("Error dealing with schema", e); - } - - getTaskManager().switchToBackground(task, launchResult); - launchResult.setBackgroundTaskOid(task.getOid()); - - showResult(launchResult); - target.add(getFeedbackPanel()); - } - - private IModel getTaskConfirmationMessageModel(ColumnMenuAction action, String actionName) { - if (action.getRowModel() == null) { - return createStringResource("pageTasks.message.confirmationMessageForMultipleTaskObject", actionName, 1); -// WebComponentUtil.getSelectedData(()).size()); - } else { - String objectName = ((SelectableBean) (action.getRowModel().getObject())).getValue().getName().getOrig(); - return createStringResource("pageTasks.message.confirmationMessageForSingleTaskObject", actionName, objectName); - } - - } - - // must be static, otherwise JVM crashes (probably because of some wicket serialization issues) - private static boolean isCoordinator(IModel rowModel, boolean isHeader) { - SelectableBean dto = getDto(rowModel, isHeader); - return dto != null && TaskTypeUtil.isCoordinator(dto.getValue()); - } - - - // must be static, otherwise JVM crashes (probably because of some wicket serialization issues) - private static boolean isManageableTreeRoot(IModel rowModel, boolean isHeader) { - SelectableBean dto = getDto(rowModel, isHeader); - return dto != null && isManageableTreeRoot(dto.getValue()); - } - - private static boolean isManageableTreeRoot(TaskType taskType) { - return TaskTypeUtil.isCoordinator(taskType) || TaskTypeUtil.isPartitionedMaster(taskType); - } - - private static SelectableBean getDto(IModel rowModel, boolean isHeader) { - if (rowModel != null && !isHeader) { - Object object = rowModel.getObject(); - if (object instanceof SelectableBean) { - return (SelectableBean) object; - } - } - return null; - } - - public static List getOids(List taskDtoList) { - List retval = new ArrayList<>(); - for (TaskType taskDto : taskDtoList) { - retval.add(taskDto.getOid()); - } - return retval; - } -} +/* + * Copyright (c) 2010-2019 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.web.page.admin.server; + +import com.evolveum.midpoint.gui.api.GuiStyleConstants; +import com.evolveum.midpoint.gui.api.component.MainObjectListPanel; +import com.evolveum.midpoint.gui.api.model.ReadOnlyModel; +import com.evolveum.midpoint.gui.api.util.WebComponentUtil; +import com.evolveum.midpoint.model.api.ModelPublicConstants; +import com.evolveum.midpoint.model.api.TaskService; +import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.SelectorOptions; +import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.result.OperationResultStatus; +import com.evolveum.midpoint.schema.util.TaskTypeUtil; +import com.evolveum.midpoint.schema.util.TaskWorkStateTypeUtil; +import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.task.api.TaskManager; +import com.evolveum.midpoint.util.exception.*; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.web.application.AuthorizationAction; +import com.evolveum.midpoint.web.application.PageDescriptor; +import com.evolveum.midpoint.web.application.Url; +import com.evolveum.midpoint.web.component.AjaxIconButton; +import com.evolveum.midpoint.web.component.data.column.*; +import com.evolveum.midpoint.web.component.menu.cog.ButtonInlineMenuItem; +import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem; +import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItemAction; +import com.evolveum.midpoint.web.component.util.SelectableBean; +import com.evolveum.midpoint.web.component.util.SelectableBeanImpl; +import com.evolveum.midpoint.web.page.admin.server.dto.OperationResultStatusPresentationProperties; +import com.evolveum.midpoint.web.session.UserProfileStorage; +import com.evolveum.midpoint.web.util.OnePageParameterEncoder; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; + +import org.apache.wicket.Component; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.behavior.AttributeAppender; +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.extensions.markup.html.repeater.data.table.IColumn; +import org.apache.wicket.extensions.markup.html.repeater.data.table.export.AbstractExportableColumn; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.jetbrains.annotations.NotNull; + +import javax.xml.datatype.XMLGregorianCalendar; +import java.util.*; +import java.util.stream.Collectors; + +@PageDescriptor( + urls = { + @Url(mountUrl = "/admin/tasks2", matchUrlForSecurity = "/admin/tasks2") + }, + action = { + @AuthorizationAction(actionUri = PageAdminTasks.AUTHORIZATION_TASKS_ALL, + label = PageAdminTasks.AUTH_TASKS_ALL_LABEL, + description = PageAdminTasks.AUTH_TASKS_ALL_DESCRIPTION), + @AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_UI_TASKS_URL, + label = "PageTasks.auth.tasks.label", + description = "PageTasks.auth.tasks.description")}) +public class TaskTablePanel extends MainObjectListPanel { + + private static final Trace LOGGER = TraceManager.getTrace(TaskTablePanel.class); + + private static final String DOT_CLASS = TaskTablePanel.class.getName() + "."; + public static final String OPERATION_SUSPEND_TASKS = DOT_CLASS + "suspendTasks"; + public static final String OPERATION_SUSPEND_TASK = DOT_CLASS + "suspendTask"; + public static final String OPERATION_RESUME_TASKS = DOT_CLASS + "resumeTasks"; + public static final String OPERATION_RESUME_TASK = DOT_CLASS + "resumeTask"; + public static final String OPERATION_DELETE_TASKS = DOT_CLASS + "deleteTasks"; + public static final String OPERATION_RECONCILE_WORKERS = DOT_CLASS + "reconcileWorkers"; + public static final String OPERATION_DELETE_WORKERS_AND_WORK_STATE = DOT_CLASS + "deleteWorkersAndWorkState"; + public static final String OPERATION_DELETE_WORK_STATE = DOT_CLASS + "deleteWorkState"; + public static final String OPERATION_DELETE_ALL_CLOSED_TASKS = DOT_CLASS + "deleteAllClosedTasks"; + public static final String OPERATION_SCHEDULE_TASKS = DOT_CLASS + "scheduleTasks"; + private static final String OPERATION_SYNCHRONIZE_TASKS = DOT_CLASS + "synchronizeTasks"; + + public static final long WAIT_FOR_TASK_STOP = 2000L; + + public TaskTablePanel(String id, UserProfileStorage.TableId tableId, Collection> options) { + super(id, TaskType.class, tableId, options); + } + + + @Override + protected void objectDetailsPerformed(AjaxRequestTarget target, TaskType object) { + taskDetailsPerformed(target, object.getOid()); + } + + @Override + protected boolean isObjectDetailsEnabled(IModel> rowModel) { + return rowModel.getObject().getValue().getOid() != null; + } + + @Override + protected List, String>> createColumns() { + return initTaskColumns(); + } + + @Override + protected List createInlineMenu() { + return createTasksInlineMenu(true); + } + + @Override + protected List createToolbarButtonsList(String buttonId) { + List buttonsList = super.createToolbarButtonsList(buttonId); + AjaxIconButton synchronizeTasks = createSynchronizeTasksButton(buttonId); + buttonsList.add(synchronizeTasks); + return buttonsList; + } + + private AjaxIconButton createSynchronizeTasksButton(String buttonId) { + AjaxIconButton synchronize = new AjaxIconButton(buttonId, new Model<>(GuiStyleConstants.CLASS_RECONCILE_MENU_ITEM), + createStringResource("pageTasks.button.synchronizeTasks")) { + + @Override + public void onClick(AjaxRequestTarget target) { + synchronizeTasksPerformed(target); + } + }; + synchronize.add(AttributeAppender.append("class", "btn btn-default btn-margin-left btn-sm")); + return synchronize; + } + + private Task createSimpleTask(String taskName) { + return getPageBase().createSimpleTask(taskName); + } + + private TaskService getTaskService() { + return getPageBase().getTaskService(); + } + + private TaskManager getTaskManager() { + return getPageBase().getTaskManager(); + } + + private void showResult(OperationResult result) { + getPageBase().showResult(result); + } + + private WebMarkupContainer getFeedbackPanel() { + return getPageBase().getFeedbackPanel(); + } + + private void navigateToNext(Class page, PageParameters parameters) { + getPageBase().navigateToNext(page, parameters); + } + + private void synchronizeTasksPerformed(AjaxRequestTarget target) { + Task opTask = createSimpleTask(OPERATION_SYNCHRONIZE_TASKS); + OperationResult result = opTask.getResult(); + + try { + getTaskService().synchronizeTasks(opTask, result); + result.computeStatus(); + if (result.isSuccess()) { // brutal hack - the subresult's message + // contains statistics + result.recordStatus(OperationResultStatus.SUCCESS, result.getLastSubresult().getMessage()); + } + } catch (RuntimeException | SchemaException | SecurityViolationException | ExpressionEvaluationException + | ObjectNotFoundException | CommunicationException | ConfigurationException e) { + result.recordFatalError(createStringResource("pageTasks.message.synchronizeTasksPerformed.fatalError").getString(), + e); + } + showResult(result); + + // refresh feedback and table + refreshTable(TaskType.class, target); + target.add(getTable()); + } + + private void taskDetailsPerformed(AjaxRequestTarget target, String oid) { + PageParameters parameters = new PageParameters(); + parameters.add(OnePageParameterEncoder.PARAMETER, oid); + navigateToNext(PageTask.class, parameters); + } + + private List, String>> initTaskColumns() { + List, String>> columns = new ArrayList<>(); + + if (!isCollectionViewPanel()){ + columns.add(createTaskCategoryColumn()); + } + columns.addAll(initCustomTaskColumns()); + + return columns; + } + + private IColumn, String> createTaskCategoryColumn() { + return new AbstractExportableColumn, String>(createStringResource("pageTasks.task.category"), TaskType.F_CATEGORY.getLocalPart()) { + + @Override + public void populateItem(Item>> item, String componentId, + final IModel> rowModel) { + item.add(new Label(componentId, + WebComponentUtil.createCategoryNameModel(TaskTablePanel.this, new PropertyModel<>(rowModel, SelectableBeanImpl.F_VALUE + "." + TaskType.F_CATEGORY.getLocalPart())))); + } + + @Override + public IModel getDataModel(IModel> rowModel) { + return WebComponentUtil.createCategoryNameModel(TaskTablePanel.this, new PropertyModel<>(rowModel, SelectableBeanImpl.F_VALUE + "." + TaskType.F_CATEGORY.getLocalPart())); + } + }; + + } + + protected List, String>> initCustomTaskColumns() { + List, String>> columns = new ArrayList<>(); + + + columns.add(createTaskExecutionStatusColumn()); + + columns.add(createProgressColumn("pageTasks.task.progress")); + columns.add(createErrorsColumn("pageTasks.task.errors")); + + columns.add(new IconColumn>(createStringResource("pageTasks.task.status"), TaskType.F_RESULT_STATUS.getLocalPart()) { + + @Override + protected DisplayType getIconDisplayType(final IModel> rowModel) { + String icon = ""; + if (rowModel != null && rowModel.getObject() != null && rowModel.getObject().getValue().getResultStatus() != null) { + icon = OperationResultStatusPresentationProperties + .parseOperationalResultStatus(rowModel.getObject().getValue().getResultStatus()).getIcon() + + " fa-lg"; + } else { + icon = OperationResultStatusPresentationProperties.UNKNOWN.getIcon() + " fa-lg"; + } + + String title = ""; + TaskType dto = rowModel.getObject().getValue(); + + if (dto != null && dto.getResultStatus() != null) { + title = createStringResource(dto.getResultStatus()).getString(); + } else { + title = createStringResource(OperationResultStatusType.UNKNOWN).getString(); + } + return WebComponentUtil.createDisplayType(icon, "", title); + } + }); + + return columns; + + } + + private EnumPropertyColumn> createTaskExecutionStatusColumn() { + return new EnumPropertyColumn>(createStringResource("pageTasks.task.execution"), TaskType.F_EXECUTION_STATUS.getLocalPart(), SelectableBeanImpl.F_VALUE + ".executionStatus") { + + @Override + protected String translate(Enum en) { + return TaskTablePanel.this.createStringResource(en).getString(); + } + }; + } + + private AbstractExportableColumn, String> createProgressColumn(String titleKey) { + return new AbstractExportableColumn, String>(createStringResource(titleKey)) { + + @Override + public void populateItem(Item>> cellItem, String componentId, final IModel> rowModel) { + if (!TaskTypeUtil.isPartitionedMaster(rowModel.getObject().getValue())) { + cellItem.add(new Label(componentId, + (IModel) () -> getProgressDescription(rowModel.getObject()))); + } else { + cellItem.add(new LinkPanel(componentId, createStringResource("PageTasks.show.child.progress")) { + + @Override + public void onClick(AjaxRequestTarget target) { + PageParameters pageParams = new PageParameters(); + pageParams.add(OnePageParameterEncoder.PARAMETER, rowModel.getObject().getValue().getOid()); + navigateToNext(PageTask.class, pageParams); + } + }); + } + + } + + @Override + public IModel getDataModel(IModel> rowModel) { + return Model.of(getProgressDescription(rowModel.getObject())); + } + }; + } + + private AbstractColumn, String> createErrorsColumn(String titleKey) { + return new AbstractColumn, String>(createStringResource(titleKey)) { + @Override + public void populateItem(Item>> cellItem, String componentId, IModel> rowModel) { + TaskType task = rowModel.getObject().getValue(); + cellItem.add(new Label(componentId, new Model<>(TaskTypeUtil.getObjectsProcessedFailures(task, getPrismContext())))); + + } + }; + } + + private String getProgressDescription(SelectableBean task) { + Long stalledSince = getStalledSince(task.getValue()); + if (stalledSince != null) { + return getString("pageTasks.stalledSince", new Date(stalledSince).toLocaleString(), getRealProgressDescription(task)); + } else { + return getRealProgressDescription(task); + } + } + + private String getRealProgressDescription(SelectableBean task) { + if (TaskTypeUtil.isWorkStateHolder(task.getValue())) { + return getBucketedTaskProgressDescription(task.getValue()); + } else { + return getPlainTaskProgressDescription(task.getValue()); + } + } + + private String getBucketedTaskProgressDescription(TaskType taskType) { + int completeBuckets = getCompleteBuckets(taskType); + Integer expectedBuckets = getExpectedBuckets(taskType); + if (expectedBuckets == null) { + return String.valueOf(completeBuckets); + } else { + return (completeBuckets*100/expectedBuckets) + "%"; + } + } + + private Integer getExpectedBuckets(TaskType taskType) { + return taskType.getWorkState() != null ? taskType.getWorkState().getNumberOfBuckets() : null; + } + + private Integer getCompleteBuckets(TaskType taskType) { + return TaskWorkStateTypeUtil.getCompleteBucketsNumber(taskType); + } + + + private String getPlainTaskProgressDescription(TaskType taskType) { + Long currentProgress = taskType.getProgress(); + if (currentProgress == null && taskType.getExpectedTotal() == null) { + return ""; // the task handler probably does not report progress at all + } else { + StringBuilder sb = new StringBuilder(); + if (currentProgress != null){ + sb.append(currentProgress); + } else { + sb.append("0"); + } + if (taskType.getExpectedTotal() != null) { + sb.append("/").append(taskType.getExpectedTotal()); + } + return sb.toString(); + } + } + + private Long getStalledSince(TaskType taskType) { + return xgc2long(taskType.getStalledSince()); + } + + private Long xgc2long(XMLGregorianCalendar gc) { + return gc != null ? XmlTypeConverter.toMillis(gc) : null; + } + + private List createTasksInlineMenu(boolean isHeader) { + List items = new ArrayList<>(); + items.add(new ButtonInlineMenuItem(createStringResource("pageTasks.button.suspendTask")) { + private static final long serialVersionUID = 1L; + + @Override + public InlineMenuItemAction initAction() { + return new ColumnMenuAction>() { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + suspendTasksPerformed(target, getRowModel()); + } + }; + } + + @Override + public String getButtonIconCssClass() { + return GuiStyleConstants.CLASS_SUSPEND_MENU_ITEM; + } + + @Override + public IModel getConfirmationMessageModel() { + String actionName = createStringResource("pageTasks.message.suspendAction").getString(); + return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); + } + + @Override + public IModel getVisible() { + IModel> rowModel = ((ColumnMenuAction) getAction()).getRowModel(); + if (rowModel == null){ + return Model.of(Boolean.TRUE); + } + SelectableBean rowModelObj = rowModel.getObject(); + boolean visible = WebComponentUtil.canSuspendTask(rowModelObj.getValue(), TaskTablePanel.this.getPageBase()); + return Model.of(visible); + } + }); + items.add(new ButtonInlineMenuItem(createStringResource("pageTasks.button.resumeTask")) { + private static final long serialVersionUID = 1L; + + @Override + public InlineMenuItemAction initAction() { + return new ColumnMenuAction>() { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + resumeTasksPerformed(target, getRowModel()); + } + }; + } + + @Override + public String getButtonIconCssClass() { + return GuiStyleConstants.CLASS_RESUME_MENU_ITEM; + } + + @Override + public IModel getConfirmationMessageModel() { + String actionName = createStringResource("pageTasks.message.resumeAction").getString(); + return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); + } + + @Override + public IModel getVisible() { + IModel> rowModel = ((ColumnMenuAction) getAction()).getRowModel(); + if (rowModel == null){ + return Model.of(Boolean.TRUE); + } + SelectableBean rowModelObj = rowModel.getObject(); + boolean visible = WebComponentUtil.canResumeTask(rowModelObj.getValue(), TaskTablePanel.this.getPageBase()); + return Model.of(visible); + } + + }); + items.add(new ButtonInlineMenuItem(createStringResource("pageTasks.button.scheduleTask")) { + private static final long serialVersionUID = 1L; + + @Override + public InlineMenuItemAction initAction() { + return new ColumnMenuAction>() { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + scheduleTasksPerformed(target, getRowModel()); + } + }; + } + + @Override + public String getButtonIconCssClass() { + return GuiStyleConstants.CLASS_START_MENU_ITEM; + } + + @Override + public IModel getConfirmationMessageModel() { + String actionName = createStringResource("pageTasks.message.runNowAction").getString(); + return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); + } + + @Override + public IModel getVisible() { + IModel> rowModel = ((ColumnMenuAction) getAction()).getRowModel(); + if (rowModel == null){ + return Model.of(Boolean.TRUE); + } + SelectableBean rowModelObj = rowModel.getObject(); + return Model.of(WebComponentUtil.canRunNowTask(rowModelObj.getValue(), TaskTablePanel.this.getPageBase())); + } + + }); + items.add(new InlineMenuItem(createStringResource("pageTasks.button.deleteTask")) { + private static final long serialVersionUID = 1L; + + @Override + public InlineMenuItemAction initAction() { + return new ColumnMenuAction>() { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + deleteTaskConfirmedPerformed(target, getRowModel()); + } + }; + } + + @Override + public IModel getConfirmationMessageModel() { + String actionName = createStringResource("pageTasks.message.deleteAction").getString(); + return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); + } + + }); + + InlineMenuItem reconcileWorkers = new InlineMenuItem(createStringResource("pageTasks.button.reconcileWorkers")) { + private static final long serialVersionUID = 1L; + + @Override + public InlineMenuItemAction initAction() { + return new ColumnMenuAction>() { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + reconcileWorkersConfirmedPerformed(target, getRowModel()); + } + }; + } + @Override + public IModel getConfirmationMessageModel() { + String actionName = createStringResource("pageTasks.message.reconcileWorkersAction").getString(); + return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); + } + + @Override + public boolean isHeaderMenuItem() { + return false; + } + }; + reconcileWorkers.setVisibilityChecker(TaskTablePanel::isCoordinator); + items.add(reconcileWorkers); + + InlineMenuItem suspendRootOnly = new InlineMenuItem(createStringResource("pageTasks.button.suspendRootOnly")) { + private static final long serialVersionUID = 1L; + + @Override + public InlineMenuItemAction initAction() { + return new ColumnMenuAction>() { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + suspendRootOnly(target, getRowModel()); + } + }; + } + + @Override + public IModel getConfirmationMessageModel() { + String actionName = createStringResource("pageTasks.message.suspendAction").getString(); + return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); + } + + @Override + public boolean isHeaderMenuItem() { + return false; + } + }; + suspendRootOnly.setVisibilityChecker(TaskTablePanel::isManageableTreeRoot); + items.add(suspendRootOnly); + + InlineMenuItem resumeRootOnly = new InlineMenuItem(createStringResource("pageTasks.button.resumeRootOnly")) { + private static final long serialVersionUID = 1L; + + @Override + public InlineMenuItemAction initAction() { + return new ColumnMenuAction>() { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + resumeRootOnly(target, getRowModel()); + } + }; + } + + @Override + public IModel getConfirmationMessageModel() { + String actionName = createStringResource("pageTasks.message.resumeAction").getString(); + return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); + } + + @Override + public boolean isHeaderMenuItem() { + return false; + } + }; + resumeRootOnly.setVisibilityChecker(TaskTablePanel::isManageableTreeRoot); + items.add(resumeRootOnly); + + InlineMenuItem deleteWorkStateAndWorkers = new InlineMenuItem(createStringResource("pageTasks.button.deleteWorkersAndWorkState")) { + private static final long serialVersionUID = 1L; + + @Override + public InlineMenuItemAction initAction() { + return new ColumnMenuAction>() { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + deleteWorkersAndWorkState(target, getRowModel()); + } + }; + } + + @Override + public IModel getConfirmationMessageModel() { + String actionName = createStringResource("pageTasks.message.deleteWorkersAndWorkState").getString(); + return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); + } + + @Override + public boolean isHeaderMenuItem() { + return false; + } + }; + deleteWorkStateAndWorkers.setVisibilityChecker(TaskTablePanel::isManageableTreeRoot); + items.add(deleteWorkStateAndWorkers); + + InlineMenuItem deleteWorkState = new InlineMenuItem(createStringResource("pageTasks.button.deleteWorkState")) { + private static final long serialVersionUID = 1L; + + @Override + public InlineMenuItemAction initAction() { + return new ColumnMenuAction>() { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + deleteWorkState(target, getRowModel()); + } + }; + } + + @Override + public IModel getConfirmationMessageModel() { + String actionName = createStringResource("pageTasks.message.deleteWorkState").getString(); + return TaskTablePanel.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); + } + + @Override + public IModel getVisible() { + IModel> rowModel = ((ColumnMenuAction) getAction()).getRowModel(); + if (rowModel == null){ + return Model.of(Boolean.TRUE); + } + SelectableBean rowModelObj = rowModel.getObject(); + return Model.of(WebComponentUtil.canSuspendTask(rowModelObj.getValue(), TaskTablePanel.this.getPageBase())); + } + + }; + items.add(deleteWorkState); + + if (isHeader) { + items.add(new InlineMenuItem(createStringResource("pageTasks.button.deleteAllClosedTasks")) { + private static final long serialVersionUID = 1L; + + @Override + public InlineMenuItemAction initAction() { + return new ColumnMenuAction>() { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + deleteAllClosedTasksConfirmedPerformed(target); + } + }; + } + + @Override + public IModel getConfirmationMessageModel() { + return createStringResource("pageTasks.message.deleteAllClosedTasksConfirm"); + } + + }); + + } + return items; + } + + //region Task-level actions + //TODO unify with TaskOperationUtils + private void suspendTasksPerformed(AjaxRequestTarget target, IModel> selectedTask) { + List selectedTasks = getSelectedTasks(target, selectedTask); + if (selectedTasks == null) { + return; + } + Task opTask = createSimpleTask(OPERATION_SUSPEND_TASKS); + OperationResult result = opTask.getResult(); + try { + List plainTasks = selectedTasks.stream().filter(dto -> !isManageableTreeRoot(dto)).collect(Collectors.toList()); + List trees = selectedTasks.stream().filter(dto -> isManageableTreeRoot(dto)).collect(Collectors.toList()); + boolean suspendedPlain = suspendPlainTasks(plainTasks, result, opTask); + boolean suspendedTrees = suspendTrees(trees, result, opTask); + result.computeStatus(); + if (result.isSuccess()) { + if (suspendedPlain && suspendedTrees) { + result.recordStatus(OperationResultStatus.SUCCESS, createStringResource("pageTasks.message.suspendTasksPerformed.success").getString()); + } else { + result.recordWarning( createStringResource("pageTasks.message.suspendTasksPerformed.warning").getString()); + } + } + } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | CommunicationException | ConfigurationException e) { + result.recordFatalError(createStringResource("pageTasks.message.suspendTasksPerformed.fatalError").getString(), e); + } + showResult(result); + + //refresh feedback and table + refreshTable(TaskType.class, target); + } + + private void resumeTasksPerformed(AjaxRequestTarget target, IModel> selectedTask) { + List selectedTasks = getSelectedTasks(target, selectedTask); + if (selectedTasks == null) { + return; + } + Task opTask = createSimpleTask(OPERATION_RESUME_TASKS); + OperationResult result = opTask.getResult(); + try { + List plainTasks = selectedTasks.stream().filter(dto -> !isManageableTreeRoot(dto)).collect(Collectors.toList()); + List trees = selectedTasks.stream().filter(dto -> isManageableTreeRoot(dto)).collect(Collectors.toList()); + getTaskService().resumeTasks(getOids(plainTasks), opTask, result); + for (TaskType tree : trees) { + getTaskService().resumeTaskTree(tree.getOid(), opTask, result); + } + result.computeStatus(); + if (result.isSuccess()) { + result.recordStatus(OperationResultStatus.SUCCESS, createStringResource("pageTasks.message.resumeTasksPerformed.success").getString()); + } + } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | CommunicationException | ConfigurationException e) { + result.recordFatalError(createStringResource("pageTasks.message.resumeTasksPerformed.fatalError").getString(), e); + } + showResult(result); + + //refresh feedback and table + refreshTable(TaskType.class, target); + } + + private boolean suspendPlainTasks(List plainTasks, OperationResult result, Task opTask) + throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, + CommunicationException, ConfigurationException { + if (!plainTasks.isEmpty()) { + return getTaskService().suspendTasks(getOids(plainTasks), PageTasks.WAIT_FOR_TASK_STOP, opTask, result); + } else { + return true; + } + } + + private boolean suspendTrees(List roots, OperationResult result, Task opTask) + throws SecurityViolationException, ObjectNotFoundException, SchemaException, ExpressionEvaluationException, + CommunicationException, ConfigurationException { + boolean suspended = true; + if (!roots.isEmpty()) { + for (TaskType root : roots) { + boolean s = getTaskService().suspendTaskTree(root.getOid(), PageTasks.WAIT_FOR_TASK_STOP, opTask, result); + suspended = suspended && s; + } + } + return suspended; + } + + private List getSelectedTasks(AjaxRequestTarget target, IModel> selectedTask) { + List selectedTasks = new ArrayList<>(); + if (selectedTask != null) { + selectedTasks.add(selectedTask.getObject().getValue()); + } else { + selectedTasks = getSelectedObjects(); + } + + if (selectedTasks.isEmpty()) { + getSession().warn("PagetTasks.nothing.selected"); + target.add(getFeedbackPanel()); + return null; + } + + return selectedTasks; + + } + + private void scheduleTasksPerformed(AjaxRequestTarget target, IModel> selectedTask) { + + List selectedTasks = getSelectedTasks(target, selectedTask); + if (selectedTasks == null) { + return; + } + Task opTask = createSimpleTask(OPERATION_SCHEDULE_TASKS); + OperationResult result = opTask.getResult(); + try { + getTaskService().scheduleTasksNow(getOids(selectedTasks), opTask, result); + result.computeStatus(); + if (result.isSuccess()) { + result.recordStatus(OperationResultStatus.SUCCESS, createStringResource("pageTasks.message.scheduleTasksPerformed.success").getString()); + } + } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | CommunicationException | ConfigurationException e) { + result.recordFatalError(createStringResource("pageTasks.message.scheduleTasksPerformed.fatalError").getString(), e); + } + showResult(result); + + //refresh feedback and table + refreshTable(TaskType.class, target); + + } + + private void deleteTaskConfirmedPerformed(AjaxRequestTarget target, IModel> task) { + List selectedTasks = getSelectedTasks(target, task); + if (selectedTasks == null) { + return; + } + + Task opTask = createSimpleTask(OPERATION_DELETE_TASKS); + OperationResult result = opTask.getResult(); + try { + getTaskService().suspendAndDeleteTasks(getOids(selectedTasks), WAIT_FOR_TASK_STOP, true, opTask, result); + result.computeStatus(); + if (result.isSuccess()) { + result.recordStatus(OperationResultStatus.SUCCESS, + createStringResource("pageTasks.message.deleteTaskConfirmedPerformed.success").getString()); + } + } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException + | RuntimeException | CommunicationException | ConfigurationException e) { + result.recordFatalError(createStringResource("pageTasks.message.deleteTaskConfirmedPerformed.fatalError").getString(), + e); + } + showResult(result); + + // refresh feedback and table + refreshTable(TaskType.class, target); + } + + private void reconcileWorkersConfirmedPerformed(AjaxRequestTarget target, @NotNull IModel> task) { + Task opTask = createSimpleTask(OPERATION_RECONCILE_WORKERS); + OperationResult result = opTask.getResult(); + try { + getTaskService().reconcileWorkers(task.getObject().getValue().getOid(), opTask, result); + result.computeStatus(); + if (result.isSuccess() && result.getSubresults().size() == 1) { // brutal hack: to show statistics + result.setMessage(result.getSubresults().get(0).getMessage()); + } + } catch (ObjectAlreadyExistsException | ObjectNotFoundException | SchemaException | SecurityViolationException + | ExpressionEvaluationException | RuntimeException | CommunicationException | ConfigurationException e) { + result.recordFatalError( + createStringResource("pageTasks.message.reconcileWorkersConfirmedPerformed.fatalError").getString(), e); + } + showResult(result); + + refreshTable(TaskType.class, target); + } + + private void suspendRootOnly(AjaxRequestTarget target, @NotNull IModel> task) { + Task opTask = createSimpleTask(OPERATION_SUSPEND_TASK); + OperationResult result = opTask.getResult(); + try { + getTaskService().suspendTasks(Collections.singleton(task.getObject().getValue().getOid()), WAIT_FOR_TASK_STOP, opTask, result); + // TODO check whether the suspension was complete + result.computeStatus(); + } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException + | RuntimeException | CommunicationException | ConfigurationException e) { + result.recordFatalError(createStringResource("pageTasks.message.suspendRootOnly.fatalError").getString(), e); + } + showResult(result); + + refreshTable(TaskType.class, target); + } + + private void resumeRootOnly(AjaxRequestTarget target, @NotNull IModel> task) { + Task opTask = createSimpleTask(OPERATION_RESUME_TASK); + OperationResult result = opTask.getResult(); + try { + getTaskService().resumeTasks(Collections.singleton(task.getObject().getValue().getOid()), opTask, result); + result.computeStatus(); + } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException + | RuntimeException | CommunicationException | ConfigurationException e) { + result.recordFatalError(createStringResource("pageTasks.message.resumeRootOnly.fatalError").getString(), e); + } + showResult(result); + + refreshTable(TaskType.class, target); + } + + private void deleteWorkersAndWorkState(AjaxRequestTarget target, @NotNull IModel> task) { + Task opTask = createSimpleTask(OPERATION_DELETE_WORKERS_AND_WORK_STATE); + OperationResult result = opTask.getResult(); + try { + getTaskService().deleteWorkersAndWorkState(task.getObject().getValue().getOid(), true, WAIT_FOR_TASK_STOP, opTask, result); + result.computeStatus(); + } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException + | RuntimeException | CommunicationException | ConfigurationException e) { + result.recordFatalError(createStringResource("pageTasks.message.deleteWorkersAndWorkState.fatalError").getString(), + e); + } + showResult(result); + + refreshTable(TaskType.class, target); + } + + private void deleteWorkState(AjaxRequestTarget target, @NotNull IModel> task) { + Task opTask = createSimpleTask(OPERATION_DELETE_WORK_STATE); + OperationResult result = opTask.getResult(); + try { + getTaskService().deleteWorkersAndWorkState(task.getObject().getValue().getOid(), false, WAIT_FOR_TASK_STOP, opTask, result); + result.computeStatus(); + } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException + | RuntimeException | CommunicationException | ConfigurationException e) { + result.recordFatalError(createStringResource("pageTasks.message.deleteWorkState.fatalError").getString(), + e); + } + showResult(result); + + refreshTable(TaskType.class, target); + } + + private void deleteAllClosedTasksConfirmedPerformed(AjaxRequestTarget target) { + OperationResult launchResult = new OperationResult(OPERATION_DELETE_ALL_CLOSED_TASKS); + Task task = createSimpleTask(OPERATION_DELETE_ALL_CLOSED_TASKS); + + task.setHandlerUri(ModelPublicConstants.CLEANUP_TASK_HANDLER_URI); + task.setName("Closed tasks cleanup"); + + try { + CleanupPolicyType policy = new CleanupPolicyType(); + policy.setMaxAge(XmlTypeConverter.createDuration(0)); + + CleanupPoliciesType policies = new CleanupPoliciesType(getPrismContext()); + policies.setClosedTasks(policy); + task.setExtensionContainerValue(SchemaConstants.MODEL_EXTENSION_CLEANUP_POLICIES, policies); + } catch (SchemaException e) { + LOGGER.error("Error dealing with schema (task {})", task, e); + launchResult.recordFatalError( + createStringResource("pageTasks.message.deleteAllClosedTasksConfirmedPerformed.fatalError").getString(), e); + throw new IllegalStateException("Error dealing with schema", e); + } + + getTaskManager().switchToBackground(task, launchResult); + launchResult.setBackgroundTaskOid(task.getOid()); + + showResult(launchResult); + target.add(getFeedbackPanel()); + } + + private IModel getTaskConfirmationMessageModel(ColumnMenuAction action, String actionName) { + if (action.getRowModel() == null) { + return createStringResource("pageTasks.message.confirmationMessageForMultipleTaskObject", actionName, getSelectedObjects().size()); +// WebComponentUtil.getSelectedData(()).size()); + } else { + String objectName = ((SelectableBean) (action.getRowModel().getObject())).getValue().getName().getOrig(); + return createStringResource("pageTasks.message.confirmationMessageForSingleTaskObject", actionName, objectName); + } + + } + + // must be static, otherwise JVM crashes (probably because of some wicket serialization issues) + private static boolean isCoordinator(IModel rowModel, boolean isHeader) { + SelectableBean dto = getDto(rowModel, isHeader); + return dto != null && TaskTypeUtil.isCoordinator(dto.getValue()); + } + + + // must be static, otherwise JVM crashes (probably because of some wicket serialization issues) + private static boolean isManageableTreeRoot(IModel rowModel, boolean isHeader) { + SelectableBean dto = getDto(rowModel, isHeader); + return dto != null && isManageableTreeRoot(dto.getValue()); + } + + private static boolean isManageableTreeRoot(TaskType taskType) { + return TaskTypeUtil.isCoordinator(taskType) || TaskTypeUtil.isPartitionedMaster(taskType); + } + + private static SelectableBean getDto(IModel rowModel, boolean isHeader) { + if (rowModel != null && !isHeader) { + Object object = rowModel.getObject(); + if (object instanceof SelectableBean) { + return (SelectableBean) object; + } + } + return null; + } + + public static List getOids(List taskDtoList) { + List retval = new ArrayList<>(); + for (TaskType taskDto : taskDtoList) { + retval.add(taskDto.getOid()); + } + return retval; + } +} From b94757b42e311d7dd78886edff7e61dd0bcc4442 Mon Sep 17 00:00:00 2001 From: Katarina Valalikova Date: Wed, 1 Apr 2020 19:48:15 +0200 Subject: [PATCH 3/5] modify instead of delete delta for auditing task actions such as (suspend, runNow, resume) - MID-3743 --- .../midpoint/model/impl/controller/ModelController.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java index 13c3269fc5d..3a1052aceb4 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java @@ -1941,12 +1941,17 @@ private void auditTaskOperation(PrismReferenceValue taskRef, AuditEventType even String requestIdentifier = ModelImplUtils.generateRequestIdentifier(); auditRecord.setRequestIdentifier(requestIdentifier); auditRecord.setTarget(taskRef); - ObjectDelta delta = prismContext.deltaFactory().object().createDeleteDelta(TaskType.class, taskRef.getOid()); + ObjectDelta delta; + if (AuditEventType.DELETE_OBJECT == event) { + delta = prismContext.deltaFactory().object().createDeleteDelta(TaskType.class, taskRef.getOid()); + } else { + //TODO should we somehow indicate deltas which are executed in taskManager? + delta = prismContext.deltaFactory().object().createEmptyModifyDelta(TaskType.class, taskRef.getOid()); + } ObjectDeltaOperation odo = new ObjectDeltaOperation<>(delta, parentResult); auditRecord.getDeltas().add(odo); if (AuditEventStage.EXECUTION == stage) { auditRecord.setOutcome(parentResult.getStatus()); - } auditHelper.audit(auditRecord, null, operationTask, parentResult); } From 1869cffe4af7622617e05efc427eb6084c71c3c4 Mon Sep 17 00:00:00 2001 From: Katarina Valalikova Date: Wed, 1 Apr 2020 22:53:24 +0200 Subject: [PATCH 4/5] create task improvements. --- .../impl/factory/TaskHandlerWrapperFactory.java | 2 +- .../web/page/admin/server/TaskBasicTabPanel.java | 15 ++++++++++----- .../admin/server/TaskHandlerSelectorPanel.java | 2 +- .../schema/constants/SchemaConstants.java | 1 + 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/TaskHandlerWrapperFactory.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/TaskHandlerWrapperFactory.java index 615559c890a..7f9bf297df6 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/TaskHandlerWrapperFactory.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/TaskHandlerWrapperFactory.java @@ -112,7 +112,7 @@ protected PrismPropertyWrapper createWrapper(PrismContainerValueWrapper< private String normalizeHandler(String handler) { handler = StringUtils.remove(handler, "-3"); - handler = StringUtils.removeStart(handler, "http://").replace("-", "/").replace("#", "/"); + handler = StringUtils.removeStart(handler, "http://midpoint.evolveum.com/xml/ns/public/").replace("-", "/").replace("#", "/"); String[] split = handler.split("/"); handler = "TaskHandlerSelector." + StringUtils.join(split, "."); return handler; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskBasicTabPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskBasicTabPanel.java index 18434e765bb..0dff1748ffb 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskBasicTabPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskBasicTabPanel.java @@ -198,7 +198,14 @@ private ItemVisibility getBasicTabVisibility(ItemPath path) { SchemaConstants.PATH_MODEL_EXTENSION_EXECUTE_OPTIONS, ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_WORKER_THREADS)); } else if (taskHandler.endsWith("task/jdbc-ping/handler-3")) { - //TODO + pathsToShow = Arrays.asList(ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.JDBC_PING_TESTS_QNAME), + ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.JDBC_PING_INTERVAL_QNAME), + ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.JDBC_PING_TEST_QUERY_QNAME), + ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.JDBC_PING_DRIVER_CLASS_NAME_QNAME), + ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.JDBC_PING_JDBC_URL_QNAME), + ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.JDBC_PING_JDBC_USERNAME_QNAME), + ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.JDBC_PING_JDBC_PASSWORD_QNAME), + ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.JDBC_PING_LOG_ON_INFO_LEVEL_QNAME)); } else if (taskHandler.endsWith("model/auditReindex/handler-3")) { //no extension attributes } else if (taskHandler.endsWith("task/lightweight-partitioning/handler-3") @@ -211,8 +218,7 @@ private ItemVisibility getBasicTabVisibility(ItemPath path) { } else if (taskHandler.endsWith("task/workers-restart/handler-3")) { //no attributes } else if (taskHandler.endsWith("model/synchronization/task/delete-not-updated-shadow/handler-3")) { - pathsToShow = Arrays.asList(ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_WORKER_THREADS), - //TODO notUpdatesShadowsDurtion + pathsToShow = Arrays.asList(ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_NOT_UPDATED_SHADOW_DURATION), ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_WORKER_THREADS), TaskType.F_OBJECT_REF); } else if (taskHandler.endsWith("model/shadowRefresh/handler-3")) { @@ -238,10 +244,9 @@ private ItemVisibility getBasicTabVisibility(ItemPath path) { } else if (taskHandler.endsWith("model/trigger/scanner/handler-3")) { pathsToShow = Arrays.asList(ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_LAST_SCAN_TIMESTAMP_PROPERTY_NAME), ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_WORKER_THREADS)); - } else if (taskHandler.endsWith("model/focus-validity-scanner/handler-3model/partitioned-focus-validity-scanner/handler-3#1") + } else if (taskHandler.endsWith("model/focus-validity-scanner/handler-3") || taskHandler.endsWith("model/partitioned-focus-validity-scanner/handler-3#1") || taskHandler.endsWith("model/partitioned-focus-validity-scanner/handler-3#2")) { pathsToShow = Arrays.asList(ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_LAST_SCAN_TIMESTAMP_PROPERTY_NAME), - // TODO policyRule ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.PO), SchemaConstants.PATH_MODEL_EXTENSION_OBJECT_TYPE, ItemPath.create(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_WORKER_THREADS)); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskHandlerSelectorPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskHandlerSelectorPanel.java index 8d08809a7fd..5c24326e511 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskHandlerSelectorPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/TaskHandlerSelectorPanel.java @@ -30,7 +30,7 @@ public class TaskHandlerSelectorPanel extends PrismPropertyPanel { public TaskHandlerSelectorPanel(String id, IModel> model, ItemPanelSettings settings) { super(id, model, settings); - Label label = new Label(ID_TASK_SPECIFICATION, createStringResource("TaskHandlerSelectorPanel.seletor.header")); + Label label = new Label(ID_TASK_SPECIFICATION, createStringResource("TaskHandlerSelectorPanel.selector.header")); add(label); label.setOutputMarkupId(true); } diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java index bf6e021c887..5f32b88a2d9 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java @@ -292,6 +292,7 @@ public abstract class SchemaConstants { public static final ItemName MODEL_EXTENSION_TRACING_PROFILE = new ItemName(NS_MODEL_EXTENSION, "tracingProfile"); public static final ItemName MODEL_EXTENSION_TRACING_ROOT = new ItemName(NS_MODEL_EXTENSION, "tracingRoot"); public static final ItemName MODEL_EXTENSION_TRACING = new ItemName(NS_MODEL_EXTENSION, "tracing"); + public static final ItemName MODEL_EXTENSION_NOT_UPDATED_SHADOW_DURATION = new ItemName(NS_MODEL_EXTENSION, "notUpdatedShadowsDuration"); public static final String NS_MODEL_DISABLE_REASON = NS_MODEL + "/disableReason"; public static final String MODEL_DISABLE_REASON_EXPLICIT = From 983bad0fc480dc5c11dad4ef5f756fb9e783bf6c Mon Sep 17 00:00:00 2001 From: Katarina Valalikova Date: Thu, 2 Apr 2020 00:17:01 +0200 Subject: [PATCH 5/5] consent revival - experimental --- .../midpoint/gui/api/page/PageBase.java | 6 +- .../component/assignment/AssignmentPanel.java | 1937 +++++----- .../assignment/GdprAssignmentPanel.java | 16 + .../assignment/SelfConsentPanel.java | 32 + .../assignment/SwitchAssignmentTypePanel.html | 2 +- .../assignment/SwitchAssignmentTypePanel.java | 1158 +++--- .../resources/static/less/midpoint-theme.less | 3236 ++++++++--------- 7 files changed, 3225 insertions(+), 3162 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/page/PageBase.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/page/PageBase.java index 0fa6483937a..cc8a321e5af 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/page/PageBase.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/page/PageBase.java @@ -1996,8 +1996,10 @@ private void createSelfServiceMenu(SideBarMenuItem menu) { } //GDPR feature.. temporary disabled MID-4281 -// addMainMenuItem(menu, GuiStyleConstants.CLASS_ICON_CONSENT, "PageAdmin.menu.consent", -// PageSelfConsents.class); + if (WebModelServiceUtils.isEnableExperimentalFeature(this)) { + addMainMenuItem(menu, GuiStyleConstants.CLASS_ICON_CONSENT, "PageAdmin.menu.consent", + PageSelfConsents.class); + } } private void createAdditionalMenu(SideBarMenuItem menu) { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentPanel.java index 35a41e5fea7..092d2a4f5e8 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentPanel.java @@ -1,966 +1,971 @@ -/* - * Copyright (c) 2018-2019 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ -package com.evolveum.midpoint.web.component.assignment; - -import com.evolveum.midpoint.gui.api.GuiStyleConstants; -import com.evolveum.midpoint.gui.api.component.AssignmentPopup; -import com.evolveum.midpoint.gui.api.component.BasePanel; -import com.evolveum.midpoint.gui.api.component.DisplayNamePanel; -import com.evolveum.midpoint.gui.api.model.LoadableModel; -import com.evolveum.midpoint.gui.api.page.PageBase; -import com.evolveum.midpoint.gui.api.prism.ItemWrapper; -import com.evolveum.midpoint.gui.api.prism.PrismContainerWrapper; -import com.evolveum.midpoint.gui.api.util.WebComponentUtil; -import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; -import com.evolveum.midpoint.gui.impl.component.MultivalueContainerDetailsPanel; -import com.evolveum.midpoint.gui.impl.component.MultivalueContainerListPanelWithDetailsPanel; -import com.evolveum.midpoint.gui.impl.component.data.column.PrismContainerWrapperColumn; -import com.evolveum.midpoint.gui.impl.component.icon.CompositedIcon; -import com.evolveum.midpoint.gui.impl.component.icon.CompositedIconBuilder; -import com.evolveum.midpoint.gui.impl.prism.*; -import com.evolveum.midpoint.gui.impl.session.ObjectTabStorage; -import com.evolveum.midpoint.model.api.AssignmentCandidatesSpecification; -import com.evolveum.midpoint.model.api.AssignmentObjectRelation; -import com.evolveum.midpoint.prism.*; -import com.evolveum.midpoint.prism.path.ItemPath; -import com.evolveum.midpoint.prism.query.ObjectFilter; -import com.evolveum.midpoint.prism.query.ObjectQuery; -import com.evolveum.midpoint.prism.query.RefFilter; -import com.evolveum.midpoint.schema.constants.ObjectTypes; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.security.api.AuthorizationConstants; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.QNameUtil; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.logging.LoggingUtils; -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.web.component.MultiCompositedButtonPanel; -import com.evolveum.midpoint.web.component.MultiFunctinalButtonDto; -import com.evolveum.midpoint.web.component.data.column.*; -import com.evolveum.midpoint.web.component.menu.cog.ButtonInlineMenuItem; -import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem; -import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItemAction; -import com.evolveum.midpoint.web.component.prism.ItemVisibility; -import com.evolveum.midpoint.web.component.prism.ValueStatus; -import com.evolveum.midpoint.web.component.search.SearchFactory; -import com.evolveum.midpoint.web.component.search.SearchItemDefinition; -import com.evolveum.midpoint.web.component.util.VisibleBehaviour; -import com.evolveum.midpoint.web.model.PrismContainerWrapperModel; -import com.evolveum.midpoint.web.session.UserProfileStorage; -import com.evolveum.midpoint.web.session.UserProfileStorage.TableId; -import com.evolveum.midpoint.xml.ns._public.common.common_3.*; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.wicket.ajax.AjaxRequestTarget; -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.extensions.markup.html.repeater.data.table.IColumn; -import org.apache.wicket.markup.html.WebMarkupContainer; -import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.list.ListItem; -import org.apache.wicket.markup.html.panel.Fragment; -import org.apache.wicket.markup.html.panel.Panel; -import org.apache.wicket.markup.repeater.Item; -import org.apache.wicket.model.IModel; -import org.apache.wicket.model.Model; - -import javax.xml.namespace.QName; -import java.util.*; - -public class AssignmentPanel extends BasePanel> { - - private static final long serialVersionUID = 1L; - - private static final Trace LOGGER = TraceManager.getTrace(AssignmentPanel.class); - - private static final String ID_ASSIGNMENTS = "assignments"; - private static final String ID_NEW_ITEM_BUTTON = "newItemButton"; - private static final String ID_BUTTON_TOOLBAR_FRAGMENT = "buttonToolbarFragment"; - - - private static final String DOT_CLASS = AssignmentPanel.class.getName() + "."; - protected static final String OPERATION_LOAD_ASSIGNMENTS_LIMIT = DOT_CLASS + "loadAssignmentsLimit"; - protected static final String OPERATION_LOAD_ASSIGNMENTS_TARGET_OBJ = DOT_CLASS + "loadAssignmentsTargetRefObject"; - protected static final String OPERATION_LOAD_ASSIGNMENT_TARGET_RELATIONS = DOT_CLASS + "loadAssignmentTargetRelations"; - protected static final String OPERATION_LOAD_ASSIGNMENT_HOLDER_SPECIFICATION = DOT_CLASS + "loadAssignmentHolderSpecification"; - - protected int assignmentsRequestsLimit = -1; - - public AssignmentPanel(String id, IModel> assignmentContainerWrapperModel) { - super(id, assignmentContainerWrapperModel); - } - - @Override - protected void onInitialize() { - super.onInitialize(); - assignmentsRequestsLimit = AssignmentsUtil.loadAssignmentsLimit(new OperationResult(OPERATION_LOAD_ASSIGNMENTS_LIMIT), getPageBase()); - initLayout(); - } - - private void initLayout() { - - MultivalueContainerListPanelWithDetailsPanel multivalueContainerListPanel = - new MultivalueContainerListPanelWithDetailsPanel(ID_ASSIGNMENTS, getModel() != null ? getModel() : Model.of(), getTableId(), - getAssignmentsTabStorage()) { - - private static final long serialVersionUID = 1L; - - @Override - protected void initPaging() { - initCustomPaging(); - } - - @Override - protected boolean enableActionNewObject() { - return isNewObjectButtonVisible(getFocusObject()); - } - - @Override - protected void cancelItemDetailsPerformed(AjaxRequestTarget target) { - AssignmentPanel.this.cancelAssignmentDetailsPerformed(target); - } - - @Override - protected ObjectQuery createQuery() { - return createObjectQuery(); - } - - @Override - protected List, String>> createColumns() { - if (AssignmentPanel.this.getModelObject() == null) { - return new ArrayList<>(); - } - return initBasicColumns(); - } - - @Override - protected void newItemPerformed(AjaxRequestTarget target, AssignmentObjectRelation assignmentTargetRelation) { - newAssignmentClickPerformed(target, assignmentTargetRelation); - } - - @Override - protected List createNewButtonDescription() { - List buttonDtoList = new ArrayList<>(); - if (AssignmentPanel.this.getModelObject() == null) { - return null; - } - if (isInducement()) { - return null; - } - - List relations = getAssignmentObjectRelationList(); -// List relations = WebComponentUtil.divideAssignmentRelationsByAllValues(loadAssignmentTargetRelationsList()); - if (relations == null) { - return null; - } - - - relations.forEach(relation -> { - MultiFunctinalButtonDto buttonDto = new MultiFunctinalButtonDto(); - buttonDto.setAssignmentObjectRelation(relation); - - DisplayType additionalButtonDisplayType = WebComponentUtil.getAssignmentObjectRelationDisplayType(AssignmentPanel.this.getPageBase(), relation, - isInducement() ? "AssignmentPanel.newInducementTitle" : "AssignmentPanel.newAssignmentTitle"); - buttonDto.setAdditionalButtonDisplayType(additionalButtonDisplayType); - - CompositedIconBuilder builder = WebComponentUtil.getAssignmentRelationIconBuilder(AssignmentPanel.this.getPageBase(), relation, - additionalButtonDisplayType.getIcon(), WebComponentUtil.createIconType(GuiStyleConstants.EVO_ASSIGNMENT_ICON, "green")); - CompositedIcon icon = null; - if (builder != null) { - icon = builder.build(); - } - buttonDto.setCompositedIcon(icon); - buttonDtoList.add(buttonDto); - }); - return buttonDtoList; - } - - - @Override - protected boolean getNewObjectGenericButtonVisibility(){ - AssignmentCandidatesSpecification spec = loadAssignmentHolderSpecification(); - return spec == null || spec.isSupportGenericAssignment(); - } - - @Override - protected DisplayType getNewObjectButtonDisplayType() { - return WebComponentUtil.createDisplayType(GuiStyleConstants.EVO_ASSIGNMENT_ICON, "green", - AssignmentPanel.this.createStringResource(isInducement() ? - "AssignmentPanel.newInducementTitle" : "AssignmentPanel.newAssignmentTitle", "", "").getString()); - } - - @Override - protected boolean isNewObjectButtonEnabled(){ - return !isAssignmentsLimitReached(); - } - - @Override - protected void deleteItemPerformed(AjaxRequestTarget target, List> toDeleteList) { - int countAddedAssignments = 0; - for (PrismContainerValueWrapper assignment : toDeleteList) { - if (ValueStatus.ADDED.equals(assignment.getStatus())){ - countAddedAssignments++; - } - } - boolean isLimitReached = isAssignmentsLimitReached(toDeleteList.size() - countAddedAssignments, true); - if (isLimitReached) { - warn(getParentPage().getString("AssignmentPanel.assignmentsLimitReachedWarning", assignmentsRequestsLimit)); - target.add(getPageBase().getFeedbackPanel()); - return; - } - super.deleteItemPerformed(target, toDeleteList); - } - - @Override - protected List> postSearch( - List> assignments) { - return customPostSearch(assignments); - } - - @Override - protected MultivalueContainerDetailsPanel getMultivalueContainerDetailsPanel( - ListItem> item) { - return createMultivalueContainerDetailsPanel(item); - } - - @Override - protected WebMarkupContainer getSearchPanel(String contentAreaId) { - return getCustomSearchPanel(contentAreaId); - } - - @Override - protected List initSearchableItems(PrismContainerDefinition containerDef) { - return createSearchableItems(containerDef); - } - - @Override - protected WebMarkupContainer initButtonToolbar(String id) { - WebMarkupContainer buttonToolbar = initCustomButtonToolbar(id); - if(buttonToolbar == null) { - return super.initButtonToolbar(id); - } - return buttonToolbar; - } - - }; - multivalueContainerListPanel.add(new VisibleBehaviour(() -> getModel() != null && getModelObject() != null)); - add(multivalueContainerListPanel); - - setOutputMarkupId(true); - } - - private List getAssignmentObjectRelationList() { - if (AssignmentPanel.this.getModelObject() == null){ - return null; - } - if (isInducement()){ - return null; - } else { - List assignmentRelationsList = - WebComponentUtil.divideAssignmentRelationsByAllValues(loadAssignmentTargetRelationsList()); - if (assignmentRelationsList == null || assignmentRelationsList.isEmpty()){ - return assignmentRelationsList; - } - QName assignmentType = getAssignmentType(); - if (assignmentType == null){ - return assignmentRelationsList; - } - List assignmentRelationsListFilteredByType = - new ArrayList<>(); - assignmentRelationsList.forEach(assignmentRelation -> { - QName objectType = assignmentRelation.getObjectTypes() != null - && !assignmentRelation.getObjectTypes().isEmpty() - ? assignmentRelation.getObjectTypes().get(0) : null; - if (QNameUtil.match(assignmentType, objectType)){ - assignmentRelationsListFilteredByType.add(assignmentRelation); - } - }); - return assignmentRelationsListFilteredByType; - } - } - - protected Fragment initCustomButtonToolbar(String contentAreaId){ - Fragment searchContainer = new Fragment(contentAreaId, ID_BUTTON_TOOLBAR_FRAGMENT, this); - - MultiCompositedButtonPanel newObjectIcon = getMultivalueContainerListPanel().getNewItemButton(ID_NEW_ITEM_BUTTON); - searchContainer.add(newObjectIcon); - - return searchContainer; - } - - protected List createSearchableItems(PrismContainerDefinition containerDef){ - List defs = new ArrayList<>(); - - if (getAssignmentType() == null) { - SearchFactory.addSearchRefDef(containerDef, ItemPath.create(AssignmentType.F_TARGET_REF), defs, AreaCategoryType.ADMINISTRATION, getPageBase()); - SearchFactory.addSearchRefDef(containerDef, ItemPath.create(AssignmentType.F_CONSTRUCTION, ConstructionType.F_RESOURCE_REF), defs, AreaCategoryType.ADMINISTRATION, getPageBase()); - SearchFactory.addSearchPropertyDef(containerDef, ItemPath.create(AssignmentType.F_POLICY_RULE, PolicyRuleType.F_NAME), defs); - SearchFactory.addSearchRefDef(containerDef, - ItemPath.create(AssignmentType.F_POLICY_RULE, PolicyRuleType.F_POLICY_CONSTRAINTS, - PolicyConstraintsType.F_EXCLUSION, ExclusionPolicyConstraintType.F_TARGET_REF), defs, AreaCategoryType.POLICY, getPageBase()); - } - SearchFactory.addSearchPropertyDef(containerDef, ItemPath.create(AssignmentType.F_ACTIVATION, ActivationType.F_ADMINISTRATIVE_STATUS), defs); - SearchFactory.addSearchPropertyDef(containerDef, ItemPath.create(AssignmentType.F_ACTIVATION, ActivationType.F_EFFECTIVE_STATUS), defs); - - defs.addAll(SearchFactory.createExtensionDefinitionList(containerDef)); - - return defs; - - } - - protected QName getAssignmentType(){ - return null; - } - - protected void initCustomPaging(){ - if (getModel() == null || getModelObject() == null){ - return; - } - getAssignmentsTabStorage().setPaging(getPrismContext().queryFactory().createPaging(0, (int) getParentPage().getItemsPerPage(UserProfileStorage.TableId.ASSIGNMENTS_TAB_TABLE))); - } - - protected ObjectTabStorage getAssignmentsTabStorage(){ - if (getModel() == null || getModelObject() == null){ - return null; - } - if (isInducement()){ - return getParentPage().getSessionStorage().getInducementsTabStorage(); - } else { - return getParentPage().getSessionStorage().getAssignmentsTabStorage(); - } - } - - protected List> customPostSearch(List> assignments) { - return assignments; - } - - protected boolean isNewObjectButtonVisible(PrismObject focusObject){ - try { - return getParentPage().isAuthorized(AuthorizationConstants.AUTZ_UI_ADMIN_ASSIGN_ACTION_URI, - AuthorizationPhaseType.REQUEST, focusObject, - null, null, null); - } catch (Exception ex){ - return WebComponentUtil.isAuthorized(AuthorizationConstants.AUTZ_UI_ADMIN_ASSIGN_ACTION_URI); - } - } - - protected ObjectQuery createObjectQuery(){ - Collection delegationRelations = getParentPage().getRelationRegistry() - .getAllRelationsFor(RelationKindType.DELEGATION); - - - //do not show archetype assignments - ObjectReferenceType archetypeRef = new ObjectReferenceType(); - archetypeRef.setType(ArchetypeType.COMPLEX_TYPE); - archetypeRef.setRelation(new QName(PrismConstants.NS_QUERY, "any")); - RefFilter archetypeFilter = (RefFilter) getParentPage().getPrismContext().queryFor(AssignmentType.class) - .item(AssignmentType.F_TARGET_REF) - .ref(archetypeRef.asReferenceValue()) - .buildFilter(); - archetypeFilter.setOidNullAsAny(true); - archetypeFilter.setRelationNullAsAny(true); - - ObjectQuery query = getParentPage().getPrismContext().queryFor(AssignmentType.class) - .not() - .item(AssignmentType.F_TARGET_REF) - .refRelation(delegationRelations.toArray(new QName[0])) - .build(); - query.addFilter(getPrismContext().queryFactory().createNot(archetypeFilter)); - return query; - } - - protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target){ - } - - private List loadAssignmentTargetRelationsList(){ - OperationResult result = new OperationResult(OPERATION_LOAD_ASSIGNMENT_TARGET_RELATIONS); - List assignmentTargetRelations = new ArrayList<>(); - PrismObject obj = getMultivalueContainerListPanel().getFocusObject(); - try { - AssignmentCandidatesSpecification spec = getPageBase().getModelInteractionService() - .determineAssignmentTargetSpecification(obj, result); - assignmentTargetRelations = spec != null ? spec.getAssignmentObjectRelations() : new ArrayList<>(); - } catch (SchemaException | ConfigurationException ex){ - result.recordPartialError(ex.getLocalizedMessage()); - LOGGER.error("Couldn't load assignment target specification for the object {} , {}", obj.getName(), ex.getLocalizedMessage()); - } - return assignmentTargetRelations; - } - - private AssignmentCandidatesSpecification loadAssignmentHolderSpecification(){ - OperationResult result = new OperationResult(OPERATION_LOAD_ASSIGNMENT_HOLDER_SPECIFICATION); - PrismObject obj = getMultivalueContainerListPanel().getFocusObject(); - AssignmentCandidatesSpecification spec = null; - try { - spec = getPageBase().getModelInteractionService() - .determineAssignmentHolderSpecification(obj, result); - } catch (SchemaException | ConfigurationException ex){ - result.recordPartialError(ex.getLocalizedMessage()); - LOGGER.error("Couldn't load assignment holder specification for the object {} , {}", obj.getName(), ex.getLocalizedMessage()); - } - return spec; - } - - protected List, String>> initBasicColumns() { - List, String>> columns = new ArrayList<>(); - - columns.add(new CheckBoxHeaderColumn<>()); - - columns.add(new IconColumn>(Model.of("")) { - - private static final long serialVersionUID = 1L; - - @Override - protected DisplayType getIconDisplayType(IModel> rowModel){ - AssignmentType assignment = rowModel.getObject().getRealValue(); - LOGGER.trace("Create icon for AssignmentType: " + assignment); - if (assignment != null && assignment.getTargetRef() != null && StringUtils.isNotEmpty(assignment.getTargetRef().getOid())){ - List targetObjectList = WebComponentUtil.loadReferencedObjectList(Collections.singletonList(assignment.getTargetRef()), OPERATION_LOAD_ASSIGNMENTS_TARGET_OBJ, - AssignmentPanel.this.getPageBase()); - if (CollectionUtils.isNotEmpty(targetObjectList) && targetObjectList.size() == 1){ - ObjectType targetObject = targetObjectList.get(0); - DisplayType displayType = WebComponentUtil.getArchetypePolicyDisplayType(targetObject, AssignmentPanel.this.getPageBase()); - if (displayType != null){ - String disabledStyle; - if (targetObject instanceof FocusType) { - disabledStyle = WebComponentUtil.getIconEnabledDisabled(((FocusType)targetObject).asPrismObject()); - if (displayType.getIcon() != null && StringUtils.isNotEmpty(displayType.getIcon().getCssClass()) && - disabledStyle != null){ - displayType.getIcon().setCssClass(displayType.getIcon().getCssClass() + " " + disabledStyle); - displayType.getIcon().setColor(""); - } - } - return displayType; - } - } - } - return WebComponentUtil.createDisplayType(WebComponentUtil.createDefaultBlackIcon( - AssignmentsUtil.getTargetType(rowModel.getObject().getRealValue()))); - } - - }); - - columns.add(new LinkColumn>(createStringResource("PolicyRulesPanel.nameColumn")){ - private static final long serialVersionUID = 1L; - - @Override - protected IModel createLinkModel(IModel> rowModel) { - LOGGER.trace("Create name for AssignmentType: " + rowModel.getObject().getRealValue()); - String name = AssignmentsUtil.getName(rowModel.getObject(), getParentPage()); - LOGGER.trace("Name for AssignmentType: " + name); - if (StringUtils.isBlank(name)) { - return createStringResource("AssignmentPanel.noName"); - } - return Model.of(name); - } - - @Override - public boolean isEnabled(IModel> rowModel) { - return rowModel.getObject().getRealValue().getFocusMappings() == null; - } - - @Override - public void onClick(AjaxRequestTarget target, IModel> rowModel) { - AssignmentPanel.this.assignmentDetailsPerformed(target); - getMultivalueContainerListPanel().itemDetailsPerformed(target, rowModel); - } - }); - - columns.add(new PrismContainerWrapperColumn<>(getModel(), AssignmentType.F_ACTIVATION, getPageBase())); - - if (getAssignmentType() == null) { - columns.add(new AbstractColumn, String>(createStringResource("AssignmentPanel.moreData")) { - private static final long serialVersionUID = 1L; - - @Override - public void populateItem(Item>> cellItem, String componentId, - IModel> rowModel) { - AssignmentType assignmentType = rowModel != null && rowModel.getObject() != null ? - rowModel.getObject().getRealValue() : null; - cellItem.add(new Label(componentId, AssignmentsUtil.getAssignmentSpecificInfoLabel(assignmentType, AssignmentPanel.this.getPageBase()))); - } - }); - } - - columns.addAll(initColumns()); - List menuActionsList = getAssignmentMenuActions(); - columns.add(new InlineMenuButtonColumn>(menuActionsList, getPageBase()){ - private static final long serialVersionUID = 1L; - - @Override - protected boolean isButtonMenuItemEnabled(IModel> rowModel){ - if (rowModel != null - && ValueStatus.ADDED.equals(rowModel.getObject().getStatus())) { - return true; - } - return !isAssignmentsLimitReached(); - } - }); - return columns; - } - - protected List, String>> initColumns(){ - return new ArrayList<>(); - } - - protected void assignmentDetailsPerformed(AjaxRequestTarget target){ - } - - protected void newAssignmentClickPerformed(AjaxRequestTarget target, AssignmentObjectRelation assignmentTargetRelation){ - AssignmentPopup popupPanel = new AssignmentPopup(getPageBase().getMainPopupBodyId()) { - - private static final long serialVersionUID = 1L; - - @Override - protected void addPerformed(AjaxRequestTarget target, List newAssignmentsList) { - super.addPerformed(target, newAssignmentsList); - addSelectedAssignmentsPerformed(target, newAssignmentsList); - } - - @Override - protected List getAvailableObjectTypesList(){ - if (assignmentTargetRelation == null || CollectionUtils.isEmpty(assignmentTargetRelation.getObjectTypes())) { - return getObjectTypesList(); - } else { - return mergeNewAssignmentTargetTypeLists(assignmentTargetRelation.getObjectTypes(), getObjectTypesList()); - } - } - - @Override - protected QName getPredefinedRelation(){ - if (assignmentTargetRelation == null){ - return null; - } - return !CollectionUtils.isEmpty(assignmentTargetRelation.getRelations()) ? assignmentTargetRelation.getRelations().get(0) : null; - } - - @Override - protected List getArchetypeRefList(){ - return assignmentTargetRelation != null ? assignmentTargetRelation.getArchetypeRefs() : null; - } - - @Override - protected ObjectFilter getSubtypeFilter(){ - return AssignmentPanel.this.getSubtypeFilter(); - } - - @Override - protected boolean isEntitlementAssignment(){ - return AssignmentPanel.this.isEntitlementAssignment(); - } - - @Override - protected PrismContainerWrapper getAssignmentWrapperModel() { - return AssignmentPanel.this.getModelObject(); - } - - @Override - protected boolean isOrgTreeTabVisible(){ - return assignmentTargetRelation == null; - } - }; - popupPanel.setOutputMarkupId(true); - popupPanel.setOutputMarkupPlaceholderTag(true); - getPageBase().showMainPopup(popupPanel, target); - } - - protected List getObjectTypesList(){ - if (getAssignmentType() == null) { - return WebComponentUtil.createAssignableTypesList(); - } else { - return Collections.singletonList(ObjectTypes.getObjectTypeFromTypeQName(getAssignmentType())); - } - } - - protected boolean isEntitlementAssignment(){ - return false; - } - - protected void addSelectedAssignmentsPerformed(AjaxRequestTarget target, List newAssignmentsList){ - if (newAssignmentsList == null || newAssignmentsList.isEmpty()) { - warn(getParentPage().getString("AssignmentTablePanel.message.noAssignmentSelected")); - target.add(getPageBase().getFeedbackPanel()); - return; - } - boolean isAssignmentsLimitReached = isAssignmentsLimitReached(newAssignmentsList != null ? newAssignmentsList.size() : 0, true); - if (isAssignmentsLimitReached) { - warn(getParentPage().getString("AssignmentPanel.assignmentsLimitReachedWarning", assignmentsRequestsLimit)); - target.add(getPageBase().getFeedbackPanel()); - return; - } - - newAssignmentsList.forEach(assignment -> { - - PrismContainerValue newAssignment = getModelObject().getItem().createNewValue(); - AssignmentType assignmentType = newAssignment.asContainerable(); - - if (assignment.getConstruction() != null && assignment.getConstruction().getResourceRef() != null) { - assignmentType.setConstruction(assignment.getConstruction()); - } else { - assignmentType.setTargetRef(assignment.getTargetRef()); - } - getMultivalueContainerListPanel().createNewItemContainerValueWrapper(newAssignment, getModelObject(), - target); - getMultivalueContainerListPanel().refreshTable(target); - getMultivalueContainerListPanel().reloadSavePreviewButtons(target); - - }); - - - } - - protected WebMarkupContainer getCustomSearchPanel(String contentAreaId) { - return new WebMarkupContainer(contentAreaId); - } - - private MultivalueContainerDetailsPanel createMultivalueContainerDetailsPanel(ListItem> item) { - if (isAssignmentsLimitReached()){ - item.getModelObject().setReadOnly(true, true); - } else if (item.getModelObject().isReadOnly()){ - item.getModelObject().setReadOnly(false, true); - } - - return new MultivalueContainerDetailsPanel(MultivalueContainerListPanelWithDetailsPanel.ID_ITEM_DETAILS, item.getModel()) { - - private static final long serialVersionUID = 1L; - - @Override - protected ItemVisibility getBasicTabVisibity(ItemWrapper itemWrapper) { - return AssignmentPanel.this.getContainerVisibility(itemWrapper); - } - - @Override - protected void addBasicContainerValuePanel(String idPanel) { - add(getBasicContainerPanel(idPanel, item.getModel())); - } - - @Override - protected DisplayNamePanel createDisplayNamePanel(String displayNamePanelId) { - IModel displayNameModel = getDisplayModel(item.getModelObject().getRealValue()); - return new DisplayNamePanel(displayNamePanelId, displayNameModel) { - - private static final long serialVersionUID = 1L; - - @Override - protected QName getRelation() { - return getRelationForDisplayNamePanel(item.getModelObject()); - } - - @Override - protected IModel getKindIntentLabelModel() { - return getKindIntentLabelModelForDisplayNamePanel(item.getModelObject()); - } - - }; - } - - }; - } - - protected Panel getBasicContainerPanel(String idPanel, IModel> model) { - ItemPanelSettings settings = new ItemPanelSettingsBuilder() - .visibilityHandler(this::getContainerVisibility) - .showOnTopLevel(true) - .editabilityHandler(this::getContainerReadability) - .build(); - getPageBase().initContainerValuePanel(idPanel, model, settings); - return getPageBase().initContainerValuePanel(idPanel, model, settings); - } - - protected boolean getContainerReadability(ItemWrapper wrapper) { - return true; - } - - protected ItemVisibility getContainerVisibility(ItemWrapper wrapper) { - if (QNameUtil.match(ActivationType.COMPLEX_TYPE, wrapper.getTypeName())) { - return ItemVisibility.AUTO; - } - if (QNameUtil.match(MetadataType.COMPLEX_TYPE, wrapper.getTypeName())) { - return ItemVisibility.AUTO; - } - if (QNameUtil.match(AssignmentType.F_TARGET_REF, wrapper.getItemName())) { - return ItemVisibility.HIDDEN; - } - - if (QNameUtil.match(OrderConstraintsType.COMPLEX_TYPE, wrapper.getTypeName())) { - return ItemVisibility.HIDDEN; - } - - if (QNameUtil.match(AssignmentSelectorType.COMPLEX_TYPE, wrapper.getTypeName())) { - return ItemVisibility.HIDDEN; - } - - if (QNameUtil.match(OtherPrivilegesLimitationType.COMPLEX_TYPE, wrapper.getTypeName())) { - return ItemVisibility.HIDDEN; - } - - if (QNameUtil.match(PolicyExceptionType.COMPLEX_TYPE, wrapper.getTypeName())) { - return ItemVisibility.HIDDEN; - } - - if (QNameUtil.match(AssignmentRelationType.COMPLEX_TYPE, wrapper.getTypeName())) { - return ItemVisibility.HIDDEN; - } - - if (QNameUtil.match(ExtensionType.COMPLEX_TYPE, wrapper.getTypeName())) { - return ItemVisibility.HIDDEN; - } - - ItemPath assignmentConditionPath = ItemPath.create(AssignmentHolderType.F_ASSIGNMENT, AssignmentType.F_CONDITION); - ItemPath inducementConditionPath = ItemPath.create(AbstractRoleType.F_INDUCEMENT, AssignmentType.F_CONDITION); - - ItemPath wrapperPath = wrapper.getPath().namedSegmentsOnly(); - if (assignmentConditionPath.isSubPath(wrapperPath) || inducementConditionPath.isSubPath(wrapperPath)) { - ItemPath assignmentConditionExpressionPath = ItemPath.create(AssignmentHolderType.F_ASSIGNMENT, AssignmentType.F_CONDITION, MappingType.F_EXPRESSION); - ItemPath inducementConditionExpressionPath = ItemPath.create(AbstractRoleType.F_INDUCEMENT, AssignmentType.F_CONDITION, MappingType.F_EXPRESSION); - if (wrapperPath.equivalent(assignmentConditionExpressionPath) || wrapperPath.equivalent(inducementConditionExpressionPath)) { - return ItemVisibility.AUTO; - } else { - return ItemVisibility.HIDDEN; - } - } - - if (ItemPath.create(AssignmentHolderType.F_ASSIGNMENT, AssignmentType.F_ACTIVATION, ActivationType.F_LOCKOUT_EXPIRATION_TIMESTAMP).equivalent(wrapper.getPath())) { - return ItemVisibility.HIDDEN; - } - - if (ItemPath.create(AssignmentHolderType.F_ASSIGNMENT, AssignmentType.F_ACTIVATION, ActivationType.F_LOCKOUT_STATUS).equivalent(wrapper.getPath())) { - return ItemVisibility.HIDDEN; - } - - - return getTypedContainerVisibility(wrapper); - } - - protected ItemVisibility getTypedContainerVisibility(ItemWrapper wrapper) { - return ItemVisibility.AUTO; - } - - private QName getRelationForDisplayNamePanel(PrismContainerValueWrapper modelObject) { - AssignmentType assignment = modelObject.getRealValue(); - if (assignment.getTargetRef() != null) { - return assignment.getTargetRef().getRelation(); - } else { - return null; - } - } - - private IModel getKindIntentLabelModelForDisplayNamePanel(PrismContainerValueWrapper modelObject) { - AssignmentType assignment = modelObject.getRealValue(); - if (assignment.getConstruction() != null){ - return createStringResource("DisplayNamePanel.kindIntentLabel", assignment.getConstruction().getKind(), - assignment.getConstruction().getIntent()); - } - return Model.of(); - } - - //TODO add to basic visibility - private ItemVisibility getActivationVisibileItems(ItemPath pathToCheck, ItemPath assignmentPath) { - if (assignmentPath.append(ItemPath.create(AssignmentType.F_ACTIVATION, ActivationType.F_LOCKOUT_EXPIRATION_TIMESTAMP)).equivalent(pathToCheck)) { - return ItemVisibility.HIDDEN; - } - - if (assignmentPath.append(ItemPath.create(AssignmentType.F_ACTIVATION, ActivationType.F_LOCKOUT_STATUS)).equivalent(pathToCheck)) { - return ItemVisibility.HIDDEN; - } - - return ItemVisibility.AUTO; - } - - private List mergeNewAssignmentTargetTypeLists(List allowedByAssignmentTargetSpecification, List availableTypesList){ - if (CollectionUtils.isEmpty(allowedByAssignmentTargetSpecification)){ - return availableTypesList; - } - if (CollectionUtils.isEmpty(availableTypesList)){ - return availableTypesList; - } - List mergedList = new ArrayList<>(); - allowedByAssignmentTargetSpecification.forEach(qnameValue -> { - ObjectTypes objectTypes = ObjectTypes.getObjectTypeFromTypeQName(qnameValue); - for (ObjectTypes availableObjectTypes : availableTypesList) { - if (availableObjectTypes.getClassDefinition().equals(objectTypes.getClassDefinition())) { - mergedList.add(objectTypes); - break; - } - } - }); - return mergedList; - } - - private IModel getDisplayModel(AssignmentType assignment){ - return (IModel) () -> { - if (assignment.getTargetRef() != null && assignment.getTargetRef().getOid() != null) { - Task task = getPageBase().createSimpleTask("Load target"); - OperationResult result = task.getResult(); - PrismObject targetObject = WebModelServiceUtils.loadObject(assignment.getTargetRef(), getPageBase(), task, result); - return targetObject != null ? (C) targetObject.asObjectable() : null; - } - if (assignment.getConstruction() != null && assignment.getConstruction().getResourceRef() != null) { - Task task = getPageBase().createSimpleTask("Load resource"); - OperationResult result = task.getResult(); - return (C) WebModelServiceUtils.loadObject(assignment.getConstruction().getResourceRef(), getPageBase(), task, result).asObjectable(); - } else if (assignment.getPersonaConstruction() != null) { - return (C) assignment.getPersonaConstruction(); - } else if (assignment.getPolicyRule() !=null) { - return (C) assignment.getPolicyRule(); - } - return null; - }; - } - - private List getAssignmentMenuActions() { - List menuItems = new ArrayList<>(); - PrismObject obj = getMultivalueContainerListPanel().getFocusObject(); - try { - boolean isUnassignAuthorized = getParentPage().isAuthorized(AuthorizationConstants.AUTZ_UI_ADMIN_UNASSIGN_ACTION_URI, - AuthorizationPhaseType.REQUEST, obj, - null, null, null); - if (isUnassignAuthorized) { - menuItems.add(new ButtonInlineMenuItem(getAssignmentsLimitReachedTitleModel("pageAdminFocus.menu.unassign")) { - private static final long serialVersionUID = 1L; - - @Override - public String getButtonIconCssClass() { - return GuiStyleConstants.CLASS_DELETE_MENU_ITEM; - } - - @Override - public InlineMenuItemAction initAction() { - return getMultivalueContainerListPanel().createDeleteColumnAction(); - } - }); - } - - } catch (Exception ex){ - LOGGER.error("Couldn't check unassign authorization for the object: {}, {}", obj.getName(), ex.getLocalizedMessage()); - if (WebComponentUtil.isAuthorized(AuthorizationConstants.AUTZ_UI_ADMIN_ASSIGN_ACTION_URI)){ - menuItems.add(new ButtonInlineMenuItem(createStringResource("PageBase.button.unassign")) { - private static final long serialVersionUID = 1L; - - @Override - public String getButtonIconCssClass() { - return GuiStyleConstants.CLASS_DELETE_MENU_ITEM; - } - - @Override - public InlineMenuItemAction initAction() { - return getMultivalueContainerListPanel().createDeleteColumnAction(); - } - }); - } - } - menuItems.add(new ButtonInlineMenuItem(createStringResource("PageBase.button.edit")) { - private static final long serialVersionUID = 1L; - - @Override - public String getButtonIconCssClass() { - return GuiStyleConstants.CLASS_EDIT_MENU_ITEM; - } - - @Override - public InlineMenuItemAction initAction() { - return getMultivalueContainerListPanel().createEditColumnAction(); - } - }); - menuItems.add(new ButtonInlineMenuItem(createStringResource("AssignmentPanel.viewTargetObject")) { - private static final long serialVersionUID = 1L; - - @Override - public String getButtonIconCssClass() { - return GuiStyleConstants.CLASS_NAVIGATE_ARROW; - } - - @Override - public InlineMenuItemAction initAction() { - return new ColumnMenuAction>() { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - PrismContainerValueWrapper assignmentContainer = getRowModel().getObject(); - PrismReferenceWrapper targetRef; - try { - targetRef = assignmentContainer.findReference(ItemPath.create(AssignmentType.F_TARGET_REF)); - } catch (SchemaException e) { - getSession().error("Couldn't show details page. More information provided in log."); - LOGGER.error("Couldn't show detials page, no targetRef reference wrapper found: {}", e.getMessage(), e); - target.add(getPageBase().getFeedbackPanel()); - return; - } - - if (targetRef != null && targetRef.getValues() != null && targetRef.getValues().size() > 0) { - PrismReferenceValueWrapperImpl refWrapper = targetRef.getValues().get(0); - if (!StringUtils.isEmpty(refWrapper.getNewValue().getOid())) { - Class targetClass = ObjectTypes.getObjectTypeFromTypeQName(refWrapper.getRealValue().getType()).getClassDefinition(); - WebComponentUtil.dispatchToObjectDetailsPage(targetClass, refWrapper.getNewValue().getOid(), AssignmentPanel.this, false); - } - } - } - }; - } - - @Override - public boolean isHeaderMenuItem(){ - return false; - } - }); - return menuItems; - } - - protected MultivalueContainerListPanelWithDetailsPanel getMultivalueContainerListPanel() { - return ((MultivalueContainerListPanelWithDetailsPanel)get(ID_ASSIGNMENTS)); - } - - //TODO override for each type ? - protected TableId getTableId() { - return UserProfileStorage.TableId.ASSIGNMENTS_TAB_TABLE; - } - - protected PageBase getParentPage() { - return getPageBase(); - } - - private IModel getAssignmentsLimitReachedTitleModel(String defaultTitleKey) { - return new LoadableModel(true) { - @Override - protected String load() { - return isAssignmentsLimitReached() ? - AssignmentPanel.this.getPageBase().createStringResource("RoleCatalogItemButton.assignmentsLimitReachedTitle", - assignmentsRequestsLimit).getString() : createStringResource(defaultTitleKey).getString(); - } - }; - } - - protected boolean isAssignmentsLimitReached() { - return isAssignmentsLimitReached(0, false); - } - - protected boolean isAssignmentsLimitReached(int selectedAssignmentsCount, boolean actionPerformed) { - if (assignmentsRequestsLimit < 0){ - return false; - } - int changedItems = 0; - List> assignmentsList = getModelObject().getValues(); - for (PrismContainerValueWrapper assignment : assignmentsList){ - if (assignment.hasChanged()){ - changedItems++; - } - } - return actionPerformed ? (changedItems + selectedAssignmentsCount) > assignmentsRequestsLimit : - (changedItems + selectedAssignmentsCount) >= assignmentsRequestsLimit; - } - - protected boolean isInducement(){ - return getModelObject() != null && getModelObject().getPath().containsNameExactly(AbstractRoleType.F_INDUCEMENT); - } - - protected ObjectFilter getSubtypeFilter(){ - return null; - } -} +/* + * Copyright (c) 2018-2019 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.web.component.assignment; + +import com.evolveum.midpoint.gui.api.GuiStyleConstants; +import com.evolveum.midpoint.gui.api.component.AssignmentPopup; +import com.evolveum.midpoint.gui.api.component.BasePanel; +import com.evolveum.midpoint.gui.api.component.DisplayNamePanel; +import com.evolveum.midpoint.gui.api.model.LoadableModel; +import com.evolveum.midpoint.gui.api.page.PageBase; +import com.evolveum.midpoint.gui.api.prism.ItemWrapper; +import com.evolveum.midpoint.gui.api.prism.PrismContainerWrapper; +import com.evolveum.midpoint.gui.api.util.WebComponentUtil; +import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; +import com.evolveum.midpoint.gui.impl.component.MultivalueContainerDetailsPanel; +import com.evolveum.midpoint.gui.impl.component.MultivalueContainerListPanelWithDetailsPanel; +import com.evolveum.midpoint.gui.impl.component.data.column.PrismContainerWrapperColumn; +import com.evolveum.midpoint.gui.impl.component.icon.CompositedIcon; +import com.evolveum.midpoint.gui.impl.component.icon.CompositedIconBuilder; +import com.evolveum.midpoint.gui.impl.prism.*; +import com.evolveum.midpoint.gui.impl.session.ObjectTabStorage; +import com.evolveum.midpoint.model.api.AssignmentCandidatesSpecification; +import com.evolveum.midpoint.model.api.AssignmentObjectRelation; +import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.ObjectFilter; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.prism.query.RefFilter; +import com.evolveum.midpoint.schema.constants.ObjectTypes; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.QNameUtil; +import com.evolveum.midpoint.util.exception.ConfigurationException; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.logging.LoggingUtils; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.web.component.MultiCompositedButtonPanel; +import com.evolveum.midpoint.web.component.MultiFunctinalButtonDto; +import com.evolveum.midpoint.web.component.data.column.*; +import com.evolveum.midpoint.web.component.menu.cog.ButtonInlineMenuItem; +import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem; +import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItemAction; +import com.evolveum.midpoint.web.component.prism.ItemVisibility; +import com.evolveum.midpoint.web.component.prism.ValueStatus; +import com.evolveum.midpoint.web.component.search.SearchFactory; +import com.evolveum.midpoint.web.component.search.SearchItemDefinition; +import com.evolveum.midpoint.web.component.util.VisibleBehaviour; +import com.evolveum.midpoint.web.model.PrismContainerWrapperModel; +import com.evolveum.midpoint.web.session.UserProfileStorage; +import com.evolveum.midpoint.web.session.UserProfileStorage.TableId; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.wicket.ajax.AjaxRequestTarget; +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.extensions.markup.html.repeater.data.table.IColumn; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.panel.Fragment; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; + +import javax.xml.namespace.QName; +import java.util.*; + +public class AssignmentPanel extends BasePanel> { + + private static final long serialVersionUID = 1L; + + private static final Trace LOGGER = TraceManager.getTrace(AssignmentPanel.class); + + private static final String ID_ASSIGNMENTS = "assignments"; + private static final String ID_NEW_ITEM_BUTTON = "newItemButton"; + private static final String ID_BUTTON_TOOLBAR_FRAGMENT = "buttonToolbarFragment"; + + + private static final String DOT_CLASS = AssignmentPanel.class.getName() + "."; + protected static final String OPERATION_LOAD_ASSIGNMENTS_LIMIT = DOT_CLASS + "loadAssignmentsLimit"; + protected static final String OPERATION_LOAD_ASSIGNMENTS_TARGET_OBJ = DOT_CLASS + "loadAssignmentsTargetRefObject"; + protected static final String OPERATION_LOAD_ASSIGNMENT_TARGET_RELATIONS = DOT_CLASS + "loadAssignmentTargetRelations"; + protected static final String OPERATION_LOAD_ASSIGNMENT_HOLDER_SPECIFICATION = DOT_CLASS + "loadAssignmentHolderSpecification"; + + protected int assignmentsRequestsLimit = -1; + + public AssignmentPanel(String id, IModel> assignmentContainerWrapperModel) { + super(id, assignmentContainerWrapperModel); + } + + @Override + protected void onInitialize() { + super.onInitialize(); + assignmentsRequestsLimit = AssignmentsUtil.loadAssignmentsLimit(new OperationResult(OPERATION_LOAD_ASSIGNMENTS_LIMIT), getPageBase()); + initLayout(); + } + + private void initLayout() { + + MultivalueContainerListPanelWithDetailsPanel multivalueContainerListPanel = + new MultivalueContainerListPanelWithDetailsPanel(ID_ASSIGNMENTS, getModel() != null ? getModel() : Model.of(), getTableId(), + getAssignmentsTabStorage()) { + + private static final long serialVersionUID = 1L; + + @Override + protected void initPaging() { + initCustomPaging(); + } + + @Override + protected boolean enableActionNewObject() { + return isNewObjectButtonVisible(getFocusObject()); + } + + @Override + protected void cancelItemDetailsPerformed(AjaxRequestTarget target) { + AssignmentPanel.this.cancelAssignmentDetailsPerformed(target); + } + + @Override + protected ObjectQuery createQuery() { + return createObjectQuery(); + } + + @Override + protected List, String>> createColumns() { + if (AssignmentPanel.this.getModelObject() == null) { + return new ArrayList<>(); + } + return initBasicColumns(); + } + + @Override + protected void newItemPerformed(AjaxRequestTarget target, AssignmentObjectRelation assignmentTargetRelation) { + newAssignmentClickPerformed(target, assignmentTargetRelation); + } + + @Override + protected List createNewButtonDescription() { + List buttonDtoList = new ArrayList<>(); + if (AssignmentPanel.this.getModelObject() == null) { + return null; + } + if (isInducement()) { + return null; + } + + List relations = getAssignmentObjectRelationList(); +// List relations = WebComponentUtil.divideAssignmentRelationsByAllValues(loadAssignmentTargetRelationsList()); + if (relations == null) { + return null; + } + + + relations.forEach(relation -> { + MultiFunctinalButtonDto buttonDto = new MultiFunctinalButtonDto(); + buttonDto.setAssignmentObjectRelation(relation); + + DisplayType additionalButtonDisplayType = WebComponentUtil.getAssignmentObjectRelationDisplayType(AssignmentPanel.this.getPageBase(), relation, + isInducement() ? "AssignmentPanel.newInducementTitle" : "AssignmentPanel.newAssignmentTitle"); + buttonDto.setAdditionalButtonDisplayType(additionalButtonDisplayType); + + CompositedIconBuilder builder = WebComponentUtil.getAssignmentRelationIconBuilder(AssignmentPanel.this.getPageBase(), relation, + additionalButtonDisplayType.getIcon(), WebComponentUtil.createIconType(GuiStyleConstants.EVO_ASSIGNMENT_ICON, "green")); + CompositedIcon icon = null; + if (builder != null) { + icon = builder.build(); + } + buttonDto.setCompositedIcon(icon); + buttonDtoList.add(buttonDto); + }); + return buttonDtoList; + } + + + @Override + protected boolean getNewObjectGenericButtonVisibility(){ + AssignmentCandidatesSpecification spec = loadAssignmentHolderSpecification(); + return spec == null || spec.isSupportGenericAssignment(); + } + + @Override + protected DisplayType getNewObjectButtonDisplayType() { + return WebComponentUtil.createDisplayType(GuiStyleConstants.EVO_ASSIGNMENT_ICON, "green", + AssignmentPanel.this.createStringResource(isInducement() ? + "AssignmentPanel.newInducementTitle" : "AssignmentPanel.newAssignmentTitle", "", "").getString()); + } + + @Override + protected boolean isNewObjectButtonEnabled(){ + return !isAssignmentsLimitReached(); + } + + @Override + protected void deleteItemPerformed(AjaxRequestTarget target, List> toDeleteList) { + int countAddedAssignments = 0; + for (PrismContainerValueWrapper assignment : toDeleteList) { + if (ValueStatus.ADDED.equals(assignment.getStatus())){ + countAddedAssignments++; + } + } + boolean isLimitReached = isAssignmentsLimitReached(toDeleteList.size() - countAddedAssignments, true); + if (isLimitReached) { + warn(getParentPage().getString("AssignmentPanel.assignmentsLimitReachedWarning", assignmentsRequestsLimit)); + target.add(getPageBase().getFeedbackPanel()); + return; + } + super.deleteItemPerformed(target, toDeleteList); + } + + @Override + protected List> postSearch( + List> assignments) { + return customPostSearch(assignments); + } + + @Override + protected MultivalueContainerDetailsPanel getMultivalueContainerDetailsPanel( + ListItem> item) { + return createMultivalueContainerDetailsPanel(item); + } + + @Override + protected WebMarkupContainer getSearchPanel(String contentAreaId) { + return getCustomSearchPanel(contentAreaId); + } + + @Override + protected List initSearchableItems(PrismContainerDefinition containerDef) { + return createSearchableItems(containerDef); + } + + @Override + protected WebMarkupContainer initButtonToolbar(String id) { + WebMarkupContainer buttonToolbar = initCustomButtonToolbar(id); + if(buttonToolbar == null) { + return super.initButtonToolbar(id); + } + return buttonToolbar; + } + + }; + multivalueContainerListPanel.add(new VisibleBehaviour(() -> getModel() != null && getModelObject() != null)); + add(multivalueContainerListPanel); + + setOutputMarkupId(true); + } + + private List getAssignmentObjectRelationList() { + if (AssignmentPanel.this.getModelObject() == null){ + return null; + } + if (isInducement()){ + return null; + } else { + List assignmentRelationsList = + WebComponentUtil.divideAssignmentRelationsByAllValues(loadAssignmentTargetRelationsList()); + if (assignmentRelationsList == null || assignmentRelationsList.isEmpty()){ + return assignmentRelationsList; + } + QName assignmentType = getAssignmentType(); + if (assignmentType == null){ + return assignmentRelationsList; + } + List assignmentRelationsListFilteredByType = + new ArrayList<>(); + assignmentRelationsList.forEach(assignmentRelation -> { + QName objectType = assignmentRelation.getObjectTypes() != null + && !assignmentRelation.getObjectTypes().isEmpty() + ? assignmentRelation.getObjectTypes().get(0) : null; + if (QNameUtil.match(assignmentType, objectType)){ + assignmentRelationsListFilteredByType.add(assignmentRelation); + } + }); + return assignmentRelationsListFilteredByType; + } + } + + protected Fragment initCustomButtonToolbar(String contentAreaId){ + Fragment searchContainer = new Fragment(contentAreaId, ID_BUTTON_TOOLBAR_FRAGMENT, this); + + MultiCompositedButtonPanel newObjectIcon = getMultivalueContainerListPanel().getNewItemButton(ID_NEW_ITEM_BUTTON); + searchContainer.add(newObjectIcon); + + return searchContainer; + } + + protected List createSearchableItems(PrismContainerDefinition containerDef){ + List defs = new ArrayList<>(); + + if (getAssignmentType() == null) { + SearchFactory.addSearchRefDef(containerDef, ItemPath.create(AssignmentType.F_TARGET_REF), defs, AreaCategoryType.ADMINISTRATION, getPageBase()); + SearchFactory.addSearchRefDef(containerDef, ItemPath.create(AssignmentType.F_CONSTRUCTION, ConstructionType.F_RESOURCE_REF), defs, AreaCategoryType.ADMINISTRATION, getPageBase()); + SearchFactory.addSearchPropertyDef(containerDef, ItemPath.create(AssignmentType.F_POLICY_RULE, PolicyRuleType.F_NAME), defs); + SearchFactory.addSearchRefDef(containerDef, + ItemPath.create(AssignmentType.F_POLICY_RULE, PolicyRuleType.F_POLICY_CONSTRAINTS, + PolicyConstraintsType.F_EXCLUSION, ExclusionPolicyConstraintType.F_TARGET_REF), defs, AreaCategoryType.POLICY, getPageBase()); + } + SearchFactory.addSearchPropertyDef(containerDef, ItemPath.create(AssignmentType.F_ACTIVATION, ActivationType.F_ADMINISTRATIVE_STATUS), defs); + SearchFactory.addSearchPropertyDef(containerDef, ItemPath.create(AssignmentType.F_ACTIVATION, ActivationType.F_EFFECTIVE_STATUS), defs); + + defs.addAll(SearchFactory.createExtensionDefinitionList(containerDef)); + + return defs; + + } + + protected QName getAssignmentType(){ + return null; + } + + protected void initCustomPaging(){ + if (getModel() == null || getModelObject() == null){ + return; + } + getAssignmentsTabStorage().setPaging(getPrismContext().queryFactory().createPaging(0, (int) getParentPage().getItemsPerPage(UserProfileStorage.TableId.ASSIGNMENTS_TAB_TABLE))); + } + + protected ObjectTabStorage getAssignmentsTabStorage(){ + if (getModel() == null || getModelObject() == null){ + return null; + } + if (isInducement()){ + return getParentPage().getSessionStorage().getInducementsTabStorage(); + } else { + return getParentPage().getSessionStorage().getAssignmentsTabStorage(); + } + } + + protected List> customPostSearch(List> assignments) { + return assignments; + } + + protected boolean isNewObjectButtonVisible(PrismObject focusObject){ + try { + return getParentPage().isAuthorized(AuthorizationConstants.AUTZ_UI_ADMIN_ASSIGN_ACTION_URI, + AuthorizationPhaseType.REQUEST, focusObject, + null, null, null); + } catch (Exception ex){ + return WebComponentUtil.isAuthorized(AuthorizationConstants.AUTZ_UI_ADMIN_ASSIGN_ACTION_URI); + } + } + + protected ObjectQuery createObjectQuery(){ + Collection delegationRelations = getParentPage().getRelationRegistry() + .getAllRelationsFor(RelationKindType.DELEGATION); + + + //do not show archetype assignments + ObjectReferenceType archetypeRef = new ObjectReferenceType(); + archetypeRef.setType(ArchetypeType.COMPLEX_TYPE); + archetypeRef.setRelation(new QName(PrismConstants.NS_QUERY, "any")); + RefFilter archetypeFilter = (RefFilter) getParentPage().getPrismContext().queryFor(AssignmentType.class) + .item(AssignmentType.F_TARGET_REF) + .ref(archetypeRef.asReferenceValue()) + .buildFilter(); + archetypeFilter.setOidNullAsAny(true); + archetypeFilter.setRelationNullAsAny(true); + + ObjectQuery query = getParentPage().getPrismContext().queryFor(AssignmentType.class) + .not() + .item(AssignmentType.F_TARGET_REF) + .refRelation(delegationRelations.toArray(new QName[0])) + .build(); + query.addFilter(getPrismContext().queryFactory().createNot(archetypeFilter)); + return query; + } + + protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target){ + } + + private List loadAssignmentTargetRelationsList(){ + OperationResult result = new OperationResult(OPERATION_LOAD_ASSIGNMENT_TARGET_RELATIONS); + List assignmentTargetRelations = new ArrayList<>(); + PrismObject obj = getMultivalueContainerListPanel().getFocusObject(); + try { + AssignmentCandidatesSpecification spec = getPageBase().getModelInteractionService() + .determineAssignmentTargetSpecification(obj, result); + assignmentTargetRelations = spec != null ? spec.getAssignmentObjectRelations() : new ArrayList<>(); + } catch (SchemaException | ConfigurationException ex){ + result.recordPartialError(ex.getLocalizedMessage()); + LOGGER.error("Couldn't load assignment target specification for the object {} , {}", obj.getName(), ex.getLocalizedMessage()); + } + return assignmentTargetRelations; + } + + private AssignmentCandidatesSpecification loadAssignmentHolderSpecification(){ + OperationResult result = new OperationResult(OPERATION_LOAD_ASSIGNMENT_HOLDER_SPECIFICATION); + PrismObject obj = getMultivalueContainerListPanel().getFocusObject(); + AssignmentCandidatesSpecification spec = null; + try { + spec = getPageBase().getModelInteractionService() + .determineAssignmentHolderSpecification(obj, result); + } catch (SchemaException | ConfigurationException ex){ + result.recordPartialError(ex.getLocalizedMessage()); + LOGGER.error("Couldn't load assignment holder specification for the object {} , {}", obj.getName(), ex.getLocalizedMessage()); + } + return spec; + } + + protected List, String>> initBasicColumns() { + List, String>> columns = new ArrayList<>(); + + columns.add(new CheckBoxHeaderColumn<>()); + + columns.add(new IconColumn>(Model.of("")) { + + private static final long serialVersionUID = 1L; + + @Override + protected DisplayType getIconDisplayType(IModel> rowModel){ + AssignmentType assignment = rowModel.getObject().getRealValue(); + LOGGER.trace("Create icon for AssignmentType: " + assignment); + if (assignment != null && assignment.getTargetRef() != null && StringUtils.isNotEmpty(assignment.getTargetRef().getOid())){ + List targetObjectList = WebComponentUtil.loadReferencedObjectList(Collections.singletonList(assignment.getTargetRef()), OPERATION_LOAD_ASSIGNMENTS_TARGET_OBJ, + AssignmentPanel.this.getPageBase()); + if (CollectionUtils.isNotEmpty(targetObjectList) && targetObjectList.size() == 1){ + ObjectType targetObject = targetObjectList.get(0); + DisplayType displayType = WebComponentUtil.getArchetypePolicyDisplayType(targetObject, AssignmentPanel.this.getPageBase()); + if (displayType != null){ + String disabledStyle; + if (targetObject instanceof FocusType) { + disabledStyle = WebComponentUtil.getIconEnabledDisabled(((FocusType)targetObject).asPrismObject()); + if (displayType.getIcon() != null && StringUtils.isNotEmpty(displayType.getIcon().getCssClass()) && + disabledStyle != null){ + displayType.getIcon().setCssClass(displayType.getIcon().getCssClass() + " " + disabledStyle); + displayType.getIcon().setColor(""); + } + } + return displayType; + } + } + } + return WebComponentUtil.createDisplayType(WebComponentUtil.createDefaultBlackIcon( + AssignmentsUtil.getTargetType(rowModel.getObject().getRealValue()))); + } + + }); + + columns.add(new LinkColumn>(createStringResource("PolicyRulesPanel.nameColumn")){ + private static final long serialVersionUID = 1L; + + @Override + protected IModel createLinkModel(IModel> rowModel) { + LOGGER.trace("Create name for AssignmentType: " + rowModel.getObject().getRealValue()); + String name = AssignmentsUtil.getName(rowModel.getObject(), getParentPage()); + LOGGER.trace("Name for AssignmentType: " + name); + if (StringUtils.isBlank(name)) { + return createStringResource("AssignmentPanel.noName"); + } + return Model.of(name); + } + + @Override + public boolean isEnabled(IModel> rowModel) { + return rowModel.getObject().getRealValue().getFocusMappings() == null; + } + + @Override + public void onClick(AjaxRequestTarget target, IModel> rowModel) { + AssignmentPanel.this.assignmentDetailsPerformed(target); + getMultivalueContainerListPanel().itemDetailsPerformed(target, rowModel); + } + }); + + columns.add(new PrismContainerWrapperColumn<>(getModel(), AssignmentType.F_ACTIVATION, getPageBase())); + + if (getAssignmentType() == null) { + columns.add(new AbstractColumn, String>(createStringResource("AssignmentPanel.moreData")) { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(Item>> cellItem, String componentId, + IModel> rowModel) { + AssignmentType assignmentType = rowModel != null && rowModel.getObject() != null ? + rowModel.getObject().getRealValue() : null; + cellItem.add(new Label(componentId, AssignmentsUtil.getAssignmentSpecificInfoLabel(assignmentType, AssignmentPanel.this.getPageBase()))); + } + }); + } + + columns.addAll(initColumns()); + List menuActionsList = getAssignmentMenuActions(); + columns.add(new InlineMenuButtonColumn>(menuActionsList, getPageBase()){ + private static final long serialVersionUID = 1L; + + @Override + protected boolean isButtonMenuItemEnabled(IModel> rowModel){ + if (rowModel != null + && ValueStatus.ADDED.equals(rowModel.getObject().getStatus())) { + return true; + } + return !isAssignmentsLimitReached(); + } + }); + return columns; + } + + protected List, String>> initColumns(){ + return new ArrayList<>(); + } + + protected void assignmentDetailsPerformed(AjaxRequestTarget target){ + } + + protected void newAssignmentClickPerformed(AjaxRequestTarget target, AssignmentObjectRelation assignmentTargetRelation){ + AssignmentPopup popupPanel = new AssignmentPopup(getPageBase().getMainPopupBodyId()) { + + private static final long serialVersionUID = 1L; + + @Override + protected void addPerformed(AjaxRequestTarget target, List newAssignmentsList) { + super.addPerformed(target, newAssignmentsList); + addSelectedAssignmentsPerformed(target, newAssignmentsList); + } + + @Override + protected List getAvailableObjectTypesList(){ + if (assignmentTargetRelation == null || CollectionUtils.isEmpty(assignmentTargetRelation.getObjectTypes())) { + return getObjectTypesList(); + } else { + return mergeNewAssignmentTargetTypeLists(assignmentTargetRelation.getObjectTypes(), getObjectTypesList()); + } + } + + @Override + protected QName getPredefinedRelation(){ + if (assignmentTargetRelation == null){ + return AssignmentPanel.this.getPredefinedRelation(); + } + return !CollectionUtils.isEmpty(assignmentTargetRelation.getRelations()) ? assignmentTargetRelation.getRelations().get(0) : null; + } + + @Override + protected List getArchetypeRefList(){ + return assignmentTargetRelation != null ? assignmentTargetRelation.getArchetypeRefs() : null; + } + + @Override + protected ObjectFilter getSubtypeFilter(){ + return AssignmentPanel.this.getSubtypeFilter(); + } + + @Override + protected boolean isEntitlementAssignment(){ + return AssignmentPanel.this.isEntitlementAssignment(); + } + + @Override + protected PrismContainerWrapper getAssignmentWrapperModel() { + return AssignmentPanel.this.getModelObject(); + } + + @Override + protected boolean isOrgTreeTabVisible(){ + return assignmentTargetRelation == null; + } + }; + popupPanel.setOutputMarkupId(true); + popupPanel.setOutputMarkupPlaceholderTag(true); + getPageBase().showMainPopup(popupPanel, target); + } + + //this is here just becasue we want to override default behaviour for GDPR assignment panel + protected QName getPredefinedRelation() { + return null; + } + + protected List getObjectTypesList(){ + if (getAssignmentType() == null) { + return WebComponentUtil.createAssignableTypesList(); + } else { + return Collections.singletonList(ObjectTypes.getObjectTypeFromTypeQName(getAssignmentType())); + } + } + + protected boolean isEntitlementAssignment(){ + return false; + } + + protected void addSelectedAssignmentsPerformed(AjaxRequestTarget target, List newAssignmentsList){ + if (newAssignmentsList == null || newAssignmentsList.isEmpty()) { + warn(getParentPage().getString("AssignmentTablePanel.message.noAssignmentSelected")); + target.add(getPageBase().getFeedbackPanel()); + return; + } + boolean isAssignmentsLimitReached = isAssignmentsLimitReached(newAssignmentsList != null ? newAssignmentsList.size() : 0, true); + if (isAssignmentsLimitReached) { + warn(getParentPage().getString("AssignmentPanel.assignmentsLimitReachedWarning", assignmentsRequestsLimit)); + target.add(getPageBase().getFeedbackPanel()); + return; + } + + newAssignmentsList.forEach(assignment -> { + + PrismContainerValue newAssignment = getModelObject().getItem().createNewValue(); + AssignmentType assignmentType = newAssignment.asContainerable(); + + if (assignment.getConstruction() != null && assignment.getConstruction().getResourceRef() != null) { + assignmentType.setConstruction(assignment.getConstruction()); + } else { + assignmentType.setTargetRef(assignment.getTargetRef()); + } + getMultivalueContainerListPanel().createNewItemContainerValueWrapper(newAssignment, getModelObject(), + target); + getMultivalueContainerListPanel().refreshTable(target); + getMultivalueContainerListPanel().reloadSavePreviewButtons(target); + + }); + + + } + + protected WebMarkupContainer getCustomSearchPanel(String contentAreaId) { + return new WebMarkupContainer(contentAreaId); + } + + private MultivalueContainerDetailsPanel createMultivalueContainerDetailsPanel(ListItem> item) { + if (isAssignmentsLimitReached()){ + item.getModelObject().setReadOnly(true, true); + } else if (item.getModelObject().isReadOnly()){ + item.getModelObject().setReadOnly(false, true); + } + + return new MultivalueContainerDetailsPanel(MultivalueContainerListPanelWithDetailsPanel.ID_ITEM_DETAILS, item.getModel()) { + + private static final long serialVersionUID = 1L; + + @Override + protected ItemVisibility getBasicTabVisibity(ItemWrapper itemWrapper) { + return AssignmentPanel.this.getContainerVisibility(itemWrapper); + } + + @Override + protected void addBasicContainerValuePanel(String idPanel) { + add(getBasicContainerPanel(idPanel, item.getModel())); + } + + @Override + protected DisplayNamePanel createDisplayNamePanel(String displayNamePanelId) { + IModel displayNameModel = getDisplayModel(item.getModelObject().getRealValue()); + return new DisplayNamePanel(displayNamePanelId, displayNameModel) { + + private static final long serialVersionUID = 1L; + + @Override + protected QName getRelation() { + return getRelationForDisplayNamePanel(item.getModelObject()); + } + + @Override + protected IModel getKindIntentLabelModel() { + return getKindIntentLabelModelForDisplayNamePanel(item.getModelObject()); + } + + }; + } + + }; + } + + protected Panel getBasicContainerPanel(String idPanel, IModel> model) { + ItemPanelSettings settings = new ItemPanelSettingsBuilder() + .visibilityHandler(this::getContainerVisibility) + .showOnTopLevel(true) + .editabilityHandler(this::getContainerReadability) + .build(); + getPageBase().initContainerValuePanel(idPanel, model, settings); + return getPageBase().initContainerValuePanel(idPanel, model, settings); + } + + protected boolean getContainerReadability(ItemWrapper wrapper) { + return true; + } + + protected ItemVisibility getContainerVisibility(ItemWrapper wrapper) { + if (QNameUtil.match(ActivationType.COMPLEX_TYPE, wrapper.getTypeName())) { + return ItemVisibility.AUTO; + } + if (QNameUtil.match(MetadataType.COMPLEX_TYPE, wrapper.getTypeName())) { + return ItemVisibility.AUTO; + } + if (QNameUtil.match(AssignmentType.F_TARGET_REF, wrapper.getItemName())) { + return ItemVisibility.HIDDEN; + } + + if (QNameUtil.match(OrderConstraintsType.COMPLEX_TYPE, wrapper.getTypeName())) { + return ItemVisibility.HIDDEN; + } + + if (QNameUtil.match(AssignmentSelectorType.COMPLEX_TYPE, wrapper.getTypeName())) { + return ItemVisibility.HIDDEN; + } + + if (QNameUtil.match(OtherPrivilegesLimitationType.COMPLEX_TYPE, wrapper.getTypeName())) { + return ItemVisibility.HIDDEN; + } + + if (QNameUtil.match(PolicyExceptionType.COMPLEX_TYPE, wrapper.getTypeName())) { + return ItemVisibility.HIDDEN; + } + + if (QNameUtil.match(AssignmentRelationType.COMPLEX_TYPE, wrapper.getTypeName())) { + return ItemVisibility.HIDDEN; + } + + if (QNameUtil.match(ExtensionType.COMPLEX_TYPE, wrapper.getTypeName())) { + return ItemVisibility.HIDDEN; + } + + ItemPath assignmentConditionPath = ItemPath.create(AssignmentHolderType.F_ASSIGNMENT, AssignmentType.F_CONDITION); + ItemPath inducementConditionPath = ItemPath.create(AbstractRoleType.F_INDUCEMENT, AssignmentType.F_CONDITION); + + ItemPath wrapperPath = wrapper.getPath().namedSegmentsOnly(); + if (assignmentConditionPath.isSubPath(wrapperPath) || inducementConditionPath.isSubPath(wrapperPath)) { + ItemPath assignmentConditionExpressionPath = ItemPath.create(AssignmentHolderType.F_ASSIGNMENT, AssignmentType.F_CONDITION, MappingType.F_EXPRESSION); + ItemPath inducementConditionExpressionPath = ItemPath.create(AbstractRoleType.F_INDUCEMENT, AssignmentType.F_CONDITION, MappingType.F_EXPRESSION); + if (wrapperPath.equivalent(assignmentConditionExpressionPath) || wrapperPath.equivalent(inducementConditionExpressionPath)) { + return ItemVisibility.AUTO; + } else { + return ItemVisibility.HIDDEN; + } + } + + if (ItemPath.create(AssignmentHolderType.F_ASSIGNMENT, AssignmentType.F_ACTIVATION, ActivationType.F_LOCKOUT_EXPIRATION_TIMESTAMP).equivalent(wrapper.getPath())) { + return ItemVisibility.HIDDEN; + } + + if (ItemPath.create(AssignmentHolderType.F_ASSIGNMENT, AssignmentType.F_ACTIVATION, ActivationType.F_LOCKOUT_STATUS).equivalent(wrapper.getPath())) { + return ItemVisibility.HIDDEN; + } + + + return getTypedContainerVisibility(wrapper); + } + + protected ItemVisibility getTypedContainerVisibility(ItemWrapper wrapper) { + return ItemVisibility.AUTO; + } + + private QName getRelationForDisplayNamePanel(PrismContainerValueWrapper modelObject) { + AssignmentType assignment = modelObject.getRealValue(); + if (assignment.getTargetRef() != null) { + return assignment.getTargetRef().getRelation(); + } else { + return null; + } + } + + private IModel getKindIntentLabelModelForDisplayNamePanel(PrismContainerValueWrapper modelObject) { + AssignmentType assignment = modelObject.getRealValue(); + if (assignment.getConstruction() != null){ + return createStringResource("DisplayNamePanel.kindIntentLabel", assignment.getConstruction().getKind(), + assignment.getConstruction().getIntent()); + } + return Model.of(); + } + + //TODO add to basic visibility + private ItemVisibility getActivationVisibileItems(ItemPath pathToCheck, ItemPath assignmentPath) { + if (assignmentPath.append(ItemPath.create(AssignmentType.F_ACTIVATION, ActivationType.F_LOCKOUT_EXPIRATION_TIMESTAMP)).equivalent(pathToCheck)) { + return ItemVisibility.HIDDEN; + } + + if (assignmentPath.append(ItemPath.create(AssignmentType.F_ACTIVATION, ActivationType.F_LOCKOUT_STATUS)).equivalent(pathToCheck)) { + return ItemVisibility.HIDDEN; + } + + return ItemVisibility.AUTO; + } + + private List mergeNewAssignmentTargetTypeLists(List allowedByAssignmentTargetSpecification, List availableTypesList){ + if (CollectionUtils.isEmpty(allowedByAssignmentTargetSpecification)){ + return availableTypesList; + } + if (CollectionUtils.isEmpty(availableTypesList)){ + return availableTypesList; + } + List mergedList = new ArrayList<>(); + allowedByAssignmentTargetSpecification.forEach(qnameValue -> { + ObjectTypes objectTypes = ObjectTypes.getObjectTypeFromTypeQName(qnameValue); + for (ObjectTypes availableObjectTypes : availableTypesList) { + if (availableObjectTypes.getClassDefinition().equals(objectTypes.getClassDefinition())) { + mergedList.add(objectTypes); + break; + } + } + }); + return mergedList; + } + + private IModel getDisplayModel(AssignmentType assignment){ + return (IModel) () -> { + if (assignment.getTargetRef() != null && assignment.getTargetRef().getOid() != null) { + Task task = getPageBase().createSimpleTask("Load target"); + OperationResult result = task.getResult(); + PrismObject targetObject = WebModelServiceUtils.loadObject(assignment.getTargetRef(), getPageBase(), task, result); + return targetObject != null ? (C) targetObject.asObjectable() : null; + } + if (assignment.getConstruction() != null && assignment.getConstruction().getResourceRef() != null) { + Task task = getPageBase().createSimpleTask("Load resource"); + OperationResult result = task.getResult(); + return (C) WebModelServiceUtils.loadObject(assignment.getConstruction().getResourceRef(), getPageBase(), task, result).asObjectable(); + } else if (assignment.getPersonaConstruction() != null) { + return (C) assignment.getPersonaConstruction(); + } else if (assignment.getPolicyRule() !=null) { + return (C) assignment.getPolicyRule(); + } + return null; + }; + } + + private List getAssignmentMenuActions() { + List menuItems = new ArrayList<>(); + PrismObject obj = getMultivalueContainerListPanel().getFocusObject(); + try { + boolean isUnassignAuthorized = getParentPage().isAuthorized(AuthorizationConstants.AUTZ_UI_ADMIN_UNASSIGN_ACTION_URI, + AuthorizationPhaseType.REQUEST, obj, + null, null, null); + if (isUnassignAuthorized) { + menuItems.add(new ButtonInlineMenuItem(getAssignmentsLimitReachedTitleModel("pageAdminFocus.menu.unassign")) { + private static final long serialVersionUID = 1L; + + @Override + public String getButtonIconCssClass() { + return GuiStyleConstants.CLASS_DELETE_MENU_ITEM; + } + + @Override + public InlineMenuItemAction initAction() { + return getMultivalueContainerListPanel().createDeleteColumnAction(); + } + }); + } + + } catch (Exception ex){ + LOGGER.error("Couldn't check unassign authorization for the object: {}, {}", obj.getName(), ex.getLocalizedMessage()); + if (WebComponentUtil.isAuthorized(AuthorizationConstants.AUTZ_UI_ADMIN_ASSIGN_ACTION_URI)){ + menuItems.add(new ButtonInlineMenuItem(createStringResource("PageBase.button.unassign")) { + private static final long serialVersionUID = 1L; + + @Override + public String getButtonIconCssClass() { + return GuiStyleConstants.CLASS_DELETE_MENU_ITEM; + } + + @Override + public InlineMenuItemAction initAction() { + return getMultivalueContainerListPanel().createDeleteColumnAction(); + } + }); + } + } + menuItems.add(new ButtonInlineMenuItem(createStringResource("PageBase.button.edit")) { + private static final long serialVersionUID = 1L; + + @Override + public String getButtonIconCssClass() { + return GuiStyleConstants.CLASS_EDIT_MENU_ITEM; + } + + @Override + public InlineMenuItemAction initAction() { + return getMultivalueContainerListPanel().createEditColumnAction(); + } + }); + menuItems.add(new ButtonInlineMenuItem(createStringResource("AssignmentPanel.viewTargetObject")) { + private static final long serialVersionUID = 1L; + + @Override + public String getButtonIconCssClass() { + return GuiStyleConstants.CLASS_NAVIGATE_ARROW; + } + + @Override + public InlineMenuItemAction initAction() { + return new ColumnMenuAction>() { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + PrismContainerValueWrapper assignmentContainer = getRowModel().getObject(); + PrismReferenceWrapper targetRef; + try { + targetRef = assignmentContainer.findReference(ItemPath.create(AssignmentType.F_TARGET_REF)); + } catch (SchemaException e) { + getSession().error("Couldn't show details page. More information provided in log."); + LOGGER.error("Couldn't show detials page, no targetRef reference wrapper found: {}", e.getMessage(), e); + target.add(getPageBase().getFeedbackPanel()); + return; + } + + if (targetRef != null && targetRef.getValues() != null && targetRef.getValues().size() > 0) { + PrismReferenceValueWrapperImpl refWrapper = targetRef.getValues().get(0); + if (!StringUtils.isEmpty(refWrapper.getNewValue().getOid())) { + Class targetClass = ObjectTypes.getObjectTypeFromTypeQName(refWrapper.getRealValue().getType()).getClassDefinition(); + WebComponentUtil.dispatchToObjectDetailsPage(targetClass, refWrapper.getNewValue().getOid(), AssignmentPanel.this, false); + } + } + } + }; + } + + @Override + public boolean isHeaderMenuItem(){ + return false; + } + }); + return menuItems; + } + + protected MultivalueContainerListPanelWithDetailsPanel getMultivalueContainerListPanel() { + return ((MultivalueContainerListPanelWithDetailsPanel)get(ID_ASSIGNMENTS)); + } + + //TODO override for each type ? + protected TableId getTableId() { + return UserProfileStorage.TableId.ASSIGNMENTS_TAB_TABLE; + } + + protected PageBase getParentPage() { + return getPageBase(); + } + + private IModel getAssignmentsLimitReachedTitleModel(String defaultTitleKey) { + return new LoadableModel(true) { + @Override + protected String load() { + return isAssignmentsLimitReached() ? + AssignmentPanel.this.getPageBase().createStringResource("RoleCatalogItemButton.assignmentsLimitReachedTitle", + assignmentsRequestsLimit).getString() : createStringResource(defaultTitleKey).getString(); + } + }; + } + + protected boolean isAssignmentsLimitReached() { + return isAssignmentsLimitReached(0, false); + } + + protected boolean isAssignmentsLimitReached(int selectedAssignmentsCount, boolean actionPerformed) { + if (assignmentsRequestsLimit < 0){ + return false; + } + int changedItems = 0; + List> assignmentsList = getModelObject().getValues(); + for (PrismContainerValueWrapper assignment : assignmentsList){ + if (assignment.hasChanged()){ + changedItems++; + } + } + return actionPerformed ? (changedItems + selectedAssignmentsCount) > assignmentsRequestsLimit : + (changedItems + selectedAssignmentsCount) >= assignmentsRequestsLimit; + } + + protected boolean isInducement(){ + return getModelObject() != null && getModelObject().getPath().containsNameExactly(AbstractRoleType.F_INDUCEMENT); + } + + protected ObjectFilter getSubtypeFilter(){ + return null; + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/GdprAssignmentPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/GdprAssignmentPanel.java index 85f0f394739..d875bcbcc02 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/GdprAssignmentPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/GdprAssignmentPanel.java @@ -7,8 +7,12 @@ package com.evolveum.midpoint.web.component.assignment; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import com.evolveum.midpoint.gui.api.util.WebComponentUtil; +import com.evolveum.midpoint.schema.constants.ObjectTypes; + import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; @@ -22,6 +26,8 @@ import com.evolveum.midpoint.web.component.data.column.CheckBoxColumn; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; +import javax.xml.namespace.QName; + public class GdprAssignmentPanel extends AbstractRoleAssignmentPanel { private static final long serialVersionUID = 1L; @@ -79,6 +85,11 @@ public Boolean getObject() { // super.addSelectedAssignmentsPerformed(target, assignmentsList, SchemaConstants.ORG_CONSENT, kind, intent); // } + @Override + protected QName getPredefinedRelation() { + return SchemaConstants.ORG_CONSENT; + } + protected ObjectQuery createObjectQuery() { return getParentPage().getPrismContext().queryFor(AssignmentType.class) .block() @@ -87,4 +98,9 @@ protected ObjectQuery createObjectQuery() { .endBlock() .build(); } + + @Override + protected List getObjectTypesList() { + return Arrays.asList(ObjectTypes.ROLE, ObjectTypes.ORG, ObjectTypes.SERVICE); + } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/SelfConsentPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/SelfConsentPanel.java index 2bbd3cfded9..b38c2719588 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/SelfConsentPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/SelfConsentPanel.java @@ -6,6 +6,15 @@ */ package com.evolveum.midpoint.web.component.assignment; +import com.evolveum.midpoint.prism.delta.ObjectDelta; + +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.web.security.util.SecurityUtils; +import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; + import org.apache.commons.lang3.StringUtils; import org.apache.wicket.RestartResponseException; import org.apache.wicket.ajax.AjaxRequestTarget; @@ -34,6 +43,8 @@ public class SelfConsentPanel extends BasePanel { private static final long serialVersionUID = 1L; + private static final transient Trace LOGGER = TraceManager.getTrace(SelfConsentPanel.class); + private static final String ID_DISPLAY_NAME = "displayName"; private static final String ID_DESCRIPTION = "description"; private static final String ID_CONSENT_ICON = "consentIcon"; @@ -45,6 +56,7 @@ public class SelfConsentPanel extends BasePanel { private static final String DOT_CLASS = SelfConsentPanel.class.getSimpleName() + "."; private static final String OPERATION_LOAD_TARGET = DOT_CLASS + "loadTargetRef"; + private static final String OPERATION_SAVE_CONSENT_DECISION = DOT_CLASS + "saveCOnsentDecision"; // private PageBase parentPage; public SelfConsentPanel(String id, IModel model, PageBase parentPage) { @@ -92,6 +104,7 @@ private void initLayout(final AbstractRoleType abstractRole) { @Override public void onClick(AjaxRequestTarget target) { SelfConsentPanel.this.getModelObject().setLifecycleState(SchemaConstants.LIFECYCLE_FAILED); + saveConsentDecision(target, SchemaConstants.LIFECYCLE_FAILED); target.add(SelfConsentPanel.this); } }; @@ -105,6 +118,7 @@ public void onClick(AjaxRequestTarget target) { @Override public void onClick(AjaxRequestTarget target) { SelfConsentPanel.this.getModelObject().setLifecycleState(SchemaConstants.LIFECYCLE_ACTIVE); + saveConsentDecision(target, SchemaConstants.LIFECYCLE_ACTIVE); target.add(SelfConsentPanel.this); } }; @@ -118,6 +132,7 @@ public void onClick(AjaxRequestTarget target) { @Override public void onClick(AjaxRequestTarget target) { SelfConsentPanel.this.getModelObject().setLifecycleState(SchemaConstants.LIFECYCLE_FAILED); + saveConsentDecision(target, SchemaConstants.LIFECYCLE_FAILED); target.add(SelfConsentPanel.this); } }; @@ -126,6 +141,23 @@ public void onClick(AjaxRequestTarget target) { } + protected void saveConsentDecision(AjaxRequestTarget target, String newLifecycleState) { + OperationResult result = new OperationResult(OPERATION_SAVE_CONSENT_DECISION); + try { + ObjectDelta delta = getPageBase().getPrismContext().deltaFor(UserType.class) + .property(ItemPath.create(getModelObject().asPrismContainerValue().getPath(), AssignmentType.F_LIFECYCLE_STATE)) + .replace(newLifecycleState).asObjectDelta(SecurityUtils.getPrincipalUser().getOid()); + WebModelServiceUtils.save(delta, result, getPageBase()); + } catch (SchemaException e) { + LOGGER.error("Cannot save consent decision {}, reason: {}", newLifecycleState, e.getMessage(), e); + result.recordFatalError("Failed to save consent decision, " + e.getMessage()); + } + + result.computeStatusIfUnknown(); + getPageBase().showResult(result, false); + target.add(getPageBase().getFeedbackPanel()); + } + private VisibleEnableBehaviour createActiveConsentBehaviour() { return new VisibleEnableBehaviour() { private static final long serialVersionUID = 1L; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/SwitchAssignmentTypePanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/SwitchAssignmentTypePanel.html index ef3599e7beb..f530e600b94 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/SwitchAssignmentTypePanel.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/SwitchAssignmentTypePanel.html @@ -18,7 +18,7 @@
- +
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/SwitchAssignmentTypePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/SwitchAssignmentTypePanel.java index 857dc22e3ba..1021d9bc5c2 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/SwitchAssignmentTypePanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/SwitchAssignmentTypePanel.java @@ -1,575 +1,583 @@ -/* - * Copyright (c) 2018 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ -package com.evolveum.midpoint.web.component.assignment; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.xml.namespace.QName; - -import com.evolveum.midpoint.gui.api.page.PageBase; -import com.evolveum.midpoint.gui.api.prism.ItemWrapper; -import com.evolveum.midpoint.gui.api.prism.PrismObjectWrapper; -import com.evolveum.midpoint.web.component.AjaxIconButton; -import com.evolveum.midpoint.web.component.objectdetails.AssignmentHolderTypeAssignmentsTabPanel; -import com.evolveum.midpoint.web.component.prism.ItemVisibility; -import com.evolveum.midpoint.web.page.admin.PageAdminFocus; -import com.evolveum.midpoint.web.page.admin.users.component.AllAssignmentsPreviewDialog; -import com.evolveum.midpoint.web.page.admin.users.component.AssignmentInfoDto; -import com.evolveum.midpoint.xml.ns._public.common.common_3.*; -import org.apache.commons.lang.StringUtils; -import org.apache.wicket.Component; -import org.apache.wicket.ajax.AjaxRequestTarget; -import org.apache.wicket.behavior.AttributeAppender; -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.extensions.markup.html.repeater.data.table.IColumn; -import org.apache.wicket.markup.html.WebMarkupContainer; -import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.repeater.Item; -import org.apache.wicket.model.IModel; -import org.apache.wicket.model.Model; - -import com.evolveum.midpoint.gui.api.component.BasePanel; -import com.evolveum.midpoint.gui.api.model.LoadableModel; -import com.evolveum.midpoint.gui.api.prism.PrismContainerWrapper; -import com.evolveum.midpoint.gui.api.util.WebComponentUtil; -import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; -import com.evolveum.midpoint.gui.impl.prism.PrismContainerValueWrapper; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.query.ObjectQuery; -import com.evolveum.midpoint.web.component.AjaxButton; -import com.evolveum.midpoint.web.component.data.column.IconColumn; -import com.evolveum.midpoint.web.component.util.VisibleBehaviour; - -/** - * Created by honchar - */ -public class SwitchAssignmentTypePanel extends BasePanel> { - private static final long serialVersionUID = 1L; - - private static final String ID_ASSIGNMENT_TYPE_BUTTONS = "assignmentTypeButtons"; - private static final String ID_ALL_ASSIGNMENTS = "allAssignments"; - private static final String ID_ROLE_TYPE_ASSIGNMENTS = "roleTypeAssignments"; - private static final String ID_ORG_TYPE_ASSIGNMENTS = "orgTypeAssignments"; - private static final String ID_SERVICE_TYPE_ASSIGNMENTS = "serviceTypeAssignments"; - private static final String ID_RESOURCE_TYPE_ASSIGNMENTS = "resourceTypeAssignments"; - private static final String ID_POLICY_RULE_TYPE_ASSIGNMENTS = "policyRuleTypeAssignments"; - private static final String ID_ENTITLEMENT_ASSIGNMENTS = "entitlementAssignments"; - private static final String ID_FOCUS_MAPPING_ASSIGNMENTS = "focusMappingAssignments"; - private static final String ID_CONSENT_ASSIGNMENTS = "consentAssignments"; - private static final String ID_SHOW_INDIRECT_ASSIGNMENTS = "showIndirectAssignmentsButton"; - private static final String ID_ASSIGNMENTS = "assignmentsPanel"; - private static final String ID_DATA_PROTECTION_ASSIGNMENTS = "dataProtectionAssignments"; - - private String activeButtonId = ID_ALL_ASSIGNMENTS; - - public SwitchAssignmentTypePanel(String id, IModel> assignmentContainerWrapperModel) { - super(id, assignmentContainerWrapperModel); - } - - @Override - protected void onInitialize(){ - super.onInitialize(); - add(new VisibleBehaviour(() -> getModelObject() != null)); - initButtonsPanel(); - initAssignmentsPanel(); - - setOutputMarkupId(true); - } - - private void initButtonsPanel(){ - WebMarkupContainer buttonsContainer = new WebMarkupContainer(ID_ASSIGNMENT_TYPE_BUTTONS); - buttonsContainer.setOutputMarkupId(true); - buttonsContainer.add(new VisibleBehaviour(() -> ID_SHOW_INDIRECT_ASSIGNMENTS.equals(activeButtonId) || - getButtonsContainerVisibilityModel().getObject())); - add(buttonsContainer); - - AjaxButton allAssignmentsButton = new AjaxButton(ID_ALL_ASSIGNMENTS, createStringResource("AssignmentPanel.allLabel")) { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - AssignmentPanel assignmentPanel = - new AssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()) { - private static final long serialVersionUID = 1L; - - @Override - protected void assignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected boolean isNewObjectButtonVisible(PrismObject focusObject){ - return !isReadonly() && super.isNewObjectButtonVisible(focusObject); - } - - }; - assignmentPanel.setOutputMarkupId(true); - switchAssignmentTypePerformed(target, assignmentPanel, ID_ALL_ASSIGNMENTS); - } - }; - allAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_ALL_ASSIGNMENTS))); - allAssignmentsButton.setOutputMarkupId(true); - allAssignmentsButton.setOutputMarkupPlaceholderTag(true); - buttonsContainer.add(allAssignmentsButton); - - AjaxButton roleTypeAssignmentsButton = new AjaxButton(ID_ROLE_TYPE_ASSIGNMENTS, createStringResource("ObjectType.RoleType")) { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - AbstractRoleAssignmentPanel assignmentPanel = - new AbstractRoleAssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()) { - private static final long serialVersionUID = 1L; - - @Override - protected QName getAssignmentType() { - return RoleType.COMPLEX_TYPE; - } - - @Override - protected void assignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected boolean isNewObjectButtonVisible(PrismObject focusObject){ - return !isReadonly() && super.isNewObjectButtonVisible(focusObject); - } - - }; - assignmentPanel.setOutputMarkupId(true); - switchAssignmentTypePerformed(target, assignmentPanel, ID_ROLE_TYPE_ASSIGNMENTS); - } - }; - roleTypeAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_ROLE_TYPE_ASSIGNMENTS))); - roleTypeAssignmentsButton.setOutputMarkupId(true); - buttonsContainer.add(roleTypeAssignmentsButton); - - AjaxButton orgTypeAssignmentsButton = new AjaxButton(ID_ORG_TYPE_ASSIGNMENTS, createStringResource("ObjectType.OrgType")) { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - AbstractRoleAssignmentPanel assignmentPanel = - new AbstractRoleAssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()) { - private static final long serialVersionUID = 1L; - - @Override - protected QName getAssignmentType() { - return OrgType.COMPLEX_TYPE; - } - - @Override - protected void assignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected boolean isNewObjectButtonVisible(PrismObject focusObject){ - return !isReadonly() && super.isNewObjectButtonVisible(focusObject); - } - }; - assignmentPanel.setOutputMarkupId(true); - switchAssignmentTypePerformed(target, assignmentPanel, ID_ORG_TYPE_ASSIGNMENTS); - } - }; - orgTypeAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_ORG_TYPE_ASSIGNMENTS))); - orgTypeAssignmentsButton.setOutputMarkupId(true); - buttonsContainer.add(orgTypeAssignmentsButton); - - AjaxButton serviceTypeAssignmentsButton = new AjaxButton(ID_SERVICE_TYPE_ASSIGNMENTS, createStringResource("ObjectType.ServiceType")) { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - AbstractRoleAssignmentPanel assignmentPanel = - new AbstractRoleAssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()) { - private static final long serialVersionUID = 1L; - - @Override - protected QName getAssignmentType() { - return ServiceType.COMPLEX_TYPE; - } - - @Override - protected void assignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected boolean isNewObjectButtonVisible(PrismObject focusObject){ - return !isReadonly() && super.isNewObjectButtonVisible(focusObject); - } - }; - assignmentPanel.setOutputMarkupId(true); - switchAssignmentTypePerformed(target, assignmentPanel, ID_SERVICE_TYPE_ASSIGNMENTS); - - } - }; - serviceTypeAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_SERVICE_TYPE_ASSIGNMENTS))); - serviceTypeAssignmentsButton.setOutputMarkupId(true); - buttonsContainer.add(serviceTypeAssignmentsButton); - - AjaxButton resourceTypeAssignmentsButton = new AjaxButton(ID_RESOURCE_TYPE_ASSIGNMENTS, createStringResource("ObjectType.ResourceType")) { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - ConstructionAssignmentPanel constructionsPanel = - new ConstructionAssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()){ - private static final long serialVersionUID = 1L; - - @Override - protected void assignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected boolean isNewObjectButtonVisible(PrismObject focusObject){ - return !isReadonly() && super.isNewObjectButtonVisible(focusObject); - } - }; - constructionsPanel.setOutputMarkupId(true); - switchAssignmentTypePerformed(target, constructionsPanel, ID_RESOURCE_TYPE_ASSIGNMENTS); - } - }; - resourceTypeAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_RESOURCE_TYPE_ASSIGNMENTS))); - resourceTypeAssignmentsButton.setOutputMarkupId(true); - buttonsContainer.add(resourceTypeAssignmentsButton); - - AjaxButton policyRuleTypeAssignmentsButton = new AjaxButton(ID_POLICY_RULE_TYPE_ASSIGNMENTS, createStringResource("AssignmentType.policyRule")) { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - PolicyRulesPanel policyRulesPanel = - new PolicyRulesPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()){ - private static final long serialVersionUID = 1L; - - @Override - protected void assignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected boolean isNewObjectButtonVisible(PrismObject focusObject){ - return !isReadonly() && super.isNewObjectButtonVisible(focusObject); - } - } ; - policyRulesPanel.setOutputMarkupId(true); - switchAssignmentTypePerformed(target, policyRulesPanel, ID_POLICY_RULE_TYPE_ASSIGNMENTS); - - } - }; - policyRuleTypeAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_POLICY_RULE_TYPE_ASSIGNMENTS))); - policyRuleTypeAssignmentsButton.setOutputMarkupId(true); - - policyRuleTypeAssignmentsButton.add(new VisibleBehaviour(() -> isAssignmentPanelVisible())); - - buttonsContainer.add(policyRuleTypeAssignmentsButton); - - AjaxButton dataProtectionButton = new AjaxButton(ID_DATA_PROTECTION_ASSIGNMENTS, createStringResource("pageAdminFocus.dataProtection")) { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - GenericAbstractRoleAssignmentPanel dataProtectionPanel = - new GenericAbstractRoleAssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()) { - private static final long serialVersionUID = 1L; - - @Override - protected void assignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected boolean isNewObjectButtonVisible(PrismObject focusObject){ - return !isReadonly() && super.isNewObjectButtonVisible(focusObject); - } - }; - dataProtectionPanel.setOutputMarkupId(true); - switchAssignmentTypePerformed(target, dataProtectionPanel, ID_DATA_PROTECTION_ASSIGNMENTS); - - } - }; - dataProtectionButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_DATA_PROTECTION_ASSIGNMENTS))); - dataProtectionButton.setOutputMarkupId(true); - dataProtectionButton.add(new VisibleBehaviour(() -> - WebModelServiceUtils.isEnableExperimentalFeature(SwitchAssignmentTypePanel.this.getPageBase()))); - buttonsContainer.add(dataProtectionButton); - - AjaxButton entitlementAssignmentsButton = new AjaxButton(ID_ENTITLEMENT_ASSIGNMENTS, createStringResource("AbstractRoleMainPanel.inducedEntitlements")) { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - InducedEntitlementsPanel entitlementAssignments = - new InducedEntitlementsPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()) { - private static final long serialVersionUID = 1L; - - @Override - protected void assignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - }; - entitlementAssignments.setOutputMarkupId(true); - switchAssignmentTypePerformed(target, entitlementAssignments, ID_ENTITLEMENT_ASSIGNMENTS); - - } - }; - entitlementAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_ENTITLEMENT_ASSIGNMENTS))); - entitlementAssignmentsButton.setOutputMarkupId(true); - - entitlementAssignmentsButton.add(new VisibleBehaviour(() -> isAssignmentPanelVisible() && isInducement())); - buttonsContainer.add(entitlementAssignmentsButton); - - AjaxButton focusMappingAssignmentsButton = new AjaxButton(ID_FOCUS_MAPPING_ASSIGNMENTS, createStringResource("AssignmentType.focusMappings")) { - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget target) { - AssignmentPanel assignmentPanel = - new AssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()) { - private static final long serialVersionUID = 1L; - - //TODO may be we will need FocusMappingsAssignmentsPanel later - @Override - protected List, String>> initBasicColumns() { - List, String>> columns = new ArrayList<>(); - - columns.add(new IconColumn>(Model.of("")) { - - private static final long serialVersionUID = 1L; - - @Override - protected DisplayType getIconDisplayType(IModel> rowModel) { - return WebComponentUtil.createDisplayType(WebComponentUtil.createDefaultBlackIcon( - AssignmentsUtil.getTargetType(rowModel.getObject().getRealValue()))); - } - - }); - - columns.add(new AbstractColumn, String>(createStringResource("PolicyRulesPanel.nameColumn")){ - private static final long serialVersionUID = 1L; - - @Override - public void populateItem(Item>> cellItem, - String componentId, final IModel> rowModel) { - String name = AssignmentsUtil.getName(rowModel.getObject(), getParentPage()); - if (StringUtils.isBlank(name)) { - name = createStringResource("AssignmentPanel.noName").getString(); - } - cellItem.add(new Label(componentId, Model.of(name))); - } - }); - return columns; - } - - @Override - protected ObjectQuery createObjectQuery(){ - ObjectQuery query = super.createObjectQuery(); - ObjectQuery focusMappingsQuery = SwitchAssignmentTypePanel.this.getPageBase().getPrismContext() - .queryFor(AssignmentType.class) - .exists(AssignmentType.F_FOCUS_MAPPINGS) - .build(); - query.addFilter(focusMappingsQuery.getFilter()); - return query; - } - - @Override - protected boolean isNewObjectButtonVisible(PrismObject focusObject){ - return false; - } - - @Override - protected QName getAssignmentType() { - return AssignmentType.F_FOCUS_MAPPINGS; - } - - }; - assignmentPanel.setOutputMarkupId(true); - switchAssignmentTypePerformed(target, assignmentPanel, ID_FOCUS_MAPPING_ASSIGNMENTS); - } - }; - focusMappingAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_FOCUS_MAPPING_ASSIGNMENTS))); - focusMappingAssignmentsButton.setOutputMarkupId(true); - - focusMappingAssignmentsButton.add(new VisibleBehaviour(() -> isAssignmentPanelVisible())); - buttonsContainer.add(focusMappingAssignmentsButton); - - //GDPR feature.. temporary disabled MID-4281 -// AjaxButton consentsButton = new AjaxButton(ID_CONSENT_ASSIGNMENTS, createStringResource("FocusType.consents")) { -// private static final long serialVersionUID = 1L; -// -// @Override -// public void onClick(AjaxRequestTarget target) { -// GdprAssignmentPanel gdprAssignmentPanel = -// new GdprAssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()){ -// private static final long serialVersionUID = 1L; -// -// @Override -// protected void assignmentDetailsPerformed(AjaxRequestTarget target) { -// target.add(SwitchAssignmentTypePanel.this); -// } -// -// @Override -// protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { -// target.add(SwitchAssignmentTypePanel.this); -// } -// }; -// gdprAssignmentPanel.setOutputMarkupId(true); -// SwitchAssignmentTypePanel.this.addOrReplace(gdprAssignmentPanel); -// target.add(SwitchAssignmentTypePanel.this); -// } -// }; -// consentsButton.setOutputMarkupId(true); -// buttonsContainer.add(consentsButton); - - AjaxIconButton showAllAssignmentsButton = new AjaxIconButton(ID_SHOW_INDIRECT_ASSIGNMENTS, new Model<>("fa fa-address-card"), - createStringResource("AssignmentTablePanel.menu.showAllAssignments")) { - - private static final long serialVersionUID = 1L; - - @Override - public void onClick(AjaxRequestTarget ajaxRequestTarget) { - showAllAssignments(ajaxRequestTarget); - } - }; - showAllAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_SHOW_INDIRECT_ASSIGNMENTS))); - showAllAssignmentsButton.setOutputMarkupId(true); - - showAllAssignmentsButton.add(new VisibleBehaviour(() -> !isInducement())); - buttonsContainer.add(showAllAssignmentsButton); - - } - - protected void showAllAssignments(AjaxRequestTarget target) { - PageBase pageBase = getPageBase(); - List previewAssignmentsList; - if (pageBase instanceof PageAdminFocus) { - previewAssignmentsList = ((PageAdminFocus) pageBase).showAllAssignmentsPerformed(target); - } else { - previewAssignmentsList = Collections.emptyList(); - } - AllAssignmentsPreviewDialog assignmentPanel = new AllAssignmentsPreviewDialog(ID_ASSIGNMENTS, previewAssignmentsList, - pageBase); - assignmentPanel.setOutputMarkupId(true); - switchAssignmentTypePerformed(target, assignmentPanel, ID_SHOW_INDIRECT_ASSIGNMENTS); - } - - private boolean isAssignmentPanelVisible() { - if (getModelObject() == null){ - return false; - } - PrismObjectWrapper objectWrapper = getModelObject().findObjectWrapper(); - if (objectWrapper == null ) { - return true; - } - return objectWrapper.getObject().asObjectable() instanceof AbstractRoleType; - } - - private LoadableModel getButtonsContainerVisibilityModel(){ - return new LoadableModel() { - @Override - protected Boolean load() { - return getAssignmentsPanel().getMultivalueContainerListPanel().isListPanelVisible(); - } - }; - } - - private void switchAssignmentTypePerformed(AjaxRequestTarget target, Component assignmentsPanel, String buttonId){ - activeButtonId = buttonId; - addOrReplace(assignmentsPanel); - target.add(SwitchAssignmentTypePanel.this); - } - - private LoadableModel getButtonStyleModel(String buttonId){ - return new LoadableModel() { - @Override - protected String load() { - if (activeButtonId.equals(buttonId)){ - return "btn btn-primary"; - } else { - return "btn btn-default"; - } - } - }; - } - - private void initAssignmentsPanel(){ - AssignmentPanel assignmentsPanel = new AssignmentPanel(ID_ASSIGNMENTS, getModel()){ - private static final long serialVersionUID = 1L; - - @Override - protected void assignmentDetailsPerformed(AjaxRequestTarget target) { - target.add(SwitchAssignmentTypePanel.this); - } - - @Override - protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target){ - target.add(SwitchAssignmentTypePanel.this); - } - }; - assignmentsPanel.setOutputMarkupId(true); - add(assignmentsPanel); - } - - public AssignmentPanel getAssignmentsPanel(){ - return (AssignmentPanel) get(ID_ASSIGNMENTS); - } - - protected boolean isInducement(){ - return false; - } - - protected boolean isReadonly(){ - return false; - } -} +/* + * Copyright (c) 2018 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.web.component.assignment; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import com.evolveum.midpoint.gui.api.page.PageBase; +import com.evolveum.midpoint.gui.api.prism.ItemWrapper; +import com.evolveum.midpoint.gui.api.prism.PrismObjectWrapper; +import com.evolveum.midpoint.web.component.AjaxIconButton; +import com.evolveum.midpoint.web.component.objectdetails.AssignmentHolderTypeAssignmentsTabPanel; +import com.evolveum.midpoint.web.component.prism.ItemVisibility; +import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; +import com.evolveum.midpoint.web.page.admin.PageAdminFocus; +import com.evolveum.midpoint.web.page.admin.users.component.AllAssignmentsPreviewDialog; +import com.evolveum.midpoint.web.page.admin.users.component.AssignmentInfoDto; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import org.apache.commons.lang.StringUtils; +import org.apache.wicket.Component; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.behavior.AttributeAppender; +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.extensions.markup.html.repeater.data.table.IColumn; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; + +import com.evolveum.midpoint.gui.api.component.BasePanel; +import com.evolveum.midpoint.gui.api.model.LoadableModel; +import com.evolveum.midpoint.gui.api.prism.PrismContainerWrapper; +import com.evolveum.midpoint.gui.api.util.WebComponentUtil; +import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; +import com.evolveum.midpoint.gui.impl.prism.PrismContainerValueWrapper; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.web.component.AjaxButton; +import com.evolveum.midpoint.web.component.data.column.IconColumn; +import com.evolveum.midpoint.web.component.util.VisibleBehaviour; + +/** + * Created by honchar + */ +public class SwitchAssignmentTypePanel extends BasePanel> { + private static final long serialVersionUID = 1L; + + private static final String ID_ASSIGNMENT_TYPE_BUTTONS = "assignmentTypeButtons"; + private static final String ID_ALL_ASSIGNMENTS = "allAssignments"; + private static final String ID_ROLE_TYPE_ASSIGNMENTS = "roleTypeAssignments"; + private static final String ID_ORG_TYPE_ASSIGNMENTS = "orgTypeAssignments"; + private static final String ID_SERVICE_TYPE_ASSIGNMENTS = "serviceTypeAssignments"; + private static final String ID_RESOURCE_TYPE_ASSIGNMENTS = "resourceTypeAssignments"; + private static final String ID_POLICY_RULE_TYPE_ASSIGNMENTS = "policyRuleTypeAssignments"; + private static final String ID_ENTITLEMENT_ASSIGNMENTS = "entitlementAssignments"; + private static final String ID_FOCUS_MAPPING_ASSIGNMENTS = "focusMappingAssignments"; + private static final String ID_CONSENT_ASSIGNMENTS = "consentAssignments"; + private static final String ID_SHOW_INDIRECT_ASSIGNMENTS = "showIndirectAssignmentsButton"; + private static final String ID_ASSIGNMENTS = "assignmentsPanel"; + private static final String ID_DATA_PROTECTION_ASSIGNMENTS = "dataProtectionAssignments"; + + private String activeButtonId = ID_ALL_ASSIGNMENTS; + + public SwitchAssignmentTypePanel(String id, IModel> assignmentContainerWrapperModel) { + super(id, assignmentContainerWrapperModel); + } + + @Override + protected void onInitialize(){ + super.onInitialize(); + add(new VisibleBehaviour(() -> getModelObject() != null)); + initButtonsPanel(); + initAssignmentsPanel(); + + setOutputMarkupId(true); + } + + private void initButtonsPanel(){ + WebMarkupContainer buttonsContainer = new WebMarkupContainer(ID_ASSIGNMENT_TYPE_BUTTONS); + buttonsContainer.setOutputMarkupId(true); + buttonsContainer.add(new VisibleBehaviour(() -> ID_SHOW_INDIRECT_ASSIGNMENTS.equals(activeButtonId) || + getButtonsContainerVisibilityModel().getObject())); + add(buttonsContainer); + + AjaxButton allAssignmentsButton = new AjaxButton(ID_ALL_ASSIGNMENTS, createStringResource("AssignmentPanel.allLabel")) { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + AssignmentPanel assignmentPanel = + new AssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()) { + private static final long serialVersionUID = 1L; + + @Override + protected void assignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected boolean isNewObjectButtonVisible(PrismObject focusObject){ + return !isReadonly() && super.isNewObjectButtonVisible(focusObject); + } + + }; + assignmentPanel.setOutputMarkupId(true); + switchAssignmentTypePerformed(target, assignmentPanel, ID_ALL_ASSIGNMENTS); + } + }; + allAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_ALL_ASSIGNMENTS))); + allAssignmentsButton.setOutputMarkupId(true); + allAssignmentsButton.setOutputMarkupPlaceholderTag(true); + buttonsContainer.add(allAssignmentsButton); + + AjaxButton roleTypeAssignmentsButton = new AjaxButton(ID_ROLE_TYPE_ASSIGNMENTS, createStringResource("ObjectType.RoleType")) { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + AbstractRoleAssignmentPanel assignmentPanel = + new AbstractRoleAssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()) { + private static final long serialVersionUID = 1L; + + @Override + protected QName getAssignmentType() { + return RoleType.COMPLEX_TYPE; + } + + @Override + protected void assignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected boolean isNewObjectButtonVisible(PrismObject focusObject){ + return !isReadonly() && super.isNewObjectButtonVisible(focusObject); + } + + }; + assignmentPanel.setOutputMarkupId(true); + switchAssignmentTypePerformed(target, assignmentPanel, ID_ROLE_TYPE_ASSIGNMENTS); + } + }; + roleTypeAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_ROLE_TYPE_ASSIGNMENTS))); + roleTypeAssignmentsButton.setOutputMarkupId(true); + buttonsContainer.add(roleTypeAssignmentsButton); + + AjaxButton orgTypeAssignmentsButton = new AjaxButton(ID_ORG_TYPE_ASSIGNMENTS, createStringResource("ObjectType.OrgType")) { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + AbstractRoleAssignmentPanel assignmentPanel = + new AbstractRoleAssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()) { + private static final long serialVersionUID = 1L; + + @Override + protected QName getAssignmentType() { + return OrgType.COMPLEX_TYPE; + } + + @Override + protected void assignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected boolean isNewObjectButtonVisible(PrismObject focusObject){ + return !isReadonly() && super.isNewObjectButtonVisible(focusObject); + } + }; + assignmentPanel.setOutputMarkupId(true); + switchAssignmentTypePerformed(target, assignmentPanel, ID_ORG_TYPE_ASSIGNMENTS); + } + }; + orgTypeAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_ORG_TYPE_ASSIGNMENTS))); + orgTypeAssignmentsButton.setOutputMarkupId(true); + buttonsContainer.add(orgTypeAssignmentsButton); + + AjaxButton serviceTypeAssignmentsButton = new AjaxButton(ID_SERVICE_TYPE_ASSIGNMENTS, createStringResource("ObjectType.ServiceType")) { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + AbstractRoleAssignmentPanel assignmentPanel = + new AbstractRoleAssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()) { + private static final long serialVersionUID = 1L; + + @Override + protected QName getAssignmentType() { + return ServiceType.COMPLEX_TYPE; + } + + @Override + protected void assignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected boolean isNewObjectButtonVisible(PrismObject focusObject){ + return !isReadonly() && super.isNewObjectButtonVisible(focusObject); + } + }; + assignmentPanel.setOutputMarkupId(true); + switchAssignmentTypePerformed(target, assignmentPanel, ID_SERVICE_TYPE_ASSIGNMENTS); + + } + }; + serviceTypeAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_SERVICE_TYPE_ASSIGNMENTS))); + serviceTypeAssignmentsButton.setOutputMarkupId(true); + buttonsContainer.add(serviceTypeAssignmentsButton); + + AjaxButton resourceTypeAssignmentsButton = new AjaxButton(ID_RESOURCE_TYPE_ASSIGNMENTS, createStringResource("ObjectType.ResourceType")) { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + ConstructionAssignmentPanel constructionsPanel = + new ConstructionAssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()){ + private static final long serialVersionUID = 1L; + + @Override + protected void assignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected boolean isNewObjectButtonVisible(PrismObject focusObject){ + return !isReadonly() && super.isNewObjectButtonVisible(focusObject); + } + }; + constructionsPanel.setOutputMarkupId(true); + switchAssignmentTypePerformed(target, constructionsPanel, ID_RESOURCE_TYPE_ASSIGNMENTS); + } + }; + resourceTypeAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_RESOURCE_TYPE_ASSIGNMENTS))); + resourceTypeAssignmentsButton.setOutputMarkupId(true); + buttonsContainer.add(resourceTypeAssignmentsButton); + + AjaxButton policyRuleTypeAssignmentsButton = new AjaxButton(ID_POLICY_RULE_TYPE_ASSIGNMENTS, createStringResource("AssignmentType.policyRule")) { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + PolicyRulesPanel policyRulesPanel = + new PolicyRulesPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()){ + private static final long serialVersionUID = 1L; + + @Override + protected void assignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected boolean isNewObjectButtonVisible(PrismObject focusObject){ + return !isReadonly() && super.isNewObjectButtonVisible(focusObject); + } + } ; + policyRulesPanel.setOutputMarkupId(true); + switchAssignmentTypePerformed(target, policyRulesPanel, ID_POLICY_RULE_TYPE_ASSIGNMENTS); + + } + }; + policyRuleTypeAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_POLICY_RULE_TYPE_ASSIGNMENTS))); + policyRuleTypeAssignmentsButton.setOutputMarkupId(true); + + policyRuleTypeAssignmentsButton.add(new VisibleBehaviour(() -> isAssignmentPanelVisible())); + + buttonsContainer.add(policyRuleTypeAssignmentsButton); + + AjaxButton dataProtectionButton = new AjaxButton(ID_DATA_PROTECTION_ASSIGNMENTS, createStringResource("pageAdminFocus.dataProtection")) { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + GenericAbstractRoleAssignmentPanel dataProtectionPanel = + new GenericAbstractRoleAssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()) { + private static final long serialVersionUID = 1L; + + @Override + protected void assignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected boolean isNewObjectButtonVisible(PrismObject focusObject){ + return !isReadonly() && super.isNewObjectButtonVisible(focusObject); + } + }; + dataProtectionPanel.setOutputMarkupId(true); + switchAssignmentTypePerformed(target, dataProtectionPanel, ID_DATA_PROTECTION_ASSIGNMENTS); + + } + }; + dataProtectionButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_DATA_PROTECTION_ASSIGNMENTS))); + dataProtectionButton.setOutputMarkupId(true); + dataProtectionButton.add(new VisibleBehaviour(() -> + WebModelServiceUtils.isEnableExperimentalFeature(SwitchAssignmentTypePanel.this.getPageBase()))); + buttonsContainer.add(dataProtectionButton); + + AjaxButton entitlementAssignmentsButton = new AjaxButton(ID_ENTITLEMENT_ASSIGNMENTS, createStringResource("AbstractRoleMainPanel.inducedEntitlements")) { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + InducedEntitlementsPanel entitlementAssignments = + new InducedEntitlementsPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()) { + private static final long serialVersionUID = 1L; + + @Override + protected void assignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + }; + entitlementAssignments.setOutputMarkupId(true); + switchAssignmentTypePerformed(target, entitlementAssignments, ID_ENTITLEMENT_ASSIGNMENTS); + + } + }; + entitlementAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_ENTITLEMENT_ASSIGNMENTS))); + entitlementAssignmentsButton.setOutputMarkupId(true); + + entitlementAssignmentsButton.add(new VisibleBehaviour(() -> isAssignmentPanelVisible() && isInducement())); + buttonsContainer.add(entitlementAssignmentsButton); + + AjaxButton focusMappingAssignmentsButton = new AjaxButton(ID_FOCUS_MAPPING_ASSIGNMENTS, createStringResource("AssignmentType.focusMappings")) { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + AssignmentPanel assignmentPanel = + new AssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()) { + private static final long serialVersionUID = 1L; + + //TODO may be we will need FocusMappingsAssignmentsPanel later + @Override + protected List, String>> initBasicColumns() { + List, String>> columns = new ArrayList<>(); + + columns.add(new IconColumn>(Model.of("")) { + + private static final long serialVersionUID = 1L; + + @Override + protected DisplayType getIconDisplayType(IModel> rowModel) { + return WebComponentUtil.createDisplayType(WebComponentUtil.createDefaultBlackIcon( + AssignmentsUtil.getTargetType(rowModel.getObject().getRealValue()))); + } + + }); + + columns.add(new AbstractColumn, String>(createStringResource("PolicyRulesPanel.nameColumn")){ + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(Item>> cellItem, + String componentId, final IModel> rowModel) { + String name = AssignmentsUtil.getName(rowModel.getObject(), getParentPage()); + if (StringUtils.isBlank(name)) { + name = createStringResource("AssignmentPanel.noName").getString(); + } + cellItem.add(new Label(componentId, Model.of(name))); + } + }); + return columns; + } + + @Override + protected ObjectQuery createObjectQuery(){ + ObjectQuery query = super.createObjectQuery(); + ObjectQuery focusMappingsQuery = SwitchAssignmentTypePanel.this.getPageBase().getPrismContext() + .queryFor(AssignmentType.class) + .exists(AssignmentType.F_FOCUS_MAPPINGS) + .build(); + query.addFilter(focusMappingsQuery.getFilter()); + return query; + } + + @Override + protected boolean isNewObjectButtonVisible(PrismObject focusObject){ + return false; + } + + @Override + protected QName getAssignmentType() { + return AssignmentType.F_FOCUS_MAPPINGS; + } + + }; + assignmentPanel.setOutputMarkupId(true); + switchAssignmentTypePerformed(target, assignmentPanel, ID_FOCUS_MAPPING_ASSIGNMENTS); + } + }; + focusMappingAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_FOCUS_MAPPING_ASSIGNMENTS))); + focusMappingAssignmentsButton.setOutputMarkupId(true); + + focusMappingAssignmentsButton.add(new VisibleBehaviour(() -> isAssignmentPanelVisible())); + buttonsContainer.add(focusMappingAssignmentsButton); + + //GDPR feature.. temporary disabled MID-4281 + AjaxIconButton consentsButton = new AjaxIconButton(ID_CONSENT_ASSIGNMENTS, createStringResource("fa fa-legal"), createStringResource("FocusType.consents")) { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + GdprAssignmentPanel gdprAssignmentPanel = + new GdprAssignmentPanel(ID_ASSIGNMENTS, SwitchAssignmentTypePanel.this.getModel()){ + private static final long serialVersionUID = 1L; + + @Override + protected void assignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + }; + gdprAssignmentPanel.setOutputMarkupId(true); + SwitchAssignmentTypePanel.this.addOrReplace(gdprAssignmentPanel); + target.add(SwitchAssignmentTypePanel.this); + } + }; + consentsButton.setOutputMarkupId(true); + consentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_SHOW_INDIRECT_ASSIGNMENTS))); + consentsButton.add(new VisibleEnableBehaviour() { + @Override + public boolean isVisible() { + return WebModelServiceUtils.isEnableExperimentalFeature(getPageBase()); + } + }); + buttonsContainer.add(consentsButton); + + AjaxIconButton showAllAssignmentsButton = new AjaxIconButton(ID_SHOW_INDIRECT_ASSIGNMENTS, new Model<>("fa fa-address-card"), + createStringResource("AssignmentTablePanel.menu.showAllAssignments")) { + + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget ajaxRequestTarget) { + showAllAssignments(ajaxRequestTarget); + } + }; + showAllAssignmentsButton.add(AttributeAppender.append("class", getButtonStyleModel(ID_SHOW_INDIRECT_ASSIGNMENTS))); + showAllAssignmentsButton.setOutputMarkupId(true); + + showAllAssignmentsButton.add(new VisibleBehaviour(() -> !isInducement())); + buttonsContainer.add(showAllAssignmentsButton); + + } + + protected void showAllAssignments(AjaxRequestTarget target) { + PageBase pageBase = getPageBase(); + List previewAssignmentsList; + if (pageBase instanceof PageAdminFocus) { + previewAssignmentsList = ((PageAdminFocus) pageBase).showAllAssignmentsPerformed(target); + } else { + previewAssignmentsList = Collections.emptyList(); + } + AllAssignmentsPreviewDialog assignmentPanel = new AllAssignmentsPreviewDialog(ID_ASSIGNMENTS, previewAssignmentsList, + pageBase); + assignmentPanel.setOutputMarkupId(true); + switchAssignmentTypePerformed(target, assignmentPanel, ID_SHOW_INDIRECT_ASSIGNMENTS); + } + + private boolean isAssignmentPanelVisible() { + if (getModelObject() == null){ + return false; + } + PrismObjectWrapper objectWrapper = getModelObject().findObjectWrapper(); + if (objectWrapper == null ) { + return true; + } + return objectWrapper.getObject().asObjectable() instanceof AbstractRoleType; + } + + private LoadableModel getButtonsContainerVisibilityModel(){ + return new LoadableModel() { + @Override + protected Boolean load() { + return getAssignmentsPanel().getMultivalueContainerListPanel().isListPanelVisible(); + } + }; + } + + private void switchAssignmentTypePerformed(AjaxRequestTarget target, Component assignmentsPanel, String buttonId){ + activeButtonId = buttonId; + addOrReplace(assignmentsPanel); + target.add(SwitchAssignmentTypePanel.this); + } + + private LoadableModel getButtonStyleModel(String buttonId){ + return new LoadableModel() { + @Override + protected String load() { + if (activeButtonId.equals(buttonId)){ + return "btn btn-primary"; + } else { + return "btn btn-default"; + } + } + }; + } + + private void initAssignmentsPanel(){ + AssignmentPanel assignmentsPanel = new AssignmentPanel(ID_ASSIGNMENTS, getModel()){ + private static final long serialVersionUID = 1L; + + @Override + protected void assignmentDetailsPerformed(AjaxRequestTarget target) { + target.add(SwitchAssignmentTypePanel.this); + } + + @Override + protected void cancelAssignmentDetailsPerformed(AjaxRequestTarget target){ + target.add(SwitchAssignmentTypePanel.this); + } + }; + assignmentsPanel.setOutputMarkupId(true); + add(assignmentsPanel); + } + + public AssignmentPanel getAssignmentsPanel(){ + return (AssignmentPanel) get(ID_ASSIGNMENTS); + } + + protected boolean isInducement(){ + return false; + } + + protected boolean isReadonly(){ + return false; + } +} diff --git a/gui/admin-gui/src/main/resources/static/less/midpoint-theme.less b/gui/admin-gui/src/main/resources/static/less/midpoint-theme.less index bf562371a0d..c21bfff8e23 100644 --- a/gui/admin-gui/src/main/resources/static/less/midpoint-theme.less +++ b/gui/admin-gui/src/main/resources/static/less/midpoint-theme.less @@ -1,1618 +1,1618 @@ -/* - * Copyright (c) 2010-2020 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ - -@import "midpoint-theme-variables.less"; - -body.custom-hold-transition { - .content-wrapper, - .right-side, - .main-footer, - .main-sidebar, - .left-side, - .main-header .navbar, - .main-header .logo { - -webkit-transition: none !important; - -moz-transition: none !important; - -ms-transition: none !important; - -o-transition: none !important; - } -} - -.main-header { - & .logo { - - & > span { - height: 100%; - width: 100%; - display: inline-block; - background: url("../img/midpoint_logo_white_180.png") no-repeat 10px 3px; - } - } - & .custom-logo { - - & > img { - display:block; - float:left; - padding-left: 10px; - vertical-align: middle; - max-height: 50px; - } - } - -} - -#wicketDebugLink { - bottom: 55px !important; -} - -div.wicket-debug-buttons { - border: 1px solid #000000; - background-color: #ffffff; - opacity: 0.7; - bottom: 85px; - display: block; - position: fixed; - right: 10px; - z-index: 1000000; - - a { - color: #0000ff; - display: block; - padding: 3px 20px; - } -} - -div.navbar-custom-menu { - margin-right: 14px; -} - -//Used in top right locale combo selection -div.btn-group.bootstrap-select.select-picker-sm { - margin-top: 10px; -} - -// for just to use fake form.form-inline (as div) in form.form-horizontal. Used in button bars. -div.form-inline > div.form-group { - margin-left: 0; - margin-right: 0; -} - -li.dropdown.user.user-menu { - & > ul.dropdown-menu { - border-color: #367fa9; - right: 0; - left: auto; - - & > li.user-footer { - border-color: #367fa9; - border-bottom-right-radius: 4px; - border-bottom-left-radius: 4px; - } - } -} - -//table context menu border fix -th.cog, td.cog { - & ul.dropdown-menu.pull-right { - border-color: #337ab7; - } -} -//end table context menu border fix - -//disabled menu css fixes -.sidebar-menu .treeview-menu > li > span { - display: block; - font-size: 14px; - padding: 5px 5px 5px 15px; -} - -.sidebar-menu .treeview-menu > li > span > .fa, -.sidebar-menu .treeview-menu > li > span > .fe, -.sidebar-menu .treeview-menu > li > span > .glyphicon, -.sidebar-menu .treeview-menu > li > span > .ion { - width: 20px; -} - -.sidebar-menu > .header { - // white-space: wrap is problematic in firefox, it wraps expand/collapse icon on next line - white-space: normal !important; -} - -.sidebar-menu > li > a > .fe { - width: 20px; -} - -.sidebar-form, .sidebar-menu > li.header { - padding: 10px 20px 10px 15px; - text-transform: uppercase; - - & i.fa, & i.fe { - margin-top: 2px; - } -} - -body .treeview-menu > li.active > span, -body .treeview-menu > li > span:hover { - color: #000; -} -//end of disabled menu css fixes - -.user-thumbnail-helper { - display: inline-block; - height: 100%; - vertical-align: middle; -} - -.user-thumbnail { - background-color: #FFFFFF; - border-radius: 4px; - height: auto; - max-width: 100%; - max-height: 100%; - vertical-align: middle; -} - -.userpanel-icon-helper { - display: inline-block; - height: 100%; - vertical-align: middle; -} - -.userpanel-icon { - background-color: #FFFFFF; - border-radius: 35%; - //height: 25px; - //width: 25px; - max-width: 25px; - max-height: 25px; - vertical-align: middle; -} - -.userpanel-photo { - background-color: #FFFFFF; - border-radius: 35%; - max-height: 115px; - max-width: 115px; - vertical-align: middle; -} - -// Classes that can be used to change icon styles (enabled, disabled, privileged, etc.) - -.icon-style-normal { - -} - -.icon-style-disabled { - color: #909090; -} - -.icon-style-archived { - color: #c0c0c0; -} - -.icon-style-privileged { - color: #a94442; -} - -.icon-style-end-user { - color: #357ca5; -} - -.icon-style-manager { - color: @object-org-color; -} - -.icon-style-warning { - color: #8a6d3b; -} - -.icon-style-up { - color: #00a65a; -} - -.icon-style-down { - color: #a94442; -} - -.icon-style-broken { - color: #f39c12; -} - -// Classes that can be added to color icons, info boxes and other widgets for particular object types - -.object-user-color { - color: @object-user-color; -} - -.object-role-color { - color: @object-role-color; -} - -.object-org-color { - color: @object-org-color; -} - -.object-service-color { - color: @object-service-color; -} - -.object-resource-color { - color: @object-resource-color; -} - -.object-task-color { - color: @object-task-color; -} - -.object-shadow-color { - color: @object-shadow-color; -} - - -.object-user-bg { - background-color: @object-user-color !important; - color: #fff !important; -} - -.object-role-bg { - background-color: @object-role-color !important; - color: #fff !important; -} - -.object-org-bg { - background-color: @object-org-color !important; - color: #fff !important; -} - -.object-service-bg { - background-color: @object-service-color !important; - color: #fff !important; -} - -.object-resource-bg { - background-color: @object-resource-color !important; - color: #fff !important; -} - -.object-task-bg { - background-color: @object-task-color !important; - color: #fff !important; -} - -.object-task-bg-gray { - background-color: #646464 !important; - color: #fff !important; -} - -.object-shadow-bg { - background-color: @object-shadow-color !important; - color: #fff !important; -} - -.object-disabled-bg { - background-color: @object-disabled-color !important; - color: #fff !important; -} - -.object-access-bg { - background-color: @object-access-color !important; - color: #fff !important; -} - -.object-failed-bg { - background-color: @object-failed-color !important; - color: #fff !important; -} - -.object-access-only-bg { - background-color: @object-access-color !important; -} - -.object-failed-only-bg { - background-color: @object-failed-color !important; -} - -// Colored boxes for each object type - -#box-object(@color) { - border-top-color: @color; - - &.box-solid { - border: 1px solid @color; - } - - &.box-solid > .box-header { - color: #fff; - background: @color; - background-color: @color; - } - -} - -.object-user-box { - #box-object(@object-user-color); -} - -.object-role-box { - #box-object(@object-role-color); -} - -.object-org-box { - #box-object(@object-org-color); -} - -.object-service-box { - #box-object(@object-service-color); -} - -.object-task-box { - #box-object(@object-task-color); -} - -.object-resource-box { - #box-object(@object-resource-color); -} - -.object-shadow-box { - #box-object(@object-shadow-color); -} - -#box-thin-object(@color) { - border: 1px solid @color; - - .box-header { - border-bottom: 1px solid @color; - } -} - -.object-user-box-thin { - #box-thin-object(@object-user-color); -} - -.object-role-box-thin { - #box-thin-object(@object-role-color); -} - -.object-org-box-thin { - #box-thin-object(@object-org-color); -} - -.object-service-box-thin { - #box-thin-object(@object-service-color); -} - -.object-resource-box-thin { - #box-thin-object(@object-resource-color); -} - -.object-shadow-box-thin { - #box-thin-object(@object-shadow-color); -} - -.object-task-box-thin { - #box-thin-object(@object-task-color); -} - -// Summary panel (panel above the edit user/role/org forms) - -#info-box-summary-panel(@color) { - border-top: 3px solid @color; - min-height: 93px; -} - -.info-box.summary-panel-user { - #info-box-summary-panel(@object-user-color); -} - -.info-box.summary-panel-role { - #info-box-summary-panel(@object-role-color); -} - -.info-box.summary-panel-org { - #info-box-summary-panel(@object-org-color); -} - -.info-box.summary-panel-service { - #info-box-summary-panel(@object-service-color); -} - -.info-box.summary-panel-resource { - #info-box-summary-panel(@object-resource-color); -} - -.info-box.summary-panel-shadow { - #info-box-summary-panel(@object-shadow-color); -} - -.info-box.summary-panel-task { - #info-box-summary-panel(@object-task-color); -} - -#info-box-icon-summary-panel(@color){ - color: #FFF !important; - background-color: @color; - padding: 3px; - white-space: nowrap; - text-align: center; - line-height: 0px; - border-radius: 0; -} - -.info-box-icon.summary-panel-user { - #info-box-icon-summary-panel(@object-user-color); -} - -.info-box-icon.summary-panel-role { - #info-box-icon-summary-panel(@object-role-color); -} - -.info-box-icon.summary-panel-org { - #info-box-icon-summary-panel(@object-org-color); -} - -.info-box-icon.summary-panel-service { - #info-box-icon-summary-panel(@object-service-color); -} - -.info-box-icon.summary-panel-resource { - #info-box-icon-summary-panel(@object-resource-color); -} - -.info-box-icon.summary-panel-shadow { - #info-box-icon-summary-panel(@object-shadow-color); -} - -.info-box-icon.summary-panel-task { - #info-box-icon-summary-panel(@object-task-color); -} - -// other info box enhancements (e.g. role assignment) - -.info-box-ethereal { - // "lighter" info box, without the border or any heavy decorations - box-shadow: none; - border: none; -} - -.info-box-icon-ethereal { - background-color: transparent; -} - -.info-box-icon-ethereal-image { - font-size: 56px; -} - -.info-box-description { - display: block; - font-weight: normal; - font-size: 14px; -} - -.relation-label { - -} - -// End-user home (PageSelfDashboard) - -.quicksearch-panel { - margin-bottom: 20px; -} - -// assignments dashboard panel -.dash-assignment-header { - - .target-name { - font-weight: bold; - margin-right: 5px; - } - - .target-display-name { - - } - - .target-relation { - margin-left: 10px; - } -} - -// Admin dashboard - -.dashboard-info-box { - > div > .info-box { - cursor: pointer; - } -} - - -// Datables/lists (BoxedTablePanel) -.boxed-table { - margin-bottom: 0px; - - &.without-box-header-top-border { - border-top: 0px; - } - - table { - // prohibit overflow of the table beyond the bounding box - table-layout: fixed; - } -} - - -.boxed-table-footer-button-toolbar { - display: inline-block; -} - -.boxed-table-footer-paging { - display: block; - float: right; - - .btn-group { - margin-left: 10px; - vertical-align: top; - } - - .paging_bootstrap { - display: inline-block; - } - - .dataTables_info { - margin-right: 10px; - display: inline-block; - vertical-align: top; - } -} - -.boxed-table-footer-paging-center { - display: block; - - .btn-group { - margin-left: 10px; - vertical-align: top; - } - - .paging_bootstrap { - display: inline-block; - } - - .dataTables_info { - margin-right: 10px; - display: inline-block; - vertical-align: top; - } -} - -// capability buttons in resource details page - -.btn-resource-capability { - width: 90px; - height: 75px; - padding-top: 10px; - white-space: normal; -} - -// resource content pages (ResourceContentPanel) - -.resource-content-selection { - - .form-group { - margin-bottom: 5px; - } -} - -.control-suffix { - text-align: left !important; - padding-left: 0px; -} - -// Feedback messages ??? - -.feedback-message.box { - box-shadow: 0 0px 0px rgba(0, 0, 0, 0.1); - word-break: inherit; -} - -.feedback-message.box-body { - padding-top : 5px; - padding-left : 10px; - padding-right : 0px; - padding-bottom : 0px; -} - -.feedback-message.box.box-solid.box-danger { - border-left: 3px solid #dd4b39; - border-right : 0px; - border-top : 0px; - border-bottom : 0px; -} - - -.feedback-message.box.box-solid.box-success { - border-left: 3px solid #00a65a; - border-right : 0px; - border-top : 0px; - border-bottom : 0px; -} - -.feedback-message.box.box-solid.box-info { - border-left: 3px solid #00c0ef; - border-right : 0px; - border-top : 0px; - border-bottom : 0px; -} - -.feedback-message.box.box-solid.box-warning { - border-left: 3px solid #f39c12; - border-right : 0px; - border-top : 0px; - border-bottom : 0px; -} - -.feedback-message.dl-horizontal { - - & dt { - width: 100px; - } -} - - -.feedback-message.dl-horizontal { - - & dd { - margin-left: 130px; - word-break: break-word; - } -} - -.feedback-message .icon { - margin-right: 10px; -} - -.feedback-message { - & .box-header .box-title { - font-size: 14px; - } - - & .box-header { - border-radius: 0 3px 3px 0; - } -} - -.summary-panel-display-name { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - display: inline; - max-width: 800px; - } - -.summary-panel-navigation-button { - display: inline; - margin-left: 10px; - color: @text-dimmed-color; -} - -.summary-panel-navigation-button:hover { - display: inline; - margin-left: 10px; - color: @text-dark-dimmed-color; -} - -.summary-panel-identifier { - white-space: pre-wrap; - color: @text-dimmed-color; - font-weight: normal; -} - -.summary-panel-title { - white-space: pre-wrap; -} - -.summary-panel-organization { - font-size: 16px; - display: block; - white-space: pre-wrap; -} - -.summary-content-box { - display: block; -} - -.summary-text-box { - display: inline-block; -} - -.summary-tag-box { - float: right; -} - -.summary-tag-box-wide { - float: right; - width: 200px; -} - -.summary-tag { - display: block; - padding-left: 10px; - padding-right: 10px; - margin: 3px; - border: 1px solid #e0e0e0; - border-radius: 3px; - background-color: #fbfbfb; - margin-right: 0px; -} - -.summary-tag-icon { - width: 20px; - margin-right: 2px; -} - -// form input for binary data upload (used e.g. for photo) - -.form-object-value-binary-box { - width: 100%; - padding: 0px; -} - -.form-object-value-binary-file-input { - width: 65%; - vertical-align: middle; - display: inline !important; -} - - - -// top navigation bar: page title - -.navbar-title { - float: left; - background-color: transparent; - padding-top: 8px; -} - -.navbar-ajax { - float: left; - - & #ajax_busy { - margin-top: 12px; - margin-left: 8px; - } -} - -.page-title { - color: #fff; - background-color: transparent; - font-size: 22px; -} - -.navbar-custom-menu > .breadcrumb { - float: left; - background: transparent; - margin-top: 10px; - margin-bottom: 0; - margin-right: 20px; - font-size: 12px; - padding: 7px 5px; - - //.border-radius(2px); - - > li > a { - color: #444; - text-decoration: none; - display: inline-block; - - > .fa, > .glyphicon, > .ion, > .fe { - margin-right: 5px; - } - } - - > li + li:before { - content: '>\00a0'; - padding: 0 0 0 5px; - } - - //@media (max-width: @screen-sm-max) { - // > .breadcrumb { - // position: relative; - // margin-top: 5px; - // top: 0; - // right: 0; - // float: none; - // background: @gray; - // padding-left: 10px; - // - // li:before { - // color: darken(@gray, 20%); - // } - // } - //} -} - -// Prism containers and attributes - -.prism-object { - & > div.prism-header { - padding-left: 15px; // to match container header padding - } -} - -.prism-multivalue-container { - margin-left: 15px; // aligning multivalue container with superior container -} - -.top-level-prism-container { - border-top: 1px solid #ddd; - padding-top: 5px; -} - -.multivalue-container > .container-wrapper > div { - padding-left: 40px; -} - -//top-level-prism-container is class for first showed container -.top-level-prism-container > .container-wrapper > div > div > -.prism-properties > .prism-containers { - padding-left: 0px; //align one-level containers -} - -//top-level-prism-container is class for first showed container -.top-level-prism-container > .container-wrapper > div > div > -.prism-properties > .prism-containers > .prism-property { - border-top: 1px solid #ddd; // line over area of container -} - -.prism-containers > .top-level-prism-container > .container-wrapper > div > div > .prism-properties > .prism-containers { - padding-left: 40px; -} -.prism-containers > .top-level-prism-container > .container-wrapper > div > div > .prism-properties > .prism-containers > .prism-property { - border-top: 0px solid #ddd; -} - - - -.top-level-prism-container .row { - margin-right: 0px; - margin-left: 0px; -} - -.top-level-prism-container .prism-header { - margin-bottom: 0px; - padding-top: 5px; - padding-bottom: 5px; -} - -.prism-container { -// border-bottom: 1px solid @table-divider-color; - margin-bottom: 15px; - padding-bottom: 15px; -} - -.multivalue-container > .container-wrapper > div > .added-value-background { - background-color: #dff0d8; // green background for new value of multivalue container -} - -.multivalue-container > .container-wrapper > div > .removed-value-background { - background-color: #f2dede; // green background for new value of multivalue container -} - -.top-level-prism-container > .prism-properties > div { - padding-left: 0px; -} - -.prism-properties { - - & > div { - padding-left: 40px; - } - - .stripe { - background-color: @table-stripe-bg-color; - } -} -.prism-header { - margin-bottom: 15px; - display: block; -} - -.prism-title { - font-size: 16px; - font-weight: 600; - color: @text-label-color; - margin-right: 15px; - float: left; - padding-top: 3px; -} - -.prism-property { - padding-top: 5px; - padding-bottom: 5px; -} - -.prism-property-label { //padding because expand collapse button, which have 37px - padding-left: 20px; - word-wrap:break-word; - padding-top: 5px; -} - -.prism-value { // DEPRECATED: rework the prism-value vs prism-property-value later - margin-top: 3px; -} - -// Common styles for object detail pages - -.assignable-header { - border-bottom: 2px solid @table-divider-color; - margin: 0px; - margin-bottom: 10px; - padding-left: 5px; // align with the checkboxes below - - div.col-xs-10 { - padding: 0 5px; - - & > input { - display: inline-block; - } - - > h3 { - display: inline-block; - margin-bottom: 5px; - margin-left: 5px; - } - } - - & > div.cog { - margin-top: 18px; - padding-right: 5px; - } -} - -.check-table-header { - padding-left: 20px; - - & > input[type="checkbox"] { - position: absolute; - margin-left: -20px; - margin-top: 6px; - } - - .check-table-label { - - .check-table-header-icon { - margin-left: 4px; - position: relative; - bottom: 1px; - } - - .check-table-header-name { - margin-left: 5px; - font-size: 18px; - color: @text-label-color !important; - } - - .check-table-header-description { - margin-left: 10px; - } - - .check-table-header-status { - margin-left: 10px; - position: relative; - bottom: 2px; - } - - .check-table-header-show-more { - color: @text-dimmed-color !important; - } - - .delegation-arrow-icon { - font-size: 24px; - margin-left: 5px; - margin-right: 5px; - position: relative; - top: 3px; - } - } -} - -.tab-label { - & > small { - margin-left: 6px; - position: relative; - top: -1px; - } -} - -.box-header.add { - background-color: #caffca; -} - -.box-header.delete { - background-color: #ffcaca; -} - -.main-form-panel { // Used on pages where there is just one main panel and it does not - // provide formatting by itself. E.g. pages that are both object lists - // and forms (such as workitems, requests). - margin-bottom: 20px; -} - -.options-container { - -} - -.option-checkbox { - float: left; - border: 1px solid @table-divider-color; - margin-right: 10px; - padding-bottom: 5px; - padding-left: 6px; - padding-right: 6px; -} - -.main-button-bar { - -} - -// Badge colors used in object details tabs (and maybe elsewhere) - -.badge-active { - background-color: #3c8dbc !important; -} - -.badge-passive { - color: #fff; - background-color: #d2d6de !important; -} - -// Projections tab (focus pages) - -.projections { - -} - -.projections-header { - -} - -.projection { - margin-bottom: 10px; - #box-thin-object(@object-shadow-color); - - .box-header { - - .box-tools { - margin-top: 5px; - } - } -} - -.check-table-header-pending-operation { - margin-left: 10px; -} - -// Assignments tab (focus pages) - -.assignments { - -} - -.assignment { - margin-bottom: 10px; - - .box-header { - - .box-tools { - margin-top: 5px; - } - } -} - -// Orgtree (OrgMemberPanel) - -span.tree-content > table { - width: 100%; - max-width: 100%; -} - -span.tree-content > table tr td:last-child { - width: 1%; - vertical-align: top; -} - -span.tree-content > table tr td:first-child { - width: 1%; - vertical-align: top; -} - -.tree-theme-windows > div > .tree-branch > .tree-node.success, .tree-subtree > .tree-branch > .tree-node.success{ - background-color: #dff0d8; -} - -.tree-subtree > .tree-branch:nth-of-type(odd) { - background-color: #f9f9f9; -} - -.tree-subtree > .tree-branch > .tree-node:hover, .tree-theme-windows > div > .tree-branch > .tree-node:hover { - background-color: #eee; -} - -.org-tree-container { - overflow-y: auto; -} - -.org-members-additional-search { - text-align: right; - margin-right: 20px !important; -} - -.org-managers-box { - - .box-body { - padding-top: 13px; - padding-bottom: 0px; - } -} - -.org-members-box { - - .box-body { - padding-top: 13px; - } -} - - -.manager-tools { // org tree manager buttons: HACK, need to figure out something better - float: right; - width: 42px; - padding-left: 10px; - padding-top: 7px; -} - -.manager-btn { // org tree manager buttons: HACK, need to figure out something better - margin: 3px; - border-style: solid; - border-width: 1px; - border-radius: 3px; - padding: 3px; - width: 23px; - text-align: center; -} - -.box-solid > .box-header > .box-tools > .cog > ul > li > a > i { - color: #fff; -} - - -// Request role page - -.request-role-col-available { - padding-right: 0px; -} - -.request-role-col-control { - -} - -.request-role-col-current { - padding-left: 0px; -} - -.request-role-box { - .box-body { - padding-bottom: 0px; - } -} - -.multiple-assignment-selector { - - .multiple-assignment-selector-section:first-child { - border-top-width: 0px; - padding-top: 0px; - min-height: 36px; - } - - .multiple-assignment-selector-section:last-child { - padding-bottom: 0px; - } -} - -.multiple-assignment-selector-section { - min-height: 48px; - padding-top: 8px; - padding-bottom: 8px; - border-top: 2px solid @table-divider-color; -} - -.multiple-assignment-selector-section-table { - .box { - border-width: 0px; - } -} - -.multiple-assignment-selector-table-container { - min-height: 415px; -} - -.multiple-assignment-selector-table { - width: 100%; -} - -.multiple-assignment-selector-table-footer { - float: left; -} - -.request-role-control-button { - &.btn-primary > i { - font-size: 32px; - } -} - -// Password change dialog (ChangePasswordPanel, PasswordPanel) - -.password-panel { -} - -.password-propagation { - margin-top: 5px; -} - -.password-propagation-legend { - padding-bottom: 10px; - border-bottom: 1px solid @table-divider-color; - margin-bottom: 10px; - margin-left: 0px; - margin-right: 0px; -} - -// operation result - -.paramtable { - border: 0px; - - .paramtable-row { - - .paramtable-name { - vertical-align: top; - } - - .paramtable-name::after { - content: ':'; - } - - .paramtable-value { - padding-left: 5px; - padding-right: 20px; - white-space: pre-wrap; - word-break: break-all; - } - } -} - -.stacktrace { - font-family: monospace; - white-space: pre-wrap; - font-size: 11px; -} - -dd.stacktrace::before { - content: none; -} - -// Shopping cart - -.shopping-cart-item-table { - margin-top: 10px; - margin-left: 0px; - margin-right: 0px; - min-height: 460px; -} - -.shopping-cart-icon { - color: #f4f4f4; - margin-top: 10px; - margin-right: 5px; -} - -.shopping-cart-item-box { - - .inner { - height: 120px; - cursor: pointer; - } - - .inner-label { - font-size: 18px; - padding-top: 10px; - padding-left: 12px; - padding-right: 12px; - padding-bottom: 10px; - max-width: 80%; - overflow: hidden; - text-overflow: ellipsis - } - .inner-description { - font-size: 11px; - padding-left: 12px; - padding-right: 12px; - max-width: 70%; - max-height: 50%; - overflow: hidden; - text-overflow: ellipsis - } -} - -.shopping-cart-item-box-footer { - padding: 3px; - padding-left: 8px; - padding-right: 8px; - color: rgba(255, 255, 255, 0.8); - display: block; - z-index: 10; - overflow-y: auto; - background: rgba(0, 0, 0, 0.1); - - .shopping-cart-item-button-details { - cursor: pointer; - } - - .shopping-cart-item-button-details-disabled { - cursor: default; - color: darkgrey; - } - - .shopping-cart-item-button-add { - cursor: pointer; - float: right; - } - - .shopping-cart-item-button-add-disabled { - cursor: default; - float: right; - color: darkgrey; - } -} - -// Object merge dialog - -.object-merge-panel { - padding-top: 10px; - padding-bottom: 10px; -} - -.object-merge-equation-panel { - padding-top: 10px; -} - -.object-merge-sign { - font-size: 80px; - padding-top: 15px; -} - -.object-merge-switch-direction-col { - padding-left: 0px; -} - -// Consent, mostly self-service pages - -.consent-info-box-icon { - background: none; -} - -.consent-buttons { // maybe figure out something better, something really reusable - float: right; - width: 80px; - padding-left: 10px; - padding-top: 7px; -} - -// Process (workflow) diagrams - -.process-box { - border: 1px solid; - border-radius: 5px; - padding: 0px; - margin: 10px; - - .box-label { - border-bottom: 1px solid; - padding-top: 3px; - padding-bottom: 3px; - font-weight: bold; - - .process-label { - - } - - .process-outcome { - float: right; - } - - } - - .box-content { - padding: 15px; - } -} - -// Tables where the first column is the name of the property/attribute -// (e.g. audit log item details) -// see MID-4300 - -td.prop-name { - min-width: 90px; - font-weight: bold; -} - -th.icon { - // The content of this column is just a single icon. - // WARNING: this means both the header and the table data - // have just a single icon. No text. - // See com.evolveum.midpoint.web.component.data.column.IconColumn - width: 30px; -} - -th.check, td.check { - // The content of this column is just a single checkbox. - // WARNING: this means both the header and the table data - // have just a single checkbox. Nothing else. - // See com.evolveum.midpoint.web.component.data.column.CheckBoxHeaderColumn - width: 34px; -} - -th.shrink { - // We want this column to fit as tightly as possible. - // E.g. for columns that have textual label but - // the content is just an icon or something much smaller - // than the header. - width: -moz-min-content; -} - -th.countLabel{ - // The content of this column is just some integer value. - // WARNING: this means both the header and the table data - // have just some integer value. - // See com.evolveum.midpoint.web.page.admin.certification.PageCertDecisions - width: 70px; -} - -.expand-collapse-button, .expand-collapse-button:hover, .expand-collapse-button:focus { //class for expand-collapse button next to title - color: @text-label-color; - width: 22px; - text-align: center; - cursor: pointer; -} - -.show-empty-button, .show-empty-button:hover .show-empty-button:focus{ //class for show-empty fields button under properties - color: @text-label-color; - font-size: 12px; - padding-bottom: 5px; -} - -.labelContainer > .text-info { // aligning i button to one row with title of container - float: left; -} - -// This will make the tooltip respect new lines. -// Lines will still wrap if they are longer than the default max-width of the container. -.tooltip-inner { - white-space:pre-wrap; -} - -.table-striped { - table-layout: fixed; // fix for text in cells -} - -.shopping-cart-icon > .badge { - margin-left: -10px !important; -} - -@media (max-width: 767px) { - .content-wrapper { - width: 100%; - } -} - -.role-catalog > .object-org-box > .org-tree-container{ - max-height: 50vh; -} - -.skin-red > .wrapper > .main-header > .navbar-static-top > .navbar-custom-menu > .shopping-cart-icon > .badge, -.skin-red-light > .wrapper > .main-header > .navbar-static-top > .navbar-custom-menu > .shopping-cart-icon > .badge{ - border-style: solid; - padding: 2px 5px; - border-color: #f4f4f4; -} - -.small-box-footer>div{ - display: inline-block; -} - -.small-box{ - cursor: default; -} - -.cursor-pointer{ - cursor: pointer; -} - -.buttons-panel-marging{ - margin: 10px; -} - -.position-relative{ - position: relative; -} - -.small-box h3{ - white-space: normal; - font-size: 28px; -} - -.tbody-nth-of-type-even>tr:nth-of-type(even) { - background-color: #f9f9f9 !important; -} -.tbody-nth-of-type-even>tr:nth-of-type(odd) { - background-color: inherit !important; -} - -@media (min-width: 1550px){ - .small-box h3 { - font-size: 35px; - } -} - -.dashboard-widgets{ - display: flex; - flex-flow: row wrap; - display: -webkit-flex; - -webkit-flex-flow: row wrap; -} - -.dashboard-info-box > .small-box { - height:100%; -} - -.dashboard-info-box > .small-box > .small-box-footer { - position: absolute; - bottom: 0px; - width: 100%; -} - -.dashboard-info-box{ - height: 100%; -} - -.padding-bottom-20 { - padding-bottom: 20px; -} -.checkbox-without-margin-bottom .checkbox{ - margin-bottom: 0px !important; - margin-top: 5px !important; -} - -th > div > .sortableLabel .row { - margin: 0px; -} - -td .prism-property-value { - width: 100% !important; -} - -th.composited-icon { - width: 30px; -} - -.small-box > .small-box-footer { - color: inherit !important; -} - -.pagination-xs>li>a { - padding: 0px 5px !important; -} - -.cog-xs { - width: 38px; -} +/* + * Copyright (c) 2010-2020 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +@import "midpoint-theme-variables.less"; + +body.custom-hold-transition { + .content-wrapper, + .right-side, + .main-footer, + .main-sidebar, + .left-side, + .main-header .navbar, + .main-header .logo { + -webkit-transition: none !important; + -moz-transition: none !important; + -ms-transition: none !important; + -o-transition: none !important; + } +} + +.main-header { + & .logo { + + & > span { + height: 100%; + width: 100%; + display: inline-block; + background: url("../img/midpoint_logo_white_180.png") no-repeat 10px 3px; + } + } + & .custom-logo { + + & > img { + display:block; + float:left; + padding-left: 10px; + vertical-align: middle; + max-height: 50px; + } + } + +} + +#wicketDebugLink { + bottom: 55px !important; +} + +div.wicket-debug-buttons { + border: 1px solid #000000; + background-color: #ffffff; + opacity: 0.7; + bottom: 85px; + display: block; + position: fixed; + right: 10px; + z-index: 1000000; + + a { + color: #0000ff; + display: block; + padding: 3px 20px; + } +} + +div.navbar-custom-menu { + margin-right: 14px; +} + +//Used in top right locale combo selection +div.btn-group.bootstrap-select.select-picker-sm { + margin-top: 10px; +} + +// for just to use fake form.form-inline (as div) in form.form-horizontal. Used in button bars. +div.form-inline > div.form-group { + margin-left: 0; + margin-right: 0; +} + +li.dropdown.user.user-menu { + & > ul.dropdown-menu { + border-color: #367fa9; + right: 0; + left: auto; + + & > li.user-footer { + border-color: #367fa9; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + } + } +} + +//table context menu border fix +th.cog, td.cog { + & ul.dropdown-menu.pull-right { + border-color: #337ab7; + } +} +//end table context menu border fix + +//disabled menu css fixes +.sidebar-menu .treeview-menu > li > span { + display: block; + font-size: 14px; + padding: 5px 5px 5px 15px; +} + +.sidebar-menu .treeview-menu > li > span > .fa, +.sidebar-menu .treeview-menu > li > span > .fe, +.sidebar-menu .treeview-menu > li > span > .glyphicon, +.sidebar-menu .treeview-menu > li > span > .ion { + width: 20px; +} + +.sidebar-menu > .header { + // white-space: wrap is problematic in firefox, it wraps expand/collapse icon on next line + white-space: normal !important; +} + +.sidebar-menu > li > a > .fe { + width: 20px; +} + +.sidebar-form, .sidebar-menu > li.header { + padding: 10px 20px 10px 15px; + text-transform: uppercase; + + & i.fa, & i.fe { + margin-top: 2px; + } +} + +body .treeview-menu > li.active > span, +body .treeview-menu > li > span:hover { + color: #000; +} +//end of disabled menu css fixes + +.user-thumbnail-helper { + display: inline-block; + height: 100%; + vertical-align: middle; +} + +.user-thumbnail { + background-color: #FFFFFF; + border-radius: 4px; + height: auto; + max-width: 100%; + max-height: 100%; + vertical-align: middle; +} + +.userpanel-icon-helper { + display: inline-block; + height: 100%; + vertical-align: middle; +} + +.userpanel-icon { + background-color: #FFFFFF; + border-radius: 35%; + //height: 25px; + //width: 25px; + max-width: 25px; + max-height: 25px; + vertical-align: middle; +} + +.userpanel-photo { + background-color: #FFFFFF; + border-radius: 35%; + max-height: 115px; + max-width: 115px; + vertical-align: middle; +} + +// Classes that can be used to change icon styles (enabled, disabled, privileged, etc.) + +.icon-style-normal { + +} + +.icon-style-disabled { + color: #909090; +} + +.icon-style-archived { + color: #c0c0c0; +} + +.icon-style-privileged { + color: #a94442; +} + +.icon-style-end-user { + color: #357ca5; +} + +.icon-style-manager { + color: @object-org-color; +} + +.icon-style-warning { + color: #8a6d3b; +} + +.icon-style-up { + color: #00a65a; +} + +.icon-style-down { + color: #a94442; +} + +.icon-style-broken { + color: #f39c12; +} + +// Classes that can be added to color icons, info boxes and other widgets for particular object types + +.object-user-color { + color: @object-user-color; +} + +.object-role-color { + color: @object-role-color; +} + +.object-org-color { + color: @object-org-color; +} + +.object-service-color { + color: @object-service-color; +} + +.object-resource-color { + color: @object-resource-color; +} + +.object-task-color { + color: @object-task-color; +} + +.object-shadow-color { + color: @object-shadow-color; +} + + +.object-user-bg { + background-color: @object-user-color !important; + color: #fff !important; +} + +.object-role-bg { + background-color: @object-role-color !important; + color: #fff !important; +} + +.object-org-bg { + background-color: @object-org-color !important; + color: #fff !important; +} + +.object-service-bg { + background-color: @object-service-color !important; + color: #fff !important; +} + +.object-resource-bg { + background-color: @object-resource-color !important; + color: #fff !important; +} + +.object-task-bg { + background-color: @object-task-color !important; + color: #fff !important; +} + +.object-task-bg-gray { + background-color: #646464 !important; + color: #fff !important; +} + +.object-shadow-bg { + background-color: @object-shadow-color !important; + color: #fff !important; +} + +.object-disabled-bg { + background-color: @object-disabled-color !important; + color: #fff !important; +} + +.object-access-bg { + background-color: @object-access-color !important; + color: #fff !important; +} + +.object-failed-bg { + background-color: @object-failed-color !important; + color: #fff !important; +} + +.object-access-only-bg { + background-color: @object-access-color !important; +} + +.object-failed-only-bg { + background-color: @object-failed-color !important; +} + +// Colored boxes for each object type + +#box-object(@color) { + border-top-color: @color; + + &.box-solid { + border: 1px solid @color; + } + + &.box-solid > .box-header { + color: #fff; + background: @color; + background-color: @color; + } + +} + +.object-user-box { + #box-object(@object-user-color); +} + +.object-role-box { + #box-object(@object-role-color); +} + +.object-org-box { + #box-object(@object-org-color); +} + +.object-service-box { + #box-object(@object-service-color); +} + +.object-task-box { + #box-object(@object-task-color); +} + +.object-resource-box { + #box-object(@object-resource-color); +} + +.object-shadow-box { + #box-object(@object-shadow-color); +} + +#box-thin-object(@color) { + border: 1px solid @color; + + .box-header { + border-bottom: 1px solid @color; + } +} + +.object-user-box-thin { + #box-thin-object(@object-user-color); +} + +.object-role-box-thin { + #box-thin-object(@object-role-color); +} + +.object-org-box-thin { + #box-thin-object(@object-org-color); +} + +.object-service-box-thin { + #box-thin-object(@object-service-color); +} + +.object-resource-box-thin { + #box-thin-object(@object-resource-color); +} + +.object-shadow-box-thin { + #box-thin-object(@object-shadow-color); +} + +.object-task-box-thin { + #box-thin-object(@object-task-color); +} + +// Summary panel (panel above the edit user/role/org forms) + +#info-box-summary-panel(@color) { + border-top: 3px solid @color; + min-height: 93px; +} + +.info-box.summary-panel-user { + #info-box-summary-panel(@object-user-color); +} + +.info-box.summary-panel-role { + #info-box-summary-panel(@object-role-color); +} + +.info-box.summary-panel-org { + #info-box-summary-panel(@object-org-color); +} + +.info-box.summary-panel-service { + #info-box-summary-panel(@object-service-color); +} + +.info-box.summary-panel-resource { + #info-box-summary-panel(@object-resource-color); +} + +.info-box.summary-panel-shadow { + #info-box-summary-panel(@object-shadow-color); +} + +.info-box.summary-panel-task { + #info-box-summary-panel(@object-task-color); +} + +#info-box-icon-summary-panel(@color){ + color: #FFF !important; + background-color: @color; + padding: 3px; + white-space: nowrap; + text-align: center; + line-height: 0px; + border-radius: 0; +} + +.info-box-icon.summary-panel-user { + #info-box-icon-summary-panel(@object-user-color); +} + +.info-box-icon.summary-panel-role { + #info-box-icon-summary-panel(@object-role-color); +} + +.info-box-icon.summary-panel-org { + #info-box-icon-summary-panel(@object-org-color); +} + +.info-box-icon.summary-panel-service { + #info-box-icon-summary-panel(@object-service-color); +} + +.info-box-icon.summary-panel-resource { + #info-box-icon-summary-panel(@object-resource-color); +} + +.info-box-icon.summary-panel-shadow { + #info-box-icon-summary-panel(@object-shadow-color); +} + +.info-box-icon.summary-panel-task { + #info-box-icon-summary-panel(@object-task-color); +} + +// other info box enhancements (e.g. role assignment) + +.info-box-ethereal { + // "lighter" info box, without the border or any heavy decorations + box-shadow: none; + border: none; +} + +.info-box-icon-ethereal { + background-color: transparent; +} + +.info-box-icon-ethereal-image { + font-size: 56px; +} + +.info-box-description { + display: block; + font-weight: normal; + font-size: 14px; +} + +.relation-label { + +} + +// End-user home (PageSelfDashboard) + +.quicksearch-panel { + margin-bottom: 20px; +} + +// assignments dashboard panel +.dash-assignment-header { + + .target-name { + font-weight: bold; + margin-right: 5px; + } + + .target-display-name { + + } + + .target-relation { + margin-left: 10px; + } +} + +// Admin dashboard + +.dashboard-info-box { + > div > .info-box { + cursor: pointer; + } +} + + +// Datables/lists (BoxedTablePanel) +.boxed-table { + margin-bottom: 0px; + + &.without-box-header-top-border { + border-top: 0px; + } + + table { + // prohibit overflow of the table beyond the bounding box + table-layout: fixed; + } +} + + +.boxed-table-footer-button-toolbar { + display: inline-block; +} + +.boxed-table-footer-paging { + display: block; + float: right; + + .btn-group { + margin-left: 10px; + vertical-align: top; + } + + .paging_bootstrap { + display: inline-block; + } + + .dataTables_info { + margin-right: 10px; + display: inline-block; + vertical-align: top; + } +} + +.boxed-table-footer-paging-center { + display: block; + + .btn-group { + margin-left: 10px; + vertical-align: top; + } + + .paging_bootstrap { + display: inline-block; + } + + .dataTables_info { + margin-right: 10px; + display: inline-block; + vertical-align: top; + } +} + +// capability buttons in resource details page + +.btn-resource-capability { + width: 90px; + height: 75px; + padding-top: 10px; + white-space: normal; +} + +// resource content pages (ResourceContentPanel) + +.resource-content-selection { + + .form-group { + margin-bottom: 5px; + } +} + +.control-suffix { + text-align: left !important; + padding-left: 0px; +} + +// Feedback messages ??? + +.feedback-message.box { + box-shadow: 0 0px 0px rgba(0, 0, 0, 0.1); + word-break: inherit; +} + +.feedback-message.box-body { + padding-top : 5px; + padding-left : 10px; + padding-right : 0px; + padding-bottom : 0px; +} + +.feedback-message.box.box-solid.box-danger { + border-left: 3px solid #dd4b39; + border-right : 0px; + border-top : 0px; + border-bottom : 0px; +} + + +.feedback-message.box.box-solid.box-success { + border-left: 3px solid #00a65a; + border-right : 0px; + border-top : 0px; + border-bottom : 0px; +} + +.feedback-message.box.box-solid.box-info { + border-left: 3px solid #00c0ef; + border-right : 0px; + border-top : 0px; + border-bottom : 0px; +} + +.feedback-message.box.box-solid.box-warning { + border-left: 3px solid #f39c12; + border-right : 0px; + border-top : 0px; + border-bottom : 0px; +} + +.feedback-message.dl-horizontal { + + & dt { + width: 100px; + } +} + + +.feedback-message.dl-horizontal { + + & dd { + margin-left: 130px; + word-break: break-word; + } +} + +.feedback-message .icon { + margin-right: 10px; +} + +.feedback-message { + & .box-header .box-title { + font-size: 14px; + } + + & .box-header { + border-radius: 0 3px 3px 0; + } +} + +.summary-panel-display-name { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + display: inline; + max-width: 800px; + } + +.summary-panel-navigation-button { + display: inline; + margin-left: 10px; + color: @text-dimmed-color; +} + +.summary-panel-navigation-button:hover { + display: inline; + margin-left: 10px; + color: @text-dark-dimmed-color; +} + +.summary-panel-identifier { + white-space: pre-wrap; + color: @text-dimmed-color; + font-weight: normal; +} + +.summary-panel-title { + white-space: pre-wrap; +} + +.summary-panel-organization { + font-size: 16px; + display: block; + white-space: pre-wrap; +} + +.summary-content-box { + display: block; +} + +.summary-text-box { + display: inline-block; +} + +.summary-tag-box { + float: right; +} + +.summary-tag-box-wide { + float: right; + width: 200px; +} + +.summary-tag { + display: block; + padding-left: 10px; + padding-right: 10px; + margin: 3px; + border: 1px solid #e0e0e0; + border-radius: 3px; + background-color: #fbfbfb; + margin-right: 0px; +} + +.summary-tag-icon { + width: 20px; + margin-right: 2px; +} + +// form input for binary data upload (used e.g. for photo) + +.form-object-value-binary-box { + width: 100%; + padding: 0px; +} + +.form-object-value-binary-file-input { + width: 65%; + vertical-align: middle; + display: inline !important; +} + + + +// top navigation bar: page title + +.navbar-title { + float: left; + background-color: transparent; + padding-top: 8px; +} + +.navbar-ajax { + float: left; + + & #ajax_busy { + margin-top: 12px; + margin-left: 8px; + } +} + +.page-title { + color: #fff; + background-color: transparent; + font-size: 22px; +} + +.navbar-custom-menu > .breadcrumb { + float: left; + background: transparent; + margin-top: 10px; + margin-bottom: 0; + margin-right: 20px; + font-size: 12px; + padding: 7px 5px; + + //.border-radius(2px); + + > li > a { + color: #444; + text-decoration: none; + display: inline-block; + + > .fa, > .glyphicon, > .ion, > .fe { + margin-right: 5px; + } + } + + > li + li:before { + content: '>\00a0'; + padding: 0 0 0 5px; + } + + //@media (max-width: @screen-sm-max) { + // > .breadcrumb { + // position: relative; + // margin-top: 5px; + // top: 0; + // right: 0; + // float: none; + // background: @gray; + // padding-left: 10px; + // + // li:before { + // color: darken(@gray, 20%); + // } + // } + //} +} + +// Prism containers and attributes + +.prism-object { + & > div.prism-header { + padding-left: 15px; // to match container header padding + } +} + +.prism-multivalue-container { + margin-left: 15px; // aligning multivalue container with superior container +} + +.top-level-prism-container { + border-top: 1px solid #ddd; + padding-top: 5px; +} + +.multivalue-container > .container-wrapper > div { + padding-left: 40px; +} + +//top-level-prism-container is class for first showed container +.top-level-prism-container > .container-wrapper > div > div > +.prism-properties > .prism-containers { + padding-left: 0px; //align one-level containers +} + +//top-level-prism-container is class for first showed container +.top-level-prism-container > .container-wrapper > div > div > +.prism-properties > .prism-containers > .prism-property { + border-top: 1px solid #ddd; // line over area of container +} + +.prism-containers > .top-level-prism-container > .container-wrapper > div > div > .prism-properties > .prism-containers { + padding-left: 40px; +} +.prism-containers > .top-level-prism-container > .container-wrapper > div > div > .prism-properties > .prism-containers > .prism-property { + border-top: 0px solid #ddd; +} + + + +.top-level-prism-container .row { + margin-right: 0px; + margin-left: 0px; +} + +.top-level-prism-container .prism-header { + margin-bottom: 0px; + padding-top: 5px; + padding-bottom: 5px; +} + +.prism-container { +// border-bottom: 1px solid @table-divider-color; + margin-bottom: 15px; + padding-bottom: 15px; +} + +.multivalue-container > .container-wrapper > div > .added-value-background { + background-color: #dff0d8; // green background for new value of multivalue container +} + +.multivalue-container > .container-wrapper > div > .removed-value-background { + background-color: #f2dede; // green background for new value of multivalue container +} + +.top-level-prism-container > .prism-properties > div { + padding-left: 0px; +} + +.prism-properties { + + & > div { + padding-left: 40px; + } + + .stripe { + background-color: @table-stripe-bg-color; + } +} +.prism-header { + margin-bottom: 15px; + display: block; +} + +.prism-title { + font-size: 16px; + font-weight: 600; + color: @text-label-color; + margin-right: 15px; + float: left; + padding-top: 3px; +} + +.prism-property { + padding-top: 5px; + padding-bottom: 5px; +} + +.prism-property-label { //padding because expand collapse button, which have 37px + padding-left: 20px; + word-wrap:break-word; + padding-top: 5px; +} + +.prism-value { // DEPRECATED: rework the prism-value vs prism-property-value later + margin-top: 3px; +} + +// Common styles for object detail pages + +.assignable-header { + border-bottom: 2px solid @table-divider-color; + margin: 0px; + margin-bottom: 10px; + padding-left: 5px; // align with the checkboxes below + + div.col-xs-10 { + padding: 0 5px; + + & > input { + display: inline-block; + } + + > h3 { + display: inline-block; + margin-bottom: 5px; + margin-left: 5px; + } + } + + & > div.cog { + margin-top: 18px; + padding-right: 5px; + } +} + +.check-table-header { + padding-left: 20px; + + & > input[type="checkbox"] { + position: absolute; + margin-left: -20px; + margin-top: 6px; + } + + .check-table-label { + + .check-table-header-icon { + margin-left: 4px; + position: relative; + bottom: 1px; + } + + .check-table-header-name { + margin-left: 5px; + font-size: 18px; + color: @text-label-color !important; + } + + .check-table-header-description { + margin-left: 10px; + } + + .check-table-header-status { + margin-left: 10px; + position: relative; + bottom: 2px; + } + + .check-table-header-show-more { + color: @text-dimmed-color !important; + } + + .delegation-arrow-icon { + font-size: 24px; + margin-left: 5px; + margin-right: 5px; + position: relative; + top: 3px; + } + } +} + +.tab-label { + & > small { + margin-left: 6px; + position: relative; + top: -1px; + } +} + +.box-header.add { + background-color: #caffca; +} + +.box-header.delete { + background-color: #ffcaca; +} + +.main-form-panel { // Used on pages where there is just one main panel and it does not + // provide formatting by itself. E.g. pages that are both object lists + // and forms (such as workitems, requests). + margin-bottom: 20px; +} + +.options-container { + +} + +.option-checkbox { + float: left; + border: 1px solid @table-divider-color; + margin-right: 10px; + padding-bottom: 5px; + padding-left: 6px; + padding-right: 6px; +} + +.main-button-bar { + +} + +// Badge colors used in object details tabs (and maybe elsewhere) + +.badge-active { + background-color: #3c8dbc !important; +} + +.badge-passive { + color: #fff; + background-color: #d2d6de !important; +} + +// Projections tab (focus pages) + +.projections { + +} + +.projections-header { + +} + +.projection { + margin-bottom: 10px; + #box-thin-object(@object-shadow-color); + + .box-header { + + .box-tools { + margin-top: 5px; + } + } +} + +.check-table-header-pending-operation { + margin-left: 10px; +} + +// Assignments tab (focus pages) + +.assignments { + +} + +.assignment { + margin-bottom: 10px; + + .box-header { + + .box-tools { + margin-top: 5px; + } + } +} + +// Orgtree (OrgMemberPanel) + +span.tree-content > table { + width: 100%; + max-width: 100%; +} + +span.tree-content > table tr td:last-child { + width: 1%; + vertical-align: top; +} + +span.tree-content > table tr td:first-child { + width: 1%; + vertical-align: top; +} + +.tree-theme-windows > div > .tree-branch > .tree-node.success, .tree-subtree > .tree-branch > .tree-node.success{ + background-color: #dff0d8; +} + +.tree-subtree > .tree-branch:nth-of-type(odd) { + background-color: #f9f9f9; +} + +.tree-subtree > .tree-branch > .tree-node:hover, .tree-theme-windows > div > .tree-branch > .tree-node:hover { + background-color: #eee; +} + +.org-tree-container { + overflow-y: auto; +} + +.org-members-additional-search { + text-align: right; + margin-right: 20px !important; +} + +.org-managers-box { + + .box-body { + padding-top: 13px; + padding-bottom: 0px; + } +} + +.org-members-box { + + .box-body { + padding-top: 13px; + } +} + + +.manager-tools { // org tree manager buttons: HACK, need to figure out something better + float: right; + width: 42px; + padding-left: 10px; + padding-top: 7px; +} + +.manager-btn { // org tree manager buttons: HACK, need to figure out something better + margin: 3px; + border-style: solid; + border-width: 1px; + border-radius: 3px; + padding: 3px; + width: 23px; + text-align: center; +} + +.box-solid > .box-header > .box-tools > .cog > ul > li > a > i { + color: #fff; +} + + +// Request role page + +.request-role-col-available { + padding-right: 0px; +} + +.request-role-col-control { + +} + +.request-role-col-current { + padding-left: 0px; +} + +.request-role-box { + .box-body { + padding-bottom: 0px; + } +} + +.multiple-assignment-selector { + + .multiple-assignment-selector-section:first-child { + border-top-width: 0px; + padding-top: 0px; + min-height: 36px; + } + + .multiple-assignment-selector-section:last-child { + padding-bottom: 0px; + } +} + +.multiple-assignment-selector-section { + min-height: 48px; + padding-top: 8px; + padding-bottom: 8px; + border-top: 2px solid @table-divider-color; +} + +.multiple-assignment-selector-section-table { + .box { + border-width: 0px; + } +} + +.multiple-assignment-selector-table-container { + min-height: 415px; +} + +.multiple-assignment-selector-table { + width: 100%; +} + +.multiple-assignment-selector-table-footer { + float: left; +} + +.request-role-control-button { + &.btn-primary > i { + font-size: 32px; + } +} + +// Password change dialog (ChangePasswordPanel, PasswordPanel) + +.password-panel { +} + +.password-propagation { + margin-top: 5px; +} + +.password-propagation-legend { + padding-bottom: 10px; + border-bottom: 1px solid @table-divider-color; + margin-bottom: 10px; + margin-left: 0px; + margin-right: 0px; +} + +// operation result + +.paramtable { + border: 0px; + + .paramtable-row { + + .paramtable-name { + vertical-align: top; + } + + .paramtable-name::after { + content: ':'; + } + + .paramtable-value { + padding-left: 5px; + padding-right: 20px; + white-space: pre-wrap; + word-break: break-all; + } + } +} + +.stacktrace { + font-family: monospace; + white-space: pre-wrap; + font-size: 11px; +} + +dd.stacktrace::before { + content: none; +} + +// Shopping cart + +.shopping-cart-item-table { + margin-top: 10px; + margin-left: 0px; + margin-right: 0px; + min-height: 460px; +} + +.shopping-cart-icon { + color: #f4f4f4; + margin-top: 10px; + margin-right: 5px; +} + +.shopping-cart-item-box { + + .inner { + height: 120px; + cursor: pointer; + } + + .inner-label { + font-size: 18px; + padding-top: 10px; + padding-left: 12px; + padding-right: 12px; + padding-bottom: 10px; + max-width: 80%; + overflow: hidden; + text-overflow: ellipsis + } + .inner-description { + font-size: 11px; + padding-left: 12px; + padding-right: 12px; + max-width: 70%; + max-height: 50%; + overflow: hidden; + text-overflow: ellipsis + } +} + +.shopping-cart-item-box-footer { + padding: 3px; + padding-left: 8px; + padding-right: 8px; + color: rgba(255, 255, 255, 0.8); + display: block; + z-index: 10; + overflow-y: auto; + background: rgba(0, 0, 0, 0.1); + + .shopping-cart-item-button-details { + cursor: pointer; + } + + .shopping-cart-item-button-details-disabled { + cursor: default; + color: darkgrey; + } + + .shopping-cart-item-button-add { + cursor: pointer; + float: right; + } + + .shopping-cart-item-button-add-disabled { + cursor: default; + float: right; + color: darkgrey; + } +} + +// Object merge dialog + +.object-merge-panel { + padding-top: 10px; + padding-bottom: 10px; +} + +.object-merge-equation-panel { + padding-top: 10px; +} + +.object-merge-sign { + font-size: 80px; + padding-top: 15px; +} + +.object-merge-switch-direction-col { + padding-left: 0px; +} + +// Consent, mostly self-service pages + +.consent-info-box-icon { + background: none; +} + +.consent-buttons { // maybe figure out something better, something really reusable + float: right; + width: 200px; + padding-left: 10px; + padding-top: 7px; +} + +// Process (workflow) diagrams + +.process-box { + border: 1px solid; + border-radius: 5px; + padding: 0px; + margin: 10px; + + .box-label { + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + font-weight: bold; + + .process-label { + + } + + .process-outcome { + float: right; + } + + } + + .box-content { + padding: 15px; + } +} + +// Tables where the first column is the name of the property/attribute +// (e.g. audit log item details) +// see MID-4300 + +td.prop-name { + min-width: 90px; + font-weight: bold; +} + +th.icon { + // The content of this column is just a single icon. + // WARNING: this means both the header and the table data + // have just a single icon. No text. + // See com.evolveum.midpoint.web.component.data.column.IconColumn + width: 30px; +} + +th.check, td.check { + // The content of this column is just a single checkbox. + // WARNING: this means both the header and the table data + // have just a single checkbox. Nothing else. + // See com.evolveum.midpoint.web.component.data.column.CheckBoxHeaderColumn + width: 34px; +} + +th.shrink { + // We want this column to fit as tightly as possible. + // E.g. for columns that have textual label but + // the content is just an icon or something much smaller + // than the header. + width: -moz-min-content; +} + +th.countLabel{ + // The content of this column is just some integer value. + // WARNING: this means both the header and the table data + // have just some integer value. + // See com.evolveum.midpoint.web.page.admin.certification.PageCertDecisions + width: 70px; +} + +.expand-collapse-button, .expand-collapse-button:hover, .expand-collapse-button:focus { //class for expand-collapse button next to title + color: @text-label-color; + width: 22px; + text-align: center; + cursor: pointer; +} + +.show-empty-button, .show-empty-button:hover .show-empty-button:focus{ //class for show-empty fields button under properties + color: @text-label-color; + font-size: 12px; + padding-bottom: 5px; +} + +.labelContainer > .text-info { // aligning i button to one row with title of container + float: left; +} + +// This will make the tooltip respect new lines. +// Lines will still wrap if they are longer than the default max-width of the container. +.tooltip-inner { + white-space:pre-wrap; +} + +.table-striped { + table-layout: fixed; // fix for text in cells +} + +.shopping-cart-icon > .badge { + margin-left: -10px !important; +} + +@media (max-width: 767px) { + .content-wrapper { + width: 100%; + } +} + +.role-catalog > .object-org-box > .org-tree-container{ + max-height: 50vh; +} + +.skin-red > .wrapper > .main-header > .navbar-static-top > .navbar-custom-menu > .shopping-cart-icon > .badge, +.skin-red-light > .wrapper > .main-header > .navbar-static-top > .navbar-custom-menu > .shopping-cart-icon > .badge{ + border-style: solid; + padding: 2px 5px; + border-color: #f4f4f4; +} + +.small-box-footer>div{ + display: inline-block; +} + +.small-box{ + cursor: default; +} + +.cursor-pointer{ + cursor: pointer; +} + +.buttons-panel-marging{ + margin: 10px; +} + +.position-relative{ + position: relative; +} + +.small-box h3{ + white-space: normal; + font-size: 28px; +} + +.tbody-nth-of-type-even>tr:nth-of-type(even) { + background-color: #f9f9f9 !important; +} +.tbody-nth-of-type-even>tr:nth-of-type(odd) { + background-color: inherit !important; +} + +@media (min-width: 1550px){ + .small-box h3 { + font-size: 35px; + } +} + +.dashboard-widgets{ + display: flex; + flex-flow: row wrap; + display: -webkit-flex; + -webkit-flex-flow: row wrap; +} + +.dashboard-info-box > .small-box { + height:100%; +} + +.dashboard-info-box > .small-box > .small-box-footer { + position: absolute; + bottom: 0px; + width: 100%; +} + +.dashboard-info-box{ + height: 100%; +} + +.padding-bottom-20 { + padding-bottom: 20px; +} +.checkbox-without-margin-bottom .checkbox{ + margin-bottom: 0px !important; + margin-top: 5px !important; +} + +th > div > .sortableLabel .row { + margin: 0px; +} + +td .prism-property-value { + width: 100% !important; +} + +th.composited-icon { + width: 30px; +} + +.small-box > .small-box-footer { + color: inherit !important; +} + +.pagination-xs>li>a { + padding: 0px 5px !important; +} + +.cog-xs { + width: 38px; +}